如何在Qt中使用UI表单在运行时进行动态翻译?

3

我正在寻找一个相对简单的示例,以了解如何进行动态翻译。我正在创建一个关于使用Qt资源系统以及UI和TS文件的教程。为此,我已经创建了一个基本的UI表单:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>widget_form</class>
 <widget class="QWidget" name="widget_form">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>860</width>
    <height>527</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Get Started</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout_2">
   <item>
    <layout class="QHBoxLayout" name="horizontalLayout_2">
     <item>
      <widget class="QPushButton" name="btn_import_file">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
         <horstretch>0</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
       <property name="styleSheet">
        <string notr="true">image: url(:/icons/files/import);</string>
       </property>
       <property name="text">
        <string/>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="btn_check_file">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
         <horstretch>0</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
       <property name="styleSheet">
        <string notr="true">image: url(:/icons/files/check);</string>
       </property>
       <property name="text">
        <string/>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="btn_delete_file">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
         <horstretch>0</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
       <property name="styleSheet">
        <string notr="true">image: url(:/icons/files/delete);</string>
       </property>
       <property name="text">
        <string/>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="btn_add_file">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
         <horstretch>0</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
       <property name="styleSheet">
        <string notr="true">image: url(:/icons/files/add);</string>
       </property>
       <property name="text">
        <string/>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QComboBox" name="cb_change_lang">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
         <horstretch>0</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
       <property name="styleSheet">
        <string notr="true"/>
       </property>
      </widget>
     </item>
    </layout>
   </item>
   <item>
    <layout class="QHBoxLayout" name="horizontalLayout">
     <item>
      <widget class="QPlainTextEdit" name="pte_file_view">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
         <horstretch>1</horstretch>
         <verstretch>1</verstretch>
        </sizepolicy>
       </property>
      </widget>
     </item>
     <item>
      <widget class="Line" name="vline_right">
       <property name="orientation">
        <enum>Qt::Vertical</enum>
       </property>
      </widget>
     </item>
     <item>
      <layout class="QVBoxLayout" name="verticalLayout">
       <item>
        <widget class="QPushButton" name="btn_csv">
         <property name="sizePolicy">
          <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
         <property name="styleSheet">
          <string notr="true">image: url(:/icons/files/csv);</string>
         </property>
         <property name="text">
          <string/>
         </property>
        </widget>
       </item>
       <item>
        <widget class="QPushButton" name="btn_code">
         <property name="sizePolicy">
          <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
         <property name="styleSheet">
          <string notr="true">image: url(:/icons/files/code);</string>
         </property>
         <property name="text">
          <string/>
         </property>
        </widget>
       </item>
       <item>
        <widget class="QPushButton" name="btn_json">
         <property name="sizePolicy">
          <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
         <property name="styleSheet">
          <string notr="true">image: url(:/icons/files/json);</string>
         </property>
         <property name="text">
          <string/>
         </property>
        </widget>
       </item>
       <item>
        <widget class="QPushButton" name="btn_xml">
         <property name="sizePolicy">
          <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
         <property name="styleSheet">
          <string notr="true">image: url(:/icons/files/xml);</string>
         </property>
         <property name="text">
          <string/>
         </property>
        </widget>
       </item>
      </layout>
     </item>
    </layout>
   </item>
  </layout>
 </widget>
 <resources>
  <include location="../resources.qrc"/>
 </resources>
 <connections/>
</ui>

我将其与一堆用作图标的图像一起添加到QRC文件中:

<RCC>
  <qresource prefix="icons/files">
    <file alias="xml">icons/file-formats/icons8-xml-96.png</file>
    <file alias="json">icons/file-formats/icons8-json-96.png</file>
    <file alias="csv">icons/file-formats/icons8-csv-96.png</file>
    <file alias="code">icons/file-formats/icons8-code-96.png</file>
  </qresource>
  <qresource prefix="icons/files">
    <file alias="import">icons/file-ops/icons8-import-96.png</file>
    <file alias="delete">icons/file-ops/icons8-delete-file-96.png</file>
    <file alias="check">icons/file-ops/icons8-check-file-96.png</file>
    <file alias="add">icons/file-ops/icons8-add-file-96.png</file>
  </qresource>
  <qresource prefix="icons/flags">
    <file alias="fr">icons/flags/icons8-france-80.png</file>
    <file alias="de">icons/flags/icons8-germany-80.png</file>
    <file alias="gb">icons/flags/icons8-great-britain-80.png</file>
    <file alias="ru">icons/flags/icons8-russian-federation-80.png</file>
  </qresource>
  <qresource prefix="forms">
     <file alias="main">ui/widget.ui</file>
  </qresource>
