Evgenii Legotckoi
Evgenii LegotckoiMay 30, 2016, 6:13 p.m.

Qt/C++ - Lesson 049. QTranslator - dynamic translation of multilingual application to Qt

Sooner or later, the developer of Qt applications meets the need multilanguage support of  his application. Then you can to use QTranslator class and Qt Linguist for creating of translations.

QTranslator object class is used to load translation from a special file with the extension .qm, which is a hexadecimal file of translations. This file is compiled from the translation file in XML format, which has the extension .ts and it is prescribed in the project profile. This file contains all of the application line, which were concluded in the tr() function. I recommend describe the entire interface of the application in English, which will be the default language, and translations have to load the desired language from the translation files. If the required translation file is not found, it will automatically be downloaded in English translation. Although you can certainly use another language as the default language.


Translation download Example

The structure of the file name of the translation has an important role in working with QTranslator . Let us see the minimum example.

#include "mainwindow.h"
#include <QApplication>
#include <QTranslator>
#include <QLibraryInfo>

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

    QTranslator qtLanguageTranslator;
    qtLanguageTranslator.load(QString("QtLanguage_") + QString("ru_RU"));
    qApp->installTranslator(&qtLanguageTranslator);

    MainWindow w;
    w.show();

    return a.exec();
}

In this example creates a class object QTranslator, in which we will download the file , which is interested for us, indicating the language. In this case, the full name of the file translation following QtLanguage_ru.qm. That is, given the general name for the file transfer QtLanguage, as well as language translation prefix _ru. But you may have noticed that as an argument for using load generated QtLanguage_ru_RU line. This is done in order to determine the proper dialect, such as the US (en_US) or British (en_GB) English. But if in the translation file name is not specified dialect, then the file will be selected without specifying a dialect, for example, QtLanguage_ru.qm.

After the translations file is downloaded, it must be installed in the application. In this case, it uses a global pointer to the application qApp->installTranslator (&qtLanguageTranslator).

Creating a translation file

Once we figured out a way to transfer the minimum settings in the application, let's understand, how do you can create a translation. To create a translation is necessary to use the following functions: tr(), trUtf8 (), translate () in the application, etc. That is, all the text that will require translation is necessary to frame it in those functions, then to create a translation file. Look it might read:

label->setText(QApplication::translate("MainWindow", "Select Language", 0));
label_2->setText(tr("Hello"));
label_3->setText(trUtf8("Hello world"));

Once in the application marked all the necessary lines, you will need to create a translation file, do the translation itself directly and compile the final translation file. To do this, use the following programs:

  1. lupdate - program for the formation of the field of translation TRANSLATIONS pro file in the file and update information on all new lines in applications that require translation.
  2. lrelease - program for the compile of the final translation file to be used in the application.
  3. Qt Linguist - directly the package itself to create translations.

The first step that needs to be done after the application has registered a string requiring translation is to add the file to be translated into pro project file. You may also want to specify the encoding information that is used for the translation.

TRANSLATIONS += QtLanguage_ru.ts

CODECFORSRC     = UTF-8

Next, you need to use a utility to create lupdate QtLanguage_ru.ts file. In Qt Creator, look here: Tools -> External -> Linguist -> lupdate.

lupdate reported the results of the search strings to translate.

Runs an external tool «D:\Qt\5.6\mingw49_32\bin\lupdate.exe» D:/AndroidQT/QTProjects/QtLanguage/QtLanguage.pro
Updating 'QtLanguage_ru.ts'...
    Found 4 source text(s) (0 new and 4 already existing)

«D:\Qt\5.6\mingw49_32\bin\lupdate.exe» completed

Next, open the Qt Linguist make translations all rows, marking, which are translated (This is purely a service information for the translator himself)

After you created the translation, save the file and compile the hex file transfer using the utility lrelease. It can be found in Qt Creator in the same place and lupdate, or run out of Qt Linguist: File -> Release.

For use file will need to place it in a directory with the application's executable file.

