Dictionary @localizer/translate 1.2.1 experimental
For complex translation tasks, the library provides support for translation dictionaries defined using Unicode MessageFormat 2.0 format. This functionality supports both static dictionaries which are defined at the compilation time, and dynamic dictionaries, where locale data can be lazily loaded on-demand.
Static loading
For straightforward scenarios, you can define all translations directly within your dictionary declaration.
import { getLocalizer } from '@localizer/core';
import { dictionary } from '@localizer/translate';
const dict = dictionary('Dictionary', {
en: {
yes: 'Yes',
no: 'No',
hello: 'Hello {$name}!',
},
fi: {
yes: 'Kyllä',
no: 'Ei',
hello: 'Hei {$name}!',
},
sv: {
yes: 'Ja',
no: 'Nej',
hello: 'Hej {$name}!',
},
});
const yes = dict.key('yes');
const no = dict.key('no');
const hello = dict.key<{ name: string }>('hello', true);
const localizer = getLocalizer('en-US');
console.log(localizer(yes));
console.log(localizer(hello({ name: 'Maria' })));
Yes
Hello Maria!
Dynamic loading
In applications supporting multiple languages, bundling all translations together can significantly increase the application size and impact performance. To address this, it's recommended to use asynchronous dictionaries, which allow translations to be loaded on demand for each locale as needed.
import { getLocalizer } from '@localizer/core';
import { asyncDictionary, globalRegistry } from '@localizer/translate';
// Indicate that translations for english language should be preloaded
await globalRegistry.loadLocale('en-US');
const dict = await asyncDictionary('Dictionary', {
en: import('./en.js'),
fi: import('./fi.js'),
sv: import('./sv.js'),
});
const yes = dict.key('yes');
const no = dict.key('no');
const hello = dict.key<{ name: string }>('hello', true);
const localizer = getLocalizer('en-US');
console.log(localizer(yes));
console.log(localizer(hello({ name: 'Maria' })));
export default {
yes: 'Yes',
no: 'No',
hello: 'Hello {$name}!',
} as const;
export default {
yes: 'Kyllä',
no: 'Ei',
hello: 'Hei {$name}!',
} as const;
export default {
yes: 'Ja',
no: 'Nej',
hello: 'Hej {$name}!',
} as const;
Yes
Hello Maria!
You can also "bake in" specific languages directly into your application bundle. This approach allows you to preload certain locales—such as your primary language—while keeping others loaded asynchronously. This is useful for optimizing performance and reducing initial load times, especially when you want to guarantee that at least one language is always available without additional network requests.
import { getLocalizer } from '@localizer/core';
import { asyncDictionary, globalRegistry } from '@localizer/translate';
import en from './en.js';
// Indicate that translations for english language should be preloaded
globalRegistry.loadLocale('en-US');
const dict = await asyncDictionary('Dictionary', {
en: import('./en.js'),
en,
fi: import('./fi.js'),
sv: import('./sv.js'),
});
const yes = dict.key('yes');
const no = dict.key('no');
const hello = dict.key<{ name: string }>('hello', true);
// ...
Formatting
As shown in previous examples, translations could include placeholders for value interpolation. When built-in MessageFormat 2 formatting functions are not used, the library uses auto-formatting to convert values to their locale-dependent representation. This allows to use custom formatters which might be necessary when dealing with complex data:
import { getLocalizer, Localizable } from '@localizer/core';
import { currency } from '@localizer/format';
import { dictionary } from '@localizer/translate';
const dict = dictionary('Dictionary', {
en: {
price: 'Price: {$value}',
},
fi: {
price: 'Hinta: {$value}',
},
sv: {
price: 'Pris: {$value}',
},
});
const price = dict.key<{ value: Localizable }>('price', true);
const localizer = getLocalizer('en-US');
console.log(localizer(price({ value: currency(1005, 'EUR') })));
Price: €1,005.00
TIP
For more details and hands-on experimentation, refer to the Unicode MessageFormat 2.0 Quick Start Guide and try out the MessageFormat Playground.