</RCC>

我使用以下的CMakeLists.txt来管理我的项目:
cmake_minimum_required(VERSION 3.13)

project(ExampleGetStarted LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(CMAKE_POSITION_INDEPENDENT_CODE OFF)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)

if(CMAKE_VERSION VERSION_LESS "3.7.0")
    set(CMAKE_INCLUDE_CURRENT_DIR ON)
endif()

find_package(Qt5
    COMPONENTS
        Widgets
        Xml
        XmlPatterns
        Concurrent
        UiTools
        LinguistTools
    REQUIRED
)
#find_package(Qt5XmlPatterns REQUIRED)

# TODO https://stackoverflow.com/questions/51217734/how-to-add-qt-translations-to-cmake

set(RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/resources/resources.qrc)
set(TS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/resources/translations)
qt5_create_translation(TS_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_DIR}/en.ts ${TS_DIR}/de.ts)
#qt5_add_translation(TS_FILES_FINISHED ${TS_DIR}/en.ts ${TS_DIR}/de.ts)
# TODO Convert configure_file to custom post-build action. QM files are initially not available
#configure_file(${QM_FILES} ${CMAKE_BINARY_DIR} COPYONLY)
#qt5_add_translation(QM_FILES ${TS_FILES})

add_executable(example_get_started
    example_get_started.cpp
    ${RESOURCES}
    ${TS_FILES}
)
target_link_libraries(example_get_started
    Qt5::Widgets
    Qt5::Xml Qt5::XmlPatterns
    Qt5::Concurrent
    Qt5::UiTools
    #Qt5::LinguistTools
)
# Copy translations to binary directory where executable can access thoses
foreach(TS_FILE ${TS_FILES})
    add_custom_command(
        TARGET example_get_started POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy
                ${TS_FILE}
                ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
        COMMENT "Copied ${TS_FILE} to binary directory"
        )
endforeach(TS_FILE)

UI表单使用以下代码进行加载(正在进行中):
#include <vector>
#include <utility>
#include <iostream>

#include <QApplication>
#include <QtWidgets>
#include <QtUiTools>
#include <QFile>
#include <QTranslator>

QScopedPointer<QTranslator> translator(new QTranslator());

static QWidget *loadUiFile(QWidget *parent)
{
    QFile file(":/forms/main");
    file.open(QIODevice::ReadOnly);

    QUiLoader loader;
    return loader.load(&file, parent);
}

