DEV Community

Cover image for Building a multi-language app with React JS 🌐

Building a multi-language app with React JS 🌐

Franklin Martinez on February 17, 2023

Nowadays, creating an app that supports multiple languages is becoming more and more indispensable to reach a wide range of users. So this time, wi...
Collapse
 
abdulkarimogaji profile image
Abdulkarim •

Exactly what i need right now, thanks alot!!

Collapse
 
flash010603 profile image
Usuario163 •

this post is just what I need! thanks!

Collapse
 
giansake profile image
Giammarco •

Thanks a lot for the tutorial! 🙌

I would like to suggest a small enhancement in App.tsx to ensure the <html> lang attribute updates dynamically whenever the language changes.
Here is my two cents:

import { Suspense, useEffect } from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import { Menu } from "./components/Menu";
import Homepage from "./pages/Homepage";
import { useTranslation } from "react-i18next";

import "./App.css";

function App() {
  const { i18n } = useTranslation();

  useEffect(() => {
    const updateHtmlLang = (lng: string) => {
      document.documentElement.lang = lng;
    };

    updateHtmlLang(i18n.language);

    i18n.on("languageChanged", updateHtmlLang);

    return () => {
      i18n.off("languageChanged", updateHtmlLang);
    };
  }, [i18n]);
  return (
    <Suspense fallback="loading">
      <BrowserRouter>
        <Menu />
        <Routes>
          <Route path="/" element={<Homepage />} />
        </Routes>
      </BrowserRouter>
    </Suspense>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode
Collapse
 
bogdanfromkyiv profile image
Bogdan Bendziukov •

Great article, thanks for sharing!

I have a question about this function: getCurrentLang(). You put it into src/i18n.ts file but never implemented it. So how can I save user's choice of selected language? So user won't need to change language from default each time page reloads/switches to another?

Collapse
 
paulv profile image
Pavlos Vaxevanis • • Edited

it would be nice to add the selected language to the local storage. Something like this perhaps:

const LanguagePicker = () => {
  const { i18n, t } = useTranslation();

  const onChangeLang = (value: string) => {
    const lang_code = value;
    i18n.changeLanguage(lang_code);
    setStorage('lang', lang_code, 18000000);
  };

  const storageLang = getStorage('lang');

  if (LANGUAGES.length < 1) return <></>;

  return (
    <select
      style={{ width: 80 }}
      onChange={onChangeLang}
      defaultValue={storageLang.length ? storageLang : i18n.language}
    >
      {LANGUAGES.map(({ code, label }) => (
        <option key={code} value={code}>
          {label}
        </option>
      ))}
    </select>
  );
};
Enter fullscreen mode Exit fullscreen mode

// import from utils

export const setStorage = (key: string, value: any[] | string, ttl: number) => {
  const now = new Date();

  // `item` is an object which contains the original value
  // as well as the time when it's supposed to expire
  const item = {
    value: value?.length > 0 ? value : [],
    expiry: now.getTime() + ttl,
  };
  localStorage.setItem(key, JSON.stringify(item));
};
Enter fullscreen mode Exit fullscreen mode
export const getStorage = (key: string) => {
  const itemStr = localStorage.getItem(key);
  if (!itemStr) {
    return [];
  }
  const item = JSON.parse(itemStr);
  const now = new Date();
  // compare the expiry time of the item with the current time
  if (now.getTime() > item.expiry) {
    // If the item is expired, delete the item from storage
    localStorage.removeItem(key);
    return [];
  }
  return item.value;
};
Enter fullscreen mode Exit fullscreen mode
Collapse
 
reza_tavakoli profile image
Reza Tavakoli •

Hi everyone, I have a problem here
All I found in this document is static and hardcode. I mean when we want to translate something english to arabic for example we have to define it in a json file.
Now I have a problem with my admin that he wanna upload new post or even update previous posts that I didn't define these new word in my json file.
To solve this problem what do you suggest?

Collapse
 
paulv profile image
Pavlos Vaxevanis •

You could make a simple cms app thats stores the translations and serves them through an endpoint (or serve the files directly) or just serve the files from a github page and give write access to your admin. repo: github.com/vaxevanis/i18nTranslations, translation file: vaxevanis.github.io/i18nTranslatio.... I hope that helps

Collapse
 
mshariq profile image
Muhammad Shariq •

Thank you for the comprehensive tutorial!!!

Collapse
 
imoaazahmed profile image
Moaaz Ahmed •

Amazing way to descripe the steps, really helps a lot 🙏

I just have a small enhancement to make the host dynamically fetched.

loadPath: `${window.location.origin}/i18n/{{lng}}.json`,
Enter fullscreen mode Exit fullscreen mode
Collapse
 
mohamedaldik profile image
Mohamed Aldik •

It makes the loadPath more flexible. Thanks

Collapse
 
awicone profile image
Vadim Ryabov •

Great, thanks. Just change 18n to i18n.use(initReactI18next)...

Collapse
 
parnazpirhadi profile image
parnazphd •

hi , thank you a lot for your post , i have a suggestion for changing layout
you can use document.body.dir = i18n.dir() to change the direction of layout.

Collapse
 
basehunter profile image
Nomen Ama •

This is fantastic. Would be even better if you includes adding the language path to the URL