Search code examples
reactjsi18nextreact-i18next

react-i18next: How can I get text in a language, that is not my current selected one?


I have the following problem: I use react with i18next and also use i18next-backend to load my translation-files. I have a languageSwitcher that I want to use not only to change the language but also to change the URL. But I need to access the namespace 'routes' of the new language before changing the language. How can I do this?

This is my i18n config:

i18n
  .use(initReactI18next)
  .use(detector)
  .use(HttpApi)
  .init({
    defaultNS: 'routes',
    fallbackLng: ['de'],
    supportedLngs: ['de', 'en'],

    detection: {
      order: ['path'],
      lookupFromPathIndex: 0,
    },
    backend: {
      loadPath: '/locales/{{lng}}/{{ns}}.json',
    },

    keySeparator: false,

    interpolation: {
      format,
    },
  });

export default i18n;

My Langugage Selector uses this function:

changeLanguage = (ln) => {
  const routes = i18n.getResourceBundle(i18n.language, 'routes');
  const currentPathname = window.location.pathname.replace(/\/+$/, '');
  let currentRouteKey = Object.keys(routes).find((key) => routes[key] === currentPathname);
  if (ln === 'en' && currentPathname === '') {
    currentRouteKey = '/en';
  }
  window.location.replace(this.props.t('routes:' + currentRouteKey, { lng: ln }));
};

German is my fallback language and the language change works when I start on the english version of my application, but it doesn't work when I start from the german version. I guess that's because the english file isn't loaded. How can I trigger this file?


Solution

  • Instead of full page reload (using location.replace) you can trigger i18next.changeLangauge to change the language, at the background the lib will load the missing language, and then you can use the History Api to change the URL.

    // pseudo code
    
    changeLanguage = (ln) => {
      i18n.changeLanguage(lng, (err) => {
          if (err) {
            // handle language change error
          }
    
          const pathnameParts = window.location.pathname.split("/");
          const currentLangPath = pathnameParts[1]; // skips the first slash
          let newPathnameParts = pathnameParts;
          if (i18n.options.supportedLngs.includes(currentLangPath)) {
            newPathnameParts = newPathnameParts.slice(2); // removes the lang part
          }
    
          newPathnameParts = [lngSubPaths[lng]].concat(
            newPathnameParts.filter(Boolean)
          );
    
          const newPathname = newPathnameParts.join("/");
    
          if (newPathname !== window.location.pathname) {
            window.history.pushState(null, "", newPathname);
          }
        });
    };
    

    Working codesandbox example