Outskirt development

I18n using React context

September 15, 2019

react
programming

In its simplest declination I18n means providing a value from a dictionary based on a key.

Babel-fish

So the idea here is to leverage react context to provide the dictionary, and then provide the value to our application through a utility function, which will be a wrapper of the context declared earlier.


To start we create the context and provide no initial value (the idea of keeping the initial value empty is something that resembles my ideal app flow where the dictionary is fetched on the run from somewhere).

// App.js
const LangCtx = React.createContext()

We’ll use the standard create-react-app boilerplate as example, and wrap the App with the context provider:

// App.js

// we export the context for the consumer component...
export const LangCtx = React.createContext()
function App() {
  return (
    <LangCtx.Provider value={{hello: 'hola'}} >      <div className="App">
       ...
      </div>
    </LangCtx.Provider>  );
}

At this point we’ll create a component which receives a single str attribute
and either translates the string (based on the context dictionary)
or returns that same string (in case no translation or dictionary is provided).

// I18n.js
import React, { useContext } from "react";

import { LangCtx } from "./App";

const I18n = ({ str }) => {  const dict = useContext(LangCtx);  const translated = dict && dict[str] ? dict[str] : str;  return <span>{translated}</span>;};

We’ll also provide a wrapper function for this component:

export const withLang = str => <I18n str={ str } />

Now we can import withLang and use it where ever we need it!

// App.js

import { withLang } from "./I18n"
function App() {
  return (
    <LangCtx.Provider value={{ hello: "ciao" }}>
      <div className="App">
        <h1> {withLang("hello")}</h1>        ...
      /div>
    </LangCtx.Provider>
  );
}

The fact that we hardcode the value we’re providing doesn’t give much advantage,
so to spice up things a little bit I’ll provide some sample dictionaries,
and rotate them with setTimeout/useState inside App.js.

// App.js
import React, { useState } from "react";

import { withLang } from "./I18n";
export const LangCtx = React.createContext();
const eng = { hello: "hello" };
const ita = { hello: "ciao" };
const spa = { hello: "hola" };
const fre = { hello: "salut" };
const por = { hello: "olá" };

const langs = [eng, ita, spa, fre, por];
let i = 0;

function App() {
    const [dict, setDict] = useState();

      setTimeout(() => {
        i++;
        setDict(langs[i % langs.length]);
      }, 2000);

      return (
        <LangCtx.Provider value={dict}>
          <div className="App">
            <h1> {withLang("hello")}</h1>
          </div>
        </LangCtx.Provider>
      );
}
export default App;

The asynchronous change of dictionary should resemble a fetch to the API…

If you want to elaborate on this post take a look at the repo (tag v1.0 is the version up to here).


Francesco Calo

Francesco Calo developing on linux in La Spezia.
Just a programming journey.