Search code examples
pythonqt4translationpyside

PySide Qt tr() does not translate, translate() does - context wrong?


I want to use a QTranslator to be able to use English text labels and still have the software showing German labels.

Unfortunately my app does not translate, except when I specify the context. The following static function instanciates a QApplication and adds the desired translators.

The first print translates 'Apple2' correctly to 'Apfel2'. The context in Qt Linguist also has the context 'app'. The second print does not translate though. tr() calls in classes (defined in the same python file) don't translate either.

def load_application():
    app = QApplication()

    qt_translator = QTranslator()
    qt_translator.load('qt_' + QLocale.system().name(), QLibraryInfo.location(QLibraryInfo.TranslationsPath))
    app.installTranslator(qt_translator)

    app_translator = QTranslator()
    r = app_translator.load('i18n/' + QLocale.system().name())
    app.installTranslator(app_translator)

    print(app.translate('app', 'Apple2'))
    print(app.tr('Apple'))

    return app

EDIT:

The part for the static function was correct. The context for the application was QApplication. This did not help with the QMainWindow subclass though. I updated the code accordingly. The context generated by pyside-lupdate for the class is MainWindow:

view

class MainWindow(QMainWindow):
    add_model_widget = None

    def __init__(self):
        QMainWindow.__init__(self)

        # Create menu bar
        menu_bar = QMenuBar(self)
        m_file = QMenu(self.tr('File'), menu_bar)
        a_add_model = QAction(QIcon('add.png'), self.tr('Add Jewel'), self)

        m_file.addAction(a_add_model)
        menu_bar.addMenu(m_file)
        self.setMenuBar(menu_bar)

def load_application():
    app = QApplication()

    app_translator = QTranslator()
    app_translator.load(QLocale.system().name(), 'i18n')
    app.installTranslator(app_translator)

    return app

controller

def initiate():
    model.initiate_mongodb()
    app = view.load_application()

    main_window = view.MainWindow()

    main_window.show()
    sys.exit(app.exec_())

Solution: The solution to my problem was that the QTranslator didn't have any parent. QTranslator(app) solved my problem.


Solution

  • This seems to happen because, unlike Qt, PySide/PyQt determines the context at runtime.

    In your example, the context will (I think) resolve to QApplication at runtime, whereas the pyside/pyqt lupdate tools will hardcode it as app. The tools only do static analysis of the source code, and so I suppose they are not smart enough to figure out what the correct class should be.

    The example code should work if you do something like this, though:

    class App(QtGui.QApplication):
        def __init__(self):
            super(App, self).__init__()
            message = self.tr('Apple')
    ...
    app = App()
    ...
    print(app.tr('Apple'))
    

    (Obviously you will need to update the translation files first).

    EDIT:

    Here's a simplified demo that works for me:

    test.py:

    import sys, os
    from PySide import QtCore, QtGui
    
    class MainWindow(QtGui.QMainWindow):
        def __init__(self):
            super(MainWindow, self).__init__()
            menu = self.menuBar().addMenu(self.tr('File'))
            menu.addAction(self.tr('Hello World'))
    
    if __name__ == '__main__':
    
        app = QtGui.QApplication(sys.argv)
        translator = QtCore.QTranslator(app)
        translator.load('i18n/tr_de', os.path.dirname(__file__))
        app.installTranslator(translator)
        window = MainWindow()
        window.show()
        sys.exit(app.exec_())
    

    i18n/tr.pro:

    SOURCES = ../test.py
    TRANSLATIONS = tr_de.ts
    

    i18n/tr_de.ts:

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE TS><TS version="1.1" language="de_DE">
    <context>
        <name>MainWindow</name>
        <message>
            <location filename="../test.py" line="7"/>
            <source>File</source>
            <translation>Datei</translation>
        </message>
        <message>
            <location filename="../test.py" line="8"/>
            <source>Hello World</source>
            <translation>Hallo Welt</translation>
        </message>
    </context>
    </TS>
    

    command output:

    $ pyside-lupdate -verbose -noobsolete i18n/tr.pro
    Updating 'tr_de.ts'...
        Found 2 source texts (2 new and 0 already existing)
    $ lrelease-qt4 i18n/tr.pro
    Updating './i18n/tr_de.qm'...
        Generated 2 translation(s) (2 finished and 0 unfinished)