From 19ca1e3ebfb54b5665cb1eecc87827373de6cec3 Mon Sep 17 00:00:00 2001 From: sanderd17 Date: Wed, 7 May 2014 08:14:57 +0000 Subject: [PATCH] Fix locale verification to also allow ICU locales without data, but still don't allow bogus locales. Patch by Yves. Fixes #2533. This was SVN commit r15122. --- .../data/mods/public/gui/locale/locale.js | 19 ++- .../mods/public/gui/locale/locale_advanced.js | 2 +- source/i18n/L10n.cpp | 111 +++++++++++------- source/i18n/L10n.h | 22 +++- source/i18n/scripting/JSInterface_L10n.cpp | 12 +- source/i18n/scripting/JSInterface_L10n.h | 7 +- 6 files changed, 114 insertions(+), 59 deletions(-) diff --git a/binaries/data/mods/public/gui/locale/locale.js b/binaries/data/mods/public/gui/locale/locale.js index 3a4f6a8afb..a4361e1f2e 100644 --- a/binaries/data/mods/public/gui/locale/locale.js +++ b/binaries/data/mods/public/gui/locale/locale.js @@ -5,16 +5,13 @@ function init() languageList.list_data = Engine.GetSupportedLocaleBaseNames(); var currentLocale = Engine.GetCurrentLocale(); - var currentLocaleBaseName = Engine.GetLocaleBaseName(currentLocale); - var currentLocaleLanguage = Engine.GetLocaleLanguage(currentLocale); + var currentLocaleDictName = Engine.GetFallbackToAvailableDictLocale(currentLocale); var useLongStrings = Engine.UseLongStrings(); var index = -1; if (useLongStrings) index = languageList.list_data.indexOf("long"); if (index == -1) - index = languageList.list_data.indexOf(currentLocaleBaseName); - if (index == -1) - index = languageList.list_data.indexOf(currentLocaleLanguage); + index = languageList.list_data.indexOf(currentLocaleDictName); if (index != -1) languageList.selected = index; @@ -65,12 +62,12 @@ function applyFromAdvancedMenu(locale) { var languageList = Engine.GetGUIObjectByName("languageList"); - var localeBaseName = Engine.GetLocaleBaseName(locale); - var localeLanguage = Engine.GetLocaleLanguage(locale); - if (languageList.list_data.indexOf(localeBaseName) != -1) - languageList.selected = languageList.list_data.indexOf(localeBaseName); - else if (languageList.list_data.indexOf(localeLanguage) != -1) - languageList.selected = languageList.list_data.indexOf(localeLanguage); + var currentLocaleDictName = Engine.GetFallbackToAvailableDictLocale(locale); + var index = -1; + index = languageList.list_data.indexOf(currentLocaleDictName); + + if (index != -1) + languageList.selected = index; var localeText = Engine.GetGUIObjectByName("localeText"); localeText.caption = locale; diff --git a/binaries/data/mods/public/gui/locale/locale_advanced.js b/binaries/data/mods/public/gui/locale/locale_advanced.js index a1fd051fa8..ebe7b67f2c 100644 --- a/binaries/data/mods/public/gui/locale/locale_advanced.js +++ b/binaries/data/mods/public/gui/locale/locale_advanced.js @@ -79,7 +79,7 @@ function updateResultingLocale() if (Engine.ValidateLocale(resultingLocaleTmp)) { resultingLocaleText.caption = resultingLocaleTmp; - var dictionaryFileList = Engine.GetDictionariesForDictLocale(Engine.GetDictionaryLocale(resultingLocaleTmp)); + var dictionaryFileList = Engine.GetDictionariesForLocale(Engine.GetDictionaryLocale(resultingLocaleTmp)); var dictionaryFileString = ""; dictionaryFileList.forEach( function (entry) { dictionaryFileString = dictionaryFileString + entry + "\n"; }); dictionaryFile.caption = dictionaryFileString; diff --git a/source/i18n/L10n.cpp b/source/i18n/L10n.cpp index 233bb818c0..2a8234204e 100644 --- a/source/i18n/L10n.cpp +++ b/source/i18n/L10n.cpp @@ -102,45 +102,23 @@ bool L10n::ValidateLocale(const std::string& localeCode) // 2. Either a dictionary for language_country or for language is available. bool L10n::ValidateLocale(Locale locale) { - int32_t count; - bool icuSupported = false; - const Locale* icuSupportedLocales = Locale::getAvailableLocales(count); - for (int i=0; i::iterator iterator = availableLocales.begin(); iterator != availableLocales.end(); ++iterator) - { - if ((strcmp((*iterator)->getLanguage(), locale.getLanguage()) == 0 && strcmp((*iterator)->getCountry(), "") == 0) || - (strcmp((*iterator)->getLanguage(), locale.getLanguage()) == 0 && strcmp((*iterator)->getCountry(), locale.getCountry()) == 0)) - { - return true; - } - } - return false; + + std::wstring dictLocale = GetFallbackToAvailableDictLocale(locale); + if (dictLocale.empty()) + return false; + + return true; } -std::vector L10n::GetDictionariesForDictLocale(const std::string& locale) +std::vector L10n::GetDictionariesForLocale(const std::string& locale) { - std::wstring tmpLocale(locale.begin(), locale.end()); std::vector ret; VfsPaths filenames; - if (vfs::GetPathnames(g_VFS, L"l10n/", tmpLocale.append(L".*.po").c_str(), filenames) < 0) - return ret; - if (filenames.size() == 0) - { - Locale tmpLocale1 = Locale::createCanonical(locale.c_str()); - if (vfs::GetPathnames(g_VFS, L"l10n/", wstring_from_utf8(tmpLocale1.getLanguage()).append(L".*.po").c_str(), filenames) < 0) - return ret; - } + std::wstring dictName = GetFallbackToAvailableDictLocale(Locale::createCanonical(locale.c_str())); + vfs::GetPathnames(g_VFS, L"l10n/", dictName.append(L".*.po").c_str(), filenames); for (VfsPaths::iterator it = filenames.begin(); it != filenames.end(); ++it) { @@ -150,6 +128,60 @@ std::vector L10n::GetDictionariesForDictLocale(const std::string& return ret; } +L10n::CheckLangAndCountry::CheckLangAndCountry(const Locale& locale) : m_MatchLocale(locale) +{ +} + +bool L10n::CheckLangAndCountry::operator()(const Locale* const locale) +{ + bool found = false; + found = strcmp(m_MatchLocale.getLanguage(), locale->getLanguage()) == 0; + found &= strcmp(m_MatchLocale.getCountry(), locale->getCountry()) == 0; + return found; +} + +L10n::CheckLang::CheckLang(const Locale& locale) : m_MatchLocale(locale) +{ +} + +bool L10n::CheckLang::operator()(const Locale* const locale) +{ + bool found = false; + found = strcmp(m_MatchLocale.getLanguage(), locale->getLanguage()) == 0; + return found; +} + +std::wstring L10n::GetFallbackToAvailableDictLocale(const std::string& locale) +{ + return GetFallbackToAvailableDictLocale(Locale::createCanonical(locale.c_str())); +} + +std::wstring L10n::GetFallbackToAvailableDictLocale(const Locale& locale) +{ + std::wstringstream stream; + + if (strcmp(locale.getCountry(), "") != 0) + { + CheckLangAndCountry fun(locale); + std::vector::iterator itr = find_if(availableLocales.begin(), availableLocales.end(), fun); + if (itr != availableLocales.end()) + { + stream << locale.getLanguage() << L"_" << locale.getCountry(); + return stream.str(); + } + } + + CheckLang fun(locale); + std::vector::iterator itr = find_if(availableLocales.begin(), availableLocales.end(), fun); + if (itr != availableLocales.end()) + { + stream << locale.getLanguage(); + return stream.str(); + } + + return L""; +} + std::string L10n::GetDictionaryLocale(std::string configLocaleString) { Locale out; @@ -180,7 +212,7 @@ void L10n::GetDictionaryLocale(std::string configLocaleString, Locale& outLocale } -// Try to find the best disctionary locale based on user configuration and system locale, set the currentLocale and reload the dictionary. +// Try to find the best dictionary locale based on user configuration and system locale, set the currentLocale and reload the dictionary. void L10n::ReevaluateCurrentLocaleAndReload() { std::string locale; @@ -427,15 +459,12 @@ void L10n::LoadDictionaryForCurrentLocale() } else { - if (vfs::GetPathnames(g_VFS, L"l10n/", (wstring_from_utf8(currentLocale.getBaseName()) + L".*.po").c_str(), filenames) < 0) - return; - } - - // If not matching country is found, try to fall back to a matching language - if (filenames.size() == 0) - { - if (vfs::GetPathnames(g_VFS, L"l10n/", (wstring_from_utf8(currentLocale.getLanguage()) + L".*.po").c_str(), filenames) < 0) + std::wstring dictName = GetFallbackToAvailableDictLocale(currentLocale); + if (vfs::GetPathnames(g_VFS, L"l10n/", dictName.append(L".*.po").c_str(), filenames) < 0) + { + LOGERROR(L"No files for the dictionary found, but at this point the input should already be validated!"); return; + } } for (VfsPaths::iterator it = filenames.begin(); it != filenames.end(); ++it) diff --git a/source/i18n/L10n.h b/source/i18n/L10n.h index e42203cf12..46077e6fa4 100644 --- a/source/i18n/L10n.h +++ b/source/i18n/L10n.h @@ -250,7 +250,27 @@ public: * @return Array of paths to files in the virtual filesystem that provide * translations for @p locale. */ - std::vector GetDictionariesForDictLocale(const std::string& locale); + std::vector GetDictionariesForLocale(const std::string& locale); + + std::wstring GetFallbackToAvailableDictLocale(const Locale& locale); + + std::wstring GetFallbackToAvailableDictLocale(const std::string& locale); + + struct CheckLangAndCountry + { + CheckLangAndCountry(const Locale& locale); + const Locale& m_MatchLocale; + + bool operator()(const Locale* const locale); + }; + + struct CheckLang + { + CheckLang(const Locale& locale); + const Locale& m_MatchLocale; + + bool operator()(const Locale* const locale); + }; /** * Returns the code of the recommended locale for the current user that the diff --git a/source/i18n/scripting/JSInterface_L10n.cpp b/source/i18n/scripting/JSInterface_L10n.cpp index e48bda94ce..e6db3e9071 100644 --- a/source/i18n/scripting/JSInterface_L10n.cpp +++ b/source/i18n/scripting/JSInterface_L10n.cpp @@ -64,6 +64,11 @@ std::vector JSI_L10n::TranslateArray(ScriptInterface::CxPrivate* U return translatedArray; } +std::wstring JSI_L10n::GetFallbackToAvailableDictLocale(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::string locale) +{ + return L10n::Instance().GetFallbackToAvailableDictLocale(locale); +} + // Return a localized version of a time given in milliseconds. std::wstring JSI_L10n::FormatMillisecondsIntoDateString(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), UDate milliseconds, std::wstring formatString) { @@ -106,9 +111,9 @@ std::string JSI_L10n::GetDictionaryLocale(ScriptInterface::CxPrivate* UNUSED(pCx return L10n::Instance().GetDictionaryLocale(configLocale); } -std::vector JSI_L10n::GetDictionariesForDictLocale(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::string locale) +std::vector JSI_L10n::GetDictionariesForLocale(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::string locale) { - return L10n::Instance().GetDictionariesForDictLocale(locale); + return L10n::Instance().GetDictionariesForLocale(locale); } std::string JSI_L10n::GetLocaleLanguage(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::string locale) @@ -163,13 +168,14 @@ void JSI_L10n::RegisterScriptFunctions(ScriptInterface& scriptInterface) scriptInterface.RegisterFunction("GetCurrentLocale"); scriptInterface.RegisterFunction, &GetAllLocales>("GetAllLocales"); scriptInterface.RegisterFunction("GetDictionaryLocale"); - scriptInterface.RegisterFunction, std::string, &GetDictionariesForDictLocale>("GetDictionariesForDictLocale"); + scriptInterface.RegisterFunction, std::string, &GetDictionariesForLocale>("GetDictionariesForLocale"); scriptInterface.RegisterFunction("UseLongStrings"); scriptInterface.RegisterFunction("GetLocaleLanguage"); scriptInterface.RegisterFunction("GetLocaleBaseName"); scriptInterface.RegisterFunction("GetLocaleCountry"); scriptInterface.RegisterFunction("GetLocaleScript"); + scriptInterface.RegisterFunction("GetFallbackToAvailableDictLocale"); scriptInterface.RegisterFunction("ValidateLocale"); scriptInterface.RegisterFunction("SaveLocale"); diff --git a/source/i18n/scripting/JSInterface_L10n.h b/source/i18n/scripting/JSInterface_L10n.h index 673464f5a9..bc397bf7a1 100644 --- a/source/i18n/scripting/JSInterface_L10n.h +++ b/source/i18n/scripting/JSInterface_L10n.h @@ -292,14 +292,14 @@ namespace JSI_L10n * Returns an array of paths to files in the virtual filesystem that provide * translations for the specified locale code. * - * This is a JavaScript interface to L10n::GetDictionariesForDictLocale(). + * This is a JavaScript interface to L10n::GetDictionariesForLocale(). * * @param pCxPrivate JavaScript context. * @param locale Locale code. * @return Array of paths to files in the virtual filesystem that provide * translations for @p locale. */ - std::vector GetDictionariesForDictLocale(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::string locale); + std::vector GetDictionariesForLocale(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::string locale); /** * Returns the ISO-639 language code of the specified locale code. @@ -357,6 +357,9 @@ namespace JSI_L10n */ std::string GetLocaleScript(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::string locale); + + std::wstring GetFallbackToAvailableDictLocale(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::string locale); + /** * Returns @c true if the current locale is the special “Long Strings” * locale. It returns @c false otherwise.