Search code examples
reactjsinternationalizationi18nextreact-i18next

useTranslation does not re-render component on languageChanged


I'm implementing React localization using react-i18next & i18n, the i18next languageChanged fires, but the components in which I use the function t() don't re-render automatically, the UI changes only when manually reloading the page.

i18n.js

import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
i18n
  // detect user language
  .use(LanguageDetector)
  // pass the i18n instance to react-i18next.
  .use(initReactI18next)
  // init i18next
  .init({
    debug: true,
    fallbackLng: "en",
    interpolation: {
      escapeValue: false,
    },
    resources: {
      en: {
        translation: {
          greeting: "Hello",
        },
      },
      ar: {
        translation: {
          greeting: "مرحبا",
        },
      },
    },
  });

export default i18n;

main.jsx

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./i18n";
import "./index.css";

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

App.jsx

import { Suspense } from "react";
import LanguageSelector from "@/components/language/LanguageSelector";
import Home from "@/pages/root/Home";

function App() {
  return (
    <Suspense fallback={<p>laoding</p>}>
      <LanguageSelector />
      <Home />
    </Suspense>
  );
}

export default App;

LanguageSelector.jsx, the component that changes the language:

import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";

const languages = [
  { code: "en", nativeName: "English" },
  { code: "ar", nativeName: "العربية" },
];

const LanguageSelector = () => {
  const { i18n } = useTranslation();

  useEffect(() => {
    document.body.dir = i18n.dir();
  }, [i18n, i18n.language]);

  return (
    <div className="flex-center mt-10 gap-5">
      {languages.map((lng) => (
        <button
          className={`${
            lng.code === i18n.resolvedLanguage ? "bg-green-100" : ""
          } border rounded-xl p-3`}
          key={lng.code}
          onClick={() => i18n.changeLanguage(lng.code)}
        >
          {lng.nativeName}
        </button>
      ))}
    </div>
  );
};

export default LanguageSelector;

Home.jsx, the component that uses t() and does not re-render on languageChange:

import React from "react";
import { useTranslation } from "react-i18next";

const Home = () => {
  const { t } = useTranslation();
  return (
    <h1 className="flex-center h-full-screen text-4xl">{t("greeting")}</h1>
  );
};

export default Home;

I have tried this Issue's solution and added these options to i18n.js init:

react: {
      bindI18n: "loaded languageChanged",
      bindI18nStore: "added",
      useSuspense: true,
    },

And that didn't help. What am I missing?


Solution

  • I got this problem too since i upgraded react-i18next from v12.3.1 to v14.0.2 yesterday. I decided to downgrade to the former version now it' fine.