2

Curated List: Our Best of Libraries for React I18n – Phrase

 2 years ago
source link: https://phrase.com/blog/posts/react-i18n-best-libraries/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

The Best Libraries for React I18n

React i18n libraries cover image | The Phrase Blog

Let's not beat around the bush: React is a strong JavaScript library that lets you build scalable UI interfaces. When it comes to internationalizing your app, though, it does not offer a built-in solution. Fortunately, there are some amazing open-source libraries that can help you manage your i18n project successfully from start to finish.

  1. The Phrase Blog
  2. Developers
  3. The Best Libraries for React I18n

This curated list features the best libraries for React i18n. It will walk you through the pros and cons of each option in terms of flexibility, scalability, and most of all, developer productivity.

Since almost every programming language has different rules and conventions, and adapting to them within the scope of those libraries may be tricky, understanding the pros and cons of each library might take time and effort.

At the time of writing, we are using the latest versions of React v16.11.0 and React Router v5.1.2. You can find all code examples in our GitHub repo.

Our base project

We will start off by layering a base project that we would like to localize. It would be a typical, unopinionated React project with a minimal boilerplate, useful for starting out fresh. Create a new app using Create React App and update the App.js with the following content:

import React from 'react';
import {Switch, Route, HashRouter as Router} from 'react-router-dom';
import Home from "./Home";
import './App.css';
const App = () => (
<Router>
<Switch>
<Route exact path="/" component={Home} />
</Switch>
</Router>
export default App;
import React from 'react';
import {Switch, Route, HashRouter as Router} from 'react-router-dom';
import Home from "./Home";

import './App.css';

const App = () => (
  <Router>
    <Switch>
      <Route exact path="/" component={Home} />
    </Switch>
  </Router>
);

export default App;
We defined the Home.js component as:
import React, {Component} from 'react';
import logo from './logo.svg'
import './Home.css';
class Home extends Component {
render() {
return (
<div className="Home">
<div className="Home-header">
<img src={logo} className="Home-logo" alt="logo"/>
<h2>Welcome to React.js</h2>
</div>
<div className="Home-container">
<div className="Home-items">
<div className="Home-item">
<h3 className="focus">Declarative</h3>
<div><p>React makes it painless to create interactive UIs. Design simple views for each state in your
application, and React will efficiently update and render just the right components when your data
changes.</p>
<p>Declarative views make your code more predictable and easier to debug.</p>
</div>
</div>
<div className="Home-item">
<h3 className="focus">Component-Based</h3>
<div>
<p>Build encapsulated components that manage their own state, then compose them to make complex UIs.</p>
<p>Since component logic is written in JavaScript instead of templates, you can easily pass rich data
through your app and keep state out of the DOM.</p>
</div>
</div>
</div>
</div>
</div>
export default Home;
import React, {Component} from 'react';
import logo from './logo.svg'
import './Home.css';

class Home extends Component {
  render() {
    return (
      <div className="Home">
        <div className="Home-header">
          <img src={logo} className="Home-logo" alt="logo"/>
          <h2>Welcome to React.js</h2>
        </div>
        <div className="Home-container">
          <div className="Home-items">
            <div className="Home-item">
              <h3 className="focus">Declarative</h3>
              <div><p>React makes it painless to create interactive UIs. Design simple views for each state in your
                application, and React will efficiently update and render just the right components when your data
                changes.</p>
                <p>Declarative views make your code more predictable and easier to debug.</p>
              </div>
            </div>
            <div className="Home-item">
              <h3 className="focus">Component-Based</h3>
              <div>
                <p>Build encapsulated components that manage their own state, then compose them to make complex UIs.</p>
                <p>Since component logic is written in JavaScript instead of templates, you can easily pass rich data
                  through your app and keep state out of the DOM.</p>
              </div>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

export default Home;

And the  Home.css component as:

.Home {
text-align: center;
.Home-logo {
height: 40vmin;
.Home-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
.Home-link {
color: #09d3ac;
.Home {
  text-align: center;
}

.Home-logo {
  height: 40vmin;
}

.Home-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}

.Home-link {
  color: #09d3ac;
}
When you run yarn start or npm start you will see the following screen:
Initial Screen | Phrase

React-intl

This library is one of the most popular solutions for i18n in React and it’s now part of Formatjs. Offered by Yahoo is bundled with common locale data like dates, currencies, numbers, and support for over  150+ languages. It builds upon the concepts of the ECMAScript’s ECMAScript’s Internationalization API namespace.

In order to use it, we need to configure a few things first.

First we need to install it:

yarn add react-intl
yarn add react-intl

Then on the root of the application just before we render the initial component, we need to add the following bootstrapping code:

/* react-intl imports */
import { IntlProvider } from 'react-intl';
/* Define your translations */
let i18nConfig = {
locale: 'el',
messages: {
"home.welcome": "Καλώς 'Ηρθατε στο {name}!",
"home.declarative": "Δηλωτικό"
/* react-intl imports */
import { IntlProvider } from 'react-intl';

/* Define your translations */
let i18nConfig = {
  locale: 'el',
  messages: {
    "home.welcome": "Καλώς 'Ηρθατε στο {name}!",
    "home.declarative": "Δηλωτικό"
  }
};

Notice that the i18nConfig contains all the specific language translations for the current locale. We could have loaded this config before the application starts using a JSON Webpack loader or an Ajax call.

When we have loaded our supported locale and config messages, then we only need to wrap the application with the that will apply the i18n context available for our internal React Components:

ReactDOM.render(
<IntlProvider
locale={i18nConfig.locale}
defaultLocale={i18nConfig.locale}
messages={i18nConfig.messages}
<App />
</IntlProvider>, document.getElementById('root'));
ReactDOM.render(
  <IntlProvider
    locale={i18nConfig.locale}
    defaultLocale={i18nConfig.locale}
    messages={i18nConfig.messages}
  >
    <App />
  </IntlProvider>, document.getElementById('root'));

Finally, we are ready to provide our translated components. We need to convert our existing text in the Home component into a series of FormattedMessage components:

import React, {Component} from 'react';
import {FormattedMessage} from 'react-intl';
import logo from './logo.svg'
import './Home.css';
class Home extends Component {
render() {
return (
<div className="Home">
<div className="Home-header">
<img src={logo} className="Home-logo" alt="logo"/>
<h2><FormattedMessage id="home.welcome" values={{name: 'React.js'}}/></h2>
</div>
<div className="Home-container">
<div className="Home-items">
<div className="Home-item">
<h3 className="focus">
<FormattedMessage id="home.declarative"/></h3>
<div><p><FormattedMessage id="home.declarative.p1" values={{name: <i>React</i>}}/></p>
<p><FormattedMessage id="home.declarative.p2"/></p>
</div>
</div>
<div className="Home-item">
<h3 className="focus"><FormattedMessage id="home.component-based"/></h3>
<div>
<p><FormattedMessage id="home.component-based.p1"/></p>
<p><FormattedMessage id="home.component-based.p2"/></p>
</div>
</div>
</div>
</div>
</div>
export default Home;
import React, {Component} from 'react';
import {FormattedMessage} from 'react-intl';
import logo from './logo.svg'
import './Home.css';

class Home extends Component {
  render() {
    return (
      <div className="Home">
        <div className="Home-header">
          <img src={logo} className="Home-logo" alt="logo"/>
          <h2><FormattedMessage id="home.welcome" values={{name: 'React.js'}}/></h2>

        </div>
        <div className="Home-container">
          <div className="Home-items">
            <div className="Home-item">
              <h3 className="focus">
                <FormattedMessage id="home.declarative"/></h3>
              <div><p><FormattedMessage id="home.declarative.p1" values={{name: <i>React</i>}}/></p>
                <p><FormattedMessage id="home.declarative.p2"/></p>
              </div>
            </div>
            <div className="Home-item">
              <h3 className="focus"><FormattedMessage id="home.component-based"/></h3>
              <div>
                <p><FormattedMessage id="home.component-based.p1"/></p>
                <p><FormattedMessage id="home.component-based.p2"/></p>
              </div>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

export default Home;

Then, we need to update our translations to match the keys for each one of the messages:

let i18nConfig = {
locale: 'el',
messages: {
"home.welcome": "Καλώς 'Ηρθατε στο {name}!",
"home.declarative": "Δηλωτικό",
"home.declarative.p1": "To {name} καθιστά ανώφελη τη δημιουργία διαδραστικών διεπαφών χρήστη. Σχεδιάστε απλές προβολές για κάθε κράτος στο δικό σας\n" +
" εφαρμογή και το React θα ενημερώσει αποτελεσματικά και θα αποδώσει τα σωστά στοιχεία όταν τα δεδομένα σας\n" +
" αλλαγές.",
"home.declarative.p2": "Οι δηλωτικές προβολές καθιστούν τον κώδικα πιο προβλέψιμο και πιο εύκολο στον εντοπισμό σφαλμάτων.",
"home.component-based": "Βασισμένο σε στοιχεία",
"home.component-based.p1": "Δημιουργήστε ενσωματωμένα στοιχεία που διαχειρίζονται τη δική τους κατάσταση, και στη συνέχεια συνθέστε τα για να δημιουργήσετε σύνθετα UI.",
"home.component-based.p2": "Δεδομένου ότι η λογική συνιστωσών είναι γραμμένη σε JavaScript αντί για πρότυπα, μπορείτε εύκολα να περάσετε πλούσια δεδομένα\n" +
" μέσω της εφαρμογής σας και να κρατήσετε την κατάσταση εκτός του & nbsp; DOM.",
let i18nConfig = {
  locale: 'el',
  messages: {
    "home.welcome": "Καλώς 'Ηρθατε στο {name}!",
    "home.declarative": "Δηλωτικό",
    "home.declarative.p1": "To {name} καθιστά ανώφελη τη δημιουργία διαδραστικών διεπαφών χρήστη. Σχεδιάστε απλές προβολές για κάθε κράτος στο δικό σας\n" +
    "                εφαρμογή και το React θα ενημερώσει αποτελεσματικά και θα αποδώσει τα σωστά στοιχεία όταν τα δεδομένα σας\n" +
    "                αλλαγές.",
    "home.declarative.p2": "Οι δηλωτικές προβολές καθιστούν τον κώδικα πιο προβλέψιμο και πιο εύκολο στον εντοπισμό σφαλμάτων.",
    "home.component-based": "Βασισμένο σε στοιχεία",
    "home.component-based.p1": "Δημιουργήστε ενσωματωμένα στοιχεία που διαχειρίζονται τη δική τους κατάσταση, και στη συνέχεια συνθέστε τα για να δημιουργήσετε σύνθετα UI.",
    "home.component-based.p2": "Δεδομένου ότι η λογική συνιστωσών είναι γραμμένη σε JavaScript αντί για πρότυπα, μπορείτε εύκολα να περάσετε πλούσια δεδομένα\n" +
    "                  μέσω της εφαρμογής σας και να κρατήσετε την κατάσταση εκτός του & nbsp; DOM.",
  }
};

Now, if we notice the app will load with the Greek translations. Notice also that the FormattedMessage can return also React components and not just text.

Translated View | Phrase

Among other things, React-intl offers some extra components:

  • FormattedDate: Formats locale-specific dates.
  • ForrmattedTime: Formats locale-specific times.
  • FormattedRelative: Formats locale-specific relative durations.
  • FormattedNumber: Formats locale-specific numbers and decimals.
  • FormattedPlural: Formats locale-specific plurals and quantities.

There is also support for React Hooks via the useIntl hook. To use it in our Functional Components, instead of importing the above components, we just call the hook and it will return the imperative formatting API as an object for us:

const HomeHeader = () => {
const intl = useIntl();
return (
<div className="Home-header">
<img src={logo} className="Home-logo" alt="logo"/>
<h2>{intl.formatMessage({id: 'home.welcome'}, {name: 'React.js'})}</h2>
</div>
class Home extends Component {
render() {
return (
<div className="Home">
<HomeHeader />
const HomeHeader = () => {
  const intl = useIntl();
  return (
    <div className="Home-header">
      <img src={logo} className="Home-logo" alt="logo"/>
      <h2>{intl.formatMessage({id: 'home.welcome'}, {name: 'React.js'})}</h2>
    </div>
  )
};

class Home extends Component {
  render() {
    return (
      <div className="Home">
        <HomeHeader />
        ...

React-intl offers a good overall package for internationalizing your React Application. However, it is not without its disadvantages. You cannot use it for non-react components as it requires the top level component to inject the context to the children. We will see how the next library helps with providing a holistic solution to this problem.

I18n Manager for Global Success
I18n Manager for Global Success

Learn how to find the best i18n manager and follow our best practices for making your business a global success.

Check out the guide

React-intl-universal

react-intl-universal is a React internationalization package developed by Alibaba Group. It builds on top of React-intl by allowing non-React components use the library by providing a singleton object that can be used to load the current locale. Let’s see how we can use this library in our project.

Install it first:

yarn add react-intl-universal
yarn add react-intl-universal

Using the i18nConfig  we need to load the translations and pass them through the intl.init  method call:

import React, {Component} from "react";
import intl from 'react-intl-universal';
// common locale data
require('intl/locale-data/jsonp/el.js');
export default class App extends Component {
state = {initDone: false};
componentDidMount() {
this.loadLocales();
loadLocales() {
intl.init({
currentLocale: i18nConfig.locale,
locales,
.then(() => {
// After loading CLDR locale data, start to render
this.setState({initDone: true});
import React, {Component} from "react";

import intl from 'react-intl-universal';
// common locale data
require('intl/locale-data/jsonp/el.js');

export default class App extends Component {

  state = {initDone: false};

  componentDidMount() {
    this.loadLocales();
  }

  loadLocales() {
    intl.init({
      currentLocale: i18nConfig.locale,
      locales,
    })
      .then(() => {
        // After loading CLDR locale data, start to render
        this.setState({initDone: true});
      });
  }
...

Once we update the state we can render the App component:

render() {
return (
this.state.initDone &&
<Router>
<Switch>
<Route exact path="/" component={Home} />
</Switch>
</Router>
render() {
    return (
      this.state.initDone &&
      <Router>
        <Switch>
          <Route exact path="/" component={Home} />
        </Switch>
      </Router>
    );
import intl from 'react-intl-universal';
intl.get('home.declarative'); // Simple text message
intl.getHtml('home.declarative.p1') // HTML message
intl.get('not-exist-key').defaultMessage('Μύνημα που δεν υπάρχει') // Default message
intl.get('home.welcome', {name:'React.js'}) // Message with variables.
import intl from 'react-intl-universal';
 
intl.get('home.declarative'); // Simple text message
intl.getHtml('home.declarative.p1') // HTML message
intl.get('not-exist-key').defaultMessage('Μύνημα που δεν υπάρχει') // Default message
intl.get('home.welcome', {name:'React.js'}) // Message with variables.

Now the API for accessing those translations is simple:

import intl from 'react-intl-universal';
intl.get('home.declarative'); // Simple text message
intl.getHtml('home.declarative.p1') // HTML message
intl.get('not-exist-key').defaultMessage('Μύνημα που δεν υπάρχει') // Default message
intl.get('home.welcome', {name:'React.js'}) // Message with variables.
import intl from 'react-intl-universal';
 
intl.get('home.declarative'); // Simple text message
intl.getHtml('home.declarative.p1') // HTML message
intl.get('not-exist-key').defaultMessage('Μύνημα που δεν υπάρχει') // Default message
intl.get('home.welcome', {name:'React.js'}) // Message with variables.

It can also handle locale-specific messages for Times, Dates, Decimals and Plurals.

LinguiJS

LinguiJS is considered a newcomer in this list, offering an impressive array of powerful features for i18n. It’s clean, simple and with low overhead. Not to mention it works with React too!

Let’s see an example usage. First we need to install a bunch of libraries:

yarn add --dev @lingui/cli @lingui/macro @babel/core babel-core@bridge
yarn add @lingui/react
yarn add --dev @lingui/cli @lingui/macro @babel/core babel-core@bridge
yarn add @lingui/react

Next we need to add a configuration file for the CLI tool that will extract and compile the messages. Create the following file with this config:

.jslingui

"localeDir": "src/locales/",
"srcPathDirs": ["src/"],
"format": "minimal",
"fallbackLocale": "el",
"sourceLocale": "en"
{
   "localeDir": "src/locales/",
   "srcPathDirs": ["src/"],
   "format": "minimal",
   "fallbackLocale": "el",
   "sourceLocale": "en"
}

We specify that we need a JSON format (using minimal) for our message formats and they will be saved in the src/locales folder.

Now let’s create the Home.js Component:

import React from 'react';
import {Trans} from "@lingui/macro"
import logo from './logo.svg'
import './Home.css';
const Home = ({name}) => {
return (
<div className="Home">
<div className="Home-header">
<img src={logo} className="Home-logo" alt="logo"/>
<Trans render="h2" id="home.welcome">Welcome to {name}!</Trans>
</div>
<div className="Home-container">
<div className="Home-items">
<div className="Home-item">
<h3 className="focus">
<Trans id="home.declarative">Declarative</Trans>
</h3>
<div>
<p>
<Trans id="home.declarative.p1">
{name} makes it painless to create interactive UIs.
Design simple views for each state in your application, and
React will efficiently update and render just the right components when your data changes.
</Trans>
</p>
<p>
<Trans id="home.declarative.p2">
Declarative views make your code more predictable and easier to debug.
</Trans>
</p>
</div>
</div>
<div className="Home-item">
<h3 className="focus">
<Trans id="home.component-based">Component-Based</Trans>
</h3>
<div>
<Trans render="p" id="home.component-based.p1">
Build encapsulated components that manage their own state, then compose them to make complex UIs.
</Trans>
<Trans render="p" id="home.component-based.p2">
Since component logic is written in JavaScript instead of templates, you can easily pass rich data
through your app and keep state out of the DOM.
</Trans>
</div>
</div>
</div>
</div>
</div>
export default Home;
import React from 'react';
import {Trans} from "@lingui/macro"
import logo from './logo.svg'
import './Home.css';

const Home = ({name}) => {
  return (
    <div className="Home">
      <div className="Home-header">
        <img src={logo} className="Home-logo" alt="logo"/>
        <Trans render="h2" id="home.welcome">Welcome to {name}!</Trans>
      </div>
      <div className="Home-container">
        <div className="Home-items">
          <div className="Home-item">
            <h3 className="focus">
              <Trans id="home.declarative">Declarative</Trans>
            </h3>
            <div>
              <p>
                <Trans id="home.declarative.p1">
                  {name} makes it painless to create interactive UIs.
                  Design simple views for each state in your application, and
                  React will efficiently update and render just the right components when your data changes.
                </Trans>
              </p>
              <p>
                <Trans id="home.declarative.p2">
                  Declarative views make your code more predictable and easier to debug.
                </Trans>
              </p>
            </div>
          </div>
          <div className="Home-item">
            <h3 className="focus">
              <Trans id="home.component-based">Component-Based</Trans>
            </h3>
            <div>
              <Trans render="p" id="home.component-based.p1">
                Build encapsulated components that manage their own state, then compose them to make complex UIs.
              </Trans>
              <Trans render="p" id="home.component-based.p2">
                Since component logic is written in JavaScript instead of templates, you can easily pass rich data
                through your app and keep state out of the DOM.
              </Trans>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

export default Home;

Then we need to extract and compile the messages that we are going to translate:

$ npm run extract
> [email protected] extract /Users/itspare/WebstormProjects/react-i18n-libraries
> lingui extract
Catalog statistics:
┌─────────────┬─────────────┬─────────┐
│ Language │ Total count │ Missing │
├─────────────┼─────────────┼─────────┤
│ el │ 7 │ 7 │
│ en (source) │ 7 │ - │
└─────────────┴─────────────┴─────────┘
(use "npm run add-locale <locale>" to add more locales)
(use "npm run extract" to update catalogs with new messages)
(use "npm run compile" to compile catalogs for production)
$ npm run compile
> lingui compile
Compiling message catalogs…
Done!
$ npm run extract                          

> [email protected] extract /Users/itspare/WebstormProjects/react-i18n-libraries
> lingui extract

Catalog statistics:
┌─────────────┬─────────────┬─────────┐
│ Language    │ Total count │ Missing │
├─────────────┼─────────────┼─────────┤
│ el          │      7      │    7    │
│ en (source) │      7      │    -    │
└─────────────┴─────────────┴─────────┘

(use "npm run add-locale <locale>" to add more locales)
(use "npm run extract" to update catalogs with new messages)
(use "npm run compile" to compile catalogs for production)

$ npm run compile
> lingui compile

Compiling message catalogs…
Done!

Note that, when you run the app the first time you will see only the English translations and not the Greek. That’s because the Greek translations are missing. We will have to add them to the src/locales/el/messages.json before we run the compile command:

"home.component-based": "Βασισμένο σε στοιχεία",
"home.component-based.p1": "Δημιουργήστε ενσωματωμένα στοιχεία που διαχειρίζονται τη δική τους κατάσταση, και στη συνέχεια συνθέστε τα για να δημιουργήσετε σύνθετα UI.",
"home.component-based.p2": "Δεδομένου ότι η λογική συνιστωσών είναι γραμμένη σε JavaScript αντί για πρότυπα, μπορείτε εύκολα να περάσετε πλούσια δεδομένα μέσω της εφαρμογής σας και να κρατήσετε την κατάσταση εκτός του & nbsp; DOM.",
"home.declarative": "Δηλωτικό",
"home.declarative.p1": "To {name} καθιστά ανώφελη τη δημιουργία διαδραστικών διεπαφών χρήστη. Σχεδιάστε απλές προβολές για κάθε κράτος στο δικό σας εφαρμογή και το React θα ενημερώσει αποτελεσματικά και θα αποδώσει τα σωστά στοιχεία όταν τα δεδομένα σας αλλαγές.",
"home.declarative.p2": "Οι δηλωτικές προβολές καθιστούν τον κώδικα πιο προβλέψιμο και πιο εύκολο στον εντοπισμό σφαλμάτων.",
"home.welcome": "Καλώς 'Ηρθατε στο {name}!"
{
  "home.component-based": "Βασισμένο σε στοιχεία",
  "home.component-based.p1": "Δημιουργήστε ενσωματωμένα στοιχεία που διαχειρίζονται τη δική τους κατάσταση, και στη συνέχεια συνθέστε τα για να δημιουργήσετε σύνθετα UI.",
  "home.component-based.p2": "Δεδομένου ότι η λογική συνιστωσών είναι γραμμένη σε JavaScript αντί για πρότυπα, μπορείτε εύκολα να περάσετε πλούσια δεδομένα μέσω της εφαρμογής σας και να κρατήσετε την κατάσταση εκτός του & nbsp; DOM.",
  "home.declarative": "Δηλωτικό",
  "home.declarative.p1": "To {name} καθιστά ανώφελη τη δημιουργία διαδραστικών διεπαφών χρήστη. Σχεδιάστε απλές προβολές για κάθε κράτος στο δικό σας εφαρμογή και το React θα ενημερώσει αποτελεσματικά και θα αποδώσει τα σωστά στοιχεία όταν τα δεδομένα σας αλλαγές.",
  "home.declarative.p2": "Οι δηλωτικές προβολές καθιστούν τον κώδικα πιο προβλέψιμο και πιο εύκολο στον εντοπισμό σφαλμάτων.",
  "home.welcome": "Καλώς 'Ηρθατε στο {name}!"
}

Once we’ve completed those step’s, we only have to load those messages into the I18nProvider component:

import { I18nProvider } from '@lingui/react';
import catalogEl from './locales/el/messages.js';
import catalogEn from './locales/en/messages.js';
const catalogs = { en: catalogEn, el: catalogEl };
ReactDOM.render(
<I18nProvider
language={i18nConfig.locale}
catalogs={catalogs}
<Home name={'React.js'}/>
</I18nProvider>, document.getElementById('root'));
import { I18nProvider } from '@lingui/react';
import catalogEl from './locales/el/messages.js';
import catalogEn from './locales/en/messages.js';
const catalogs = { en: catalogEn, el: catalogEl };

ReactDOM.render(
  <I18nProvider
    language={i18nConfig.locale}
    catalogs={catalogs}
  >
    <Home name={'React.js'}/>
  </I18nProvider>, document.getElementById('root'));

Now if we run the app we will see the same screen translated as before. LinguiJS offers a lot of cool features so I urge you to consider it for your next project.

Having explored those three powerful libraries for localization, let’s see one more option that competes equally with the latter.

i18next

i18next aims to target high as it promises to give you a complete solution to localize your product from web to mobile and desktop. i18next is a plugin-based framework and provides you with plugins to:

  • detect the user language
  • load the translations
  • optionally cache the translations
  • extension, by using post-processing – e.g. to enable sprintf support.

It works well with small projects and scales when the project has many translation files to load.

Let’s see how we can use it in our React App.

Install it first:

yarn add i18next react-i18next i18next-browser-languagedetector
yarn add i18next react-i18next i18next-browser-languagedetector

Next, we need to create a file that will load our i18next configuration and any plugins we need to use. Let’s create a file named i18n.js and put our translations there:

import i18n from 'i18next';
import { initReactI18next } from "react-i18next";
import LanguageDetector from 'i18next-browser-languagedetector';
.use(initReactI18next)
.use(LanguageDetector)
.init({
// we init with resources
resources: {
translations: {
"Welcome to React.js": "Welcome to React.js",
"Declarative": "Declarative",
"React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.": "React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.",
"Declarative views make your code more predictable and easier to debug.": "Declarative views make your code more predictable and easier to debug."
translations: {
"Welcome to React.js": "Καλώς 'Ηρθατε στο React.js!",
"Declarative": "Δηλωτικό",
"React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.": "To {{name}} καθιστά ανώφελη τη δημιουργία διαδραστικών διεπαφών χρήστη. Σχεδιάστε απλές προβολές για κάθε κράτος στο δικό σας\\n\" +\n" +
" εφαρμογή και το React θα ενημερώσει αποτελεσματικά και θα αποδώσει τα σωστά στοιχεία όταν τα δεδομένα σας " +
" αλλαγές.",
"Declarative views make your code more predictable and easier to debug.": "Οι δηλωτικές προβολές καθιστούν τον κώδικα πιο προβλέψιμο και πιο εύκολο στον εντοπισμό σφαλμάτων."
fallbackLng: 'en',
debug: true,
// have a common namespace used around the full app
ns: ['translations'],
defaultNS: 'translations',
keySeparator: false, // we use content as keys
interpolation: {
escapeValue: false, // not needed for react!!
formatSeparator: ','
react: {
wait: true
export default i18n;
import i18n from 'i18next';
import { initReactI18next } from "react-i18next";
import LanguageDetector from 'i18next-browser-languagedetector';

i18n
  .use(initReactI18next)
  .use(LanguageDetector)
  .init({
    // we init with resources
    resources: {
      en: {
        translations: {
          "Welcome to React.js": "Welcome to React.js",
          "Declarative": "Declarative",
          "React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.": "React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.",
          "Declarative views make your code more predictable and easier to debug.": "Declarative views make your code more predictable and easier to debug."
        }
      },
      el: {
        translations: {
          "Welcome to React.js": "Καλώς 'Ηρθατε στο React.js!",
          "Declarative": "Δηλωτικό",
          "React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.": "To {{name}} καθιστά ανώφελη τη δημιουργία διαδραστικών διεπαφών χρήστη. Σχεδιάστε απλές προβολές για κάθε κράτος στο δικό σας\\n\" +\n" +
            "                    εφαρμογή και το React θα ενημερώσει αποτελεσματικά και θα αποδώσει τα σωστά στοιχεία όταν τα δεδομένα σας " +
            "                    αλλαγές.",
          "Declarative views make your code more predictable and easier to debug.": "Οι δηλωτικές προβολές καθιστούν τον κώδικα πιο προβλέψιμο και πιο εύκολο στον εντοπισμό σφαλμάτων."
        }
      }
    },
    fallbackLng: 'en',
    debug: true,

    // have a common namespace used around the full app
    ns: ['translations'],
    defaultNS: 'translations',

    keySeparator: false, // we use content as keys

    interpolation: {
      escapeValue: false, // not needed for react!!
      formatSeparator: ','
    },

    react: {
      wait: true
    }
  });

export default i18n;

We needed to put some fallback translations so that we have at least English displayed. Also, we used a LanguageDetector  plugin that will use a variety of method to detect the clients supported languages.

Next, we need to update our root component to use this i18n config inside the index.js:

import {I18nextProvider} from 'react-i18next';
import i18n from './i18n';
ReactDOM.render(
<I18nextProvider i18n={ i18n }>
<App />
</I18nextProvider>, document.getElementById('root'));
import {I18nextProvider} from 'react-i18next';
import i18n from './i18n';

ReactDOM.render(
  <I18nextProvider i18n={ i18n }>
  <App />
</I18nextProvider>, document.getElementById('root'));

So now we are ready to go. Let’s see how we can use it in our main Home.js component:

import React, {Component} from 'react';
import { withTranslation, Trans } from 'react-i18next';
import logo from './logo.svg';
import './Home.css';
class Home extends Component {
render() {
const { t, i18n } = this.props;
const changeLanguage = (lng) => {
i18n.changeLanguage(lng);
return (
<div className="Home">
<div className="Home-header">
<img src={logo} className="Home-logo" alt="logo"/>
<h2>{t('Welcome to React.js')}</h2>
<button onClick={() => changeLanguage('el')}>el</button>
<button onClick={() => changeLanguage('en')}>en</button>
</div>
<div className="Home-container">
<div className="Home-items">
<div className="Home-item">
<h3 className="focus">
{t('Declarative')}
</h3>
<div><p>
<Trans name={'React.js'}>
React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.
</Trans>
</p>
<p><Trans>Declarative views make your code more predictable and easier to debug.</Trans></p>
</div>
</div>
</div>
</div>
</div>
// extended main view with translate hoc
export default withTranslation('translations')(Home);
import React, {Component} from 'react';
import { withTranslation, Trans } from 'react-i18next';
import logo from './logo.svg';
import './Home.css';

class Home extends Component {

  render() {
    const { t, i18n } = this.props;

    const changeLanguage = (lng) => {
      i18n.changeLanguage(lng);
    };

    return (
      <div className="Home">
        <div className="Home-header">
          <img src={logo} className="Home-logo" alt="logo"/>
          <h2>{t('Welcome to React.js')}</h2>
          <button onClick={() => changeLanguage('el')}>el</button>
          <button onClick={() => changeLanguage('en')}>en</button>

        </div>
        <div className="Home-container">
          <div className="Home-items">
            <div className="Home-item">
              <h3 className="focus">
                {t('Declarative')}
              </h3>
              <div><p>
                <Trans name={'React.js'}>
                  React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.
                </Trans>
              </p>
                <p><Trans>Declarative views make your code more predictable and easier to debug.</Trans></p>
              </div>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

// extended main view with translate hoc
export default withTranslation('translations')(Home);

We need to wrap our component with the withTranslation HOC passing our namespace. Then we have access to our translations. The Trans component enables you to nest any react content to be translated as one string. Supports both plural and interpolation.

We also added a little language switcher there. If you try to use it you may notice that the switch happens almost instantly and it does not reload the page.

i18next is a huge framework and it supports all the major javascript frameworks over there. I suggest you give it a try and see what a complete solution it is.

Concluding our list of libraries for Reach i18n

When it comes to internationalizing your React apps, it’s important to provide a holistic and future-proof solution that will not inhibit your development efforts. At the end of the day, it’s not just updating some JSON files. Fortunately, Phrase can make your life as a developer easier! To learn more about Phrase, please refer to the Getting Started guide.

If you found these libraries helpful, stay tuned for more on our blog because we still have some substantial answers to deliver. Internationalization has a lot of factors you need to consider to provide the best locale experience for your ever-growing international user base.


Authored by Theo. Last updated on February 16th, 2022 .
3.8 (76.13%) 320 votes
Comments

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK