Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions packages/vue-i18n-core/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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"
}
4 changes: 4 additions & 0 deletions packages/vue-i18n-core/src/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand Down
60 changes: 60 additions & 0 deletions packages/vue-i18n-core/test/i18n.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: `
<h1>Root</h1>
<form>
<select v-model="locale">
<option value="en">en</option>
<option value="ja">ja</option>
</select>
</form>
<p>{{ t('hi') }}</p>
<p>{{ message }}</p>
<p>{{ error }}</p>
`
})
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 () => {
Expand Down