Internationalization with Qt

应用程序的国际化就是使得程序能在国际间可用而不仅仅是在本国可用的过程。

Relevant Qt Classes andAPIs

以下的类支持Qt的国际化。

QTextCodec

QTextDecoder

QTextEncoder

QTranslator

QLocale

Languages and WritingSystems

有时,国际化是比较简单的,例如,把美国的应用程序让澳大利亚或英国的用户可访问,只需要简单的改变拼写。但是,把美国的应用程序对日本用户可用,或者韩国的应用程序对德国人可用,不仅仅需要软件操作不同的语言,还需要使用不同的输入技术,不同的字符编码和显示规则。

对于开发者,Qt尽可能的把国际化简单化。Qt内置提供的所有的输入控制和文本绘制方法支持所有的语言。内置的字体引擎能同时正确和精美的显示来自各种不同的输入系统的文本。

Qt支持大多数现在用的语言,特别是:

·        所有的东亚国家的语言(中文,日文和韩文)

·        所有的西方国家的语言 (使用拉丁文)

·        阿拉伯语

·        斯拉夫字母语言

·        希腊语

·        希伯来语

·        泰国和老挝语

·        所有不需要特殊处理的 Unicode 6.2 编码的脚本

·        孟加拉语

·        缅甸语

·        梵文

·        吉吉拉特语

·        果鲁穆奇语

·        坎那达语

·        高棉语

·        马拉雅拉姆语

·        泰米尔语

·        泰卢固语

·        藏语

以上列表都是被支持和在所有的平台上都能工作的,只要系统有渲染这些安装的输入系统的字体。

在Windows, Linux 和 Unix系统,使用字体配置,下面的语言也能支持:

·        迪维希语

·        叙利亚语

·        西非书面语言

在Mac OS系统,下面的语言也被支持:

·        奥里雅语

·        僧伽罗语

许多的书写系统表现出特殊的功能:

·        特殊的自动换行形式:一些亚洲语言字之间没有空白,自动换行可以发生在任何字符的后面,比如中文,日文和韩文,或者在逻辑词边界的泰语。

·        双向书写:阿拉伯语和希伯来语是从右到左书写的,除了数字和嵌入的英文单词是从左到右书写之外。

·        非间距或变音符号(欧洲语言的口音或变音符号):一些语言比如越南语大量的使用这些符号,并且一些字符同时有超过一个标记来表明读音。

·        连字:在特殊的语境,一些成对的字符被一些字结合的连字替换。常见的例子是,在美国和欧洲书记中使用的 fl 和fi的连字。

Qt视图照顾到以上列出的特殊的特性,你通常不用担心这些特性,只要你使用Qt 的输入控制和Qt的显示控制。

支持这些书写系统对程序员是透明的,完全被封装在Qt's text engine. 。这意味着你在用特定的语言时不需要知道任何书写系统信息,除了以下几点:

·        QPainter::drawText(int x, inty, const QString &str)把绘制的字符串的左边缘在给定的x,y参数的位置。这通常会给你左对齐的字符串。阿拉伯语和希伯来语的应用程序的字符串通常是右对齐的,所以对于这些语言需要用接收QRect的drawText() 版本,这样才与语言一直。

·        当你自己写文本输入控制时,用QTextLayout。在某些语言,宽度和形状会根据周围的字符而改变,这就是QTextLayout所考虑的。写输入控制通常需要知道一种特定的脚本使用方法的知识。通常最简单的方法是继承QLineEdit 或 QTextEdit.。

Step by Step

用Qt写跨平台的国际化软件是一个温和,渐进的过程。在一些的阶段,你的软件可以变得国际化:

UseQString for All User-Visible Text

由于 QString 内部使用了Unicode编码,世上的所有语言都能用熟悉的文本处理操作进行透明的处理。因为所有向用户显示文本的Qt函数都是以Qstring作为参数的,所有不存在从 char * 转换到 QString的开销。

在程序员空间的字符串(如QObject 名和文件格式文本)不需要用Qstring,传统的char * 或QByteArray 就足够了。

你可能没注意到你用Unicode编码:Qstring和 Qchar 就像用传统的C中的const char * 和char 一样那么简单。

当进行隐式转换为QString是,源码中的char *被假定是用UTF-8编码。如果你的C字面值字符串用的是不同的编码,用 QString::fromLatin1() 或QTextCodec把它转换为Unicode 编码的Qstring。