Dynamic translation of Application

Loading translation app - it's good, but what if you need to change the dynamic translation? Let's look at a simple example where there QComboBox indicating two languages: English and Russian.

Structure of project

  • QtLanguage.pro -project profile;
  • main.cpp - project file with the main function;
  • mainwindow.h - header file of apllication main window;
  • mainwindow.cpp - source file of main window;
  • mainwindow.ui - form of main window.

mainwindow.ui

I prefer to use a graphic designer to create a GUI application, as it accelerates the development, unless you want something complicated in the appearance of the application, so create a window with the following appearance.

In this window, there are:

  • label
  • label_2
  • comboBox

With the transfer of which we will work. Ease of graphic designer is also the fact that it automatically generates retranslateUi () method, which is used to change the translation of all the signatures that are used in the application, although you can own to register manually a similar method, but personally I do not want to waste time on it, which it may very well be created automatically. For example, in this lesson, it looks as follows:

void retranslateUi(QMainWindow *MainWindow)
{
    MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0));
    label_2->setText(QApplication::translate("MainWindow", "The QTranslator class provides internationalization support for text output.An object of this class contains a set of translations from a source language to a target language. QTranslator provides functions to look up translations in a translation file. Translation files are created using Qt Linguist.", 0));
    label->setText(QApplication::translate("MainWindow", "Select Language", 0));
} // retranslateUi

QtLanguage.pro

As mentioned above, indicate the name of the translation file in the project profile.

#-------------------------------------------------
#
# Project created by QtCreator 2016-05-22T14:34:42
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = QtLanguage
TEMPLATE = app


SOURCES += main.cpp\
        mainwindow.cpp

HEADERS  += mainwindow.h

FORMS    += mainwindow.ui

TRANSLATIONS = QtLanguage_ru.ts

CODECFORSRC     = UTF-8

main.cpp

And here in this file will not change anything.

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

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

    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.h

In the header of the main window of the application must be declared QTranslator object class and override the method changeEvent (QEvent * event) , which will be determined by the application of language change event.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTranslator>
#include <QEvent>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

protected:
    // The method of obtaining the events in the main application window
    // In it will be checked events change transfer applications
    void changeEvent(QEvent * event) override;

private:
    Ui::MainWindow *ui;
    QTranslator qtLanguageTranslator;   // Select the translation in a separate field, otherwise it will not work
};

#endif // MAINWINDOW_H

mainwindow.cpp

The logic of the application is as follows: when you change the item in the combo box will change the translation of the application.

Note. Do not forget to put the translation file with the extension qm next to the application's executable file and collect the required dll , otherwise it not will work.

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QApplication>
#include <QTranslator>
#include <QLibraryInfo>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // Set two points with the text of the locales in the combo box
    ui->comboBox->addItems(QStringList() << "ru_RU" << "en_US");

    // connect to the signal change of combo box item 
    // to lambda function that will change application translation 
    // where there is an interesting point. 
    // Since QComboBox has an overload signal signatures, 
    // then we need to cast to the desired signal signature. 
    // In this case, we use the name of the item at its change
    connect(ui->comboBox, static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentIndexChanged),
            [=](const QString &str){
        qtLanguageTranslator.load("QtLanguage_" + str, ".");   // load translation
        qApp->installTranslator(&qtLanguageTranslator);        // Set the translation in the application
    });

    // Make an initial transfer to the initialization of the application window
    qtLanguageTranslator.load(QString("QtLanguage_") + QString("ru_RU"));
    qApp->installTranslator(&qtLanguageTranslator);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::changeEvent(QEvent *event)
{
    // In the case of events changing the application language
    if (event->type() == QEvent::LanguageChange) {
        ui->retranslateUi(this);    // translate the window again
    }
}

Result

As a result, you will receive an application with support for two languages in its graphical user interface.

Download example of Application with QTranslator

Video lesson

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

w
  • May 16, 2017, 10:45 a.m.

Не работает....

