Changelog - 2026-11-01
The i18n provider takes lazy sources, so a catalogue stays out of the boot bundle
New FeatureIn one line. An entry of i18nSources is the messages object, or now a function that returns a promise of it, called the first time its locale is used. An application that ships two catalogues no longer carries both in the boot bundle: one POS app cut 293 kB gzip (25%) from its boot by dropping one. Objects work as before.
ts
import { englishMessages, type II18nProviderOptions } from '@venizia/ardor';
const i18nProviderOptions: II18nProviderOptions = {
i18nSources: {
en: englishMessages,
vi: () => import('./vi'), // a chunk, loaded when Vietnamese is picked
},
languages: [
{ locale: 'en', name: 'English' },
{ locale: 'vi', name: 'Tieng Viet' },
], // ...
};What changed
TI18nSource.II18nProviderOptions.i18nSourcesisRecord<string, TI18nSource>, whereTI18nSourceisobject | (() => Promise<object>).- What a loader returns. The messages, or an ES module whose default export is the messages (
export default { ... }, whatimport('./vi')resolves to). Anything else counts as a failed load. - First render. When the starting locale is lazy,
ArdorApplicationshowssuspenseuntil its messages arrive, as it does for a feature's lazy messages. - A failed load does not stop the admin. A file that does not download, or a chunk that did not arrive, is logged through the provider's
this.logger; the locale shows the English messages and the features' messages. The failure is not remembered, so the nextchangeLocale()calls the loader again. - Loaded once. After a loader delivers, the messages are kept.
Features.hasPendingMessagesandFeatures.loadMessages(the renamedhasPendingFeatureMessagesandloadFeatureMessages) also look at the application's lazy sources, not only at the features' lazy messages.loadMessagescallschangeLocalewhen either has a loader that has not delivered.- A subclass of
DefaultI18nProvider. The provider has a newprotected localeSourcesmember, andcomposeMessagesreads a locale throughthis.localeSources.readNow({ locale }). That call returns the messages, orundefinedfor a loader that has not delivered. A subclass that overridescomposeMessagesand readsi18nProviderOptions.i18nSources[locale]itself can now get a function, so read throughlocaleSources. - Size. The admin bundle grows by about 0.4 kB brotli for this; its budget is 10.5 kB (was 10 kB).
Who is affected
- An app with more than one catalogue in
i18nSources. Turn the ones the first screen does not need into loaders. - An app with a subclass of
DefaultI18nProviderthat overridescomposeMessages. Read the locale throughthis.localeSources.readNow({ locale }). - An app with one catalogue, or a custom i18n provider that is not a subclass. Nothing to do.
See i18n.