0

I'm using i18next with React and Vite for loading the translation for my app. In the app, I have a child component that allows users to set a banner message in some languages, and it uses a key from the translation to display a prefill message. The child component also has a language selector but just to preview the message in other languages, not changing the app languauge. In other words, the child component uses the same translation but a different laguage state. Before applying the lazy loading translation, the child component works just fine as the translations of all the supported languages are loaded. But after implementing the lazy load, it only loads the current language, which causes the other language prefill message to display just a key.

I tried to add the trannslation under resoures for i18next init options but it won't lazy load at all. Then I've tried to add the missing bundle after the init, but it will prevent the page from loading new translation on language changes. Below is how I setup i18n and my resourcesToBackend function.

const resourcesToBackend: (res: any) => BackendModule = (res) => ({
  type: 'backend',
  init: function (services, backendOptions, i18nextOptions) {
    // no init needed
  },
  read: function (language, namespace, callback) {
    if (typeof res === 'function') {
      // in case someone wants to customize the loading...
      if (res.length < 3) {
        // no callback
        try {
          const r = res(language, namespace);
          if (r && typeof r.then === 'function') {
            // promise
            r.then((data) => {
              callback(null, (data && data.default) || data);
            }).catch(callback);
          } else {
            // sync
            callback(null, r);
          }
        } catch (err) {
          callback(err, null);
        }
        return;
      }

      // normal with callback
      res(language, namespace, callback);
      return;
    }

    callback(null, res && res[language] && res[language][namespace]);
  },
});



i18next
  .use(initReactI18next)
  .use(languageDetector)
  .use(
    resourcesToBackend(
      (language: string, namespace: string) => import(`./${namespace}-${language}.json`),
    ),
  )
  .init({
    partialBundledLanguages: true,
    supportedLngs: SUPPORTED_LANGUAGES,
    resources: {},
    defaultNS: DEFAULT_NAMESPACE,
    interpolation: {
      escapeValue: false,
    },
  })
  .then(() => {
    BANNER_SUPPORTED_LANGUAGES.forEach((lang) => {
      i18next.addResourceBundle(
        lang.toLowerCase(),
        DEFAULT_NAMESPACE,
        BANNER_PREFILL_MESSAGES[lang.toLowerCase()],
        true, // to extend the loaded resources
        true, // to update the translation if the key is available in the resources
      );
    });
  })
  .catch((e) => {
    console.log(e);
  });

Is there a way to make my case works? I want to keep the translation and anything related in the i18n only. So far I've tried the above methods, but none of them worked so maybe my last resort is to move all the translations used by the child component to the child folder.

1 Answer 1

0

Never mind, I found an easy way to adapt this using multiple instances of react-i18next from this GitHub issue. Guess I'm overthinking it.

Just create a global instance and another instance, each of which loads different translations. Then wrap the global app with <I18NextProvider i18n={globalInstance} /> and use the other instance in the child component, either wrap the component with the same I18NextProvider or using the hook const { t } = useTranslation('banner', { i18n: childInstance });. Note that you should be aware of the namespace, as they load from different files.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.