From 7cc11c2439e4204aaf2356128cf468398d08abe1 Mon Sep 17 00:00:00 2001 From: digua Date: Thu, 23 Jul 2026 14:41:44 +0800 Subject: [PATCH] feat(docs): remember language preference Persist the active documentation locale and restore it when users revisit the root URL. Open the VitePress development site automatically on startup. --- docs/.vitepress/theme/index.ts | 61 +++++++++++++++++++++++++++++++++- docs/package.json | 2 +- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts index ea7a407d..43e0f0f7 100644 --- a/docs/.vitepress/theme/index.ts +++ b/docs/.vitepress/theme/index.ts @@ -1,4 +1,63 @@ +import type { Theme } from 'vitepress' import DefaultTheme from 'vitepress/theme' import './style.css' -export default DefaultTheme +type DocsLocale = 'en' | 'cn' | 'tw' + +const LANGUAGE_PREFERENCE_KEY = 'chatlab-docs-language' + +function getLocaleFromPath(path: string): DocsLocale { + if (path === '/cn' || path.startsWith('/cn/')) return 'cn' + if (path === '/tw' || path.startsWith('/tw/')) return 'tw' + return 'en' +} + +function getBrowserLocale(): DocsLocale { + const languages = navigator.languages.length > 0 ? navigator.languages : [navigator.language] + + for (const language of languages) { + const normalized = language.toLowerCase() + if (/^zh-(tw|hk|mo|hant)/.test(normalized)) return 'tw' + if (normalized.startsWith('zh')) return 'cn' + } + + return 'en' +} + +function readPreferredLocale(): DocsLocale | null { + try { + const locale = localStorage.getItem(LANGUAGE_PREFERENCE_KEY) + return locale === 'en' || locale === 'cn' || locale === 'tw' ? locale : null + } catch { + return null + } +} + +function savePreferredLocale(locale: DocsLocale): void { + try { + localStorage.setItem(LANGUAGE_PREFERENCE_KEY, locale) + } catch { + // Language preference persistence is optional. + } +} + +export default { + extends: DefaultTheme, + enhanceApp({ router }) { + if (typeof window === 'undefined') return + + const initialPath = window.location.pathname + if (initialPath === '/') { + const preferredLocale = readPreferredLocale() ?? getBrowserLocale() + if (preferredLocale !== 'en') { + window.location.replace(`/${preferredLocale}/${window.location.search}${window.location.hash}`) + return + } + } + + savePreferredLocale(getLocaleFromPath(initialPath)) + router.onAfterRouteChange = (to) => { + savePreferredLocale(getLocaleFromPath(to)) + } + }, +} satisfies Theme diff --git a/docs/package.json b/docs/package.json index 9ac59635..512667a0 100644 --- a/docs/package.json +++ b/docs/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "scripts": { - "dev": "vitepress dev . --port 3120", + "dev": "vitepress dev . --port 3120 --open", "build": "vitepress build .", "preview": "vitepress preview ." },