qmltc: Properly escape translation strings

We have QQmlJSUtils::toLiteral() for that. Extend it to handle byte
arrays in addition to strings and use it.

Fixes: QTBUG-134726
Change-Id: Ibde1f56b25794fc8c49b796303c4f39933aedb42
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
This commit is contained in:
Ulf Hermann 2025-04-10 17:11:42 +02:00
parent f181086eeb
commit 916f5b51c8
6 changed files with 49 additions and 23 deletions

View File

@ -73,13 +73,13 @@ struct Q_QMLCOMPILER_EXPORT QQmlJSUtils
Returns escaped version of \a s. This function is mostly useful for code
generators.
*/
static QString escapeString(QString s)
template<typename String, typename CharacterLiteral, typename StringView>
static String escapeString(String s)
{
using namespace Qt::StringLiterals;
return s.replace('\\'_L1, "\\\\"_L1)
.replace('"'_L1, "\\\""_L1)
.replace('\n'_L1, "\\n"_L1)
.replace('?'_L1, "\\?"_L1);
return s.replace(CharacterLiteral('\\'), StringView("\\\\"))
.replace(CharacterLiteral('"'), StringView("\\\""))
.replace(CharacterLiteral('\n'), StringView("\\n"))
.replace(CharacterLiteral('?'), StringView("\\?"));
}
/*! \internal
@ -89,9 +89,14 @@ struct Q_QMLCOMPILER_EXPORT QQmlJSUtils
\note This function escapes \a s before wrapping it.
*/
static QString toLiteral(const QString &s, QStringView ctor = u"QStringLiteral")
template<
typename String = QString,
typename CharacterLiteral = QLatin1Char,
typename StringView = QLatin1StringView>
static String toLiteral(const String &s, StringView ctor = StringView("QStringLiteral"))
{
return ctor % u"(\"" % escapeString(s) % u"\")";
return ctor % StringView("(\"")
% escapeString<String, CharacterLiteral, StringView>(s) % StringView("\")");
}
/*! \internal

View File

@ -143,6 +143,8 @@ set(qml_sources
attachedComponentProperty.qml
attachedNamespacedProperty.qml
newLineTranslation.qml
)
set(js_sources

View File

@ -0,0 +1,6 @@
import QtQml
QtObject {
objectName: qsTr("Hello World \n")
}

View File

@ -97,6 +97,8 @@
#include "attachedcomponentproperty.h"
#include "attachednamespacedproperty.h"
#include "newlinetranslation.h"
// Qt:
#include <QtCore/qstring.h>
#include <QtCore/qbytearray.h>
@ -3455,4 +3457,11 @@ void tst_qmltc::attachedNamespacedProperty()
checkOverlayAttached(&createdByQmltc);
}
void tst_qmltc::newLineTranslation()
{
QQmlEngine e;
PREPEND_NAMESPACE(newLineTranslation) createdByQmltc(&e);
QCOMPARE(createdByQmltc.objectName(), "Hello World \n"_L1);
}
QTEST_MAIN(tst_qmltc)

View File

@ -110,4 +110,6 @@ private slots:
void attachedComponentProperty();
void attachedNamespacedProperty();
void newLineTranslation();
};

View File

@ -253,29 +253,31 @@ void QmltcCodeGenerator::generate_createBindingOnProperty(
}
}
static QByteArray toLiteral(const QByteArray &utf8)
{
return QQmlJSUtils::toLiteral<QByteArray, char, QByteArrayView>(utf8);
}
static QString serializeTranslation(const QQmlTranslation::QsTrIdData &data)
{
QString result = QStringLiteral(R"(QQmlTranslation(QQmlTranslation::QsTrIdData(
QStringLiteral("%1"),
return QStringLiteral(R"(QQmlTranslation(QQmlTranslation::QsTrIdData(
%1,
%4)))")
.arg(QString::fromUtf8(data.id()))
.arg(toLiteral(data.id()))
.arg(data.number());
return result;
}
static QString serializeTranslation(const QQmlTranslation::QsTrData &data)
{
QString result = QStringLiteral(R"(QQmlTranslation(QQmlTranslation::QsTrData(
QStringLiteral("%1"),
QStringLiteral("%2"),
QStringLiteral("%3"),
return QStringLiteral(R"(QQmlTranslation(QQmlTranslation::QsTrData(
%1,
%2,
%3,
%4)))")
.arg(QString::fromUtf8(data.context()), QString::fromUtf8(data.text()),
QString::fromUtf8(data.comment()))
.arg(toLiteral(data.context()),
toLiteral(data.text()),
toLiteral(data.comment()))
.arg(data.number());
return result;
}
static QString serializeTranslation(const QQmlTranslation &translation)