DominicSeel
DominicSeel

Reputation: 572

react-i18next with multiple translation-files

I have a little problem in my application. I use i18next and react-i18next for the translation and have already included it. The whole translation comes from 1 file for each language and that is a mess with over 4000 rows :(

Now I want update this so that i18next would take the translation files placed in the different component-folders and their children-folders.

The folder-structure should look like this after the update:

scr
- components
-- Header
---translations (en/translation.json, de/translation.json)
-- Dashboard
--- translations (en/translation.json, de/translation.json)
--- Menu
---- translations (en/translation.json, de/translation.json)
---- ExampleComponent.tsx
---- ...
--- Cards
---- translations (en/translation.json, de/translation.json)
...

I already figured out how I can handle the automatic export via babel and babel-i18next-plugin with the "namespace"

So, my code (example Menu) would be written like this:

const { t } = useTranslation("Dashboard/Menu")

const explString = t("ExampleComponent.ExampleString","This is an example")

In babel I placed the plugin like this:

[i18next-plugin, {"outputPath": "src/components/{{ns}}/translations/{{locale}}/translation.json"}]

This runs without problems. It takes the namespace as a folder-structure and places the translation-files into the translation-folder including the correct keys.

Now, how I can tell i18next, where to find the translation-files? I could only figure out that I can import the files (file-by-file) inside a resource. I tried backend plugins (html-backend, async-storage-backend, local-storage-backend and filesystem) with

backend: { loadPath: "components/{{ns}}/translations/{{lng}}/translation.json" }

(The i18next.ts is placed inside src/)

and I get the warnings that the keys aren't found.

Also, you can see that I use TypeScript.

In my webpack I tried it with the ts-i18next-loader with this inside the webpack configuration file:

  {
    test: /\translation.json$/,
    exclude: /node_modules/,
    loader: 'i18next-ts-loader',
    options: {
      localeFilesPattern: 'src/components/{{ns}}/translations/{{lng}}/translation.json',
    },
  },

If I only had 5-6 translation-files for each language / namespace it would not be a problem to put it inside the resource but at the end I have more than 100 files for each language.

Would be nice if anyone had a solution to my problem. If you need any further information I can update the post.

Cheers

Upvotes: 2

Views: 8156

Answers (3)

vvauban
vvauban

Reputation: 485

1️⃣ Use i18next-resources-to-backend

npm install i18next-resources-to-backend

2️⃣ Add in your src folder your locales files:

enter image description here

3️⃣ In your i18n.js file, change your i18n config with:

 i18n
  .use(initReactI18next) // passes i18n down to react-i18next
  .use(resourcesToBackend((language, namespace, callback) => {
    import(`./locales/${language}/${namespace}.json`)
      .then((resources) => {
        callback(null, resources)
      })
      .catch((error) => {
        console.log(error)
        callback(error, null)
      })
  }))
  .init({
    // resources,
    fallbackLng: 'fr',
    lng: 'fr',
    interpolation: {
      escapeValue: false // react already safes from xss
    }
  });

Note the additional line I needed compared to adrai answer.

ℹ the translation.json files look like:

 {
  "hi": "Hello world!"
}

Upvotes: 1

adrai
adrai

Reputation: 3168

There's an alternative plugin to be used, suggested in the official documentation: https://www.i18next.com/how-to/add-or-load-translations#lazy-load-in-memory-translations

i18next-resources-to-backend helps to transform resources to an i18next backend. This means, you can also lazy load translations, for example when using webpack:

import i18next from 'i18next';
import resourcesToBackend from 'i18next-resources-to-backend';

i18next
  .use(resourcesToBackend((language, namespace, callback) => {
    import(`./locales/${language}/${namespace}.json`)
      .then((resources) => {
        callback(null, resources)
      })
      .catch((error) => {
        callback(error, null)
      })
  }))
  .init({ /* other options */ })

Upvotes: 2

DominicSeel
DominicSeel

Reputation: 572

Found the solution. After i included the "webpack backend for i18next" it solved the problem and the translation gets the correct file.

i18next webpack backend by SimeonC

Upvotes: 0

Related Questions