import { useI18n } from 'vue-i18n'; import { SUPPORTED_LOCALES, LOCALE_UI_LABELS, type Locale } from '@thebet365/shared'; import api from '../api'; import { useAuthStore } from '../stores/auth'; import { ensurePlayerLocale } from '../i18n'; const STORAGE_KEY = 'locale'; const COOKIE_MAX_AGE = 365 * 24 * 60 * 60; export const APP_LOCALES = SUPPORTED_LOCALES.map((code) => ({ code, label: LOCALE_UI_LABELS[code] ?? code, })); function persistLocale(code: string) { localStorage.setItem(STORAGE_KEY, code); document.cookie = `${STORAGE_KEY}=${encodeURIComponent(code)};path=/;max-age=${COOKIE_MAX_AGE};SameSite=Lax`; } export function useAppLocale() { const i18n = useI18n({ useScope: 'global' }); const { locale } = i18n; const auth = useAuthStore(); function applyLocale(code: string) { if (!(SUPPORTED_LOCALES as readonly string[]).includes(code)) return; locale.value = code; persistLocale(code); } async function setLocale(code: string) { if (!(SUPPORTED_LOCALES as readonly string[]).includes(code)) return; if (locale.value === code) return; if (auth.token) { try { await api.post('/player/language', { locale: code }); if (auth.user) { auth.user = { ...auth.user, locale: code }; localStorage.setItem('user', JSON.stringify(auth.user)); } } catch { /* 离线或 token 过期时仍保留本地语言 */ } } await ensurePlayerLocale(i18n, code as Locale); applyLocale(code); } /** 将当前语言同步到后端,仅在有 token 时执行,不修改本地 locale */ async function syncLocaleToBackend() { if (!auth.token) return; try { await api.post('/player/language', { locale: locale.value }); if (auth.user) { auth.user = { ...auth.user, locale: locale.value }; localStorage.setItem('user', JSON.stringify(auth.user)); } } catch { /* ignore */ } } async function initFromUser(userLocale?: string | null) { if (userLocale && (SUPPORTED_LOCALES as readonly string[]).includes(userLocale)) { await ensurePlayerLocale(i18n, userLocale as Locale); applyLocale(userLocale); } } return { locales: APP_LOCALES, setLocale, applyLocale, initFromUser, syncLocaleToBackend }; }