static void retranslate(QString lang_code)
{
    std::cout << "Translating to " << lang_code.toStdString() << std::endl;
    std::cout << "Looking into directory \"" << QApplication::applicationDirPath().toStdString() << "\"" << std::endl;
    if (lang_code == QString("fr"))
    {
        if (translator->load("fr", QApplication::applicationDirPath()))
        {
            QApplication::instance()->installTranslator(translator.data());
            std::cout << "Switched to " << lang_code.toStdString() << std::endl;
        }
        else
            std::cout << "Unable to load translation for " << lang_code.toStdString() << std::endl;
    }
    else if (lang_code == QString("de"))
    {
        if (translator->load("de", QApplication::applicationDirPath()))
        {
            QApplication::instance()->installTranslator(translator.data());
            std::cout << "Switched to " << lang_code.toStdString() << std::endl;
        }
        else
            std::cout << "Unable to load translation for " << lang_code.toStdString() << std::endl;
    }
    else if (lang_code == QString("ru"))
    {
        if (translator->load("ru", QApplication::applicationDirPath()))
        {
            QApplication::instance()->installTranslator(translator.data());
            std::cout << "Switched to " << lang_code.toStdString() << std::endl;
        }
        else
            std::cout << "Unable to load translation for " << lang_code.toStdString() << std::endl;
    }
    else
    {
        QApplication::instance()->removeTranslator(translator.data());
    }
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // Translations need to be created before widgets they affect
    /*
if (!translator->load("en_GB.qm"))
    std::cout << "Unable to load translation file \"en_GB\"" << std::endl;
app.installTranslator(translator.data());
if (!translator->load("de_DE.qm"))
    std::cout << "Unable to load translation file \"de_DE\"" << std::endl;
app.installTranslator(translator.data());
std::cout << translator->language().toStdString() << std::endl;
*/

    QWidget *widget = loadUiFile(nullptr);
    widget->findChild<QPushButton *>("btn_add_file")->setToolTip(QObject::tr("Create a new file"));
    widget->findChild<QPushButton *>("btn_check_file")->setToolTip(QObject::tr("Check the opened file's contents for errors"));
    widget->findChild<QPushButton *>("btn_delete_file")->setToolTip(QObject::tr("Deletes the opened file's contents"));
    widget->findChild<QPushButton *>("btn_import_file")->setToolTip(QObject::tr("Import existing file"));
    QComboBox *cb_change_lang = widget->findChild<QComboBox *>("cb_change_lang");
    std::vector<std::pair<QString, QIcon>> langs = {
        std::pair<QString, QIcon>(QObject::tr("English (en)"), QIcon(":/icons/flags/gb")),
        std::pair<QString, QIcon>(QObject::tr("Deutsch (de)"), QIcon(":/icons/flags/de")),
        std::pair<QString, QIcon>(QObject::tr("Français (fr)"), QIcon(":/icons/flags/fr")),
        std::pair<QString, QIcon>(QObject::tr("Руский (ru)"), QIcon(":/icons/flags/ru"))};
    auto lang_idx = 0;
    for (auto lang : langs)
    {
        cb_change_lang->insertItem(lang_idx, lang.first);
        cb_change_lang->setItemIcon(lang_idx, lang.second);
        lang_idx++;
    }

    QRegularExpression regex("\\(([^()]+)\\)");
    QObject::connect(cb_change_lang,
                     qOverload<int>(&QComboBox::currentIndexChanged),
                     [=](int idx)
                     {
                         retranslate(regex.match(langs.at(cb_change_lang->currentIndex()).first).captured(1));
                     });
    std::cout << regex.match(langs.at(cb_change_lang->currentIndex()).first).captured(1).toStdString() << std::endl;

    widget->show();
    return app.exec();
}

小部件长这样:

Widget that uses QRC, TS and UI files

我想保留我的小部件的创建方式(在C++中加载UI文件并添加一些额外功能)。我的QTranslator是全局的原因是需要让翻译器与QApplication实例同生共死。

它应该工作的方式(但目前没有)是每当更改QComboBox(屏幕截图右上角)中当前选定的项目时,每个按钮的工具提示都会被翻译。我对Qt的翻译设施非常陌生,而且文档在这方面并不真正出色(这是个人意见)。

在开始动态翻译之前,我在main()中加载了一个QM文件,它可以工作-工具提示以QM文件所用的语言显示。只有在添加新功能后,我才看不到任何变化。

1个回答

1

我四处搜索并在官方Qt论坛上询问。一些给我的建议让我重新调整了我的代码:

CMakeLists.txt

cmake_minimum_required(VERSION 3.13)

project(ExampleGetStarted LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)

find_package(Qt5
    COMPONENTS
        Core
        Widgets
        Xml
        XmlPatterns
        Concurrent
        UiTools
        LinguistTools
    REQUIRED
)

set(RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/resources/resources.qrc)
set(TS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/resources/translations)
qt5_create_translation(TS_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_DIR}/en.ts ${TS_DIR}/de.ts ${TS_DIR}/fr.ts ${TS_DIR}/ru.ts)


