From 14657847fe6cd395d35b275ef838051089a596aa Mon Sep 17 00:00:00 2001 From: digua Date: Sat, 25 Jul 2026 00:55:56 +0800 Subject: [PATCH] feat(web): streamline Web WASM locale startup --- apps/web-wasm/index.html | 2 +- apps/web-wasm/src/locale-bootstrap.test.ts | 12 ++++++ apps/web-wasm/src/locale-bootstrap.ts | 22 +++++++++++ apps/web-wasm/src/main.ts | 3 ++ apps/web-wasm/src/pages/HomePage.vue | 15 +------- src/components/home/HomeFooter.vue | 17 ++++++--- .../home/home-footer-config.test.ts | 13 ++++++- src/components/home/home-footer-config.ts | 8 ++++ src/i18n/index.ts | 10 ++++- src/i18n/types.test.ts | 17 +++++++++ src/i18n/types.ts | 37 ++++++++++++++----- src/services/preferences/browser.ts | 6 +-- 12 files changed, 127 insertions(+), 35 deletions(-) create mode 100644 apps/web-wasm/src/locale-bootstrap.test.ts create mode 100644 apps/web-wasm/src/locale-bootstrap.ts create mode 100644 src/i18n/types.test.ts diff --git a/apps/web-wasm/index.html b/apps/web-wasm/index.html index 67b8d710..cdbd2f13 100644 --- a/apps/web-wasm/index.html +++ b/apps/web-wasm/index.html @@ -1,5 +1,5 @@ - + diff --git a/apps/web-wasm/src/locale-bootstrap.test.ts b/apps/web-wasm/src/locale-bootstrap.test.ts new file mode 100644 index 00000000..240a49bb --- /dev/null +++ b/apps/web-wasm/src/locale-bootstrap.test.ts @@ -0,0 +1,12 @@ +import assert from 'node:assert/strict' +import test from 'node:test' +import { resolveWebWasmInitialLocale } from './locale-bootstrap' + +test('uses the saved Web WASM locale before browser language detection', () => { + assert.equal(resolveWebWasmInitialLocale('ja-JP', ['zh-CN']), 'ja-JP') +}) + +test('detects the browser language for a first visit or invalid saved locale', () => { + assert.equal(resolveWebWasmInitialLocale('', ['zh-Hant-TW']), 'zh-TW') + assert.equal(resolveWebWasmInitialLocale('unsupported', ['en-GB']), 'en-US') +}) diff --git a/apps/web-wasm/src/locale-bootstrap.ts b/apps/web-wasm/src/locale-bootstrap.ts new file mode 100644 index 00000000..fb01c9fc --- /dev/null +++ b/apps/web-wasm/src/locale-bootstrap.ts @@ -0,0 +1,22 @@ +import { detectSystemLocale, isValidLocale, setLocale, type LocaleType } from '@/i18n' +import { WEB_WASM_LOCALE_STORAGE_KEY } from '@/services/preferences/browser' + +export function resolveWebWasmInitialLocale( + savedLocale: string | null | undefined, + browserLanguages?: readonly string[] +): LocaleType { + return savedLocale && isValidLocale(savedLocale) ? savedLocale : detectSystemLocale(browserLanguages) +} + +export function initializeWebWasmLocale(): LocaleType { + let savedLocale: string | null = null + try { + savedLocale = globalThis.localStorage?.getItem(WEB_WASM_LOCALE_STORAGE_KEY) ?? null + } catch { + // Storage may be unavailable in hardened browser contexts; browser language remains a safe default. + } + + const locale = resolveWebWasmInitialLocale(savedLocale) + setLocale(locale) + return locale +} diff --git a/apps/web-wasm/src/main.ts b/apps/web-wasm/src/main.ts index 662fb197..88a4a01b 100644 --- a/apps/web-wasm/src/main.ts +++ b/apps/web-wasm/src/main.ts @@ -16,8 +16,11 @@ import { registerWebWasmAdapters } from '@/services/browser-runtime/register' import { handleWebWasmPageHide } from './runtime-lifecycle' import { WebWasmSessionSync } from './session-sync' import { useSessionStore } from '@/stores/session' +import { initializeWebWasmLocale } from './locale-bootstrap' import '@/assets/styles/main.css' +initializeWebWasmLocale() + async function start(): Promise { reportRuntimeLog({ level: 'info', scope: 'web-wasm-bootstrap', message: 'Initializing Web WASM services' }) installGlobalErrorReporting() diff --git a/apps/web-wasm/src/pages/HomePage.vue b/apps/web-wasm/src/pages/HomePage.vue index 26337c5a..8fa7a6d8 100644 --- a/apps/web-wasm/src/pages/HomePage.vue +++ b/apps/web-wasm/src/pages/HomePage.vue @@ -5,10 +5,8 @@ import { useI18n } from 'vue-i18n' import { storeToRefs } from 'pinia' import logoSvg from '@/assets/images/logo.svg' import AgreementModal from '@/components/home/AgreementModal.vue' -import ChangelogModal from '@/components/home/ChangelogModal.vue' import HomeFooter from '@/components/home/HomeFooter.vue' import ImportArea from '@/components/import/ImportArea.vue' -import LanguageSelectModal from '@/components/home/LanguageSelectModal.vue' import { availableLocales, type LocaleType } from '@/i18n' import { useSettingsStore } from '@/stores/settings' import { useSessionStore } from '@/stores/session' @@ -20,7 +18,6 @@ const sessionStore = useSessionStore() const { sessions } = storeToRefs(sessionStore) const isMounted = ref(false) const languageMenuOpen = ref(false) -const changelogModalRef = ref | null>(null) const agreementModalRef = ref | null>(null) const isDark = useDark() const toggleDark = useToggle(isDark) @@ -170,20 +167,10 @@ onMounted(() => { - + - - - diff --git a/src/components/home/HomeFooter.vue b/src/components/home/HomeFooter.vue index 7dfee4d6..390b0344 100644 --- a/src/components/home/HomeFooter.vue +++ b/src/components/home/HomeFooter.vue @@ -4,11 +4,17 @@ import { useI18n } from 'vue-i18n' import { CHATLAB_SITE_BASE, getChatlabSiteLocalePath, getChatlabSiteLangQuery } from '@/utils/chatlabSiteLocale' import { IS_ELECTRON } from '@/utils/platform' import { usePlatformService } from '@/services' -import { resolveHomeFooterConfigSource } from './home-footer-config' +import { filterHomeFooterLinks, resolveHomeFooterConfigSource } from './home-footer-config' -const props = defineProps<{ - remoteConfigEnabled: boolean -}>() +const props = withDefaults( + defineProps<{ + remoteConfigEnabled: boolean + showChangelog?: boolean + }>(), + { + showChangelog: true, + } +) const emit = defineEmits<{ openChangelog: [] @@ -69,6 +75,7 @@ function getDefaultLinks(): FooterLink[] { } const footerLinks = ref(getDefaultLinks()) +const visibleFooterLinks = computed(() => filterHomeFooterLinks(footerLinks.value, props.showChangelog)) // 社交链接配置(由远程配置 socialData 直接提供) interface SocialData { @@ -210,7 +217,7 @@ watch(locale, () => {