Allow loading of empty translation files

Do not return false for loading an empty .qm file - that is, a valid
file without any translations. We're already shipping empty .qm
files for English translations of Qt since a while, mainly as a
stop for the QTranslator::load(const QLocale &, ...) logic.

Note that QCoreApplication::installTranslator() will still return
false for an empty translation file - which is ok, because it
arguably does not make much sense to install it.

[ChangeLog][QtCore][QTranslator] It is now possible to load qm files
without any translations. This is particularly useful for the
language the untranslated strings are written in; logic to
load translations can now handle the source language like all
other languages.

Task-number: QTBUG-31031
Change-Id: Ibcb84aa755538cb2fa21b14f8635295a58440bbb
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io>
bb10
Kai Koehne 2018-07-05 17:12:18 +02:00
parent 4e0404a6d2
commit 9146432dc6
7 changed files with 46 additions and 30 deletions

View File

@ -533,7 +533,7 @@ bool QTranslatorPrivate::do_load(const QString &realname, const QString &directo
// memory, so no need to use QFile to copy it again.
Q_ASSERT(!d->resource);
d->resource = new QResource(realname);
if (resource->isValid() && !resource->isCompressed() && resource->size() > MagicLength
if (resource->isValid() && !resource->isCompressed() && resource->size() >= MagicLength
&& !memcmp(resource->data(), magic, MagicLength)) {
d->unmapLength = resource->size();
d->unmapPointer = reinterpret_cast<char *>(const_cast<uchar *>(resource->data()));
@ -553,7 +553,7 @@ bool QTranslatorPrivate::do_load(const QString &realname, const QString &directo
return false;
qint64 fileSize = file.size();
if (fileSize <= MagicLength || quint32(-1) <= fileSize)
if (fileSize < MagicLength || quint32(-1) <= fileSize)
return false;
{
@ -858,8 +858,6 @@ bool QTranslatorPrivate::do_load(const uchar *data, int len, const QString &dire
data += blockLen;
}
if (dependencies.isEmpty() && (!offsetArray || !messageArray))
ok = false;
if (ok && !isValidNumerusRules(numerusRulesArray, numerusRulesLength))
ok = false;
if (ok) {
@ -1138,8 +1136,8 @@ QString QTranslator::translate(const char *context, const char *sourceText, cons
bool QTranslator::isEmpty() const
{
Q_D(const QTranslator);
return !d->unmapPointer && !d->unmapLength && !d->messageArray &&
!d->offsetArray && !d->contextArray && d->subTranslators.isEmpty();
return !d->messageArray && !d->offsetArray && !d->contextArray
&& d->subTranslators.isEmpty();
}
QT_END_NAMESPACE

View File

@ -1,6 +1,7 @@
<RCC>
<qresource prefix="/android_testdata">
<file>hellotr_la.qm</file>
<file>hellotr_empty.qm</file>
<file>msgfmt_from_po.qm</file>
<file>dependencies_la.qm</file>
</qresource>

View File

@ -0,0 +1 @@
<クd<>箆!ソ`。スン

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1"/>

View File

@ -5,5 +5,5 @@ SOURCES = tst_qtranslator.cpp
RESOURCES += qtranslator.qrc
android:!android-embedded: RESOURCES += android_testdata.qrc
else: TESTDATA += dependencies_la.qm hellotr_la.qm msgfmt_from_po.qm
else: TESTDATA += dependencies_la.qm hellotr_empty.qm hellotr_la.qm msgfmt_from_po.qm

View File

@ -1,5 +1,6 @@
<RCC>
<qresource prefix="/tst_qtranslator">
<file>hellotr_la.qm</file>
<file>hellotr_empty.qm</file>
</qresource>
</RCC>

View File

@ -41,13 +41,12 @@ protected:
private slots:
void initTestCase();
void load_data();
void load();
void load2();
void threadLoad();
void testLanguageChange();
void plural();
void translate_qm_file_generated_with_msgfmt();
void loadFromResource();
void loadDirectory();
void dependencies();
void translationInThreadWhileInstallingTranslator();
@ -106,24 +105,45 @@ bool tst_QTranslator::eventFilter(QObject *, QEvent *event)
return false;
}
void tst_QTranslator::load()
void tst_QTranslator::load_data()
{
QTest::addColumn<QString>("filepath");
QTest::addColumn<bool>("isEmpty");
QTest::addColumn<QString>("translation");
QTranslator tor( 0 );
tor.load("hellotr_la");
QVERIFY(!tor.isEmpty());
QCOMPARE(tor.translate("QPushButton", "Hello world!"), QLatin1String("Hallo Welt!"));
QTest::newRow("hellotr_la") << "hellotr_la.qm" << false << "Hallo Welt!";
QTest::newRow("hellotr_empty") << "hellotr_empty.qm" << true << "";
}
void tst_QTranslator::load2()
void tst_QTranslator::load()
{
QTranslator tor( 0 );
QFile file("hellotr_la.qm");
file.open(QFile::ReadOnly);
QByteArray data = file.readAll();
tor.load((const uchar *)data.constData(), data.length());
QVERIFY(!tor.isEmpty());
QCOMPARE(tor.translate("QPushButton", "Hello world!"), QLatin1String("Hallo Welt!"));
QFETCH(QString, filepath);
QFETCH(bool, isEmpty);
QFETCH(QString, translation);
{
QTranslator tor;
QVERIFY(tor.load(QFileInfo(filepath).baseName()));
QCOMPARE(tor.isEmpty(), isEmpty);
QCOMPARE(tor.translate("QPushButton", "Hello world!"), translation);
}
{
QFile file(filepath);
file.open(QFile::ReadOnly);
QByteArray data = file.readAll();
QTranslator tor;
QVERIFY(tor.load((const uchar *)data.constData(), data.length()));
QCOMPARE(tor.isEmpty(), isEmpty);
QCOMPARE(tor.translate("QPushButton", "Hello world!"), translation);
}
{
QTranslator tor;
QVERIFY(tor.load(QString(":/tst_qtranslator/%1").arg(filepath)));
QCOMPARE(tor.isEmpty(), isEmpty);
QCOMPARE(tor.translate("QPushButton", "Hello world!"), translation);
}
}
class TranslatorThread : public QThread
@ -240,14 +260,6 @@ void tst_QTranslator::translate_qm_file_generated_with_msgfmt()
qApp->removeTranslator(&translator);
}
void tst_QTranslator::loadFromResource()
{
QTranslator tor;
tor.load(":/tst_qtranslator/hellotr_la.qm");
QVERIFY(!tor.isEmpty());
QCOMPARE(tor.translate("QPushButton", "Hello world!"), QLatin1String("Hallo Welt!"));
}
void tst_QTranslator::loadDirectory()
{
QString current_base = QDir::current().dirName();