Usetr() for All Literal Text

如果你的程序有用“”引用的向用户显示的文本,确保用QCoreApplication::translate() 函数来处理它。要实现这一过程基本上都需要用 QObject::tr().。例如:假设LoginWidget 是QWidget:的子类:

LoginWidget::LoginWidget()
{
    QLabel*label =newQLabel(tr("Password:"));
    ...
}

这个占了你可能写的99%的用户可见字符串。

如果引用的文本不在 QObject 子类的成员函数中,用一个适当的类的tr()函数或直接用 QCoreApplication::translate() 函数。

void some_global_function(LoginWidget *logwid)
{
    QLabel*label =newQLabel(
                LoginWidget::tr("Password:"), logwid);
}
 
void same_global_function(LoginWidget *logwid)
{
    QLabel*label =newQLabel(
                qApp->translate("LoginWidget","Password:"), logwid);
}

如果你需要翻译的文本完全在函数的外部,那么可以用这两个宏:QT_TR_NOOP() 和QT_TRANSLATE_NOOP().。它们仅仅为以下介绍的 lupdate 工具提取的文本进行标记,宏只是扩展文本。

QT_TR_NOOP()的例子:

QString FriendlyConversation::greeting(int type)
{
    staticconst char *greeting_strings[]= {
        QT_TR_NOOP("Hello"),
        QT_TR_NOOP("Goodbye")
    };
    return tr(greeting_strings[type]);
}

QT_TR_NOOP()的例子:

staticconst char *greeting_strings[]= {
    QT_TRANSLATE_NOOP("FriendlyConversation","Hello"),
    QT_TRANSLATE_NOOP("FriendlyConversation","Goodbye")
};
 
QString FriendlyConversation::greeting(int type)
{
    return tr(greeting_strings[type]);
}
 
QString global_greeting(int type)
{
    return qApp->translate("FriendlyConversation",
                           greeting_strings[type]);
}

如果你用宏QT_NO_CAST_FROM_ASCII定义来编译软件禁止从const char * 到Qstring 的转换,你就可能捕获任何漏掉的字符串。

UseQKeySequence() for Accelerator Values

快捷键值如 Ctrl+Q 或 Alt+F也需要翻译。如果你在程序中为“quit”退出用硬编码 Qt::CTRL + Qt::Key_Q ,转换器就不能重写它们。正确的做法是:

exitAct =newQAction(tr("E&xit"),this);
exitAct->setShortcuts(QKeySequence::Quit);

UseQString::arg() for Dynamic Text

QString::arg() 提供简单的替换参数的方法:

void FileCopier::showProgress(int done, int total,
                              constQString&currentFile)
{
    label.setText(tr("%1 of %2 files copied.\nCopying: %3")
                  .arg(done)
                  .arg(total)
                  .arg(currentFile));
}

在有的语言中参数的顺序可能需要改变,实现这个只需要改变参数中%的顺序就好。例如:

QString s1 ="%1 of %2 files copied. Copying: %3";
QString s2 ="Kopierer nu %3. Av totalt %2 filer er %1 kopiert.";
 
qDebug() << s1.arg(5).arg(10).arg("somefile.txt");
qDebug() << s2.arg(5).arg(10).arg("somefile.txt");

生成了正确的英语和挪威语的输出:

5 of 10 files copied. Copying: somefile.txt
Kopierer nu somefile.txt. Av totalt 10 filer er 5 kopiert.

ProduceTranslations

一旦你在整个程序中用了tr(),你可以在你的程序中开始对用户可见文本生成翻译。

翻译Qt程序需要三个步骤:

1.     运行lupdate工具 来提取Qt程序C++源代码中可以翻译的文本,生成给翻译器的一个消息文件(TS文件)。该工具识别tr()和以上提到的宏 QT_TR*_NOOP()并生成TS文件。

2.    用Qt Linguist.为TS文件中的源文本提供翻译,因为TS文件是XML格式,你也可以手工进行编辑。

3.    运行lrelease 从TS文件中得到一个轻型的消息文件(QM文件),只适合最终用途。想象TS文件是源文件,QM文件是目标文件。翻译器编辑TS文件,但是程序的用户只需要QM文件。这些文件都是独立于平台和地域的。

典型的,你每次发布程序都需要重复这些步骤。Linguist 工具尽可能重用之前的版本的翻译。

在运行lupdate 之前,你应该准备工程文件。例如:

