sc/source/core/inc/cellkeytranslator.hxx  |   45 +------
 sc/source/core/tool/cellkeytranslator.cxx |  183 ++++++++++--------------------
 sc/source/core/tool/interpr1.cxx          |    4 
 sc/source/core/tool/interpr5.cxx          |    2 
 4 files changed, 71 insertions(+), 163 deletions(-)

New commits:
commit 28a2ee25d9d776f1f13a9f1fa67e19cef3dc6a76
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Wed Feb 5 11:48:55 2025 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Sun Feb 9 15:38:31 2025 +0100

    tdf#164995: only match keywords for requested locale and opcode
    
    The fuzzy search, where a matching keyword for a different language
    and/or function could be returned, resulted in the French "version"
    standing for standard "release", changing semantics.
    
    Change-Id: Icf96f0e0c0c032ce7779bf53fe73af060a59a484
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181313
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sc/source/core/inc/cellkeytranslator.hxx 
b/sc/source/core/inc/cellkeytranslator.hxx
index 622b62ac4903..adb471a1267a 100644
--- a/sc/source/core/inc/cellkeytranslator.hxx
+++ b/sc/source/core/inc/cellkeytranslator.hxx
@@ -40,14 +40,11 @@ struct Locale;
 
     function.
 
-    Note that when the locale and/or the opcode is specified, the function
-    tries to find a string with matching locale and/or opcode. But when it
-    fails to find one that satisfies the specified locale and/or opcode, it
-    returns a translated string with non-matching locale and/or opcode if
-    available. */
+    Note that the function only finds a string with matching locale and opcode.
+    Locale is matched as close as possible */
 namespace ScCellKeywordTranslator
 {
-void transKeyword(OUString& rName, const css::lang::Locale* pLocale, OpCode 
eOpCode);
+void transKeyword(OUString& rName, const css::lang::Locale& rLocale, OpCode 
eOpCode);
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/tool/cellkeytranslator.cxx 
b/sc/source/core/tool/cellkeytranslator.cxx
index 0c55db684aef..3a77651b5aab 100644
--- a/sc/source/core/tool/cellkeytranslator.cxx
+++ b/sc/source/core/tool/cellkeytranslator.cxx
@@ -78,70 +78,28 @@ struct ScCellKeyword
 
 typedef std::unordered_map<OUString, std::vector<ScCellKeyword>> 
ScCellKeywordHashMap;
 
-void lclMatchKeyword(OUString& rName, const ScCellKeywordHashMap& aMap,
-                            OpCode eOpCode, const lang::Locale* pLocale)
+void lclMatchKeyword(OUString& rName, const ScCellKeywordHashMap& aMap, OpCode 
eOpCode,
+                     const lang::Locale& rLocale)
 {
-    ScCellKeywordHashMap::const_iterator itrEnd = aMap.end();
+    assert(eOpCode != ocNone);
     ScCellKeywordHashMap::const_iterator itr = aMap.find(rName);
 
-    if ( itr == itrEnd || itr->second.empty() )
+    if (itr == aMap.end() || itr->second.empty())
         // No candidate strings exist.  Bail out.
         return;
 
-    if ( eOpCode == ocNone && !pLocale )
-    {
-        // Since no locale nor opcode matching is needed, simply return
-        // the first item on the list.
-        rName = itr->second.front().msName;
-        return;
-    }
-
-    LanguageTag aLanguageTag( pLocale ? *pLocale : 
lang::Locale(u""_ustr,u""_ustr,u""_ustr));
+    LanguageTag aLanguageTag(rLocale);
     const OUString* aBestMatchName = nullptr;
     LocaleMatch eLocaleMatchLevel = LOCALE_MATCH_NONE;
-    bool bOpCodeMatched = false;
 
     for (auto const& elem : itr->second)
     {
-        if ( eOpCode != ocNone && pLocale )
-        {
-            if (elem.meOpCode == eOpCode)
-            {
-                LocaleMatch eLevel = lclLocaleCompare(elem.mrLocale, 
aLanguageTag);
-                if ( eLevel == LOCALE_MATCH_ALL )
-                {
-                    // Name with matching opcode and locale found.
-                    rName = elem.msName;
-                    return;
-                }
-                else if ( eLevel > eLocaleMatchLevel )
-                {
-                    // Name with a better matching locale.
-                    eLocaleMatchLevel = eLevel;
-                    aBestMatchName = &elem.msName;
-                }
-                else if ( !bOpCodeMatched )
-                    // At least the opcode matches.
-                    aBestMatchName = &elem.msName;
-
-                bOpCodeMatched = true;
-            }
-        }
-        else if ( eOpCode != ocNone && !pLocale )
-        {
-            if ( elem.meOpCode == eOpCode )
-            {
-                // Name with a matching opcode preferred.
-                rName = elem.msName;
-                return;
-            }
-        }
-        else if ( pLocale )
+        if (elem.meOpCode == eOpCode)
         {
             LocaleMatch eLevel = lclLocaleCompare(elem.mrLocale, aLanguageTag);
             if ( eLevel == LOCALE_MATCH_ALL )
             {
-                // Name with matching locale preferred.
+                // Name with matching opcode and locale found.
                 rName = elem.msName;
                 return;
             }
@@ -252,17 +210,16 @@ ScCellKeywordHashMap MakeMap()
 
 } // namespace
 
-void ScCellKeywordTranslator::transKeyword(OUString& rName, const 
css::lang::Locale* pLocale,
+void ScCellKeywordTranslator::transKeyword(OUString& rName, const 
css::lang::Locale& rLocale,
                                            OpCode eOpCode)
 {
     static const ScCellKeywordHashMap saStringNameMap(MakeMap());
     static utl::TransliterationWrapper 
saTransWrapper(comphelper::getProcessComponentContext(),
                                                       
TransliterationFlags::LOWERCASE_UPPERCASE);
 
-    const LanguageType nLang = pLocale ? 
LanguageTag(*pLocale).makeFallback().getLanguageType()
-                                       : 
ScGlobal::oSysLocale->GetLanguageTag().getLanguageType();
+    const LanguageType nLang = 
LanguageTag(rLocale).makeFallback().getLanguageType();
     rName = saTransWrapper.transliterate(rName, nLang, 0, rName.getLength(), 
nullptr);
-    lclMatchKeyword(rName, saStringNameMap, eOpCode, pLocale);
+    lclMatchKeyword(rName, saStringNameMap, eOpCode, rLocale);
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index b3231e66b646..e651348598d4 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -2373,7 +2373,7 @@ void ScInterpreter::ScCell()
     {
         ScRefCellValue aCell(mrDoc, aCellPos);
 
-        ScCellKeywordTranslator::transKeyword(aInfoType, 
&ScGlobal::GetLocale(), ocCell);
+        ScCellKeywordTranslator::transKeyword(aInfoType, 
ScGlobal::GetLocale(), ocCell);
 
 // *** ADDRESS INFO ***
         if( aInfoType == "COL" )
@@ -2590,7 +2590,7 @@ void ScInterpreter::ScCellExternal()
     }
     aRef.SetAbsTab(-1); // revert the value.
 
-    ScCellKeywordTranslator::transKeyword(aInfoType, &ScGlobal::GetLocale(), 
ocCell);
+    ScCellKeywordTranslator::transKeyword(aInfoType, ScGlobal::GetLocale(), 
ocCell);
     ScExternalRefManager* pRefMgr = mrDoc.GetExternalRefManager();
 
     if ( aInfoType == "COL" )
diff --git a/sc/source/core/tool/interpr5.cxx b/sc/source/core/tool/interpr5.cxx
index f282d5fe7169..671fdaf0be1e 100644
--- a/sc/source/core/tool/interpr5.cxx
+++ b/sc/source/core/tool/interpr5.cxx
@@ -3336,7 +3336,7 @@ void ScInterpreter::ScInfo()
         return;
 
     OUString aStr = GetString().getString();
-    ScCellKeywordTranslator::transKeyword(aStr, &ScGlobal::GetLocale(), 
ocInfo);
+    ScCellKeywordTranslator::transKeyword(aStr, ScGlobal::GetLocale(), ocInfo);
     if( aStr == "SYSTEM" )
         PushString( u"" SC_INFO_OSVERSION ""_ustr );
     else if( aStr == "OSVERSION" )
commit 78d5ca5e451a52ccc72051dcf05ce3a72bbcb94b
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Wed Feb 5 11:48:52 2025 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Sun Feb 9 15:38:25 2025 +0100

    Simplify implementation of ScCellKeywordTranslator::transKeyword
    
    Move everything except the function declaration into CXX.
    
    Change-Id: Ib804431d27ded92e0fe7981beb4dbefc6c99ea76
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181312
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Jenkins

diff --git a/sc/source/core/inc/cellkeytranslator.hxx 
b/sc/source/core/inc/cellkeytranslator.hxx
index f2a30d77d72d..622b62ac4903 100644
--- a/sc/source/core/inc/cellkeytranslator.hxx
+++ b/sc/source/core/inc/cellkeytranslator.hxx
@@ -20,34 +20,18 @@
 #pragma once
 
 #include <formula/opcode.hxx>
-#include <unotools/transliterationwrapper.hxx>
-#include <vector>
-#include <memory>
-#include <unordered_map>
+#include <rtl/ustring.hxx>
 
 namespace com::sun::star::lang
 {
 struct Locale;
 }
 
-struct TransItem;
-
-struct ScCellKeyword
-{
-    OUString msName;
-    OpCode meOpCode;
-    const css::lang::Locale& mrLocale;
-
-    ScCellKeyword(const OUString& sName, OpCode eOpCode, const 
css::lang::Locale& rLocale);
-};
-
-typedef std::unordered_map<OUString, ::std::vector<ScCellKeyword>> 
ScCellKeywordHashMap;
-
 /** Translate cell function keywords.
 
-    This class provides a convenient way to translate a string keyword used as
+    Provides a convenient way to translate a string keyword used as
     a cell function argument.  Since Calc's built-in cell functions don't
-    localize string keywords, this class is used mainly to deal with an Excel
+    localize string keywords, this is used mainly to deal with an Excel
     document where string names may be localized.
 
     To use, simply call the
@@ -61,21 +45,9 @@ typedef std::unordered_map<OUString, 
::std::vector<ScCellKeyword>> ScCellKeyword
     fails to find one that satisfies the specified locale and/or opcode, it
     returns a translated string with non-matching locale and/or opcode if
     available. */
-class ScCellKeywordTranslator
+namespace ScCellKeywordTranslator
 {
-public:
-    static void transKeyword(OUString& rName, const css::lang::Locale* 
pLocale, OpCode eOpCode);
-    ~ScCellKeywordTranslator();
-
-private:
-    ScCellKeywordTranslator();
-
-    void addToMap(const OUString& rKey, const OUString& pName, const 
css::lang::Locale& rLocale,
-                  OpCode eOpCode);
-
-    static ::std::unique_ptr<ScCellKeywordTranslator> spInstance;
-    ScCellKeywordHashMap maStringNameMap;
-    ::utl::TransliterationWrapper maTransWrapper;
+void transKeyword(OUString& rName, const css::lang::Locale* pLocale, OpCode 
eOpCode);
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/tool/cellkeytranslator.cxx 
b/sc/source/core/tool/cellkeytranslator.cxx
index 2837a4a4aa68..0c55db684aef 100644
--- a/sc/source/core/tool/cellkeytranslator.cxx
+++ b/sc/source/core/tool/cellkeytranslator.cxx
@@ -17,17 +17,18 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
  */
 
-#include <memory>
+#include <sal/config.h>
+
+#include <vector>
+#include <unordered_map>
+
 #include <global.hxx>
 #include <cellkeytranslator.hxx>
 #include <comphelper/processfactory.hxx>
 #include <i18nlangtag/lang.h>
 #include <i18nutil/transliteration.hxx>
-#include <rtl/ustring.hxx>
 #include <unotools/syslocale.hxx>
-#include <com/sun/star/uno/Sequence.hxx>
-
-using ::com::sun::star::uno::Sequence;
+#include <unotools/transliterationwrapper.hxx>
 
 using namespace ::com::sun::star;
 
@@ -42,44 +43,42 @@ enum LocaleMatch
     LOCALE_MATCH_ALL
 };
 
-}
-
-static LocaleMatch lclLocaleCompare(const lang::Locale& rLocale1, const 
LanguageTag& rLanguageTag2)
+LocaleMatch lclLocaleCompare(const lang::Locale& rLocale1, const LanguageTag& 
rLanguageTag2)
 {
-    LocaleMatch eMatchLevel = LOCALE_MATCH_NONE;
     LanguageTag aLanguageTag1( rLocale1);
 
-    if ( aLanguageTag1.getLanguage() == rLanguageTag2.getLanguage() )
-        eMatchLevel = LOCALE_MATCH_LANG;
-    else
-        return eMatchLevel;
+    if (aLanguageTag1.getLanguage() != rLanguageTag2.getLanguage())
+        return LOCALE_MATCH_NONE;
 
-    if ( aLanguageTag1.getScript() == rLanguageTag2.getScript() )
-        eMatchLevel = LOCALE_MATCH_LANG_SCRIPT;
-    else
-        return eMatchLevel;
+    if (aLanguageTag1.getScript() != rLanguageTag2.getScript())
+        return LOCALE_MATCH_LANG;
 
-    if ( aLanguageTag1.getCountry() == rLanguageTag2.getCountry() )
-        eMatchLevel = LOCALE_MATCH_LANG_SCRIPT_COUNTRY;
-    else
-        return eMatchLevel;
+    if (aLanguageTag1.getCountry() != rLanguageTag2.getCountry())
+        return LOCALE_MATCH_LANG_SCRIPT;
 
-    if (aLanguageTag1 == rLanguageTag2)
-        return LOCALE_MATCH_ALL;
+    if (aLanguageTag1 != rLanguageTag2)
+        return LOCALE_MATCH_LANG_SCRIPT_COUNTRY;
 
-    return eMatchLevel;
+    return LOCALE_MATCH_ALL;
 }
 
-ScCellKeyword::ScCellKeyword(const OUString& sName, OpCode eOpCode, const 
lang::Locale& rLocale) :
-    msName(sName),
-    meOpCode(eOpCode),
-    mrLocale(rLocale)
+struct ScCellKeyword
 {
-}
+    OUString msName;
+    OpCode meOpCode;
+    const css::lang::Locale& mrLocale;
+
+    ScCellKeyword(const OUString& sName, OpCode eOpCode, const 
css::lang::Locale& rLocale)
+        : msName(sName)
+        , meOpCode(eOpCode)
+        , mrLocale(rLocale)
+    {
+    }
+};
 
-::std::unique_ptr<ScCellKeywordTranslator> ScCellKeywordTranslator::spInstance;
+typedef std::unordered_map<OUString, std::vector<ScCellKeyword>> 
ScCellKeywordHashMap;
 
-static void lclMatchKeyword(OUString& rName, const ScCellKeywordHashMap& aMap,
+void lclMatchKeyword(OUString& rName, const ScCellKeywordHashMap& aMap,
                             OpCode eOpCode, const lang::Locale* pLocale)
 {
     ScCellKeywordHashMap::const_iterator itrEnd = aMap.end();
@@ -160,35 +159,22 @@ static void lclMatchKeyword(OUString& rName, const 
ScCellKeywordHashMap& aMap,
         rName = *aBestMatchName;
 }
 
-void ScCellKeywordTranslator::transKeyword(OUString& rName, const 
lang::Locale* pLocale, OpCode eOpCode)
+ScCellKeywordHashMap MakeMap()
 {
-    if (!spInstance)
-        spInstance.reset( new ScCellKeywordTranslator );
-
-    LanguageType nLang = pLocale ?
-        LanguageTag(*pLocale).makeFallback().getLanguageType() : 
ScGlobal::oSysLocale->GetLanguageTag().getLanguageType();
-    Sequence<sal_Int32> aOffsets;
-    rName = spInstance->maTransWrapper.transliterate(rName, nLang, 0, 
rName.getLength(), &aOffsets);
-    lclMatchKeyword(rName, spInstance->maStringNameMap, eOpCode, pLocale);
-}
+    ScCellKeywordHashMap map;
 
-struct TransItem
-{
-    OUString            from;
-    OUString            to;
-    OpCode              func;
-};
-
-ScCellKeywordTranslator::ScCellKeywordTranslator() :
-    maTransWrapper( ::comphelper::getProcessComponentContext(),
-                    TransliterationFlags::LOWERCASE_UPPERCASE )
-{
     // All keywords must be uppercase, and the mapping must be from the
     // localized keyword to the English keyword.
+    struct TransItem
+    {
+        OUString from;
+        OUString to;
+        OpCode func;
+    };
 
     // French language locale
 
-    static const lang::Locale aFr(u"fr"_ustr, u""_ustr, u""_ustr);
+    static const lang::Locale aFr(u"fr"_ustr, {}, {});
 
     static constexpr TransItem pFr[] = {
         { u"ADRESSE"_ustr, u"ADDRESS"_ustr, ocCell },
@@ -208,11 +194,11 @@ ScCellKeywordTranslator::ScCellKeywordTranslator() :
     };
 
     for (const auto& element : pFr)
-        addToMap(element.from, element.to, aFr, element.func);
+        map[element.from].emplace_back(element.to, element.func, aFr);
 
     // Hungarian language locale
 
-    static const lang::Locale aHu(u"hu"_ustr, u""_ustr, u""_ustr);
+    static const lang::Locale aHu(u"hu"_ustr, {}, {});
 
     static constexpr TransItem pHu[] = {
         { u"CÍM"_ustr, u"ADDRESS"_ustr, ocCell },
@@ -236,11 +222,11 @@ ScCellKeywordTranslator::ScCellKeywordTranslator() :
     };
 
     for (const auto& element : pHu)
-        addToMap(element.from, element.to, aHu, element.func);
+        map[element.from].emplace_back(element.to, element.func, aHu);
 
     // German language locale
 
-    static const lang::Locale aDe(u"de"_ustr, u""_ustr, u""_ustr);
+    static const lang::Locale aDe(u"de"_ustr, {}, {});
 
     static constexpr TransItem pDe[] = {
         { u"ZEILE"_ustr, u"ROW"_ustr, ocCell },
@@ -259,28 +245,24 @@ ScCellKeywordTranslator::ScCellKeywordTranslator() :
     };
 
     for (const auto& element : pDe)
-        addToMap(element.from, element.to, aDe, element.func);
-}
+        map[element.from].emplace_back(element.to, element.func, aDe);
 
-ScCellKeywordTranslator::~ScCellKeywordTranslator()
-{
+    return map;
 }
 
-void ScCellKeywordTranslator::addToMap(const OUString& rKey, const OUString& 
pName, const lang::Locale& rLocale, OpCode eOpCode)
-{
-    ScCellKeyword aKeyItem( pName, eOpCode, rLocale );
-
-    ScCellKeywordHashMap::iterator itrEnd = maStringNameMap.end();
-    ScCellKeywordHashMap::iterator itr = maStringNameMap.find(rKey);
+} // namespace
 
-    if ( itr == itrEnd )
-    {
-        // New keyword.
-        std::vector<ScCellKeyword> aVector { std::move(aKeyItem) };
-        maStringNameMap.emplace(rKey, aVector);
-    }
-    else
-        itr->second.emplace_back(std::move(aKeyItem));
+void ScCellKeywordTranslator::transKeyword(OUString& rName, const 
css::lang::Locale* pLocale,
+                                           OpCode eOpCode)
+{
+    static const ScCellKeywordHashMap saStringNameMap(MakeMap());
+    static utl::TransliterationWrapper 
saTransWrapper(comphelper::getProcessComponentContext(),
+                                                      
TransliterationFlags::LOWERCASE_UPPERCASE);
+
+    const LanguageType nLang = pLocale ? 
LanguageTag(*pLocale).makeFallback().getLanguageType()
+                                       : 
ScGlobal::oSysLocale->GetLanguageTag().getLanguageType();
+    rName = saTransWrapper.transliterate(rName, nLang, 0, rName.getLength(), 
nullptr);
+    lclMatchKeyword(rName, saStringNameMap, eOpCode, pLocale);
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to