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: */