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

silence fallback warnings #510

Merged
merged 5 commits into from
Jan 23, 2019
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
19 changes: 15 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export default class VueI18n {
_watcher: any
_i18nWatcher: Function
_silentTranslationWarn: boolean
_silentFallbackWarn: boolean
_dateTimeFormatters: Object
_numberFormatters: Object
_path: I18nPath
Expand Down Expand Up @@ -89,6 +90,9 @@ export default class VueI18n {
this._silentTranslationWarn = options.silentTranslationWarn === undefined
? false
: !!options.silentTranslationWarn
this._silentFallbackWarn = options.silentFallbackWarn === undefined
? false
: !!options.silentFallbackWarn
this._dateTimeFormatters = {}
this._numberFormatters = {}
this._path = new I18nPath()
Expand Down Expand Up @@ -184,6 +188,9 @@ export default class VueI18n {
get silentTranslationWarn (): boolean { return this._silentTranslationWarn }
set silentTranslationWarn (silent: boolean): void { this._silentTranslationWarn = silent }

get silentFallbackWarn (): boolean { return this._silentFallbackWarn }
set silentFallbackWarn (silent: boolean): void { this._silentFallbackWarn = silent }

_getMessages (): LocaleMessages { return this._vm.messages }
_getDateTimeFormats (): DateTimeFormats { return this._vm.dateTimeFormats }
_getNumberFormats (): NumberFormats { return this._vm.numberFormats }
Expand All @@ -210,6 +217,10 @@ export default class VueI18n {
return !val && !isNull(this._root) && this._fallbackRoot
}

_isSilentFallback (locale: Locale): boolean {
return this._silentFallbackWarn && (this._isFallbackRoot() || locale !== this.fallbackLocale)
}

_interpolate (
locale: Locale,
message: LocaleMessageObject,
Expand All @@ -230,7 +241,7 @@ export default class VueI18n {
if (isPlainObject(message)) {
ret = message[key]
if (typeof ret !== 'string') {
if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn && !this._isSilentFallback(locale)) {
warn(`Value of key '${key}' is not a string!`)
}
return null
Expand All @@ -243,7 +254,7 @@ export default class VueI18n {
if (typeof pathRet === 'string') {
ret = pathRet
} else {
if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn && !this._isSilentFallback(locale)) {
warn(`Value of key '${key}' is not a string!`)
}
return null
Expand Down Expand Up @@ -359,7 +370,7 @@ export default class VueI18n {

res = this._interpolate(fallback, messages[fallback], key, host, interpolateMode, args, [key])
if (!isNull(res)) {
if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn && !this._silentFallbackWarn) {
warn(`Fall back to translate the keypath '${key}' with '${fallback}' locale.`)
}
return res
Expand All @@ -379,7 +390,7 @@ export default class VueI18n {
host, 'string', parsedArgs.params
)
if (this._isFallbackRoot(ret)) {
if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn && !this._silentFallbackWarn) {
warn(`Fall back to translate the keypath '${key}' with root locale.`)
}
/* istanbul ignore if */
Expand Down
1 change: 1 addition & 0 deletions src/mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export default {
options.i18n.formatter = this.$root.$i18n.formatter
options.i18n.fallbackLocale = this.$root.$i18n.fallbackLocale
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
}
Expand Down
173 changes: 158 additions & 15 deletions test/unit/silent.test.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,168 @@
describe('silent', () => {
it('should be suppressed translate warnings', () => {
const vm = new Vue({
i18n: new VueI18n({
locale: 'en',
silentTranslationWarn: true,
let spy
beforeEach(() => {
spy = sinon.spy(console, 'warn')
})
afterEach(() => {
spy.restore()
})

describe('silentTranslationWarn', () => {
it('should be suppressed translate warnings', () => {
const vm = new Vue({
i18n: new VueI18n({
locale: 'en',
silentTranslationWarn: true,
messages: {
en: { who: 'root' },
ja: { who: 'ルート' }
}
})
})

vm.$t('foo.bar.buz')
assert(spy.notCalled === true)

// change
vm.$i18n.silentTranslationWarn = false
vm.$t('foo.bar.buz')
assert(spy.callCount === 2)
})
})

describe('silentFallbackWarn', () => {
let i18n
beforeEach(() => {
i18n = new VueI18n({
locale: 'hu',
fallbackLocale: 'en',
silentFallbackWarn: true,
messages: {
en: { who: 'root' },
ja: { who: 'ルート' }
en: { winner: 'winner' },
hu: { chickenDinner: 'csirkevacsora' }
}
})
})

const spy = sinon.spy(console, 'warn')
vm.$t('foo.bar.buz')
assert(spy.notCalled === true)
it('should suppress `Fall back to ${fallback} locale` warnings', () => {
const vm = new Vue({ i18n })
const warningRegex = /Fall back to .* 'en' locale./
vm.$t('winner')
assert(spy.getCalls().some(call => call.args[0].match(warningRegex)) === false)

// change
vm.$i18n.silentTranslationWarn = false
vm.$t('foo.bar.buz')
assert(spy.callCount === 2)
vm.$i18n.silentFallbackWarn = false
vm.$t('winner')
assert(spy.getCalls().some(call => call.args[0].match(warningRegex)) === true)
})

spy.restore()
it('should suppress `Fall back to root locale` warnings.', () => {
const el = document.createElement('div')
const root = new Vue({
i18n,
components: {
subComponent: {
i18n: { messages: { hu: { name: 'Név' } } },
render (h) { return h('p') }
}
},
render (h) { return h('sub-component') }
}).$mount(el)
const vm = root.$children[0]
const warningRegex = /Fall back to .* root locale./

vm.$t('chickenDinner')
assert(spy.getCalls().some(call => call.args[0].match(warningRegex)) === false)

vm.$i18n.silentFallbackWarn = false
vm.$t('chickenDinner')
assert(spy.getCalls().some(call => call.args[0].match(warningRegex)) === true)
})

describe('if first try is null or undefined,', () => {
it('should suppress `not a string` warnings for fallback to fallbackLocale.', () => {
const vm = new Vue({ i18n })
const warningRegex = /Value of .* is not a string./
vm.$t('winner')
assert(spy.getCalls().some(call => call.args[0].match(warningRegex)) === false)

vm.$i18n.silentFallbackWarn = false
vm.$t('winner')
assert(spy.getCalls().some(call => call.args[0].match(warningRegex)) === true)
})

it('should supress `not a string` warnings for fallback to root.', () => {
const el = document.createElement('div')
const root = new Vue({
i18n,
components: {
subComponent: {
i18n: { messages: { hu: { name: 'Név' } } },
render (h) { return h('p') }
}
},
render (h) { return h('sub-component') }
}).$mount(el)
const vm = root.$children[0]
const warningRegex = /Value of .* is not a string./
vm.$t('chickenDinner')
assert(spy.getCalls().some(call => call.args[0].match(warningRegex)) === false)

vm.$i18n.silentFallbackWarn = false
vm.$t('chickenDinner')
assert(spy.getCalls().some(call => call.args[0].match(warningRegex)) === true)
})
})

describe('if first try is not null, undefined, array, plain object or string,', () => {
it('should suppress `not a string` warnings for fallback to fallbackLocale.', () => {
const vm = new Vue({
i18n: new VueI18n({
locale: 'hu',
fallbackLocale: 'en',
silentFallbackWarn: true,
messages: {
en: { winner: 'winner' },
hu: { winner: true } // translation value is boolean
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kazupon is it the right use case? boolean, number etc?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it the right use case?
yes! that's correct! not a string is warning!

}
})
})
const warningRegex = /Value of .* is not a string./
vm.$t('winner')
assert(spy.getCalls().some(call => call.args[0].match(warningRegex)) === false)

vm.$i18n.silentFallbackWarn = false
vm.$t('winner')
assert(spy.getCalls().some(call => call.args[0].match(warningRegex)) === true)
})

it('should supress `not a string` warnings for fallback to root.', () => {
const el = document.createElement('div')
const root = new Vue({
i18n,
components: {
subComponent: {
i18n: { messages: { hu: { chickenDinner: 11 } } }, // translation value is number
render (h) { return h('p') }
}
},
render (h) { return h('sub-component') }
}).$mount(el)
const vm = root.$children[0]
const warningRegex = /Value of .* is not a string./
vm.$t('chickenDinner')
assert(spy.getCalls().some(call => call.args[0].match(warningRegex)) === false)

vm.$i18n.silentFallbackWarn = false
vm.$t('chickenDinner')
assert(spy.getCalls().some(call => call.args[0].match(warningRegex)) === true)
})
})

it('should not suppress `not a string` warnings when no further fallback is possible.', () => {
const vm = new Vue({ i18n })
const warningRegex = /Value of .* is not a string./
vm.$t('loser')
assert(spy.getCalls().some(call => call.args[0].match(warningRegex)) === true)
})
})
})
11 changes: 11 additions & 0 deletions vuepress/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,17 @@ Whether suppress warnings outputted when localization fails.

If `true`, suppress localization fail warnings.

#### silentFallbackWarn

> :new: 8.8+

* **Type:** `Boolean`
* **Default:** `false`

Whether suppress warnings when falling back to either `fallbackLocale` or `root`.

If `true`, warnings will be generated only when no translation is available at all, and not for fallbacks.

#### preserveDirectiveContent

> 8.7+
Expand Down
9 changes: 9 additions & 0 deletions vuepress/guide/component.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ Outputs the following:

As in the example above, if the component doesn't have the locale message, it falls back to globally defined localization info. The component uses the language set in the root instance (in the above example: `locale: 'ja'`).

Note, that by default falling back to root locale generates two warnings in the console:

```console
[vue-i18n] Value of key 'message.greeting' is not a string!
[vue-i18n] Fall back to translate the keypath 'message.greeting' with root locale.
```

To suppress these warnings (while keeping those which warn of the total absence of translation for the given key) set `silentFallbackWarn: true` when initializing the `VueI18n` instance.

If you hope localize in the component locale, you can realize with `sync: false` and `locale` in `i18n` option.

## Translation in functional component
Expand Down
9 changes: 9 additions & 0 deletions vuepress/guide/fallback.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,12 @@ Output the below:
```html
<p>hello world</p>
```

Note, that by default falling back to `fallbackLocale` generates two console warnings:

```console
[vue-i18n] Value of key 'message' is not a string!
[vue-i18n] Fall back to translate the keypath 'message' with 'en' locale.
```

To suppress these warnings (while keeping those which warn of the total absence of translation for the given key) set `silentFallbackWarn: true` when initializing the `VueI18n` instance.