From 66953bf328aef750876591793e7b55693bf29151 Mon Sep 17 00:00:00 2001 From: montellese Date: Wed, 22 Oct 2014 11:27:42 +0200 Subject: [PATCH] adjust language loading/handling logic adjust all paths to language files (special://xbmc/language/...) unify loading/changing language add update/fallback for locale.language setting including matching an old language name to an installable language addon move , and from langinfo.xml to addon.xml rename CLangInfo's GetLocale() to GetSystemLocale() --- language/English/strings.po | 12 +- system/settings/settings.xml | 4 +- xbmc/Application.cpp | 61 ++-- xbmc/Application.h | 1 + xbmc/GUIInfoManager.cpp | 2 +- xbmc/LangInfo.cpp | 316 +++++++++++++----- xbmc/LangInfo.h | 83 ++++- xbmc/guilib/LocalizeStrings.cpp | 35 +- xbmc/guilib/LocalizeStrings.h | 4 +- xbmc/interfaces/legacy/ModuleXbmc.cpp | 2 +- .../devices/PeripheralCecAdapter.cpp | 44 +-- xbmc/profiles/ProfilesManager.cpp | 16 +- xbmc/settings/AdvancedSettings.h | 3 +- xbmc/settings/Settings.cpp | 2 + xbmc/utils/SortUtils.cpp | 9 +- xbmc/utils/StringUtils.cpp | 2 +- xbmc/utils/Weather.cpp | 8 +- xbmc/video/dialogs/GUIDialogSubtitles.cpp | 3 +- xbmc/windows/GUIWindowLoginScreen.cpp | 11 + 19 files changed, 425 insertions(+), 193 deletions(-) diff --git a/language/English/strings.po b/language/English/strings.po index 4ccf60d6607a6..6985299d80591 100644 --- a/language/English/strings.po +++ b/language/English/strings.po @@ -12904,7 +12904,17 @@ msgctxt "#24132" msgid "Would you like to switch to this language?" msgstr "" -#empty strings from id 24133 to 24998 +#: xbmc/Application.cpp +msgctxt "#24133" +msgid "Failed to load language" +msgstr "" + +#: xbmc/Application.cpp +msgctxt "#24134" +msgid "We were unable to load your configured language. Please check your language settings." +msgstr "" + +#empty strings from id 24135 to 24998 msgctxt "#24999" msgid "Hide incompatible" diff --git a/system/settings/settings.xml b/system/settings/settings.xml index 44bceba709693..b0194dac53c70 100644 --- a/system/settings/settings.xml +++ b/system/settings/settings.xml @@ -116,7 +116,7 @@ 0 - English + resource.language.en_gb kodi.resource.language @@ -848,7 +848,7 @@ 1 English - languages + languagenames , 1 3 diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp index 44a281266b2e0..82aada0b4f856 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp @@ -47,6 +47,7 @@ #include "guilib/GUIColorManager.h" #include "guilib/StereoscopicsManager.h" #include "guilib/GUITextLayout.h" +#include "addons/LanguageResource.h" #include "addons/Skin.h" #include "interfaces/generic/ScriptInvocationManager.h" #ifdef HAS_PYTHON @@ -664,26 +665,6 @@ bool CApplication::Create() update_emu_environ();//apply the GUI settings - // Load the langinfo to have user charset <-> utf-8 conversion - std::string strLanguage = CSettings::Get().GetString("locale.language"); - strLanguage[0] = toupper(strLanguage[0]); - - std::string strLangInfoPath = StringUtils::Format("special://xbmc/language/%s/langinfo.xml", strLanguage.c_str()); - - CLog::Log(LOGINFO, "load language info file: %s", strLangInfoPath.c_str()); - g_langInfo.Load(strLangInfoPath); - g_langInfo.SetAudioLanguage(CSettings::Get().GetString("locale.audiolanguage")); - g_langInfo.SetSubtitleLanguage(CSettings::Get().GetString("locale.subtitlelanguage")); - - std::string strLanguagePath = "special://xbmc/language/"; - - CLog::Log(LOGINFO, "load %s language file, from path: %s", strLanguage.c_str(), strLanguagePath.c_str()); - if (!g_localizeStrings.Load(strLanguagePath, strLanguage)) - { - CLog::LogF(LOGFATAL, "Failed to load %s language file, from path: %s", strLanguage.c_str(), strLanguagePath.c_str()); - return false; - } - #ifdef TARGET_WINDOWS CWIN32Util::SetThreadLocalLocale(true); // enable independent locale for each thread, see https://connect.microsoft.com/VisualStudio/feedback/details/794122 #endif // TARGET_WINDOWS @@ -952,11 +933,11 @@ bool CApplication::InitDirectoriesLinux() appPath = appBinPath; /* Check if binaries and arch independent data files are being kept in * separate locations. */ - if (!CDirectory::Exists(URIUtils::AddFileToFolder(appPath, "language"))) + if (!CDirectory::Exists(URIUtils::AddFileToFolder(appPath, "system"))) { /* Attempt to locate arch independent data files. */ CUtil::GetHomePath(appPath); - if (!CDirectory::Exists(URIUtils::AddFileToFolder(appPath, "language"))) + if (!CDirectory::Exists(URIUtils::AddFileToFolder(appPath, "system"))) { fprintf(stderr, "Unable to find path to %s data files!\n", appName.c_str()); exit(1); @@ -1162,11 +1143,15 @@ bool CApplication::Initialize() if (!m_bPlatformDirectories) #endif { - CDirectory::Create("special://xbmc/language"); CDirectory::Create("special://xbmc/addons"); CDirectory::Create("special://xbmc/sounds"); } + // load the language and its translated strings + bool fallbackLanguage = false; + if (!LoadLanguage(false, fallbackLanguage)) + return false; + // Load curl so curl_global_init gets called before any service threads // are started. Unloading will have no effect as curl is never fully unloaded. // To quote man curl_global_init: @@ -1267,6 +1252,9 @@ bool CApplication::Initialize() CPeripheralImon::GetCountOfImonsConflictWithDInput() == 0 ); #endif + if (fallbackLanguage) + CGUIDialogOK::ShowAndGetInput(24133, 24134); + // show info dialog about moved configuration files if needed ShowAppMigrationMessage(); @@ -4895,23 +4883,22 @@ CPerformanceStats &CApplication::GetPerformanceStats() bool CApplication::SetLanguage(const std::string &strLanguage) { - std::string strPreviousLanguage = CSettings::Get().GetString("locale.language"); - if (strLanguage != strPreviousLanguage) - { - std::string strLangInfoPath = StringUtils::Format("special://xbmc/language/%s/langinfo.xml", strLanguage.c_str()); - if (!g_langInfo.Load(strLangInfoPath)) - return false; + // nothing to be done if the language hasn't changed + if (strLanguage == CSettings::Get().GetString("locale.language")) + return true; - CSettings::Get().SetString("locale.language", strLanguage); + return CSettings::Get().SetString("locale.language", strLanguage); +} - if (!g_localizeStrings.Load("special://xbmc/language/", strLanguage)) - return false; +bool CApplication::LoadLanguage(bool reload, bool& fallback) +{ + // load the configured langauge + if (!g_langInfo.SetLanguage(fallback, "", reload)) + return false; - // also tell our weather and skin to reload as these are localized - g_weatherManager.Refresh(); - g_PVRManager.LocalizationChanged(); - ReloadSkin(); - } + // set the proper audio and subtitle languages + g_langInfo.SetAudioLanguage(CSettings::Get().GetString("locale.audiolanguage")); + g_langInfo.SetSubtitleLanguage(CSettings::Get().GetString("locale.subtitlelanguage")); return true; } diff --git a/xbmc/Application.h b/xbmc/Application.h index 683655596d780..ec5dfac33ebdc 100644 --- a/xbmc/Application.h +++ b/xbmc/Application.h @@ -372,6 +372,7 @@ class CApplication : public CXBApplicationEx, public IPlayerCallback, public IMs bool GetRenderGUI() const { return m_renderGUI; }; bool SetLanguage(const std::string &strLanguage); + bool LoadLanguage(bool reload, bool& fallback); ReplayGainSettings& GetReplayGainSettings() { return m_replayGainSettings; } diff --git a/xbmc/GUIInfoManager.cpp b/xbmc/GUIInfoManager.cpp index 9abfc581915b0..a6b2052425627 100644 --- a/xbmc/GUIInfoManager.cpp +++ b/xbmc/GUIInfoManager.cpp @@ -1926,7 +1926,7 @@ std::string CGUIInfoManager::GetLabel(int info, int contextWindow, std::string * } break; case SYSTEM_LANGUAGE: - strLabel = CSettings::Get().GetString("locale.language"); + strLabel = g_langInfo.GetEnglishLanguageName(); break; case SYSTEM_TEMPERATURE_UNITS: strLabel = g_langInfo.GetTempUnitString(); diff --git a/xbmc/LangInfo.cpp b/xbmc/LangInfo.cpp index 2b9e12eed71a9..ed87d06463486 100644 --- a/xbmc/LangInfo.cpp +++ b/xbmc/LangInfo.cpp @@ -23,6 +23,9 @@ #include "ApplicationMessenger.h" #include "FileItem.h" #include "Util.h" +#include "addons/AddonInstaller.h" +#include "addons/AddonManager.h" +#include "addons/LanguageResource.h" #include "filesystem/Directory.h" #include "guilib/LocalizeStrings.h" #include "pvr/PVRManager.h" @@ -33,6 +36,7 @@ #include "utils/log.h" #include "utils/LangCodeExpander.h" #include "utils/StringUtils.h" +#include "utils/URIUtils.h" #include "utils/Weather.h" #include "utils/XBMCTinyXML.h" #include "utils/XMLUtils.h" @@ -46,16 +50,23 @@ using namespace PVR; #define SPEED_UNIT_STRINGS 20200 +struct SortLanguage +{ + bool operator()(const std::pair &left, const std::pair &right) + { + std::string strLeft = left.first; + std::string strRight = right.first; + StringUtils::ToLower(strLeft); + StringUtils::ToLower(strRight); + + return strLeft.compare(strRight) < 0; + } +}; + CLangInfo::CRegion::CRegion(const CRegion& region): - m_strGuiCharSet(region.m_strGuiCharSet), - m_strSubtitleCharSet(region.m_strSubtitleCharSet), - m_strDVDMenuLanguage(region.m_strDVDMenuLanguage), - m_strDVDAudioLanguage(region.m_strDVDAudioLanguage), - m_strDVDSubtitleLanguage(region.m_strDVDSubtitleLanguage), m_strLangLocaleName(region.m_strLangLocaleName), m_strLangLocaleCodeTwoChar(region.m_strLangLocaleCodeTwoChar), m_strRegionLocaleName(region.m_strRegionLocaleName), - m_forceUnicodeFont(region.m_forceUnicodeFont), m_strName(region.m_strName), m_strDateFormatLong(region.m_strDateFormatLong), m_strDateFormatShort(region.m_strDateFormatShort), @@ -81,12 +92,6 @@ CLangInfo::CRegion::~CRegion() void CLangInfo::CRegion::SetDefaults() { m_strName="N/A"; - m_forceUnicodeFont=false; - m_strGuiCharSet="CP1252"; - m_strSubtitleCharSet="CP1252"; - m_strDVDMenuLanguage="en"; - m_strDVDAudioLanguage="en"; - m_strDVDSubtitleLanguage="en"; m_strLangLocaleName = "English"; m_strLangLocaleCodeTwoChar = "en"; @@ -198,7 +203,7 @@ void CLangInfo::CRegion::SetGlobalLocale() strLocale = "C"; } - g_langInfo.m_locale = current_locale; // TODO: move to CLangInfo class + g_langInfo.m_systemLocale = current_locale; // TODO: move to CLangInfo class locale::global(current_locale); #endif g_charsetConverter.resetSystemCharset(); @@ -236,10 +241,14 @@ void CLangInfo::OnSettingChanged(const CSetting *setting) } } -bool CLangInfo::Load(const std::string& strFileName, bool onlyCheckLanguage /*= false*/) +bool CLangInfo::Load(const std::string& strLanguage, bool onlyCheckLanguage /*= false*/) { SetDefaults(); + string strFileName = GetLanguageInfoPath(strLanguage); + if (!onlyCheckLanguage) + CLog::Log(LOGINFO, "CLangInfo: load language info file: %s", strFileName.c_str()); + CXBMCTinyXML xmlDoc; if (!xmlDoc.LoadFile(strFileName)) { @@ -247,6 +256,26 @@ bool CLangInfo::Load(const std::string& strFileName, bool onlyCheckLanguage /*= return false; } + // get the matching language addon + m_languageAddon = GetLanguageAddon(strLanguage); + if (m_languageAddon == NULL) + { + CLog::Log(onlyCheckLanguage ? LOGDEBUG : LOGERROR, "Unknown language %s", strLanguage.c_str()); + return false; + } + + if (!onlyCheckLanguage) + { + // get some language-specific information from the language addon + m_strGuiCharSet = m_languageAddon->GetGuiCharset(); + m_forceUnicodeFont = m_languageAddon->ForceUnicodeFont(); + m_strSubtitleCharSet = m_languageAddon->GetSubtitleCharset(); + m_strDVDMenuLanguage = m_languageAddon->GetDvdMenuLanguage(); + m_strDVDAudioLanguage = m_languageAddon->GetDvdAudioLanguage(); + m_strDVDSubtitleLanguage = m_languageAddon->GetDvdSubtitleLanguage(); + m_sortTokens = m_languageAddon->GetSortTokens(); + } + TiXmlElement* pRootElement = xmlDoc.RootElement(); if (pRootElement->ValueStr() != "language") { @@ -281,39 +310,6 @@ bool CLangInfo::Load(const std::string& strFileName, bool onlyCheckLanguage /*= if (g_LangCodeExpander.ConvertToTwoCharCode(tmp, m_defaultRegion.m_strLangLocaleName)) m_defaultRegion.m_strLangLocaleCodeTwoChar = tmp; - const TiXmlNode *pCharSets = pRootElement->FirstChild("charsets"); - if (pCharSets && !pCharSets->NoChildren()) - { - const TiXmlElement *pGui = pCharSets->FirstChildElement("gui"); - if (pGui && !pGui->NoChildren()) - { - if (StringUtils::EqualsNoCase(XMLUtils::GetAttribute(pGui, "unicodefont"), "true")) - m_defaultRegion.m_forceUnicodeFont=true; - - m_defaultRegion.m_strGuiCharSet=pGui->FirstChild()->ValueStr(); - } - - const TiXmlNode *pSubtitle = pCharSets->FirstChild("subtitle"); - if (pSubtitle && !pSubtitle->NoChildren()) - m_defaultRegion.m_strSubtitleCharSet=pSubtitle->FirstChild()->ValueStr(); - } - - const TiXmlNode *pDVD = pRootElement->FirstChild("dvd"); - if (pDVD && !pDVD->NoChildren()) - { - const TiXmlNode *pMenu = pDVD->FirstChild("menu"); - if (pMenu && !pMenu->NoChildren()) - m_defaultRegion.m_strDVDMenuLanguage=pMenu->FirstChild()->ValueStr(); - - const TiXmlNode *pAudio = pDVD->FirstChild("audio"); - if (pAudio && !pAudio->NoChildren()) - m_defaultRegion.m_strDVDAudioLanguage=pAudio->FirstChild()->ValueStr(); - - const TiXmlNode *pSubtitle = pDVD->FirstChild("subtitle"); - if (pSubtitle && !pSubtitle->NoChildren()) - m_defaultRegion.m_strDVDSubtitleLanguage=pSubtitle->FirstChild()->ValueStr(); - } - const TiXmlNode *pRegions = pRootElement->FirstChild("regions"); if (pRegions && !pRegions->NoChildren()) { @@ -378,19 +374,37 @@ bool CLangInfo::Load(const std::string& strFileName, bool onlyCheckLanguage /*= } g_charsetConverter.reinitCharsetsFromSettings(); - if (!onlyCheckLanguage) - LoadTokens(pRootElement->FirstChild("sorttokens"), g_advancedSettings.m_vecTokens); - return true; } +std::string CLangInfo::GetLanguagePath(const std::string &language) +{ + if (language.empty()) + return ""; + + std::string addonId = ADDON::CLanguageResource::GetAddonId(language); + + std::string path = URIUtils::AddFileToFolder(GetLanguagePath(), addonId); + URIUtils::AddSlashAtEnd(path); + + return path; +} + +std::string CLangInfo::GetLanguageInfoPath(const std::string &language) +{ + if (language.empty()) + return ""; + + return URIUtils::AddFileToFolder(GetLanguagePath(language), "langinfo.xml"); +} + bool CLangInfo::CheckLanguage(const std::string& language) { CLangInfo li; - return li.Load("special://xbmc/language/" + language + "/langinfo.xml", true); + return li.Load(language, true); } -void CLangInfo::LoadTokens(const TiXmlNode* pTokens, vector& vecTokens) +void CLangInfo::LoadTokens(const TiXmlNode* pTokens, set& vecTokens) { if (pTokens && !pTokens->NoChildren()) { @@ -403,10 +417,10 @@ void CLangInfo::LoadTokens(const TiXmlNode* pTokens, vector& vecTok if (pToken->FirstChild() && pToken->FirstChild()->Value()) { if (strSep.empty()) - vecTokens.push_back(pToken->FirstChild()->ValueStr()); + vecTokens.insert(pToken->FirstChild()->ValueStr()); else for (unsigned int i=0;iFirstChild()->ValueStr()+strSep[i]); + vecTokens.insert(pToken->FirstChild()->ValueStr() + strSep[i]); } pToken = pToken->NextSiblingElement(); } @@ -421,52 +435,171 @@ void CLangInfo::SetDefaults() m_defaultRegion.SetDefaults(); // Set the default region, we may be unable to load langinfo.xml - m_currentRegion=&m_defaultRegion; + m_currentRegion = &m_defaultRegion; - m_locale = std::locale::classic(); + m_systemLocale = std::locale::classic(); + + m_forceUnicodeFont = false; + m_strGuiCharSet = "CP1252"; + m_strSubtitleCharSet = "CP1252"; + m_strDVDMenuLanguage = "en"; + m_strDVDAudioLanguage = "en"; + m_strDVDSubtitleLanguage = "en"; + m_sortTokens.clear(); m_languageCodeGeneral = "eng"; } std::string CLangInfo::GetGuiCharSet() const { - std::string strCharSet; - strCharSet=CSettings::Get().GetString("locale.charset"); - if (strCharSet=="DEFAULT") - strCharSet=m_currentRegion->m_strGuiCharSet; + CSettingString* charsetSetting = static_cast(CSettings::Get().GetSetting("locale.charset")); + if (charsetSetting->IsDefault()) + return m_strGuiCharSet; - return strCharSet; + return charsetSetting->GetValue(); } std::string CLangInfo::GetSubtitleCharSet() const { - std::string strCharSet=CSettings::Get().GetString("subtitles.charset"); - if (strCharSet=="DEFAULT") - strCharSet=m_currentRegion->m_strSubtitleCharSet; + CSettingString* charsetSetting = static_cast(CSettings::Get().GetSetting("subtitles.charset")); + if (charsetSetting->IsDefault()) + return m_strSubtitleCharSet; - return strCharSet; + return charsetSetting->GetValue(); } -bool CLangInfo::SetLanguage(const std::string &strLanguage) +LanguageResourcePtr CLangInfo::GetLanguageAddon(const std::string& locale /* = "" */) const { - string strLangInfoPath = StringUtils::Format("special://xbmc/language/%s/langinfo.xml", strLanguage.c_str()); - if (!Load(strLangInfoPath)) + if (locale.empty() || + (m_languageAddon != NULL && (locale.compare(m_languageAddon->ID()) == 0 || m_languageAddon->GetLocale().Equals(locale)))) + return m_languageAddon; + + std::string addonId = ADDON::CLanguageResource::GetAddonId(locale); + if (addonId.empty()) + addonId = CSettings::Get().GetString("locale.language"); + + ADDON::AddonPtr addon; + if (ADDON::CAddonMgr::Get().GetAddon(addonId, addon, ADDON::ADDON_RESOURCE_LANGUAGE, true) && addon != NULL) + return std::dynamic_pointer_cast(addon); + + return NULL; +} + +std::string CLangInfo::GetEnglishLanguageName(const std::string& locale /* = "" */) const +{ + LanguageResourcePtr addon = GetLanguageAddon(locale); + if (addon == NULL) + return ""; + + return addon->Name(); +} + +bool CLangInfo::SetLanguage(const std::string &strLanguage /* = "" */, bool reloadServices /* = true */) +{ + bool fallback; + return SetLanguage(fallback, strLanguage, reloadServices); +} + +bool CLangInfo::SetLanguage(bool& fallback, const std::string &strLanguage /* = "" */, bool reloadServices /* = true */) +{ + fallback = false; + + std::string language = strLanguage; + if (language.empty()) + { + language = CSettings::Get().GetString("locale.language"); + + if (language.empty()) + { + CLog::Log(LOGFATAL, "CLangInfo: cannot load empty language."); + return false; + } + } + + LanguageResourcePtr languageAddon = GetLanguageAddon(language); + if (languageAddon == NULL) + { + CLog::Log(LOGINFO, "CLangInfo: unable to load language \"%s\". Trying to determine matching language addon...", language.c_str()); + + // we may have to fall back to the default language + std::string defaultLanguage = static_cast(CSettings::Get().GetSetting("locale.language"))->GetDefault(); + std::string newLanguage = defaultLanguage; + + // try to determine a language addon matching the given language in name + if (!ADDON::CLanguageResource::FindLanguageAddonByName(language, newLanguage)) + { + CLog::Log(LOGERROR, "CLangInfo: unable to find language addon matching \"%s\". Falling back to default language.", language.c_str()); + + CAddonDatabase addondb; + if (addondb.Open()) + { + // update the addon repositories to check if there's a matching language addon available for download + CAddonInstaller::Get().UpdateRepos(true, true); + + ADDON::VECADDONS languageAddons; + if (addondb.GetAddons(languageAddons, ADDON::ADDON_RESOURCE_LANGUAGE) && !languageAddons.empty()) + { + // try to get the proper language addon by its name from all available language addons + if (ADDON::CLanguageResource::FindLanguageAddonByName(language, newLanguage, languageAddons)) + { + if (CAddonInstaller::Get().Install(newLanguage, true, "", false, false)) + CLog::Log(LOGINFO, "CLangInfo: successfully installed language addon \"%s\" matching current language \"%s\"", newLanguage.c_str(), language.c_str()); + else + CLog::Log(LOGERROR, "CLangInfo: failed to installed language addon \"%s\" matching current language \"%s\"", newLanguage.c_str(), language.c_str()); + } + else + CLog::Log(LOGERROR, "CLangInfo: unable to match old language \"%s\" to any available language addon", language.c_str()); + } + else + CLog::Log(LOGERROR, "CLangInfo: no language addons available to match against \"%s\"", language.c_str()); + } + else + CLog::Log(LOGERROR, "CLangInfo: unable to open addon database to look for a language addon matching \"%s\"", language.c_str()); + } + + // if the new language matches the default language we are loading the + // default language as a fallback + if (newLanguage == defaultLanguage) + { + CLog::Log(LOGINFO, "CLangInfo: fall back to the default language \"%s\"", defaultLanguage.c_str()); + fallback = true; + } + + if (!CSettings::Get().SetString("locale.language", newLanguage)) + return false; + + CSettings::Get().Save(); + return true; + } + + CLog::Log(LOGINFO, "CLangInfo: loading %s language information...", language.c_str()); + if (!Load(language)) + { + CLog::LogF(LOGFATAL, "CLangInfo: failed to load %s language information", language.c_str()); return false; + } - if (!g_localizeStrings.Load("special://xbmc/language/", strLanguage)) + CLog::Log(LOGINFO, "CLangInfo: loading %s language strings...", language.c_str()); + if (!g_localizeStrings.Load(GetLanguagePath(), language)) + { + CLog::LogF(LOGFATAL, "CLangInfo: failed to load %s language strings", language.c_str()); return false; + } - // also tell our weather and skin to reload as these are localized - g_weatherManager.Refresh(); - g_PVRManager.LocalizationChanged(); - CApplicationMessenger::Get().ExecBuiltIn("ReloadSkin", false); + if (reloadServices) + { + // also tell our weather and skin to reload as these are localized + g_weatherManager.Refresh(); + g_PVRManager.LocalizationChanged(); + CApplicationMessenger::Get().ExecBuiltIn("ReloadSkin", false); + } return true; } bool CLangInfo::CheckLoadLanguage(const std::string &language) { - return Load("special://xbmc/language/" + language + "/langinfo.xml", true); + return Load(language, true); } // three char language code (not win32 specific) @@ -510,7 +643,7 @@ const std::string CLangInfo::GetDVDMenuLanguage() const { std::string code; if (!g_LangCodeExpander.ConvertToTwoCharCode(code, m_currentRegion->m_strLangLocaleName)) - code = m_currentRegion->m_strDVDMenuLanguage; + code = m_strDVDMenuLanguage; return code; } @@ -520,7 +653,7 @@ const std::string CLangInfo::GetDVDAudioLanguage() const { std::string code; if (!g_LangCodeExpander.ConvertToTwoCharCode(code, m_audioLanguage)) - code = m_currentRegion->m_strDVDAudioLanguage; + code = m_strDVDAudioLanguage; return code; } @@ -530,14 +663,18 @@ const std::string CLangInfo::GetDVDSubtitleLanguage() const { std::string code; if (!g_LangCodeExpander.ConvertToTwoCharCode(code, m_subtitleLanguage)) - code = m_currentRegion->m_strDVDSubtitleLanguage; + code = m_strDVDSubtitleLanguage; return code; } -const std::string& CLangInfo::GetLanguageLocale() const +const CLocale& CLangInfo::GetLocale() const { - return m_currentRegion->m_strLangLocaleCodeTwoChar; + LanguageResourcePtr language = GetLanguageAddon(); + if (language != NULL) + return language->GetLocale(); + + return CLocale::Empty; } const std::string& CLangInfo::GetRegionLocale() const @@ -626,6 +763,27 @@ const std::string& CLangInfo::GetSpeedUnitString() const return g_localizeStrings.Get(SPEED_UNIT_STRINGS+m_currentRegion->m_speedUnit); } +std::set CLangInfo::GetSortTokens() const +{ + std::set sortTokens = m_sortTokens; + sortTokens.insert(g_advancedSettings.m_vecTokens.begin(), g_advancedSettings.m_vecTokens.end()); + + return sortTokens; +} + +void CLangInfo::SettingOptionsLanguageNamesFiller(const CSetting *setting, std::vector< std::pair > &list, std::string ¤t, void *data) +{ + // find languages... + ADDON::VECADDONS addons; + if (!ADDON::CAddonMgr::Get().GetAddons(ADDON::ADDON_RESOURCE_LANGUAGE, addons, true)) + return; + + for (ADDON::VECADDONS::const_iterator addon = addons.begin(); addon != addons.end(); ++addon) + list.push_back(make_pair((*addon)->Name(), (*addon)->Name())); + + sort(list.begin(), list.end(), SortLanguage()); +} + void CLangInfo::SettingOptionsStreamLanguagesFiller(const CSetting *setting, std::vector< std::pair > &list, std::string ¤t, void *data) { list.push_back(make_pair(g_localizeStrings.Get(308), "original")); diff --git a/xbmc/LangInfo.h b/xbmc/LangInfo.h index 84c95639b4472..9b371381f2522 100644 --- a/xbmc/LangInfo.h +++ b/xbmc/LangInfo.h @@ -21,8 +21,11 @@ #include "settings/lib/ISettingCallback.h" #include "utils/GlobalsHandling.h" +#include "utils/Locale.h" #include +#include +#include #include #include #include @@ -38,6 +41,12 @@ class TiXmlNode; +namespace ADDON +{ + class CLanguageResource; +} +typedef std::shared_ptr LanguageResourcePtr; + class CLangInfo : public ISettingCallback { public: @@ -46,7 +55,15 @@ class CLangInfo : public ISettingCallback virtual void OnSettingChanged(const CSetting *setting); - bool Load(const std::string& strFileName, bool onlyCheckLanguage = false); + bool Load(const std::string& strLanguage, bool onlyCheckLanguage = false); + + /*! + \brief Returns the language addon for the given locale (or the current one). + + \param locale (optional) Locale of the language (current if empty) + \return Language addon for the given locale or NULL if the locale is invalid. + */ + LanguageResourcePtr GetLanguageAddon(const std::string& locale = "") const; std::string GetGuiCharSet() const; std::string GetSubtitleCharSet() const; @@ -54,7 +71,30 @@ class CLangInfo : public ISettingCallback // three char language code (not win32 specific) const std::string& GetLanguageCode() const { return m_languageCodeGeneral; } - bool SetLanguage(const std::string &strLanguage); + /*! + \brief Returns the given language's name in English + + \param locale (optional) Locale of the language (current if empty) + */ + std::string GetEnglishLanguageName(const std::string& locale = "") const; + + /*! + \brief Sets and loads the given (or configured) language, its details and strings. + + \param strLanguage (optional) Language to be loaded. + \param reloadServices (optional) Whether to reload services relying on localization. + \return True if the language has been successfully loaded, false otherwise. + */ + bool SetLanguage(const std::string &strLanguage = "", bool reloadServices = true); + /*! + \brief Sets and loads the given (or configured) language, its details and strings. + + \param fallback Whether the fallback language has been loaded instead of the given language. + \param strLanguage (optional) Language to be loaded. + \param reloadServices (optional) Whether to reload services relying on localization. + \return True if the language has been successfully loaded, false otherwise. + */ + bool SetLanguage(bool& fallback, const std::string &strLanguage = "", bool reloadServices = true); bool CheckLoadLanguage(const std::string &language); const std::string& GetAudioLanguage() const; @@ -78,11 +118,16 @@ class CLangInfo : public ISettingCallback const std::string& GetRegionLocale() const; /*! - \brief Returns the two character ISO 639-1 language code of the current language. + \brief Returns the full locale of the current language. + */ + const CLocale& GetLocale() const; + + /*! + \brief Returns the system's current locale. */ - const std::string& GetLanguageLocale() const; + const std::locale& GetSystemLocale() const { return m_systemLocale; } - bool ForceUnicodeFont() const { return m_currentRegion->m_forceUnicodeFont; } + bool ForceUnicodeFont() const { return m_forceUnicodeFont; } const std::string& GetDateFormat(bool bLongDate=false) const; @@ -135,13 +180,17 @@ class CLangInfo : public ISettingCallback void SetCurrentRegion(const std::string& strName); const std::string& GetCurrentRegion() const; - const std::locale& GetLocale() const - { return m_locale; } + std::set GetSortTokens() const; + + static std::string GetLanguagePath() { return "resource://"; } + static std::string GetLanguagePath(const std::string &language); + static std::string GetLanguageInfoPath(const std::string &language); static bool CheckLanguage(const std::string& language); - static void LoadTokens(const TiXmlNode* pTokens, std::vector& vecTokens); + static void LoadTokens(const TiXmlNode* pTokens, std::set& vecTokens); + static void SettingOptionsLanguageNamesFiller(const CSetting *setting, std::vector< std::pair > &list, std::string ¤t, void *data); static void SettingOptionsStreamLanguagesFiller(const CSetting *setting, std::vector< std::pair > &list, std::string ¤t, void *data); static void SettingOptionsRegionsFiller(const CSetting *setting, std::vector< std::pair > &list, std::string ¤t, void *data); @@ -159,15 +208,9 @@ class CLangInfo : public ISettingCallback void SetSpeedUnit(const std::string& strUnit); void SetTimeZone(const std::string& strTimeZone); void SetGlobalLocale(); - std::string m_strGuiCharSet; - std::string m_strSubtitleCharSet; - std::string m_strDVDMenuLanguage; - std::string m_strDVDAudioLanguage; - std::string m_strDVDSubtitleLanguage; std::string m_strLangLocaleName; std::string m_strLangLocaleCodeTwoChar; std::string m_strRegionLocaleName; - bool m_forceUnicodeFont; std::string m_strName; std::string m_strDateFormatLong; std::string m_strDateFormatShort; @@ -186,7 +229,17 @@ class CLangInfo : public ISettingCallback MAPREGIONS m_regions; CRegion* m_currentRegion; // points to the current region CRegion m_defaultRegion; // default, will be used if no region available via langinfo.xml - std::locale m_locale; // current locale, matching GUI settings + std::locale m_systemLocale; // current locale, matching GUI settings + + LanguageResourcePtr m_languageAddon; + + std::string m_strGuiCharSet; + bool m_forceUnicodeFont; + std::string m_strSubtitleCharSet; + std::string m_strDVDMenuLanguage; + std::string m_strDVDAudioLanguage; + std::string m_strDVDSubtitleLanguage; + std::set m_sortTokens; std::string m_audioLanguage; std::string m_subtitleLanguage; diff --git a/xbmc/guilib/LocalizeStrings.cpp b/xbmc/guilib/LocalizeStrings.cpp index a90938139d83e..4f04a02c26e1b 100644 --- a/xbmc/guilib/LocalizeStrings.cpp +++ b/xbmc/guilib/LocalizeStrings.cpp @@ -20,6 +20,7 @@ #include "system.h" #include "LocalizeStrings.h" +#include "addons/LanguageResource.h" #include "utils/CharsetConverter.h" #include "utils/log.h" #include "filesystem/SpecialProtocol.h" @@ -63,13 +64,13 @@ bool CLocalizeStrings::LoadSkinStrings(const std::string& path, const std::strin std::string encoding; if (!LoadStr2Mem(path, language, encoding)) { - if (StringUtils::EqualsNoCase(language, SOURCE_LANGUAGE)) // no fallback, nothing to do + if (StringUtils::EqualsNoCase(language, ADDON_LANGUAGE_DEFAULT)) // no fallback, nothing to do return false; } // load the fallback - if (!StringUtils::EqualsNoCase(language, SOURCE_LANGUAGE)) - LoadStr2Mem(path, SOURCE_LANGUAGE, encoding); + if (!StringUtils::EqualsNoCase(language, ADDON_LANGUAGE_DEFAULT)) + LoadStr2Mem(path, ADDON_LANGUAGE_DEFAULT, encoding); return true; } @@ -80,14 +81,26 @@ bool CLocalizeStrings::LoadStr2Mem(const std::string &pathname_in, const std::st std::string pathname = CSpecialProtocol::TranslatePathConvertCase(pathname_in + language); if (!XFILE::CDirectory::Exists(pathname)) { - CLog::Log(LOGDEBUG, - "LocalizeStrings: no translation available in currently set gui language, at path %s", - pathname.c_str()); - return false; + bool exists = false; + std::string lang; + // check if there's a language addon using the old language naming convention + if (ADDON::CLanguageResource::FindLegacyLanguage(language, lang)) + { + pathname = CSpecialProtocol::TranslatePathConvertCase(pathname_in + lang); + exists = XFILE::CDirectory::Exists(pathname); + } + + if (!exists) + { + CLog::Log(LOGDEBUG, + "LocalizeStrings: no translation available in currently set gui language, at path %s", + pathname.c_str()); + return false; + } } if (LoadPO(URIUtils::AddFileToFolder(pathname, "strings.po"), encoding, offset, - StringUtils::EqualsNoCase(language, SOURCE_LANGUAGE))) + StringUtils::EqualsNoCase(language, CORE_LANGUAGE_DEFAULT) || StringUtils::EqualsNoCase(language, ADDON_LANGUAGE_DEFAULT))) return true; CLog::Log(LOGDEBUG, "LocalizeStrings: no strings.po file exist at %s, fallback to strings.xml", @@ -185,7 +198,7 @@ bool CLocalizeStrings::LoadXML(const std::string &filename, std::string &encodin bool CLocalizeStrings::Load(const std::string& strPathName, const std::string& strLanguage) { - bool bLoadFallback = !StringUtils::EqualsNoCase(strLanguage, SOURCE_LANGUAGE); + bool bLoadFallback = !StringUtils::EqualsNoCase(strLanguage, CORE_LANGUAGE_DEFAULT); std::string encoding; CSingleLock lock(m_critSection); @@ -194,14 +207,14 @@ bool CLocalizeStrings::Load(const std::string& strPathName, const std::string& s if (!LoadStr2Mem(strPathName, strLanguage, encoding)) { // try loading the fallback - if (!bLoadFallback || !LoadStr2Mem(strPathName, SOURCE_LANGUAGE, encoding)) + if (!bLoadFallback || !LoadStr2Mem(strPathName, CORE_LANGUAGE_DEFAULT, encoding)) return false; bLoadFallback = false; } if (bLoadFallback) - LoadStr2Mem(strPathName, SOURCE_LANGUAGE, encoding); + LoadStr2Mem(strPathName, CORE_LANGUAGE_DEFAULT, encoding); // fill in the constant strings m_strings[20022].strTranslated = ""; diff --git a/xbmc/guilib/LocalizeStrings.h b/xbmc/guilib/LocalizeStrings.h index d161414ffd145..9d1c90c94abdd 100644 --- a/xbmc/guilib/LocalizeStrings.h +++ b/xbmc/guilib/LocalizeStrings.h @@ -46,7 +46,8 @@ struct LocStr }; // The default fallback language is fixed to be English -const std::string SOURCE_LANGUAGE = "English"; +const std::string CORE_LANGUAGE_DEFAULT = "resource.language.en_gb"; +const std::string ADDON_LANGUAGE_DEFAULT = "English"; class CLocalizeStrings { @@ -58,6 +59,7 @@ class CLocalizeStrings void ClearSkinStrings(); const std::string& Get(uint32_t code) const; void Clear(); + protected: void Clear(uint32_t start, uint32_t end); diff --git a/xbmc/interfaces/legacy/ModuleXbmc.cpp b/xbmc/interfaces/legacy/ModuleXbmc.cpp index 56691aa1df5cf..e4be5b033b9d7 100644 --- a/xbmc/interfaces/legacy/ModuleXbmc.cpp +++ b/xbmc/interfaces/legacy/ModuleXbmc.cpp @@ -178,7 +178,7 @@ namespace XBMCAddon String getLanguage(int format /* = CLangCodeExpander::ENGLISH_NAME */, bool region /*= false*/) { XBMC_TRACE; - std::string lang = CSettings::Get().GetString("locale.language"); + std::string lang = g_langInfo.GetEnglishLanguageName(); switch (format) { diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp index 819177a7258f3..b3c9d07b2d827 100644 --- a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp +++ b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp @@ -557,49 +557,49 @@ void CPeripheralCecAdapter::SetMenuLanguage(const char *strLanguage) std::string strGuiLanguage; if (!strcmp(strLanguage, "bul")) - strGuiLanguage = "Bulgarian"; + strGuiLanguage = "bg_bg"; else if (!strcmp(strLanguage, "hrv")) - strGuiLanguage = "Croatian"; + strGuiLanguage = "hr_hr"; else if (!strcmp(strLanguage, "cze")) - strGuiLanguage = "Czech"; + strGuiLanguage = "cs_cz"; else if (!strcmp(strLanguage, "dan")) - strGuiLanguage = "Danish"; + strGuiLanguage = "da_dk"; else if (!strcmp(strLanguage, "dut")) - strGuiLanguage = "Dutch"; + strGuiLanguage = "nl_nl"; else if (!strcmp(strLanguage, "eng")) - strGuiLanguage = "English"; + strGuiLanguage = "en_gb"; else if (!strcmp(strLanguage, "fin")) - strGuiLanguage = "Finnish"; + strGuiLanguage = "fi_fi"; else if (!strcmp(strLanguage, "fre")) - strGuiLanguage = "French"; + strGuiLanguage = "fr_fr"; else if (!strcmp(strLanguage, "ger")) - strGuiLanguage = "German"; + strGuiLanguage = "de_de"; else if (!strcmp(strLanguage, "gre")) - strGuiLanguage = "Greek"; + strGuiLanguage = "el_gr"; else if (!strcmp(strLanguage, "hun")) - strGuiLanguage = "Hungarian"; + strGuiLanguage = "hu_hu"; else if (!strcmp(strLanguage, "ita")) - strGuiLanguage = "Italian"; + strGuiLanguage = "it_it"; else if (!strcmp(strLanguage, "nor")) - strGuiLanguage = "Norwegian"; + strGuiLanguage = "nb_no"; else if (!strcmp(strLanguage, "pol")) - strGuiLanguage = "Polish"; + strGuiLanguage = "pl_pl"; else if (!strcmp(strLanguage, "por")) - strGuiLanguage = "Portuguese"; + strGuiLanguage = "pt_pt"; else if (!strcmp(strLanguage, "rum")) - strGuiLanguage = "Romanian"; + strGuiLanguage = "ro_ro"; else if (!strcmp(strLanguage, "rus")) - strGuiLanguage = "Russian"; + strGuiLanguage = "ru_ru"; else if (!strcmp(strLanguage, "srp")) - strGuiLanguage = "Serbian"; + strGuiLanguage = "sr_rs@latin"; else if (!strcmp(strLanguage, "slo")) - strGuiLanguage = "Slovenian"; + strGuiLanguage = "sl_si"; else if (!strcmp(strLanguage, "spa")) - strGuiLanguage = "Spanish"; + strGuiLanguage = "es_es"; else if (!strcmp(strLanguage, "swe")) - strGuiLanguage = "Swedish"; + strGuiLanguage = "sv_se"; else if (!strcmp(strLanguage, "tur")) - strGuiLanguage = "Turkish"; + strGuiLanguage = "tr_tr"; if (!strGuiLanguage.empty()) { diff --git a/xbmc/profiles/ProfilesManager.cpp b/xbmc/profiles/ProfilesManager.cpp index 5098fb6987c9f..e48cfa409f78d 100644 --- a/xbmc/profiles/ProfilesManager.cpp +++ b/xbmc/profiles/ProfilesManager.cpp @@ -27,6 +27,7 @@ #include "LangInfo.h" #include "PasswordManager.h" #include "Util.h" +#include "dialogs/GUIDialogOK.h" #include "dialogs/GUIDialogYesNo.h" #include "filesystem/Directory.h" #include "filesystem/DirectoryCache.h" @@ -249,27 +250,14 @@ bool CProfilesManager::LoadProfile(size_t index) CreateProfileFolders(); - // Load the langinfo to have user charset <-> utf-8 conversion - string strLanguage = CSettings::Get().GetString("locale.language"); - strLanguage[0] = toupper(strLanguage[0]); - - string strLangInfoPath = StringUtils::Format("special://xbmc/language/%s/langinfo.xml", strLanguage.c_str()); - CLog::Log(LOGINFO, "CProfilesManager: load language info file: %s", strLangInfoPath.c_str()); - g_langInfo.Load(strLangInfoPath); - - CButtonTranslator::GetInstance().Load(true); - g_localizeStrings.Load("special://xbmc/language/", strLanguage); - CDatabaseManager::Get().Initialize(); + CButtonTranslator::GetInstance().Load(true); CInputManager::Get().SetMouseEnabled(CSettings::Get().GetBool("input.enablemouse")); g_infoManager.ResetCache(); g_infoManager.ResetLibraryBools(); - // always reload the skin - we need it for the new language strings - g_application.ReloadSkin(); - if (m_currentProfile != 0) { CXBMCTinyXML doc; diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h index b9d98b271f9a3..da319ab1e9f12 100644 --- a/xbmc/settings/AdvancedSettings.h +++ b/xbmc/settings/AdvancedSettings.h @@ -19,6 +19,7 @@ * */ +#include #include #include @@ -286,7 +287,7 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler bool m_bVideoScannerIgnoreErrors; int m_iVideoLibraryDateAdded; - std::vector m_vecTokens; // cleaning strings tied to language + std::set m_vecTokens; //TuxBox int m_iTuxBoxStreamtsPort; bool m_bTuxBoxSubMenuSelection; diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp index c40b18f965765..56b3c0fa086a1 100644 --- a/xbmc/settings/Settings.cpp +++ b/xbmc/settings/Settings.cpp @@ -229,6 +229,7 @@ void CSettings::Uninitialize() m_settingsManager->UnregisterSettingOptionsFiller("epgguideviews"); m_settingsManager->UnregisterSettingOptionsFiller("fontheights"); m_settingsManager->UnregisterSettingOptionsFiller("fonts"); + m_settingsManager->UnregisterSettingOptionsFiller("languagenames"); m_settingsManager->UnregisterSettingOptionsFiller("refreshchangedelays"); m_settingsManager->UnregisterSettingOptionsFiller("refreshrates"); m_settingsManager->UnregisterSettingOptionsFiller("regions"); @@ -571,6 +572,7 @@ void CSettings::InitializeOptionFillers() m_settingsManager->RegisterSettingOptionsFiller("audiostreamsilence", CAEFactory::SettingOptionsAudioStreamsilenceFiller); m_settingsManager->RegisterSettingOptionsFiller("charsets", CCharsetConverter::SettingOptionsCharsetsFiller); m_settingsManager->RegisterSettingOptionsFiller("fonts", GUIFontManager::SettingOptionsFontsFiller); + m_settingsManager->RegisterSettingOptionsFiller("languagenames", CLangInfo::SettingOptionsLanguageNamesFiller); m_settingsManager->RegisterSettingOptionsFiller("refreshchangedelays", CDisplaySettings::SettingOptionsRefreshChangeDelaysFiller); m_settingsManager->RegisterSettingOptionsFiller("refreshrates", CDisplaySettings::SettingOptionsRefreshRatesFiller); m_settingsManager->RegisterSettingOptionsFiller("regions", CLangInfo::SettingOptionsRegionsFiller); diff --git a/xbmc/utils/SortUtils.cpp b/xbmc/utils/SortUtils.cpp index a9fa99aa16696..73fd49db04335 100644 --- a/xbmc/utils/SortUtils.cpp +++ b/xbmc/utils/SortUtils.cpp @@ -19,6 +19,7 @@ */ #include "SortUtils.h" +#include "LangInfo.h" #include "URL.h" #include "Util.h" #include "XBDateTime.h" @@ -782,11 +783,11 @@ const Fields& SortUtils::GetFieldsForSorting(SortBy sortBy) string SortUtils::RemoveArticles(const string &label) { - for (unsigned int i = 0; i < g_advancedSettings.m_vecTokens.size(); ++i) + std::set sortTokens = g_langInfo.GetSortTokens(); + for (std::set::const_iterator token = sortTokens.begin(); token != sortTokens.end(); ++token) { - if (g_advancedSettings.m_vecTokens[i].size() < label.size() && - strnicmp(g_advancedSettings.m_vecTokens[i].c_str(), label.c_str(), g_advancedSettings.m_vecTokens[i].size()) == 0) - return label.substr(g_advancedSettings.m_vecTokens[i].size()); + if (token->size() < label.size() && StringUtils::StartsWith(label, *token)) + return label.substr(token->size()); } return label; diff --git a/xbmc/utils/StringUtils.cpp b/xbmc/utils/StringUtils.cpp index 6950bf66f5930..7dd344d08c0d7 100644 --- a/xbmc/utils/StringUtils.cpp +++ b/xbmc/utils/StringUtils.cpp @@ -741,7 +741,7 @@ int64_t StringUtils::AlphaNumericCompare(const wchar_t *left, const wchar_t *rig wchar_t *ld, *rd; wchar_t lc, rc; int64_t lnum, rnum; - const collate& coll = use_facet< collate >( g_langInfo.GetLocale() ); + const collate& coll = use_facet< collate >(g_langInfo.GetSystemLocale()); int cmp_res = 0; while (*l != 0 && *r != 0) { diff --git a/xbmc/utils/Weather.cpp b/xbmc/utils/Weather.cpp index d3d228acbb7b5..63f9b3125c95c 100644 --- a/xbmc/utils/Weather.cpp +++ b/xbmc/utils/Weather.cpp @@ -227,10 +227,14 @@ void CWeatherJob::FormatTemperature(std::string &text, int temp) void CWeatherJob::LoadLocalizedToken() { // We load the english strings in to get our tokens + std::string language = CORE_LANGUAGE_DEFAULT; + CSettingString* languageSetting = static_cast(CSettings::Get().GetSetting("locale.language")); + if (languageSetting != NULL) + language = languageSetting->GetDefault(); // Try the strings PO file first CPODocument PODoc; - if (PODoc.LoadFile("special://xbmc/language/English/strings.po")) + if (PODoc.LoadFile(URIUtils::AddFileToFolder(CLangInfo::GetLanguagePath(language), "strings.po"))) { int counter = 0; @@ -265,7 +269,7 @@ void CWeatherJob::LoadLocalizedToken() "fallback to strings.xml file"); // We load the tokens from the strings.xml file - std::string strLanguagePath = "special://xbmc/language/English/strings.xml"; + std::string strLanguagePath = URIUtils::AddFileToFolder(CLangInfo::GetLanguagePath(language), "strings.xml"); CXBMCTinyXML xmlDoc; if (!xmlDoc.LoadFile(strLanguagePath) || !xmlDoc.RootElement()) diff --git a/xbmc/video/dialogs/GUIDialogSubtitles.cpp b/xbmc/video/dialogs/GUIDialogSubtitles.cpp index 01d050331e05c..2d225a5009b20 100644 --- a/xbmc/video/dialogs/GUIDialogSubtitles.cpp +++ b/xbmc/video/dialogs/GUIDialogSubtitles.cpp @@ -22,6 +22,7 @@ #include "GUIUserMessages.h" #include "Application.h" #include "GUIDialogSubtitles.h" +#include "LangInfo.h" #include "addons/AddonManager.h" #include "cores/IPlayer.h" #include "dialogs/GUIDialogKaiToast.h" @@ -349,7 +350,7 @@ void CGUIDialogSubtitles::Search(const std::string &search/*=""*/) preferredLanguage = strLanguage; } else if (StringUtils::EqualsNoCase(preferredLanguage, "default")) - preferredLanguage = CSettings::Get().GetString("locale.language"); + preferredLanguage = g_langInfo.GetEnglishLanguageName(); url.SetOption("preferredlanguage", preferredLanguage); diff --git a/xbmc/windows/GUIWindowLoginScreen.cpp b/xbmc/windows/GUIWindowLoginScreen.cpp index e56e0dddd7f09..8e1864dd6a0b8 100644 --- a/xbmc/windows/GUIWindowLoginScreen.cpp +++ b/xbmc/windows/GUIWindowLoginScreen.cpp @@ -32,6 +32,7 @@ #include "interfaces/json-rpc/JSONRPC.h" #endif #include "interfaces/Builtins.h" +#include "utils/log.h" #include "utils/Weather.h" #include "utils/StringUtils.h" #include "network/Network.h" @@ -313,9 +314,19 @@ void CGUIWindowLoginScreen::LoadProfile(unsigned int profile) // reload the add-ons, or we will first load all add-ons from the master account without checking disabled status ADDON::CAddonMgr::Get().ReInit(); + bool fallbackLanguage = false; + if (!g_application.LoadLanguage(true, fallbackLanguage)) + { + CLog::Log(LOGFATAL, "CGUIWindowLoginScreen: unable to load language for profile \"%s\"", CProfilesManager::Get().GetCurrentProfile().getName().c_str()); + return; + } + g_weatherManager.Refresh(); g_application.SetLoggingIn(true); + if (fallbackLanguage) + CGUIDialogOK::ShowAndGetInput("Failed to load language", "We were unable to load your configured language. Please check your language settings."); + #ifdef HAS_JSONRPC JSONRPC::CJSONRPC::Initialize(); #endif