/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include // Translated style names must be unique static void checkStyleNames(const OString& aLanguage) { std::map aLocalizedStyleNames; std::map aLocalizedNumStyleNames; std::vector repeatedEntries; OString aPoPath = OString(getenv("SRC_ROOT")) + "/translations/source/" + aLanguage + "/sw/source/ui/utlui.po"; PoIfstream aPoInput; aPoInput.open(aPoPath); if( !aPoInput.isOpen() ) std::cerr << "Warning: Cannot open " << aPoPath << std::endl; for(;;) { PoEntry aPoEntry; aPoInput.readEntry(aPoEntry); bool bRepeated = false; if( aPoInput.eof() ) { break; } if( !aPoEntry.isFuzzy() && aPoEntry.getSourceFile() == "poolfmt.src" && aPoEntry.getGroupId().startsWith("STR_POOLCOLL") ) { OString aMsgStr = aPoEntry.getMsgStr(); if( aMsgStr.isEmpty() ) continue; if( aLocalizedStyleNames.find(aMsgStr) == aLocalizedStyleNames.end() ) aLocalizedStyleNames[aMsgStr] = 1; else { aLocalizedStyleNames[aMsgStr]++; bRepeated = true; } } if( !aPoEntry.isFuzzy() && aPoEntry.getSourceFile() == "poolfmt.src" && aPoEntry.getGroupId().startsWith("STR_POOLNUMRULE") ) { OString aMsgStr = aPoEntry.getMsgStr(); if( aMsgStr.isEmpty() ) continue; if( aLocalizedNumStyleNames.find(aMsgStr) == aLocalizedNumStyleNames.end() ) aLocalizedNumStyleNames[aMsgStr] = 1; else { aLocalizedNumStyleNames[aMsgStr]++; bRepeated = true; } } if (bRepeated) repeatedEntries.push_back(aPoEntry); } aPoInput.close(); for( std::map::iterator it=aLocalizedStyleNames.begin(); it!=aLocalizedStyleNames.end(); ++it) { if( it->second > 1 ) { std::cout << "ERROR: Style name translations must be unique in:\n" << aPoPath << "\nLanguage: " << aLanguage << "\nDuplicated translation is: " << it->first << "\nSee STR_POOLCOLL_*\n\n"; } } for( std::map::iterator it=aLocalizedNumStyleNames.begin(); it!=aLocalizedNumStyleNames.end(); ++it) { if( it->second > 1 ) { std::cout << "ERROR: Style name translations must be unique in:\n" << aPoPath << "\nLanguage: " << aLanguage << "\nDuplicated translation is: " << it->first << "\nSee STR_POOLNUMRULE_*\n\n"; } } aPoInput.open(aPoPath); if( !aPoInput.isOpen() ) std::cerr << "Warning: Cannot open " << aPoPath << std::endl; PoOfstream aPoOutput; aPoOutput.open(aPoPath+".new"); PoHeader aTmp("sw/source/ui/utlui"); aPoOutput.writeHeader(aTmp); bool bAnyError = false; for(;;) { PoEntry aPoEntry; bool bError = false; aPoInput.readEntry(aPoEntry); if( aPoInput.eof() ) break; for (auto const& repeatedEntry : repeatedEntries) { if (repeatedEntry.getMsgId() == aPoEntry.getMsgId() && repeatedEntry.getGroupId() == aPoEntry.getGroupId()) { bError = true; break; } } if (bError) { bAnyError = true; } else { aPoOutput.writeEntry(aPoEntry); } } aPoInput.close(); aPoOutput.close(); OUString aPoPathURL; osl::FileBase::getFileURLFromSystemPath(OStringToOUString(aPoPath, RTL_TEXTENCODING_UTF8), aPoPathURL); if( bAnyError ) osl::File::move(aPoPathURL + ".new", aPoPathURL); else osl::File::remove(aPoPathURL + ".new"); } // Translated spreadsheet function names must be unique static void checkFunctionNames(const OString& aLanguage) { std::map aLocalizedFunctionNames; std::map aLocalizedCoreFunctionNames; std::vector repeatedEntries; OString aPoPaths[4]; OUString aPoPathURL; aPoPaths[0] = OString(getenv("SRC_ROOT")) + "/translations/source/" + aLanguage + "/formula/source/core/resource.po"; PoIfstream aPoInput; aPoInput.open(aPoPaths[0]); if( !aPoInput.isOpen() ) std::cerr << "Warning: Cannot open " << aPoPaths[0] << std::endl; for(;;) { PoEntry aPoEntry; aPoInput.readEntry(aPoEntry); if( aPoInput.eof() ) break; if( !aPoEntry.isFuzzy() && aPoEntry.getGroupId() == "RID_STRLIST_FUNCTION_NAMES" ) { OString aMsgStr = aPoEntry.getMsgStr(); if( aMsgStr.isEmpty() ) continue; if( aLocalizedCoreFunctionNames.find(aMsgStr) == aLocalizedCoreFunctionNames.end() ) aLocalizedCoreFunctionNames[aMsgStr] = 1; if( aLocalizedFunctionNames.find(aMsgStr) == aLocalizedFunctionNames.end() ) { aLocalizedFunctionNames[aMsgStr] = 1; } else { aLocalizedFunctionNames[aMsgStr]++; repeatedEntries.push_back(aPoEntry); } } } aPoInput.close(); aPoPaths[1] = OString(getenv("SRC_ROOT")) + "/translations/source/" + aLanguage + "/scaddins/source/analysis.po"; aPoInput.open(aPoPaths[1]); if( !aPoInput.isOpen() ) std::cerr << "Warning: Cannot open " << aPoPaths[1] << std::endl; for(;;) { PoEntry aPoEntry; aPoInput.readEntry(aPoEntry); if( aPoInput.eof() ) break; if( !aPoEntry.isFuzzy() && aPoEntry.getGroupId() == "RID_ANALYSIS_FUNCTION_NAMES" ) { OString aMsgStr = aPoEntry.getMsgStr(); if( aMsgStr.isEmpty() ) continue; if( aLocalizedCoreFunctionNames.find(aMsgStr) != aLocalizedCoreFunctionNames.end() ) aMsgStr += "_ADD"; if( aLocalizedFunctionNames.find(aMsgStr) == aLocalizedFunctionNames.end() ) { aLocalizedFunctionNames[aMsgStr] = 1; } else { aLocalizedFunctionNames[aMsgStr]++; repeatedEntries.push_back(aPoEntry); } } } aPoInput.close(); aPoPaths[2] = OString(getenv("SRC_ROOT")) + "/translations/source/" + aLanguage + "/scaddins/source/datefunc.po"; aPoInput.open(aPoPaths[2]); if( !aPoInput.isOpen() ) std::cerr << "Warning: Cannot open " << aPoPaths[2] << std::endl; for(;;) { PoEntry aPoEntry; aPoInput.readEntry(aPoEntry); if( aPoInput.eof() ) break; if( !aPoEntry.isFuzzy() && aPoEntry.getGroupId() == "RID_DATE_FUNCTION_NAMES" ) { OString aMsgStr = aPoEntry.getMsgStr(); if( aMsgStr.isEmpty() ) continue; if( aLocalizedCoreFunctionNames.find(aMsgStr) != aLocalizedCoreFunctionNames.end() ) aMsgStr += "_ADD"; if( aLocalizedFunctionNames.find(aMsgStr) == aLocalizedFunctionNames.end() ) { aLocalizedFunctionNames[aMsgStr] = 1; } else { aLocalizedFunctionNames[aMsgStr]++; repeatedEntries.push_back(aPoEntry); } } } aPoInput.close(); aPoPaths[3] = OString(getenv("SRC_ROOT")) + "/translations/source/" + aLanguage + "/scaddins/source/pricing.po"; aPoInput.open(aPoPaths[3]); if( !aPoInput.isOpen() ) std::cerr << "Warning: Cannot open " << aPoPaths[3] << std::endl; for(;;) { PoEntry aPoEntry; aPoInput.readEntry(aPoEntry); if( aPoInput.eof() ) { break; } if( !aPoEntry.isFuzzy() && aPoEntry.getGroupId() == "RID_PRICING_FUNCTION_NAMES" ) { OString aMsgStr = aPoEntry.getMsgStr(); if( aMsgStr.isEmpty() ) continue; if( aLocalizedCoreFunctionNames.find(aMsgStr) != aLocalizedCoreFunctionNames.end() ) aMsgStr += "_ADD"; if( aLocalizedFunctionNames.find(aMsgStr) == aLocalizedFunctionNames.end() ) { aLocalizedFunctionNames[aMsgStr] = 1; } else { aLocalizedFunctionNames[aMsgStr]++; repeatedEntries.push_back(aPoEntry); } } } aPoInput.close(); for( std::map::iterator it=aLocalizedFunctionNames.begin(); it!=aLocalizedFunctionNames.end(); ++it) { if( it->second > 1 ) { std::cout << ("ERROR: Spreadsheet function name translations must be" " unique.\nLanguage: ") << aLanguage << "\nDuplicated translation is: " << it->first << "\n\n"; } } for (int i=0;i<4;i++) { aPoInput.open(aPoPaths[i]); if( !aPoInput.isOpen() ) std::cerr << "Warning: Cannot open " << aPoPaths[i] << std::endl; PoOfstream aPoOutput; aPoOutput.open(aPoPaths[i]+".new"); switch (i) { case 0: { PoHeader hd(OString("formula/source/core/resource")); aPoOutput.writeHeader(hd); break; } case 1: { PoHeader hd(OString("scaddins/source/analysis")); aPoOutput.writeHeader(hd); break; } case 2: { PoHeader hd(OString("scaddins/source/datefunc")); aPoOutput.writeHeader(hd); break; } case 3: { PoHeader hd(OString("scaddins/source/pricing")); aPoOutput.writeHeader(hd); break; } } bool bAnyError = false; for(;;) { PoEntry aPoEntry; bool bError = false; aPoInput.readEntry(aPoEntry); if( aPoInput.eof() ) break; for (auto const& repeatedEntry : repeatedEntries) { if (repeatedEntry.getMsgId() == aPoEntry.getMsgId() && repeatedEntry.getGroupId() == aPoEntry.getGroupId()) { bError = true; break; } } if (bError) { bAnyError = true; } else { aPoOutput.writeEntry(aPoEntry); } } aPoInput.close(); aPoOutput.close(); osl::FileBase::getFileURLFromSystemPath(OStringToOUString(aPoPaths[i], RTL_TEXTENCODING_UTF8), aPoPathURL); if( bAnyError ) osl::File::move(aPoPathURL + ".new", aPoPathURL); else osl::File::remove(aPoPathURL + ".new"); } } // In instsetoo_native/inc_openoffice/windows/msi_languages.po // where an en-US string ends with '|', translation must end // with '|', too. static void checkVerticalBar(const OString& aLanguage) { OString aPoPath = OString(getenv("SRC_ROOT")) + "/translations/source/" + aLanguage + "/instsetoo_native/inc_openoffice/windows/msi_languages.po"; PoIfstream aPoInput; aPoInput.open(aPoPath); PoOfstream aPoOutput; aPoOutput.open(aPoPath+".new"); if( !aPoInput.isOpen() ) std::cerr << "Warning: Cannot open " << aPoPath << std::endl; PoHeader aTmp("instsetoo_native/inc_openoffice/windows/msi_languages"); aPoOutput.writeHeader(aTmp); bool bError = false; for(;;) { PoEntry aPoEntry; aPoInput.readEntry(aPoEntry); if( aPoInput.eof() ) break; if( !aPoEntry.isFuzzy() && aPoEntry.getMsgId().endsWith("|") && !aPoEntry.getMsgStr().isEmpty() && !aPoEntry.getMsgStr().endsWith("|") ) { std::cout << ("ERROR: Missing '|' character at the end of translated" " string.\nIt causes runtime error in installer.\nFile: ") << aPoPath << std::endl << "Language: " << aLanguage << std::endl << "English: " << aPoEntry.getMsgId() << std::endl << "Localized: " << aPoEntry.getMsgStr() << std::endl << std::endl; bError = true; } else aPoOutput.writeEntry(aPoEntry); } aPoInput.close(); aPoOutput.close(); OUString aPoPathURL; osl::FileBase::getFileURLFromSystemPath(OStringToOUString(aPoPath, RTL_TEXTENCODING_UTF8), aPoPathURL); if( bError ) osl::File::move(aPoPathURL + ".new", aPoPathURL); else osl::File::remove(aPoPathURL + ".new"); } // In starmath/source.po Math symbol names (from symbol.src) // must not contain spaces static void checkMathSymbolNames(const OString& aLanguage) { OString aPoPath = OString(getenv("SRC_ROOT")) + "/translations/source/" + aLanguage + "/starmath/source.po"; PoIfstream aPoInput; aPoInput.open(aPoPath); PoOfstream aPoOutput; aPoOutput.open(aPoPath+".new"); if( !aPoInput.isOpen() ) std::cerr << "Warning: Cannot open " << aPoPath << std::endl; PoHeader aTmp("starmath/source"); aPoOutput.writeHeader(aTmp); bool bError = false; for(;;) { PoEntry aPoEntry; aPoInput.readEntry(aPoEntry); if( aPoInput.eof() ) break; if( !aPoEntry.isFuzzy() && aPoEntry.getGroupId() == "RID_UI_SYMBOL_NAMES" && !aPoEntry.getMsgStr().isEmpty() && (aPoEntry.getMsgStr().indexOf(" ") != -1) ) { std::cout << "ERROR: Math symbol names must not contain spaces.\nFile: " << aPoPath << std::endl << "Language: " << aLanguage << std::endl << "English: " << aPoEntry.getMsgId() << std::endl << "Localized: " << aPoEntry.getMsgStr() << std::endl << std::endl; bError = true; } else aPoOutput.writeEntry(aPoEntry); } aPoInput.close(); aPoOutput.close(); OUString aPoPathURL; osl::FileBase::getFileURLFromSystemPath(OStringToOUString(aPoPath, RTL_TEXTENCODING_UTF8), aPoPathURL); if( bError ) osl::File::move(aPoPathURL + ".new", aPoPathURL); else osl::File::remove(aPoPathURL + ".new"); } int main() { try { OString aLanguages(getenv("ALL_LANGS")); if( aLanguages.isEmpty() ) { std::cerr << "Usage: bin/run pocheck\n"; return 1; } for(sal_Int32 i = 1;;++i) // skip en-US { OString aLanguage = aLanguages.getToken(i,' '); if( aLanguage.isEmpty() ) break; if( aLanguage == "qtz" ) continue; checkStyleNames(aLanguage); checkFunctionNames(aLanguage); checkVerticalBar(aLanguage); checkMathSymbolNames(aLanguage); } return 0; } catch (std::exception& e) { std::cerr << "pocheck: exception " << e.what() << std::endl; return 1; } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */