Internationalization aka i18n is a concept that refers to the development of user interfaces in different languages. The major benefit of supporting multiple languages is that it expands our reach. But, sometimes we are even required to support a specific language.
For example, government websites are mostly using the national/local language of their country.
Recently, JavaScript has emerged as the most popular language for the web, mobile, desktop, and even game development. So, today we will look at some available options for the translation of UI in JavaScript. Later on, I’ll create a project in a step by step manner to automate the localization of the React app.
There are many popular JavaScript libraries to handle the internationalization of an app. I have listed some of them below.
For the sake of this tutorial, I’ll use LinguiJS. It has a light footprint of 5 kb and is very easy for beginners to get started.
Table of Contents:
In this tutorial, we’ll create a React web app and translate its UI into 3 languages e.g. English, Chinese, and Urdu. In the end, you will be able to easily change the UI language using a simple dropdown menu.
LinguiJS is relatively a new internationalization library. But, it offers some features that are not available in popular competitors like react-intl and i18next.
For example, LinguiJS is packed with Macros that can be used to generate message syntax for components.
I even compiled a brief list of features that makes LinguiJS stand out from its competitors. You can have a look at these features below.
If your app is used in real-time like a chat system or game then LinguiJS can be a great choice. It is designed to be efficient for resource-intensive applications. For example, Caliopen (a unified messaging platform) is actively using LinguiJS.
In case you are already using another localization library but want a more robust solution then I would highly suggest you try LinguiJS. It can be a lightweight alternative for something like react-intl.
In this section, I will help you understand the integration between LinguiJS and React. To make things a bit easier and smooth, we will make use of the Create React App package by Facebook.
To follow along with this tutorial, you must already have Node.js installed. Its latest version is packed with tools like npm and npx. So, you don’t have to install them separately.
Our first step is to install the latest release of the Create React App package on the local machine. To do so, open the console/terminal inside the desired folder on your system. On Windows, a quick way is to type “cmd” in the address bar to open the console window in the current folder.
Now, execute this command.
npx create-react-app linguijs_project
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, type this command in the console and run it.
cd linguijs_project
Now, you will be inside the project folder and ready to install LinguiJS.
Basically, the developers of LinguiJS had divided the whole library into different modules. For now, we are interested in CLI, Macro, Loader, and React. We also need Babel compiler core and babel-bridge to support older versions of Bable.
Let’s install all these dependencies in our React project.
npm i --save-dev @lingui/cli @lingui/macro @lingui/loader @babel/core babel-core@bridge npm i --save @lingui/react
It’s time to set up LinguiJS 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. Here are the contents of this file.
{ "localeDir": "src/locales/", "srcPathDirs": ["src/"], "format": "minimal", "sourceLocale": "en" }
The “src” directory will hold the source files of messages. Whereas the LinguiJS will extract messages from these files and write them inside the language-specific folder. For example, each language (e.g. English, Urdu, French, etc.) will have their own sub-folders inside the src/locales/ folder.
Also, one of the important things is to choose the right format for message translation. Some of the available formats include:
po is recommended by the developers of LinguiJS. But, in my opinion, it’s just a matter of personal preference. Most of us might find the minimal (e.g. JSON) format a bit easier to read than others. So, in this tutorial, I’ll use the minimal format.
Anyway, you can read more about each format here.
At this point, we have to inform the npm about some required scripts. So, let’s update the package.json file that comes with the “Create React App”. It will be located at the root of your React project.
{ "scripts": { "add-locale": "lingui add-locale", "extract": "lingui extract", "compile": "lingui compile" } }
Basically, these scripts will be executed when we run the npm. In other words, LinguiJS need these above-mentioned scripts to work correctly.
One more thing, inside the package.json file you will see the scripts section is already there but containing some other scripts. Don’t worry, they were added by the Create React APP. You just need to copy the “add-locale”, “extract”, and “compile” scripts from the above-mentioned code-snippet and add them manually.
The “add-locale” script will enable us to create different languages for our user interface. For example, execute this code to add English, Chinese, and Urdu locale.
npm run add-locale en zh ur
You may have a look at the supported language codes on the official IANA website.
The Create React App already comes with a basic home page. Its code resides inside /src/App.js. To make this tutorial a bit easier we can simply update this file using our code.
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>Pakistan</Trans></li> <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?
Basically, it helps us to dynamically change the language of the user interface. It makes use of a simple HTML select dropdown.
Here are the full contents of /src/components/LanguageSelector.js file.
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. It is responsible for importing the translations of the selected language and rendering the whole web page.
Here’s the source code for /src/index.js file.
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'));
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 whereas 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.
Anyways, execute this command to extract messages from the source code.
npm run extract
We have created a web page that displays a list of 3 countries (e.g. Pakistan, United States, and Finland). Now, we have to translate the user interface into all supported languages.
Previously, we added the English, Chinese, and Urdu locale in our project. As the default language is English, so LinguiJS is smart enough to automatically fill the English translations.
Here are the contents for /src/locales/en/ messages.json file, in case you want to have a look.
{ "Finland": "Finland", "Name of Countries": "Name of Countries", "Pakistan": "Pakistan", "United States": "United States" }
I have already translated these messages in the Urdu language. So, let’s open /src/locales/ur/messages.json and replace its content with the below code.
{ "Finland": "فن لینڈ", "Name of Countries": "ممالک کا نام", "Pakistan": "پاکستان", "United States": "امریکہ" }
Similarly, open /src/locales/zh/messages.json and update it with the following translations.
{ "Finland": "芬兰", "Name of Countries": "国家名称", "Pakistan": "巴基斯坦", "United States": "美国" }
Just like any other Create React App, we can check out this project by executing this command in the console.
npm start
Today, you just saw how easy it is to integrate LinguiJS with a React app.
The best thing about LinguiJS is that it can automatically manage the translation key-value pairs for all languages. It initializes the message with an empty string to prevent errors in the runtime.
Overall, in my opinion, LinguiJS can be a great alternative for your existing JavaScript projects.