Qt国际化

来源:互联网 发布:淘宝店铺如何更换客服 编辑:程序博客网 时间:2024/05/01 04:58

嘿嘿,本文只是试图从纯C++的角度告诉你 Qt 的国际化是到底是怎么一回事(注:本文只看一个点,不看面)。而不会一步一步告诉你Qt的国际化/本地化怎么用(这些东西在Qt Manual、论坛 以及 相关书籍中介绍的够多了)。

Qt 国际化所做的就是这点东西:

  • 首先,提取要翻译的字符串,手动翻译,生成一个qm文件,以备使用
  • 其次,程序中使用QTranslator安装翻译文件
  • 最后,tr函数去查找有没有对应的字符串,有则使用,
    • 没有怎么办,就按照某种编码将参数窄字符串变成QString呗

至于动态翻译:点一下菜单,界面文字全改变,这在Qt中是相当容易实现的东西。

其实,根本就没有动态这回事。所谓的动态翻译,就是我们加载了一个新的翻译文件,然后将界面的文字用新的重新设置了一遍。

我们找个超简单的C++的小例子看看,并一步一步让它变的复杂一点点。

例子一

看一个 hello world 的例子:

  • 为了稍后国际化,我们先用一个 tr 宏包住了所有要显示的字符串。
  • 同样为了程序可以在所有平台下运行,我们的输出使用的是宽字符wchar_t

#include <iostream>#include <string>#include <locale.h>#define tr(X) L##Xint main(){    setlocale(LC_ALL, "");    std::wcout<<tr("hello")<<tr(" ")<<tr("world")<<std::endl;    return 0;}

恩,编译运行,看到结果

hello world

例子二

如何翻译这个程序呢?

  • 要有 翻译后的文字 吧
  • 要使用 翻译后的文字 吧
  • 要处理 没有翻译的文字 吧

词典?

源单词和目标单词的对应关系,我们就叫它词典好了。

  • 创建3个全局的map,分别用来存在中文、日文、挪威文的翻译
  • 创建一个辅助函数create_map和辅助变量dummy用来初始化这3个map

typedef std::map<std::string, std::wstring> Map;Map chinese;Map japanese;Map norwegian;int create_maps(){    chinese["hello"] = L"你好";    chinese["world"] = L"世界";    japanese["hello"] = L"こんにちは";    japanese["world"] = L"世界";    norwegian["hello"] = L"hallo";    norwegian["world"] = L"verden";    return 0;}int dummy = create_maps();

关联

有了翻译的内容,需要安装一下,让我们的程序知道翻译内容的存在吧?

Map * globalMap = 0;int main(){    setlocale(LC_ALL, "");    globalMap = & chinese; //install    std::wcout<<tr("hello")<<tr(" ")<<tr("world")<<std::endl;    return 0;}

使用

第一个例子中的宏可以丢掉了,我们写一个函数:

  • 如果安装了词典,且存在翻译的内容,使用之
  • 其他,将窄字符串用某种规则直接转成宽字符串

std::wstring tr(const char * text){    if (globalMap && globalMap->count(text)) {        return (*globalMap)[text];    }    wchar_t wcs[100];    mbstowcs(wcs, text, 99);    return std::wstring(wcs);}

拼盘

将3部分合到一块:

#include <iostream>#include <string>#include <cstdlib>#include <map>#include <locale.h>typedef std::map<std::string, std::wstring> Map;Map chinese;Map japanese;Map norwegian;int create_maps(){    chinese["hello"] = L"你好";    chinese["world"] = L"世界";    japanese["hello"] = L"こんにちは";    japanese["world"] = L"世界";    norwegian["hello"] = L"hallo";    norwegian["world"] = L"verden";    return 0;}int dummy = create_maps();Map * globalMap = 0;std::wstring tr(const char * text){    if (globalMap && globalMap->count(text)) {        return (*globalMap)[text];    }    wchar_t wcs[100];    mbstowcs(wcs, text, 99);    return std::wstring(wcs);}//#define tr(X) L##Xint main(){    setlocale(LC_ALL, "");    globalMap = & chinese;    std::wcout<<tr("hello")<<tr(" ")<<tr("world")<<std::endl;    return 0;}

看看运行结果:

你好 世界

对比Qt

Qt 又做了什么呢?

Qt

我们的例子

 

lupdate/lrelease/...

Map/Map/Map

生成翻译/词典文件

QTranslator

globalMap

安装翻译文件

QObject::tr()
QCoreApplication::translate()

tr()

使用翻译文件

从根本上说,Qt 国际化所做的就是这点东西:

  • 首先,提取要翻译的字符串,手动翻译,生成一个qm文件,以备使用
  • 其次,程序中使用QTranslator安装翻译文件
  • 最后,tr函数去查找有没有对应的字符串,有则使用,
    • 没有怎么办,就按照某种编码将参数窄字符串变成QString呗?

注意,tr就是一个将 const char * 变成 QString 的函数:

QString QObject::tr ( const char * sourceText,...)

对于tr,我们在Qt中translate、tr关系 与中文问题 有了比较详细的讨论,此处就不重复了。

Qt动态翻译

点一下菜单,界面文字全改变,这在Qt中是相当容易实现的东西。也就是大家所说的动态翻译。

其实,根本就没有动态这回事。所谓的动态翻译,就是我们加载了一个新的翻译文件,然后将界面的文字用新的重新设置了一遍。

考虑我们前面的例子,稍微改改:

int main(){    setlocale(LC_ALL, "");    std::wstring welcome = tr("hello"); //1st    globalMap = & chinese;    welcome = tr("hello"); //2nd        globalMap = & japanese;    welcome = tr("hello"); //3rd    return 0;}

尽管都是用tr,但3处 welcome 的内容却不相同,动态翻译也就是这回事。

  • 一个button的文字如何改变? 通过 setText
  • 在button上,"hello" ==> "你好" 是改变么? 显然,于是这个过程需要setText

这也是为什么,uic生成的代码 ui_xxx.h 中始终有:

    void retranslateUi(QDialog *Dialog)    {        Dialog->setWindowTitle(QApplication::translate("Dialog", "Dialog", 0, QApplication::UnicodeUTF8));        groupBox->setTitle(QApplication::translate("Dialog", "GroupBox", 0, QApplication::UnicodeUTF8));    } // retranslateUi

这种函数存在的原因。

当你安装了新的翻译文件以后,只需要重新调用一遍这个函数就行了。

但你安装新的翻译文件后,应用程序会给各个窗口发送一个事件,此时,是调用上述函数的最佳时机

void MainWindow::changeEvent(QEvent *e){    QMainWindow::changeEvent(e);    switch (e->type()) {    case QEvent::LanguageChange:        ui->retranslateUi(this);        break;    default:        break;    }}

大家对这个函数应该都不陌生,毕竟,Qt Creator会自动为你生成它。不管你到底用还是不用。