summaryrefslogtreecommitdiffstats
path: root/xbmc/utils/Locale.cpp
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2020-10-19 00:52:24 +0200
committermanuel <manuel@mausz.at>2020-10-19 00:52:24 +0200
commitbe933ef2241d79558f91796cc5b3a161f72ebf9c (patch)
treefe3ab2f130e20c99001f2d7a81d610c78c96a3f4 /xbmc/utils/Locale.cpp
parent5f8335c1e49ce108ef3481863833c98efa00411b (diff)
downloadkodi-pvr-build-be933ef2241d79558f91796cc5b3a161f72ebf9c.tar.gz
kodi-pvr-build-be933ef2241d79558f91796cc5b3a161f72ebf9c.tar.bz2
kodi-pvr-build-be933ef2241d79558f91796cc5b3a161f72ebf9c.zip
sync with upstream
Diffstat (limited to 'xbmc/utils/Locale.cpp')
-rw-r--r--xbmc/utils/Locale.cpp284
1 files changed, 284 insertions, 0 deletions
diff --git a/xbmc/utils/Locale.cpp b/xbmc/utils/Locale.cpp
new file mode 100644
index 0000000..0a2d692
--- /dev/null
+++ b/xbmc/utils/Locale.cpp
@@ -0,0 +1,284 @@
1/*
2 * Copyright (C) 2015-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9#include "Locale.h"
10
11#include "utils/StringUtils.h"
12
13const CLocale CLocale::Empty;
14
15CLocale::CLocale()
16 : m_language(),
17 m_territory(),
18 m_codeset(),
19 m_modifier()
20{ }
21
22CLocale::CLocale(const std::string& language)
23 : m_language(),
24 m_territory(),
25 m_codeset(),
26 m_modifier()
27{
28 m_valid = ParseLocale(language, m_language, m_territory, m_codeset, m_modifier);
29}
30
31CLocale::CLocale(const std::string& language, const std::string& territory)
32 : m_language(language),
33 m_territory(territory),
34 m_codeset(),
35 m_modifier()
36{
37 Initialize();
38}
39
40CLocale::CLocale(const std::string& language, const std::string& territory, const std::string& codeset)
41 : m_language(language),
42 m_territory(territory),
43 m_codeset(codeset),
44 m_modifier()
45{
46 Initialize();
47}
48
49CLocale::CLocale(const std::string& language, const std::string& territory, const std::string& codeset, const std::string& modifier)
50 : m_language(language),
51 m_territory(territory),
52 m_codeset(codeset),
53 m_modifier(modifier)
54{
55 Initialize();
56}
57
58CLocale::~CLocale() = default;
59
60CLocale CLocale::FromString(const std::string& locale)
61{
62 return CLocale(locale);
63}
64
65bool CLocale::operator==(const CLocale& other) const
66{
67 if (!m_valid && !other.m_valid)
68 return true;
69
70 return m_valid == other.m_valid &&
71 StringUtils::EqualsNoCase(m_language, other.m_language) &&
72 StringUtils::EqualsNoCase(m_territory, other.m_territory) &&
73 StringUtils::EqualsNoCase(m_codeset, other.m_codeset) &&
74 StringUtils::EqualsNoCase(m_modifier, other.m_modifier);
75}
76
77std::string CLocale::ToString() const
78{
79 if (!m_valid)
80 return "";
81
82 std::string locale = ToShortString();
83
84 if (!m_codeset.empty())
85 locale += "." + m_codeset;
86
87 if (!m_modifier.empty())
88 locale += "@" + m_modifier;
89
90 return locale;
91}
92
93std::string CLocale::ToStringLC() const
94{
95 if (!m_valid)
96 return "";
97
98 std::string locale = ToString();
99 StringUtils::ToLower(locale);
100
101 return locale;
102}
103
104std::string CLocale::ToShortString() const
105{
106 if (!m_valid)
107 return "";
108
109 std::string locale = m_language;
110
111 if (!m_territory.empty())
112 locale += "_" + m_territory;
113
114 return locale;
115}
116
117std::string CLocale::ToShortStringLC() const
118{
119 if (!m_valid)
120 return "";
121
122 std::string locale = ToShortString();
123 StringUtils::ToLower(locale);
124
125 return locale;
126}
127
128bool CLocale::Equals(const std::string& locale) const
129{
130 CLocale other = FromString(locale);
131
132 return *this == other;
133}
134
135bool CLocale::Matches(const std::string& locale) const
136{
137 CLocale other = FromString(locale);
138
139 if (!m_valid && !other.m_valid)
140 return true;
141 if (!m_valid || !other.m_valid)
142 return false;
143
144 if (!StringUtils::EqualsNoCase(m_language, other.m_language))
145 return false;
146 if (!m_territory.empty() && !other.m_territory.empty() && !StringUtils::EqualsNoCase(m_territory, other.m_territory))
147 return false;
148 if (!m_codeset.empty() && !other.m_codeset.empty() && !StringUtils::EqualsNoCase(m_codeset, other.m_codeset))
149 return false;
150 if (!m_modifier.empty() && !other.m_modifier.empty() && !StringUtils::EqualsNoCase(m_modifier, other.m_modifier))
151 return false;
152
153 return true;
154}
155
156std::string CLocale::FindBestMatch(const std::set<std::string>& locales) const
157{
158 std::string bestMatch = "";
159 int bestMatchRank = -1;
160
161 for (auto const& locale : locales)
162 {
163 // check if there is an exact match
164 if (Equals(locale))
165 return locale;
166
167 int matchRank = GetMatchRank(locale);
168 if (matchRank > bestMatchRank)
169 {
170 bestMatchRank = matchRank;
171 bestMatch = locale;
172 }
173 }
174
175 return bestMatch;
176}
177
178std::string CLocale::FindBestMatch(const std::unordered_map<std::string, std::string>& locales) const
179{
180 std::string bestMatch = "";
181 int bestMatchRank = -1;
182
183 for (auto const& locale : locales)
184 {
185 // check if there is an exact match
186 if (Equals(locale.first))
187 return locale.first;
188
189 int matchRank = GetMatchRank(locale.first);
190 if (matchRank > bestMatchRank)
191 {
192 bestMatchRank = matchRank;
193 bestMatch = locale.first;
194 }
195 }
196
197 return bestMatch;
198}
199
200bool CLocale::CheckValidity(const std::string& language, const std::string& territory, const std::string& codeset, const std::string& modifier)
201{
202 static_cast<void>(territory);
203 static_cast<void>(codeset);
204 static_cast<void>(modifier);
205
206 return !language.empty();
207}
208
209bool CLocale::ParseLocale(const std::string &locale, std::string &language, std::string &territory, std::string &codeset, std::string &modifier)
210{
211 if (locale.empty())
212 return false;
213
214 language.clear();
215 territory.clear();
216 codeset.clear();
217 modifier.clear();
218
219 // the format for a locale is [language[_territory][.codeset][@modifier]]
220 std::string tmp = locale;
221
222 // look for the modifier after @
223 size_t pos = tmp.find("@");
224 if (pos != std::string::npos)
225 {
226 modifier = tmp.substr(pos + 1);
227 tmp = tmp.substr(0, pos);
228 }
229
230 // look for the codeset after .
231 pos = tmp.find(".");
232 if (pos != std::string::npos)
233 {
234 codeset = tmp.substr(pos + 1);
235 tmp = tmp.substr(0, pos);
236 }
237
238 // look for the codeset after _
239 pos = tmp.find("_");
240 if (pos != std::string::npos)
241 {
242 territory = tmp.substr(pos + 1);
243 StringUtils::ToUpper(territory);
244 tmp = tmp.substr(0, pos);
245 }
246
247 // what remains is the language
248 language = tmp;
249 StringUtils::ToLower(language);
250
251 return CheckValidity(language, territory, codeset, modifier);
252}
253
254void CLocale::Initialize()
255{
256 m_valid = CheckValidity(m_language, m_territory, m_codeset, m_modifier);
257 if (m_valid)
258 {
259 StringUtils::ToLower(m_language);
260 StringUtils::ToUpper(m_territory);
261 }
262}
263
264int CLocale::GetMatchRank(const std::string& locale) const
265{
266 CLocale other = FromString(locale);
267
268 // both locales must be valid and match in language
269 if (!m_valid || !other.m_valid ||
270 !StringUtils::EqualsNoCase(m_language, other.m_language))
271 return -1;
272
273 int rank = 0;
274 // matching in territory is considered more important than matching in
275 // codeset and/or modifier
276 if (!m_territory.empty() && !other.m_territory.empty() && StringUtils::EqualsNoCase(m_territory, other.m_territory))
277 rank += 3;
278 if (!m_codeset.empty() && !other.m_codeset.empty() && StringUtils::EqualsNoCase(m_codeset, other.m_codeset))
279 rank += 1;
280 if (!m_modifier.empty() && !other.m_modifier.empty() && StringUtils::EqualsNoCase(m_modifier, other.m_modifier))
281 rank += 1;
282
283 return rank;
284}