[XAudio2] avoid leak + fix voice creation for closest match
[xbmc.git] / xbmc / LangInfo.cpp
blobbc6a28614530c695d3075cdc8552bb04c68d2838
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 "LangInfo.h"
11 #include "DatabaseManager.h"
12 #include "ServiceBroker.h"
13 #include "XBDateTime.h"
14 #include "addons/AddonInstaller.h"
15 #include "addons/AddonManager.h"
16 #include "addons/LanguageResource.h"
17 #include "addons/RepositoryUpdater.h"
18 #include "addons/addoninfo/AddonType.h"
19 #include "guilib/LocalizeStrings.h"
20 #include "messaging/ApplicationMessenger.h"
21 #include "pvr/PVRManager.h"
22 #include "settings/AdvancedSettings.h"
23 #include "settings/Settings.h"
24 #include "settings/SettingsComponent.h"
25 #include "settings/lib/Setting.h"
26 #include "settings/lib/SettingDefinitions.h"
27 #include "utils/CharsetConverter.h"
28 #include "utils/LangCodeExpander.h"
29 #include "utils/StringUtils.h"
30 #include "utils/URIUtils.h"
31 #include "utils/XBMCTinyXML.h"
32 #include "utils/XMLUtils.h"
33 #include "utils/log.h"
34 #include "weather/WeatherManager.h"
36 #include <algorithm>
37 #include <stdexcept>
39 namespace
41 std::string GetDateStringWithFormat(const CDateTime& date, const std::string& format)
43 // Return the formatted date together with the format used.
44 // eg: '1/02/2003 (D/MM/YYYY)'
45 return date.GetAsLocalizedDate(format) + " (" + format + ")";
47 } // namespace
49 using namespace PVR;
51 static std::string shortDateFormats[] = {
52 // clang-format off
53 // short date formats using "/"
54 "DD/MM/YYYY",
55 "MM/DD/YYYY",
56 "YYYY/MM/DD",
57 "D/M/YYYY",
58 // short date formats using "-"
59 "DD-MM-YYYY",
60 "MM-DD-YYYY",
61 "YYYY-MM-DD",
62 "YYYY-M-D",
63 // short date formats using "."
64 "DD.MM.YYYY",
65 "DD.M.YYYY",
66 "D.M.YYYY",
67 "D. M. YYYY",
68 "YYYY.MM.DD",
69 // short date formats with abbreviated month and 2 digit year
70 "D-mmm-YY",
71 "DD-mmm-YY",
72 "D mmm YY",
73 "DD mmm YY",
74 // clang-format on
77 static std::string longDateFormats[] = {
78 "DDDD, D MMMM YYYY",
79 "DDDD, DD MMMM YYYY",
80 "DDDD, D. MMMM YYYY",
81 "DDDD, DD. MMMM YYYY",
82 "DDDD, MMMM D, YYYY",
83 "DDDD, MMMM DD, YYYY",
84 "DDDD D MMMM YYYY",
85 "DDDD DD MMMM YYYY",
86 "DDDD D. MMMM YYYY",
87 "DDDD DD. MMMM YYYY",
88 "D. MMMM YYYY",
89 "DD. MMMM YYYY",
90 "D. MMMM. YYYY",
91 "DD. MMMM. YYYY",
92 "YYYY. MMMM. D"
95 #define TIME_FORMAT_MM_SS ":mm:ss"
96 #define TIME_FORMAT_SINGLE_12 "h" TIME_FORMAT_MM_SS
97 #define TIME_FORMAT_DOUBLE_12 "hh" TIME_FORMAT_MM_SS
98 #define TIME_FORMAT_SINGLE_24 "H" TIME_FORMAT_MM_SS
99 #define TIME_FORMAT_DOUBLE_24 "HH" TIME_FORMAT_MM_SS
101 #define TIME_FORMAT_12HOURS "12hours"
102 #define TIME_FORMAT_24HOURS "24hours"
104 typedef struct TemperatureInfo {
105 CTemperature::Unit unit;
106 std::string name;
107 } TemperatureInfo;
109 static TemperatureInfo temperatureInfo[] = {
110 { CTemperature::UnitFahrenheit, "f" },
111 { CTemperature::UnitKelvin, "k" },
112 { CTemperature::UnitCelsius, "c" },
113 { CTemperature::UnitReaumur, "re" },
114 { CTemperature::UnitRankine, "ra" },
115 { CTemperature::UnitRomer, "ro" },
116 { CTemperature::UnitDelisle, "de" },
117 { CTemperature::UnitNewton, "n" }
120 #define TEMP_UNIT_STRINGS 20027
122 typedef struct SpeedInfo {
123 CSpeed::Unit unit;
124 std::string name;
125 } SpeedInfo;
127 static SpeedInfo speedInfo[] = {
128 { CSpeed::UnitKilometresPerHour, "kmh" },
129 { CSpeed::UnitMetresPerMinute, "mpmin" },
130 { CSpeed::UnitMetresPerSecond, "mps" },
131 { CSpeed::UnitFeetPerHour, "fth" },
132 { CSpeed::UnitFeetPerMinute, "ftm" },
133 { CSpeed::UnitFeetPerSecond, "fts" },
134 { CSpeed::UnitMilesPerHour, "mph" },
135 { CSpeed::UnitKnots, "kts" },
136 { CSpeed::UnitBeaufort, "beaufort" },
137 { CSpeed::UnitInchPerSecond, "inchs" },
138 { CSpeed::UnitYardPerSecond, "yards" },
139 { CSpeed::UnitFurlongPerFortnight, "fpf" }
142 #define SPEED_UNIT_STRINGS 20200
144 #define SETTING_REGIONAL_DEFAULT "regional"
146 static std::string ToTimeFormat(bool use24HourClock, bool singleHour, bool meridiem)
148 if (use24HourClock)
149 return singleHour ? TIME_FORMAT_SINGLE_24 : TIME_FORMAT_DOUBLE_24;
151 if (!meridiem)
152 return singleHour ? TIME_FORMAT_SINGLE_12 : TIME_FORMAT_DOUBLE_12;
154 return StringUtils::Format(g_localizeStrings.Get(12382), ToTimeFormat(false, singleHour, false));
157 static std::string ToSettingTimeFormat(const CDateTime& time, const std::string& timeFormat)
159 return StringUtils::Format(g_localizeStrings.Get(20036),
160 time.GetAsLocalizedTime(timeFormat, true), timeFormat);
163 static CTemperature::Unit StringToTemperatureUnit(const std::string& temperatureUnit)
165 std::string unit(temperatureUnit);
166 StringUtils::ToLower(unit);
168 for (const TemperatureInfo& info : temperatureInfo)
170 if (info.name == unit)
171 return info.unit;
174 return CTemperature::UnitCelsius;
177 static CSpeed::Unit StringToSpeedUnit(const std::string& speedUnit)
179 std::string unit(speedUnit);
180 StringUtils::ToLower(unit);
182 for (const SpeedInfo& info : speedInfo)
184 if (info.name == unit)
185 return info.unit;
188 return CSpeed::UnitKilometresPerHour;
191 struct SortLanguage
193 bool operator()(const StringSettingOption &left, const StringSettingOption &right) const
195 std::string strLeft = left.label;
196 std::string strRight = right.label;
197 StringUtils::ToLower(strLeft);
198 StringUtils::ToLower(strRight);
200 return strLeft.compare(strRight) < 0;
204 CLangInfo::CRegion::CRegion()
206 SetDefaults();
209 void CLangInfo::CRegion::SetDefaults()
211 m_strName="N/A";
212 m_strLangLocaleName = "English";
213 m_strLangLocaleCodeTwoChar = "en";
215 m_strDateFormatShort="DD/MM/YYYY";
216 m_strDateFormatLong="DDDD, D MMMM YYYY";
217 m_strTimeFormat="HH:mm:ss";
218 m_tempUnit = CTemperature::UnitCelsius;
219 m_speedUnit = CSpeed::UnitKilometresPerHour;
220 m_strTimeZone.clear();
223 void CLangInfo::CRegion::SetTemperatureUnit(const std::string& strUnit)
225 m_tempUnit = StringToTemperatureUnit(strUnit);
228 void CLangInfo::CRegion::SetSpeedUnit(const std::string& strUnit)
230 m_speedUnit = StringToSpeedUnit(strUnit);
233 void CLangInfo::CRegion::SetTimeZone(const std::string& strTimeZone)
235 m_strTimeZone = strTimeZone;
238 void CLangInfo::CRegion::SetGlobalLocale()
240 std::string strLocale;
241 if (m_strRegionLocaleName.length() > 0)
243 #ifdef TARGET_WINDOWS
244 std::string strLang, strRegion;
245 g_LangCodeExpander.ConvertToISO6391(m_strLangLocaleName, strLang);
246 g_LangCodeExpander.ConvertToISO6391(m_strRegionLocaleName, strRegion);
247 strLocale = strLang + "-" + strRegion;
248 #else
249 strLocale = m_strLangLocaleName + "_" + m_strRegionLocaleName;
250 #endif
251 #ifdef TARGET_POSIX
252 strLocale += ".UTF-8";
253 #endif
255 g_langInfo.m_originalLocale = std::locale(std::locale::classic(), new custom_numpunct(m_cDecimalSep, m_cThousandsSep, m_strGrouping));
257 CLog::Log(LOGDEBUG, "trying to set locale to {}", strLocale);
259 // We need to set the locale to only change the collate. Otherwise,
260 // decimal separator is changed depending of the current language
261 // (ie. "," in French or Dutch instead of "."). This breaks atof() and
262 // others similar functions.
263 #if !(defined(TARGET_FREEBSD) || defined(TARGET_DARWIN_OSX) || defined(__UCLIBC__))
264 // on FreeBSD, darwin and uClibc-based systems libstdc++ is compiled with
265 // "generic" locale support
266 std::locale current_locale = std::locale::classic(); // C-Locale
269 std::locale lcl = std::locale(strLocale.c_str());
270 strLocale = lcl.name();
271 current_locale = current_locale.combine< std::collate<wchar_t> >(lcl);
272 current_locale = current_locale.combine< std::ctype<wchar_t> >(lcl);
273 current_locale = current_locale.combine< std::time_get<wchar_t> >(lcl);
274 current_locale = current_locale.combine< std::time_put<wchar_t> >(lcl);
276 assert(std::use_facet< std::numpunct<char> >(current_locale).decimal_point() == '.');
278 } catch(...) {
279 current_locale = std::locale::classic();
280 strLocale = "C";
283 g_langInfo.m_systemLocale = current_locale; //! @todo move to CLangInfo class
284 g_langInfo.m_collationtype = 0;
285 std::locale::global(current_locale);
286 #endif
288 #ifndef TARGET_WINDOWS
289 if (setlocale(LC_COLLATE, strLocale.c_str()) == NULL ||
290 setlocale(LC_CTYPE, strLocale.c_str()) == NULL ||
291 setlocale(LC_TIME, strLocale.c_str()) == NULL)
293 strLocale = "C";
294 setlocale(LC_COLLATE, strLocale.c_str());
295 setlocale(LC_CTYPE, strLocale.c_str());
296 setlocale(LC_TIME, strLocale.c_str());
298 #else
299 std::wstring strLocaleW;
300 g_charsetConverter.utf8ToW(strLocale, strLocaleW);
301 if (_wsetlocale(LC_COLLATE, strLocaleW.c_str()) == NULL ||
302 _wsetlocale(LC_CTYPE, strLocaleW.c_str()) == NULL ||
303 _wsetlocale(LC_TIME, strLocaleW.c_str()) == NULL)
305 strLocale = "C";
306 strLocaleW = L"C";
307 _wsetlocale(LC_COLLATE, strLocaleW.c_str());
308 _wsetlocale(LC_CTYPE, strLocaleW.c_str());
309 _wsetlocale(LC_TIME, strLocaleW.c_str());
311 #endif
313 g_charsetConverter.resetSystemCharset();
314 CLog::Log(LOGINFO, "global locale set to {}", strLocale);
316 #ifdef TARGET_ANDROID
317 // Force UTF8 for, e.g., vsnprintf
318 setlocale(LC_ALL, "C.UTF-8");
319 #endif
322 CLangInfo::CLangInfo()
324 SetDefaults();
325 m_shortDateFormat = m_defaultRegion.m_strDateFormatShort;
326 m_longDateFormat = m_defaultRegion.m_strDateFormatLong;
327 m_timeFormat = m_defaultRegion.m_strTimeFormat;
328 m_use24HourClock = DetermineUse24HourClockFromTimeFormat(m_defaultRegion.m_strTimeFormat);
329 m_temperatureUnit = m_defaultRegion.m_tempUnit;
330 m_speedUnit = m_defaultRegion.m_speedUnit;
331 m_collationtype = 0;
334 CLangInfo::~CLangInfo() = default;
336 void CLangInfo::OnSettingChanged(const std::shared_ptr<const CSetting>& setting)
338 if (setting == NULL)
339 return;
341 auto settingsComponent = CServiceBroker::GetSettingsComponent();
342 if (!settingsComponent)
343 return;
345 auto settings = settingsComponent->GetSettings();
346 if (!settings)
347 return;
349 const std::string &settingId = setting->GetId();
350 if (settingId == CSettings::SETTING_LOCALE_AUDIOLANGUAGE)
351 SetAudioLanguage(std::static_pointer_cast<const CSettingString>(setting)->GetValue());
352 else if (settingId == CSettings::SETTING_LOCALE_SUBTITLELANGUAGE)
353 SetSubtitleLanguage(std::static_pointer_cast<const CSettingString>(setting)->GetValue());
354 else if (settingId == CSettings::SETTING_LOCALE_LANGUAGE)
356 if (!SetLanguage(std::static_pointer_cast<const CSettingString>(setting)->GetValue()))
358 auto langsetting = settings->GetSetting(CSettings::SETTING_LOCALE_LANGUAGE);
359 if (!langsetting)
361 CLog::Log(LOGERROR, "Failed to load setting for: {}", CSettings::SETTING_LOCALE_LANGUAGE);
362 return;
365 std::static_pointer_cast<CSettingString>(langsetting)->Reset();
368 else if (settingId == CSettings::SETTING_LOCALE_COUNTRY)
369 SetCurrentRegion(std::static_pointer_cast<const CSettingString>(setting)->GetValue());
370 else if (settingId == CSettings::SETTING_LOCALE_SHORTDATEFORMAT)
371 SetShortDateFormat(std::static_pointer_cast<const CSettingString>(setting)->GetValue());
372 else if (settingId == CSettings::SETTING_LOCALE_LONGDATEFORMAT)
373 SetLongDateFormat(std::static_pointer_cast<const CSettingString>(setting)->GetValue());
374 else if (settingId == CSettings::SETTING_LOCALE_TIMEFORMAT)
375 SetTimeFormat(std::static_pointer_cast<const CSettingString>(setting)->GetValue());
376 else if (settingId == CSettings::SETTING_LOCALE_USE24HOURCLOCK)
378 Set24HourClock(std::static_pointer_cast<const CSettingString>(setting)->GetValue());
380 // update the time format
381 settings->SetString(CSettings::SETTING_LOCALE_TIMEFORMAT,
382 PrepareTimeFormat(GetTimeFormat(), m_use24HourClock));
384 else if (settingId == CSettings::SETTING_LOCALE_TEMPERATUREUNIT)
385 SetTemperatureUnit(std::static_pointer_cast<const CSettingString>(setting)->GetValue());
386 else if (settingId == CSettings::SETTING_LOCALE_SPEEDUNIT)
387 SetSpeedUnit(std::static_pointer_cast<const CSettingString>(setting)->GetValue());
390 void CLangInfo::OnSettingsLoaded()
392 // set the temperature and speed units based on the settings
393 const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
394 SetShortDateFormat(settings->GetString(CSettings::SETTING_LOCALE_SHORTDATEFORMAT));
395 SetLongDateFormat(settings->GetString(CSettings::SETTING_LOCALE_LONGDATEFORMAT));
396 Set24HourClock(settings->GetString(CSettings::SETTING_LOCALE_USE24HOURCLOCK));
397 SetTimeFormat(settings->GetString(CSettings::SETTING_LOCALE_TIMEFORMAT));
398 SetTemperatureUnit(settings->GetString(CSettings::SETTING_LOCALE_TEMPERATUREUNIT));
399 SetSpeedUnit(settings->GetString(CSettings::SETTING_LOCALE_SPEEDUNIT));
402 bool CLangInfo::Load(const std::string& strLanguage)
404 SetDefaults();
406 std::string strFileName = GetLanguageInfoPath(strLanguage);
408 CXBMCTinyXML xmlDoc;
409 if (!xmlDoc.LoadFile(strFileName))
411 CLog::Log(LOGERROR, "unable to load {}: {} at line {}", strFileName, xmlDoc.ErrorDesc(),
412 xmlDoc.ErrorRow());
413 return false;
416 // get the matching language addon
417 m_languageAddon = GetLanguageAddon(strLanguage);
418 if (m_languageAddon == NULL)
420 CLog::Log(LOGERROR, "Unknown language {}", strLanguage);
421 return false;
424 // get some language-specific information from the language addon
425 m_strGuiCharSet = m_languageAddon->GetGuiCharset();
426 m_forceUnicodeFont = m_languageAddon->ForceUnicodeFont();
427 m_strSubtitleCharSet = m_languageAddon->GetSubtitleCharset();
428 m_strDVDMenuLanguage = m_languageAddon->GetDvdMenuLanguage();
429 m_strDVDAudioLanguage = m_languageAddon->GetDvdAudioLanguage();
430 m_strDVDSubtitleLanguage = m_languageAddon->GetDvdSubtitleLanguage();
431 m_sortTokens = m_languageAddon->GetSortTokens();
433 TiXmlElement* pRootElement = xmlDoc.RootElement();
434 if (pRootElement->ValueStr() != "language")
436 CLog::Log(LOGERROR, "{} Doesn't contain <language>", strFileName);
437 return false;
440 if (pRootElement->Attribute("locale"))
441 m_defaultRegion.m_strLangLocaleName = pRootElement->Attribute("locale");
443 #ifdef TARGET_WINDOWS
444 // Windows need 3 chars isolang code
445 if (m_defaultRegion.m_strLangLocaleName.length() == 2)
447 if (!g_LangCodeExpander.ConvertISO6391ToISO6392B(m_defaultRegion.m_strLangLocaleName, m_defaultRegion.m_strLangLocaleName, true))
448 m_defaultRegion.m_strLangLocaleName = "";
451 if (!g_LangCodeExpander.ConvertWindowsLanguageCodeToISO6392B(m_defaultRegion.m_strLangLocaleName, m_languageCodeGeneral))
452 m_languageCodeGeneral = "";
453 #else
454 if (m_defaultRegion.m_strLangLocaleName.length() != 3)
456 if (!g_LangCodeExpander.ConvertToISO6392B(m_defaultRegion.m_strLangLocaleName, m_languageCodeGeneral))
457 m_languageCodeGeneral = "";
459 else
460 m_languageCodeGeneral = m_defaultRegion.m_strLangLocaleName;
461 #endif
463 std::string tmp;
464 if (g_LangCodeExpander.ConvertToISO6391(m_defaultRegion.m_strLangLocaleName, tmp))
465 m_defaultRegion.m_strLangLocaleCodeTwoChar = tmp;
467 const TiXmlNode *pRegions = pRootElement->FirstChild("regions");
468 if (pRegions && !pRegions->NoChildren())
470 const TiXmlElement *pRegion=pRegions->FirstChildElement("region");
471 while (pRegion)
473 CRegion region(m_defaultRegion);
474 region.m_strName = XMLUtils::GetAttribute(pRegion, "name");
475 if (region.m_strName.empty())
476 region.m_strName=g_localizeStrings.Get(10005); // Not available
478 if (pRegion->Attribute("locale"))
479 region.m_strRegionLocaleName = pRegion->Attribute("locale");
481 #ifdef TARGET_WINDOWS
482 // Windows need 3 chars regions code
483 if (region.m_strRegionLocaleName.length() == 2)
485 if (!g_LangCodeExpander.ConvertISO31661Alpha2ToISO31661Alpha3(region.m_strRegionLocaleName, region.m_strRegionLocaleName))
486 region.m_strRegionLocaleName = "";
488 #endif
490 const TiXmlNode *pDateLong=pRegion->FirstChild("datelong");
491 if (pDateLong && !pDateLong->NoChildren())
492 region.m_strDateFormatLong=pDateLong->FirstChild()->ValueStr();
494 const TiXmlNode *pDateShort=pRegion->FirstChild("dateshort");
495 if (pDateShort && !pDateShort->NoChildren())
496 region.m_strDateFormatShort=pDateShort->FirstChild()->ValueStr();
498 const TiXmlElement *pTime=pRegion->FirstChildElement("time");
499 if (pTime && !pTime->NoChildren())
501 region.m_strTimeFormat=pTime->FirstChild()->Value();
502 region.m_strMeridiemSymbols[MeridiemSymbolAM] = XMLUtils::GetAttribute(pTime, "symbolAM");
503 region.m_strMeridiemSymbols[MeridiemSymbolPM] = XMLUtils::GetAttribute(pTime, "symbolPM");
506 const TiXmlNode *pTempUnit=pRegion->FirstChild("tempunit");
507 if (pTempUnit && !pTempUnit->NoChildren())
508 region.SetTemperatureUnit(pTempUnit->FirstChild()->ValueStr());
510 const TiXmlNode *pSpeedUnit=pRegion->FirstChild("speedunit");
511 if (pSpeedUnit && !pSpeedUnit->NoChildren())
512 region.SetSpeedUnit(pSpeedUnit->FirstChild()->ValueStr());
514 const TiXmlNode *pTimeZone=pRegion->FirstChild("timezone");
515 if (pTimeZone && !pTimeZone->NoChildren())
516 region.SetTimeZone(pTimeZone->FirstChild()->ValueStr());
518 const TiXmlElement *pThousandsSep = pRegion->FirstChildElement("thousandsseparator");
519 if (pThousandsSep)
521 if (!pThousandsSep->NoChildren())
523 region.m_cThousandsSep = pThousandsSep->FirstChild()->Value()[0];
524 if (pThousandsSep->Attribute("groupingformat"))
525 region.m_strGrouping = StringUtils::BinaryStringToString(pThousandsSep->Attribute("groupingformat"));
526 else
527 region.m_strGrouping = "\3";
530 else
532 region.m_cThousandsSep = ',';
533 region.m_strGrouping = "\3";
536 const TiXmlElement *pDecimalSep = pRegion->FirstChildElement("decimalseparator");
537 if (pDecimalSep)
539 if (!pDecimalSep->NoChildren())
540 region.m_cDecimalSep = pDecimalSep->FirstChild()->Value()[0];
542 else
543 region.m_cDecimalSep = '.';
545 m_regions.insert(PAIR_REGIONS(region.m_strName, region));
547 pRegion=pRegion->NextSiblingElement("region");
550 const std::string& strName = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_COUNTRY);
551 SetCurrentRegion(strName);
553 g_charsetConverter.reinitCharsetsFromSettings();
555 return true;
558 std::string CLangInfo::GetLanguagePath(const std::string &language)
560 if (language.empty())
561 return "";
563 std::string addonId = ADDON::CLanguageResource::GetAddonId(language);
565 std::string path = URIUtils::AddFileToFolder(GetLanguagePath(), addonId);
566 URIUtils::AddSlashAtEnd(path);
568 return path;
571 std::string CLangInfo::GetLanguageInfoPath(const std::string &language)
573 if (language.empty())
574 return "";
576 return URIUtils::AddFileToFolder(GetLanguagePath(language), "langinfo.xml");
579 bool CLangInfo::UseLocaleCollation()
581 if (m_collationtype == 0)
583 // Determine collation to use. When using MySQL/MariaDB or a platform that does not support
584 // locale language collation then use accent folding internal equivalent of utf8_general_ci
585 m_collationtype = 1;
586 if (!StringUtils::EqualsNoCase(
587 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_databaseMusic.type,
588 "mysql") &&
589 !StringUtils::EqualsNoCase(
590 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_databaseVideo.type,
591 "mysql") &&
592 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_useLocaleCollation)
594 // Check that locale collation facet is implemented on the platform
595 const std::collate<wchar_t>& coll = std::use_facet<std::collate<wchar_t>>(m_systemLocale);
596 wchar_t lc = L'z';
597 wchar_t rc = 0x00E2; // Latin small letter a with circumflex
598 int comp_result = coll.compare(&lc, &lc + 1, &rc, &rc + 1);
599 if (comp_result > 0)
600 // Latin small letter a with circumflex put before z - collation works
601 m_collationtype = 2;
604 return m_collationtype == 2;
607 void CLangInfo::LoadTokens(const TiXmlNode* pTokens, std::set<std::string>& vecTokens)
609 if (pTokens && !pTokens->NoChildren())
611 const TiXmlElement *pToken = pTokens->FirstChildElement("token");
612 while (pToken)
614 std::string strSep= " ._";
615 if (pToken->Attribute("separators"))
616 strSep = pToken->Attribute("separators");
617 if (pToken->FirstChild() && pToken->FirstChild()->Value())
619 if (strSep.empty())
620 vecTokens.insert(pToken->FirstChild()->ValueStr());
621 else
622 for (unsigned int i=0;i<strSep.size();++i)
623 vecTokens.insert(pToken->FirstChild()->ValueStr() + strSep[i]);
625 pToken = pToken->NextSiblingElement();
630 void CLangInfo::SetDefaults()
632 m_regions.clear();
634 //Reset default region
635 m_defaultRegion.SetDefaults();
637 // Set the default region, we may be unable to load langinfo.xml
638 m_currentRegion = &m_defaultRegion;
640 m_systemLocale = std::locale::classic();
642 m_forceUnicodeFont = false;
643 m_strGuiCharSet = "CP1252";
644 m_strSubtitleCharSet = "CP1252";
645 m_strDVDMenuLanguage = "en";
646 m_strDVDAudioLanguage = "en";
647 m_strDVDSubtitleLanguage = "en";
648 m_sortTokens.clear();
650 m_languageCodeGeneral = "eng";
653 std::string CLangInfo::GetGuiCharSet() const
655 std::shared_ptr<CSettingString> charsetSetting = std::static_pointer_cast<CSettingString>(CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(CSettings::SETTING_LOCALE_CHARSET));
656 if (charsetSetting == NULL || charsetSetting->IsDefault())
657 return m_strGuiCharSet;
659 return charsetSetting->GetValue();
662 std::string CLangInfo::GetSubtitleCharSet() const
664 std::shared_ptr<CSettingString> charsetSetting = std::static_pointer_cast<CSettingString>(CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(CSettings::SETTING_SUBTITLES_CHARSET));
665 if (charsetSetting->IsDefault())
666 return m_strSubtitleCharSet;
668 return charsetSetting->GetValue();
671 void CLangInfo::GetAddonsLanguageCodes(std::map<std::string, std::string>& languages)
673 ADDON::VECADDONS addons;
674 CServiceBroker::GetAddonMgr().GetAddons(addons, ADDON::AddonType::RESOURCE_LANGUAGE);
675 for (const auto& addon : addons)
677 const LanguageResourcePtr langAddon =
678 std::dynamic_pointer_cast<ADDON::CLanguageResource>(addon);
679 std::string langCode{langAddon->GetLocale().ToShortStringLC()};
680 StringUtils::Replace(langCode, '_', '-');
681 languages.emplace(langCode, addon->Name());
685 LanguageResourcePtr CLangInfo::GetLanguageAddon(const std::string& locale /* = "" */) const
687 if (locale.empty() ||
688 (m_languageAddon != NULL && (locale.compare(m_languageAddon->ID()) == 0 || m_languageAddon->GetLocale().Equals(locale))))
689 return m_languageAddon;
691 std::string addonId = ADDON::CLanguageResource::GetAddonId(locale);
692 if (addonId.empty())
693 addonId = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_LANGUAGE);
695 ADDON::AddonPtr addon;
696 if (CServiceBroker::GetAddonMgr().GetAddon(addonId, addon, ADDON::AddonType::RESOURCE_LANGUAGE,
697 ADDON::OnlyEnabled::CHOICE_YES) &&
698 addon != NULL)
699 return std::dynamic_pointer_cast<ADDON::CLanguageResource>(addon);
701 return NULL;
704 std::string CLangInfo::ConvertEnglishNameToAddonLocale(const std::string& langName)
706 ADDON::VECADDONS addons;
707 CServiceBroker::GetAddonMgr().GetAddons(addons, ADDON::AddonType::RESOURCE_LANGUAGE);
708 for (const auto& addon : addons)
710 if (StringUtils::CompareNoCase(addon->Name(), langName) == 0)
712 const LanguageResourcePtr langAddon =
713 std::dynamic_pointer_cast<ADDON::CLanguageResource>(addon);
714 std::string locale = langAddon->GetLocale().ToShortStringLC();
715 StringUtils::Replace(locale, '_', '-');
716 return locale;
719 return "";
722 std::string CLangInfo::GetEnglishLanguageName(const std::string& locale /* = "" */) const
724 LanguageResourcePtr addon = GetLanguageAddon(locale);
725 if (addon == NULL)
726 return "";
728 return addon->Name();
731 bool CLangInfo::SetLanguage(std::string language /* = "" */, bool reloadServices /* = true */)
733 if (language.empty())
734 language = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_LANGUAGE);
736 auto& addonMgr = CServiceBroker::GetAddonMgr();
737 ADDON::AddonPtr addon;
739 // Find the chosen language add-on if it's enabled
740 if (!addonMgr.GetAddon(language, addon, ADDON::AddonType::RESOURCE_LANGUAGE,
741 ADDON::OnlyEnabled::CHOICE_YES))
743 if (!addonMgr.IsAddonInstalled(language) ||
744 (addonMgr.IsAddonDisabled(language) && !addonMgr.EnableAddon(language)))
746 CLog::Log(LOGWARNING,
747 "CLangInfo::{}: could not find or enable language add-on '{}', loading default...",
748 __func__, language);
749 language = std::static_pointer_cast<const CSettingString>(
750 CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(
751 CSettings::SETTING_LOCALE_LANGUAGE))
752 ->GetDefault();
754 if (!addonMgr.GetAddon(language, addon, ADDON::AddonType::RESOURCE_LANGUAGE,
755 ADDON::OnlyEnabled::CHOICE_NO))
757 CLog::Log(LOGFATAL, "CLangInfo::{}: could not find default language add-on '{}'", __func__,
758 language);
759 return false;
764 CLog::Log(LOGINFO, "CLangInfo: loading {} language information...", language);
765 if (!Load(language))
767 CLog::LogF(LOGFATAL, "CLangInfo: failed to load {} language information", language);
768 return false;
771 CLog::Log(LOGINFO, "CLangInfo: loading {} language strings...", language);
772 if (!g_localizeStrings.Load(GetLanguagePath(), language))
774 CLog::LogF(LOGFATAL, "CLangInfo: failed to load {} language strings", language);
775 return false;
778 ADDON::VECADDONS addons;
779 if (CServiceBroker::GetAddonMgr().GetInstalledAddons(addons))
781 const std::string locale = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_LANGUAGE);
782 for (const auto& addon : addons)
784 const std::string path = URIUtils::AddFileToFolder(addon->Path(), "resources", "language/");
785 g_localizeStrings.LoadAddonStrings(path, locale, addon->ID());
789 if (reloadServices)
791 // also tell our weather and skin to reload as these are localized
792 CServiceBroker::GetWeatherManager().Refresh();
793 CServiceBroker::GetPVRManager().LocalizationChanged();
794 CServiceBroker::GetDatabaseManager().LocalizationChanged();
795 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr,
796 "ReloadSkin");
799 return true;
802 // three char language code (not win32 specific)
803 const std::string& CLangInfo::GetAudioLanguage() const
805 if (!m_audioLanguage.empty())
806 return m_audioLanguage;
808 return m_languageCodeGeneral;
811 void CLangInfo::SetAudioLanguage(const std::string& language)
813 if (language.empty()
814 || StringUtils::EqualsNoCase(language, "default")
815 || StringUtils::EqualsNoCase(language, "original")
816 || StringUtils::EqualsNoCase(language, "mediadefault")
817 || !g_LangCodeExpander.ConvertToISO6392B(language, m_audioLanguage))
818 m_audioLanguage.clear();
821 // three char language code (not win32 specific)
822 const std::string& CLangInfo::GetSubtitleLanguage() const
824 if (!m_subtitleLanguage.empty())
825 return m_subtitleLanguage;
827 return m_languageCodeGeneral;
830 void CLangInfo::SetSubtitleLanguage(const std::string& language)
832 if (language.empty()
833 || StringUtils::EqualsNoCase(language, "default")
834 || StringUtils::EqualsNoCase(language, "original")
835 || !g_LangCodeExpander.ConvertToISO6392B(language, m_subtitleLanguage))
836 m_subtitleLanguage.clear();
839 // two character codes as defined in ISO639
840 const std::string CLangInfo::GetDVDMenuLanguage() const
842 std::string code;
843 if (!g_LangCodeExpander.ConvertToISO6391(m_currentRegion->m_strLangLocaleName, code))
844 code = m_strDVDMenuLanguage;
846 return code;
849 // two character codes as defined in ISO639
850 const std::string CLangInfo::GetDVDAudioLanguage() const
852 std::string code;
853 if (!g_LangCodeExpander.ConvertToISO6391(m_audioLanguage, code))
854 code = m_strDVDAudioLanguage;
856 return code;
859 // two character codes as defined in ISO639
860 const std::string CLangInfo::GetDVDSubtitleLanguage() const
862 std::string code;
863 if (!g_LangCodeExpander.ConvertToISO6391(m_subtitleLanguage, code))
864 code = m_strDVDSubtitleLanguage;
866 return code;
869 const CLocale& CLangInfo::GetLocale() const
871 LanguageResourcePtr language = GetLanguageAddon();
872 if (language != NULL)
873 return language->GetLocale();
875 return CLocale::Empty;
878 const std::string& CLangInfo::GetRegionLocale() const
880 return m_currentRegion->m_strRegionLocaleName;
883 const std::locale& CLangInfo::GetOriginalLocale() const
885 return m_originalLocale;
888 // Returns the format string for the date of the current language
889 const std::string& CLangInfo::GetDateFormat(bool bLongDate /* = false */) const
891 if (bLongDate)
892 return GetLongDateFormat();
894 return GetShortDateFormat();
897 void CLangInfo::SetDateFormat(const std::string& dateFormat, bool bLongDate /* = false */)
899 if (bLongDate)
900 SetLongDateFormat(dateFormat);
901 else
902 SetShortDateFormat(dateFormat);
905 const std::string& CLangInfo::GetShortDateFormat() const
907 return m_shortDateFormat;
910 void CLangInfo::SetShortDateFormat(const std::string& shortDateFormat)
912 std::string newShortDateFormat = shortDateFormat;
913 if (shortDateFormat == SETTING_REGIONAL_DEFAULT)
914 newShortDateFormat = m_currentRegion->m_strDateFormatShort;
916 m_shortDateFormat = newShortDateFormat;
919 const std::string& CLangInfo::GetLongDateFormat() const
921 return m_longDateFormat;
924 void CLangInfo::SetLongDateFormat(const std::string& longDateFormat)
926 std::string newLongDateFormat = longDateFormat;
927 if (longDateFormat == SETTING_REGIONAL_DEFAULT)
928 newLongDateFormat = m_currentRegion->m_strDateFormatShort;
930 m_longDateFormat = newLongDateFormat;
933 // Returns the format string for the time of the current language
934 const std::string& CLangInfo::GetTimeFormat() const
936 return m_timeFormat;
939 void CLangInfo::SetTimeFormat(const std::string& timeFormat)
941 std::string newTimeFormat = timeFormat;
942 if (timeFormat == SETTING_REGIONAL_DEFAULT)
943 newTimeFormat = m_currentRegion->m_strTimeFormat;
945 m_timeFormat = PrepareTimeFormat(newTimeFormat, m_use24HourClock);
948 bool CLangInfo::Use24HourClock() const
950 return m_use24HourClock;
953 void CLangInfo::Set24HourClock(bool use24HourClock)
955 m_use24HourClock = use24HourClock;
958 void CLangInfo::Set24HourClock(const std::string& str24HourClock)
960 bool use24HourClock = false;
961 if (str24HourClock == TIME_FORMAT_12HOURS)
962 use24HourClock = false;
963 else if (str24HourClock == TIME_FORMAT_24HOURS)
964 use24HourClock = true;
965 else if (str24HourClock == SETTING_REGIONAL_DEFAULT)
967 Set24HourClock(m_currentRegion->m_strTimeFormat);
968 return;
970 else
971 use24HourClock = DetermineUse24HourClockFromTimeFormat(str24HourClock);
973 if (m_use24HourClock == use24HourClock)
974 return;
976 m_use24HourClock = use24HourClock;
979 const std::string& CLangInfo::GetTimeZone() const
981 return m_currentRegion->m_strTimeZone;
984 // Returns the AM/PM symbol of the current language
985 const std::string& CLangInfo::GetMeridiemSymbol(MeridiemSymbol symbol) const
987 // nothing to return if we use 24-hour clock
988 if (m_use24HourClock)
989 return StringUtils::Empty;
991 return MeridiemSymbolToString(symbol);
994 const std::string& CLangInfo::MeridiemSymbolToString(MeridiemSymbol symbol)
996 switch (symbol)
998 case MeridiemSymbolAM:
999 return g_localizeStrings.Get(378);
1001 case MeridiemSymbolPM:
1002 return g_localizeStrings.Get(379);
1004 default:
1005 break;
1008 return StringUtils::Empty;
1011 // Fills the array with the region names available for this language
1012 void CLangInfo::GetRegionNames(std::vector<std::string>& array)
1014 for (const auto &region : m_regions)
1016 std::string strName=region.first;
1017 if (strName=="N/A")
1018 strName=g_localizeStrings.Get(10005); // Not available
1019 array.emplace_back(std::move(strName));
1023 // Set the current region by its name, names from GetRegionNames() are valid.
1024 // If the region is not found the first available region is set.
1025 void CLangInfo::SetCurrentRegion(const std::string& strName)
1027 ITMAPREGIONS it=m_regions.find(strName);
1028 if (it!=m_regions.end())
1029 m_currentRegion=&it->second;
1030 else if (!m_regions.empty())
1031 m_currentRegion=&m_regions.begin()->second;
1032 else
1033 m_currentRegion=&m_defaultRegion;
1035 m_currentRegion->SetGlobalLocale();
1037 const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
1038 if (settings->GetString(CSettings::SETTING_LOCALE_SHORTDATEFORMAT) == SETTING_REGIONAL_DEFAULT)
1039 SetShortDateFormat(m_currentRegion->m_strDateFormatShort);
1040 if (settings->GetString(CSettings::SETTING_LOCALE_LONGDATEFORMAT) == SETTING_REGIONAL_DEFAULT)
1041 SetLongDateFormat(m_currentRegion->m_strDateFormatLong);
1042 if (settings->GetString(CSettings::SETTING_LOCALE_USE24HOURCLOCK) == SETTING_REGIONAL_DEFAULT)
1044 Set24HourClock(m_currentRegion->m_strTimeFormat);
1046 // update the time format
1047 SetTimeFormat(settings->GetString(CSettings::SETTING_LOCALE_TIMEFORMAT));
1049 if (settings->GetString(CSettings::SETTING_LOCALE_TIMEFORMAT) == SETTING_REGIONAL_DEFAULT)
1050 SetTimeFormat(m_currentRegion->m_strTimeFormat);
1051 if (settings->GetString(CSettings::SETTING_LOCALE_TEMPERATUREUNIT) == SETTING_REGIONAL_DEFAULT)
1052 SetTemperatureUnit(m_currentRegion->m_tempUnit);
1053 if (settings->GetString(CSettings::SETTING_LOCALE_SPEEDUNIT) == SETTING_REGIONAL_DEFAULT)
1054 SetSpeedUnit(m_currentRegion->m_speedUnit);
1057 // Returns the current region set for this language
1058 const std::string& CLangInfo::GetCurrentRegion() const
1060 return m_currentRegion->m_strName;
1063 CTemperature::Unit CLangInfo::GetTemperatureUnit() const
1065 return m_temperatureUnit;
1068 void CLangInfo::SetTemperatureUnit(CTemperature::Unit temperatureUnit)
1070 if (m_temperatureUnit == temperatureUnit)
1071 return;
1073 m_temperatureUnit = temperatureUnit;
1075 // refresh weather manager as temperatures need re-translating
1076 // NOTE: this could be called before our service manager is up
1077 if (CServiceBroker::IsServiceManagerUp())
1078 CServiceBroker::GetWeatherManager().Refresh();
1081 void CLangInfo::SetTemperatureUnit(const std::string& temperatureUnit)
1083 CTemperature::Unit unit = CTemperature::UnitCelsius;
1084 if (temperatureUnit == SETTING_REGIONAL_DEFAULT)
1085 unit = m_currentRegion->m_tempUnit;
1086 else
1087 unit = StringToTemperatureUnit(temperatureUnit);
1089 SetTemperatureUnit(unit);
1092 std::string CLangInfo::GetTemperatureAsString(const CTemperature& temperature) const
1094 if (!temperature.IsValid())
1095 return g_localizeStrings.Get(13205); // "Unknown"
1097 CTemperature::Unit temperatureUnit = GetTemperatureUnit();
1098 return StringUtils::Format("{}{}", temperature.ToString(temperatureUnit),
1099 GetTemperatureUnitString());
1102 // Returns the temperature unit string for the current language
1103 const std::string& CLangInfo::GetTemperatureUnitString() const
1105 return GetTemperatureUnitString(m_temperatureUnit);
1108 const std::string& CLangInfo::GetTemperatureUnitString(CTemperature::Unit temperatureUnit)
1110 return g_localizeStrings.Get(TEMP_UNIT_STRINGS + temperatureUnit);
1113 void CLangInfo::SetSpeedUnit(CSpeed::Unit speedUnit)
1115 if (m_speedUnit == speedUnit)
1116 return;
1118 m_speedUnit = speedUnit;
1120 // refresh weather manager as speeds need re-translating
1121 // NOTE: this could be called before our service manager is up
1122 if (CServiceBroker::IsServiceManagerUp())
1123 CServiceBroker::GetWeatherManager().Refresh();
1126 void CLangInfo::SetSpeedUnit(const std::string& speedUnit)
1128 CSpeed::Unit unit = CSpeed::UnitKilometresPerHour;
1129 if (speedUnit == SETTING_REGIONAL_DEFAULT)
1130 unit = m_currentRegion->m_speedUnit;
1131 else
1132 unit = StringToSpeedUnit(speedUnit);
1134 SetSpeedUnit(unit);
1137 CSpeed::Unit CLangInfo::GetSpeedUnit() const
1139 return m_speedUnit;
1142 std::string CLangInfo::GetSpeedAsString(const CSpeed& speed) const
1144 if (!speed.IsValid())
1145 return g_localizeStrings.Get(13205); // "Unknown"
1147 return StringUtils::Format("{}{}", speed.ToString(GetSpeedUnit()), GetSpeedUnitString());
1150 // Returns the speed unit string for the current language
1151 const std::string& CLangInfo::GetSpeedUnitString() const
1153 return GetSpeedUnitString(m_speedUnit);
1156 const std::string& CLangInfo::GetSpeedUnitString(CSpeed::Unit speedUnit)
1158 return g_localizeStrings.Get(SPEED_UNIT_STRINGS + speedUnit);
1161 std::set<std::string> CLangInfo::GetSortTokens() const
1163 std::set<std::string> sortTokens = m_sortTokens;
1164 for (const auto& t : CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_vecTokens)
1165 sortTokens.insert(t);
1167 return sortTokens;
1170 bool CLangInfo::DetermineUse24HourClockFromTimeFormat(const std::string& timeFormat)
1172 // if the time format contains a "h" it's 12-hour and otherwise 24-hour clock format
1173 return timeFormat.find('h') == std::string::npos;
1176 bool CLangInfo::DetermineUseMeridiemFromTimeFormat(const std::string& timeFormat)
1178 // if the time format contains "xx" it's using meridiem
1179 return timeFormat.find("xx") != std::string::npos;
1182 std::string CLangInfo::PrepareTimeFormat(const std::string& timeFormat, bool use24HourClock)
1184 std::string preparedTimeFormat = timeFormat;
1185 if (use24HourClock)
1187 // replace all "h" with "H"
1188 StringUtils::Replace(preparedTimeFormat, 'h', 'H');
1190 // remove any "xx" for meridiem
1191 StringUtils::Replace(preparedTimeFormat, "x", "");
1193 else
1194 // replace all "H" with "h"
1195 StringUtils::Replace(preparedTimeFormat, 'H', 'h');
1197 StringUtils::Trim(preparedTimeFormat);
1199 return preparedTimeFormat;
1202 void CLangInfo::SettingOptionsLanguageNamesFiller(const SettingConstPtr& setting,
1203 std::vector<StringSettingOption>& list,
1204 std::string& current,
1205 void* data)
1207 // find languages...
1208 ADDON::VECADDONS addons;
1209 if (!CServiceBroker::GetAddonMgr().GetAddons(addons, ADDON::AddonType::RESOURCE_LANGUAGE))
1210 return;
1212 for (const auto &addon : addons)
1213 list.emplace_back(addon->Name(), addon->Name());
1215 sort(list.begin(), list.end(), SortLanguage());
1218 void CLangInfo::SettingOptionsISO6391LanguagesFiller(const SettingConstPtr& setting,
1219 std::vector<StringSettingOption>& list,
1220 std::string& current,
1221 void* data)
1223 std::vector<std::string> languages = g_LangCodeExpander.GetLanguageNames(
1224 CLangCodeExpander::ISO_639_1, CLangCodeExpander::LANG_LIST::INCLUDE_USERDEFINED);
1226 for (const auto &language : languages)
1227 list.emplace_back(language, language);
1230 void CLangInfo::SettingOptionsAudioStreamLanguagesFiller(const SettingConstPtr& setting,
1231 std::vector<StringSettingOption>& list,
1232 std::string& current,
1233 void* data)
1235 list.emplace_back(g_localizeStrings.Get(307), "mediadefault");
1236 list.emplace_back(g_localizeStrings.Get(308), "original");
1237 list.emplace_back(g_localizeStrings.Get(309), "default");
1239 AddLanguages(list);
1242 void CLangInfo::SettingOptionsSubtitleStreamLanguagesFiller(const SettingConstPtr& setting,
1243 std::vector<StringSettingOption>& list,
1244 std::string& current,
1245 void* data)
1247 list.emplace_back(g_localizeStrings.Get(231), "none");
1248 list.emplace_back(g_localizeStrings.Get(13207), "forced_only");
1249 list.emplace_back(g_localizeStrings.Get(308), "original");
1250 list.emplace_back(g_localizeStrings.Get(309), "default");
1252 AddLanguages(list);
1255 void CLangInfo::SettingOptionsSubtitleDownloadlanguagesFiller(
1256 const SettingConstPtr& setting,
1257 std::vector<StringSettingOption>& list,
1258 std::string& current,
1259 void* data)
1261 list.emplace_back(g_localizeStrings.Get(308), "original");
1262 list.emplace_back(g_localizeStrings.Get(309), "default");
1264 AddLanguages(list);
1267 void CLangInfo::SettingOptionsRegionsFiller(const SettingConstPtr& setting,
1268 std::vector<StringSettingOption>& list,
1269 std::string& current,
1270 void* data)
1272 std::vector<std::string> regions;
1273 g_langInfo.GetRegionNames(regions);
1274 std::sort(regions.begin(), regions.end(), sortstringbyname());
1276 bool match = false;
1277 for (unsigned int i = 0; i < regions.size(); ++i)
1279 std::string region = regions[i];
1280 list.emplace_back(region, region);
1282 if (!match && region == std::static_pointer_cast<const CSettingString>(setting)->GetValue())
1284 match = true;
1285 current = region;
1289 if (!match && !regions.empty())
1290 current = regions[0];
1293 void CLangInfo::SettingOptionsShortDateFormatsFiller(const SettingConstPtr& setting,
1294 std::vector<StringSettingOption>& list,
1295 std::string& current,
1296 void* data)
1298 bool match = false;
1299 const std::string& shortDateFormatSetting = std::static_pointer_cast<const CSettingString>(setting)->GetValue();
1301 CDateTime now = CDateTime::GetCurrentDateTime();
1303 list.emplace_back(StringUtils::Format(g_localizeStrings.Get(20035),
1304 GetDateStringWithFormat(
1305 now, g_langInfo.m_currentRegion->m_strDateFormatShort)),
1306 SETTING_REGIONAL_DEFAULT);
1308 if (shortDateFormatSetting == SETTING_REGIONAL_DEFAULT)
1310 match = true;
1311 current = SETTING_REGIONAL_DEFAULT;
1314 for (const std::string& shortDateFormat : shortDateFormats)
1316 list.emplace_back(GetDateStringWithFormat(now, shortDateFormat), shortDateFormat);
1318 if (!match && shortDateFormatSetting == shortDateFormat)
1320 match = true;
1321 current = shortDateFormat;
1325 if (!match && !list.empty())
1326 current = list[0].value;
1329 void CLangInfo::SettingOptionsLongDateFormatsFiller(const SettingConstPtr& setting,
1330 std::vector<StringSettingOption>& list,
1331 std::string& current,
1332 void* data)
1334 bool match = false;
1335 const std::string& longDateFormatSetting = std::static_pointer_cast<const CSettingString>(setting)->GetValue();
1337 CDateTime now = CDateTime::GetCurrentDateTime();
1339 list.emplace_back(StringUtils::Format(g_localizeStrings.Get(20035),
1340 GetDateStringWithFormat(
1341 now, g_langInfo.m_currentRegion->m_strDateFormatLong)),
1342 SETTING_REGIONAL_DEFAULT);
1344 if (longDateFormatSetting == SETTING_REGIONAL_DEFAULT)
1346 match = true;
1347 current = SETTING_REGIONAL_DEFAULT;
1350 for (const std::string& longDateFormat : longDateFormats)
1352 list.emplace_back(GetDateStringWithFormat(now, longDateFormat), longDateFormat);
1354 if (!match && longDateFormatSetting == longDateFormat)
1356 match = true;
1357 current = longDateFormat;
1361 if (!match && !list.empty())
1362 current = list[0].value;
1365 void CLangInfo::SettingOptionsTimeFormatsFiller(const SettingConstPtr& setting,
1366 std::vector<StringSettingOption>& list,
1367 std::string& current,
1368 void* data)
1370 bool match = false;
1371 const std::string& timeFormatSetting = std::static_pointer_cast<const CSettingString>(setting)->GetValue();
1373 CDateTime now = CDateTime::GetCurrentDateTime();
1374 bool use24hourFormat = g_langInfo.Use24HourClock();
1376 list.emplace_back(
1377 StringUtils::Format(g_localizeStrings.Get(20035),
1378 ToSettingTimeFormat(now, g_langInfo.m_currentRegion->m_strTimeFormat)),
1379 SETTING_REGIONAL_DEFAULT);
1380 if (timeFormatSetting == SETTING_REGIONAL_DEFAULT)
1382 match = true;
1383 current = SETTING_REGIONAL_DEFAULT;
1386 if (use24hourFormat)
1388 list.emplace_back(ToSettingTimeFormat(now, TIME_FORMAT_SINGLE_24), TIME_FORMAT_SINGLE_24);
1389 if (timeFormatSetting == TIME_FORMAT_SINGLE_24)
1391 current = TIME_FORMAT_SINGLE_24;
1392 match = true;
1395 list.emplace_back(ToSettingTimeFormat(now, TIME_FORMAT_DOUBLE_24), TIME_FORMAT_DOUBLE_24);
1396 if (timeFormatSetting == TIME_FORMAT_DOUBLE_24)
1398 current = TIME_FORMAT_DOUBLE_24;
1399 match = true;
1402 else
1404 list.emplace_back(ToSettingTimeFormat(now, TIME_FORMAT_SINGLE_12), TIME_FORMAT_SINGLE_12);
1405 if (timeFormatSetting == TIME_FORMAT_SINGLE_12)
1407 current = TIME_FORMAT_SINGLE_12;
1408 match = true;
1411 list.emplace_back(ToSettingTimeFormat(now, TIME_FORMAT_DOUBLE_12), TIME_FORMAT_DOUBLE_12);
1412 if (timeFormatSetting == TIME_FORMAT_DOUBLE_12)
1414 current = TIME_FORMAT_DOUBLE_12;
1415 match = true;
1418 std::string timeFormatSingle12Meridiem = ToTimeFormat(false, true, true);
1419 list.emplace_back(ToSettingTimeFormat(now, timeFormatSingle12Meridiem), timeFormatSingle12Meridiem);
1420 if (timeFormatSetting == timeFormatSingle12Meridiem)
1422 current = timeFormatSingle12Meridiem;
1423 match = true;
1426 std::string timeFormatDouble12Meridiem = ToTimeFormat(false, false, true);
1427 list.emplace_back(ToSettingTimeFormat(now, timeFormatDouble12Meridiem), timeFormatDouble12Meridiem);
1428 if (timeFormatSetting == timeFormatDouble12Meridiem)
1430 current = timeFormatDouble12Meridiem;
1431 match = true;
1435 if (!match && !list.empty())
1436 current = list[0].value;
1439 void CLangInfo::SettingOptions24HourClockFormatsFiller(const SettingConstPtr& setting,
1440 std::vector<StringSettingOption>& list,
1441 std::string& current,
1442 void* data)
1444 bool match = false;
1445 const std::string& clock24HourFormatSetting = std::static_pointer_cast<const CSettingString>(setting)->GetValue();
1447 // determine the 24-hour clock format of the regional setting
1448 int regionalClock24HourFormatLabel = DetermineUse24HourClockFromTimeFormat(g_langInfo.m_currentRegion->m_strTimeFormat) ? 12384 : 12383;
1449 list.emplace_back(StringUtils::Format(g_localizeStrings.Get(20035),
1450 g_localizeStrings.Get(regionalClock24HourFormatLabel)),
1451 SETTING_REGIONAL_DEFAULT);
1452 if (clock24HourFormatSetting == SETTING_REGIONAL_DEFAULT)
1454 match = true;
1455 current = SETTING_REGIONAL_DEFAULT;
1458 list.emplace_back(g_localizeStrings.Get(12383), TIME_FORMAT_12HOURS);
1459 if (clock24HourFormatSetting == TIME_FORMAT_12HOURS)
1461 current = TIME_FORMAT_12HOURS;
1462 match = true;
1465 list.emplace_back(g_localizeStrings.Get(12384), TIME_FORMAT_24HOURS);
1466 if (clock24HourFormatSetting == TIME_FORMAT_24HOURS)
1468 current = TIME_FORMAT_24HOURS;
1469 match = true;
1472 if (!match && !list.empty())
1473 current = list[0].value;
1476 void CLangInfo::SettingOptionsTemperatureUnitsFiller(const SettingConstPtr& setting,
1477 std::vector<StringSettingOption>& list,
1478 std::string& current,
1479 void* data)
1481 bool match = false;
1482 const std::string& temperatureUnitSetting = std::static_pointer_cast<const CSettingString>(setting)->GetValue();
1484 list.emplace_back(
1485 StringUtils::Format(g_localizeStrings.Get(20035),
1486 GetTemperatureUnitString(g_langInfo.m_currentRegion->m_tempUnit)),
1487 SETTING_REGIONAL_DEFAULT);
1488 if (temperatureUnitSetting == SETTING_REGIONAL_DEFAULT)
1490 match = true;
1491 current = SETTING_REGIONAL_DEFAULT;
1494 for (const TemperatureInfo& info : temperatureInfo)
1496 list.emplace_back(GetTemperatureUnitString(info.unit), info.name);
1498 if (!match && temperatureUnitSetting == info.name)
1500 match = true;
1501 current = info.name;
1505 if (!match && !list.empty())
1506 current = list[0].value;
1509 void CLangInfo::SettingOptionsSpeedUnitsFiller(const SettingConstPtr& setting,
1510 std::vector<StringSettingOption>& list,
1511 std::string& current,
1512 void* data)
1514 bool match = false;
1515 const std::string& speedUnitSetting = std::static_pointer_cast<const CSettingString>(setting)->GetValue();
1517 list.emplace_back(
1518 StringUtils::Format(g_localizeStrings.Get(20035),
1519 GetSpeedUnitString(g_langInfo.m_currentRegion->m_speedUnit)),
1520 SETTING_REGIONAL_DEFAULT);
1521 if (speedUnitSetting == SETTING_REGIONAL_DEFAULT)
1523 match = true;
1524 current = SETTING_REGIONAL_DEFAULT;
1527 for (const SpeedInfo& info : speedInfo)
1529 list.emplace_back(GetSpeedUnitString(info.unit), info.name);
1531 if (!match && speedUnitSetting == info.name)
1533 match = true;
1534 current = info.name;
1538 if (!match && !list.empty())
1539 current = list[0].value;
1542 void CLangInfo::AddLanguages(std::vector<StringSettingOption> &list)
1544 std::vector<std::string> languages = g_LangCodeExpander.GetLanguageNames(
1545 CLangCodeExpander::ISO_639_1, CLangCodeExpander::LANG_LIST::INCLUDE_ADDONS_USERDEFINED);
1547 for (const auto& language : languages)
1548 list.emplace_back(language, language);