sw/inc/strings.hrc                          |    1 +
 sw/source/ui/misc/translatelangselect.cxx   |   11 ++++++-----
 sw/source/uibase/shells/textsh1.cxx         |   14 ++++++++++----
 sw/source/uibase/shells/translatehelper.cxx |   13 ++++++++++++-
 4 files changed, 29 insertions(+), 10 deletions(-)

New commits:
commit 2bfe6dcbda3e29adc7495bb74173683abce1d461
Author:     Mike Kaganski <[email protected]>
AuthorDate: Tue Dec 23 15:58:21 2025 +0500
Commit:     Mike Kaganski <[email protected]>
CommitDate: Sun Dec 28 12:09:38 2025 +0100

    tdf#152706: Trim the stored API URL before appending query
    
    There already was a call to trim, obviously aimed to handle accidental
    spaces entered by user. But the call only happened after the original
    URL string was concatenated with a query string; so the trailing space
    would not be trimmed.
    
    Fix it here.
    
    Change-Id: Ice6bd7bed2742b44fef52fcd6edd8f6739a2ca46
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196255
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <[email protected]>

diff --git a/sw/source/ui/misc/translatelangselect.cxx 
b/sw/source/ui/misc/translatelangselect.cxx
index 061d0662e1dd..15a2a406ad3f 100644
--- a/sw/source/ui/misc/translatelangselect.cxx
+++ b/sw/source/ui/misc/translatelangselect.cxx
@@ -27,6 +27,7 @@
 #include <translatelangselect.hxx>
 #include <pagedesc.hxx>
 #include <poolfmt.hxx>
+#include <o3tl/string_view.hxx>
 #include <sal/log.hxx>
 #include <ndtxt.hxx>
 #include <shellio.hxx>
