From 9c0bc82f891af861502d4f251e9fecd7dfaf3fe8 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Tue, 17 Jun 2025 10:34:57 +0900 Subject: [PATCH 1/2] fix: error on duplicate useI18n calling on local scope --- packages/vue-i18n-core/src/errors.ts | 8 +++- packages/vue-i18n-core/src/i18n.ts | 4 ++ packages/vue-i18n-core/test/i18n.test.ts | 60 ++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/packages/vue-i18n-core/src/errors.ts b/packages/vue-i18n-core/src/errors.ts index 51aca94a6..f8ce2c3c8 100644 --- a/packages/vue-i18n-core/src/errors.ts +++ b/packages/vue-i18n-core/src/errors.ts @@ -22,7 +22,9 @@ export const I18nErrorCodes = { CANNOT_SETUP_VUE_DEVTOOLS_PLUGIN: 30, NOT_INSTALLED_WITH_PROVIDE: 31, // unexpected error - UNEXPECTED_ERROR: 32 + UNEXPECTED_ERROR: 32, + // duplicate `useI18n` calling + DUPLICATE_USE_I18N_CALLING: 33 } as const type I18nErrorCodes = (typeof I18nErrorCodes)[keyof typeof I18nErrorCodes] @@ -49,5 +51,7 @@ export const errorMessages: { [code: number]: string } = { [I18nErrorCodes.INVALID_VALUE]: `Invalid value`, [I18nErrorCodes.CANNOT_SETUP_VUE_DEVTOOLS_PLUGIN]: `Cannot setup vue-devtools plugin`, [I18nErrorCodes.NOT_INSTALLED_WITH_PROVIDE]: - 'Need to install with `provide` function' + 'Need to install with `provide` function', + [I18nErrorCodes.DUPLICATE_USE_I18N_CALLING]: + "Duplicate `useI18n` calling by local scope. Please don't call it on local scope" } diff --git a/packages/vue-i18n-core/src/i18n.ts b/packages/vue-i18n-core/src/i18n.ts index 4bc2dd365..6f2d37f08 100644 --- a/packages/vue-i18n-core/src/i18n.ts +++ b/packages/vue-i18n-core/src/i18n.ts @@ -610,6 +610,10 @@ export function useI18n< setupLifeCycle(i18nInternal, instance, composer) i18nInternal.__setInstance(instance, composer) + } else { + if (__DEV__ && scope === 'local') { + throw createI18nError(I18nErrorCodes.DUPLICATE_USE_I18N_CALLING) + } } return composer as unknown as Composer< diff --git a/packages/vue-i18n-core/test/i18n.test.ts b/packages/vue-i18n-core/test/i18n.test.ts index 01816a30f..c13783ddb 100644 --- a/packages/vue-i18n-core/test/i18n.test.ts +++ b/packages/vue-i18n-core/test/i18n.test.ts @@ -344,6 +344,66 @@ describe('useI18n', () => { errorMessages[I18nErrorCodes.NOT_INSTALLED_WITH_PROVIDE] ) }) + + test(errorMessages[I18nErrorCodes.DUPLICATE_USE_I18N_CALLING], async () => { + const i18n = createI18n({ + legacy: false, + locale: 'en', + fallbackLocale: ['en'], + messages: { + en: { hello: 'hello!' } + } + }) + + const useMyComposable = () => { + const count = ref(0) + const { t } = useI18n({ + messages: { + en: { + there: 'hi there! {count}' + } + } + }) + return { message: t('there', { count: count.value }) } + } + + let error = '' + const App = defineComponent({ + setup() { + let message: string = '' + let t: any // eslint-disable-line @typescript-eslint/no-explicit-any + try { + const i18n = useI18n({ + messages: { + en: { + hi: 'hi!' + } + } + }) + t = i18n.t + const ret = useMyComposable() + message = ret.message + } catch (e: any) { + error = e.message + } + return { t, message, error } + }, + template: ` +

Root

+
+ +
+

{{ t('hi') }}

+

{{ message }}

+

{{ error }}

+ ` + }) + await mount(App, i18n as any) // eslint-disable-line @typescript-eslint/no-explicit-any + expect(error).toBe(errorMessages[I18nErrorCodes.DUPLICATE_USE_I18N_CALLING]) + }) }) test('slot reactivity', async () => { From f7247a7a5371593c29ff33d4baa79fe6e64941a5 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Tue, 17 Jun 2025 10:46:10 +0900 Subject: [PATCH 2/2] fix --- packages/vue-i18n-core/src/errors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vue-i18n-core/src/errors.ts b/packages/vue-i18n-core/src/errors.ts index f8ce2c3c8..3d1581d93 100644 --- a/packages/vue-i18n-core/src/errors.ts +++ b/packages/vue-i18n-core/src/errors.ts @@ -53,5 +53,5 @@ export const errorMessages: { [code: number]: string } = { [I18nErrorCodes.NOT_INSTALLED_WITH_PROVIDE]: 'Need to install with `provide` function', [I18nErrorCodes.DUPLICATE_USE_I18N_CALLING]: - "Duplicate `useI18n` calling by local scope. Please don't call it on local scope" + 'Duplicate local-scope `useI18n` call detected. Call `useI18n` only once per component.' }