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 "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"
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
+ ")";
51 static std::string shortDateFormats
[] = {
53 // short date formats using "/"
58 // short date formats using "-"
63 // short date formats using "."
69 // short date formats with abbreviated month and 2 digit year
77 static std::string longDateFormats
[] = {
81 "DDDD, DD. MMMM YYYY",
83 "DDDD, MMMM DD, YYYY",
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
;
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
{
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
)
149 return singleHour
? TIME_FORMAT_SINGLE_24
: TIME_FORMAT_DOUBLE_24
;
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
)
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
)
188 return CSpeed::UnitKilometresPerHour
;
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()
209 void CLangInfo::CRegion::SetDefaults()
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
;
249 strLocale
= m_strLangLocaleName
+ "_" + m_strRegionLocaleName
;
252 strLocale
+= ".UTF-8";
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() == '.');
279 current_locale
= std::locale::classic();
283 g_langInfo
.m_systemLocale
= current_locale
; //! @todo move to CLangInfo class
284 g_langInfo
.m_collationtype
= 0;
285 std::locale::global(current_locale
);
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
)
294 setlocale(LC_COLLATE
, strLocale
.c_str());
295 setlocale(LC_CTYPE
, strLocale
.c_str());
296 setlocale(LC_TIME
, strLocale
.c_str());
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
)
307 _wsetlocale(LC_COLLATE
, strLocaleW
.c_str());
308 _wsetlocale(LC_CTYPE
, strLocaleW
.c_str());
309 _wsetlocale(LC_TIME
, strLocaleW
.c_str());
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");
322 CLangInfo::CLangInfo()
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
;
334 CLangInfo::~CLangInfo() = default;
336 void CLangInfo::OnSettingChanged(const std::shared_ptr
<const CSetting
>& setting
)
341 auto settingsComponent
= CServiceBroker::GetSettingsComponent();
342 if (!settingsComponent
)
345 auto settings
= settingsComponent
->GetSettings();
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
);
361 CLog::Log(LOGERROR
, "Failed to load setting for: {}", CSettings::SETTING_LOCALE_LANGUAGE
);
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
)
406 std::string strFileName
= GetLanguageInfoPath(strLanguage
);
409 if (!xmlDoc
.LoadFile(strFileName
))
411 CLog::Log(LOGERROR
, "unable to load {}: {} at line {}", strFileName
, xmlDoc
.ErrorDesc(),
416 // get the matching language addon
417 m_languageAddon
= GetLanguageAddon(strLanguage
);
418 if (m_languageAddon
== NULL
)
420 CLog::Log(LOGERROR
, "Unknown language {}", strLanguage
);
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
);
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
= "";
454 if (m_defaultRegion
.m_strLangLocaleName
.length() != 3)
456 if (!g_LangCodeExpander
.ConvertToISO6392B(m_defaultRegion
.m_strLangLocaleName
, m_languageCodeGeneral
))
457 m_languageCodeGeneral
= "";
460 m_languageCodeGeneral
= m_defaultRegion
.m_strLangLocaleName
;
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");
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
= "";
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");
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"));
527 region
.m_strGrouping
= "\3";
532 region
.m_cThousandsSep
= ',';
533 region
.m_strGrouping
= "\3";
536 const TiXmlElement
*pDecimalSep
= pRegion
->FirstChildElement("decimalseparator");
539 if (!pDecimalSep
->NoChildren())
540 region
.m_cDecimalSep
= pDecimalSep
->FirstChild()->Value()[0];
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();
558 std::string
CLangInfo::GetLanguagePath(const std::string
&language
)
560 if (language
.empty())
563 std::string addonId
= ADDON::CLanguageResource::GetAddonId(language
);
565 std::string path
= URIUtils::AddFileToFolder(GetLanguagePath(), addonId
);
566 URIUtils::AddSlashAtEnd(path
);
571 std::string
CLangInfo::GetLanguageInfoPath(const std::string
&language
)
573 if (language
.empty())
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
586 if (!StringUtils::EqualsNoCase(
587 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_databaseMusic
.type
,
589 !StringUtils::EqualsNoCase(
590 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_databaseVideo
.type
,
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
);
597 wchar_t rc
= 0x00E2; // Latin small letter a with circumflex
598 int comp_result
= coll
.compare(&lc
, &lc
+ 1, &rc
, &rc
+ 1);
600 // Latin small letter a with circumflex put before z - collation works
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");
614 std::string strSep
= " ._";
615 if (pToken
->Attribute("separators"))
616 strSep
= pToken
->Attribute("separators");
617 if (pToken
->FirstChild() && pToken
->FirstChild()->Value())
620 vecTokens
.insert(pToken
->FirstChild()->ValueStr());
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()
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
);
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
) &&
699 return std::dynamic_pointer_cast
<ADDON::CLanguageResource
>(addon
);
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
, '_', '-');
722 std::string
CLangInfo::GetEnglishLanguageName(const std::string
& locale
/* = "" */) const
724 LanguageResourcePtr addon
= GetLanguageAddon(locale
);
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...",
749 language
= std::static_pointer_cast
<const CSettingString
>(
750 CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(
751 CSettings::SETTING_LOCALE_LANGUAGE
))
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__
,
764 CLog::Log(LOGINFO
, "CLangInfo: loading {} language information...", language
);
767 CLog::LogF(LOGFATAL
, "CLangInfo: failed to load {} language information", language
);
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
);
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());
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,
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
)
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
)
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
843 if (!g_LangCodeExpander
.ConvertToISO6391(m_currentRegion
->m_strLangLocaleName
, code
))
844 code
= m_strDVDMenuLanguage
;
849 // two character codes as defined in ISO639
850 const std::string
CLangInfo::GetDVDAudioLanguage() const
853 if (!g_LangCodeExpander
.ConvertToISO6391(m_audioLanguage
, code
))
854 code
= m_strDVDAudioLanguage
;
859 // two character codes as defined in ISO639
860 const std::string
CLangInfo::GetDVDSubtitleLanguage() const
863 if (!g_LangCodeExpander
.ConvertToISO6391(m_subtitleLanguage
, code
))
864 code
= m_strDVDSubtitleLanguage
;
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
892 return GetLongDateFormat();
894 return GetShortDateFormat();
897 void CLangInfo::SetDateFormat(const std::string
& dateFormat
, bool bLongDate
/* = false */)
900 SetLongDateFormat(dateFormat
);
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
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
);
971 use24HourClock
= DetermineUse24HourClockFromTimeFormat(str24HourClock
);
973 if (m_use24HourClock
== use24HourClock
)
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
)
998 case MeridiemSymbolAM
:
999 return g_localizeStrings
.Get(378);
1001 case MeridiemSymbolPM
:
1002 return g_localizeStrings
.Get(379);
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 ®ion
: m_regions
)
1016 std::string strName
=region
.first
;
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
;
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
)
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
;
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
)
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
;
1132 unit
= StringToSpeedUnit(speedUnit
);
1137 CSpeed::Unit
CLangInfo::GetSpeedUnit() const
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
);
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
;
1187 // replace all "h" with "H"
1188 StringUtils::Replace(preparedTimeFormat
, 'h', 'H');
1190 // remove any "xx" for meridiem
1191 StringUtils::Replace(preparedTimeFormat
, "x", "");
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
,
1207 // find languages...
1208 ADDON::VECADDONS addons
;
1209 if (!CServiceBroker::GetAddonMgr().GetAddons(addons
, ADDON::AddonType::RESOURCE_LANGUAGE
))
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
,
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
,
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");
1242 void CLangInfo::SettingOptionsSubtitleStreamLanguagesFiller(const SettingConstPtr
& setting
,
1243 std::vector
<StringSettingOption
>& list
,
1244 std::string
& current
,
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");
1255 void CLangInfo::SettingOptionsSubtitleDownloadlanguagesFiller(
1256 const SettingConstPtr
& setting
,
1257 std::vector
<StringSettingOption
>& list
,
1258 std::string
& current
,
1261 list
.emplace_back(g_localizeStrings
.Get(308), "original");
1262 list
.emplace_back(g_localizeStrings
.Get(309), "default");
1267 void CLangInfo::SettingOptionsRegionsFiller(const SettingConstPtr
& setting
,
1268 std::vector
<StringSettingOption
>& list
,
1269 std::string
& current
,
1272 std::vector
<std::string
> regions
;
1273 g_langInfo
.GetRegionNames(regions
);
1274 std::sort(regions
.begin(), regions
.end(), sortstringbyname());
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())
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
,
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
)
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
)
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
,
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
)
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
)
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
,
1371 const std::string
& timeFormatSetting
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
1373 CDateTime now
= CDateTime::GetCurrentDateTime();
1374 bool use24hourFormat
= g_langInfo
.Use24HourClock();
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
)
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
;
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
;
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
;
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
;
1418 std::string timeFormatSingle12Meridiem
= ToTimeFormat(false, true, true);
1419 list
.emplace_back(ToSettingTimeFormat(now
, timeFormatSingle12Meridiem
), timeFormatSingle12Meridiem
);
1420 if (timeFormatSetting
== timeFormatSingle12Meridiem
)
1422 current
= timeFormatSingle12Meridiem
;
1426 std::string timeFormatDouble12Meridiem
= ToTimeFormat(false, false, true);
1427 list
.emplace_back(ToSettingTimeFormat(now
, timeFormatDouble12Meridiem
), timeFormatDouble12Meridiem
);
1428 if (timeFormatSetting
== timeFormatDouble12Meridiem
)
1430 current
= timeFormatDouble12Meridiem
;
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
,
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
)
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
;
1465 list
.emplace_back(g_localizeStrings
.Get(12384), TIME_FORMAT_24HOURS
);
1466 if (clock24HourFormatSetting
== TIME_FORMAT_24HOURS
)
1468 current
= TIME_FORMAT_24HOURS
;
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
,
1482 const std::string
& temperatureUnitSetting
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
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
)
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
)
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
,
1515 const std::string
& speedUnitSetting
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
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
)
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
)
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
);