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:
2026-03-29 14:56:25 +00:00
parent 565e72927d
commit b3c6999218
15 changed files with 125 additions and 43 deletions

View File

@@ -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>
);