Description
The i18n module for Nest.
Installation
$ npm i --save nestjs-i18n
Quick Start
Structure
create a directory and in it define your language keys as directories.
i18n
├── en
│ ├── category.json
│ └── auth.json
└── nl
├── category.json
└── auth.json
Translation File
The format for the translation file could look like this:
{
"HELLO_MESSAGE": "Hello {username}",
"GOODBYE_MESSAGE": "Goodbye {username}",
"USER_ADDED_PRODUCT": "{0.username} added {1.productName} to cart",
"SETUP": {
"WELCOME": "Welcome {0.username}",
"GOODBYE": "Goodbye {0.username}"
},
"ARRAY": [
"ONE",
"TWO",
"THREE"
]
}
String formatting is done by: string-format
Translation Module
To use the translation service we first add the module. The I18nModule
has an @Global()
attribute so you should only import it once.
import { Module } from '@nestjs/common';
import * as path from 'path';
import { I18nModule } from 'nestjs-i18n';
@Module({
imports: [
I18nModule.forRoot({
path: path.join(__dirname, '/i18n'),
filePattern: '*.json',
fallbackLanguage: 'en',
}),
],
controllers: []
})
export class AppModule {}
Using forRootAsync()
import { Module } from '@nestjs/common';
import * as path from 'path';
import { I18nModule } from 'nestjs-i18n';
@Module({
imports: [
I18nModule.forRootAsync({
useFactory: (config: ConfigurationService) => ({
path: configService.i18nPath,
fallbackLanguage: configService.fallbackLanguage, // e.g., 'en'
filePattern: configService.i18nFilePattern, // e.g., '*.i18n.json'
}),
inject: [ConfigurationService]
}),
],
controllers: []
})
export class AppModule {}
Language Resolvers
To make it easier to manage in what language to respond you can make use of resolvers
@Module({
imports: [
I18nModule.forRoot({
path: path.join(__dirname, '/i18n/'),
fallbackLanguage: 'en',
resolvers: [
new QueryResolver(['lang', 'locale', 'l']),
new HeaderResolver(),
],
}),
],
controllers: [HelloController],
})
export class AppModule {}
Currently, there are two build-in resolvers
Resolver | Default value |
---|---|
QueryResolver |
none |
HeaderResolver |
accept-language |
To implement your own resolver (or custom logic) use the I18nResolver
interface.
Using Translation Service and Language Resolver
@Controller()
export class SampleController {
constructor(
private readonly i18n: I18nService,
) {}
@Get()
sample(
@I18nLang() lang: string
) {
this.i18n.translate('HELLO_MESSAGE', {lang: lang, args: {id: 1, username: 'Toon'}});
this.i18n.translate('SETUP.WELCOME', {lang: 'en', args: {id: 1, username: 'Toon'}});
this.i18n.translate('ARRAY.0', {lang: 'en'});
}
}
Missing Translations
If you require a translation that is missing, I18n
will log an error. However, you can also write these missing translations to a new file in order to help translating your application later on.
This behaviour can be controlled via the saveMissing: boolean
attribute when adding the I18nModule
to your application. Thereby, true
describes the following behaviour:
Say, you request the translation mail.registration.subject
in a de
language, and this specific key is missing. This will create a de/mail.missing
file in your i18n
folder and add the following content:
{
"registration": {
"subject": ""
}
}
CLI
To easily check if your i18n folder is correctly structured you can use the following command:
nest-i18n check <i18n-path>
example: nest-i18n check src/i18n
This is very useful inside a CI environment to prevent releases with missing translations.
Breaking changes:
-
from V4.0.0 on we changed the signature of the
translate
method, the language is now optional, if no language is given it'll fallback to thefallbackLanguage
-
from V3.0.0 on we load translations based on their directory name instead of file name. Change your translations files to the structure above: info