@coherent.js/i18n
Internationalization for Coherent.js applications: translations with interpolation and pluralization, locale-aware formatters, and locale management.
pnpm add @coherent.js/i18nTranslations
Create a translator, add messages per locale, and translate with t().
Interpolation uses {{name}} placeholders by default:
import { createTranslator } from '@coherent.js/i18n';
const translator = createTranslator({ defaultLocale: 'en', fallbackLocale: 'en' });
translator.addTranslations('en', {
common: {
welcome: 'Welcome',
hello: 'Hello, {{name}}!'
}
});
translator.addTranslations('fr', {
common: {
welcome: 'Bienvenue',
hello: 'Bonjour, {{name}} !'
}
});
translator.t('common.hello', { name: 'Ada' }); // "Hello, Ada!"
translator.setLocale('fr');
translator.t('common.welcome'); // "Bienvenue"Keys are dot-paths into the translation object. Missing keys fall back to
fallbackLocale, then to the key itself (customizable via
missingKeyHandler).
Scoped translators
createScopedTranslator(translator, namespace) prefixes every key, which keeps
component code short:
import { createScopedTranslator } from '@coherent.js/i18n';
const t = createScopedTranslator(translator, 'common');
t('hello', { name: 'Ada' }); // same as translator.t('common.hello', ...)Formatters
Locale-aware date, number, currency, and list formatting built on Intl:
import { createFormatters } from '@coherent.js/i18n';
const fmt = createFormatters('en-US');
fmt.date.format(new Date()); // "1/15/2026"
fmt.number.format(12345.678); // "12,345.678"
fmt.currency.format(1999.99); // "$1,999.99"Individual formatter classes (DateFormatter, NumberFormatter,
CurrencyFormatter, ListFormatter) are also exported.
Locale management
import {
createLocaleManager,
detectLocale,
normalizeLocale,
isRTL,
getLocaleDirection
} from '@coherent.js/i18n';
const locales = createLocaleManager({ defaultLocale: 'en-US' });
locales.getLocale(); // current locale
detectLocale(); // best-guess locale for the environment
normalizeLocale('EN_us'); // "en-US"
isRTL('ar'); // true
getLocaleDirection('he'); // "rtl"Using translations in components
Components are plain functions, so pass the translator (or a scoped t) like
any other dependency:
export function Greeting({ t, name }) {
return { p: { text: t('hello', { name }) } };
}