在 PySide 上完成 QtQuick 本地化
Complete QtQuick Localization on PySide
我知道 Localization in QtQuick from top to bottom 上发布了几乎相同的问题,但那里的人已经知道如何开始,而且它基于 C++。
在我的问题中,我还必须实时翻译 QML 端的所有字符串,但后端使用 Python (PySide) 而不是 C++。由于我是这部分的新手,我不知道如何以最少的 Python 使用来实现这一点。
根据链接的问题,我目前能够:
- 将 QT_TR_NOOP() 附加到我所有的可翻译字符串,以便在运行时进行翻译。
但是我不清楚那里描述的进一步步骤。 Python 的 QML 文档非常简约。
非常感谢您提供一些详细的描述或示例。
逻辑类似于在 C++ 中所做的,因为 QML 不会改变任何东西,您只需要调整 python 中的逻辑。
步骤如下:
使用 lupdate 从 qml 生成 .ts。
lupdate main.qml -ts i18n_es.ts
使用 Qt Linguist 添加翻译。
使用 lrelease 将 .ts 编译为 .qm。
lrelease i18n_es.ts i18n_es.qm
使用 python 加载 .qm。
├── main.py
├── qml
│ └── main.qml
└── translations
├── i18n_es.qm
├── i18n_es.ts
├── i18n_fr.qm
└── i18n_fr.ts
main.py
import os
import re
import sys
from pathlib import Path
from PySide2.QtCore import (
Property,
QCoreApplication,
QDir,
QObject,
Qt,
QTranslator,
QUrl,
Signal,
Slot,
)
from PySide2.QtGui import QGuiApplication, QStandardItem, QStandardItemModel
from PySide2.QtQml import QQmlApplicationEngine
CURRENT_DIRECTORY = Path(__file__).resolve().parent
QML_DIRECTORY = CURRENT_DIRECTORY / "qml"
TRANSLATIONS_DIR = CURRENT_DIRECTORY / "translations"
class Translator(QObject):
language_changed = Signal(name="languageChanged")
def __init__(self, engine, parent=None):
super().__init__(parent)
self._engine = engine
self._languages_model = QStandardItemModel()
self.load_translations()
self._translator = QTranslator()
@Slot(str)
def set_language(self, language):
if language != "Default":
trans_dir = QDir(os.fspath(TRANSLATIONS_DIR))
filename = trans_dir.filePath(f"i18n_{language}.qm")
if not self._translator.load(filename):
print("Failed")
QGuiApplication.installTranslator(self._translator)
else:
QGuiApplication.removeTranslator(self._translator)
self._engine.retranslate()
def languages_model(self):
return self._languages_model
languages = Property(QObject, fget=languages_model, constant=True)
def load_translations(self):
self._languages_model.clear()
item = QStandardItem("Default")
self._languages_model.appendRow(item)
trans_dir = QDir(os.fspath(TRANSLATIONS_DIR))
for filename in trans_dir.entryList(["*.qm"], QDir.Files, QDir.Name):
language = re.search(r"i18n_(.*?)\.qm", filename).group(1)
item = QStandardItem(language)
self._languages_model.appendRow(item)
def main():
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
translator = Translator(engine, app)
engine.rootContext().setContextProperty("translator", translator)
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)
sys.exit(app.exec_())
if __name__ == "__main__":
main()
main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
ApplicationWindow {
width: 640
height: 480
visible: true
title: qsTr("Title")
ListModel {
id: list_model
ListElement {
name: QT_TR_NOOP("house")
}
ListElement {
name: QT_TR_NOOP("table")
}
ListElement {
name: QT_TR_NOOP("chair")
}
}
ColumnLayout {
anchors.fill: parent
ComboBox {
model: translator ? translator.languages : null
textRole: "display"
Layout.fillWidth: true
onActivated: function(index) {
translator.set_language(currentText);
}
}
Button {
text: qsTr("name")
Layout.fillWidth: true
}
ListView {
model: list_model
Layout.fillWidth: true
Layout.fillHeight: true
delegate: Text {
text: qsTr(name)
}
}
}
}
完整示例为here。
我知道 Localization in QtQuick from top to bottom 上发布了几乎相同的问题,但那里的人已经知道如何开始,而且它基于 C++。
在我的问题中,我还必须实时翻译 QML 端的所有字符串,但后端使用 Python (PySide) 而不是 C++。由于我是这部分的新手,我不知道如何以最少的 Python 使用来实现这一点。
根据链接的问题,我目前能够:
- 将 QT_TR_NOOP() 附加到我所有的可翻译字符串,以便在运行时进行翻译。
但是我不清楚那里描述的进一步步骤。 Python 的 QML 文档非常简约。
非常感谢您提供一些详细的描述或示例。
逻辑类似于在 C++ 中所做的,因为 QML 不会改变任何东西,您只需要调整 python 中的逻辑。
步骤如下:
使用 lupdate 从 qml 生成 .ts。
lupdate main.qml -ts i18n_es.ts
使用 Qt Linguist 添加翻译。
使用 lrelease 将 .ts 编译为 .qm。
lrelease i18n_es.ts i18n_es.qm
使用 python 加载 .qm。
├── main.py
├── qml
│ └── main.qml
└── translations
├── i18n_es.qm
├── i18n_es.ts
├── i18n_fr.qm
└── i18n_fr.ts
main.py
import os
import re
import sys
from pathlib import Path
from PySide2.QtCore import (
Property,
QCoreApplication,
QDir,
QObject,
Qt,
QTranslator,
QUrl,
Signal,
Slot,
)
from PySide2.QtGui import QGuiApplication, QStandardItem, QStandardItemModel
from PySide2.QtQml import QQmlApplicationEngine
CURRENT_DIRECTORY = Path(__file__).resolve().parent
QML_DIRECTORY = CURRENT_DIRECTORY / "qml"
TRANSLATIONS_DIR = CURRENT_DIRECTORY / "translations"
class Translator(QObject):
language_changed = Signal(name="languageChanged")
def __init__(self, engine, parent=None):
super().__init__(parent)
self._engine = engine
self._languages_model = QStandardItemModel()
self.load_translations()
self._translator = QTranslator()
@Slot(str)
def set_language(self, language):
if language != "Default":
trans_dir = QDir(os.fspath(TRANSLATIONS_DIR))
filename = trans_dir.filePath(f"i18n_{language}.qm")
if not self._translator.load(filename):
print("Failed")
QGuiApplication.installTranslator(self._translator)
else:
QGuiApplication.removeTranslator(self._translator)
self._engine.retranslate()
def languages_model(self):
return self._languages_model
languages = Property(QObject, fget=languages_model, constant=True)
def load_translations(self):
self._languages_model.clear()
item = QStandardItem("Default")
self._languages_model.appendRow(item)
trans_dir = QDir(os.fspath(TRANSLATIONS_DIR))
for filename in trans_dir.entryList(["*.qm"], QDir.Files, QDir.Name):
language = re.search(r"i18n_(.*?)\.qm", filename).group(1)
item = QStandardItem(language)
self._languages_model.appendRow(item)
def main():
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
translator = Translator(engine, app)
engine.rootContext().setContextProperty("translator", translator)
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)
sys.exit(app.exec_())
if __name__ == "__main__":
main()
main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
ApplicationWindow {
width: 640
height: 480
visible: true
title: qsTr("Title")
ListModel {
id: list_model
ListElement {
name: QT_TR_NOOP("house")
}
ListElement {
name: QT_TR_NOOP("table")
}
ListElement {
name: QT_TR_NOOP("chair")
}
}
ColumnLayout {
anchors.fill: parent
ComboBox {
model: translator ? translator.languages : null
textRole: "display"
Layout.fillWidth: true
onActivated: function(index) {
translator.set_language(currentText);
}
}
Button {
text: qsTr("name")
Layout.fillWidth: true
}
ListView {
model: list_model
Layout.fillWidth: true
Layout.fillHeight: true
delegate: Text {
text: qsTr(name)
}
}
}
}
完整示例为here。