Разработаем приложение, которое поддерживает два языка: русский и английский. Чтобы не усложнять задачу, составим его из двух окон. Первое позволит выбрать локаль и ввести имя пользователя. А второе всего лишь отобразит приветствие на основе указанного имени. Получится примерно следующее:
Начнем с окна выбора локали и имени пользователя. Мы уже подробно рассматривали создание диалоговых окон в 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-приложения