Mit dem Qt Designer lassen sich grafische Oberflächen von Programmen leicht erstellen, auch für die PyQt-Bibliothek von Python. Allerdings wird die GUI immer nur in einer Sprache erstellt. Zur Laufzeit wäre es sehr aufwändig, die Texte mit den üblichen Mitteln wie gnu gettext auszutauschen. Qt sieht für dieses Problem den Qt Translator vor.
Er nutzt binäre Übersetzungsdateien, die mit dem Qt Linguist erzeugten und compiliert werden. Grundlage sind Wortlisten, die das Hilfsprogramm lupdate aus den Quelltexten der .ui Dateien extrahiert.
Um Designer und Linguist nutzen zu können, müssen unter Debian die Qt-Entwicklungswerkzeuge installiert werden:
sudo apt-get qt6-tools-dev-tools
Die Applikationen (u.a. designer, linguist, lupdate) befinden sich danach im Verzeichnis
/usr/lib/qt6/bin
Zur Verienfachung sollte man dieses directory in den PATH aufnehmen.
Zunächst erstellt man also in üblicher Weise mit dem Qt Designer die .ui Datei. Sie enthält in einer XML-Struktur die Beschreibung der Bedienoberfläche inklusive der angezeigten Texte. Das berühmte Hallo-Welt-Beispiel:

…erzeugt zum Beispiel folgende .ui Date:
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>150</x>
<y>130</y>
<width>91</width>
<height>22</height>
</rect>
</property>
<property name="text">
<string>Hallo Welt!</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>
Das Hilfsprogramm lupdate
extrahiert die Texte aus der .ui
Datei:
/usr/lib/qt6/bin/lupdate hallowelt.ui -ts hallowelt.ts
… und erzeugt folgende .ts Datei, in der die Übersetzung noch als unerledigt markiert ist:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>Dialog</name>
<message>
<location filename="hallowelt.ui" line="14"/>
<source>Dialog</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="hallowelt.ui" line="26"/>
<source>Hallo Welt!</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>
Die Übersetzung erledigt man mit dem Qt Linguist, in dem man die .ts Datei öffnet und zunächst Quell- und Zielsprache auswählt:

Danach klickt man den jeweiligen Ursprungstext an, trägt die Übersetzung ein und markiert sie mit dem Haken in der Menüleiste als erledigt.

Die um die Übersetzungen ergänzte .ts
Datei wird über „Datei -> Speichern
” gespeichert und sieht dann so aus:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="en_US" sourcelanguage="de_DE">
<context>
<name>Dialog</name>
<message>
<location filename="hallowelt.ui" line="14"/>
<source>Dialog</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="hallowelt.ui" line="26"/>
<source>Hallo Welt!</source>
<translation>Hello World</translation>
</message>
</context>
</TS>
Wenn alle Übersetzungen eingetragen sind, kann die Datei in Binärform über „Datei -> Freigeben
” gespeichert werden. Das erzeugt die .qm
Datei, die später in Python geladen wird.
Damit sind die Vorbereitungen getroffen, und die Übersetzung kann in der Python-Applikation geladen werden. Eine minimale Test-Applikation lädt mit uic.load
die mit dem Designer erzeugte GUI-Datei hallowelt.ui
:
import sys
from os import getcwd, path
from PyQt6 import uic
from PyQt6.QtWidgets import QApplication, QDialog
class HalloWelt(QDialog):
def __init__(self):
super(HalloWelt, self).__init__()
uic.loadUi(path.join(getcwd(), 'hallowelt.ui'), self)
self.show()
app = QApplication(sys.argv)
window = HalloWelt()
app.exec()
Sie erzeugt folgendes Fenster:

Nun binden wir den Translator ein und laden die oben erzeugte englische Übersetzung in Binärform (hallowelt.qm
):
import sys
from os import getcwd, path
from PyQt6 import uic
from PyQt6.QtCore import QTranslator
from PyQt6.QtWidgets import QApplication, QDialog
class HalloWelt(QDialog):
def __init__(self):
super(HalloWelt, self).__init__()
uic.loadUi(path.join(getcwd(), 'hallowelt.ui'), self)
self.show()
app = QApplication(sys.argv)
translator = QTranslator(app)
if translator.load("hallowelt.qm", getcwd()):
app.installTranslator(translator)
window = HalloWelt()
app.exec()
Damit sieht das Fenster dann so aus:

Um die Sprache dynamisch wechseln zu können, erweitern wir die Oberfläche um zwei Tasten zum Umschalten:

… und geben ihnen die Funktion, die Übersetzung neu zu laden:
import sys
from os import getcwd, path
from PyQt6 import uic
from PyQt6.uic import loadUiType
from PyQt6.QtCore import QTranslator
from PyQt6.QtWidgets import QApplication, QDialog
UiClass, BaseClass = loadUiType('hallowelt.ui')
class HalloWelt(BaseClass, UiClass):
def __init__(self):
super(HalloWelt, self).__init__()
self.translator = None
uic.loadUi(path.join(getcwd(), 'hallowelt.ui'), self)
self.btnDe.clicked.connect(lambda: self.change_translation('de'))
self.btnEn.clicked.connect(lambda: self.change_translation('en'))
self.show()
def change_translation(self, lang):
if self.translator: app.removeTranslator(self.translator)
self.translator = QTranslator(app)
if self.translator.load(f"hallowelt_{lang}.qm", getcwd()):
app.installTranslator(self.translator)
self.retranslateUi(self)
app = QApplication(sys.argv)
translator = QTranslator(app)
if translator.load("hallowelt_de.qm", getcwd()):
app.installTranslator(translator)
window = HalloWelt()
app.exec()
Für jede Sprache muss jeweils eine .ts
und .qm
Datei angelegt werden. Dazu erzeugt man sich eine Projektdatei (hallowelt.pro
) und trägt die Quellen und Ziele der Übersetzungen ein:
SOURCES += hallowelt.ui hallowelt.py
TRANSLATIONS += hallowelt_de.ts hallowelt_en.ts
Dann kann man sich mit lupdate
in einem Rutsch alle .ts
-Dateien anlegen lassen:
$ /usr/lib/qt6/bin/lupdate hallowelt.pro
Info: creating stash file /home/joerg/PycharmProjects/test/.qmake.stash
Updating 'hallowelt_de.ts'...
Found 4 source text(s) (4 new and 0 already existing)
Updating 'hallowelt_en.ts'...
Found 4 source text(s) (4 new and 0 already existing)
Im Linuist kann man entweder jede Sprache getrennt in ihrer .ts
-Datei bearbeiten und freigeben, oder alle .ts
-Dateien gleichzeitig öffnen. Im letzteren Fall werden dann alle Übersetzungen gleichzeitig angezeigt. Nach Abschluss der Arbeiten kann man dann alle .ts
-Dateien mit „Alles speichern
” und alle .qm
-Dateien mit „Alles freigeben
” erzeugen lassen.

Mit den qm-Dateien lässt sich dann die Übersetzung in der laufenden Applikation umschalten:


Nutzt man ohnehin den Qt-Translator für die Übersetzung der mit dem Qt-Designer erzeugten Elemente, kann man auch alle anderen Texte in der Python-Applikation damit übersetzen. Damit lupdate
die Texte sicher findet (und um etwas Schreibarbeit einzusparen), legt man sich die tr-Funktion des Translators am besten auf eine Variable „tr
”:
tr = translator.tr
translated_text = tr('Hallo Welt')