From 46b271d75c9fd673035bb6725b32694501a5320d Mon Sep 17 00:00:00 2001 From: James Turner Date: Fri, 12 Oct 2018 10:49:14 +0100 Subject: [PATCH] Packages: improve localised string support --- simgear/package/CatalogTest.cxx | 22 +++++- simgear/package/Package.cxx | 93 ++++++++++++++++++------ simgear/package/Package.hxx | 4 +- simgear/package/catalogTest1/catalog.xml | 26 +++++++ 4 files changed, 118 insertions(+), 27 deletions(-) diff --git a/simgear/package/CatalogTest.cxx b/simgear/package/CatalogTest.cxx index 8e752e82..d0d1d93a 100644 --- a/simgear/package/CatalogTest.cxx +++ b/simgear/package/CatalogTest.cxx @@ -148,6 +148,7 @@ int parseTest() SGPath rootPath = simgear::Dir::current().path(); rootPath.append("testRoot"); pkg::Root* root = new pkg::Root(rootPath, "8.1.12"); + root->setLocale("de"); pkg::CatalogRef cat = pkg::Catalog::createFromPath(root, SGPath(SRC_DIR "/catalogTest1")); SG_VERIFY(cat.valid()); @@ -172,7 +173,7 @@ int parseTest() pkg::PackageRef p2 = cat->getPackageById("c172p"); SG_VERIFY(p2.valid()); SG_CHECK_EQUAL(p2->qualifiedId(), "org.flightgear.test.catalog1.c172p"); - SG_CHECK_EQUAL(p2->description(), "A plane made by Cessna on Jupiter"); + SG_CHECK_EQUAL(p2->description(), "German description of C172"); pkg::Package::PreviewVec thumbs = p2->previewsForVariant(0); SG_CHECK_EQUAL(thumbs.size(), 3); @@ -217,7 +218,7 @@ int parseTest() SG_CHECK_EQUAL(skisVariant, skisVariantFull); SG_CHECK_EQUAL(p2->getLocalisedProp("description", skisVariant), - "A plane with skis"); + "German description of C172 with skis"); SG_CHECK_EQUAL(p2->getLocalisedProp("author", skisVariant), "Standard author"); @@ -225,6 +226,7 @@ int parseTest() SG_VERIFY(floatsVariant > 0); SG_CHECK_EQUAL(p2->parentIdForVariant(floatsVariant), "c172p"); + // no DE localisation description provided for the floats variant SG_CHECK_EQUAL(p2->getLocalisedProp("description", floatsVariant), "A plane with floats"); SG_CHECK_EQUAL(p2->getLocalisedProp("author", floatsVariant), @@ -257,6 +259,12 @@ int parseTest() string_list primaries = {"c172p", "c172r"}; SG_VERIFY(p2->primaryVariants() == primaries); +/////////// + pkg::PackageRef p3 = cat->getPackageById("b737-NG"); + SG_VERIFY(p3.valid()); + SG_CHECK_EQUAL(p3->description(), "German description of B737NG XYZ"); + + // test filtering / searching too string_set tags(p2->tags()); SG_CHECK_EQUAL(tags.size(), 4); @@ -305,6 +313,16 @@ int parseTest() queryText->setStringValue("any-of/description", "float"); SG_VERIFY(p2->matches(queryText.ptr())); } + + // match localized variant descriptions + { + SGPropertyNode_ptr queryText(new SGPropertyNode); + queryText->setStringValue("any-of/description", "XYZ"); + SG_VERIFY(p3->matches(queryText.ptr())); + } + + + delete root; return EXIT_SUCCESS; } diff --git a/simgear/package/Package.cxx b/simgear/package/Package.cxx index 17613093..3dc0e73d 100644 --- a/simgear/package/Package.cxx +++ b/simgear/package/Package.cxx @@ -44,7 +44,7 @@ void Package::initWithProps(const SGPropertyNode* aProps) { m_props = const_cast(aProps); // cache tag values - BOOST_FOREACH(const SGPropertyNode* c, aProps->getChildren("tag")) { + for (auto c : aProps->getChildren("tag")) { std::string t(c->getStringValue()); m_tags.insert(boost::to_lower_copy(t)); } @@ -133,22 +133,8 @@ bool Package::matches(const SGPropertyNode* aFilter) const if ((filter_name == "text") || (filter_name == "description")) { handled = true; - std::string n(aFilter->getStringValue()); - boost::to_lower(n); - size_t pos = boost::to_lower_copy(description()).find(n); - if (pos != std::string::npos) { - return true; - } - - for (auto var : m_props->getChildren("variant")) { - if (var->hasChild("description")) { - std::string variantDesc(var->getStringValue("description")); - boost::to_lower(variantDesc); - size_t pos = variantDesc.find(n); - if (pos != std::string::npos) { - return true; - } - } + if (matchesDescription(aFilter->getStringValue())) { + return true; } } @@ -158,6 +144,50 @@ bool Package::matches(const SGPropertyNode* aFilter) const return false; } + +bool Package::matchesDescription(const std::string &search) const +{ + std::string n(search); + boost::to_lower(n); + + bool localized; + auto d = getLocalisedString(m_props, "description", &localized); + boost::to_lower(d); + if (d.find(n) != std::string::npos) { + return true; + } + + // try non-localized description too, if the abovce was a localized one + if (localized) { + const std::string baseDesc = m_props->getStringValue("description"); + auto pos = boost::to_lower_copy(baseDesc).find(n); + if (pos != std::string::npos) { + return true; + } + } + + // try each variant's description + for (auto var : m_props->getChildren("variant")) { + auto vd = getLocalisedString(var, "description", &localized); + if (!vd.empty()) { + boost::to_lower(vd); + if (vd.find(n) != std::string::npos) { + return true; + } + } + + if (localized) { + // try non-localized variant description + std::string vd = var->getStringValue("description"); + boost::to_lower(vd); + if (vd.find(n) != std::string::npos) { + return true; + } + } + } // of variant iteration + + return false; +} bool Package::isInstalled() const { @@ -307,14 +337,29 @@ std::string Package::getLocalisedProp(const std::string& aName, const unsigned i return getLocalisedString(propsForVariant(vIndex, aName.c_str()), aName.c_str()); } -std::string Package::getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const +std::string Package::getLocalisedString(const SGPropertyNode* aRoot, const char* aName, bool* isLocalized) const { - std::string locale = m_catalog->root()->getLocale(); - if (aRoot->hasChild(locale)) { - const SGPropertyNode* localeRoot = aRoot->getChild(locale.c_str()); - if (localeRoot->hasChild(aName)) { - return localeRoot->getStringValue(aName); - } + // we used to place localised strings under /sim//name - but this + // potentially pollutes the /sim namespace + // we now check first in /sim/localized//name first + const auto& locale = m_catalog->root()->getLocale(); + if (isLocalized) *isLocalized = false; + + if (locale.empty()) { + return aRoot->getStringValue(aName); + } + + const SGPropertyNode* localeRoot; + if (aRoot->hasChild("localized")) { + localeRoot = aRoot->getChild("localized")->getChild(locale); + } else { + // old behaviour where locale nodes are directly beneath /sim + localeRoot = aRoot->getChild(locale); + } + + if (localeRoot && localeRoot->hasChild(aName)) { + if (isLocalized) *isLocalized = true; + return localeRoot->getStringValue(aName); } return aRoot->getStringValue(aName); diff --git a/simgear/package/Package.hxx b/simgear/package/Package.hxx index ac38f758..03e44717 100644 --- a/simgear/package/Package.hxx +++ b/simgear/package/Package.hxx @@ -225,12 +225,14 @@ private: */ bool validate() const; - std::string getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const; + std::string getLocalisedString(const SGPropertyNode* aRoot, const char* aName, bool* isLocalized = nullptr) const; PreviewVec previewsFromProps(const SGPropertyNode_ptr& ptr) const; SGPropertyNode_ptr propsForVariant(const unsigned int vIndex, const char* propName = nullptr) const; + bool matchesDescription(const std::string &search) const; + SGPropertyNode_ptr m_props; std::string m_id; string_set m_tags; diff --git a/simgear/package/catalogTest1/catalog.xml b/simgear/package/catalogTest1/catalog.xml index 2a46604f..e16b3ec2 100644 --- a/simgear/package/catalogTest1/catalog.xml +++ b/simgear/package/catalogTest1/catalog.xml @@ -32,6 +32,15 @@ 860 Standard author + + + German description of C172 + + + French description of C172 + + + cessna ga piston @@ -99,6 +108,15 @@ C172 with skis A plane with skis + + + German description of C172 with skis + + + French description of C172 with skis + + + c172p @@ -157,6 +175,14 @@ jet ifr + + + German description of B737NG XYZ + + + French description of B737NG + + 5 5