## CyberStrikeAI 前端国际化方案 本文档说明 CyberStrikeAI Web 前端(`web/templates/index.html` + `web/static/js/*.js`)的国际化设计与开发规范,确保在不引入打包工具和不改动后端路由的前提下,实现可扩展、低返工的多语言支持。 当前目标: - **支持中英文切换(zh-CN / en-US)** - 后续可方便扩展更多语言(如 ja-JP、ko-KR 等) --- ## 一、总体设计原则 - **前端主导的客户端国际化**:所有 UI 文案在浏览器端根据当前语言动态渲染,后端 Go 仅负责结构和数据,不参与语言分发。 - **单一 HTML 模板**:继续使用一份 `index.html` 模板,不为不同语言复制模板文件。 - **文案与逻辑分离**:所有可见文本通过「键值表」管理(多语言 JSON),HTML / JS 只写 key,不直接写中文/英文常量。 - **渐进式改造**:先覆盖 header / 登录 / 侧边栏 / 系统设置等关键区域,其他页面按模块逐步迁移,避免一次性大改动。 - **可回退默认语言**:即使目标语言未完全翻译,也能回退到默认中文,不出现原始 key。 --- ## 二、技术选型与目录结构 ### 2.1 技术选型 - **i18n 引擎**:使用 [i18next](https://www.i18next.com/) 的浏览器 UMD 版本(通过 CDN 引入),无需打包器。 - **资源格式**:每种语言一份 JSON 文件,采用「域 + 语义」的层级 key 方案,例如: - `common.ok` - `nav.dashboard` - `header.apiDocs` - `settings.robot.wecom.token` ### 2.2 目录结构 - `web/templates/index.html` - 页面骨架 + 所有静态文案位置,将逐步改为 `data-i18n` 标记。 - `web/static/js/i18n.js` - 前端 i18n 初始化与 DOM 应用逻辑(本方案新增)。 - `web/static/i18n/`(新增目录) - `zh-CN.json`:中文文案(默认语言) - `en-US.json`:英文文案 - 未来可新增:`ja-JP.json`、`ko-KR.json` 等。 --- ## 三、文案组织规范 ### 3.1 Key 命名约定 - 采用「**模块.语义**」形式,最多 2–3 级,确保可读性: - 导航:`nav.dashboard`、`nav.chat`、`nav.settings` - 头部:`header.title`、`header.apiDocs`、`header.logout` - 登录:`login.title`、`login.subtitle`、`login.passwordLabel`、`login.submit` - 仪表盘:`dashboard.title`、`dashboard.refresh`、`dashboard.runningTasks` - 系统设置:`settings.title`、`settings.nav.basic`、`settings.nav.robot`、`settings.apply` - 机器人配置:`settings.robot.wecom.enabled`、`settings.robot.wecom.token` 等。 - 尽量按「界面区域」而不是「文件名」划分域,便于非开发人员理解。 ### 3.2 JSON 示例 `web/static/i18n/zh-CN.json` 示例: ```json { "common": { "ok": "确定", "cancel": "取消" }, "nav": { "dashboard": "仪表盘", "chat": "对话", "infoCollect": "信息收集", "tasks": "任务管理", "vulnerabilities": "漏洞管理", "settings": "系统设置" }, "header": { "title": "CyberStrikeAI", "apiDocs": "API 文档", "logout": "退出登录", "language": "界面语言" }, "login": { "title": "登录 CyberStrikeAI", "subtitle": "请输入配置中的访问密码", "passwordLabel": "密码", "passwordPlaceholder": "输入登录密码", "submit": "登录" } } ``` 英文文件 `en-US.json` 保持相同 key,不同 value: ```json { "common": { "ok": "OK", "cancel": "Cancel" }, "nav": { "dashboard": "Dashboard", "chat": "Chat", "infoCollect": "Recon", "tasks": "Tasks", "vulnerabilities": "Vulnerabilities", "settings": "Settings" }, "header": { "title": "CyberStrikeAI", "apiDocs": "API Docs", "logout": "Sign out", "language": "Interface language" }, "login": { "title": "Sign in to CyberStrikeAI", "subtitle": "Enter the access password from config", "passwordLabel": "Password", "passwordPlaceholder": "Enter password", "submit": "Sign in" } } ``` > 约定:**新增界面时,必须先定义 i18n key,再在 HTML/JS 中使用 key**,禁止直接写死中文/英文。 --- ## 四、HTML 标记规范(data-i18n) ### 4.1 基本规则 - 使用 `data-i18n` 将元素文本与某个 key 绑定: ```html 仪表盘 ``` - 默认行为:脚本会替换元素的 `textContent`。 - 同时翻译属性时,额外使用 `data-i18n-attr`,逗号分隔多个属性名: ```html ``` ### 4.2 默认文本的作用 - HTML 内的中文默认值作为「**无 JS / 初始化前**」的占位内容: - 页面在 JS 尚未加载完成时不会出现空白或 key。 - JS 初始化后会用当前语言覆盖这些文本。 --- ## 五、JavaScript 中的文案规范 ### 5.1 全局翻译函数 `t()` 由 `i18n.js` 暴露以下全局函数: - `window.t(key: string): string` - 返回当前语言下的翻译文本,若缺失则回退到默认语言,再不行则返回 key 本身。 - `window.changeLanguage(lang: string): Promise` - 切换语言并刷新页面文案(不会刷新整页)。 示例(以 `web/static/js/settings.js` 为例): ```js // 之前 alert('加载配置失败: ' + error.message); // 之后 alert(t('settings.loadConfigFailed') + ': ' + error.message); ``` > 规范:**JS 内所有面向用户的提示、按钮文字、对话框标题都应通过 `t()` 获取**,不直接写死中文/英文。 ### 5.2 渐进迁移建议 - 优先改造: - 频繁弹出的错误提示 / 成功提示; - 登录相关、系统设置相关文案。 - 低优先级: - 仅面向运维人员的调试提示,可以暂时保留英文/中文常量。 --- ## 六、i18n 初始化与语言切换实现 ### 6.1 语言选择策略 - 默认语言:`zh-CN`。 - 优先级(从高到低): 1. `localStorage` 中的用户选择(key:`csai_lang`)。 2. 浏览器 `navigator.language`(`zh` 开头 → `zh-CN`,否则 `en-US`)。 3. 默认 `zh-CN`。 ### 6.2 初始化流程(`i18n.js`) 1. 读取初始语言。 2. 初始化 i18next: - `lng` 为当前语言; - `fallbackLng` 为 `zh-CN`; - 资源先留空,采用按需加载。 3. 通过 `fetch` 拉取 `/static/i18n/{lng}.json` 并 `i18next.addResources`。 4. 更新: - `` 属性; - 所有带 `data-i18n` / `data-i18n-attr` 的元素。 5. 暴露 `window.t` 与 `window.changeLanguage`。 ### 6.3 DOM 应用逻辑 伪代码: ```js function applyTranslations(root = document) { const elements = root.querySelectorAll('[data-i18n]'); elements.forEach(el => { const key = el.getAttribute('data-i18n'); if (!key) return; const text = i18next.t(key); if (text) { el.textContent = text; } const attrList = el.getAttribute('data-i18n-attr'); if (attrList) { attrList.split(',').map(s => s.trim()).forEach(attr => { if (!attr) return; const val = i18next.t(key); if (val) el.setAttribute(attr, val); }); } }); } ``` > 对于由 JS 动态插入的元素,需要在插入后再次调用 `applyTranslations(新容器)`。 --- ## 七、语言切换 UI 规范 ### 7.1 位置与形态 - 位置:`index.html` header 右侧 `API 文档` 按钮附近(靠近用户头像)。 - 交互形式: - 一个紧凑的语言切换组件,例如: - `🌐` 图标 + 当前语言文本(`中文` / `English`)的下拉按钮; - 下拉内容列出所有可用语言。 ### 7.2 示例结构 ```html
``` 对应 JS(在 `i18n.js` 中): ```js function onLanguageSelect(lang) { changeLanguage(lang).then(updateLangLabel).catch(console.error); closeLangDropdown(); } function updateLangLabel() { const labelEl = document.getElementById('current-lang-label'); if (!labelEl) return; const lang = i18next.language || 'zh-CN'; labelEl.textContent = lang.startsWith('zh') ? '中文' : 'English'; } ``` > 规范:**语言切换只更新文案,不刷新整页,也不修改 URL hash**。 --- ## 八、开发流程建议 ### 8.1 新增 / 修改界面的流程 1. 设计界面时,先列出所有文案。 2. 在对应语言 JSON 中补充/修改 key 与翻译。 3. 在 HTML 中使用 `data-i18n`,在 JS 中使用 `t('...')`。 4. 在浏览器中切换中英文,确认两种语言显示都正确。 ### 8.2 渐进式改造顺序(推荐) 1. **阶段 1(已规划)** - 引入 i18next 与 `i18n.js`。 - 新建 `zh-CN.json` / `en-US.json`(先覆盖 header / 登录 / 左侧导航)。 - 实现 header 区域语言切换组件。 2. **阶段 2**(已完成) - 系统设置页面(包括机器人配置页面)全部文案 i18n 化。 - `settings.js` 中的提示与错误信息改用 `t()`。 3. **阶段 3**(进行中) - 仪表盘、任务管理、漏洞管理、MCP、Skills、Roles 等页面按模块逐步迁移。 4. **阶段 4** - 清理 JS / HTML 中残留的硬编码中文,统一通过 i18n。 --- ## 九、后续扩展新语言 当需要新增语言时: 1. 在 `web/static/i18n/` 中新增 `{lang}.json`,复制现有英文/中文文件结构,补充对应翻译。 2. 在语言切换下拉中添加对应选项,例如: - `data-lang="ja-JP"` / 文本 `日本語` 3. 无需修改 `i18n.js` 或现有 HTML/JS 逻辑,即可支持新语言。 --- ## 十、注意事项与坑点 - **不要复制多份 HTML 模板** 来做多语言,那样维护成本极高,本方案统一由前端 i18n 控制。 - **避免 key 直接用中文/英文句子**,统一采用「模块.语义」短 key,便于 diff 与搜索。 - 避免在 CSS 中写死文本(如 `content: "xxx"`),如确有需要,应通过 JS 设置并走 i18n。 - 对于后端返回的可本地化错误文本(未来可能支持),优先由后端根据 `Accept-Language` 返回对应语言,前端只负责展示。