include/svtools/strings.hrc | 3 lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx | 36 ++++++---- sw/source/core/edit/edlingu.cxx | 2 3 files changed, 29 insertions(+), 12 deletions(-)
New commits: commit 59923249e45993805f1f82399d0251f4b63e549b Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Wed Oct 16 17:12:12 2024 +0500 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Tue Oct 22 23:15:55 2024 +0200 tdf#160127: Improve grammar check popups from Duden When there is a grammar check error that it has no suggestions for, Duden may return a JSON without suggestions, but still informing about the type of the error, like ... { "offset": 468, "length": 8, "errorcode": 21, "type": "orth", "proposals": [] }, ... Before the change, we underlined the error, but right-clicking it would only bring the normal Writer's context menu, as if there were no error. This was made in commit 7697ef9d8fbbed7afba10c00ff9f5362d0540cdd (Proof reading suggestions:, 2023-11-28); before that change, the context menu was shown, but since it had no suggestions, and no explanation text, it was considered better to just not show the grammar check results. But no menu for an underlined word is no better; so let's instead show the explanation, based on the type of the error reported by Duden - that is stored in SingleProofreadingError::aShortComment. Also set aFullComment, which is used in the grammar check dialog. Incidentally, it even improves popups with suggestions, because it now has the explanation as well, where previously only was an icon without any text. It may be further improved in a follow-up, because there is "errorcode" in the message, which we may use to add more details to the explanation. tdf#160127 should be fixed with this, too; but if there are cases when there are neither suggestions, nor explanation available, it will need further work. Change-Id: I62cde204e0142d6226c9c9486f1cdb5ffc20dca8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175017 Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> Tested-by: Jenkins (cherry picked from commit 3233383b2631788e7cfb0dd0b92d879322561616) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175397 Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de> diff --git a/include/svtools/strings.hrc b/include/svtools/strings.hrc index ab18119242b3..faa3e7cd4b2a 100644 --- a/include/svtools/strings.hrc +++ b/include/svtools/strings.hrc @@ -350,5 +350,8 @@ #define STR_DESCRIPTION_MYTHES NC_("STR_DESCRIPTION_MYTHES", "MyThes Thesaurus") #define STR_DESCRIPTION_IGNOREALLLIST NC_("STR_DESCRIPTION_IGNOREALLLIST", "List of Ignored Words") #define STR_DESCRIPTION_LANGUAGETOOL NC_("STR_DESCRIPTION_LANGUAGETOOL", "LanguageTool Remote Grammar Checker") +#define STR_DESCRIPTION_SPELLING_ERROR NC_("STR_DESCRIPTION_SPELLING_ERROR", "Spelling error") +#define STR_DESCRIPTION_GRAMMAR_ERROR NC_("STR_DESCRIPTION_GRAMMAR_ERROR_LONG", "Grammar error") +#define STR_DESCRIPTION_STYLE_ERROR NC_("STR_DESCRIPTION_STYLE_ERROR", "Bad style") /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx b/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx index e0a9fd8a718d..00dccc9b2db2 100644 --- a/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx +++ b/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx @@ -235,28 +235,42 @@ uno::Sequence<SingleProofreadingError> parseJson(std::string&& json, std::string return {}; } +OUString DudenTypeToComment(const std::string& type, const Locale& rLocale) +{ + // TODO: consider also "errorcode", some values of which are explained + // at https://main.dks.epc.de/doc/Relnotes.html + TranslateId id = STR_DESCRIPTION_SPELLING_ERROR; // matches both "orth" and "term" + if (type == "gram") + id = STR_DESCRIPTION_GRAMMAR_ERROR; + else if (type == "style") + id = STR_DESCRIPTION_STYLE_ERROR; + std::locale loc(Translate::Create("svt", LanguageTag(rLocale))); + return Translate::get(id, loc); +} + void parseDudenResponse(ProofreadingResult& rResult, std::string&& aJSONBody) { rResult.aErrors = parseJson( std::move(aJSONBody), "check-positions", - [](const boost::property_tree::ptree& rPos, SingleProofreadingError& rError) { + [& locale = rResult.aLocale](const boost::property_tree::ptree& rPos, + SingleProofreadingError& rError) { rError.nErrorStart = rPos.get<int>("offset", 0); rError.nErrorLength = rPos.get<int>("length", 0); rError.nErrorType = text::TextMarkupType::PROOFREADING; - //rError.aShortComment = ?? - //rError.aFullComment = ?? const std::string sType = rPos.get<std::string>("type", {}); + rError.aShortComment = DudenTypeToComment(sType, locale); + rError.aFullComment = rError.aShortComment; rError.aProperties = { lcl_GetLineColorPropertyFromErrorId(sType) }; - const auto proposals = rPos.get_child_optional("proposals"); - if (!proposals) - return; - rError.aSuggestions.realloc(std::min(proposals->size(), MAX_SUGGESTIONS_SIZE)); - auto itProp = proposals->begin(); - for (auto& rSuggestion : asNonConstRange(rError.aSuggestions)) + if (const auto proposals = rPos.get_child_optional("proposals")) { - rSuggestion = OStringToOUString(itProp->second.data(), RTL_TEXTENCODING_UTF8); - itProp++; + rError.aSuggestions.realloc(std::min(proposals->size(), MAX_SUGGESTIONS_SIZE)); + auto itProp = proposals->begin(); + for (auto& rSuggestion : asNonConstRange(rError.aSuggestions)) + { + rSuggestion = OStringToOUString(itProp->second.data(), RTL_TEXTENCODING_UTF8); + itProp++; + } } }); } diff --git a/sw/source/core/edit/edlingu.cxx b/sw/source/core/edit/edlingu.cxx index 5731d2b2be49..17c93ed4ece3 100644 --- a/sw/source/core/edit/edlingu.cxx +++ b/sw/source/core/edit/edlingu.cxx @@ -1032,7 +1032,7 @@ bool SwEditShell::GetGrammarCorrection( [rErrorPosInText, nLen](const linguistic2::SingleProofreadingError &rError) { return rError.nErrorStart <= rErrorPosInText && rErrorPosInText + nLen <= rError.nErrorStart + rError.nErrorLength - && rError.aSuggestions.size() > 0; }); + && (rError.aSuggestions.hasElements() || !rError.aShortComment.isEmpty()); }); if (pError != std::cend(rResult.aErrors)) { rSuggestions = pError->aSuggestions;