news 2026/9/11 5:14:25

如何为 1Panel 新增一种界面语言并按贡献指南完成全部注册与验证?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何为 1Panel 新增一种界面语言并按贡献指南完成全部注册与验证?

如何为 1Panel 新增一种界面语言并按贡献指南完成全部注册与验证?

【免费下载链接】1Panel🔥 1Panel is a modern, open-source Linux server management panel and a lightweight AI management platform.项目地址: https://gitcode.com/GitHub_Trending/1p/1Panel

为 1Panel 增加一种界面语言不是复制一个语言文件就结束的:一个完整 locale 会同时涉及前端(Vue 3 +vue-i18n+ Element Plus)、Core 服务(Go i18n YAML)、Agent 服务(独立 Go i18n YAML)、应用商店元数据模型,以及项目 README 五个面。只改前端模块不构成完整的 locale 支持。docs/TRANSLATION.md 给出了全部需要创建或修改的文件清单、验证命令和 PR checklist,CONTRIBUTING.md 的 "Add a new translation" 一节也指向这份指南,并建议参考已有的参考 PR(西语完整 locale 的#10352)作为具体例子。

本文按该指南的 Step 0–11 走一遍完整流程,并以指南中 PR 标题约定示例使用的德语(运行时 localede-DE)作为贯穿示例,说明每一处改动的位置、写法和完成后的验证方式。

第一步:先确定 locale 代码,再动手改代码

先选定规范化的运行时 locale(canonical runtime locale):用 BCP 47 语言标签,并在运行时 locale 的所有出现位置保持同一套大小写。文件名和第三方 locale 包的大小写不一定和它一致,不能由运行时 locale 直接推导文件名——大小写或编码不同时要显式补一条映射。

指南中给出的代码对照表(以现有语言为例):

Language运行时 locale前端模块Element Plus pack后端 YAML应用商店 keyREADME
Simplified Chinesezhzh.tszh-cnzh.yamlzhREADME.zh-Hans.md
Traditional Chinesezh-Hantzh-Hant.tszh-twzh-Hant.yamlzh-hantREADME.zh-Hant.md
Englishenen.tsenen.yamlenREADME.md
Brazilian Portuguesept-BRpt-br.tspt-brpt-BR.yamlpt-brREADME.pt-br.md
Spanish (Spain)es-ESes-es.tseses-ES.yamles-esREADME.es-es.md
Laololo.tslolo.yamlloREADME.lo.md

规则:简单编码用全小写(jakolo),变体用标准 BCP 47 大小写(pt-BRes-ESzh-Hant)。对德语示例,运行时 locale 为de-DE,后续代码块中的占位符含义为:

  • <runtime-locale>:你选定的运行时 locale,如de-DE
  • <module-name>:前端模块文件名(不含扩展名),大小写可不同,如de-de
  • <app-store-key>:应用商店 JSON key,全小写,如de-de
  • <Native language name>:该语言的本地化名称,用作界面菜单显示名。

改动前,先全仓搜索硬编码的 locale 集合,避免漏掉新增的选择器、白名单或兼容性映射:

rg "zh-Hant|pt-BR|es-ES" frontend core agent

把模式替换成你要新增的 locale 后执行,命中位置都要逐一检查是否需要加入新语言。

第二步:前端翻译模块与两处注册

新增语言模块

从英文模块复制并翻译,注意从你改动所在的同一分支复制,不要依赖固定的 key 数或行数:

frontend/src/lang/modules/en.ts -> frontend/src/lang/modules/<module-name>.ts

以下保持不变(除非英文源发生了结构性变化):对象 key、嵌套结构和 TypeScript 语法;{0}${name}{{ .detail }}等插值占位符;HTML 标签、Markdown、URL、产品名、命令和配置键;文件末尾的getFuLocaleMessage合并。传给getFuLocaleMessage的必须是运行时 locale,即使模块文件名大小写不同:

import { getFuLocaleMessage } from '@/lang/fu'; const message = { commons: { // Translated values. }, }; export default { ...getFuLocaleMessage('<runtime-locale>'), ...message, };

机器翻译可以做第一遍,但每条字符串都要在界面上下文中复查。

注册 loader 与 FU 消息

在 frontend/src/lang/index.ts 的LOCALE_LOADERS中加入运行时 locale 到模块文件的映射(该文件当前包含zhzh-Hantenpt-BRjarumskolotrfaes-ES共 12 个条目,新语言需要第 13 条):

const LOCALE_LOADERS: Record<string, LocaleLoader> = { // Existing entries. '<runtime-locale>': () => import('./modules/<module-name>'), };

在 frontend/src/lang/fu.ts 的fuLocales中加同一 key。这部分消息属于共享 FU 表格和 steps 组件,不由主语言模块提供:

const fuLocales: Record<string, FuLocaleMessage> = { // Existing entries. '<runtime-locale>': { fu: { table: { more: '...', custom_table_rows: '...', }, steps: { cancel: '...', prev: '...', next: '...', finish: '...', }, }, }, };

第三步:注册 Element Plus locale

Element Plus 为日期选择、分页、弹层等组件提供自己的翻译。在 frontend/src/App.vue 中导入对应语言包并在i18nLocale计算属性里映射运行时 locale:

import localePack from 'element-plus/es/locale/lang/<element-plus-code>'; const i18nLocale = computed(() => { // Existing mappings. if (globalStore.language === '<runtime-locale>') return localePack; return zhCn; });

先在frontend/node_modules/element-plus/es/locale/lang/中确认语言包存在。若 Element Plus 不提供该语言,不要在 PR 中导入一个不存在的模块,而是把所选 fallback 写入 PR 说明。

第四步:把语言暴露到每个前端入口

登录页:frontend/src/views/login/components/login-form.vue 中当前有两个不同登录布局对应的语言菜单,新 locale 要加进两个菜单块,再把本地化名称加进languageLabelMap

const languageLabelMap: Record<string, string> = { // Existing entries. '<runtime-locale>': '<Native language name>', };

指南明确提醒:只改languageLabelMap只会改变选中项的显示名,不会新增可选菜单项,所以两种登录布局都要手工验证。

面板设置:在 frontend/src/views/setting/panel/index.vue 的languageOptions中加一项:

const languageOptions = ref([ // Existing entries. { value: '<runtime-locale>', label: '<Native language name>' }, ]);

公开分享页:在 frontend/src/views/share/index.vue 的supportedLocales中加运行时 locale。这个列表控制浏览器语言识别,以及公开分享请求使用的Accept-Language头。

与 locale 相关的 fallback:审查按语言选择 API 字段的比较逻辑。指南举的例子是 frontend/src/views/log/operation/index.vue:操作记录提供中文和英文两个详情字段,中文运行时 locale 用detailZH,其余 locale 保留可见的detailENfallback;应优先用一个共享 fallback 分支,而不是把每个非中文 locale 逐个加进新的硬编码列表。

第五步:放开登录接口的语言校验

后端会校验登录请求携带的语言,新语言必须加入 core/app/dto/auth.go 中Language字段的oneof校验标签:

Language string `json:"language" validate:"oneof=zh en ... <runtime-locale>"`

当前该行实际内容为validate:"required,oneof=zh en 'zh-Hant' ko ja ru ms 'pt-BR' tr 'es-ES' fa lo",注意带连字符的编码在现有写法中加了引号。没有这处改动,新语言能出现在登录页上,但登录请求会作为非法参数被拒绝。编辑完成后对该 Go 文件跑gofmt

第六步:Core 与 Agent 的 YAML 目录(两个独立模块)

Core 和 Agent 是各自独立的 Go module,目录互不相通,必须分别复制翻译。

Core:

core/i18n/lang/en.yaml -> core/i18n/lang/<runtime-locale>.yaml

然后在 core/i18n/i18n.go 的langFiles中注册:

var langFiles = map[string]string{ // Existing entries. "<runtime-locale>": "lang/<runtime-locale>.yaml", }

Agent:

agent/i18n/lang/en.yaml -> agent/i18n/lang/<runtime-locale>.yaml

在 agent/i18n/i18n.go 的langFiles中做同样注册。两边翻译时只改值,保留全部 YAML key 和占位符,例如:

ErrInvalidParams: "Translated text: {{ .detail }}" ErrRecordExist: "Translated text"

两个关键约束:不要把 Core 的 YAML 拷进 Agent,两边 key 集合不同;这两个i18n.go都用//go:embed lang/*内嵌目录,若任一文件加载失败会 panic([i18n] failed to init language files),所以 YAML 语法错误会直接导致对应服务起不来。

第七步:扩展应用商店的 locale 模型

应用商店名称和描述使用独立的 locale 字段,需要在仓库两侧 schema 各加一个字段:

在 agent/app/dto/app.go 的Locale结构体中(当前包含enjamspt-brruzh-hantzhkotres-esfalo):

type Locale struct { // Existing fields. NewLanguage string `json:"<app-store-key>"` }

在 frontend/src/api/interface/app.ts 的Locale接口中用同一 JSON key:

interface Locale { // Existing fields. '<app-store-key>': string; }

同时在 core/cmd/server/app/app_config.yml 的description示例中加上新 key——这个内嵌模板会在 server 命令为本地应用配置做脚手架时写入。

另外审查 frontend/src/utils/app-store.ts:能直接小写映射到应用商店 key 的简单编码通常无需特殊处理;区域性或文字变体可能需要显式的运行时 locale 到应用商店 key 的映射。指南同时说明:这些 schema 改动只是让仓库"能读"该 locale,翻译后的应用名称和描述维护在外部应用商店数据源中,需要单独协调;在该数据存在之前,应用商店会 fallback 到英文。

第八步:本地化 README

把根 README 复制到 docs 目录并翻译:

README.md -> docs/README.<readme-code>.md

翻译时保留 Markdown 结构、HTML、图片、链接、命令、badge 和代码示例;从docs/下的新位置逐个核对相对链接——在仓库根目录能用的链接,在本地化文件里可能需要不同的相对路径。然后保持语言导航同步:

  1. 在 README.md 的语言 badge 行加入新 README 链接;
  2. 在现有每个docs/README.*.md的语言 badge 行加入同一链接;
  3. 在 docs/TRANSLATION.md 的 Locale code reference 表中加入该 locale。

badge 标签用语言本地名。README 后缀可以沿用现有文档惯例(zh-Hanspt-bres-es),不必与运行时 locale 大小写一致。

第九步:格式化与重新生成 API 文档

对所有改动的 Go 源文件跑gofmt

gofmt -w core/app/dto/auth.go core/i18n/i18n.go gofmt -w agent/app/dto/app.go agent/i18n/i18n.go

登录语言枚举和应用商店 locale 模型都体现在生成的 Swagger 文件里。安装与仓库兼容的swag命令后,从 Core 模块运行生成测试:

cd core go test ./cmd/server/docs -run TestGenerateSwaggerDoc

它会更新core/cmd/server/docs/下的生成文件,不要手工编辑 Swagger 输出。如果生成器不可用,要在 PR 中明确说明,而不是提交过期的手工修改。

第十步:自动化验证

从仓库根目录执行(除命令中显式cd的位置外):

# Frontend type checking. cd frontend npm run type-check # Lint only the frontend files changed by the locale contribution. ./node_modules/.bin/eslint \ src/lang/modules/<module-name>.ts \ src/lang/index.ts \ src/lang/fu.ts \ src/App.vue \ src/views/login/components/login-form.vue \ src/views/setting/panel/index.vue \ src/views/share/index.vue \ src/views/log/operation/index.vue \ src/api/interface/app.ts \ src/utils/app-store.ts # Compile and test the directly affected Go packages. cd ../core go test ./i18n ./app/dto cd ../agent go test ./i18n ./app/dto # Check whitespace errors in all changed files. cd .. git diff --check

eslint参数清单即本次改动涉及的前端文件列表,<module-name>替换为你新建的模块文件名。go test ./i18n ./app/dto编译并测试直接受影响的包——由于两个i18n.go都在加载失败时 panic,YAML 解析错误和 key 问题会在这里暴露。

再人工比对每个翻译目录与英文源:前端模块的 key 与嵌套一致;Core 和 Agent 的每个 YAML 与对应英文文件 key 完全一致;占位符、格式化 token、HTML 标签、URL、命令均保留;YAML 可解析且无重复 key;README 链接与 badge 均能解析到目标文件。

第十一步:手工验证清单

指南给出的界面级验证项(勾选式):

  • 两种登录布局都显示该语言本地名且可选中;
  • 登录请求携带该 locale 时成功,不被校验拒绝;
  • 设置 -> 面板 -> 语言能切换到该 locale,刷新后保留;
  • Element Plus 的日期、分页、选择器、确认组件显示预期语言;
  • 一条代表性的 Core API 错误消息是翻译后的;
  • 一条代表性的 Agent 任务/错误消息是翻译后的;
  • 公开分享页能识别浏览器 locale 并发送预期的Accept-Language值;
  • 操作日志详情通过正确的中文或英文 fallback 保持可见;
  • 应用商店元数据在该 locale 可用时使用它,缺失时 fallback 到英文;
  • 本地化 README 渲染正确,每个 README 语言 badge 都链向它;
  • 常见屏幕尺寸下布局、标点、截断和文字方向正确。

若目标是右到左语言(RTL),指南提醒要额外验证登录页、导航、表单、表格、对话框以及 IP 地址这类混合方向内容;RTL 布局支持可能需要超出翻译字符串的独立前端改动。

外部资源与 PR 收尾

有两类运行时资源不在本仓库维护:应用商店的名称和描述来自外部应用商店数据源;以language/lang.tar.gz下载的语言 shell 资源通过 1Panel 资源服务发布。仓库内的 locale 支持不会自动更新它们;新语言如需要,要与相应维护者协调发布,并在 PR 中记录状态;除非维护者要求,不要把生成或下载的归档加进仓库。

PR 标题约定:

feat(i18n): add <language name> (<runtime-locale>) locale support

指南给的示例是feat(i18n): add German (de-DE) locale support

提交前对照指南末尾的 "Complete pull-request checklist" 逐项检查,它覆盖了本文全部步骤:五种代码的文档化、前端模块/LOCALE_LOADERS/fuLocales/App.vue映射、两个登录菜单与languageLabelMaplanguageOptionssupportedLocales、locale 敏感 fallback、登录校验器、Core 与 Agent 目录及注册、应用商店三处 schema 与app-store.ts、README 与 badge 同步、Go 格式化与 Swagger 重生成、各类检查与手工项、外部资源工作状态。若某个面(如应用商店外部数据)刻意不在本次范围内,要在 PR 中明确说明。

【免费下载链接】1Panel🔥 1Panel is a modern, open-source Linux server management panel and a lightweight AI management platform.项目地址: https://gitcode.com/GitHub_Trending/1p/1Panel

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 5:12:02

破解ZLibrary反爬机制:Python爬虫高级技巧

1. 项目背景与核心挑战ZLibrary作为全球最大的数字图书馆之一&#xff0c;其反爬机制经历了多次迭代升级。2023年最新统计显示&#xff0c;平台日均拦截异常请求超过1200万次&#xff0c;其中针对Python爬虫的识别准确率高达92%。这主要得益于其动态渲染验证、行为指纹分析和请…

作者头像 李华
网站建设 2026/9/11 5:09:45

铸造行业温度控制技术突破与应用实践

1. 铸造行业温度控制的痛点与挑战在铸造生产线上&#xff0c;金属熔液的温度控制精度直接决定了铸件质量和工艺稳定性。以某年产20万吨的大型球墨铸铁厂为例&#xff0c;其熔炼车间每天需要处理超过600吨铁水&#xff0c;温度波动超过15℃就会导致球化不良、缩松等缺陷&#xf…

作者头像 李华
网站建设 2026/9/11 5:07:54

Python魔法方法__imod__:原地取模运算详解

1. Python魔法方法__imod__深度解析在Python中&#xff0c;魔法方法&#xff08;Magic Methods&#xff09;是那些以双下划线开头和结尾的特殊方法&#xff0c;它们为类提供了运算符重载的能力。今天我们要重点讨论的是__imod__这个不太常见但非常有用的魔法方法。__imod__方法…

作者头像 李华
网站建设 2026/9/11 5:07:18

嵌入式Linux下Modbus RTU通信的四大硬核挑战与实战方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 5:01:48

Python实现壁纸自动下载工具的技术解析

1. 项目概述&#xff1a;用Python打造壁纸自动下载工具每次手动下载壁纸都要经历"搜索→筛选→保存"的重复操作&#xff1f;作为Python开发者&#xff0c;我花了三天时间开发了一套全自动壁纸下载脚本。这个工具能根据关键词自动抓取高清壁纸&#xff0c;支持定时任务…

作者头像 李华