tools/linguist/lupdate/main.cpp
changeset 33 3e2da88830cd
parent 30 5dc02b23752f
child 37 758a864f9613
equal deleted inserted replaced
30:5dc02b23752f 33:3e2da88830cd
    55 
    55 
    56 #include <iostream>
    56 #include <iostream>
    57 
    57 
    58 static QString m_defaultExtensions;
    58 static QString m_defaultExtensions;
    59 
    59 
    60 static void printErr(const QString & out)
       
    61 {
       
    62     qWarning("%s", qPrintable(out));
       
    63 }
       
    64 
       
    65 static void printOut(const QString & out)
    60 static void printOut(const QString & out)
    66 {
    61 {
    67     std::cerr << qPrintable(out);
    62     std::cerr << qPrintable(out);
    68 }
    63 }
       
    64 
       
    65 class LU {
       
    66     Q_DECLARE_TR_FUNCTIONS(LUpdate)
       
    67 };
    69 
    68 
    70 static void recursiveFileInfoList(const QDir &dir,
    69 static void recursiveFileInfoList(const QDir &dir,
    71     const QSet<QString> &nameFilters, QDir::Filters filter,
    70     const QSet<QString> &nameFilters, QDir::Filters filter,
    72     QFileInfoList *fileinfolist)
    71     QFileInfoList *fileinfolist)
    73 {
    72 {
   148         ConversionData cd;
   147         ConversionData cd;
   149         Translator tor;
   148         Translator tor;
   150         cd.m_sortContexts = !(options & NoSort);
   149         cd.m_sortContexts = !(options & NoSort);
   151         if (QFile(fileName).exists()) {
   150         if (QFile(fileName).exists()) {
   152             if (!tor.load(fileName, cd, QLatin1String("auto"))) {
   151             if (!tor.load(fileName, cd, QLatin1String("auto"))) {
   153                 printErr(cd.error());
   152                 printOut(cd.error());
   154                 *fail = true;
   153                 *fail = true;
   155                 continue;
   154                 continue;
   156             }
   155             }
   157             tor.resolveDuplicates();
   156             tor.resolveDuplicates();
   158             cd.clearErrors();
   157             cd.clearErrors();
   159             if (setCodec && fetchedTor.codec() != tor.codec())
   158             if (setCodec && fetchedTor.codec() != tor.codec())
   160                 qWarning("lupdate warning: Codec for tr() '%s' disagrees with "
   159                 printOut(LU::tr("lupdate warning: Codec for tr() '%1' disagrees with"
   161                          "existing file's codec '%s'. Expect trouble.",
   160                                 " existing file's codec '%2'. Expect trouble.\n")
   162                          fetchedTor.codecName().constData(), tor.codecName().constData());
   161                          .arg(QString::fromLatin1(fetchedTor.codecName()),
       
   162                               QString::fromLatin1(tor.codecName())));
   163             if (!targetLanguage.isEmpty() && targetLanguage != tor.languageCode())
   163             if (!targetLanguage.isEmpty() && targetLanguage != tor.languageCode())
   164                 qWarning("lupdate warning: Specified target language '%s' disagrees with "
   164                 printOut(LU::tr("lupdate warning: Specified target language '%1' disagrees with"
   165                          "existing file's language '%s'. Ignoring.",
   165                                 " existing file's language '%2'. Ignoring.\n")
   166                          qPrintable(targetLanguage), qPrintable(tor.languageCode()));
   166                          .arg(targetLanguage, tor.languageCode()));
   167             if (!sourceLanguage.isEmpty() && sourceLanguage != tor.sourceLanguageCode())
   167             if (!sourceLanguage.isEmpty() && sourceLanguage != tor.sourceLanguageCode())
   168                 qWarning("lupdate warning: Specified source language '%s' disagrees with "
   168                 printOut(LU::tr("lupdate warning: Specified source language '%1' disagrees with"
   169                          "existing file's language '%s'. Ignoring.",
   169                                 " existing file's language '%2'. Ignoring.\n")
   170                          qPrintable(sourceLanguage), qPrintable(tor.sourceLanguageCode()));
   170                          .arg(sourceLanguage, tor.sourceLanguageCode()));
   171         } else {
   171         } else {
   172             if (setCodec)
   172             if (setCodec)
   173                 tor.setCodec(fetchedTor.codec());
   173                 tor.setCodec(fetchedTor.codec());
   174             if (!targetLanguage.isEmpty())
   174             if (!targetLanguage.isEmpty())
   175                 tor.setLanguageCode(targetLanguage);
   175                 tor.setLanguageCode(targetLanguage);
   208             out.stripObsoleteMessages();
   208             out.stripObsoleteMessages();
   209         out.stripEmptyContexts();
   209         out.stripEmptyContexts();
   210 
   210 
   211         out.normalizeTranslations(cd);
   211         out.normalizeTranslations(cd);
   212         if (!cd.errors().isEmpty()) {
   212         if (!cd.errors().isEmpty()) {
   213             printErr(cd.error());
   213             printOut(cd.error());
   214             cd.clearErrors();
   214             cd.clearErrors();
   215         }
   215         }
   216         if (!out.save(fileName, cd, QLatin1String("auto"))) {
   216         if (!out.save(fileName, cd, QLatin1String("auto"))) {
   217             printErr(cd.error());
   217             printOut(cd.error());
   218             *fail = true;
   218             *fail = true;
   219         }
   219         }
   220     }
   220     }
   221 }
   221 }
   222 
   222 
   294     QByteArray codecForSource = _codecForSource;
   294     QByteArray codecForSource = _codecForSource;
   295     QStringList tmp = visitor.values(QLatin1String("CODECFORSRC"));
   295     QStringList tmp = visitor.values(QLatin1String("CODECFORSRC"));
   296     if (!tmp.isEmpty()) {
   296     if (!tmp.isEmpty()) {
   297         codecForSource = tmp.last().toLatin1();
   297         codecForSource = tmp.last().toLatin1();
   298         if (!QTextCodec::codecForName(codecForSource)) {
   298         if (!QTextCodec::codecForName(codecForSource)) {
   299             qWarning("lupdate warning: Codec for source '%s' is invalid. "
   299             printOut(LU::tr("lupdate warning: Codec for source '%1' is invalid."
   300                      "Falling back to codec for tr().", codecForSource.constData());
   300                             " Falling back to codec for tr().\n")
       
   301                      .arg(QString::fromLatin1(codecForSource)));
   301             codecForSource.clear();
   302             codecForSource.clear();
   302         }
   303         }
   303     }
   304     }
   304     if (visitor.templateType() == ProFileEvaluator::TT_Subdirs) {
   305     if (visitor.templateType() == ProFileEvaluator::TT_Subdirs) {
   305         QStringList subProFiles;
   306         QStringList subProFiles;
   450             options &= ~Verbose;
   451             options &= ~Verbose;
   451             continue;
   452             continue;
   452         } else if (arg == QLatin1String("-target-language")) {
   453         } else if (arg == QLatin1String("-target-language")) {
   453             ++i;
   454             ++i;
   454             if (i == argc) {
   455             if (i == argc) {
   455                 qWarning("The option -target-language requires a parameter.");
   456                 printOut(LU::tr("The option -target-language requires a parameter.\n"));
   456                 return 1;
   457                 return 1;
   457             }
   458             }
   458             targetLanguage = args[i];
   459             targetLanguage = args[i];
   459             continue;
   460             continue;
   460         } else if (arg == QLatin1String("-source-language")) {
   461         } else if (arg == QLatin1String("-source-language")) {
   461             ++i;
   462             ++i;
   462             if (i == argc) {
   463             if (i == argc) {
   463                 qWarning("The option -source-language requires a parameter.");
   464                 printOut(LU::tr("The option -source-language requires a parameter.\n"));
   464                 return 1;
   465                 return 1;
   465             }
   466             }
   466             sourceLanguage = args[i];
   467             sourceLanguage = args[i];
   467             continue;
   468             continue;
   468         } else if (arg == QLatin1String("-disable-heuristic")) {
   469         } else if (arg == QLatin1String("-disable-heuristic")) {
   469             ++i;
   470             ++i;
   470             if (i == argc) {
   471             if (i == argc) {
   471                 qWarning("The option -disable-heuristic requires a parameter.");
   472                 printOut(LU::tr("The option -disable-heuristic requires a parameter.\n"));
   472                 return 1;
   473                 return 1;
   473             }
   474             }
   474             arg = args[i];
   475             arg = args[i];
   475             if (arg == QLatin1String("sametext")) {
   476             if (arg == QLatin1String("sametext")) {
   476                 options &= ~HeuristicSameText;
   477                 options &= ~HeuristicSameText;
   477             } else if (arg == QLatin1String("similartext")) {
   478             } else if (arg == QLatin1String("similartext")) {
   478                 options &= ~HeuristicSimilarText;
   479                 options &= ~HeuristicSimilarText;
   479             } else if (arg == QLatin1String("number")) {
   480             } else if (arg == QLatin1String("number")) {
   480                 options &= ~HeuristicNumber;
   481                 options &= ~HeuristicNumber;
   481             } else {
   482             } else {
   482                 qWarning("Invalid heuristic name passed to -disable-heuristic.");
   483                 printOut(LU::tr("Invalid heuristic name passed to -disable-heuristic.\n"));
   483                 return 1;
   484                 return 1;
   484             }
   485             }
   485             continue;
   486             continue;
   486         } else if (arg == QLatin1String("-locations")) {
   487         } else if (arg == QLatin1String("-locations")) {
   487             ++i;
   488             ++i;
   488             if (i == argc) {
   489             if (i == argc) {
   489                 qWarning("The option -locations requires a parameter.");
   490                 printOut(LU::tr("The option -locations requires a parameter.\n"));
   490                 return 1;
   491                 return 1;
   491             }
   492             }
   492             if (args[i] == QLatin1String("none")) {
   493             if (args[i] == QLatin1String("none")) {
   493                 options |= NoLocations;
   494                 options |= NoLocations;
   494             } else if (args[i] == QLatin1String("relative")) {
   495             } else if (args[i] == QLatin1String("relative")) {
   495                 options |= RelativeLocations;
   496                 options |= RelativeLocations;
   496             } else if (args[i] == QLatin1String("absolute")) {
   497             } else if (args[i] == QLatin1String("absolute")) {
   497                 options |= AbsoluteLocations;
   498                 options |= AbsoluteLocations;
   498             } else {
   499             } else {
   499                 qWarning("Invalid parameter passed to -locations.");
   500                 printOut(LU::tr("Invalid parameter passed to -locations.\n"));
   500                 return 1;
   501                 return 1;
   501             }
   502             }
   502             continue;
   503             continue;
   503         } else if (arg == QLatin1String("-no-ui-lines")) {
   504         } else if (arg == QLatin1String("-no-ui-lines")) {
   504             options |= NoUiLines;
   505             options |= NoUiLines;
   520             printOut(QObject::tr("lupdate version %1\n").arg(QLatin1String(QT_VERSION_STR)));
   521             printOut(QObject::tr("lupdate version %1\n").arg(QLatin1String(QT_VERSION_STR)));
   521             return 0;
   522             return 0;
   522         } else if (arg == QLatin1String("-codecfortr")) {
   523         } else if (arg == QLatin1String("-codecfortr")) {
   523             ++i;
   524             ++i;
   524             if (i == argc) {
   525             if (i == argc) {
   525                 qWarning("The -codecfortr option should be followed by a codec name.");
   526                 printOut(LU::tr("The -codecfortr option should be followed by a codec name.\n"));
   526                 return 1;
   527                 return 1;
   527             }
   528             }
   528             codecForTr = args[i].toLatin1();
   529             codecForTr = args[i].toLatin1();
   529             continue;
   530             continue;
   530         } else if (arg == QLatin1String("-ts")) {
   531         } else if (arg == QLatin1String("-ts")) {
   531             metTsFlag = true;
   532             metTsFlag = true;
   532             continue;
   533             continue;
   533         } else if (arg == QLatin1String("-extensions")) {
   534         } else if (arg == QLatin1String("-extensions")) {
   534             ++i;
   535             ++i;
   535             if (i == argc) {
   536             if (i == argc) {
   536                 qWarning("The -extensions option should be followed by an extension list.");
   537                 printOut(LU::tr("The -extensions option should be followed by an extension list.\n"));
   537                 return 1;
   538                 return 1;
   538             }
   539             }
   539             extensions = args[i];
   540             extensions = args[i];
   540             continue;
   541             continue;
   541         } else if (arg == QLatin1String("-pro")) {
   542         } else if (arg == QLatin1String("-pro")) {
   542             ++i;
   543             ++i;
   543             if (i == argc) {
   544             if (i == argc) {
   544                 qWarning("The -pro option should be followed by a filename of .pro file.");
   545                 printOut(LU::tr("The -pro option should be followed by a filename of .pro file.\n"));
   545                 return 1;
   546                 return 1;
   546             }
   547             }
   547             proFiles += args[i];
   548             proFiles += args[i];
   548             numFiles++;
   549             numFiles++;
   549             continue;
   550             continue;
   550         } else if (arg.startsWith(QLatin1String("-I"))) {
   551         } else if (arg.startsWith(QLatin1String("-I"))) {
   551             if (arg.length() == 2) {
   552             if (arg.length() == 2) {
   552                 ++i;
   553                 ++i;
   553                 if (i == argc) {
   554                 if (i == argc) {
   554                     qWarning("The -I option should be followed by a path.");
   555                     printOut(LU::tr("The -I option should be followed by a path.\n"));
   555                     return 1;
   556                     return 1;
   556                 }
   557                 }
   557                 includePath += args[i];
   558                 includePath += args[i];
   558             } else {
   559             } else {
   559                 includePath += args[i].mid(2);
   560                 includePath += args[i].mid(2);
   560             }
   561             }
   561             continue;
   562             continue;
   562         } else if (arg.startsWith(QLatin1String("-")) && arg != QLatin1String("-")) {
   563         } else if (arg.startsWith(QLatin1String("-")) && arg != QLatin1String("-")) {
   563             qWarning("Unrecognized option '%s'", qPrintable(arg));
   564             printOut(LU::tr("Unrecognized option '%1'.\n").arg(arg));
   564             return 1;
   565             return 1;
   565         }
   566         }
   566 
   567 
   567         QStringList files;
   568         QStringList files;
   568         if (arg.startsWith(QLatin1String("@"))) {
   569         if (arg.startsWith(QLatin1String("@"))) {
   569             QFile lstFile(arg.mid(1));
   570             QFile lstFile(arg.mid(1));
   570             if (!lstFile.open(QIODevice::ReadOnly)) {
   571             if (!lstFile.open(QIODevice::ReadOnly)) {
   571                 qWarning("lupdate error: List file '%s' is not readable",
   572                 printOut(LU::tr("lupdate error: List file '%1' is not readable.\n")
   572                          qPrintable(lstFile.fileName()));
   573                          .arg(lstFile.fileName()));
   573                 return 1;
   574                 return 1;
   574             }
   575             }
   575             while (!lstFile.atEnd())
   576             while (!lstFile.atEnd())
   576                 files << QString::fromLocal8Bit(lstFile.readLine().trimmed());
   577                 files << QString::fromLocal8Bit(lstFile.readLine().trimmed());
   577         } else {
   578         } else {
   584                     if (file.endsWith(QLatin1Char('.') + fmt.extension, Qt::CaseInsensitive)) {
   585                     if (file.endsWith(QLatin1Char('.') + fmt.extension, Qt::CaseInsensitive)) {
   585                         QFileInfo fi(file);
   586                         QFileInfo fi(file);
   586                         if (!fi.exists() || fi.isWritable()) {
   587                         if (!fi.exists() || fi.isWritable()) {
   587                             tsFileNames.append(QFileInfo(file).absoluteFilePath());
   588                             tsFileNames.append(QFileInfo(file).absoluteFilePath());
   588                         } else {
   589                         } else {
   589                             qWarning("lupdate warning: For some reason, '%s' is not writable.\n",
   590                             printOut(LU::tr("lupdate warning: For some reason, '%1' is not writable.\n")
   590                                     qPrintable(file));
   591                                      .arg(file));
   591                         }
   592                         }
   592                         found = true;
   593                         found = true;
   593                         break;
   594                         break;
   594                     }
   595                     }
   595                 }
   596                 }
   596                 if (!found) {
   597                 if (!found) {
   597                     qWarning("lupdate error: File '%s' has no recognized extension\n",
   598                     printOut(LU::tr("lupdate error: File '%1' has no recognized extension.\n")
   598                              qPrintable(file));
   599                              .arg(file));
   599                     return 1;
   600                     return 1;
   600                 }
   601                 }
   601             }
   602             }
   602             numFiles++;
   603             numFiles++;
   603         } else {
   604         } else {
   604             foreach (const QString &file, files) {
   605             foreach (const QString &file, files) {
   605                 QFileInfo fi(file);
   606                 QFileInfo fi(file);
   606                 if (!fi.exists()) {
   607                 if (!fi.exists()) {
   607                     qWarning("lupdate error: File '%s' does not exists\n", qPrintable(file));
   608                     printOut(LU::tr("lupdate error: File '%1' does not exist.\n").arg(file));
   608                     return 1;
   609                     return 1;
   609                 }
   610                 }
   610                 if (file.endsWith(QLatin1String(".pro"), Qt::CaseInsensitive)
   611                 if (file.endsWith(QLatin1String(".pro"), Qt::CaseInsensitive)
   611                     || file.endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) {
   612                     || file.endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) {
   612                     proFiles << file;
   613                     proFiles << file;
   613                 } else if (fi.isDir()) {
   614                 } else if (fi.isDir()) {
   614                     if (options & Verbose)
   615                     if (options & Verbose)
   615                         printOut(QObject::tr("Scanning directory '%1'...").arg(file));
   616                         printOut(QObject::tr("Scanning directory '%1'...\n").arg(file));
   616                     QDir dir = QDir(fi.filePath());
   617                     QDir dir = QDir(fi.filePath());
   617                     projectRoots.insert(dir.absolutePath() + QLatin1Char('/'));
   618                     projectRoots.insert(dir.absolutePath() + QLatin1Char('/'));
   618                     if (extensionsNameFilters.isEmpty()) {
   619                     if (extensionsNameFilters.isEmpty()) {
   619                         foreach (QString ext, extensions.split(QLatin1Char(','))) {
   620                         foreach (QString ext, extensions.split(QLatin1Char(','))) {
   620                             ext = ext.trimmed();
   621                             ext = ext.trimmed();
   648                             } while (++depth < 3 && offset > scanRootLen);
   649                             } while (++depth < 3 && offset > scanRootLen);
   649                         }
   650                         }
   650                     }
   651                     }
   651                 } else {
   652                 } else {
   652                     sourceFiles << QDir::cleanPath(fi.absoluteFilePath());;
   653                     sourceFiles << QDir::cleanPath(fi.absoluteFilePath());;
       
   654                     projectRoots.insert(fi.absolutePath() + QLatin1Char('/'));
   653                 }
   655                 }
   654             }
   656             }
   655             numFiles++;
   657             numFiles++;
   656         }
   658         }
   657     } // for args
   659     } // for args
   660         printUsage();
   662         printUsage();
   661         return 1;
   663         return 1;
   662     }
   664     }
   663 
   665 
   664     if (!targetLanguage.isEmpty() && tsFileNames.count() != 1)
   666     if (!targetLanguage.isEmpty() && tsFileNames.count() != 1)
   665         std::cerr << "lupdate warning: -target-language usually only "
   667         printOut(LU::tr("lupdate warning: -target-language usually only"
   666                      "makes sense with exactly one TS file.\n";
   668                         " makes sense with exactly one TS file.\n"));
   667     if (!codecForTr.isEmpty() && tsFileNames.isEmpty())
   669     if (!codecForTr.isEmpty() && tsFileNames.isEmpty())
   668         std::cerr << "lupdate warning: -codecfortr has no effect without -ts.\n";
   670         printOut(LU::tr("lupdate warning: -codecfortr has no effect without -ts.\n"));
   669 
   671 
   670     bool fail = false;
   672     bool fail = false;
   671     if (proFiles.isEmpty()) {
   673     if (proFiles.isEmpty()) {
   672         if (tsFileNames.isEmpty())
   674         if (tsFileNames.isEmpty())
   673             std::cerr << "lupdate warning: no TS files specified. "
   675             printOut(LU::tr("lupdate warning:"
   674                          "Only diagnostics will be produced.\n";
   676                             " no TS files specified. Only diagnostics will be produced.\n"));
   675 
   677 
   676         Translator fetchedTor;
   678         Translator fetchedTor;
   677         ConversionData cd;
   679         ConversionData cd;
   678         cd.m_noUiLines = options & NoUiLines;
   680         cd.m_noUiLines = options & NoUiLines;
   679         cd.m_projectRoots = projectRoots;
   681         cd.m_projectRoots = projectRoots;
   683         processSources(fetchedTor, sourceFiles, cd);
   685         processSources(fetchedTor, sourceFiles, cd);
   684         updateTsFiles(fetchedTor, tsFileNames, !codecForTr.isEmpty(),
   686         updateTsFiles(fetchedTor, tsFileNames, !codecForTr.isEmpty(),
   685                       sourceLanguage, targetLanguage, options, &fail);
   687                       sourceLanguage, targetLanguage, options, &fail);
   686     } else {
   688     } else {
   687         if (!sourceFiles.isEmpty() || !includePath.isEmpty()) {
   689         if (!sourceFiles.isEmpty() || !includePath.isEmpty()) {
   688             qWarning("lupdate error: Both project and source files / include paths specified.\n");
   690             printOut(LU::tr("lupdate error:"
       
   691                             " Both project and source files / include paths specified.\n"));
   689             return 1;
   692             return 1;
   690         }
   693         }
   691         if (!tsFileNames.isEmpty()) {
   694         if (!tsFileNames.isEmpty()) {
   692             Translator fetchedTor;
   695             Translator fetchedTor;
   693             fetchedTor.setCodecName(codecForTr);
   696             fetchedTor.setCodecName(codecForTr);