Java 使用 GNU 的 Gettext 工具实现国际化

在 Java 中最常见的实现国际化(i18n)的方式应该是使用 .properties 资源文件。本文将使用另一种方式实现 Java 代码的国际化与本地化(l10n)。
Gettext 是一个可用于多种语言的国际化工具。相比于传统的 key – value 资源文件方式,其不同点有:

使用 properties 的传统方式 GNU gettext
key 是短文本 key 是纯文本形式的未翻译内容
翻译文件通常命名为 resources_locale.properties, 文件内容只能包含 ASCII 文本,非 ASCII 文字会被用 Unicode 编码代替 翻译文件通常命名为resources.local.po,文件内容可以使用任意编码可以包含任意字符
ResourceBundle.getString会在找不到翻译内容时抛出异常 gettext当找不到翻译内容时会返回 key.
不支持单复数及上下文翻译 支持单复数和上下文相关的翻译

下面,将通过一个示例来演示如何在 Java 中使用 Gettext 实现国际化。

一般步骤:

  1. 相关工具下载。
  2. 引入依赖,编写工具类。
  3. 在需要翻译的地方调用相关翻译方法。
  4. 抽取待翻译内容。
  5. 翻译。
  6. 生成翻译后资源文件。
  7. 运行。

相关工具下载。

在 Gettext 主页上可以找到其源代码,*nix 通常自带了相关工具,不需另行下载。当然,也可以在主页上找到用于 Windows 的工具包:https://mlocati.github.io/articles/gettext-iconv-windows.html
我下载的是 64 位绿色版: gettext0.19.8.1-iconv1.14-static-64.zip 解压后建议添加其下 bin 目录到 Path 中,方便后续输入命令。

引入依赖,编写工具类。

首先随便新建一个工程,这里使用的是 Maven 空项目。添加 libintl 的依赖。
如下:

如果你不是使用 Maven, 那么可以搜索下载这个 jar 包。

编写翻译工具类:

这里,我使用的是 WordPress 中的国际化函数名称,实际上 gettext 习惯上也是使用下划线作为其别名的,因为文字输出相对频繁,因此使用简短的名称。

  • __(msgid)用于普通翻译。
  • _x(msgid,context)用于上下文翻译。如,post 一词,即可表示“文章”,也可表示“发表”,要区分则使用一个上下文字符串标识到底是哪一个意思。
  • _n(msgid,msg_plural,n)用于单复数翻译。当 n 为单数时返回 msgid 的翻译,当 n 为复数时,返回 msg_plural 的翻译。
  • _nx(msgid,msg_plural,n,context)就是上下文相关单复数翻译啦。

在需要翻译的地方调用相关翻译方法。

现在随便试一下输出:

抽取待翻译内容。

使用下载的工具提取翻译字符串。命令用法

网上的示例都是只有最简单的提取普通翻译字符串的方法,没有写如何提取单复数翻译字符串。看了一圈文档终于找到了。使用 -kxxx即可,但具体 xxx 该怎么写呢?
文档中有示例:

For Java: GettextResource.gettext:2, GettextResource.ngettext:2,3, GettextResource.pgettext:2c,3, GettextResource.npgettext:2c,3,4, gettext, ngettext:1,2, pgettext:1c,2, npgettext:1c,2,3, getString.

因此,对应过来我们的工具类,完整的命令就是:(在src/main/目录下运行的示例)

  • -kxxx 用于指明抽取哪些函数同时指明第几个参数是什么含义。
  • -o 用于指明输出文件
  • 后面跟着要扫描的 java 源文件
  • 最后使用 –from-code UTF-8 指明编码。

该命令将生成一个翻译模板文件(.pot),内容如下:

翻译。

复制模板文件为待翻译文件: messages_zh_CN.po 修改需要的翻译的地方

特别注意需要修改第 17 行文件编码,否则下一步报错。

生成翻译后资源文件。

使用 msgfmt 命令。(在src/main/目录下运行的示例)

  • –java2 表明生成 JDK1.2+ 的class 文件(内部使用的是 Object 数组,如果用 –java 则内部使用的是 Hashtable )。
  • -d resources 保存在 resources 目录
  • -r Messages 生成的类名的 BaseName.
  • -l zh_CN 该翻译文件的语言编码
  • 最后是翻译完的文件。

gettext命令
gettext命令

可能 gettext 使用的编译命令是 1.3 版本的, path 中 javac 是 1.8 的则会报警告。觉得烦的话,可以使用 –source 选项生成 .java 文件再自行编译。(不过这样直接编译还是报不安全,因为public java.util.Enumeration getKeys ()方法没有用泛型)

运行。

运行效果:

运行结果
运行结果

修改合并。

当之后源文件有修改时,可以使用 msgmerge 合并更改,而不需删除原翻译。
比如上述 java 文件最后一行语句去掉注释,直接运行的话是没有翻译的,会显示原文,因此我们打算把新的待翻译内容也抽取出来。
仍用 xgettext 命令抽取,不过你可以保存为另一个 .pot 文件名,当然覆盖也是可以的。
然后合并到已翻译文件:
用法:

  • -U 表示更新已有翻译文件。

然后再进行翻译、生成的步骤即可。

参考连接:


“Java 使用 GNU 的 Gettext 工具实现国际化”的2个回复

Loading...

发表评论

电子邮件地址不会被公开。 必填项已用*标注