i18nit API Reference
Complete API documentation for i18nit.
Table of Contents
Types
Locale
type Locale = string;A string representing a locale identifier (e.g., 'en', 'es', 'fr-FR').
PluralForm
type PluralForm = 'zero' | 'one' | 'two' | 'few' | 'many' | 'other';Plural category used for pluralization rules.
PluralMessages
type PluralMessages = Partial<Record<PluralForm, string>> & { other: string };Object defining plural forms for a message. The other form is required.
Example:
const messages = {
items: {
zero: 'No items',
one: 'One item',
other: '{count} items',
},
};MessageFunction
type MessageFunction = (
vars: Record<string, unknown>,
helpers: {
number: (value: number, options?: Intl.NumberFormatOptions) => string;
date: (value: Date | number, options?: Intl.DateTimeFormatOptions) => string;
}
) => string;A function that returns a dynamic translation string.
Example:
const messages = {
timestamp: (vars, helpers) => {
const date = vars.date as Date;
return `Updated: ${helpers.date(date, { dateStyle: 'short' })}`;
},
};MessageValue
type MessageValue = string | PluralMessages | MessageFunction;A translation can be a string, plural messages object, or a function.
Messages
type Messages = Record<string, MessageValue>;Collection of translations for a locale.
TranslateParams
type TranslateParams = {
locale?: Locale;
fallback?: string;
escape?: boolean;
};Options for translation methods.
- locale: Override the current locale for this translation
- fallback: Custom fallback string if translation not found
- escape: Enable/disable HTML escaping for this translation
I18nConfig
type I18nConfig = {
locale?: Locale;
fallback?: Locale | Locale[];
messages?: Record<Locale, Messages>;
loaders?: Record<Locale, () => Promise<Messages>>;
escape?: boolean;
missingKey?: (key: string, locale: Locale) => string;
missingVar?: 'preserve' | 'empty' | 'error';
};Configuration object for creating an i18n instance.
createI18n()
Create a new i18n instance.
Signature
function createI18n(config?: I18nConfig): I18nParameters
- config (
I18nConfig, optional): Configuration object
Returns
- I18n: A new i18n instance
Example
import { createI18n } from '@vielzeug/i18nit';
const i18n = createI18n({
locale: 'en',
fallback: 'en',
messages: {
en: {
greeting: 'Hello!',
},
es: {
greeting: '¡Hola!',
},
},
escape: false,
missingKey: (key) => `[${key}]`,
missingVar: 'empty',
});I18n Instance
Translation Methods
t()
Translate a message key with optional variables and options.
t(key: string, vars?: Record<string, unknown>, options?: TranslateParams): stringParameters:
- key: Translation key (supports dot notation)
- vars: Variables for interpolation
- options: Translation options
Returns: Translated string
Example:
i18n.t('greeting'); // "Hello!"
i18n.t('welcome', { name: 'Alice' }); // "Welcome, Alice!"
i18n.t('hello', undefined, { locale: 'es' }); // "¡Hola!"
i18n.t('user.name'); // "Name"Notes:
- Use
undefinedfor vars if you only want to pass options - Supports nested keys with dot notation
- Variables are interpolated using
{varName}syntax - Numbers are automatically formatted based on locale
tl()
Translate with automatic async loading (if loader registered).
async tl(key: string, vars?: Record<string, unknown>, options?: TranslateParams): Promise<string>Parameters:
- key: Translation key
- vars: Variables for interpolation
- options: Translation options
Returns: Promise resolving to translated string
Example:
// Automatically loads Spanish if not yet loaded
await i18n.tl('greeting', undefined, { locale: 'es' });
// With variables
await i18n.tl('welcome', { name: 'Bob' }, { locale: 'fr' });Locale Management
getLocale()
Get the current locale.
getLocale(): LocaleReturns: Current locale string
Example:
const currentLocale = i18n.getLocale(); // "en"setLocale()
Set the current locale and notify subscribers.
setLocale(locale: Locale): voidParameters:
- locale: Locale to set
Example:
i18n.setLocale('es');
i18n.setLocale('fr-FR');Notes:
- Triggers subscriber callbacks
- Does nothing if locale is already set
Message Management
add()
Add messages to a locale (merges with existing).
add(locale: Locale, messages: Messages): voidParameters:
- locale: Target locale
- messages: Messages to add
Example:
i18n.add('en', {
newKey: 'New translation',
another: 'Another one',
});
// Merges with existing messagesset()
Replace all messages for a locale.
set(locale: Locale, messages: Messages): voidParameters:
- locale: Target locale
- messages: Messages to set
Example:
i18n.set('en', {
greeting: 'Hello!',
// All previous messages are replaced
});getMessages()
Get all messages for a locale.
getMessages(locale: Locale): Messages | undefinedParameters:
- locale: Target locale
Returns: Messages object or undefined if locale not found
Example:
const messages = i18n.getMessages('en');
console.log(messages); // { greeting: 'Hello!', ... }hasLocale()
Check if a locale is loaded.
hasLocale(locale: Locale): booleanParameters:
- locale: Locale to check
Returns: True if locale exists
Example:
if (i18n.hasLocale('es')) {
console.log('Spanish is loaded');
}has()
Check if a translation key exists.
has(key: string, locale?: Locale): booleanParameters:
- key: Translation key
- locale: Locale to check (uses current if not provided)
Returns: True if key exists
Example:
if (i18n.has('greeting')) {
console.log('Greeting exists');
}
if (i18n.has('greeting', 'es')) {
console.log('Spanish greeting exists');
}Async Loading
register()
Register a loader function for a locale.
register(locale: Locale, loader: () => Promise<Messages>): voidParameters:
- locale: Target locale
- loader: Async function that returns messages
Example:
i18n.register('es', async () => {
const response = await fetch('/locales/es.json');
return response.json();
});
// Or with dynamic import
i18n.register('fr', () => import('./locales/fr.json'));load()
Load translations for a locale.
async load(locale: Locale): Promise<void>Parameters:
- locale: Locale to load
Returns: Promise that resolves when loaded
Example:
await i18n.load('es');
console.log('Spanish loaded');
// Load multiple
await Promise.all([i18n.load('es'), i18n.load('fr')]);Notes:
- Does nothing if locale already loaded
- Caches loading promise to prevent duplicate requests
- Calls
add()internally to merge loaded messages
hasAsync()
Check if a key exists, loading locale if needed.
async hasAsync(key: string, locale?: Locale): Promise<boolean>Parameters:
- key: Translation key
- locale: Locale to check (uses current if not provided)
Returns: Promise resolving to true if key exists
Example:
if (await i18n.hasAsync('greeting', 'es')) {
console.log('Spanish greeting exists');
}Formatting Helpers
number()
Format a number with locale-specific formatting.
number(value: number, options?: Intl.NumberFormatOptions, locale?: Locale): stringParameters:
- value: Number to format
- options: Intl.NumberFormat options
- locale: Locale to use (uses current if not provided)
Returns: Formatted number string
Example:
i18n.number(1234.56); // "1,234.56" (en-US)
i18n.number(1234.56, { style: 'currency', currency: 'USD' }); // "$1,234.56"
i18n.number(0.856, { style: 'percent' }); // "85.6%"
i18n.number(1234.56, undefined, 'de'); // "1.234,56"date()
Format a date with locale-specific formatting.
date(value: Date | number, options?: Intl.DateTimeFormatOptions, locale?: Locale): stringParameters:
- value: Date object or timestamp
- options: Intl.DateTimeFormat options
- locale: Locale to use (uses current if not provided)
Returns: Formatted date string
Example:
const date = new Date('2024-01-15');
i18n.date(date); // "1/15/2024" (en-US)
i18n.date(date, { dateStyle: 'long' }); // "January 15, 2024"
i18n.date(date, { dateStyle: 'full', timeStyle: 'short' });
// "Monday, January 15, 2024 at 12:00 AM"
// With timestamp
i18n.date(Date.now(), { dateStyle: 'medium' });Namespaces
namespace()
Create a namespaced translator.
namespace(ns: string): {
t: (key: string, vars?: Record<string, unknown>, options?: TranslateParams) => string;
tl: (key: string, vars?: Record<string, unknown>, options?: TranslateParams) => Promise<string>;
}Parameters:
- ns: Namespace prefix
Returns: Object with t and tl methods
Example:
const errors = i18n.namespace('errors');
const user = i18n.namespace('user');
errors.t('required'); // Same as i18n.t('errors.required')
user.t('profile.name'); // Same as i18n.t('user.profile.name')
// With async loading
await errors.tl('validation', undefined, { locale: 'es' });Subscriptions
subscribe()
Subscribe to locale changes.
subscribe(handler: (locale: Locale) => void): () => voidParameters:
- handler: Callback function called when locale changes
Returns: Unsubscribe function
Example:
const unsubscribe = i18n.subscribe((locale) => {
console.log('Locale changed to:', locale);
// Update UI, trigger re-renders, etc.
});
// Later...
unsubscribe();Notes:
- Handler is called immediately upon subscription
- Handler errors are caught and ignored
- Multiple subscribers are supported
Configuration
locale
locale?: LocaleDefault: 'en'
Initial locale for the instance.
Example:
createI18n({ locale: 'es' });fallback
fallback?: Locale | Locale[]Default: []
Fallback locale(s) used when translation not found.
Example:
// Single fallback
createI18n({ locale: 'en-US', fallback: 'en' });
// Multiple fallbacks
createI18n({ locale: 'pt-BR', fallback: ['pt', 'es', 'en'] });Fallback chain example:
// locale: 'en-US', fallback: ['en', 'es']
// Chain: en-US → en → esmessages
messages?: Record<Locale, Messages>Default: {}
Initial translation messages.
Example:
createI18n({
messages: {
en: {
greeting: 'Hello!',
user: {
name: 'Name',
},
},
es: {
greeting: '¡Hola!',
user: {
name: 'Nombre',
},
},
},
});loaders
loaders?: Record<Locale, () => Promise<Messages>>Default: {}
Async loader functions for lazy-loading translations.
Example:
createI18n({
loaders: {
es: async () => {
const response = await fetch('/locales/es.json');
return response.json();
},
fr: () => import('./locales/fr.json'),
},
});escape
escape?: booleanDefault: false
Enable HTML escaping globally.
Example:
createI18n({ escape: true });
// Can be overridden per translation
i18n.t('key', { html: '<b>bold</b>' }, { escape: false });missingKey
missingKey?: (key: string, locale: Locale) => stringDefault: (key) => key
Custom handler for missing translation keys.
Example:
createI18n({
missingKey: (key, locale) => {
console.warn(`Missing: ${key} (${locale})`);
return `[${key}]`;
},
});missingVar
missingVar?: 'preserve' | 'empty' | 'error'Default: 'empty'
Behavior when variable is missing in interpolation.
'preserve': Keep the placeholder (e.g.,{name})'empty': Replace with empty string'error': Throw an error
Example:
// Preserve
createI18n({ missingVar: 'preserve' });
i18n.t('Hello, {name}!'); // "Hello, {name}!"
// Empty (default)
createI18n({ missingVar: 'empty' });
i18n.t('Hello, {name}!'); // "Hello, !"
// Error
createI18n({ missingVar: 'error' });
i18n.t('Hello, {name}!'); // throws Error: Missing variable: nameMessage Types
String Messages
Simple string translations.
const messages = {
greeting: 'Hello!',
welcome: 'Welcome to our app',
};String with Variables
Strings with interpolation using {varName} syntax.
const messages = {
greeting: 'Hello, {name}!',
info: 'You have {count} new messages',
};
i18n.t('greeting', { name: 'Alice' }); // "Hello, Alice!"
i18n.t('info', { count: 5 }); // "You have 5 new messages"Nested variables:
const messages = {
userInfo: 'User: {user.name} ({user.email})',
};
i18n.t('userInfo', { user: { name: 'Bob', email: 'bob@example.com' } });
// "User: Bob (bob@example.com)"Array variables:
const messages = {
list: 'Items: {items[0]}, {items[1]}',
};
i18n.t('list', { items: ['apple', 'banana'] });
// "Items: apple, banana"Plural Messages
Object with plural forms based on language rules.
const messages = {
items: {
zero: 'No items',
one: 'One item',
other: '{count} items',
},
};
i18n.t('items', { count: 0 }); // "No items"
i18n.t('items', { count: 1 }); // "One item"
i18n.t('items', { count: 5 }); // "5 items"Required forms by language:
- English:
one,other - French:
one(0-1),other - Arabic:
zero,one,two,few,many,other - Russian:
one,few,many,other - Polish:
one,few,many
Function Messages
Dynamic messages with custom logic.
const messages = {
greeting: (vars) => {
const hour = new Date().getHours();
const name = vars.name as string;
if (hour < 12) return `Good morning, ${name}!`;
if (hour < 18) return `Good afternoon, ${name}!`;
return `Good evening, ${name}!`;
},
price: (vars, helpers) => {
const amount = vars.amount as number;
return helpers.number(amount, { style: 'currency', currency: 'USD' });
},
timestamp: (vars, helpers) => {
const date = vars.date as Date;
return `Posted ${helpers.date(date, { dateStyle: 'medium' })}`;
},
};
i18n.t('greeting', { name: 'Alice' }); // "Good morning, Alice!"
i18n.t('price', { amount: 99.99 }); // "$99.99"
i18n.t('timestamp', { date: new Date() }); // "Posted Feb 9, 2026"Best Practices
1. Type Safety
// Define message keys as types
type MessageKeys = 'greeting' | 'farewell';
// Use with TypeScript
const i18n = createI18n<Record<MessageKeys, string>>({
messages: {
en: {
greeting: 'Hello',
farewell: 'Goodbye',
},
},
});2. Organize by Feature
const messages = {
en: {
auth: { ... },
user: { ... },
products: { ... },
},
};3. Use Namespaces
const auth = i18n.namespace('auth');
const user = i18n.namespace('user');
auth.t('login');
user.t('profile.name');4. Lazy Load Translations
createI18n({
loaders: {
es: () => import('./locales/es.json'),
fr: () => import('./locales/fr.json'),
},
});5. Handle Missing Keys
createI18n({
missingKey: (key, locale) => {
console.warn(`Missing: ${key} (${locale})`);
return key.split('.').pop() || key;
},
});For complete usage examples, see Usage Guide and Examples.