c++ - 如果在 Qt 中使用国际化,则翻译 "dynamic"内容

标签 c++ qt internationalization translation

我目前正在评估 C++ 框架 Qt v5.4.1。目前我是 试图理解和应用Internationalization with Qt .

我通过 文章帮助How to create a multi lingual application that can switch the language at runtime?我知道如何使用 Qt Linguist Translation 源 (.ts) 文件以及如何生成 Qt Linguist Message (.qm) 文件。我用 构建系统 CMake自动生成,效果非常好。

在我的项目中,翻译是从 Qt 资源集合 (.qrc) 加载的 文件编译到应用程序中。我知道如何通过翻译“静态”字符串 成员函数 QObject::tr()QObject::translate() .

现在是棘手的部分:我想在我的应用程序发展的同时添加语言。 目前我有以下两个 .ts 文件:

  • foo_ui_de_DE.ts
  • foo_ui_en_US.ts

这些是通过构建通过lrelease编译成以下两个.qm文件 过程:

  • foo_ui_de_DE.qm
  • foo_ui_en_US.qm

构建过程自动生成一个 .qrc 文件 translations.qrc 和 通过rcc将该文件编译成可执行文件。

来自声明文件(.h)的相关源代码:

#include <QMainWindow>
#include <QLocale>
#include <QString>
#include <QTranslator>

class MainWindow : public QMainWindow {
  Q_OBJECT

 public:
  /**
   * Initializes a new instance of the MainWindow class with the given parent.
   *
   * @param parent The parent.
   */
  explicit MainWindow(QWidget* parent = 0);

 private slots:
  /**
   * Loads a language by the given language shortcut (e.g. `de_DE`, `en_US`).
   */
  void LoadLanguage(QLocale const& kLocale);

  void SwitchTranslator(QTranslator& translator,
                        QString const& kLocale,
                        QString const& kFilename);

  /**
   * Creates the language menu dynamically.
   */
  void CreateLanguageMenu();

 protected:
  /**
   * Handler which is activated when a new translator is loaded or the system
   * language is changed.
   */
  void changeEvent(QEvent* event);

 protected slots:
  /**
   * Slot which is called by the language menu actions.
   */
  void slotLanguageChanged(QAction* action);

 private:
  /**
   * The translations for this application.
   */
  QTranslator translator_;

  /**
   * The translations for the Qt Widgets used in this application.
   */
  QTranslator qt_translator_;

  /**
   * Contains the currently loaded locale.
   */
  QLocale locale_;

  /**
   * The main window of the application.
   */
  Ui::MainWindow* ui_;
};

来自定义文件(.cc)的相关源代码:

#include <QLibraryInfo>

#include "main_window.h"

#include "ui_main_window.h"

MainWindow::MainWindow(QWidget* the_parent)
    : QMainWindow{the_parent},
      ui_{new Ui::MainWindow} {
  ui_->setupUi(this);
  CreateLanguageMenu();
}

MainWindow::~MainWindow() {
  delete ui_;
}

void MainWindow::LoadLanguage(QLocale const& kNewLocale) {
  QLocale::setDefault(kNewLocale);
  QString const kLanguageName{QLocale::languageToString(kNewLocale.language())};

  SwitchTranslator(translator_, "qt_" + kNewLocale.bcp47Name(),
                   QLibraryInfo::location(QLibraryInfo::TranslationsPath));
  SwitchTranslator(qt_translator_,
                   qApp->applicationName() + '_' + kNewLocale.name(),
                   ":/translations");
  statusBar()->showMessage(
      tr("Language changed to %1").arg(kLanguageName));
  locale_ = kNewLocale;
}

void MainWindow::SwitchTranslator(QTranslator& translator,
                                  QString const& kLocale,
                                  QString const& kFilename) {
  qApp->removeTranslator(&translator);

  if (translator.load(kLocale, kFilename)) {
    qApp->installTranslator(&translator);
  }
}

