Translations
Package and application level translations made easy.
Installation
- Yarn
- pnpm
- npm
yarn add @boost/translate
pnpm add @boost/translate
npm install @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'schangeLocale
method. - Passed on the command line with the
--locale
option. - Defined a
LANGUAGE
orLANG
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).
- JavaScript
- JSON
- YAML
module.exports = {
welcome: 'Hello {{name}}!',
};
{
"welcome": "Hello {{name}}!"
}
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.
- JavaScript
- JSON
- YAML
module.exports = {
partner: 'Significant other',
partner_male: 'Husband',
partner_female: 'Wife',
};
{
"partner": "Significant other",
"partner_male": "Husband",
"partner_female": "Wife"
}
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.
- JavaScript
- JSON
- YAML
module.exports = {
item: '{{count}} item',
item_plural: '{{count}} items',
};
{
"item": "{{count}} item",
"item_plural": "{{count}} items"
}
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.
- JavaScript
- JSON
- YAML
module.exports = {
dialog: {
confirm: 'Are you sure?',
back: 'Go back!',
},
};
{
"dialog": {
"confirm": "Are you sure?",
"back": "Go back!"
}
}
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.
- JavaScript
- JSON
- YAML
module.exports = {
confirm: 'Are you sure? $t(warning)',
warning: 'This cannot be undone!',
};
{
"confirm": "Are you sure? $t(warning)",
"warning": "This cannot be undone!"
}
confirm: 'Are you sure? $t(warning)'
warning: This cannot be undone!
msg('prompts:confirm'); // Are you sure? This cannot be undone!