@@ -139,7 +140,9 @@ IMPL_LINK_NOARG(SwTranslateLangSelectDlg, 
LangSelectTranslateHdl, weld::Button&,
         = officecfg::Office::Linguistic::Translation::Deepl::ApiURL::get();
     std::optional<OUString> oDeeplKey
         = officecfg::Office::Linguistic::Translation::Deepl::AuthKey::get();
-    if (!oDeeplAPIUrl || oDeeplAPIUrl->isEmpty() || !oDeeplKey || 
oDeeplKey->isEmpty())
+    auto sApiUrlTrimmed = oDeeplAPIUrl ? o3tl::trim(*oDeeplAPIUrl) : 
std::u16string_view();
+    auto sKeyTrimmed = oDeeplKey ? o3tl::trim(*oDeeplKey) : 
std::u16string_view();
+    if (sApiUrlTrimmed.empty() || sKeyTrimmed.empty())
     {
         SAL_WARN("sw.ui", "SwTranslateLangSelectDlg: API options are not set");
         m_xDialog->response(RET_CANCEL);
@@ -147,10 +150,8 @@ IMPL_LINK_NOARG(SwTranslateLangSelectDlg, 
LangSelectTranslateHdl, weld::Button&,
     }
 
     const OString aAPIUrl
-        = OUStringToOString(rtl::Concat2View(*oDeeplAPIUrl + 
"?tag_handling=html"),
-                            RTL_TEXTENCODING_UTF8)
-              .trim();
-    const OString aAuthKey = OUStringToOString(*oDeeplKey, 
RTL_TEXTENCODING_UTF8).trim();
+        = OUStringToOString(sApiUrlTrimmed, RTL_TEXTENCODING_UTF8) + 
"?tag_handling=html";
+    const OString aAuthKey = OUStringToOString(sKeyTrimmed, 
RTL_TEXTENCODING_UTF8);
     const auto aTargetLang
         = 
getLanguageVec().at(SwTranslateLangSelectDlg::selectedLangIdx).getLanguage();
 
diff --git a/sw/source/uibase/shells/textsh1.cxx 
b/sw/source/uibase/shells/textsh1.cxx
index 497ecc8c6d86..78b90721acb9 100644
--- a/sw/source/uibase/shells/textsh1.cxx
+++ b/sw/source/uibase/shells/textsh1.cxx
@@ -2305,13 +2305,16 @@ void SwTextShell::Execute(SfxRequest &rReq)
         {
             std::optional<OUString> oDeeplAPIUrl = 
officecfg::Office::Linguistic::Translation::Deepl::ApiURL::get();
             std::optional<OUString> oDeeplKey = 
officecfg::Office::Linguistic::Translation::Deepl::AuthKey::get();
-            if (!oDeeplAPIUrl || oDeeplAPIUrl->isEmpty() || !oDeeplKey || 
oDeeplKey->isEmpty())
+            auto sApiUrlTrimmed = oDeeplAPIUrl ? o3tl::trim(*oDeeplAPIUrl) : 
std::u16string_view();
+            auto sKeyTrimmed = oDeeplKey ? o3tl::trim(*oDeeplKey) : 
std::u16string_view();
+            if (sApiUrlTrimmed.empty() || sKeyTrimmed.empty())
             {
                 SAL_WARN("sw.ui", "SID_FM_TRANSLATE: API options are not set");
                 break;
             }
-            const OString aAPIUrl = 
OUStringToOString(rtl::Concat2View(*oDeeplAPIUrl + "?tag_handling=html"), 
RTL_TEXTENCODING_UTF8).trim();
-            const OString aAuthKey = OUStringToOString(*oDeeplKey, 
RTL_TEXTENCODING_UTF8).trim();
+            const OString aAPIUrl
+                = OUStringToOString(sApiUrlTrimmed, RTL_TEXTENCODING_UTF8) + 
"?tag_handling=html";
+            const OString aAuthKey = OUStringToOString(sKeyTrimmed, 
RTL_TEXTENCODING_UTF8);
             OString aTargetLang = OUStringToOString(static_cast<const 
SfxStringItem*>(pTargetLangStringItem)->GetValue(), RTL_TEXTENCODING_UTF8);
             SwTranslateHelper::TranslateAPIConfig aConfig({aAPIUrl, aAuthKey, 
aTargetLang});
             SwTranslateHelper::TranslateDocument(rWrtSh, aConfig);
@@ -3966,7 +3969,10 @@ void SwTextShell::GetState( SfxItemSet &rSet )
                     }
                     std::optional<OUString> oDeeplAPIUrl = 
officecfg::Office::Linguistic::Translation::Deepl::ApiURL::get();
                     std::optional<OUString> oDeeplKey = 
officecfg::Office::Linguistic::Translation::Deepl::AuthKey::get();
-                    if (!oDeeplAPIUrl || oDeeplAPIUrl->isEmpty() || !oDeeplKey 
|| oDeeplKey->isEmpty())
+                    auto sApiUrlTrimmed
+                        = oDeeplAPIUrl ? o3tl::trim(*oDeeplAPIUrl) : 
std::u16string_view();
+                    auto sKeyTrimmed = oDeeplKey ? o3tl::trim(*oDeeplKey) : 
std::u16string_view();
+                    if (sApiUrlTrimmed.empty() || sKeyTrimmed.empty())
                     {
                         rSet.DisableItem(nWhich);
                     }
commit 329b88bd2abc2ee09a371a29c0bbb85fd7b6e1f7
Author:     Mike Kaganski <[email protected]>
AuthorDate: Tue Dec 23 15:56:32 2025 +0500
Commit:     Mike Kaganski <[email protected]>
CommitDate: Sun Dec 28 12:09:32 2025 +0100

    tdf#152706: Show an error message on translation error
    
    I don't know if this may be called in a headless way; if it
    may, then a proper interaction handler should be passed to
    TranslateDocumentCancellable.
    
    Change-Id: I4a0f9170ebece54d6debcd36e495d33e97e57980
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196254
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <[email protected]>

diff --git a/sw/inc/strings.hrc b/sw/inc/strings.hrc
index 7fb72a1d2840..0dc4bc9bd2df 100644
--- a/sw/inc/strings.hrc
+++ b/sw/inc/strings.hrc
@@ -301,6 +301,7 @@
 #define STR_HIDE_NOTE_AUTHOR                    NC_("STR_HIDE_NOTE_AUTHOR", 
"H~ide All Comments by $1")
 #define STR_OUTLINE_NUMBERING                   NC_("STR_OUTLINE_NUMBERING", 
"Heading Numbering")
 #define STR_STATSTR_SWTRANSLATE                 NC_("STR_STATSTR_SWTRANSLATE", 
