Overview
Internationalization (i18n) and localization is critical in software development to expand the reach of your application. Sometimes, it’s even required to create an app with a specific language built into it. For instance, most government website pages are translated to the local and national language of their own country.
With the majority of websites relying on JavaScript, it’s no wonder that there are many popular JavaScript libraries set up to handle the internationalization of applications. Some of the most well-known libraries are:
For the purpose of this article, I’ll demonstrate how to use Lingui.js. This is a powerful library that not only handles internationalization in native JavaScript applications, but also in React, one of the most well-known JavaScript libraries. Lingui.js has a light size of only 5KB and is very easy for beginners to get started with.
Introducing Lingui.js
Lingui.js is a relatively new internationalization library, but it offers some features that aren’t available in popular competitor libraries like react-intl and i18next. For example, Lingui.js is packed with macros that can be used to generate message syntax for components. Some other prominent features of Lingui.js are:
- Optimized for performance (only 5KB in size)
- Easy to integrate with React and React Native applications
- Its community is active on GitHub as well as Spectrum
- Lingui.js provides thorough documentation with step-by-step tutorials and API references
- It uses ICU MessageFormat that makes UI translations readable
- Offers support for rich-text, which is missing in many competing libraries
- Lingui.js has its own CLI to streamline the whole process of translating the user interface
In general, Lingui.js can be integrated in any type of static application. And if you have a real-time application like a chat system or online game, then Lingui.js can be a great choice because it’s designed to be efficient for resource-intensive applications. For example, Caliopen (a unified messaging platform) is actively using Lingui.js.
In this article, we’ll work on a sample project to integrate Lingui.js within a React application. To make it easier, we will use the create-react-app package.
Prerequisites
To follow along with this tutorial, you must already have Node.js installed on your system. Its latest version is packaged with tools like npm and npx so you don’t have to install them separately.
Getting started
Our first step is to install the latest release of the create-react-app package on our local machine. To do so, open the console/terminal inside the desired folder on your system. After that, execute this command:
npx create-react-app my-app
It will take some time to install all the dependencies and set up a basic React app, so please be patient. After the setup is complete, run this command:
cd my-app
Now, you’ll be inside the project folder and ready to install Lingui.js.
Essentially, the developers of Lingui.js have divided the whole library into different modules. For now, we are interested in CLI, macro, and React. We also need Babel compiler core and babel-bridge to support older versions of Babel.
Let’s install all these dependencies in our React project:
npm i --save-dev @lingui/cli @lingui/macro @babel/core [email protected] npm i --save @lingui/react
Lingui.js configuration
It’s time to set up Lingui.js by informing it about the location of the messages file, format to use, and the default UI language. To do so, you have to create a file named .linguirc
inside the root of your project. The content of this file should look like this:
{ "localeDir": "src/locales/", "srcPathDirs": ["src/"], "format": "minimal", "sourceLocale": "en" }
The src
directory will hold the source files of messages, whereas the Lingui.js will extract messages from these files and write them inside the language-specific folder. Each language (e.g., English, Urdu, Chinese, etc.,) will have their own subfolders inside the src/locales/
folder.
Also, it’s important to choose the right format for message translation. Some of the available formats include:
lingui
: Each message is returned in a pre-defined format like thisminimal
: Each message is returned in a simple JSON format like thispo
: Each message is returned as a file
Lingui.js recommends the po
format. In general, it’s a matter of personal preference and the setup of your current application. Most of us might find the minimal
(i.e., JSON) format easier to read than others. So, in this tutorial, we’ll use the minimal
format. To learn more about each format, refer to this section of the docs.
Update package.json
At this point, we have to add some scripts in package.json
.
{ "scripts": { "add-locale": "lingui add-locale", "extract": "lingui extract", "compile": "lingui compile" } }
With the above commands, we will be able to generate new locales as well as compile and extract current locales in our application.
Add user interface languages
Executing the add-locale
script will enable us to create different languages for our user interface:
npm run add-locale en zh ur
To do so, you may have a look at the supported language codes on the official IANA website.
Create a webpage
The CRA app already comes with a basic homepage. You can find this file under /src/App.js
. We will modify this file like this:
import React, { useState, useEffect } from 'react'; import { Trans } from '@lingui/macro'; import LanguageSelector from './components/LanguageSelector'; function App({ language, onLanguageChange }) { return ( <div className="App"> <LanguageSelector language={language} onChangeLangage={onLanguageChange} /> <header className="App-header"> <h1><Trans>Name of Countries</Trans></h1> </header> <ul> <li><Trans>United States</Trans></li> <li><Trans>Finland</Trans></li> </ul> </div> ); } export default App;
Did you notice that we are using a LanguageSelector
component?
This helps us to dynamically change the language of the user interface. It makes use of a simple HTML select dropdown. This is what this component looks like:
import React from 'react'; function LanguageSelector({ language, onChangeLangage }) { function handleChange(event) { event.preventDefault(); onChangeLangage(event.target.value); } return ( <div className="select"> <select onChange={handleChange} value={language}> <option value="en">English</option> <option value="ur">Urdu</option> <option value="zh">Chinese</option> </select> </div> ); } export default LanguageSelector;
Finally, we need to update our main /src/index.js
file. This file is responsible for importing the translations of the selected language and rendering the whole webpage.
import React, { useState } from 'react'; import ReactDOM from 'react-dom'; import { I18nProvider } from '@lingui/react'; import App from './App'; async function loadMessages(language) { return await import(`@lingui/loader!./locales/${language}/messages.json`); } function LocalizedApp() { const [catalogs, setCatalogs] = useState({}) const [language, setLanguage] = useState('en'); async function handleLanguageChange(language) { const newCatalog = await loadMessages(language); const newCatalogs = { ...catalogs, [language]: newCatalog }; setCatalogs(newCatalogs); setLanguage(language); } return ( <I18nProvider language={language} catalogs={catalogs}> <App language={language} onLanguageChange={handleLanguageChange} /> </I18nProvider> ); } ReactDOM.render(<LocalizedApp />, document.getElementById('root'));
Extract messages from source code
Now that we have wrapped some text inside <Trans> … </Trans>
macro, it’s time to extract all those messages from the source code and then make key-value pairs inside each locale. The key will work as an ID where the value will be its translation in a specific language.
In the English language, the key and value pair will remain the same. But we have to change the values in other languages. By default, their value will be empty strings and we have to add the translations manually.
Execute the npm run extract
command to extract messages from the source code.
User interface translation
We have created a webpage that displays a list of two countries: Finland and the United States. Now, we have to translate the user interface into all supported languages.
Previously, we added the English, Chinese, and Urdu locale to our project. The default language is English, and Lingui.js is smart enough to automatically fill the English translations:
{ "Finland": "Finland", "Name of Countries": "Name of Countries", "United States": "United States" }
Now, open /src/locales/ur/messages.json
and replace its content with the below code.
{ "Finland": "فن لینڈ", "Name of Countries": "ممالک کا نام", "United States": "امریکہ" }
Similarly, open /src/locales/zh/messages.json
and update it with the following translations.
{ "Finland": "芬兰", "Name of Countries": "国家名称", "United States": "美国" }
At this point, we are ready to compile the translations so that we can use them in our application. To do so, execute the compile command npm run compile
.
Run the project
To run the application, run the command npm start
.
Conclusion
Together, we learned how easy it is to integrate Lingui.js with a React app and add internationalization capabilities to your application.
One of the best perks of Lingui.js is that it can automatically manage the translation key-value pairs for all languages. This initializes the message with an empty string to prevent errors in the runtime. After that, you’ll simply add specific translations for different key-values and see your application in a new language.
Get setup with LogRocket's modern React error tracking in minutes:
- Visit https://logrocket.com/signup/ to get an app ID.
- Install LogRocket via NPM or script tag.
LogRocket.init()
must be called client-side, not server-side. - (Optional) Install plugins for deeper integrations with your stack:
- Redux middleware
- ngrx middleware
- Vuex plugin
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>