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?
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