🐛(i18n) same frontend and backend language using shared cookies

frontend: switch to cookie-based language selection
backend: use cookie for language
This commit is contained in:
rvveber
2024-10-22 18:17:53 +02:00
committed by Anthony LC
parent ff364f8b3d
commit 3c374e3cc7
9 changed files with 58 additions and 96 deletions

View File

@@ -23,6 +23,7 @@
"@openfun/cunningham-react": "2.9.4",
"@tanstack/react-query": "5.59.15",
"i18next": "23.16.2",
"i18next-browser-languagedetector": "8.0.0",
"idb": "8.0.0",
"lodash": "4.17.21",
"luxon": "3.5.0",

View File

@@ -1,55 +0,0 @@
import { LANGUAGE_LOCAL_STORAGE } from '../conf';
import { getLanguage, splitLocaleCode } from '../utils';
describe('i18n utils', () => {
afterEach(() => {
localStorage.removeItem(LANGUAGE_LOCAL_STORAGE);
});
it('checks language code is correctly splitted', () => {
expect(splitLocaleCode('fr_FR')).toEqual({ language: 'fr', region: 'FR' });
expect(splitLocaleCode('en_US')).toEqual({ language: 'en', region: 'US' });
expect(splitLocaleCode('en')).toEqual({
language: 'en',
region: undefined,
});
expect(splitLocaleCode('fr-FR')).toEqual({ language: 'fr', region: 'FR' });
expect(splitLocaleCode('en-US')).toEqual({ language: 'en', region: 'US' });
});
it('checks that we get expected language from local storage', () => {
localStorage.setItem(LANGUAGE_LOCAL_STORAGE, 'fr_FR');
expect(getLanguage()).toEqual('fr');
localStorage.removeItem(LANGUAGE_LOCAL_STORAGE);
localStorage.setItem(LANGUAGE_LOCAL_STORAGE, 'en_FR');
expect(getLanguage()).toEqual('en');
localStorage.setItem(LANGUAGE_LOCAL_STORAGE, 'xx_XX');
expect(getLanguage()).toEqual('fr');
});
it('checks that we get expected language from browser', () => {
Object.defineProperty(navigator, 'language', {
value: 'fr',
writable: false,
configurable: true,
});
expect(getLanguage()).toEqual('fr');
Object.defineProperty(navigator, 'language', {
value: 'en',
writable: false,
configurable: true,
});
expect(getLanguage()).toEqual('en');
Object.defineProperty(navigator, 'language', {
value: 'xx',
writable: false,
configurable: true,
});
expect(getLanguage()).toEqual('fr');
});
});

View File

@@ -2,5 +2,5 @@ export const LANGUAGES_ALLOWED: { [key: string]: string } = {
en: 'English',
fr: 'Français',
};
export const LANGUAGE_LOCAL_STORAGE = 'impress-language';
export const BASE_LANGUAGE = 'fr';
export const LANGUAGE_COOKIE_NAME = 'docs_language';
export const BASE_LANGUAGE = 'en';

View File

@@ -1,15 +1,23 @@
import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import { initReactI18next } from 'react-i18next';
import { LANGUAGES_ALLOWED, LANGUAGE_LOCAL_STORAGE } from './conf';
import { BASE_LANGUAGE, LANGUAGES_ALLOWED, LANGUAGE_COOKIE_NAME } from './conf';
import resources from './translations.json';
import { getLanguage } from './utils';
i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
resources,
lng: getLanguage(),
fallbackLng: BASE_LANGUAGE,
supportedLngs: Object.keys(LANGUAGES_ALLOWED),
detection: {
order: ['cookie', 'navigator'], // detection order
caches: ['cookie'], // Use cookies to store the language preference
lookupCookie: LANGUAGE_COOKIE_NAME,
cookieMinutes: 525600, // Expires after one year
},
interpolation: {
escapeValue: false,
},
@@ -20,11 +28,4 @@ i18n
throw new Error('i18n initialization failed');
});
// Save language in local storage
i18n.on('languageChanged', (lng) => {
if (typeof window !== 'undefined') {
localStorage.setItem(LANGUAGE_LOCAL_STORAGE, lng);
}
});
export default i18n;

View File

@@ -1,28 +0,0 @@
import {
BASE_LANGUAGE,
LANGUAGES_ALLOWED,
LANGUAGE_LOCAL_STORAGE,
} from './conf';
export const splitLocaleCode = (language: string) => {
const locale = language.split(/[-_]/);
return {
language: locale[0],
region: locale.length === 2 ? locale[1] : undefined,
};
};
export const getLanguage = () => {
if (typeof window === 'undefined') {
return BASE_LANGUAGE;
}
const languageStore =
localStorage.getItem(LANGUAGE_LOCAL_STORAGE) || navigator?.language;
const language = splitLocaleCode(languageStore).language;
return Object.keys(LANGUAGES_ALLOWED).includes(language)
? language
: BASE_LANGUAGE;
};