feat: DSL 磁力聚合 — 搜索/解析/预览/投递 + cilisousuo 源 + 中英双语 + Docker 部署

This commit is contained in:
ice-a
2026-10-16 18:53:45 +08:00
commit d6999104bf
64 changed files with 16524 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
import { en2zh, normalizeWs, zh2en } from './i18n-dict'
export type Locale = 'en' | 'zh'
const STORAGE_KEY = 'dsl-locale'
function readInitialLocale(): Locale {
if (import.meta.client) {
const v = localStorage.getItem(STORAGE_KEY)
if (v === 'en' || v === 'zh') return v
}
return 'en' // 默认英文
}
// 模块级响应式语言状态(默认英文)
export const locale = ref<Locale>(readInitialLocale())
export function setLocale(next: Locale) {
locale.value = next
if (import.meta.client) {
localStorage.setItem(STORAGE_KEY, next)
document.documentElement.lang = next === 'zh' ? 'zh-CN' : 'en'
translateDocument()
}
}
/** 把一段中文(或英文)文本按当前语言翻译;找不到映射时原样返回 */
export function translateText(input: string): string {
if (!input) return input
const key = normalizeWs(input)
const map = locale.value === 'zh' ? en2zh : zh2en
return map[key] ?? input
}
/** 遍历 root 下的文本节点与常见属性,按当前语言就地翻译 */
export function walkAndTranslate(root: Node = document.body) {
if (!root || !import.meta.client) return
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT)
const fixes: { node: Text; text: string }[] = []
let n: Node | null
while ((n = walker.nextNode())) {
const t = (n as Text).textContent || ''
if (!t.trim()) continue
const tr = translateText(t)
if (tr !== t) fixes.push({ node: n as Text, text: tr })
}
for (const f of fixes) f.node.textContent = f.text
// 翻译属性(title / placeholder / alt)
if (root instanceof HTMLElement) {
root.querySelectorAll<HTMLElement>('*').forEach((el) => {
for (const attr of ['title', 'placeholder', 'alt']) {
const v = el.getAttribute(attr)
if (!v) continue
const tr = translateText(v)
if (tr !== v) el.setAttribute(attr, tr)
}
})
}
}
export function translateDocument() {
if (import.meta.client) walkAndTranslate(document.body)
}