ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Git 核心本地化(l10n)贡献指南:翻译流程、POT 生成与字符串标记全解

Git 核心本地化(l10n)贡献指南:翻译流程、POT 生成与字符串标记全解 Git 核心本地化l10n贡献指南翻译流程、POT 生成与字符串标记全解【免费下载链接】gitGit Source Code Mirror - This is a publish-only repository but pull requests can be turned into patches to the mailing list via GitGitGadget (https://gitgitgadget.github.io/). Please follow Documentation/SubmittingPatches procedure for any of your improvements.项目地址: https://gitcode.com/gh_mirrors/git15/gitGit 是一个高度国际化的开源项目其核心命令的用户界面porcelain 层文案通过 GNU gettext 体系支持数十种语言。本文以仓库内 po/README.md 为骨架结合 Makefile 中的 l10n 构建规则、gettext.h、git-sh-i18n.sh 与 perl/Git/I18N.pm 等源码实现系统讲解如何为 Git 贡献新语言翻译、维护既有翻译文件、理解 POT 模板的生成机制以及开发者在 C / Shell / Perl 源码中正确标记可翻译字符串的方法。读完本文你将掌握从po-init初始化到git-po-helper校验的完整 l10n 工作流并能在自己的 Git 相关项目中复现这套国际化基础设施。一、po/目录与语言代码约定仓库根目录下的 po/ 目录保存 Git 核心Core Git的翻译文件。当前仓库中实际包含 19 个语言的翻译文件例如de.po德语、is.po冰岛语、pt_PT.po葡萄牙-葡萄牙、zh_CN.po简体中文、zh_TW.po繁体中文等以及两个关键文件po/README.md本文所依据的 l10n 贡献指南po/TEAMS各语言团队的负责人Leader、成员及其对应的专用翻译仓库地址清单按语言字段字母序排列。Git 官方文档使用XX作为语言代码的占位符如po/XX.po。语言代码有两种合法形式ll或ll_CC其中ll是 ISO 639 定义的双字母语言代码CC是 ISO 3166 定义的国家/地区双字母代码例如de—— 德语Germanzh_CN—— 简体中文Simplified Chinesept_BR—— 巴西葡萄牙语与pt_PT区分地区变体。这意味着“XX”并不一定只有两位字母只要文件名符合po/ll.po或po/ll_CC.po的模式即可。二、整体翻译流程l10n 窗口与协作数据流2.1 参与角色l10n 协调员l10n coordinatorJiang Xinworldhello.netgmail.com负责在协调员仓库中统筹各语言的本地化工作语言团队Language Team XX每种语言有独立团队多贡献者语言需要推举一名团队负责人team leader使协调员只需与每种语言的一名代表交互核心开发者core developers负责在源码中标记可翻译字符串。2.2 数据流po/README.md 给出了如下数据流示意沿用原文档中的 ASCII 图------------------- ------------------ | Git source code | ----(2)--- | L10n coordinator | | repository | ---(5)---- | repository | ------------------- ------------------ | | ^ (1) (3) (4) V v | ---------------------------------- | Language Team XX | ----------------------------------各步骤的时序如下可翻译字符串在源码中被标记由核心开发者完成见后文“标记字符串”一节翻译迭代iteration可随时开始即使 l10n 窗口尚未开启从源码仓库的master分支拉取最新代码步骤 1运行make po-update PO_FILEpo/XX.po更新消息文件翻译po/XX.po文件l10n 协调员从源码仓库拉取并宣布 l10n 窗口开启步骤 2语言团队从协调员仓库拉取针对协调员维护的树开始新一轮翻译迭代步骤 3git pull --rebase拉取协调员仓库make po-update PO_FILEpo/XX.po更新消息文件翻译po/XX.po使用git rebase -i将琐碎的 l10n 提交压缩squash合并语言团队向协调员发送 pull request步骤 4协调员检查并合并协调员请求将成果合入上游源码仓库步骤 5。2.3 已有翻译的维护路径如果你要参与某种已有语言的翻译先查看 po/TEAMS 中该语言是否存在专门的翻译仓库若存在fork 该专用仓库并在其中开展工作注意某些发行版如 Ubuntu 等有自己独立的 l10n 工作流其 Git 翻译与 Git 官方对应版本可能存在差异。此类发行版中的错误翻译应通过发行版自己的流程报告与修复而不是直接提交到 Git 官方。三、动态生成的 POT 模板git.pot 与 git-core.pot3.1 为什么 POT 不在仓库中POTPortable Object Template文件是翻译者创建或更新翻译文件的模板。历史上仓库曾保存过由 l10n 协调员生成的po/git.pot但该文件已从源码树中移除。现在两个 POT 文件po/git.pot与po/git-core.pot都可以在需要时动态生成。从 Makefile 的实现可以看到生成机制## We generate intermediate .build/pot/po/%.po files containing an ## extract of the translations we find in each file in the source ## tree. We will assemble them using msgcat to create the final ## po/git.pot file. LOCALIZED_ALL_GEN_PO LOCALIZED_C_GEN_PO $(LOCALIZED_C:%.build/pot/po/%.po) LOCALIZED_ALL_GEN_PO $(LOCALIZED_C_GEN_PO) LOCALIZED_SH_GEN_PO $(LOCALIZED_SH:%.build/pot/po/%.po) LOCALIZED_ALL_GEN_PO $(LOCALIZED_SH_GEN_PO) LOCALIZED_PERL_GEN_PO $(LOCALIZED_PERL:%.build/pot/po/%.po) LOCALIZED_ALL_GEN_PO $(LOCALIZED_PERL_GEN_PO)即先用 xgettext 对每个被本地化的源文件C/H、Shell 脚本、Perl 脚本分别抽取生成中间.po文件再通过msgcat汇总为最终的po/git.pot。其中被抽取的源文件集合在 Makefile 中定义为LOCALIZED_C $(sort $(FOUND_C_SOURCES) $(FOUND_H_SOURCES) $(GENERATED_H)) LOCALIZED_SH $(sort $(SCRIPT_SH) git-sh-setup.sh) LOCALIZED_PERL $(sort $(SCRIPT_PERL))对应三组 xgettext 抽取参数MakefileXGETTEXT_FLAGS_C $(XGETTEXT_FLAGS) --languageC \ --keyword_ --keywordN_ --keywordQ_:1,2 XGETTEXT_FLAGS_SH $(XGETTEXT_FLAGS) --languageShell \ --keywordgettextln --keywordeval_gettextln XGETTEXT_FLAGS_PERL $(XGETTEXT_FLAGS) --languagePerl \ --keyword__ --keywordN__ --keyword__n:1,2注意 C 语言抽取对Q_使用了:1,2位置参数语法表示第一个和第二个参数都是可翻译字符串Shell 只抽取gettextln/eval_gettextlnPerl 则抽取__/N__/__n。此外 Makefile 中设置了公共抽取标志其中--add-commentsTRANSLATORS:会把源码中以TRANSLATORS:开头的注释一并提取到 PO/POT 文件中供译者参考--msgid-bugs-address指定了 msgid 问题反馈地址。3.2 生成完整模板make po/git.potpo/git.pot是语言团队准备翻译所用的完整模板翻译者不应修改该文件。手动生成命令make po/git.pot等价地也可用make pot见 Makefile。生成目标依赖所有.build/pot/po/%.po中间文件与自动生成的头部最终用msgcat汇总Makefile。3.3 生成核心模板make po/git-core.pot完整模板po/git.pot包含5000 多条消息对新手语言贡献者而言工作量巨大。因此 Git 定义了“核心翻译core translation”——完成一种新语言翻译所需的最小工作集其模板为po/git-core.potmake po/git-core.pot核心模板的抽取范围来自 Makefile 中显式列出的 7 个“高频使用”文件LOCALIZED_C_CORE LOCALIZED_C_CORE builtin/checkout.c LOCALIZED_C_CORE builtin/clone.c LOCALIZED_C_CORE builtin/index-pack.c LOCALIZED_C_CORE builtin/push.c LOCALIZED_C_CORE builtin/reset.c LOCALIZED_C_CORE remote.c LOCALIZED_C_CORE wt-status.c这些文件覆盖了git checkout、git clone、git push、git reset等日常命令的用户可见输出构成了新语言最实用的最小翻译集。不过 Makefile 中也有 TODO 注释指出以“整个文件”为单位挑选核心文件是一种较粗糙的启发式策略会把一些很少见到的error()消息一并纳入未来可能改用 spatch 等工具先剔除error/die/warning类消息来优化核心集。四、初始化新语言make po-init本步骤由语言团队执行。如果语言XX还没有翻译文件po/XX.po第一次添加翻译时运行make po-init PO_FILEpo/XX.po其中XX是语言代码例如de、is、pt_BR、zh_CN等。从 Makefile 的实现看po-init的逻辑是目标依赖po/git-core.pot即新翻译基于核心模板只包含最小消息集适合新语言起步若po/XX.po已存在则报错退出防止覆盖已有翻译否则调用msginit --inputpo/git-core.pot --outputpo/XX.po --no-translator --localeXX生成初始文件。完成翻译测试见下文“测试你的改动”后提交结果并请求 l10n 协调员拉取。五、更新已有翻译make po-update本步骤由语言团队执行。更新既有翻译文件有两种场景只是改进措辞直接编辑po/XX.po中的翻译字符串需要同步上游源码中新增的可翻译字符串运行make po-update PO_FILEpo/XX.po从 Makefile 可以看到po-update的执行细节依赖目标po/git.pot即先动态生成完整模板校验PO_FILE环境变量必须匹配po/%.po模式若po/XX.po不存在则给出提示指引先使用make po-init PO_FILEpo/XX.po调用msgmerge --add-location --backupoff --update po/XX.po po/git.pot对应 Makefile 中的MSGMERGE_FLAGS --add-location --backupoff --update。--add-location会为每条消息添加源码位置行location lines方便翻译工具定位翻译上下文。但提交到仓库时建议提交不带位置信息的po/XX.po以节省仓库空间并让补丁更容易审阅。5.1 通过 clean filter 自动去除位置信息要让仓库中自动保存无位置的po/XX.po可配置 Git 属性与 clean filter在.git/info/attributes中为po/XX.po定义新属性/po/XX.po filtergettext-no-location配置gettext-no-locationclean filter 的驱动去掉文件名和位置git config --global filter.gettext-no-location.clean \ msgcat --no-location -对于 gettext 0.20 及以上版本还可以只保留文件名、去掉位置行git config --global filter.gettext-no-location.clean \ msgcat --add-locationfile -配置完成后即可向 l10n 协调员请求拉取。六、理解 fuzzy 翻译Fuzzy 翻译模糊翻译是指被fuzzy注释标记的翻译条目它表示因为对应的msgid已经改变这条翻译已过时。其行为要点编译时msgfmt会忽略fuzzy 条目fuzzy 标记可以手工添加但大多数情况下是运行msgmerge更新XX.po时自动标记的修复相应翻译后必须删除注释中的fuzzy标记该条目才会重新生效。七、测试你的改动本步骤由语言团队在创建或更新po/XX.po之后执行。提交前回到仓库顶层目录运行make在带有 GNU gettext 的系统上即非 Solaris这会用msgfmt --check编译修改过的 PO 文件。--check会标记大量常见错误例如缺少 printf 格式字符串译文与原文在是否以换行符开头/结尾上不一致。l10n 协调员还会使用辅助程序见下文“PO helper”一节检查贡献git-po-helper check-po po/XX.po git-po-helper check-commits rev-list-opts此外Git 的测试套件本身在LANGC LC_ALLC环境下运行见 Makefile 中XGETTEXT_INCLUDE_TESTS相关的t/t0200/test.c、t/t0200/test.sh、t/t0200/test.perl因此新增翻译时无需修改测试——测试始终以英文基线运行翻译不会影响测试结果。八、在源码中标记字符串C / Shell / Perl 三套接口本步骤由核心开发者执行。字符串被翻译前必须先标记。Git 使用包装了系统 gettext 库的国际化接口因此 GNU gettext 文档在 GNU 系统终端输入info gettext中的大部分建议都适用。8.1 标记原则只标记人读的字符串porcelain 接口不要把所有内容都标记Git 的 plumbing 工具输出主要被程序读取若在非 C 语言环境下被翻译会破坏依赖其输出的脚本plumbing 字符串是 Git API 的一部分不应翻译调整字符串使其易于翻译参考info (gettext)Preparing Strings涉及数量词单复数的字符串可能需要拆分使用Q_()包装器见下内容不清或有歧义时使用TRANSLATORS:注释告知译者这些注释会被 xgettext 提取到po/*.po文件中。真实示例见 builtin/am.c/* * TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a] * in your translation. The program will only accept English * input at this point. */ printf(_(Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: ));另一个来自 sequencer.c 的示例/* TRANSLATORS: %s will be revert or cherry-pick */ return error(_(%s: Unable to write new index file), action_name(opts));8.2 C 语言接口在 C 文件顶部包含builtin.h它会连带引入gettext.h定义 gettext 接口。当前导出的函数见 gettext.h_()—— 标记并翻译字符串printf(_(HEAD is now at %s), hex);Q_()—— 标记并翻译复数形式字符串ngettext()的包装printf(Q_(%d commit, %d commits, number_of_commits));N_()—— 静态初始化内的“只标记不翻译”透传宏static const char *reset_type_names[] { N_(mixed), N_(soft), N_(hard), N_(merge), N_(keep), NULL };之后在运行时再通过_()查表翻译die(_(%s reset is not allowed in a bare repository), _(reset_type_names[reset_type]));这里_()无法静态确定翻译字符串是什么但因为它已用N_()标记过运行时的消息目录查询仍能成功。从实现角度看gettext.h_()在git_gettext_enabled为假或 msgid 为空时直接返回原文/空串否则调用gettext(msgid)Q_()在未启用翻译时按n 1返回单数/复数形式启用时调用ngettext(msgid, plu, n)N_()就是恒等宏#define N_(msgid) msgid在NO_GETTEXT编译配置下gettext(s)与ngettext(s,p,n)会被替换为直通实现。8.3 Shell 接口Git 的 Shell gettext 接口是gettext.sh的包装。在git-sh-setup之后立即导入. git-sh-setup . git-sh-i18n然后使用gettext或eval_gettext# 常量消息 gettext A message for the user; echo # 插值变量 detailsoh noes eval_gettext An error occurred: \$details; echo此外还有自动追加换行的包装gettextln/eval_gettextln定义于 git-sh-i18n.shgettextln A message for the user detailsoh noes eval_gettextln An error occurred: \$detailsgit-sh-i18n.sh 还展示了运行时策略脚本会探测gettext.sh是否存在自动选择gnuGNU libintl 的 gettext.sh、gettext_without_eval_gettextSolaris 等只有 gettext(1) 而无 eval_gettext 的环境用git sh-i18n--envsubst实现变量替换或fallthrough完全无 gettext 时直通输出英文三种方案并通过GIT_INTERNAL_GETTEXT_SH_SCHEME导出决策。更多接口说明见 GNU info 手册info (gettext)sh。第一个被翻译的 Shell 命令是git-am可参考其历史git log --reverse -p --grepi18n git-am.sh8.4 Perl 接口Git::I18N模块提供Locale::Messages功能的受限子集perl/Git/I18N.pmuse Git::I18N; print __(Welcome to Git!\n); printf __(The following error occurred: %s\n), $error;模块导出__、__n、N__三个函数__对应 gettext__n对应 ngettextN__是只标记不翻译的透传。若Locale::Messages无法加载它不是 Perl 核心模块模块会回退到直通桩函数保证脚本在无 gettext 环境下也能运行。运行perldoc perl/Git/I18N.pm可查看完整说明。九、PO helper 与 l10n 提交规范9.1 git-po-helper为了让XX.po的维护更简单l10n 协调员和语言团队负责人可使用专门为 Git l10n 工作流编写的辅助程序git-po-helper它是 gettext 工具套件的一个包装器。从源码构建和安装方法见git-po-helper/README位于独立的 git-po-helper 项目仓库。常用命令git-po-helper check-po XX.po # 检查语法 git-po-helper check-commits rev-list-opts # 检查提交 git-po-helper team --check # 检查 po/TEAMS 文件语法9.2 l10n 贡献者必须遵守的约定每个 l10n 提交的主题subject应以l10n:为前缀提交主题中不得使用非 ASCII 字符提交主题第一行不超过50个字符日志其余行不超过72个字符提交日志需添加Signed-off-by尾注与其他 Git 提交一致可用git commit -s自动添加创建提交前用msgfmt或git-po-helper check-po XX.po检查语法压缩琐碎提交保持历史清晰不要编辑po/目录以外的文件其他子系统git-gui、gitk以及 Git 自身各有其工作流补丁贡献方法参见 Documentation/SubmittingPatches。9.3 新语言贡献者的附加约定按 iso-639 和 iso-3166 规范初始化XX.po的恰当文件名必须基于“核心翻译Core translation”完成一个最小翻译集在 po/TEAMS 中按正确格式添加新条目并运行git-po-helper team --check校验po/TEAMS的语法。十、小结Git 的本地化体系由三条流水线构成核心开发者在 C/Shell/Perl 源码中标记字符串_()、Q_()、N_()、gettext/eval_gettext、__/__n构建系统动态生成 POT 模板po/git.pot完整模板与基于 7 个高频命令文件的po/git-core.pot核心模板语言团队按 l10n 窗口迭代维护翻译po-init起步、po-update同步、msgmerge标记 fuzzy、git-po-helper校验、clean filter 剥离位置行。理解这套流程无论是为 Git 贡献一门新语言、维护既有翻译还是在自己项目中搭建类似的多语言基础设施都能直接复用其方法论与工具链。【免费下载链接】gitGit Source Code Mirror - This is a publish-only repository but pull requests can be turned into patches to the mailing list via GitGitGadget (https://gitgitgadget.github.io/). Please follow Documentation/SubmittingPatches procedure for any of your improvements.项目地址: https://gitcode.com/gh_mirrors/git15/git创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表