Localization
Framework-agnostic i18n in a few hundred lines of TypeScript. Translation dictionaries, placeholder interpolation, count-based plural rules, locale-switching events — all from one core. Works in Node, browser, with React, Vue, Svelte, vanilla JS. For React JSX placeholders (<strong> as a translation value), pair with @mongez/react-localization.
Highlighted features
Per-locale dictionaries
extend(“en”, {…}), extend(“ar”, {…}) — flat or nested keyword maps, registered any time. Switch with setCurrentLocaleCode.
Placeholder interpolation
trans(“greet”, { name: “Ada” }) with default :name pattern, or a custom regex via configuration. Pluggable converter for non-string output.
Count-based plurals
Custom countRules pick from key_zero, key_one, key_many when a count placeholder is present. Locale-specific rules supported.
Fallback chain
Missing in current locale → look in fallback locale → return keyword itself. Inline-object form returns the object on full miss so consumers can detect it.
Locale-switching events
localizationEvents.onChange(cb) fires when the current locale flips — drive re-renders, persist the choice, update an HTML lang attribute.
Install
npm install @mongez/localizationyarn add @mongez/localizationpnpm add @mongez/localization@mongez/events and @mongez/reinforcements install automatically as runtime deps.
Quick peek
import { setLocalizationConfigurations, extend, trans, setCurrentLocaleCode } from "@mongez/localization";
setLocalizationConfigurations({ defaultLocaleCode: "en", fallback: "en" });
extend("en", { home: "Home", greet: "Hello :name" });extend("ar", { home: "الرئيسية", greet: "مرحبا :name" });
trans("home"); // "Home"trans("greet", { name: "Ada" }); // "Hello Ada"
setCurrentLocaleCode("ar");trans("home"); // "الرئيسية"Configure once at boot, register dictionaries per locale, read by keyword. Switching the current locale flips every subsequent trans() call.
Mental model
| Concept | Mental model |
|---|---|
| Translation dictionary | { [locale]: Keywords }. Keywords may nest. |
| Keyword | Identifier you ask for at runtime. May use dot-notation to read nested groups. |
| Translatable | string or { [locale]: string }. The object form is for inline per-feature translations. |
| Converter | Function that interpolates placeholder values. Default plainConverter; React uses jsxConverter. |
| Placeholder pattern | Regex matched inside translation strings. Default :name. |
| Count rule | (n: number) => boolean. Picks one of several key_<rule> translations for a { count } placeholder. |
The fallback chain
When trans(keyword) runs:
- Look up
keywordin the current locale. - If missing, look in the fallback locale.
- If still missing, return the keyword itself.
For the inline-object form (trans({ en: "Home", ar: "..." })), step 1 reads obj[currentLocale], step 2 reads obj[fallbackLocale], step 3 returns the object unchanged so consumers can detect the miss.
Scope boundaries
| Concern | Lives in | Why |
|---|---|---|
JSX placeholders (<strong> as a value) | @mongez/react-localization | Keep the core framework-agnostic |
| React hooks for re-rendering on locale change | (not provided) | Use localizationEvents.onChange to drive a re-render via local state |
| Persisting the selected locale | (not provided) | Bring your own — varies per framework |
| ICU MessageFormat / nested message syntax | (not provided) | Out of scope — this package is name → string + placeholders |
Where to go next
- Translations —
extend, dictionary shapes, registration patterns - Translating —
trans,transFrom,transObject - Interpolation — placeholder patterns, custom converters
- Count translations — plural rules, fallback chain
- Events —
localizationEvents, locale-change hooks - Recipes — common patterns