Evgenii Legotckoi
  • May 16, 2017, 10:51 a.m.

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

А к чему относится такая проблема? Есть QPlainTextEdit. У него есть горячие клавиши. Но они работает только на английском языке : Когда на клавиатуре нажимается ctrl + 'x', горячая клавиша "вырезать" срабатывает. Но при нажатии ctrl + 'ч' не срабатывает. Стоит создать тему на форуме или это что-то само собой разумеющиеся?
Данный код в main.cpp не помог :

    QString translatorFileName = QLatin1String("qt_");
    translatorFileName += QLocale::system().name();
    QTranslator *translator = new QTranslator(&a);
    if (translator->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
        a.installTranslator(translator);

А вы случаем не переводили эти сочетания клавиш там, где они устанавливаются? Если где-то есть этот перевод, то есть там подставлена tr() b trUtf8() функция, то могут быть проблемы, лучше те куски кода не оборачивать в функции перевода и не делать перевода, тем более, что это и не нужно. Скорее всего коды клавиш неправильно определяются.

IscanderChe
  • July 12, 2018, 4:08 p.m.
Скачал пример, увы, не работает. Комбобокс исправно пашет, переключения языков нет.

Ещё подскажите, как без шаманства кастования переключать язык? Например, как это обычно бывает, после перезагрузки приложения.
Evgenii Legotckoi
  • July 12, 2018, 4:11 p.m.

Странно. Должен был бы работать... проверю на досуге.

Вообще сохраняют инфоромацию о языке в QSettings, который нужно установить. Закрывают приложение и после запуска из QSettings подтягивается инофрмация о локализации приложения, после чего загружается требуемый язык.
Evgenii Legotckoi
  • July 12, 2018, 4:17 p.m.

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

Arrow
  • July 13, 2018, 5:55 p.m.
Хорошая статья. Только один вопрос как это сделать для CMake?

Интересует именно запись в CMakeList

  1. TRANSLATIONS += QtLanguage_ru.ts
  2. CODECFORSRC = UTF-8
Пытался так, но не работает и хотя в документации написано так.

file(GLOB TRANSLATION_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.ts)

qt5_add_translation(TRANSLATION_QM ${TRANSLATION_FILES})
add_custom_target(translations DEPENDS ${TRANSLATION_QM})
Ругается на
qt5_add_translation
пишет - неизвестная команда.

qt5_create_translation понимает, но ничего не происходит.
Evgenii Legotckoi
  • July 15, 2018, 12:49 a.m.

У меня на руках есть один проект, где какие-то потуги с переводами и подключением этого добра в CMAKE делались.

Но там файл перевода добавляется прямо в ресурсы проекта. То есть бинарных qm файл переводов добавлялся в qrc файл. То есть при компилировании перевод сохранялся как ресурс, а потом уже из ресурсов забирался.
 
qt5_add_resources(RCC_RESOURCES
        resources/translations.qrc
        )

add_executable({RCC_RESOURCES})
Как понимаю,
qt5_add_translation или qt5_create_translation
Должны ещё создать этот самый бинарный qm файл переводов
Arrow
  • July 15, 2018, 12:58 a.m.

Спасибо,  попробую.

Arrow
  • July 17, 2018, 7:34 p.m.
Работает так:

find_package (Qt5LinguistTools)
file (GLOB TS_FILES ${SOURCE_DIR}/translations/*.ts)
qt5_add_translation (QM_FILES ${TS_FILES})
add_custom_target (translations ALL DEPENDS ${QM_FILES})
......
add_executable (${PROJECT_NAME} ${SOURCE_FILES} ${HEADER_FILES} ${UI_FILES} ${RESOURCES} ${QM_FILES})
grig_p
  • Aug. 13, 2019, 8:17 p.m.

Здравствуйте!

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

static const QString V01 = "Вариант 01";
static const QString V02 = "Вариант 02";

Потом, они используются в мэпе:

QMap<int, QString> Variants =
{
    std::pair<int, QString> (1, V01)
  , std::pair<int, QString> (2, V02)
}

В конце есть функция, возвращающая сроку по коду:

QString variant(const int varCode)
{
    return Variants.value(varCode);
}

Как быть в такой ситуации? Константы в tr() не обернешь.

Сделал так:

static const QString V01 = QCoreApplication::tr("Вариант 01");
static const QString V02 = QCoreApplication::tr("Вариант 02");

Лингвист видит эти значения в контексте QCoreApplication,
позволяет их перевести, но доступа к переводу нет,
выводится на русском языке.
Что я делаю не так?

Evgenii Legotckoi
  • Aug. 13, 2019, 8:43 p.m.

Самая главная проблема в том, что у вас это константные переменные, и инициализируется они один единственный раз при запуске программы.
Поэтому делать динамический перевод в таком случае у вас не получится. Вам нужно иначе подходить к этой проблеме.

Напишите код так.

QString variant(const int varCode)
{
    switch (varCode)
    {
        case 1: return QCoreApplication::tr("Вариант 01");
        case 2: return QCoreApplication::tr("Вариант 02");
        default: return QString();
    }
}
grig_p
  • Aug. 14, 2019, 11:27 a.m.
  • (edited)

Спасибо большое. Получилось

P
  • Nov. 20, 2019, 1:10 a.m.

Здравствуйте.
Спасибо за статью. Сделал перевод программы. Все работает.
Только я делал не динамический, но это пока и не надо.
Но с одной проблемой все же столкнулся.
В программе есть сцена. На ней создаются некие графические элементы.
в конструкторе элементов устанавливаю всплывающую подсказку,
например такую

this->setToolTip(tr("Кнопка"));

Все переводится кроме тултипов.
Не подскажете куда копать?

Evgenii Legotckoi
  • Nov. 20, 2019, 1:50 p.m.

Добрый день.

Вы используете QGraphicsItem? вообще побольшу бы кусок кода, чтобы иметь большее представление. Мысли есть, но не уверен

P
  • Nov. 20, 2019, 2:10 p.m.
  • (edited)

да, есть классы наследуемые от QGraphicsItem.
в программе при нажатии определенных кнопок(слева на картинке), на сцене появляются Item-ы
с разными настройками. в конструкторе ни чего особого нет,только координаты,название,тултип.

перевод загружается так

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTranslator translator;
    translator.load(QString("Language_en"));
    a.installTranslator(&translator);
    MainWindow w;
    w.show();

    return a.exec();
}
Evgenii Legotckoi
  • Nov. 20, 2019, 2:25 p.m.
  • (edited)

Вообще, метод tr является частью класса QObject, если он у вас используется в конструкторе, то вы должны были использовать множественное наследование для вашей кастомной кнопки. Поскольку графические объекты одни из немногих классов, которые не наследуются от QObject, кроме QGraphicsObject, но там также множественное наследование используется.

То есть заголовочный код вашей кнопки должен выглядеть так

class Button : public QObject, public QGraphicsItem
{
    Q_OBJECT
public:
    /* и так далее */
}

Убедитесь, что у вас присутсвует макрос Q_OBJECT, он отвечает за мета информацию и включение возможности перевода.

Если же вы не наследовались от QObject, то перевод можно также включить с помощью другого макроса

class Button : public QGraphicsItem
{
    Q_DECLARE_TR_FUNCTIONS(Button)
public:
    /* и так далее */
}
Evgenii Legotckoi
  • Nov. 20, 2019, 2:30 p.m.

И в качестве дополнения из личного опыта. Пишите лучше все тексты на английском языке в функциях tr )))

