i18n With React Intl and SimpleLocalize
React Intl is a popular internationalization library. This article demonstrates how to set it up in a new React project and how to manage translations with SimpleLocalize.
Create React App
yarn create react-app react-intl-tutorial --template typescript
Create a React
app with Typescript
support.
Install react-intl
yarn add react-intl
Automatic Message ID Generation
We need an ID to identify the message to be translated. While explicit ID would lead to potential collision, we can use babel-plugin-formatjs
to generate the ID automatically.
yarn add -D babel-plugin-formatjs
We then need to add the plugin to Babel configuration. But we cannot do this with the default create-react-app
setup. Run react eject
to expose the Babel configuration. Open webpack.config.js
and add the following configure to babel-loader
:
[
"formatjs",
{
"idInterpolationPattern": "[sha512:contenthash:base64:6]",
"ast": true
}
]
Refer to this file.
Add IntlProvider
react-intl
provides locale info and translations via IntlProvider
component.
ReactDOM.render(
<React.StrictMode>
<IntlProvider locale={'en'} defaultLocale="en" messages=>
<App />
</IntlProvider>
</React.StrictMode>,
document.getElementById("root")
);
locale
and messages
are hardcoded currently. We will fix this when we have the translations ready.
useIntl hook
We can now use useIntl
hook to get translations.
function App() {
const { formatMessage } = useIntl();
return (
<div className="App">
<p>
{formatMessage({
defaultMessage: "Hello everyone",
})}
</p>
</div>
);
}
Message Extraction
The app has defined a simple message. @formatjs/cli
provides an extract
command to scan through the application and gather all messages to be translated into a file. The format can be customized depending on the Translation Management System you use. For more details, refer to this document. We will use SimpleLocalize
which formatjs
provides a simple
format for it.
Install @formatjs/cli
:
yarn add -D @formatjs/cli
Add "extract": "formatjs extract"
to scripts
in package.json
.
Then run the command to extract the messages:
yarn extract src/**/*.tsx --out-file SimpleLocalize/en.json --format simple
Upload default messages to SimpleLocalize
SimpleLocalize
allows us to upload default messages via Web UI, Command Line, or API.
curl -s https://get.simplelocalize.io/install | bash
simplelocalize upload \
--apiKey PROJECT_API_KEY \
--uploadPath SimpleLocalize/en.json \
--uploadFormat single-language-json \
--languageKey en
PS: The Command Line Tool doesn’t support Windows.
Download translations
When translation finishes, SimpleLocalize
allows us to download translations via the Command Line Tool as well.
simplelocalize download \
--apiKey PROJECT_API_KEY \
--downloadPath SimpleLocalize/{lang}.json \
--downloadFormat single-language-json
Message Compilation
When translations are downloaded, use @formatjs/cli
to compile the messages to the format react-intl
requires.
Add "compile": "formatjs compile"
to scripts
in package.json
. Then run the command to compile the messages:
for translationFile in SimpleLocalize/*.json
do
yarn compile $translationFile --ast --out-file src/lang/$(basename -- $translationFile) --format simple
done
Consume translations
We can now load translations into the application.
const locale = 'fr';
import(`./lang/${locale}.json`).then(messages => ReactDOM.render(
<React.StrictMode>
<IntlProvider locale={locale} defaultLocale="en" messages={messages}>
<App />
</IntlProvider>
</React.StrictMode>,
document.getElementById("root")
));
Github Actions
We can use Github Actions to automate the message management flow.
name: Upload Translation Keys to SimpleLocalize
on:
workflow_dispatch:
jobs:
Upload-Translation-Keys:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: "14.x"
- name: Extract Translation Keys
run: |
yarn install
yarn extract src/**/*.tsx --out-file SimpleLocalize/en.json --format simple
- name: Upload Translation Keys
run: |
curl -s https://get.simplelocalize.io/install | bash
simplelocalize upload \
--apiKey $ \
--uploadPath SimpleLocalize/en.json \
--uploadFormat single-language-json \
--languageKey en
And
name: Download Translations From SimpleLocalize
on:
workflow_dispatch:
jobs:
Download-Translations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: "14.x"
- name: Download Translations
run: |
curl -s https://get.simplelocalize.io/install | bash
simplelocalize download \
--apiKey $ \
--downloadPath SimpleLocalize/{lang}.json \
--downloadFormat single-language-json
- name: Compile Translations
run: |
yarn install
for translationFile in SimpleLocalize/*.json
do
yarn compile $translationFile --ast --out-file src/lang/$(basename -- $translationFile) --format simple
done
- name: Commit translation updates
run: |
git config user.email "$"
git config user.name "$"
git add src
git commit -m "Update translations" || echo "No translation updates."
git push
ICU Message Syntax
FormatJS
supports robust ICU syntax. Refer to this document for more details. It also provides a Linter to help you write the syntax correctly.