From 98b78a1e354b9070031acd2ee2e420b50a374318 Mon Sep 17 00:00:00 2001 From: MadDogOwner Date: Wed, 17 Jun 2026 15:21:34 +0800 Subject: [PATCH] feat(i18n): fallback to English when translation is missing - Cache English dictionary for reuse as fallback - Merge non-English locales with English base (locale on top) - Fall back to English if a locale fails to load entirely Co-authored-by: GitHub Copilot --- src/app/i18n.ts | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/app/i18n.ts b/src/app/i18n.ts index 21fb518e4..48b0ebbe8 100644 --- a/src/app/i18n.ts +++ b/src/app/i18n.ts @@ -39,13 +39,36 @@ export type Lang = keyof typeof langs export type RawDictionary = typeof en.dict export type Dictionary = i18n.Flatten -// Fetch and flatten the dictionary +// English dictionary cache for fallback +let enDictCache: Dictionary | null = null + +const fetchEnDict = async (): Promise => { + if (!enDictCache) { + const dict: RawDictionary = (await import("~/lang/en/entry")).dict + enDictCache = i18n.flatten(dict) + } + return enDictCache +} + +// Fetch and flatten the dictionary, with English fallback const fetchDictionary = async (locale: Lang): Promise => { try { const dict: RawDictionary = (await import(`~/lang/${locale}/entry.ts`)).dict - return i18n.flatten(dict) // Flatten dictionary for easier access to keys + const flatDict = i18n.flatten(dict) + + // If not English, merge with English as fallback (English keys underneath, locale on top) + if (locale !== "en") { + const enDict = await fetchEnDict() + return { ...enDict, ...flatDict } as Dictionary + } + + return flatDict } catch (err) { console.error(`Error loading dictionary for locale: ${locale}`, err) + // Fallback to English if the requested locale fails to load + if (locale !== "en") { + return await fetchEnDict() + } throw new Error(`Failed to load dictionary for ${locale}`) } }