Create a Multi-Language Website with React Context API
Tags: react, javascript, webdev, tutorial
Published: 2019-11-07 21:30:45

In this article, I will try to explain my approach to develop a multi-language website with React Context API. If you are used to reading code better than words, you can examine the example project from [this Github repository](https://github.com/hcoz/react-context-multilang).

And here is the [live POC of the project.](https://nice-cliff-047044a03.azurestaticapps.net)
(This link exists on the Github Repo too)

First, I strongly suggest taking a glance at [the React Context API](https://reactjs.org/docs/context.html) and [useContext Hook](https://reactjs.org/docs/hooks-reference.html#usecontext) documents from the official React website.

And here we go! This is the folder structure of the project:
![Folder Structure](https://dev-to-uploads.s3.amazonaws.com/i/nspc3g3al3iwvhyivzlx.png)

Texts are stored as JSON for each language. You can see the example for English below:
```
{
  "exploreHeader": "Explore",
  "welcomeDescription": "This is a demo app for multi-language website with React Context API",
  "clickMe": "Click Me",
  "aboutMe": "For more info about the author",
  "buttonClicked": "You clicked to button!"
}
```

All of them are stored in a dictionary object and it will be shown according to the selected language which I will explain later in this article.
```
import tr from './tr.json';
import en from './en.json';
import de from './de.json';

export const dictionaryList = { en, tr, de };

export const languageOptions = {
  en: 'English',
  tr: 'Türkçe',
  de: 'Deutsch'
};
```
The language selector is filled by `languageOptions`. User can change the language of the website from there.


I will create a context that contains the selected language and dictionary.
```
import { languageOptions, dictionaryList } from '../languages';

// create the language context with default selected language
export const LanguageContext = createContext({
  userLanguage: 'en',
  dictionary: dictionaryList.en
});
```

Then define the Context Provider. We can set the selected language and get related texts from the dictionary by this context provider.
```
// it provides the language context to app
export function LanguageProvider({ children }) {
  const defaultLanguage = window.localStorage.getItem('rcml-lang');
  const [userLanguage, setUserLanguage] = useState(defaultLanguage || 'en');

  const provider = {
    userLanguage,
    dictionary: dictionaryList[userLanguage],
    userLanguageChange: selected => {
      const newLanguage = languageOptions[selected] ? selected : 'en'
      setUserLanguage(newLanguage);
      window.localStorage.setItem('rcml-lang', newLanguage);
    }
  };

  return (
    <LanguageContext.Provider value={provider}>
      {children}
    </LanguageContext.Provider>
  );
};
```

When the language selector is changed, it will call the `userLanguageChange()` method of the provider.

You can examine the __LanguageSelector.js__ below:
```
import React, { useContext } from 'react';

import { languageOptions } from '../languages';
import { LanguageContext } from '../containers/Language';

export default function LanguageSelector() {
  const { userLanguage, userLanguageChange } = useContext(LanguageContext);

  // set selected language by calling context method
  const handleLanguageChange = e => userLanguageChange(e.target.value);
  
  return (
    <select
      onChange={handleLanguageChange}
      value={userLanguage}
    >
      {Object.entries(languageOptions).map(([id, name]) => (
        <option key={id} value={id}>{name}</option>
      ))}
    </select>
  );
};
```

And we need to wrap the main component which is __App.js__ with  `LanguageProvider`. 
```
function App() {
  return (
    <LanguageProvider>
      <div className="App">
        <header className="App-header">
          <LanguageSelector />
        </header>

        <Explore />
      </div>
    </LanguageProvider>
  );
}
```

Then, we define `Text` component to translate our texts.
```
// get text according to id & current language
export function Text({ tid }) {
  const languageContext = useContext(LanguageContext);

  return languageContext.dictionary[tid] || tid;
};
```

Now, we can use this component to gather related text according to the selected language from predefined language objects (which I mentioned at the beginning of the article).
Also, we can call the language context directly to use such as the input placeholder example below.
Here are several usage examples in a component:
```
export default function Explore() {
  const [clickText, setClickText] = useState();
  const { dictionary } = useContext(LanguageContext);

  const handleClick = () => {
    setClickText(<Text tid="buttonClicked" />);
  }

  return (
    <div>
      <h1><Text tid="exploreHeader" /></h1>
      <p><Text tid="welcomeDescription" /></p>

      <div>
        <input type="text" placeholder={dictionary.enterText} />
        <button onClick={handleClick}>
          <Text tid="clickMe" />
        </button>
        <p>{clickText}</p>
      </div>

      <a href="https://halilcanozcelik.com" target="_blank" rel="noopener noreferrer">
        <Text tid="aboutMe" />
      </a>
    </div>
  );
}
```

Additionally, the selected language should be stored in the database or local storage of the browsers and context states filled by this option at the beginning. An option of languageOptions can be used for a fallback scenario, I used English (“en”) in this project. Also, I have stored the selected language in local storage and reading from there at the beginning. If there is no info, then using browser language as the default language.
I hope it will be helpful.