Skip to content

Commit

Permalink
fix: fallback linked message params
Browse files Browse the repository at this point in the history
  • Loading branch information
kazupon committed Aug 29, 2024
1 parent 064ac8c commit 0a59d34
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 41 deletions.
47 changes: 24 additions & 23 deletions packages/core-base/src/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ type ExtractToStringKey<T> = Extract<keyof T, 'toString'>
type ExtractToStringFunction<T> = T[ExtractToStringKey<T>]
// prettier-ignore
type StringConvertable<T> = ExtractToStringKey<T> extends never
? unknown
: ExtractToStringFunction<T> extends (...args: any) => string // eslint-disable-line @typescript-eslint/no-explicit-any
? T
: unknown
? unknown
: ExtractToStringFunction<T> extends (...args: any) => string // eslint-disable-line @typescript-eslint/no-explicit-any
? T
: unknown

/**
*
Expand Down Expand Up @@ -110,7 +110,8 @@ export type MessageFunction<T = string> =

export type MessageFunctions<T = string> = Record<string, MessageFunction<T>>
export type MessageResolveFunction<T = string> = (
key: string
key: string,
useLinked: boolean
) => MessageFunction<T>

export type MessageNormalize<T = string> = (
Expand Down Expand Up @@ -310,27 +311,27 @@ function pluralDefault(choice: number, choicesLength: number): number {
if (choicesLength === 2) {
// prettier-ignore
return choice
? choice > 1
? 1
: 0
: 1
? choice > 1
? 1
: 0
: 1
}
return choice ? Math.min(choice, 2) : 0
}

function getPluralIndex<T, N>(options: MessageContextOptions<T, N>): number {
// prettier-ignore
const index = isNumber(options.pluralIndex)
? options.pluralIndex
: -1
? options.pluralIndex
: -1
// prettier-ignore
return options.named && (isNumber(options.named.count) || isNumber(options.named.n))
? isNumber(options.named.count)
? options.named.count
: isNumber(options.named.n)
? options.named.n
: index
: index
? isNumber(options.named.count)
? options.named.count
: isNumber(options.named.n)
? options.named.n
: index
: index
}

function normalizeNamed(pluralIndex: number, props: PluralizationProps): void {
Expand Down Expand Up @@ -371,13 +372,13 @@ export function createMessageContext<T = string, N = {}>(
isNumber(options.pluralIndex) && normalizeNamed(pluralIndex, _named)
const named = (key: string): unknown => _named[key]

function message(key: Path): MessageFunction<T> {
function message(key: Path, useLinked?: boolean): MessageFunction<T> {
// prettier-ignore
const msg = isFunction(options.messages)
? options.messages(key)
: isObject(options.messages)
? options.messages[key]
: false
? options.messages(key, !!useLinked)
: isObject(options.messages)
? options.messages[key]
: false
return !msg
? options.parent
? options.parent.message(key) // resolve from parent messages
Expand Down Expand Up @@ -425,7 +426,7 @@ export function createMessageContext<T = string, N = {}>(
type = arg2 || type
}
}
const ret = message(key)(ctx)
const ret = message(key, true)(ctx)
const msg =
// The message in vnode resolved with linked are returned as an array by processor.nomalize
type === 'vnode' && isArray(ret) && modifier
Expand Down
11 changes: 7 additions & 4 deletions packages/core-base/src/translate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1156,13 +1156,16 @@ function getMessageContextOptions<Messages, Message = string>(
fallbackContext
} = context

const resolveMessage = (key: string): MessageFunction<Message> => {
const resolveMessage = (
key: string,
useLinked: boolean
): MessageFunction<Message> => {
let val = resolveValue(message, key)

// fallback to root context
if (val == null && fallbackContext) {
// fallback
if (val == null && (fallbackContext || useLinked)) {
const [, , message] = resolveMessageFormat(
fallbackContext,
fallbackContext || context, // NOTE: if has fallbackContext, fallback to root, else if use linked, fallback to local context
key,
locale,
fallbackLocale as FallbackLocale,
Expand Down
50 changes: 36 additions & 14 deletions packages/core-base/test/translate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -810,23 +810,45 @@ describe('edge cases', () => {
})
})

test('fallback context', () => {
const parent = context({
locale: 'en',
messages: {
en: { hello: 'hello man!', hi: 'hi' }
}
})
describe('fallback context', () => {
test('root (parent context)', () => {
const parent = context({
locale: 'en',
messages: {
en: { hello: 'hello man!', hi: 'hi' }
}
})

const ctx = context({
locale: 'en',
messages: {
en: { hi: 'hi! @:hello' }
}
const ctx = context({
locale: 'en',
messages: {
en: { hi: 'hi! @:hello' }
}
})
ctx.fallbackContext = parent

expect(translate(ctx, 'hi')).toEqual('hi! hello man!')
})
ctx.fallbackContext = parent

expect(translate(ctx, 'hi')).toEqual('hi! hello man!')
test('local (self context)', () => {
const ctx = context({
locale: 'en',
messages: {
en: {
apples: 'Apples',
no_results: 'No @.lower:{0} found'
},
'en-variant': {
no_results: 'No @.lower:{0} found'
}
}
})

expect(translate(ctx, 'no_results', ['apples'])).toEqual('No apples found')
expect(
translate(ctx, 'no_results', ['apples'], { locale: 'en-variant' })
).toEqual('No apples found')
})
})

describe('processor', () => {
Expand Down
47 changes: 47 additions & 0 deletions packages/vue-i18n-core/test/issues.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1359,3 +1359,50 @@ test('#1809', async () => {
})
expect(i18n.global.t('hi')).toEqual('hi kazupon')
})

test('#1912', async () => {
const i18n = createI18n({
legacy: false,
locale: 'en',
messages: {
en: {
hello: 'Hello, Vue I18n',
language: 'Languages',
apples: 'Apples',
no_results: 'No @.lower:{0} found'
},
'en-variant': {
no_results: 'No @.lower:{0} found'
}
}
})

let loc: ReturnType<typeof useI18n>['locale']
const App = defineComponent({
template: `
<form>
<select v-model="locale">
<option value="en">en</option>
<option value="en-variant">en-variant</option>
</select>
</form>
<p>{{ t('no_results', ['apples']) }}</p>
`,
setup() {
const { t, locale } = useI18n()
// @ts-ignore
loc = locale
return { t, locale }
}
})
const wrapper = await mount(App, i18n)
await nextTick()

const el = wrapper.find('p')
expect(el?.innerHTML).include(`No apples found`)
// @ts-ignore
loc.value = 'en-variant'
await nextTick()

expect(el?.innerHTML).include(`No apples found`)
})

0 comments on commit 0a59d34

Please sign in to comment.