Qt将翻译文本转换为英语

Qt将翻译文本转换为英语,qt,Qt,我的Qt应用程序支持动态翻译,即用户可以在应用程序运行时更改语言 现在我需要找到翻译字符串的英文对应词,但似乎找不到方法 比如说 给定QString s=tr(“你好”); 翻译完成后,我需要能够从s获得“你好” 以前有没有人这样做过,或者对如何实现有什么想法 谢谢在Qt中,无法从翻译后的字符串中获取原始字符串。最终,实际的转换是由QTranslator类完成的,该类不公开反向查找函数,甚至不公开为私有API 您需要更改代码以避免反向字符串查找。一种方法是始终将英文字符串或其他标识符存储在需要的

我的Qt应用程序支持动态翻译,即用户可以在应用程序运行时更改语言

现在我需要找到翻译字符串的英文对应词,但似乎找不到方法

比如说 给定QString s=tr(“你好”); 翻译完成后,我需要能够从s获得“你好”

以前有没有人这样做过,或者对如何实现有什么想法


谢谢

在Qt中,无法从翻译后的字符串中获取原始字符串。最终,实际的转换是由
QTranslator
类完成的,该类不公开反向查找函数,甚至不公开为私有API

您需要更改代码以避免反向字符串查找。一种方法是始终将英文字符串或其他标识符存储在需要的位置


这实际上是使用QAction时的常见情况,这就是为什么QAction提供在翻译字符串旁边存储任意数据的原因,在
QAction::setData()

中,在我的应用程序中,我需要将翻译消息写入UI,将原始消息写入程序日志文件

我的解决方案是创建一个包装类,该类可以转换数据和原始数据

class TS {
public:
    TS(const char* str) {
        init(str);
    }

    TS(const QString& str) {
        init(str.toStdString().c_str());
    }

    TS& arg(const QString& arg1, const bool translate = true) {
        this->orig = this->orig.arg(arg1);
        if (translate) {
            this->tran = this->tran.arg(qApp->translate("", arg1.toStdString().c_str()));
        } else {
            this->tran = this->tran.arg(arg1);
        }
        return *this;
    }

    TS& arg(const int arg1) {
        this->orig = this->orig.arg(arg1);
        this->tran = this->tran.arg(arg1);
        return *this;
    }

    inline const QString& getOrig() const {
        return this->orig;
    }

    inline const QString& getTran() const {
        return this->tran;
    }

private:
    inline void init(const char* str) {
        this->orig = str;
        this->tran = qApp->translate("", str);
    }

private:
    QString orig;
    QString tran;
};
用法:

void info(const TS& rsMsg);

...

m_rLog.info(QT_TRANSLATE_NOOP("", "Plain Text"));
m_rLog.info(TS(QT_TRANSLATE_NOOP("", "Text with argument : %1")).arg( 123 ));

根据Mykhailo Bryzhaks的回答,我稍微采用了这个类,这样我们就可以在.ts文件中包含上下文,这将使大型解决方案的实现变得更加简单:

#ifndef TrString_h__
#define TrString_h__

#include <QString>
#include <QRegularExpression>
#include <cassert>

class QObject;

namespace
{
    static QRegularExpression s_findClassNameRegExp("(?<=\\bclass\\s)(\\w+)");
    static QRegularExpression s_findQuotesRegExp("\"([^\"\\\\]|\\\\.)*\"");
}

#define TRStringVoid(QT_TRANSLATE_NOOP_STRING) TrString<void>(#QT_TRANSLATE_NOOP_STRING)
#define TRString(QT_TR_NOOP_STRING) TrString<decltype(this)>(this, #QT_TR_NOOP_STRING)

// Use      //: MyComment
// one line before the call to add a comment for the translator

namespace
{
    const QString kQT_TR_NOOP_Macro = "QT_TR_NOOP(";
    const QString kQT_TRANSLATE_NOOP_Macro = "QT_TRANSLATE_NOOP(";
    const QString kQT_TRANSLATE_NOOP_3_Macro = "QT_TRANSLATE_NOOP3(";
}

