Spec-Zone.ru › Qt

Написание исходного кода для перевода

Написание кроссплатформенного международного программного обеспечения с Qt — это плавный, поэтапный процесс. Ваше программное обеспечение можно локализовать на этапах, описанных в следующих разделах. Для получения дополнительной информации о локализации приложения Qt Quick, см. Локализация и интернационализация с Qt Quick.

Использование QString для всего текстового контента, отображаемого пользователю

Поскольку QString использует кодировку Unicode внутри, все языки мира могут обрабатываться прозрачно с использованием знакомых операций обработки текста. Кроме того, поскольку все функции Qt, которые отображают текст пользователю, принимают QString в качестве параметра, нет char * преобразования QString.

Строки, которые находятся в "пространстве программиста" (такие как имена QObject и тексты форматов файлов), не должны использовать QString; подойдёт традиционная char * или класс QByteArray.

Вы вряд ли заметите, что используете Unicode; QString и QChar — это просто более удобные версии грубых const char * и char из традиционного C.

char * строки в исходном коде предполагаются закодированными в UTF-8, когда неявно преобразуются в QString. Если ваш строковый литерал C использует другую кодировку, используйте QString::fromLatin1() или QTextCodec для преобразования литерала в закодированную Unicode QString.

Использование tr() для всего текстового контента

В любом месте вашей программы, где используется строковый литерал (текст в кавычках), который будет отображаться пользователю, убедитесь, что он обрабатывается функцией QCoreApplication::translate(). Для достижения этой цели достаточно использовать функцию tr() для получения переведённого текста для ваших классов, обычно для целей отображения. Эта функция также используется для указания тех строковых констант в приложении, которые подлежат переводу.

Например, предположим, что LoginWidget является подклассом QWidget:

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

Это учитывает 99% пользовательских строк, которые вы, скорее всего, напишете.

Если текст в кавычках не находится в методе члена подкласса QObject, используйте либо функцию tr() соответствующего класса, либо функцию QCoreApplication::translate() напрямую:

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

void same_global_function(LoginWidget *logwid)
{
    QLabel *label = new QLabel(
                QCoreApplication::translate("LoginWidget", "Password:"), logwid);
}

Qt индексирует каждую переводимую строку по контексту перевода, с которым она связана; это обычно имя подкласса QObject.

Контексты перевода определяются для новых классов, основанных на QObject, с помощью макроса Q_OBJECT в каждом новом определении класса.

Когда вызывается tr(), она ищет переводимую строку с помощью объекта QTranslator. Для работы перевода один или несколько таких объектов должны быть установлены в объекте приложения, как описано в Разделе по включению перевода.

Перевод строк в QML происходит точно так же, как и в C++, с единственным отличием: необходимо вызвать qsTr() вместо tr(). См. также страницу Локализация и интернационализация с Qt Quick.

Определение контекста перевода

Контекст перевода для QObject и каждого подкласса QObject — это само имя класса. Разработчики, создающие подклассы QObject, должны использовать макрос Q_OBJECT в определении своего класса, чтобы переопределить контекст перевода. Этот макрос устанавливает контекст в имя подкласса.

Например, следующее определение класса включает макрос Q_OBJECT, реализуя новую функцию tr(), которая использует контекст MainWindow.

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow();
    ...

Если Q_OBJECT не используется в определении класса, контекст наследуется от базового класса. Например, поскольку все классы Qt, основанные на QObject, предоставляют контекст, новый подкласс QWidget, определённый без макроса Q_OBJECT, будет использовать контекст QWidget при вызове его функции tr().

Использование tr() для получения перевода

Следующий пример демонстрирует, как получить перевод для класса, показанного в предыдущем разделе:

