nestjs-i18n

repository·main·Indexed 20 days ago

https://github.com/toonvanstrijp/nestjs-i18n

A highly configurable internationalization library for NestJS providing multi-language support across HTTP, GraphQL, gRPC, and WebSockets. It integrates with DTO validation and view engines, offering built-in resolvers for headers, cookies, and gRPC metadata, as well as an abstract loader for custom translation sources.

Tokens
44.1K
Snippets
175
Records
216
Agent score
71%

What's inside nestjs-i18n

  1. Overview of nestjs-i18n features

    main

    nestjs-i18n

    nestjs-i18n is a highly configurable internationalization library for NestJS. It allows you to manage multiple languages in your project by providing tools for translation, variable formatting, and more. The library is designed to be extensible, allowing you to plug in your own language resolvers, loaders, and formatters.

    Key Features:

    • Type safety: Ensure your translation keys are type-safe.
    • Variable formatting: Inject dynamic data into translation strings.
    • Nested translations: Organize translation files using nested structures.
    • Fallback languages: Define default languages when a translation is missing.
    • Live reloading: Automatically update translations during development.
    • Plurals support: Handle pluralization rules for different languages.
    • Protocol support: Built-in support for GraphQL and gRPC.
    • DTO validation: Integrate translations into your Data Transfer Object validation.
    • View engine support: Works with hbs, pug, and ejs.
    • Extensibility: Support for custom resolvers, loaders, and formatters.
  2. What are Loaders in nestjs-i18n

    main

    Loaders are the components responsible for fetching translation data and the list of available languages for your application. nestjs-i18n provides two built-in loaders:

    • I18nJsonLoader: The default loader for JSON files.
    • I18nYamlLoader: A loader for YAML files.

    Loaders can be configured to fetch data from files, databases, or other external sources.

  3. Understand the I18nTranslation interface structure

    main

    The I18nTranslation interface represents a translation object that can be deeply nested. It is defined as an indexable object where keys are strings and values can be either a direct translation string or another nested I18nTranslation object. This allows for hierarchical translation keys (e.g., errors.validation.required).

    {
      "key": "string | { [key: string]: string | I18nTranslation }
    }
  4. Understand the ResolverWithOptions type alias

    main
    The ResolverWithOptions type alias is a composite type used for configuring i18n resolvers. It combines the properties defined in ResolverWithOptionsBase with the capabilities of an OptionProvider. This allows a resolver configuration to be passed either as a static object or as a provider that can resolve its options dynamically (e.g., via a factory function or a service injection).
  5. Implement a custom I18nLoader

    main

    The I18nLoader is an abstract class used to define how translation data is fetched and which languages are supported. To use a custom source for your translations (e.g., a database, an external API, or a remote storage service), you must extend this class and implement its two abstract methods: languages() and load().

    • languages(): Must return a Promise or Observable that resolves to an array of strings representing the supported language codes (e.g., ['en', 'fr']).
    • load(): Must return a Promise or Observable that resolves to an I18nTranslation object containing the actual translation data.
  6. How to implement a custom I18n resolver

    main

    If the built-in resolvers do not meet your requirements, you can implement a custom language resolver. To do this, your class must implement the I18nLanguageResolver interface found in src/interfaces/i18n-language-resolver.interface.ts.

    You can refer to the existing implementations in src/resolvers to understand how to handle the detection logic and return the detected language string.

  7. How to access the current I18nContext (v10.0.0+)

    main

    Starting from version 10.0.0, I18nRequestScopeService has been removed in favor of async_hooks support. You can now retrieve the current translation context anywhere in your application using I18nContext.current().

    // Access the current context without needing request scope injection
    const context = I18nContext.current();
  8. Implement a custom loader using I18nAbstractLoader

    main

    If you need to load translations from a source other than JSON or YAML (e.g., a database, an external API, or a custom file format), you can extend the I18nAbstractLoader class.

    To create a functional custom loader, you must implement the following abstract methods:

    1. formatData(data: any): any: Defines how the raw data retrieved from your source should be transformed into the translation format.
    2. getDefaultOptions(): Partial<I18nAbstractLoaderOptions>: Returns the default configuration options for your specific loader.

    I18nAbstractLoader provides several protected helper methods to assist in the implementation, such as parseLanguages(), parseTranslations(), and assignPrefixedTranslation().

  9. Understand option precedence for i18next-compatible options

    main

    When configuring keySeparator, nsSeparator, returnObjects, or joinArrays, there is a hierarchy of precedence:

    1. Per-call options: Options passed directly to i18n.t(key, options) always take the highest precedence.
    2. Module-level options: Options defined in I18nModule.forRoot(options) serve as the default for the entire application.

    If a per-call option is provided, it will override the global module-level setting for that specific translation call.

    // Module default
    I18nModule.forRoot({
      joinArrays: ' | ',
    })
    
    // This call overrides the module default with a comma separator
    i18n.t('test.ARRAY', { joinArrays: ', ' }) // => 'ONE, TWO, THREE'
  10. How resolvers work and how to add them

    main

    Resolvers determine the current language of a request. nestjs-i18n processes the resolvers array in order; if the first resolver cannot determine a language, it moves to the next.

    Built-in resolvers include:

    • QueryResolver: Resolves language from URL query parameters.
    • HeaderResolver: Resolves language from HTTP headers.
    • CookieResolver: Resolves language from cookies.
    • AcceptLanguageResolver: Resolves language from the Accept-Language header.
    import { Module } from '@nestjs/common';
    import path from 'path';
    import {
      AcceptLanguageResolver,
      I18nJsonLoader,
      I18nModule,
      QueryResolver,
      HeaderResolver,
      CookieResolver,
    } from 'nestjs-i18n';
    
    @Module({
      imports: [
        I18nModule.forRootAsync({
          useFactory: (configService: ConfigService) => ({
            fallbackLanguage: "en",
            loaderOptions: {
              path: path.join(__dirname, "/i18n/"),
              watch: true,
            },
          }),
          resolvers: [
            new QueryResolver(["lang", "l"]),
            new HeaderResolver(["x-custom-lang"]),
            new CookieResolver(),
            AcceptLanguageResolver,
          ],
          inject: [ConfigService],
        }),
      ],
      controllers: [],
    })
    export class AppModule {}