diff --git a/packages/vue-i18n-core/src/errors.ts b/packages/vue-i18n-core/src/errors.ts index c9cc541b1..ce9bc2726 100644 --- a/packages/vue-i18n-core/src/errors.ts +++ b/packages/vue-i18n-core/src/errors.ts @@ -1,6 +1,6 @@ import { - createCompileError, - CORE_ERROR_CODES_EXTEND_POINT + CORE_ERROR_CODES_EXTEND_POINT, + createCompileError } from '@intlify/core-base' import type { BaseError } from '@intlify/shared' @@ -26,7 +26,9 @@ export const I18nErrorCodes = { // not compatible legacy vue-i18n constructor NOT_COMPATIBLE_LEGACY_VUE_I18N: 33, // Not available Compostion API in Legacy API mode. Please make sure that the legacy API mode is working properly - NOT_AVAILABLE_COMPOSITION_IN_LEGACY: 34 + NOT_AVAILABLE_COMPOSITION_IN_LEGACY: 34, + // duplicate `useI18n` calling + DUPLICATE_USE_I18N_CALLING: 35 } as const type I18nErrorCodes = (typeof I18nErrorCodes)[keyof typeof I18nErrorCodes] @@ -57,5 +59,7 @@ export const errorMessages: { [code: number]: string } = { [I18nErrorCodes.NOT_COMPATIBLE_LEGACY_VUE_I18N]: 'Not compatible legacy VueI18n.', [I18nErrorCodes.NOT_AVAILABLE_COMPOSITION_IN_LEGACY]: - 'Not available Compostion API in Legacy API mode. Please make sure that the legacy API mode is working properly' + 'Not available Compostion API in Legacy API mode. Please make sure that the legacy API mode is working properly', + [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 1fc5eec4f..75cb6e39f 100644 --- a/packages/vue-i18n-core/src/i18n.ts +++ b/packages/vue-i18n-core/src/i18n.ts @@ -772,6 +772,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 0d6ae7488..9707cb07f 100644 --- a/packages/vue-i18n-core/test/i18n.test.ts +++ b/packages/vue-i18n-core/test/i18n.test.ts @@ -622,6 +622,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]) + }) }) describe('slot reactivity', () => {