// Use TRString or TRStringVoid macro to get an instance of this class
template <class T> class TrString
{
    enum class MacroType { Unknown, QT_TR_NOOP, QT_TRANSLATE_NOOP, QT_TRANSLATE_NOOP3 };

public:
    // used for global functions where T is void
    template <typename SfinaeT = void, typename SfinaeT2 = std::enable_if_t<std::is_void<T>::value, T>>
    TrString(const char* lineString)
        : m_native(lineString)
    {
        m_macroType = getLineStringType(lineString);

        assert(("You must use TRStringVoid(QT_TRANSLATE_NOOP('Context','StringToTranslate')) here because you are not in a class context.",
            (m_macroType == MacroType::QT_TRANSLATE_NOOP || m_macroType == MacroType::QT_TRANSLATE_NOOP3)));

        initStrings();
    }

    // used for calls from within objects
    template <typename SfinaeT = void, typename SfinaeT2 = std::enable_if_t<!std::is_void<T>::value, T>>
    TrString(SfinaeT2 caller, const char* lineString)
        : m_native(lineString)
    {
        m_macroType = getLineStringType(lineString);
        checkIfTemplateHasCorrectType(caller);
        initStrings();
    }

    TrString& operator=(const TrString& other)
    {
        m_scope = other.m_scope;
        m_native = other.m_native;
        m_translated = other.m_translated;
    }

    TrString& arg(const TrString& arg1)
    {
        this->m_native = this->m_native.arg(arg1.native());
        this->m_translated = this->m_translated.arg(qApp->translate(m_scope.toLocal8Bit().data(), arg1.translated().toLocal8Bit().data()));

        return *this;
    }

    TrString& arg(const QString arg1)
    {
        this->m_native = this->m_native.arg(arg1);
        this->m_translated = this->m_translated.arg(arg1);
        return *this;
    }

    TrString& arg(const double arg1)
    {
        this->m_native = this->m_native.arg(arg1);
        this->m_translated = this->m_translated.arg(arg1);
        return *this;
    }

    inline const QString& native() const
    {
        return this->m_native;
    }

    inline const QString& translated() const
    {
        return this->m_translated;
    }

private:
    template<class SfinaeT = T>
    typename std::enable_if<!std::is_polymorphic< std::remove_pointer_t<SfinaeT>>::value, void>::type
        checkIfTemplateHasCorrectType(SfinaeT caller)
    {
        assert(("You must use TRString(QT_TRANSLATE_NOOP('Context', 'StringToTranslate')) here because your class does not derive from QObject.",
            (m_macroType == MacroType::QT_TRANSLATE_NOOP || m_macroType == MacroType::QT_TRANSLATE_NOOP3)));
    }

    template<class SfinaeT = T>
    typename std::enable_if<std::is_polymorphic< std::remove_pointer_t<SfinaeT>>::value, void>::type
        checkIfTemplateHasCorrectType(SfinaeT caller)
    {
        if (!dynamic_cast<QObject*>(caller))
            assert(("You must use TRString(QT_TRANSLATE_NOOP('Context', 'StringToTranslate')) here because your class does not derive from QObject.",
            (m_macroType == MacroType::QT_TRANSLATE_NOOP || m_macroType == MacroType::QT_TRANSLATE_NOOP3)));
        else
            m_isDerivedFromQObject = true;
    }

    MacroType getLineStringType(QString lineString) const
    {
        if (m_native.contains(kQT_TR_NOOP_Macro))
            return MacroType::QT_TR_NOOP;
        else if (m_native.contains(kQT_TRANSLATE_NOOP_3_Macro))
            return MacroType::QT_TRANSLATE_NOOP3;
        else if (m_native.contains(kQT_TRANSLATE_NOOP_Macro))
            return MacroType::QT_TRANSLATE_NOOP;
        else
        {
            assert(("You must you TRString(QT_TR_NOOP('StringToTranslate') or TRString(QT_TRANSLATE_NOOP('Context', 'StringToTranslate')) if you are not in a QObject derived class for this to work.", false));
            return MacroType::Unknown;
        }
    }

    inline void initStrings()
    {
        QRegularExpressionMatchIterator regExpIter = s_findQuotesRegExp.globalMatch(m_native);
        QStringList macroArguments;

        while (regExpIter.hasNext())
        {
            QRegularExpressionMatch match = regExpIter.next();
            QString argumentString = match.captured(0);
            argumentString.remove(0, 1);
            argumentString.remove(argumentString.length() - 1, 1);
            macroArguments.push_back(argumentString);
        }

        if (macroArguments.size() == 1 && m_macroType == MacroType::QT_TR_NOOP)
        {
            m_scope = QRegularExpressionMatch(s_findClassNameRegExp.match(typeid(T).name())).captured(0);
            m_native = macroArguments[0];
        }
        else if ((macroArguments.size() == 2 && m_macroType == MacroType::QT_TRANSLATE_NOOP) || (macroArguments.size() == 3 && m_macroType == MacroType::QT_TRANSLATE_NOOP3))
        {
            m_scope = macroArguments[0];
            m_native = macroArguments[1];
        }
        else
        {
            assert(("You must you TRString(QT_TR_NOOP('StringToTranslate') or TRString(QT_TRANSLATE_NOOP('Context', 'StringToTranslate')) if you are not in a QObject derived class for this to work.", false));
        }

        m_translated = qApp->translate(m_scope.toLocal8Bit().data(), m_native.toLocal8Bit().data());
    }

    MacroType m_macroType = MacroType::Unknown;
    bool m_isDerivedFromQObject = false;
    QString m_native;
    QString m_translated;
    QString m_scope;
};

