工作流:基于 GNU gettext 与 Launchpad 的 PO 文件导入导出实战)
aria2 多语言翻译i18n工作流基于 GNU gettext 与 Launchpad 的 PO 文件导入导出实战【免费下载链接】aria2aria2 is a lightweight multi-protocol multi-source, cross platform download utility operated in command-line. It supports HTTP/HTTPS, FTP, SFTP, BitTorrent and Metalink.项目地址: https://gitcode.com/gh_mirrors/ar/aria2aria2 作为一款跨平台、支持多协议的命令行下载工具其用户界面与日志信息同样实现了国际化i18n。本文以仓库内 po/README.rst 为骨架完整讲解 aria2 的 gettext 翻译工作流翻译协作在 Launchpad 平台上完成、PO 文件不进入代码仓库、而在制作发行包时通过import-po脚本统一导入并深入仓库源码剖析po目录各文件、import-po脚本执行细节与运行时本地化绑定帮助你掌握一套可复用的平台翻译 仓库导入 构建整合开源软件翻译管线。一、aria2 的国际化基础设施与po目录定位aria2 使用 GNU gettext 标准方案管理多语言消息。仓库根目录的 Makefile.am 第 1 行将po列为顶层子目录之一SUBDIRS po lib deps src doc test而 configure.ac 通过两条宏声明启用 gettext 支持AM_GNU_GETTEXT([external]) AM_GNU_GETTEXT_VERSION([0.19])AM_GNU_GETTEXT([external])使用系统外部安装的 gettext 工具链而不是将 gettext 的源码打进发行包AM_GNU_GETTEXT_VERSION([0.19])声明构建时要求 gettext 版本不低于 0.19。在源码仓库中po目录刻意保持精简只保留了四个非翻译内容文件当前仓库实际状态po/README.rst翻译工作流说明即本文主体po/POTFILES.in需要提取翻译条目的源码文件清单po/Makevarsgettext 在po目录生成 POT/PO 时使用的变量配置po/LINGUAS已启用语言的代码清单当前为空由导入脚本动态生成。也就是说实际的*.po翻译文件并不存储在 Git 仓库中。这是本工作流最核心的设计决策翻译过程全部在 Launchpad 翻译平台aria2 项目页上协作完成只有到制作发行包distribution archive时才将平台导出的 PO 文件批量导入po目录并参与构建。这样可以避免仓库因频繁的翻译提交而膨胀也让翻译贡献者无需掌握 Git 即可参与。二、整体工作流PO 文件不入库发布时随发行包导入以 po/README.rst 的说明为主线aria2 的翻译管线分为三个阶段协作翻译贡献者在 Launchpad 翻译平台直接对 aria2 的翻译模板POT进行翻译产出各语言的 PO 文件导出发布者在 Launchpad 页面通过download链接下载包含全部语言 PO 文件的归档launchpad-export.tar.gz导入运行仓库顶层脚本 import-po解压归档、重命名 PO 文件、移入po目录并执行make update-po让翻译与最新源码保持同步随后随发行包一起发布。整个流程保证了源码仓库 ↔ 翻译平台 ↔ 发行包三者之间的单向数据流翻译成果以发行包的形式到达用户而不是以每次提交的形式涌入 Git 历史。三、从 Launchpad 导出 PO 文件po/README.rst 中导出的操作极其简单只有两步访问 Launchpad 上 aria2 项目的翻译页面点击页面中的download链接下载名为launchpad-export.tar.gz的归档文件。该归档在撰写本文档时包含Launchpad 上已翻译的全部语言的 PO 文件。需要说明的是这个归档的目录结构比较特殊详见下文import-po解析因此官方强烈建议不要手动解压搬运而是统一交给import-po脚本处理。四、用import-po脚本导入 launchpad-export.tar.gzimport-po是仓库根目录下的 POSIX shell 脚本import-po用法为./import-po /path/to/launchpad-export.tar.gz脚本开头对输入做了两项防御性检查未指定归档路径时打印用法并退出Usage: import-po /path/to/launchpad-export.tar.gz Specify input launchpad-export.tar.gz file指定文件不存在时同样报错退出。4.1 解压与目录整理脚本在工作目录创建临时目录launchpad-work若已存在则先删除随后将归档解压进去tar -x -C $WORK_DIR -f $INPUT_TGZ脚本注释明确提醒launchpad 导出的归档目录结构比较怪异甚至包含绝对路径。因此它不按固定层级逐个处理而是先把$WORK_DIR/aria2/顶层下的全部*.po统一挪到临时目录根下mv $WORK_DIR/aria2/*.po $WORK_DIR这一拍平操作让后续的批量重命名不再受目录层级干扰。4.2 重命名与去 CR 处理接下来对每个 PO 文件做三件事import-posed -i -e s/\\r// $file # 1) 去除消息中的 \r 回车字符 bn$(basename $file) bn${bn#aria2-} # 2) 去掉 aria2- 前缀 mv $file $PO_DIR/$bn # 3) 移入 po 目录去\rLaunchpad 导出的条目中常混有回车字符会影响编译出的消息串因此先统一清除重命名平台导出的文件名形如aria2-zh_CN.po脚本剥离aria2-前缀得到zh_CN.po这样的标准 locale 名与 gettext 的 locale 目录规范locale/LC_MESSAGES/domain.mo对齐。4.3 同步维护 LINGUAS在逐个处理 PO 文件的同时脚本会重建 po/LINGUASimport-poecho -n enquot enboldquot $PO_DIR/LINGUAS ... echo -n ${bn%.po} $PO_DIR/LINGUAS首先写入两个 gettext 特殊 localeenquot启用智能引号替换的英语与enboldquot带加粗引号标记的英语然后每导入一个 PO 文件就把去掉.po后缀的语言代码追加进去最终 LINGUAS 即成为本次发行包实际包含语言的权威清单。这解释了为什么仓库中的 po/LINGUAS 初始为空——它完全由导入脚本按发行批次动态生成。4.4 收尾与make update-po脚本最后删除临时目录并切到po目录执行cd $PO_DIR make update-pomake update-po是 GNU gettext 的标准目标其作用包括依据 po/POTFILES.in 重新扫描源码并生成最新的aria2.pot模板将刚导入的各语言 PO 与最新模板合并merge为新出现的原文条目补上空翻译、标记已过时的旧条目使 PO 文件与当前源码字符串保持一致为后续编译成.mo消息目录做准备。至此导入流程闭环归档 → 解压 → 清洗重命名 → 移入po目录 → LINGUAS 更新 → POT/PO 同步。五、po目录的构建配置POTFILES.in 与 Makevars除 README 与 LINGUAS 外po目录中另外两个文件直接决定了翻译内容的来源与生成方式理解它们有助于排查某个字符串为什么没有被翻译这类问题。5.1 POTFILES.in可翻译字符串的来源清单po/POTFILES.in 列出了所有参与 xgettext 提取的源码文件全部集中在src/下例如src/DownloadEngine.cc src/MultiUrlRequestInfo.cc src/RequestGroupMan.cc src/OptionHandler.cc src/OptionHandlerImpl.h src/usage_text.h src/version_usage.cc src/option_processing.cc src/OptionHandlerException.cc src/UnknownOptionException.cc src/BtSetup.cc src/AbstractCommand.cc src/AdaptiveURISelector.cc src/BtStopDownloadCommand.cc src/DHTConnectionImpl.cc src/HttpListenCommand.cc src/PeerListenCommand.cc src/RequestGroup.cc src/SingleFileAllocationIterator.cc src/TimedHaltCommand.cc src/message.h从清单可以看出aria2 的翻译覆盖面既包括用户可见的错误提示与日志如AbstractCommand.cc中的恢复下载失败提示、HttpListenCommand.cc中的 RPC 监听端口提示也包括参数与帮助文本OptionHandler.cc、usage_text.h、version_usage.cc。只有列入该清单的文件其可翻译字符串才会被提取进aria2.pot——新增源码文件若想支持多语言需要同步登记到此清单中。5.2 Makevars消息域、提取关键字与版权归属po/Makevars 是 gettext 在po目录生成 POT 时读取的变量文件几个关键项变量取值含义DOMAIN$(PACKAGE)消息域与包名一致即aria2对应安装目录下的aria2.mosubdir/top_builddirpo/..供构建系统定位po目录XGETTEXT_OPTIONS--keyword_ --keywordN_指定 xgettext 识别_(...)与N_(...)两种标记COPYRIGHT_HOLDERTatsuhiro Tsujikawa写入 POT 文件头部的版权持有人即项目维护者MSGID_BUGS_ADDRESS项目官网地址翻译者在源字符串有问题时的反馈地址EXTRA_LOCALE_CATEGORIES空除LC_MESSAGES外是否启用其他 locale 分类其中XGETTEXT_OPTIONS与源码的标记方式一一对应源码中一切以_(...)包裹的字符串都会被提取。例如 src/DownloadEngine.cc 中的关停提示A2_LOG_NOTICE(_(Shutdown sequence commencing...以及 src/AdaptiveURISelector.cc 中的速度限制调整日志、src/BtStopDownloadCommand.cc 中的停种提示等都是通过_()宏进入 POT 的。六、源码层面的 gettext 接入从提取标记到运行时翻译翻译工作流的最终落地取决于源码在运行时如何加载消息目录。这一点在 src/Platform.cc 的程序初始化路径中体现得最为直接#ifdef ENABLE_NLS setlocale(LC_CTYPE, ); setlocale(LC_MESSAGES, ); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif // ENABLE_NLSsetlocale(LC_CTYPE, )/setlocale(LC_MESSAGES, )根据环境变量如LANG、LC_ALL激活当前 locale 的字符集与消息分类bindtextdomain(PACKAGE, LOCALEDIR)将消息域aria2绑定到消息目录安装路径LOCALEDIR即po编译产出的.mo文件所安装到的prefix/share/locale/lang/LC_MESSAGES/aria2.motextdomain(PACKAGE)把当前进程的默认消息域设为aria2。这一切都包裹在#ifdef ENABLE_NLS中即构建时可通过configure --disable-nls关闭本地化。配套的 lib/gettext.h 是标准 GNU gettext 辅助头文件由 lib/Makefile.am 的EXTRA_DIST gettext.h随发行包分发它在 NLS 关闭时提供退化实现gettext(Msgid)直接原样返回字符串从而让源码无需#ifdef也能正常编译。其中还定义了gettext_noop(String)宏用于只标记、不在当前位置翻译的场景——它适合静态初始化数组中的字符串真正的翻译发生在字符串被使用的其他位置。综上从提取POTFILES.inXGETTEXT_OPTIONS、生成make update-po、安装LOCALEDIR下的.mo到加载bindtextdomaintextdomain构成一条完整的 gettext 链路而 Launchpad 导出 →import-po导入正是这条链路的翻译供给端。七、实战注意点与常见问题基于上述源码与脚本实现参与 aria2 翻译维护时需注意以下几点不要在仓库中直接手工编辑 PO 文件PO 文件是发行时的产物。若强行手工修改下次import-po会被平台导出的版本覆盖改动随之丢失。正确的翻译修改应回到 Launchpad 平台完成。确保归档文件名与预期一致import-po依赖 Launchpad 当前导出归档的默认命名launchpad-export.tar.gzREADME 中也注明这是撰写时的名称平台若改名需相应调整脚本入参。新语言不会自动生效语言是否进入发行包取决于import-po运行时生成的 po/LINGUASenquot、enboldquot 各语言代码。平台上有翻译、但归档中缺失的语言不会出现在清单里。新增源码文件的翻译登记在源码中新增_(...)字符串后若该文件不在 po/POTFILES.in 中则不会进入 POT 模板翻译者自然看不到这些字符串。构建前提整套 gettext 工具链由 configure.ac 的AM_GNU_GETTEXT([external])/AM_GNU_GETTEXT_VERSION([0.19])约束构建环境需提供 gettext 0.19 及以上的xgettext、msgmerge、msgfmt等工具也可通过--disable-nls完全关闭本地化编译。结语aria2 的翻译工作流是一套平台协作翻译 发行时集中导入的典型实践po目录保持精简、PO 文件不落库import-po 脚本承担了解压、清洗、重命名、LINGUAS 维护与make update-po的全部职责而 src/Platform.cc、lib/gettext.h、po/Makevars 与 po/POTFILES.in 共同保证了从源码提取到运行时加载的完整闭环。理解了这套管线你不仅掌握了 aria2 自身翻译的维护方法也能为其他采用 gettext 的 C/C 项目设计类似的、与代码仓库解耦的社区翻译协作流程。【免费下载链接】aria2aria2 is a lightweight multi-protocol multi-source, cross platform download utility operated in command-line. It supports HTTP/HTTPS, FTP, SFTP, BitTorrent and Metalink.项目地址: https://gitcode.com/gh_mirrors/ar/aria2创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考