Lazy-load translations

How to lazy-load translations.


For apps that contain a lot of translated content, it is preferable not to bundle all the messages in the main bundle but rather lazy-load only the language that the users selected. This can be achieved with Nuxt i18n module by letting the module know where your translation files are located so it can dynamically import them when the app loads or when the user switches to another language. To enable translations lazy-loading, follow these steps when configuring Nuxt i18n module:

  • Set lazy option to true (or to configuration object if you want to customize some options).
  • Set langDir option to the directory (cannot be empty) that contains your translation files.
  • Configure locales option as an array of objects, where each object has a file or files key whose value is the translation file corresponding to the locale.
  • Optionally, remove all messages that you might have passed to Vue I18n via the vueI18n option.
  • Each file or files can return either an Object, or a function that returns Promise which must return an Object.

Basic usage

Example files structure:

nuxt-project/
├── lang/
│   ├── en-US.json
│   ├── es-ES.js
│   ├── fr-FR.ts
├── nuxt.config.ts

Configuration example:

nuxt.config.ts
export default defineNuxtConfig({
  // ...

  i18n: {
    locales: [
      {
        code: 'en',
        file: 'en-US.json'
      },
      {
        code: 'es',
        file: 'es-ES.js'
      },
      {
        code: 'fr',
        file: 'fr-FR.ts'
      }
    ],
    lazy: true,
    langDir: 'lang',
    defaultLocale: 'en'
  },

  // ...
})
lang/fr-FR.ts
export default defineI18nLocale(async (locale) => {
  return {
    welcome: 'Welcome'
  }
})

// or

export default {
  welcome: 'Welcome'
}
If your function returns an object of locale messages, you must define it in the defineI18nLocale composable function.About defineI18nLocale details, see the here.
Support for JS/TS format resources is an experimental feature and is disabled by default, to enable this set the experimental.jsTsFormatResource module option to true.
If the function returns an Object available in nuxt i18n module, you can configure the dynamic locale messages, like the API (including external API) or back-end, via fetch:
export default defineI18nLocale((locale) => {
  // for example, fetch locale messages from nuxt server
  return $fetch(`/api/${locale}`)
})

Multiple files lazy loading

The files property can be used to lazy load multiple files.

This is useful because it is efficient to manage multiple files that only define differences without duplicating locale messages.

For example, let’s take the case of supporting the Spanish language. According to wikipedia, there are 20 countries where Spanish is spoken as an official language!

If these countries are all configured using file, it would be difficult to maintain due to the duplication of locale messages for each country.

In this scenario, it would be easier to keep all shared (common) locale messages for the target language in a seperate file and define dialectal variations for each country seperately is well to prevent duplication, which is easier to maintain.

The following is an example of a lang directory containing locale files for the Spanish language:

nuxt-project/
├── lang/
│   ├── es.json     # locale messages for common Spanish
│   ├── es-AR.json  # locale messages for Argentina
│   ├── es-UY.json  # locale messages for Uruguay
│   ├── es-US.json  # locale messages for Estados Unidos
|   ...             # other countries ...
├── nuxt.config.ts

The following is an example of the configuration in nuxt.config.ts:

nuxt.config.ts
export default defineNuxtConfig({
  // ...

  i18n: {
    locales: [
      // ...

      /**
       * Example definition with `files` for Spanish speaking countries 
       */

      {
        code: 'es-AR',
        name: 'Español (Argentina)',
        // lazy loading order: `es.json` -> `es-AR.json`, and then merge 'es-AR.json' with 'es.json'
        files: ['es.json', 'es-AR.json']
      },
      {
        code: 'es-UY',
        name: 'Español (Uruguay)',
        // lazy loading order: `es.json` -> `es-UY.json`, and then merge 'es-UY.json' with 'es.json'
        files: ['es.json', 'es-UY.json']
      },
      {
        code: 'es-US',
        name: 'Español (Estados Unidos)',
        // lazy loading order: `es.json` -> `es-US.json`, and then merge 'es-US.json' with 'es.json'
        files: ['es.json', 'es-US.json']
      },

      // ...
    ],
    lazy: true,
    langDir: 'lang',
    defaultLocale: 'en',
  },

  // ...
})

Please not the usage of the files property, as the above configuration specifies an array containing multiple file names.

@nuxtjs/i18n will load locale messages with lazy loading in the order of the array specified in files. It then overrides the locale messages in the order in which they were loaded.

In the above es-AR example, which has es.json and es-AR.json defined in files. In this case, @nuxtjs/i18n lazy-loads es.json, then it lazy-loads es-AR.json and overrides es.json locale messages.

In the example above, only two files are defined for files, of course you can specify more files over 2 files. In that case, the files will be loaded and override in array order too.

By taking advantage of the characteristic that locale messages are overridden in sequence, it's possible to manage locale messages by defining them on a differential basis. By adding shared (common) locale messages as the first entry of files, followed by file entries of regional/dialectal locale messages, it's possible to manage resources while avoiding the duplication of locale messages.

Caching

Lazy loaded locale messages are cached based on their filename, file and files shared across locales will be used from cache once loaded. By default caching is enabled for static files, and disabled for files that return messages via a function.

Caching can be configured per file by setting file or entries of files to objects with the following type signature { path: string, cache?: boolean}. The example below demonstrates several valid file configurations.

nuxt.config.ts
export default defineNuxtConfig({
  // ...

  i18n: {
    locales: [
      // ...

      /**
       * Example definition with `files` for Spanish speaking countries 
       */
      {
        code: 'es-ES',
        name: 'Español (Spain)',
        // file with cache disabled
        file: { path: 'es.js', cache: false }
      },
      {
        code: 'es-AR',
        name: 'Español (Argentina)',
        // files with cache disabled
        files: [{ path: 'es.js', cache: false }, { path: 'es-AR.js', cache: false} ]
      },
      {
        code: 'es-UY',
        name: 'Español (Uruguay)',
        // strings and object configurations can be mixed
        files: [{ path: 'es.js', cache: false }, 'es-UY.json']
      },

      // ...
    ],
    lazy: true,
    langDir: 'lang',
    defaultLocale: 'en',
  },

  // ...
})