@talosjs/translation component is an internationalization layer for multi-language applications. You extend the Translation base class, point it at a dictionary, and resolve localized strings with trans(key, options), which handles dot-notation keys, {{ param }} interpolation, and count-driven pluralization. The dictionary is keyed by locale, with en as the always-present fallback, across 31 supported locale codes.
How lookups resolve
One dictionary covers every locale: each leaf carries its translations keyed by locale code (en, fr, es, …), and en is the guaranteed fallback when a target locale is missing. You reach nested entries with dot-notation keys like trans("user.profile.name"), however deep the dictionary nests. {{ param }} placeholders are filled through params, so there’s no string concatenation, and pluralization picks the right sibling key (<key>, <key>_plural, <key>_zero) from the count you pass. Register a translation class with a decorator and resolve it from the container.
How it works
You extendTranslation and implement two methods: getName() returns a stable identifier for the domain, and getDict() returns the dictionary. Lookups go through has() and trans(), which resolve the requested locale, fall back to en, interpolate, and pick the right plural form.
trans() accepts a TransOptionsType:
Resolution order: the requested
lang is tried first, then the en fallback. A missing key throws with KEY_NOT_FOUND; a key present but absent in both the locale and the en fallback throws with LOCALE_NOT_FOUND. Pluralization picks <key> when count === 1, <key>_plural when count > 1 or count < 0, and <key>_zero when count === 0 (falling back to _plural if _zero is absent).
The supported locale codes are exported as locales:
Usage
ExtendTranslation, load a dictionary, and resolve keys through trans().
{{ param }} placeholders, and pluralization uses sibling keys selected by count:
Exceptions
The component throwsTranslationException when a key cannot be resolved. It carries a machine-readable key, a human-readable message, and a data object (with the lookup key and lang).
Keeping dictionaries reliable
Always provide anen value, since it’s the fallback for every locale; a key without one throws LOCALE_NOT_FOUND whenever the target locale is missing. Group keys by domain along stable dot-notation paths like user.profile.name so dictionaries stay navigable and getName() maps cleanly to a domain. Keep placeholders verbatim: {{ name }} and {{ count }} have to appear identically across locales, with only the surrounding words changing.
For pluralized keys, pass count and provide the <key>, <key>_plural, and optionally <key>_zero siblings so the correct form is selected. Translate meaning rather than words, phrasing each string the way a native speaker writing the product UI would and following the locale’s capitalization and punctuation conventions. When you complete locales, fill blanks only; keep keys stable and existing entries intact.
CLI command
Scaffold a translation class, its test file, and a siblingtranslations.yml dictionary with the generator. It writes the class under modules/<module>/src/translations/<Name>Translation.ts and installs @talosjs/translation if it is missing.
The generated class extends
Translation and loads the sibling translations.yml as its dictionary, ready for you to fill the keys:
translations.yml is written once per folder, so translation classes in the same translations/ directory share one dictionary.
See translation:create for the full command reference.
Use with Claude and Codex
The generator ships matchingtranslation:create and translation:translate skills. The first runs the scaffold and guides your AI agent through filling the dictionary; the second translates existing dictionaries meaning-for-meaning, completing every target locale from the en source. Initialize the skills once for your agent.
- Claude
- Codex
Prompt
translation:create --name=Checkout, then fills the translations.yml dictionary with the en and fr entries for each key.