Native translation support @localizer/translate 1.0.1 experimental
The TypeScript-native translation support provides two primary primitives: translate()
for specifying individual translatable values, and dictionary()
for organizing comprehensive sets of translations. Additionally, the plural()
processor enables the creation of nuanced and context-aware pluralization rules, making complex translations more intuitive and manageable.
Individual translations
To define standalone individual translations, use the translate()
function. This function operates in two modes:
- Static mode: Ideal for predefined translations that do not depend on runtime data.
- Dynamic mode: Suitable for translations derived from runtime data, such as backend responses.
Static translations
import { getLocalizer } from '@localizer/core';
import { translate } from '@localizer/translate';
const enUS = getLocalizer('en-US');
const ruRU = getLocalizer('ru-RU');
const yes = translate({
en: 'Yes',
ru: 'Да',
});
console.log(enUS(yes));
console.log(ruRU(yes));
Yes
Да
Unlike a basic localization function that relies on a switch(locale) { ... }
construct, this approach leverages locale resolution. This ensures that translations are dynamically resolved based on the most appropriate locale, providing greater flexibility and accuracy in multilingual applications.
TIP
The values in the TranslationMap
can be either strings or Localizable
values
Dynamic translations
Dynamic translation support is particularly useful when dealing with backend responses that include embedded translations. For example:
{
"status_en": "Paid",
"status_fi": "Maksettu",
"status_sv": "Betald"
}
To process such data, the dynamic variant of the translate()
function can be utilized:
// ...
const data = {
status_en: 'Paid',
status_fi: 'Maksettu',
status_sv: 'Betald',
};
const dataFormatter = translate<typeof data>((it) => ({
en: it.status_en,
fi: it.status_fi,
sv: it.status_sv,
}));
const enUS = getLocalizer('en-US');
const fiFI = getLocalizer('fi-FI');
console.log(enUS(dataFormatter(data)));
console.log(fiFI(dataFormatter(data)));
Paid
Maksettu
For simpler cases where the data structure directly aligns with the TranslationMap
, the library offers the translation
value formatter. This is particularly useful for straightforward mappings without additional processing:
// ...
const dataSimple = {
status: {
en: 'Paid',
fi: 'Maksettu',
sv: 'Betald',
},
};
const enUS = getLocalizer('en-US');
const fiFI = getLocalizer('fi-FI');
console.log(enUS(translation(dataSimple.status))); // Outputs: "Paid"
console.log(fiFI(translation(dataSimple.status))); // Outputs: "Maksettu"
Paid
Maksettu
This approach simplifies the translation process when the data structure is already in a format compatible with the library's expectations.
Dictionaries
Several individual translations can be combined to form a dictionary using dictionary()
function:
import { getLocalizer } from '@localizer/core';
import { translate } from '@localizer/translate';
const enUS = getLocalizer('en-US');
const frFR = getLocalizer('fr-FR');
const translations = dictionary({
yes: {
en: 'Yes',
fr: 'Oui',
es: 'Sí',
de: 'Ja',
},
no: {
en: 'No',
fr: 'Non',
es: 'No',
de: 'Nein',
},
});
console.log(enUS(translations.yes));
console.log(frFR(translations.yes));
Yes
Oui
Similar to translate()
, the values in a dictionary can either be a TranslationMap
or functions that generate a TranslationMap
. Using functions allows for more complex translations that accept arguments, enabling dynamic and context-sensitive localization:
import { getLocalizer } from '@localizer/core';
import { decimal } from '@localizer/format';
import { dictionary } from '@localizer/translate';
const enUS = getLocalizer('en-US');
const fiFI = getLocalizer('fi-FI');
const svFI = getLocalizer('sv-FI');
const translations = dictionary({
files: (count: number) => ({
en: loc`${decimal(count)} files`,
fi: loc`${decimal(count)} tiedostoa`,
sv: loc`${decimal(count)} filer`,
}),
});
console.log(enUS(translations.files(0)));
console.log(fiFI(translations.files(1)));
console.log(svFI(translations.files(101)));
0 files
1 tiedostoa
101 filer
Be cautious with translation maps
When defining translation maps, avoid using native string interpolation directly, as it can lead to inconsistencies. Instead, use the library's value formatting utilities to ensure proper localization:
const translations = dictionary({
files: (count: number) => ({
en: `${count} files`, // ❌ Avoid native string interpolation
fi: `${count} tiedostoa`,
sv: `${count} filer`,
}),
});
While this approach might work in simple cases, it bypasses the library's formatting capabilities, such as handling locale-specific number formatting. A better solution is to use the loc
and decimal
utilities:
const translations = dictionary({
files: (count: number) => ({
en: loc`${decimal(count)} files`, // ✅ Use value formatting for consistency
fi: loc`${decimal(count)} tiedostoa`,
sv: loc`${decimal(count)} filer`,
}),
});
This ensures that translations are consistent and adhere to locale-specific formatting rules.
Pluralization
The example with file counts demonstrates the use of the plural()
function to handle pluralization rules for different languages. This function enables precise and locale-specific pluralization, ensuring that translations are grammatically correct and contextually appropriate.
Here is how the plural()
function can be used to define translations for file counts:
import { getLocalizer } from '@localizer/core';
import { decimal } from '@localizer/format';
import { dictionary, plural } from '@localizer/translate';
import { one, two, few, many, other } from '@localizer/translate';
const enUS = getLocalizer('en-US');
const fiFI = getLocalizer('fi-FI');
const svFI = getLocalizer('sv-FI');
const translations = dictionary({
files: (count: number) => ({
en: plural(count, {
0: 'No files',
[one]: loc`${decimal(count)} file`,
[other]: loc`${decimal(count)} files`,
}),
fi: plural(count, {
0: 'Ei tiedostoja',
[one]: loc`${decimal(count)} tiedosto`,
[other]: loc`${decimal(count)} tiedostoa`,
}),
sv: plural(count, {
0: 'Inga filer',
[one]: loc`${decimal(count)} fil`,
[other]: loc`${decimal(count)} filer`,
}),
}),
});
console.log(enUS(translations.files(0)));
console.log(fiFI(translations.files(1)));
console.log(svFI(translations.files(101)));
No files
1 tiedosto
101 filer
By leveraging the plural()
function, you can define flexible and accurate pluralization rules for each language, ensuring that your application provides a seamless multilingual experience.