HEADERS         = funnydialog.h \
                  wackywidget.h
SOURCES         = funnydialog.cpp \
                  main.cpp \
                  wackywidget.cpp
FORMS           = fancybox.ui
TRANSLATIONS    = superapp_dk.ts \
                  superapp_fi.ts \
                  superapp_no.ts \
                  superapp_se.ts

当你运行 lupdate 或 lrelease,时,你必须把工程文件名作为命令行的参数。

在这个例子中,支持四种语言:丹麦,芬兰,挪威和瑞典。如果你用qmake,lupdate通常不需要额外的工程文件。一旦你添加了TRANSLATIONS条目qmake工程文件就能正常工作。

在你的程序中,必须为用户的语言适当的调用QTranslator::load() 装载翻译文件,并用QCoreApplication::installTranslator()进行安装。

linguistlupdate 和 lrelease被安装到Qt安装的根目录中的bin子目录。点击QtLinguist 的Help|Manual进入用户手册。它包含一个开始的教程。

Qt本身包含超过400个需要翻译成目标语言的字符串。你会找到很多个翻译文件,以及在QtTranslations 模块中翻译成其他语言的模板。

典型的,你的程序的main()函数看起来像这样:

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
 
    QTranslator qtTranslator;
    qtTranslator.load("qt_"+QLocale::system().name(),
            QLibraryInfo::location(QLibraryInfo::TranslationsPath));
    app.installTranslator(&qtTranslator);
 
    QTranslator myappTranslator;
    myappTranslator.load("myapp_"+QLocale::system().name());
    app.installTranslator(&myappTranslator);
 
    ...
    return app.exec();
}

注意:用 QLibraryInfo::location() 来定位Qt translations。开发者应该在运行时传递QLibraryInfo::TranslationsPath 到这个函数而不是用程序的环境变量QTDIR来请求该该路径。

Supportfor Encodings

QTextCodec类和 QTextStream工具很容易的支持许多用户数据的输入输出编码。当程序启动时,当处理外部的8位数据,程序的语言环境奖觉得使用的8位编码。QTextCodec::codecForLocale()返回一个可以用来转换本地编码和Unicode的解码器。

程序偶尔需要除了默认8位编码之外的编码。例如,一个程序在 Cyrillic KOI8-R地区可能需要输出 Cyrillic 的ISO 8859-5 编码;可能的代码如下:

QString string =...; // some Unicode text
 
QTextCodec*codec =QTextCodec::codecForName("ISO 8859-5");
QByteArray encodedString = codec->fromUnicode(string);

把Unicode转换为本地的8位编码,一个简便的方法是: QString::toLocal8Bit() 函数返回这样的8位编码数据。另外的捷径是 QString::toUtf8(), 返回8位的UTF-8编码的文本。这个很好的保存了Unicode 信息,如果文本完全是ASCII看起来像纯的ASCII文本。

其他的转换方法,有QString::fromUtf8() 和 QString::fromLocal8Bit()方便的函数,或者是通常代码,从ISO 8859-5 Cyrillic 转换到 Unicode的演示:

QByteArray encodedString =...; // some ISO 8859-5 encoded text
 
QTextCodec*codec =QTextCodec::codecForName("ISO 8859-5");
QString string = codec->toUnicode(encodedString);

Unicode I/O 应用来使全世界范围用户的文档可移植性最大化。由于用户可能需要处理已经存在的文档,有时它也需要支持其他编码。需要支持的最重要的额外编码就是QTextCodec::codecForLocale(),返回的。因为它是用户最可能用来与其他人或应用程序交互的。

Qt支持大多数本地最经常使用的编码。

有时对于不怎么经常使用的编码你可能需要写自己的QTextCodec子类。如果比较紧急,可以联系Qt技术支持团队或在Qt兴趣列表里找是否有人已经实现了对该编码的支持。

Localize

本地化是适应本地规则的过程,例如显示数据和时间用本地的首选格式。这样的本地化可以使用适当的tr()字符串达到。

void Clock::setTime(const QTime &time)
{
    if (tr("AMPM") =="AMPM") {
        // 12-hour clock
    } else {
        // 24-hour clock
    }
}

在例子中,对于美国,判断为真并会进入12小时的分支。但是在欧洲翻译的结果会是其他所以进入23小时分支。

使用 QLocale 类对数字,日期,货币字符串进行本地化。