#endif // TrString_h__
课堂外使用:

auto logString = TRStringVoid(QT_TRANSLATE_NOOP("Main", "Log message in main"));

如果您无意中使用了错误的Qt宏或错误的TRString宏,将创建一个断言,并显示一条关于如何修复调用的消息

因此,我遇到了同样的情况,我还希望避免在代码中重复一些字符串文本,并且仍然能够向我的应用程序的用户打印一些翻译后的错误消息,但随后将文本的原始英文版本记录到日志中

我开始使用jaba的代码,但在使用一些特殊字符(如“\n”和一些Unicode标记)时遇到了一些问题。事实证明,Qt解析由翻译宏标记的字符串文本的方法涉及替换这些特殊字符。transcode函数直接取自Qt的语言学家源代码,以便在运行时执行相同的过程。否则,translate函数将无法找到字符串,因为翻译文件中存储的内容与编译后的字符串不完全匹配。所以我能想到的是这样的:

#pragma once

#include <QApplication>

#include <QString>
#include <QRegularExpression>
#include <cassert>

class QObject;

//NOTE: enable_if_t is only available in C++14 so we need to define it here
template< bool Condition, typename T = void >
using enable_if_t = typename std::enable_if<Condition, T>::type;

namespace
{
    constexpr char QT_TR_NOOP_MACRO [] = "QT_TR_NOOP(";
    constexpr char QT_TRANSLATE_NOOP_MACRO [] = "QT_TRANSLATE_NOOP(";
    constexpr char QT_TRANSLATE_NOOP_3_MACRO [] = "QT_TRANSLATE_NOOP3(";

    //TODO: Add QT_TR_N_NOOP, QT_TRANSLATE_N_NOOP, QT_TRANSLATE_N_NOOP3
    enum class MacroType { Unknown, QT_TR_NOOP, QT_TRANSLATE_NOOP, QT_TRANSLATE_NOOP3 };

