Skip to main content

Translations

API BackendTooling

Package and application level translations made easy.

Installation

yarn add @boost/translate

Environment variables

  • LANGUAGE, LANG - The locale to explicitly use for translation loading.

Translators

Translating messages is based around the concept of a "translator", which is an implementation around i18next that provides file system based resources bundles, in-memory caching, sane default configuration, automatic locale detection, plus all the features found in i18next.

The translator is designed for Node.js, primarily for package level translations, command line scripts, developer tools, and even applications, but not for the web or the browser.

To begin, instantiate a translator with createTranslator with a list of namespaces to load, a list of resource paths to locate bundles in, and an optional TranslatorOptions object. This returns a function that can be used for loading and retrieving translations.

import { createTranslator } from '@boost/translate';

const msg = await createTranslator(['common', 'errors'], '../path/to/resources');

The first namespace provided becomes the "default namespace".

The returned translator function, aptly named msg above, should be used anywhere that a message string should be translated. It accepts translation key(s) as the 1st argument, an optional object for interpolation as the 2nd argument, and an optional MessageOptions object as the 3rd argument.

msg('common:welcome', { name: 'Boost' }); // Hello Boost!

Once the translator has been created, associated resource files must also be created.

Locale detection

To load resource bundles, we require a locale. A locale is code based representation of a human language and is based on IETF language tags. Boost locales align with ISO 639, with the language being lowercased (en), and the optional region being uppercased and separated by a dash (en-US).

The locale is automatically detected from the environment using the following lookup strategies, one by one, until a valid locale is found.

  • Defined by the locale option or through the translator's changeLocale method.
  • Passed on the command line with the --locale option.
  • Defined a LANGUAGE or LANG environment variable.
  • Inherited from the operating system.

Resources

A resource bundle is a per locale collection of namespaced translation files, located within a resource path passed to createTranslator.

An example file structure of a resources folder, with multiple locale bundles, would look something like the following.

res/
├── en/
│ ├── common.yaml
│ ├── errors.yaml
│ └── validations.yaml
├── en-GB/
│ ├── common.yaml
│ └── validations.yaml
└── fr/
└── ...

Namespaces

A namespace is a file that contains translations, is located within a locale bundle, and can be written in JavaScript, JSON, or YAML (default and preferred).

res/en/common.js
module.exports = {
welcome: 'Hello {{name}}!',
};

When retrieving messages with the translator function, the namespace can be targeted by prefixing the key and separating with a colon.

msg('common:welcome'); // Hello {{name}}!

Translations

A translation is a message string (also known as copy) identified by a unique key (per namespace). They can be retrieved using the translator function (msg above).

Translations inherit all functionality from i18next, so I suggest reading up on the essentials.

Context

Contextual messages allow for different messages based on contextual data, through the combination of multiple keys and the context option.

res/en/user.js
module.exports = {
partner: 'Significant other',
partner_male: 'Husband',
partner_female: 'Wife',
};
msg('user:partner', {}, { context: 'male' }); // Husband
msg('user:partner', {}, { context: 'female' }); // Wife

Plurals

Pluralizing messages is easily solved through the combination of multiple keys and the count option.

res/en/cart.js
module.exports = {
item: '{{count}} item',
item_plural: '{{count}} items',
};
msg('cart:item', {}, { count: 1 }); // 1 item
msg('cart:item', {}, { count: 10 }); // 10 items

Nesting

There are 2 forms of nesting. The first is nested keys within a namespace file, and they can be accessed using dot notation.

res/en/prompts.js
module.exports = {
dialog: {
confirm: 'Are you sure?',
back: 'Go back!',
},
};
msg('prompts:dialog.back'); // Go back!

The second form is nested messages through a special $t() syntax.

res/en/prompts.js
module.exports = {
confirm: 'Are you sure? $t(warning)',
warning: 'This cannot be undone!',
};
msg('prompts:confirm'); // Are you sure? This cannot be undone!