2.0.0 • Published 2 years ago

@jochlain/translations v2.0.0

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

Translation module

CI state

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

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

NameTypeDescription
defaultProxy<Translator>If call like a function it calls create static method, else is the Translation class.
DEFAULT_DOMAINstringModule constant
DEFAULT_LOCALEstringModule constant
TranslatorProxy<Translator>The default export of the module
createTranslatorFunctionStatic method create
formatMessageFunctionDefault format method
getCatalogValueFunctionStatic method getCatalogValue
mergeCatalogsFunctionStatic method mergeCatalogs
translateFunctionStatic method translate

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

NameTypeDefaultDescription
catalogsMap<string, CatalogType>[]Translation catalogs
fallbackDomainstring'messages'Default domain used in translate
fallbackLocalestring'en'Default locale used in translate
formatterFormatterType{ format }Formate message with locale and replacements
translationsTranslationType{}Translation catalogs formatted as object

Constructor

Parameters
NameTypeDefault
catalogsMap<string, CatalogType>Empty Map
optionsOptionsType{}
Return value
Type
Translator

Static methods

Parameters
NameTypeDefaultDescription
translationsTranslationType{}Translation catalogs by locale and domains
optionsOptionsType{}Options to set member default value
Return value
TypeDescription
TranslatorA translator instance

Browse catalog to find value assigned to key

Parameters
NameType
catalogCatalogType | undefined
keystring
Return value
TypeDescription
stringThe value in the catalog attached to the key or the key if not found

Format a key from domain and locale.

Parameters
NameType
domainstring
localestring
Return value
TypeDescription
stringThe formatted key

Deep merge many catalogs

Parameters
NameType
target?CatalogType
sourcesCatalogType[]
Return value
TypeDescription
CatalogTypeA catalog with deep merged values

Get domain and locale from key.

Parameters
NameType
keystring
Return value
TypeDescription
string, stringThe domain and the locale

Translate a message from a simple catalog

Parameters
NameTypeDefault
catalog{ locale: string: string }{}
replacements?ReplacementType{}
localestringDEFAULT_LOCALE
formatterFormatterType{ format }
Return value
TypeDescription
stringThe translated message

Methods

Add a catalog to translations map

Parameters
NameTypeDefault
catalogCatalogType{}
localestringthis.fallbackLocale
domainstringthis.fallbackDomain
Return value
TypeDescription
TranslatorThe translator instance to chain methods

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
NameTypeDefault
localestringthis.fallbackLocale
domainstringthis.fallbackDomain
Return value
TypeDescription
CatalogType | undefinedThe catalog of messages attached to domain and locale

Get all domains fill in catalogs map

Return value
TypeDescription
string[]The domains

Get all locales fill in catalogs map

Return value
TypeDescription
string[]The locales

Get message attached to key in catalog attached to domain and locale in catalogs.
See getCatalog and getCatalogValue

Parameters
NameTypeDefault
keystringnone
localestringthis.fallbackLocale
domainstringthis.fallbackDomain
Return value
TypeDescription
stringMessage attached to key or key if not found

Get messages attached to key

Parameters
NameTypeDefault
keystringnone
domainstringthis.fallbackDomain
Return value
TypeDescription
{ locale: string :string }A collection of messages by locale

Set the fallbackDomain member

Parameters
NameTypeDefault
domainstringDEFAULT_DOMAIN
Return value
TypeDescription
TranslatorThe translator instance to chain methods

Set the fallbackLocale member

Parameters
NameTypeDefault
localestringDEFAULT_LOCALE
Return value
TypeDescription
TranslatorThe translator instance to chain methods

Set the formatter member

Parameters
NameTypeDefault
formatterFormatterType{ format }
Return value
TypeDescription
TranslatorThe translator instance to chain methods

Set the formatter member

Parameters
NameTypeDefault
translationsTranslationTypeThe translations to append
Return value
TypeDescription
TranslatorThe translator instance to chain methods

Clone instance with fallbackDomain domain parameter

Parameters
NameType
domainstring
Return value
TypeDescription
TranslatorA new translator instance

Clone instance with formatter

Parameters
NameType
formatterFormatterType
Return value
TypeDescription
TranslatorA new translator instance

Clone instance with fallbackLocale locale parameter

Parameters
NameType
localestring
Return value
TypeDescription
TranslatorA new translator instance

Clone instance with domain, formatter, locale.

Parameters
NameTypeDefault
domainstringthis.fallbackDomain
localestringthis.fallbackLocale
formatterFormatterTypethis.formatter
Return value
TypeDescription
TranslatorA 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;
}
2.0.0

2 years ago

1.4.2

2 years ago

1.4.1

2 years ago

1.4.0

2 years ago

1.3.2

2 years ago

1.3.1

2 years ago

1.3.0

2 years ago

1.2.12

2 years ago

1.2.11

2 years ago

1.2.10

2 years ago

1.2.9

2 years ago

1.2.8

2 years ago

1.2.7

2 years ago

1.2.6

2 years ago

1.2.5

2 years ago

1.2.4

2 years ago

1.2.3

2 years ago

1.2.2

2 years ago

1.2.1

2 years ago

1.2.0

2 years ago

1.1.2

2 years ago

1.1.1

2 years ago

1.1.0

2 years ago

1.0.0

2 years ago