# nestjs-i18n keeps translations type safe and lets you swap the loader

> nestjs-i18n is the internationalisation module for Nest, with type safety, plurals, fallback languages, formatting and support for GraphQL, gRPC, DTO validation and template view engines. Its loader, resolver and formatter are all replaceable, and the package is MIT licensed.

**toonvanstrijp/nestjs-i18n** — The i18n module for nestjs.

- Repository: https://github.com/toonvanstrijp/nestjs-i18n
- Website: https://nestjs-i18n.com
- Stars: 723 · Forks: 141
- Language: TypeScript
- License: NOASSERTION
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/toonvanstrijp-nestjs-i18n

## Type safety for translation keys, not just translated strings

nestjs-i18n is the internationalisation module for Nest, and the feature list is broad enough that it is worth separating the different kinds of value. There is type safety for your translation keys, variable formatting for interpolated values, fallback languages, plural forms, live reloading while you work, and support for GraphQL, gRPC and DTO validation. On the rendering side there is view engine support for handlebars, pug and ejs.

The type safety part is the one that changes how a codebase is written. If your keys are typed, then a renamed message is a compile error rather than a string that silently renders as the key itself at runtime. For a project with dozens of message files and several people editing them, that moves a class of bug from production into the editor, and it is the reason to look at this module rather than a string table you write yourself.

The project describes itself as highly configurable, and the mechanism behind that claim is at the bottom of the feature list: custom resolvers, custom loaders and custom formatters. Those three extension points are what separate a module from a set of helpers, and they are covered in their own documentation pages on the project site.

The package is published to npm as `nestjs-i18n`, the author is Toon van Strijp, and the project is MIT licensed. The current version in the package manifest is 10.8.5.

## The loader and the resolver are the extension points

A language resolver decides, for a given request, which language is in play. A loader decides where the translation data comes from and in what shape. A formatter decides how a value is turned into a string for a given language. The project lets you write and plug in your own versions of all three, and the change history shows how far that reaches.

The loader became explicit at version 6, when the `I18nParser` was implemented so that formats other than JSON could be supported. The change to version 9 renamed the `parser` property to `loader`, and that same release stopped the `translate` function from returning a promise. So the format of your translation files and the way you load them are a supported decision, not a hardcoded assumption.

The resolver's contract changed as well, and the reason is architectural. From version 8 the internal `I18n-middleware` was replaced by an interceptor, so the module can supply an `ExecutionContext` and work across protocols rather than only over HTTP, which is what makes the gRPC and WebSocket support possible. The consequence for you is narrow but sharp: if you wrote a custom resolver, the `resolve` method no longer receives the `req` object and takes the `ExecutionContext` as its argument instead. The project points at a resolver example for the migration.

The resolver is the piece to think hardest about, because it is where your application's notion of a user meets the module's notion of a language.

## The translate API has changed shape across major versions

The project keeps a list of breaking changes, and it is the most useful page in the documentation for anyone adopting an older major version. Four of the entries change how you call the module.

At version 3, translations are loaded based on their directory name instead of the file name, so the layout of your translation folder has to match the documented structure. At version 4, the signature of the `translate` function changed so that the `language` argument is optional, falling back to the `fallbackLanguage` when it is not given. At version 6 came the `I18nParser` described above, and with it a `translate` function that returns a `Promise<string>`, which means calling it as `await i18n.translate('HELLO')`.

Then version 9 reversed part of that. The `translate` function no longer returns a promise, so the await from version 6 becomes unnecessary, and the property called `parser` was renamed to `loader`. Version 10 removed the `I18nRequestScopeService` altogether, because the module now has `async_hooks` support, and the current context can be obtained with `I18nContext.current()`.

Read as a whole, the trend is away from promises and towards a synchronous call with an explicit context lookup, and away from middleware towards interceptors. If you are upgrading across several majors, those four entries are the diff you actually have to plan for, not the feature list.

## A bin entry that generates the type definitions

The package ships a command line binary, `nestjs-i18n`, and the manifest wires it to `./bin/nestjs-i18n.mjs`. The script that uses it is `generate:types`, and it exists because the type safety feature needs a generated artefact: the type definitions describing your translation keys are derived from your translation files rather than written by hand.

That is the part worth understanding about the type safety story. The keys are not typed by a decorator or by a convention the framework infers. They come out of your message files, and a command turns them into types. The trade is the usual one for generated types: the generation step has to run when the messages change, and a stale generated file will type check against keys that no longer exist.

The rest of the toolchain is a fairly conventional TypeScript project. The build is `npx rimraf dist && tsc -p tsconfig.build.json`, tests run under Jest with a configuration at `tests/jest-test.json` and run in band, linting is done with oxlint and formatting with oxfmt. There is a single `verify` script that chains format check, lint and the coverage run, which is what a pull request check would call. The package publishes only `dist` and `bin` to npm, and the entry points are `./dist/index.js` with types at `./dist/index.d.ts`.

