KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Жасмин Бланшет - QT 4: программирование GUI на С++

Жасмин Бланшет - QT 4: программирование GUI на С++

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Жасмин Бланшет, "QT 4: программирование GUI на С++" бесплатно, без регистрации.
Перейти на страницу:

В общем виде вызов 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);

Проблема состоит в том, что утилита 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"),

QT_TRANSLATE_NOOP("OrderForm", "Dried Red Rose Bouquet"),

QT_TRANSLATE_NOOP("OrderForm", "Mixed Peonies Bouquet"),

0

};

Здесь аргумент контекста должен совпадать с контекстом при будущем вызове функции tr() или translate().

Когда мы начинаем использовать в приложении функцию tr(), легко можно забыть в каких-то случаях о необходимости задавать видимые пользователем строки через вызов функции tr() (особенно если это делается впервые). Эти пропущенные строки фактически могут быть обнаружены переводчиком или, еще хуже, пользователями переведенного приложения, когда некоторые строки будут отображаться с применением первоначального языка. Чтобы не допустить этого, мы можем указать Qt на необходимость запрета неявных преобразований с типа const char * на тип QString. Это делается путем определения препроцессорного символа QT_NO_CAST_FROM_ASCII перед включением любого заголовочного файла Qt. Наиболее простой способ обеспечения установки этого символа состоит в добавлении следующей строки в файл .pro:

DEFINES += QT_NO_CAST_FROM_ASCII

Это заставит нас каждый строковый литерал использовать через вызов tr() или QLatin1String() в зависимости от того, надо ли его переводить или нет. Строки, которые не будут заданы именно таким образом, приведут к выводу сообщения об ошибке компилятора и заставят нас восполнить пропущенные вызовы функций tr() или QLatin1String().

После заключения всех видимых пользователем строк в вызовы функций tr() для обеспечения перевода нам остается только загрузить файл перевода. Обычно мы это делаем в функции приложения main(). Например, ниже показано, как можно попытаться загрузить файл перевода, который зависит от пользовательской локализации приложения:

01 int main(int argc, char *argv[])

02 {

03 QApplication app(argc, argv);

04 QTranslator appTranslator;

05 appTranslator.load("myapp_" + QLocale::system().name(),

06 qApp->applicationDirPath());

07 app.installTranslator(&appTranslator);

08 …

09 return app.exec();

10 }

Функция QLocale::system() возвращает объект QLocale, который содержит информацию о пользовательской локализации. Обычно имя локализации является частью имени файла .qm. Локализации можно задавать более или менее точно; например, fr задает европейский французский язык, fr_CA задает канадский французский язык, a fr_CA.ISO8859-15 задает канадский французский язык с использованием кодировки ISO 8859-15 (которая поддерживает символы «^», «КЬ», «№» и «Ы» — в исходном бумажном издании французский куда-то подевался %) ).

Если локализацией является fr_CA.ISO8859-15, функция QTranslator::load() сначала попытается загрузить файл myapp_fr_CA.ISO8859-15.qm. Если этого файла нет, функция load() на следующем шаге попытается загрузить файл myapp_fr_CA.qm, затем myapp_fr.qm и, наконец, myapp.qm, и это будет последней попыткой. В обычных случаях нам необходимо предоставить только файл myapp_fr.qm, содержащий перевод на стандартный французский язык, но если нам нужен другой файл перевода для говорящих на французском в Канаде, мы можем также обеспечить файл myapp_fr_CA.qm, и он будет использован для локализации fr_CA.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*