diff --git a/platform/get_text_by_id.cpp b/platform/get_text_by_id.cpp index f60be22468..8e215d1f5e 100644 --- a/platform/get_text_by_id.cpp +++ b/platform/get_text_by_id.cpp @@ -17,8 +17,10 @@ string GetTextSourceString(platform::TextSource textSource) { switch (textSource) { - case platform::TextSource::TtsSound: - return string("sound-strings"); + case platform::TextSource::TtsSound: + return string("sound-strings"); + case platform::TextSource::Countries: + return string("countries-strings"); } ASSERT(false, ()); return string(); diff --git a/platform/get_text_by_id.hpp b/platform/get_text_by_id.hpp index b153617820..5486c90485 100644 --- a/platform/get_text_by_id.hpp +++ b/platform/get_text_by_id.hpp @@ -11,7 +11,8 @@ namespace platform // For the time being it's only strings for TTS. enum class TextSource { - TtsSound = 0 + TtsSound = 0, // maneuvers text to speech strings + Countries // countries names strings }; class GetTextById; diff --git a/storage/country_name_getter.cpp b/storage/country_name_getter.cpp new file mode 100644 index 0000000000..46247081fe --- /dev/null +++ b/storage/country_name_getter.cpp @@ -0,0 +1,40 @@ +#include "storage/country_name_getter.hpp" + +#include "base/assert.hpp" + +namespace storage +{ + +void CountryNameGetter::SetLocale(string const & locale) +{ + m_getCurLang = platform::GetTextByIdFactory(platform::TextSource::Countries, locale); +} + +void CountryNameGetter::SetLocaleForTesting(string const & jsonBuffer, string const & locale) +{ + m_getCurLang = platform::ForTestingGetTextByIdFactory(jsonBuffer, locale); +} + +string CountryNameGetter::operator()(TCountryId const & countryId) const +{ + ASSERT(!countryId.empty(), ()); + + if (m_getCurLang == nullptr) + return countryId; + + string name = (*m_getCurLang)(countryId); + if (name.empty()) + return countryId; + + return name; +} + +string CountryNameGetter::GetLocale() const +{ + if (m_getCurLang == nullptr) + return string(); + + return m_getCurLang->GetLocale(); +} + +} // namespace storage diff --git a/storage/country_name_getter.hpp b/storage/country_name_getter.hpp new file mode 100644 index 0000000000..37b83103ac --- /dev/null +++ b/storage/country_name_getter.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include "storage/index.hpp" + +#include "platform/get_text_by_id.hpp" + +#include "std/string.hpp" +#include "std/unique_ptr.hpp" + +namespace storage +{ + +/// CountryNameGetter is responsible for generating text name for TCountryId in a specified locale +/// To get this country name use operator(). +/// If the country caption is not available for specified locale, class tries to find it in +/// English locale. +class CountryNameGetter +{ +public: + /// @return current locale. For example "en", "ru", "zh-Hant" and so on. + /// \note The method returns correct locale after SetLocale has been called. + /// If not, it returns an empty string. + string GetLocale() const; + + /// \brief Sets a locale. + /// @param locale is a string representation of locale. For example "en", "ru", "zh-Hant" and so on. + /// \note See countries/languages.txt for the full list of available locales. + void SetLocale(string const & locale); + + string operator()(TCountryId const & countryId) const; + + // for testing + void SetLocaleForTesting(string const & jsonBuffer, string const & locale); + +private: + unique_ptr m_getCurLang; +}; + +} // namespace storage diff --git a/storage/storage.cpp b/storage/storage.cpp index 92978f91f8..2f58e03651 100644 --- a/storage/storage.cpp +++ b/storage/storage.cpp @@ -842,6 +842,16 @@ bool Storage::IsCountryFirstInQueue(TCountryId const & countryId) const return !m_queue.empty() && m_queue.front().GetCountryId() == countryId; } +void Storage::SetLocale(string const & locale) +{ + m_countryNameGetter.SetLocale(locale); +} + +string Storage::GetLocale() const +{ + return m_countryNameGetter.GetLocale(); +} + void Storage::SetDownloaderForTesting(unique_ptr && downloader) { m_downloader = move(downloader); @@ -852,6 +862,16 @@ void Storage::SetCurrentDataVersionForTesting(int64_t currentVersion) m_currentVersion = currentVersion; } +void Storage::SetDownloadingUrlsForTesting(vector const & downloadingUrls) +{ + m_downloadingUrlsForTesting = downloadingUrls; +} + +void Storage::SetLocaleForTesting(string const & jsonBuffer, string const & locale) +{ + m_countryNameGetter.SetLocaleForTesting(jsonBuffer, locale); +} + Storage::TLocalFilePtr Storage::GetLocalFile(TCountryId const & countryId, int64_t version) const { auto const it = m_localFiles.find(countryId); @@ -1132,11 +1152,9 @@ void Storage::GetNodeAttrs(TCountryId const & countryId, NodeAttrs & nodeAttrs) StatusAndError statusAndErr = ParseStatus(NodeStatus(*node)); nodeAttrs.m_status = statusAndErr.status; nodeAttrs.m_error = statusAndErr.error; - // @TODO(bykoianko) NodeAttrs::m_nodeLocalName should be in local language. - nodeAttrs.m_nodeLocalName = countryId; + nodeAttrs.m_nodeLocalName = m_countryNameGetter(countryId); nodeAttrs.m_parentCountryId = nodeValue.GetParent(); - // @TODO(bykoianko) NodeAttrs::m_parentLocalName should be in local language. - nodeAttrs.m_parentLocalName = nodeAttrs.m_parentCountryId; + nodeAttrs.m_parentLocalName = m_countryNameGetter(nodeAttrs.m_parentCountryId); } void Storage::DoClickOnDownloadMap(TCountryId const & countryId) diff --git a/storage/storage.hpp b/storage/storage.hpp index 21e40b156f..ff548f910c 100644 --- a/storage/storage.hpp +++ b/storage/storage.hpp @@ -1,6 +1,7 @@ #pragma once #include "storage/country.hpp" +#include "storage/country_name_getter.hpp" #include "storage/index.hpp" #include "storage/map_files_downloader.hpp" #include "storage/queued_country.hpp" @@ -146,6 +147,8 @@ private: // on the map. TDownloadFn m_downloadMapOnTheMap; + CountryNameGetter m_countryNameGetter; + void DownloadNextCountryFromQueue(); void LoadCountriesFile(string const & pathToCountriesFile, @@ -411,13 +414,15 @@ public: /// @param[out] res Populated with oudated countries. void GetOutdatedCountries(vector & countries) const; + /// Sets and gets locale, which is used to get localized counries names + void SetLocale(string const & locale); + string GetLocale() const; + // for testing: void SetDownloaderForTesting(unique_ptr && downloader); void SetCurrentDataVersionForTesting(int64_t currentVersion); - void SetDownloadingUrlsForTesting(vector const & downloadingUrls) - { - m_downloadingUrlsForTesting = downloadingUrls; - } + void SetDownloadingUrlsForTesting(vector const & downloadingUrls); + void SetLocaleForTesting(string const & jsonBuffer, string const & locale); private: friend void UnitTest_StorageTest_DeleteCountrySingleMwm(); diff --git a/storage/storage.pro b/storage/storage.pro index e94eef5136..03761dad3d 100644 --- a/storage/storage.pro +++ b/storage/storage.pro @@ -14,6 +14,7 @@ HEADERS += \ country.hpp \ country_decl.hpp \ country_info_getter.hpp \ + country_name_getter.hpp \ country_polygon.hpp \ http_map_files_downloader.hpp \ index.hpp \ @@ -28,6 +29,7 @@ SOURCES += \ country.cpp \ country_decl.cpp \ country_info_getter.cpp \ + country_name_getter.cpp \ http_map_files_downloader.cpp \ index.cpp \ queued_country.cpp \ diff --git a/storage/storage_tests/country_name_getter_test.cpp b/storage/storage_tests/country_name_getter_test.cpp new file mode 100644 index 0000000000..32c8e2492f --- /dev/null +++ b/storage/storage_tests/country_name_getter_test.cpp @@ -0,0 +1,27 @@ +#include "testing/testing.hpp" + +#include "storage/country_name_getter.hpp" + +UNIT_TEST(CountryNameGetterTest) +{ + string const shortJson = + "\ + {\ + \"Russia_Moscow\":\"Москва\",\ + \"Russia_Rostov-on-Don\":\"Ростов-на-Дону\"\ + }"; + + storage::CountryNameGetter getter; + + TEST_EQUAL(string(), getter.GetLocale(), ()); + TEST_EQUAL(string("Russia_Moscow"), getter("Russia_Moscow"), ()); + TEST_EQUAL(string("Russia_Rostov-on-Don"), getter("Russia_Rostov-on-Don"), ()); + TEST_EQUAL(string("Russia_Murmansk"), getter("Russia_Murmansk"), ()); + + getter.SetLocaleForTesting(shortJson, "ru"); + + TEST_EQUAL(string("ru"), getter.GetLocale(), ()); + TEST_EQUAL(string("Москва"), getter("Russia_Moscow"), ()); + TEST_EQUAL(string("Ростов-на-Дону"), getter("Russia_Rostov-on-Don"), ()); + TEST_EQUAL(string("Russia_Murmansk"), getter("Russia_Murmansk"), ()); +} diff --git a/storage/storage_tests/storage_tests.cpp b/storage/storage_tests/storage_tests.cpp index 2c2a3baaf0..a89652a04b 100644 --- a/storage/storage_tests/storage_tests.cpp +++ b/storage/storage_tests/storage_tests.cpp @@ -1256,4 +1256,89 @@ UNIT_TEST(StorageTest_CalcLimitRect) TEST(AlmostEqualRectsAbs(boundingBox, expectedBoundingBox), ()); } + +UNIT_TEST(StorageTest_CountriesNamesTest) +{ + string const ruJson = + "\ + {\ + \"Countries\":\"Весь мир\",\ + \"Abkhazia\":\"Абхазия\",\ + \"Algeria\":\"Алжир\",\ + \"Algeria_Central\":\"Алжир (центральная часть)\",\ + \"Algeria_Coast\":\"Алжир (побережье)\"\ + }"; + + string const frJson = + "\ + {\ + \"Countries\":\"Des pays\",\ + \"Abkhazia\":\"Abkhazie\",\ + \"Algeria\":\"Algérie\",\ + \"Algeria_Central\":\"Algérie (partie centrale)\",\ + \"Algeria_Coast\":\"Algérie (Côte)\"\ + }"; + + Storage storage(kSingleMwmCountriesTxt, make_unique()); + + // set russian locale + + storage.SetLocaleForTesting(ruJson, "ru"); + TEST_EQUAL(string("ru"), storage.GetLocale(), ()); + + NodeAttrs nodeAttrs; + storage.GetNodeAttrs("Abkhazia", nodeAttrs); + TEST_EQUAL(nodeAttrs.m_nodeLocalName, "Абхазия", ()); + TEST_EQUAL(nodeAttrs.m_parentLocalName, "Весь мир", ()); + + nodeAttrs = NodeAttrs(); + storage.GetNodeAttrs("Algeria", nodeAttrs); + TEST_EQUAL(nodeAttrs.m_nodeLocalName, "Алжир", ()); + TEST_EQUAL(nodeAttrs.m_parentLocalName, "Весь мир", ()); + + nodeAttrs = NodeAttrs(); + storage.GetNodeAttrs("Algeria_Coast", nodeAttrs); + TEST_EQUAL(nodeAttrs.m_nodeLocalName, "Алжир (побережье)", ()); + TEST_EQUAL(nodeAttrs.m_parentLocalName, "Алжир", ()); + + nodeAttrs = NodeAttrs(); + storage.GetNodeAttrs("Algeria_Central", nodeAttrs); + TEST_EQUAL(nodeAttrs.m_nodeLocalName, "Алжир (центральная часть)", ()); + TEST_EQUAL(nodeAttrs.m_parentLocalName, "Алжир", ()); + + nodeAttrs = NodeAttrs(); + storage.GetNodeAttrs("South Korea_South", nodeAttrs); + TEST_EQUAL(nodeAttrs.m_nodeLocalName, "South Korea_South", ()); + TEST_EQUAL(nodeAttrs.m_parentLocalName, "Весь мир", ()); + + // set french locale + + storage.SetLocaleForTesting(frJson, "fr"); + TEST_EQUAL(string("fr"), storage.GetLocale(), ()); + + nodeAttrs = NodeAttrs(); + storage.GetNodeAttrs("Abkhazia", nodeAttrs); + TEST_EQUAL(nodeAttrs.m_nodeLocalName, "Abkhazie", ()); + TEST_EQUAL(nodeAttrs.m_parentLocalName, "Des pays", ()); + + nodeAttrs = NodeAttrs(); + storage.GetNodeAttrs("Algeria", nodeAttrs); + TEST_EQUAL(nodeAttrs.m_nodeLocalName, "Algérie", ()); + TEST_EQUAL(nodeAttrs.m_parentLocalName, "Des pays", ()); + + nodeAttrs = NodeAttrs(); + storage.GetNodeAttrs("Algeria_Coast", nodeAttrs); + TEST_EQUAL(nodeAttrs.m_nodeLocalName, "Algérie (Côte)", ()); + TEST_EQUAL(nodeAttrs.m_parentLocalName, "Algérie", ()); + + nodeAttrs = NodeAttrs(); + storage.GetNodeAttrs("Algeria_Central", nodeAttrs); + TEST_EQUAL(nodeAttrs.m_nodeLocalName, "Algérie (partie centrale)", ()); + TEST_EQUAL(nodeAttrs.m_parentLocalName, "Algérie", ()); + + nodeAttrs = NodeAttrs(); + storage.GetNodeAttrs("South Korea_South", nodeAttrs); + TEST_EQUAL(nodeAttrs.m_nodeLocalName, "South Korea_South", ()); + TEST_EQUAL(nodeAttrs.m_parentLocalName, "Des pays", ()); +} } // namespace storage diff --git a/storage/storage_tests/storage_tests.pro b/storage/storage_tests/storage_tests.pro index de4509a56a..1366ac456d 100644 --- a/storage/storage_tests/storage_tests.pro +++ b/storage/storage_tests/storage_tests.pro @@ -33,6 +33,7 @@ HEADERS += \ SOURCES += \ ../../testing/testingmain.cpp \ country_info_getter_test.cpp \ + country_name_getter_test.cpp \ fake_map_files_downloader.cpp \ helpers.cpp \ queued_country_tests.cpp \