P
  • Nov. 20, 2019, 2:43 p.m.

у меня множественное наследование.
сначала основной класс myitem

class myItem : public QObject, public QGraphicsItem
{
    Q_OBJECT
    Q_INTERFACES(QGraphicsItem)
public:
    myItem(int x, int y, int w, int h);
    .....
    .....
    ..

со всякими переменными.

а потом от него все остальные , которые появляются на сцене.

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

Evgenii Legotckoi
  • Nov. 20, 2019, 2:55 p.m.

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

P
  • Nov. 20, 2019, 3:02 p.m.
myButton::myButton(int x, int y, int w, int h) : myItem (x, y, w, h)
{
  static int i = 1;
  myVar.text = "Btn" + QString::number(i++);
  myVar.myType = typeSimpleButton;
  this->setToolTip(tr("Кнопка"));
  myVar.func_read = 1;
  configVisibleWidgets |= 1<<visibleSettings::Hsize | 1<<visibleSettings::Wsize
      | 1<<visibleSettings::Color1 | 1<<visibleSettings::ColorText | 1<<visibleSettings::Color2
      | 1<<visibleSettings::TextEdit | 1<<visibleSettings::ModbusWrite
      | 1<<visibleSettings::Toggle | 1<<fontSizeSelect | 1<<itSlave;
}
myItem::myItem(int x, int y, int w, int h)
{
  myVar.rect.x =x;
  myVar.rect.y=y;
  myVar.rect.w=w;
  myVar.rect.h=h;
  setFlags(QGraphicsItem::ItemIsMovable |
           QGraphicsItem::ItemIsSelectable |
           QGraphicsRectItem::ItemIsFocusable);
}
P
  • Nov. 20, 2019, 3:14 p.m.

при этом тултипы заданные в редакторе форм переводятся...

Evgenii Legotckoi
  • Nov. 20, 2019, 3:29 p.m.

проблема в конструкторе, напишите так

myItem::myItem(int x, int y, int w, int h) : QObject()
{
  myVar.rect.x =x;
  myVar.rect.y=y;
  myVar.rect.w=w;
  myVar.rect.h=h;
  setFlags(QGraphicsItem::ItemIsMovable |
           QGraphicsItem::ItemIsSelectable |
           QGraphicsRectItem::ItemIsFocusable);
}
P
  • Nov. 20, 2019, 4:05 p.m.

добавил : QObject()
ни чего не изменилось.

ладно. что-нибудь придумаю

Evgenii Legotckoi
  • Nov. 20, 2019, 4:08 p.m.

Тогда хоть убейте, не знаю. Где-то не хватает или макроса или корректной реализации конструктора.

Comments

Only authorized users can post comments.
Please, Log in or Sign up
B

C++ - Test 002. Constants