add_executable(example_get_started
    example_get_started.cpp
    ${RESOURCES}
    ${TS_FILES}
)
target_link_libraries(example_get_started
    Qt5::Core
    Qt5::Widgets
    Qt5::Xml Qt5::XmlPatterns
    Qt5::Concurrent
    Qt5::UiTools
)
# Copy translations to binary directory where executable can access these
foreach(TS_FILE ${TS_FILES})
    add_custom_command(
        TARGET example_get_started POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy
                ${TS_FILE}
                ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
        COMMENT "Copied ${TS_FILE} to binary directory"
        )
endforeach(TS_FILE)

CPP文件

#include <vector>
#include <utility>

#include <QApplication>
#include <QtWidgets>
#include <QtUiTools>
#include <QFile>
#include <QTranslator>
#include <QDebug>

// Needs to be included so that the header file is generated. Note that if the UI file is in a subdirectory, that also needs to be specified here
#include "resources/ui/ui_widget.h"

QScopedPointer<QTranslator> translator(new QTranslator());

class MainWidget : public QWidget
{
    Q_OBJECT

    Ui::widget_form *ui;
    QString lang_curr = "en";

public:
    MainWidget(QWidget* parent=nullptr)
        : QWidget(parent),
          ui(new Ui::widget_form)
    {
        ui->setupUi(this);

        QRegularExpression regex("\\(([^()]+)\\)");
        QObject::connect(ui->cb_change_lang,
                         qOverload<int>(&QComboBox::currentIndexChanged),
                         [=](int idx)
                         {
                             retranslate(regex.match(ui->cb_change_lang->currentText()).captured(1));
                         });
    }

