mateclaw/mateclaw-ui/src/i18n/index.ts
matevip 22894ac4b1 perf(channels): split Channels.vue, lazy-load modal, async locales, keep-alive route
- Extract create/edit modal into ChannelEditModal.vue (defineAsyncComponent),
  shrinking Channels.vue from 1438 to 370 lines and dropping ~30KB from the
  initial route chunk.
- Move side-effect logic into composables: useWeixinQrcodePoll (QR + 2s status
  poll, auto-cleanup) and useWecomBotAuth (lazy SDK script with module-level
  promise dedupe). Pure config-JSON helpers move to utils/channelConfigJson.ts.
- Switch i18n locales from static imports to dynamic import keyed by current
  locale; applyLocale becomes async to avoid first-render flicker.
- /channels route opts into keep-alive (meta.keepAlive=true). Channels.vue
  pauses status polling in onDeactivated and resumes in onActivated, with an
  isActive guard to prevent late-resolving timers from leaking after navigation.
- Initial load goes from serial 3-RTT to Promise.all + 4-card el-skeleton.
2026-04-28 11:08:36 +08:00

59 lines
1.8 KiB
TypeScript

import { createI18n } from 'vue-i18n'
import { ref } from 'vue'
import { settingsApi } from '@/api'
export type AppLocale = 'zh-CN' | 'en-US'
const STORAGE_KEY = 'mateclaw_locale'
const DEFAULT_LOCALE: AppLocale = 'zh-CN'
export const currentLocale = ref<AppLocale>(DEFAULT_LOCALE)
export const i18n = createI18n({
legacy: false,
locale: DEFAULT_LOCALE,
fallbackLocale: DEFAULT_LOCALE,
messages: {} as Record<AppLocale, any>,
})
const loadedLocales = new Set<AppLocale>()
// Each locale dictionary is ~78KB. Splitting them into their own chunks keeps
// the entry bundle ~150KB lighter — only the active locale is fetched on cold
// start, the other one only when the user switches language.
async function loadLocaleMessages(locale: AppLocale) {
if (loadedLocales.has(locale)) return
const messages = locale === 'zh-CN'
? (await import('./locales/zh-CN')).default
: (await import('./locales/en-US')).default
i18n.global.setLocaleMessage(locale, messages)
loadedLocales.add(locale)
}
function normalizeLocale(locale?: string | null): AppLocale {
if (locale === 'en' || locale === 'en-US') {
return 'en-US'
}
return 'zh-CN'
}
export async function applyLocale(locale?: string | null) {
const normalized = normalizeLocale(locale)
// Must finish loading messages before flipping currentLocale, otherwise the
// first render after a switch would show the i18n keys verbatim.
await loadLocaleMessages(normalized)
currentLocale.value = normalized
i18n.global.locale.value = normalized
localStorage.setItem(STORAGE_KEY, normalized)
return normalized
}
export async function initializeLocale() {
try {
const res: any = await settingsApi.getLanguage()
return await applyLocale(res.data)
} catch {
return await applyLocale(localStorage.getItem(STORAGE_KEY))
}
}