i18next / i18next-browser-languageDetector

language detector used in browser environment for i18next
MIT License
865 stars 88 forks source link

Language in localStorage gets overwritten on load #250

Closed mathiasmoeller closed 2 years ago

mathiasmoeller commented 2 years ago

🐛 Bug Report

I am using i18next and i18next-browser-languagedetector in my application to handle localization. When I change the language the new value gets stored in the local storage. When I refresh, the language gets reset to english (the default) and the local storage value is overwritten.

When I remove .use(LanguageDetector) the language stays the language saved in local storage.

This is a pretty basic problem and I couldn't find other bug reports so I think there is a high chance the issue is in my setup. I can't figure out where though. That's why I thought I'll open a Bug Report and see if other people face the same issue.

To Reproduce

Setup:

import i18n from 'i18next';
import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import { initReactI18next } from 'react-i18next';

const loadPath = () => {
  return '/locales/{{lng}}/{{ns}}.json';
};

i18n
  .use(Backend)
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    fallbackLng: 'en',
    load: 'languageOnly',
    detection: {
      order: ['localStorage', 'navigator'],
    },
    interpolation: {
      escapeValue: false,
    },
    backend: {
      loadPath,
    },
    react: {
      useSuspense: isDevMode,
    },
    returnObjects: true,
  });

Expected behavior

The language should still be the one saved in local storage (before refresh) after reloading the page.

Your Environment

adrai commented 2 years ago

Can you provide a codesandbox example?

mathiasmoeller commented 2 years ago

I can't reproduce it there unfortunately. I'm not overwriting the language manually anywhere so I don't know why this happens... I know it's not much to work with, I was just hoping there might be obvious issues with my setup or other people experiencing a similar behaviour since I am lost

adrai commented 2 years ago

sorry, without being able to reproduce it, I'm not able to help

mathiasmoeller commented 2 years ago

Okay, thanks anyways for the fast reply! I'll close the issue then to keep your Repo clean ;)

giusepperaso commented 2 years ago

This also happens to me; it seems that if you define a fallbackLng, every time you refresh the page the language gets resetted.

This fix is very ugly but it works for my use case

import i18next from "i18next";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";

import en from "./translations/en.json";
import it from "./translations/it.json";
import es from "./translations/es.json";

const resources = { en, it, es };

i18next.use(initReactI18next).init({
  resources,
  fallbackLng: (code) => {
    if (
      !Object.keys(resources).some((k) => {
        return (
          localStorage.getItem("i18nextLng") || window.navigator.language
        )?.includes(k);
      })
    ) {
      return ["en"];
    }
    return [code];
  },
  interpolation: {
    escapeValue: false,
  },
});

i18next.use(LanguageDetector).init();
adrai commented 2 years ago

@GiuseppeRaso If you could provide a reproducible example (without fix) that would help to investigate the root cause.

giusepperaso commented 2 years ago

Sorry for the late reply, here's a simulaton of the issue https://codesandbox.io/s/i18next-browser-languagedetector-issue-250-4cksh?file=/src/i18nsetup.js

To replicate the issue: 1) select en or it 2) refresh the page 3) you will see that the language is always resetted to es (the fallback language)

Without fallbackLng the behaviour looks correct, infact if you select the language A, on refresh you keep having A

So the problem lies in fallbackLng

EDIT: even without refreshing the page, you will see that es gets automatically selected at startup even if your language is en or it

adrai commented 2 years ago

Why did you init i18next twice? Why not injecting the languageDetector directly before the first init call... fyi: if setting the debug flag to true, you should see a warning about that...

btw: this example works: https://codesandbox.io/s/i18next-browser-languagedetector-issue-250-forked-ehxmt?file=/src/i18nsetup.js:279-328

giusepperaso commented 2 years ago

My bad, I thought that 'init' had to be called for every 'use' call

Thanks!