    ~MainWidget()
    {
        delete ui;
    }
protected:
    void changeEvent(QEvent *event) override
    {
        if (event->type() == QEvent::LanguageChange)
        {
            ui->retranslateUi(this);
        }

        return QWidget::changeEvent(event);
    }
private:
    void retranslate(QString lang_code)
    {
        if (lang_code == QString("fr"))
        {
            if (translator->load("fr", QApplication::applicationDirPath()))
            {
                QApplication::instance()->removeTranslator(translator.data());
                QApplication::instance()->installTranslator(translator.data());
                lang_curr = lang_code;
            }
            else
                qDebug() << "Unable to load translation for " << lang_code;
        }
        else if (lang_code == QString("de"))
        {
            if (translator->load("de", QApplication::applicationDirPath()))
            {
                QApplication::instance()->removeTranslator(translator.data());
                QApplication::instance()->installTranslator(translator.data());
                lang_curr = lang_code;
            }
            else
                qDebug() << "Unable to load translation for " << lang_code;
        }
        else if (lang_code == QString("ru"))
        {
            if (translator->load("ru", QApplication::applicationDirPath()))
            {
                QApplication::instance()->removeTranslator(translator.data());
                QApplication::instance()->installTranslator(translator.data());
                lang_curr = lang_code;
            }
            else
                qDebug() << "Unable to load translation for " << lang_code;
        }
        else
        {
            if (translator->load("en", QApplication::applicationDirPath()))
            {
                QApplication::instance()->removeTranslator(translator.data());
                QApplication::instance()->installTranslator(translator.data());
                lang_curr = lang_code;
            }
            else
                qDebug() << "Unable to load translation for " << lang_code;
        }
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    MainWidget mw;
    mw.show();
    return app.exec();
}

#include "example_get_started.moc"

XML UI表单文件

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>widget_form</class>
 <widget class="QWidget" name="widget_form">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>860</width>
    <height>527</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string notr="true">Get Started</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout_2">
   <item>
    <layout class="QHBoxLayout" name="horizontalLayout_2">
     <item>
      <widget class="QPushButton" name="btn_create_file">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
         <horstretch>0</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
       <property name="toolTip">
        <string>Create a new file</string>
       </property>
       <property name="styleSheet">
        <string notr="true">image: url(:/icons/files/create);</string>
       </property>
       <property name="text">
        <string/>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="btn_import_file">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
         <horstretch>0</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
       <property name="toolTip">
        <string>Import existing file</string>
       </property>
       <property name="styleSheet">
        <string notr="true">image: url(:/icons/files/import);</string>
       </property>
       <property name="text">
        <string/>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="btn_delete_file">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
         <horstretch>0</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
       <property name="toolTip">
        <string>Delete the opened file's contents</string>
       </property>
       <property name="styleSheet">
        <string notr="true">image: url(:/icons/files/delete);</string>
       </property>
       <property name="text">
        <string/>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="btn_check_file">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
         <horstretch>0</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
       <property name="toolTip">
        <string>Check the opened file's contents for errors</string>
       </property>
       <property name="styleSheet">
        <string notr="true">image: url(:/icons/files/check);</string>
       </property>
       <property name="text">
        <string/>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QComboBox" name="cb_change_lang">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
         <horstretch>0</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
       <property name="styleSheet">
        <string notr="true"/>
       </property>
       <item>
        <property name="text">
         <string>English (en)</string>
        </property>
        <property name="icon">
         <iconset resource="../resources.qrc">
          <normaloff>:/icons/flags/gb</normaloff>:/icons/flags/gb</iconset>
        </property>
       </item>
       <item>
        <property name="text">
         <string>Deutsch (de)</string>
        </property>
        <property name="icon">
         <iconset resource="../resources.qrc">
          <normaloff>:/icons/flags/de</normaloff>:/icons/flags/de</iconset>
        </property>
       </item>
       <item>
        <property name="text">
         <string>Français (fr)</string>
        </property>
        <property name="icon">
         <iconset resource="../resources.qrc">
          <normaloff>:/icons/flags/fr</normaloff>:/icons/flags/fr</iconset>
        </property>
       </item>
       <item>
        <property name="text">
         <string>Руский (ru)</string>
        </property>
        <property name="icon">
         <iconset resource="../resources.qrc">
          <normaloff>:/icons/flags/ru</normaloff>:/icons/flags/ru</iconset>
        </property>
       </item>
      </widget>
     </item>
    </layout>
   </item>
   <item>
    <layout class="QHBoxLayout" name="horizontalLayout">
     <item>
      <widget class="QPlainTextEdit" name="pte_file_view">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
         <horstretch>1</horstretch>
         <verstretch>1</verstretch>
        </sizepolicy>
       </property>
      </widget>
     </item>
     <item>
      <widget class="Line" name="vline_right">
       <property name="orientation">
        <enum>Qt::Vertical</enum>
       </property>
      </widget>
     </item>
     <item>
      <layout class="QVBoxLayout" name="verticalLayout">
       <item>
        <widget class="QPushButton" name="btn_csv">
         <property name="sizePolicy">
          <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
         <property name="toolTip">
          <string>Create CSV file</string>
         </property>
         <property name="styleSheet">
          <string notr="true">image: url(:/icons/files/csv);</string>
         </property>
         <property name="text">
          <string/>
         </property>
        </widget>
       </item>
       <item>
        <widget class="QPushButton" name="btn_code">
         <property name="sizePolicy">
          <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
         <property name="toolTip">
          <string>Create script file</string>
         </property>
         <property name="styleSheet">
          <string notr="true">image: url(:/icons/files/code);</string>
         </property>
         <property name="text">
          <string/>
         </property>
        </widget>
       </item>
       <item>
        <widget class="QPushButton" name="btn_json">
         <property name="sizePolicy">
          <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
         <property name="toolTip">
          <string>Create JSON file</string>
         </property>
         <property name="styleSheet">
          <string notr="true">image: url(:/icons/files/json);</string>
         </property>
         <property name="text">
          <string/>
         </property>
        </widget>
       </item>
       <item>
        <widget class="QPushButton" name="btn_xml">
         <property name="sizePolicy">
          <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
         <property name="toolTip">
          <string>Create XML file</string>
         </property>
         <property name="styleSheet">
          <string notr="true">image: url(:/icons/files/xml);</string>
         </property>
         <property name="text">
          <string/>
         </property>
        </widget>
       </item>
      </layout>
     </item>
    </layout>
   </item>
  </layout>
 </widget>
 <resources>
  <include location="../resources.qrc"/>
 </resources>
 <connections/>
</ui>

我所做的是:
  • QUiLoader替换为我更有经验的标准UI表单文件加载方式(我对UI表单一般没有太多经验:D)

