Kasra Khosravi Chief Problem Solver @ MyToolBox.Dev

How to set up internationalization in React using Lingui.js

5 min read 1550

Internationalization React Lingui

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.

We made a custom demo for .
No really. Click here to check it out.

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 babel-core@bridge
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 this
  • minimal: Each message is returned in a simple JSON format like this
  • po: 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.

You come here a lot! We hope you enjoy the LogRocket blog. Could you fill out a survey about what you want us to write about?

    Which of these topics are you most interested in?
    ReactVueAngularNew frameworks
    Do you spend a lot of time reproducing errors in your apps?
    YesNo
    Which, if any, do you think would help you reproduce errors more effectively?
    A solution to see exactly what a user did to trigger an errorProactive monitoring which automatically surfaces issuesHaving a support team triage issues more efficiently
    Thanks! Interested to hear how LogRocket can improve your bug fixing processes? Leave your email:

    Full visibility into production React apps

    Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

    LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

    The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

    Modernize how you debug your React apps — .

    Kasra Khosravi Chief Problem Solver @ MyToolBox.Dev

    Leave a Reply