用过Qt的人都知道它自带有多语言支持的功能,只要在源码中将需要翻译的字符串用tr
包裹起来,就可以很轻松的利用其提供的 Qt Linguist 软件进行文字翻译。
如果我们的工程并非Qt项目,那么可以考虑使用 gettext 解决方案。其实现库libintl
是C语言开发的,在 linux 系统上用的比较多。
在C++中,更适合使用 Boost.Locale,用于替代libintl
。
基本用法
需要了解的是,Boost.Locale 只是一个运行时,它本身并不生成语言文件。我们需要使用gettext
的相关工具去进行提取和翻译工作。
文本假设你已经知道了如何制作.mo等语言文件。
一个简单的例子:
1 |
|
对于上面的例子,以下文件路径都是合法的
1 | \languages\zh\LC_MESSAGES\foo.mo |
generate 方法使用空字符串作为参数时将采用系统默认区域 + UTF8
编码
1 | // 重载了 () 操作符,等同于调用 generate 方法 |
翻译字符串主要是两个静态方法translate
和gettext
。translate
返回的是一个模板类basic_message
,它允许原文延迟翻译,也就是只有在需要string
的时候才会翻译。
而gettext
方法是建立在basic_message
之上的,它会立即构造一个basic_message
并且调用str()
方法得到字符串。
1 | template<typename CharType> |
如果只是想立即得到译文,用gettext
就够了。
gettext
- 获得译文,没有译文就返回原文
1
std::string str = boost::locale::gettext("Love");
- 第二个参数可以指定 locale
1
std::string str = boost::locale::gettext("Love", de);
dgettext
从指定的 domain(文件) 中获取译文。
1 | std::string str1 = boost::locale::dgettext("foo2", "Love"); |
ngettext
ngettext
用于处理某些语言的复数形式
1 | auto count = 1; |
pgettext
根据上下文获得译文。上下文功能在某些场景下是有用的,它可以使同一个原文返回不同的译文。
1 | std::string str1 = boost::locale::pgettext("ctx1", "Love"); |
总结
gettext
是高级别的方法,使用简单。还有扩展的的方法如dgettext
、ngettext
、pgettext
等等。我们只要记住三个字母:
d
表示domain
,支持指定域(语言文件)。n
表示number
,用于处理复数形式。p
表示specific
,表示处理特定语境下的语句。
gettext
所有的方法如下,看字母就知道怎么用了
1 | boost::locale::gettext() |
translate
前面说过,translate
才是底层的API,主要用于需要延迟翻译的时候,使用方法和gettext
差不多
1 | std::string str = boost::locale::translate("Love").str(); |
实践
软件首次运行时一般有三种选择
- 默认采用英文显示。
- 有安装程序的,在安装过程中让用户决定使用的语言。
- 跟随系统区域设置决定使用哪种语言。
对于第三种方式,我们需要获取计算机的区域设置。上面说过generator
支持用空字符串来生成系统默认区域的locale,但是编码是用的UTF-8。
如果我们想获取系统的区域设置,可以用boost完成这项工作:
1 | std::string localeStr = boost::locale::util::get_system_locale(); |
然后将结果告诉generator
,这样程序首次运行时将使用系统默认的语言显示了。
1 | std::locale loc = boost::locale::generator().generate(localeStr); |