How to translate the buttons in qmessagebox?
Asked Answered
T

7

24

I have a QMessageBox like this:

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

How could I translate the Yes/No word? since there is no place to place a tr()?

Tainataint answered 21/7, 2015 at 7:39 Comment(1)
Possible duplicate #18979562Klina
K
21

Sorry, I'm late, but there is a best way of solving your issue.

The right way is not to manually translate those strings. Qt already includes translations in the translation folder.

The idea is to load the translations (qm files) included in Qt.

I'd like to show you a code to get the message translated according to your locale:

#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();
}

Notes:

  • You can load a different locate creating a new QLocale object and setting it using void QLocale::setDefault(const QLocale & locale). Example.
  • I'm loading qt_*.qm and qtbase_*.qm because since Qt 5.3 the translations are splited in different files. In fact, for QMessageBox the translated strings are in qtbase_*.qm. Loading both is a good practice. More info. There are more qm files like qtquickcontrols_*.qm or qtmultimedia_*qm. Load the required ones according to your requirements.
  • Maybe you can find the text you're trying to translate is not translated yet by Qt. In this case, I recommend you to upgrade the Qt version to check if the translation exists in the most recent version or code yourself the change. Some useful links: here and here.
Klina answered 22/7, 2015 at 8:27 Comment(3)
Have you tested that the translations work in the final build? The Qt translation files are included? Because I have the same issue. It works in debug and release but not in the final build. #46075103Sorus
@Sorus Generally, the release configuration has the final installation files. What's the difference between release and final in your case?Klina
My final release did not contain the qt qm files which I referenced in code using qtTranslator->load("qt_" + language, QLibraryInfo::location(QLibraryInfo::TranslationsPath)); which gives a path from qt framework. I didn't add them in my project.Sorus
T
16

This is the way to do that:

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"));

And to show the message:

messageBox.exec();
Tibia answered 21/7, 2015 at 7:45 Comment(6)
Thanks, it works. But my problem is that in my application, there are a lot of message box. Is there any way I can get the button translated in batch instead of doing this setButtonText for each messageBox?Tainataint
You will have to change QMessageBox::question to QMessageBox messageBox in code everywhere. In translations you will need to set Yes and No only where it will be necessary, there should a few places only.Tibia
The problem with QMessageBox::question is that it is unlocalizable so you have to replace itTibia
You can create your own wrapper, which will be inherited from QMessageBox and call setButtonText() methods inside of it.Maxwellmaxy
Yes, you can replace the QMessageBox::question to the calls of your own wrapperTibia
This is completely unnecessary. Qt is already fully localized.Chatwin
J
5

update: I found in D:\Qt\Qt5.7.0\5.7\Src\qttranslations\translations\qtbase_**.ts already has the QPlatformTheme's translation srouce file (Unfortunately, there is no qtbase_zh_CN.ts), you can also copy a qtbase_**.ts and modify it immediately. If you are a Chinese like me, thanks to wisaly(github), he has already translated the qtbase to Chinese, and here is my fork on github.


After reading the Qt source code, I solved this issue. (My Qt's version is Qt 5.7.0, and installed in C:\Qt\Qt5.7.0 with Src)

Open the C:\Qt\Qt5.7.0\5.7\Src\qtbase\src\gui\gui.pro and insert a line like below to generate a Chinese translation file:

TRANSLATIONS    +=  gui_zh.ts

Open the gui.pro project with Qt Creator and use lupdate to generate a new cute's translation source file named gui_zh.ts.

Open the qui_zh.ts using Linguist and translate the QPlatformTheme item. Here only translated “&Yes” as a example: enter image description here

After translated, use lrelease to generate a binary translation file (gui_zh.qm).

Lastly, load the translations files (gui_zh.qm) to your QApplication, the button's text of QMessageBox will be ok.

My results are:

QMessageBox::information(this,
    QString("警告"),
    QString("测试文本"),
    QMessageBox::Yes | QMessageBox::No
);

enter image description here

By the way, you can also use this method to sovle the right contextmenu's transtions issues of some QWidgets like QTextEdit by add translations to C:\Qt\Qt5.7.0\5.7\Src\qtbase\src\widgets\widgets.pro.

Jollify answered 15/12, 2017 at 11:36 Comment(0)
K
2

I wrote a special QMessageBoxEx class for this issue.

// 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)
{

}

Gist: https://gist.github.com/kleuter/81a75a50e60a75aa0370a66ededc0c31

Keshiakesia answered 3/9, 2017 at 21:57 Comment(0)
S
1

There's no reason to do this. These texts are localized in Qt's own localization files. You need to provide, and perhaps also load, Qt's localizations within your application.

Scully answered 21/7, 2015 at 15:46 Comment(6)
Unfortunately this is not working with many languages. I had the problems with French though I loaded all the localizations and I checked their files, translations missedTibia
Also Qt localization is for limited number of languages I believeTibia
@Tibia Nothing prevents you or anyone else from fixing up these translation files. Sounds trivial compared to the pain of messing up with every messagebox instance.Chatwin
Agree with you that this is another way to go. You need to load qt language file in your application.Tibia
@Tibia It's the only way to go. Anything else is sheer insanity.Chatwin
@KubaOber Totally agree. I've answered with a better solution, IMHO.Klina
J
1

You can translate Text "Save" in this case to different language by clicking translatable check box as below.

enter image description here

Which language is depending on the locale you load when loading the application. You can do this as follows

QApplication app(argc, argv);
//loading my_translation_pt file
QString file= app.applicationDirPath() +"/my_translation_pt";
QTranslator translator;
translator.load(file);
//Setting the translator to the QApp
app.installTranslator(&translator);

sample my_translation_pt file is attached below

enter image description here

you can encode the tranlation using
c:\Qt\4.7.1\bin>lrelease.exe :\temp\my_translation_pt

Juni answered 4/11, 2018 at 23:25 Comment(0)
R
0

I do this this way, no need to create a subclass:

int Feedback = QMessageBox::information(this, "Info title", "Message to user.", "MyLocal_OK_text", "MyLocal_Cancel_text");

if(Feedback == 1){
  //MyLocal_Cancel_text chosen actions
   }
Roma answered 23/6, 2023 at 8:51 Comment(3)
Could you explain how the translation is done here? Or are you suggesting one should just put the message in the target language manually?Nudicaul
The result is the number of the button in the order it has been specified after message text. So pressing the first button in QMessageBox::information(this, "Info title", "Message to user.", "Yes", "No") will return button will return 0 for Yes and 1 for NoTaft
This answer is off-topic.Villon

© 2022 - 2024 — McMap. All rights reserved.