KPanel 多语言架构与本地化契约
August 2, 2026 · View on GitHub
- 状态:架构与当前公开页面的中英文覆盖均已落地
- 首期语言:
zh-CN、en-US - 默认资源:
zh-CN
1. 目标与边界
KPanel 使用前端静态语言资源呈现界面,不把翻译文本作为宿主机、Docker、Nginx 或
kejilion.sh 的第二套业务事实。API、审计、任务凭据和脚本协议继续使用稳定字段与错误码;
语言只影响当前浏览器的显示。
当前已完成全局框架、路由标题、登录、初始化、Agent 状态、公共错误状态,以及概览、网站、 应用市场、Docker、文件、体检、集群、活动记录、监控、环境管理和设置等公开业务页面的 中英文支持。命令、路径、文件内容、日志、交互终端和第三方原始错误保持原文。
2. 语言选择
优先级固定为:
- 当前浏览器已保存的用户选择;
- 首次访问时,浏览器首选语言以
zh开头则使用zh-CN; - 其他所有浏览器语言统一使用
en-US。
用户手动切换后写入 localStorage 的 kejilion-panel-locale,之后不再随浏览器语言变化。
偏好不上传服务器,不进入审计,不跨浏览器或设备同步。存储不可用时仍可切换当前页面,
下次访问重新按浏览器语言判断。
3. 资源与运行时
web/src/i18n/messages/zh-CN.ts是键集合与中文回退真源。web/src/i18n/messages/en-US.ts必须满足相同的LocaleMessages类型,不允许少键或多键。- 业务页既有中文文案由
web/src/i18n/pages/<route>/en-US.ts维护一一对应的英文短语; 动态参数统一使用{0}、{1}等位置占位符。 - 中文资源随基础包加载;英文资源通过动态
import()按需加载。 - 英文业务短语按当前路由独立懒加载;公共组件短语由
pages/shared提供,不合并进首屏。 - 切换语言时先完成资源加载,再原子更新活动语言、
document.lang与显示文案。 - 加载失败回退中文,不能让页面空白或保留一半新语言。
- 插值仅替换
{name}形式的文本参数;模板通过 Vue 文本绑定渲染,不允许语言资源携带v-html或可执行内容。 - 英文模式下的短语本地化仅处理 KPanel 管理的文本节点与
placeholder、title、aria-label;pre、code、xterm、代码编辑器和标记为data-i18n-ignore的原始输出区 永不翻译。切回中文时原子恢复原文,不重新请求业务 API。
键名使用 domain.subject,公共键放在 common、route、nav、auth、agent、
state 和 error 命名空间。后续业务资源按路由模块组织,并随对应路由代码块加载,
不得把所有业务语言包重新合并进首屏。
4. API 与错误本地化
界面优先根据稳定的 API code 映射本地文案。未知错误码保留服务端 detail/message,
便于管理员定位真实问题;无详情时使用本地通用失败提示。
新增或修改可展示错误时必须:
- 后端返回稳定、与语言无关的
code; - 前端为已知用户场景登记本地化映射;
- 不依据英文错误文本做业务分支;
- 不翻译命令输出、文件内容、容器日志、脚本终端和第三方原始错误。
5. 性能与稳定预算
zh-CN基础运行时和核心资源的 gzip 增量目标不超过8 KiB。- 非中文用户只额外请求当前语言资源,不预取未选择语言。
- 语言切换不刷新页面、不重新请求业务 API、不重建 Session。
- 路由标题和
document.title必须响应语言切换。 - 连续快速切换以最后一次选择为准,较早的异步加载结果不得覆盖新选择。
- 语言包下载失败、
localStorage被禁用或值损坏时必须保持可操作的中文界面。
6. 开发与验收规则
新增用户可见文案时:
- 优先复用现有键;确需新增时先加入
zh-CN,再补齐所有已发布语言。 - 业务标识、协议字段、命令、路径、产品名和第三方专有名词保持原文。
- 复核中英文长度对侧栏、按钮、弹窗、移动端和无障碍标签的影响。
- 执行语言选择、资源键一致性、错误码映射、类型检查、单元测试和生产构建。
- 执行
npm run i18n:check,确认所有公开业务文案均有词条、参数占位一致、无残留中文 或已知异常翻译标记。 - 检查构建清单,确认非默认语言仍是独立懒加载资源。
发布新语言前必须完成全局框架和所有公开业务路由,不对用户提供只有导航被翻译的正式语言。 开发中的语言可在功能分支验证,但不得在正式版本标记为完整支持。
7. 回滚
本地化运行时不修改服务端数据。回滚前端版本即可恢复旧界面;浏览器中保存的未知语言值会被 忽略并重新使用受支持语言,不需要数据迁移。