Guest PWA vollständig lokalisiert
This commit is contained in:
124
resources/js/guest/i18n/LocaleContext.tsx
Normal file
124
resources/js/guest/i18n/LocaleContext.tsx
Normal file
@@ -0,0 +1,124 @@
|
||||
import React from 'react';
|
||||
import { DEFAULT_LOCALE, SUPPORTED_LOCALES, type LocaleCode, isLocaleCode } from './messages';
|
||||
|
||||
export interface LocaleContextValue {
|
||||
locale: LocaleCode;
|
||||
setLocale: (next: LocaleCode) => void;
|
||||
resetLocale: () => void;
|
||||
hydrated: boolean;
|
||||
defaultLocale: LocaleCode;
|
||||
storageKey: string;
|
||||
availableLocales: typeof SUPPORTED_LOCALES;
|
||||
}
|
||||
|
||||
const LocaleContext = React.createContext<LocaleContextValue | undefined>(undefined);
|
||||
|
||||
function sanitizeLocale(value: string | null | undefined, fallback: LocaleCode = DEFAULT_LOCALE): LocaleCode {
|
||||
if (value && isLocaleCode(value)) {
|
||||
return value;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
export interface LocaleProviderProps {
|
||||
children: React.ReactNode;
|
||||
defaultLocale?: LocaleCode;
|
||||
storageKey?: string;
|
||||
}
|
||||
|
||||
export function LocaleProvider({
|
||||
children,
|
||||
defaultLocale = DEFAULT_LOCALE,
|
||||
storageKey = 'guestLocale_global',
|
||||
}: LocaleProviderProps) {
|
||||
const resolvedDefault = sanitizeLocale(defaultLocale, DEFAULT_LOCALE);
|
||||
const [locale, setLocaleState] = React.useState<LocaleCode>(resolvedDefault);
|
||||
const [userLocale, setUserLocale] = React.useState<LocaleCode | null>(null);
|
||||
const [hydrated, setHydrated] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
setHydrated(false);
|
||||
|
||||
if (typeof window === 'undefined') {
|
||||
setLocaleState(resolvedDefault);
|
||||
setUserLocale(null);
|
||||
setHydrated(true);
|
||||
return;
|
||||
}
|
||||
|
||||
let stored: string | null = null;
|
||||
try {
|
||||
stored = window.localStorage.getItem(storageKey);
|
||||
} catch (error) {
|
||||
console.warn('Failed to read stored locale', error);
|
||||
}
|
||||
|
||||
const nextLocale = sanitizeLocale(stored, resolvedDefault);
|
||||
setLocaleState(nextLocale);
|
||||
setUserLocale(isLocaleCode(stored) ? stored : null);
|
||||
setHydrated(true);
|
||||
}, [storageKey, resolvedDefault]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!hydrated || userLocale !== null) {
|
||||
return;
|
||||
}
|
||||
setLocaleState(resolvedDefault);
|
||||
}, [hydrated, userLocale, resolvedDefault]);
|
||||
|
||||
const setLocale = React.useCallback(
|
||||
(next: LocaleCode) => {
|
||||
const safeLocale = sanitizeLocale(next, resolvedDefault);
|
||||
setLocaleState(safeLocale);
|
||||
setUserLocale(safeLocale);
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
try {
|
||||
window.localStorage.setItem(storageKey, safeLocale);
|
||||
} catch (error) {
|
||||
console.warn('Failed to persist locale', error);
|
||||
}
|
||||
}
|
||||
},
|
||||
[storageKey, resolvedDefault],
|
||||
);
|
||||
|
||||
const resetLocale = React.useCallback(() => {
|
||||
setUserLocale(null);
|
||||
setLocaleState(resolvedDefault);
|
||||
if (typeof window !== 'undefined') {
|
||||
try {
|
||||
window.localStorage.removeItem(storageKey);
|
||||
} catch (error) {
|
||||
console.warn('Failed to clear stored locale', error);
|
||||
}
|
||||
}
|
||||
}, [resolvedDefault, storageKey]);
|
||||
|
||||
const value = React.useMemo<LocaleContextValue>(
|
||||
() => ({
|
||||
locale,
|
||||
setLocale,
|
||||
resetLocale,
|
||||
hydrated,
|
||||
defaultLocale: resolvedDefault,
|
||||
storageKey,
|
||||
availableLocales: SUPPORTED_LOCALES,
|
||||
}),
|
||||
[locale, setLocale, resetLocale, hydrated, resolvedDefault, storageKey],
|
||||
);
|
||||
|
||||
return <LocaleContext.Provider value={value}>{children}</LocaleContext.Provider>;
|
||||
}
|
||||
|
||||
export function useLocale(): LocaleContextValue {
|
||||
const ctx = React.useContext(LocaleContext);
|
||||
if (!ctx) {
|
||||
throw new Error('useLocale must be used within a LocaleProvider');
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
export function useOptionalLocale(): LocaleContextValue | undefined {
|
||||
return React.useContext(LocaleContext);
|
||||
}
|
||||
Reference in New Issue
Block a user