React i18next and correct way of changing language

Hopefully this helps someone in the future. The documentation doesn't exactly give you the full picture of how to set up detection, and then I found a closed Github issue where several people were asking a reasonable question, and the maintainers were kinda rude in their responses but also happened to supply a link that should have been in the documentation - but is referenced absolutely no where outside of that Github comment. That example cleared up my issue with a few small adjustments from what the current documentation states to do.

I was then able to get language detection in my url with https:www.domain.com?lng=es as well as when using a browser extension that let me change the browser language.

Heres my working i18n.ts file:

import i18n from 'i18next'
import LanguageDetector from 'i18next-browser-languagedetector'
import { initReactI18next } from 'react-i18next'
import XHR from "i18next-http-backend" // <---- add this

import commonDe from './locales/de/common.json'
import commonEn from './locales/en/common.json'
import commonEs from './locales/es/common.json'
import commonFr from './locales/fr/common.json'

const resources = {
  de: { common: commonDe },
  en: { common: commonEn },
  es: { common: commonEs },
  fr: { common: commonFr }
}

const options = {
  order: ['querystring', 'navigator'],
  lookupQuerystring: 'lng'
}

i18n
  .use(XHR) // <---- add this
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    // lng: 'en' // <--- turn off for detection to work
    detection: options,
    resources,
    ns: ['common'],
    defaultNS: 'common',
    fallbackLng: 'en',
    supportedLngs: ['de', 'en', 'es', 'fr'],
    interpolation: {
      escapeValue: false,
    },
    debug: false,
  })

export default i18n

(bonus help - if theres anyone jammed up on this part)

I am working in a Next.js project, and the above file was loaded in the project-root/pages/_app.tsx file like this:

import React from 'react'
import { AppProps } from 'next/app'
import '../i18n/i18n'

import '../public/styles.css'

const TacoFridayApp = ({ Component, pageProps}: AppProps): JSX.Element => {
  
  return <Component {...pageProps} />
}

export default TacoFridayApp

According to the documentation, you shouldn't need to specify the language yourself:

import i18next from 'i18next';
import LngDetector from 'i18next-browser-languagedetector';

i18next
  .use(LngDetector)
  .init({
    detection: options
  });

And according to this piece of source in i18next, it indeed uses the detection capabilities of the plugin:

if (!lng && this.services.languageDetector) lng = this.services.languageDetector.detect();

Is this the correct way of doing it?

So, no, it isn't . Let the plugin do it's job. :)


I think you are very close. You can just set i18n with fallback language initially. And then after loading saved language information for localstorage or localforage or whatever storage, call i18nInstance.changeLanguage(lng).