Search code examples
reactjstypescripti18nextreact-i18next

How to use i18next on a custom Typescript library and a host at the same time?


I am making a typescript library that accepts an object and spits out an excel. This library is supposed to be used with several React apps. Each React app[Host] will provide an object and the custom library returns an excel.

All the React apps use i18next for translation. The custom library also needs to use its own set of translations so that also has i18next. I am trying to avoid passing the translation strings from the Host to my library.

Problem: As soon as I call any function in my library, i18next in the library takes over the i18n of Host. This is expected, As we have two i18next.init() functions [One in my library and one in the host]. Whoever gets called last wins [Library in my case]. All the translation strings in the Host are noted to be missing [by the i18nxt of library] since the newly initialized i18next in the library can't see Host translations.

Question:

How can I approach this problem, if I need to keep i18n on both the library and host? I am expecting both to have their own translations.

I believe you won't need any code to understand the problem.


Solution

  • As I have updated my question, I have managed to get this working. In my case, I have multiple react host apps which use my library. Some hosts don't have i18next installed and some already have it as a dependency. I needed a way to detect whether i8next is initialized or not. If it is not initialized initialize it with the excel generation library resources. Below is the code where I am detecting and adding/updating the resources based on the status of i18next. For my library resources, I am using a namespace so there won't be a name collition. You can access your library resources like t("tkdirectequibuild:heading"). I had to specify the namespace along with key always, which is not that bad. I kept lang as optional as i18next can detect the language in case of an already instantiated host.

    import i18next from "i18next";
    import enResources from "./translations/en/translation.json";
    import frResources from "./translations/fr/translation.json";
    
    export function addExcelResource(lang?: string) {
      if (i18next.isInitialized) {
        console.info("i18Next Exists");
        if (!i18next.hasResourceBundle("en", "tkdirectequibuild")) {
          console.info("en-Added");
          i18next.addResourceBundle("en", "tkdirectequibuild", enResources);
        }
        if (!i18next.hasResourceBundle("fr", "tkdirectequibuild")) {
          console.info("fr-Added");
          i18next.addResourceBundle("fr", "tkdirectequibuild", frResources);
        }
        if (lang) {
          i18next.changeLanguage(lang);
        }
      } else {
        console.info("i18Next is missing in the HOST. Adding our own");
        i18next.init({
          lng: lang,
          ns: ["tkdirectequibuild"],
          initImmediate: false,
          resources: {
            en: {
              tkdirectequibuild: enResources,
            },
            fr: {
              tkdirectequibuild: frResources,
            },
          },
        });
      }
    
      return i18next;
    }
    

    In the calling library function, I added these lines,

    const i18n = addExcelResource(lang); const { t } = i18n;