6.9 KiB
运行时语言与国际化
运维输出与界面文案
Server、Agent、后台任务、安装/卸载脚本以及浏览器 PoW 调试日志的固定文案使用英文。语言切换不会改变控制台日志或 OTel 异常信息,便于跨语言检索和排障。任务参数、文件名、用户配置和第三方错误保留原文,可能包含中文。
前端使用 next-intl,支持 en、zh-CN 和 ru,默认语言仍为 en。语言偏好按 NEXT_LOCALE Cookie、浏览器语言、默认语言的顺序解析,俄语区域变体(如 ru-RU)归一为 ru。文案维护在 frontend/messages/fragments,通过 node scripts/merge-i18n-fragments.mjs 生成主消息包,禁止手动修改生成的 en.json、zh-CN.json 和 ru.json。技术示例与 HTML 使用原始消息读取,避免把代码中的花括号当作 ICU 参数。
语言选择器始终从各语言自己的资源读取名称:English、中文、Русский,不随当前界面语言翻译语言名称。日期、数字和日历跟随界面语言;语言切换不改变既有时区。俄语数量文案使用 ICU 的 one、few、many 和 other 分支。
静态导出仍预渲染英文。<head> 中的独立启动脚本在正文绘制前读取语言偏好;若与预渲染语言不同,则暂时隐藏正文,Provider 提交对应语言资源后再显示,避免刷新时闪现英文。脚本不依赖应用 bundle,损坏的 Cookie 会回退到浏览器语言。脚本加载出错或等待超过 10 秒时,显示同语言的独立恢复提示和重新加载按钮;应用恢复后隐藏提示并清理等待监听,避免无限空白页。格式化使用的语言在 Provider 更新上下文前同步,已有数据的首次本地化渲染也使用正确的日期和数字格式。
不在 React 渲染上下文中的浏览器代码(如网络异常和纯表单工具)通过 frontend/i18n/runtime.ts 调用同一套 next-intl 文案。消息在使用时解析语言,不在模块导入时固定语言。API 客户端发送当前界面语言的 Accept-Language。
服务端展示边界
pkg/i18n/locales 保留内置服务端文案的英文、中文和俄语版本,英文同时是运行时源码中的基准文案。展示接口依次采用 NEXT_LOCALE Cookie、Accept-Language,没有支持的语言时回退英文。
- 错误中间件先记录原始英文异常及 OTel 状态,再翻译 HTTP 响应中的
error_msg。登录流程使用的smtp_invalid:和need_email_code:控制前缀保持不变。 - 任务类型、参数说明、执行记录和内置通知元数据使用请求内的副本进行翻译,避免修改共享注册表或持久化记录。
- 默认定时任务名称可翻译;管理员自定义名称、通知接收目标和已保存的消息模板保留原文。
- 通知接收目标只识别既有技术标识
system、0和历史别名系统;显示译文System、Система不会扩大保留目标集合,也不会把同名普通用户改投给管理员。 - 新任务执行详情保存英文系统文案。历史中文文本通过已知的完整文案或格式模板在读取时展示为英文,不执行数据库回写。
格式模板只识别已登记的系统消息,并逐字保留捕获到的参数;时间戳也保留。未知消息原样返回。此兼容机制只用于系统拥有的展示字段,不能用来翻译任意用户数据,也不能通过比较翻译后的文本决定业务状态。任务重试和存储配置校验使用错误类型进行分类。
持久化兼容性
上传统计原有的六个中文分类名同时是数据库计数器键和 API 分类标识,不能当作标签直接改名。保留这些既有键,前端图表、图例和最大分类说明单独使用语言包标签;无需清空或重建现有统计。
历史 SQL 迁移、测试样例、中文项目文档以及用户已经保存的数据不属于待替换的运行时固定文案。离线页面和通知模板一旦由管理员选择、编辑并保存,就作为用户数据处理,不随界面语言切换而回写。
系统配置描述和内置邮件模板的名称、说明可能来自历史 seed。管理界面仅在配置键或内置模板键已登记、且文本与已知语言默认值完全一致时,使用 builtin-metadata 语言分片展示;未知键、自定义描述与非内置模板保持原文。编辑表单保留原始状态,单纯保存其他字段不会把展示翻译写回数据库;邮件主题和正文始终按已保存内容显示。内置源站错误页和离线页在选择模板或空值预览时使用当前语言,已保存的自定义 HTML 保持不变。
系统状态 API 的诊断时长和容量字符串保留英文及技术单位,界面在展示边界转换为当前语言;原始字符串继续用于既有内存计算。数据库计数采用当前 next-intl 上下文格式化。日历使用 DayPicker 扩展语言包,同时翻译日期与导航、下拉框、选中日期等无障碍名称。
校验与扩展
在仓库根目录运行 node scripts/audit-non-english.mjs 可生成完整的非 ASCII 文本清单,默认输出到被 Git 忽略的 .codex-artifacts/non-english-audit/。occurrences.csv 包含文件、行号、模块、分类和原文;JSON 另含字符位置、Unicode 码点、字符集及跳过的文件;review-candidates.csv 单列待审查源码。命令读取所有已跟踪和未被忽略的新文件,不按业务目录名称排除内容,也识别 Unicode 转义。
清单包含标点、表情、注释、文档、语言资源与历史迁移,不表示每个命中都需要替换。依赖、构建输出和私有环境文件不进入清单;二进制文件单独列出,不执行截图 OCR 或解包。生成的 Swagger 和中文文档站配置保留中文,既有上传分类键保留兼容性。字符集也不等同于语言,例如 Han 字符可能属于中文或日文。
pnpm check:i18n 校验三个语言包的键、标签和 $ 变量一致性,并检查 Go、TypeScript/TSX 和安装脚本中的汉字、日文假名、韩文及西里尔字母运行时文本;注释、语言资源、测试样例、六个上传持久化键及通知历史目标别名有明确边界。该检查同时接入 make code-check 和现有前端 CI。俄语资源测试还验证命名参数、真实 rich-text 渲染、ICU 格式、复数边界、可复制的限速语法及 HTML 模板占位符,服务端测试验证格式动词、模板变量和枚举值。技术标识(如 10r/s、30m、true、and)不随语言翻译。
新增语言时,补齐前端分片、语言配置与 Provider 消息映射,以及服务端同名语言目录项,并验证格式占位符一致。新增系统消息仍以英文作为源文案,在相应语言资源中补齐译文。新增数据协议应使用稳定标识与参数,不再引入以中文显示文案充当持久化键的设计。