Translations
The translation dictionary is a TranslationsList = { [localeCode: string]: Keywords }, where Keywords is a recursive map of strings or nested keyword groups.
Shape
type TranslationsList = { [localeCode: string]: Keywords };type Keywords = { [key: string]: string | Keywords };const translations: TranslationsList = { en: { home: "Home", ui: { sidebar: "Sidebar", menu: "Menu", }, }, ar: { home: "الرئيسية", ui: { sidebar: "الشريط الجانبي", }, },};Reads use dot-notation: trans("ui.sidebar") reads translations[currentLocale].ui.sidebar.
extend(localeCode, keywords)
The idiomatic registration call. Multiple calls for the same locale merge — keep one file per locale and re-extend per feature:
import { extend } from "@mongez/localization";
extend("en", { home: "Home" });extend("en", { contact: "Contact Us" });extend("en", { ui: { sidebar: "Sidebar" },});The merge is recursive (provided by @mongez/reinforcements’ merge), so nested groups accumulate too.
groupedTranslations(groupKey?, dict)
Declares translations keyword-first (every keyword carries its locale map), the inverse of extend:
import { groupedTranslations } from "@mongez/localization";
groupedTranslations({ home: { en: "Home", ar: "الرئيسية" }, contact: { en: "Contact Us", ar: "اتصل بنا" },});Optionally namespace a flat dictionary under a prefix:
groupedTranslations("store", { orders: { en: "Orders", ar: "الطلبات" }, products: { en: "Products", ar: "المنتجات" },});// Reads as: trans("store.orders"), trans("store.products")Nested groups work too — the locale map is whichever leaf object has only string leaves:
groupedTranslations({ general: { home: { en: "Home", ar: "الرئيسية" }, },});// trans("general.home")Internally, groupedTranslations flattens the input, splits each path on ., treats the last segment as the locale code, and writes the leaf into translationsList[localeCode][keyword]. So groupedTranslations and extend write into the same underlying map — you can mix them freely.
setTranslationsList / getTranslationsList / getKeywordsListOf
setTranslationsList(list: TranslationsList): void // full replacegetTranslationsList(): TranslationsList // live referencegetKeywordsListOf(locale: string): Keywords | nullsetTranslationsList replaces the entire map — useful when you load translations from a single JSON file at boot:
setTranslationsList(await fetch("/api/i18n").then(r => r.json()));Alternatively, set translations via the configuration object:
setLocalizationConfigurations({ translations: { en: { home: "Home" }, ar: { home: "الرئيسية" } },});setLocalizationConfigurations({ translations }) calls setTranslationsList internally — same effect.
Pattern: one file per locale
import { extend } from "@mongez/localization";extend("en", { home: "Home", contact: "Contact" });
// src/locales/ar.tsimport { extend } from "@mongez/localization";extend("ar", { home: "الرئيسية", contact: "اتصل" });
// src/config/localization.tsimport "src/locales/en";import "src/locales/ar";import { setLocalizationConfigurations } from "@mongez/localization";
setLocalizationConfigurations({ defaultLocaleCode: "en", fallback: "en",});Pattern: one file per feature (keyword-first)
import { groupedTranslations } from "@mongez/localization";
groupedTranslations("cart", { empty: { en: "Your cart is empty", ar: "سلتك فارغة" }, checkout: { en: "Checkout", ar: "الدفع" },});// somewhere in the cart featuretrans("cart.empty");trans("cart.checkout");The downside is that lookups via the dynamic string (trans("cart.empty")) don’t get keyword-scope type checking. If you want that, see translating.md for transObject.