As globalization grows, writing React applications for a wide audience in different regions and geographies means making it accessible across languages.

With internationalization capabilities, the React Intl library provides a mechanism for correctly translating file text into other languages.

In this tutorial, we’ll learn how to use the React Intl library to set up internationalization functionality in React projects. We will create a simple application that allows users to select and see their favorite language when viewing the application.

We will also persist the chosen language in the browser’s store so that the content is still available after the page refreshes or upon subsequent access.

Here is the final product we will build together.

Interact with the finished web page to get familiar with the interface, so with this in mind, let’s get started

Internationalization and localization

As mentioned earlier, React Intl allows us to set internationalization in the React application. But what exactly is internationalization?

Internationalization is the process of designing a product — in this case, the React app — for use in different locales. It is often abbreviated to Intl or I18N.

In contrast, localization, abbreviated l10N, focuses on translating an internationalized application from its original language into a specific language.

But hey, translation isn’t just about converting text or information into the target language. Cultural differences must also be taken into account, such as how numbers and dates are written, or how units and currency are placed in different regions.

Fortunately, with the React Intl library, we can seamlessly achieve the results we want.

Setting the React Project

Let’s start by getting our simple React project — which defaults to English — from the GitHub repository. We can then add support for three more languages. French, German and Japanese.

So go to the terminal, switch to a directory to save the project, and run the following command to download the startup file.

git clone https://github.com/Ibaslogic/i18n_react_intl_starter

Copy the code

Once the project files are started, open them with a code editor. We must run NPM install in the project directory to create a node_modules folder for the project.

Make sure you have Node.js installed on your computer to complete this tutorial.

Now, use NPM start to start the development server. We should see our application loaded at http://localhost:3000 in the browser.

If we look at the file structure of the project, we should have the following.

Project_folder ├─ Node_modules ├─ Public ├─ SRC │ ├─ Components │ ├─ app.js │ ├─ content.js │ │ ├─ Footer │ │ └ ─ ─ the Header. Js │ ├ ─ ─ index. The CSS │ └ ─ ─ index. The js ├ ─ ─ the gitignore ├ ─ ─ package - lock. Json ├ ─ ─ package. The json ├ ─ ─ the README. Md └ ─ ─  yarn.lockCopy the code

Very good. Now that we’re on the same page, let’s look at how to use the React Intl library in our application.

Configure the React Intl library

To use this library, we must install it by stopping the development server and running the following command from the terminal.

npm install react-intl

Copy the code

This library gives us all the apis and components we need to achieve internationalization in our applications.

Let’s wrap our top-level application or root component with a provider component from the library; In this case, we will use

.

What is theIntlProviderComponents?

As the name implies, IntlProvider ensures that important configurations are provided or provided for the child components in the tree.

The React Intl child components are called formatted components. They are responsible for proper translation and formatting at run time. These components are.

  • FormattedMessage
  • FormattedNumber
  • FormattedDate
  • FormattedPlural
  • There are many

For internationalization projects using the React Intl library, the FormattedMessage component is often used, allowing users to translate and format strings and messages from simple to complex. We’re going to use this in a second.

Back in our project, let’s open the parent component file SRC/Components/app.js and wrap the child component with IntlProvider.

Be sure to import IntlProvider from react-intl at the top of the file.

Our file should look something like this.

. import { IntlProvider } from "react-intl"; const App = () => { return ( <IntlProvider> <div> <Header /> <Content /> <Footer /> </div> </IntlProvider> ); }; export default App;Copy the code

Let’s take a moment and examine what the IntlProvider component returns. First, document the component.

. const App = () => { console.log(IntlProvider); return ( ... ) ; }; .Copy the code

Then, check the browser’s console.

By looking at defaultProps, we can see all the default configuration items used by IntlProvider. This component also tells us to configure a locale.

So, let’s update this component to add the items needed to recognize and display translations to IntlProvider, including the following items.

return (
  <IntlProvider messages={{}} locale="en" defaultLocale="en">
    <div>
      <Header />
      <Content />
      <Footer />
    </div>
  </IntlProvider>
);

Copy the code

By adding the Locale item and saving it, the error disappears immediately.

This locale, which accepts a string, determines what language our application is rendered in. We will add this value dynamically based on what the user selects in the foreground.

The Messages object contains a set of translation strings ready to be displayed in the foreground. These will also be added dynamically based on the current locale.

Finally, the defaultLocale item is the defaultLocale and should match the application’s default language.

Before we load the translated information for our project, let’s play around and familiarize ourselves with the formatted components.

Open the SRC/Components/footer.js file and add the formatting components to the return statement.

