quasar-frameworkvitest

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


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.


Solution

  • 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. :-)