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

fix: cannot fallback at tm / $tm #403

Merged
merged 1 commit into from
Mar 18, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 30 additions & 0 deletions docs/api/injection.md
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,36 @@ The input / output is the same as for VueI18n instance. About that details, see

If found locale message, `true`, else `false`.

### $tm(key)

Locale messages getter

**Signature:**
```typescript
$tm(key: Path): LocaleMessageValue<VueMessageType> | {}
```

**Details**

If [i18n component options](injection#i18n) is specified, it’s get in preferentially local scope locale messages than global scope locale messages.

If [i18n component options](injection#i18n) isn’t specified, it’s get with global scope locale messages.

Based on the current `locale`, locale messages will be returned from Composer instance messages.

If you change the `locale`, the locale messages returned will also correspond to the locale.

If there are no locale messages for the given `key` in the composer instance messages, they will be returned with [fallbacking](../../guide/essentials/fallback).

#### Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| key | Path | A target locale message key |

#### Returns

Locale messages

### $d(value)

Datetime formatting
Expand Down
35 changes: 30 additions & 5 deletions packages/vue-i18n/src/composer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
number,
parseNumberArgs,
clearNumberFormat,
getLocaleChain,
NOT_REOSLVED,
DevToolsTimelineEvents
} from '@intlify/core-base'
Expand Down Expand Up @@ -138,7 +139,7 @@ export interface ComposerOptions<Message = VueMessageType> {
*
* @VueI18nSee [Fallbacking](../../guide/essentials/fallback)
*
* @defaultValue `true`
* @defaultValue The default `'en-US'` for the `locale` if it's not specified, or it's `locale` value
*/
fallbackLocale?: FallbackLocale
/**
Expand Down Expand Up @@ -764,6 +765,12 @@ export interface Composer<
* @remarks
* If [UseI18nScope](general#usei18nscope) `'local'` or Some [UseI18nOptions](composition#usei18noptions) are specified at `useI18n`, it’s translated in preferentially local scope locale messages than global scope locale messages.
*
* Based on the current `locale`, locale messages will be returned from Composer instance messages.
*
* If you change the `locale`, the locale messages returned will also correspond to the locale.
*
* If there are no locale messages for the given `key` in the composer instance messages, they will be returned with [fallbacking](../../guide/essentials/fallback).
*
* @param key - A target locale message key
*
* @return Locale messages
Expand Down Expand Up @@ -1405,13 +1412,31 @@ export function createComposer<
return resolveValue(message, key) !== null
}

function __resolveMessages(key: Path): LocaleMessageValue<Message> | null {
const context = getCoreContext()
let messages: LocaleMessageValue<Message> | null = null
const locales = getLocaleChain<Message>(
context,
_fallbackLocale.value,
_locale.value
)
for (let i = 0; i < locales.length; i++) {
const targetLocaleMessages = _messages.value[locales[i]] || {}
const messageValue = resolveValue(targetLocaleMessages, key)
if (messageValue != null) {
messages = messageValue as LocaleMessageValue<Message>
break
}
}
return messages
}

// tm
function tm(key: Path): LocaleMessageValue<Message> | {} {
const messages = _messages.value[_locale.value] || {}
const target = resolveValue(messages, key)
const messages = __resolveMessages(key)
// prettier-ignore
return target != null
? target as LocaleMessageValue<Message>
return messages != null
? messages
: __root
? __root.tm(key) as LocaleMessageValue<Message> || {}
: {}
Expand Down
8 changes: 7 additions & 1 deletion packages/vue-i18n/src/legacy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export interface VueI18nOptions {
*
* @VueI18nSee [Fallbacking](../../guide/essentials/fallback)
*
* @defaultValue `true`
* @defaultValue The default `'en-US'` for the `locale` if it's not specified, or it's `locale` value
*/
fallbackLocale?: FallbackLocale
/**
Expand Down Expand Up @@ -653,6 +653,12 @@ export interface VueI18n<
*
* If [i18n component options](injection#i18n) isn't specified, it’s get with global scope locale messages.
*
* Based on the current `locale`, locale messages will be returned from Composer instance messages.
*
* If you change the `locale`, the locale messages returned will also correspond to the locale.
*
* If there are no locale messages for the given `key` in the composer instance messages, they will be returned with [fallbacking](../../guide/essentials/fallback).
*
* @param key - A target locale message key
*
* @return Locale messages
Expand Down
5 changes: 4 additions & 1 deletion packages/vue-i18n/src/vue.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -639,10 +639,13 @@ declare module '@vue/runtime-core' {
* @remarks
* In {@link I18nMode | Composition API mode}, the `$tm` is injected by `app.config.globalProperties`.
* the input / output is the same as for Composer instance, and it work on **global scope**. About that details, see {@link Composer#tm | `Composer.tm` }.
* Based on the current `locale`, locale messages will be returned from Composer instance messages.
* If you change the `locale`, the locale messages returned will also correspond to the locale.
* If there are no locale messages for the given `key` in the composer instance messages, they will be returned with fallbacking.
*
* @param key - A target locale message key
*
* @return locale messages
* @returns locale messages
*/
$tm(key: Path): LocaleMessageValue<VueMessageType> | {}
}
Expand Down
92 changes: 68 additions & 24 deletions packages/vue-i18n/test/composer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -829,39 +829,83 @@ describe('n', () => {
})
})

