diff --git a/addons/kodi.resource/addon.xml b/addons/kodi.resource/addon.xml
new file mode 100644
index 0000000000000..8002e410c8dd2
--- /dev/null
+++ b/addons/kodi.resource/addon.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/addons/kodi.resource/language.xsd b/addons/kodi.resource/language.xsd
new file mode 100644
index 0000000000000..63d5cae3bb842
--- /dev/null
+++ b/addons/kodi.resource/language.xsd
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/language/English/strings.po b/language/English/strings.po
index e95433f75b562..4ccf60d6607a6 100644
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -12377,7 +12377,10 @@ msgctxt "#24025"
msgid "Context Items"
msgstr ""
-#empty string with id 24026
+#: xbmc/addons/Addon.cpp
+msgctxt "#24026"
+msgid "Languages"
+msgstr ""
#: xbmc/addons/Addon.cpp
msgctxt "#24027"
@@ -12896,7 +12899,12 @@ msgctxt "#24131"
msgid "Enable to parse for CC in video stream. Puts slightly more load on the CPU"
msgstr ""
-#empty strings from id 24132 to 24998
+#: xbmc/addons/LanguageResource.cpp
+msgctxt "#24132"
+msgid "Would you like to switch to this language?"
+msgstr ""
+
+#empty strings from id 24133 to 24998
msgctxt "#24999"
msgid "Hide incompatible"
diff --git a/xbmc/addons/Addon.cpp b/xbmc/addons/Addon.cpp
index bd4ad7bf59dc2..d59b099cece02 100644
--- a/xbmc/addons/Addon.cpp
+++ b/xbmc/addons/Addon.cpp
@@ -91,7 +91,8 @@ static const TypeMapping types[] =
{"xbmc.addon.executable", ADDON_EXECUTABLE, 1043, "DefaultAddonProgram.png" },
{"xbmc.audioencoder", ADDON_AUDIOENCODER, 200, "DefaultAddonAudioEncoder.png" },
{"kodi.audiodecoder", ADDON_AUDIODECODER, 201, "DefaultAddonAudioDecoder.png" },
- {"xbmc.service", ADDON_SERVICE, 24018, "DefaultAddonService.png" }};
+ {"xbmc.service", ADDON_SERVICE, 24018, "DefaultAddonService.png" },
+ {"kodi.resource.language", ADDON_RESOURCE_LANGUAGE, 24026, "DefaultAddonLanguage.png" }};
const std::string TranslateType(const ADDON::TYPE &type, bool pretty/*=false*/)
{
diff --git a/xbmc/addons/AddonManager.cpp b/xbmc/addons/AddonManager.cpp
index 67a7f62b1f33f..75d263442eb61 100644
--- a/xbmc/addons/AddonManager.cpp
+++ b/xbmc/addons/AddonManager.cpp
@@ -22,6 +22,7 @@
#include "AudioEncoder.h"
#include "AudioDecoder.h"
#include "DllLibCPluff.h"
+#include "LanguageResource.h"
#include "utils/StringUtils.h"
#include "utils/JobManager.h"
#include "threads/SingleLock.h"
@@ -172,6 +173,8 @@ AddonPtr CAddonMgr::Factory(const cp_extension_t *props)
}
case ADDON_SKIN:
return AddonPtr(new CSkinInfo(props));
+ case ADDON_RESOURCE_LANGUAGE:
+ return AddonPtr(new CLanguageResource(props));
case ADDON_VIZ_LIBRARY:
return AddonPtr(new CAddonLibrary(props));
case ADDON_REPOSITORY:
@@ -531,6 +534,9 @@ bool CAddonMgr::GetDefault(const TYPE &type, AddonPtr &addon)
case ADDON_WEB_INTERFACE:
setting = CSettings::Get().GetString("services.webskin");
break;
+ case ADDON_RESOURCE_LANGUAGE:
+ setting = CSettings::Get().GetString("locale.language");
+ break;
default:
return false;
}
@@ -562,6 +568,9 @@ bool CAddonMgr::SetDefault(const TYPE &type, const std::string &addonID)
case ADDON_SCRAPER_TVSHOWS:
CSettings::Get().SetString("scrapers.tvshowsdefault",addonID);
break;
+ case ADDON_RESOURCE_LANGUAGE:
+ CSettings::Get().SetString("locale.language", addonID);
+ break;
default:
return false;
}
@@ -759,6 +768,8 @@ AddonPtr CAddonMgr::AddonFromProps(AddonProps& addonProps)
return AddonPtr(new CAudioEncoder(addonProps));
case ADDON_AUDIODECODER:
return AddonPtr(new CAudioDecoder(addonProps));
+ case ADDON_RESOURCE_LANGUAGE:
+ return AddonPtr(new CLanguageResource(addonProps));
case ADDON_REPOSITORY:
return AddonPtr(new CRepository(addonProps));
case ADDON_CONTEXT_ITEM:
diff --git a/xbmc/addons/IAddon.h b/xbmc/addons/IAddon.h
index 8cbcd043ef518..576169cf4cc4f 100644
--- a/xbmc/addons/IAddon.h
+++ b/xbmc/addons/IAddon.h
@@ -52,6 +52,7 @@ namespace ADDON
ADDON_AUDIOENCODER,
ADDON_CONTEXT_ITEM,
ADDON_AUDIODECODER,
+ ADDON_RESOURCE_LANGUAGE,
ADDON_VIDEO, // virtual addon types
ADDON_AUDIO,
ADDON_IMAGE,
diff --git a/xbmc/addons/LanguageResource.cpp b/xbmc/addons/LanguageResource.cpp
new file mode 100644
index 0000000000000..d45450d78aec8
--- /dev/null
+++ b/xbmc/addons/LanguageResource.cpp
@@ -0,0 +1,200 @@
+/*
+* Copyright (C) 2005-2013 Team XBMC
+* http://xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, see
+* .
+*
+*/
+#include "LanguageResource.h"
+#include "LangInfo.h"
+#include "addons/AddonManager.h"
+#include "dialogs/GUIDialogKaiToast.h"
+#include "dialogs/GUIDialogYesNo.h"
+#include "guilib/GUIWindowManager.h"
+#include "settings/Settings.h"
+#include "utils/StringUtils.h"
+
+#define LANGUAGE_SETTING "locale.language"
+#define LANGUAGE_ADDON_PREFIX "resource.language."
+
+using namespace std;
+
+namespace ADDON
+{
+
+CLanguageResource::CLanguageResource(const cp_extension_t *ext)
+ : CResource(ext)
+{
+ m_forceUnicodeFont = false;
+ if (ext != NULL)
+ {
+ // parse attributes
+ std::string locale = CAddonMgr::Get().GetExtValue(ext->configuration, "@locale");
+ m_locale = CLocale::FromString(locale);
+
+ // parse
+ cp_cfg_element_t *charsetsElement = CAddonMgr::Get().GetExtElement(ext->configuration, "charsets");
+ if (charsetsElement != NULL)
+ {
+ m_charsetGui = CAddonMgr::Get().GetExtValue(charsetsElement, "gui");
+ m_forceUnicodeFont = CAddonMgr::Get().GetExtValue(charsetsElement, "gui@unicodefont") == "true";
+ m_charsetSubtitle = CAddonMgr::Get().GetExtValue(charsetsElement, "subtitle");
+ }
+
+ // parse
+ cp_cfg_element_t *dvdElement = CAddonMgr::Get().GetExtElement(ext->configuration, "dvd");
+ if (dvdElement != NULL)
+ {
+ m_dvdLanguageMenu = CAddonMgr::Get().GetExtValue(dvdElement, "menu");
+ m_dvdLanguageAudio = CAddonMgr::Get().GetExtValue(dvdElement, "audio");
+ m_dvdLanguageSubtitle = CAddonMgr::Get().GetExtValue(dvdElement, "subtitle");
+ }
+ // fall back to the language of the addon if a DVD language is not defined
+ if (m_dvdLanguageMenu.empty())
+ m_dvdLanguageMenu = m_locale.GetLanguageCode();
+ if (m_dvdLanguageAudio.empty())
+ m_dvdLanguageAudio = m_locale.GetLanguageCode();
+ if (m_dvdLanguageSubtitle.empty())
+ m_dvdLanguageSubtitle = m_locale.GetLanguageCode();
+
+ // parse
+ cp_cfg_element_t *sorttokensElement = CAddonMgr::Get().GetExtElement(ext->configuration, "sorttokens");
+ if (sorttokensElement != NULL)
+ {
+ for (size_t i = 0; i < sorttokensElement->num_children; ++i)
+ {
+ cp_cfg_element_t &tokenElement = sorttokensElement->children[i];
+ if (tokenElement.name != NULL && strcmp(tokenElement.name, "token") == 0 &&
+ tokenElement.value != NULL)
+ {
+ std::string token(tokenElement.value);
+ std::string separators = CAddonMgr::Get().GetExtValue(&tokenElement, "@separators");
+ if (separators.empty())
+ separators = " ._";
+
+ for (std::string::const_iterator separator = separators.begin(); separator != separators.end(); ++separator)
+ m_sortTokens.insert(token + *separator);
+ }
+ }
+ }
+ }
+}
+
+CLanguageResource::CLanguageResource(const CLanguageResource &rhs)
+ : CResource(rhs),
+ m_locale(rhs.m_locale)
+{ }
+
+AddonPtr CLanguageResource::Clone() const
+{
+ return AddonPtr(new CLanguageResource(*this));
+}
+
+bool CLanguageResource::IsInUse() const
+{
+ return StringUtils::EqualsNoCase(CSettings::Get().GetString(LANGUAGE_SETTING), ID());
+}
+
+bool CLanguageResource::OnPreInstall()
+{
+ return IsInUse();
+}
+
+void CLanguageResource::OnPostInstall(bool restart, bool update)
+{
+ if (restart ||
+ (!update && CGUIDialogYesNo::ShowAndGetInput(Name(), g_localizeStrings.Get(24132), "", "")))
+ {
+ CGUIDialogKaiToast *toast = (CGUIDialogKaiToast *)g_windowManager.GetWindow(WINDOW_DIALOG_KAI_TOAST);
+ if (toast)
+ {
+ toast->ResetTimer();
+ toast->Close(true);
+ }
+
+ if (IsInUse())
+ g_langInfo.SetLanguage(ID());
+ else
+ CSettings::Get().SetString(LANGUAGE_SETTING, ID());
+ }
+}
+
+bool CLanguageResource::IsAllowed(const std::string &file) const
+{
+ return file.empty() ||
+ StringUtils::EqualsNoCase(file.c_str(), "langinfo.xml") ||
+ StringUtils::EqualsNoCase(file.c_str(), "strings.po") ||
+ StringUtils::EqualsNoCase(file.c_str(), "strings.xml");
+}
+
+std::string CLanguageResource::GetAddonId(const std::string& locale)
+{
+ if (locale.empty())
+ return "";
+
+ std::string addonId = locale;
+ if (!StringUtils::StartsWith(addonId, LANGUAGE_ADDON_PREFIX))
+ addonId = LANGUAGE_ADDON_PREFIX + locale;
+
+ StringUtils::ToLower(addonId);
+ return addonId;
+}
+
+bool CLanguageResource::FindLegacyLanguage(const std::string &locale, std::string &legacyLanguage)
+{
+ if (locale.empty())
+ return false;
+
+ std::string addonId = GetAddonId(locale);
+
+ AddonPtr addon;
+ if (!CAddonMgr::Get().GetAddon(addonId, addon, ADDON_RESOURCE_LANGUAGE, true))
+ return false;
+
+ legacyLanguage = addon->Name();
+ return true;
+}
+
+bool CLanguageResource::FindLanguageAddonByName(const std::string &legacyLanguage, std::string &addonId, const VECADDONS &languageAddons /* = VECADDONS() */)
+{
+ if (legacyLanguage.empty())
+ return false;
+
+ VECADDONS addons;
+ if (!languageAddons.empty())
+ addons = languageAddons;
+ else if (!CAddonMgr::Get().GetAddons(ADDON_RESOURCE_LANGUAGE, addons, true) || addons.empty())
+ return false;
+
+ // try to find a language that matches the old language in name or id
+ for (VECADDONS::const_iterator addon = addons.begin(); addon != addons.end(); ++addon)
+ {
+ const CLanguageResource* languageAddon = static_cast(addon->get());
+
+ // check if the old language matches the language addon id, the language
+ // locale or the language addon name
+ if (legacyLanguage.compare((*addon)->ID()) == 0 ||
+ languageAddon->GetLocale().Equals(legacyLanguage) ||
+ StringUtils::EqualsNoCase(legacyLanguage, languageAddon->Name()))
+ {
+ addonId = (*addon)->ID();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+}
diff --git a/xbmc/addons/LanguageResource.h b/xbmc/addons/LanguageResource.h
new file mode 100644
index 0000000000000..8167fb60195be
--- /dev/null
+++ b/xbmc/addons/LanguageResource.h
@@ -0,0 +1,80 @@
+#pragma once
+/*
+ * Copyright (C) 2014 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * .
+ *
+ */
+
+#include
+
+#include "addons/Resource.h"
+#include "utils/Locale.h"
+
+namespace ADDON
+{
+class CLanguageResource : public CResource
+{
+public:
+ CLanguageResource(const AddonProps &props)
+ : CResource(props)
+ { }
+ CLanguageResource(const cp_extension_t *ext);
+ virtual ~CLanguageResource() { }
+
+ virtual AddonPtr Clone() const;
+
+ virtual bool IsInUse() const;
+
+ virtual bool OnPreInstall();
+ virtual void OnPostInstall(bool restart, bool update);
+
+ virtual bool IsAllowed(const std::string &file) const;
+
+ const CLocale& GetLocale() const { return m_locale; }
+
+ const std::string& GetGuiCharset() const { return m_charsetGui; }
+ bool ForceUnicodeFont() const { return m_forceUnicodeFont; }
+ const std::string& GetSubtitleCharset() const { return m_charsetSubtitle; }
+
+ const std::string& GetDvdMenuLanguage() const { return m_dvdLanguageMenu; }
+ const std::string& GetDvdAudioLanguage() const { return m_dvdLanguageAudio; }
+ const std::string& GetDvdSubtitleLanguage() const { return m_dvdLanguageSubtitle; }
+
+ const std::set& GetSortTokens() const { return m_sortTokens; }
+
+ static std::string GetAddonId(const std::string& locale);
+
+ static bool FindLegacyLanguage(const std::string &locale, std::string &legacyLanguage);
+ static bool FindLanguageAddonByName(const std::string &legacyLanguage, std::string &addonId, const VECADDONS &languageAddons = VECADDONS());
+
+private:
+ CLanguageResource(const CLanguageResource &rhs);
+
+ CLocale m_locale;
+
+ std::string m_charsetGui;
+ bool m_forceUnicodeFont;
+ std::string m_charsetSubtitle;
+
+ std::string m_dvdLanguageMenu;
+ std::string m_dvdLanguageAudio;
+ std::string m_dvdLanguageSubtitle;
+
+ std::set m_sortTokens;
+};
+
+}
diff --git a/xbmc/addons/Makefile b/xbmc/addons/Makefile
index e8eca6ad05049..6ab60b733409c 100644
--- a/xbmc/addons/Makefile
+++ b/xbmc/addons/Makefile
@@ -16,6 +16,7 @@ SRCS=Addon.cpp \
GUIDialogAddonSettings.cpp \
GUIViewStateAddonBrowser.cpp \
GUIWindowAddonBrowser.cpp \
+ LanguageResource.cpp \
PluginSource.cpp \
Repository.cpp \
Scraper.cpp \
diff --git a/xbmc/addons/Resource.h b/xbmc/addons/Resource.h
new file mode 100644
index 0000000000000..4e4884e9987b7
--- /dev/null
+++ b/xbmc/addons/Resource.h
@@ -0,0 +1,50 @@
+#pragma once
+/*
+ * Copyright (C) 2014 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * .
+ *
+ */
+
+#include
+
+#include "addons/Addon.h"
+
+namespace ADDON
+{
+
+class CResource : public CAddon
+{
+public:
+ virtual ~CResource() { }
+
+ virtual AddonPtr Clone() const = 0;
+
+ virtual bool IsAllowed(const std::string &file) const = 0;
+
+protected:
+ CResource(const AddonProps &props)
+ : CAddon(props)
+ { }
+ CResource(const cp_extension_t *ext)
+ : CAddon(ext)
+ { }
+ CResource(const CResource &rhs)
+ : CAddon(rhs)
+ { }
+};
+
+}