Skip to content

主题与国际化系统 ​

本文引用的源码文件

本文引用的文件

目录 ​

  1. 引言
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考虑
  8. 故障排查指南
  9. 结论
  10. 附录

引言 ​

本文件系统性梳理 AI Helper 的主题与国际化体系,覆盖以下目标:

  • 解释 CSS 变量 Token 体系、设计令牌定义、主题切换机制与动态样式更新。
  • 说明亮/暗主题实现原理,包括颜色映射、对比度检查与可访问性保证。
  • 描述扩展端与 Agent 端的国际化框架,包括消息文件组织、运行时语言切换与复数形式处理策略。
  • 给出翻译工作流程:翻译文件维护、缺失键检测与自动同步建议。
  • 提供添加新主题变体、实现多语言界面的具体实践路径。
  • 说明主题审计工具使用方法,包括自动化检测、合规报告和改进建议。
  • 总结 i18n 最佳实践:文案提取、上下文管理与性能优化。
  • 说明浏览器原生 API 的使用,包括 Intl API 和本地化数据处理。

本项目为双进程架构:Chrome 扩展端(Manifest V3,src/)与独立本地代理端 Agent(Node.js,agent/src/server.js)。两端版本号保持同步,文档以 2.3.1 为准。

项目结构 ​

主题与国际化相关代码分布在以下位置:

  • 主题 Token 与运行时:src/shared/theme.css、src/shared/theme.js
  • 主题审计与迁移脚本:scripts/theme-dark-audit.mjs、scripts/theme-contrast-check.py、scripts/theme-map.json
  • 扩展端国际化:src/shared/i18n.js、src/shared/locales/
  • Agent 端国际化:agent/src/i18n.js、agent/src/sys-lang.js、agent/src/locales/
  • Chrome 扩展元数据消息:_locales/{en,zh_CN}/messages.json
graph TB
subgraph "扩展端"
TCSS["theme.css<br/>Token 定义"]
TJ["theme.js<br/>主题读写与同步"]
I18N["i18n.js<br/>扩展端国际化"]
LOCALES_ZH["locales/zh.js"]
LOCALES_EN["locales/en.js"]
end
subgraph "Agent 端"
AI18N["i18n.js<br/>Agent 端国际化"]
SYS_LANG["sys-lang.js<br/>系统语言探测"]
A_LOCALES_ZH["locales/zh.json"]
A_LOCALES_EN["locales/en.json"]
end
subgraph "脚本与门禁"
AUDIT["theme-dark-audit.mjs<br/>动态对比度审计"]
CONTRAST["theme-contrast-check.py<br/>静态对比度门禁"]
MAP["theme-map.json<br/>色值→Token 映射"]
end
subgraph "Chrome 消息"
M_EN["_locales/en/messages.json"]
M_ZH["_locales/zh_CN/messages.json"]
end
TCSS --> TJ
TJ --> AUDIT
TJ --> CONTRAST
TJ --> MAP
I18N --> LOCALES_ZH
I18N --> LOCALES_EN
AI18N --> SYS_LANG
AI18N --> A_LOCALES_ZH
AI18N --> A_LOCALES_EN
M_EN -.-> I18N
M_ZH -.-> I18N

图表来源

章节来源

核心组件 ​

  • 主题 Token 层:通过 CSS 变量集中定义语义色,区分亮/暗两套值,所有界面颜色只引用 token,禁止硬编码色值。
  • 主题运行时:读取用户偏好(light/dark/system),计算生效值并写入 <html data-theme>,订阅者监听变更刷新 UI。
  • 主题审计与门禁:静态脚本校验 token 对比度;Playwright 探针在真实渲染页面中检测对比度不达标与“白斑”。
  • 扩展端 i18n:同步 t(key, params),支持运行时语言切换、跨环境同步、DOM 属性批量填充。
  • Agent 端 i18n:解析 Accept-Language,按权重匹配语言,提供 t(lang, key, params) 与 getRequestI18n(req)。
  • Chrome 消息:_locales 下 messages.json 用于扩展名、描述、命令等元数据国际化。

章节来源

架构总览 ​

主题与国际化在扩展端与 Agent 端分别运行,但共享一致的语义约定:

  • 主题:Token 定义在 theme.css,运行时由 theme.js 控制 data-theme,审计脚本保障 WCAG 可达性。
  • 国际化:扩展端使用 src/shared/i18n.js 与 locales/.js;Agent 端使用 agent/src/i18n.js 与 locales/.json;Chrome 元数据使用 _locales/messages.json。
