From 5c46c07e272d46ea7c95b7bf0cdd510a93e4c6d6 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Wed, 8 Mar 2017 13:44:41 +0900 Subject: [PATCH] :star: new: add `sync` option --- decls/i18n.js | 8 ++++++-- src/index.js | 23 +++++++++++++++++++++++ src/mixin.js | 10 +++++++++- test/unit/component.test.js | 23 ++++++++++++++++++++++- 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/decls/i18n.js b/decls/i18n.js index 6d1853df8..4a8b91014 100644 --- a/decls/i18n.js +++ b/decls/i18n.js @@ -11,12 +11,14 @@ declare type I18nOptions = { formatter?: Formatter, missing?: MissingHandler, root?: I18n, - fallbackRoot?: boolean + fallbackRoot?: boolean, + sync?: boolean } declare interface I18n { static install: () => void, static version: string, + get vm() :any, get locale (): string, set locale (locale: string): void, get fallbackLocale (): string, @@ -29,7 +31,9 @@ declare interface I18n { set formatter (formatter: Formatter): void, t (key: string, ...args: any): string, tc (key: string, choice?: number, ...args: any): any, - te (key: string, ...args: any): boolean + te (key: string, ...args: any): boolean, + watchLocale (): any, + unwatchLocale (): boolean } declare type FormatterOptions = Dictionary diff --git a/src/index.js b/src/index.js index 32916d2c4..6836a9bd8 100644 --- a/src/index.js +++ b/src/index.js @@ -14,10 +14,12 @@ export default class VueI18n { _vm: any _formatter: Formatter _root: ?I18n + _sync: ?boolean _fallbackRoot: boolean _fallbackLocale: string _missing: ?MissingHandler _exist: Function + _watcher: any constructor (options: I18nOptions = {}) { const locale: string = options.locale || 'en-US' @@ -27,6 +29,7 @@ export default class VueI18n { this._formatter = options.formatter || new BaseFormatter() this._missing = options.missing this._root = options.root || null + this._sync = options.sync || false this._fallbackRoot = options.fallbackRoot || false this._exist = (message: Object, key: string): boolean => { @@ -44,6 +47,26 @@ export default class VueI18n { Vue.config.silent = silent } + watchLocale (): any { + if (!this._sync || !this._root) { return null } + const target: any = this._vm + this._watcher = this._root.vm.$watch('locale', (val) => { + target.$set(target, 'locale', val) + }, { immediate: true }) + return this._watcher + } + + unwatchLocale (): boolean { + if (!this._sync || !this._watcher) { return false } + if (this._watcher) { + this._watcher() + delete this._watcher + } + return true + } + + get vm (): any { return this._vm } + get messages (): Messages { return this._vm.$data.messages } set messages (messages: Messages): void { this._vm.$set(this._vm, 'messages', messages) } diff --git a/src/mixin.js b/src/mixin.js index 94cfbb147..9c7d54583 100644 --- a/src/mixin.js +++ b/src/mixin.js @@ -53,9 +53,12 @@ export default { options.i18n.root = this.$root.$i18n } this.$i18n = new VueI18n(options.i18n) + if (options.i18n.sync) { + this._localeWatcher = this.$i18n.watchLocale() + } } else { if (process.env.NODE_ENV !== 'production') { - warn(`Cannot be interpreted 'i18n' options.`) + warn(`Cannot be interpreted 'i18n' option.`) } } } else if (this.$root && this.$root.$i18n && typeName(this.$root.$i18n) === 'VueI18n') { @@ -65,6 +68,11 @@ export default { }, destroyed () { + if (this._localeWatcher) { + this.$i18n.unwatchLocale() + delete this._localeWatcher + } + this.$i18n = null } } diff --git a/test/unit/component.test.js b/test/unit/component.test.js index 8b4b7703b..83d67b506 100644 --- a/test/unit/component.test.js +++ b/test/unit/component.test.js @@ -46,9 +46,26 @@ describe('component translation', () => { } }, child2: { + components: { + 'sub-child2': { + i18n: { + sync: true, + messages: { + en: { who: 'sub-child2' }, + ja: { who: 'サブの子2' } + } + }, + render (h) { + return h('div', {}, [ + h('p', { ref: 'who' }, [this.$t('who')]) + ]) + } + } + }, render (h) { return h('div', {}, [ - h('p', { ref: 'who' }, [this.$t('who')]) + h('p', { ref: 'who' }, [this.$t('who')]), + h('sub-child2', { ref: 'sub-child2' }) ]) } } @@ -70,11 +87,13 @@ describe('component translation', () => { const child1Fallback = vm.$refs.child1.$refs.fallback const child2 = vm.$refs.child2.$refs.who const subChild1 = vm.$refs.child1.$refs['sub-child1'].$refs.who + const subChild2 = vm.$refs.child2.$refs['sub-child2'].$refs.who assert.equal(root.textContent, 'ルート') assert.equal(child1.textContent, 'child1') assert.equal(child1Fallback.textContent, 'フォールバック') assert.equal(child2.textContent, 'ルート') assert.equal(subChild1.textContent, 'ルート') + assert.equal(subChild2.textContent, 'サブの子2') // change locale i18n.locale = 'en' @@ -85,6 +104,8 @@ describe('component translation', () => { assert.equal(child1Fallback.textContent, 'fallback') assert.equal(child2.textContent, 'root') assert.equal(subChild1.textContent, 'root') + assert.equal(subChild2.textContent, 'sub-child2') + vm.$destroy() }).then(() => { assert(vm.$i18n === null)