Qt中的i18n

翻译流程

  1. 在源代码中标记待翻译的字符串
  2. 使用lupdate生成.ts文件
  3. 使用linguist工具读写.ts文件进行翻译
  4. 使用lrelease工具将.ts文件转换成.qm文件
  5. 在Qt程序中加载.qm文件。

标记字符串

常用的有QObject::tr(),QCoreApplication::translate()和QT_TRANSLATE_NOOP,lupdate工具也支持其他一些标记宏,可以命令行去查看。

在Qt中,每个待翻译的字符串都要属于一个context,所以,标记的时候要注意的也是context。

  1. QT_TRANSLATE_NOOP
    QT_TRANSLATE_NOOP仅仅用于标记字符串,可以查看这个宏的定义,这个宏需要传入两个参数,第一个参数是context,第二个参数是待翻译的字符串。但是,宏的最终结果知识单纯的使用字符串本身。其实,这个宏仅仅是给lupdate工具识别使用的,lupdate遇到这个宏的时候,它就知道了“字符串clay是需要翻译的,并且属于clay_context上下文”。

如此,在Qt程序运行时,运行到源码中QT_TRANSLATE_NOOP的位置时,这依然是一个普通的字符串而已,如果需要翻译,需要再次调用QCoreApplication::translate(),传入context和字符串。

  1. tr()
    继承自QObject的对象,都有一个tr()方法,只需要传入待翻译的字符串即可。这个方法实际上做了两件事:
  • 标记字符串
  • 运行时执行翻译
    tr()方法实际上会把当前的类名作为context,最终调用QCoreApplication::translate()进行翻译。
  1. QCoreApplication::translate()
    这是一个全局可用的翻译方法,它同样需要context和字符串这两个参数。QCoreApplication::translate()和tr()一样做了两件事,不同的是,QCoreApplication::translate()方法可以传入context参数,并且可以全局调用。

  2. 自定义标记宏
    可以自定义类似QT_TRANSLATE_NOOP标记的宏,但是,在自定义以后,调用lupdate生成.ts文件的时候,需要增加额外的参数告诉lupdate你定义的这个标记红,lupdate才能识别到。

Danger
  1. 尽量不要动态修改语言,因为qt中安装、卸载translator的时候,不是线程安全的!
    之前遇到过一个情况,一个子线程在不断的调用QProcess::waitFinished(0),在waitFinished方法的内部,如果超时,实际上会抛出一个错误,而这个错误会用QObject::tr()翻译!这种隐藏在Qt源代码里边的翻译行为,我们是无法预知的,所以动态切换语言,实在是有点风险,如果全部的翻译操作对开发人员来说都是可知并且可控的话,那么这个行为才是安全的!

  2. 在Qt的程序中,不使用Qt框架下的这套i18n工具,动态切换语言,或许才是安全的。