"Translating document...")
+#define STR_SWTRANSLATE_ERROR                   NC_("STR_SWTRANSLATE_ERROR", 
"Error translating document.")
 /* To translators: $1 == will be replaced by STR_WORDCOUNT_WORDARG, and $2 by 
STR_WORDCOUNT_COLARG
    e.g. Selected: 1 word, 2 characters */
 #define STR_WORDCOUNT                           NC_("STR_WORDCOUNT", 
"Selected: $1, $2")
diff --git a/sw/source/uibase/shells/translatehelper.cxx 
b/sw/source/uibase/shells/translatehelper.cxx
index ae2461481e36..bc2a1eaef785 100644
--- a/sw/source/uibase/shells/translatehelper.cxx
+++ b/sw/source/uibase/shells/translatehelper.cxx
@@ -196,7 +196,10 @@ void TranslateDocumentCancellable(SwWrtShell& rWrtSh, 
const TranslateAPIConfig&
             }
             else
             {
-                // TODO: show error?
+                std::unique_ptr<weld::MessageDialog> 
xBox(Application::CreateMessageDialog(
+                    nullptr, VclMessageType::Error, VclButtonsType::Ok,
+                    SwResId(STR_SWTRANSLATE_ERROR)));
+                xBox->run();
                 break;
             }
 
commit 3cfc00a638dfaffc48019242bcbd66f98bfb9318
Author:     Mike Kaganski <[email protected]>
AuthorDate: Tue Dec 23 15:51:47 2025 +0500
Commit:     Mike Kaganski <[email protected]>
CommitDate: Sun Dec 28 12:09:26 2025 +0100

    tdf#152706: don't overwrite source on translation failure
    
    linguistic::Translate returns an empty string, when any error occurs
    (it may be a malformed URL, or wrong key, or a server error). Then
    PasteHTMLToPaM would replace the selection with nothing, and after
    that, show a "Requested clipboard format is not available" message.
    
    This change checks the returned string, to avoid the replacement. It
    doesn't show a message itself (TODO in a follow-up).
    
    Change-Id: Ia92b0d0a609386bf3988fc9ef7e01da84311ab38
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196253
    Reviewed-by: Mike Kaganski <[email protected]>
    Tested-by: Jenkins

diff --git a/sw/source/uibase/shells/translatehelper.cxx 
b/sw/source/uibase/shells/translatehelper.cxx
index 10b2976f5b2e..ae2461481e36 100644
--- a/sw/source/uibase/shells/translatehelper.cxx
+++ b/sw/source/uibase/shells/translatehelper.cxx
@@ -190,7 +190,15 @@ void TranslateDocumentCancellable(SwWrtShell& rWrtSh, 
const TranslateAPIConfig&
             const auto aOut = SwTranslateHelper::ExportPaMToHTML(cursor.get());
             const auto aTranslatedOut = linguistic::Translate(
                 rConfig.m_xTargetLanguage, rConfig.m_xAPIUrl, 
rConfig.m_xAuthKey, aOut);
-            SwTranslateHelper::PasteHTMLToPaM(rWrtSh, cursor.get(), 
aTranslatedOut);
+            if (!aTranslatedOut.isEmpty())
+            {
+                SwTranslateHelper::PasteHTMLToPaM(rWrtSh, cursor.get(), 
aTranslatedOut);
+            }
+            else
+            {
+                // TODO: show error?
+                break;
+            }
 
             if (xStatusIndicator.is() && nCount)
                 xStatusIndicator->setValue((100 * ++nProgress) / nCount);

Reply via email to