不建议本地化图片,选择适合所有地方的清晰的图标,而不是依据本地的双关语或伸展隐喻。例外的是向左向右图片对于阿拉伯和希伯来语本地化需要进行翻转。

Dynamic Translation

一些应用程序如Qt Linguist,,当它们还在运行时必须支持转到用户设置的语言。要让Widgets意识到转换到安装的 Qtranslators,重新实现widget的 changeEvent()函数检查是否是 LanguageChange事件,并用tr()函数更新显示文本。例如:

void MyWidget::changeEvent(QEvent *event)
{
    if (e->type() == QEvent::LanguageChange) {
        titleLabel->setText(tr("Document Title"));
        ...
        okPushButton->setText(tr("&OK"));
    } else
        QWidget::changeEvent(event);
}

其他所有的事件通过调用默认实现的函数。

安装的translators 列表可能随着 LocaleChange事件相应的改变,或应用程序可以提供一个接口运行用户改变当前的程序语言。

QWidget子类的默认事件处理响应 QEvent::LanguageChange事件,必要时调用这个函数。

当用 QCoreApplication::installTranslator() 函数安装新的一个翻译时会发出LanguageChange事件。此外,其他程序组件也可以强制widget通过发出LanguageChange事件来更新它们自己。

Translating Non-Qt Classes

有时有必要对不是继承 QObject或用Q_OBJECT 宏的类中的字符串支持国际化开启翻译功能。由于Qt在运行时翻译字符串基于它们关联的类和 lupdate 在源码中查找可以翻译的字符串,非Qt类必须用一种机制可以提供这些信息。

一种方法是用Q_DECLARE_TR_FUNCTIONS() 宏给非Qt类添加翻译支持:

class MyClass
{
    Q_DECLARE_TR_FUNCTIONS(MyClass)
 
public:
    MyClass();
    ...
};

这使得该类可以用tr()函数翻译与该类相关联的字符串和使得lupdate 可以在源码中查找可以翻译的字符串。

另外的方法:在特定的上下午中可以调用 QCoreApplication::translate() 函数,而且该函数可以被lupdate 和 Qt Linguist.识别。

System Support

在Qt运行的一些操作系统和windows系统仅仅是有限的支持Unicode。在下面的系统的支持的级别对Qt在这些平台上的支持有一定的影响,即使通常Qt程序不需要太关心平台限制:

Unix/X11

n  语言环境导向的字体和输入方法,Qt隐藏了这些并提供了Unicode 的输入输出。

n   文件系统约定如 UTF-8如今在Unix大部分变体默认使用。所有的Qt函数都接受Unicode,但是把文件名转换为本地的8位编码,这就是Unix的约定。

n   文件的IO默认为当地的8位编码,在QTextStream与Unicode选项。

n  一些老的Unix发布版本仅仅包含支持一些语言环境。例如,如果你有一个/usr/share/locale/ja_JP.EUC 目录,这不意味着可以显示日文,你必须有安装的日文字体并且 /usr/share/locale/ja_JP.EUC 必须是完整的。为了达到最好的效果,从系统供应商那里获取完整的语言环境。

Linux

Qt提供全部的Unicode 支持,包括输入方法,字体,剪贴板和拖放。

n   在所有现代的Linux发布版文件系统通常用UTF-8编码,而且不会有问题。文件IO默认为UTF-8。

Windows

n  Qt提供全部的Unicode 支持,包括输入方法,字体,剪贴板,拖放和文件名。

n  文件IO默认为Latin1,与在  QTextStream的Unicode选项。注意,一些windows程序不理解大端模式的Unicode 文本文件即使这是在没有高级别协议的Unicode标准规定顺序。

http://blog.csdn.net/hai200501019/article/details/9192967

