Fix SSL SAN cert + React hydration #423
- SAN cert covers all 5 PWA domains (tasks,cal,plans,goals,chat) - i18n hydration: SSR uses cs default, localStorage after mount - Matches ThemeProvider pattern Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -57,13 +57,11 @@ export function I18nProvider({ children }: { children: ReactNode }) {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
if (typeof window !== "undefined") {
|
||||
const stored = localStorage.getItem(STORAGE_KEY) as Locale | null;
|
||||
if (stored && MESSAGES[stored]) {
|
||||
setLocaleState(stored);
|
||||
}
|
||||
const stored = localStorage.getItem(STORAGE_KEY) as Locale | null;
|
||||
if (stored && MESSAGES[stored]) {
|
||||
setLocaleState(stored);
|
||||
}
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
const setLocale = useCallback((newLocale: Locale) => {
|
||||
@@ -73,29 +71,32 @@ export function I18nProvider({ children }: { children: ReactNode }) {
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Always use "cs" for translations until mounted to match SSR output
|
||||
const activeLocale = mounted ? locale : "cs";
|
||||
|
||||
const t = useCallback(
|
||||
(key: string): string => {
|
||||
const value = getNestedValue(MESSAGES[locale], key);
|
||||
const value = getNestedValue(MESSAGES[activeLocale], key);
|
||||
if (value !== undefined) return value;
|
||||
// Fallback: return last segment of the key (the raw value) instead of "undefined"
|
||||
return key.split(".").pop() || key;
|
||||
},
|
||||
[locale]
|
||||
[activeLocale]
|
||||
);
|
||||
|
||||
const localeInfo = LOCALES.find((l) => l.code === locale) || LOCALES[0];
|
||||
const localeInfo = LOCALES.find((l) => l.code === activeLocale) || LOCALES[0];
|
||||
const dir = localeInfo.dir;
|
||||
const isRTL = dir === "rtl";
|
||||
|
||||
// Update html attributes when locale changes
|
||||
// Update html attributes when locale changes (only after mount)
|
||||
useEffect(() => {
|
||||
if (!mounted) return;
|
||||
document.documentElement.lang = locale;
|
||||
document.documentElement.dir = dir;
|
||||
}, [locale, dir, mounted]);
|
||||
document.documentElement.dir = LOCALES.find((l) => l.code === locale)?.dir || "ltr";
|
||||
}, [locale, mounted]);
|
||||
|
||||
return (
|
||||
<I18nContext.Provider value={{ locale, setLocale, t, dir, isRTL }}>
|
||||
<I18nContext.Provider value={{ locale: activeLocale, setLocale, t, dir, isRTL }}>
|
||||
{children}
|
||||
</I18nContext.Provider>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user