Tutorial

I18n with React and i18next

Published on October 24, 2017
Default avatar

By Danny Hurlburt

I18n with React and i18next

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

More and more apps are being designed for the global market which means your app will need to work for an audience using various languages and dialects. React does not have internationalization (i18n) built-in, but it is not hard to internationalize an app, especially with the help from i18next.

i18next is an i18n framework written in and for JavaScript. It provides the standard i18n features of interpolation, formatting, and handling plurals and context.

A 30,000 foot view of i18next would be that it provides a function that takes a key, some options, and returns the value for the current language.

The following is a simple example of using the aforementioned function with a simple key and no options.

i18n.t('error') // 'An error occurred' in English and
                // 'Ocurrió un error' in Spanish.

Because the function will likely be called several times in an app, the creators of i18next have chosen a shortname: t – which is short for translate. It is common to see the t function in the i18next documentation and you will see it used here in this post.

Although i18next is designed to work with many frameworks, this post will focus on how to internationalize a React app using i18next.

In order to use i18next with React, the t function needs to be made available to the components that need to be internationalized. This can be done by various means. We’ll demonstrate a couple below.

Manual Integration

Before i18next can be used, it needs to be configured. Here is the configuration used by the examples in this post. It turns off value-escaping since React already takes care of that for us, it sets the current language to English, and it hardcodes translations for two languages (English and Spanish). See the i18next configuration for more options.

Module: i18n.js
import i18next from 'i18next';

i18next
  .init({
    interpolation: {
      // React already does escaping
      escapeValue: false,
    },
    lng: 'en', // 'en' | 'es'
    // Using simple hardcoded resources for simple example
    resources: {
      en: {
        translation: {
          age: { label: 'Age', },
          home: { label: 'Home', },
          name: { label: 'Name', },
        },
      },
      es: {
        translation: {
          age: { label: 'Años', },
          home: { label: 'Casa', },
          name: { label: 'Nombre', },
        },
      },
    },
  })

export default i18next

Manual integration begins with importing our pre-configured instance of i18next which will provide the t function.

import React from 'react';

// Import a pre-configured instance of i18next
import i18n from './i18n';

function Gator({ gator }) {
  return (
    <div className="Gator">
      <label>i18n.t('name.label')</label>
      <span>{ gator.name } 🐊</span>
      <label>i18n.t('age.label')</label>
      <span>{ gator.age }</span>
      <label>i18n.t('home.label')</label>
      <span>{ gator.home }</span>
    </div>
  )
}

Although the example above will render the labels using the current language (English), the labels won’t be updated after the language changes since React does not yet know how to determine when the language has changed. So, let’s tweak the code to re-render the component when the language changes.

import React from 'react';

// Import a pre-configured instance of i18next
import i18n from './i18n';

class Gator extends React.Component {

  constructor(props) {
    super(props)
    this.state = {
      lng: 'en'
    }
    this.onLanguageChanged = this.onLanguageChanged.bind(this)
  }

  componentDidMount() {
    i18n.on('languageChanged', this.onLanguageChanged)
  }

  componentWillUnmount() {
    i18n.off('languageChanged', this.onLanguageChanged)
  }

  onLanguageChanged(lng) {
    this.setState({
      lng: lng
    })
  }

  render() {
    let gator = this.props.gator,
        lng = this.state.lng

    return (
      <div>
        <label>{ i18n.t('name.label', { lng }) }</label>
        <span>{ gator.name } 🐊</span>
        <label>{ i18n.t('age.label', { lng }) }</label>
        <span>{ gator.age }</span>
        <label>{ i18n.t('home.label', { lng }) }</label>
        <span>{ gator.home }</span>
      </div>
    )
  }
}

See a working example of the above code.

Although we fixed the problem of the component not re-rendering after the language changes, we introduced a lot of boilerplate code:

  1. Added two lifecycle methods (componentDidMount and componentWillUnmount). (Which means we had to switch from a functional component to a class component.)

  2. Added an event listener so we can notify React that the language changed.

  3. Introduced a mechanism to cause the component to re-render. In the example above, state is being used. Another alternative is to call forceUpdate after the language changes.

Is there an easier way? Yes, there is!

The react-i18next Binding

Fortunately, there is an easier way with a binding: react-i18next.

import React from 'react';
import { I18n } from 'react-i18next';

// Import a pre-configured instance of i18next
import i18n_unused from './i18n';

function Gator({ gator }) {
  return (
    <I18n>
      {
        (t) => {
          return (
            <div>
              <label>{ t('name.label') }</label>
              <span>{ gator.name } 🐊</span>
              <label>{ t('age.label') }</label>
              <span>{ gator.age }</span>
              <label>{ t('home.label') }</label>
              <span>{ gator.home }</span>
            </div>
          )
        }
      }
    </I18n>
  )
}

The React binding for i18next provides the I18n component. It expects a single function expression as its children. This function will be passed the t function. (The use of a function expression as children of a component is known as the function-as-children pattern.)

A lot easier! See a working example of the above code.

So, take a look at i18next and react-i18next for more details on configuration, more advanced translation, and other binding options.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
Danny Hurlburt

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel