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 0 : std::cout << "ERROR: Spreadsheet function name translations must be unique.\n" <<
276 0 : "Language: " << aLanguage <<
277 0 : "\nDuplicated translation is: " << it->first << "\n\n";
278 : }
279 : }
280 :
281 0 : for (int i=0;i<4;i++)
282 : {
283 0 : aPoInput.open(aPoPaths[i]);
284 0 : if( !aPoInput.isOpen() )
285 0 : std::cerr << "Warning: Cannot open " << aPoPaths[i] << std::endl;
286 0 : PoOfstream aPoOutput;
287 0 : aPoOutput.open(aPoPaths[i]+".new");
288 :
289 0 : switch (i)
290 : {
291 : case 0:
292 : {
293 0 : PoHeader hd(OString("formula/source/core/resource"));
294 0 : aPoOutput.writeHeader(hd);
295 0 : break;
296 : }
297 : case 1:
298 : {
299 0 : PoHeader hd(OString("scaddins/source/analysis"));
300 0 : aPoOutput.writeHeader(hd);
301 0 : break;
302 : }
303 : case 2:
304 : {
305 0 : PoHeader hd(OString("scaddins/source/datefunc"));
306 0 : aPoOutput.writeHeader(hd);
307 0 : break;
308 : }
309 : case 3:
310 : {
311 0 : PoHeader hd(OString("scaddins/source/pricing"));
312 0 : aPoOutput.writeHeader(hd);
313 0 : break;
314 : }
315 : }
316 0 : bool bAnyError = false;
317 :
318 : for(;;)
319 : {
320 0 : PoEntry aPoEntry;
321 0 : bool bError = false;
322 0 : aPoInput.readEntry(aPoEntry);
323 0 : if( aPoInput.eof() )
324 0 : break;
325 0 : for ( std::list<PoEntry>::iterator it=repeatedEntries.begin(); it!=repeatedEntries.end(); ++it)
326 : {
327 0 : if (it->getMsgId() == aPoEntry.getMsgId() && it->getGroupId() == aPoEntry.getGroupId())
328 : {
329 0 : bError = true;
330 0 : break;
331 : }
332 : }
333 0 : if (bError)
334 : {
335 0 : bAnyError = true;
336 : }
337 : else
338 : {
339 0 : aPoOutput.writeEntry(aPoEntry);
340 : }
341 0 : }
342 0 : aPoInput.close();
343 0 : aPoOutput.close();
344 0 : osl::FileBase::getFileURLFromSystemPath(OStringToOUString(aPoPaths[i], RTL_TEXTENCODING_UTF8), aPoPathURL);
345 0 : if( bAnyError )
346 0 : osl::File::move(aPoPathURL + ".new", aPoPathURL);
347 : else
348 0 : osl::File::remove(aPoPathURL + ".new");
349 0 : }
350 0 : }
351 :
352 : // In instsetoo_native/inc_openoffice/windows/msi_languages.po
353 : // where an en-US string ends with '|', translation must end
354 : // with '|', too.
355 0 : static void checkVerticalBar(const OString& aLanguage)
356 : {
357 0 : OString aPoPath = OString(getenv("SRC_ROOT")) +
358 0 : "/translations/source/" +
359 0 : aLanguage +
360 0 : "/instsetoo_native/inc_openoffice/windows/msi_languages.po";
361 0 : PoIfstream aPoInput;
362 0 : aPoInput.open(aPoPath);
363 0 : PoOfstream aPoOutput;
364 0 : aPoOutput.open(aPoPath+".new");
365 0 : if( !aPoInput.isOpen() )
366 0 : std::cerr << "Warning: Cannot open " << aPoPath << std::endl;
367 0 : PoHeader aTmp("instsetoo_native/inc_openoffice/windows/msi_languages");
368 0 : aPoOutput.writeHeader(aTmp);
369 0 : bool bError = false;
370 :
371 : for(;;)
372 : {
373 0 : PoEntry aPoEntry;
374 0 : aPoInput.readEntry(aPoEntry);
375 0 : if( aPoInput.eof() )
376 0 : break;
377 0 : if( !aPoEntry.isFuzzy() && aPoEntry.getMsgId().endsWith("|") &&
378 0 : !aPoEntry.getMsgStr().isEmpty() && !aPoEntry.getMsgStr().endsWith("|") )
379 : {
380 0 : std::cout << "ERROR: Missing '|' character at the end of translated string.\n" <<
381 0 : "It causes runtime error in installer.\n" <<
382 0 : "File: " << aPoPath << std::endl <<
383 0 : "Language: " << aLanguage << std::endl <<
384 0 : "English: " << aPoEntry.getMsgId() << std::endl <<
385 0 : "Localized: " << aPoEntry.getMsgStr() << std::endl << std::endl;
386 0 : bError = true;
387 : }
388 : else
389 0 : aPoOutput.writeEntry(aPoEntry);
390 0 : }
391 0 : aPoInput.close();
392 0 : aPoOutput.close();
393 0 : OUString aPoPathURL;
394 0 : osl::FileBase::getFileURLFromSystemPath(OStringToOUString(aPoPath, RTL_TEXTENCODING_UTF8), aPoPathURL);
395 0 : if( bError )
396 0 : osl::File::move(aPoPathURL + ".new", aPoPathURL);
397 : else
398 0 : osl::File::remove(aPoPathURL + ".new");
399 0 : }
400 :
401 : // In starmath/source.po Math symbol names (from symbol.src)
402 : // must not contain spaces
403 0 : static void checkMathSymbolNames(const OString& aLanguage)
404 : {
405 0 : OString aPoPath = OString(getenv("SRC_ROOT")) +
406 0 : "/translations/source/" +
407 0 : aLanguage +
408 0 : "/starmath/source.po";
409 0 : PoIfstream aPoInput;
410 0 : aPoInput.open(aPoPath);
411 0 : PoOfstream aPoOutput;
412 0 : aPoOutput.open(aPoPath+".new");
413 0 : if( !aPoInput.isOpen() )
414 0 : std::cerr << "Warning: Cannot open " << aPoPath << std::endl;
415 0 : PoHeader aTmp("starmath/source");
416 0 : aPoOutput.writeHeader(aTmp);
417 0 : bool bError = false;
418 :
419 : for(;;)
420 : {
421 0 : PoEntry aPoEntry;
422 0 : aPoInput.readEntry(aPoEntry);
423 0 : if( aPoInput.eof() )
424 0 : break;
425 0 : if( !aPoEntry.isFuzzy() && aPoEntry.getGroupId() == "RID_UI_SYMBOL_NAMES" &&
426 0 : !aPoEntry.getMsgStr().isEmpty() && (aPoEntry.getMsgStr().indexOf(" ") != -1) )
427 : {
428 0 : std::cout << "ERROR: Math symbol names must not contain spaces.\n" <<
429 0 : "File: " << aPoPath << std::endl <<
430 0 : "Language: " << aLanguage << std::endl <<
431 0 : "English: " << aPoEntry.getMsgId() << std::endl <<
432 0 : "Localized: " << aPoEntry.getMsgStr() << std::endl << std::endl;
433 0 : bError = true;
434 : }
435 : else
436 0 : aPoOutput.writeEntry(aPoEntry);
437 0 : }
438 0 : aPoInput.close();
439 0 : aPoOutput.close();
440 0 : OUString aPoPathURL;
441 0 : osl::FileBase::getFileURLFromSystemPath(OStringToOUString(aPoPath, RTL_TEXTENCODING_UTF8), aPoPathURL);
442 0 : if( bError )
443 0 : osl::File::move(aPoPathURL + ".new", aPoPathURL);
444 : else
445 0 : osl::File::remove(aPoPathURL + ".new");
446 0 : }
447 :
448 0 : int main()
449 : {
450 0 : OString aLanguages(getenv("ALL_LANGS"));
451 0 : if( aLanguages.isEmpty() )
452 : {
453 0 : std::cerr << "Usage: make cmd cmd=solver/*/bin/pocheck\n";
454 0 : return 1;
455 : }
456 0 : for(sal_Int32 i = 1;;++i) // skip en-US
457 : {
458 0 : OString aLanguage = aLanguages.getToken(i,' ');
459 0 : if( aLanguage.isEmpty() )
460 0 : break;
461 0 : if( aLanguage == "qtz" )
462 0 : continue;
463 0 : checkStyleNames(aLanguage);
464 0 : checkFunctionNames(aLanguage);
465 0 : checkVerticalBar(aLanguage);
466 0 : checkMathSymbolNames(aLanguage);
467 0 : }
468 0 : return 0;
469 0 : }
470 :
471 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|