react-routerlocalizationinternationalizationi18nextreact-i18next

How to translate location URL when changing language?


I am currently facing a wall in the localization process of a website. Using i18next, all of our routes are translated and default language has the locale path removed from the URL.

In other words:
/accueil -> /en/home
/produits -> /en/products
and so on...

My issue is when I change the language, the url does not follow (which is to be expected, since i18next doesn't talk directly to react-router).

i18next configuration:

i18n
  .use(detector)
  .use(initReactI18next)
  .init({
    whitelist: ['fr', 'en'],
    fallbackLng: 'fr',
    defaultNS: 'common',

    detection: {
      lookupFromPathIndex: 0,
      checkWhitelist: true
    },

    interpolation: {
      escapeValue: false
    },

    resources: {
      en: {
        routes: enRoutes,
        [...]
      },
      fr: {
        routes: frRoutes,
        [...]
      }
    }
  });

fr/routes.json:

{
  "home": "/accueil",
  "products": "/produits",
  [...]
}

en/routes.json:

{
  "home": "/en/home",
  "products": "en/products",
  [...]
}

Router portion in app.jsx:

<Router forceRefresh>
  <Switch>
    <Route path={`/:locale(en|fr)?${t('routes:home')}`} component={HomeComponent} />
    <Route path={`/:locale(en|fr)?${t('routes:products')}`} component={ProductsComponent} />
  </Switch>
</Router>

With the following configuration, pages render without issue and easily translate when i18n.changeLanguage is called, but the url doesn't change with it. I've searched everywhere and can't seem to find a go-to approach to translate the url once the language is changed.

I also want to handle a case where the user would change the locale manually directly in the browser url field.

I have tried updating the url on 'languageChanged' event in i18next, but finding the key to the page currently being since adds a lot of complications.

Thx in advance for any help provided.


Solution

  • I finally found an easy and clean method to change the route while also changing the language.

      const changeLanguage = (nextLanguage) => {
        const routes = i18n.getResourceBundle(i18n.language, 'routes');
        const currentPathname = window.location.pathname.replace(/\/+$/, '');
        const currentRouteKey = Object.keys(routes).find((key) => routes[key] === currentPathname);
    
        window.location.replace(t(`routes:${currentRouteKey}`, { lng: nextLanguage }));
      };
    

    I also needed to change the i18next detection options as follow:

    detection: {
      order: ['path', ...otherMethods]
      lookupFromPathIndex: 0,
      checkWhitelist: true
    },
    

    I can now safely call this changeLanguage wrapper anywhere and it will handle both the language change (which goes to the default in case it's not part of the url) and the route change.