PT 助手 Plus 多语言(i18n)体系解析:语言文件格式、翻译协作流程与临时语言加载机制
PT 助手 Plus 多语言(i18n)体系解析:语言文件格式、翻译协作流程与临时语言加载机制
PT 助手 Plus(PT Plugin Plus)是一个面向 PT 站用户的浏览器扩展,其配置页、搜索页、后台服务等模块的全部文案均通过一套自建的多语言(i18n)体系管理。本文以仓库中 resource/i18n/README.md 为核心骨架,结合 resource/i18n/ 下的真实语言文件与 src/options/i18n.ts、src/background/i18n.ts 等源码实现,系统讲解语言文件的 JSON 规范、翻译协作与文案更新流程,以及如何在配置页中「临时添加新语言」进行本地化测试。读完本文,你将能独立完成一份新语言文件的编写、校验与临时加载测试,并理解该插件前后端两条 i18n 链路的底层工作方式。
一、多语言现状:以中文为源、英文为桥
按 resource/i18n/README.md 的说明,PT 助手 Plus 的多语言环境仍处于「构建中」状态:现阶段的主要工作是把中文文案翻译为英文,待英文文案可复用的程度达标后,英文将作为后续其他语言的源文件(即从英文再翻译为法、德、日等其他语言)。这意味着当前仓库内置的两份语言文件具有不同定位:
- resource/i18n/zh-CN.json:简体中文,是内容的原始来源;
- resource/i18n/en.json:英文(Beta),是当前翻译主战场,也将是未来多语言扩展的中间桥梁。
从 src/options/i18n.ts 可以看到,配置页在构造 i18nService 时会固定预加载这两份内置语言包,保证任何用户打开配置页都有可用的界面语言:
constructor() {
// 加载所有语言包
this.loadLangResource("en");
this.loadLangResource("zh-CN");
}
值得注意的是,src/options/i18n.ts 中 VueI18n 的 fallbackLocale 被设置为 "en"。因此当用户切换到某个未完全翻译的语言时,缺失的词条会回退显示英文,而不是空白或报错——这也正是文档要求"英文文案先可用"的技术原因之一。
二、语言文件格式规范:一份 JSON 就是一门语言
要参与翻译或测试新语言,首先必须理解语言文件的结构。仓库中 resource/i18n/en.json 与 resource/i18n/zh-CN.json 是同构的 JSON,顶层包含四个字段:
| 字段 | 类型 | 说明 |
|---|---|---|
name |
string | 语言显示名称,如 "English (Beta)"、"简体中文 Chinese (Simplified)",用于配置页语言下拉列表 |
code |
string | 语言代码,如 en、zh-CN,是加载与切换语言的唯一标识 |
authors |
string[] | 该语言文件的译者署名列表 |
words |
object | 实际的文案字典,按业务模块层层嵌套 |
这个结构与 src/interface/common.ts 中定义的 i18nResource 类型一一对应:
export type i18nResource = {
name: string;
code: string;
authors?: Array<string>;
words: Dictionary<any>;
};
words 字典采用模块化嵌套,顶层键与配置页的页面/功能模块对应,例如:
app:应用名、初始化提示等全局文案;common:通用操作(确认/取消/复制/删除等);navigation:配置页左侧导航;settings.base:常规设置各项参数;searchTorrent:搜索结果页相关文案;service.controller/service.searcher:后台服务的提示信息;contentPage:站点页面工具栏与右键菜单文案。
以 resource/i18n/en.json 的 common 段为例,典型结构如下:
"common": {
"changeLanguage": "Switch language",
"addLanguage": "Add a new language temporarily",
"removeConfirm": "Are you sure you want to delete this record?",
"removeSelectedConfirm": "Are you sure you want to delete these {count} selected records?",
"orderMode": {
"asc": "ASC",
"desc": "DESC"
}
}
语言文件中存在两种跨词条复用语法,翻译时必须保留原样、不要改动:
- 引用语法
@:(...):引用其他词条的值,例如 en.json 中"title": "@:(app.name)"表示复用app.name("PT Plugin Plus"),"ok": "@:(common.ok)"复用通用"OK"。这在配置页的 VueI18n 链路中由 src/options/i18n.ts 的setLocaleMessage注册后自动解析; - 占位符插值
{xxx}:运行时替换为动态内容,如"lastUpdate": "last updated on {time}"、"searchFinished": "Search completed, found {count} results, time: {second} seconds."。后台链路(src/background/i18n.ts)在初始化 i18next 时显式配置了插值前缀/后缀为{与},与 JSON 文件中的写法完全对应:
i18next.init({
interpolation: {
prefix: "{",
suffix: "}"
}
});
因此,新增/修改词条时只需维护键值对,动态文案统一走 {占位符} 模式,翻译者无需关心运行时的插值细节。
三、翻译协作与文案更新流程
3.1 参与英文翻译的两种方式
resource/i18n/README.md 明确给出了两条参与路径:
- 在线翻译:通过 Transifex 平台的
pt-plugin-plus-dev项目在线翻译(本文不展开外部平台链接,按仓库文档指引在配置页右下角或项目文档中获取入口); - Git 方式:直接以 git 方式更新本目录下的 resource/i18n/en.json 文件,提交后由项目维护者复核合并。
对于第二种方式,翻译者应遵循上文的格式规范:保持 JSON 合法、保留 @:(...) 引用与 {...} 占位符、按 words 的模块嵌套结构逐段翻译,并在 authors 数组中追加自己的署名。
3.2 文案更新的标准流水线
文档描述的更新流程是一条单向流水线:
中文词汇增加 -> 提交至 Transifex 的 dev 项目 -> 翻译为英文 -> 复核 -> 转为正式文案 -> 翻译为其他语言
拆解如下:
- 源头上游:新功能或界面调整首先在 resource/i18n/zh-CN.json 中增加中文词条;
- 翻译环节:中文词条进入 Transifex
dev项目,由英文翻译者翻译; - 质量关卡:翻译完成后需要人工复核,只有复核通过的文案才会转正;
- 下游扩散:正式英文文案成为源文件,再据此翻译为其他语言。
这条流水线解释了为什么 en.json 当前标注为 "Beta":只有英文文案被复核转正后,才会作为其他语言的翻译基准,从而保证多语言内容的一致性与质量。
四、如何测试已翻译的新语言
resource/i18n/README.md 提供了完整的本地测试步骤,是语言贡献者验证自己翻译成果的标准流程:
- 版本前提:将助手更新至
v1.0.9之后的版本(该功能随版本引入,若版本过低将看不到对应入口); - 进入配置页:打开 PT 助手 Plus 的配置页面;
- 打开语言菜单:点击页面右下角的
切换语言按钮,在弹出的菜单中选择临时添加新语言; - 选择语言文件:在弹出的文件选择器中选中已翻译好的语言文件,例如
zh-TW.json; - 验证结果:如果文件格式正确,配置页界面应能立即切换到新语言显示;如果格式有误,则会收到"无效的语言文件!"提示;
- 来源说明:如果文案是通过 Transifex 在线翻译的,可从平台下载已翻译好的文件进行同样的测试;
- 临时性提示:通过该方式添加的语言文件仅本次生效,浏览器重启后恢复到默认状态,不会污染用户的语言配置。
从源码看,这条测试路径的界面入口在 src/options/components/Footer.vue:右下角的 切换语言 菜单(对应 common.changeLanguage)中渲染一个"临时添加新语言"项(对应 common.addLanguage),点击后触发隐藏的 <input type="file"> 选择器;语言列表则来自 window.i18nService.config(即运行时从资源服务器加载的 i18n.json 语言清单)。测试用的临时语言文件会显示在同一个语言下拉列表中,并在首次加载后置为当前语言。
五、临时语言加载的底层实现机制
临时添加新语言并非简单的"读文件、显示文案",其背后是配置页 i18n 服务(src/options/i18n.ts)与界面组件(Footer.vue)的协同工作。
5.1 文件读取与校验
在 Footer.vue 的 addLanguage 方法中,选中的文件先通过 FileReader.readAsText 读取为文本,再用 JSON.parse 解析为对象,并做最少必要校验:
let result = JSON.parse(e.target.result);
if (result.code && result.words) {
this.loadLanguage(result);
this.invalidFile = false;
} else {
this.invalidFile = true;
}
即文件必须至少包含 code(语言代码)与 words(文案字典)两个字段才算有效,这与 i18nResource 类型的要求一致;任何解析异常都会置 invalidFile = true,界面随即弹出"无效的语言文件!"错误提示。
5.2 去重、添加与替换
loadLanguage 方法(Footer.vue)在注册新语言前先检查该语言代码是否已存在:
- 不存在:调用
window.i18nService.add(resource)注册新语言,并把语言名称追加到界面语言列表; - 已存在:弹窗询问"该语言已存在,是否需要替换?",确认后调用
window.i18nService.replace(resource)覆盖原有词条。
对应地,src/options/i18n.ts 的 add 与 replace 通过 VueI18n 的 setLocaleMessage 注入 words,并立即把当前语言切换为新增/替换的语言代码。其中 add 在语言已存在时会直接 reject,保证 loadedLanguages 数组(即当前会话已注册的语言集合)不会重复。
5.3 语言配置与资源加载链路
语言文件并非写死在代码中,而是运行时从资源服务器拉取。配置页 i18n 服务初始化时先请求 ${API.host}/i18n.json 获取支持的语言清单(loadConfig),再按需请求 ${API.host}/i18n/${langCode}.json 加载具体语言包(loadLangResource),见 src/options/i18n.ts。API.host 即资源服务器地址(src/service/api.ts)。这套机制说明:新增一种正式语言,本质上就是往资源服务器上放一份符合规范的 i18n/<code>.json,并在 i18n.json 清单中登记;而"临时添加新语言"则绕过了服务器,直接从本地文件加载,因此只在当前浏览器会话内生效。
5.4 后台服务的 i18n 链路
插件后台(background)使用的是另一套基于 i18next 的 i18n 服务(src/background/i18n.ts),同样支持 reset(按代码加载语言包)、add(临时新增)与 replace(替换)方法,语言包同样从 ${API.host}/i18n/${langCode}.json 拉取,并通过 i18next.addResourceBundle 注入。后台初始语言取自 service.options.locale || "en",当目标语言加载失败时(如网络异常或文件缺失),会自动回退到英文(reset("en"))。因此,测试一份新语言时,若配置页显示正常而部分提示仍为英文,可留意后台链路是否同样需要加载该语言包。
六、小结
PT 助手 Plus 的多语言体系可以概括为四个要点:
- 格式统一:语言即一份
{name, code, authors, words}结构的 JSON 文件,词条按模块嵌套、支持@:(...)引用与{...}插值; - 流程清晰:以简体中文为源,经 Transifex 或 git 提交翻译为英文,复核转正后作为其他语言的基准;
- 测试便捷:
v1.0.9之后可在配置页右下角"临时添加新语言"直接加载本地文件即时预览,失败时给出明确错误提示; - 架构双轨:配置页(vue-i18n)与后台(i18next)各自维护一套 i18n 服务,但共享同一套语言文件格式与资源地址,且均以英文作为兜底回退语言。
对于希望为该项目贡献翻译或扩展新语言的开发者,可对照 resource/i18n/en.json 与 resource/i18n/zh-CN.json 编写自己的语言文件,按上文步骤在本地验证,再通过文档所述渠道提交。