Qt-国际化(语言切换)

x33g5p2x  于2022-04-11 转载在 其他  
字(7.9k)|赞(0)|评价(0)|浏览(353)

在Qt中,所有的输入部件和文本绘制方式对Qt支持的所有语言都提供了内置的支持。Qt内置的字体引擎可以在同一时间正确而且精细地绘制不同的文本,这些文本可以包含来自众多不同书写系统的字符。如果想了解更多的相关知识,可以在帮助中通过Overview of the Translation Process关键字查看。

Qt对把应用程序翻译为本地语言提供了很好的支持,可以使用Qt Linguist工具完成应用程序的翻译工作,这个工具在第1章就已经介绍过了,这里将进一步介绍。

使用Qt Linguist翻译工具

这一小节先通过一个简单的例子介绍Qt中翻译应用程序的整个过程,然后再介绍其中需要注意的方面,这部分内容可以通过Qt Linguist Manual关键字查看。在Qt中编写代码时要对需要显示的字符串调用tr()函数,完成代码编写后对这个应用程序的翻译主要包含3步:

①运行lupdate工具,从C++源代码中提取要翻译的文本,这时会生成一个.ts文件,这个文件是XML格式的;

②在Qt Linguist 中打开.ts文件,并完成翻译工作;

③运行lrelease工具,从.ts文件中获得.qm文件,它是一个二进制文件。这里的.ts文件是供翻译人员使用的,而程序运行时只需要使用.qm文件,这两个文件都是与平台无关的。

下面通过一个简单的例子来介绍整个翻译过程,该例子实现了将一个英文版本的应用程序翻译为简体中文版本。

  1. 第一步,编写源码。新建Qt Widgets应用,项目名称为myI18N,类名为MainWindow ,基类保持QMainWindow不变。建立完项目后,单击mainwindow.ui文件进入设计模式,先添加一个“&File”菜单,再为其添加一个“&New”子菜单并设置快捷键为Ctrl+N,然后往界面上拖入一个Push Button。

下面再使用代码添加几个标签,打开mainwindow.cpp文件,添加头文件#include < QLabel>,然后在构造函数中添加代码:

QLabel *label = new QLabel(this);
    label->setText(tr("hello Qt!"));
    label->move(100,50);

    QLabel *label2 = new QLabel(this);
    label2->setText(tr("password", "mainwindow"));
    label2->move(100,80);

    QLabel *label3 = new QLabel(this);
    int id = 123;
    QString name = "yafei";
    label3->setText(tr("ID is %1,Name is %2").arg(id).arg(name));
    label3->resize(150, 12);
    label3->move(100, 120);

这里向界面上添加了3个标签,因为这3个标签中的内容都是用户可见的,所以要调用tr()函数。在label2中调用tr()函数时还使用了第二个参数,其实, tr()函数共有3个参数,它的原型如下:

QString Q0bject::tr(const char* sourceText,const char *disambiguation= Q_NULILPTR,int n =-1)[static]

第一个参数 sourceText就是要显示的字符串, tr()函数会返回sourceText 的译文。

第二个参数 disambiguation是消除歧义字符串,比如这里的password,如果一个程序中需要输入多个不同的密码,那么在没有上下文的情况下就很难确定这个password到底指哪个密码。这个参数一般使用类名或者部件名,比如这里使用了mainwindow,就说明这个password是在 mainwindow上的。

第三个参数n表明是否使用了复数,因为英文单词中复数一般要在单词末尾加“s”,比如“1 message”,复数时为“2messages”。遇到这种情况,就可以使用这个参数,它可以根据数值来判断是否需要添加“s”,例如:

int n = messages.count();
showMessage(tr("%n message(s) saved","",n));

tr()函数3个参数更多的用法介绍可以在帮助中通过 Writing Source CodeTranslation关键字查看。

  1. 第二步:更改项目文件。要在项目文件中指定生成的.ts文件,每一种翻译语言对应一个. ts文件。

打开myl18N.pro 文件,在最后面添加如下一行代码;

TRANSLATIONS = myI18N_zh_CN.ts

这就表明生成的.ts文件的文件名是以myI18N_zh_CN.ts
可以随便写,这里的_zh_CN是为了表示简体中文
最后crts+s保存

