Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : */
9 :
10 : #include <iostream>
11 : #include <map>
12 : #include <list>
13 : #include <vector>
14 : #include <rtl/string.hxx>
15 : #include <rtl/ustring.hxx>
16 : #include <osl/file.hxx>
17 : #include "po.hxx"
18 :
19 : // Translated style names must be unique
20 0 : static void checkStyleNames(const OString& aLanguage)
21 : {
22 0 : std::map<OString,sal_uInt16> aLocalizedStyleNames;
23 0 : std::map<OString,sal_uInt16> aLocalizedNumStyleNames;
24 0 : std::list<PoEntry> repeatedEntries;
25 :
26 0 : OString aPoPath = OString(getenv("SRC_ROOT")) +
27 0 : "/translations/source/" +
28 0 : aLanguage + "/sw/source/ui/utlui.po";
29 0 : PoIfstream aPoInput;
30 0 : aPoInput.open(aPoPath);
31 0 : if( !aPoInput.isOpen() )
32 0 : std::cerr << "Warning: Cannot open " << aPoPath << std::endl;
33 :
34 : for(;;)
35 : {
36 0 : PoEntry aPoEntry;
37 0 : aPoInput.readEntry(aPoEntry);
38 0 : bool bRepeated = false;
39 0 : if( aPoInput.eof() )
40 : {
41 0 : break;
42 : }
43 :
44 0 : if( !aPoEntry.isFuzzy() && aPoEntry.getSourceFile() == "poolfmt.src" &&
45 0 : aPoEntry.getGroupId().startsWith("STR_POOLCOLL") )
46 : {
47 0 : OString aMsgStr = aPoEntry.getMsgStr();
48 0 : if( aMsgStr.isEmpty() )
49 0 : continue;
50 0 : if( aLocalizedStyleNames.find(aMsgStr) == aLocalizedStyleNames.end() )
51 0 : aLocalizedStyleNames[aMsgStr] = 1;
52 : else {
53 0 : aLocalizedStyleNames[aMsgStr]++;
54 0 : bRepeated = true;
55 0 : }
56 : }
57 0 : if( !aPoEntry.isFuzzy() && aPoEntry.getSourceFile() == "poolfmt.src" &&
58 0 : aPoEntry.getGroupId().startsWith("STR_POOLNUMRULE") )
59 : {
60 0 : OString aMsgStr = aPoEntry.getMsgStr();
61 0 : if( aMsgStr.isEmpty() )
62 0 : continue;
63 0 : if( aLocalizedNumStyleNames.find(aMsgStr) == aLocalizedNumStyleNames.end() )
64 0 : aLocalizedNumStyleNames[aMsgStr] = 1;
65 : else {
66 0 : aLocalizedNumStyleNames[aMsgStr]++;
67 0 : bRepeated = true;
68 0 : }
69 : }
70 0 : if (bRepeated)
71 0 : repeatedEntries.push_back(aPoEntry);
72 0 : }
73 0 : aPoInput.close();
74 :
75 0 : for( std::map<OString,sal_uInt16>::iterator it=aLocalizedStyleNames.begin(); it!=aLocalizedStyleNames.end(); ++it)
76 : {
77 0 : if( it->second > 1 )
78 : {
79 0 : std::cout << "ERROR: Style name translations must be unique in:\n" <<
80 0 : aPoPath << "\nLanguage: " << aLanguage << "\nDuplicated translation is: " << it->first <<
81 0 : "\nSee STR_POOLCOLL_*\n\n";
82 : }
83 : }
84 0 : for( std::map<OString,sal_uInt16>::iterator it=aLocalizedNumStyleNames.begin(); it!=aLocalizedNumStyleNames.end(); ++it)
85 : {
86 0 : if( it->second > 1 )
87 : {
88 0 : std::cout << "ERROR: Style name translations must be unique in:\n" <<
89 0 : aPoPath << "\nLanguage: " << aLanguage << "\nDuplicated translation is: " << it->first <<
90 0 : "\nSee STR_POOLNUMRULE_*\n\n";
91 : }
92 : }
93 0 : aPoInput.open(aPoPath);
94 0 : if( !aPoInput.isOpen() )
95 0 : std::cerr << "Warning: Cannot open " << aPoPath << std::endl;
96 0 : PoOfstream aPoOutput;
97 0 : aPoOutput.open(aPoPath+".new");
98 0 : PoHeader aTmp("sw/source/ui/utlui");
99 0 : aPoOutput.writeHeader(aTmp);
100 0 : bool bAnyError = false;
101 :
102 : for(;;)
103 : {
104 0 : PoEntry aPoEntry;
105 0 : bool bError = false;
106 0 : aPoInput.readEntry(aPoEntry);
107 0 : if( aPoInput.eof() )
108 0 : break;
109 0 : for ( std::list<PoEntry>::iterator it=repeatedEntries.begin(); it!=repeatedEntries.end(); ++it) {
110 0 : if (it->getMsgId() == aPoEntry.getMsgId() && it->getGroupId() == aPoEntry.getGroupId()) {
111 0 : bError = true;
112 0 : break;
113 : }
114 : }
115 0 : if (bError) {
116 0 : bAnyError = true;
117 : } else {
118 0 : aPoOutput.writeEntry(aPoEntry);
119 : }
120 0 : }
121 0 : aPoInput.close();
122 0 : aPoOutput.close();
123 0 : OUString aPoPathURL;
124 0 : osl::FileBase::getFileURLFromSystemPath(OStringToOUString(aPoPath, RTL_TEXTENCODING_UTF8), aPoPathURL);
125 0 : if( bAnyError )
126 0 : osl::File::move(aPoPathURL + ".new", aPoPathURL);
127 : else
128 0 : osl::File::remove(aPoPathURL + ".new");
129 :
130 0 : }
131 :
132 : // Translated spreadsheet function names must be unique
133 0 : static void checkFunctionNames(const OString& aLanguage)
134 : {
135 0 : std::map<OString,sal_uInt16> aLocalizedFunctionNames;
136 0 : std::map<OString,sal_uInt16> aLocalizedCoreFunctionNames;
137 :
138 0 : std::list<PoEntry> repeatedEntries;
139 :
140 0 : OString aPoPaths[4];
141 0 : OUString aPoPathURL;
142 :
143 0 : aPoPaths[0] = OString(getenv("SRC_ROOT")) +
144 0 : "/translations/source/" +
145 0 : aLanguage +
146 0 : "/formula/source/core/resource.po";
147 0 : PoIfstream aPoInput;
148 0 : aPoInput.open(aPoPaths[0]);
149 0 : if( !aPoInput.isOpen() )
150 0 : std::cerr << "Warning: Cannot open " << aPoPaths[0] << std::endl;
151 :
152 : for(;;)
153 : {
154 0 : PoEntry aPoEntry;
155 0 : aPoInput.readEntry(aPoEntry);
156 0 : if( aPoInput.eof() )
157 0 : break;
158 0 : if( !aPoEntry.isFuzzy() && aPoEntry.getGroupId() == "RID_STRLIST_FUNCTION_NAMES" )
159 : {
160 0 : OString aMsgStr = aPoEntry.getMsgStr();
161 0 : if( aMsgStr.isEmpty() )
162 0 : continue;
163 0 : if( aLocalizedCoreFunctionNames.find(aMsgStr) == aLocalizedCoreFunctionNames.end() )
164 0 : aLocalizedCoreFunctionNames[aMsgStr] = 1;
165 0 : if( aLocalizedFunctionNames.find(aMsgStr) == aLocalizedFunctionNames.end() ) {
166 0 : aLocalizedFunctionNames[aMsgStr] = 1;
167 : } else {
168 0 : aLocalizedFunctionNames[aMsgStr]++;
169 0 : repeatedEntries.push_back(aPoEntry);
170 0 : }
171 : }
172 0 : }
173 0 : aPoInput.close();
174 :
175 0 : aPoPaths[1] = OString(getenv("SRC_ROOT")) +
176 0 : "/translations/source/" +
177 0 : aLanguage +
178 0 : "/scaddins/source/analysis.po";
179 0 : aPoInput.open(aPoPaths[1]);
180 0 : if( !aPoInput.isOpen() )
181 0 : std::cerr << "Warning: Cannot open " << aPoPaths[1] << std::endl;
182 :
183 : for(;;)
184 : {
185 0 : PoEntry aPoEntry;
186 0 : aPoInput.readEntry(aPoEntry);
187 0 : if( aPoInput.eof() )
188 0 : break;
189 0 : if( !aPoEntry.isFuzzy() && aPoEntry.getGroupId() == "RID_ANALYSIS_FUNCTION_NAMES" )
190 : {
191 0 : OString aMsgStr = aPoEntry.getMsgStr();
192 0 : if( aMsgStr.isEmpty() )
193 0 : continue;
194 0 : if( aLocalizedCoreFunctionNames.find(aMsgStr) != aLocalizedCoreFunctionNames.end() )
195 0 : aMsgStr += "_ADD";
196 0 : if( aLocalizedFunctionNames.find(aMsgStr) == aLocalizedFunctionNames.end() ) {
197 0 : aLocalizedFunctionNames[aMsgStr] = 1;
198 : } else {
199 0 : aLocalizedFunctionNames[aMsgStr]++;
200 0 : repeatedEntries.push_back(aPoEntry);
201 0 : }
202 : }
203 0 : }
204 0 : aPoInput.close();
205 :
206 :
207 0 : aPoPaths[2] = OString(getenv("SRC_ROOT")) +
208 0 : "/translations/source/" +
209 0 : aLanguage +
210 0 : "/scaddins/source/datefunc.po";
211 0 : aPoInput.open(aPoPaths[2]);
212 0 : if( !aPoInput.isOpen() )
213 0 : std::cerr << "Warning: Cannot open " << aPoPaths[2] << std::endl;
214 :
215 : for(;;)
216 : {
217 0 : PoEntry aPoEntry;
218 0 : aPoInput.readEntry(aPoEntry);
219 0 : if( aPoInput.eof() )
220 0 : break;
221 0 : if( !aPoEntry.isFuzzy() && aPoEntry.getGroupId() == "RID_DATE_FUNCTION_NAMES" )
222 : {
223 0 : OString aMsgStr = aPoEntry.getMsgStr();
224 0 : if( aMsgStr.isEmpty() )
225 0 : continue;
226 0 : if( aLocalizedCoreFunctionNames.find(aMsgStr) != aLocalizedCoreFunctionNames.end() )
227 0 : aMsgStr += "_ADD";
228 0 : if( aLocalizedFunctionNames.find(aMsgStr) == aLocalizedFunctionNames.end() ) {
229 0 : aLocalizedFunctionNames[aMsgStr] = 1;
230 : } else {
231 0 : aLocalizedFunctionNames[aMsgStr]++;
232 0 : repeatedEntries.push_back(aPoEntry);
233 0 : }
234 : }
235 0 : }
236 0 : aPoInput.close();
237 :
238 0 : aPoPaths[3] = OString(getenv("SRC_ROOT")) +
239 0 : "/translations/source/" +
240 0 : aLanguage +
241 0 : "/scaddins/source/pricing.po";
242 0 : aPoInput.open(aPoPaths[3]);
243 0 : if( !aPoInput.isOpen() )
244 0 : std::cerr << "Warning: Cannot open " << aPoPaths[3] << std::endl;
245 :
246 : for(;;)
247 : {
248 0 : PoEntry aPoEntry;
249 0 : aPoInput.readEntry(aPoEntry);
250 0 : if( aPoInput.eof() )
251 : {
252 0 : break;
253 : }
254 :
255 0 : if( !aPoEntry.isFuzzy() && aPoEntry.getGroupId() == "RID_PRICING_FUNCTION_NAMES" )
256 : {
257 0 : OString aMsgStr = aPoEntry.getMsgStr();
258 0 : if( aMsgStr.isEmpty() )
259 0 : continue;
260 0 : if( aLocalizedCoreFunctionNames.find(aMsgStr) != aLocalizedCoreFunctionNames.end() )
261 0 : aMsgStr += "_ADD";
262 0 : if( aLocalizedFunctionNames.find(aMsgStr) == aLocalizedFunctionNames.end() ) {
263 0 : aLocalizedFunctionNames[aMsgStr] = 1;
264 : } else {
265 0 : aLocalizedFunctionNames[aMsgStr]++;
266 0 : repeatedEntries.push_back(aPoEntry);
267 0 : }
268 : }
269 0 : }
270 0 : aPoInput.close();
271 0 : for( std::map<OString,sal_uInt16>::iterator it=aLocalizedFunctionNames.begin(); it!=aLocalizedFunctionNames.end(); ++it)
272 : {
273 0 : if( it->second > 1 )
274 : {
275 : std::cout
276 : << ("ERROR: Spreadsheet function name translations must be"
277 0 : " unique.\nLanguage: ")
278 0 : << aLanguage << "\nDuplicated translation is: " << it->first
279 0 : << "\n\n";
280 : }
281 : }
282 :
283 0 : for (int i=0;i<4;i++)
284 : {
285 0 : aPoInput.open(aPoPaths[i]);
286 0 : if( !aPoInput.isOpen() )
287 0 : std::cerr << "Warning: Cannot open " << aPoPaths[i] << std::endl;
288 0 : PoOfstream aPoOutput;
289 0 : aPoOutput.open(aPoPaths[i]+".new");
290 :
291 0 : switch (i)
292 : {
293 : case 0:
294 : {
295 0 : PoHeader hd(OString("formula/source/core/resource"));
296 0 : aPoOutput.writeHeader(hd);
297 0 : break;
298 : }
299 : case 1:
300 : {
301 0 : PoHeader hd(OString("scaddins/source/analysis"));
302 0 : aPoOutput.writeHeader(hd);
303 0 : break;
304 : }
305 : case 2:
306 : {
307 0 : PoHeader hd(OString("scaddins/source/datefunc"));
308 0 : aPoOutput.writeHeader(hd);
309 0 : break;
310 : }
311 : case 3:
312 : {
313 0 : PoHeader hd(OString("scaddins/source/pricing"));
314 0 : aPoOutput.writeHeader(hd);
315 0 : break;
316 : }
317 : }
318 0 : bool bAnyError = false;
319 :
320 : for(;;)
321 : {
322 0 : PoEntry aPoEntry;
323 0 : bool bError = false;
324 0 : aPoInput.readEntry(aPoEntry);
325 0 : if( aPoInput.eof() )
326 0 : break;
327 0 : for ( std::list<PoEntry>::iterator it=repeatedEntries.begin(); it!=repeatedEntries.end(); ++it)
328 : {
329 0 : if (it->getMsgId() == aPoEntry.getMsgId() && it->getGroupId() == aPoEntry.getGroupId())
330 : {
331 0 : bError = true;
332 0 : break;
333 : }
334 : }
335 0 : if (bError)
336 : {
337 0 : bAnyError = true;
338 : }
339 : else
340 : {
341 0 : aPoOutput.writeEntry(aPoEntry);
342 : }
343 0 : }
344 0 : aPoInput.close();
345 0 : aPoOutput.close();
346 0 : osl::FileBase::getFileURLFromSystemPath(OStringToOUString(aPoPaths[i], RTL_TEXTENCODING_UTF8), aPoPathURL);
347 0 : if( bAnyError )
348 0 : osl::File::move(aPoPathURL + ".new", aPoPathURL);
349 : else
350 0 : osl::File::remove(aPoPathURL + ".new");
351 0 : }
352 0 : }
353 :
354 : // In instsetoo_native/inc_openoffice/windows/msi_languages.po
355 : // where an en-US string ends with '|', translation must end
356 : // with '|', too.
357 0 : static void checkVerticalBar(const OString& aLanguage)
358 : {
359 0 : OString aPoPath = OString(getenv("SRC_ROOT")) +
360 0 : "/translations/source/" +
361 0 : aLanguage +
362 0 : "/instsetoo_native/inc_openoffice/windows/msi_languages.po";
363 0 : PoIfstream aPoInput;
364 0 : aPoInput.open(aPoPath);
365 0 : PoOfstream aPoOutput;
366 0 : aPoOutput.open(aPoPath+".new");
367 0 : if( !aPoInput.isOpen() )
368 0 : std::cerr << "Warning: Cannot open " << aPoPath << std::endl;
369 0 : PoHeader aTmp("instsetoo_native/inc_openoffice/windows/msi_languages");
370 0 : aPoOutput.writeHeader(aTmp);
371 0 : bool bError = false;
372 :
373 : for(;;)
374 : {
375 0 : PoEntry aPoEntry;
376 0 : aPoInput.readEntry(aPoEntry);
377 0 : if( aPoInput.eof() )
378 0 : break;
379 0 : if( !aPoEntry.isFuzzy() && aPoEntry.getMsgId().endsWith("|") &&
380 0 : !aPoEntry.getMsgStr().isEmpty() && !aPoEntry.getMsgStr().endsWith("|") )
381 : {
382 : std::cout
383 : << ("ERROR: Missing '|' character at the end of translated"
384 0 : " string.\nIt causes runtime error in installer.\nFile: ")
385 0 : << aPoPath << std::endl
386 0 : << "Language: " << aLanguage << std::endl
387 0 : << "English: " << aPoEntry.getMsgId() << std::endl
388 0 : << "Localized: " << aPoEntry.getMsgStr() << std::endl
389 0 : << std::endl;
390 0 : bError = true;
391 : }
392 : else
393 0 : aPoOutput.writeEntry(aPoEntry);
394 0 : }
395 0 : aPoInput.close();
396 0 : aPoOutput.close();
397 0 : OUString aPoPathURL;
398 0 : osl::FileBase::getFileURLFromSystemPath(OStringToOUString(aPoPath, RTL_TEXTENCODING_UTF8), aPoPathURL);
399 0 : if( bError )
400 0 : osl::File::move(aPoPathURL + ".new", aPoPathURL);
401 : else
402 0 : osl::File::remove(aPoPathURL + ".new");
403 0 : }
404 :
405 : // In starmath/source.po Math symbol names (from symbol.src)
406 : // must not contain spaces
407 0 : static void checkMathSymbolNames(const OString& aLanguage)
408 : {
409 0 : OString aPoPath = OString(getenv("SRC_ROOT")) +
410 0 : "/translations/source/" +
411 0 : aLanguage +
412 0 : "/starmath/source.po";
413 0 : PoIfstream aPoInput;
414 0 : aPoInput.open(aPoPath);
415 0 : PoOfstream aPoOutput;
416 0 : aPoOutput.open(aPoPath+".new");
417 0 : if( !aPoInput.isOpen() )
418 0 : std::cerr << "Warning: Cannot open " << aPoPath << std::endl;
419 0 : PoHeader aTmp("starmath/source");
420 0 : aPoOutput.writeHeader(aTmp);
421 0 : bool bError = false;
422 :
423 : for(;;)
424 : {
425 0 : PoEntry aPoEntry;
426 0 : aPoInput.readEntry(aPoEntry);
427 0 : if( aPoInput.eof() )
428 0 : break;
429 0 : if( !aPoEntry.isFuzzy() && aPoEntry.getGroupId() == "RID_UI_SYMBOL_NAMES" &&
430 0 : !aPoEntry.getMsgStr().isEmpty() && (aPoEntry.getMsgStr().indexOf(" ") != -1) )
431 : {
432 : std::cout
433 0 : << "ERROR: Math symbol names must not contain spaces.\nFile: "
434 0 : << aPoPath << std::endl
435 0 : << "Language: " << aLanguage << std::endl
436 0 : << "English: " << aPoEntry.getMsgId() << std::endl
437 0 : << "Localized: " << aPoEntry.getMsgStr() << std::endl
438 0 : << std::endl;
439 0 : bError = true;
440 : }
441 : else
442 0 : aPoOutput.writeEntry(aPoEntry);
443 0 : }
444 0 : aPoInput.close();
445 0 : aPoOutput.close();
446 0 : OUString aPoPathURL;
447 0 : osl::FileBase::getFileURLFromSystemPath(OStringToOUString(aPoPath, RTL_TEXTENCODING_UTF8), aPoPathURL);
448 0 : if( bError )
449 0 : osl::File::move(aPoPathURL + ".new", aPoPathURL);
450 : else
451 0 : osl::File::remove(aPoPathURL + ".new");
452 0 : }
453 :
454 0 : int main()
455 : {
456 0 : OString aLanguages(getenv("ALL_LANGS"));
457 0 : if( aLanguages.isEmpty() )
458 : {
459 0 : std::cerr << "Usage: bin/run pocheck\n";
460 0 : return 1;
461 : }
462 0 : for(sal_Int32 i = 1;;++i) // skip en-US
463 : {
464 0 : OString aLanguage = aLanguages.getToken(i,' ');
465 0 : if( aLanguage.isEmpty() )
466 0 : break;
467 0 : if( aLanguage == "qtz" )
468 0 : continue;
469 0 : checkStyleNames(aLanguage);
470 0 : checkFunctionNames(aLanguage);
471 0 : checkVerticalBar(aLanguage);
472 0 : checkMathSymbolNames(aLanguage);
473 0 : }
474 0 : return 0;
475 0 : }
476 :
477 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|