IT Notes

QTranslator: Интернационализация в Qt

Разработаем приложение, которое поддерживает два языка: русский и английский. Чтобы не усложнять задачу, составим его из двух окон. Первое позволит выбрать локаль и ввести имя пользователя. А второе всего лишь отобразит приветствие на основе указанного имени. Получится примерно следующее:

qt-i10n-thumbnail

Даем пользователю выбор

Начнем с окна выбора локали и имени пользователя. Мы уже подробно рассматривали создание диалоговых окон в Qt, поэтому в этот раз обойдемся без лишних рассуждений. Файл introdialog.h:

#ifndef INTRODIALOG_H
#define INTRODIALOG_H

#include <QDialog>

class QComboBox;
class QLineEdit;

class IntroDialog : public QDialog {
    Q_OBJECT

public:
    IntroDialog( QWidget* parent = 0 );
    ~IntroDialog();

    QString getLocale() const;
    QString getName() const;

private:
    QComboBox* m_localeCmb;
    QLineEdit* m_nameEdit;
};

#endif // INTRODIALOG_H

Соответствующая реализация introdialog.cpp:

#include "introdialog.h"

#include <QGridLayout>
#include <QComboBox>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>

IntroDialog::IntroDialog( QWidget* parent )
    : QDialog( parent ) {

    QGridLayout* l = new QGridLayout;

    QLabel* localeLbl = new QLabel( trUtf8( "Choose locale:" ) );
    localeLbl->setAlignment( Qt::AlignRight );
    l->addWidget( localeLbl, 0, 0 );
    m_localeCmb = new QComboBox;
    m_localeCmb->addItems( QStringList() << "en_US" << "ru_RU" );
    int index = m_localeCmb->findText( QLocale::system().name() );
    if( index != -1 ) {
        m_localeCmb->setCurrentIndex( index );
    }
    l->addWidget( m_localeCmb, 0, 1 );

    l->addWidget( new QLabel( trUtf8( "Enter your name:" ) ), 1, 0 );
    m_nameEdit = new QLineEdit;
    l->addWidget( m_nameEdit, 1, 1 );

    QPushButton* okBtn = new QPushButton( "OK" );
    connect( okBtn, SIGNAL( clicked( bool ) ), SLOT( accept() ) );
    l->addWidget( okBtn, 2, 1 );

    setLayout( l );
}

IntroDialog::~IntroDialog() {
}

QString IntroDialog::getLocale() const {
    return m_localeCmb->currentText();
}

QString IntroDialog::getName() const {
    return m_nameEdit->text();
}

Обратим внимание на две строки из фрагмента выше:

...
QLabel* localeLbl = new QLabel( trUtf8( "Choose locale:" ) );
...
l->addWidget( new QLabel( trUtf8( "Enter your name:" ) ), 1, 0 );
...

При инициализации текста меток QLabel мы используем функцию QObject::trUtf8(). Она позволяет ввести текст по умолчанию в кодировке UTF-8. Затем мы займемся его переводом на русский. Важным моментом является то, что строки не должны инициализировать статически. Вызов tfUtf8() должен происходить после установки объекта-переводчика.

Обратите внимание, что мы поместили в комбо-бокс имена локалей ru_RU (русская локаль) и en_US (английская локаль):

m_localeCmb->addItems( QStringList() << "en_US" << "ru_RU" );

Логичным допущением становится то, что по умолчанию выбирается местная системная локаль, которую мы узнаем с помощью QLocale::system().name():

int index = m_localeCmb->findText( QLocale::system().name() );
if( index != -1 ) {
    m_localeCmb->setCurrentIndex( index );
}
Реклама

Инициализация перевода

Теперь займемся файлом main.cpp:

#include "introdialog.h"
#include <QApplication>

#include <QTranslator>
#include <QLocale>
#include <QLabel>
#include <QDebug>

static const QString SYSTEM_LOCALE = QLocale::system().name();

QString generateTrFileName( const QString& locale ) {
    return QString( "i18ndemo_%1" ).arg( locale );
}

int main( int argc, char* argv[] ) {
    QApplication a( argc, argv );

    QTranslator translator;
    if( translator.load( generateTrFileName( SYSTEM_LOCALE ) ), "." ) {
        a.installTranslator( &translator );
    }

    IntroDialog w;
    if( w.exec() != QDialog::Accepted ) {
        return 0;
    }

    translator.load( generateTrFileName( w.getLocale() ), "." );

    QLabel lbl( QObject::trUtf8( "Hello, <strong>%1</strong>!" ).arg( w.getName() ) );
    lbl.setAlignment( Qt::AlignHCenter | Qt::AlignVCenter );
    lbl.resize( 400, 400 );
    lbl.show();

    return a.exec();
}

