react-i18next: Unable to have multiple i18next instances (React apps) on the same page

I have a page which contains 2 React apps, each having their own i18n.js config file like the one below. The last app to load seems to conflict with the “translation” namespace of the first app and triggers an error. The only way that I can have both of them load successfully is to import the i18n.js from the first app and add additional namespaces to it at runtime. However, doing it this way creates a dependency between two unrelated apps.

// React App #1
// project/src/ReactApp1/i18n.js

i18n
    .use(LanguageDetector)
    .use(initReactI18next)
    .init({
        fallbackLng: "en",
        interpolation: {escapeValue: false},
        resources: {
            "en": {translation: require("./translations/en.json")},
        },
    });

export default i18n;
// Workaround for React App #2
// project/src/ReactApp2/i18n.js

// Ideally I would like to use a config file like the one above instead of this one which
// depends on the first config.
import i18n from "../ReactApp1/i18n";

i18n.addResourceBundle("en", "a_different_namespace", require("./translations/en.json"));

export default i18n;

Occurs in react-i18next version i18next 14.1.1 / react-i18next 10.0.2

Expected behaviour I expected that two separate i18next instances would not overwrite each other’s translation namespaces.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 6
  • Comments: 26 (10 by maintainers)

Most upvoted comments

It worked! I left an example for any future readers:

Edit j27n3k65yw

I appreciate your assistance with my issue and also the great work you have put into i18next!

@msheakoski thanks, unfortunately, your CSB link leads to a 404

I have created two separate instances as you suggested in your last comment, but the second instance still contains translations from the namespace of the first instance:

Instance 1

import * as LanguageDetector from "i18next-browser-languagedetector";
import i18n from "i18next";
import {initReactI18next} from "react-i18next";

const newInstance1 = i18n.createInstance();

newInstance1
    .use(LanguageDetector)
    .use(initReactI18next)
    .init({
        fallbackLng: "en",
        interpolation: {
            escapeValue: false,
        },
        resources: {
            "en": {translation: require("./translations/en.json")},
            "en-GB": {translation: require("./translations/en-GB.json")},
        },
    });

export default newInstance1;

Instance 2

import * as LanguageDetector from "i18next-browser-languagedetector";
import i18n from "i18next";
import {initReactI18next} from "react-i18next";

const newInstance2 = i18n.createInstance();

newInstance2
    .use(LanguageDetector)
    .use(initReactI18next)
    .init({
        fallbackLng: "en",
        interpolation: {
            escapeValue: false,
        },
        resources: {
            "en": {translation: require("./translations/en.json")},
        },
    });

export default newInstance2;

When I log the i18n instance in the second app via const {t, i18n} = this.props; console.log(i18n); i18n.store.data contains translations from the first instance.

Ah and further your using same react-i18next for both apps? If so .use(initReactI18next) won’t work as it’s one global state. You will need to use the I18nextProvider: https://react.i18next.com/latest/i18nextprovider#what-it-does to pass i18n to your JSX tree

Is that possible to enable typings somehow if multiple instances are used?

It worked! I left an example for any future readers:

Edit j27n3k65yw

I appreciate your assistance with my issue and also the great work you have put into i18next!

Hi, the link is not working anymore

@angusryer simpler would be to create a custom backend that handles both or using https://github.com/i18next/i18next-chained-backend on the same instance

having multiple instances is doable by using: https://react.i18next.com/latest/i18nextprovider (allows also nesting if the right context provider wraps the inner components)

mixing instances in same component could be some extra work as you can’t use the provider in that case but have to import the needed instances yourself and use the t function from them

regarding tests…if those are unit tests even if you use the unmocked t…you still somehow inject an i18n instance to the component (using provider or whatever)…I would move those assertions for right i18n usage to e2e tests.

Thanks for helping me explore this. I managed to remove the need for two instances by just fetching another translation resource after login and using addResourceBundle to merge it with the existing one from the first instance. This ended up being quite easy 🤗

For tests, after removing one i18n instance, I created a __mock__ folder with a near-copy of my actual i18n config module (but made to be synchronous). Then I had to add jest.mock('../my/custom/i18n') to all my test files

in your component library using the newly created instance don’t use .use(initReactI18next) only work with wrapping into the i18nextProvider

Thank you for your advice, @jamuhl! I will give this a try in the next day and report my results. Does the <I18nextProvider> tag need to be outside of my <App> component, or can I put it as the outermost tag inside of my <App>'s render method like this?

class App {
  render() {
    return (
      <I18nextProvider i18n={i18n}>
        <div>Hello, world!</div>
        <OtherComponent/>
      </I18nextProvider>
    );
  }
}