Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add a new option fallbackRootWithEmptyString #1441

Merged
merged 2 commits into from
Jan 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions decls/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ declare type I18nOptions = {
modifiers?: Modifiers,
root?: I18n, // for internal
fallbackRoot?: boolean,
fallbackRootWithEmptyString?: boolean,
formatFallbackMessages?: boolean,
sync?: boolean,
silentTranslationWarn?: boolean | RegExp,
Expand Down
14 changes: 14 additions & 0 deletions gitbook/en/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,20 @@ You can specify the below some options of `I18nOptions` constructor options of [

If `false`, it's warned, and is returned the key.

#### fallbackRootWithEmptyString

> :new: 8.26+

- **Type:** `Boolean`

- **Default:** `true`

In the component localization, whether to fall back to root level (global) localization when local message is an empty string.

Please note the default behavior in vue-i18n 9.x is to not falling back to root for local message that is empty string.

If `false`, the empty local message will not fall back to root and will be kept as empty string.

#### sync

- **Type:** `Boolean`
Expand Down
8 changes: 6 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export default class VueI18n {
_root: any
_sync: boolean
_fallbackRoot: boolean
_fallbackRootWithEmptyString: boolean
_localeChainCache: { [key: string]: Array<Locale>; }
_missing: ?MissingHandler
_exist: Function
Expand Down Expand Up @@ -95,6 +96,9 @@ export default class VueI18n {
this._fallbackRoot = options.fallbackRoot === undefined
? true
: !!options.fallbackRoot
this._fallbackRootWithEmptyString = options.fallbackRootWithEmptyString === undefined
? true
: !!options.fallbackRootWithEmptyString
this._formatFallbackMessages = options.formatFallbackMessages === undefined
? false
: !!options.formatFallbackMessages
Expand Down Expand Up @@ -379,7 +383,7 @@ export default class VueI18n {
}

_isFallbackRoot (val: any): boolean {
return !val && !isNull(this._root) && this._fallbackRoot
return (this._fallbackRootWithEmptyString? !val : isNull(val)) && !isNull(this._root) && this._fallbackRoot
}

_isSilentFallbackWarn (key: Path): boolean {
Expand Down Expand Up @@ -461,7 +465,7 @@ export default class VueI18n {
// We are going to replace each of
// them with its translation
const matches: any = ret.match(linkKeyMatcher)

// eslint-disable-next-line no-autofix/prefer-const
for (let idx in matches) {
// ie compatible: filter custom array
Expand Down
127 changes: 127 additions & 0 deletions test/unit/component.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,131 @@ describe('component translation', () => {
vm.$destroy()
}).then(done)
})

it('fallbackRootWithEmptyString default to be true', done => {
const el = document.createElement('div')
let vm = new Vue({
i18n,
components: {
child: { // translation with component
i18n: {
locale: 'en-US',
sync: false,
messages: {
'en-US': {
who: 'child'
},
'ja-JP': {
who: '子',
}
},
},
components: {
'sub-child': { // translation with root
i18n: {
locale: 'ja-JP',
sync: false,
messages: {
'en-US': {
who: 'sub-child'
},
'ja-JP': {
who: ''
}
},
sharedMessages: { // shared messages for child1 component
'en-US': { foo: { bar: 'bar' } },
'ja-JP': { foo: { bar: 'バー' } }
}
},
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('sub-child', { ref: 'sub-child' })
])
}
},
},
render (h) {
return h('div', {}, [
h('p', { ref: 'who' }, [this.$t('who')]),
h('child', { ref: 'child' }),
])
}
}).$mount(el)
Vue.nextTick().then(() => {
assert.strictEqual(vm.$refs.child.$refs['sub-child'].$refs.who.textContent, 'ルート')
}).then(done)
})

it('fallbackRootWithEmptyString should work when set to false', done => {
const el = document.createElement('div')
let vm = new Vue({
i18n,
components: {
child: { // translation with component
i18n: {
locale: 'en-US',
sync: false,
messages: {
'en-US': {
who: 'child'
},
'ja-JP': {
who: '子',
}
},
},
components: {
'sub-child': { // translation with root
i18n: {
locale: 'ja-JP',
sync: false,
fallbackRootWithEmptyString: false,
messages: {
'en-US': {
who: 'sub-child'
},
'ja-JP': {
who: ''
}
},
sharedMessages: { // shared messages for child1 component
'en-US': { foo: { bar: 'bar' } },
'ja-JP': { foo: { bar: 'バー' } }
}
},
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('sub-child', { ref: 'sub-child' })
])
}
},
},
render (h) {
return h('div', {}, [
h('p', { ref: 'who' }, [this.$t('who')]),
h('child', { ref: 'child' }),
])
}
}).$mount(el)
Vue.nextTick().then(() => {
assert.strictEqual(vm.$refs.child.$refs['sub-child'].$refs.who.textContent, '')
}).then(done)
})
})
3 changes: 2 additions & 1 deletion types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ declare namespace VueI18n {
modifiers?: Modifiers,
missing?: MissingHandler;
fallbackRoot?: boolean;
fallbackRootWithEmptyString?: boolean,
formatFallbackMessages?: boolean;
sync?: boolean;
silentTranslationWarn?: boolean | RegExp;
Expand Down Expand Up @@ -240,7 +241,7 @@ declare class VueI18n {
te(key: VueI18n.Path, locale?: VueI18n.Locale): boolean;
d(value: number | Date, key?: VueI18n.Path, locale?: VueI18n.Locale): VueI18n.DateTimeFormatResult;
d(value: number | Date, args?: { [key: string]: string }): VueI18n.DateTimeFormatResult;
d(value: number | Date, options?: VueI18n.DateTimeFormatOptions): VueI18n.DateTimeFormatResult;
d(value: number | Date, options?: VueI18n.DateTimeFormatOptions): VueI18n.DateTimeFormatResult;
n(value: number, key?: VueI18n.Path, locale?: VueI18n.Locale): VueI18n.NumberFormatResult;
n(value: number, args?: { [key: string]: string }): VueI18n.NumberFormatResult;
n(value: number, options?: VueI18n.NumberFormatOptions, locale?: VueI18n.Locale): VueI18n.NumberFormatResult;
Expand Down
14 changes: 14 additions & 0 deletions vuepress/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,20 @@ In the component localization, whether to fall back to root level (global) local

If `false`, it's warned, and is returned the key.

#### fallbackRootWithEmptyString

> :new: 8.26+

- **Type:** `Boolean`

- **Default:** `true`

In the component localization, whether to fall back to root level (global) localization when local message is an empty string.

Please note the default behavior in vue-i18n 9.x is to not falling back to root for local message that is empty string.

If `false`, the empty local message will not fall back to root and will be kept as empty string.

#### sync

* **Type:** `Boolean`
Expand Down
14 changes: 14 additions & 0 deletions vuepress/pt/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,20 @@ Ao usar a localização em componentes, determina se deve consultar a localizaç

Se definido como `false`, um aviso será lançado e uma chave retornada.

#### fallbackRootWithEmptyString

> :new: Adicionado na versão 8.26+

* **Tipo:** `Boolean`

* **Padrão:** `true`

Na localização do componente, se deve retornar à localização de nível raiz (global) quando a mensagem local for uma string vazia.

Por favor, note que o comportamento padrão no vue-i18n 9.x é não voltar ao root para a mensagem local que é uma string vazia.

Se for `false`, a mensagem local vazia não retornará ao root e será mantida como string vazia.

#### sync

* **Tipo:** `Boolean`
Expand Down
14 changes: 14 additions & 0 deletions vuepress/ru/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,20 @@ sidebar: auto

При значении `false` будет выбрасываться предупреждение и возвращаться ключ.

#### fallbackRootWithEmptyString

> :new: Добавлено в версии 8.26+

* **Тип:** `Boolean`

* **По умолчанию:** `true`

В локализации компонента укажите, следует ли вернуться к локализации корневого уровня (глобальной), если локальное сообщение представляет собой пустую строку.

Обратите внимание, что поведение по умолчанию в vue-i18n 9.x заключается в том, чтобы не возвращаться к корневому каталогу для локального сообщения, которое является пустой строкой.

Если `false`, пустое локальное сообщение не будет возвращено в корень и будет храниться как пустая строка.

#### sync

* **Тип:** `Boolean`
Expand Down
14 changes: 14 additions & 0 deletions vuepress/zh/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,20 @@ vue-i18n 版本

如果为 `false`,则会发出警告,并返回 key。

#### fallbackRootWithEmptyString

> :new: 8.26+ 新增

* **Type:** `Boolean`

* **Default:** `true`

在组件本地化中,当本地化文本为空字符串时,是否回退到根级别 (全局) 本地化。

请注意,vue-i18n 9.x版本的默认行为是对空字符串本地化文本进行回退到根级别本地化。

如果为`false`,则空的本地化文本将不会回退到根目录,并将保留为空字符串。

#### sync

* **类型:**`Boolean`
Expand Down