fix(frontend): 修复前端审计问题并补充回归测试

This commit is contained in:
yangjianbo
2026-02-14 11:56:08 +08:00
parent d04b47b3ca
commit f6bff97d26
27 changed files with 772 additions and 219 deletions

View File

@@ -1,53 +1,83 @@
import { createI18n } from 'vue-i18n'
import en from './locales/en'
import zh from './locales/zh'
type LocaleCode = 'en' | 'zh'
type LocaleMessages = Record<string, any>
const LOCALE_KEY = 'sub2api_locale'
const DEFAULT_LOCALE: LocaleCode = 'en'
function getDefaultLocale(): string {
// Check localStorage first
const localeLoaders: Record<LocaleCode, () => Promise<{ default: LocaleMessages }>> = {
en: () => import('./locales/en'),
zh: () => import('./locales/zh')
}
function isLocaleCode(value: string): value is LocaleCode {
return value === 'en' || value === 'zh'
}
function getDefaultLocale(): LocaleCode {
const saved = localStorage.getItem(LOCALE_KEY)
if (saved && ['en', 'zh'].includes(saved)) {
if (saved && isLocaleCode(saved)) {
return saved
}
// Check browser language
const browserLang = navigator.language.toLowerCase()
if (browserLang.startsWith('zh')) {
return 'zh'
}
return 'en'
return DEFAULT_LOCALE
}
export const i18n = createI18n({
legacy: false,
locale: getDefaultLocale(),
fallbackLocale: 'en',
messages: {
en,
zh
},
fallbackLocale: DEFAULT_LOCALE,
messages: {},
// 禁用 HTML 消息警告 - 引导步骤使用富文本内容driver.js 支持 HTML
// 这些内容是内部定义的,不存在 XSS 风险
warnHtmlMessage: false
})
export function setLocale(locale: string) {
if (['en', 'zh'].includes(locale)) {
i18n.global.locale.value = locale as 'en' | 'zh'
localStorage.setItem(LOCALE_KEY, locale)
document.documentElement.setAttribute('lang', locale)
const loadedLocales = new Set<LocaleCode>()
export async function loadLocaleMessages(locale: LocaleCode): Promise<void> {
if (loadedLocales.has(locale)) {
return
}
const loader = localeLoaders[locale]
const module = await loader()
i18n.global.setLocaleMessage(locale, module.default)
loadedLocales.add(locale)
}
export function getLocale(): string {
return i18n.global.locale.value
export async function initI18n(): Promise<void> {
const current = getLocale()
await loadLocaleMessages(current)
document.documentElement.setAttribute('lang', current)
}
export async function setLocale(locale: string): Promise<void> {
if (!isLocaleCode(locale)) {
return
}
await loadLocaleMessages(locale)
i18n.global.locale.value = locale
localStorage.setItem(LOCALE_KEY, locale)
document.documentElement.setAttribute('lang', locale)
}
export function getLocale(): LocaleCode {
const current = i18n.global.locale.value
return isLocaleCode(current) ? current : DEFAULT_LOCALE
}
export const availableLocales = [
{ code: 'en', name: 'English', flag: '🇺🇸' },
{ code: 'zh', name: '中文', flag: '🇨🇳' }
]
] as const
export default i18n