1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
)
44 if (idx2
== std::string_view::npos
)
46 return OString(rFilename
.substr(std::max(idx1
, idx2
)+1));
49 bool lcl_ReadPoChecked(
50 PoEntry
& o_rPoEntry
, PoIfstream
& rPoFile
,
51 const OString
& rFileName
)
55 rPoFile
.readEntry( o_rPoEntry
);
57 catch (const PoIfstream::Exception
&)
59 SAL_WARN("l10ntools", rFileName
<< " contains invalid entry");
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
)
91 rReturn
= sText
[ nLangIndex
];
93 sText
[ nLangIndex
] = ""_ostr
;
94 bReturn
= bTextFirst
[ nLangIndex
];
95 bTextFirst
[ nLangIndex
] = false;
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);
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
);
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()));
143 aPoInput
.open( sPoFileName
);
144 if ( !aPoInput
.isOpen() )
146 SAL_WARN("l10ntools", "Can't open file: " << sPoFileName
);
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
);
164 if( !lcl_ReadPoChecked(aNextPo
, aPoInput
, sPoFileName
) )
166 bSkipCurrentPOFile
= true;
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;
185 OString sTemp
= aActPo
.getMsgStr();
186 if( aActPo
.isFuzzy() || sTemp
.isEmpty() )
187 sTemp
= aActPo
.getMsgId();
188 switch( aActPo
.getType() )
192 sExText
= aActPo
.getMsgId();
194 case PoEntry::TQUICKHELPTEXT
:
196 sExQHText
= aActPo
.getMsgId();
198 case PoEntry::TTITLE
:
200 sExTitle
= aActPo
.getMsgId();
203 if( !lcl_ReadPoChecked(aNextPo
, aPoInput
, sPoFileName
) )
205 bSkipCurrentPOFile
= true;
210 bInSameComp
= PoEntry::IsInSameComp(aActPo
, aNextPo
);
211 } while( bInSameComp
);
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
);
224 aActPo
.getResourceType(), aActPo
.getGroupId(),
225 aActPo
.getLocalId(), "qtz"_ostr
,
227 sExTitle
, aActPo
.getSourceFile(),
228 false, bCaseSensitive
);
232 aInputStream
>> sPoFile
;
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
;
254 sGID
= pResData
->sId
;
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
;
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
);
300 auto mit
= aMap
.find( sKey
);
301 if(mit
!= aMap
.end())
302 pMergeEntrys
= mit
->second
.get();
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
320 const OString sTemp
= OString::Concat(rInFilename
) + rGID
+ rLID
+ rTYP
;
321 pMergeEntrys
->InsertEntry(
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
);
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
);
340 return sKey
; // officecfg case sensitive identifier
341 return sKey
.toAsciiUpperCase();
344 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */