Разработаем приложение, которое поддерживает два языка: русский и английский. Чтобы не усложнять задачу, составим его из двух окон. Первое позволит выбрать локаль и ввести имя пользователя. А второе всего лишь отобразит приветствие на основе указанного имени. Получится примерно следующее:
Начнем с окна выбора локали и имени пользователя. Мы уже подробно рассматривали создание диалоговых окон в 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. Воспользуемся вторым вариантом при подготовке русского перевода. Интерфейс приложения достаточно очевиден, поэтому обойдемся без комментариев:
После сохранения содержимое файла 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, <strong>%1</strong>!</source>
<translation>Здравствуйте, <strong>%1</strong>!</translation>
</message>
</context>
</TS>
Но и это еще не все. После завершения работы над переводом нужно его скомпилировать. Это можно сделать в консоли с помощью следующей команды:
lrelease I18nDemo.pro
После этого появится соответствующий бинарный файл i18ndemo_ru.qm. Его нужно поместить в каталог с исполняемым файлом нашего проекта. Вот теперь можно считать, что работа окончена. Перевод успешно подключен и будет использоваться в приложении.
QTranslator::load() мы указываем имя i18ndemo_ru_RU, а находится i18ndemo_ru.qm. Это связано с тем, что у языков бывают диалекты. В частности, английский может быть американским en_US или британским en_GB. Если не получится найти перевод для project_name_en_GB, то QTranslator попытается загрузить просто project_name_en;Скачать исходники с примером многоязычного Qt-приложения