qmllint: allow mixing ID based with text based translation
Since 6.10 Qt i18n component allows mixing id based with text
based translation and this is reflected in lrelease, lupdate,
and documentation.
This patch is a partial revert of
8b61addfa4
and removes the
qmllint warning in the case of mixing these two.
Pick-to: 6.10
Change-Id: Iae2407da2bc5cc21fc3664051834c99b8c72fe58
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
This commit is contained in:
parent
db1a9e1ac5
commit
142b267ed1
|
@ -93,6 +93,19 @@ private:
|
|||
Element m_qtObject;
|
||||
};
|
||||
|
||||
class QQmlJSTranslationFunctionMismatchCheck : public QQmlSA::PropertyPass
|
||||
{
|
||||
public:
|
||||
using QQmlSA::PropertyPass::PropertyPass;
|
||||
|
||||
void onCall(const QQmlSA::Element &element, const QString &propertyName,
|
||||
const QQmlSA::Element &readScope, QQmlSA::SourceLocation location) override;
|
||||
|
||||
private:
|
||||
enum TranslationType : quint8 { None, Normal, IdBased };
|
||||
TranslationType m_lastTranslationFunction = None;
|
||||
};
|
||||
|
||||
void QdsBindingValidator::onRead(const QQmlSA::Element &element, const QString &propertyName,
|
||||
const QQmlSA::Element &readScope, QQmlSA::SourceLocation location)
|
||||
{
|
||||
|
@ -142,6 +155,51 @@ void QdsBindingValidator::onWrite(const QQmlSA::Element &, const QString &proper
|
|||
}
|
||||
}
|
||||
|
||||
void QQmlJSTranslationFunctionMismatchCheck::onCall(const QQmlSA::Element &element,
|
||||
const QString &propertyName,
|
||||
const QQmlSA::Element &readScope,
|
||||
QQmlSA::SourceLocation location)
|
||||
{
|
||||
Q_UNUSED(readScope);
|
||||
|
||||
const QQmlSA::Element globalJSObject = resolveBuiltinType(u"GlobalObject");
|
||||
if (element != globalJSObject)
|
||||
return;
|
||||
|
||||
constexpr std::array translationFunctions = {
|
||||
"qsTranslate"_L1,
|
||||
"QT_TRANSLATE_NOOP"_L1,
|
||||
"qsTr"_L1,
|
||||
"QT_TR_NOOP"_L1,
|
||||
};
|
||||
|
||||
constexpr std::array idTranslationFunctions = {
|
||||
"qsTrId"_L1,
|
||||
"QT_TRID_NOOP"_L1,
|
||||
};
|
||||
|
||||
const bool isTranslation =
|
||||
std::find(translationFunctions.cbegin(), translationFunctions.cend(), propertyName)
|
||||
!= translationFunctions.cend();
|
||||
const bool isIdTranslation =
|
||||
std::find(idTranslationFunctions.cbegin(), idTranslationFunctions.cend(), propertyName)
|
||||
!= idTranslationFunctions.cend();
|
||||
|
||||
if (!isTranslation && !isIdTranslation)
|
||||
return;
|
||||
|
||||
const TranslationType current = isTranslation ? Normal : IdBased;
|
||||
|
||||
if (m_lastTranslationFunction == None) {
|
||||
m_lastTranslationFunction = current;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_lastTranslationFunction != current) {
|
||||
emitWarning("Do not mix translation functions", qmlTranslationFunctionMismatch, location);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlLintQdsPlugin::registerPasses(PassManager *manager, const Element &rootElement)
|
||||
{
|
||||
if (!rootElement.filePath().endsWith(u".ui.qml"))
|
||||
|
@ -151,6 +209,8 @@ void QmlLintQdsPlugin::registerPasses(PassManager *manager, const Element &rootE
|
|||
QAnyStringView(), QAnyStringView());
|
||||
manager->registerPropertyPass(std::make_shared<QdsBindingValidator>(manager, rootElement),
|
||||
QAnyStringView(), QAnyStringView());
|
||||
manager->registerPropertyPass(std::make_unique<QQmlJSTranslationFunctionMismatchCheck>(manager),
|
||||
QString(), QString(), QString());
|
||||
manager->registerElementPass(std::make_unique<QdsElementValidator>(manager));
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@ qt_internal_add_module(QmlCompiler
|
|||
qqmlsaconstants.h
|
||||
qqmlsasourcelocation.cpp qqmlsasourcelocation.h qqmlsasourcelocation_p.h
|
||||
qresourcerelocater.cpp qresourcerelocater_p.h
|
||||
qqmljstranslationfunctionmismatchcheck_p.h qqmljstranslationfunctionmismatchcheck.cpp
|
||||
qqmljscontextproperties_p.h qqmljscontextproperties.cpp
|
||||
qqmljsusercontextproperties_p.h qqmljsusercontextproperties.cpp
|
||||
NO_UNITY_BUILD_SOURCES
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include <QtQmlCompiler/private/qqmljsimporter_p.h>
|
||||
#include <QtQmlCompiler/private/qqmljsimportvisitor_p.h>
|
||||
#include <QtQmlCompiler/private/qqmljsliteralbindingcheck_p.h>
|
||||
#include <QtQmlCompiler/private/qqmljstranslationfunctionmismatchcheck_p.h>
|
||||
|
||||
#include <QtCore/qjsonobject.h>
|
||||
#include <QtCore/qfileinfo.h>
|
||||
|
@ -657,9 +656,6 @@ QQmlJSLinter::lintFile(const QString &filename, const QString *fileContents, con
|
|||
&QQmlSA::PassManagerPrivate::deletePassManager);
|
||||
passMan->registerPropertyPass(std::make_unique<QQmlJSLiteralBindingCheck>(passMan.get()),
|
||||
QString(), QString(), QString());
|
||||
passMan->registerPropertyPass(
|
||||
std::make_unique<QQmlJSTranslationFunctionMismatchCheck>(passMan.get()), QString(),
|
||||
QString(), QString());
|
||||
|
||||
QQmlSA::PropertyPassBuilder(passMan.get())
|
||||
.withOnCall([](QQmlSA::PropertyPass *self, const QQmlSA::Element &, const QString &,
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "qqmljstranslationfunctionmismatchcheck_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
void QQmlJSTranslationFunctionMismatchCheck::onCall(const QQmlSA::Element &element,
|
||||
const QString &propertyName,
|
||||
const QQmlSA::Element &readScope,
|
||||
QQmlSA::SourceLocation location)
|
||||
{
|
||||
Q_UNUSED(readScope);
|
||||
|
||||
const QQmlSA::Element globalJSObject = resolveBuiltinType(u"GlobalObject");
|
||||
if (element != globalJSObject)
|
||||
return;
|
||||
|
||||
constexpr std::array translationFunctions = {
|
||||
"qsTranslate"_L1,
|
||||
"QT_TRANSLATE_NOOP"_L1,
|
||||
"qsTr"_L1,
|
||||
"QT_TR_NOOP"_L1,
|
||||
};
|
||||
|
||||
constexpr std::array idTranslationFunctions = {
|
||||
"qsTrId"_L1,
|
||||
"QT_TRID_NOOP"_L1,
|
||||
};
|
||||
|
||||
const bool isTranslation =
|
||||
std::find(translationFunctions.cbegin(), translationFunctions.cend(), propertyName)
|
||||
!= translationFunctions.cend();
|
||||
const bool isIdTranslation =
|
||||
std::find(idTranslationFunctions.cbegin(), idTranslationFunctions.cend(), propertyName)
|
||||
!= idTranslationFunctions.cend();
|
||||
|
||||
if (!isTranslation && !isIdTranslation)
|
||||
return;
|
||||
|
||||
const TranslationType current = isTranslation ? Normal : IdBased;
|
||||
|
||||
if (m_lastTranslationFunction == None) {
|
||||
m_lastTranslationFunction = current;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_lastTranslationFunction != current) {
|
||||
emitWarning("Do not mix translation functions", qmlTranslationFunctionMismatch, location);
|
||||
}
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
|
@ -1,35 +0,0 @@
|
|||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef QQMLJSTRANSLATIONMISMATCHCHECK_P_H
|
||||
#define QQMLJSTRANSLATIONMISMATCHCHECK_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
|
||||
#include "qqmlsa.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QQmlJSTranslationFunctionMismatchCheck : public QQmlSA::PropertyPass
|
||||
{
|
||||
public:
|
||||
using QQmlSA::PropertyPass::PropertyPass;
|
||||
|
||||
void onCall(const QQmlSA::Element &element, const QString &propertyName,
|
||||
const QQmlSA::Element &readScope, QQmlSA::SourceLocation location) override;
|
||||
|
||||
private:
|
||||
enum TranslationType: quint8 { None, Normal, IdBased };
|
||||
TranslationType m_lastTranslationFunction = None;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
#endif // QQMLJSTRANSLATIONMISMATCHCHECK_P_H
|
|
@ -1,6 +0,0 @@
|
|||
import QtQuick
|
||||
|
||||
Item {
|
||||
property string qsTrNoop: QT_TR_NOOP("hello")
|
||||
property string qsTrIdString: qsTrId(qsTrNoop)
|
||||
}
|
|
@ -3,4 +3,5 @@ import QtQuick
|
|||
Item {
|
||||
property string translated: qsTrId("Hello")
|
||||
property string translatedNoOP: QT_TRID_NOOP("Hello")
|
||||
property string qsTrInExpression: "Hello" + qsTr("World") + "!"
|
||||
}
|
||||
|
|
|
@ -570,15 +570,6 @@ void TestQmllint::dirtyQmlCode_data()
|
|||
QTest::newRow("BadScriptBindingOnGroup")
|
||||
<< QStringLiteral("badScriptBinding.group.qml")
|
||||
<< Result{ { { "Could not find property \"bogusProperty\"."_L1, 3, 10 } } };
|
||||
{
|
||||
const QString warning = u"Do not mix translation functions"_s;
|
||||
QTest::addRow("BadTranslationMix")
|
||||
<< testFile(u"translations/BadMix.qml"_s)
|
||||
<< Result{ { { warning, 5, 49 }, { warning, 6, 56 }, } };
|
||||
QTest::addRow("BadTranslationMixWithMacros")
|
||||
<< testFile(u"translations/BadMixWithMacros.qml"_s)
|
||||
<< Result{ { { warning, 5, 29 } } };
|
||||
}
|
||||
QTest::newRow("CoerceToVoid")
|
||||
<< QStringLiteral("coercetovoid.qml")
|
||||
<< Result{ { { "Function without return type annotation returns double"_L1 } } };
|
||||
|
@ -3420,6 +3411,12 @@ void TestQmllint::qdsPlugin_data()
|
|||
<< Result{ { Message{ functionError, 4, 5 }, Message{ functionError, 13, 9 } },
|
||||
{ Message{ functionError, 7, 9 }, Message{ functionError, 10, 9 } } };
|
||||
}
|
||||
{
|
||||
const QString warning = u"Do not mix translation functions"_s;
|
||||
QTest::addRow("BadTranslationMix")
|
||||
<< u"qdsPlugin/BadMix.ui.qml"_s
|
||||
<< Result{ { Message{ warning, 5, 49 }, { warning, 6, 56 } } };
|
||||
}
|
||||
}
|
||||
|
||||
void TestQmllint::qdsPlugin()
|
||||
|
|
Loading…
Reference in New Issue