// ...
import { FormattedDate, FormattedNumber, FormattedPlural } from "react-intl";

const Footer = () => {
  // ...
  return (
    <div className="container mt">
      {/* ... */}

      <FormattedDate value={Date.now()} />
      <br />
      <FormattedNumber value={2000} />
      <br />
      <FormattedPlural value={5} one="1 click" other="5 clicks" />
    </div>
  );
};

// ...

Copy the code

Next, save the file and examine the front end. We should have this display.

5/29/2021 // Your current date 2000 5 ClicksCopy the code

Locale If we change the IntlProvider item to DE and save the file again, we have the data in German.

29.5.2021

2.000

Copy the code

This is awesome. React Intl is using formatting components (FormattedDate and FormattedNumber, respectively) to format dates and numbers based on the selected area.

These formatting components have a value item that accepts the data to be formatted.

We can further customize these components by taking advantage of its other items. For example, we could have the following.

return (
  <div className="container mt">
    {/* ... */}

    <FormattedDate
      value={Date.now()}
      year="numeric"
      month="long"
      day="2-digit"
    />
    <br />
    <FormattedNumber value={2000} style={`currency`} currency="USD" />
    <br />
    {/* ... */}
  </div>
);

Copy the code

And then, we get this English (en).

May 29, 2021 // your current date

$2,000.00

Copy the code

And then we get this German (de).

29. Mai 2021

2.000,00 $

Copy the code

In addition to these two components, we also have the FormattedPlural component, which allows us to deal with complex numbers in our application. As you can see in the example above, the component selects the complex category based on the value it receives.

Use the React Intl API

Another option is to format our data via the React Intl API. While using component methods in React is preferred because it works seamlessly with other React components, there are situations where API methods are needed, such as when an element’s placeholder,title, or aria-label must be translated.

Any time we use formatting components to render React elements, they use the React Intl API behind the scenes.

Let’s see how this API works. Import useIntl Hook from react-intl again in footer. js.

import { FormattedDate, FormattedNumber, FormattedPlural, useIntl } from "react-intl";

Copy the code

Make sure this is done in a functional React component.

If we record useIntl hooks in the console, we should see all the available functions that need to format our data.

// ...
const Footer = () => {
  // ...
  const intl = useIntl();
  console.log(intl);

  return (
    <div className="container mt">
      {/* ... */}
    </div>
  );
};
// ...
>
Copy the code

One of these functions is formatDate; Let’s apply it.

Update the return statement in the footer.js file to include this function.

// ...
const Footer = () => {
  // ...
  const intl = useIntl();
  return (
    <div className="container mt">
      {/* <... */}
      <br />
      <input placeholder={intl.formatDate(Date.now())} />
    </div>
  );
};
// ...

Copy the code

Check the foreground and see the input field. Locale remember to change the value of the IntlProvider to see how it works.

We can further customize this by adding optional configurations.

<input
  placeholder={intl.formatDate(Date.now(), {
    year: "numeric",
    month: "long",
    day: "2-digit",
  })}
/>

Copy the code

Now that we’re familiar with these formatters, let’s get back to our project.

Translate the application’s source text string

To support other regions, we must translate the source text. For this tutorial, let’s use Google Translate.

Create a folder named i18n in the SRC directory. In this folder, create two different files called locales.js and messages.js. The locales.js file will hold the languages we support, while the messages.js file will hold the corresponding translations.

Add this to the i18n/locales.js file.

export const LOCALES = {
  ENGLISH: "en-US",
  JAPANESE: "ja-JA",
  FRENCH: "fr-FR",
  GERMAN: "de-DE",
};

Copy the code

This is necessary to avoid manually adding localization. To access en-us, for example, we will use [locales.english].

Where does the code come from?