sequenceDiagram
participant User as "用户"
participant ThemeJS as "theme.js"
participant CSS as "theme.css"
participant Audit as "theme-dark-audit.mjs"
participant I18NExt as "i18n.js(扩展端)"
participant I18NAg as "i18n.js(Agent 端)"
User->>ThemeJS : 设置主题偏好 light/dark/system
ThemeJS->>ThemeJS : resolve(preference)
ThemeJS->>Document : 写入 data-theme
Note over ThemeJS,CSS : CSS 变量随 data-theme 切换
Audit->>Document : 遍历已渲染元素测对比度/白斑
Audit-->>Audit : 输出违规清单或审计通过
User->>I18NExt : 切换语言 zh/en
I18NExt->>I18NExt : setLanguage + storage.onChanged
I18NExt->>DOM : applyI18n 刷新文案
I18NExt->>I18NAg : (Agent 端独立,按请求头解析语言)

图表来源

详细组件分析 ​

主题 Token 体系与动态样式更新 ​

  • Token 定义集中在 :root 与 html[data-theme="dark"] 两块,语义命名如 --bg-page、--text-primary、--brand-500、--danger-soft-bg 等。
  • 运行时通过 theme.js 的 preference/resolved 状态机:
    • getTheme() 返回用户偏好;getResolvedTheme() 返回实际生效值。
    • initTheme() 初始化 matchMedia 监听系统主题变化,注册 chrome.storage.onChanged 跨环境同步。
    • setTheme(pref) 校验合法值后写入存储并触发 apply() 更新 DOM 属性。
  • 防闪烁:模块顶层同步读取 localStorage 镜像 appThemeResolved,先落一次 data-theme,再异步从 chrome.storage.local 恢复正式值。
flowchart TD
Start(["调用 setTheme(pref)"]) --> Validate{"pref 是否合法?"}
Validate --> |否| Return["忽略无效值"]
Validate --> |是| Apply["apply(resolve(pref))"]
Apply --> SetAttr["documentElement.setAttribute('data-theme', resolved)"]
Apply --> SaveStorage["chrome.storage.local.set({appTheme})"]
Apply --> Notify["通知订阅者 cb(resolved)"]
Notify --> End(["完成"])

图表来源

章节来源

亮/暗主题实现原理与可访问性保证 ​

  • 颜色映射:亮/暗两套 token 值,文本、背景、品牌、状态、边框、阴影、浮层等全面覆盖;部分固定不翻转(如 --mark-bg、--paper、--code-bg/--code-fg)。
  • 对比度门禁:
    • 静态:scripts/theme-contrast-check.py 解析 theme.css 暗色块,对文本类阈值 4.5:1、图形类 3:1 进行 WCAG 校验。
    • 动态:scripts/theme-dark-audit.mjs 用 Playwright 加载 dist 扩展,侧边栏与配置页切 dark,逐个面板展开,遍历已渲染元素实测前景/背景合成后的对比度,并检测“白斑”(近纯白大块背景)。
  • 可访问性:遵循 WCAG 1.4.3 文本对比度与 1.4.11 非文本对比度;暗色下原生控件 accent-color 统一品牌强调色;markdown-body 在暗色下覆盖默认亮色库样式。
flowchart TD
LoadCSS["加载 theme.css"] --> ParseDark["解析暗色 token 集合"]
ParseDark --> Classify["分类:文本/图形/装饰性分隔"]
Classify --> CalcContrast["按 WCAG 公式计算对比度"]
CalcContrast --> Threshold{"是否低于阈值?"}
Threshold --> |是| Fail["[AA FAIL] 记录未达标项"]
Threshold --> |否| Pass["通过"]
Fail --> Report["输出报告并退出码非零"]
Pass --> Done["门禁通过"]

图表来源

章节来源

主题审计工具使用方法 ​

  • 前置条件:先执行 npm run build:silent 构建 dist。
  • 动态审计:node scripts/theme-dark-audit.mjs [--keep]
    • 启动 Chromium 持久化上下文,加载 dist 扩展。
    • 将 side_panel.html 与 options.html 切到 dark,逐个面板/Tab 展开,注入审计函数遍历元素。
    • 输出“白斑”与“对比度不达标”清单;存在违规则 exit 1。
  • 静态审计:python3 scripts/theme-contrast-check.py src/shared/theme.css
    • 仅校验 theme.css 暗色 token 对比度,不依赖渲染。
  • 色值迁移:scripts/theme-map.json 维护 direct/contextDispatch/rgbaFamilies/bands/whitelist,辅助迁移与审查。
sequenceDiagram
participant Dev as "开发者"
participant Audit as "theme-dark-audit.mjs"
participant PW as "Playwright"
participant Ext as "dist 扩展"
Dev->>Audit : node scripts/theme-dark-audit.mjs
Audit->>PW : launchPersistentContext(load-extension=dist)
PW->>Ext : 打开 side_panel.html / options.html
Audit->>Ext : setDark(appTheme='dark')
Audit->>Ext : evaluate(AUDIT_FN) 遍历元素
Ext-->>Audit : {violations, blotches}
Audit-->>Dev : 输出报告/exit 码

