雅安市有哪些区:乱谈Qt程序之i18n的实现(从C++到Qt)

来源:百度文库 编辑:九乡新闻网 时间:2024/04/29 14:36:30

乱谈Qt程序之i18n的实现(从C++到Qt)

分类: Qt C/C++ 2011-08-22 20:22 819人阅读 评论(1) 收藏 举报

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

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

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

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

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

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

例子一

看一个 hello world 的例子:

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

#include  #include  #include  #define tr(X) L##X int main() { setlocale(LC_ALL, ""); std::wcout<

恩,编译运行,看到结果

hello world

例子二

如何翻译这个程序呢?

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

词典?

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

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

typedef std::map 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<

使用

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

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

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  #include  #include  #include  #include   typedef std::map 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##X  int main() { setlocale(LC_ALL, "");  globalMap = & chinese;  std::wcout<

看看运行结果:

你好 世界

对比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会自动为你生成它。不管你到底用还是不用。