PT 助手 Plus 多语言(i18n)体系解析:语言文件格式、翻译协作流程与临时语言加载机制

原创2026-10-01 16:56:511,339 阅读
文章标签:前端

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 的多语言环境仍处于「构建中」状态:现阶段的主要工作是把中文文案翻译为英文,待英文文案可复用的程度达标后,英文将作为后续其他语言的源文件(即从英文再翻译为法、德、日等其他语言)。这意味着当前仓库内置的两份语言文件具有不同定位:

从 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"
  }
}

语言文件中存在两种跨词条复用语法,翻译时必须保留原样、不要改动:

  1. 引用语法 @:(...):引用其他词条的值,例如 en.json 中 "title": "@:(app.name)" 表示复用 app.name("PT Plugin Plus"),"ok": "@:(common.ok)" 复用通用"OK"。这在配置页的 VueI18n 链路中由 src/options/i18n.ts 的 setLocaleMessage 注册后自动解析;
  2. 占位符插值 {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 明确给出了两条参与路径:

  1. 在线翻译:通过 Transifex 平台的 pt-plugin-plus-dev 项目在线翻译(本文不展开外部平台链接,按仓库文档指引在配置页右下角或项目文档中获取入口);
  2. 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 提供了完整的本地测试步骤,是语言贡献者验证自己翻译成果的标准流程:

  1. 版本前提:将助手更新至 v1.0.9 之后的版本(该功能随版本引入,若版本过低将看不到对应入口);
  2. 进入配置页:打开 PT 助手 Plus 的配置页面;
  3. 打开语言菜单:点击页面右下角的 切换语言 按钮,在弹出的菜单中选择 临时添加新语言;
  4. 选择语言文件:在弹出的文件选择器中选中已翻译好的语言文件,例如 zh-TW.json;
  5. 验证结果:如果文件格式正确,配置页界面应能立即切换到新语言显示;如果格式有误,则会收到"无效的语言文件!"提示;
  6. 来源说明:如果文案是通过 Transifex 在线翻译的,可从平台下载已翻译好的文件进行同样的测试;
  7. 临时性提示:通过该方式添加的语言文件仅本次生效,浏览器重启后恢复到默认状态,不会污染用户的语言配置。

从源码看,这条测试路径的界面入口在 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 的多语言体系可以概括为四个要点:

  1. 格式统一:语言即一份 {name, code, authors, words} 结构的 JSON 文件,词条按模块嵌套、支持 @:(...) 引用与 {...} 插值;
  2. 流程清晰:以简体中文为源,经 Transifex 或 git 提交翻译为英文,复核转正后作为其他语言的基准;
  3. 测试便捷:v1.0.9 之后可在配置页右下角"临时添加新语言"直接加载本地文件即时预览,失败时给出明确错误提示;
  4. 架构双轨:配置页(vue-i18n)与后台(i18next)各自维护一套 i18n 服务,但共享同一套语言文件格式与资源地址,且均以英文作为兜底回退语言。

对于希望为该项目贡献翻译或扩展新语言的开发者,可对照 resource/i18n/en.json 与 resource/i18n/zh-CN.json 编写自己的语言文件,按上文步骤在本地验证,再通过文档所述渠道提交。

登录后查看全文
PT-Plugin-Plus