3.第三步,使用lupdate生成.ts文件。当要进行翻译工作时,先要使用lupdate工具来提取源代码中的翻译文本,生成. ts文件。

选择“工具→外部→Qt语言家→更新翻译(lupdate)”菜单项

从概要信息输出栏中可以看到,更新了myll8N_zh_CN.ts文件,发现了8个源文本,其中有8条新的翻译和0条已经存在的翻译。

这表明可以对程序代码进行更改,然后多次运行lupdate,而只需要翻译新添加的内容。

可以在项目目录中使用写字板打开这个.ts文件,可以看到它是XML格式的,其中记录了字符串的位置和是否已经被翻译等信息。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="zh_CN">
<context>
    <name>MainWindow</name>
    <message>
        <location filename="mainwindow.ui" line="14"/>
        <source>MainWindow</source>
        <translation>应用程序主窗口</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="27"/>
        <source>PushButton</source>
        <translation>按钮</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="42"/>
        <source>&amp;File</source>
        <translation>文件(&amp;F)</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="59"/>
        <source>&amp;New</source>
        <translation>新建(&amp;N)</translation>
    </message>
    <message>
        <location filename="mainwindow.ui" line="62"/>
        <source>Ctrl+N</source>
        <translation>Ctrl+N</translation>
    </message>
    <message>
        <location filename="mainwindow.cpp" line="12"/>
        <source>hello Qt!</source>
        <translation>你好 Qt!</translation>
    </message>
    <message>
        <location filename="mainwindow.cpp" line="16"/>
        <source>password</source>
        <comment>mainwindow</comment>
        <translation>密码</translation>
    </message>
    <message>
        <location filename="mainwindow.cpp" line="22"/>
        <source>ID is %1,Name is %2</source>
        <translation>账号是%1,名字是%2</translation>
    </message>
</context>
</TS>
  1. 第四步,使用Qt Linguist完成翻译。这一步一般是翻译人员来做的,就是在QtLinguist中打开.ts文件,然后对字符串逐个翻译。

在系统的开始菜单(Qt 5.6.0分类下)启动Linguist(打开Linguist的方法),然后单击界面左上角的打开图标(快捷键Ctrl+O),在弹出的文件对话框中进入项目目录,打开 myIl8N_ zh_CN文件,这时整个界面如图所示。QtLinguist窗口主要由以下几部分组成:

  1. 菜单栏和工具栏

  1. 上下文窗口

  1. 短语和表单

  1. 翻译区域

  2. 短语和猜测

  3. 警告窗口

下面来翻译程序。在翻译区域可以看到现在已经是要翻译成汉语,这是因为. ts文件名中包含了中文的区域代码。
如果这里没有正确显示要翻译成的语言,那么可以使用“编辑→翻译文件设置”菜单项来更改。

下面首先对 Main Window进行翻译,在汉语译文处翻译为“应用程序主窗口”,然后按下Ctrl+Return(即回车键)完成翻译并开始翻译第二个字符串。

按照这种方法完成所有字符串的翻译工作,如表所列,其中的一些翻译问题放到下一节再讲。

翻译完成后按下Ctrl+S保存更改。这里对Qt Linguist只是进行了简单的介绍,详细内容可以在帮助中通过Qt Linguist Manual:Translators关键字查看。

  1. 第五步,使用 Irelease生成.qm文件。可以在Qt Linguist 中使用“文件→发布”和“文件→另外发布为” 两个菜单项来生成当前已打开的.ts文件对应的.qm文件,文件会生成在.ts所在目录下。

还可以通过Qt Creator的“工具→外部→Qt语言家→发布翻译(lrelease)”菜单项来完成。

  1. 第六步,使用.qm文件。下面在项目中添加代码并使用.qm文件来更改界面的语言。
    进人 main.cpp文件,添加头文件#include < QTranslator>,然后在“QApplica-tion a(argc,argv)”;代码下添加如下代码:
QTranslator translator;
    translator.load("../myI18N/myI18N_zh_CN.qm");
    a.installTranslator(&translator);

…表示当前项目工程目录,使用了相对路径
为QApplication a对象使用了翻译