test('tm', async () => {
const composer = createComposer({
locale: 'ja',
messages: {
en: {},
ja: {
foo: {
bar: {
buz: 'hello'
},
codes: {
errors: ['error1', 'error2']
describe('tm', () => {
test('basic', async () => {
const composer = createComposer({
locale: 'ja',
messages: {
en: {},
ja: {
foo: {
bar: {
buz: 'hello'
},
codes: {
errors: ['error1', 'error2']
}
}
}
}
}
})

let messages1 = composer.tm('foo.bar')
let messages2 = composer.tm('foo.codes')
expect(messages1).toEqual({ buz: 'hello' })
expect(messages2).toEqual({ errors: ['error1', 'error2'] })

watchEffect(() => {
messages1 = composer.tm('foo.bar')
messages2 = composer.tm('foo.codes')
})

composer.locale.value = 'en'
await nextTick()

expect(messages1).toEqual({ buz: 'hello' })
expect(messages2).toEqual({ errors: ['error1', 'error2'] })
})

let messages1 = composer.tm('foo.bar')
let messages2 = composer.tm('foo.codes')
expect(messages1).toEqual({ buz: 'hello' })
expect(messages2).toEqual({ errors: ['error1', 'error2'] })
test('fallback to local locale', async () => {
const composer = createComposer({
locale: 'en',
fallbackLocale: 'ja',
messages: {
ja: {
foo: {
bar: {
buz: 'hello'
}
}
}
}
})

watchEffect(() => {
messages1 = composer.tm('foo.bar')
messages2 = composer.tm('foo.codes')
const messages1 = composer.tm('foo')
expect(messages1).toEqual({ bar: { buz: 'hello' } })
})

composer.locale.value = 'en'
await nextTick()
test('fallback to global locale', async () => {
const __root = createComposer({
locale: 'en',
fallbackLocale: 'ja',
messages: {
ja: {
foo: {
bar: {
buz: 'hello'
}
}
}
}
})
const child = createComposer({
inheritLocale: true,
__root
})

expect(messages1).toEqual({})
expect(messages2).toEqual({})
const messages1 = child.tm('foo')
expect(messages1).toEqual({ bar: { buz: 'hello' } })
})
})

test('te', async () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/vue-i18n/test/legacy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,8 @@ test('tm', async () => {
i18n.locale = 'en'
await nextTick()

expect(messages1).toEqual({})
expect(messages2).toEqual({})
expect(messages1).toEqual({ buz: 'hello' })
expect(messages2).toEqual({ errors: ['error1', 'error2'] })
})

test('getLocaleMessage / setLocaleMessage / mergeLocaleMessage', () => {
Expand Down