pythonpyqtpyqt4pyqt5qt-linguist

How to change languages(translations) dynamically on PyQt5?


I wonder if it is possible to change the languages(translations) dynamically without using qt designer to make the UI? That means I don't want to use the function retranslateUi() to update the program interface.

Here is my code, but I'm stuck on lines marked #1 #2 #3. Don't know what I should use to update the interface.

import sys
from PyQt5.QtCore import Qt, QTranslator
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLabel, 
QComboBox, QVBoxLayout


class Demo(QWidget):
    def __init__(self):
        super(Demo, self).__init__()
        self.button = QPushButton(self.tr('Start'), self)
        self.label = QLabel(self.tr('Hello, World'), self)
        self.label.setAlignment(Qt.AlignCenter)

        self.combo = QComboBox(self)
        self.combo.addItem('English')
        self.combo.addItem('中文')
        self.combo.addItem('français')
        self.combo.currentTextChanged.connect(self.change_func)

        self.trans = QTranslator(self)

        self.v_layout = QVBoxLayout()
        self.v_layout.addWidget(self.combo)
        self.v_layout.addWidget(self.button)
        self.v_layout.addWidget(self.label)
        self.setLayout(self.v_layout)

    def change_func(self):
        print(self.combo.currentText())
        if self.combo.currentText() == '中文':
            self.trans.load('eng-chs')
            _app = QApplication.instance()
            _app.installTranslator(self.trans)
            # 1

        elif self.combo.currentText() == 'français':
            self.trans.load('eng-fr')
            _app = QApplication.instance()
            _app.installTranslator(self.trans)
            # 2

        else:
            _app = QApplication.instance()
            _app.removeTranslator(self.trans) 
             # 3


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

Any help would be appreciated.


Solution

  • TL; DR; It is not necessary to use Qt Designer


    You should not use Qt Designer necessarily but you should use the same technique, that is, create a method that could be called retranslateUi() and in it set the texts using translate() instead of tr() (for more details read the docs). Calling that method when you change language for it must use the changeEvent() event. For example in your case the code is as follows:

    import sys
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    class Demo(QtWidgets.QWidget):
        def __init__(self):
            super(Demo, self).__init__()
            self.button = QtWidgets.QPushButton()
            self.label = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
    
            self.combo = QtWidgets.QComboBox(self)
            self.combo.currentIndexChanged.connect(self.change_func)
    
            self.trans = QtCore.QTranslator(self)
    
            self.v_layout = QtWidgets.QVBoxLayout(self)
            self.v_layout.addWidget(self.combo)
            self.v_layout.addWidget(self.button)
            self.v_layout.addWidget(self.label)
    
            options = ([('English', ''), ('français', 'eng-fr' ), ('中文', 'eng-chs'), ])
            
            for i, (text, lang) in enumerate(options):
                self.combo.addItem(text)
                self.combo.setItemData(i, lang)
            self.retranslateUi()
    
        @QtCore.pyqtSlot(int)
        def change_func(self, index):
            data = self.combo.itemData(index)
            if data:
                self.trans.load(data)
                QtWidgets.QApplication.instance().installTranslator(self.trans)
            else:
                QtWidgets.QApplication.instance().removeTranslator(self.trans)
    
        def changeEvent(self, event):
            if event.type() == QtCore.QEvent.LanguageChange:
                self.retranslateUi()
            super(Demo, self).changeEvent(event)
    
        def retranslateUi(self):
            self.button.setText(QtWidgets.QApplication.translate('Demo', 'Start'))
            self.label.setText(QtWidgets.QApplication.translate('Demo', 'Hello, World'))
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        demo = Demo()
        demo.show()
        sys.exit(app.exec_())
    

    Then generate the .ts:

    pylupdate5 main.py  -ts eng-chs.ts
    pylupdate5 main.py  -ts eng-fr.ts
    

    Then use Qt Linguist to do the translations.

    And finally the .qm:

    lrelease eng-fr.ts eng-chs.qm
    

    enter image description here

    enter image description here

    enter image description here

    The complete project you find here.