10.4.5 • Published 2 days ago

nestjs-i18n v10.4.5

Weekly downloads
11,102
License
MIT
Repository
github
Last release
2 days ago

Build Status Greenkeeper badge Coverage Status

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 of a 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 a @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: (configService: 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: [
        { use: QueryResolver, options: ['lang', 'locale', 'l'] },
        HeaderResolver,
        new CookieResolver(['lang', 'locale', 'l']),
      ],
    }),
  ],
  controllers: [HelloController],
})
export class AppModule {}

Currently, there are two built-in resolvers

ResolverDefault value
QueryResolvernone
HeaderResolveraccept-language
CookieResolverlang

To implement your own resolver (or custom logic) use the I18nResolver interface. The resolvers are provided via the nestjs dependency injection, this way you can inject your own services if needed.

@Injectable()
export class QueryResolver implements I18nResolver {
  constructor(@I18nResolverOptions() private keys: string[]) {}

  resolve(req: any) {
    let lang: string;

    for (const key of this.keys) {
      if (req.query != undefined && req.query[key] !== undefined) {
        lang = req.query[key];
        break;
      }
    }

    return lang;
  }
}

To provide initial options to your custom resolver use the @I18nResolverOptions() decorator, also provide the resolver as followed:

I18nModule.forRoot({
  path: path.join(__dirname, '/i18n/'),
  fallbackLanguage: 'en',
  saveMissing: false,
  resolvers: [{ use: QueryResolver, options: ['lang', 'locale', 'l'] }],
});

Using forRootAsync()

I18nModule.forRootAsync({
  useFactory: () => {
    return {
      path: path.join(__dirname, '/i18n'),
      fallbackLanguage: 'en',
      saveMissing: false,
    };
  },
  resolvers: [{ use: QueryResolver, options: ['lang', 'locale', 'l'] }],
});

Translating with i18n module

I18nLang decorator and I18nService

@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' });
  }
}

I18n decorator

@Controller()
export class SampleController {
  @Get()
  sample(@I18n() i18n: I18nContext) {
    i18n.translate('HELLO_MESSAGE', { args: { id: 1, username: 'Toon' } });
    i18n.translate('SETUP.WELCOME', { args: { id: 1, username: 'Toon' } });
    i18n.translate('ARRAY.0');
  }
}

No need to handle lang manually.

I18nRequestScopeService within a custom service using request scoped translation service

@Injectable()
export class SampleService {
  constructor(private readonly i18n: I18nRequestScopeService) {}

  doFancyStuff() {
    this.i18n.translate('HELLO_MESSAGE', { args: { id: 1, username: 'Toon' } });
    this.i18n.translate('SETUP.WELCOME', { args: { id: 1, username: 'Toon' } });
    this.i18n.translate('ARRAY.0');
  }
}

To be used within other services like sending E-mails. The advantage is that you don't have to worry about transporting lang from the Request to your service.

Use with caution! The I18nRequestScopeService uses the REQUEST scope and is no singleton. This will be inherited to all consumers of I18nRequestScopeService! Read Nest Docs for more information.

Dont use I18nRequestScopeService within controllers. The I18n decorator is a much better solution.

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 V5.0.0 ... TODO
  • 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 the fallbackLanguage

  • 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

11.0.0-beta

2 days ago

10.4.5

2 months ago

10.4.0

5 months ago

10.3.4

7 months ago

10.3.5

7 months ago

10.3.6

7 months ago

10.3.7

6 months ago

10.3.2

8 months ago

10.3.0

8 months ago

10.3.1

8 months ago

10.2.7-rc.1

10 months ago

10.2.5

1 year ago

10.2.6

1 year ago

10.0.0

1 year ago

10.1.0-next.2

1 year ago

10.1.0-next.3

1 year ago

10.2.3

1 year ago

10.2.4

1 year ago

10.1.0-next.0

1 year ago

10.1.0-next.1

1 year ago

9.2.3

1 year ago

9.2.2

1 year ago

9.2.1

2 years ago

10.2.0

1 year ago

10.2.1

1 year ago

9.3.0

1 year ago

10.1.0

1 year ago

9.1.10

2 years ago

9.1.9

2 years ago

9.1.8

2 years ago

9.1.7

2 years ago

9.2.0

2 years ago

9.0.13

2 years ago

9.1.1

2 years ago

9.1.0

2 years ago

9.1.6

2 years ago

9.1.5

2 years ago

9.1.4

2 years ago

9.1.3

2 years ago

9.1.2

2 years ago

9.0.12

2 years ago

9.0.11

2 years ago

9.0.10

2 years ago

9.0.9

2 years ago

9.0.8

2 years ago

9.0.7

2 years ago

9.0.6

2 years ago

9.0.5

2 years ago

9.0.4

2 years ago

9.0.3

2 years ago

8.3.0

2 years ago

8.3.2

2 years ago

8.3.1

2 years ago

9.0.2

2 years ago

9.0.1

2 years ago

9.0.0

2 years ago

8.2.2

2 years ago

8.1.8

2 years ago

8.1.9

2 years ago

8.2.1

2 years ago

8.2.0

2 years ago

8.1.7

3 years ago

8.1.6

3 years ago

8.1.5

3 years ago

8.1.4

3 years ago

8.1.3

3 years ago

8.1.2

3 years ago

8.1.1

3 years ago

8.1.0

3 years ago

8.0.11

3 years ago

8.0.10

4 years ago

8.0.9

4 years ago

8.0.8

4 years ago

8.0.7

4 years ago

8.0.6

4 years ago

8.0.5

4 years ago

8.0.4

4 years ago

8.0.3

4 years ago

8.0.2

4 years ago

8.0.1

4 years ago

8.0.0

4 years ago

7.0.0

4 years ago

6.0.1

4 years ago

6.0.0

4 years ago

5.1.0

4 years ago

5.0.1

4 years ago

5.0.0

4 years ago

4.1.3

4 years ago

4.1.2

4 years ago

4.1.1

4 years ago

4.1.0

4 years ago

4.0.6

5 years ago

4.0.5

5 years ago

4.0.4

5 years ago

4.0.3

5 years ago

4.0.2

5 years ago

4.0.1

5 years ago

4.0.0

5 years ago

3.1.0

5 years ago

3.0.1

5 years ago

3.0.0

5 years ago

2.2.3

5 years ago

2.2.2

5 years ago

2.2.1

5 years ago

2.2.0

5 years ago

2.1.4

5 years ago

2.1.3

5 years ago

2.1.2

5 years ago

2.1.1

5 years ago

2.1.0

5 years ago

2.0.2

5 years ago

2.0.1

5 years ago

2.0.0

5 years ago

1.0.1

5 years ago

1.0.0

5 years ago