Evgenii Legotckoi
Evgenii Legotckoi5 июня 2016 г. 12:43

QML - Урок 025. Динамический перевод мультиязычного приложения на QML

После того, как мы ознакомились с переводами интерфейса приложения на Qt/C++ , настало время изучить возможности динамического перевода приложения, интерфейс которого написан на QML.

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

  1. Требуется дополнительная настройка .pro файла проекта;
  2. Сам процесс загрузки переводов для нужного языка осуществляется в C++ слое;
  3. Переинициализация перевода интерфейса осуществляется в QML слое с помощью функции qsTr();
  4. После загрузки перевода, нужно отправить сигнал из C++ слоя в QML слой, чтобы заново перевести интерфейс приложения, что аналогично и для С++ приложения, но требует настройки взаимодействия С++ слоя с QML слоем.

Структура проекта

Создаём проект, в который будут входит следующие файлы:

  • QmlLanguage.pro - профайл проекта;
  • deployment.pri - файл настройки деплоя, создаётся по умолчанию;
  • main.cpp - файл исходных кодов с функцией main;
  • qmltranslator.h - заголовочный файл класса загрузки перевода;
  • qmltranslator.cpp - файл исходных кодов класса загрузки перевода;
  • main.qml - основной файл QML слоя.

QmlLanguage.pro

Создание файла перевода будет аналогичным тому, как это делается при создании переводов для Qt/C++ приложения. То есть нужно подключить файл перевода, с которым будет работать Qt Linguist :

# Добавляем файл переводов,
# который является по сути файлом "исходных кодов" для нашего перевода
TRANSLATIONS += QmlLanguage_ru.ts

Далее запускаем утилиту lupdate, чтобы создать данный файл переводов, редактируем его в Qt Linguist , и запустил утилиту lrelease создаём бинарный файл перевода, который будет подключаться в приложение.

Подробнее об этом Вы можете прочитать в предыдущей статье по использованию QTranslator .

Самый важный момент для работы с переводами в QML то, что нужно подключить все файлы QML в качестве исходников, как обычные C++ файлы. Но с отметкой, что только для использования lupdate_only.

lupdate_only {
    SOURCES += main.qml
}

Ниже полный листинг .pro файла проекта.

TEMPLATE = app

QT += qml quick widgets

CONFIG += c++11

SOURCES += main.cpp \
    qmltranslator.cpp

# Для того, чтобы создать файл переводов со строками из ресурсов qml
# понадобится включить файл qml в качестве обычных исходников в pro файле
# но только для использования утилиты lupdate, чтобы она могла узнать,
# какие строки нуждаются в переводе
lupdate_only {
    SOURCES += main.qml
}

RESOURCES += qml.qrc \
    translations.qrc

# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =

# Default rules for deployment.
include(deployment.pri)

# Добавляем файл переводов,
# который является по сути файлом "исходных кодов" для нашего перевода
TRANSLATIONS += QmlLanguage_ru.ts

HEADERS += \
    qmltranslator.h

main.cpp

Поскольку подключение файлов переводов осуществляется в C++ слое, то потребуется зарегистрировать объект класса переводов в контексте QML. В данном случае мы напишем класс QmlTranslator, который будет обёрткой над QTranslator, поскольку тот класс не имеет методов, с которыми мы могли бы работать через QML.

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QtQml>
#include "qmltranslator.h"

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

    // Создаём объект для работы с переводами ...
    QmlTranslator qmlTranslator;

    QQmlApplicationEngine engine;
    // и регистрируем его в качестве контекста в Qml слое
    engine.rootContext()->setContextProperty("qmlTranslator", &qmlTranslator);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

qmltranslator.h

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

Метод установки перевода необходимо пометить макросом Q_INVOKABLE, чтобы была возможность использовать его в QML слое.

#ifndef QMLTRANSLATOR_H
#define QMLTRANSLATOR_H

#include <QObject>
#include <QTranslator>

class QmlTranslator : public QObject
{
    Q_OBJECT

public:
    explicit QmlTranslator(QObject *parent = 0);

signals:
    // Сигнал об изменении текущего языка для изменения перевода интерфейса
    void languageChanged();

public:
    // Метод установки перевода, который будет доступен в QML
    Q_INVOKABLE void setTranslation(QString translation);

private:
    QTranslator m_translator;
};

#endif // QMLTRANSLATOR_H

qmltranslator.cpp

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

QmlTranslator::QmlTranslator(QObject *parent) : QObject(parent)
{

}

void QmlTranslator::setTranslation(QString translation)
{
    m_translator.load(":/QmlLanguage_" + translation, "."); // Загружаем перевод
    qApp->installTranslator(&m_translator);                 // Устанавливаем его в приложение
    emit languageChanged();                                 // Сигнализируем об изменении текущего перевода
}