    MacroType getMacroTypeFromString(const QString& str)
    {
        if (str.contains(QT_TR_NOOP_MACRO))
            return MacroType::QT_TR_NOOP;
        else if (str.contains(QT_TRANSLATE_NOOP_3_MACRO))
            return MacroType::QT_TRANSLATE_NOOP3;
        else if (str.contains(QT_TRANSLATE_NOOP_MACRO))
            return MacroType::QT_TRANSLATE_NOOP;
        else
        {
            return MacroType::Unknown;
        }
    }

    QStringList extractArguments(const QString& raw)
    {
        QStringList macroArguments;

        const QRegularExpression findQuotesRegExp("\"([^\"\\\\]|\\\\.)*\"");
        QRegularExpressionMatchIterator regExpIter = findQuotesRegExp.globalMatch(raw);

        while (regExpIter.hasNext())
        {
            QRegularExpressionMatch match = regExpIter.next();
            QString argumentString = match.captured(0);
            argumentString.remove(0, 1); // Remove leading quote
            argumentString.remove(argumentString.length() - 1, 1); // Remove trailing quote
            macroArguments.push_back(argumentString);
        }

        return macroArguments;
    }

    QString transcode(const QString &str)
    {
        static const char tab[] = "abfnrtv";
        static const char backTab[] = "\a\b\f\n\r\t\v";
        // This function has to convert back to bytes, as C's \0* sequences work at that level.
        const QByteArray ba = str.toUtf8();
        std::vector<uchar> in(std::begin(ba), std::end(ba));
        size_t inputLength = in.size();
        QByteArray out;
        out.reserve(static_cast<int>(inputLength));

        for (size_t i = 0; i < inputLength;)
        {
            uchar c = in[i++];
            if (c == '\\')
            {
                if (i >= inputLength)
                    break;

                c = in[i++];

                if (c == '\n')
                    continue;

                if (c == 'x' || c == 'u' || c == 'U')
                {
                    const bool unicode = (c != 'x');
                    QByteArray hex;

                    while (i < inputLength && isxdigit((c = in[i])))
                    {
                        hex += static_cast<char>(c);
                        i++;
                    }

                    if (unicode)
                    {
                        out += QString(QChar(hex.toUInt(nullptr, 16))).toUtf8();
                    }
                    else
                    {
                        out += static_cast<char>(hex.toUInt(nullptr, 16));
                    }
                }
                else if (c >= '0' && c < '8')
                {
                    QByteArray oct;
                    int n = 0;
                    oct += static_cast<char>(c);

                    while (n < 2 && i < inputLength && (c = in[i]) >= '0' && c < '8')
                    {
                        i++;
                        n++;
                        oct += static_cast<char>(c);
                    }

                    out += static_cast<char>(oct.toUInt(nullptr, 8));
                }
                else
                {
                    const char *p = strchr(tab, c);
                    out += !p ? static_cast<char>(c) : backTab[p - tab];
                }
            }
            else
            {
                out += static_cast<char>(c);
            }
        }

        return QString::fromUtf8(out.constData(), out.length());
    }
}

#define TR_STRING_VOID(QT_TRANSLATE_NOOP_STRING) TranslatedString<void>(#QT_TRANSLATE_NOOP_STRING)
#define TR_STRING(QT_TR_NOOP_STRING) TranslatedString<decltype(this)>(#QT_TR_NOOP_STRING)

