File tree Expand file tree Collapse file tree 3 files changed +70
-2
lines changed Expand file tree Collapse file tree 3 files changed +70
-2
lines changed Original file line number Diff line number Diff line change @@ -22,7 +22,9 @@ export const I18nErrorCodes = {
2222 CANNOT_SETUP_VUE_DEVTOOLS_PLUGIN : 30 ,
2323 NOT_INSTALLED_WITH_PROVIDE : 31 ,
2424 // unexpected error
25- UNEXPECTED_ERROR : 32
25+ UNEXPECTED_ERROR : 32 ,
26+ // duplicate `useI18n` calling
27+ DUPLICATE_USE_I18N_CALLING : 33
2628} as const
2729
2830type I18nErrorCodes = ( typeof I18nErrorCodes ) [ keyof typeof I18nErrorCodes ]
@@ -49,5 +51,7 @@ export const errorMessages: { [code: number]: string } = {
4951 [ I18nErrorCodes . INVALID_VALUE ] : `Invalid value` ,
5052 [ I18nErrorCodes . CANNOT_SETUP_VUE_DEVTOOLS_PLUGIN ] : `Cannot setup vue-devtools plugin` ,
5153 [ I18nErrorCodes . NOT_INSTALLED_WITH_PROVIDE ] :
52- 'Need to install with `provide` function'
54+ 'Need to install with `provide` function' ,
55+ [ I18nErrorCodes . DUPLICATE_USE_I18N_CALLING ] :
56+ 'Duplicate local-scope `useI18n` call detected. Call `useI18n` only once per component.'
5357}
Original file line number Diff line number Diff line change @@ -610,6 +610,10 @@ export function useI18n<
610610 setupLifeCycle ( i18nInternal , instance , composer )
611611
612612 i18nInternal . __setInstance ( instance , composer )
613+ } else {
614+ if ( __DEV__ && scope === 'local' ) {
615+ throw createI18nError ( I18nErrorCodes . DUPLICATE_USE_I18N_CALLING )
616+ }
613617 }
614618
615619 return composer as unknown as Composer <
Original file line number Diff line number Diff line change @@ -344,6 +344,66 @@ describe('useI18n', () => {
344344 errorMessages [ I18nErrorCodes . NOT_INSTALLED_WITH_PROVIDE ]
345345 )
346346 } )
347+
348+ test ( errorMessages [ I18nErrorCodes . DUPLICATE_USE_I18N_CALLING ] , async ( ) => {
349+ const i18n = createI18n ( {
350+ legacy : false ,
351+ locale : 'en' ,
352+ fallbackLocale : [ 'en' ] ,
353+ messages : {
354+ en : { hello : 'hello!' }
355+ }
356+ } )
357+
358+ const useMyComposable = ( ) => {
359+ const count = ref ( 0 )
360+ const { t } = useI18n ( {
361+ messages : {
362+ en : {
363+ there : 'hi there! {count}'
364+ }
365+ }
366+ } )
367+ return { message : t ( 'there' , { count : count . value } ) }
368+ }
369+
370+ let error = ''
371+ const App = defineComponent ( {
372+ setup ( ) {
373+ let message : string = ''
374+ let t : any // eslint-disable-line @typescript-eslint/no-explicit-any
375+ try {
376+ const i18n = useI18n ( {
377+ messages : {
378+ en : {
379+ hi : 'hi!'
380+ }
381+ }
382+ } )
383+ t = i18n . t
384+ const ret = useMyComposable ( )
385+ message = ret . message
386+ } catch ( e : any ) {
387+ error = e . message
388+ }
389+ return { t, message, error }
390+ } ,
391+ template : `
392+ <h1>Root</h1>
393+ <form>
394+ <select v-model="locale">
395+ <option value="en">en</option>
396+ <option value="ja">ja</option>
397+ </select>
398+ </form>
399+ <p>{{ t('hi') }}</p>
400+ <p>{{ message }}</p>
401+ <p>{{ error }}</p>
402+ `
403+ } )
404+ await mount ( App , i18n as any ) // eslint-disable-line @typescript-eslint/no-explicit-any
405+ expect ( error ) . toBe ( errorMessages [ I18nErrorCodes . DUPLICATE_USE_I18N_CALLING ] )
406+ } )
347407} )
348408
349409test ( 'slot reactivity' , async ( ) => {
You can’t perform that action at this time.
0 commit comments