@akashjs/i18n API
createI18n(config)
Create an i18n instance with signal-based locale switching.
function createI18n(config: I18nConfig): I18n;import { createI18n } from '@akashjs/i18n';
const i18n = createI18n({
defaultLocale: 'en',
messages: {
en: { hello: 'Hello' },
es: { hello: 'Hola' },
},
});I18nConfig
interface I18nConfig {
/** Default locale on startup */
defaultLocale: string;
/** Static messages keyed by locale */
messages?: LocaleMessages;
/** Lazy-load messages for a locale on demand */
loadMessages?: (locale: string) => Promise<Messages>;
/** Fallback locale when a key is missing in the current locale */
fallbackLocale?: string;
/** Custom pluralization rules keyed by locale */
pluralRules?: Record<string, (count: number) => string>;
}Messages types
/** Nested or flat message object */
type Messages = Record<string, string | Messages>;
/** All messages keyed by locale */
type LocaleMessages = Record<string, Messages>;I18n
The object returned by createI18n().
interface I18n {
t: (key: string, params?: Record<string, string | number>) => string;
locale: ReadonlySignal<string>;
setLocale: (locale: string) => Promise<void>;
te: (key: string) => boolean;
availableLocales: () => string[];
}I18n.t(key, params?)
Translate a key with optional interpolation parameters.
function t(key: string, params?: Record<string, string | number>): string;i18n.t('greeting'); // 'Hello'
i18n.t('welcome', { name: 'Alice' }); // 'Welcome, Alice!'Nested keys use dot notation:
i18n.t('nav.home'); // Looks up messages.nav.homeReturns the key itself if no translation is found:
i18n.t('missing.key'); // 'missing.key'Pluralization
When params includes a count property, t() resolves a plural form. Define plural variants as sub-keys:
// messages: { items: { one: '{count} item', other: '{count} items' } }
i18n.t('items', { count: 1 }); // '1 item'
i18n.t('items', { count: 5 }); // '5 items'The plural form is determined by the active locale's plural rule. The resolved sub-key (e.g. items.one) is looked up, then interpolated with all params.
I18n.te(key)
Check if a translation key exists in the current locale or fallback locale.
function te(key: string): boolean;i18n.te('greeting'); // true
i18n.te('nonexistent'); // falseI18n.setLocale(locale)
Set the active locale. If messages for the locale are not loaded and a loadMessages function was provided, it is called first.
function setLocale(locale: string): Promise<void>;await i18n.setLocale('es');
i18n.t('greeting'); // Now returns the Spanish translationMessages are cached after the first load. Switching back to a previously loaded locale does not re-fetch.
I18n.locale
A readonly signal containing the current locale string. Reactive — reading it inside a computed or render function tracks it as a dependency.
const locale: ReadonlySignal<string>;i18n.locale(); // 'en'
await i18n.setLocale('fr');
i18n.locale(); // 'fr'I18n.availableLocales()
Returns an array of all locale codes that have loaded messages.
function availableLocales(): string[];i18n.availableLocales(); // ['en', 'es']Pluralization Rules
Built-in rules follow CLDR conventions for these locales:
| Locale | Forms |
|---|---|
en | one (count === 1), other |
es | one (count === 1), other |
fr | one (count <= 1), other |
ar | zero, one, two, few (3-10), many (11-99), other |
Provide custom rules via I18nConfig.pluralRules:
const i18n = createI18n({
defaultLocale: 'pl',
pluralRules: {
pl: (count) => {
const mod10 = count % 10;
const mod100 = count % 100;
if (count === 1) return 'one';
if (mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14)) return 'few';
return 'many';
},
},
messages: {
pl: {
files: {
one: '{count} plik',
few: '{count} pliki',
many: '{count} plików',
},
},
},
});A plural rule function receives the count number and returns the sub-key string ('one', 'other', 'few', etc.). If no rule exists for the current locale, the English rule is used as a fallback.