分类: LINUX
2008-05-05 20:08:32
应用的国际化就是使应用成为能被非本国的人使用的过程。
有的情况下,国际化很简单,例如,使一个US应用可被Australian或者British用户理解,工作可能少于几个拼写修正。但是使一个US应用可以被Japanese用户使用,或者一个Korean应用可被German用户使用,就会需要软件不仅工作于不同语言下,还要使用不同的输入技术、字符编码和表达习惯。
也参见手册。
以Qt来编写多平台国际化的软件是一个和缓的、逐步增加的过程。你的软件可以按下面的几个阶段实现国际化:
既然QString内部就使用Unicode编码,那么使用常见的文本处理手段,就可以透彻地处理世界上的每种语言。同时,既然所有向用户呈现文本的Qt函数都把QString作为参数,也就没有了char*到QString的转换的时间开销。
在“程序员空间”(例如的名称和文件格式文本)的字符串不需要使用QString;传统的char*或者类就够用了。
你不大可能注意到你在使用Unicode;QString和就如同早期版本的传统C中的粗糙的const char*和char。
无论你的程序在哪里对将会呈现给用户的文本使用了"quoted text",要确保它被()函数处理过。其实做到这一点只需要使用()。例如,假设LoginWidget是QWidget的一个子类:
LoginWidget::LoginWidget() { *label = new ( tr("Password:"), this ); ... }
这就解决了你可能要写的用户可见的字符串的99%。
如果这些quoted text不是在子类的成员函数中,可以使用一个适当的类的tr()函数,或者直接使用()函数:
void some_global_function( LoginWidget *logwid ) { *label = new ( LoginWidget::tr("Password:"), logwid ); } void same_global_function( LoginWidget *logwid ) { *label = new ( qApp->("LoginWidget", "Password:"), logwid ); }
如果你需要不在函数里的可翻译文本,有两个宏可以帮忙:QT_TR_NOOP()和QT_TRANSLATE_NOOP()。它们仅仅标示出文本,以便于被下面描述的lupdate工具提取。宏扩展为只是文本(没有上下文)。
QT_TR_NOOP()的例子:
QString FriendlyConversation::greeting( int greet_type ) { static const char* greeting_strings[] = { QT_TR_NOOP( "Hello" ), QT_TR_NOOP( "Goodbye" ) }; return tr( greeting_strings[greet_type] ); }
QT_TRANSLATE_NOOP()的例子:
static const char* greeting_strings[] = { QT_TRANSLATE_NOOP( "FriendlyConversation", "Hello" ), QT_TRANSLATE_NOOP( "FriendlyConversation", "Goodbye" ) }; QString FriendlyConversation::greeting( int greet_type ) { return tr( greeting_strings[greet_type] ); } global_greeting( int greet_type ) { return qApp->( "FriendlyConversation", greeting_strings[greet_type] ); }
如果你使用定义的宏QT_NO_CAST_ASCII编译你的软件,从而关闭了从const char*到的自动转换,你很可能会捕捉到你错过的字符串。更多信息参见()。关闭这个转换会使编程有点儿麻烦。
如果你的源码语言使用Latin-1之外的字符集,你会发现()比()更好用,因为tr()依赖于(),这使它比QObject::trUtf8()更脆弱。
加速键值,例如Ctrl+Q或者Alt+F,也需要翻译。如果你的应用给“Quit”直接编码(hardcode)为CTRL+Key_Q,翻译者就不能重载它了。正确的习惯用法是
*file = new ( this ); file->( tr("&Quit"), this, SLOT(quit()), QKeySequence(tr("Ctrl+Q", "File|Quit")) );
对于国际化的文本,在字符串中类似printf()风格的插入参数一般是不好的选择,因为有时候有必要在翻译时改变参数的顺序。不管怎样,QString::arg()函数为参数替换提供了一种简单的途径:
void FileCopier::showProgress( int done, int total, const & current_file ) { label.setText( tr("%1 of %2 files copied.\nCopying: %3") .arg(done) .arg(total) .arg(current_file) ); }
在应用中通篇使用tr()之后,你就可以开始创作程序中用户可见的文本的译本了。
手册提供了关于Qt翻译工具、Qt语言学家、lupdate和lrelease的进一步信息。
Qt应用的翻译过程分为三步:
典型地,你将对应用地每个发表版本重复这几步。lupdate工具会尽力重用以前的发表版本的译文。
在你运行lupdate之前,你应该准备一个项目文件。这是一个项目文件(.pro文件)的例子:
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时,你必须以命令行参数给出项目文件的名称。
在本例中,支持四种语言:Danish、Finnish、Norwegian和Swedish。如果你使用qmake(或者tmake),你一般不需要给lupdate的附加项目文件;只要你加上TRANSLATIONS条目,你的qmake项目文件就会正常工作。
在应用中,你必须使用()来装载对应用户语言的译文文件,再使用()来安装它们。
如果你一直使用以前的Qt工具(findtr、msg2qm和mergetr),可以使用qm2ts来转换你以前的.qm文件。
语言学家、lupdate和lrelease安装在$QTDIR/bin。在Qt语言学家中点击Help|Manual,就可访问用户手册,它包含了让你起步的演示教程。
虽然这些工具提供了生成.qm文件的方便途径,可任何能编写.qm文件的系统也都够用。你可以制做一个应用,以利用()把译文加入到中,接着再利用()写出一个.qm文件。用这种办法可以从任何你选择的源文件中产生译文。
Qt本身包含有大约400个也需要翻译为目标语言的字符串。在$QTDIR/translations下,你会找到French和German的译文文件,也可以作为翻译为其他语言的模板。
典型地,你的应用的main()函数会类似这样:
int main( int argc, char **argv ) { app( argc, argv ); // translation file for Qt qt( 0 ); qt.( QString( "qt_" ) + QTextCodec::locale(), "." ); app.( &qt ); // translation file for application strings myapp( 0 ); myapp.( QString( "myapp_" ) + QTextCodec::locale(), "." ); app.( &myapp ); ... return app.(); }
类和中的工具,方便你支持很多对于用户数据的输入输出编码。当应用启动时,机器的地区(locale)决定了处理8-bit数据——例如对于字体选择、文本显示、8-bit文本I/O和字符输入——所用的8-bit编码。
应用有时会需要不同于缺省本地8-bit编码的编码。例如,一个Cyrillic KOI8-R locale(俄罗斯的事实标准locale)的应用可能需要以ISO 8859-5编码输出Cyrillic。这样的代码可能会是:
string = ...; // some Unicode text * codec = QTextCodec::( "ISO 8859-5" ); encoded_string = codec->( string ); ...; // use encoded_string in 8-bit operations
对于把Unicode转换为本地8-bit编码,有一个快捷办法:的()方法返回的就是这样的8-bit数据。另一个有用的快捷办法是()方法,它以8-bit的UTF-8编码返回文本——有趣之处在于,如果Unicode完全是US-ASCII的话,它可以完全保留Unicode信息,而看起来又是一般的US-ASCII。
至于其他方式的转换,有()和()两个方便的函数,或者通用的代码,按下面从ISO 8859-5 Cyrillic到Unicode所演示:
encoded_string = ...; // Some ISO 8859-5 encoded text. * codec = QTextCodec::("ISO 8859-5"); string = codec->(encoded_string); ...; // Use string in all of Qt's QString operations.
理想状态下应该使用Unicode的I/O,因为这最大地提高了世界各地的用户之间的文档兼容性。可实际上,支持所有适当的你的用户为处理已存在的文档而会需要用到的编码,也是有用的。通常,Unicode(UTF16或者UTF8)最适于在任何人之间传递信息,然而在同一语言或者民族群体内部,一种本地标准一般更为合适。要支持的最重要的编码是由()所返回的那个,因为这是用户最可能需要用来与其他人和应用(这是local8Bit()所使用的编码器)通讯的一个。
考虑到大多数Unix系统对本地8-bit编码和Unicode之间的转换没有内建支持,可能有必要编写你自己的子类。视紧迫程度而定,可以联系Trolltech的技术支持或者询问qt-interest邮件列表以看看是否已经有别人已经致力于支持某种编码。一个有用的过渡办法是,可以使用()函数以构造一个数据驱动的编码器,虽然这种办法会有内存和速度上的恶化,尤其是带有动态装载库。关于编写自己的QTextCodec详情,参见QTextCodec主类的文档。
本地化是适应本地习惯比如日期时间表达方式的过程。这样的本地化可以使用适当的tr()字符串完成,即使是"magic" words,像这个有些做作的例子所示意的:
void Clock::setTime(const & t) { if ( tr("AMPM") == "AMPM" ) { // 12-hour clock } else { // 24-hour clock } }
图象本地化不推荐。请选择清晰的适用于任何地区的图标,而不要依赖于当地的双关语或者引申的暗喻。
支持Unicode的操作系统和窗口系统还处于开发初期。底层系统所能得到的支持程度会影响Qt在该平台上所提供的支持,但是以Qt编写的应用一般不必太关心实际限制。
Trolltech并没有那么多资源或者专门技术,可以在Qt里立即加入世界上所有语言的支持。所以我们很期待与有这些专门技术的人一起工作。在下几个次版本号中,我们希望能对你选择的语言加入支持,直到任何人都可以使用Qt和以Qt开发的所有程序,而不管他们使用什么语言。
单字节编码(European Latin-1和KOI8-R等)和多字节编码(East Asian EUC-JP等)的语言都已支持。对于那些“复杂”的编码——需要从右至左输入或者复杂字符组成的编码(例如Arabic、Hebrew和Thai script)——已经实现,但是Indic script的范畴(Hindi、Devanagari、Bengali等)还在开发中。现在的情况是:
编码 | 状态 |
---|---|
Windows上的所有编码 | 本地的编码总是支持。 |
ISO标准编码 ISO 8859-1、 ISO 8859-2、 ISO 8859-3、 ISO 8859-4、 ISO 8859-5、 ISO 8859-7、 ISO 8859-9和 ISO 8859-15 | 完全支持。 |
KOI8-R | 完全支持。 |
eucJP、JIS和ShiftJIS | 完全支持。在X11上对于XIM协议使用eucJP,在Japanese Windows NT上使用IME Windows NT。Serika Kurusugawa和其他人正在介入这个工作。是X11上测试过的输入法。 |
eucKR | 支持。Mizi Research正在介入这个工作。是测试过的输入法。 |
Big5 | Qt包含着一个由Ming Che-Chuang开发的Big5编解码器。正在xcin (2.5.x) XIM server上展开测试。 |
eucTW | 外部开发中。 |
关于Qt中对不同的writing system的支持,更多信息参见。
如果你有兴趣参与已有的成果,或是支持以上提到的之外的新编码,你的工作可以被考虑包括在Qt官方发布中,或者只是与你的应用打包在一起。
最后,我们希望能帮助Unix成为面向Unicode(Unicode-oriented),正如Windows正在做的那样。这就意味着,在字体服务器中使用新的进展而带来的更好的字体支持,例如、和x-tt;同时还有(一种Unicode编码)文件名,比如使用。
对于有的locale,很多Unix发布版只包括部分支持。例如,如果你有/usr/share/locale/ja_JP.EUC目录,这并不一定意味着你可以显示Japanese文本;你还需要JIS编码的字体(或者Unicode字体),以及/usr/share/locale/ja_JP.EUC目录,才能够达到目的。要达到最好的结果,使用你的系统提供商那里来的完全locale。
这些类同国际化Qt应用有关。
从和到EUC-JP字符集的转换 | |
从和到EUC-KR字符集的转换 | |
从和到Chinese GB18030/GBK/GB2312编码的转换 | |
从和到Chinese GBK编码的转换 | |
从和到visually ordered Hebrew的转换 | |
从和到JIS字符集的转换 | |
从和到Shift-JIS的转换 | |
文本编码之间的转换 | |
基于状态(State-based)的解码器 | |
基于状态的编码器 | |
文本输出的国际化支持 | |
Translator的信息及其属性 | |
从和到Tamil TSCII编码的转换 |