diff --git a/map/languages.cpp b/map/languages.cpp index 0815b7b0d4..cbf9b7de2b 100644 --- a/map/languages.cpp +++ b/map/languages.cpp @@ -10,6 +10,7 @@ #include "../coding/multilang_utf8_string.hpp" #include "../platform/platform.hpp" +#include "../platform/preferred_languages.hpp" #include "../std/algorithm.hpp" #include "../std/sstream.hpp" @@ -96,8 +97,9 @@ namespace languages void GetCurrentSettings(CodesAndNamesT & outLanguages) { string settingsString; + // get preffered languages from the system if (!Settings::Get(SETTING_LANG_KEY, settingsString)) - settingsString = DEFAULT_LANGUAGES; // @TODO get preffered languages from the system + settingsString = languages::PreferredLanguages(); CodesT currentCodes; Collector c(currentCodes); @@ -133,4 +135,5 @@ namespace languages } return !outLanguages.empty(); } + } diff --git a/platform/platform.pro b/platform/platform.pro index be31118f99..201d86856a 100644 --- a/platform/platform.pro +++ b/platform/platform.pro @@ -50,6 +50,8 @@ HEADERS += \ download_manager.hpp \ location.hpp \ concurrent_runner.hpp \ + preferred_languages.hpp \ SOURCES += \ location_manager.cpp \ + preferred_languages.cpp \ diff --git a/platform/platform_tests/language_test.cpp b/platform/platform_tests/language_test.cpp new file mode 100644 index 0000000000..012f12cb98 --- /dev/null +++ b/platform/platform_tests/language_test.cpp @@ -0,0 +1,36 @@ +#include "../../testing/testing.hpp" + +#include "../../std/string.hpp" +#include "../../std/vector.hpp" + +namespace languages +{ + void FilterLanguages(vector & langs); +} + +UNIT_TEST(LangFilter) +{ + vector v; + v.push_back("en"); + v.push_back("en-GB"); + v.push_back("zh"); + v.push_back("es-SP"); + v.push_back("zh-penyn"); + v.push_back("en-US"); + v.push_back("ru_RU"); + v.push_back("es"); + + languages::FilterLanguages(v); + + vector c; + c.push_back("en"); + c.push_back("zh"); + c.push_back("es"); + c.push_back("ru"); + + TEST_EQUAL(v.size(), c.size(), (v, c)); + for (size_t i = 0; i < c.size(); ++i) + { + TEST_EQUAL(c[i], v[i], (v, c)); + } +} diff --git a/platform/platform_tests/platform_tests.pro b/platform/platform_tests/platform_tests.pro index da14c67e16..2363eac358 100644 --- a/platform/platform_tests/platform_tests.pro +++ b/platform/platform_tests/platform_tests.pro @@ -27,3 +27,4 @@ SOURCES += \ download_test.cpp \ jansson_test.cpp \ concurrent_runner_test.cpp \ + language_test.cpp \ diff --git a/platform/preferred_languages.cpp b/platform/preferred_languages.cpp new file mode 100644 index 0000000000..130f3fb055 --- /dev/null +++ b/platform/preferred_languages.cpp @@ -0,0 +1,114 @@ +#include "preferred_languages.hpp" + +#include "../base/string_utils.hpp" +#include "../base/logging.hpp" + +#include "../std/target_os.hpp" +#include "../std/set.hpp" + +#if defined(OMIM_OS_MAC) || defined(OMIM_OS_IPHONE) + #include + #include + +#elif defined(OMIM_OS_WINDOWS) + // @TODO + +#else + #error "Define language preferences for your platform" + +#endif + +namespace languages +{ + +class LangFilter +{ + set & m_known; +public: + LangFilter(set & known) : m_known(known) {} + bool operator()(string const & t) + { + return !m_known.insert(t).second; + } +}; + +class NormalizeFilter +{ +public: + void operator()(string & t) + { + strings::SimpleTokenizer const iter(t, "-_ "); + if (iter) + t = *iter; + else + { + LOG(LWARNING, ("Invalid language")); + } + } +}; + +void FilterLanguages(vector & langs) +{ + // normalize languages: en-US -> en, ru_RU -> ru etc. + for_each(langs.begin(), langs.end(), NormalizeFilter()); + { // tmp storage + set known; + // remove duplicate languages + langs.erase(remove_if(langs.begin(), langs.end(), LangFilter(known)), langs.end()); + } +} + +void SystemPreferredLanguages(vector & languages) +{ +#if defined(OMIM_OS_MAC) || defined(OMIM_OS_IPHONE) + // Mac and iOS implementation + CFArrayRef langs = CFLocaleCopyPreferredLanguages(); + char buf[30]; + for (CFIndex i = 0; i < CFArrayGetCount(langs); ++i) + { + CFStringRef strRef = (CFStringRef)CFArrayGetValueAtIndex(langs, i); + CFStringGetCString(strRef, buf, 30, kCFStringEncodingUTF8); + languages.push_back(buf); + } + CFRelease(langs); + +#elif defined(OMIM_OS_WINDOWS) + // @TODO Windows implementation +#else + #error "Define language preferences for your platform" +#endif + + FilterLanguages(languages); +} + +string PreferredLanguages() +{ + vector arr; + + SystemPreferredLanguages(arr); + + // generate output string + string result; + for (size_t i = 0; i < arr.size(); ++i) + { + result.append(arr[i]); + result.push_back('|'); + } + if (result.empty()) + result = "default"; + else + result.resize(result.size() - 1); + return result; +} + +string CurrentLanguage() +{ + vector arr; + SystemPreferredLanguages(arr); + if (arr.empty()) + return "en"; + else + return arr[0]; +} + +} diff --git a/platform/preferred_languages.hpp b/platform/preferred_languages.hpp new file mode 100644 index 0000000000..a492fefbe9 --- /dev/null +++ b/platform/preferred_languages.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "../std/string.hpp" + +namespace languages +{ + +/// @return system language preferences in the form "en|ru|es|zh" +string PreferredLanguages(); +/// @return language code for current user in the form "en" +string CurrentLanguage(); + +}