template <class T> class TranslatedString
{

public:

    explicit TranslatedString(const char* raw)
    {
        init(raw);
    }

    inline const QString& native() const
    {
        return m_Native;
    }

    inline QString translated() const
    {
        return QCoreApplication::translate(qUtf8Printable(m_Scope), qUtf8Printable(m_Native));
    }

private:

    //TODO: The init method should be SFINAE'd such that only the
    //      respective macros for void vs QObject subclass are supported
    //

    inline void init(const QString& raw)
    {
        m_MacroType = getMacroTypeFromString(raw);

        assert(("Unsupported Qt translation Macro Type", (m_MacroType != MacroType::Unknown)));

        QStringList macroArguments = extractArguments(raw);

(macroArguments.size() == 2)));

        if (macroArguments.size() == 1 && m_MacroType == MacroType::QT_TR_NOOP)
        {
            const QRegularExpression findClassNameRegExp("(?<=\\bclass\\s)(\\w+)");
            m_Scope = QRegularExpressionMatch(findClassNameRegExp.match(typeid(T).name())).captured(0);
            m_Native = transcode(macroArguments[0]);
        }
        else if ((macroArguments.size() == 2 && m_MacroType == MacroType::QT_TRANSLATE_NOOP) || (macroArguments.size() == 3 && m_MacroType == MacroType::QT_TRANSLATE_NOOP3))
        {
            m_Scope = macroArguments[0];
            m_Native = transcode(macroArguments[1]);
        }
        else
        {
            //TODO: Figure out what to put here
        }
    }

    MacroType m_MacroType = MacroType::Unknown;
    QString m_Native;
    QString m_Scope;
};
#pragma一次
#包括
#包括
#包括
#包括
类QObject;
//注意:如果仅在C++14中可用,则启用,因此我们需要在此处定义它
模板
使用enable_if_t=typename std::enable_if::type;
名称空间
{
constexpr char QT_TR_NOOP_MACRO[]=“QT_TR_NOOP(”;
constexpr char QT_TRANSLATE_NOOP_宏[]=“QT_TRANSLATE_NOOP(”;
constexpr char QT_TRANSLATE_NOOP_3_MACRO[]=“QT_TRANSLATE_NOOP3(”;
//TODO:添加QT_TR_N_NOOP、QT_TRANSLATE_N_NOOP、QT_TRANSLATE_N_NOOP3
枚举类宏类型{Unknown,QT_TR_NOOP,QT_TRANSLATE_NOOP,QT_TRANSLATE_NOOP3};
宏类型getMacroTypeFromString(常量QString&str)
{
if(str.contains(QT_TR_NOOP_宏))
返回宏类型::QT_TR_NOOP;
else if(str.contains(QT_TRANSLATE_NOOP_3_MACRO))
返回宏类型::QT_TRANSLATE_NOOP3;
else if(str.contains(QT_TRANSLATE_NOOP_MACRO))
返回宏类型::QT_TRANSLATE_NOOP;
其他的
{
返回宏类型::未知;
}
}
QStringList提取参数(常量QString&raw)
{
QStringList宏参数;
常量QRegularExpression findQuotesRegExp(“\”([^\\\\\\\]\\\\\)*”);
QRegularExpressionMatchIterator regExpIter=findQuotesRegExp.globalMatch(原始);
while(regExpIter.hasNext())
{
QRegularExpressionMatch=regExpIter.next();
QString argumentString=match.captured(0);
argumentString.remove(0,1);//删除前导引号
argumentString.remove(argumentString.length()-1,1);//删除尾随引号
宏参数。推回(argumentString);
}
返回宏参数;
}
QString转码(const QString&str)
{
静态常量字符选项卡[]=“abfnrtv”;
static const char backTab[]=“\a\b\f\n\r\t\v”;
//此函数必须转换回字节,因为C的\0*序列在该级别工作。
const QByteArray ba=str.toUtf8();
std::vector in(std::begin(ba),std::end(ba));
size_t inputLength=in.size();
QByteArray out;
输出保留(静态_转换(输入长度));
对于(大小i=0;i=输入长度)
打破
c=在[i++]中;
如果(c=='\n')
继续;
如果(c='x'| | c='u'| | c='u')
{
const bool unicode=(c!='x');
QByteArray十六进制;
而(i='0'&&c<'8')为else
{
QByteArray十月;
int n=0;
oct+=静态(c);
而(n<2&&i='0'&&c<'8')
{
i++;
n++;
auto logString = TRStringVoid(QT_TRANSLATE_NOOP("Main", "Log message in main"));
#pragma once

#include <QApplication>

#include <QString>
#include <QRegularExpression>
#include <cassert>

class QObject;

//NOTE: enable_if_t is only available in C++14 so we need to define it here
template< bool Condition, typename T = void >
using enable_if_t = typename std::enable_if<Condition, T>::type;

namespace
{
    constexpr char QT_TR_NOOP_MACRO [] = "QT_TR_NOOP(";
    constexpr char QT_TRANSLATE_NOOP_MACRO [] = "QT_TRANSLATE_NOOP(";
    constexpr char QT_TRANSLATE_NOOP_3_MACRO [] = "QT_TRANSLATE_NOOP3(";

    //TODO: Add QT_TR_N_NOOP, QT_TRANSLATE_N_NOOP, QT_TRANSLATE_N_NOOP3
    enum class MacroType { Unknown, QT_TR_NOOP, QT_TRANSLATE_NOOP, QT_TRANSLATE_NOOP3 };

    MacroType getMacroTypeFromString(const QString& str)
    {
        if (str.contains(QT_TR_NOOP_MACRO))
            return MacroType::QT_TR_NOOP;
        else if (str.contains(QT_TRANSLATE_NOOP_3_MACRO))
            return MacroType::QT_TRANSLATE_NOOP3;
        else if (str.contains(QT_TRANSLATE_NOOP_MACRO))
            return MacroType::QT_TRANSLATE_NOOP;
        else
        {
            return MacroType::Unknown;
        }
    }

    QStringList extractArguments(const QString& raw)
    {
        QStringList macroArguments;

        const QRegularExpression findQuotesRegExp("\"([^\"\\\\]|\\\\.)*\"");
        QRegularExpressionMatchIterator regExpIter = findQuotesRegExp.globalMatch(raw);

        while (regExpIter.hasNext())
        {
            QRegularExpressionMatch match = regExpIter.next();
            QString argumentString = match.captured(0);
            argumentString.remove(0, 1); // Remove leading quote
            argumentString.remove(argumentString.length() - 1, 1); // Remove trailing quote
            macroArguments.push_back(argumentString);
        }

        return macroArguments;
    }

    QString transcode(const QString &str)
    {
        static const char tab[] = "abfnrtv";
        static const char backTab[] = "\a\b\f\n\r\t\v";
        // This function has to convert back to bytes, as C's \0* sequences work at that level.
        const QByteArray ba = str.toUtf8();
        std::vector<uchar> in(std::begin(ba), std::end(ba));
        size_t inputLength = in.size();
        QByteArray out;
        out.reserve(static_cast<int>(inputLength));

        for (size_t i = 0; i < inputLength;)
        {
            uchar c = in[i++];
            if (c == '\\')
            {
                if (i >= inputLength)
                    break;

                c = in[i++];

                if (c == '\n')
                    continue;

                if (c == 'x' || c == 'u' || c == 'U')
                {
                    const bool unicode = (c != 'x');
                    QByteArray hex;

                    while (i < inputLength && isxdigit((c = in[i])))
                    {
                        hex += static_cast<char>(c);
                        i++;
                    }

                    if (unicode)
                    {
                        out += QString(QChar(hex.toUInt(nullptr, 16))).toUtf8();
                    }
                    else
                    {
                        out += static_cast<char>(hex.toUInt(nullptr, 16));
                    }
                }
                else if (c >= '0' && c < '8')
                {
                    QByteArray oct;
                    int n = 0;
                    oct += static_cast<char>(c);

                    while (n < 2 && i < inputLength && (c = in[i]) >= '0' && c < '8')
                    {
                        i++;
                        n++;
                        oct += static_cast<char>(c);
                    }

                    out += static_cast<char>(oct.toUInt(nullptr, 8));
                }
                else
                {
                    const char *p = strchr(tab, c);
                    out += !p ? static_cast<char>(c) : backTab[p - tab];
                }
            }
            else
            {
                out += static_cast<char>(c);
            }
        }

        return QString::fromUtf8(out.constData(), out.length());
    }
}

#define TR_STRING_VOID(QT_TRANSLATE_NOOP_STRING) TranslatedString<void>(#QT_TRANSLATE_NOOP_STRING)
#define TR_STRING(QT_TR_NOOP_STRING) TranslatedString<decltype(this)>(#QT_TR_NOOP_STRING)

template <class T> class TranslatedString
{

public:

    explicit TranslatedString(const char* raw)
    {
        init(raw);
    }

    inline const QString& native() const
    {
        return m_Native;
    }

    inline QString translated() const
    {
        return QCoreApplication::translate(qUtf8Printable(m_Scope), qUtf8Printable(m_Native));
    }

private:

    //TODO: The init method should be SFINAE'd such that only the
    //      respective macros for void vs QObject subclass are supported
    //

    inline void init(const QString& raw)
    {
        m_MacroType = getMacroTypeFromString(raw);

        assert(("Unsupported Qt translation Macro Type", (m_MacroType != MacroType::Unknown)));

        QStringList macroArguments = extractArguments(raw);

(macroArguments.size() == 2)));

        if (macroArguments.size() == 1 && m_MacroType == MacroType::QT_TR_NOOP)
        {
            const QRegularExpression findClassNameRegExp("(?<=\\bclass\\s)(\\w+)");
            m_Scope = QRegularExpressionMatch(findClassNameRegExp.match(typeid(T).name())).captured(0);
            m_Native = transcode(macroArguments[0]);
        }
        else if ((macroArguments.size() == 2 && m_MacroType == MacroType::QT_TRANSLATE_NOOP) || (macroArguments.size() == 3 && m_MacroType == MacroType::QT_TRANSLATE_NOOP3))
        {
            m_Scope = macroArguments[0];
            m_Native = transcode(macroArguments[1]);
        }
        else
        {
            //TODO: Figure out what to put here
        }
    }

    MacroType m_MacroType = MacroType::Unknown;
    QString m_Native;
    QString m_Scope;
};
std::enable_if_t<std::is_convertible<T, QObject>::value
namespace
{
    enum class ERROR
    {
        COUNT,
        ARGUMENT_SWAP,
    };

    static const std::map<ERROR, TranslatedString<void>> ERROR_STRINGS =
    {
        std::make_pair(ERROR::COUNT, TR_STRING_VOID(QT_TRANSLATE_NOOP("MainWindow", "%1"))),
        // Translated text could be given as "Second Argument: %2,   First Argument: %1"
        std::make_pair(ERROR::ARGUMENT_SWAP, TR_STRING_VOID(QT_TRANSLATE_NOOP("MainWindow", "First Argument: %1,   Second Argument: %2"))),
    };
}

void MainWindow::retranslateUi()
{
    static int count = 0;
    count++;

    // This has the copyright symbol unicode in it.
    auto ts = TR_STRING(QT_TR_NOOP("Test translation. \xC2\xA9"));

    // Both the translated string and the original text are available
    ui->translatedLabel->setText(ts.translated());
    ui->nativeLabel->setText(ts.native());

    ui->translatedCountLabel->setText(ERROR_STRINGS.at(COUNT).translated().arg(count));
    ui->nativeCountLabel->setText(ERROR_STRINGS.at(COUNT).native().arg(count));

    // Note that the arguments need to be provided to each string
    // so that they can be replaced according to the correct order
    // of the translated text which is only available at runtime.
    ui->translatedSwappedArgumentsLabel->setText(ERROR_STRINGS.at(ARGUMENT_SWAP).translated().arg(50.0).arg("String"));
    ui->swappedArgumentsLabel->setText(ERROR_STRINGS.at(ARGUMENT_SWAP).native().arg(50.0).arg("String"));
}