Quasar Vitest: How to set up i18n boot file for both the dev/prod and the test

Quasar Vitest: How to set up i18n boot file for both the dev/prod and the test
typescript
Ethan Jackson

The recommendation for i18n in Quasar is to add it to a boot file like this:

import { defineBoot } from '#q-app/wrappers' import { createI18n } from 'vue-i18n' import messages from 'src/i18n' export default defineBoot(({ app }) => { const i18n = createI18n({ locale: 'en-US', globalInjection: true, messages }) // Set i18n instance on app app.use(i18n) })

From: https://quasar.dev/options/app-internationalization#setup-manually

However, when you run tests under Vitest as per https://testing.quasar.dev/packages/unit-vitest/ the boot files are not executed meaning your i18n will remain uninitialised.

In my app I use the i18n in both the Vue components and in some of the plain JS classes. I specifically want to test the JS classes and the tests are failing because the i18n is uninitialised.

I attempted to use one of the suggestions about installQuasarPlugin but still no success - i18n remained initialised.

Answer

So, what I did instead was:

  1. Created a composable for the i18n like this:
/** * Composable to provide GLOBAL i18n functionality * for both Vue and Business Logic. * * Note: This is used to get the i18n instance into the boot file for Vue components. * It is also used directly for the BL classes. */ import { createI18n } from 'vue-i18n' // ie uses @/yourapp/i18n/index.js which loads all the language files into one object import messages from '@/yourapp/i18n' // Run once, and export i18n so it can be used in the boot file // so it gets injected into the Vue components. export const i18n = createI18n({ legacy: false, // Use false so it is the same as what the app uses. ie the Composition API mode. locale: 'en-AU', fallbackLocale: 'en-AU', globalInjection: true, warnHtmlMessage: false, silentTranslationWarn: true, silentFallbackWarn: true, messages // The complete set for all locales }) // Export the methods for use in your BL classes. export function usei18n () { const setGlobalLocale = async (locale) => { i18n.global.locale.value = locale } const getGlobalLocale = () => { return i18n.global.locale.value } const getGlobalMessages = () => { return i18n.global.messages.value } const getTranslate = () => { return i18n.global.t } return { i18n, setGlobalLocale, getGlobalLocale, getGlobalMessages, getTranslate } }
  1. In my JS classes I use it in the normal way for composables:
import { usei18n } from '@/platform/use/usei18n.js' const { setGlobalLocale, getGlobalLocale } = usei18n()
  1. In the boot file I use the composable:
// Use our composable which is also used for the BL classes import { i18n } from '@/platform/use/usei18n' export default ({ app }) => { // Just plug it into the app. app.use(i18n) }

Works well. :-)

Related Articles