Version v2.2.0 Size 2.4 KB gzip Dependencies Zero dependencies
Why Lingua?
Lingua separates immutable translation from mutable locale state. Use one catalog per locale, then select static or stateful API from whether locale can change.
ts
// Before
const message = catalogs[locale]?.inbox?.[count === 1 ? 'one' : 'other'] ?? 'inbox';
// After
const output = i18n.translate('inbox', { count });| Feature | Lingua | i18next | FormatJS |
|---|---|---|---|
| Bundle size | 2.4 KB | Varies by selected modules | Varies by selected modules |
| Zero runtime dependencies | |||
| Explicit plural catalog nodes | Convention/config dependent | ICU-message dependent | |
| Declared lazy locale catalogs | Plugin/config dependent | Application-defined | |
| Immutable locale snapshots | Application-defined | Application-defined |
Use Lingua when you need a compact TypeScript runtime with explicit catalog structure, deterministic fallback, and framework-neutral subscriptions.
Consider i18next or FormatJS when you need their plugin ecosystems, message extraction pipelines, or framework-specific integrations.
Installation
sh
pnpm add @vielzeug/linguash
npm install @vielzeug/linguash
yarn add @vielzeug/linguaQuick Start
Create locale store with static catalogs, then dispose it when owner ends.
ts
import { createTranslationStore } from '@vielzeug/lingua';
const i18n = createTranslationStore({
catalogs: {
de: { inbox: { plural: { one: 'Eine Nachricht', other: '{count} Nachrichten' } } },
en: { inbox: { plural: { one: 'One message', other: '{count} messages' } } },
},
locale: 'en',
});
try {
console.log(i18n.translate('inbox', { count: 3 }));
await i18n.setLocale('de');
console.log(i18n.translate('inbox', { count: 1 }));
} finally {
i18n.dispose();
}Features
createCatalogTranslator()compiles one immutable fixed-locale catalog.createTranslator()compiles immutable locale-keyed catalogs.createTranslationStore()manages locale changes and declared catalogs.translate()renders text and plural messages through explicit catalog nodes.translateDynamic()makes runtime-key lookup explicit.load()deduplicates lazy catalog loading per locale.getSnapshot()andsubscribe()expose immutable translator revisions.serialize()andhydrateTranslationStore()transfer resolved SSR catalogs.createFormatter()andvalidateCatalog()remain isolated subpath tools.