The code en-us comes from language-country code, Although we can directly use [language] (http://www.gnu.org/savannah-checkouts/gnu/gettext/manual/gettext.html#Language-Codes) code, Without adding [COUNTRY] (http://www.gnu.org/savannah-checkouts/gnu/gettext/manual/gettext.html#Country-Codes) code.

However, in cases where multiple countries have the same language, it may be useful to add a COUNTRY clarifier. For example, American English would be en-US and British English would be en-GB.

React translation

Now, in the i18n/messages.js file, add the following translation.

import { LOCALES } from "./locales"; export const messages = { [LOCALES.ENGLISH]: { learn_to: "Hello, let's learn how to use React-Intl", price_display: "How {n, number, ::currency/USD} is displayed in your selected language", number_display: "This is how {n, number} is formatted in the selected locale", start_today: "Start Today: {d, date}", // menu about_project: "About the project", contact_us: "Contact us", }, [LOCALES.FRENCH]: { learn_to: "Bonjour, apprenons a utiliser react-intl ", price_display: Comment {n, number, ::currency/USD} $s'affiche dans la langue selectionnee ", number_display: "Voici comment {n, number} sont formates dans les parametres regionaux selectionnes ", start_today: "Commencement of commencement here: {d, date}", // Commencement of commencement here:" commencement of commencement here: {d, date}", // Menu About_project: "A propos du projet", contact_us: "Contactez-nous", }, [LOCALES.GERMAN]: { learn_to: "Hallo, lass uns lernen, wie man React-Intl benutzt", price_display: "Wie {n, number, ::currency/USD} in Ihrer ausgewahlten Sprache angezeigt wird", number_display: "Auf Diese Weise Werden {n, number} im Ausgewahlten Gebietsschema formatiert", start_today: Beginnen Sie Heute: {d, date}", // menu About_project: "Uber das Projekt", contact_us: "Kontaktiere uns",}, [LOCALES. {learn_to: "こ ん に ち は, React - Intl の make い を learn び ま し ょ う", price_display: "Sentaku し た words で {} n, number, : : currency/USD が ど の よ う に said さ れ る か", number_display: "こ れ は, sentaku し た ロ ケ ー ル で {n, number} が フ ォ ー マ ッ ト さ れ る method で す." Beginning today, start_today: "か ら め る : {d, date}", / / menu about_project: "プ ロ ジ ェ ク ト に つ い て", contact_us: "ask お い close わ せ",,}};Copy the code

This file contains translations of our application source text and supported locales. Note each unique ID and key, which can be named for anything; We’ll use them to inject their corresponding strings into our application.

For now, let’s focus on simple strings and ignore the arguments in braces, also known as placeholders.

Next, let’s load the data in the Message item of the IntlProvider component.

We can see from the data that we can access English translation objects like this.

messages[LOCALES.ENGLISH]

Copy the code

The same applies elsewhere.

So, let’s assign this English translation to the Messages prop of the Provider component. Later in this tutorial, we will define a logic that dynamically injects translated information based on the locale chosen by the user.

In the Components/app.js file, import LOCALES and Messages at the top of the file.

import { LOCALES } from ".. /i18n/locales"; import { messages } from ".. /i18n/messages";Copy the code

Then, update

, so we have the following.

const App = () => {
  const locale = LOCALES.ENGLISH;

  return (
    <IntlProvider
      messages={messages[locale]}
      locale={locale}
      defaultLocale={LOCALES.ENGLISH}
    >
      ...
    </IntlProvider>
  );
};

export default App;

Copy the code

From the code, we can infer that the English data is loaded in the Provider component and can be accessed through child components.

As mentioned earlier, we will use FormattedMessage to format these complex strings. This component is ideal if our information combines dates, numbers, or just simple information.

We’ll start by converting a simple string, “Hello, let’s learn how to use React-intl”.

Go to the Components /Content.js file and import the FormattedMessage.

import { FormattedMessage } from "react-intl";

Copy the code

The string is then replaced with the component.

import { FormattedMessage } from "react-intl";

const Content = () => {
  return (
    <div className="container hero">
      <h1><FormattedMessage id="learn_to" /></h1>
      {/* ... */}
    </div>
  );
};

export default Content;

Copy the code

It’s that simple. To test our work, we can manually change locale in the app.js file to JAPANESE.

const locale = LOCALES.JAPANESE;

Copy the code

Save and see the changes in the foreground.

The FormattedMessage used in the above code requires an ID whose value matches a specific key in the translation file, and then returns the corresponding string for the current locale. Remember that this ID is unique among all supported languages in the translation file.

Using parameter

When we see a message that contains a date, amount, or number, we replace it with parameters.

Earlier, we learned how to format values of these types using FormattedDate and FormattedNumber. But here we’ll use the FormattedMessage because these values are part of the string.

If we look at the translation file, we replace these value types according to this pattern: {key, type, format}.

For example, we have something like this.

price_display:
  "How {n, number, ::currency/USD} is displayed in your selected language",

Copy the code

The first element, n, is the key and looks up the appropriate data from the data object. The second element is the data type to be interpreted, which conforms to a specific locality.

The third argument, which is optional, allows us to specify additional information about the element type.

In the above case, we say that the placeholder for number must be formatted into dollar currency. Then, React Intl locates the currency. You can find a list of currency codes here.

Using the FormattedMessage to convert this type of string, we get something like this.

<FormattedMessage id="price_display" values={{n: 59.99}} />Copy the code

As expected, ID finds the translation for the current locale, and the placeholder is replaced by the value of key.

If we applied this logic to our project, the components/Content.js file would now look like this.

import { FormattedMessage } from "react-intl"; const Content = () => { return ( <div className="container hero"> <h1><FormattedMessage id="learn_to" /></h1> <p><FormattedMessage id="price_display" values={{ n: /></p> <p><FormattedMessage id="number_display" values={{n: 2000 }} /></p> <p><FormattedMessage id="start_today" values={{ d: new Date() }} /></p> </div> ); }; export default Content;Copy the code

Save the file and test the application by changing the locale in the Component/app.js file to another supported language.

const locale = LOCALES.JAPANESE;

Copy the code

Our application should look like this.

Use the plural of React Intl

Earlier, we learned how to use the
component to process a simple plural text. In this section, we will use
to implement complex numbers in rich text messages.

Currently, if we click the count button in the foreground, when the count is singular, which is at 1, we don’t have the logic to display the correct text.

When formatting currencies using {key, type, format} patterns, we can use the same pattern, but replace type and format with matches and {key, type, format} patterns, respectively.

By applying this pattern, we can add the following to our English translation objects.

click_count: "You clicked {count, plural, one {# time} other {# times}}"

Copy the code

The plural categories, one and other, match the singular and plural forms in the first and second braces, preceded by #, which represents the count number.

If we translated the message into the language of another region and applied the same logic, we would have the following German.

click_count:
      "Sie haben {count, plural, one {# Mal} other {# Mal}} geklickt",

Copy the code

For French.

Click_count: "Vous avez clique {count, plural, one {# fois} other {# fois}}",Copy the code

For Japanese.

Click_count: "{count, plural, one # {to} other # {to}} ク リ ッ ク し ま し た",Copy the code

Save the file and open the Components/footer.js file to render the translation using the FormattedMessage component.

And then, find this element.

<p>You clicked {count} times</p>

Copy the code

Replace the above with the following.

<p>
  <FormattedMessage id="click_count" values={{ count: count }} />
</p> 

Copy the code

We also have to import the FormattedMessage component from react-Intl.

import {
  // ...
  FormattedMessage,
} from "react-intl";

Copy the code

Save the file again. Let’s reload the front end and test our work.

We can now add translation support for menu items. First, import the FormattedMessage from the components/ header. js file like this.

import { FormattedMessage } from "react-intl";

Copy the code

We need access to the individual menu keys used in the translation file. To do this, let’s update the Menu array to include the key.

const menu = [
  {
    key: "about_project",
    // ...
  },
  {
    key: "contact_us",
    // ...
  },
];

Copy the code

We can now access the translation in the FormattedMessage using the key.

First, find the following code.

{menu.map(({ title, path }) => (
  <li key={title}>
    <a href={path}>{title}</a>
  </li>
))}

Copy the code

And then, I’m going to replace it with this.

{menu.map(({ title, path, key }) => (
  <li key={title}>
    <a href={path}>
      <FormattedMessage id={key} />
    </a>
  </li>
))}

Copy the code

Save the file and test the application.

To localize the front button and its call to action text, let’s assign keys to the button in the i18n/message.js file.

For English objects, add the following.

click_button: "Please click the button below",
click_here: "click here",

Copy the code

For French, add this.

click_button: "Veuillez cliquer sur le bouton ci-dessous",
click_here: "Cliquez ici",

Copy the code

Using the code above and Google Translate, add translations for other locales, such as Japanese and German.

Once we’re done, let’s open components/ footer.js and replace the text string with FormattedMessage.

return (
  <div className="container mt">
    {/* Footer content here */}
    <p><FormattedMessage id="click_button" /></p>
    <button onClick={onChange}>
      <FormattedMessage id="click_here" />
    </button>
    {/* ... */}
  </div>
);

Copy the code

Save the file and reload the foreground. Note that the description of the button and the text of the button are updated in French.

Add the option to switch languages in the foreground

To provide an option to switch languages on the front end, we must open the components/ header. js file and add the following at the top of the return statement.

// Languages const Languages = [{name: "English", code: locales. English}, {name: "Japanese ", code: Locales.japanese}, {name: "Francais ", code: locales.French}, {name: "Deutsche", code: locales.german},];Copy the code

Then, import the LOCALES at the top of the file.

import { LOCALES } from ".. /i18n/locales";Copy the code

Next, we’ll loop through the Languages array to generate our drop-down menu.

Again, in the file, find the div container element.

<div className="switcher">
  {/* Language switch dropdown here */}
</div>

Copy the code

Then, update it and see the following.

<div className="switcher">
  {/* Language switch dropdown here */}
  Languages{" "}
  <select>
    {languages.map(({ name, code }) => (
      <option key={code} value={code}>
        {name}
      </option>
    ))}
  </select>
</div>

Copy the code

Save it and add this simple style to the SRC /index.css file.

.switcher select {
  width: 99px;
  height: 30px;
}

Copy the code

Save the file again and look at the drop-down menu on the front end. Currently, switching between languages doesn’t change the content of the page, so let’s fix that.

If you’re familiar with React forms handling, this process should be a piece of cake. If not, that’s fine, because we’ll do it together.

In React, form input should be a controlled input, unlike HTML forms.

To do this, we will add a value item and an onChange event to the SELECT element. The value item is specified as the current locale, while onChange updates the value based on the user’s choice.

At the same time, update the SELECT element to include these items.

<select onChange="" value="">
  ..
</select>

Copy the code

Since IntlProvider is in the parent component, app.js must also know the current locale, so let’s set the logic in the file.

We can pass the necessary data to the Header child component via props. This process is called prop drilling.

Open components/ app.js and add a state where the default language is English.

import { useState } from "react"; . const App = () => { const locale = LOCALES.ENGLISH; const [currentLocale, setCurrentLocale] = useState(locale); return ( <IntlProvider messages={messages[currentLocale]} locale={currentLocale} defaultLocale={LOCALES.ENGLISH} > ... </IntlProvider> ); }; export default App;Copy the code

Don’t forget to import useState Hook from React to get the current locale.

Now, let’s pass the locale to the Header child and use it in the SELECT element.

In the app.js file, update the

instance in
, so we have the following.

<Header currentLocale={currentLocale}/>

Copy the code

Save the file and open header.js to access the data; Pass it to the value item of the SELECT element.

. const Header = (props) => { ... return ( <header> <div className="container header_content"> ... <nav> ... </nav> <div className="spacer"></div> <div className="switcher"> {/* Language switch dropdown here */} Languages{" "} <select onChange="" value={props.currentLocale}> ... </select> </div> </div> </header> ); }; export default Header;Copy the code

Call props, as shown below.

const Header = (props) => { 

Copy the code

Next, we will use the onChange event to handle the updates.

In the app.js file, add the following handler above the return statement and pass it down to the Header component via the prop.

const handleChange = (e) => {
  setCurrentLocale(e.target.value);
};

Copy the code

Now the code looks something like this.

. const App = () => { ... const handleChange = (e) => { setCurrentLocale(e.target.value); }; return ( ... <div> <Header currentLocale={currentLocale} handleChange={handleChange} /> ... </div> ... ) ; };Copy the code

Save the file and access the handler inside the Header component.

Simply update the SELECT element, so we have the following.

<select onChange={props.handleChange} value={props.currentLocale}>

Copy the code

Now we can test our application. It worked! Very good.

Be sure to translate the language text next to the drop-down list as well.

Preserves the selected locale in the browser’s local store

Currently, if we switch out of the default locale and reload the page, the content reverts to its default state. We don’t want that.

In this section, we’ll see how you can easily persist the selected locale into the browser’s store. This means that the user’s favorite language content can still be seen on the page when the page is reloaded and on subsequent visits, further improving the user experience.

First, open the app.js file and add this code above the return statement.

//localstorage
function getInitialLocal() {
  // getting stored items
  const savedLocale = localStorage.getItem("locale");
  return savedLocale || LOCALES.ENGLISH;
}

Copy the code

Then, update the state to use this function.

const [currentLocale, setCurrentLocale] = useState(getInitialLocal());

Copy the code

Finally, the handleChange is updated to include stored objects.

const handleChange = (e) => {
  setCurrentLocale(e.target.value);
  // storing locale in the localstorage
  localStorage.setItem("locale", e.target.value);
};

Copy the code

Remove this line from the app.js file as it is now redundant.

const locale = LOCALES.ENGLISH;

Copy the code

Now, save the file and test the application. Be sure to reload the page to see if the data persists in storage.

Because we start using the getItem() method to access local storage to check for any saved locales or to return a fallback, the returned locale is assigned to the state variable currentLocale.

Similarly, we use the setItem() method to save the locale selected by the user into a Storage object.

Read more about how to persist the state of your React component in local storage.

conclusion

We’ve covered almost everything we need to know about the React Intl library. We’ve learned how to apply the library to the React application and how to persist user-selected locations in local storage.

I hope you found this guide helpful. If you have questions or contributions, I’ll be in the comments section. You can also find the source code for the entire project in the GitHub repository.

The postReact Intl: Internationalize your React appsappeared first onLogRocket Blog.