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
 
flash010603 profile image
Usuario163

this post is just what I need! thanks!

Collapse
 
abdulkarimogaji profile image
Abdulkarim

Exactly what i need right now, thanks alot!!

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
 
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
 
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
 
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
 
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
 
mshariq profile image
Muhammad Shariq

Thank you for the comprehensive tutorial!!!

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

Collapse
 
awicone profile image
Vadim Ryabov

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