[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / guilib / LocalizeStrings.cpp
blob659eb3d7c59ab12756b39b06830726516be32756
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "LocalizeStrings.h"
11 #include "addons/LanguageResource.h"
12 #include "filesystem/Directory.h"
13 #include "filesystem/SpecialProtocol.h"
14 #include "threads/SharedSection.h"
15 #include "utils/CharsetConverter.h"
16 #include "utils/POUtils.h"
17 #include "utils/StringUtils.h"
18 #include "utils/URIUtils.h"
19 #include "utils/log.h"
21 #include <mutex>
22 #include <shared_mutex>
24 /*! \brief Tries to load ids and strings from a strings.po file to the `strings` map.
25 * It should only be called from the LoadStr2Mem function to have a fallback.
26 \param pathname The directory name, where we look for the strings file.
27 \param strings [out] The resulting strings map.
28 \param encoding Encoding of the strings. For PO files we only use utf-8.
29 \param offset An offset value to place strings from the id value.
30 \param bSourceLanguage If we are loading the source English strings.po.
31 \return false if no strings.po file was loaded.
33 static bool LoadPO(const std::string &filename, std::map<uint32_t, LocStr>& strings,
34 std::string &encoding, uint32_t offset = 0 , bool bSourceLanguage = false)
36 CPODocument PODoc;
37 if (!PODoc.LoadFile(filename))
38 return false;
40 int counter = 0;
42 while ((PODoc.GetNextEntry()))
44 uint32_t id;
45 if (PODoc.GetEntryType() == ID_FOUND)
47 bool bStrInMem = strings.find((id = PODoc.GetEntryID()) + offset) != strings.end();
48 PODoc.ParseEntry(bSourceLanguage);
50 if (bSourceLanguage && !PODoc.GetMsgid().empty())
52 if (bStrInMem && (strings[id + offset].strOriginal.empty() ||
53 PODoc.GetMsgid() == strings[id + offset].strOriginal))
54 continue;
55 else if (bStrInMem)
56 CLog::Log(
57 LOGDEBUG,
58 "POParser: id:{} was recently re-used in the English string file, which is not yet "
59 "changed in the translated file. Using the English string instead",
60 id);
61 strings[id + offset].strTranslated = PODoc.GetMsgid();
62 counter++;
64 else if (!bSourceLanguage && !bStrInMem && !PODoc.GetMsgstr().empty())
66 strings[id + offset].strTranslated = PODoc.GetMsgstr();
67 strings[id + offset].strOriginal = PODoc.GetMsgid();
68 counter++;
71 else if (PODoc.GetEntryType() == MSGID_FOUND)
73 //! @todo implement reading of non-id based string entries from the PO files.
74 //! These entries would go into a separate memory map, using hash codes for fast look-up.
75 //! With this memory map we can implement using gettext(), ngettext(), pgettext() calls,
76 //! so that we don't have to use new IDs for new strings. Even we can start converting
77 //! the ID based calls to normal gettext calls.
79 else if (PODoc.GetEntryType() == MSGID_PLURAL_FOUND)
81 //! @todo implement reading of non-id based pluralized string entries from the PO files.
82 //! We can store the pluralforms for each language, in the langinfo.xml files.
86 CLog::Log(LOGDEBUG, "LocalizeStrings: loaded {} strings from file {}", counter, filename);
87 return true;
90 /*! \brief Loads language ids and strings to memory map `strings`.
91 \param pathname The directory name, where we look for the strings file.
92 \param language We load the strings for this language. Fallback language is always English.
93 \param strings [out] The resulting strings map.
94 \param encoding Encoding of the strings. For PO files we only use utf-8.
95 \param offset An offset value to place strings from the id value.
96 \return false if no strings.po file was loaded.
98 static bool LoadStr2Mem(const std::string &pathname_in, const std::string &language,
99 std::map<uint32_t, LocStr>& strings, std::string &encoding, uint32_t offset = 0 )
101 std::string pathname = CSpecialProtocol::TranslatePathConvertCase(pathname_in + language);
102 if (!XFILE::CDirectory::Exists(pathname))
104 bool exists = false;
105 std::string lang;
106 // check if there's a language addon using the old language naming convention
107 if (ADDON::CLanguageResource::FindLegacyLanguage(language, lang))
109 pathname = CSpecialProtocol::TranslatePathConvertCase(pathname_in + lang);
110 exists = XFILE::CDirectory::Exists(pathname);
113 if (!exists)
114 return false;
117 bool useSourceLang = StringUtils::EqualsNoCase(language, LANGUAGE_DEFAULT) || StringUtils::EqualsNoCase(language, LANGUAGE_OLD_DEFAULT);
119 return LoadPO(URIUtils::AddFileToFolder(pathname, "strings.po"), strings, encoding, offset, useSourceLang);
122 static bool LoadWithFallback(const std::string& path, const std::string& language, std::map<uint32_t, LocStr>& strings)
124 std::string encoding;
125 if (!LoadStr2Mem(path, language, strings, encoding))
127 if (StringUtils::EqualsNoCase(language, LANGUAGE_DEFAULT)) // no fallback, nothing to do
128 return false;
131 // load the fallback
132 if (!StringUtils::EqualsNoCase(language, LANGUAGE_DEFAULT))
133 LoadStr2Mem(path, LANGUAGE_DEFAULT, strings, encoding);
135 return true;
138 CLocalizeStrings::CLocalizeStrings(void) = default;
140 CLocalizeStrings::~CLocalizeStrings(void) = default;
142 void CLocalizeStrings::ClearSkinStrings()
144 // clear the skin strings
145 std::unique_lock<CSharedSection> lock(m_stringsMutex);
146 Clear(31000, 31999);
149 bool CLocalizeStrings::LoadSkinStrings(const std::string& path, const std::string& language)
151 //! @todo shouldn't hold lock while loading file
152 std::unique_lock<CSharedSection> lock(m_stringsMutex);
153 ClearSkinStrings();
154 // load the skin strings in.
155 return LoadWithFallback(path, language, m_strings);
158 bool CLocalizeStrings::Load(const std::string& strPathName, const std::string& strLanguage)
160 std::map<uint32_t, LocStr> strings;
161 if (!LoadWithFallback(strPathName, strLanguage, strings))
162 return false;
164 // fill in the constant strings
165 strings[20022].strTranslated = "";
166 strings[20027].strTranslated = "°F";
167 strings[20028].strTranslated = "K";
168 strings[20029].strTranslated = "°C";
169 strings[20030].strTranslated = "°Ré";
170 strings[20031].strTranslated = "°Ra";
171 strings[20032].strTranslated = "°Rø";
172 strings[20033].strTranslated = "°De";
173 strings[20034].strTranslated = "°N";
175 strings[20200].strTranslated = "km/h";
176 strings[20201].strTranslated = "m/min";
177 strings[20202].strTranslated = "m/s";
178 strings[20203].strTranslated = "ft/h";
179 strings[20204].strTranslated = "ft/min";
180 strings[20205].strTranslated = "ft/s";
181 strings[20206].strTranslated = "mph";
182 strings[20207].strTranslated = "kts";
183 strings[20208].strTranslated = "Beaufort";
184 strings[20209].strTranslated = "inch/s";
185 strings[20210].strTranslated = "yard/s";
186 strings[20211].strTranslated = "Furlong/Fortnight";
188 std::unique_lock<CSharedSection> lock(m_stringsMutex);
189 Clear();
190 m_strings = std::move(strings);
191 return true;
194 const std::string& CLocalizeStrings::Get(uint32_t dwCode) const
196 std::shared_lock<CSharedSection> lock(m_stringsMutex);
197 ciStrings i = m_strings.find(dwCode);
198 if (i == m_strings.end())
200 return StringUtils::Empty;
202 return i->second.strTranslated;
205 void CLocalizeStrings::Clear()
207 std::unique_lock<CSharedSection> lock(m_stringsMutex);
208 m_strings.clear();
211 void CLocalizeStrings::Clear(uint32_t start, uint32_t end)
213 std::unique_lock<CSharedSection> lock(m_stringsMutex);
214 iStrings it = m_strings.begin();
215 while (it != m_strings.end())
217 if (it->first >= start && it->first <= end)
218 m_strings.erase(it++);
219 else
220 ++it;
224 bool CLocalizeStrings::LoadAddonStrings(const std::string& path, const std::string& language, const std::string& addonId)
226 std::map<uint32_t, LocStr> strings;
227 if (!LoadWithFallback(path, language, strings))
228 return false;
230 std::unique_lock<CSharedSection> lock(m_addonStringsMutex);
231 auto it = m_addonStrings.find(addonId);
232 if (it != m_addonStrings.end())
233 m_addonStrings.erase(it);
235 return m_addonStrings.emplace(std::string(addonId), std::move(strings)).second;
238 std::string CLocalizeStrings::GetAddonString(const std::string& addonId, uint32_t code)
240 std::shared_lock<CSharedSection> lock(m_addonStringsMutex);
241 auto i = m_addonStrings.find(addonId);
242 if (i == m_addonStrings.end())
243 return StringUtils::Empty;
245 auto j = i->second.find(code);
246 if (j == i->second.end())
247 return StringUtils::Empty;
249 return j->second.strTranslated;