Create a Multi-Language Website with React Context API

halilcanozcelik

Halil Can Ozcelik

Posted on November 7, 2019

Create a Multi-Language Website with React Context API

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.

And here is the live POC of the project.
(This link exists on the Github Repo too)

First, I strongly suggest taking a glance at the React Context API and useContext Hook documents from the official React website.

And here we go! This is the folder structure of the project:
Folder Structure

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!"
}
Enter fullscreen mode Exit fullscreen mode

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'
};
Enter fullscreen mode Exit fullscreen mode

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
});
Enter fullscreen mode Exit fullscreen mode

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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;
};
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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.

💖 💪 🙅 🚩
halilcanozcelik
Halil Can Ozcelik

Posted on November 7, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related