How to translate your React app, with i18next and some Python
I work on an e-commerce website that serves customers in 5 languages (English, French, Danish, Swedish, and Dutch). The main gist of the website is built with a PHP framework called Symfony. However, some areas which require better interactivity are coded in React. How do we go about the localization or internationalization (a.k.a. i18n ) of these React apps?
1. Start with the right tools for the translators
The first step is to decide on a tool that works for the different users that will be using it. Developers and translators have very different needs and skill sets. Originally we started with Localise (which is very cheap) and then when we had more means we switched to Lokalize, which is a lot more powerful and offers a much better experience for both developers and translators. Both tools allow us to translate across any language pair (we need to be able to translate from French to English, and then from English to the Scandinavian languages). More importantly, both tools offer an API that allows us to export all the data with a given tag (e.g., "react") to either YAML or JSON format, so we've integrated that into our build process (using a Python script to download the translation contents into the right place)
2. Start with the right npm library
To integrate the translated text into our React app(s), we needed a library that supported :
- String interpolation: i.e. going from Hello {{name}} to Hello Bob
- Plurals: Injecting a variable like "count" into the translation function which then provides the translated version of the text
- A format that our translation tool exports (i.e. JSON or Yaml)
- Hooks!
We settled on react-i18next with provides a React integration for the i18next library.
3. Set up i18next in React
The initial installation is as simple as :
npm install react-i18next i18next --save
or
yarn add react-i18next i18next
Once that is done, the library needs to be configured. For that purpose, we have a file called i18n.ts at the root of our src/ folder.
This file has the following structure :
// src/i18n.ts
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
let en = require('./loc/loc.en.json');
let fr = require('./loc/loc.fr.json');
const resources = { en, fr };
i18n
.use(initReactI18next) // passes i18n down to react-i18next
.init({
resources,
lng: 'en', // start with english
fallbackLng: 'en', // default to english if key is missing
debug: false, // this is probably the default value
// because of how our PHP i18n is configured
// we namespace with react. You might want to adapt this
defaultNS: 'react',
keySeparator: false, // we don't use "messages.welcome" format
interpolation: {
escapeValue: false // react already protects vs xss
}
});
export default i18n;
You can of course access translations in other ways such as from an HTTP backend (using the i18next-http-backend library);
We then import this in our App.tsx file:
// src/App.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import './i18n';
// etc...
Once that is done, we're good to go to start using our library!
4. Set the language
The library exposes a useTranslation hook that we retrieve with :
import { useTranslation } from 'react-i18next';
The hook provides two things. The first is an instance of the i18n library, the second is the translation function itself.
const {t, i18} = useTranslation();
The first step is to set the current language for the i18next library. In our case, as the React app is integrated into a PHP framework (namely, Symfony), the language is already determined and gets passed down in the props :
useEffect(() => {
i18n.changeLanguage(props.lang);
}, [props.lang]);
Once again, there are different ways of doing this, one common way of doing so would be to detect and inject the language (with the "i18next-browser-languagedetector" library), then show the user an interface to switch languages.
5. Download the Loc (using python) from Lokalise
The following Python script connects to the Lokalise API and downloads the localized text in JSON format. We use the "dotenv" library to retrieve configuration (like the API key !) from a .env file
If you are using Loco / localise.biz the following script should get you started at getting the work done :
Key Takeways
Now that we are all set up, translating the app is a breeze: anywhere we have text, we replace it with a call to the translator function. So this:
<button>Press me!</button>
Becomes this :
<button>{t('press_me')</button>
(And we then use 'press_me' as the key for "Press me!" in English and "Appuyez-Moi" in French.
And there we are, good to go. Or as the French say: "Voila, c'est parti !"
We help you better understand software development. Receive the latest blog posts, videos, insights and news from the frontlines of web development