linguistic/source/gciterator.cxx | 49 ++++++++++++++++++++++++++------------- linguistic/source/gciterator.hxx | 14 ++++++++--- 2 files changed, 44 insertions(+), 19 deletions(-)
New commits: commit 21db28345999ee840542532224d67f1f2527f16e Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Sun Mar 5 11:06:29 2023 +0300 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Mon Mar 6 14:49:14 2023 +0000 tdf#152459: fallback to language-only when looking for grammar checker LanguageTool registers itself for languages like "en-US", "es-AR", "de-DE"; but also for generic "en", "es", "de". When the requested language, like "fr-CH" or "es-PH", is not found in the registered grammar checkers, the fallback strings will be attempted. Change-Id: Id460db8d378f246ea98191d22bdb3537fd1aee1c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148201 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> (cherry picked from commit e7ae5b4793fb74309d5d1f32c3c696d07071d676) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148232 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/linguistic/source/gciterator.cxx b/linguistic/source/gciterator.cxx index 581f356f215e..993b0258db32 100644 --- a/linguistic/source/gciterator.cxx +++ b/linguistic/source/gciterator.cxx @@ -488,8 +488,30 @@ void GrammarCheckingIterator::ProcessResult( } +std::pair<OUString, std::optional<OUString>> +GrammarCheckingIterator::getServiceForLocale(const lang::Locale& rLocale) const +{ + if (!rLocale.Language.isEmpty()) + { + const OUString sBcp47 = LanguageTag::convertToBcp47(rLocale, false); + GCImplNames_t::const_iterator aLangIt(m_aGCImplNamesByLang.find(sBcp47)); + if (aLangIt != m_aGCImplNamesByLang.end()) + return { aLangIt->second, {} }; + + for (const auto& sFallbackBcp47 : LanguageTag(rLocale).getFallbackStrings(false)) + { + aLangIt = m_aGCImplNamesByLang.find(sFallbackBcp47); + if (aLangIt != m_aGCImplNamesByLang.end()) + return { aLangIt->second, sFallbackBcp47 }; + } + } + + return {}; +} + + uno::Reference< linguistic2::XProofreader > GrammarCheckingIterator::GetGrammarChecker( - const lang::Locale &rLocale ) + lang::Locale &rLocale ) { uno::Reference< linguistic2::XProofreader > xRes; @@ -503,11 +525,11 @@ uno::Reference< linguistic2::XProofreader > GrammarCheckingIterator::GetGrammarC m_bGCServicesChecked = true; } - const LanguageType nLang = LanguageTag::convertToLanguageType( rLocale, false); - GCImplNames_t::const_iterator aLangIt( m_aGCImplNamesByLang.find( nLang ) ); - if (aLangIt != m_aGCImplNamesByLang.end()) // matching configured language found? + if (const auto& [aSvcImplName, oFallbackBcp47] = getServiceForLocale(rLocale); + !aSvcImplName.isEmpty()) // matching configured language found? { - OUString aSvcImplName( aLangIt->second ); + if (oFallbackBcp47) + rLocale = LanguageTag::convertToLocale(*oFallbackBcp47, false); GCReferences_t::const_iterator aImplNameIt( m_aGCReferencesByService.find( aSvcImplName ) ); if (aImplNameIt != m_aGCReferencesByService.end()) // matching impl name found? { @@ -1086,8 +1108,7 @@ void GrammarCheckingIterator::GetConfiguredGCSvcs_Impl() { // only the first entry is used, there should be only one grammar checker per language const OUString aImplName( aImplNames[0] ); - const LanguageType nLang = LanguageTag::convertToLanguageType( rElementName ); - aTmpGCImplNamesByLang[ nLang ] = aImplName; + aTmpGCImplNamesByLang[rElementName] = aImplName; } } else @@ -1135,17 +1156,17 @@ void GrammarCheckingIterator::SetServiceList( { ::osl::Guard< ::osl::Mutex > aGuard( MyMutex() ); - LanguageType nLanguage = LinguLocaleToLanguage( rLocale ); + OUString sBcp47 = LanguageTag::convertToBcp47(rLocale, false); OUString aImplName; if (rSvcImplNames.hasElements()) aImplName = rSvcImplNames[0]; // there is only one grammar checker per language - if (!LinguIsUnspecified(nLanguage) && nLanguage != LANGUAGE_DONTKNOW) + if (!LinguIsUnspecified(sBcp47) && !sBcp47.isEmpty()) { if (!aImplName.isEmpty()) - m_aGCImplNamesByLang[ nLanguage ] = aImplName; + m_aGCImplNamesByLang[sBcp47] = aImplName; else - m_aGCImplNamesByLang.erase( nLanguage ); + m_aGCImplNamesByLang.erase(sBcp47); } } @@ -1155,11 +1176,7 @@ uno::Sequence< OUString > GrammarCheckingIterator::GetServiceList( { ::osl::Guard< ::osl::Mutex > aGuard( MyMutex() ); - OUString aImplName; // there is only one grammar checker per language - LanguageType nLang = LinguLocaleToLanguage( rLocale ); - GCImplNames_t::const_iterator aIt( m_aGCImplNamesByLang.find( nLang ) ); - if (aIt != m_aGCImplNamesByLang.end()) - aImplName = aIt->second; + const OUString aImplName = getServiceForLocale(rLocale).first; // there is only one grammar checker per language if (!aImplName.isEmpty()) return { aImplName }; diff --git a/linguistic/source/gciterator.hxx b/linguistic/source/gciterator.hxx index c4cc076b3c9b..f159a9ad968f 100644 --- a/linguistic/source/gciterator.hxx +++ b/linguistic/source/gciterator.hxx @@ -40,6 +40,8 @@ #include <i18nlangtag/lang.h> #include <map> +#include <optional> +#include <utility> #include <deque> #include "defs.hxx" @@ -97,8 +99,8 @@ class GrammarCheckingIterator: DocMap_t m_aDocIdMap; - // language -> implname mapping - typedef std::map< LanguageType, OUString > GCImplNames_t; + // BCP-47 language tag -> implname mapping + typedef std::map< OUString, OUString > GCImplNames_t; GCImplNames_t m_aGCImplNamesByLang; // implname -> UNO reference mapping @@ -136,13 +138,19 @@ class GrammarCheckingIterator: sal_Int32 GetSuggestedEndOfSentence( const OUString &rText, sal_Int32 nSentenceStartPos, const css::lang::Locale &rLocale ); void GetConfiguredGCSvcs_Impl(); - css::uno::Reference< css::linguistic2::XProofreader > GetGrammarChecker( const css::lang::Locale & rLocale ); + css::uno::Reference< css::linguistic2::XProofreader > GetGrammarChecker( css::lang::Locale & rLocale ); css::uno::Reference< css::util::XChangesBatch > const & GetUpdateAccess() const; GrammarCheckingIterator( const GrammarCheckingIterator & ) = delete; GrammarCheckingIterator & operator = ( const GrammarCheckingIterator & ) = delete; + // Gets the grammar checker service, using fallback locales if necessary, + // and the BCP-47 tag for the updated locale, if the fallback was used. + // Precondition: MyMutex() is locked. + std::pair<OUString, std::optional<OUString>> + getServiceForLocale(const css::lang::Locale& rLocale) const; + public: void DequeueAndCheck();