Translation module
From a catalog of translations, translate your content with or not parameters.
Can work with Symfony translations structure in Node environment and/or with Webpack using Babel.
See how to integrate with :
Summary
Installation
npm install --save @jochlain/translations
Usage
Translations catalog example
const CATALOG = {
en: {
messages: {
hello: "Hi",
"translations.are.incredible": 'The translations are incredible.',
very: { compound: { key: "The compound key" } },
},
forms: {
"This field is required.": "This field is required."
},
},
es: {
messages: {
hello: "Holà",
"translations.are.incredible": 'Las traducciones son increíbles.',
very: { compound: { key: "La llave compuesta" } },
},
forms: {
"This field is required.": "Este campo es obligatorio.",
},
},
fr: {
messages: {
hello: "Bonjour",
"translations.are.incredible": "Les traductions sont incroyables.",
very: { compound: { key: "La clé composée" } },
},
forms: {
"This field is required.": "Ce champs est obligatoire.",
},
},
it: {
messages: {
hello: "Ciao",
"translations.are.incredible": 'Le traduzioni sono incredibili.',
very: { compound: { key: "La chiave composta" } },
},
forms: {
"This field is required.": "Questo campo è richiesto.",
},
},
};
import Translator, { translate } from "@jochlain/translations";
const translator = Translator(CATALOG);
console.log(translator.translate('hello')); // => "Hi"
console.log(translator.translate('hello', null, null, 'fr')); // => "Bonjour"
// With unknown informations
console.log(translator.translate('hello', null, 'forms')); // => "hello"
console.log(translator.translate('hello', null, 'validators')); // => "hello"
console.log(translator.translate('hello', null, null, 'ar')); // => "hello"
// Compound key
console.log(translator.translate('very.compound.key')); // => "The compound key"
// Fake compound key
console.log(translator.translate('translations.are.incredible')); // => "The translations are incredible."
// Usage of with* helper
const translatorFormsEn = translator.withDomain('forms');
const translatorFormsFr = translatorFormsEn.withLocale('fr');
console.log(translatorFormsEn.translate('This field is required.')); // => "This field is required."
console.log(translatorFormsFr.translate('This field is required.')); // => "Ce champs est obligatoire."
console.log(translate({ en: 'Hello', fr: 'Bonjour' })); // => "Hello"
console.log(translate({ en: 'Hello', fr: 'Bonjour' }, null, 'fr')); // => "Bonjour"
For more usage sample see Jest test
Intl integration
Intl installation
npm i -S intl-messageformat
Usage with Intl
import Translator from "@jochlain/translations";
import { IntlMessageFormat } from "intl-messageformat";
const formatter = { format: (message, replacements, locale) => (new IntlMessageFormat(message, locale).format(replacements)) };
const translator = Translator(CATALOG, { formatter });
Questions and answers
Why ?
Because I can't found a simple and secured way to send translations to front shared by server.
Who ?
For little project directly or bigger project with babel macro.
Where ?
In a node / browser / compiled / SSR.
Documentation
Types
type ReplacementType = { [key: string]: number|string };
type FormatType = (message: string, replacements: ReplacementType, locale: string) => string;
type FormatterType = { format: FormatType };
type CatalogType = { [key: string]: string|CatalogType };
type TranslationType = { [locale: string]: { [domain: string]: CatalogType } };
type OptionsType = { locale?: string, domain?: string, formatter?: FormatterType };
Constants
DEFAULT_DOMAIN="messages"
DEFAULT_LOCALE="en"
Module
Translator proxy
If is applied like below, it calls static method create.
If is constructed like below, is calls the constructor.
import Translator from "@jochlain/translations";
const domain = 'messages';
const locale = 'en';
const catalogs = new Map();
catalogs.set('messages-en', { hello: 'Hello' });
const translations = { en: { messages: { hello: 'Hello' } } };
const translator_applied = Translator(translations, { domain, locale }); // call static method create.
const translator_constructed = new Translator(catalogs, { domain, locale }); // construct new instance
Translator class
Members
Name |
Type |
Default |
Description |
catalogs |
Map<string, CatalogType> |
[] |
Translation catalogs |
fallbackDomain |
string |
'messages' |
Default domain used in translate
|
fallbackLocale |
string |
'en' |
Default locale used in translate
|
formatter |
FormatterType |
{ format } |
Formate message with locale and replacements |
translations |
TranslationType |
{} |
Translation catalogs formatted as object |
Constructor
constructor(catalogs, options)
Parameters
Return value
Static methods
create(translations, options)
Create Translator instance with another catalogs format and set fallback values.
Parameters
Name |
Type |
Default |
Description |
translations |
TranslationType |
{} |
Translation catalogs by locale and domains |
options |
OptionsType |
{} |
Options to set member default value |
Return value
getCatalogValue(catalog, key)
Browse catalog to find value assigned to key
Parameters
Return value
Type |
Description |
string |
The value in the catalog attached to the key or the key if not found |
getKey(domain, locale)
Format a key from domain and locale.
Parameters
Name |
Type |
domain |
string |
locale |
string |
Return value
Type |
Description |
string |
The formatted key |
mergeCatalogs(target, ...sources)
Deep merge many catalogs
Parameters
Return value
Type |
Description |
CatalogType |
A catalog with deep merged values |
parseKey(key)
Get domain and locale from key.
Parameters
Return value
Type |
Description |
[string, string] |
The domain and the locale |
translate(catalog, replacements, locale, formatter)
Translate a message from a simple catalog
Parameters
Return value
Type |
Description |
string |
The translated message |
Methods
addCatalog(catalog, domain, locale)
Add a catalog to translations map
Parameters
Return value
Type |
Description |
Translator |
The translator instance to chain methods |
getCatalog(domain, locale)
Get the catalog attached to domain and locale in catalogs map.
If locale
is like en_US
it looks first for a en_US
catalog and if not looks for a en
catalog.
Parameters
Return value
Type |
Description |
CatalogType | undefined |
The catalog of messages attached to domain and locale |
getDomains()
Get all domains fill in catalogs map
Return value
Type |
Description |
string[] |
The domains |
getLocales()
Get all locales fill in catalogs map
Return value
Type |
Description |
string[] |
The locales |
getMessage(key, domain, locale)
Get message attached to key in catalog attached to domain and locale in catalogs.
See getCatalog and getCatalogValue
Parameters
Return value
Type |
Description |
string |
Message attached to key or key if not found |
getMessages(key, domain)
Get messages attached to key
Parameters
Return value
Type |
Description |
{ [locale: string] :string } |
A collection of messages by locale |
setFallbackDomain(domain)
Set the fallbackDomain member
Parameters
Return value
Type |
Description |
Translator |
The translator instance to chain methods |
setFallbackLocale(locale)
Set the fallbackLocale member
Parameters
Return value
Type |
Description |
Translator |
The translator instance to chain methods |
setFormatter(formatter)
Set the formatter member
Parameters
Return value
Type |
Description |
Translator |
The translator instance to chain methods |
setTranslations(translations)
Set the formatter member
Parameters
Return value
Type |
Description |
Translator |
The translator instance to chain methods |
withDomain(domain)
Clone instance with fallbackDomain domain parameter
Parameters
Return value
Type |
Description |
Translator |
A new translator instance |
withFormatter(formatter)
Clone instance with formatter
Parameters
Return value
Type |
Description |
Translator |
A new translator instance |
withLocale(locale)
Clone instance with fallbackLocale locale parameter
Parameters
Return value
Type |
Description |
Translator |
A new translator instance |
with({ domain, formatter, locale })
Clone instance with domain, formatter, locale.
Parameters
Return value
Type |
Description |
Translator |
A new translator instance |
Default format method
By default, format method search each replacement key with a RegExp and replace them by their values.
That's the next part I'm going to look at.
function format(message: string, replacements: ReplacementType, locale: string = DEFAULT_LOCALE) {
let result = message;
for (let keys = Object.keys(replacements), idx = 0; idx < keys.length; idx++) {
result = result.replace(new RegExp(`${keys[idx]}`, 'g'), String(replacements[keys[idx]]));
}
return result;
}