Skip to content

Commit

Permalink
Add onComponentInstanceCreated constructor option (#892)
Browse files Browse the repository at this point in the history
Takes listener function that will be called when component-local
instance of VueI18n is created.

This allows for extending component-local VueI18n instances. Those are
created when Vue component specifies i18n options in an "i18n" property
as a plain object.

This allows Nuxt to also extend those instances in addition to extending
the root instance, so that there are no missing properties that would
cause users code to crash.

Fixes #887
  • Loading branch information
rchl committed May 26, 2020
1 parent 80c8af3 commit 885637f
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 9 deletions.
4 changes: 3 additions & 1 deletion decls/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,14 @@ declare type NumberFormatOptions = {
};
declare type NumberFormat = { [key: string]: NumberFormatOptions };
declare type NumberFormats = { [key: Locale]: NumberFormat };
declare type Modifiers = { [key: string]: (str : string) => string };
declare type Modifiers = { [key: string]: (str: string) => string };

declare type TranslateResult = string | LocaleMessages;
declare type DateTimeFormatResult = string;
declare type NumberFormatResult = string;
declare type MissingHandler = (locale: Locale, key: Path, vm?: any) => string | void;
declare type PostTranslationHandler = (str: string, key?: string) => string;
declare type ComponentInstanceCreatedListener = (newI18n: I18n, rootI18n: I18n) => void;

declare type FormattedNumberPartType = 'currency' | 'decimal' | 'fraction' | 'group' | 'infinity' | 'integer' | 'literal' | 'minusSign' | 'nan' | 'plusSign' | 'percentSign';
declare type FormattedNumberPart = {
Expand Down Expand Up @@ -84,6 +85,7 @@ declare type I18nOptions = {
warnHtmlInMessage?: WarnHtmlInMessageLevel,
sharedMessages?: LocaleMessage,
postTranslation?: PostTranslationHandler,
componentInstanceCreatedListener?: ComponentInstanceCreatedListener,
};

declare type IntlAvailability = {
Expand Down
8 changes: 8 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export default class VueI18n {
_numberFormatters: Object
_path: I18nPath
_dataListeners: Array<any>
_componentInstanceCreatedListener: ?ComponentInstanceCreatedListener
_preserveDirectiveContent: boolean
_warnHtmlInMessage: WarnHtmlInMessageLevel
_postTranslation: ?PostTranslationHandler
Expand Down Expand Up @@ -101,6 +102,7 @@ export default class VueI18n {
this._numberFormatters = {}
this._path = new I18nPath()
this._dataListeners = []
this._componentInstanceCreatedListener = options.componentInstanceCreatedListener || null
this._preserveDirectiveContent = options.preserveDirectiveContent === undefined
? false
: !!options.preserveDirectiveContent
Expand Down Expand Up @@ -227,6 +229,12 @@ export default class VueI18n {
}, { immediate: true })
}

onComponentInstanceCreated (newI18n: I18n) {
if (this._componentInstanceCreatedListener) {
this._componentInstanceCreatedListener(newI18n, this)
}
}

get vm (): any { return this._vm }

get messages (): LocaleMessages { return looseClone(this._getMessages()) }
Expand Down
23 changes: 15 additions & 8 deletions src/mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,19 @@ export default {
this._i18n = options.i18n
this._i18nWatcher = this._i18n.watchI18nData()
} else if (isPlainObject(options.i18n)) {
const rootI18n = this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n
? this.$root.$i18n
: null
// component local i18n
if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
if (rootI18n) {
options.i18n.root = this.$root
options.i18n.formatter = this.$root.$i18n.formatter
options.i18n.fallbackLocale = this.$root.$i18n.fallbackLocale
options.i18n.formatFallbackMessages = this.$root.$i18n.formatFallbackMessages
options.i18n.silentTranslationWarn = this.$root.$i18n.silentTranslationWarn
options.i18n.silentFallbackWarn = this.$root.$i18n.silentFallbackWarn
options.i18n.pluralizationRules = this.$root.$i18n.pluralizationRules
options.i18n.preserveDirectiveContent = this.$root.$i18n.preserveDirectiveContent
options.i18n.formatter = rootI18n.formatter
options.i18n.fallbackLocale = rootI18n.fallbackLocale
options.i18n.formatFallbackMessages = rootI18n.formatFallbackMessages
options.i18n.silentTranslationWarn = rootI18n.silentTranslationWarn
options.i18n.silentFallbackWarn = rootI18n.silentFallbackWarn
options.i18n.pluralizationRules = rootI18n.pluralizationRules
options.i18n.preserveDirectiveContent = rootI18n.preserveDirectiveContent
}

// init locale messages via custom blocks
Expand Down Expand Up @@ -67,6 +70,10 @@ export default {
if (options.i18n.sync === undefined || !!options.i18n.sync) {
this._localeWatcher = this.$i18n.watchLocale()
}

if (rootI18n) {
rootI18n.onComponentInstanceCreated(this._i18n)
}
} else {
if (process.env.NODE_ENV !== 'production') {
warn(`Cannot be interpreted 'i18n' option.`)
Expand Down
2 changes: 2 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ declare namespace VueI18n {

type MissingHandler = (locale: Locale, key: Path, vm: Vue | null, values: any) => string | void;
type PostTranslationHandler = (str: string, key?: string) => string;
type ComponentInstanceCreatedListener = (newVm: VueI18n & IVueI18n, rootVm: VueI18n & IVueI18n) => void;

interface IntlAvailability {
dateTimeFormat: boolean;
Expand All @@ -113,6 +114,7 @@ declare namespace VueI18n {
warnHtmlInMessage?: WarnHtmlInMessageLevel;
sharedMessages?: LocaleMessages;
postTranslation?: PostTranslationHandler;
componentInstanceCreatedListener?: ComponentInstanceCreatedListener;
}
}

Expand Down
12 changes: 12 additions & 0 deletions vuepress/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,18 @@ A handler for post processing of translation. The handler gets after being calle

This handler is useful if you want to filter on translated text such as space trimming.

#### componentInstanceCreatedListener

> 8.18+
* **Type:** `ComponentInstanceCreatedListener`

* **Default:** `null`

A handler for getting notified when component-local instance was created. The handler gets called with new and old (root) VueI18n instances.

This handler is useful when extending the root VueI18n instance and wanting to also apply those extensions to component-local instance.

### Properties

#### locale
Expand Down
12 changes: 12 additions & 0 deletions vuepress/ru/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,18 @@ sidebar: auto

Может пригодиться при необходимости дополнительно обработать итоговый текст перевода, например избавиться от висящих пробелов.

#### componentInstanceCreatedListener

> 8.18+
* **Type:** `ComponentInstanceCreatedListener`

* **Default:** `null`

A handler for getting notified when component-local instance was created. The handler gets called with new and old (root) VueI18n instances.

This handler is useful when extending the root VueI18n instance and wanting to also apply those extensions to component-local instance.

### Свойства

#### locale
Expand Down

0 comments on commit 885637f

Please sign in to comment.