图表来源

章节来源

扩展端国际化框架 ​

  • 语言包:src/shared/locales/zh.js 与 en.js,按模块分组,key 点分访问(如 common.confirm)。
  • 运行时:
    • t(key, params):当前语言查找 → 英文 fallback → 返回 key 本身便于发现遗漏。
    • setLanguage(lang, persist=true):写入 chrome.storage.local,通知订阅者刷新。
    • initI18n():从 storage 读取语言偏好,未设置时根据浏览器语言自动检测并持久化;注册 storage.onChanged 跨环境同步。
    • applyI18n(root):批量填充 data-i18n、data-i18n-placeholder、data-i18n-title、data-i18n-aria-label。
  • 动态注册:registerTranslations(lang, dict) 允许模块按需追加文案。
classDiagram
class I18NExt {
+SUPPORTED_LANGUAGES
+DEFAULT_LANGUAGE
+t(key, params) string
+getLanguage() string
+setLanguage(lang, persist) void
+subscribe(cb) function
+registerTranslations(lang, dict) void
+initI18n() Promise~string~
+applyI18n(root) void
}
class LocalesZH {
<<module>>
}
class LocalesEN {
<<module>>
}
I18NExt --> LocalesZH : "导入"
I18NExt --> LocalesEN : "导入"

图表来源

章节来源

Agent 端国际化框架 ​

  • 语言包:agent/src/locales/zh.json 与 en.json,按 error/rag/message/auth/exec/security/trash/search/skill/mcp/server/memory 等模块组织。
  • 语言探测:
    • sys-lang.js:优先读取 LANGUAGE/LC_ALL/LC_MESSAGES/LANG 环境变量,其次 Intl.DateTimeFormat().resolvedOptions().locale,最终回退 'en'。
    • i18n.js:DEFAULT_LANG = env.AI_HELPER_LANG > detectSystemLang();parseAcceptLanguage(req.headers['accept-language']) 按 q 权重排序,精确匹配或前缀匹配(如 zh-CN → zh)。
  • 翻译函数:
    • t(lang, key, params):点分 key 查找,找不到回退 DEFAULT_LANG,仍无则返回 key;params 支持 {name} 插值。
    • getRequestI18n(req):封装 lang 与 t 闭包供路由使用。
flowchart TD
Req["HTTP 请求"] --> Parse["parseAcceptLanguage(header)"]
Parse --> Match{"是否匹配 zh/en?"}
Match --> |是| UseLang["使用匹配语言"]
Match --> |否| Fallback["回退 DEFAULT_LANG"]
UseLang --> T["t(lang, key, params)"]
Fallback --> T
T --> Interp["参数插值 {name}"]
Interp --> Resp["返回本地化字符串"]

图表来源

章节来源

翻译工作流程与维护建议 ​

  • 文件组织:
    • 扩展端:src/shared/locales/{zh.js,en.js},按模块分组,key 点分访问。
    • Agent 端:agent/src/locales/{zh.json,en.json},JSON 扁平对象。
    • Chrome 元数据:_locales/{en,zh_CN}/messages.json。
  • 缺失键检测:
    • 扩展端 t(key) 在未找到时返回 key 本身,便于在 UI 上直接暴露遗漏。
    • Agent 端 t(lang,key,params) 同样回退 key,测试用例可断言渲染结果不含残留占位符。
  • 自动同步建议:
    • 基于 theme-map.json 的模式,建立 i18n-key-map.json,扫描源码中 t() 调用与 data-i18n* 属性,生成待补充键列表。
    • CI 阶段比较 zh.js/en.js 与 zh.json/en.json 的 key 集,差异即告警。
  • 复数形式处理:
    • 当前实现未内置 ICU 复数规则;建议在模板层按 count 分支选择不同 key(如 item_one/item_other),或使用轻量 pluralizer 包装 t()。

章节来源

添加新主题变体的步骤 ​

  • 在 theme.css 新增主题选择器(例如 html[data-theme="custom"]),复制现有亮/暗 token 结构并调整色值。
  • 在 theme.js 的 VALID 数组中添加新变体,并在 resolve() 中处理 system/custom 逻辑。
  • 在 theme-map.json 的 whitelist 中登记必要例外色值(若引入新的固定色)。
  • 运行 theme-contrast-check.py 与 theme-dark-audit.mjs 验证对比度与渲染合规。

章节来源

