tdf#161775 sfx2: SfxRedactionHelper: actually use font for layout
[LibreOffice.git] / l10ntools / source / merge.cxx
blob88a39173aa507faec2d9160101307d794f979438
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include <algorithm>
24 #include <cstdlib>
25 #include <fstream>
26 #include <iostream>
27 #include <string>
28 #include <utility>
29 #include <vector>
31 #include <export.hxx>
32 #include <po.hxx>
34 namespace
36 OString lcl_NormalizeFilename(std::string_view rFilename)
38 size_t idx1 = rFilename.rfind( '\\' );
39 size_t idx2 = rFilename.rfind( '/' );
40 if (idx1 == std::string_view::npos && idx2 == std::string_view::npos)
41 return OString(rFilename);
42 if (idx1 == std::string_view::npos)
43 idx1 = 0;
44 if (idx2 == std::string_view::npos)
45 idx2 = 0;
46 return OString(rFilename.substr(std::max(idx1, idx2)+1));
49 bool lcl_ReadPoChecked(
50 PoEntry& o_rPoEntry, PoIfstream& rPoFile,
51 const OString& rFileName)
53 try
55 rPoFile.readEntry( o_rPoEntry );
57 catch (const PoIfstream::Exception&)
59 SAL_WARN("l10ntools", rFileName << " contains invalid entry");
60 return false;
62 return true;
69 ResData::ResData( OString _sGId )
71 sGId(std::move( _sGId ))
73 sGId = sGId.replaceAll("\r"_ostr, OString());
76 ResData::ResData( OString _sGId, OString _sFilename)
78 sGId(std::move( _sGId )),
79 sFilename(std::move( _sFilename ))
81 sGId = sGId.replaceAll("\r"_ostr, OString());
87 bool MergeEntrys::GetText( OString &rReturn,
88 const OString &nLangIndex, bool bDel )
90 bool bReturn = true;
91 rReturn = sText[ nLangIndex ];
92 if ( bDel )
93 sText[ nLangIndex ] = ""_ostr;
94 bReturn = bTextFirst[ nLangIndex ];
95 bTextFirst[ nLangIndex ] = false;
96 return bReturn;
99 namespace
101 OString GetDoubleBars()
103 //DOUBLE VERTICAL LINE instead of || because the translations make their
104 //way into action_names under gtk3 where || is illegal
105 return u8"\u2016"_ostr;
109 OString MergeEntrys::GetQTZText(const ResData& rResData, std::string_view rOrigText)
111 const OString sFilename = rResData.sFilename.copy(rResData.sFilename.lastIndexOf('/')+1);
112 const OString sKey =
113 PoEntry::genKeyId(sFilename + rResData.sGId + rResData.sId + rResData.sResTyp + rOrigText);
114 return sKey + GetDoubleBars() + rOrigText;
119 MergeDataFile::MergeDataFile(
120 const OString &rFileName, std::string_view rFile,
121 bool bCaseSensitive, bool bWithQtz )
123 auto const env = getenv("ENABLE_RELEASE_BUILD");
124 OString sEnableReleaseBuild(env == nullptr ? "" : env);
126 std::ifstream aInputStream( rFileName.getStr() );
127 if ( !aInputStream.is_open() )
129 SAL_WARN("l10ntools", "Can't open po path container file for " << rFileName);
130 return;
132 std::string sPoFile;
133 aInputStream >> sPoFile;
134 bool bFirstLang = true;
135 while( !aInputStream.eof() )
137 bool bSkipCurrentPOFile = false;
138 const OString sFileName( lcl_NormalizeFilename(rFile) );
139 const bool bReadAll = sFileName.isEmpty();
140 // coverity[tainted_data] - this is a build time tool
141 const OString sPoFileName(sPoFile.data(), static_cast<sal_Int32>(sPoFile.length()));
142 PoIfstream aPoInput;
143 aPoInput.open( sPoFileName );
144 if ( !aPoInput.isOpen() )
146 SAL_WARN("l10ntools", "Can't open file: " << sPoFileName);
147 return;
150 OString sLang;
151 //Get language id from path
153 static constexpr OString sTransSource("translations/source/"_ostr);
154 const sal_Int32 nStart =
155 sPoFileName.indexOf(sTransSource)+sTransSource.getLength();
156 const sal_Int32 nCount =
157 sPoFileName.indexOf('/',nStart) - nStart;
158 sLang = sPoFileName.copy(nStart,nCount);
160 aLanguageSet.insert( sLang );
161 PoEntry aNextPo;
164 if( !lcl_ReadPoChecked(aNextPo, aPoInput, sPoFileName) )
166 bSkipCurrentPOFile = true;
167 break;
169 } while( !aPoInput.eof() && aNextPo.getSourceFile() != sFileName && !bReadAll );
170 while( !aPoInput.eof() && (aNextPo.getSourceFile() == sFileName || bReadAll ) && !bSkipCurrentPOFile )
172 PoEntry aActPo( aNextPo );
174 bool bInSameComp = false;
175 OString sText;
176 OString sQHText;
177 OString sTitle;
178 OString sExText;
179 OString sExQHText;
180 OString sExTitle;
183 if( bInSameComp )
184 aActPo = aNextPo;
185 OString sTemp = aActPo.getMsgStr();
186 if( aActPo.isFuzzy() || sTemp.isEmpty() )
187 sTemp = aActPo.getMsgId();
188 switch( aActPo.getType() )
190 case PoEntry::TTEXT:
191 sText = sTemp;
192 sExText = aActPo.getMsgId();
193 break;
194 case PoEntry::TQUICKHELPTEXT:
195 sQHText = sTemp;
196 sExQHText = aActPo.getMsgId();
197 break;
198 case PoEntry::TTITLE:
199 sTitle = sTemp;
200 sExTitle = aActPo.getMsgId();
201 break;
203 if( !lcl_ReadPoChecked(aNextPo, aPoInput, sPoFileName) )
205 bSkipCurrentPOFile = true;
206 break;
208 if (aPoInput.eof())
209 break;
210 bInSameComp = PoEntry::IsInSameComp(aActPo, aNextPo);
211 } while( bInSameComp );
213 InsertEntry(
214 aActPo.getResourceType(), aActPo.getGroupId(),
215 aActPo.getLocalId(), sLang, sText,
216 sQHText, sTitle, aActPo.getSourceFile(),
217 bFirstLang, bCaseSensitive );
219 if( bFirstLang && bWithQtz &&
220 sEnableReleaseBuild != "TRUE" )
222 aLanguageSet.insert("qtz"_ostr);
223 InsertEntry(
224 aActPo.getResourceType(), aActPo.getGroupId(),
225 aActPo.getLocalId(), "qtz"_ostr,
226 sExText, sExQHText,
227 sExTitle, aActPo.getSourceFile(),
228 false, bCaseSensitive );
231 aPoInput.close();
232 aInputStream >> sPoFile;
233 bFirstLang = false;
235 aInputStream.close();
238 MergeDataFile::~MergeDataFile()
242 std::vector<OString> MergeDataFile::GetLanguages() const
244 return std::vector<OString>(aLanguageSet.begin(),aLanguageSet.end());
247 MergeEntrys *MergeDataFile::GetMergeData( ResData *pResData , bool bCaseSensitive )
249 OString sOldG = pResData->sGId;
250 OString sOldL = pResData->sId;
251 OString sGID = pResData->sGId;
252 OString sLID;
253 if (sGID.isEmpty())
254 sGID = pResData->sId;
255 else
256 sLID = pResData->sId;
257 pResData->sGId = sGID;
258 pResData->sId = sLID;
260 OString sKey = CreateKey( pResData->sResTyp , pResData->sGId , pResData->sId , pResData->sFilename , bCaseSensitive );
262 auto mit = aMap.find( sKey );
263 if(mit != aMap.end())
265 pResData->sGId = sOldG;
266 pResData->sId = sOldL;
267 return mit->second.get();
269 pResData->sGId = sOldG;
270 pResData->sId = sOldL;
271 return nullptr;
274 MergeEntrys *MergeDataFile::GetMergeEntrys( ResData *pResData )
276 // search for requested MergeEntrys
277 return GetMergeData( pResData );
280 MergeEntrys *MergeDataFile::GetMergeEntrysCaseSensitive( ResData *pResData )
282 // search for requested MergeEntrys
283 return GetMergeData( pResData , true );
286 void MergeDataFile::InsertEntry(
287 std::string_view rTYP, std::string_view rGID,
288 std::string_view rLID, const OString &nLANG,
289 const OString &rTEXT, const OString &rQHTEXT,
290 const OString &rTITLE, std::string_view rInFilename,
291 bool bFirstLang, bool bCaseSensitive )
293 MergeEntrys *pMergeEntrys = nullptr;
295 // search for MergeData
296 OString sKey = CreateKey(rTYP , rGID , rLID , rInFilename , bCaseSensitive);
298 if( !bFirstLang )
300 auto mit = aMap.find( sKey );
301 if(mit != aMap.end())
302 pMergeEntrys = mit->second.get();
306 if( !pMergeEntrys )
308 pMergeEntrys = new MergeEntrys;
309 if (!aMap.emplace( sKey, std::unique_ptr<MergeEntrys>(pMergeEntrys) ).second)
311 std::cerr << "Duplicate entry " << sKey << "\n";
312 std::exit(EXIT_FAILURE);
317 // insert the cur string
318 if( nLANG =="qtz" )
320 const OString sTemp = OString::Concat(rInFilename) + rGID + rLID + rTYP;
321 pMergeEntrys->InsertEntry(
322 nLANG,
323 rTEXT.isEmpty()? rTEXT : PoEntry::genKeyId(sTemp + rTEXT) + GetDoubleBars() + rTEXT,
324 rQHTEXT.isEmpty()? rQHTEXT : PoEntry::genKeyId(sTemp + rQHTEXT) + GetDoubleBars() + rQHTEXT,
325 rTITLE.isEmpty()? rTITLE : PoEntry::genKeyId(sTemp + rTITLE) + GetDoubleBars() + rTITLE );
327 else
329 pMergeEntrys->InsertEntry( nLANG , rTEXT, rQHTEXT, rTITLE );
333 OString MergeDataFile::CreateKey(std::string_view rTYP, std::string_view rGID,
334 std::string_view rLID, std::string_view rFilename, bool bCaseSensitive)
336 static const char sStroke[] = "-";
337 OString sKey = OString::Concat(rTYP) + sStroke + rGID + sStroke + rLID + sStroke +
338 lcl_NormalizeFilename(rFilename);
339 if(bCaseSensitive)
340 return sKey; // officecfg case sensitive identifier
341 return sKey.toAsciiUpperCase();
344 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */