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(); |
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); |