Skip to content

Commit

Permalink
⭐ new: fallback formatting (#637) by @sebwas
Browse files Browse the repository at this point in the history
* Add formatting of fallback messages

* Make use of (de-)activation option

* Add documentation for proposed feature

* 🆙 update: add getter/setter

* 📝 docs: move to vuepress

* 👕 refactor: update
  • Loading branch information
sebwas authored and kazupon committed Aug 12, 2019
1 parent 1cc4c72 commit bf9929c
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 1 deletion.
3 changes: 3 additions & 0 deletions decls/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ declare type I18nOptions = {
missing?: MissingHandler,
root?: I18n, // for internal
fallbackRoot?: boolean,
formatFallbackMessages?: boolean,
sync?: boolean,
silentTranslationWarn?: boolean | RegExp,
silentFallbackWarn?: boolean | RegExp,
Expand Down Expand Up @@ -106,6 +107,8 @@ declare interface I18n {
set missing (handler: MissingHandler): void,
get formatter (): Formatter,
set formatter (formatter: Formatter): void,
get formatFallbackMessages (): boolean,
set formatFallbackMessages (fallback: boolean): void,
get silentTranslationWarn (): boolean | RegExp,
set silentTranslationWarn (silent: boolean | RegExp): void,
get silentFallbackWarn (): boolean | RegExp,
Expand Down
15 changes: 14 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export default class VueI18n {
_exist: Function
_silentTranslationWarn: boolean | RegExp
_silentFallbackWarn: boolean | RegExp
_formatFallbackMessages: boolean
_dateTimeFormatters: Object
_numberFormatters: Object
_path: I18nPath
Expand Down Expand Up @@ -76,6 +77,9 @@ export default class VueI18n {
this._fallbackRoot = options.fallbackRoot === undefined
? true
: !!options.fallbackRoot
this._formatFallbackMessages = options.formatFallbackMessages === undefined
? false
: !!options.formatFallbackMessages
this._silentTranslationWarn = options.silentTranslationWarn === undefined
? false
: options.silentTranslationWarn
Expand Down Expand Up @@ -228,6 +232,9 @@ export default class VueI18n {
this._vm.$set(this._vm, 'fallbackLocale', locale)
}

get formatFallbackMessages (): boolean { return this._formatFallbackMessages }
set formatFallbackMessages (fallback: boolean): void { this._formatFallbackMessages = fallback }

get missing (): ?MissingHandler { return this._missing }
set missing (handler: MissingHandler): void { this._missing = handler }

Expand Down Expand Up @@ -274,7 +281,13 @@ export default class VueI18n {
)
}
}
return key

if (this._formatFallbackMessages) {
const parsedArgs = parseArgs(...values)
return this._render(key, 'string', parsedArgs.params, key)
} else {
return key
}
}

_isFallbackRoot (val: any): boolean {
Expand Down
1 change: 1 addition & 0 deletions src/mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export default {
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
Expand Down
54 changes: 54 additions & 0 deletions test/unit/basic.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,60 @@ describe('basic', () => {
})
})

describe('format arguments of fallback', () => {
describe('if activated', () => {
describe('named', () => {
it('should return replaced string', () => {
i18n = new VueI18n({
locale: 'en',
fallbackLocale: 'en',
formatFallbackMessages: true
})

assert.strictEqual(
i18n.t('Hello {name}, how are you?', { name: 'kazupon' }),
'Hello kazupon, how are you?'
)
})
})

describe('list', () => {
it('should return replaced string', () => {
i18n = new VueI18n({
locale: 'en',
fallbackLocale: 'en',
formatFallbackMessages: true
})

assert.strictEqual(
i18n.t('Hello {0}, how are you?', ['kazupon']),
'Hello kazupon, how are you?'
)
})
})
})

describe('if not activated', () => {
describe('named', () => {
it('should not return replaced string', () => {
assert.strictEqual(
i18n.t('Hello {name}, how are you?', { name: 'kazupon' }),
'Hello {name}, how are you?'
)
})
})

describe('list', () => {
it('should not return replaced string', () => {
assert.strictEqual(
i18n.t('Hello {0}, how are you?', ['kazupon']),
'Hello {0}, how are you?'
)
})
})
})
})

describe('locale argument', () => {
it('should return empty string', () => {
assert.strictEqual(i18n.t('message.hello', 'ja'), messages.ja.message.hello)
Expand Down
3 changes: 3 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ declare namespace VueI18n {
formatter?: Formatter;
missing?: MissingHandler;
fallbackRoot?: boolean;
formatFallbackMessages?: boolean;
sync?: boolean;
silentTranslationWarn?: boolean | RegExp;
silentFallbackWarn?: boolean | RegExp;
Expand Down Expand Up @@ -143,6 +144,7 @@ export declare interface IVueI18n {
fallbackLocale: VueI18n.Locale;
missing: VueI18n.MissingHandler;
formatter: VueI18n.Formatter;
formatFallbackMessages: boolean;
silentTranslationWarn: boolean | RegExp;
silentFallbackWarn: boolean | RegExp;
preserveDirectiveContent: boolean;
Expand All @@ -162,6 +164,7 @@ declare class VueI18n {
fallbackLocale: VueI18n.Locale;
missing: VueI18n.MissingHandler;
formatter: VueI18n.Formatter;
formatFallbackMessages: boolean;
silentTranslationWarn: boolean | RegExp;
silentFallbackWarn: boolean | RegExp;
preserveDirectiveContent: boolean;
Expand Down
50 changes: 50 additions & 0 deletions vuepress/guide/fallback.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,53 @@ Note, that by default falling back to `fallbackLocale` generates two console war
```

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.

## Fallback interpolation

Since the keys to the translations are strings, the original message can be used as a key instead of the path.
E.g.

```javascript
const messages = {
ja: {
'Hello world': 'こんにちは、世界'
}
}
```

This way the translations can be used in a very natural way, automatically falling back to the source language if the translated string cannot be found:

```html
<p>{{ $t('Hello world') }}</p>
```

To enrich this feature, interpolation of fallback messages can be turned on by setting `formatFallbackMessages` to `true`:

```javascript
const messages = {
ru: {
'Hello {name}': 'Здравствуйте {name}'
}
}

const i18n = new VueI18n({
locale: 'ru',
fallbackLocale: 'en',
formatFallbackMessages: true,
messages
})
```

When you template the below:

```html
<p>{{ $t('Hello {name}', { name: 'John' }}) }}</p>
<p>{{ $t('The weather today is {condition}!', { condition: 'sunny' }) }}</p>
```

The following will be the output:

```html
<p>Здравствуйте John</p>
<p>The weather today is sunny!</p>
```

0 comments on commit bf9929c

Please sign in to comment.