@ooneex/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) — dot-notation keys, {{ param }} interpolation, and count-driven pluralization are built in. The dictionary is keyed by locale, with en as the always-present fallback, across 31 supported locale codes.
Why this component
- One dictionary, every locale. Each leaf carries its translations keyed by locale code (
en,fr,es, …);enis the guaranteed fallback when a target locale is missing. - Dot-notation keys. Access nested entries like
trans("user.profile.name")regardless of how deep the dictionary nests. - Interpolation built in. Fill
{{ param }}placeholders throughparamswithout string concatenation. - Pluralization by count. Sibling keys (
<key>,<key>_plural,<key>_zero) are selected automatically from thecountyou pass. - Container-managed. 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.
| Member | Purpose |
|---|---|
trans(key, options?) | Resolve a localized string for key; interpolates params and selects the plural form from count. |
has(key) | Whether key exists in the dictionary. |
getName() | Abstract — a stable identifier for the translation domain. |
getDict() | Abstract — returns the TranslationDictType dictionary. |
trans() accepts a TransOptionsType:
| Option | Type | Purpose |
|---|---|---|
lang | LocaleType | Target locale. Defaults to en. |
params | TransParamsType | Values for {{ param }} placeholders. |
count | number | Selects the pluralization sibling (singular / _plural / _zero). |
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).
| Key | When |
|---|---|
KEY_NOT_FOUND | The requested key does not exist in the dictionary. |
LOCALE_NOT_FOUND | The key exists but has no value for the requested locale or the en fallback. |
Best practices
- Always provide an
envalue. It is the fallback for every locale; a key withoutenthrowsLOCALE_NOT_FOUNDwhenever the target locale is missing. - Group keys by domain. Use stable dot-notation paths like
user.profile.nameso dictionaries stay navigable andgetName()maps cleanly to a domain. - Keep placeholders verbatim.
{{ name }}and{{ count }}must appear identically across locales; only the surrounding words change. - Always pass
countfor pluralized keys. Provide<key>,<key>_plural, and (optionally)<key>_zerosiblings so the correct form is selected. - Translate meaning, not words. Phrase each string the way a native speaker writing the product UI would, matching the locale’s capitalization and punctuation conventions.
- Never overwrite correct translations. When completing 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 @ooneex/translation if it is missing.
| Option | Description | Default |
|---|---|---|
--name | Translation class name. The Translation suffix is appended automatically. | Prompted if omitted |
--module | Target module the class is generated into. | shared |
--override | Overwrite an existing class without prompting. | false |
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.