  • 将我在源代码中设置的所有工具提示移动到UI表单文件中-下一个点会更详细地介绍

  • 在使用UI表单文件的窗口小部件的源代码中添加changeEvent() - 通过处理QEvent::LanguageChanged并使用这种方式加载UI,可以访问retranslateUi()函数。当生成表示UI表单文件的头文件(这里是ui_widget.h)时,该函数会自动生成。该函数使得可以自动重新翻译所有标记为可翻译的字符串(在Qt Designer中,这是translateable复选框)。最初(在前一个点之前),我发现retranslateUi()不包括我的任何工具提示。显然,在源代码中混合字符串和UI表单字符串不像我想象的那样有效。通过将工具提示移动到UI表单文件中,我从最初的

     void retranslateUi(QWidget *widget_form)
     {
         btn_create_file->setText(QString());
         btn_import_file->setText(QString());
         btn_delete_file->setText(QString());
         btn_check_file->setText(QString());
         cb_change_lang->setItemText(0, QCoreApplication::translate("widget_form", "English (en)", nullptr));
         cb_change_lang->setItemText(1, QCoreApplication::translate("widget_form", "Deutsch (de)", nullptr));
         cb_change_lang->setItemText(2, QCoreApplication::translate("widget_form", "Fran\303\247ais (fr)", nullptr));
         cb_change_lang->setItemText(3, QCoreApplication::translate("widget_form", "\320\240\321\203\321\201\320\272\320\270\320\271 (ru)", nullptr));
         btn_csv->setText(QString());
         btn_code->setText(QString());
         btn_json->setText(QString());
         btn_xml->setText(QString());
         (void)widget_form;
     } // retranslateUi
    

    变成了

     void retranslateUi(QWidget *widget_form)
     {
     #if QT_CONFIG(tooltip)
         btn_create_file->setToolTip(QCoreApplication::translate("widget_form", "Create a new file", nullptr));
     #endif // QT_CONFIG(tooltip)
         btn_create_file->setText(QString());
     #if QT_CONFIG(tooltip)
         btn_import_file->setToolTip(QCoreApplication::translate("widget_form", "Import existing file", nullptr));
     #endif // QT_CONFIG(tooltip)
         btn_import_file->setText(QString());
     #if QT_CONFIG(tooltip)
         btn_delete_file->setToolTip(QCoreApplication::translate("widget_form", "Delete the opened file's contents", nullptr));
     #endif // QT_CONFIG(tooltip)
         btn_delete_file->setText(QString());
     #if QT_CONFIG(tooltip)
         btn_check_file->setToolTip(QCoreApplication::translate("widget_form", "Check the opened file's contents for errors", nullptr));
     #endif // QT_CONFIG(tooltip)
         btn_check_file->setText(QString());
         cb_change_lang->setItemText(0, QCoreApplication::translate("widget_form", "English (en)", nullptr));
         cb_change_lang->setItemText(1, QCoreApplication::translate("widget_form", "Deutsch (de)", nullptr));
         cb_change_lang->setItemText(2, QCoreApplication::translate("widget_form", "Fran\303\247ais (fr)", nullptr));
         cb_change_lang->setItemText(3, QCoreApplication::translate("widget_form", "\320\240\321\203\321\201\320\272\320\270\320\271 (ru)", nullptr));
    #if QT_CONFIG(tooltip) btn_csv->setToolTip(QCoreApplication::translate("widget_form", "Create CSV file", nullptr)); #endif // QT_CONFIG(tooltip) btn_csv->setText(QString()); #if QT_CONFIG(tooltip) btn_code->setToolTip(QCoreApplication::translate("widget_form", "

    注意:我忘记将组合框项目标记为不可翻译,所以它们在此处出现。通常情况下,将语言名称放在其原始语言中,并使其对于区域设置的更改保持不变是一个好习惯,否则用户会感到困惑(不懂英语但想切换到中文,而语言名称却用英语书写,这必然会导致糟糕的用户体验)。

    因此,最终结果是(使用 Google 翻译法语和俄语 :P)

    UI - English

    UI - German

    UI - French

    UI - Russian


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接