Когда мы вызываем 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);
Проблема состоит в том, что утилита lupdate не сможет извлечь строковую константу «OpenDrawer 2D», поскольку она не входит в вызов функции tr. Это означает, что переводчик не будет иметь возможность перевести эту строку. Эта проблема часто возникает и при построении динамических строк:
// НЕПРАВИЛЬНО
statusBar->showMessage(tr("Host " + hostName + " found"));
Здесь значение строки, которую мы передаем функции tr, меняется в зависимости от значения hostName, и поэтому мы не можем ожидать, что перевод функцией tr будет выполнен правильно.
Решение заключается в применении функции QString::arg:
statusBar->showMessage(tr("Host %1 found").arg(hostName));
Обратите внимание на то, как это работает: строковый литерал «Host %1 found» (хост %1 найден) передается функции tr. Если загружен файл перевода на французский язык, tr возвратит что-то подобное «Нфtе %1 trouvй». Параметр «%1» замещается на содержимое переменной hostName.
Хотя в целом не рекомендуется вызывать tr для переменной, это может сработать. Мы должны использовать макрос QT_TR_NOOP для пометки тех строковых литералов, перевод которых должен быть выполнен до их присваивания переменной. Это лучше всего делать для статических массивов строк. Например:
01 void OrderForm::init
02 {
03 static const char * const flowers[] = {
04 QT_TR_NOOP("Medium Stem Pink Roses"),
05 QT_TR_NOOP("One Dozen Boxed Roses"),
06 QT_TR_NOOP("Calypso Orchid"),
07 QT_TR_NOOP("Dried Red Rose Bouquet"),
08 QT_TR_NOOP("Mixed Peonies Bouquet"),
09 0
10 };
11 for (int i = 0; flowers[i]; ++i)
12 comboBox->addItem(tr(flowers[i]));
13 }
Макрос QT_TR_NOOP просто возвращает свой аргумент. Но утилита lupdate обнаружит все строки, заданные в виде аргумента макроса QT_TR_NOOP, и поэтому они смогут быть переведены. При использовании позже этой переменной мы вызываем, как обычно, tr для выполнения перевода. Несмотря на передачу функции tr переменной, перевод все-таки будет выполнен.
Существует также макрос QT_TRANSLATE_NOOP, который работает подобно макросу QT_TR_NOOP, но для него, кроме того, задается контекст. Этот макрос удобно использовать для инициализации переменных вне класса:
static const char * const flowers[] = {
QT_TRANSLATE_NOOP("OrderForm", "Medium Stem Pink Roses"),
QT_TRANSLATE_NOOP("OrderForm", "One Dozen Boxed Roses"),
QT_TRANSLATE_NOOP("OrderForm", "Calypso Orchid"),