До отображения диалогового окна IntroDialog мы создаем объект QTranslator. Он умеет загружать файл перевода с помощью вызова load(). Первым аргументом эта функция-член принимает базовое имя файла перевода, а во втором - путь в файловой системе, где этот файл нужно искать.

Формирование базового имени файла перевода осуществляется в нашей функции generateTrFileName(). Она принимает имя локали, и возвращает строку вида i18ndemo_ru_RU.

Если QTranslator::load() возвращает true, то загрузка файла с переводом прошла успешна, и мы можем установить его для приложения:

if( translator.load( generateTrFileName( SYSTEM_LOCALE ) ), "." ) {
    a.installTranslator( &translator );
}

Когда пользователь выбирает в диалоговом окне локаль и нажимает OK, мы повторно ее загружаем в уже существующий экземпляр translator'а:

translator.load( generateTrFileName( w.getLocale() ), "." );

Далее мы просто создаем и отображаем QLabel с приветственной надписью. Вновь с использованием QObject::trUtf8().

Приложение уже можно запустить, но поскольку у нас нет переводов, то все надписи будут на английском. Что можно считать вполне уместным поведением по умолчанию. Но нас такой вариант не устраивает.

Реклама

Готовим перевод

Для добавления переводов подправим pro-файл I18nDemo.pro:

#-------------------------------------------------
#
# Project created by QtCreator 2016-05-09T12:29:18
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = I18nDemo
TEMPLATE = app


SOURCES += main.cpp\
        introdialog.cpp

HEADERS  += introdialog.h

TRANSLATIONS = i18ndemo_ru.ts

Нас интересует переменная TRANSLATIONS, в которой указывается список ts-файлов с переводом. Мы определили всего один: для русского языка. Аналогично можно расширить список на произвольное количество переводов:

TRANSLATIONS = i18ndemo_ru.ts \
               i18ndemo_fr.ts \
               i18ndemo_de.ts

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

lupdate I18nDemo.pro

В результате появится файл: i18ndemo_ru.ts. Это обычный текстовый файл в формате XML. Его можно редактировать в любом текстовом редакторе или с помощью специального приложения Qt Linguist. Воспользуемся вторым вариантом при подготовке русского перевода. Интерфейс приложения достаточно очевиден, поэтому обойдемся без комментариев:

qt-linguist-thumbnail

После сохранения содержимое файла i18ndemo_ru.ts станет примерно таким:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ru_RU">
<context>
    <name>IntroDialog</name>
    <message>
        <location filename="introdialog.cpp" line="14"/>
        <source>Choose locale:</source>
        <translation>Выберите локаль:</translation>
    </message>
    <message>
        <location filename="introdialog.cpp" line="25"/>
        <source>Enter your name:</source>
        <translation>Введите ваше имя:</translation>
    </message>
</context>
<context>
    <name>QObject</name>
    <message>
        <location filename="main.cpp" line="30"/>
        <source>Hello, &lt;strong&gt;%1&lt;/strong&gt;!</source>
        <translation>Здравствуйте, &lt;strong&gt;%1&lt;/strong&gt;!</translation>
    </message>
</context>
</TS>

Но и это еще не все. После завершения работы над переводом нужно его скомпилировать. Это можно сделать в консоли с помощью следующей команды:

lrelease I18nDemo.pro

После этого появится соответствующий бинарный файл i18ndemo_ru.qm. Его нужно поместить в каталог с исполняемым файлом нашего проекта. Вот теперь можно считать, что работа окончена. Перевод успешно подключен и будет использоваться в приложении.

Несколько замечаний

  1. Поиск файла перевода довольно интеллектуален. Например, при вызове QTranslator::load() мы указываем имя i18ndemo_ru_RU, а находится i18ndemo_ru.qm. Это связано с тем, что у языков бывают диалекты. В частности, английский может быть американским en_US или британским en_GB. Если не получится найти перевод для project_name_en_GB, то QTranslator попытается загрузить просто project_name_en;
  2. Имеет смысл задуматься о помещении переводов в файл-ресурсов;
  3. Выбранный язык нужно хранить в конфигурационном файле, чтобы пользователю не приходилось выбирать его каждый раз при запуске приложения. Системную локаль в этом вопросе можно рассматривать лишь в качестве отправной точки.

Исходники

 Скачать исходники с примером многоязычного Qt-приложения

Понравилась статья?
Не забудь поделиться ей с друзьями!
Реклама

Похожие публикации

Комментарии

Комментарий удален

RSS RSS-рассылка

Популярное