Better approach for using i18next library - but I don't know how to achieve it

68 views Asked by At

My question is at the bottom of the post

import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import { Provider } from "react-redux";
// Bootstrap CSS
import "bootstrap/dist/css/bootstrap.min.css";
// Bootstrap Bundle JS
import "bootstrap/dist/js/bootstrap.bundle.min";
import "./styles/index.scss";
import { store } from "./store/store.ts";
import i18next from "i18next";
import { initReactI18next } from "react-i18next";
import HttpApi from "i18next-http-backend";
import LanguageDetector from "i18next-browser-languagedetector";
import { Suspense } from "react";


i18next
  .use(HttpApi)
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    supportedLngs: ["en", "hr"],
    fallbackLng: "en",
    debug: false,
    backend: {
      loadPath: "/locales/{{lng}}/translation.json",
    },
  });

const loadingMarkup = (
  <div className="py-4 text-center">
    <h3>Loading..</h3>
  </div>
);

ReactDOM.createRoot(document.getElementById("root")!).render(
  <Provider store={store}>
    <Suspense fallback={loadingMarkup}>
      {/* EVERYTHING WILL BE LOADED ONLY AFTER LANGUAGE JSON IS FETCHED 
          you can now use translations in components without fear */}
      <App />
    </Suspense>
  </Provider>
);

This presupposes I have json file for every language in public folder:

public/locales/en/translation.json:
{
  "welcome_message": "Welcome to the app"
  "go_back": "Go back"
}

public/locales/de/translation.json:
{
  "welcome_message": "Willkommen in der App"
  "go_back": "Geh zurück"
}

But I want to have one main json file with translations for every language, like this:

public/locales/translations.json:
{
  "welcome_message": {
    "en": "Welcome to the app",
    "de": "Willkommen in der App"
  }
  "go_back": {
     "en": "Go back",
     "de": "Geh zurück"
  }
}

When specific language is requested from browser, this main file is used to generate json file for that language. For example, if "en" is requested, returned file is:

{
  "welcome_message": "Welcome to the app!",
  "go_back": "Go back"
}

My proposed approach is more organized and less error prone. I am pretty frustrated that this is not default way how i18next works. Is it possible to achieve it somehow?

I cannot find any resource talking about this problem. AI chatbots are also pretty useless. I think it is possible to do it pretty easily by storing translation files on some separate server (like node + express) and requesting jsons from it, but I want solution with using only react.

1

There are 1 answers

0
hokwanhung On

I would post my answer for the sake of attracting even better ideas. In the i18next's plugins documentation, there are quite a few plugins for formatting the translation files.

The plugin that could help is the i18next-shopify one; it can allow the below formatting; though you must still specify a default language, you can do something like this:

import i18next from "i18next";
import ShopifyFormat from "@shopify/i18next-shopify";

i18next.use(ShopifyFormat).init({
  lng: "en",
  resources: {
    en: {
      translation: {
        welcome_message: {
          "en": "Welcome to the app",
          "de": "Willkommen in der App",
        },
        go_back: {
          "en": "Go back!",
          "de": "Geh zurück",
        },
      },
    }
  }
});

i18next.t("welcome_message.en"); // -> Welcome to the app
i18next.t("go_back.de"); // -> Geh zurück

However, I would say even though this solution could work, it is a solution with an extra step, and react-i18next (and also i18next) does always prefer the format of ./locales/{language}/{namespace}.json.

It is just a common practice to separate translation files with languages, and if you want to clarify the structure of the files, you can use namespace as the principles suggest.

Hope the above answer will help.