70 lines
2.0 KiB
TypeScript
70 lines
2.0 KiB
TypeScript
import { createContext, useContext, useState, useEffect, type ReactNode } from 'react';
|
|
import { en, type TextConfig } from '../config/locales/en';
|
|
import { de } from '../config/locales/de';
|
|
import type { Language } from '../data/types';
|
|
|
|
const LANGUAGE_STORAGE_KEY = 'preferred-language';
|
|
|
|
interface LanguageContextType {
|
|
language: Language;
|
|
setLanguage: (lang: Language) => void;
|
|
texts: TextConfig;
|
|
}
|
|
|
|
const LanguageContext = createContext<LanguageContextType | undefined>(undefined);
|
|
|
|
function normalizeLanguage(value: string | null): Language | null {
|
|
if (value === 'de' || value === 'en') return value;
|
|
return null;
|
|
}
|
|
|
|
function getStoredLanguage(): Language | null {
|
|
try {
|
|
return normalizeLanguage(globalThis.localStorage?.getItem(LANGUAGE_STORAGE_KEY) ?? null);
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function detectBrowserLanguage(): Language {
|
|
const browserLanguage = globalThis.navigator?.language?.toLowerCase() ?? '';
|
|
return browserLanguage.startsWith('en') ? 'en' : 'de';
|
|
}
|
|
|
|
export function detectInitialLanguage(): Language {
|
|
return getStoredLanguage() ?? detectBrowserLanguage();
|
|
}
|
|
|
|
export function LanguageProvider({ initialLanguage, children }: Readonly<{ initialLanguage?: Language; children: ReactNode; }>) {
|
|
const [language, setLanguage] = useState<Language>(initialLanguage ?? detectInitialLanguage());
|
|
|
|
const texts = language === 'de' ? de : en;
|
|
|
|
const handleSetLanguage = (lang: Language) => {
|
|
setLanguage(lang);
|
|
};
|
|
|
|
useEffect(() => {
|
|
document.documentElement.lang = language;
|
|
try {
|
|
globalThis.localStorage?.setItem(LANGUAGE_STORAGE_KEY, language);
|
|
} catch {
|
|
// Ignore storage errors (private mode, denied storage, etc.).
|
|
}
|
|
}, [language]);
|
|
|
|
return (
|
|
<LanguageContext.Provider value={{ language, setLanguage: handleSetLanguage, texts }}>
|
|
{children}
|
|
</LanguageContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useLanguage() {
|
|
const context = useContext(LanguageContext);
|
|
if (context === undefined) {
|
|
throw new Error('useLanguage must be used within a LanguageProvider');
|
|
}
|
|
return context;
|
|
}
|