1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Linguist of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtCore/QDir>
30#include <QtCore/QDebug>
31#include <QtCore/QFile>
32#include <QtCore/QByteArray>
33
34#include <QtTest/QtTest>
35
36class tst_lrelease : public QObject
37{
38 Q_OBJECT
39
40public:
41 tst_lrelease()
42 : lrelease(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/lrelease")
43 , dataDir(QFINDTESTDATA("testdata/"))
44 {}
45
46private:
47
48private slots:
49 void translate();
50 void compressed();
51 void idbased();
52 void markuntranslated();
53 void dupes();
54 void noTranslations();
55
56private:
57 void doCompare(const QStringList &actual, const QString &expectedFn);
58
59 QString lrelease;
60 QString dataDir;
61};
62
63void tst_lrelease::doCompare(const QStringList &actual, const QString &expectedFn)
64{
65 QFile file(expectedFn);
66 QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
67 QStringList expected = QString(file.readAll()).trimmed().split(sep: '\n');
68
69 int i = 0, ei = expected.size(), gi = actual.size();
70 for (; ; i++) {
71 if (i == gi) {
72 if (i == ei)
73 return;
74 gi = 0;
75 break;
76 } else if (i == ei) {
77 ei = 0;
78 break;
79 } else if (!QRegExp(expected.at(i)).exactMatch(str: actual.at(i))) {
80 while ((ei - 1) >= i && (gi - 1) >= i &&
81 (QRegExp(expected.at(i: ei - 1)).exactMatch(str: actual.at(i: gi - 1))))
82 ei--, gi--;
83 break;
84 }
85 }
86 QString diff;
87 for (int j = qMax(a: 0, b: i - 3); j < i; j++)
88 diff += expected.at(i: j) + '\n';
89 diff += "<<<<<<< got\n";
90 for (int j = i; j < gi; j++) {
91 diff += actual.at(i: j) + '\n';
92 if (j >= i + 5) {
93 diff += "...\n";
94 break;
95 }
96 }
97 diff += "=========\n";
98 for (int j = i; j < ei; j++) {
99 diff += expected.at(i: j) + '\n';
100 if (j >= i + 5) {
101 diff += "...\n";
102 break;
103 }
104 }
105 diff += ">>>>>>> expected\n";
106 for (int j = ei; j < qMin(a: ei + 3, b: expected.size()); j++)
107 diff += expected.at(i: j) + '\n';
108 QFAIL(qPrintable("Output for " + expectedFn + " does not meet expectations:\n" + diff));
109}
110
111void tst_lrelease::translate()
112{
113 QVERIFY(!QProcess::execute(lrelease, QStringList() << (dataDir + "translate.ts")));
114
115 QTranslator translator;
116 QVERIFY(translator.load(dataDir + "translate.qm"));
117 qApp->installTranslator(messageFile: &translator);
118
119 QCOMPARE(QObject::tr("\nnewline at the start"), QString("\nNEWLINE AT THE START"));
120 QCOMPARE(QObject::tr("newline at the end\n"), QString("NEWLINE AT THE END\n"));
121 QCOMPARE(QObject::tr("newline and space at the end\n "), QString("NEWLINE AND SPACE AT THE END\n "));
122 QCOMPARE(QObject::tr("space and newline at the end \n"), QString("SPACE AND NEWLINE AT THE END \n"));
123 QCOMPARE(QObject::tr("\ttab at the start and newline at the end\n"), QString("\tTAB AT THE START AND NEWLINE AT THE END\n"));
124 QCOMPARE(QObject::tr("\n\tnewline and tab at the start"), QString("\n\tNEWLINE AND TAB AT THE START"));
125 QCOMPARE(QObject::tr(" \tspace and tab at the start"), QString(" \tSPACE AND TAB AT THE START"));
126 QCOMPARE(QObject::tr(" string that does not exist"), QString(" string that does not exist"));
127
128 QCOMPARE(QCoreApplication::translate("CubeForm", "Test"), QString::fromLatin1("BBBB"));
129 QCOMPARE(QCoreApplication::translate("", "Test", "Empty context"), QString("AAAA"));
130
131 // Test plurals
132 QString txed = QCoreApplication::translate(context: "Plurals", key: "There are %n houses", disambiguation: 0, n: 0);
133 QCOMPARE(QString::fromLatin1("[%1]").arg(txed), QString("[There are 0 houses]"));
134 QCOMPARE(QCoreApplication::translate("Plurals", "There are %n houses", 0, 1), QString("There is 1 house"));
135 QCOMPARE(QCoreApplication::translate("Plurals", "There are %n houses", 0, 2), QString("There are 2 houses"));
136 QCOMPARE(QCoreApplication::translate("Plurals", "There are %n houses", 0, 3), QString("There are 3 houses"));
137
138
139 // More plurals
140 QCOMPARE(tr("There are %n cars", "More Plurals", 0) , QString("There are 0 cars"));
141 QCOMPARE(tr("There are %n cars", "More Plurals", 1) , QString("There is 1 car"));
142 QCOMPARE(tr("There are %n cars", "More Plurals", 2) , QString("There are 2 cars"));
143 QCOMPARE(tr("There are %n cars", "More Plurals", 3) , QString("There are 3 cars"));
144
145
146 QCOMPARE(QCoreApplication::translate("no_en", "Kj\xc3\xb8r K\xc3\xa5re, kj\xc3\xa6re"), QString::fromUtf8("Drive K\xc3\xa5re, dear"));
147 QCOMPARE(QCoreApplication::translate("en_no", "Drive K\xc3\xa5re, dear"), QString::fromUtf8("Kj\xc3\xb8r K\xc3\xa5re, kj\xc3\xa6re"));
148 QCOMPARE(QCoreApplication::translate("en_ch", "Chinese symbol:"), QString::fromUtf8("Chinese symbol:\xe7\xb0\x9f"));
149
150// printf("halo\r\nhallo");
151 // QCOMPARE(tr("This\r\nwill fail"), QString("THIS\nWILL FAIL")); // \r\n = 0d 0a
152
153 QCOMPARE(tr("Completely random string"),
154 QString::fromLatin1("Super-lange Uebersetzung mit Schikanen\x9c"
155 "Mittlere Uebersetung\x9c"
156 "Kurze Uebers."));
157
158 qApp->removeTranslator(messageFile: &translator);
159}
160
161void tst_lrelease::compressed()
162{
163 QVERIFY(!QProcess::execute(lrelease, QStringList() << "-compress" << (dataDir + "compressed.ts")));
164
165 QTranslator translator;
166 QVERIFY(translator.load(dataDir + "compressed.qm"));
167 qApp->installTranslator(messageFile: &translator);
168
169 QCOMPARE(QCoreApplication::translate("Context1", "Foo"), QString::fromLatin1("in first context"));
170 QCOMPARE(QCoreApplication::translate("Context2", "Bar"), QString::fromLatin1("in second context"));
171
172 QCOMPARE(QCoreApplication::translate("Action1", "Component Name"), QString::fromLatin1("translation in first context"));
173 QCOMPARE(QCoreApplication::translate("Action2", "Component Name"), QString::fromLatin1("translation in second context"));
174 QCOMPARE(QCoreApplication::translate("Action3", "Component Name"), QString::fromLatin1("translation in third context"));
175
176}
177
178void tst_lrelease::idbased()
179{
180 QVERIFY(!QProcess::execute(lrelease, QStringList() << "-idbased" << (dataDir + "idbased.ts")));
181
182 QTranslator translator;
183 QVERIFY(translator.load(dataDir + "idbased.qm"));
184 qApp->installTranslator(messageFile: &translator);
185
186 QCOMPARE(qtTrId("test_id"), QString::fromLatin1("This is a test string."));
187 QCOMPARE(qtTrId("untranslated_id"), QString::fromLatin1("This has no translation."));
188}
189
190void tst_lrelease::markuntranslated()
191{
192 QVERIFY(!QProcess::execute(lrelease, QStringList() << "-markuntranslated" << "#" << "-idbased" << (dataDir + "idbased.ts")));
193
194 QTranslator translator;
195 QVERIFY(translator.load(dataDir + "idbased.qm"));
196 qApp->installTranslator(messageFile: &translator);
197
198 QCOMPARE(qtTrId("test_id"), QString::fromLatin1("This is a test string."));
199 QCOMPARE(qtTrId("untranslated_id"), QString::fromLatin1("#This has no translation."));
200}
201
202void tst_lrelease::dupes()
203{
204 QProcess proc;
205 proc.start(program: lrelease, arguments: QStringList() << (dataDir + "dupes.ts"), mode: QIODevice::ReadWrite | QIODevice::Text);
206 QVERIFY(proc.waitForFinished());
207 QVERIFY(proc.exitStatus() == QProcess::NormalExit);
208 doCompare(actual: QString(proc.readAllStandardError()).trimmed().split(sep: '\n'), expectedFn: dataDir + "dupes.errors");
209}
210
211void tst_lrelease::noTranslations()
212{
213 QProcess proc;
214 proc.start(program: lrelease, arguments: { dataDir + "no-translations.pro" });
215 QVERIFY(proc.waitForFinished());
216 QCOMPARE(proc.exitStatus(), QProcess::NormalExit);
217 QCOMPARE(proc.exitCode(), 0);
218 auto stderrOutput = proc.readAllStandardError();
219 QVERIFY(stderrOutput.contains("lrelease warning: Met no 'TRANSLATIONS' entry in project file"));
220}
221
222QTEST_MAIN(tst_lrelease)
223#include "tst_lrelease.moc"
224

source code of qttools/tests/auto/linguist/lrelease/tst_lrelease.cpp