69 lines
1.8 KiB
TypeScript
69 lines
1.8 KiB
TypeScript
import i18n from "i18next";
|
|
import { initReactI18next } from "react-i18next";
|
|
|
|
import en from "./locales/en/common.json";
|
|
import de from "./locales/de/common.json";
|
|
|
|
const LANGUAGE_STORAGE_KEY = "contract-companion.language";
|
|
const SUPPORTED_LANGUAGES = ["en", "de"] as const;
|
|
|
|
type SupportedLanguage = (typeof SUPPORTED_LANGUAGES)[number];
|
|
|
|
function normalizeLanguage(value?: string | null): SupportedLanguage {
|
|
if (!value) return "en";
|
|
const lower = value.toLowerCase();
|
|
const match = SUPPORTED_LANGUAGES.find((lang) => lower.startsWith(lang));
|
|
return match ?? "en";
|
|
}
|
|
|
|
function detectInitialLanguage(): SupportedLanguage {
|
|
if (typeof window === "undefined") {
|
|
return "en";
|
|
}
|
|
|
|
try {
|
|
const stored = window.localStorage.getItem(LANGUAGE_STORAGE_KEY);
|
|
if (stored) {
|
|
return normalizeLanguage(stored);
|
|
}
|
|
} catch {
|
|
// Access to localStorage might be blocked (e.g., privacy mode); ignore and fall back to navigator.
|
|
}
|
|
|
|
return normalizeLanguage(window.navigator.language);
|
|
}
|
|
|
|
const initialLanguage = detectInitialLanguage();
|
|
|
|
i18n.use(initReactI18next).init({
|
|
resources: {
|
|
en: { translation: en },
|
|
de: { translation: de }
|
|
},
|
|
lng: initialLanguage,
|
|
fallbackLng: "en",
|
|
supportedLngs: ["en", "de"],
|
|
interpolation: {
|
|
escapeValue: false
|
|
}
|
|
});
|
|
|
|
if (typeof window !== "undefined") {
|
|
const applyLanguageSideEffects = (lang: string) => {
|
|
const normalized = normalizeLanguage(lang);
|
|
try {
|
|
window.localStorage.setItem(LANGUAGE_STORAGE_KEY, normalized);
|
|
} catch {
|
|
// Ignore storage write failures (private mode, etc.)
|
|
}
|
|
if (typeof document !== "undefined") {
|
|
document.documentElement.setAttribute("lang", normalized);
|
|
}
|
|
};
|
|
|
|
applyLanguageSideEffects(initialLanguage);
|
|
i18n.on("languageChanged", applyLanguageSideEffects);
|
|
}
|
|
|
|
export default i18n;
|