Shared Instance Setup
Problem
You need one i18n instance shared across your entire app with a mix of eagerly-loaded and lazily-loaded locale catalogs. Creating multiple instances causes diverging locale state and duplicated catalog downloads.
Solution
Create a single instance in a dedicated module and export it. Pass static messages for the default locale and async loader functions for all others.
ts
import { createI18n } from '@vielzeug/lingua';
// i18n.ts — exported singleton
export const i18n = createI18n({
fallback: 'en',
locale: 'en',
catalogs: {
en: {
auth: { login: 'Log in', logout: 'Log out' },
greeting: 'Hello, {name}!',
inbox: { zero: 'No messages', one: 'One message', other: '{count} messages' },
nav: { home: 'Home' },
},
de: () => import('./locales/de.json').then((m) => m.default),
fr: () => import('./locales/fr.json').then((m) => m.default),
},
});
// In your app entry point
await i18n.preload('fr');
// In any component or module
import { i18n } from './i18n';
i18n.t('greeting', { name: 'Alice' });
i18n.tp('inbox', 3);Pitfalls
- Do not call
createI18nmore than once per app. Every call creates an independent locale state — there is no global registry. preloadin the entry point does not block rendering. Await it before your first render if translated content is needed immediately.- Passing the
encatalog as a static object means it is always bundled. Keep it small, or lazy-load it too if the default locale varies.