Если мы хотим иметь многоязыковую версию нашего приложения, мы должны сделать две вещи:
• убедиться, что все строки, которые видит пользователь, проходят через функцию tr();
• загрузить файл перевода (.qm) при запуске приложения.
Ничего подобного не надо делать, если приложения никогда не будут переводиться на другой язык. Однако применение функции tr() почти не требует дополнительных усилий и оставляет дверь открытой для их перевода когда-нибудь в будущем.
Функция tr() является статической функцией, определенной в классе QObject и переопределяемой в каждом подклассе, в котором встречается макрос Q_OBJECT. При ее использовании в рамках подкласса QObject мы можем вызывать tr() без ограничений. Вызов tr() возвращает перевод строки, если он имеется, и первоначальный текст в противном случае.
Для подготовки файлов переводов мы должны запустить утилиту Qt lupdate. Эта утилита собирает все строковые константы, которые встречаются в вызовах tr(), и формирует файлы переводов, содержащие все эти подготовленные к переводу строки. Эти файлы могут затем быть переданы переводчику для добавления к ним перевода строк. Эта процедура рассматривается позже в данной главе в разделе «Перевод приложений».
В общем виде вызов tr() имеет следующий синтаксис:
Контекст::tr(исходныйТекст, комментарий)
Здесь Контекст — имя подкласса QObject, в котором используется макрос Q_OBJECT. Нам не требуется его указывать, если мы вызываем tr() в функции—члене рассматриваемого класса. Аргумент исходныйТекст — текстовая константа, которую нужно будет переводить. Аргумент комментарий является необязательным, и он может использоваться для предоставления переводчику дополнительной информации.
Ниже приводится несколько примеров:
01 RockyWidget::RockyWidget(QWidget *parent)
02 : QWidget(parent)
03 {
04 QString str1 = tr("Letter");
05 QString str2 = RockyWidget::tr("Letter");
06 QString str3 = SnazzyDialog::tr("Letter");
07 QString str4 = SnazzyDialog::tr("Letter", "US paper size");
08 }
Первые два вызова tr() выполняются в контексте объекта RockyWidget (скалистый виджет), а вторые два — в контексте объекта SnazzyDialog (притягательное диалоговое окно). В качестве исходного текста во всех четырех случаях используется слово «Letter» (буква). Последний вызов имеет также комментарий, помогающий переводчику точнее понять смысл исходного текста.
Строки в различных контекстах (классах) переводятся независимо друг от друга. Переводчики, как правило, одновременно работают только с одним контекстом, причем часто при этом работает приложение и на экране отображается виджет или диалоговое окно, которые необходимо перевести.
Когда мы вызываем tr() из глобальной функции, мы должны явно указать контекст. Любой подкласс QObject может использоваться в приложении в качестве контекста. Если такого подкласса нет, мы всегда можем использовать сам класс QObject. Например:
01 int main(int argc, char *argv[])
02 {
03 QApplication app(argc, argv);
04 QPushButton button(QObject::tr("Hello Qt!"));
05 button.show();
06 return app.exec();
07 }
До сих пор во всех примерах контекст задавался именем класса. Это удобно, поскольку мы почти всегда можем опустить его, но на самом деле это не так. Наиболее общий способ перевода строки в Qt заключается в использовании функции QApplication::translate(), которая принимает три аргумента: контекст, исходный текст и необязательный комментарий. Например, ниже приводится другой способ перевода «Hello Qt!»:
QApplication::translate("Global Stuff", "Hello Qt!");
На этот раз мы поместили текст в контекст «Global Stuff» (глобальное вещество — ну нихрена себе перевод :) ).
Функции tr() и translate() играют двоякую роль: они являются маркерами, которые утилита lupdate использует для поиска видимых пользователем строк, и одновременно они являются функциями С++, которые переводят текст. Это отражается на том, как следует записывать программный код. Например, следующий программный код не сработает:
// НЕПРАВИЛЬНО
const char *appName = "OpenDrawer 2D";
QString translated = tr(appName);