帮助:翻译:错误
处理翻译错误
当识别出翻译问题时,需要确定问题的来源。这可能是翻译问题、打包问题或源代码问题。在修复或报告错误之前,需要确定问题的来源:确定字符串所属的包,确定 po 文件中字符串的确切位置,并找到正确的修复方法。
将应用程序中的字符串映射到可见字符串并不简单:您看到的字符串可能由 po 文件中的多个特定字符串甚至来自多个包组成。找到问题的根源需要一些工作。此外,SUSE 提供了一些特殊功能,允许从上游导入修复,因此无需手动修复上游中已修复的内容。
报告和修复翻译问题的步骤
- 识别问题类型(翻译、代码、打包)
- 识别翻译域和字符串
- 将域分配给包
- 选择正确的报告方式(下游、上游、请求翻译人员工作)
- 使用正确的错误跟踪器
下面将详细介绍所有这些步骤。
不同翻译名称之间的关系
翻译域
翻译域标识翻译项目。它等于已安装 .mo 文件的基本名称。
语言包名称
语言包名称通常从源包名称派生。它可能与翻译域不同,但在大多数情况下名称相似,只是版本号或大小写有所不同。
包名称
包名称也可以从源包名称派生,但对于库,名称不同。
源包名称
它是源项目的名称。多个包(包括语言包)可以具有相同的源包。
识别问题类型
每个翻译问题可能有多种来源。每种来源都需要不同的处理方式
- 翻译:缺失、不正确或不完整的翻译。需要向翻译维护者或协调员(上游或 SUSE)报告错误。可能需要额外的步骤才能将字符串返回到系统中的包中。
- 代码:代码缺少翻译支持,翻译支持无法工作或不完整。此外,应用程序使用糟糕的屈折变化将单词从句子中连接起来的情况,同一英文字符串在不同上下文中需要不同的翻译(并且 po 文件不允许这样做)的情况,正确的翻译被应用程序破坏的情况都是代码问题。此外,英文文本有错误也是代码问题。
- 打包:翻译存在,代码也正确,但包含翻译文件的包未传递到您的系统,或者未自动安装应安装的包。
有时很难确定问题的正确来源,您需要应用一些启发式方法。在某些情况下,简单的检查无法确定,您需要请求包维护者查看问题。
简单猜测
- 字符串翻译不正确(拼写错误等)=> 翻译(几乎可以肯定)
- 字符串以机械方式被破坏(例如,重音字符丢失或被破坏)=> 代码(几乎可以肯定)
- 相同的字符串在其他语言中是正确的(并且不等于英文字符串)。=> 缺失或不完整的翻译(确定)
最常见问题来源的快速检查
所有语言中的所有字符串都是英文:
- 检查与未翻译包相关的 -lang 包是否已安装。
如果未安装 => 包收集问题(包在介质或安装镜像中丢失),打包问题(缺少语言补丁)
- 检查 LANG 变量是否设置正确,以及 LC_MESSAGES 和 LC_ALL 是否未被不正确地设置。
如果是 => 您的系统配置错误,或者系统中发生了非常糟糕的事情。
通用文本(确定、取消)是英文,但应用程序本身已翻译
- 检查与应用程序 GUI 工具包相关的 -lang 包是否已安装(例如 gtk3-lang)。
如果未安装 => 包收集问题(包在介质或安装镜像中丢失),打包问题(缺少语言补丁)
其他语言正常,但在我的语言中应用程序只有英文
如果是 => 缺少翻译问题
应用程序可能缺少您语言的翻译,或者翻译不完整。
您需要找到 po/pot 文件中的字符串,然后请求翻译。
所有语言中都一致缺少一个字符串
如果是 => 这里有两种可能的来源
- 上游在发布之前才添加此字符串,翻译人员没有足够的时间进行翻译。=> 上游翻译问题。
- 存在一个编程问题,影响字符串的可翻译性。
- 存在一个 SUSE 特定的补丁添加了此字符串,但缺少其翻译机制。=> SUSE 打包问题。
请参阅下方如何区分这两种情况。
我使用 msgunfmt 在 mo 文件中看到字符串,但在应用程序中没有。
请在进行更深入的研究之前,也检查 /usr/share/locale-bundle 和 /usr/share/locale-langpack。那里的字符串优先。
识别翻译域和字符串
如果您怀疑问题来源存在于翻译文件中,您需要将应用程序中的字符串分配给翻译文件中的确切消息。或者文件,因为在应用程序中可见的一个字符串可能由多个部分组成,这些部分甚至可能来自多个不同的翻译域。
一旦将字符串分配给包,您就可以将报告或修复定向到正确的目标。
完成这项工作没有简单直接的方法。您可以从简单快速的启发式方法开始,如果它们失败,请尝试更复杂更精确的方法。
字符串分解启发式方法
翻译消息中的字符串可能与您看到的字符串不同。没有简单的方法可以将字符串分解为消息。但在某些情况下,您可以使用简单的启发式方法进行猜测。
您可以在进行字符串查找之前或在第一次查找失败时应用这些启发式方法。
将数字替换为 %d
如果您在消息中看到一个数字,它可能表示为 %d。
示例:“有 2 个打开的文件。” => “有 %d 个打开的文件。”
将“-ing”替换为 %s
有时句子有一个“可变”单词,通常表示为动名词。
示例:“读取时出错。” => “读取时 %s。”+“读取”
以“:”分隔
冒号通常表示应用程序字符串和库字符串(通常是错误)之间的分隔符。
示例:“读取错误:找不到该文件或目录” => “读取错误:%s”+“找不到该文件或目录”
快速启发式方法
字符串属于与应用程序本身相同的包和域
这是最简单的启发式方法,适用于很大比例的字符串。只需查看相关包的 pot/po 文件。如果您很幸运,字符串将以您需要的完全相同的上下文存在于其中。
示例:gnome-control-center 中的所有字符串检查应首先检查 gnome-control-center pot/po 文件。
字符串属于工具包
如果问题中的字符串是通用字符串(例如“确定”、“取消”、“文件”),并且您无法在应用程序的 pot/po 文件中找到该字符串,您可以查看 GUI 工具包的 pot/po 文件(例如 gtk3、glib2 等)
示例:gnome-control-center 中的“确定”和“取消”字符串属于 gtk3 pot/po 文件。
字符串属于插件
某些应用程序可以通过插件扩展。插件可以具有完全集成到应用程序中的 GUI,但插件实现中的字符串属于不同的域。
示例:eiciel 在 nautilus 中实现 ACL 和扩展属性。但是,即使这些功能完全集成到 nautilus 中,您也应检查与 ACL 相关的所有字符串在 eiciel pot/po 文件中。
字符串属于使用的库
库通常包含特定于特定函数的字符串,尤其是错误消息。如果您正在搜索特定函数实现中的字符串,您应该查看提供的库。
示例:用于 CIFS/SMB 的工具可以显示来自 samba 库的字符串。您应该特别查看 samba pot/po 文件中的错误消息。
搜索
搜索已安装的语言文件中的字符串
这种简单快速的方法可以提供快速猜测,但如果任何语言中都没有翻译该字符串,则很容易失败。它也可能为短通用字符串提供许多错误的匹配项。
grep -l -r "{string in question}" /usr/share/locale*
替代版本(干净的输出,需要更长的时间才能获得第一个输出)
grep -l -r "{string in question}" /usr/share/locale* | sed 's:.*/::;s/\.mo$//' | uniq -d
文件名部分(不包括尾随 mo)是您的翻译域。如果您只看到一个域匹配项,就完成了。您很可能找到了您的字符串。
优点:非常快
缺点:经常出现假阴性和假阳性
在实时系统中搜索字符串
这种方法需要大量的机器时间,并且经常提供许多错误的匹配项。但如果其他方法都失败,它可以找到该字符串。
grep -l -r "{string in question}" /*bin /etc /usr /opt
如果找到合适的候选者,则将其分配给软件包
rpm -qf {file}
优点:可以找到未标记用于翻译的字符串。
缺点:非常慢。经常出现假阳性。
分析方法
如果快速方法失败,分析方法总是可以找到你的字符串。
strace
Strace 是一个常用的跟踪工具。你可以使用它来获取所有尝试访问的翻译域的列表。它在主仓库中可用。
扫描所有尝试打开的与语言环境相关的文件(以及结果)
strace -f -o strace.log {command you want to analyze}
grep 'open.*locale' strace.log
你可以在这里看到所有不成功的尝试。只要失败序列以成功结束,这些尝试都是无害的。
扫描所有尝试打开的域名
strace -f -o strace.log {command you want to analyze}
sed -n 's:^.*open.*/locale.*/\([^/]*\)\.mo.*$:\1:p' strace.log | sort -u
注意:在用 strace 跟踪时,应用程序可能会运行得稍微慢一些。
示例
test@test:~> strace -f -o strace.log gnome-clocks
test@test:~> grep 'open.*locale' strace.log
4336 open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
4336 open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
4336 open("/usr/lib/locale/cs_CZ.utf8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = 3
4336 open("/usr/lib/locale/cs_CZ.utf8/LC_MEASUREMENT", O_RDONLY|O_CLOEXEC) = 3
...
4336 open("/usr/share/locale-bundle/cs.utf8/LC_MESSAGES/libgweather-locations.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
4336 open("/usr/share/locale-langpack/cs/LC_MESSAGES/libgweather-locations.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
4336 open("/usr/share/locale/cs/LC_MESSAGES/libgweather-locations.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
4336 open("/usr/share/locale-bundle/cs/LC_MESSAGES/libgweather-locations.mo", O_RDONLY) = 25
test@test:~> sed -n 's:^.*open.*/locale.*/\([^/]*\)\.mo.*$:\1:p' strace.log | sort -u
atk10
desktop_translations
gdk-pixbuf
glib20
gnome-clocks
gnome-desktop-3.0
gtk30
gtk30-properties
json-glib-1.0
libc
libgweather-locations
pulseaudio
wrap-gettext
wrap-gettext 在更高的层次上工作,它会向你报告所有使用的 gettext。它是 trace-wrappers 包的一部分,目前仅存在于 OBS home:sbrabec 仓库 中。你可以使用 13.1 二进制包用于 SLE12。
使用此工具,你可以深入了解应用程序内部的字符串组成。与 strace 不同,你可以在这里看到每个字符串查找。但你无法像使用 strace 那样看到文件查找。
扫描并在控制台显示
wrap-gettext {command you want to analyze}
当你想在组成时查看特定对话框时,这种形式很有用。提示:输入几个回车键作为分隔符,然后将控制台滚回。
在所有其他情况下,你更喜欢将日志记录到文件。
wrap-gettext {command you want to analyze} 2>wrap-gettext.log
注意:你可能会看到一个奇怪的 0004 或 ^D 字符。它就像上下文和字符串内容之间的内部分隔符,并且在带有 msgctxt 标签的字符串中使用(代替 |)。
示例
test@test:~> wrap-gettext gnome-clocks 2>wrap-gettext.log
test@test:~> less wrap-gettext.log
WRAP: bindtextdomain("gnome-clocks", "/usr/share/locale") = "/usr/share/locale"
WRAP: bind_textdomain_codeset("gnome-clocks", "UTF-8") = "UTF-8"
WRAP: textdomain("gnome-clocks") = "gnome-clocks"
WRAP: bindtextdomain("glib20", "/usr/share/locale") = "/usr/share/locale"
WRAP: bind_textdomain_codeset("glib20", "UTF-8") = "UTF-8"
WRAP: textdomain("(null)") = "gnome-clocks"
WRAP: dcgettext("(null)", "", LC_MESSAGES) = ""
WRAP: dcgettext("glib20", "The unique identifier for the application", LC_MESSAGES) = "The unique identifier for the application"
...
WRAP: dcgettext("gtk30", "keyboard label|F1", LC_MESSAGES) = "keyboard label|F1"
WRAP: dcgettext("gtk30-properties", "Standard cursor type", LC_MESSAGES) = "Standardní typ kurzoru"
WRAP: dcgettext("gtk30-properties", "Cursor type", LC_MESSAGES) = "Typ kurzoru"
WRAP: dcgettext("gtk30-properties", "Display of this cursor", LC_MESSAGES) = "Zobrazení tohoto kurzoru"
WRAP: dcgettext("gtk30-properties", "Display", LC_MESSAGES) = "Zobrazení"
WRAP: bindtextdomain("pulseaudio", "/usr/share/locale") = "/usr/share/locale"
WRAP: bind_textdomain_codeset("pulseaudio", "UTF-8") = "UTF-8"
WRAP: dcgettext("pulseaudio", "%0.1f MiB", LC_MESSAGES) = "%0.1f MiB"
WRAP: dcgettext("pulseaudio", "%0.1f KiB", LC_MESSAGES) = "%0.1f KiB"
重要:如果该字符串未出现在 wrap-gettext 日志中,这意味着它未正确标记为可翻译。
watch-gettext
Watch-gettext 的工作方式与 wrap-gettext 非常相似。它包装所有 gettext 调用并显示帮助程序以可视化字符串的来源。它目前位于 M17N OBS 仓库 中。
该工具在每个可翻译字符串前加上一个数字。它还会写入一个日志(伪 .po 文件)以及这些数字。如果你想识别任何字符串,只需在 watch-gettext 包装器内运行应用程序,检查加上前缀的数字,然后查看日志。你将看到字符串的来源。
使用此工具,你可以快速了解应用程序内部的字符串组成。你可以直接看到每个字符串的组成。
扫描并在控制台显示
watch-gettext {command you want to analyze}
它会写入一个伪 .po 文件,其中包含所有访问的日志以及你在应用程序中看到的参考编号。
字符串验证
有时你的字符串过于通用,你有很多匹配项,并且不确定哪个匹配项是正确的。这里有一个简单的验证方法
msgunfmt /usr/share/{locale_dir}/{language}/LC_MESSAGES/{domain}.mo -o test.po
现在编辑 test.po 并向你的字符串添加一些无意义的字符。
然后以 root 身份执行
# Save original translations.
sudo mv /usr/share/{locale_dir}/{language}/LC_MESSAGES/{domain}.mo /usr/share/{locale_dir}/{language}/LC_MESSAGES/{domain}.mo.save
# And install our one.
sudo msgfmt test.po -o /usr/share/{locale_dir}/{language}/LC_MESSAGES/{domain}.mo
locale_dir 可以是“locale”、“locale-bundle”或“locale-langpack” domain 是软件包的翻译域。在大多数情况下,它等于带有不同版本说明的 lang 包名称。
然后重新启动你的应用程序。你应该在你的字符串中看到无意义的字符。
你确认找到了正确的字符串!
现在恢复原始翻译。
# Save original translations.
sudo mv /usr/share/{locale_dir}/{language}/LC_MESSAGES/{domain}.mo.save /usr/share/{locale_dir}/{language}/LC_MESSAGES/{domain}.mo
示例
test@test:~> msgunfmt /usr/share/locale-langpack/cs/LC_MESSAGES/gnome-clocks.mo -o gnome-clocks.po # Mangle msgstr "Start" to msgstr "Staqqqrt" test@test:~> gedit gnome-clocks.po test@test:~> sudo mv /usr/share/locale-langpack/cs/LC_MESSAGES/gnome-clocks.mo /usr/share/locale-langpack/cs/LC_MESSAGES/gnome-clocks.mo.save root's password: test@test:~> sudo msgfmt gnome-clocks.po -o /usr/share/locale-langpack/cs/LC_MESSAGES/gnome-clocks.mo # And now you should see "Staqqqrt" instead of "Start" test@test:~> gnome-clocks test@test:~> sudo mv /usr/share/locale-langpack/cs/LC_MESSAGES/gnome-clocks.mo.save /usr/share/locale-langpack/cs/LC_MESSAGES/gnome-clocks.mo
将域分配给软件包
将翻译域分配给软件包是你的工作的最后一步。
如果你知道 -lang 包名称或库包名称,并且需要源包名称(例如,用于报告目的)
- -lang 包的名称可能与存在问题的包的名称不同。最可能的名称可以通过以下方式构造:
rpm -qi {package}
然后搜索“Source RPM”。获取名称的基础,添加“-lang”,你就得到了最可能的 lang 包名称。
示例
libgtk-3-0 的翻译缺失。
rpm -qi libgtk-3-0
你会在输出中看到
Source RPM : gtk3-3.10.4-12.1.src.rpm
=> 相应的源包是 (肯定) gtk3,lang 包名称将是 (可能) gtk3-lang。
lang 包名称的此规则并非 100% 有效。如果你需要 lang 包名称,并且无法找到它,你需要查看源 rpm 规范文件。
桌面、xml 和类似文件中的翻译
桌面文件
在 SUSE 中,.desktop 文件中的翻译以特殊方式处理。有两种完全分离的方法可以将字符串放入包中
- 在规范文件中使用宏 %suse_update_desktop_file 将所有翻译收集到 desktop-translations 包中,以及 LCN 中的 desktop-translations.pot 和使用 desktop-translations 的 SUSE 特定补丁的桌面环境。这些包可以从 LCN 的 desktop-translation 项目获得字符串修复。
- 标准的上游感知方法,它直接从桌面文件获取翻译。这些包只能在构建时使用例如 translation-update-upstream 更新翻译(但不能使用 translation-update)。
XML 和其他类似文件
在某些项目中,XML 和其他类似文件中的翻译可能硬编码到文件中。此类文件包含所有语言的翻译在一个文件中。如果你需要修复此类文件,只能在构建时使用例如 translation-update-upstream 更新翻译(但不能使用 translation-update)。
幸运的是,现在大多数 XML 文件都以更好的方式翻译:应翻译的标签以前缀“_”字符,并且 XML 文件在运行时由代码预处理。此类 XML 文件的翻译来自标准的 gettext 文件,并且可以通过所有标准方式进行更新。
报告错误
软件包收集问题
此问题是由安装仓库或你正在使用的镜像中缺少 -lang 包引起的。
报告
向维护软件包集合或二进制仓库的人员报告。
只报告一次,并列出受影响的软件包。
修复
通过添加所有缺失的软件包来修复。
重要提示
最好只对一种覆盖良好的语言和每个软件包的单个字符串继续测试。在解决此问题之前,停止进一步测试你的产品!这浪费了你的工作。此错误几乎总是影响所有语言。
打包问题
如果相应的 -lang(或 bundle-lang)包可用但未安装
检查
- 检查你是否在 YaST 中选择了你的语言支持。
- 检查 YaST 是否可以看到所需的 lang 包。
报告
- 向 SUSE 软件包维护者报告。每个软件包只报告一次。
- 如果这是一个安装镜像的问题(例如,live CD/DVD),请向镜像创建者报告。这可能是一个软件包收集问题。
修复
该软件包可能没有正确使用 %lang_package、%find_lang 和 %files -f %{name}.lang 宏。
说明
- 一些 SUSE 产品使用每种语言的翻译捆绑包(bundle-lang-{package_set}-{language})。它们提供与特定 lang 包相同的文件。
重要提示
最好只对一种覆盖良好的语言继续测试。在解决此问题之前,停止进一步测试你的产品!这浪费了你的工作。此错误几乎总是影响所有语言。
代码问题
代码问题包括源代码本身中的所有类型的问题
- 所讨论的字符串未正确标记为可翻译,例如 _("{string}")、N_("{string}") 或 ...gettext("{string}")。可以定义更多的宏,使用一个大写字母和下划线会更方便。
- 该字符串已标记为可翻译,但使用了错误的 gettext 调用类型。
- 该字符串已标记为可翻译,但代码使用了无效的上下文(错误的域、在 gettext 初始化之前调用等)
- 该字符串已正确标记为可翻译,但该文件未包含在 POTFILES 中。
- 代码的技术部分是正确的,但该字符串不符合可翻译规则,因此无法翻译成某些语言,例如由于屈折变化。
- 英文字符串是同音词,需要添加上下文才能正确翻译成其他语言。
- SUSE 软件包添加了一个带有新字符串的补丁,但该软件包没有添加对其翻译的支持(用于补丁翻译的项目称为 gnome-patch-translation)。
代码问题报告给上游(作为代码问题),或报告给 SUSE 软件包维护者。SUSE 补丁中的问题始终报告给软件包维护者。
翻译问题
最终分配字符串
在报告翻译问题之前,你需要最终确定字符串的位置。解压源包并查看它。如果该字符串位于上游 tarball 中,则是一个上游问题。如果该字符串位于 SUSE 补丁之一中,则是一个 SUSE 问题。
通用规则
将翻译错误报告给软件包维护者是没有意义的。软件包维护者无法修复它(没有母语人士的帮助)。
翻译不正确
这是一个简单的案例。你需要找到字符串的翻译维护者并向他们报告问题。
翻译缺失或不完整
报告这些问题是没有意义的。翻译团队只是没有足够的精力进行翻译,并且反复声明它不会改善情况。
如果你真的需要修复此问题,唯一的解决方法是找到翻译人员,加入翻译项目并使其完整。
字符串是 SUSE 特定补丁
如果该字符串位于 SUSE 补丁中,软件包需要特别注意。软件包维护者应使用 gnome-patch-translation 添加翻译新字符串的可能性。(与它的名称相反,该工具可以支持不仅仅是 GNOME。)Packager 维护者应遵循其 README。
翻译来源
SUSE 使用多个翻译来源
- SUSE LCN 项目处理主要针对 SUSE 特定的软件包的翻译。它还包含几个不再在上游维护的软件包。
- 上游软件包是最常见的字符串来源。它使用来自上游的字符串。
- 更新工具提供了一种向用户传递翻译更新的替代方法,但它们使用与上述相同的翻译来源(以及最新的上游快照)。
根据翻译来源,你必须选择正确的报告错误的方式。
LCN 项目错误
如果你将 LCN 识别为主要的翻译来源,请向
- openSUSE:提及为“最后翻译者”的人员。
- SLE:向 Novell Bugzilla 报告你的产品,组件 Translations。
上游错误
如果软件包具有活动的上游,则翻译错误报告给上游
较大的项目(GNOME、KDE)拥有自己的翻译项目,并且该错误报告给翻译项目。该错误报告给最终负责其修复的母语人士。如果你想做比单个修复更多的工作,加入翻译团队会很有用。
小型项目没有翻译项目,没有直接参与开发的母语人士。你正在报告,并且你负责你的修复是正确的。
在报告给上游之前,你必须检查上游维护的版本是否仍然包含所讨论的字符串
- 查找最新的上游 pot 文件并检查你的字符串。请注意,有些项目有两个或多个维护翻译的分支。在这种情况下,你应该检查所有分支。
- 字符串在这里。=> 问题可以在上游解决。
- 字符串不在。=> 问题必须由 SUSE 软件包维护者和 SUSE 翻译人员作为特殊情况解决。你必须从 pot 文件中提取这些删除的字符串,并且软件包维护者必须添加特殊的合并项。
GNOME
GNOME 上游具有两级支持
- GNOME Bugzilla Infrastructure/l10n 是报告 GNOME 翻译错误的正确位置。这是一个志愿者项目,因此报告缺失的翻译是没有意义的。
- 加入 GNOME 翻译项目 对于定期翻译工作非常推荐。翻译人员将获得翻译权限。
GNOME L10N 是只读访问最新翻译的门户。
上游合作
- 如果项目有活跃的上游维护,切勿在 SUSE 中修复上游的 bug。这样的修复会在下一次 SUSE 版本更新中丢失,或者会导致大量的冲突。
- 如果您想参与有活跃上游维护的翻译工作,应该与上游的翻译团队保持联系。
Bug 已在上游或 LCN 中修复。现在怎么办?
现在假设您的 bug 终于在上游或新的翻译在 LCN 中得到了修复。
SUSE 的流程可以为导入修复提供很多帮助,但在某些情况下需要一些额外的工作。
- 如果软件包的翻译项目位于 LCN 中,并且您的产品处于预发布阶段,您无需做任何事情。会有翻译轮次,在翻译轮次结束后,翻译应该被导入到软件包中,要么由软件包维护者直接导入,要么由 translation-update-upstream 项目间接导入。
- 如果软件包包含在 translation-update-upstream 项目中,并且修复出现在活跃的上游仓库中,修复也会在下一次翻译收集期间自动导入。(您可以通过源 spec 文件中的 translation-update-upstream 命令识别此类软件包。)
- 如果软件包未包含在 translation-update-upstream 项目中,您需要提交一个 bug 并将其分配给软件包维护者。软件包维护者会选择最新的翻译并提交软件包。
- 如果您的 SUSE 版本已经发布,则有一个特殊的 translation-update 包。它可以提供翻译更新,而无需重新构建任何包含代码的软件包。这种方式尤其在发布后使用。
软件包维护者须知
翻译更新软件包的工作原理?
作为软件包维护者,您经常需要更新翻译。翻译通常与上游项目一起提供,位于主 tarball 中的 po 目录中。由于翻译工作通常比代码滞后,您经常会被要求更新翻译。为了简化这项工作,SUSE 中有几个特殊的工具。
translation-update
translation-update 是最简单的方法来更新。它可以在安装时提供最新的翻译,而无需重新构建任何软件包。这个特性是由 glibc 中 SUSE 特定的覆盖目录定义 允许的。为此付出的代价是为所有用户双重安装翻译文件。
重要提示:如果在更新目录中找到 mo 文件,则根本不会读取原始 mo 文件。这是 glibc 补丁中定义的行为。translation-update 包中只能包含完整的翻译。
此软件包包含三个 tarball
translation-update-from-translation-update-upstream-*.tar.bz2
由 translation-update-upstream 辅助脚本生成的 tarball。请参阅下文。请勿手动编辑!
translation-update.tar.bz2
手动创建的包含翻译更新的软件包。现在可能为空。
translation-update2.tar.bz2
手动创建的包含翻译热修复的软件包。这里的字符串优先于所有其他字符串。现在可能为空。
translation-update-upstream
translation-update-upstream 是一个可以在构建时提供翻译更新的软件包。支持它的每个软件包都必须在其 %prep 阶段包含 translation-update-upstream 命令
%prep %setup -q # Here you unpack everything that comes from upstream # Here apply all patches that come from upstream and bring new upstream strings translation-update-upstream # Here apply all other patches
translation-update-upstream 提供编译时的字符串。更新的 translation-update-upstream 必须在软件包编译时可用,并且字符串将结束于软件包的 po 目录中,以及编译后的 -lang 子软件包中。
重要提示:需要翻译更新的每个软件包都必须至少在 translation-update-upstream 软件包中的一个名为 *.tlst 的文件中列出。每一行定义一个更新 URL。
在 .tlst 文件中,翻译更新源有两个级别。标有mandatory 标签的源将完全包含在软件包中,并优先于所有其他翻译。未标有该标签的源将被比较,并应用“较新的翻译优先”的策略。
translation-update-upstream 有几个辅助脚本,由其维护者调用
辅助脚本 upstream-collect.sh
这是主脚本。脚本从 .tlst 文件中定义的所有源收集字符串,将它们与软件包中实际可用的字符串进行比较,并最终创建一个更新 tarball。
辅助脚本 translation-update-upstream-to-translation-update.sh
并非总是能够满足 translation-update-upstream 的要求,并在编译时提供它。这解释了此脚本的目的。它遍历所有字符串和所有受支持的软件包,并检测哪些软件包将不会使用更新的 translation-update-upstream 进行重新构建。此脚本的输出是一个 tarball。软件包维护者必须将此 tarball作为 translation-update 软件包的一部分进行打包(即,将其复制到另一个软件包)。
此脚本主要适用于服务包和在线更新。
辅助脚本 check-translation-completeness.sh
此脚本只是对所有软件包中的所有字符串进行翻译统计。
辅助脚本配置 upstream-collect.conf
这是上述辅助脚本的配置文件。它定义了发布中软件包的源。
辅助脚本 create-tlst-step*
这些脚本需要一个特殊的环境(将完整的发行版 RPM 树挂载在文件系统中),并将所有软件包中的 po 文件与上游仓库中的 po 文件进行比较(目前仅为 GNOME GTP),并搜索匹配项。结果,它会生成一个包含上游源的 .tlst 文件(目前仅为 upstream-gnome_gtp.tlst)。
gnome-patch-translation
gnome-patch-translation 是一种可以翻译 SUSE 特定补丁中字符串的工具。这些字符串在代码中标记为所有其他字符串的翻译,但如果没有进一步的努力,它们将永远无法到达翻译人员。
此工具可以收集这些字符串,将它们合并到一个可以上传到 LCN 的文件中。翻译人员然后上传翻译,这些翻译在软件包构建期间被导入。
除了软件包的初始工作外,所有这些工作都无需软件包维护者的任何工作。gnome-patch-translation 软件包的维护者将一次性将翻译导入到 SUSE 中的所有这些软件包。
gnome-patch-translation 维护者应遵循其 HOWTO。
%prep 阶段应如下所示(与 translation-update-upstream 一起
%prep %setup -q # Here you unpack everything that comes from upstream # Here apply all patches that come from upstream and bring new upstream strings translation-update-upstream gnome-patch-translation-prepare # Here apply patches that introduce new SUSE specific strings and also all other patches gnome-patch-translation-update
该工具比较这两个运行之间的 pot 文件并找到差异。在调用辅助脚本时,这些字符串被收集。
重要提示:在补丁中具有自定义字符串的每个软件包都必须在 gnome-patch-translation 软件包的相应 LCN 中列出,以及所提问的 SUSE 产品的 gnome-patch-translation.conf 文件中。
gettext 工具高级用法提示
将两个 po 文件合并为一个
在将两个 po 文件合并为一个时,您必须决定如何处理这些文件中不同的翻译。
合并时,如果翻译不同,则使用第一个找到的
msgcat --use-first file1.po file2.po -o joint.po
第二种方法是用“rejects”合并文件,每当字符串不同时
msgcat file1.po file2.po -o joint.po
在这种情况下,两个项目中翻译相同或唯一的全部消息将保持不变,但翻译不同的消息将包含一个特殊的字符串“#-#-#-#-#”分隔的两个实例,并且整个字符串将被标记为模糊。
过滤 po 文件
如果您想完全删除标记为模糊的消息
msgattrib --no-fuzzy old.po -o new.po
如果您想完全删除标记为过时的消息
msgattrib --no-obsolete old.po -o new.po
查找唯一消息
如果您想找到仅存在于其中一个比较的 po 文件中的消息
msgcomm --unique file1.po file2.po -o unique.po
有时您想找到 file2.po 中唯一的字符串。您可以通过组合两个工具来做到这一点
msgcat --use-first file1.po file2.po -o bothfiles_tmp.po msgcomm --unique bothfiles_tmp.po file1.po -o unique-in-file2.po rm bothfiles_tmp.po
