Type-checked and intuitive way to internationalize applications in Javascript and ReactJS using ICU message format.
Internationalization is the design and development of a product, application or document content that enables easy localization for target audiences that vary in culture, region, or language.
Building applications and products for international audiences involves internationalization (i.e: preparing app for translation) and localization (i.e: adoption of application to meet language and cultural requirements). Lingui provides tools to make i18n of JS applications using ICU message format as easy as possible.
TL;DR: Compare js-lingui with react-intl and react-i18next
Internationalization consists of three steps:
- Specify parts for localization - This is required even for monolingual apps, because it allows to use pluralization, polite forms, date/time formatting, etc.
- Build a message catalog - Message catalogs are passed to translators
- Load translated messages and switch application language
The first part of i18n process is wrapping all texts with component or function, which replaces source text with translation during runtime. js-lingui
uses ICU Message Format which allows using of variables, plural forms and date/number formats.
First install babel preset for using js-lingui
in Vanilla JS apps and add it
to your babel config:
yarn add --dev babel-preset-lingui-js
# or
npm install --save-dev babel-preset-lingui-js
lingui-js
provides i18n.t
template tag for translation, i18n.plural
,
i18n.select
, i18n.selectOrdinal
methods for pluralization and custom forms:
import i18n from 'lingui-i18n'
i18n.t`January`
const name = "Fred"
i18n.t`Hello, my name is ${name}`
i18n.plural({
value: count,
one: `# Book`,
other: `# Books`
})
First install babel preset for using js-lingui
in React apps and add it to your
babel config:
yarn add --dev babel-preset-lingui-react
# or
npm install --save-dev babel-preset-lingui-react
lingui-react
provides several component for React applications: Trans
is the main component
for general translation, Plural
and Select
for pluralization and custom
forms (e.g: polite forms):
import React from 'react'
import { Trans, Plural } from 'lingui-react'
const App = ({ name, count }) => (
<div>
// Static text
<Trans>January</Trans>
// Variables
<Trans>Hello, my name is {name}</Trans>
// Components
<Trans>See the <a href="/more">description</a> below.</Trans>
// Plurals
<Plural
value={count}
zero={<strong>No books</strong>}
one="# book"
other="# books"
/>
</div>
)
Sometimes it's necessary to translate also a text attributes, which don't accept
React components. lingui-react
has WithI18n
decorator, which injects i18n
object from lingui-i18n
.
import React from 'react'
import { WithI18n } from 'lingui-react'
// Translating text attributes
const LinkWithTooltip = WithI18n()(({ articleName, i18n }) => (
<a
href="/more"
title={i18n.t`Link to ${articleName}`}
>
<Trans>Link</Trans>
</a>
))
At this point, application is available only in one language (English). When no translations are available the default texts are used.
๐ก See tutorial about i18n in React
Translators are working with message catalogs which are mapping of messages from source to target language. The simplest form is a dictionary, where key is source message and value is translated one:
const fr = {
"January": "Janvier",
"Hello, my name is {name}": "Salut, je m'appelle {name}",
"See the <0>description</0> below.": "...",
"{count, plural, zero {<0>No books</0>} one {# book} other {# books}": "..."
}
The key is also called message ID. It must be unique across application. It should also include all parameters so translators can change the order of words and parameters if required.
js-lingui
provides a CLI for building and compiling message catalogs:
npm install --save-dev lingui-cli
# or
yarn add --dev lingui-cli
# add directories for target languages
lingui add-locale en fr
# extract messages from source to message catalogs
lingui extract
Target directory for locales is configured in package.json
:
{
"lingui": {
"localeDir": "./locale"
}
}
Under the hood, there're three babel plugins responsible for creating message catalogs:
-
babel-plugin-lingui-transform-js
This plugin transforms methods and template tag from
lingui-i18n
into ICU message format which becomes message ID.i18n.t`Hello, my name is ${name}` /* becomes this entry in source language file: * { * "Hello, my name is {name}": "" * } */
-
babel-plugin-lingui-transform-react
This plugin transforms components from
lingui-react
(e.g:Trans
) into ICU message format which becomes message ID.Note: It's also possible to use custom message IDs. Simply pass
id
attribute toTrans
component and children's going to be used as a default message only.<Trans id="month.january">January</Trans> /* becomes this entry in source language file: * { * "month.january": "January", * ... * } */
-
babel-plugin-lingui-extract-messages
- It extracts all message IDs into temporary catalogs, one catalog per file.
The result is one message catalog per language (e.g: locale/fr/messages.json
).
Translated message catalogs must be loaded back to application. The process depends on type of application.
lingui-i18n
uses .load(messages)
method to load message catalog and
.use(language)
to select a language:
import i18n from 'lingui-i18n'
import messagesEn from './locales/en/messages.json'
import messagesFr from './locales/fr/messages.json'
// load message catalogs
i18n.load({
en: messagesEn,
fr: messagesFr
})
// activate english language
i18n.activate('en')
lingui-react
provides ProvideI18n
component which receives active language
and messages for that language:
import React from 'react'
import { ProvideI18n } from 'lingui-react'
import App from './App'
import messages from './locales/fr/messages.json'
render(
<ProvideI18n language="fr" messages={{ fr: messages }}>
<App />
</ProvideI18n>,
document.getElementById('app')
)
When we render messages from the first part, we get them translated in French:
<Trans>January</Trans>
// becomes: Janvier
const name = "Fred"
<Trans>Hello, my name is {name}</Trans>
// becomes: Salut, je m'appelle Fred
<Trans>See the <a href="/more">description</a> below.</Trans>
// becomes: Voir <a href="/more">la description</a> ci-dessous
const count = 42
<Plural
value={count}
zero={<strong>No books</strong>}
one="# book"
other="# books"
/>
// becomes: 42 livres
See wiki for more info or example-usecase for detailed example.
lingui-i18n
Docs
Functions for I18n in Javascript.
lingui-react
Docs
Components for I18n in React.
lingui-cli
Docs
Command line interface for working with message catalogs.
babel-preset-lingui-js
Docs
babel-preset-lingui-react
Docs
babel-plugin-lingui-transform-js
Docs
Transform function from lingui-i18n
into ICU message format.
babel-plugin-lingui-transform-react
Docs
Transform components from lingui-react
into ICU message format.
Extract all messages for translation to external files.