如何翻译 qmessagebox 中的按钮?

23

我有一个像这样的 QMessageBox

QMessageBox::question(this, tr("Sure want to quit?"), 
    tr("Sure to quit?"), QMessageBox::Yes | QMessageBox::No);

我该如何翻译"Yes/No"这个单词呢?因为没有地方可以放置tr()函数?


1
可能是重复的问题 http://stackoverflow.com/questions/18979062/qt-dynamic-translation-of-dialog-windows - Tarod
7个回答

20

抱歉,我来晚了,但是有一种最好的方法可以解决您的问题。

正确的方法不是手动翻译这些字符串。Qt已经在translation文件夹中包含了翻译。

思路是加载Qt中包含的翻译(qm文件)。

我想向您展示一段代码,根据您的语言环境获取翻译后的消息:

#include <QDebug>
#include <QtWidgets/QApplication>
#include <QMessageBox>
#include <QTranslator>
#include <QLibraryInfo>

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

    QApplication app(argc, argv);

    QTranslator qtTranslator;
    if (qtTranslator.load(QLocale::system(),
                "qt", "_",
                QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
    {
        qDebug() << "qtTranslator ok";
        app.installTranslator(&qtTranslator);
    }

    QTranslator qtBaseTranslator;
    if (qtBaseTranslator.load("qtbase_" + QLocale::system().name(),
                QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
    {
        qDebug() << "qtBaseTranslator ok";
        app.installTranslator(&qtBaseTranslator);
    }

    QMessageBox::question(0, QObject::tr("Sure want to quit?"), QObject::tr("Sure to quit?"), QMessageBox::Yes | QMessageBox::No);

    return app.exec();
}

注意事项:

  • 您可以通过创建一个新的QLocale对象并使用void QLocale::setDefault(const QLocale & locale)来设置它,以加载不同的语言环境。示例
  • 我正在加载qt_*.qmqtbase_*.qm,因为自Qt 5.3以来,翻译被拆分成不同的文件。实际上,对于QMessageBox,翻译字符串在qtbase_*.qm中。同时加载两个文件是一个好习惯。更多信息。还有更多的qm文件,如qtquickcontrols_*.qmqtmultimedia_*qm。根据您的需求加载所需的文件。
  • 也许您会发现您要翻译的文本尚未被Qt翻译。在这种情况下,我建议您升级Qt版本以检查最新版本中是否存在翻译,或者自己编写更改。一些有用的链接:这里这里

你测试过翻译在最终版本中是否有效吗?Qt的翻译文件已经包含了吗?因为我也遇到了同样的问题。它在调试和发布版本中都有效,但在最终版本中无效。https://dev59.com/EKTja4cB1Zd3GeqPJvLK - Mihai
@Mihai 一般来说,发布配置包含最终的安装文件。在你的情况下,发布和最终版本有什么区别呢? - Tarod
我的最终版本中没有包含我在代码中引用的qt qm文件,我使用qtTranslator->load("qt_" + language, QLibraryInfo::location(QLibraryInfo::TranslationsPath))来加载它们,这个路径是从qt框架中获取的。我没有将它们添加到我的项目中。 - Mihai

15

这是做那件事的方法:

QMessageBox messageBox(QMessageBox::Question,
            tr("Sure want to quit?"),
            tr("Sure to quit?"),
            QMessageBox::Yes | QMessageBox::No,
            this);
    messageBox.setButtonText(QMessageBox::Yes, tr("Yes"));
    messageBox.setButtonText(QMessageBox::No, tr("No"));

并展示这条消息:

messageBox.exec();

谢谢,它有效了。但我的问题是,在我的应用程序中有很多消息框。有没有办法批量翻译按钮,而不是为每个消息框都执行setButtonText? - Nicholas Yu
你需要在代码中将QMessageBox :: question更改为QMessageBox messageBox。在翻译中,您只需要在必要的地方设置“是”和“否”,这应该只有几个地方。 - demonplus
1
QMessageBox::question存在的问题是它无法本地化,因此您需要替换它。 - demonplus
1
您可以创建自己的包装器,该包装器将从 QMessageBox 继承并在其中调用 setButtonText() 方法。 - t3ft3l--i
是的,您可以将QMessageBox :: question替换为调用您自己的包装器。 - demonplus
5
没必要了,Qt已经完全本地化了。 - Kuba hasn't forgotten Monica

5
更新: 我在 D:\Qt\Qt5.7.0\5.7\Src\qttranslations\translations\qtbase_**.ts 中找到了 QPlatformTheme 的翻译源文件(不幸的是,没有qtbase_zh_CN.ts),你也可以复制一个 qtbase_**.ts 并立即进行修改。 如果你和我一样是中国人,感谢wisaly(github),他已经将 qtbase 翻译成了中文,这里是我在 github 上的分支
阅读Qt源代码后,我解决了这个问题。(我的Qt版本是Qt 5.7.0,安装在 C:\ Qt \ Qt5.7.0 内,带有Src)
打开 C:\ Qt \ Qt5.7.0 \ 5.7 \ Src \ qtbase \ src \ gui \ gui.pro 并插入以下行以生成中国翻译文件:
TRANSLATIONS    +=  gui_zh.ts

使用Qt Creator打开gui.pro项目,使用lupdate生成一个新的cute翻译源文件,命名为gui_zh.ts。 使用Linguist打开qui_zh.ts并翻译QPlatformTheme项。这里只以“&Yes”作为示例进行翻译: enter image description here 翻译完成后,使用lrelease生成一个二进制翻译文件(gui_zh.qm)。
最后,将翻译文件(gui_zh.qm)加载到您的QApplication中,QMessageBox按钮的文本就会变成翻译后的内容。
我的结果是:
QMessageBox::information(this,
    QString("警告"),
    QString("测试文本"),
    QMessageBox::Yes | QMessageBox::No
);

enter image description here

顺便说一下,你也可以使用这种方法来解决一些 QWidgets (如 QTextEdit)的右键上下文菜单转换问题,通过向 C:\Qt\Qt5.7.0\5.7\Src\qtbase\src\widgets\widgets.pro 添加翻译。

2
我为此问题编写了一个特殊的QMessageBoxEx类。
// init once your button texts
QMessageBoxEx::setCustomTextForButton(QMessageBox::Yes, "Да");
QMessageBoxEx::setCustomTextForButton(QMessageBox::No, "Нет");

// example usage
if (QMessageBoxEx::question(this, "Внимание", "Ошибка", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
{
   // OK
}

// header

class QMessageBoxEx : public QMessageBox
{
private:

    static QMap<QMessageBox::StandardButton, QString> m_customButtonNames;

protected:

    static void setCustomTextForButtons(QMessageBoxEx &msgBox);

public:

    QMessageBoxEx(QWidget *parent);

    static void setCustomTextForButton(QMessageBox::StandardButton button, const QString &text);

    static QMessageBox::StandardButton critical(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, QMessageBox::StandardButton defaultButton = NoButton);
    static QMessageBox::StandardButton information(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, QMessageBox::StandardButton defaultButton = NoButton);
    static QMessageBox::StandardButton question(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No), QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
    static QMessageBox::StandardButton warning(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, QMessageBox::StandardButton defaultButton = NoButton);

};

// implementation

QMap<QMessageBox::StandardButton, QString> QMessageBoxEx::m_customButtonNames;

void QMessageBoxEx::setCustomTextForButton(QMessageBox::StandardButton button, const QString &text)
{
    if (m_customButtonNames.contains(button))
        m_customButtonNames.erase(m_customButtonNames.find(button));

    m_customButtonNames[button] = text;
}

void QMessageBoxEx::setCustomTextForButtons(QMessageBoxEx &msgBox)
{
    if (m_customButtonNames.size())
    {
        QMessageBox::StandardButtons buttons = msgBox.standardButtons();

        for (auto button : m_customButtonNames.keys())
        {
            if (buttons & button)
            {
                msgBox.setButtonText(button, m_customButtonNames[button]);
            }
        }
    }
}

QMessageBox::StandardButton QMessageBoxEx::critical(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
{
    QMessageBoxEx msgBox(parent);

    msgBox.setIcon(QMessageBox::Critical);
    msgBox.setWindowTitle(title);
    msgBox.setText(text);
    msgBox.setStandardButtons(buttons);
    msgBox.setDefaultButton(defaultButton);

    setCustomTextForButtons(msgBox);

    return (QMessageBox::StandardButton)msgBox.exec();
}

QMessageBox::StandardButton QMessageBoxEx::information(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
{
    QMessageBoxEx msgBox(parent);

    msgBox.setIcon(QMessageBox::Information);
    msgBox.setWindowTitle(title);
    msgBox.setText(text);
    msgBox.setStandardButtons(buttons);
    msgBox.setDefaultButton(defaultButton);

    setCustomTextForButtons(msgBox);

    return (QMessageBox::StandardButton)msgBox.exec();
}

QMessageBox::StandardButton QMessageBoxEx::question(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
{
    QMessageBoxEx msgBox(parent);

    msgBox.setIcon(QMessageBox::Question);
    msgBox.setWindowTitle(title);
    msgBox.setText(text);
    msgBox.setStandardButtons(buttons);
    msgBox.setDefaultButton(defaultButton);

    setCustomTextForButtons(msgBox);

    return (QMessageBox::StandardButton)msgBox.exec();
}

QMessageBox::StandardButton QMessageBoxEx::warning(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
{
    QMessageBoxEx msgBox(parent);

    msgBox.setIcon(QMessageBox::Warning);
    msgBox.setWindowTitle(title);
    msgBox.setText(text);
    msgBox.setStandardButtons(buttons);
    msgBox.setDefaultButton(defaultButton);

    setCustomTextForButtons(msgBox);

    return (QMessageBox::StandardButton)msgBox.exec();
}

QMessageBoxEx::QMessageBoxEx(QWidget *parent) : QMessageBox(parent)
{

}

要翻译的内容:

要点: https://gist.github.com/kleuter/81a75a50e60a75aa0370a66ededc0c31


1

没有理由这样做。这些文本已经在Qt自己的本地化文件中进行了本地化。您需要在应用程序中提供并可能还要加载Qt的本地化。


很不幸,这在许多语言中都无法正常工作。我在使用法语时遇到了问题,尽管我加载了所有的本地化文件并检查了它们的翻译,但仍然存在翻译缺失的情况。 - demonplus
此外,我认为Qt本地化仅适用于有限数量的语言。 - demonplus
@demonplus 没有任何阻止你或其他人修复这些翻译文件的事情。相比于搞乱每个消息框实例的痛苦,这听起来微不足道。 - Kuba hasn't forgotten Monica
我同意你的看法,这是另一种可行的方法。你需要在你的应用程序中加载qt语言文件。 - demonplus
@demonplus 这是唯一的出路。其他任何选择都是纯粹的疯狂。 - Kuba hasn't forgotten Monica
@KubaOber 完全同意。在我看来,我已经用更好的解决方案回答了。 - Tarod

1
在此情况下,您可以通过点击下面的可翻译复选框将文本“保存”翻译成不同的语言。

enter image description here

加载应用程序时,语言取决于您加载的区域设置。您可以按照以下方式执行此操作: 附上示例my_translation_pt文件。 enter image description here 您可以使用以下命令对翻译进行编码:
c:\Qt\4.7.1\bin>lrelease.exe :\temp\my_translation_pt

0
我这样做,不需要创建子类。
int Feedback = QMessageBox::information(this, "Info title", "Message to user.", "MyLocal_OK_text", "MyLocal_Cancel_text");

if(Feedback == 1){
  //MyLocal_Cancel_text chosen actions
   }

你能解释一下这里的翻译是如何进行的吗?还是你建议直接手动将信息放入目标语言中? - Abderrahmene Rayene Mihoub
结果是按钮的编号,按照在消息文本之后指定的顺序。因此,在QMessageBox::information(this, "Info title", "Message to user.", "Yes", "No")中按下第一个按钮将返回0表示Yes,1表示No。 - Sebastian 'polrus' Turzanski
这个回答与主题无关。 - Burak

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