main.qml

Интерфейс приложения будет выглядеть следующим образом:

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

Поскольку мы зарегистрировали qmlTranslator в контексте QML слоя, то в обработчике изменения текста в комбобоксе будем вызывать метод изменения языка в объекте qmlTranslator. А чтобы отслеживать сигнал изменения языка, необходимо с помощью типа Connections подключить к этому сигналу и написать обработчик, в котором будет вызываться функция retranslateUi(). В функции retranslateUi() вынесены все текстовые свойства всех объектов, которые необходимо подвергнуть переводу. Сделано это для упрощения логики и уменьшения избыточного кода.

import QtQuick 2.6
import QtQuick.Controls 1.5

ApplicationWindow {
    id: applicationWindow
    visible: true
    width: 640
    height: 480

    Label {
        id: helloLabel
        height: 50
        anchors {
            top: parent.top
            left: parent.left
            right: parent.horizontalCenter
            margins: 10
        }
    }

    ComboBox {
        id: comboBox
        anchors {
            top: parent.top
            left: parent.horizontalCenter
            right: parent.right
            margins: 10
        }

        model: ["ru_RU", "en_US"]

        // При изменении текста, инициализируем установку перевода через С++ слой
        onCurrentTextChanged: {
            qmlTranslator.setTranslation(comboBox.currentText)
        }
    }

    Label {
        id: labelText
        wrapMode: Text.Wrap
        anchors {
            top: helloLabel.bottom
            left: parent.left
            right: parent.right
            margins: 10
        }
    }

    // Подключаемся к объекту переводчика
    Connections {
        target: qmlTranslator   // был зарегистрирован в main.cpp
        onLanguageChanged: {    // при получении сигнала изменения языка
            retranslateUi()     // инициализируем перевод интерфейса
        }
    }

    // Функция перевода интерфейса
    function retranslateUi() {
        applicationWindow.title = qsTr("Hello World")
        helloLabel.text = qsTr("Hello World")
        labelText.text = qsTr("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.")
    }

    // Запускаем перевод приложения, когда окно приложения было создано
    Component.onCompleted: {
        retranslateUi();
    }
}

Итог

В целом динамический перевод приложения на Qt/QML мало чем отличается от перевода приложения с использованием только Qt/C++. Ключевым моментом является то, что нужно правильно подключить сигналы и слоты и правильно вызывать методы для инициализации перевода.

Скачать QML приложение с динамическим переводом

Видеоурок

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

ДЧ
  • 31 января 2019 г. 5:25
  • (ред.)

Всё отлично :)
Только у меня вопрос: а как вместо ru_RU и en_US написать в ComboBox'e Russian и English чтобы сохранить функцию смены языка :)

UPD Разобрался
В comboBox model я пишу так:

model: ["English", "Russian"]

И перед отправкой кода ru_RU или en_US в С++ делаю проверку

onCurrentTextChanged: {
            if(comboBox.currentText === "Russian")
                qmlTranslator.setTranslation("ru_RU")
            if(comboBox.currentText === "English")
                qmlTranslator.setTranslation("en_US")
        }
zloi
  • 15 июля 2019 г. 5:32

В Qt 5.10 была добавлена новая функция по переводу qml файлов. Теперь не нужно писать класс оболочку, достаточно вызвать функцию engine.retranslate(); и все обновится само.

Evgenii Legotckoi
  • 15 июля 2019 г. 5:35

Это хорошая новость!!!!

Комментарии

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

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:50баллов,
  • Очки рейтинга-4
m
  • molni99
  • 25 октября 2024 г. 22:37

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80баллов,
  • Очки рейтинга4
m
  • molni99
  • 25 октября 2024 г. 22:29

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:20баллов,
  • Очки рейтинга-10
Последние комментарии
ИМ
Игорь Максимов22 ноября 2024 г. 8:51
Django - Урок 017. Кастомизированная страница авторизации на Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii Legotckoi31 октября 2024 г. 11:37
Django - Урок 064. Как написать расширение для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZE19 октября 2024 г. 5:19
Читалка fb3-файлов на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов5 октября 2024 г. 4:51
Django - Урок 064. Как написать расширение для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55 июля 2024 г. 8:02
QML - Урок 016. База данных SQLite и работа с ней в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Сейчас обсуждают на форуме
m
moogo22 ноября 2024 г. 4:17
Mosquito Spray System Effective Mosquito Systems for Backyard | Eco-Friendly Misting Control Device & Repellent Spray - Moogo ; Upgrade your backyard with our mosquito-repellent device! Our misters conce…
Evgenii Legotckoi
Evgenii Legotckoi24 июня 2024 г. 12:11
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey115 ноября 2024 г. 3:04
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProject4 июня 2022 г. 0:49
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…

Следите за нами в социальных сетях