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:
lazy
option to true
(or to configuration object if you want to customize some options).langDir
option to the directory (cannot be empty) that contains your translation files.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.vueI18n
option.file
or files
can return either an Object
, or a function that returns Promise
which must return an Object
.Example files structure:
nuxt-project/
├── lang/
│ ├── en-US.json
│ ├── es-ES.js
│ ├── fr-FR.ts
├── nuxt.config.ts
Configuration example:
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'
}
})
export default defineI18nLocale(async locale => {
return {
welcome: 'Bienvenue'
}
})
// or
export default {
welcome: 'Bienvenue'
}
defineI18nLocale
composable function.About defineI18nLocale
details, see the here.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}`)
})
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 separate file and define dialectal variations for each country separately 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
:
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 note 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.
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.
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'
}
})
As only the current locale translations are loaded you have to manually load a locale to be able to use its translations.
Nuxt i18n extends Vue i18n to provide the loadLocaleMessages
function to manually load locale messages, the example below demonstrates its usage.
const { loadLocaleMessages, t } = useI18n()
await loadLocaleMessages('nl')
const welcome = computed(() => t('welcome')) // Welcome!
const welcomeDutch = computed(() => t('welcome', 1, { locale: 'nl' })) // Welkom!
loadLocaleMessages
function will always load messages, unnecessary loading can impact performance.