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.
11 #include "ServiceBroker.h"
12 #include "XBDateTime.h"
13 #include "addons/AddonInstaller.h"
14 #include "addons/AddonManager.h"
15 #include "addons/LanguageResource.h"
16 #include "addons/RepositoryUpdater.h"
17 #include "addons/addoninfo/AddonType.h"
18 #include "guilib/LocalizeStrings.h"
19 #include "messaging/ApplicationMessenger.h"
20 #include "pvr/PVRManager.h"
21 #include "settings/AdvancedSettings.h"
22 #include "settings/Settings.h"
23 #include "settings/SettingsComponent.h"
24 #include "settings/lib/Setting.h"
25 #include "settings/lib/SettingDefinitions.h"
26 #include "utils/CharsetConverter.h"
27 #include "utils/LangCodeExpander.h"
28 #include "utils/StringUtils.h"
29 #include "utils/URIUtils.h"
30 #include "utils/XBMCTinyXML.h"
31 #include "utils/XMLUtils.h"
32 #include "utils/log.h"
33 #include "weather/WeatherManager.h"
40 static std::string shortDateFormats
[] = {
41 // short date formats using "/"
46 // short date formats using "-"
51 // short date formats using "."
59 static std::string longDateFormats
[] = {
63 "DDDD, DD. MMMM YYYY",
65 "DDDD, MMMM DD, YYYY",
77 #define TIME_FORMAT_MM_SS ":mm:ss"
78 #define TIME_FORMAT_SINGLE_12 "h" TIME_FORMAT_MM_SS
79 #define TIME_FORMAT_DOUBLE_12 "hh" TIME_FORMAT_MM_SS
80 #define TIME_FORMAT_SINGLE_24 "H" TIME_FORMAT_MM_SS
81 #define TIME_FORMAT_DOUBLE_24 "HH" TIME_FORMAT_MM_SS
83 #define TIME_FORMAT_12HOURS "12hours"
84 #define TIME_FORMAT_24HOURS "24hours"
86 typedef struct TemperatureInfo
{
87 CTemperature::Unit unit
;
91 static TemperatureInfo temperatureInfo
[] = {
92 { CTemperature::UnitFahrenheit
, "f" },
93 { CTemperature::UnitKelvin
, "k" },
94 { CTemperature::UnitCelsius
, "c" },
95 { CTemperature::UnitReaumur
, "re" },
96 { CTemperature::UnitRankine
, "ra" },
97 { CTemperature::UnitRomer
, "ro" },
98 { CTemperature::UnitDelisle
, "de" },
99 { CTemperature::UnitNewton
, "n" }
102 #define TEMP_UNIT_STRINGS 20027
104 typedef struct SpeedInfo
{
109 static SpeedInfo speedInfo
[] = {
110 { CSpeed::UnitKilometresPerHour
, "kmh" },
111 { CSpeed::UnitMetresPerMinute
, "mpmin" },
112 { CSpeed::UnitMetresPerSecond
, "mps" },
113 { CSpeed::UnitFeetPerHour
, "fth" },
114 { CSpeed::UnitFeetPerMinute
, "ftm" },
115 { CSpeed::UnitFeetPerSecond
, "fts" },
116 { CSpeed::UnitMilesPerHour
, "mph" },
117 { CSpeed::UnitKnots
, "kts" },
118 { CSpeed::UnitBeaufort
, "beaufort" },
119 { CSpeed::UnitInchPerSecond
, "inchs" },
120 { CSpeed::UnitYardPerSecond
, "yards" },
121 { CSpeed::UnitFurlongPerFortnight
, "fpf" }
124 #define SPEED_UNIT_STRINGS 20200
126 #define SETTING_REGIONAL_DEFAULT "regional"
128 static std::string
ToTimeFormat(bool use24HourClock
, bool singleHour
, bool meridiem
)
131 return singleHour
? TIME_FORMAT_SINGLE_24
: TIME_FORMAT_DOUBLE_24
;
134 return singleHour
? TIME_FORMAT_SINGLE_12
: TIME_FORMAT_DOUBLE_12
;
136 return StringUtils::Format(g_localizeStrings
.Get(12382), ToTimeFormat(false, singleHour
, false));
139 static std::string
ToSettingTimeFormat(const CDateTime
& time
, const std::string
& timeFormat
)
141 return StringUtils::Format(g_localizeStrings
.Get(20036),
142 time
.GetAsLocalizedTime(timeFormat
, true), timeFormat
);
145 static CTemperature::Unit
StringToTemperatureUnit(const std::string
& temperatureUnit
)
147 std::string
unit(temperatureUnit
);
148 StringUtils::ToLower(unit
);
150 for (const TemperatureInfo
& info
: temperatureInfo
)
152 if (info
.name
== unit
)
156 return CTemperature::UnitCelsius
;
159 static CSpeed::Unit
StringToSpeedUnit(const std::string
& speedUnit
)
161 std::string
unit(speedUnit
);
162 StringUtils::ToLower(unit
);
164 for (const SpeedInfo
& info
: speedInfo
)
166 if (info
.name
== unit
)
170 return CSpeed::UnitKilometresPerHour
;
175 bool operator()(const StringSettingOption
&left
, const StringSettingOption
&right
) const
177 std::string strLeft
= left
.label
;
178 std::string strRight
= right
.label
;
179 StringUtils::ToLower(strLeft
);
180 StringUtils::ToLower(strRight
);
182 return strLeft
.compare(strRight
) < 0;
186 CLangInfo::CRegion::CRegion()
191 void CLangInfo::CRegion::SetDefaults()
194 m_strLangLocaleName
= "English";
195 m_strLangLocaleCodeTwoChar
= "en";
197 m_strDateFormatShort
="DD/MM/YYYY";
198 m_strDateFormatLong
="DDDD, D MMMM YYYY";
199 m_strTimeFormat
="HH:mm:ss";
200 m_tempUnit
= CTemperature::UnitCelsius
;
201 m_speedUnit
= CSpeed::UnitKilometresPerHour
;
202 m_strTimeZone
.clear();
205 void CLangInfo::CRegion::SetTemperatureUnit(const std::string
& strUnit
)
207 m_tempUnit
= StringToTemperatureUnit(strUnit
);
210 void CLangInfo::CRegion::SetSpeedUnit(const std::string
& strUnit
)
212 m_speedUnit
= StringToSpeedUnit(strUnit
);
215 void CLangInfo::CRegion::SetTimeZone(const std::string
& strTimeZone
)
217 m_strTimeZone
= strTimeZone
;
220 void CLangInfo::CRegion::SetGlobalLocale()
222 std::string strLocale
;
223 if (m_strRegionLocaleName
.length() > 0)
225 #ifdef TARGET_WINDOWS
226 std::string strLang
, strRegion
;
227 g_LangCodeExpander
.ConvertToISO6391(m_strLangLocaleName
, strLang
);
228 g_LangCodeExpander
.ConvertToISO6391(m_strRegionLocaleName
, strRegion
);
229 strLocale
= strLang
+ "-" + strRegion
;
231 strLocale
= m_strLangLocaleName
+ "_" + m_strRegionLocaleName
;
234 strLocale
+= ".UTF-8";
237 g_langInfo
.m_originalLocale
= std::locale(std::locale::classic(), new custom_numpunct(m_cDecimalSep
, m_cThousandsSep
, m_strGrouping
));
239 CLog::Log(LOGDEBUG
, "trying to set locale to {}", strLocale
);
241 // We need to set the locale to only change the collate. Otherwise,
242 // decimal separator is changed depending of the current language
243 // (ie. "," in French or Dutch instead of "."). This breaks atof() and
244 // others similar functions.
245 #if !(defined(TARGET_FREEBSD) || defined(TARGET_DARWIN_OSX) || defined(__UCLIBC__))
246 // on FreeBSD, darwin and uClibc-based systems libstdc++ is compiled with
247 // "generic" locale support
248 std::locale current_locale
= std::locale::classic(); // C-Locale
251 std::locale lcl
= std::locale(strLocale
.c_str());
252 strLocale
= lcl
.name();
253 current_locale
= current_locale
.combine
< std::collate
<wchar_t> >(lcl
);
254 current_locale
= current_locale
.combine
< std::ctype
<wchar_t> >(lcl
);
255 current_locale
= current_locale
.combine
< std::time_get
<wchar_t> >(lcl
);
256 current_locale
= current_locale
.combine
< std::time_put
<wchar_t> >(lcl
);
258 assert(std::use_facet
< std::numpunct
<char> >(current_locale
).decimal_point() == '.');
261 current_locale
= std::locale::classic();
265 g_langInfo
.m_systemLocale
= current_locale
; //! @todo move to CLangInfo class
266 g_langInfo
.m_collationtype
= 0;
267 std::locale::global(current_locale
);
270 #ifndef TARGET_WINDOWS
271 if (setlocale(LC_COLLATE
, strLocale
.c_str()) == NULL
||
272 setlocale(LC_CTYPE
, strLocale
.c_str()) == NULL
||
273 setlocale(LC_TIME
, strLocale
.c_str()) == NULL
)
276 setlocale(LC_COLLATE
, strLocale
.c_str());
277 setlocale(LC_CTYPE
, strLocale
.c_str());
278 setlocale(LC_TIME
, strLocale
.c_str());
281 std::wstring strLocaleW
;
282 g_charsetConverter
.utf8ToW(strLocale
, strLocaleW
);
283 if (_wsetlocale(LC_COLLATE
, strLocaleW
.c_str()) == NULL
||
284 _wsetlocale(LC_CTYPE
, strLocaleW
.c_str()) == NULL
||
285 _wsetlocale(LC_TIME
, strLocaleW
.c_str()) == NULL
)
289 _wsetlocale(LC_COLLATE
, strLocaleW
.c_str());
290 _wsetlocale(LC_CTYPE
, strLocaleW
.c_str());
291 _wsetlocale(LC_TIME
, strLocaleW
.c_str());
295 g_charsetConverter
.resetSystemCharset();
296 CLog::Log(LOGINFO
, "global locale set to {}", strLocale
);
298 #ifdef TARGET_ANDROID
299 // Force UTF8 for, e.g., vsnprintf
300 setlocale(LC_ALL
, "C.UTF-8");
304 CLangInfo::CLangInfo()
307 m_shortDateFormat
= m_defaultRegion
.m_strDateFormatShort
;
308 m_longDateFormat
= m_defaultRegion
.m_strDateFormatLong
;
309 m_timeFormat
= m_defaultRegion
.m_strTimeFormat
;
310 m_use24HourClock
= DetermineUse24HourClockFromTimeFormat(m_defaultRegion
.m_strTimeFormat
);
311 m_temperatureUnit
= m_defaultRegion
.m_tempUnit
;
312 m_speedUnit
= m_defaultRegion
.m_speedUnit
;
316 CLangInfo::~CLangInfo() = default;
318 void CLangInfo::OnSettingChanged(const std::shared_ptr
<const CSetting
>& setting
)
323 auto settingsComponent
= CServiceBroker::GetSettingsComponent();
324 if (!settingsComponent
)
327 auto settings
= settingsComponent
->GetSettings();
331 const std::string
&settingId
= setting
->GetId();
332 if (settingId
== CSettings::SETTING_LOCALE_AUDIOLANGUAGE
)
333 SetAudioLanguage(std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue());
334 else if (settingId
== CSettings::SETTING_LOCALE_SUBTITLELANGUAGE
)
335 SetSubtitleLanguage(std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue());
336 else if (settingId
== CSettings::SETTING_LOCALE_LANGUAGE
)
338 if (!SetLanguage(std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue()))
340 auto langsetting
= settings
->GetSetting(CSettings::SETTING_LOCALE_LANGUAGE
);
343 CLog::Log(LOGERROR
, "Failed to load setting for: {}", CSettings::SETTING_LOCALE_LANGUAGE
);
347 std::static_pointer_cast
<CSettingString
>(langsetting
)->Reset();
350 else if (settingId
== CSettings::SETTING_LOCALE_COUNTRY
)
351 SetCurrentRegion(std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue());
352 else if (settingId
== CSettings::SETTING_LOCALE_SHORTDATEFORMAT
)
353 SetShortDateFormat(std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue());
354 else if (settingId
== CSettings::SETTING_LOCALE_LONGDATEFORMAT
)
355 SetLongDateFormat(std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue());
356 else if (settingId
== CSettings::SETTING_LOCALE_TIMEFORMAT
)
357 SetTimeFormat(std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue());
358 else if (settingId
== CSettings::SETTING_LOCALE_USE24HOURCLOCK
)
360 Set24HourClock(std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue());
362 // update the time format
363 settings
->SetString(CSettings::SETTING_LOCALE_TIMEFORMAT
,
364 PrepareTimeFormat(GetTimeFormat(), m_use24HourClock
));
366 else if (settingId
== CSettings::SETTING_LOCALE_TEMPERATUREUNIT
)
367 SetTemperatureUnit(std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue());
368 else if (settingId
== CSettings::SETTING_LOCALE_SPEEDUNIT
)
369 SetSpeedUnit(std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue());
372 void CLangInfo::OnSettingsLoaded()
374 // set the temperature and speed units based on the settings
375 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
376 SetShortDateFormat(settings
->GetString(CSettings::SETTING_LOCALE_SHORTDATEFORMAT
));
377 SetLongDateFormat(settings
->GetString(CSettings::SETTING_LOCALE_LONGDATEFORMAT
));
378 Set24HourClock(settings
->GetString(CSettings::SETTING_LOCALE_USE24HOURCLOCK
));
379 SetTimeFormat(settings
->GetString(CSettings::SETTING_LOCALE_TIMEFORMAT
));
380 SetTemperatureUnit(settings
->GetString(CSettings::SETTING_LOCALE_TEMPERATUREUNIT
));
381 SetSpeedUnit(settings
->GetString(CSettings::SETTING_LOCALE_SPEEDUNIT
));
384 bool CLangInfo::Load(const std::string
& strLanguage
)
388 std::string strFileName
= GetLanguageInfoPath(strLanguage
);
391 if (!xmlDoc
.LoadFile(strFileName
))
393 CLog::Log(LOGERROR
, "unable to load {}: {} at line {}", strFileName
, xmlDoc
.ErrorDesc(),
398 // get the matching language addon
399 m_languageAddon
= GetLanguageAddon(strLanguage
);
400 if (m_languageAddon
== NULL
)
402 CLog::Log(LOGERROR
, "Unknown language {}", strLanguage
);
406 // get some language-specific information from the language addon
407 m_strGuiCharSet
= m_languageAddon
->GetGuiCharset();
408 m_forceUnicodeFont
= m_languageAddon
->ForceUnicodeFont();
409 m_strSubtitleCharSet
= m_languageAddon
->GetSubtitleCharset();
410 m_strDVDMenuLanguage
= m_languageAddon
->GetDvdMenuLanguage();
411 m_strDVDAudioLanguage
= m_languageAddon
->GetDvdAudioLanguage();
412 m_strDVDSubtitleLanguage
= m_languageAddon
->GetDvdSubtitleLanguage();
413 m_sortTokens
= m_languageAddon
->GetSortTokens();
415 TiXmlElement
* pRootElement
= xmlDoc
.RootElement();
416 if (pRootElement
->ValueStr() != "language")
418 CLog::Log(LOGERROR
, "{} Doesn't contain <language>", strFileName
);
422 if (pRootElement
->Attribute("locale"))
423 m_defaultRegion
.m_strLangLocaleName
= pRootElement
->Attribute("locale");
425 #ifdef TARGET_WINDOWS
426 // Windows need 3 chars isolang code
427 if (m_defaultRegion
.m_strLangLocaleName
.length() == 2)
429 if (!g_LangCodeExpander
.ConvertISO6391ToISO6392B(m_defaultRegion
.m_strLangLocaleName
, m_defaultRegion
.m_strLangLocaleName
, true))
430 m_defaultRegion
.m_strLangLocaleName
= "";
433 if (!g_LangCodeExpander
.ConvertWindowsLanguageCodeToISO6392B(m_defaultRegion
.m_strLangLocaleName
, m_languageCodeGeneral
))
434 m_languageCodeGeneral
= "";
436 if (m_defaultRegion
.m_strLangLocaleName
.length() != 3)
438 if (!g_LangCodeExpander
.ConvertToISO6392B(m_defaultRegion
.m_strLangLocaleName
, m_languageCodeGeneral
))
439 m_languageCodeGeneral
= "";
442 m_languageCodeGeneral
= m_defaultRegion
.m_strLangLocaleName
;
446 if (g_LangCodeExpander
.ConvertToISO6391(m_defaultRegion
.m_strLangLocaleName
, tmp
))
447 m_defaultRegion
.m_strLangLocaleCodeTwoChar
= tmp
;
449 const TiXmlNode
*pRegions
= pRootElement
->FirstChild("regions");
450 if (pRegions
&& !pRegions
->NoChildren())
452 const TiXmlElement
*pRegion
=pRegions
->FirstChildElement("region");
455 CRegion
region(m_defaultRegion
);
456 region
.m_strName
= XMLUtils::GetAttribute(pRegion
, "name");
457 if (region
.m_strName
.empty())
458 region
.m_strName
=g_localizeStrings
.Get(10005); // Not available
460 if (pRegion
->Attribute("locale"))
461 region
.m_strRegionLocaleName
= pRegion
->Attribute("locale");
463 #ifdef TARGET_WINDOWS
464 // Windows need 3 chars regions code
465 if (region
.m_strRegionLocaleName
.length() == 2)
467 if (!g_LangCodeExpander
.ConvertISO31661Alpha2ToISO31661Alpha3(region
.m_strRegionLocaleName
, region
.m_strRegionLocaleName
))
468 region
.m_strRegionLocaleName
= "";
472 const TiXmlNode
*pDateLong
=pRegion
->FirstChild("datelong");
473 if (pDateLong
&& !pDateLong
->NoChildren())
474 region
.m_strDateFormatLong
=pDateLong
->FirstChild()->ValueStr();
476 const TiXmlNode
*pDateShort
=pRegion
->FirstChild("dateshort");
477 if (pDateShort
&& !pDateShort
->NoChildren())
478 region
.m_strDateFormatShort
=pDateShort
->FirstChild()->ValueStr();
480 const TiXmlElement
*pTime
=pRegion
->FirstChildElement("time");
481 if (pTime
&& !pTime
->NoChildren())
483 region
.m_strTimeFormat
=pTime
->FirstChild()->Value();
484 region
.m_strMeridiemSymbols
[MeridiemSymbolAM
] = XMLUtils::GetAttribute(pTime
, "symbolAM");
485 region
.m_strMeridiemSymbols
[MeridiemSymbolPM
] = XMLUtils::GetAttribute(pTime
, "symbolPM");
488 const TiXmlNode
*pTempUnit
=pRegion
->FirstChild("tempunit");
489 if (pTempUnit
&& !pTempUnit
->NoChildren())
490 region
.SetTemperatureUnit(pTempUnit
->FirstChild()->ValueStr());
492 const TiXmlNode
*pSpeedUnit
=pRegion
->FirstChild("speedunit");
493 if (pSpeedUnit
&& !pSpeedUnit
->NoChildren())
494 region
.SetSpeedUnit(pSpeedUnit
->FirstChild()->ValueStr());
496 const TiXmlNode
*pTimeZone
=pRegion
->FirstChild("timezone");
497 if (pTimeZone
&& !pTimeZone
->NoChildren())
498 region
.SetTimeZone(pTimeZone
->FirstChild()->ValueStr());
500 const TiXmlElement
*pThousandsSep
= pRegion
->FirstChildElement("thousandsseparator");
503 if (!pThousandsSep
->NoChildren())
505 region
.m_cThousandsSep
= pThousandsSep
->FirstChild()->Value()[0];
506 if (pThousandsSep
->Attribute("groupingformat"))
507 region
.m_strGrouping
= StringUtils::BinaryStringToString(pThousandsSep
->Attribute("groupingformat"));
509 region
.m_strGrouping
= "\3";
514 region
.m_cThousandsSep
= ',';
515 region
.m_strGrouping
= "\3";
518 const TiXmlElement
*pDecimalSep
= pRegion
->FirstChildElement("decimalseparator");
521 if (!pDecimalSep
->NoChildren())
522 region
.m_cDecimalSep
= pDecimalSep
->FirstChild()->Value()[0];
525 region
.m_cDecimalSep
= '.';
527 m_regions
.insert(PAIR_REGIONS(region
.m_strName
, region
));
529 pRegion
=pRegion
->NextSiblingElement("region");
532 const std::string
& strName
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_COUNTRY
);
533 SetCurrentRegion(strName
);
535 g_charsetConverter
.reinitCharsetsFromSettings();
540 std::string
CLangInfo::GetLanguagePath(const std::string
&language
)
542 if (language
.empty())
545 std::string addonId
= ADDON::CLanguageResource::GetAddonId(language
);
547 std::string path
= URIUtils::AddFileToFolder(GetLanguagePath(), addonId
);
548 URIUtils::AddSlashAtEnd(path
);
553 std::string
CLangInfo::GetLanguageInfoPath(const std::string
&language
)
555 if (language
.empty())
558 return URIUtils::AddFileToFolder(GetLanguagePath(language
), "langinfo.xml");
561 bool CLangInfo::UseLocaleCollation()
563 if (m_collationtype
== 0)
565 // Determine collation to use. When using MySQL/MariaDB or a platform that does not support
566 // locale language collation then use accent folding internal equivalent of utf8_general_ci
568 if (!StringUtils::EqualsNoCase(
569 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_databaseMusic
.type
,
571 !StringUtils::EqualsNoCase(
572 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_databaseVideo
.type
,
574 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_useLocaleCollation
)
576 // Check that locale collation facet is implemented on the platform
577 const std::collate
<wchar_t>& coll
= std::use_facet
<std::collate
<wchar_t>>(m_systemLocale
);
579 wchar_t rc
= 0x00E2; // Latin small letter a with circumflex
580 int comp_result
= coll
.compare(&lc
, &lc
+ 1, &rc
, &rc
+ 1);
582 // Latin small letter a with circumflex put before z - collation works
586 return m_collationtype
== 2;
589 void CLangInfo::LoadTokens(const TiXmlNode
* pTokens
, std::set
<std::string
>& vecTokens
)
591 if (pTokens
&& !pTokens
->NoChildren())
593 const TiXmlElement
*pToken
= pTokens
->FirstChildElement("token");
596 std::string strSep
= " ._";
597 if (pToken
->Attribute("separators"))
598 strSep
= pToken
->Attribute("separators");
599 if (pToken
->FirstChild() && pToken
->FirstChild()->Value())
602 vecTokens
.insert(pToken
->FirstChild()->ValueStr());
604 for (unsigned int i
=0;i
<strSep
.size();++i
)
605 vecTokens
.insert(pToken
->FirstChild()->ValueStr() + strSep
[i
]);
607 pToken
= pToken
->NextSiblingElement();
612 void CLangInfo::SetDefaults()
616 //Reset default region
617 m_defaultRegion
.SetDefaults();
619 // Set the default region, we may be unable to load langinfo.xml
620 m_currentRegion
= &m_defaultRegion
;
622 m_systemLocale
= std::locale::classic();
624 m_forceUnicodeFont
= false;
625 m_strGuiCharSet
= "CP1252";
626 m_strSubtitleCharSet
= "CP1252";
627 m_strDVDMenuLanguage
= "en";
628 m_strDVDAudioLanguage
= "en";
629 m_strDVDSubtitleLanguage
= "en";
630 m_sortTokens
.clear();
632 m_languageCodeGeneral
= "eng";
635 std::string
CLangInfo::GetGuiCharSet() const
637 std::shared_ptr
<CSettingString
> charsetSetting
= std::static_pointer_cast
<CSettingString
>(CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(CSettings::SETTING_LOCALE_CHARSET
));
638 if (charsetSetting
== NULL
|| charsetSetting
->IsDefault())
639 return m_strGuiCharSet
;
641 return charsetSetting
->GetValue();
644 std::string
CLangInfo::GetSubtitleCharSet() const
646 std::shared_ptr
<CSettingString
> charsetSetting
= std::static_pointer_cast
<CSettingString
>(CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(CSettings::SETTING_SUBTITLES_CHARSET
));
647 if (charsetSetting
->IsDefault())
648 return m_strSubtitleCharSet
;
650 return charsetSetting
->GetValue();
653 void CLangInfo::GetAddonsLanguageCodes(std::map
<std::string
, std::string
>& languages
)
655 ADDON::VECADDONS addons
;
656 CServiceBroker::GetAddonMgr().GetAddons(addons
, ADDON::AddonType::RESOURCE_LANGUAGE
);
657 for (const auto& addon
: addons
)
659 const LanguageResourcePtr langAddon
=
660 std::dynamic_pointer_cast
<ADDON::CLanguageResource
>(addon
);
661 std::string langCode
{langAddon
->GetLocale().ToShortStringLC()};
662 StringUtils::Replace(langCode
, '_', '-');
663 languages
.emplace(langCode
, addon
->Name());
667 LanguageResourcePtr
CLangInfo::GetLanguageAddon(const std::string
& locale
/* = "" */) const
669 if (locale
.empty() ||
670 (m_languageAddon
!= NULL
&& (locale
.compare(m_languageAddon
->ID()) == 0 || m_languageAddon
->GetLocale().Equals(locale
))))
671 return m_languageAddon
;
673 std::string addonId
= ADDON::CLanguageResource::GetAddonId(locale
);
675 addonId
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_LANGUAGE
);
677 ADDON::AddonPtr addon
;
678 if (CServiceBroker::GetAddonMgr().GetAddon(addonId
, addon
, ADDON::AddonType::RESOURCE_LANGUAGE
,
679 ADDON::OnlyEnabled::CHOICE_YES
) &&
681 return std::dynamic_pointer_cast
<ADDON::CLanguageResource
>(addon
);
686 std::string
CLangInfo::ConvertEnglishNameToAddonLocale(const std::string
& langName
)
688 ADDON::VECADDONS addons
;
689 CServiceBroker::GetAddonMgr().GetAddons(addons
, ADDON::AddonType::RESOURCE_LANGUAGE
);
690 for (const auto& addon
: addons
)
692 if (StringUtils::CompareNoCase(addon
->Name(), langName
) == 0)
694 const LanguageResourcePtr langAddon
=
695 std::dynamic_pointer_cast
<ADDON::CLanguageResource
>(addon
);
696 std::string locale
= langAddon
->GetLocale().ToShortStringLC();
697 StringUtils::Replace(locale
, '_', '-');
704 std::string
CLangInfo::GetEnglishLanguageName(const std::string
& locale
/* = "" */) const
706 LanguageResourcePtr addon
= GetLanguageAddon(locale
);
710 return addon
->Name();
713 bool CLangInfo::SetLanguage(std::string language
/* = "" */, bool reloadServices
/* = true */)
715 if (language
.empty())
716 language
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_LANGUAGE
);
718 auto& addonMgr
= CServiceBroker::GetAddonMgr();
719 ADDON::AddonPtr addon
;
721 // Find the chosen language add-on if it's enabled
722 if (!addonMgr
.GetAddon(language
, addon
, ADDON::AddonType::RESOURCE_LANGUAGE
,
723 ADDON::OnlyEnabled::CHOICE_YES
))
725 if (!addonMgr
.IsAddonInstalled(language
) ||
726 (addonMgr
.IsAddonDisabled(language
) && !addonMgr
.EnableAddon(language
)))
728 CLog::Log(LOGWARNING
,
729 "CLangInfo::{}: could not find or enable language add-on '{}', loading default...",
731 language
= std::static_pointer_cast
<const CSettingString
>(
732 CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(
733 CSettings::SETTING_LOCALE_LANGUAGE
))
736 if (!addonMgr
.GetAddon(language
, addon
, ADDON::AddonType::RESOURCE_LANGUAGE
,
737 ADDON::OnlyEnabled::CHOICE_NO
))
739 CLog::Log(LOGFATAL
, "CLangInfo::{}: could not find default language add-on '{}'", __func__
,
746 CLog::Log(LOGINFO
, "CLangInfo: loading {} language information...", language
);
749 CLog::LogF(LOGFATAL
, "CLangInfo: failed to load {} language information", language
);
753 CLog::Log(LOGINFO
, "CLangInfo: loading {} language strings...", language
);
754 if (!g_localizeStrings
.Load(GetLanguagePath(), language
))
756 CLog::LogF(LOGFATAL
, "CLangInfo: failed to load {} language strings", language
);
760 ADDON::VECADDONS addons
;
761 if (CServiceBroker::GetAddonMgr().GetInstalledAddons(addons
))
763 const std::string locale
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_LANGUAGE
);
764 for (const auto& addon
: addons
)
766 const std::string path
= URIUtils::AddFileToFolder(addon
->Path(), "resources", "language/");
767 g_localizeStrings
.LoadAddonStrings(path
, locale
, addon
->ID());
773 // also tell our weather and skin to reload as these are localized
774 CServiceBroker::GetWeatherManager().Refresh();
775 CServiceBroker::GetPVRManager().LocalizationChanged();
776 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_EXECUTE_BUILT_IN
, -1, -1, nullptr,
783 // three char language code (not win32 specific)
784 const std::string
& CLangInfo::GetAudioLanguage() const
786 if (!m_audioLanguage
.empty())
787 return m_audioLanguage
;
789 return m_languageCodeGeneral
;
792 void CLangInfo::SetAudioLanguage(const std::string
& language
)
795 || StringUtils::EqualsNoCase(language
, "default")
796 || StringUtils::EqualsNoCase(language
, "original")
797 || StringUtils::EqualsNoCase(language
, "mediadefault")
798 || !g_LangCodeExpander
.ConvertToISO6392B(language
, m_audioLanguage
))
799 m_audioLanguage
.clear();
802 // three char language code (not win32 specific)
803 const std::string
& CLangInfo::GetSubtitleLanguage() const
805 if (!m_subtitleLanguage
.empty())
806 return m_subtitleLanguage
;
808 return m_languageCodeGeneral
;
811 void CLangInfo::SetSubtitleLanguage(const std::string
& language
)
814 || StringUtils::EqualsNoCase(language
, "default")
815 || StringUtils::EqualsNoCase(language
, "original")
816 || !g_LangCodeExpander
.ConvertToISO6392B(language
, m_subtitleLanguage
))
817 m_subtitleLanguage
.clear();
820 // two character codes as defined in ISO639
821 const std::string
CLangInfo::GetDVDMenuLanguage() const
824 if (!g_LangCodeExpander
.ConvertToISO6391(m_currentRegion
->m_strLangLocaleName
, code
))
825 code
= m_strDVDMenuLanguage
;
830 // two character codes as defined in ISO639
831 const std::string
CLangInfo::GetDVDAudioLanguage() const
834 if (!g_LangCodeExpander
.ConvertToISO6391(m_audioLanguage
, code
))
835 code
= m_strDVDAudioLanguage
;
840 // two character codes as defined in ISO639
841 const std::string
CLangInfo::GetDVDSubtitleLanguage() const
844 if (!g_LangCodeExpander
.ConvertToISO6391(m_subtitleLanguage
, code
))
845 code
= m_strDVDSubtitleLanguage
;
850 const CLocale
& CLangInfo::GetLocale() const
852 LanguageResourcePtr language
= GetLanguageAddon();
853 if (language
!= NULL
)
854 return language
->GetLocale();
856 return CLocale::Empty
;
859 const std::string
& CLangInfo::GetRegionLocale() const
861 return m_currentRegion
->m_strRegionLocaleName
;
864 const std::locale
& CLangInfo::GetOriginalLocale() const
866 return m_originalLocale
;
869 // Returns the format string for the date of the current language
870 const std::string
& CLangInfo::GetDateFormat(bool bLongDate
/* = false */) const
873 return GetLongDateFormat();
875 return GetShortDateFormat();
878 void CLangInfo::SetDateFormat(const std::string
& dateFormat
, bool bLongDate
/* = false */)
881 SetLongDateFormat(dateFormat
);
883 SetShortDateFormat(dateFormat
);
886 const std::string
& CLangInfo::GetShortDateFormat() const
888 return m_shortDateFormat
;
891 void CLangInfo::SetShortDateFormat(const std::string
& shortDateFormat
)
893 std::string newShortDateFormat
= shortDateFormat
;
894 if (shortDateFormat
== SETTING_REGIONAL_DEFAULT
)
895 newShortDateFormat
= m_currentRegion
->m_strDateFormatShort
;
897 m_shortDateFormat
= newShortDateFormat
;
900 const std::string
& CLangInfo::GetLongDateFormat() const
902 return m_longDateFormat
;
905 void CLangInfo::SetLongDateFormat(const std::string
& longDateFormat
)
907 std::string newLongDateFormat
= longDateFormat
;
908 if (longDateFormat
== SETTING_REGIONAL_DEFAULT
)
909 newLongDateFormat
= m_currentRegion
->m_strDateFormatShort
;
911 m_longDateFormat
= newLongDateFormat
;
914 // Returns the format string for the time of the current language
915 const std::string
& CLangInfo::GetTimeFormat() const
920 void CLangInfo::SetTimeFormat(const std::string
& timeFormat
)
922 std::string newTimeFormat
= timeFormat
;
923 if (timeFormat
== SETTING_REGIONAL_DEFAULT
)
924 newTimeFormat
= m_currentRegion
->m_strTimeFormat
;
926 m_timeFormat
= PrepareTimeFormat(newTimeFormat
, m_use24HourClock
);
929 bool CLangInfo::Use24HourClock() const
931 return m_use24HourClock
;
934 void CLangInfo::Set24HourClock(bool use24HourClock
)
936 m_use24HourClock
= use24HourClock
;
939 void CLangInfo::Set24HourClock(const std::string
& str24HourClock
)
941 bool use24HourClock
= false;
942 if (str24HourClock
== TIME_FORMAT_12HOURS
)
943 use24HourClock
= false;
944 else if (str24HourClock
== TIME_FORMAT_24HOURS
)
945 use24HourClock
= true;
946 else if (str24HourClock
== SETTING_REGIONAL_DEFAULT
)
948 Set24HourClock(m_currentRegion
->m_strTimeFormat
);
952 use24HourClock
= DetermineUse24HourClockFromTimeFormat(str24HourClock
);
954 if (m_use24HourClock
== use24HourClock
)
957 m_use24HourClock
= use24HourClock
;
960 const std::string
& CLangInfo::GetTimeZone() const
962 return m_currentRegion
->m_strTimeZone
;
965 // Returns the AM/PM symbol of the current language
966 const std::string
& CLangInfo::GetMeridiemSymbol(MeridiemSymbol symbol
) const
968 // nothing to return if we use 24-hour clock
969 if (m_use24HourClock
)
970 return StringUtils::Empty
;
972 return MeridiemSymbolToString(symbol
);
975 const std::string
& CLangInfo::MeridiemSymbolToString(MeridiemSymbol symbol
)
979 case MeridiemSymbolAM
:
980 return g_localizeStrings
.Get(378);
982 case MeridiemSymbolPM
:
983 return g_localizeStrings
.Get(379);
989 return StringUtils::Empty
;
992 // Fills the array with the region names available for this language
993 void CLangInfo::GetRegionNames(std::vector
<std::string
>& array
)
995 for (const auto ®ion
: m_regions
)
997 std::string strName
=region
.first
;
999 strName
=g_localizeStrings
.Get(10005); // Not available
1000 array
.emplace_back(std::move(strName
));
1004 // Set the current region by its name, names from GetRegionNames() are valid.
1005 // If the region is not found the first available region is set.
1006 void CLangInfo::SetCurrentRegion(const std::string
& strName
)
1008 ITMAPREGIONS it
=m_regions
.find(strName
);
1009 if (it
!=m_regions
.end())
1010 m_currentRegion
=&it
->second
;
1011 else if (!m_regions
.empty())
1012 m_currentRegion
=&m_regions
.begin()->second
;
1014 m_currentRegion
=&m_defaultRegion
;
1016 m_currentRegion
->SetGlobalLocale();
1018 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
1019 if (settings
->GetString(CSettings::SETTING_LOCALE_SHORTDATEFORMAT
) == SETTING_REGIONAL_DEFAULT
)
1020 SetShortDateFormat(m_currentRegion
->m_strDateFormatShort
);
1021 if (settings
->GetString(CSettings::SETTING_LOCALE_LONGDATEFORMAT
) == SETTING_REGIONAL_DEFAULT
)
1022 SetLongDateFormat(m_currentRegion
->m_strDateFormatLong
);
1023 if (settings
->GetString(CSettings::SETTING_LOCALE_USE24HOURCLOCK
) == SETTING_REGIONAL_DEFAULT
)
1025 Set24HourClock(m_currentRegion
->m_strTimeFormat
);
1027 // update the time format
1028 SetTimeFormat(settings
->GetString(CSettings::SETTING_LOCALE_TIMEFORMAT
));
1030 if (settings
->GetString(CSettings::SETTING_LOCALE_TIMEFORMAT
) == SETTING_REGIONAL_DEFAULT
)
1031 SetTimeFormat(m_currentRegion
->m_strTimeFormat
);
1032 if (settings
->GetString(CSettings::SETTING_LOCALE_TEMPERATUREUNIT
) == SETTING_REGIONAL_DEFAULT
)
1033 SetTemperatureUnit(m_currentRegion
->m_tempUnit
);
1034 if (settings
->GetString(CSettings::SETTING_LOCALE_SPEEDUNIT
) == SETTING_REGIONAL_DEFAULT
)
1035 SetSpeedUnit(m_currentRegion
->m_speedUnit
);
1038 // Returns the current region set for this language
1039 const std::string
& CLangInfo::GetCurrentRegion() const
1041 return m_currentRegion
->m_strName
;
1044 CTemperature::Unit
CLangInfo::GetTemperatureUnit() const
1046 return m_temperatureUnit
;
1049 void CLangInfo::SetTemperatureUnit(CTemperature::Unit temperatureUnit
)
1051 if (m_temperatureUnit
== temperatureUnit
)
1054 m_temperatureUnit
= temperatureUnit
;
1056 // refresh weather manager as temperatures need re-translating
1057 // NOTE: this could be called before our service manager is up
1058 if (CServiceBroker::IsServiceManagerUp())
1059 CServiceBroker::GetWeatherManager().Refresh();
1062 void CLangInfo::SetTemperatureUnit(const std::string
& temperatureUnit
)
1064 CTemperature::Unit unit
= CTemperature::UnitCelsius
;
1065 if (temperatureUnit
== SETTING_REGIONAL_DEFAULT
)
1066 unit
= m_currentRegion
->m_tempUnit
;
1068 unit
= StringToTemperatureUnit(temperatureUnit
);
1070 SetTemperatureUnit(unit
);
1073 std::string
CLangInfo::GetTemperatureAsString(const CTemperature
& temperature
) const
1075 if (!temperature
.IsValid())
1076 return g_localizeStrings
.Get(13205); // "Unknown"
1078 CTemperature::Unit temperatureUnit
= GetTemperatureUnit();
1079 return StringUtils::Format("{}{}", temperature
.ToString(temperatureUnit
),
1080 GetTemperatureUnitString());
1083 // Returns the temperature unit string for the current language
1084 const std::string
& CLangInfo::GetTemperatureUnitString() const
1086 return GetTemperatureUnitString(m_temperatureUnit
);
1089 const std::string
& CLangInfo::GetTemperatureUnitString(CTemperature::Unit temperatureUnit
)
1091 return g_localizeStrings
.Get(TEMP_UNIT_STRINGS
+ temperatureUnit
);
1094 void CLangInfo::SetSpeedUnit(CSpeed::Unit speedUnit
)
1096 if (m_speedUnit
== speedUnit
)
1099 m_speedUnit
= speedUnit
;
1101 // refresh weather manager as speeds need re-translating
1102 // NOTE: this could be called before our service manager is up
1103 if (CServiceBroker::IsServiceManagerUp())
1104 CServiceBroker::GetWeatherManager().Refresh();
1107 void CLangInfo::SetSpeedUnit(const std::string
& speedUnit
)
1109 CSpeed::Unit unit
= CSpeed::UnitKilometresPerHour
;
1110 if (speedUnit
== SETTING_REGIONAL_DEFAULT
)
1111 unit
= m_currentRegion
->m_speedUnit
;
1113 unit
= StringToSpeedUnit(speedUnit
);
1118 CSpeed::Unit
CLangInfo::GetSpeedUnit() const
1123 std::string
CLangInfo::GetSpeedAsString(const CSpeed
& speed
) const
1125 if (!speed
.IsValid())
1126 return g_localizeStrings
.Get(13205); // "Unknown"
1128 return StringUtils::Format("{}{}", speed
.ToString(GetSpeedUnit()), GetSpeedUnitString());
1131 // Returns the speed unit string for the current language
1132 const std::string
& CLangInfo::GetSpeedUnitString() const
1134 return GetSpeedUnitString(m_speedUnit
);
1137 const std::string
& CLangInfo::GetSpeedUnitString(CSpeed::Unit speedUnit
)
1139 return g_localizeStrings
.Get(SPEED_UNIT_STRINGS
+ speedUnit
);
1142 std::set
<std::string
> CLangInfo::GetSortTokens() const
1144 std::set
<std::string
> sortTokens
= m_sortTokens
;
1145 for (const auto& t
: CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_vecTokens
)
1146 sortTokens
.insert(t
);
1151 bool CLangInfo::DetermineUse24HourClockFromTimeFormat(const std::string
& timeFormat
)
1153 // if the time format contains a "h" it's 12-hour and otherwise 24-hour clock format
1154 return timeFormat
.find('h') == std::string::npos
;
1157 bool CLangInfo::DetermineUseMeridiemFromTimeFormat(const std::string
& timeFormat
)
1159 // if the time format contains "xx" it's using meridiem
1160 return timeFormat
.find("xx") != std::string::npos
;
1163 std::string
CLangInfo::PrepareTimeFormat(const std::string
& timeFormat
, bool use24HourClock
)
1165 std::string preparedTimeFormat
= timeFormat
;
1168 // replace all "h" with "H"
1169 StringUtils::Replace(preparedTimeFormat
, 'h', 'H');
1171 // remove any "xx" for meridiem
1172 StringUtils::Replace(preparedTimeFormat
, "x", "");
1175 // replace all "H" with "h"
1176 StringUtils::Replace(preparedTimeFormat
, 'H', 'h');
1178 StringUtils::Trim(preparedTimeFormat
);
1180 return preparedTimeFormat
;
1183 void CLangInfo::SettingOptionsLanguageNamesFiller(const SettingConstPtr
& setting
,
1184 std::vector
<StringSettingOption
>& list
,
1185 std::string
& current
,
1188 // find languages...
1189 ADDON::VECADDONS addons
;
1190 if (!CServiceBroker::GetAddonMgr().GetAddons(addons
, ADDON::AddonType::RESOURCE_LANGUAGE
))
1193 for (const auto &addon
: addons
)
1194 list
.emplace_back(addon
->Name(), addon
->Name());
1196 sort(list
.begin(), list
.end(), SortLanguage());
1199 void CLangInfo::SettingOptionsISO6391LanguagesFiller(const SettingConstPtr
& setting
,
1200 std::vector
<StringSettingOption
>& list
,
1201 std::string
& current
,
1204 std::vector
<std::string
> languages
= g_LangCodeExpander
.GetLanguageNames(
1205 CLangCodeExpander::ISO_639_1
, CLangCodeExpander::LANG_LIST::INCLUDE_USERDEFINED
);
1207 for (const auto &language
: languages
)
1208 list
.emplace_back(language
, language
);
1211 void CLangInfo::SettingOptionsAudioStreamLanguagesFiller(const SettingConstPtr
& setting
,
1212 std::vector
<StringSettingOption
>& list
,
1213 std::string
& current
,
1216 list
.emplace_back(g_localizeStrings
.Get(307), "mediadefault");
1217 list
.emplace_back(g_localizeStrings
.Get(308), "original");
1218 list
.emplace_back(g_localizeStrings
.Get(309), "default");
1223 void CLangInfo::SettingOptionsSubtitleStreamLanguagesFiller(const SettingConstPtr
& setting
,
1224 std::vector
<StringSettingOption
>& list
,
1225 std::string
& current
,
1228 list
.emplace_back(g_localizeStrings
.Get(231), "none");
1229 list
.emplace_back(g_localizeStrings
.Get(13207), "forced_only");
1230 list
.emplace_back(g_localizeStrings
.Get(308), "original");
1231 list
.emplace_back(g_localizeStrings
.Get(309), "default");
1236 void CLangInfo::SettingOptionsSubtitleDownloadlanguagesFiller(
1237 const SettingConstPtr
& setting
,
1238 std::vector
<StringSettingOption
>& list
,
1239 std::string
& current
,
1242 list
.emplace_back(g_localizeStrings
.Get(308), "original");
1243 list
.emplace_back(g_localizeStrings
.Get(309), "default");
1248 void CLangInfo::SettingOptionsRegionsFiller(const SettingConstPtr
& setting
,
1249 std::vector
<StringSettingOption
>& list
,
1250 std::string
& current
,
1253 std::vector
<std::string
> regions
;
1254 g_langInfo
.GetRegionNames(regions
);
1255 std::sort(regions
.begin(), regions
.end(), sortstringbyname());
1258 for (unsigned int i
= 0; i
< regions
.size(); ++i
)
1260 std::string region
= regions
[i
];
1261 list
.emplace_back(region
, region
);
1263 if (!match
&& region
== std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue())
1270 if (!match
&& !regions
.empty())
1271 current
= regions
[0];
1274 void CLangInfo::SettingOptionsShortDateFormatsFiller(const SettingConstPtr
& setting
,
1275 std::vector
<StringSettingOption
>& list
,
1276 std::string
& current
,
1280 const std::string
& shortDateFormatSetting
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
1282 CDateTime now
= CDateTime::GetCurrentDateTime();
1285 StringUtils::Format(g_localizeStrings
.Get(20035),
1286 now
.GetAsLocalizedDate(g_langInfo
.m_currentRegion
->m_strDateFormatShort
)),
1287 SETTING_REGIONAL_DEFAULT
);
1288 if (shortDateFormatSetting
== SETTING_REGIONAL_DEFAULT
)
1291 current
= SETTING_REGIONAL_DEFAULT
;
1294 for (const std::string
& shortDateFormat
: shortDateFormats
)
1296 list
.emplace_back(now
.GetAsLocalizedDate(shortDateFormat
), shortDateFormat
);
1298 if (!match
&& shortDateFormatSetting
== shortDateFormat
)
1301 current
= shortDateFormat
;
1305 if (!match
&& !list
.empty())
1306 current
= list
[0].value
;
1309 void CLangInfo::SettingOptionsLongDateFormatsFiller(const SettingConstPtr
& setting
,
1310 std::vector
<StringSettingOption
>& list
,
1311 std::string
& current
,
1315 const std::string
& longDateFormatSetting
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
1317 CDateTime now
= CDateTime::GetCurrentDateTime();
1320 StringUtils::Format(g_localizeStrings
.Get(20035),
1321 now
.GetAsLocalizedDate(g_langInfo
.m_currentRegion
->m_strDateFormatLong
)),
1322 SETTING_REGIONAL_DEFAULT
);
1323 if (longDateFormatSetting
== SETTING_REGIONAL_DEFAULT
)
1326 current
= SETTING_REGIONAL_DEFAULT
;
1329 for (const std::string
& longDateFormat
: longDateFormats
)
1331 list
.emplace_back(now
.GetAsLocalizedDate(longDateFormat
), longDateFormat
);
1333 if (!match
&& longDateFormatSetting
== longDateFormat
)
1336 current
= longDateFormat
;
1340 if (!match
&& !list
.empty())
1341 current
= list
[0].value
;
1344 void CLangInfo::SettingOptionsTimeFormatsFiller(const SettingConstPtr
& setting
,
1345 std::vector
<StringSettingOption
>& list
,
1346 std::string
& current
,
1350 const std::string
& timeFormatSetting
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
1352 CDateTime now
= CDateTime::GetCurrentDateTime();
1353 bool use24hourFormat
= g_langInfo
.Use24HourClock();
1356 StringUtils::Format(g_localizeStrings
.Get(20035),
1357 ToSettingTimeFormat(now
, g_langInfo
.m_currentRegion
->m_strTimeFormat
)),
1358 SETTING_REGIONAL_DEFAULT
);
1359 if (timeFormatSetting
== SETTING_REGIONAL_DEFAULT
)
1362 current
= SETTING_REGIONAL_DEFAULT
;
1365 if (use24hourFormat
)
1367 list
.emplace_back(ToSettingTimeFormat(now
, TIME_FORMAT_SINGLE_24
), TIME_FORMAT_SINGLE_24
);
1368 if (timeFormatSetting
== TIME_FORMAT_SINGLE_24
)
1370 current
= TIME_FORMAT_SINGLE_24
;
1374 list
.emplace_back(ToSettingTimeFormat(now
, TIME_FORMAT_DOUBLE_24
), TIME_FORMAT_DOUBLE_24
);
1375 if (timeFormatSetting
== TIME_FORMAT_DOUBLE_24
)
1377 current
= TIME_FORMAT_DOUBLE_24
;
1383 list
.emplace_back(ToSettingTimeFormat(now
, TIME_FORMAT_SINGLE_12
), TIME_FORMAT_SINGLE_12
);
1384 if (timeFormatSetting
== TIME_FORMAT_SINGLE_12
)
1386 current
= TIME_FORMAT_SINGLE_12
;
1390 list
.emplace_back(ToSettingTimeFormat(now
, TIME_FORMAT_DOUBLE_12
), TIME_FORMAT_DOUBLE_12
);
1391 if (timeFormatSetting
== TIME_FORMAT_DOUBLE_12
)
1393 current
= TIME_FORMAT_DOUBLE_12
;
1397 std::string timeFormatSingle12Meridiem
= ToTimeFormat(false, true, true);
1398 list
.emplace_back(ToSettingTimeFormat(now
, timeFormatSingle12Meridiem
), timeFormatSingle12Meridiem
);
1399 if (timeFormatSetting
== timeFormatSingle12Meridiem
)
1401 current
= timeFormatSingle12Meridiem
;
1405 std::string timeFormatDouble12Meridiem
= ToTimeFormat(false, false, true);
1406 list
.emplace_back(ToSettingTimeFormat(now
, timeFormatDouble12Meridiem
), timeFormatDouble12Meridiem
);
1407 if (timeFormatSetting
== timeFormatDouble12Meridiem
)
1409 current
= timeFormatDouble12Meridiem
;
1414 if (!match
&& !list
.empty())
1415 current
= list
[0].value
;
1418 void CLangInfo::SettingOptions24HourClockFormatsFiller(const SettingConstPtr
& setting
,
1419 std::vector
<StringSettingOption
>& list
,
1420 std::string
& current
,
1424 const std::string
& clock24HourFormatSetting
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
1426 // determine the 24-hour clock format of the regional setting
1427 int regionalClock24HourFormatLabel
= DetermineUse24HourClockFromTimeFormat(g_langInfo
.m_currentRegion
->m_strTimeFormat
) ? 12384 : 12383;
1428 list
.emplace_back(StringUtils::Format(g_localizeStrings
.Get(20035),
1429 g_localizeStrings
.Get(regionalClock24HourFormatLabel
)),
1430 SETTING_REGIONAL_DEFAULT
);
1431 if (clock24HourFormatSetting
== SETTING_REGIONAL_DEFAULT
)
1434 current
= SETTING_REGIONAL_DEFAULT
;
1437 list
.emplace_back(g_localizeStrings
.Get(12383), TIME_FORMAT_12HOURS
);
1438 if (clock24HourFormatSetting
== TIME_FORMAT_12HOURS
)
1440 current
= TIME_FORMAT_12HOURS
;
1444 list
.emplace_back(g_localizeStrings
.Get(12384), TIME_FORMAT_24HOURS
);
1445 if (clock24HourFormatSetting
== TIME_FORMAT_24HOURS
)
1447 current
= TIME_FORMAT_24HOURS
;
1451 if (!match
&& !list
.empty())
1452 current
= list
[0].value
;
1455 void CLangInfo::SettingOptionsTemperatureUnitsFiller(const SettingConstPtr
& setting
,
1456 std::vector
<StringSettingOption
>& list
,
1457 std::string
& current
,
1461 const std::string
& temperatureUnitSetting
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
1464 StringUtils::Format(g_localizeStrings
.Get(20035),
1465 GetTemperatureUnitString(g_langInfo
.m_currentRegion
->m_tempUnit
)),
1466 SETTING_REGIONAL_DEFAULT
);
1467 if (temperatureUnitSetting
== SETTING_REGIONAL_DEFAULT
)
1470 current
= SETTING_REGIONAL_DEFAULT
;
1473 for (const TemperatureInfo
& info
: temperatureInfo
)
1475 list
.emplace_back(GetTemperatureUnitString(info
.unit
), info
.name
);
1477 if (!match
&& temperatureUnitSetting
== info
.name
)
1480 current
= info
.name
;
1484 if (!match
&& !list
.empty())
1485 current
= list
[0].value
;
1488 void CLangInfo::SettingOptionsSpeedUnitsFiller(const SettingConstPtr
& setting
,
1489 std::vector
<StringSettingOption
>& list
,
1490 std::string
& current
,
1494 const std::string
& speedUnitSetting
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
1497 StringUtils::Format(g_localizeStrings
.Get(20035),
1498 GetSpeedUnitString(g_langInfo
.m_currentRegion
->m_speedUnit
)),
1499 SETTING_REGIONAL_DEFAULT
);
1500 if (speedUnitSetting
== SETTING_REGIONAL_DEFAULT
)
1503 current
= SETTING_REGIONAL_DEFAULT
;
1506 for (const SpeedInfo
& info
: speedInfo
)
1508 list
.emplace_back(GetSpeedUnitString(info
.unit
), info
.name
);
1510 if (!match
&& speedUnitSetting
== info
.name
)
1513 current
= info
.name
;
1517 if (!match
&& !list
.empty())
1518 current
= list
[0].value
;
1521 void CLangInfo::AddLanguages(std::vector
<StringSettingOption
> &list
)
1523 std::vector
<std::string
> languages
= g_LangCodeExpander
.GetLanguageNames(
1524 CLangCodeExpander::ISO_639_1
, CLangCodeExpander::LANG_LIST::INCLUDE_ADDONS_USERDEFINED
);
1526 for (const auto& language
: languages
)
1527 list
.emplace_back(language
, language
);