Qt国际化(Q_DECLARE_TR_FUNCTIONS() 宏给非Qt类添加翻译支持,以前没见过QTextEncoder和QTextDecoder和QLibraryInfo::location()和QEvent::LanguageChange)的更多相关文章

  1. 封装QtCore(在非Qt项目里使用QString,QJson,QFileInfo,QFile等类)

    单独封装QtCore 一直以来使用QT的特性使用惯了,很多东西QT都封装得很好.如果突然有一天,不使用QT开发了,是不是不习惯. 比如我们经常使用QString很多方法,string,wstring之 ...

  2. QT国际化 一 (lupdate/linguits/lrelease)

    QT国际化(lupdate/linguits/lrelease) 本文由乌合之众瞎写http://www.cnblogs.com/oloroso/ qt国际化其实就是qt中字符串的字符集编码的设置.当 ...

  3. Qt国际化详细介绍,中文乱码以及解决方案

    Qt国际化的一般步骤 运行 lupdate,从应用程序的代码中提取所有界面上的可见字符.        这些可见字符必须被 tr() .QCoreApplication::translate().Qt ...

  4. 【Qt】Qt国际化【转】

    简介 Qt国际化属于Qt高级中的一部分,本想着放到后面来说,上节刚好介绍了Qt Linguist,趁热打铁就一起了解下. 对于绝大多数的应用程序,在刚启动时,需要加载默认的语言(或最后一次设置的语言) ...

  5. C++在使用Qt中SLOT宏须要注意的一个小细节

    大家都知道C++虚函数的机制,对于基类定义为虚函数的地方,子类假设覆写,在基类指针或者引用来指向子类的时候会实现动态绑定. 但假设指针去调用非虚函数,这个时候会调用C++的静态绑定,去推断当前的指针是 ...

  6. C++在使用Qt中SLOT宏需要注意的一个小细节

    大家都知道C++虚函数的机制,对于基类定义为虚函数的地方,子类如果覆写,在基类指针或者引用来指向子类的时候会实现动态绑定. 但如果指针去调用非虚函数,这个时候会调用C++的静态绑定,去判断当前的指针是 ...

  7. QT之在QML中使用C++类和对象

    QML其实是对ECMAScript的扩展,融合了Qt object系统,它是一种新的解释性语言,QML引擎虽然由Qt C++实现,但QML对象的运行环境说到底和C++对象的上下文环境是不通的,是平行的 ...

  8. 非Qt工程使用Qt的信号槽机制

    非Qt工程,使用Qt的信号槽机制,蛋疼不?反正我现在就是要做这样一件蛋疼的事. 要使用Qt的信号槽机制,下面是从Qt Assist里面关于 signal & slots 的一句介绍: All ...

  9. QT国际化(中英转换)

    转载:https://blog.csdn.net/u012528526/article/details/54707233 QT国际化(中英转换) 我们都知道在安卓中,想做国际化很简单,只需要建立对应的 ...

随机推荐

  1. JNI(2)

    JNI(2) 访问字段和方法 JNI允许本地代码访问java 对象的字段和方法. 调用需要两个步骤: 例如调用cls类的f方法, 1. 获取方法ID jmethodID mid = env->G ...

  2. .Net将多个DLL打包为一个DLL(ILMerge)

    在做.Net底层编码过程中,为了功能独立,有可能会生成多个DLL,引用时非常不便.这方面微软提供了一个ILMerge工具原版DOS工具,可以将多个DLL合并成一个.下载完成后需要安装一下,然后通过DO ...

  3. C# 日期格式转换 string类型 20150329 转换为 2015/03/29

    DateTime.ParseExact("20150329", "yyyyMMdd", System.Globalization.CultureInfo.Cur ...

  4. [译]Stairway to Integration Services Level 5 - 增量删除数据

    在 dbo.Contact中添加一行记录 Use AdventureWorks go Insert Into dbo.Contact (FirstName, MiddleName, LastName, ...

  5. perl 处理json 数组格式

    [root@dr-mysql01 ~]# cat a1.pl use Encode; use JSON; use URI::Escape; use LWP::Simple; my $host = &q ...

  6. cocos2dx进阶学习之场景切换

    背景 在学习马里奥时,我们学习到从菜单场景到游戏场景的切换,代码如下 void CMMenuScene::OnStartCallBack( CCObject *pSender ) { CCDirect ...

  7. java学习之观察者设计模式

    package com.gh.observer; import java.util.Observable; /** * 被观察者对象 * 必须继承被观察者抽象类 * @author ganhang * ...

  8. ZIOZIA_百度百科

    ZIOZIA_百度百科 ZIOZIA

  9. BNU Invading system

    http://www.bnuoj.com/bnuoj/problem_show.php?pid=29364 这个题被坑了. 题意:密码就是那些数字里面的数,转换成二进制后1最少的那个数,当1的个数相同 ...

  10. epoll的LT和ET模式

    原理參考该博客 从man手冊中,得到ET和LT的详细描写叙述例如以下 EPOLL事件有两种模型: Edge Triggered (ET) Level Triggered (LT) 假如有这样一个样例: ...