  • Result:16points,
  • Rating points-10
B

C++ - Test 001. The first program and data types

  • Result:46points,
  • Rating points-6
FL

C++ - Test 006. Enumerations

  • Result:80points,
  • Rating points4
Last comments
k
kmssrFeb. 9, 2024, 2:43 a.m.
Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVADec. 25, 2023, 6:30 p.m.
Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJoDec. 25, 2023, 4:38 p.m.
Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
GvozdikDec. 19, 2023, 5:01 a.m.
Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Now discuss on the forum
AC
Alexandru CodreanuJan. 19, 2024, 7:57 p.m.
QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…
BlinCT
BlinCTDec. 27, 2023, 4:57 p.m.
Растягивать Image на парент по высоте Ну и само собою дял включения scrollbar надо чтобы был Flickable. Так что выходит как то так Flickable{ id: root anchors.fill: parent clip: true property url linkFile p…
Дмитрий
ДмитрийJan. 10, 2024, 12:18 p.m.
Qt Creator загружает всю оперативную память Проблема решена. Удалось разобраться с помощью утилиты strace. Запустил ее: strace ./qtcreator Начал выводиться весь лог работы креатора. В один момент он начал считывать фай…
Evgenii Legotckoi
Evgenii LegotckoiDec. 12, 2023, 2:48 p.m.
Побуквенное сравнение двух строк Добрый день. Там случайно не высылается этот сигнал textChanged ещё и при форматировани текста? Если решиать в лоб, то можно просто отключать сигнал/слотовое соединение внутри слота и …

Follow us in social networks