pyqt5qt-designerqt-linguist

Is there a way to use retreanslateUi in python code while the function being described in .ui file?


I'm creating a multilanguage desktop app using Qt Designer and PyQt5. I'm following this answer to make my app change languages dynamically.

I've created a .ui file via Qt Designer and I'm loading the UI directly in python code via loadUi. Therefore, the function retranslateUi is described in my ui.file unlike the retranslateUi function in link above (it is present in python code). I wouldn't like to put the described function in python code because there's a lot buttons and labels. How can I use this function in my code and to keep it only in .ui file?


Solution

  • uic.loadUi

    If you use the loadUi method it doesn't implement the retranslateUi method so if you use that method then the solution is the same as the previous post.

    demo.ui

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>Demo</class>
     <widget class="QWidget" name="Demo">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>102</width>
        <height>108</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>Form</string>
      </property>
      <layout class="QVBoxLayout" name="verticalLayout">
       <item>
        <widget class="QComboBox" name="combo"/>
       </item>
       <item>
        <widget class="QPushButton" name="button">
         <property name="text">
          <string>Start</string>
         </property>
        </widget>
       </item>
       <item>
        <widget class="QLabel" name="label">
         <property name="text">
          <string>Hello, World</string>
         </property>
         <property name="alignment">
          <set>Qt::AlignCenter</set>
         </property>
        </widget>
       </item>
      </layout>
     </widget>
     <resources/>
     <connections/>
    </ui>
    

    main.py

    import sys
    from PyQt5 import QtCore, QtGui, QtWidgets, uic
    
    
    class Demo(QtWidgets.QWidget):
        def __init__(self):
            super(Demo, self).__init__()
            uic.loadUi("demo.ui", self)
    
            self.combo.currentIndexChanged.connect(self.change_func)
    
            self.trans = QtCore.QTranslator(self)
    
            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-fr.qm
    lrelease eng-chs.ts eng-chs.qm
    

    pyuic

    On the other hand, if you are using pyuic5 to convert the .py then if the retranslateUi method is implemented so you can use it:

    pyuic5 demo.ui -o demo_ui.py
    pylupdate5 demo_ui.py  -ts eng-chs.ts
    pylupdate5 demo_ui.py  -ts eng-fr.ts
    

    Then use Qt Linguist to do the translations.

    And finally the .qm:

    lrelease eng-fr.ts eng-fr.qm
    lrelease eng-chs.ts eng-chs.qm
    

    main.py

    import sys
    from PyQt5 import QtCore, QtGui, QtWidgets, uic
    from demo_ui import Ui_Demo
    
    class Demo(QtWidgets.QWidget, Ui_Demo):
        def __init__(self):
            super(Demo, self).__init__()
            self.setupUi(self)
    
            self.combo.currentIndexChanged.connect(self.change_func)
    
            self.trans = QtCore.QTranslator(self)
    
            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(self)
    
        @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(self)
            super(Demo, self).changeEvent(event)
    
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        demo = Demo()
        demo.show()
        sys.exit(app.exec_())