Перевод свойств в QML

#python #qml #translation #pyside2

Вопрос:

Я знаю процесс перевода строк в QML. Но есть ли способ полностью перевести свойства QML с помощью функций QML? Я работаю с PySide2, и мне нужно будет перевести свойства, определенные на стороне Python и QML. В качестве минималистичного примера пока без функций перевода:

main. py

 class example_model(QObject):
    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self._model = QStandardItemModel()

    @Property(str, constant=True)
    def python_property(self):
        return "Example String"

def main():
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()
    context = engine.rootContext()
    model = example_model( parent=context)
    context.setContextProperty("exampleModel", model)
    engine.load(QUrl(QUrl.fromLocalFile(os.path.join(os.path.dirname(inspect.getfile(lambda: None)), "main.qml"))))

    return app.exec_()
    
if __name__ == '__main__':
    sys.exit(main())
 

main.qml

 import QtQuick 2.12
import QtQuick.Controls 2.12

ApplicationWindow {
    id: root
    width: 200
    height: 400
    visible: true
    property string qmlProperty: "exampleString"

    Text{
        text: QT_TR_NOOP(exampleModel.python_property)
    }
    Text{
        text: QT_TR_NOOP(root.qmlProperty)
    }
}
 

Как я могу добиться того, чтобы эти два свойства ( python_property и qmlProperty ) были правильно обнаружены функцией Qt lupdate или любой другой функцией соответственно. Мне нужен динамический перевод, поэтому engine.retranslate() функция будет использоваться.

Комментарии:

1. Во-первых, QT_TR_NOOP это, как следует из названия, не-операция, поэтому то, как вы ее здесь используете, ничего не даст. Вы должны разместить его повсюду "exampleString" , чтобы люпдейт обнаружил его. И я думаю , что вы можете завершить свой квест, поставив qsTr вместо двух привязок QT_TR_NOOP , но не на 100% уверены в этом. Стоит отметить, что lupdate ставит main.qml в качестве контекста, поэтому вам следует позаботиться о том, где QT_TR_NOOP и qsTr используются

Ответ №1:

Перевод похож на QML только тем, что для использования перевода python вам необходимо использовать qsTranslate, где вы должны передать контекст (имя класса python), поскольку он отличается от контекста qml (имя класса .файл qml).

С другой стороны, кажется, что OP не понимает работу QT_TR_NOOP, поэтому рекомендуется просмотреть документы.

Используя следующий пример, я покажу процесс перевода:

 import os
import sys
from pathlib import Path

from PySide2.QtCore import (
    Property,
    QCoreApplication,
    QObject,
    Qt,
    QTimer,
    QTranslator,
    QUrl,
)
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine

CURRENT_DIRECTORY = Path(__file__).resolve().parent
QML_DIRECTORY = CURRENT_DIRECTORY / "qml"
TRANSLATIONS_DIR = CURRENT_DIRECTORY / "translations"


class PythonModel(QObject):
    def python_property(self):
        return self.tr("Python Example String")

    pythonProperty = Property(str, fget=python_property, constant=True)


def main():
    app = QGuiApplication(sys.argv)

    py_tranlator = QTranslator()
    res = py_tranlator.load(os.fspath(TRANSLATIONS_DIR / "py.qm"))
    assert res

    qml_tranlator = QTranslator()
    res = qml_tranlator.load(os.fspath(TRANSLATIONS_DIR / "qml.qm"))
    assert res

    python_model = PythonModel(app)

    engine = QQmlApplicationEngine()
    engine.rootContext().setContextProperty("pythonModel", python_model)

    filename = os.fspath(QML_DIRECTORY / "main.qml")
    url = QUrl.fromLocalFile(filename)

    def handle_object_created(obj, obj_url):
        if obj is None and url == obj_url:
            QCoreApplication.exit(-1)

    engine.objectCreated.connect(handle_object_created, Qt.QueuedConnection)
    engine.load(url)

    ok = False

    def handle_timeout():
        nonlocal ok
        if ok:
            QCoreApplication.installTranslator(py_tranlator)
            QCoreApplication.installTranslator(qml_tranlator)
        else:
            QCoreApplication.removeTranslator(py_tranlator)
            QCoreApplication.removeTranslator(qml_tranlator)

        engine.retranslate()

        ok = not ok

    timer = QTimer(interval=1000, timeout=handle_timeout)
    timer.start()

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
 
 import QtQuick 2.12
import QtQuick.Controls 2.12

ApplicationWindow {
    id: root

    property string qmlProperty: qsTr("QML Example String")

    width: 200
    height: 400
    visible: true

    Column {
        Text {
            text: qsTranslate("pythonModel", pythonModel.pythonProperty)
        }

        Text {
            text: root.qmlProperty
        }

    }

}
 
 ├── main.py
├── qml
│   └── main.qml
└── translations
    ├── py.qm
    ├── py.ts
    ├── qml.qm
    └── qml.ts
 
  1. Создайте .ts с помощью pyside2-lupdate и lupdate:
     pyside2-lupdate main.py -ts translations/py.ts
    lupdate qml/main.qml -ts translations/qml.ts 
     
  2. Добавьте переводы с помощью инструмента Qt Linguist.
  3. Сгенерируйте .qm с использованием lrelease:
     lrelease translations/py.ts translations/py.qm
    lrelease translations/qml.ts translations/qml.qm
     
  4. Затем вам нужно загрузить оба перевода.

Если вы не хотите иметь несколько .ts или .qm, вы можете использовать lconvert для объединения файлов.

Полный пример вы можете найти здесь.