|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 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 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
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 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "translator.h" |
|
43 #include "proreader.h" |
|
44 |
|
45 #include <QtCore/QCoreApplication> |
|
46 #include <QtCore/QDebug> |
|
47 #include <QtCore/QDir> |
|
48 #include <QtCore/QFile> |
|
49 #include <QtCore/QFileInfo> |
|
50 #include <QtCore/QRegExp> |
|
51 #include <QtCore/QString> |
|
52 #include <QtCore/QStringList> |
|
53 #include <QtCore/QTextStream> |
|
54 #include <QtCore/QTranslator> |
|
55 |
|
56 static void printOut(const QString & out) |
|
57 { |
|
58 QTextStream stream(stdout); |
|
59 stream << out; |
|
60 } |
|
61 |
|
62 static void printUsage() |
|
63 { |
|
64 printOut(QCoreApplication::tr( |
|
65 "Usage:\n" |
|
66 " lrelease [options] project-file\n" |
|
67 " lrelease [options] ts-files [-qm qm-file]\n\n" |
|
68 "lrelease is part of Qt's Linguist tool chain. It can be used as a\n" |
|
69 "stand-alone tool to convert XML-based translations files in the TS\n" |
|
70 "format into the 'compiled' QM format used by QTranslator objects.\n\n" |
|
71 "Options:\n" |
|
72 " -help Display this information and exit\n" |
|
73 " -idbased\n" |
|
74 " Use IDs instead of source strings for message keying\n" |
|
75 " -compress\n" |
|
76 " Compress the QM files\n" |
|
77 " -nounfinished\n" |
|
78 " Do not include unfinished translations\n" |
|
79 " -removeidentical\n" |
|
80 " If the translated text is the same as\n" |
|
81 " the source text, do not include the message\n" |
|
82 " -silent\n" |
|
83 " Do not explain what is being done\n" |
|
84 " -version\n" |
|
85 " Display the version of lrelease and exit\n" |
|
86 )); |
|
87 } |
|
88 |
|
89 static bool loadTsFile(Translator &tor, const QString &tsFileName, bool /* verbose */) |
|
90 { |
|
91 ConversionData cd; |
|
92 bool ok = tor.load(tsFileName, cd, QLatin1String("auto")); |
|
93 if (!ok) { |
|
94 qWarning("lrelease error: %s\n", qPrintable(cd.error())); |
|
95 } else { |
|
96 if (!cd.errors().isEmpty()) |
|
97 printOut(cd.error()); |
|
98 } |
|
99 return ok; |
|
100 } |
|
101 |
|
102 static bool releaseTranslator(Translator &tor, const QString &qmFileName, |
|
103 bool verbose, bool ignoreUnfinished, |
|
104 bool removeIdentical, bool idBased, TranslatorSaveMode mode) |
|
105 { |
|
106 Translator::reportDuplicates(tor.resolveDuplicates(), qmFileName, verbose); |
|
107 |
|
108 if (verbose) |
|
109 printOut(QCoreApplication::tr( "Updating '%1'...\n").arg(qmFileName)); |
|
110 if (removeIdentical) { |
|
111 if ( verbose ) |
|
112 printOut(QCoreApplication::tr( "Removing translations equal to source text in '%1'...\n").arg(qmFileName)); |
|
113 tor.stripIdenticalSourceTranslations(); |
|
114 } |
|
115 |
|
116 QFile file(qmFileName); |
|
117 if (!file.open(QIODevice::WriteOnly)) { |
|
118 qWarning("lrelease error: cannot create '%s': %s\n", |
|
119 qPrintable(qmFileName), qPrintable(file.errorString())); |
|
120 return false; |
|
121 } |
|
122 |
|
123 ConversionData cd; |
|
124 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); |
|
130 file.close(); |
|
131 |
|
132 if (!ok) { |
|
133 qWarning("lrelease error: cannot save '%s': %s\n", |
|
134 qPrintable(qmFileName), qPrintable(cd.error())); |
|
135 return false; |
|
136 } else if (!cd.errors().isEmpty()) { |
|
137 printOut(cd.error()); |
|
138 } |
|
139 return true; |
|
140 } |
|
141 |
|
142 static bool releaseTsFile(const QString& tsFileName, bool verbose, |
|
143 bool ignoreUnfinished, bool removeIdentical, bool idBased, TranslatorSaveMode mode) |
|
144 { |
|
145 Translator tor; |
|
146 if (!loadTsFile(tor, tsFileName, verbose)) |
|
147 return false; |
|
148 |
|
149 QString qmFileName = tsFileName; |
|
150 foreach (const Translator::FileFormat &fmt, Translator::registeredFileFormats()) { |
|
151 if (qmFileName.endsWith(QLatin1Char('.') + fmt.extension)) { |
|
152 qmFileName.chop(fmt.extension.length() + 1); |
|
153 break; |
|
154 } |
|
155 } |
|
156 qmFileName += QLatin1String(".qm"); |
|
157 |
|
158 return releaseTranslator(tor, qmFileName, verbose, ignoreUnfinished, removeIdentical, idBased, mode); |
|
159 } |
|
160 |
|
161 int main(int argc, char **argv) |
|
162 { |
|
163 QCoreApplication app(argc, argv); |
|
164 QStringList args = app.arguments(); |
|
165 QTranslator translator; |
|
166 if (translator.load(QLatin1String("lrelease_") + QLocale::system().name())) |
|
167 app.installTranslator(&translator); |
|
168 |
|
169 bool verbose = true; // the default is true starting with Qt 4.2 |
|
170 bool ignoreUnfinished = false; |
|
171 bool idBased = false; |
|
172 // the default mode is SaveEverything starting with Qt 4.2 |
|
173 TranslatorSaveMode mode = SaveEverything; |
|
174 bool removeIdentical = false; |
|
175 Translator tor; |
|
176 QString outputFile; |
|
177 int numFiles = 0; |
|
178 |
|
179 for (int i = 1; i < argc; ++i) { |
|
180 if (args[i] == QLatin1String("-compress")) { |
|
181 mode = SaveStripped; |
|
182 continue; |
|
183 } else if (args[i] == QLatin1String("-idbased")) { |
|
184 idBased = true; |
|
185 continue; |
|
186 } else if (args[i] == QLatin1String("-nocompress")) { |
|
187 mode = SaveEverything; |
|
188 continue; |
|
189 } else if (args[i] == QLatin1String("-removeidentical")) { |
|
190 removeIdentical = true; |
|
191 continue; |
|
192 } else if (args[i] == QLatin1String("-nounfinished")) { |
|
193 ignoreUnfinished = true; |
|
194 continue; |
|
195 } else if (args[i] == QLatin1String("-silent")) { |
|
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) { |
|
206 printUsage(); |
|
207 return 1; |
|
208 } |
|
209 i++; |
|
210 outputFile = args[i]; |
|
211 } else if (args[i] == QLatin1String("-help")) { |
|
212 printUsage(); |
|
213 return 0; |
|
214 } else if (args[i][0] == QLatin1Char('-')) { |
|
215 printUsage(); |
|
216 return 1; |
|
217 } else { |
|
218 numFiles++; |
|
219 } |
|
220 } |
|
221 |
|
222 if (numFiles == 0) { |
|
223 printUsage(); |
|
224 return 1; |
|
225 } |
|
226 |
|
227 for (int i = 1; i < argc; ++i) { |
|
228 if (args[i][0] == QLatin1Char('-') || args[i] == outputFile) |
|
229 continue; |
|
230 |
|
231 if (args[i].endsWith(QLatin1String(".pro"), Qt::CaseInsensitive) |
|
232 || args[i].endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) { |
|
233 QHash<QByteArray, QStringList> varMap; |
|
234 bool ok = evaluateProFile(args[i], verbose, &varMap ); |
|
235 if (ok) { |
|
236 QStringList translations = varMap.value("TRANSLATIONS"); |
|
237 if (translations.isEmpty()) { |
|
238 qWarning("lrelease warning: Met no 'TRANSLATIONS' entry in" |
|
239 " project file '%s'\n", |
|
240 qPrintable(args[i])); |
|
241 } else { |
|
242 foreach (const QString &trans, translations) |
|
243 if (!releaseTsFile(trans, verbose, ignoreUnfinished, removeIdentical, idBased, mode)) |
|
244 return 1; |
|
245 } |
|
246 } else { |
|
247 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" |
|
249 "Try the following syntax:\n" |
|
250 " lrelease [options] ts-files [-qm qm-file]\n"); |
|
251 } |
|
252 } else { |
|
253 if (outputFile.isEmpty()) { |
|
254 if (!releaseTsFile(args[i], verbose, ignoreUnfinished, removeIdentical, idBased, mode)) |
|
255 return 1; |
|
256 } else { |
|
257 if (!loadTsFile(tor, args[i], verbose)) |
|
258 return 1; |
|
259 } |
|
260 } |
|
261 } |
|
262 |
|
263 if (!outputFile.isEmpty()) |
|
264 return releaseTranslator(tor, outputFile, verbose, ignoreUnfinished, |
|
265 removeIdentical, idBased, mode) ? 0 : 1; |
|
266 |
|
267 return 0; |
|
268 } |