source: trunk/tools/linguist/lrelease/main.cpp@ 1030

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

OS/2: Remove suport for system-wide qt.conf files.

This turns not to be necessary. The new code is much simpler and has
less platform-dependent details. Note that hard-coded component paths
are now relative to the parent of the directory containing QtCore4.dll, not
to that directory itself as before. This in particular makes qt.conf not necessary
for the development builds at all.

For official (RPM) release builds, full hard-coded paths will be used so qt.conf
is not necessary at all. It will only be in use in portable ZIP distributions to
override these hard-coded paths of RPM builds.

File size: 13.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
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 [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "translator.h"
43#include "profileevaluator.h"
44
45#ifndef QT_BOOTSTRAPPED
46#include <QtCore/QCoreApplication>
47#include <QtCore/QTranslator>
48#endif
49#include <QtCore/QDebug>
50#include <QtCore/QDir>
51#include <QtCore/QFile>
52#include <QtCore/QFileInfo>
53#include <QtCore/QRegExp>
54#include <QtCore/QString>
55#include <QtCore/QStringList>
56#include <QtCore/QTextStream>
57
58#include <iostream>
59
60QT_USE_NAMESPACE
61
62#ifdef QT_BOOTSTRAPPED
63static void initBinaryDir(
64#ifndef Q_OS_WIN
65 const char *argv0
66#endif
67 );
68
69struct LR {
70 static inline QString tr(const char *sourceText, const char *comment = 0)
71 {
72 return QCoreApplication::translate("LRelease", sourceText, comment);
73 }
74};
75#else
76class LR {
77 Q_DECLARE_TR_FUNCTIONS(LRelease)
78};
79#endif
80
81static void printOut(const QString & out)
82{
83 QTextStream stream(stdout);
84 stream << out;
85}
86
87static void printUsage()
88{
89 printOut(LR::tr(
90 "Usage:\n"
91 " lrelease [options] project-file\n"
92 " lrelease [options] ts-files [-qm qm-file]\n\n"
93 "lrelease is part of Qt's Linguist tool chain. It can be used as a\n"
94 "stand-alone tool to convert XML-based translations files in the TS\n"
95 "format into the 'compiled' QM format used by QTranslator objects.\n\n"
96 "Options:\n"
97 " -help Display this information and exit\n"
98 " -idbased\n"
99 " Use IDs instead of source strings for message keying\n"
100 " -compress\n"
101 " Compress the QM files\n"
102 " -nounfinished\n"
103 " Do not include unfinished translations\n"
104 " -removeidentical\n"
105 " If the translated text is the same as\n"
106 " the source text, do not include the message\n"
107 " -markuntranslated <prefix>\n"
108 " If a message has no real translation, use the source text\n"
109 " prefixed with the given string instead\n"
110 " -silent\n"
111 " Do not explain what is being done\n"
112 " -version\n"
113 " Display the version of lrelease and exit\n"
114 ));
115}
116
117static bool loadTsFile(Translator &tor, const QString &tsFileName, bool /* verbose */)
118{
119 ConversionData cd;
120 bool ok = tor.load(tsFileName, cd, QLatin1String("auto"));
121 if (!ok) {
122 std::cerr << qPrintable(LR::tr("lrelease error: %1").arg(cd.error()));
123 } else {
124 if (!cd.errors().isEmpty())
125 printOut(cd.error());
126 }
127 cd.clearErrors();
128 return ok;
129}
130
131static bool releaseTranslator(Translator &tor, const QString &qmFileName,
132 ConversionData &cd, bool removeIdentical)
133{
134 tor.reportDuplicates(tor.resolveDuplicates(), qmFileName, cd.isVerbose());
135
136 if (cd.isVerbose())
137 printOut(LR::tr("Updating '%1'...\n").arg(qmFileName));
138 if (removeIdentical) {
139 if (cd.isVerbose())
140 printOut(LR::tr("Removing translations equal to source text in '%1'...\n").arg(qmFileName));
141 tor.stripIdenticalSourceTranslations();
142 }
143
144 QFile file(qmFileName);
145 if (!file.open(QIODevice::WriteOnly)) {
146 std::cerr << qPrintable(LR::tr("lrelease error: cannot create '%1': %2\n")
147 .arg(qmFileName, file.errorString()));
148 return false;
149 }
150
151 tor.normalizeTranslations(cd);
152 bool ok = tor.release(&file, cd);
153 file.close();
154
155 if (!ok) {
156 std::cerr << qPrintable(LR::tr("lrelease error: cannot save '%1': %2")
157 .arg(qmFileName, cd.error()));
158 } else if (!cd.errors().isEmpty()) {
159 printOut(cd.error());
160 }
161 cd.clearErrors();
162 return ok;
163}
164
165static bool releaseTsFile(const QString& tsFileName,
166 ConversionData &cd, bool removeIdentical)
167{
168 Translator tor;
169 if (!loadTsFile(tor, tsFileName, cd.isVerbose()))
170 return false;
171
172 QString qmFileName = tsFileName;
173 foreach (const Translator::FileFormat &fmt, Translator::registeredFileFormats()) {
174 if (qmFileName.endsWith(QLatin1Char('.') + fmt.extension)) {
175 qmFileName.chop(fmt.extension.length() + 1);
176 break;
177 }
178 }
179 qmFileName += QLatin1String(".qm");
180
181 return releaseTranslator(tor, qmFileName, cd, removeIdentical);
182}
183
184int main(int argc, char **argv)
185{
186#ifdef QT_BOOTSTRAPPED
187 initBinaryDir(
188#ifndef Q_OS_WIN
189 argv[0]
190#endif
191 );
192#else
193 QCoreApplication app(argc, argv);
194#ifndef Q_OS_WIN32
195 QTranslator translator;
196 QTranslator qtTranslator;
197 QString sysLocale = QLocale::system().name();
198 QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
199 if (translator.load(QLatin1String("linguist_") + sysLocale, resourceDir)
200 && qtTranslator.load(QLatin1String("qt_") + sysLocale, resourceDir)) {
201 app.installTranslator(&translator);
202 app.installTranslator(&qtTranslator);
203 }
204#endif // Q_OS_WIN32
205#endif // QT_BOOTSTRAPPED
206
207 ConversionData cd;
208 cd.m_verbose = true; // the default is true starting with Qt 4.2
209 bool removeIdentical = false;
210 Translator tor;
211 QStringList inputFiles;
212 QString outputFile;
213
214 for (int i = 1; i < argc; ++i) {
215 if (!strcmp(argv[i], "-compress")) {
216 cd.m_saveMode = SaveStripped;
217 continue;
218 } else if (!strcmp(argv[i], "-idbased")) {
219 cd.m_idBased = true;
220 continue;
221 } else if (!strcmp(argv[i], "-nocompress")) {
222 cd.m_saveMode = SaveEverything;
223 continue;
224 } else if (!strcmp(argv[i], "-removeidentical")) {
225 removeIdentical = true;
226 continue;
227 } else if (!strcmp(argv[i], "-nounfinished")) {
228 cd.m_ignoreUnfinished = true;
229 continue;
230 } else if (!strcmp(argv[i], "-markuntranslated")) {
231 if (i == argc - 1) {
232 printUsage();
233 return 1;
234 }
235 cd.m_unTrPrefix = QString::fromLocal8Bit(argv[++i]);
236 } else if (!strcmp(argv[i], "-silent")) {
237 cd.m_verbose = false;
238 continue;
239 } else if (!strcmp(argv[i], "-verbose")) {
240 cd.m_verbose = true;
241 continue;
242 } else if (!strcmp(argv[i], "-version")) {
243 printOut(LR::tr("lrelease version %1\n").arg(QLatin1String(QT_VERSION_STR)));
244 return 0;
245 } else if (!strcmp(argv[i], "-qm")) {
246 if (i == argc - 1) {
247 printUsage();
248 return 1;
249 }
250 outputFile = QString::fromLocal8Bit(argv[++i]);
251 } else if (!strcmp(argv[i], "-help")) {
252 printUsage();
253 return 0;
254 } else if (argv[i][0] == '-') {
255 printUsage();
256 return 1;
257 } else {
258 inputFiles << QString::fromLocal8Bit(argv[i]);
259 }
260 }
261
262 if (inputFiles.isEmpty()) {
263 printUsage();
264 return 1;
265 }
266
267 foreach (const QString &inputFile, inputFiles) {
268 if (inputFile.endsWith(QLatin1String(".pro"), Qt::CaseInsensitive)
269 || inputFile.endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) {
270 QFileInfo fi(inputFile);
271 ProFile pro(fi.absoluteFilePath());
272
273 ProFileEvaluator visitor;
274 visitor.setVerbose(cd.isVerbose());
275
276 if (!visitor.queryProFile(&pro)) {
277 std::cerr << qPrintable(LR::tr(
278 "lrelease error: cannot read project file '%1'.\n")
279 .arg(inputFile));
280 continue;
281 }
282 if (!visitor.accept(&pro)) {
283 std::cerr << qPrintable(LR::tr(
284 "lrelease error: cannot process project file '%1'.\n")
285 .arg(inputFile));
286 continue;
287 }
288
289 QStringList translations = visitor.values(QLatin1String("TRANSLATIONS"));
290 if (translations.isEmpty()) {
291 std::cerr << qPrintable(LR::tr(
292 "lrelease warning: Met no 'TRANSLATIONS' entry in project file '%1'\n")
293 .arg(inputFile));
294 } else {
295 QDir proDir(fi.absolutePath());
296 foreach (const QString &trans, translations)
297 if (!releaseTsFile(QFileInfo(proDir, trans).filePath(), cd, removeIdentical))
298 return 1;
299 }
300 } else {
301 if (outputFile.isEmpty()) {
302 if (!releaseTsFile(inputFile, cd, removeIdentical))
303 return 1;
304 } else {
305 if (!loadTsFile(tor, inputFile, cd.isVerbose()))
306 return 1;
307 }
308 }
309 }
310
311 if (!outputFile.isEmpty())
312 return releaseTranslator(tor, outputFile, cd, removeIdentical) ? 0 : 1;
313
314 return 0;
315}
316
317#ifdef QT_BOOTSTRAPPED
318
319#ifdef Q_OS_WIN
320# include <windows.h>
321#endif
322
323static QString binDir;
324
325static void initBinaryDir(
326#ifndef Q_OS_WIN
327 const char *_argv0
328#endif
329 )
330{
331 // this is in sync with qmake_libraryInfoFile() from qmake/option.cpp
332#ifdef Q_OS_WIN
333 wchar_t module_name[MAX_PATH];
334 GetModuleFileName(0, module_name, MAX_PATH);
335 QFileInfo filePath = QString::fromWCharArray(module_name);
336 binDir = filePath.filePath();
337#elif defined(Q_OS_OS2)
338 QFileInfo filePath;
339 static char appFileName[CCHMAXPATH] = "\0";
340 if (!appFileName[0]) {
341 PPIB ppib;
342 DosGetInfoBlocks(NULL, &ppib);
343 DosQueryModuleName(ppib->pib_hmte, sizeof(appFileName), appFileName);
344 }
345 binDir = QFileInfo(QString::fromLocal8Bit(appFileName)).filePath();
346#else
347 QString argv0 = QFile::decodeName(QByteArray(_argv0));
348 QString absPath;
349
350 if (!argv0.isEmpty() && argv0.at(0) == QLatin1Char('/')) {
351 /*
352 If argv0 starts with a slash, it is already an absolute
353 file path.
354 */
355 absPath = argv0;
356 } else if (argv0.contains(QLatin1Char('/'))) {
357 /*
358 If argv0 contains one or more slashes, it is a file path
359 relative to the current directory.
360 */
361 absPath = QDir::current().absoluteFilePath(argv0);
362 } else {
363 /*
364 Otherwise, the file path has to be determined using the
365 PATH environment variable.
366 */
367 QByteArray pEnv = qgetenv("PATH");
368 QDir currentDir = QDir::current();
369 QStringList paths = QString::fromLocal8Bit(pEnv.constData()).split(QLatin1String(":"));
370 for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
371 if ((*p).isEmpty())
372 continue;
373 QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0);
374 QFileInfo candidate_fi(candidate);
375 if (candidate_fi.exists() && !candidate_fi.isDir()) {
376 binDir = candidate_fi.canonicalPath();
377 return;
378 }
379 }
380 return;
381 }
382
383 QFileInfo fi(absPath);
384 if (fi.exists())
385 binDir = fi.canonicalPath();
386#endif
387}
388
389QT_BEGIN_NAMESPACE
390
391// The name is hard-coded in QLibraryInfo
392QString qmake_libraryInfoFile()
393{
394 if (binDir.isEmpty())
395 return QString();
396 return QDir(binDir).filePath(QString::fromLatin1("qt.conf"));
397}
398
399QT_END_NAMESPACE
400
401#endif // QT_BOOTSTRAPPED
Note: See TracBrowser for help on using the repository browser.