portfolio-page/src/contexts/LanguageContext.tsx

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;
}