## The documentation is a Docusaurus site in the same repository

The documentation is not a separate site in a separate repository. The repository root contains `docusaurus.config.js`, a `sidebars.js`, a `docs/` directory and a `static/` directory, and the manifest carries a full set of Docusaurus scripts for serving, building, deploying, clearing the cache, writing translations and writing heading ids.

That arrangement has a practical consequence. The docs for the quickstart, the type safety guide, the formatting guide, the fallback language guide, the plurals guide, the GraphQL guide, the gRPC guide and the DTO validation guide live in the same tree as the code and are versioned with it, so a documentation example and the module it describes are much less likely to drift apart than they would be in a separate docs repository. The flip side is that the docs source is part of what a contributor has to navigate.

There are also two sample projects, `samples/simple` and `samples/dto-validation`, which is a faster way to see the module in a working Nest application than reading a guide. The `samples/` directory is worth more attention than it usually gets, because the DTO validation sample in particular shows how the module's validation support is meant to be wired in rather than only described.

The repository also carries a code of conduct, a contributing guide, a `LICENSE.md`, an `.oxlintrc.json` and an `.oxfmtrc.json` for the newer lint and format tooling, and a `pnpm-lock.yaml` alongside an `.npmrc` and an `.nvmrc`.

## Where nestjs-i18n is the wrong tool

The first limit is the framework. This is a module for Nest, built on Nest's dependency injection, its interceptors and its pipes, and it plugs into Nest's request lifecycle. It is not a general internationalisation library, and there is nothing here that a plain Express application or a serverless function would use.

The second is the cost of the API churn. Five major versions in the list, and each one that touches the call signature forces a migration. A team that adopts version 10 today and reads the changelog will find that the resolution mechanism changed twice, that the loader was renamed, that `translate` was a promise and then was not, and that the request scope service disappeared. The project documents each change and points at migration guides, so this is manageable work rather than a warning sign, but it is work, and it is the price of a module that has grown quickly.

The third is the dependency on the generated types. If your team does not want a code generation step in the build, or cannot accept that translation files are the source of truth for what a key is called, then the type safety feature is not for you and the rest of the module is still usable without it.

The last is timing. The repository is not archived and the last push was on 2026-10-12, but the newest published release is v10.8.5 from 2026-07-07, with v10.8.4 in May 2026 and v10.8.1 in April 2026. There is work in the branch that is not in a release yet, which is normal, but it means the version you install and the version the docs describe can differ.

## Conclusion

nestjs-i18n fits a Nest application that already has several languages and wants type safe translation keys, a replaceable loader for its translation format, and support for GraphQL, gRPC or DTO validation without assembling that itself. It does not fit a project that is not on Nest, and it does not fit a team unwilling to absorb a decade of API churn, since the module has changed the shape of translate, the middleware, the loader and the request scope across major versions. Check three things first: the version you are on, since v9 renamed parser to loader and made translate synchronous while v10 removed the request scope service, the formatter and loader you need, and the fact that translation files are loaded by directory name since v3, so your file layout has to match.

## FAQ

### How do I install nestjs-i18n?

The package is published to npm as `nestjs-i18n`, and the project documentation points to its quickstart page and the guides for setup. The module also ships a `nestjs-i18n` command that the `generate:types` script uses to derive translation key types from your message files.

### What does the type safety feature in nestjs-i18n do?

It gives your translation keys types, so a renamed message becomes a compile error rather than a string that renders as its own key at runtime. The types are generated from your translation files by the `nestjs-i18n` binary.

### Why did the translate function stop returning a promise?

Version 6 introduced the `I18nParser` and a `translate` function returning a `Promise<string>`, and version 9 renamed `parser` to `loader` and made `translate` synchronous again. Code written for version 6 needs the await removed when moving to version 9.

### What changed for custom resolvers in version 8?

The internal `I18n-middleware` was replaced by an interceptor so the module can pass an `ExecutionContext` and work over protocols such as gRPC and WebSockets. A custom resolver's `resolve` method now takes the `ExecutionContext` as an argument instead of the request object.

### Which protocols and integrations does nestjs-i18n support?

The feature list covers GraphQL, gRPC, DTO validation and view engines with handlebars, pug and ejs, alongside plurals, fallback languages, variable formatting and live reloading. Custom resolvers, loaders and formatters can be plugged in.

## Sources

- [Issues](https://github.com/toonvanstrijp/nestjs-i18n/issues)
- [Project website](https://nestjs-i18n.com)
- [README](https://github.com/toonvanstrijp/nestjs-i18n/blob/main/README.md)
- [Releases](https://github.com/toonvanstrijp/nestjs-i18n/releases)
- [toonvanstrijp/nestjs-i18n on GitHub](https://github.com/toonvanstrijp/nestjs-i18n)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/toonvanstrijp-nestjs-i18n
