Usually I do translate my Python applications with GNU gettext. But I realized that standard elements (e.g. QDialogButtonBox.Yes
) in a Qt GUI are not translated.
So I found examples with QTranslator
. I'm not sure if this is the correct approach. I would expect that Qt handles the translation itself and realize which locale is currently activate. I would expect a simple switch like .use_current_local()
.
I couldn't find such an Qt option so I tried the QTranslator
examples without understanding them in all details. The example here does run without errors but the buttons are not translated and looking like this.
I tried three variants for the value of the locale variable: explicit de_DE.UTF8
, QLocale.system().name
(returns de_DE
) and qt_de_DE
. The latter seems wired but comes from an real world example which I don't understand.
#!/usr/bin/env python3
from PyQt5.QtWidgets import QApplication, QDialogButtonBox
from PyQt5.QtCore import QTranslator, QLocale, QLibraryInfo
def get_translator():
translator = QTranslator()
# Variant 1
loc = QLocale.system().name()
# Variant 2
# loc = 'de_DE.utf-8', # qt_%s' % locale,
# Variant 3
# loc = 'qt_de_DE',
print(f'{loc=}') # <-- de_DE
translator.load(
loc,
QLibraryInfo.location(QLibraryInfo.TranslationsPath)
)
return translator
if __name__ == '__main__':
app = QApplication([])
t = get_translator()
app.installTranslator(t)
buttonBox = QDialogButtonBox(
QDialogButtonBox.Ok
| QDialogButtonBox.Cancel
| QDialogButtonBox.Yes
| QDialogButtonBox.No
)
buttonBox.show()
app.exec()
Please note I'm not interested to use Qt to replace my GNU gettext setup. I just want to have the standard Qt elements translated also. All other strings I set myself are still translated via GNU gettext.
I do use Debian 12 here. The qttranslations5-l10n
package is installed. Other Qt applications (e.g. backintime-qt
) do work and translate standard GUI elements like buttons without problems.
The problem is caused by a bug (see below) in the PyQt5 PyPI package. This package installs a local copy of Qt5 which includes invalid translation files. The specific issue is that the qt_xx.qm file depends on several other translation files, and if any one of them is missing, QTranslator.load()
will fail.
A temporary work-around is to copy/link the missing translation files from your system qt5 installation to your local pip installation, like this:
cp /usr/share/qt5/translations/qtscript_*.qm ~/.local/lib/python3.9/site-packages/PyQt5/Qt5/translations
Note that, ironically, it doesn't actually matter what the contents of these files are, since PyQt5 has never provided the QtScript module (which Qt has long-since deprecated anyway).
The bug is revealed by decompiling the qt_xx.qm file, like so:
lconvert /usr/share/qt/translations/qt_de.qm
which gives:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de">
<dependencies>
<dependency catalog="qtbase_de"/>
<dependency catalog="qtscript_de"/>
<dependency catalog="qtmultimedia_de"/>
<dependency catalog="qtxmlpatterns_de"/>
</dependencies>
</TS>
The relevant translations are actually provided by the qtbase_de file, but because the PyQt5 PyPI package does not include the qtscript_de file, QTranslator
bails out of the entire load operation!
UPDATE:
I reported the bug on the pyqt mailing-list, and the author has now fixed the underlying issue. However, it appears the PyPI packages won't be updated until a new version of PyQt5 is released, so until then, the above work-around will still be needed.