diff --git a/indexer/editable_map_object.cpp b/indexer/editable_map_object.cpp index e87414f626..ef6e4d2cd3 100644 --- a/indexer/editable_map_object.cpp +++ b/indexer/editable_map_object.cpp @@ -96,7 +96,7 @@ StringUtf8Multilang const & EditableMapObject::GetName() const { return m_name; NamesDataSource EditableMapObject::GetNamesDataSource() const { - const auto mwmInfo = GetID().m_mwmId.GetInfo(); + auto const mwmInfo = GetID().m_mwmId.GetInfo(); if (!mwmInfo) return NamesDataSource(); diff --git a/indexer/feature.cpp b/indexer/feature.cpp index b05151515a..08ba0f2df0 100644 --- a/indexer/feature.cpp +++ b/indexer/feature.cpp @@ -1,18 +1,16 @@ #include "indexer/classificator.hpp" #include "indexer/feature.hpp" -#include "indexer/classificator.hpp" #include "indexer/feature_algo.hpp" #include "indexer/feature_impl.hpp" #include "indexer/feature_loader_base.hpp" +#include "indexer/feature_utils.hpp" #include "indexer/feature_visibility.hpp" #include "indexer/osm_editor.hpp" #include "geometry/distance.hpp" #include "geometry/robust_orientation.hpp" -#include "platform/preferred_languages.hpp" - #include "base/range_iterator.hpp" #include "base/stl_helpers.hpp" @@ -499,79 +497,22 @@ FeatureType::geom_stat_t FeatureType::GetTrianglesSize(int scale) const return geom_stat_t(sz, m_triangles.size()); } -struct BestMatchedLangNames -{ - string m_defaultName; - string m_nativeName; - string m_intName; - string m_englishName; - - bool operator()(int8_t code, string const & name) - { - int8_t const defaultCode = StringUtf8Multilang::kDefaultCode; - static int8_t const nativeCode = StringUtf8Multilang::GetLangIndex(languages::GetCurrentNorm()); - int8_t const intCode = StringUtf8Multilang::kInternationalCode; - int8_t const englishCode = StringUtf8Multilang::kEnglishCode; - - if (code == defaultCode) - m_defaultName = name; - else if (code == nativeCode) - m_nativeName = name; - else if (code == intCode) - { - // There are many "junk" names in Arabian island. - m_intName = name.substr(0, name.find_first_of(',')); - // int_name should be used as name:en when name:en not found - if ((nativeCode == englishCode) && m_nativeName.empty()) - m_nativeName = m_intName; - } - else if (code == englishCode) - m_englishName = name; - return true; - } -}; - void FeatureType::GetPreferredNames(string & defaultName, string & intName) const { + if (!HasName()) + return; + ParseCommon(); - - BestMatchedLangNames matcher; - ForEachName(matcher); - - defaultName.swap(matcher.m_defaultName); - - if (!matcher.m_nativeName.empty()) - intName.swap(matcher.m_nativeName); - else if (!matcher.m_intName.empty()) - intName.swap(matcher.m_intName); - else - intName.swap(matcher.m_englishName); - - if (defaultName.empty()) - defaultName.swap(intName); - else - { - // filter out similar intName - if (!intName.empty() && defaultName.find(intName) != string::npos) - intName.clear(); - } + ::GetPreferredNames(GetID(), GetNames(), defaultName, intName); } void FeatureType::GetReadableName(string & name) const { + if (!HasName()) + return; + ParseCommon(); - - BestMatchedLangNames matcher; - ForEachName(matcher); - - if (!matcher.m_nativeName.empty()) - name.swap(matcher.m_nativeName); - else if (!matcher.m_defaultName.empty()) - name.swap(matcher.m_defaultName); - else if (!matcher.m_intName.empty()) - name.swap(matcher.m_intName); - else - name.swap(matcher.m_englishName); + ::GetReadableName(GetID(), GetNames(), name); } string FeatureType::GetHouseNumber() const diff --git a/indexer/feature_utils.cpp b/indexer/feature_utils.cpp index e5469c6e9d..86a5e5203a 100644 --- a/indexer/feature_utils.cpp +++ b/indexer/feature_utils.cpp @@ -1,15 +1,86 @@ +#include "indexer/classificator.hpp" +#include "indexer/feature.hpp" +#include "indexer/feature_data.hpp" #include "indexer/feature_utils.hpp" #include "indexer/feature_visibility.hpp" -#include "indexer/classificator.hpp" -#include "indexer/feature_data.hpp" #include "indexer/scales.hpp" #include "geometry/point2d.hpp" +#include "platform/preferred_languages.hpp" + +#include "coding/multilang_utf8_string.hpp" + #include "base/base.hpp" #include "std/vector.hpp" +namespace +{ +void GetMwmLangName(FeatureID const & id, StringUtf8Multilang const & src, string & out) +{ + auto const mwmInfo = id.m_mwmId.GetInfo(); + + if (!mwmInfo) + return; + + vector mwmLangCodes; + mwmInfo->GetRegionData().GetLanguages(mwmLangCodes); + + for (auto const code : mwmLangCodes) + { + if (src.GetString(code, out)) + return; + } +} + +void GetNames(FeatureID const & id, StringUtf8Multilang const & src, string & primary, + string & secondary) +{ + vector primaryCodes = {StringUtf8Multilang::kDefaultCode}; + vector secondaryCodes = {StringUtf8Multilang::GetLangIndex(languages::GetCurrentNorm()), + StringUtf8Multilang::kInternationalCode, + StringUtf8Multilang::kEnglishCode}; + + auto primaryIndex = primaryCodes.size(); + auto secondaryIndex = secondaryCodes.size(); + + primary.clear(); + secondary.clear(); + + auto const findAndSet = [](vector const & langs, int8_t const code, string const & name, + size_t & bestIndex, string & outName) + { + auto const it = find(langs.begin(), langs.end(), code); + if (it != langs.end() && bestIndex > distance(langs.begin(), it)) + { + bestIndex = distance(langs.begin(), it); + outName = name; + } + }; + + src.ForEach([&](int8_t code, string const & name) + { + if (primaryIndex != 0) + findAndSet(primaryCodes, code, name, primaryIndex, primary); + + if (secondaryIndex != 0) + findAndSet(secondaryCodes, code, name, secondaryIndex, secondary); + + return true; + }); + + if (primary.empty()) + GetMwmLangName(id, src, primary); + + if (secondaryIndex < secondaryCodes.size() && + secondaryCodes[secondaryIndex] == StringUtf8Multilang::kInternationalCode) + { + // There are many "junk" names in Arabian island. + secondary = secondary.substr(0, secondary.find_first_of(',')); + } +} +} // namespace namespace feature { @@ -147,4 +218,41 @@ int GetFeatureViewportScale(TypesHolder const & types) return impl::GetFeatureEstimator().GetViewportScale(types); } +void GetPreferredNames(FeatureID const & id, StringUtf8Multilang const & src, string & primary, + string & secondary) +{ + // Primary name using priority: + // - default name; + // - country language name. + // Secondary name using priority: + // - device language name; + // - international name; + // - english name. + GetNames(id, src, primary, secondary); + + if (primary.empty()) + { + primary.swap(secondary); + } + else + { + // Filter out similar intName. + if (!secondary.empty() && primary.find(secondary) != string::npos) + secondary.clear(); + } +} + +void GetReadableName(FeatureID const & id, StringUtf8Multilang const & src, string & out) +{ + // Names using priority: + // - device language name; + // - international name; + // - english name; + // - default name; + // - country language name. + // Secondary name is preffered to display on the map and place page. + string primary, secondary; + GetNames(id, src, primary, secondary); + out = secondary.empty() ? primary : secondary; +} } // namespace feature diff --git a/indexer/feature_utils.hpp b/indexer/feature_utils.hpp index 1cfa5a38ac..e7e0f46306 100644 --- a/indexer/feature_utils.hpp +++ b/indexer/feature_utils.hpp @@ -4,6 +4,8 @@ #include "base/base.hpp" +struct FeatureID; +class StringUtf8Multilang; namespace feature { @@ -11,4 +13,8 @@ namespace feature /// Get viewport scale to show given feature. Used in search. int GetFeatureViewportScale(TypesHolder const & types); + + void GetPreferredNames(FeatureID const & id, StringUtf8Multilang const & src, string & primary, + string & secondary); + void GetReadableName(FeatureID const & id, StringUtf8Multilang const & src, string & out); } // namespace feature diff --git a/map/place_page_info.cpp b/map/place_page_info.cpp index 706f0447b1..7fbbe1c26a 100644 --- a/map/place_page_info.cpp +++ b/map/place_page_info.cpp @@ -1,9 +1,8 @@ #include "place_page_info.hpp" +#include "indexer/feature_utils.hpp" #include "indexer/osm_editor.hpp" -#include "platform/preferred_languages.hpp" - namespace place_page { char const * const Info::kSubtitleSeparator = " • "; @@ -48,16 +47,10 @@ string Info::GetTitle() const if (!m_customName.empty()) return m_customName; - // Prefer names in native language over default ones. - int8_t const langCode = StringUtf8Multilang::GetLangIndex(languages::GetCurrentNorm()); - if (langCode != StringUtf8Multilang::kUnsupportedLanguageCode) - { - string native; - if (m_name.GetString(langCode, native)) - return native; - } + string name; + feature::GetReadableName(GetID(), m_name, name); - return GetDefaultName(); + return name; } string Info::GetSubtitle() const