From 3710df916fb8464dd3b89d49db697aec38627688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20Andr=C3=A9?= Date: Sat, 14 Mar 2026 23:34:22 +0100 Subject: [PATCH] fix(ui): harden bootstrap locale fallback --- packages/ui/src/lib/i18n/index.tsx | 12 +++++++++--- packages/ui/src/lib/ui-bootstrap-cache.ts | 17 ++++++++++++++--- packages/ui/src/stores/preferences.tsx | 11 +++++++++-- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/packages/ui/src/lib/i18n/index.tsx b/packages/ui/src/lib/i18n/index.tsx index f9949de2..60bcc52b 100644 --- a/packages/ui/src/lib/i18n/index.tsx +++ b/packages/ui/src/lib/i18n/index.tsx @@ -117,9 +117,15 @@ async function loadLocaleMessages(locale: Locale): Promise { export async function preloadLocaleMessages(preferredLocale?: string | null): Promise { const resolvedLocale = matchSupportedLocale(preferredLocale ?? undefined) ?? detectNavigatorLocale() ?? "en" - globalMessages = await loadLocaleMessages(resolvedLocale) - setGlobalRevision((value) => value + 1) - return resolvedLocale + try { + globalMessages = await loadLocaleMessages(resolvedLocale) + setGlobalRevision((value) => value + 1) + return resolvedLocale + } catch { + globalMessages = enMessages + setGlobalRevision((value) => value + 1) + return "en" + } } export function tGlobal(key: string, params?: TranslateParams): string { diff --git a/packages/ui/src/lib/ui-bootstrap-cache.ts b/packages/ui/src/lib/ui-bootstrap-cache.ts index 422d3887..173803a8 100644 --- a/packages/ui/src/lib/ui-bootstrap-cache.ts +++ b/packages/ui/src/lib/ui-bootstrap-cache.ts @@ -1,8 +1,8 @@ export type UiBootstrapTheme = "light" | "dark" | "system" export interface UiBootstrapCacheSnapshot { - theme?: UiBootstrapTheme - locale?: string + theme?: UiBootstrapTheme | null + locale?: string | null } const UI_BOOTSTRAP_CACHE_KEY = "codenomad:ui-bootstrap" @@ -41,7 +41,18 @@ export function writeUiBootstrapCache(snapshot: UiBootstrapCacheSnapshot) { } try { - window.localStorage.setItem(UI_BOOTSTRAP_CACHE_KEY, JSON.stringify(snapshot)) + const previous = readUiBootstrapCache() + const next: UiBootstrapCacheSnapshot = { + theme: snapshot.theme === undefined ? previous.theme : snapshot.theme ?? undefined, + locale: snapshot.locale === undefined ? previous.locale : snapshot.locale ?? undefined, + } + + if (!next.theme && !next.locale) { + window.localStorage.removeItem(UI_BOOTSTRAP_CACHE_KEY) + return + } + + window.localStorage.setItem(UI_BOOTSTRAP_CACHE_KEY, JSON.stringify(next)) } catch { /* noop */ } diff --git a/packages/ui/src/stores/preferences.tsx b/packages/ui/src/stores/preferences.tsx index 442adfca..ddc0a718 100644 --- a/packages/ui/src/stores/preferences.tsx +++ b/packages/ui/src/stores/preferences.tsx @@ -600,10 +600,17 @@ const configContextValue: ConfigContextValue = { export const ConfigProvider: ParentComponent = (props) => { createEffect(() => { + if (!isLoaded()) { + return + } + const bucket = uiConfigBucket() + const theme = bucket.theme + const locale = bucket.settings?.locale + writeUiBootstrapCache({ - theme: bucket.theme, - locale: bucket.settings?.locale, + theme: theme ?? null, + locale: locale ?? null, }) })