Using Transifex Native to add internationalization (i18n) to a React app
Tags: react, javascript, i18n, webdev
Published: 2022-05-09 16:36:57

Internationalization in an application provides multi-language support for a target set of app users that vary in region and language. Building such an application can be challenging, but there are many solutions available to add support for multiple languages in React ecosystem. One of these solutions is the [Transifex](https://www.transifex.com/). It allows a cloud service that serves translation phrases when implementing internationalization and localization in your React applications.

The translations are fetched continuously over the air (OTA) to the application. This way, you get to keep the translation as a separate layer from the application's development phase.

In this tutorial, let's learn how to integrate Transifex Native in a React application to use internationalization. We will walk you through setting up a new app on Transifex and the implementation steps required to integrate its SDK in a React application. After integrating the SDK, we will see how to create and manage translatable content that can be managed and updated on the cloud.

## Prerequisites

To follow this tutorial, you will need:

- [Transifex account](https://www.transifex.com/)
- [Node.js](https://nodejs.org/) `14.x.x` or above installed
- A basic understanding of [React](https://reactjs.org/)

You will find the complete code for the tutorial in this [GitHub repository](https://github.com/amandeepmittal/transifex-react-app-demo).

## Setting up a React app

Let's start by creating a React app. Open up a terminal window and create a new React project using the `create-react-app` toolchain.

```shell
npx create-react-app transifex-react

# after the project directory is created
# navigate inside it
cd transifex-react
```

After navigating inside the project directory, you will come across the familiar `src` directory, part of the pre-defined folder structure that `create-react-app` creates. This directory contains the source code of your React app. Let's build a general login page in the `src/App.js` file as an example.

The login page will be a simple form with a title and a subtitle that describes the form, email and password input fields, and a button. The focus of the example is to keep it minimal and learn how to use Transifex Native SDK. However, the example will conclude when the app user fills in the details in the form and presses the sign-in button. After the button is pressed, an alert box is shown.

Open up the `App.js` file and add the following code snippet:

```js
import './App.css';

function App() {
  const handleSubmit = event => {
    event.preventDefault();
    alert('Your form is submitted!');
  };

  return (
    <div className="app">
      <div className="form">
        <h1>Login form</h1>
        <p className="subtitle">Please enter your credentials to proceed.</p>
        <form onSubmit={handleSubmit}>
          <div className="input-container">
            <label>Email</label>
            <input type="text" name="email" required />
          </div>
          <div className="input-container">
            <label>Password</label>
            <input type="password" name="password" required />
          </div>
          <button className="button-container" type="submit">
            <p className="button-text">Sign in</p>
          </button>
        </form>
      </div>
    </div>
  );
}

export default App;
```

Also, add the following CSS styles to the `App.css` file:

```css
.app {
  display: flex;
  margin-top: 20px;
  justify-content: center;
  height: 100vh;
  background-color: #fff;
}

.subtitle {
  padding-bottom: 20px;
}

.button-container {
  display: flex;
  justify-content: center;
  align-items: center;
  border-radius: 8px;
  background: #01d28e;
  width: 100%;
  height: 40px;
  margin-top: 20px;
  padding: 10px 20px;
}

.button-text {
  color: #fff;
  font-size: 18px;
  font-weight: bold;
}

.input-container {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 10px;
}
```

From the terminal window, run the `npm start` command to see the login page in action. You will see the following output in the browser window:

![ss1](https://i.imgur.com/qiOAYXu.png)

## Installing Transifex Native SDK

To use Transifex Native, the first step is to install the [Transifex JavaScript SDK](https://developers.transifex.com/docs/javascript-sdk). It also provides packages for different frameworks. Since the example app is built using React, also install the Transifex SDK extension for React.

To do so, run the following command from the project directory:

```shell
npm install @transifex/native @transifex/cli @transifex/react --save
```

Briefly, let's take a look at what each package does:

- `@transifex/native` is the core library package
- `@transifex/cli` is the command line interface package. It collects all the localization phrases from the React app and pushes them to the Transifex Native project. It is enabled by adding a custom npm script to the `package.json` file
- `@transifex/react` is a library extension that provides components and hooks to internationalize phrases in the React app

Transifex Native SDK retrieves translation phrases using a custom CDN called [Content Delivery Service (CDS)](https://developers.transifex.com/docs/content-delivery-service). As a developer, you have to option to use Transifex's hosted service or opt for self-hosting.

## Creating a Transifex Native project

After signing in to the Transifex account, start by creating a new project.

On the **Add a new project** page:

- Add the name of the project
- For **Choose project type**, select the **Native** option since the example app is using the JavaScript SDK. Transifex also offers File-based and Live project type options
- For **Assign to team**, select **Create a new team** for this project. You can also select **Assign this project to an existing team** and then select the team from the dropdown menu if you already have a team
- Under **Select languages**, set the source of the language to English. Under Target languages, select as many languages you want to provide translation support in your application. For the example app, select Spanish and French

![ss2](https://i.imgur.com/JGSDu1k.png)

After adding these details, click the **Create project** button to create a new Transifex project. You will see the following dashboard screen in the browser window:

![ss3](https://i.imgur.com/YeXFxnE.png)

To connect the Transifex Native SDK with your account, you need to add your Transifex account credentials to the project. Then, click **Resources** from the side menu on the dashboard. You will see the following screen:

![ss4](https://i.imgur.com/x1MgrzK.png)

Click the button **Generate Native Credentials now** at the bottom of the page. It will open a popup that will display the `token` and `secret` keys.

![ss5](https://i.imgur.com/d7M2sLF.png)

The `token` is required to initialize the Transifex Native SDK in the React app. Both `token` and `secret` are used to push translation phrases from the React app to the Transifex service.

You will need both of these keys in your React app. Create a `.env` file in the React app and paste them as shown in the following code snippet:

```shell
REACT_APP_TRANSIFEX_TOKEN=XXXX
REACT_APP_TRANSIFEX_SECRET=XXXX
```

The `X`'s represent the actual key in the above code snippet. After copying the keys to the `.env` file, you can close the popup.

## Initializing the Transifex Native SDK in the React app

To initialize the Transifex Native SDK, you need to import the `@transifex/native` package in your React app. In the `App.js` file, add the following import statement:

```js
// rest of the import statements

import { tx } from '@transifex/native';
```

The `tx` has a `init` method that is used to initialize the Transifex Native SDK. It requires the value of the token to be passed. For example, add the following code snippet before the `App` function:

```js
tx.init({
  token: process.env.REACT_APP_TRANSIFEX_TOKEN,
});
```

If you are using the latest version of the `create-react-app`, you can directly read the value of environment variables defined inside the `.env` file using the prefix `process.env.REACT_APP_`.

## Using Transifex in the React app

Transifex React extension package provides a `T` component that will translate the text passed as a prop. It also provides `LanguagePicker` that will display a dropdown menu with the enabled languages in your Transifex project.

The `T` component has a required prop called `_str` that accepts the translation phase as a string value. After the header and the subtitle, let's also add the `LanguagePicker` component to show the dropdown menu to display language options.

Modify the JSX in the `App` component as shown below:

```jsx
return (
  <div className="app">
    <div className="form">
      <h1>
        <T _str="Login form" />
      </h1>
      <p className="subtitle">
        <T _str="Please enter your credentials to proceed." />
      </p>
      <div className="picker">
        <p className="picker-title">
          <T _str="Select the language: " />
        </p>{' '}
        <LanguagePicker />
      </div>
      <form onSubmit={handleSubmit}>
        <div className="input-container">
          <label>
            <T _str="Email" />
          </label>
          <input type="text" name="email" required />
        </div>
        <div className="input-container">
          <label>
            <T _str="Password" />
          </label>
          <input type="password" name="password" required />
        </div>
        <button className="button-container" type="submit">
          <p className="button-text">
            <T _str="Sign in" />
          </p>
        </button>
      </form>
    </div>
  </div>
);
```

In the above code snippet, notice that the `T` component is wrapped by the other HTML and React components to apply custom styling previously defined.

There are [additional props](https://developers.transifex.com/docs/react-sdk#t-component) available on the `T` component.

Modify the `App.css` file and the following code snippet to apply some styles for the text preceding the `LanguagePicker` component.

```css
/* After the rest of the code */

.picker {
  display: flex;
  margin-top: 10px;
  padding: 10px;
  flex-direction: row;
}

.picker-title {
  font-size: 18px;
  font-weight: bold;
  margin-right: 10px;
}
```

If you have been running the dev server, you will need to restart the server to see the changes. Re-run the command `npm start` from the terminal window and go back to the browser window to see the changes:

![ss6](https://i.imgur.com/DSMqXSn.gif)

In the above screenshot, notice that the `LanguagePicker` displays the languages that are enabled in the Transifex project (such as English, the source language, and target languages, Spanish and French).

## Syncing translation strings with Transifex

The next step to enable translation is to sync the translation strings added in the previous section using the `T` component with the Transifex project. After that, it will use the Transifex Native CLI to push collect all the translation phrases from the React app and push them to the Transifex project.

To do so, let's define a custom npm script in the `package.json` file:

```json
{
  // ...
  "scripts": {
    "sync-translations": "./node_modules/.bin/txjs-cli push src/ --token=<TOKEN> --secret=<SECRET>"
  }
}
```

In the above snippet, replace the `<TOKEN>` and `<SECRET>` with the actual values of the `token` and `secret` keys.

Next, run this npm script from the terminal window to push the translation phases.

```shell
npm run sync-translations
```

To verify that the translation strings are pushed to the Transifex project, go to the Transifex project in the browser window. You will see how the number of source strings increased (depending on how many translation strings were added in the React app).

![ss7](https://i.imgur.com/xKplbRC.png)

As shown above, the current React app has six phrases that can be translated.

## Adding translations

After pushing the translation strings, you can add the translation for each phrase. Then, from the dashboard screen, click the button **Translate** button. This will open a new page to the interface where you can manually add the translation for each phrase.

First, it will ask to select the source language. Choose _French_ from the dropdown menu.

![ss8](https://i.imgur.com/ET7Ja6G.png)

After selecting the language, all the strings are shown on the left-hand side. Select each of the strings, and then on the right-hand side, add the appropriate translation for each string depending on the target language. Click **Save Translation** to save the translated string.

![ss9](https://i.imgur.com/whsFNwf.png)

Repeat this for all the phrases and both languages. After adding all the translations, the status of each phrase changes from gray to green. It is used to indicate that the translation of the specific phase is active and is translated.

![ss10](https://i.imgur.com/i2vEHMs.png)

## Running the React app

Let's go back to the React app to see the translation in action. Since the syncing between Transifex and the React app is done by a hosted CDN-like service, there is no requirement to restart the server.

![ss11](https://i.imgur.com/fOrpwnj.gif)

## Exploring the Transifex React package

[Transifex React package](https://developers.transifex.com/docs/react-sdk) also provides other utilities in the form of hooks.

For example, you can use the `useLanguages` hook to asynchronously fetch the supported languages (both source and target) from the Transifex project.

Another useful hook provided by the package is the [useLocal hook](https://developers.transifex.com/docs/react-sdk#uselocale-hook). It is used to return a state variable with the currently selected locale. To see it in action, let's modify the `App` function component:

```js
import { tx } from '@transifex/native';
import { T, LanguagePicker, useLocale } from '@transifex/react';

import './App.css';

tx.init({
  token: process.env.REACT_APP_TRANSIFEX_TOKEN,
});

function App() {
  const currentLocale = useLocale();

  const handleSubmit = event => {
    event.preventDefault();
    alert('Your form is submitted!');
  };

  return (
    <div className="app">
      <div className="form">
        <h1>
          <T _str="Login form" />
        </h1>
        <p className="subtitle">
          <T _str="Please enter your credentials to proceed." />
          <p>Currently selected locale is {currentLocale}.</p>
        </p>
        <div className="picker">
          <p className="picker-title">
            <T _str="Select the language: " />
          </p>{' '}
          <LanguagePicker />
        </div>

        {/* rest of the code remains same*/}
      </div>
    </div>
  );
}
```

Here is the output after this step:

![ss12](https://i.imgur.com/wCehGJ2.png)

## Conclusion

Thanks for reading this article. Using Transifex is quite simple to integrate, and I personally found it fun to use. Compared to an open-source alternative, it is paid if using Transifex hosting service but does provide [self-hosting](https://developers.transifex.com/docs/content-delivery-service#self-hosted-cds-service) option.

Another feature I like about it is the Over the Air feature that allows for managing and updating translations in an automated way. Instead of having large json files, translatable phrases are maintained using an interface. It also bridges the gap between managing translations in different languages and the development of the application.

### Further Reading
Check out the guide on implementing [Localization in React apps](https://www.transifex.com/blog/2021/react-localization-with-transifex-native/) using Transifex Native