实现多语言界面的步骤 ​

  • 在 zh.js 与 en.js 中新增对应 key 与文案。
  • 在需要国际化的 DOM 元素上添加 data-i18n、data-i18n-placeholder、data-i18n-title、data-i18n-aria-label。
  • 在页面加载或语言切换后调用 applyI18n(root) 刷新文案。
  • 如需动态文案,使用 registerTranslations(lang, dict) 追加模块级文案。

章节来源

浏览器原生 API 的使用 ​

  • 主题:matchMedia('(prefers-color-scheme: dark)') 监听系统主题变化。
  • 国际化:
    • 扩展端:chrome.i18n.getUILanguage() 用于浏览器 UI 语言检测。
    • Agent 端:Intl.DateTimeFormat().resolvedOptions().locale 作为系统语言回退。
  • 本地化数据处理:Agent 端 parseAcceptLanguage 解析 Accept-Language 头部,按 q 权重排序并支持前缀匹配。

章节来源

依赖关系分析 ​

  • 主题依赖:
    • theme.js 依赖 chrome.storage.local 与 matchMedia。
    • theme-dark-audit.mjs 依赖 Playwright 与 dist 产物。
    • theme-contrast-check.py 依赖 Python 与 theme.css。
  • 国际化依赖:
    • 扩展端 i18n.js 依赖 locales/*.js 与 chrome.storage.local。
    • Agent 端 i18n.js 依赖 locales/*.json 与 sys-lang.js。
    • Chrome 消息 _locales/messages.json 由扩展框架加载。
graph LR
ThemeJS["theme.js"] --> Storage["chrome.storage.local"]
ThemeJS --> MQ["matchMedia"]
Audit["theme-dark-audit.mjs"] --> PW["Playwright"]
Contrast["theme-contrast-check.py"] --> CSS["theme.css"]
I18NExt["i18n.js(扩展端)"] --> Locales["locales/*.js"]
I18NAg["i18n.js(Agent 端)"] --> SysLang["sys-lang.js"]
I18NAg --> ALocales["locales/*.json"]
ChromeMsg["_locales/messages.json"] --> ExtMeta["扩展元数据"]

图表来源

章节来源

性能考虑 ​

  • 主题切换:
    • 防闪烁:先用 localStorage 镜像立即打标 data-theme,避免首屏闪白。
    • 订阅者仅在 resolved 真正变化时触发,避免重复刷新。
  • 国际化:
    • t() 采用点分查找与简单正则插值,开销低;fallback 链短(当前语言 → 英文 → key)。
    • applyI18n 使用 querySelectorAll 批量操作,适合页面加载与语言切换后一次性刷新。
  • 审计:
    • 静态对比度检查在 CI 中快速失败;动态审计仅在必要时运行,避免频繁 Playwright 开销。

[本节为通用指导,不直接分析具体文件]

故障排查指南 ​

  • 主题问题:
    • 现象:暗色下文字不可读或出现白斑。
    • 排查:运行 theme-dark-audit.mjs 查看违规清单;检查 theme.css 暗色 token 是否满足 WCAG;确认 HTML data-theme 是否正确。
  • 国际化问题:
    • 现象:UI 显示原始 key 或英文 fallback。
    • 排查:确认 zh.js/en.js 中存在对应 key;检查 data-i18n* 属性是否正确;确认 initI18n() 已调用且 storage.onChanged 正常。
  • Agent 端语言错误:
    • 现象:API 响应文案未按预期语言返回。
    • 排查:检查 Accept-Language 头部;确认 sys-lang.js 与 i18n.js 的 DEFAULT_LANG 与 SUPPORTED_LANGS;验证 locales/*.json 中 key 是否存在。

章节来源

结论 ​

本项目通过 CSS 变量 Token 体系与 theme.js 运行时实现了稳定、可审计的亮/暗主题切换;通过扩展端与 Agent 端两套 i18n 模块覆盖了 UI 与后端文案需求;配合静态与动态审计脚本确保可访问性与渲染质量。建议在后续迭代中完善复数形式处理、建立 i18n key 自动同步门禁,并持续优化主题 Token 的可维护性与扩展性。

[本节为总结,不直接分析具体文件]

附录 ​

  • 最佳实践清单:
    • 主题:始终使用 token,避免硬编码色值;新增主题需过静态与动态审计。
    • 国际化:文案模块化分组;使用 data-i18n* 声明式绑定;t() 调用处保留 key 以便发现遗漏。
    • 性能:减少 applyI18n 调用频率;避免在高频回调中重复查询 DOM。
    • 可访问性:遵循 WCAG 文本与非文本对比度;暗色下原生控件 accent-color 统一。
    • 浏览器 API:合理使用 matchMedia、chrome.i18n、Intl API。

[本节为通用指导,不直接分析具体文件]