summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakumi ASAKI <asaki@sra.co.jp>2015-12-15 13:46:09 +0900
committerOswald Buddenhagen <oswald.buddenhagen@qt.io>2016-10-25 09:01:07 +0000
commitf2ebd51d96ad49eb826a4e37e67d506fffcbd40c (patch)
treee95097a54d14d577251f2f6a3247db81a9efc716
parent8e7e60dbdea04c943bc6d50290db12d3fefd39f2 (diff)
lupdate: Add qrc resource file support
lupdate parses qrc files specified by the RESOURCES qmake variable or by command line options, and adds files in them as source files. [ChangeLog][lupdate] Added qrc resource file support Task-number: QTBUG-53206 Change-Id: Id7f952487ab11e062db9c5a419fb2ee3c4716740 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io>
-rw-r--r--src/linguist/linguist/doc/src/linguist-manual.qdoc34
-rw-r--r--src/linguist/lupdate/main.cpp132
-rw-r--r--tests/auto/linguist/lupdate/testdata/good/parseqrc/main.cpp42
-rw-r--r--tests/auto/linguist/lupdate/testdata/good/parseqrc/main.js1
-rw-r--r--tests/auto/linguist/lupdate/testdata/good/parseqrc/main.qml40
-rw-r--r--tests/auto/linguist/lupdate/testdata/good/parseqrc/project.pro7
-rw-r--r--tests/auto/linguist/lupdate/testdata/good/parseqrc/project.qrc5
-rw-r--r--tests/auto/linguist/lupdate/testdata/good/parseqrc/project.ts.result25
-rw-r--r--tests/auto/linguist/lupdate/testdata/good/resources_cmdline/lupdatecmd1
-rw-r--r--tests/auto/linguist/lupdate/testdata/good/resources_cmdline/main.js1
-rw-r--r--tests/auto/linguist/lupdate/testdata/good/resources_cmdline/main.qml40
-rw-r--r--tests/auto/linguist/lupdate/testdata/good/resources_cmdline/project.qrc6
-rw-r--r--tests/auto/linguist/lupdate/testdata/good/resources_cmdline/project.ts.result17
13 files changed, 294 insertions, 57 deletions
diff --git a/src/linguist/linguist/doc/src/linguist-manual.qdoc b/src/linguist/linguist/doc/src/linguist-manual.qdoc
index 722b853a0..308bc9f1c 100644
--- a/src/linguist/linguist/doc/src/linguist-manual.qdoc
+++ b/src/linguist/linguist/doc/src/linguist-manual.qdoc
@@ -847,7 +847,8 @@
The \c lupdate tool extracts user interface strings from your application.
It reads the application .pro file to identify which source files
contain text to be translated. This means your source files must be listed
- in the \c SOURCES or \c HEADERS entry in the .pro file. If your files are
+ in the \c SOURCES or \c HEADERS entry in the .pro file, or in resource
+ files listed in the \c RESOURCE entry. If your files are
not listed, the text in them will not be found.
An example of a complete \c .pro file with four translation source
@@ -870,37 +871,6 @@
\snippet doc_src_linguist-manual.cpp 3
- \section2 Use a Conditional to Hide QML Source From the Compiler
-
- The SOURCES variable is intended for C++ source files. If you list QML
- or JavaScript source files there, the compiler tries to build them as though
- they are C++ files. As a workaround, you can use an \c lupdate_only{...}
- conditional statement so the \c lupdate tool sees the .qml files but the C++
- compiler ignores them.
-
- For example, the following .pro file snippet specifies two .qml files in
- the application:
-
- \code
- lupdate_only {
- SOURCES = main.qml \
- MainPage.qml
- }
- \endcode
-
- You can also specify the .qml source files with a wildcard match. The
- search is not recursive so you need to specify each directory where there
- are user interface strings in the source code:
-
- \code
- lupdate_only {
- SOURCES = *.qml \
- *.js \
- content/*.qml \
- content/*.js
- }
- \endcode
-
\section1 Internationalizing Applications
Design your application so that it can be adapted to various languages and
diff --git a/src/linguist/lupdate/main.cpp b/src/linguist/lupdate/main.cpp
index 9fc3d8c80..dd73a9e5b 100644
--- a/src/linguist/lupdate/main.cpp
+++ b/src/linguist/lupdate/main.cpp
@@ -49,6 +49,7 @@
#include <QtCore/QStringList>
#include <QtCore/QTranslator>
#include <QtCore/QLibraryInfo>
+#include <QtCore/QXmlStreamReader>
#include <iostream>
@@ -395,6 +396,73 @@ public:
static EvalHandler evalHandler;
+static bool isSupportedExtension(const QString &ext)
+{
+ return ext == QLatin1String("qml")
+ || ext == QLatin1String("js") || ext == QLatin1String("qs")
+ || ext == QLatin1String("ui") || ext == QLatin1String("jui");
+}
+
+static QStringList getResources(const QString &resourceFile, QMakeVfs *vfs)
+{
+ Q_ASSERT(vfs);
+ if (!vfs->exists(resourceFile))
+ return QStringList();
+ QString content;
+ QString errStr;
+ if (!vfs->readFile(resourceFile, &content, &errStr)) {
+ printErr(LU::tr("lupdate error: Can not read %1: %2\n").arg(resourceFile, errStr));
+ return QStringList();
+ }
+ QStringList fileList;
+ QString dirPath = QFileInfo(resourceFile).path();
+ QXmlStreamReader reader(content);
+ bool isFileTag = false;
+ QStringList tagStack;
+ tagStack << QLatin1String("RCC") << QLatin1String("qresource") << QLatin1String("file");
+ int curDepth = 0;
+ while (!reader.atEnd()) {
+ QXmlStreamReader::TokenType t = reader.readNext();
+ switch (t) {
+ case QXmlStreamReader::StartElement:
+ if (curDepth >= tagStack.count() || reader.name() != tagStack.at(curDepth)) {
+ printErr(LU::tr("unexpected <%1> tag\n").arg(reader.name().toString()));
+ continue;
+ }
+ if (++curDepth == tagStack.count())
+ isFileTag = true;
+ break;
+
+ case QXmlStreamReader::EndElement:
+ isFileTag = false;
+ if (curDepth == 0 || reader.name() != tagStack.at(curDepth - 1)) {
+ printErr(LU::tr("unexpected closing <%1> tag\n").arg(reader.name().toString()));
+ continue;
+ }
+ --curDepth;
+ break;
+
+ case QXmlStreamReader::Characters:
+ if (isFileTag) {
+ QString fn = reader.text().toString();
+ if (!QFileInfo(fn).isAbsolute())
+ fn = dirPath + QLatin1Char('/') + fn;
+ QFileInfo cfi(fn);
+ if (isSupportedExtension(cfi.suffix()))
+ fileList << cfi.filePath();
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (reader.error() != QXmlStreamReader::NoError)
+ printErr(LU::tr("lupdate error: %1:%2: %3\n")
+ .arg(resourceFile, QString::number(reader.lineNumber()), reader.errorString()));
+ return fileList;
+}
+
static QStringList getSources(const char *var, const char *vvar, const QStringList &baseVPaths,
const QString &projectDir, const ProFileEvaluator &visitor)
{
@@ -405,7 +473,7 @@ static QStringList getSources(const char *var, const char *vvar, const QStringLi
}
static QStringList getSources(const ProFileEvaluator &visitor, const QString &projectDir,
- const QStringList &excludes)
+ const QStringList &excludes, QMakeVfs *vfs)
{
QStringList baseVPaths;
baseVPaths += visitor.absolutePathValues(QLatin1String("VPATH"), projectDir);
@@ -420,6 +488,10 @@ static QStringList getSources(const ProFileEvaluator &visitor, const QString &pr
sourceFiles += getSources("FORMS", "VPATH_FORMS", baseVPaths, projectDir, visitor);
+ QStringList resourceFiles = getSources("RESOURCES", "VPATH_RESOURCES", baseVPaths, projectDir, visitor);
+ foreach (const QString &resource, resourceFiles)
+ sourceFiles += getResources(resource, vfs);
+
QStringList installs = visitor.values(QLatin1String("INSTALLS"))
+ visitor.values(QLatin1String("DEPLOYMENT"));
installs.removeDuplicates();
@@ -445,12 +517,8 @@ static QStringList getSources(const ProFileEvaluator &visitor, const QString &pr
while (iterator.hasNext()) {
iterator.next();
QFileInfo cfi = iterator.fileInfo();
- QString ext = cfi.suffix();
- if (ext == QLatin1String("qml")
- || ext == QLatin1String("js") || ext == QLatin1String("qs")
- || ext == QLatin1String("ui") || ext == QLatin1String("jui")) {
+ if (isSupportedExtension(cfi.suffix()))
sourceFiles << cfi.filePath();
- }
}
}
}
@@ -612,7 +680,7 @@ static void processProject(
cd.m_sourceIsUtf16 = options & SourceIsUtf16;
cd.m_includePath = visitor.absolutePathValues(QLatin1String("INCLUDEPATH"), proPath);
cd.m_excludes = getExcludes(visitor, proPath);
- QStringList sourceFiles = getSources(visitor, proPath, cd.m_excludes);
+ QStringList sourceFiles = getSources(visitor, proPath, cd.m_excludes, vfs);
QSet<QString> sourceDirs;
sourceDirs.insert(proPath + QLatin1Char('/'));
foreach (const QString &sf, sourceFiles)
@@ -723,7 +791,7 @@ int main(int argc, char **argv)
#endif // Q_OS_WIN32
#endif
- m_defaultExtensions = QLatin1String("java,jui,ui,c,c++,cc,cpp,cxx,ch,h,h++,hh,hpp,hxx,js,qs,qml");
+ m_defaultExtensions = QLatin1String("java,jui,ui,c,c++,cc,cpp,cxx,ch,h,h++,hh,hpp,hxx,js,qs,qml,qrc");
QStringList args = app.arguments();
QStringList tsFileNames;
@@ -733,6 +801,7 @@ int main(int argc, char **argv)
QMultiHash<QString, QString> allCSources;
QSet<QString> projectRoots;
QStringList sourceFiles;
+ QStringList resourceFiles;
QStringList includePath;
QStringList alienFiles;
QString targetLanguage;
@@ -986,25 +1055,33 @@ int main(int argc, char **argv)
int scanRootLen = dir.absolutePath().length();
foreach (const QFileInfo &fi, fileinfolist) {
QString fn = QDir::cleanPath(fi.absoluteFilePath());
- sourceFiles << fn;
-
- if (!fn.endsWith(QLatin1String(".java"))
- && !fn.endsWith(QLatin1String(".jui"))
- && !fn.endsWith(QLatin1String(".ui"))
- && !fn.endsWith(QLatin1String(".js"))
- && !fn.endsWith(QLatin1String(".qs"))
- && !fn.endsWith(QLatin1String(".qml"))) {
- int offset = 0;
- int depth = 0;
- do {
- offset = fn.lastIndexOf(QLatin1Char('/'), offset - 1);
- QString ffn = fn.mid(offset + 1);
- allCSources.insert(ffn, fn);
- } while (++depth < 3 && offset > scanRootLen);
+ if (fn.endsWith(QLatin1String(".qrc"), Qt::CaseInsensitive)) {
+ resourceFiles << fn;
+ } else {
+ sourceFiles << fn;
+
+ if (!fn.endsWith(QLatin1String(".java"))
+ && !fn.endsWith(QLatin1String(".jui"))
+ && !fn.endsWith(QLatin1String(".ui"))
+ && !fn.endsWith(QLatin1String(".js"))
+ && !fn.endsWith(QLatin1String(".qs"))
+ && !fn.endsWith(QLatin1String(".qml"))) {
+ int offset = 0;
+ int depth = 0;
+ do {
+ offset = fn.lastIndexOf(QLatin1Char('/'), offset - 1);
+ QString ffn = fn.mid(offset + 1);
+ allCSources.insert(ffn, fn);
+ } while (++depth < 3 && offset > scanRootLen);
+ }
}
}
} else {
- sourceFiles << QDir::cleanPath(fi.absoluteFilePath());;
+ QString fn = QDir::cleanPath(fi.absoluteFilePath());
+ if (fn.endsWith(QLatin1String(".qrc"), Qt::CaseInsensitive))
+ resourceFiles << fn;
+ else
+ sourceFiles << fn;
projectRoots.insert(fi.absolutePath() + QLatin1Char('/'));
}
}
@@ -1034,11 +1111,16 @@ int main(int argc, char **argv)
cd.m_projectRoots = projectRoots;
cd.m_includePath = includePath;
cd.m_allCSources = allCSources;
+ if (!resourceFiles.isEmpty()) {
+ QMakeVfs vfs;
+ foreach (const QString &resource, resourceFiles)
+ sourceFiles << getResources(resource, &vfs);
+ }
processSources(fetchedTor, sourceFiles, cd);
updateTsFiles(fetchedTor, tsFileNames, alienFiles,
sourceLanguage, targetLanguage, options, &fail);
} else {
- if (!sourceFiles.isEmpty() || !includePath.isEmpty()) {
+ if (!sourceFiles.isEmpty() || !resourceFiles.isEmpty() || !includePath.isEmpty()) {
printErr(LU::tr("lupdate error:"
" Both project and source files / include paths specified.\n"));
return 1;
diff --git a/tests/auto/linguist/lupdate/testdata/good/parseqrc/main.cpp b/tests/auto/linguist/lupdate/testdata/good/parseqrc/main.cpp
new file mode 100644
index 000000000..7108f6784
--- /dev/null
+++ b/tests/auto/linguist/lupdate/testdata/good/parseqrc/main.cpp
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// IMPORTANT!!!! If you want to add testdata to this file,
+// always add it to the end in order to not change the linenumbers of translations!!!
+
+
+void func1() {
+ QApplication::tr("Hello world");
+}
+
+
diff --git a/tests/auto/linguist/lupdate/testdata/good/parseqrc/main.js b/tests/auto/linguist/lupdate/testdata/good/parseqrc/main.js
new file mode 100644
index 000000000..b2e1dd9e0
--- /dev/null
+++ b/tests/auto/linguist/lupdate/testdata/good/parseqrc/main.js
@@ -0,0 +1 @@
+qsTr("From JavaScript file");
diff --git a/tests/auto/linguist/lupdate/testdata/good/parseqrc/main.qml b/tests/auto/linguist/lupdate/testdata/good/parseqrc/main.qml
new file mode 100644
index 000000000..ea2258343
--- /dev/null
+++ b/tests/auto/linguist/lupdate/testdata/good/parseqrc/main.qml
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+QtObject {
+ function translate() {
+ qsTr("From QML file in root");
+ }
+}
diff --git a/tests/auto/linguist/lupdate/testdata/good/parseqrc/project.pro b/tests/auto/linguist/lupdate/testdata/good/parseqrc/project.pro
new file mode 100644
index 000000000..5000c7396
--- /dev/null
+++ b/tests/auto/linguist/lupdate/testdata/good/parseqrc/project.pro
@@ -0,0 +1,7 @@
+
+SOURCES += main.cpp
+
+RESOURCES += project.qrc
+RESOURCES += main.qml
+
+TRANSLATIONS = project.ts
diff --git a/tests/auto/linguist/lupdate/testdata/good/parseqrc/project.qrc b/tests/auto/linguist/lupdate/testdata/good/parseqrc/project.qrc
new file mode 100644
index 000000000..87bacf228
--- /dev/null
+++ b/tests/auto/linguist/lupdate/testdata/good/parseqrc/project.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+ <file>main.js</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/linguist/lupdate/testdata/good/parseqrc/project.ts.result b/tests/auto/linguist/lupdate/testdata/good/parseqrc/project.ts.result
new file mode 100644
index 000000000..6dcd8c2a5
--- /dev/null
+++ b/tests/auto/linguist/lupdate/testdata/good/parseqrc/project.ts.result
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1">
+<context>
+ <name>QApplication</name>
+ <message>
+ <location filename="main.cpp" line="39"/>
+ <source>Hello world</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>main</name>
+ <message>
+ <location filename="main.js" line="1"/>
+ <source>From JavaScript file</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="main.qml" line="38"/>
+ <source>From QML file in root</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+</TS>
diff --git a/tests/auto/linguist/lupdate/testdata/good/resources_cmdline/lupdatecmd b/tests/auto/linguist/lupdate/testdata/good/resources_cmdline/lupdatecmd
new file mode 100644
index 000000000..f3709944b
--- /dev/null
+++ b/tests/auto/linguist/lupdate/testdata/good/resources_cmdline/lupdatecmd
@@ -0,0 +1 @@
+lupdate project.qrc -ts project.ts
diff --git a/tests/auto/linguist/lupdate/testdata/good/resources_cmdline/main.js b/tests/auto/linguist/lupdate/testdata/good/resources_cmdline/main.js
new file mode 100644
index 000000000..b2e1dd9e0
--- /dev/null
+++ b/tests/auto/linguist/lupdate/testdata/good/resources_cmdline/main.js
@@ -0,0 +1 @@
+qsTr("From JavaScript file");
diff --git a/tests/auto/linguist/lupdate/testdata/good/resources_cmdline/main.qml b/tests/auto/linguist/lupdate/testdata/good/resources_cmdline/main.qml
new file mode 100644
index 000000000..ea2258343
--- /dev/null
+++ b/tests/auto/linguist/lupdate/testdata/good/resources_cmdline/main.qml
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+QtObject {
+ function translate() {
+ qsTr("From QML file in root");
+ }
+}
diff --git a/tests/auto/linguist/lupdate/testdata/good/resources_cmdline/project.qrc b/tests/auto/linguist/lupdate/testdata/good/resources_cmdline/project.qrc
new file mode 100644
index 000000000..c5bf15067
--- /dev/null
+++ b/tests/auto/linguist/lupdate/testdata/good/resources_cmdline/project.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+ <file>main.qml</file>
+ <file>main.js</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/linguist/lupdate/testdata/good/resources_cmdline/project.ts.result b/tests/auto/linguist/lupdate/testdata/good/resources_cmdline/project.ts.result
new file mode 100644
index 000000000..82719c026
--- /dev/null
+++ b/tests/auto/linguist/lupdate/testdata/good/resources_cmdline/project.ts.result
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1">
+<context>
+ <name>main</name>
+ <message>
+ <location filename="main.qml" line="38"/>
+ <source>From QML file in root</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="main.js" line="1"/>
+ <source>From JavaScript file</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+</TS>