注意,这几行代码一定要放到创建部件的代码之前

比如这里放到了“Main Window;”一行代码之前

这样才能对该部件进行翻译。另外,有时可能因为部件的大小问题使得翻译后的文本无法完全显示,较好地解决方法就是使用布局管理器。

现在可以运行程序查看效果。

项目程序代码:代码我就不贴了
项目

程序翻译中的问题

1 对所有用户可见的文本使用QString

因为QString内部使用了Unicode编码,所以世界上所有的语言都可以使用熟悉的文本处理操作来进行处理。而且,因为所有的Qt函数都使用QString 作为参数来向用户呈现文本内容,所以没有char *到QString的转换开销。

2 对所有字符串文本使用tr()函数

无论什么时候使用要呈现给用户的文本,都要使用tr()函数进行处理

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

如果引用的文本没有在QObject子类的成员函数中,那么可以使用一个合适的类的tr函数,或者直接使用QCoreApplication::translate()函数。

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

如果要在不同的函数中使用要翻译的文本,那么可以使用QT_TR_NOOP()宏和QT_TRANSLATE_NOOP()宏,它们仅仅对该文本进行标记来方便lupdate工具提取。

使用QT_TR_NOOP()的例子:

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

使用QT_TRANSLATE_NOOP()的例子:

static const char * greeting_strings[]=
{
QT_TRANSLATE_NOOP("FriendlyConversation" ,"Hell1o"),
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]);
}

3 对加速键的值使用QKeySequence()函数

类似于Ctrl+Q或者Alt+F等加速键的值也需要被翻译。如果使用了硬编码的Qt::CTRL+Qt::Key_Q作为退出操作的快捷键,那么翻译将无法覆盖它。正确的习惯用法为:

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

4 对动态文本使用QString::arg()函数

对于字符串中使用arg()函数添加的变量,其中的%1、%2等参数的顺序在翻译时可以改变,它们对应的值不会改变。

5 支持编码

QTextCodec类以及QTextStream使得Qt可以很容易地支持大量用户数据的输入和输出编码。当一个应用程序启动时,机器的语言环境便会决定处理8位数据(例如,字体选择、文本显示,8位文本I/O和字符输入等)时使用的8位编码。
应用程序有时也需要使用默认的本地8位编码以外的编码,例如,使用ISO 8859 -5编码,代码如下:

QString string=.....; //一些Unicode文本

//换编码格式
QTextCodec *codec=QTextCodec::codecForName("ISO 8859-5");
QByteArray encodedString=codec->fromUnicode(string);

如果要将Unicode转换为本地8位编码,那么可以使用QString::toLocal8Bit()函数;

还有一个QString :: toUtf8()函数可以返回使用8位UTF-8编码的文本。

要将其他编码转换为Unicode编码,那么可以使用QTextCodec类的 toUnicode()函数,还有QString : : fromUtf8()和QString : : fromLocal8Bit()等。
使用QTextCodec::codecForLocale()返回的编码是最重要的一个编码,因为这个是用户与他人或者其他应用程序进行通信最有可能使用的编码。

6.翻译非QT类

如果要使一个类中的字符串支持国际化,那么该类或者继承自QObject类或者使用Q_OBJECT宏。而对于非Qt类,如果要支持翻译,需要在类定义的开始使用Q_DECLARE_TR_FUNCTIONS()宏,例如:

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

这样就可以在该类中使用tr函数了

7 自动判断语言环境

如果在一个程序中提供了多种语言选择,那么最好的方法就是在程序启动时判断本地的语言环境,然后加载对应的.qm文件。

可以使用QLocale::system().name()来获取本地的语言环境,它会返回QString类型的“语言_国家”格式的字符串,其中的语言用两个小写字母表示,符合ISO 639编码;国家使用两个大写字母表示,符合ISO3166国家编码。例如,中国简体中文的表示为“zh_CN”.

可以使用这个返回值来调用不同的文件,使应用程序自动使用相应的语言。

其他

国际化中还有本地化,在应用程序运行时动态进行语言更改等内容,这里就不再介绍,感兴趣的读者可以在帮助中通过Internationalization关键字参考。

相关文章