< ?xml version="1.0" encoding="UTF-8"?>
< !DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" "http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd">
Qt4.7.0文档翻译:写下能翻译的代码,Writing Source Code for Translation
基础
开发者使用tr()函数来为他她们的类获取翻译后的文字,这些文字一般用于显示。这个函数也用来指示程序中的哪些文字串可以被翻译。
Qt使用与可翻译的字符串相关联的翻译上下文来对每个可翻译的字符串进行索引;这通常是使用那个字符串的QObject子类的名字。
在每个新的基于QObject的类的定义中,使用Q_OBJECT宏来定义翻译上下文。
当tr()被调用时,它使用一个QTranslator对象来查找可翻译的字符串。要让翻译起作用,必须用下面的启用翻译小节中描述的方法来将一个或者多个QTranslator对象安装到程序对象中。
定义一个翻译上下文
QObject和每个QObject子类的翻译上下文都是类名本身。子类化QObject的开发者必须在他她们的类定义中使用Q_OBJECT宏来覆盖翻译上下文。这个宏将翻译上下文设置成那个子类的名字。
例如,下面的类定义中包含了Q_OBJECT宏,这样就实现了一个使用MainWindow上下文的新的tr():
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
…
如果在类定义中没有使用Q_OBJECT,那么就会从基类继承上下文。例如,由于Qt 中所有基于QObject的类都提供一个上下文,所以一个没有使用Q_OBJECT宏的QWidget子类在它的tr()函数被调用时会使用QWidget上下文。
使用tr()来获取一个翻译
下面的示例展示了如何为前一节里提到的类获取一个翻译:
void MainWindow::createMenus()
{
fileMenu = menuBar()->addMenu(tr(“&File”));
…
在这里,翻译上下文是MainWindow,因为被调用的函数是MainWindow::tr()。tr()函数返回的文字是从MainWindow上下文里获取的对于”&File”的翻译。
当使用Qt 的翻译工具lupdate来处理一组源文件时,包含在tr()调用里的文字就被储存在翻译文件中对应于它的翻译上下文的区域中。
在某些情况下,通过完整地指定对tr()的调用来显式地指定一个翻译上下文是很有用的;例如:
QString text = QScrollBar::tr(“Page up”);
这个调用从QScrollBar上下文中获取对”Page up”的翻译文字。开发者还可以使用QCoreApplication::translate()函数来获取特定翻译上下文中的翻译。
翻译者注释
开发者可以包含关于每个可翻译的字符串的信息,以帮助翻译者进行翻译。当lupdate处理源文件时,会提取这些信息。建议以这样的形式来在你的代码中对tr()调用进行注释:
//: …
或者
/*: … */
例如:
//: This name refers to a host name.
hostNameLabel->setText(tr(“Name:”));
/*: This text refers to a C++ code example. */
QString example = tr(“Example”);
在这些示例中,注释会在每次调用的上下文中传递给的字符串关联起来。
向字符串中添加元数据
可以向每个可翻译的消息里附上附加数据。当lupdate处理源文件时,会提取这些数据。建议用以下的形式来对你的代码中的tr()调用进行注释,以加入元数据:
//= <标识符>
这个可以用来赋予这条消息一个唯一的标识符,以支持那些需要它的工具。
另一种添加元数据的方法是使用下面的语法:
//~ <字段名> <字段内容>
这个可以用来将元数据附加到消息中。字段名应当包含:一个域前缀(可能是这个字段对应的文件格式的常用文件扩展名)、一个连字号和一个由下划线分隔的实际字段名。在TS文件中存储时,字段名加上前缀”extra-”组成一个XML 元素名字。字段内容会按照XML规则进行转义处理,否则将会按照原文的形式在元素的内容中出现。每个消息中都可以添加任意数量的唯一字段。
示例:
//: This is a comment for the translator.
//= qtn_foo_bar
//~ loc-layout_id foo_dialog
//~ loc-blank False
//~ magic-stuff This might mean something magic.
QString text = MyMagicClass::tr(“Sim sala bim.”);
在magic 翻译者注释之前出现的元数据将对整个TS 文件起作用。
消除歧义
如果在相同的翻译上下文里将相同的可翻译字符串应用到不同的角色,那么可以将一个附加的标识字符串传递给tr()。这个可选的消歧参数会用来区分在其它属性都相同的字符串。
示例:
MyWindow::MyWindow()
{
QLabel *senderLabel = new QLabel(tr(“Name:”));
QLabel *recipientLabel = new QLabel(tr(“Name:”, “recipient”));
…
在Qt 4.4 及更早的版本里,这个消歧参数是首选的向翻译者提供注释的方式。
字符编码
你可以通过调用QTextCodec::setCodecForTr()来为源代码文字设置编码。默认情况下,将假设源代码文字是Latin-1 编码的。
处理复数
某些可翻译的字符串包含整数的占位符,并且需要依据实际使用的值进行不同的翻译。
为了帮助解决这个问题,开发者将一个附加的整数参数传递给tr()函数,并且典型地在每个可翻译的字符串里为复数使用一个特殊的标记。
如果这个参数是大于等于0的,那么在结果字符串中出现的所有的%n会被指定的值的十进制表示所替换。另外,所使用的翻译会根据每种语言的规则来按照实际值进行适配。
示例:
int n = messages.count();
showMessage(tr(“%n message(s) saved”, “”, n));
下面的表格显示了,依据实际的翻译,将会返回什么字符串:
|
|
实际翻译 |
||
|
n |
未翻译 |
法语 |
英语 |
|
0 |
“0 message(s) saved” |
“0 message sauvegardé” |
“0 messages saved” |
|
1 |
“1 message(s) saved” |
“1 message sauvegardé” |
“1 message saved” |
|
2 |
“2 message(s) saved” |
“2 messages sauvegardés“ |
“2 messages saved” |
|
37 |
“37 message(s) saved” |
“37 messages sauvegardés“ |
“37 messages saved” |
这个方法比传统实现方式更灵活;例如,
n == 1 ? tr(“%n message saved”) : tr(“%n messages saved”)
因为它也适合那些有多种复数形式(e.g., Irish has a special “dual” form that should be used when nis 2)的目标语言,并且在 n == 0 时对于像法语那样要求是单数形式的语言也能正确处理。查看Qt Linguist 手册以了解细节。
除了%n之外,你可以使用%Ln来为n产生一个本地化的表示。转换过程使用由QLocale::setDefault()设置的默认地域信息。(如果没有指定默认地域信息,就会使用”C”地域信息。)
可以在复数翻译规则文档中找到对于包含复数的字符串的翻译规则列表。
启用翻译
典型地,你的程序的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 的翻译。开发者在他她的程序中应当在运行时通过向这个函数传递QLibraryInfo::TranslationsPath来获取翻译所在的路径,而不是使用QTDIR环境变量。