tools/linguist/lrelease/main.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
2:56cd8111b7f7 3:41300fa6a67c
    40 ****************************************************************************/
    40 ****************************************************************************/
    41 
    41 
    42 #include "translator.h"
    42 #include "translator.h"
    43 #include "proreader.h"
    43 #include "proreader.h"
    44 
    44 
       
    45 #ifndef QT_BOOTSTRAPPED
    45 #include <QtCore/QCoreApplication>
    46 #include <QtCore/QCoreApplication>
       
    47 #include <QtCore/QTranslator>
       
    48 #endif
    46 #include <QtCore/QDebug>
    49 #include <QtCore/QDebug>
    47 #include <QtCore/QDir>
    50 #include <QtCore/QDir>
    48 #include <QtCore/QFile>
    51 #include <QtCore/QFile>
    49 #include <QtCore/QFileInfo>
    52 #include <QtCore/QFileInfo>
    50 #include <QtCore/QRegExp>
    53 #include <QtCore/QRegExp>
    51 #include <QtCore/QString>
    54 #include <QtCore/QString>
    52 #include <QtCore/QStringList>
    55 #include <QtCore/QStringList>
    53 #include <QtCore/QTextStream>
    56 #include <QtCore/QTextStream>
    54 #include <QtCore/QTranslator>
    57 
       
    58 QT_USE_NAMESPACE
       
    59 
       
    60 #ifdef QT_BOOTSTRAPPED
       
    61 static void initBinaryDir(
       
    62 #ifndef Q_OS_WIN
       
    63         const char *argv0
       
    64 #endif
       
    65         );
       
    66 #endif
    55 
    67 
    56 static void printOut(const QString & out)
    68 static void printOut(const QString & out)
    57 {
    69 {
    58     QTextStream stream(stdout);
    70     QTextStream stream(stdout);
    59     stream << out;
    71     stream << out;
    77         "    -nounfinished\n"
    89         "    -nounfinished\n"
    78         "           Do not include unfinished translations\n"
    90         "           Do not include unfinished translations\n"
    79         "    -removeidentical\n"
    91         "    -removeidentical\n"
    80         "           If the translated text is the same as\n"
    92         "           If the translated text is the same as\n"
    81         "           the source text, do not include the message\n"
    93         "           the source text, do not include the message\n"
       
    94         "    -markuntranslated <prefix>\n"
       
    95         "           If a message has no real translation, use the source text\n"
       
    96         "           prefixed with the given string instead\n"
    82         "    -silent\n"
    97         "    -silent\n"
    83         "           Do not explain what is being done\n"
    98         "           Do not explain what is being done\n"
    84         "    -version\n"
    99         "    -version\n"
    85         "           Display the version of lrelease and exit\n"
   100         "           Display the version of lrelease and exit\n"
    86     ));
   101     ));
    98     }
   113     }
    99     return ok;
   114     return ok;
   100 }
   115 }
   101 
   116 
   102 static bool releaseTranslator(Translator &tor, const QString &qmFileName,
   117 static bool releaseTranslator(Translator &tor, const QString &qmFileName,
   103     bool verbose, bool ignoreUnfinished,
   118     ConversionData &cd, bool removeIdentical)
   104     bool removeIdentical, bool idBased, TranslatorSaveMode mode)
   119 {
   105 {
   120     tor.reportDuplicates(tor.resolveDuplicates(), qmFileName, cd.isVerbose());
   106     Translator::reportDuplicates(tor.resolveDuplicates(), qmFileName, verbose);
   121 
   107 
   122     if (cd.isVerbose())
   108     if (verbose)
       
   109         printOut(QCoreApplication::tr( "Updating '%1'...\n").arg(qmFileName));
   123         printOut(QCoreApplication::tr( "Updating '%1'...\n").arg(qmFileName));
   110     if (removeIdentical) {
   124     if (removeIdentical) {
   111         if ( verbose )
   125         if (cd.isVerbose())
   112             printOut(QCoreApplication::tr( "Removing translations equal to source text in '%1'...\n").arg(qmFileName));
   126             printOut(QCoreApplication::tr( "Removing translations equal to source text in '%1'...\n").arg(qmFileName));
   113         tor.stripIdenticalSourceTranslations();
   127         tor.stripIdenticalSourceTranslations();
   114     }
   128     }
   115 
   129 
   116     QFile file(qmFileName);
   130     QFile file(qmFileName);
   118         qWarning("lrelease error: cannot create '%s': %s\n",
   132         qWarning("lrelease error: cannot create '%s': %s\n",
   119                  qPrintable(qmFileName), qPrintable(file.errorString()));
   133                  qPrintable(qmFileName), qPrintable(file.errorString()));
   120         return false;
   134         return false;
   121     }
   135     }
   122 
   136 
   123     ConversionData cd;
       
   124     tor.normalizeTranslations(cd);
   137     tor.normalizeTranslations(cd);
   125     cd.m_verbose = verbose;
       
   126     cd.m_ignoreUnfinished = ignoreUnfinished;
       
   127     cd.m_idBased = idBased;
       
   128     cd.m_saveMode = mode;
       
   129     bool ok = tor.release(&file, cd);
   138     bool ok = tor.release(&file, cd);
   130     file.close();
   139     file.close();
   131 
   140 
   132     if (!ok) {
   141     if (!ok) {
   133         qWarning("lrelease error: cannot save '%s': %s\n",
   142         qWarning("lrelease error: cannot save '%s': %s\n",
   137         printOut(cd.error());
   146         printOut(cd.error());
   138     }
   147     }
   139     return true;
   148     return true;
   140 }
   149 }
   141 
   150 
   142 static bool releaseTsFile(const QString& tsFileName, bool verbose,
   151 static bool releaseTsFile(const QString& tsFileName,
   143     bool ignoreUnfinished, bool removeIdentical, bool idBased, TranslatorSaveMode mode)
   152     ConversionData &cd, bool removeIdentical)
   144 {
   153 {
   145     Translator tor;
   154     Translator tor;
   146     if (!loadTsFile(tor, tsFileName, verbose))
   155     if (!loadTsFile(tor, tsFileName, cd.isVerbose()))
   147         return false;
   156         return false;
   148 
   157 
   149     QString qmFileName = tsFileName;
   158     QString qmFileName = tsFileName;
   150     foreach (const Translator::FileFormat &fmt, Translator::registeredFileFormats()) {
   159     foreach (const Translator::FileFormat &fmt, Translator::registeredFileFormats()) {
   151         if (qmFileName.endsWith(QLatin1Char('.') + fmt.extension)) {
   160         if (qmFileName.endsWith(QLatin1Char('.') + fmt.extension)) {
   153             break;
   162             break;
   154         }
   163         }
   155     }
   164     }
   156     qmFileName += QLatin1String(".qm");
   165     qmFileName += QLatin1String(".qm");
   157 
   166 
   158     return releaseTranslator(tor, qmFileName, verbose, ignoreUnfinished, removeIdentical, idBased, mode);
   167     return releaseTranslator(tor, qmFileName, cd, removeIdentical);
   159 }
   168 }
   160 
   169 
   161 int main(int argc, char **argv)
   170 int main(int argc, char **argv)
   162 {
   171 {
       
   172 #ifdef QT_BOOTSTRAPPED
       
   173     initBinaryDir(
       
   174 #ifndef Q_OS_WIN
       
   175             argv[0]
       
   176 #endif
       
   177             );
       
   178 #else
   163     QCoreApplication app(argc, argv);
   179     QCoreApplication app(argc, argv);
   164     QStringList args = app.arguments();
       
   165     QTranslator translator;
   180     QTranslator translator;
   166     if (translator.load(QLatin1String("lrelease_") + QLocale::system().name()))
   181     if (translator.load(QLatin1String("lrelease_") + QLocale::system().name()))
   167         app.installTranslator(&translator);
   182         app.installTranslator(&translator);
   168 
   183 #endif
   169     bool verbose = true; // the default is true starting with Qt 4.2
   184 
   170     bool ignoreUnfinished = false;
   185     ConversionData cd;
   171     bool idBased = false;
   186     cd.m_verbose = true; // the default is true starting with Qt 4.2
   172     // the default mode is SaveEverything starting with Qt 4.2
       
   173     TranslatorSaveMode mode = SaveEverything;
       
   174     bool removeIdentical = false;
   187     bool removeIdentical = false;
   175     Translator tor;
   188     Translator tor;
       
   189     QStringList inputFiles;
   176     QString outputFile;
   190     QString outputFile;
   177     int numFiles = 0;
       
   178 
   191 
   179     for (int i = 1; i < argc; ++i) {
   192     for (int i = 1; i < argc; ++i) {
   180         if (args[i] == QLatin1String("-compress")) {
   193         if (!strcmp(argv[i], "-compress")) {
   181             mode = SaveStripped;
   194             cd.m_saveMode = SaveStripped;
   182             continue;
   195             continue;
   183         } else if (args[i] == QLatin1String("-idbased")) {
   196         } else if (!strcmp(argv[i], "-idbased")) {
   184             idBased = true;
   197             cd.m_idBased = true;
   185             continue;
   198             continue;
   186         } else if (args[i] == QLatin1String("-nocompress")) {
   199         } else if (!strcmp(argv[i], "-nocompress")) {
   187             mode = SaveEverything;
   200             cd.m_saveMode = SaveEverything;
   188             continue;
   201             continue;
   189         } else if (args[i] == QLatin1String("-removeidentical")) {
   202         } else if (!strcmp(argv[i], "-removeidentical")) {
   190             removeIdentical = true;
   203             removeIdentical = true;
   191             continue;
   204             continue;
   192         } else if (args[i] == QLatin1String("-nounfinished")) {
   205         } else if (!strcmp(argv[i], "-nounfinished")) {
   193             ignoreUnfinished = true;
   206             cd.m_ignoreUnfinished = true;
   194             continue;
   207             continue;
   195         } else if (args[i] == QLatin1String("-silent")) {
   208         } else if (!strcmp(argv[i], "-markuntranslated")) {
   196             verbose = false;
       
   197             continue;
       
   198         } else if (args[i] == QLatin1String("-verbose")) {
       
   199             verbose = true;
       
   200             continue;
       
   201         } else if (args[i] == QLatin1String("-version")) {
       
   202             printOut(QCoreApplication::tr( "lrelease version %1\n").arg(QLatin1String(QT_VERSION_STR)) );
       
   203             return 0;
       
   204         } else if (args[i] == QLatin1String("-qm")) {
       
   205             if (i == argc - 1) {
   209             if (i == argc - 1) {
   206                 printUsage();
   210                 printUsage();
   207                 return 1;
   211                 return 1;
   208             }
   212             }
   209             i++;
   213             cd.m_unTrPrefix = QString::fromLocal8Bit(argv[++i]);
   210             outputFile = args[i];
   214         } else if (!strcmp(argv[i], "-silent")) {
   211         } else if (args[i] == QLatin1String("-help")) {
   215             cd.m_verbose = false;
       
   216             continue;
       
   217         } else if (!strcmp(argv[i], "-verbose")) {
       
   218             cd.m_verbose = true;
       
   219             continue;
       
   220         } else if (!strcmp(argv[i], "-version")) {
       
   221             printOut(QCoreApplication::tr( "lrelease version %1\n").arg(QLatin1String(QT_VERSION_STR)) );
       
   222             return 0;
       
   223         } else if (!strcmp(argv[i], "-qm")) {
       
   224             if (i == argc - 1) {
       
   225                 printUsage();
       
   226                 return 1;
       
   227             }
       
   228             outputFile = QString::fromLocal8Bit(argv[++i]);
       
   229         } else if (!strcmp(argv[i], "-help")) {
   212             printUsage();
   230             printUsage();
   213             return 0;
   231             return 0;
   214         } else if (args[i][0] == QLatin1Char('-')) {
   232         } else if (argv[i][0] == '-') {
   215             printUsage();
   233             printUsage();
   216             return 1;
   234             return 1;
   217         } else {
   235         } else {
   218             numFiles++;
   236             inputFiles << QString::fromLocal8Bit(argv[i]);
   219         }
   237         }
   220     }
   238     }
   221 
   239 
   222     if (numFiles == 0) {
   240     if (inputFiles.isEmpty()) {
   223         printUsage();
   241         printUsage();
   224         return 1;
   242         return 1;
   225     }
   243     }
   226 
   244 
   227     for (int i = 1; i < argc; ++i) {
   245     foreach (const QString &inputFile, inputFiles) {
   228         if (args[i][0] == QLatin1Char('-') || args[i] == outputFile)
   246         if (inputFile.endsWith(QLatin1String(".pro"), Qt::CaseInsensitive)
   229             continue;
   247             || inputFile.endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) {
   230 
       
   231         if (args[i].endsWith(QLatin1String(".pro"), Qt::CaseInsensitive)
       
   232             || args[i].endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) {
       
   233             QHash<QByteArray, QStringList> varMap;
   248             QHash<QByteArray, QStringList> varMap;
   234             bool ok = evaluateProFile(args[i], verbose, &varMap );
   249             bool ok = evaluateProFile(inputFile, cd.isVerbose(), &varMap);
   235             if (ok) {
   250             if (ok) {
   236                 QStringList translations = varMap.value("TRANSLATIONS");
   251                 QStringList translations = varMap.value("TRANSLATIONS");
   237                 if (translations.isEmpty()) {
   252                 if (translations.isEmpty()) {
   238                     qWarning("lrelease warning: Met no 'TRANSLATIONS' entry in"
   253                     qWarning("lrelease warning: Met no 'TRANSLATIONS' entry in"
   239                              " project file '%s'\n",
   254                              " project file '%s'\n",
   240                              qPrintable(args[i]));
   255                              qPrintable(inputFile));
   241                 } else {
   256                 } else {
   242                     foreach (const QString &trans, translations)
   257                     foreach (const QString &trans, translations)
   243                         if (!releaseTsFile(trans, verbose, ignoreUnfinished, removeIdentical, idBased, mode))
   258                         if (!releaseTsFile(trans, cd, removeIdentical))
   244                             return 1;
   259                             return 1;
   245                 }
   260                 }
   246             } else {
   261             } else {
   247                 qWarning("error: lrelease encountered project file functionality that is currently not supported.\n"
   262                 qWarning("error: lrelease encountered project file functionality that is currently not supported.\n"
   248                     "You might want to consider using TS files as input instead of a project file.\n"
   263                     "You might want to consider using TS files as input instead of a project file.\n"
   249                     "Try the following syntax:\n"
   264                     "Try the following syntax:\n"
   250                     "    lrelease [options] ts-files [-qm qm-file]\n");
   265                     "    lrelease [options] ts-files [-qm qm-file]\n");
   251             }
   266             }
   252         } else {
   267         } else {
   253             if (outputFile.isEmpty()) {
   268             if (outputFile.isEmpty()) {
   254                 if (!releaseTsFile(args[i], verbose, ignoreUnfinished, removeIdentical, idBased, mode))
   269                 if (!releaseTsFile(inputFile, cd, removeIdentical))
   255                     return 1;
   270                     return 1;
   256             } else {
   271             } else {
   257                 if (!loadTsFile(tor, args[i], verbose))
   272                 if (!loadTsFile(tor, inputFile, cd.isVerbose()))
   258                     return 1;
   273                     return 1;
   259             }
   274             }
   260         }
   275         }
   261     }
   276     }
   262 
   277 
   263     if (!outputFile.isEmpty())
   278     if (!outputFile.isEmpty())
   264         return releaseTranslator(tor, outputFile, verbose, ignoreUnfinished,
   279         return releaseTranslator(tor, outputFile, cd, removeIdentical) ? 0 : 1;
   265                                  removeIdentical, idBased, mode) ? 0 : 1;
       
   266 
   280 
   267     return 0;
   281     return 0;
   268 }
   282 }
       
   283 
       
   284 #ifdef QT_BOOTSTRAPPED
       
   285 
       
   286 #ifdef Q_OS_WIN
       
   287 # include <windows.h>
       
   288 #endif
       
   289 
       
   290 static QString binDir;
       
   291 
       
   292 static void initBinaryDir(
       
   293 #ifndef Q_OS_WIN
       
   294         const char *_argv0
       
   295 #endif
       
   296         )
       
   297 {
       
   298 #ifdef Q_OS_WIN
       
   299     wchar_t module_name[MAX_PATH];
       
   300     GetModuleFileName(0, module_name, MAX_PATH);
       
   301     QFileInfo filePath = QString::fromWCharArray(module_name);
       
   302     binDir = filePath.filePath();
       
   303 #else
       
   304     QString argv0 = QFile::decodeName(QByteArray(_argv0));
       
   305     QString absPath;
       
   306 
       
   307     if (!argv0.isEmpty() && argv0.at(0) == QLatin1Char('/')) {
       
   308         /*
       
   309           If argv0 starts with a slash, it is already an absolute
       
   310           file path.
       
   311         */
       
   312         absPath = argv0;
       
   313     } else if (argv0.contains(QLatin1Char('/'))) {
       
   314         /*
       
   315           If argv0 contains one or more slashes, it is a file path
       
   316           relative to the current directory.
       
   317         */
       
   318         absPath = QDir::current().absoluteFilePath(argv0);
       
   319     } else {
       
   320         /*
       
   321           Otherwise, the file path has to be determined using the
       
   322           PATH environment variable.
       
   323         */
       
   324         QByteArray pEnv = qgetenv("PATH");
       
   325         QDir currentDir = QDir::current();
       
   326         QStringList paths = QString::fromLocal8Bit(pEnv.constData()).split(QLatin1String(":"));
       
   327         for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
       
   328             if ((*p).isEmpty())
       
   329                 continue;
       
   330             QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0);
       
   331             QFileInfo candidate_fi(candidate);
       
   332             if (candidate_fi.exists() && !candidate_fi.isDir()) {
       
   333                 binDir = candidate_fi.canonicalPath();
       
   334                 return;
       
   335             }
       
   336         }
       
   337         return;
       
   338     }
       
   339 
       
   340     QFileInfo fi(absPath);
       
   341     if (fi.exists())
       
   342         binDir = fi.canonicalPath();
       
   343 #endif
       
   344 }
       
   345 
       
   346 QT_BEGIN_NAMESPACE
       
   347 
       
   348 // The name is hard-coded in QLibraryInfo
       
   349 QString qmake_libraryInfoFile()
       
   350 {
       
   351     if (binDir.isEmpty())
       
   352         return QString();
       
   353     return QDir(binDir).filePath(QString::fromLatin1("qt.conf"));
       
   354 }
       
   355 
       
   356 QT_END_NAMESPACE
       
   357 
       
   358 #endif // QT_BOOTSTRAPPED