void MainWindow::createMenus()
{
    fileMenu = menuBar()->addMenu(tr("&File"));
    ...

Здесь контекст перевода — MainWindow, потому что вызвана функция MainWindow::tr(). Возвращаемый функцией tr() текст — это перевод "&Файл", полученный из контекста MainWindow.

При использовании инструмента перевода Qt, lupdate, для обработки набора исходных файлов, текст, заключённый в вызовы tr(), хранится в разделе файла перевода, соответствующем его контексту перевода.

В некоторых ситуациях полезно явно указать контекст перевода, полностью квалифицируя вызов tr(); например:

QString text = QScrollBar::tr("Page up");

Этот вызов получает переведённый текст "Перейти на предыдущую страницу" из контекста QScrollBar. Разработчики также могут использовать функцию QCoreApplication::translate() для получения перевода для определённого контекста перевода.

Использование tr() для локализации чисел

Вы можете локализовать числа, используя соответствующие строки tr():

void Clock::setTime(const QTime &time)
{
    if (tr("AMPM") == "AMPM") {
        // 12-hour clock
    } else {
        // 24-hour clock
    }
}

В примере для США мы оставим перевод "AMPM" как есть и тем самым будем использовать 12-часовой формат времени; но в Европе мы переведём его на что-то другое, чтобы код использовал 24-часовой формат времени.

Перевод классов, не являющихся классами Qt

Иногда необходимо предоставить поддержку интернационализации для строк, используемых в классах, которые не наследуют QObject или не используют макрос Q_OBJECT для включения функций перевода. Поскольку Qt переводит строки во время выполнения на основе класса, к которому они относятся, и lupdate ищет переводимые строки в исходном коде, классы, не являющиеся классами Qt, должны использовать механизмы, которые также предоставляют эту информацию.

Один из способов сделать это — добавить поддержку перевода в класс, не являющийся классом Qt, с помощью макроса Q_DECLARE_TR_FUNCTIONS(); например:

class MyClass
{
    Q_DECLARE_TR_FUNCTIONS(MyClass)

public:
    MyClass();
    ...
};

Это предоставляет классу функции tr(), которые могут использоваться для перевода строк, связанных с классом, и позволяет lupdate найти переводимые строки в исходном коде.

В качестве альтернативы, функцию QCoreApplication::translate() можно вызвать со специфическим контекстом, и это будет распознано lupdate и Qt Linguist.

Комментарии для переводчиков

Разработчики могут включать информацию о каждой переводимой строке, чтобы помочь переводчикам в процессе перевода. Эти данные извлекаются при использовании 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");

В этих примерах комментарии будут связаны со строками, переданными в tr() в контексте каждого вызова.

Добавление метаданных к строкам

Дополнительные данные могут быть прикреплены к каждому переводимому сообщению. Они извлекаются при использовании lupdate для обработки исходных файлов. Рекомендуемый способ добавления метаданных — добавление комментариев к вызовам tr() в вашем коде в виде:

//= <id>

Это может использоваться для присвоения сообщению уникального идентификатора для поддержки инструментов, которым он необходим.

Альтернативный способ прикрепления метаданных — использование следующего синтаксиса:

//~ <field name> <field contents>

Это позволяет прикрепить метаданные к сообщению. Имя поля должно состоять из префикса домена (возможно, условного расширения файла формата файла, вдохновлённого полем), дефиса и фактического имени поля в обозначении с нижним подчеркиванием. Для хранения в файлах 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.");

Вы можете использовать ключевое слово TRANSLATOR для комментариев переводчика. Метаданные, появляющиеся непосредственно перед ключевым словом TRANSLATOR, применяются ко всему файлу TS.

Разъяснение неоднозначности

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

Пример:

MyWindow::MyWindow()
{
    QLabel *senderLabel = new QLabel(tr("Name:"));
    QLabel *recipientLabel = new QLabel(tr("Name:", "recipient"));
    ...

В Qt 4.4 и более ранних версиях этот параметр разъяснения неоднозначности был предпочтительным способом указания комментариев для переводчиков.

Обработка множественного числа

Некоторые переводимые строки содержат заполнитель для целых чисел и должны переводиться по-разному в зависимости от используемых значений.

Для решения этой проблемы разработчики передают дополнительный целочисленный аргумент функции tr() и обычно используют специальную запись для множественного числа в каждой переводимой строке.

Если этот аргумент равен или больше нуля, все вхождения %n в результирующей строке заменяются десятичной записью переданного значения. Кроме того, используемый перевод будет адаптироваться к значению в соответствии с правилами каждого языка.

Пример:

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

Таблица ниже показывает, какая строка возвращается в зависимости от активного перевода:

Активный перевод
n Без перевода Французский Английский
0 "Сохранено 0 сообщений" "Сохранено 0 сообщение" "Сохранено 0 сообщений"
1 "Сохранено 1 сообщение" "Сохранено 1 сообщение" "Сохранено 1 сообщение"
2 "Сохранено 2 сообщения" "Сохранено 2 сообщения" "Сохранено 2 сообщения"
37 "Сохранено 37 сообщений" "Сохранено 37 сообщений" "Сохранено 37 сообщений"

Этот метод более гибкий, чем традиционный подход; например,

n == 1 ? tr("%n message saved") : tr("%n messages saved")

потому что он также работает с целевыми языками, имеющими несколько форм множественного числа (например, ирландский имеет особую форму «двойственного» числа, которая должна использоваться, когда n равно 2), и он правильно обрабатывает случай n == 0 для языков, таких как французский, которые требуют единственного числа.

Для обработки форм множественного числа на родном языке вам также необходимо загрузить файл перевода для этого языка. Утилита lupdate имеет параметр командной строки -pluralonly, который позволяет создавать файлы TS, содержащие только записи с формами множественного числа.

Дополнительные сведения об этом вопросе см. в статье Qt Quarterly Формы множественного числа в переводах.

Вместо %n, вы можете использовать %Ln, чтобы получить локализованное представление n. Преобразование использует локаль по умолчанию, установленную с помощью QLocale::setDefault(). (Если локаль по умолчанию не была задана, используется системная локаль.)

Сводка правил, используемых для перевода строк, содержащих формы множественного числа, представлена в документе Правила перевода для форм множественного числа.

Перевод текста, находящегося вне подкласса QObject

Использование QCoreApplication::translate()

Если цитируемый текст не находится в методе члена подкласса QObject, используйте либо функцию tr() соответствующего класса, либо функцию QCoreApplication::translate() напрямую:

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

void same_global_function(LoginWidget *logwid)
{
    QLabel *label = new QLabel(
            QCoreApplication::translate("LoginWidget", "Password:"),
            logwid);
}

Использование QT_TR_NOOP() и QT_TRANSLATE_NOOP() в C++

Если вам необходимо иметь полностью внефункциональный переводимый текст, есть две макрокоманды для помощи: 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", "Hello"),
    QT_TRANSLATE_NOOP("FriendlyConversation", "Goodbye")
};

QString FriendlyConversation::greeting(int type)
{
    return tr(greeting_strings[type]);
}

QString global_greeting(int type)
{
    return QCoreApplication::translate("FriendlyConversation",
                                       greeting_strings[type]);
}

Если вы отключите const char * автоматическое преобразование в QString путем компиляции вашего программного обеспечения с определенной макрокомандой QT_NO_CAST_FROM_ASCII, вы, скорее всего, обнаружите любые отсутствующие строки. Дополнительную информацию см. в QString::fromUtf8() и QString::fromLatin1().

Использование QKeySequence() для значений акселераторов

Значения акселераторов, такие как Ctrl+Q или Alt+F, также необходимо переводить. Если вы встроили Qt::CTRL + Qt::Key_Q для «выход» в своем приложении, переводчики не смогут его переопределить. Правильный способ:

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

Использование пронумерованных аргументов

Функции QString::arg() предлагают простой способ подстановки аргументов:

void FileCopier::showProgress(int done, int total,
                              const QString &currentFile)
{
    label.setText(tr("%1 of %2 files copied.\nCopying: %3")
                  .arg(done)
                  .arg(total)
                  .arg(currentFile));
}

В некоторых языках порядок аргументов может потребоваться изменить, и это можно легко сделать, изменив порядок аргументов % . Например:

QString s1 = "%1 of %2 files copied. Copying: %3";
QString s2 = "Kopierer nu %3. Av totalt %2 filer er %1 kopiert.";

qDebug() << s1.arg(5).arg(10).arg("somefile.txt");
qDebug() << s2.arg(5).arg(10).arg("somefile.txt");

выводит правильный результат на английском и норвежском языках:

5 of 10 files copied. Copying: somefile.txt
Kopierer nu somefile.txt. Av totalt 10 filer er 5 kopiert.

Дополнительные материалы

Руководство по Qt Linguist, Пример Hello tr(), Правила перевода для форм множественного числа

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.2/i18n-source-translation.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API