void MainWindow::CreateLanguageMenu() {
  // TODO(wolters): This is not optimal, since it does not work automatically
  // with the .qm files added as a resource to the application.
  //: Translation for the human language German.
  QT_TR_NOOP("German");
  //: Translation for the human language English.
  QT_TR_NOOP("English");

  QActionGroup* language_group{new QActionGroup(ui_->menuLanguage)};
  language_group->setExclusive(true);

  connect(language_group, SIGNAL(triggered(QAction*)), this,
          SLOT(slotLanguageChanged(QAction*)));

  QLocale const kDefaultLocale{QLocale::system()};
  QDir const kDirectory{QApplication::applicationDirPath() + "/.."};
  QStringList const kFileNames{kDirectory.entryList(QStringList("*.qm"))};

  for (QString const& kFileName : kFileNames) {
    QLocale const kLocale{QFileInfo{kFileName}.completeBaseName().replace(
        qApp->applicationName() + "_", "")};
    QString const kCountryCode{
        kLocale.name().toLower().mid(kLocale.name().lastIndexOf('_') + 1)};
    QIcon const kIcon{":/icons/flags/" + kCountryCode + ".png"};
    QAction* action{new QAction{
        kIcon,
        // TODO(wolters): This does not work.
        tr(QLocale::languageToString(kLocale.language()).toStdString().c_str()),
        this}};
    action->setCheckable(true);
    action->setData(kLocale);

    ui_->menuLanguage->addAction(action);
    language_group->addAction(action);

    if (kDefaultLocale == kLocale) {
      action->setChecked(true);
    }
  }
}

void MainWindow::changeEvent(QEvent* the_event) {
  if (nullptr != the_event) {
    switch (the_event->type()) {
      // QEvent::LanguageChange is send if a translator is loaded.
      case QEvent::LanguageChange:
        ui_->retranslateUi(this);
        break;
      // QEvent::LocaleChange is send, if the system language changes.
      case QEvent::LocaleChange:
        LoadLanguage(QLocale::system());
        break;
      default:
        break;
    }
  }

  QMainWindow::changeEvent(the_event);
}

void MainWindow::slotLanguageChanged(QAction* action) {
  if (nullptr != action) {
    LoadLanguage(qvariant_cast<QLocale>(action->data()));
  }
}

源码已经在评论中描述了我遇到的问题。

  1. 如果应用程序启动,则使用当前系统区域设置 重新翻译用户界面。这有效,我可以看到菜单中的项目 Languages 以德语人类语言出现(我已经翻译了这两个项目 在 .ts 文件中)。但是当我通过菜单将语言从德语切换到 英语,两个项目标签得到翻译。
  2. 该方法通常不是最优的,因为我不想修改 源代码(QT_TR_NOOP 上面),如果一种新的人类语言被添加到 应用。最佳工作流程是:
    1. 将所有支持的语言以其正确的语言添加到所有 .ts 文件中。
    2. 动态翻译菜单项。

我想我误解了什么,但我找不到解决办法 在 WWW 上搜索了一会儿。

2015-04-01 更新:我想我使用了错误的方法。重要的部分是 Languages 菜单是在成员函数 CreateLanguageMenu() 中动态创建的。我需要如何翻译动态创建的菜单项这个问题的答案。所以这都是关于 QAction* action{new QAction{kIcon, tr(QLocale::languageToString(kLocale.language()).toStdString().c_str()), this}}; 行那个功能。我认为我需要某种在编译时可用的查找功能...

最佳答案

正如您已经提到的,您需要实时查找功能。 我建议这样的黑客: 创建 QAction 对象时使用对象名称作为语言标识符

QT_TR_NOOP("LANG_ENG")
QAction* langAction = ...;
langAction->setObjectName("LANG_ENG");

在 Language Change 事件上调用一些方法来重新定义这个 Action

void retranslateLangActions()
{
    QList<QAction*> widgetActions = this->findChildren<QAction*>();
    foreach(QAction* act, widgetActions) // qt foreach macro
    {
        QString objName = act->objectName();
        if (objName.startsWith("LANG_"))
        {
            act->setText(tr(objName.toStdString().c_str()));
        }
    }
}

关于c++ - 如果在 Qt 中使用国际化,则翻译 "dynamic"内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29376918/

相关文章:

PHP:UTF8 中西里尔字符串的不区分大小写的 preg_replace

c++ - 解析字符串对失败。恶灵 x3 语法

linux - Qt 4.8.5 -- 编译 ResourceFile.qrc 时出错

Angular:使用 AOT 时如何在运行时获取当前语言环境

c++ - 在静态函数中发出信号

c++ - 在qt中单击按钮重写文件内容

mysql - 一列 SQL 表,该列是一个 ID - 这很疯狂吗?

c++ - Visual Studio 2012 和 2010 中基于 Opengl Sierpinski Shader 的 C 代码

c++ - rapidjson cocos2d-x解析

c++ - 使用 std::move 和 std::shared_ptr 有什么好处和风险(如果有的话)