source: trunk/tools/linguist/lupdate/main.cpp@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 28.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the Qt Linguist of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "lupdate.h"
43
44#include <translator.h>
45#include <profileevaluator.h>
46
47#include <QtCore/QCoreApplication>
48#include <QtCore/QDebug>
49#include <QtCore/QDir>
50#include <QtCore/QFile>
51#include <QtCore/QFileInfo>
52#include <QtCore/QString>
53#include <QtCore/QStringList>
54#include <QtCore/QTextCodec>
55
56#include <iostream>
57
58static QString m_defaultExtensions;
59
60static void printErr(const QString & out)
61{
62 qWarning("%s", qPrintable(out));
63}
64
65static void printOut(const QString & out)
66{
67 std::cerr << qPrintable(out);
68}
69
70static void recursiveFileInfoList(const QDir &dir,
71 const QSet<QString> &nameFilters, QDir::Filters filter,
72 QFileInfoList *fileinfolist)
73{
74 foreach (const QFileInfo &fi, dir.entryInfoList(filter))
75 if (fi.isDir())
76 recursiveFileInfoList(QDir(fi.absoluteFilePath()), nameFilters, filter, fileinfolist);
77 else if (nameFilters.contains(fi.suffix()))
78 fileinfolist->append(fi);
79}
80
81static void printUsage()
82{
83 printOut(QObject::tr(
84 "Usage:\n"
85 " lupdate [options] [project-file]...\n"
86 " lupdate [options] [source-file|path]... -ts ts-files\n\n"
87 "lupdate is part of Qt's Linguist tool chain. It extracts translatable\n"
88 "messages from Qt UI files, C++, Java and JavaScript/QtScript source code.\n"
89 "Extracted messages are stored in textual translation source files (typically\n"
90 "Qt TS XML). New and modified messages can be merged into existing TS files.\n\n"
91 "Options:\n"
92 " -help Display this information and exit.\n"
93 " -no-obsolete\n"
94 " Drop all obsolete strings.\n"
95 " -extensions <ext>[,<ext>]...\n"
96 " Process files with the given extensions only.\n"
97 " The extension list must be separated with commas, not with whitespace.\n"
98 " Default: '%1'.\n"
99 " -pluralonly\n"
100 " Only include plural form messages.\n"
101 " -silent\n"
102 " Do not explain what is being done.\n"
103 " -no-sort\n"
104 " Do not sort contexts in TS files.\n"
105 " -no-recursive\n"
106 " Do not recursively scan the following directories.\n"
107 " -recursive\n"
108 " Recursively scan the following directories (default).\n"
109 " -I <includepath> or -I<includepath>\n"
110 " Additional location to look for include files.\n"
111 " May be specified multiple times.\n"
112 " -locations {absolute|relative|none}\n"
113 " Specify/override how source code references are saved in TS files.\n"
114 " Default is absolute.\n"
115 " -no-ui-lines\n"
116 " Do not record line numbers in references to UI files.\n"
117 " -disable-heuristic {sametext|similartext|number}\n"
118 " Disable the named merge heuristic. Can be specified multiple times.\n"
119 " -pro <filename>\n"
120 " Name of a .pro file. Useful for files with .pro file syntax but\n"
121 " different file suffix. Projects are recursed into and merged.\n"
122 " -source-language <language>[_<region>]\n"
123 " Specify the language of the source strings for new files.\n"
124 " Defaults to POSIX if not specified.\n"
125 " -target-language <language>[_<region>]\n"
126 " Specify the language of the translations for new files.\n"
127 " Guessed from the file name if not specified.\n"
128 " -ts <ts-file>...\n"
129 " Specify the output file(s). This will override the TRANSLATIONS\n"
130 " and nullify the CODECFORTR from possibly specified project files.\n"
131 " -codecfortr <codec>\n"
132 " Specify the codec assumed for tr() calls. Effective only with -ts.\n"
133 " -version\n"
134 " Display the version of lupdate and exit.\n"
135 ).arg(m_defaultExtensions));
136}
137
138static void updateTsFiles(const Translator &fetchedTor, const QStringList &tsFileNames,
139 const QByteArray &codecForTr, const QString &sourceLanguage, const QString &targetLanguage,
140 UpdateOptions options, bool *fail)
141{
142 QDir dir;
143 QString err;
144 foreach (const QString &fileName, tsFileNames) {
145 QString fn = dir.relativeFilePath(fileName);
146 ConversionData cd;
147 Translator tor;
148 cd.m_sortContexts = !(options & NoSort);
149 if (QFile(fileName).exists()) {
150 if (!tor.load(fileName, cd, QLatin1String("auto"))) {
151 printErr(cd.error());
152 *fail = true;
153 continue;
154 }
155 tor.resolveDuplicates();
156 cd.clearErrors();
157 if (!codecForTr.isEmpty() && codecForTr != tor.codecName())
158 qWarning("lupdate warning: Codec for tr() '%s' disagrees with "
159 "existing file's codec '%s'. Expect trouble.",
160 codecForTr.constData(), tor.codecName().constData());
161 if (!targetLanguage.isEmpty() && targetLanguage != tor.languageCode())
162 qWarning("lupdate warning: Specified target language '%s' disagrees with "
163 "existing file's language '%s'. Ignoring.",
164 qPrintable(targetLanguage), qPrintable(tor.languageCode()));
165 if (!sourceLanguage.isEmpty() && sourceLanguage != tor.sourceLanguageCode())
166 qWarning("lupdate warning: Specified source language '%s' disagrees with "
167 "existing file's language '%s'. Ignoring.",
168 qPrintable(sourceLanguage), qPrintable(tor.sourceLanguageCode()));
169 } else {
170 if (!codecForTr.isEmpty())
171 tor.setCodecName(codecForTr);
172 if (!targetLanguage.isEmpty())
173 tor.setLanguageCode(targetLanguage);
174 else
175 tor.setLanguageCode(Translator::guessLanguageCodeFromFileName(fileName));
176 if (!sourceLanguage.isEmpty())
177 tor.setSourceLanguageCode(sourceLanguage);
178 }
179 tor.makeFileNamesAbsolute(QFileInfo(fileName).absoluteDir());
180 if (options & NoLocations)
181 tor.setLocationsType(Translator::NoLocations);
182 else if (options & RelativeLocations)
183 tor.setLocationsType(Translator::RelativeLocations);
184 else if (options & AbsoluteLocations)
185 tor.setLocationsType(Translator::AbsoluteLocations);
186 if (options & Verbose)
187 printOut(QObject::tr("Updating '%1'...\n").arg(fn));
188
189 UpdateOptions theseOptions = options;
190 if (tor.locationsType() == Translator::NoLocations) // Could be set from file
191 theseOptions |= NoLocations;
192 Translator out = merge(tor, fetchedTor, theseOptions, err);
193 if (!codecForTr.isEmpty())
194 out.setCodecName(codecForTr);
195
196 if ((options & Verbose) && !err.isEmpty()) {
197 printOut(err);
198 err.clear();
199 }
200 if (options & PluralOnly) {
201 if (options & Verbose)
202 printOut(QObject::tr("Stripping non plural forms in '%1'...\n").arg(fn));
203 out.stripNonPluralForms();
204 }
205 if (options & NoObsolete)
206 out.stripObsoleteMessages();
207 out.stripEmptyContexts();
208
209 out.normalizeTranslations(cd);
210 if (!cd.errors().isEmpty()) {
211 printErr(cd.error());
212 cd.clearErrors();
213 }
214 if (!out.save(fileName, cd, QLatin1String("auto"))) {
215 printErr(cd.error());
216 *fail = true;
217 }
218 }
219}
220
221static QStringList getSources(const char *var, const char *vvar, const QStringList &baseVPaths,
222 const QString &projectDir, const ProFileEvaluator &visitor)
223{
224 QStringList vPaths = visitor.absolutePathValues(QLatin1String(vvar), projectDir);
225 vPaths += baseVPaths;
226 vPaths.removeDuplicates();
227 return visitor.absoluteFileValues(QLatin1String(var), projectDir, vPaths, 0);
228}
229
230static QStringList getSources(const ProFileEvaluator &visitor, const QString &projectDir)
231{
232 QStringList baseVPaths;
233 baseVPaths += visitor.absolutePathValues(QLatin1String("VPATH"), projectDir);
234 baseVPaths << projectDir; // QMAKE_ABSOLUTE_SOURCE_PATH
235 baseVPaths += visitor.absolutePathValues(QLatin1String("DEPENDPATH"), projectDir);
236 baseVPaths.removeDuplicates();
237
238 QStringList sourceFiles;
239
240 // app/lib template
241 sourceFiles += getSources("SOURCES", "VPATH_SOURCES", baseVPaths, projectDir, visitor);
242
243 sourceFiles += getSources("FORMS", "VPATH_FORMS", baseVPaths, projectDir, visitor);
244 sourceFiles += getSources("FORMS3", "VPATH_FORMS3", baseVPaths, projectDir, visitor);
245
246 QStringList vPathsInc = baseVPaths;
247 vPathsInc += visitor.absolutePathValues(QLatin1String("INCLUDEPATH"), projectDir);
248 vPathsInc.removeDuplicates();
249 sourceFiles += visitor.absoluteFileValues(QLatin1String("HEADERS"), projectDir, vPathsInc, 0);
250
251 sourceFiles.removeDuplicates();
252 sourceFiles.sort();
253
254 return sourceFiles;
255}
256
257static void processSources(Translator &fetchedTor,
258 const QStringList &sourceFiles, ConversionData &cd)
259{
260 QStringList sourceFilesCpp;
261 for (QStringList::const_iterator it = sourceFiles.begin(); it != sourceFiles.end(); ++it) {
262 if (it->endsWith(QLatin1String(".java"), Qt::CaseInsensitive))
263 loadJava(fetchedTor, *it, cd);
264 else if (it->endsWith(QLatin1String(".ui"), Qt::CaseInsensitive)
265 || it->endsWith(QLatin1String(".jui"), Qt::CaseInsensitive))
266 loadUI(fetchedTor, *it, cd);
267 else if (it->endsWith(QLatin1String(".js"), Qt::CaseInsensitive)
268 || it->endsWith(QLatin1String(".qs"), Qt::CaseInsensitive))
269 loadQScript(fetchedTor, *it, cd);
270 else
271 sourceFilesCpp << *it;
272 }
273 loadCPP(fetchedTor, sourceFilesCpp, cd);
274 if (!cd.error().isEmpty())
275 printOut(cd.error());
276}
277
278static void processProjects(
279 bool topLevel, bool nestComplain, const QStringList &proFiles,
280 UpdateOptions options, const QByteArray &codecForSource,
281 const QString &targetLanguage, const QString &sourceLanguage,
282 Translator *parentTor, bool *fail);
283
284static void processProject(
285 bool nestComplain, const QFileInfo &pfi, ProFileEvaluator &visitor,
286 UpdateOptions options, const QByteArray &_codecForSource,
287 const QString &targetLanguage, const QString &sourceLanguage,
288 Translator *fetchedTor, bool *fail)
289{
290 QByteArray codecForSource = _codecForSource;
291 QStringList tmp = visitor.values(QLatin1String("CODECFORSRC"));
292 if (!tmp.isEmpty()) {
293 codecForSource = tmp.last().toLatin1();
294 if (!QTextCodec::codecForName(codecForSource)) {
295 qWarning("lupdate warning: Codec for source '%s' is invalid. "
296 "Falling back to codec for tr().", codecForSource.constData());
297 codecForSource.clear();
298 }
299 }
300 if (visitor.templateType() == ProFileEvaluator::TT_Subdirs) {
301 QStringList subProFiles;
302 QDir proDir(pfi.absoluteDir());
303 foreach (const QString &subdir, visitor.values(QLatin1String("SUBDIRS"))) {
304 QString subPro = QDir::cleanPath(proDir.absoluteFilePath(subdir));
305 QFileInfo subInfo(subPro);
306 if (subInfo.isDir())
307 subProFiles << (subPro + QLatin1Char('/')
308 + subInfo.fileName() + QLatin1String(".pro"));
309 else
310 subProFiles << subPro;
311 }
312 processProjects(false, nestComplain, subProFiles, options, codecForSource,
313 targetLanguage, sourceLanguage, fetchedTor, fail);
314 } else {
315 ConversionData cd;
316 cd.m_noUiLines = options & NoUiLines;
317 cd.m_codecForSource = codecForSource;
318 cd.m_includePath = visitor.values(QLatin1String("INCLUDEPATH"));
319 QStringList sourceFiles = getSources(visitor, pfi.absolutePath());
320 QSet<QString> sourceDirs;
321 sourceDirs.insert(QDir::cleanPath(pfi.absolutePath()) + QLatin1Char('/'));
322 foreach (const QString &sf, sourceFiles)
323 sourceDirs.insert(sf.left(sf.lastIndexOf(QLatin1Char('/')) + 1));
324 QStringList rootList = sourceDirs.toList();
325 rootList.sort();
326 for (int prev = 0, curr = 1; curr < rootList.length(); )
327 if (rootList.at(curr).startsWith(rootList.at(prev)))
328 rootList.removeAt(curr);
329 else
330 prev = curr++;
331 cd.m_projectRoots = QSet<QString>::fromList(rootList);
332 processSources(*fetchedTor, sourceFiles, cd);
333 }
334}
335
336static void processProjects(
337 bool topLevel, bool nestComplain, const QStringList &proFiles,
338 UpdateOptions options, const QByteArray &codecForSource,
339 const QString &targetLanguage, const QString &sourceLanguage,
340 Translator *parentTor, bool *fail)
341{
342 foreach (const QString &proFile, proFiles) {
343 ProFileEvaluator visitor;
344 visitor.setVerbose(options & Verbose);
345
346 QFileInfo pfi(proFile);
347 ProFile pro(pfi.absoluteFilePath());
348 if (!visitor.queryProFile(&pro) || !visitor.accept(&pro)) {
349 if (topLevel)
350 *fail = true;
351 continue;
352 }
353
354 if (visitor.contains(QLatin1String("TRANSLATIONS"))) {
355 if (parentTor) {
356 if (topLevel) {
357 std::cerr << "lupdate warning: TS files from command line "
358 "will override TRANSLATIONS in " << qPrintable(proFile) << ".\n";
359 goto noTrans;
360 } else if (nestComplain) {
361 std::cerr << "lupdate warning: TS files from command line "
362 "prevent recursing into " << qPrintable(proFile) << ".\n";
363 continue;
364 }
365 }
366 QStringList tsFiles;
367 QDir proDir(pfi.absolutePath());
368 foreach (const QString &tsFile, visitor.values(QLatin1String("TRANSLATIONS")))
369 tsFiles << QFileInfo(proDir, tsFile).filePath();
370 if (tsFiles.isEmpty()) {
371 // This might mean either a buggy PRO file or an intentional detach -
372 // we can't know without seeing the actual RHS of the assignment ...
373 // Just assume correctness and be silent.
374 continue;
375 }
376 Translator tor;
377 QByteArray codecForTr;
378 QStringList tmp = visitor.values(QLatin1String("CODEC"))
379 + visitor.values(QLatin1String("DEFAULTCODEC"))
380 + visitor.values(QLatin1String("CODECFORTR"));
381 if (!tmp.isEmpty()) {
382 codecForTr = tmp.last().toLatin1();
383 tor.setCodecName(codecForTr);
384 }
385 processProject(false, pfi, visitor, options, codecForSource,
386 targetLanguage, sourceLanguage, &tor, fail);
387 updateTsFiles(tor, tsFiles, codecForTr, sourceLanguage, targetLanguage, options, fail);
388 continue;
389 }
390 noTrans:
391 if (!parentTor) {
392 if (topLevel)
393 std::cerr << "lupdate warning: no TS files specified. Only diagnostics "
394 "will be produced for '" << qPrintable(proFile) << "'.\n";
395 Translator tor;
396 processProject(nestComplain, pfi, visitor, options, codecForSource,
397 targetLanguage, sourceLanguage, &tor, fail);
398 } else {
399 processProject(nestComplain, pfi, visitor, options, codecForSource,
400 targetLanguage, sourceLanguage, parentTor, fail);
401 }
402 }
403}
404
405int main(int argc, char **argv)
406{
407 QCoreApplication app(argc, argv);
408 m_defaultExtensions = QLatin1String("ui,c,c++,cc,cpp,cxx,ch,h,h++,hh,hpp,hxx");
409
410 QStringList args = app.arguments();
411 QStringList tsFileNames;
412 QStringList proFiles;
413 QMultiHash<QString, QString> allCSources;
414 QSet<QString> projectRoots;
415 QStringList sourceFiles;
416 QStringList includePath;
417 QString targetLanguage;
418 QString sourceLanguage;
419 QByteArray codecForTr;
420
421 UpdateOptions options =
422 Verbose | // verbose is on by default starting with Qt 4.2
423 HeuristicSameText | HeuristicSimilarText | HeuristicNumber;
424 int numFiles = 0;
425 bool metTsFlag = false;
426 bool recursiveScan = true;
427
428 QString extensions = m_defaultExtensions;
429 QSet<QString> extensionsNameFilters;
430
431 for (int i = 1; i < argc; ++i) {
432 QString arg = args.at(i);
433 if (arg == QLatin1String("-help")
434 || arg == QLatin1String("--help")
435 || arg == QLatin1String("-h")) {
436 printUsage();
437 return 0;
438 } else if (arg == QLatin1String("-pluralonly")) {
439 options |= PluralOnly;
440 continue;
441 } else if (arg == QLatin1String("-noobsolete")
442 || arg == QLatin1String("-no-obsolete")) {
443 options |= NoObsolete;
444 continue;
445 } else if (arg == QLatin1String("-silent")) {
446 options &= ~Verbose;
447 continue;
448 } else if (arg == QLatin1String("-target-language")) {
449 ++i;
450 if (i == argc) {
451 qWarning("The option -target-language requires a parameter.");
452 return 1;
453 }
454 targetLanguage = args[i];
455 continue;
456 } else if (arg == QLatin1String("-source-language")) {
457 ++i;
458 if (i == argc) {
459 qWarning("The option -source-language requires a parameter.");
460 return 1;
461 }
462 sourceLanguage = args[i];
463 continue;
464 } else if (arg == QLatin1String("-disable-heuristic")) {
465 ++i;
466 if (i == argc) {
467 qWarning("The option -disable-heuristic requires a parameter.");
468 return 1;
469 }
470 arg = args[i];
471 if (arg == QLatin1String("sametext")) {
472 options &= ~HeuristicSameText;
473 } else if (arg == QLatin1String("similartext")) {
474 options &= ~HeuristicSimilarText;
475 } else if (arg == QLatin1String("number")) {
476 options &= ~HeuristicNumber;
477 } else {
478 qWarning("Invalid heuristic name passed to -disable-heuristic.");
479 return 1;
480 }
481 continue;
482 } else if (arg == QLatin1String("-locations")) {
483 ++i;
484 if (i == argc) {
485 qWarning("The option -locations requires a parameter.");
486 return 1;
487 }
488 if (args[i] == QLatin1String("none")) {
489 options |= NoLocations;
490 } else if (args[i] == QLatin1String("relative")) {
491 options |= RelativeLocations;
492 } else if (args[i] == QLatin1String("absolute")) {
493 options |= AbsoluteLocations;
494 } else {
495 qWarning("Invalid parameter passed to -locations.");
496 return 1;
497 }
498 continue;
499 } else if (arg == QLatin1String("-no-ui-lines")) {
500 options |= NoUiLines;
501 continue;
502 } else if (arg == QLatin1String("-verbose")) {
503 options |= Verbose;
504 continue;
505 } else if (arg == QLatin1String("-no-recursive")) {
506 recursiveScan = false;
507 continue;
508 } else if (arg == QLatin1String("-recursive")) {
509 recursiveScan = true;
510 continue;
511 } else if (arg == QLatin1String("-no-sort")
512 || arg == QLatin1String("-nosort")) {
513 options |= NoSort;
514 continue;
515 } else if (arg == QLatin1String("-version")) {
516 printOut(QObject::tr("lupdate version %1\n").arg(QLatin1String(QT_VERSION_STR)));
517 return 0;
518 } else if (arg == QLatin1String("-codecfortr")) {
519 ++i;
520 if (i == argc) {
521 qWarning("The -codecfortr option should be followed by a codec name.");
522 return 1;
523 }
524 codecForTr = args[i].toLatin1();
525 continue;
526 } else if (arg == QLatin1String("-ts")) {
527 metTsFlag = true;
528 continue;
529 } else if (arg == QLatin1String("-extensions")) {
530 ++i;
531 if (i == argc) {
532 qWarning("The -extensions option should be followed by an extension list.");
533 return 1;
534 }
535 extensions = args[i];
536 continue;
537 } else if (arg == QLatin1String("-pro")) {
538 ++i;
539 if (i == argc) {
540 qWarning("The -pro option should be followed by a filename of .pro file.");
541 return 1;
542 }
543 proFiles += args[i];
544 numFiles++;
545 continue;
546 } else if (arg.startsWith(QLatin1String("-I"))) {
547 if (arg.length() == 2) {
548 ++i;
549 if (i == argc) {
550 qWarning("The -I option should be followed by a path.");
551 return 1;
552 }
553 includePath += args[i];
554 } else {
555 includePath += args[i].mid(2);
556 }
557 continue;
558 } else if (arg.startsWith(QLatin1String("-")) && arg != QLatin1String("-")) {
559 qWarning("Unrecognized option '%s'", qPrintable(arg));
560 return 1;
561 }
562
563 if (metTsFlag) {
564 bool found = false;
565 foreach (const Translator::FileFormat &fmt, Translator::registeredFileFormats()) {
566 if (arg.endsWith(QLatin1Char('.') + fmt.extension, Qt::CaseInsensitive)) {
567 QFileInfo fi(arg);
568 if (!fi.exists() || fi.isWritable()) {
569 tsFileNames.append(QFileInfo(arg).absoluteFilePath());
570 } else {
571 qWarning("lupdate warning: For some reason, '%s' is not writable.\n",
572 qPrintable(arg));
573 }
574 found = true;
575 break;
576 }
577 }
578 if (!found) {
579 qWarning("lupdate error: File '%s' has no recognized extension\n",
580 qPrintable(arg));
581 return 1;
582 }
583 } else if (arg.endsWith(QLatin1String(".pro"), Qt::CaseInsensitive)
584 || arg.endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) {
585 proFiles << arg;
586 numFiles++;
587 } else {
588 QFileInfo fi(arg);
589 if (!fi.exists()) {
590 qWarning("lupdate error: File '%s' does not exists\n", qPrintable(arg));
591 return 1;
592 } else if (fi.isDir()) {
593 if (options & Verbose)
594 printOut(QObject::tr("Scanning directory '%1'...").arg(arg));
595 QDir dir = QDir(fi.filePath());
596 projectRoots.insert(dir.absolutePath() + QLatin1Char('/'));
597 if (extensionsNameFilters.isEmpty()) {
598 foreach (QString ext, extensions.split(QLatin1Char(','))) {
599 ext = ext.trimmed();
600 if (ext.startsWith(QLatin1Char('.')))
601 ext.remove(0, 1);
602 extensionsNameFilters.insert(ext);
603 }
604 }
605 QDir::Filters filters = QDir::Files | QDir::NoSymLinks;
606 if (recursiveScan)
607 filters |= QDir::AllDirs | QDir::NoDotAndDotDot;
608 QFileInfoList fileinfolist;
609 recursiveFileInfoList(dir, extensionsNameFilters, filters, &fileinfolist);
610 int scanRootLen = dir.absolutePath().length();
611 foreach (const QFileInfo &fi, fileinfolist) {
612 QString fn = QDir::cleanPath(fi.absoluteFilePath());
613 sourceFiles << fn;
614
615 if (!fn.endsWith(QLatin1String(".java"))
616 && !fn.endsWith(QLatin1String(".ui"))
617 && !fn.endsWith(QLatin1String(".js"))
618 && !fn.endsWith(QLatin1String(".qs"))) {
619 int offset = 0;
620 int depth = 0;
621 do {
622 offset = fn.lastIndexOf(QLatin1Char('/'), offset - 1);
623 QString ffn = fn.mid(offset + 1);
624 allCSources.insert(ffn, fn);
625 } while (++depth < 3 && offset > scanRootLen);
626 }
627 }
628 } else {
629 sourceFiles << QDir::cleanPath(fi.absoluteFilePath());;
630 }
631 numFiles++;
632 }
633 } // for args
634
635 if (numFiles == 0) {
636 printUsage();
637 return 1;
638 }
639
640 if (!targetLanguage.isEmpty() && tsFileNames.count() != 1)
641 std::cerr << "lupdate warning: -target-language usually only "
642 "makes sense with exactly one TS file.\n";
643 if (!codecForTr.isEmpty() && tsFileNames.isEmpty())
644 std::cerr << "lupdate warning: -codecfortr has no effect without -ts.\n";
645
646 bool fail = false;
647 if (proFiles.isEmpty()) {
648 if (tsFileNames.isEmpty())
649 std::cerr << "lupdate warning: no TS files specified. "
650 "Only diagnostics will be produced.\n";
651
652 Translator fetchedTor;
653 ConversionData cd;
654 cd.m_noUiLines = options & NoUiLines;
655 cd.m_projectRoots = projectRoots;
656 cd.m_includePath = includePath;
657 cd.m_allCSources = allCSources;
658 fetchedTor.setCodecName(codecForTr);
659 processSources(fetchedTor, sourceFiles, cd);
660 updateTsFiles(fetchedTor, tsFileNames, codecForTr,
661 sourceLanguage, targetLanguage, options, &fail);
662 } else {
663 if (!sourceFiles.isEmpty() || !includePath.isEmpty()) {
664 qWarning("lupdate error: Both project and source files / include paths specified.\n");
665 return 1;
666 }
667 if (!tsFileNames.isEmpty()) {
668 Translator fetchedTor;
669 fetchedTor.setCodecName(codecForTr);
670 processProjects(true, true, proFiles, options, QByteArray(),
671 targetLanguage, sourceLanguage, &fetchedTor, &fail);
672 updateTsFiles(fetchedTor, tsFileNames, codecForTr,
673 sourceLanguage, targetLanguage, options, &fail);
674 } else {
675 processProjects(true, false, proFiles, options, QByteArray(),
676 targetLanguage, sourceLanguage, 0, &fail);
677 }
678 }
679 return fail ? 1 : 0;
680}
Note: See TracBrowser for help on using the repository browser.