Rebased ref, commits from common ancestor:
commit 45b74b4b7e61751b350fcbc2526d482a2ad1b18b
Author:     Mert Tumer <mert.tu...@collabora.com>
AuthorDate: Tue Jul 5 12:03:27 2022 +0300
Commit:     Mert Tumer <mert.tu...@collabora.com>
CommitDate: Thu Jul 14 18:45:31 2022 +0300

    wip translate
    
    Signed-off-by: Mert Tumer <mert.tu...@collabora.com>

diff --git a/cui/Library_cui.mk b/cui/Library_cui.mk
index d455a64ab266..c4c0a52b2ef4 100644
--- a/cui/Library_cui.mk
+++ b/cui/Library_cui.mk
@@ -181,6 +181,7 @@ $(eval $(call gb_Library_add_exception_objects,cui,\
     cui/source/options/optgenrl \
     cui/source/options/opthtml \
     cui/source/options/optlanguagetool \
+    cui/source/options/optdeepl \
     cui/source/options/optinet2 \
     cui/source/options/optjava \
     cui/source/options/optjsearch \
diff --git a/cui/UIConfig_cui.mk b/cui/UIConfig_cui.mk
index 806779daaa9d..0ed879e2b228 100644
--- a/cui/UIConfig_cui.mk
+++ b/cui/UIConfig_cui.mk
@@ -139,6 +139,7 @@ $(eval $(call gb_UIConfig_add_uifiles,cui,\
        cui/uiconfig/ui/optgeneralpage \
        cui/uiconfig/ui/opthtmlpage \
        cui/uiconfig/ui/langtoolconfigpage \
+       cui/uiconfig/ui/deepltabpage \
        cui/uiconfig/ui/optionsdialog \
        cui/uiconfig/ui/optjsearchpage \
        cui/uiconfig/ui/optlanguagespage \
diff --git a/cui/inc/treeopt.hrc b/cui/inc/treeopt.hrc
index 952b79ea92d4..6d5bc4004a53 100644
--- a/cui/inc/treeopt.hrc
+++ b/cui/inc/treeopt.hrc
@@ -55,7 +55,8 @@ const std::pair<TranslateId, sal_uInt16> 
SID_LANGUAGE_OPTIONS_RES[] =
     { NC_("SID_LANGUAGE_OPTIONS_RES", "Searching in Japanese"),  
RID_SVXPAGE_JSEARCH_OPTIONS },
     { NC_("SID_LANGUAGE_OPTIONS_RES", "Asian Layout"),  
RID_SVXPAGE_ASIAN_LAYOUT },
     { NC_("SID_LANGUAGE_OPTIONS_RES", "Complex Text Layout"),  
RID_SVXPAGE_OPTIONS_CTL },
-    { NC_("SID_LANGUAGE_OPTIONS_RES", "LanguageTool Server Settings"),  
RID_SVXPAGE_LANGTOOL_OPTIONS }
+    { NC_("SID_LANGUAGE_OPTIONS_RES", "LanguageTool Server Settings"),  
RID_SVXPAGE_LANGTOOL_OPTIONS },
+    { NC_("SID_LANGUAGE_OPTIONS_RES", "DeepL Server Settings"),  
RID_SVXPAGE_DEEPL_OPTIONS }
 };
 
 const std::pair<TranslateId, sal_uInt16> SID_INET_DLG_RES[] =
diff --git a/cui/source/options/optdeepl.cxx b/cui/source/options/optdeepl.cxx
new file mode 100644
index 000000000000..94b48ccc2f43
--- /dev/null
+++ b/cui/source/options/optdeepl.cxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "optdeepl.hxx"
+#include <svtools/deeplcfg.hxx>
+
+OptDeeplTabPage::OptDeeplTabPage(weld::Container* pPage,
+                                               weld::DialogController* 
pController,
+                                               const SfxItemSet& rSet)
+    : SfxTabPage(pPage, pController, "cui/ui/deepltabpage.ui", "OptDeeplPage", 
&rSet)
+    , m_xAPIUrl(m_xBuilder->weld_entry("apiurl"))
+    , m_xAuthKey(m_xBuilder->weld_entry("authkey"))
+{
+
+}
+
+OptDeeplTabPage::~OptDeeplTabPage() {}
+
+void OptDeeplTabPage::Reset(const SfxItemSet*)
+{
+    SvxDeeplOptions& rDeeplOptions = SvxDeeplOptions::Get();
+    m_xAPIUrl->set_text(rDeeplOptions.getAPIUrl());
+    m_xAuthKey->set_text(rDeeplOptions.getAuthKey());
+}
+
+bool OptDeeplTabPage::FillItemSet(SfxItemSet*)
+{
+    SvxDeeplOptions& rDeeplOptions = SvxDeeplOptions::Get();
+    rDeeplOptions.setAPIUrl(m_xAPIUrl->get_text());
+    rDeeplOptions.setAuthKey(m_xAuthKey->get_text());
+    return false;
+}
+
+std::unique_ptr<SfxTabPage> OptDeeplTabPage::Create(weld::Container* pPage,
+                                                           
weld::DialogController* pController,
+                                                           const SfxItemSet* 
rAttrSet)
+{
+    return std::make_unique<OptDeeplTabPage>(pPage, pController, *rAttrSet);
+}
diff --git a/cui/source/options/optdeepl.hxx b/cui/source/options/optdeepl.hxx
new file mode 100644
index 000000000000..124f9494c4aa
--- /dev/null
+++ b/cui/source/options/optdeepl.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include <sfx2/tabdlg.hxx>
+
+class OptDeeplTabPage : public SfxTabPage
+{
+public:
+    OptDeeplTabPage(weld::Container* pPage, weld::DialogController* 
pController,
+                           const SfxItemSet& rSet);
+    virtual ~OptDeeplTabPage() override;
+    static std::unique_ptr<SfxTabPage>
+    Create(weld::Container* pPage, weld::DialogController* pController, const 
SfxItemSet* rAttrSet);
+
+    virtual bool FillItemSet(SfxItemSet* rSet) override;
+    virtual void Reset(const SfxItemSet* rSet) override;
+
+private:
+    std::unique_ptr<weld::Entry> m_xAPIUrl;
+    std::unique_ptr<weld::Entry> m_xAuthKey;
+};
diff --git a/cui/source/options/treeopt.cxx b/cui/source/options/treeopt.cxx
index e3029ca45eaf..1ab88a7e5381 100644
--- a/cui/source/options/treeopt.cxx
+++ b/cui/source/options/treeopt.cxx
@@ -64,6 +64,7 @@
 #include <treeopt.hxx>
 #include "optbasic.hxx"
 #include "optlanguagetool.hxx"
+#include "optdeepl.hxx"
 
 #include <com/sun/star/awt/XContainerWindowEventHandler.hpp>
 #include <com/sun/star/awt/ContainerWindowProvider.hpp>
@@ -299,6 +300,7 @@ static std::unique_ptr<SfxTabPage> 
CreateGeneralTabPage(sal_uInt16 nId, weld::Co
         case RID_SVXPAGE_ACCESSIBILITYCONFIG:       fnCreate = 
&SvxAccessibilityOptionsTabPage::Create; break;
         case RID_SVXPAGE_OPTIONS_CTL:               fnCreate = 
&SvxCTLOptionsPage::Create ; break;
         case RID_SVXPAGE_LANGTOOL_OPTIONS:          fnCreate = 
&OptLanguageToolTabPage::Create ; break;
+        case RID_SVXPAGE_DEEPL_OPTIONS:             fnCreate = 
&OptDeeplTabPage::Create ; break;
         case RID_SVXPAGE_OPTIONS_JAVA:              fnCreate = 
&SvxJavaOptionsPage::Create ; break;
 #if HAVE_FEATURE_OPENCL
         case RID_SVXPAGE_OPENCL:                    fnCreate = 
&SvxOpenCLTabPage::Create ; break;
diff --git a/cui/uiconfig/ui/deepltabpage.ui b/cui/uiconfig/ui/deepltabpage.ui
new file mode 100644
index 000000000000..f17ff52a787e
--- /dev/null
+++ b/cui/uiconfig/ui/deepltabpage.ui
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface domain="cui">
+  <requires lib="gtk+" version="3.20"/>
+  <object class="GtkBox" id="OptDeeplPage">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="orientation">vertical</property>
+    <child>
+      <object class="GtkGrid" id="grid1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="column_homogeneous">True</property>
+        <child>
+          <object class="GtkLabel" id="label1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="halign">start</property>
+            <property name="xpad">5</property>
+            <property name="ypad">5</property>
+            <property name="label" translatable="yes" 
context="deepltabpage|label1">DeepL API Options</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">grid1</property>
+            <attributes>
+              <attribute name="weight" value="bold"/>
+            </attributes>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLinkButton" id="privacy">
+            <property name="label" translatable="yes" 
context="deepltabpage|privacy">Please read the privacy policy</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="halign">start</property>
+            <property name="relief">none</property>
+            <property name="uri">https://www.deepl.com/privacy/</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkGrid" id="grid2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_left">5</property>
+            <property name="margin_right">5</property>
+            <property name="margin_top">5</property>
+            <property name="margin_bottom">5</property>
+            <property name="row_spacing">6</property>
+            <property name="column_spacing">5</property>
+            <child>
+              <object class="GtkLabel" id="label2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">start</property>
+                <property name="margin_left">5</property>
+                <property name="label" translatable="yes" 
context="deepltabpage|privacy">API URL:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">apiurl</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label3">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">start</property>
+                <property name="margin_right">5</property>
+                <property name="label" translatable="yes" 
context="deepltabpage|label3">Auth Key:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">authkey</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="apiurl">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hexpand">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="authkey">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hexpand">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/include/sfx2/pageids.hxx b/include/sfx2/pageids.hxx
index 9371848b784a..1464ec40c55a 100644
--- a/include/sfx2/pageids.hxx
+++ b/include/sfx2/pageids.hxx
@@ -57,6 +57,7 @@
 #define RID_SVXPAGE_COLORCONFIG             (RID_SVX_START + 249)
 #define RID_SVXPAGE_BASICIDE_OPTIONS        (RID_SVX_START + 209)
 #define RID_SVXPAGE_LANGTOOL_OPTIONS        (RID_SVX_START + 210)
+#define RID_SVXPAGE_DEEPL_OPTIONS           (RID_SVX_START + 211)
 
 // Resource-Id's ------------------------------------------------------------
 
diff --git a/include/sfx2/sfxsids.hrc b/include/sfx2/sfxsids.hrc
index 39a3ec5bf9d6..1937368ba2b9 100644
--- a/include/sfx2/sfxsids.hrc
+++ b/include/sfx2/sfxsids.hrc
@@ -208,6 +208,7 @@ class SvxSearchItem;
 #define SID_VIEW_DATA_SOURCE_BROWSER        (SID_SFX_START + 1660)
 #define SID_UNPACK                          (SID_SFX_START + 1662)
 // (SID_SFX_START + 1663) used further down
+#define SID_ATTR_TARGETLANG_STR             (SID_SFX_START + 1664)
     // FREE
 #define SID_OUTPUTSTREAM                    (SID_SFX_START + 1666)
 #define SID_IMAGE_ORIENTATION               (SID_SFX_START + 1667)
diff --git a/include/svtools/deeplcfg.hxx b/include/svtools/deeplcfg.hxx
new file mode 100644
index 000000000000..b8e8ca4d7cd4
--- /dev/null
+++ b/include/svtools/deeplcfg.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+#include <unotools/configitem.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <svtools/svtdllapi.h>
+
+using namespace utl;
+using namespace com::sun::star::uno;
+
+struct DeeplOptions_Impl;
+
+class SVT_DLLPUBLIC SvxDeeplOptions final : public utl::ConfigItem
+{
+public:
+    SvxDeeplOptions();
+    virtual ~SvxDeeplOptions() override;
+
+    virtual void Notify(const css::uno::Sequence<OUString>& _rPropertyNames) 
override;
+    static SvxDeeplOptions& Get();
+
+    const OUString getAPIUrl() const;
+    void setAPIUrl(const OUString& rVal);
+
+    const OUString& getAuthKey() const;
+    void setAuthKey(const OUString& rVal);
+
+private:
+    std::unique_ptr<DeeplOptions_Impl> pImpl;
+    void Load(const css::uno::Sequence<OUString>& rPropertyNames);
+    virtual void ImplCommit() override;
+    static const Sequence<OUString>& GetPropertyNames();
+};
diff --git a/include/svx/svxids.hrc b/include/svx/svxids.hrc
index 573f036128c8..f8e162a973a6 100644
--- a/include/svx/svxids.hrc
+++ b/include/svx/svxids.hrc
@@ -570,7 +570,7 @@ class SdrAngleItem;
 #define SID_FM_FILECONTROL                              ( SID_SVX_START + 605 )
 //( SID_SVX_START + 606 ) is used by SID_DRAWTBX_REDACTED_EXPORT
 #define SID_FM_NAVIGATIONBAR                            ( SID_SVX_START + 607 )
-//FREE
+#define SID_FM_TRANSLATE                                ( SID_SVX_START + 608 )
 //FREE
 #define SID_FM_DELETEROWS                               ( SID_SVX_START + 610 )
 //FREE
diff --git a/include/vcl/unohelp3.hxx b/include/vcl/unohelp3.hxx
new file mode 100644
index 000000000000..2d3bfb4e5f28
--- /dev/null
+++ b/include/vcl/unohelp3.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <cppuhelper/weak.hxx>
+#include <rtl/ustring.hxx>
+#include <osl/mutex.hxx>
+#include <vcl/dllapi.h>
+#include <vcl/IDialogRenderable.hxx>
+
+namespace vcl::unohelper {
+
+    class VCL_DLLPUBLIC HtmlTransferable final :
+                            public css::datatransfer::XTransferable,
+                            public ::cppu::OWeakObject
+    {
+    private:
+        OString            data;
+
+    public:
+                        HtmlTransferable( OString sData );
+                        virtual ~HtmlTransferable() override;
+
+        // css::uno::XInterface
+        css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) 
override;
+        void          SAL_CALL acquire() noexcept override  { 
OWeakObject::acquire(); }
+        void          SAL_CALL release() noexcept override  { 
OWeakObject::release(); }
+
+        // css::datatransfer::XTransferable
+        css::uno::Any SAL_CALL getTransferData( const 
css::datatransfer::DataFlavor& aFlavor ) override;
+        css::uno::Sequence< css::datatransfer::DataFlavor > SAL_CALL 
getTransferDataFlavors(  ) override;
+        sal_Bool SAL_CALL isDataFlavorSupported( const 
css::datatransfer::DataFlavor& aFlavor ) override;
+    };
+
+}  // namespace vcl::unohelper
diff --git 
a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu 
b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu
index 37996759a90d..59c46c8472b4 100644
--- a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu
+++ b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu
@@ -1333,6 +1333,14 @@
           <value>1</value>
         </prop>
       </node>
+      <node oor:name=".uno:Translate" oor:op="replace">
+        <prop oor:name="Label" oor:type="xs:string">
+          <value xml:lang="en-US">Translate...</value>
+        </prop>
+        <prop oor:name="Properties" oor:type="xs:int">
+          <value>1</value>
+        </prop>
+      </node>
       <node oor:name=".uno:FormatColumns" oor:op="replace">
         <prop oor:name="Label" oor:type="xs:string">
           <value xml:lang="en-US">Co~lumns...</value>
diff --git a/officecfg/registry/schema/org/openoffice/Office/Linguistic.xcs 
b/officecfg/registry/schema/org/openoffice/Office/Linguistic.xcs
index a3fc5f1296c8..c80db6c6aa09 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Linguistic.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Linguistic.xcs
@@ -444,6 +444,28 @@
           </prop>
       </group>
     </group>
+    <group oor:name="Translation">
+      <info>
+        <desc>Contains translation relevant settings.</desc>
+      </info>
+      <group oor:name="Deepl">
+        <info>
+          <desc>Contains DeepL API relevant settings.</desc>
+        </info>
+        <prop oor:name="ApiURL" oor:type="xs:string">
+          <info>
+            <desc>Deepl Translator API URL</desc>
+            <label>URL for the Deepl translator api</label>
+          </info>
+        </prop>
+        <prop oor:name="AuthKey" oor:type="xs:string">
+          <info>
+            <desc>Deepl Translator API URL Authkey</desc>
+            <label>Auth key for the Deepl translator api</label>
+          </info>
+        </prop>
+      </group>
+    </group>
     <group oor:name="Hyphenation">
       <info>
         <desc>Contains hyphenation relevant settings.</desc>
diff --git a/svtools/Library_svt.mk b/svtools/Library_svt.mk
index 94b4f8848ba5..895c34780443 100644
--- a/svtools/Library_svt.mk
+++ b/svtools/Library_svt.mk
@@ -83,6 +83,7 @@ $(eval $(call gb_Library_add_exception_objects,svt,\
     svtools/source/config/fontsubstconfig \
     svtools/source/config/htmlcfg \
     svtools/source/config/languagetoolcfg \
+    svtools/source/config/deeplcfg \
     svtools/source/config/itemholder2 \
     svtools/source/config/miscopt \
     svtools/source/config/slidesorterbaropt \
diff --git a/svtools/source/config/deeplcfg.cxx 
b/svtools/source/config/deeplcfg.cxx
new file mode 100644
index 000000000000..edace497a482
--- /dev/null
+++ b/svtools/source/config/deeplcfg.cxx
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/log.hxx>
+#include <sal/config.h>
+#include <svtools/deeplcfg.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <tools/debug.hxx>
+
+using namespace utl;
+using namespace com::sun::star::uno;
+
+struct DeeplOptions_Impl
+{
+    OUString sAPIUrl;
+    OUString sAuthKey;
+};
+
+const Sequence<OUString>& SvxDeeplOptions::GetPropertyNames()
+{
+    static Sequence<OUString> const aNames{
+        "Deepl/ApiURL",
+        "Deepl/AuthKey",
+    };
+    return aNames;
+}
+
+const OUString SvxDeeplOptions::getAPIUrl() const { return pImpl->sAPIUrl; }
+
+void SvxDeeplOptions::setAPIUrl(const OUString& rVal)
+{
+    pImpl->sAPIUrl = rVal;
+    SetModified();
+}
+
+const OUString& SvxDeeplOptions::getAuthKey() const { return pImpl->sAuthKey; }
+
+void SvxDeeplOptions::setAuthKey(const OUString& rVal)
+{
+    pImpl->sAuthKey = rVal;
+    SetModified();
+}
+
+namespace
+{
+class theSvxDeeplOptions
+    : public rtl::Static<SvxDeeplOptions, theSvxDeeplOptions>
+{
+};
+}
+
+SvxDeeplOptions& SvxDeeplOptions::Get() { return theSvxDeeplOptions::get(); }
+
+SvxDeeplOptions::SvxDeeplOptions()
+    : ConfigItem("Office.Linguistic/Translation")
+    , pImpl(new DeeplOptions_Impl)
+{
+    Load(GetPropertyNames());
+}
+
+SvxDeeplOptions::~SvxDeeplOptions() {}
+void SvxDeeplOptions::Notify(const css::uno::Sequence<OUString>&)
+{
+    Load(GetPropertyNames());
+}
+
+void SvxDeeplOptions::Load(const css::uno::Sequence<OUString>& aNames)
+{
+    Sequence<Any> aValues = GetProperties(aNames);
+    const Any* pValues = aValues.getConstArray();
+    DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties 
failed");
+    if (aValues.getLength() != aNames.getLength())
+        return;
+    for (int nProp = 0; nProp < aNames.getLength(); nProp++)
+    {
+        if (!pValues[nProp].hasValue())
+            continue;
+        switch (nProp)
+        {
+            case 0:
+                pValues[nProp] >>= pImpl->sAPIUrl;
+                break;
+            case 1:
+                pValues[nProp] >>= pImpl->sAuthKey;
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+void SvxDeeplOptions::ImplCommit()
+{
+    const Sequence<OUString>& aNames = GetPropertyNames();
+    Sequence<Any> aValues(aNames.getLength());
+    Any* pValues = aValues.getArray();
+    for (int nProp = 0; nProp < aNames.getLength(); nProp++)
+    {
+        switch (nProp)
+        {
+            case 0:
+                pValues[nProp] <<= pImpl->sAPIUrl;
+                break;
+            case 1:
+                pValues[nProp] <<= pImpl->sAuthKey;
+                break;
+            default:
+                break;
+        }
+    }
+    PutProperties(aNames, aValues);
+}
\ No newline at end of file
diff --git a/svx/sdi/svx.sdi b/svx/sdi/svx.sdi
index 9ab00de7e881..ac886aaa0cd4 100644
--- a/svx/sdi/svx.sdi
+++ b/svx/sdi/svx.sdi
@@ -1596,6 +1596,23 @@ SfxBoolItem NavigationBar SID_FM_NAVIGATIONBAR
     GroupId = SfxGroupId::Controls;
 ]
 
+SfxBoolItem Translate SID_FM_TRANSLATE
+(SfxStringItem TargetLang SID_ATTR_TARGETLANG_STR)
+[
+    AutoUpdate = FALSE,
+    FastCall = TRUE,
+    ReadOnlyDoc = FALSE,
+    Toggle = FALSE,
+    Container = FALSE,
+    RecordAbsolute = FALSE,
+    RecordPerSet;
+
+    AccelConfig = FALSE,
+    MenuConfig = FALSE,
+    ToolBoxConfig = FALSE,
+    GroupId = SfxGroupId::Format;
+]
+
 
 SfxBoolItem Combobox SID_INSERT_COMBOBOX
 
diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk
index a49d53d0509f..5408e28b867a 100644
--- a/sw/Library_sw.mk
+++ b/sw/Library_sw.mk
@@ -91,6 +91,7 @@ $(eval $(call gb_Library_use_externals,sw,\
        icuuc \
        icu_headers \
        libxml2 \
+    curl \
 ))
 
 $(eval $(call gb_Library_add_exception_objects,sw,\
diff --git a/sw/Library_swui.mk b/sw/Library_swui.mk
index 4c1d9614f56c..f4cd9cbf5432 100644
--- a/sw/Library_swui.mk
+++ b/sw/Library_swui.mk
@@ -150,6 +150,7 @@ $(eval $(call gb_Library_add_exception_objects,swui,\
     sw/source/ui/misc/pgfnote \
     sw/source/ui/misc/pggrid \
     sw/source/ui/misc/srtdlg \
+    sw/source/ui/misc/translatelangselect \
     sw/source/ui/misc/swmodalredlineacceptdlg \
     sw/source/ui/misc/titlepage \
     sw/source/ui/table/colwd \
diff --git a/sw/UIConfig_swriter.mk b/sw/UIConfig_swriter.mk
index 73abd66dee9b..7d2fc662ae22 100644
--- a/sw/UIConfig_swriter.mk
+++ b/sw/UIConfig_swriter.mk
@@ -178,6 +178,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/swriter,\
        sw/uiconfig/swriter/ui/insertautotextdialog \
        sw/uiconfig/swriter/ui/insertbookmark \
        sw/uiconfig/swriter/ui/insertbreak \
+       sw/uiconfig/swriter/ui/translationdialog \
        sw/uiconfig/swriter/ui/insertcaption \
        sw/uiconfig/swriter/ui/insertdbcolumnsdialog \
        sw/uiconfig/swriter/ui/insertfootnote \
diff --git a/sw/inc/swabstdlg.hxx b/sw/inc/swabstdlg.hxx
index 0963de35da21..19d12a736e66 100644
--- a/sw/inc/swabstdlg.hxx
+++ b/sw/inc/swabstdlg.hxx
@@ -375,6 +375,18 @@ public:
     virtual sal_uInt16          GetRestartPage() const = 0;
 };
 
+class SwLanguageListItem;
+
+class AbstractSwTranslateLangSelectDlg
+{
+protected:
+    virtual ~AbstractSwTranslateLangSelectDlg() = default;
+public:
+    virtual std::shared_ptr<weld::DialogController> getDialogController() = 0;
+    virtual std::optional<SwLanguageListItem> GetSelectedLanguage() = 0;
+};
+
+
 class SwAbstractDialogFactory
 {
 public:
@@ -398,6 +410,7 @@ public:
     CreateSwContentControlListItemDlg(weld::Window* pParent, 
SwContentControlListItem& rItem) = 0;
 
     virtual std::shared_ptr<AbstractSwBreakDlg> CreateSwBreakDlg(weld::Window 
*pParent, SwWrtShell &rSh) = 0;
+    virtual std::shared_ptr<AbstractSwTranslateLangSelectDlg> 
CreateSwTranslateLangSelectDlg(weld::Window *pParent) = 0;
     virtual VclPtr<VclAbstractDialog> CreateSwChangeDBDlg(SwView& rVw) = 0;
     virtual VclPtr<SfxAbstractTabDialog>  CreateSwCharDlg(weld::Window* 
pParent, SwView& pVw, const SfxItemSet& rCoreSet,
         SwCharDlgMode nDialogMode, const OUString* pFormatStr = nullptr) = 0;
diff --git a/sw/sdi/_textsh.sdi b/sw/sdi/_textsh.sdi
index 84750b937715..128591f1673d 100644
--- a/sw/sdi/_textsh.sdi
+++ b/sw/sdi/_textsh.sdi
@@ -1796,5 +1796,11 @@ interface BaseText
         StateMethod = GetState ;
     ]
 
+    SID_FM_TRANSLATE
+    [
+        ExecMethod = Execute ;
+        StateMethod = GetState ;
+    ]
+
 }  // end of interface text
 
diff --git a/sw/source/ui/dialog/swdlgfact.cxx 
b/sw/source/ui/dialog/swdlgfact.cxx
index 17f0ed1d3a03..b89321133188 100644
--- a/sw/source/ui/dialog/swdlgfact.cxx
+++ b/sw/source/ui/dialog/swdlgfact.cxx
@@ -90,6 +90,7 @@
 #include <uiborder.hxx>
 #include <mmresultdialogs.hxx>
 #include <formatlinebreak.hxx>
+#include <translatelangselect.hxx>
 
 using namespace ::com::sun::star;
 using namespace css::frame;
@@ -802,6 +803,12 @@ sal_uInt16 AbstractMailMergeWizard_Impl::GetRestartPage() 
const
     return m_xDlg->GetRestartPage();
 }
 
+std::optional<SwLanguageListItem> 
AbstractSwTranslateLangSelectDlg_Impl::GetSelectedLanguage()
+{
+    SwTranslateLangSelectDlg* pDlg = 
dynamic_cast<SwTranslateLangSelectDlg*>(m_xDlg.get());
+    return pDlg->GetSelectedLanguage();
+}
+
 VclPtr<AbstractSwInsertAbstractDlg> 
SwAbstractDialogFactory_Impl::CreateSwInsertAbstractDlg(weld::Window* pParent)
 {
     return 
VclPtr<AbstractSwInsertAbstractDlg_Impl>::Create(std::make_unique<SwInsertAbstractDlg>(pParent));
@@ -861,6 +868,11 @@ std::shared_ptr<AbstractSwBreakDlg> 
SwAbstractDialogFactory_Impl::CreateSwBreakD
     return 
std::make_shared<AbstractSwBreakDlg_Impl>(std::make_unique<SwBreakDlg>(pParent, 
rSh));
 }
 
+std::shared_ptr<AbstractSwTranslateLangSelectDlg> 
SwAbstractDialogFactory_Impl::CreateSwTranslateLangSelectDlg(weld::Window* 
pParent)
+{
+    return 
std::make_shared<AbstractSwTranslateLangSelectDlg_Impl>(std::make_unique<SwTranslateLangSelectDlg>(pParent));
+}
+
 VclPtr<VclAbstractDialog> 
SwAbstractDialogFactory_Impl::CreateSwChangeDBDlg(SwView& rVw)
 {
 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
diff --git a/sw/source/ui/dialog/swdlgfact.hxx 
b/sw/source/ui/dialog/swdlgfact.hxx
index 8690d9db8129..7e7615ef9220 100644
--- a/sw/source/ui/dialog/swdlgfact.hxx
+++ b/sw/source/ui/dialog/swdlgfact.hxx
@@ -187,6 +187,19 @@ public:
     virtual std::shared_ptr<weld::DialogController> getDialogController() 
override { return m_xDlg; }
 };
 
+class AbstractSwTranslateLangSelectDlg_Impl : public 
AbstractSwTranslateLangSelectDlg
+{
+    std::shared_ptr<weld::DialogController> m_xDlg;
+public:
+    explicit 
AbstractSwTranslateLangSelectDlg_Impl(std::shared_ptr<weld::DialogController> p)
+        : m_xDlg(std::move(p))
+    {
+    }
+
+    virtual std::shared_ptr<weld::DialogController> getDialogController() 
override { return m_xDlg; }
+    virtual std::optional<SwLanguageListItem> GetSelectedLanguage() override;
+};
+
 class AbstractSwTableWidthDlg_Impl : public VclAbstractDialog
 {
     std::unique_ptr<SwTableWidthDlg> m_xDlg;
@@ -684,6 +697,7 @@ public:
                                       SwContentControlListItem& rItem) 
override;
 
     virtual std::shared_ptr<AbstractSwBreakDlg> CreateSwBreakDlg(weld::Window 
*pParent, SwWrtShell &rSh) override;
+    virtual std::shared_ptr<AbstractSwTranslateLangSelectDlg> 
CreateSwTranslateLangSelectDlg(weld::Window *pParent) override;
     virtual VclPtr<VclAbstractDialog> CreateSwChangeDBDlg(SwView& rVw) 
override;
     virtual VclPtr<SfxAbstractTabDialog>  CreateSwCharDlg(weld::Window* 
pParent, SwView& pVw, const SfxItemSet& rCoreSet,
         SwCharDlgMode nDialogMode, const OUString* pFormatStr = nullptr) 
override;
diff --git a/sw/source/ui/misc/translatelangselect.cxx 
b/sw/source/ui/misc/translatelangselect.cxx
new file mode 100644
index 000000000000..9a05e6c738f3
--- /dev/null
+++ b/sw/source/ui/misc/translatelangselect.cxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/svapp.hxx>
+#include <osl/diagnose.h>
+
+#include <uitool.hxx>
+#include <swtypes.hxx>
+#include <wrtsh.hxx>
+#include <view.hxx>
+#include <viewopt.hxx>
+#include <translatelangselect.hxx>
+#include <pagedesc.hxx>
+#include <poolfmt.hxx>
+#include <sal/log.hxx>
+
+int SwTranslateLangSelectDlg::selectedLangIdx = -1;
+SwTranslateLangSelectDlg::SwTranslateLangSelectDlg(weld::Window *pParent)
+    : GenericDialogController(pParent, 
"modules/swriter/ui/translationdialog.ui", "LanguageSelectDialog")
+    , m_xLanguageListBox(m_xBuilder->weld_combo_box("combobox1"))
+    , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+    , m_xBtnTranslate(m_xBuilder->weld_button("translate"))
+    , m_xLanguageVec(
+    {
+        SwLanguageListItem("BG", "Bulgarian"),
+        SwLanguageListItem("CS", "Czech"),
+        SwLanguageListItem("DA", "Danish"),
+        SwLanguageListItem("DE", "German"),
+        SwLanguageListItem("EL", "Greek"),
+        SwLanguageListItem("EN-GB", "English (British)"),
+        SwLanguageListItem("EN-US", "English (American)"),
+        SwLanguageListItem("ET", "Estonian"),
+        SwLanguageListItem("FI", "Finnish"),
+        SwLanguageListItem("FR", "French"),
+        SwLanguageListItem("HU", "Hungarian"),
+        SwLanguageListItem("ID", "Indonesian"),
+        SwLanguageListItem("IT", "Italian"),
+        SwLanguageListItem("JA", "Japanese"),
+        SwLanguageListItem("LT", "Lithuanian"),
+        SwLanguageListItem("LV", "Dutch"),
+        SwLanguageListItem("PL", "Polish"),
+        SwLanguageListItem("PT-BR", "Portuguese (Brazilian)"),
+        SwLanguageListItem("PT-PT", "Portuguese (European)"),
+        SwLanguageListItem("RO", "Romanian"),
+        SwLanguageListItem("RU", "Russian"),
+        SwLanguageListItem("SK", "Slovak"),
+        SwLanguageListItem("SL", "Slovenian"),
+        SwLanguageListItem("SV", "Swedish"),
+        SwLanguageListItem("TR", "Turkish"),
+        SwLanguageListItem("ZH", "Chinese (simplified)"),
+    })
+{
+    m_xLanguageListBox->connect_changed(LINK(this, SwTranslateLangSelectDlg, 
LangSelectHdl));
+    m_xBtnCancel->connect_clicked(LINK(this, SwTranslateLangSelectDlg, 
LangSelectCancelHdl));
+    m_xBtnTranslate->connect_clicked(LINK(this, SwTranslateLangSelectDlg, 
LangSelectTranslateHdl));
+    for (const auto& item : m_xLanguageVec)
+    {
+        m_xLanguageListBox->append_text(OStringToOUString(item.getName(), 
RTL_TEXTENCODING_UTF8));
+    }
+
+    if (SwTranslateLangSelectDlg::selectedLangIdx != -1)
+    {
+        
m_xLanguageListBox->set_active(SwTranslateLangSelectDlg::selectedLangIdx);
+    }
+}
+
+std::optional<SwLanguageListItem> 
SwTranslateLangSelectDlg::GetSelectedLanguage()
+{
+    if (SwTranslateLangSelectDlg::selectedLangIdx != -1)
+    {
+        return m_xLanguageVec.at(SwTranslateLangSelectDlg::selectedLangIdx);
+    }
+
+    return {};
+}
+
+
+IMPL_LINK(SwTranslateLangSelectDlg, LangSelectHdl, weld::ComboBox&, rBox, void)
+{
+    const auto selected = m_xLanguageListBox->get_active();
+    SwTranslateLangSelectDlg::selectedLangIdx = selected;
+}
+
+IMPL_LINK(SwTranslateLangSelectDlg, LangSelectCancelHdl, weld::Button&, 
rButton, void)
+{
+    m_xDialog->response(RET_CANCEL);
+}
+
+IMPL_LINK(SwTranslateLangSelectDlg, LangSelectTranslateHdl, weld::Button&, 
rButton, void)
+{
+    m_xDialog->response(RET_OK);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/inc/translatelangselect.hxx 
b/sw/source/uibase/inc/translatelangselect.hxx
new file mode 100644
index 000000000000..84e5669b7fcb
--- /dev/null
+++ b/sw/source/uibase/inc/translatelangselect.hxx
@@ -0,0 +1,58 @@
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include <vcl/weld.hxx>
+#include <rtl/string.h>
+#include <vector>
+#include <optional>
+//class SwWrtShell;
+
+class SwLanguageListItem final
+{
+public:
+    SwLanguageListItem(const OString& sLanguage, const OString& sName) : 
m_sLanguage(sLanguage), m_sName(sName) {}
+    const OString& getLanguage() const { return m_sLanguage; }
+    const OString& getName() const { return m_sName; }
+
+private:
+    const OString m_sLanguage;
+    const OString m_sName;
+};
+
+class SwTranslateLangSelectDlg final : public weld::GenericDialogController
+{
+public:
+    static int selectedLangIdx;
+    SwTranslateLangSelectDlg(weld::Window* pParent/*, SwWrtShell& rSh*/);
+    std::optional<SwLanguageListItem> GetSelectedLanguage();
+
+private:
+    std::unique_ptr<weld::ComboBox> m_xLanguageListBox;
+    std::unique_ptr<weld::Button> m_xBtnCancel;
+    std::unique_ptr<weld::Button> m_xBtnTranslate;
+    std::vector<SwLanguageListItem> m_xLanguageVec;
+
+    DECL_LINK(LangSelectHdl, weld::ComboBox&, void );
+    DECL_LINK(LangSelectCancelHdl, weld::Button&, void );
+    DECL_LINK(LangSelectTranslateHdl, weld::Button&, void );
+};
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/shells/textsh1.cxx 
b/sw/source/uibase/shells/textsh1.cxx
index 8d7c07e104ca..e221e7dadaaa 100644
--- a/sw/source/uibase/shells/textsh1.cxx
+++ b/sw/source/uibase/shells/textsh1.cxx
@@ -35,6 +35,7 @@
 #include <sfx2/bindings.hxx>
 #include <sfx2/viewfrm.hxx>
 #include <vcl/unohelp2.hxx>
+#include <vcl/unohelp3.hxx>
 #include <vcl/weld.hxx>
 #include <sfx2/request.hxx>
 #include <svl/eitem.hxx>
@@ -78,6 +79,8 @@
 #include <editeng/acorrcfg.hxx>
 #include <swabstdlg.hxx>
 #include <sfx2/sfxdlg.hxx>
+#include <com/sun/star/text/XTextContent.hpp>
+#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
 #include <com/sun/star/container/XNameContainer.hpp>
 #include <com/sun/star/beans/XPropertySet.hpp>
 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
@@ -103,6 +106,15 @@
 #include <bookmark.hxx>
 #include <linguistic/misc.hxx>
 #include <authfld.hxx>
+#include <unoparagraph.hxx>
+#include <ndtxt.hxx>
+#include <shellio.hxx>
+#include <curl/curl.h>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/json_parser.hpp>
+#include <translatelangselect.hxx>
+#include <swwait.hxx>
+#include <svtools/deeplcfg.hxx>
 
 using namespace ::com::sun::star;
 using namespace com::sun::star::beans;
@@ -1503,6 +1515,169 @@ void SwTextShell::Execute(SfxRequest &rReq)
         }
     }
     break;
+    case SID_FM_TRANSLATE:
+    {
+        // TODO
+        // collabora online
+        // move htmltransferable to sw/
+        // progressbar
+        SvxDeeplOptions& rDeeplOptions = SvxDeeplOptions::Get();
+        if (rDeeplOptions.getAPIUrl().isEmpty() || 
rDeeplOptions.getAuthKey().isEmpty())
+        {
+            SAL_WARN("deepl", "API options are not set");
+            break;
+        }
+        OString aAPIUrl = OUStringToOString(OUString(rDeeplOptions.getAPIUrl() 
+ "?tag_handling=html"), RTL_TEXTENCODING_UTF8).trim();
+        OString aAuthKey = OUStringToOString(rDeeplOptions.getAuthKey(), 
RTL_TEXTENCODING_UTF8).trim();
+        SwPaM *pPaM = nullptr;
+        if (rWrtSh.HasSelection())
+        {
+            pPaM = rWrtSh.GetCursor();
+        }
+        auto replacePara = [&rWrtSh, aAuthKey, aAPIUrl](const OString& res, 
const OString& targetLang, SwPaM *pCursor, bool isSelection = false) {
+            // curl deepl
+            std::unique_ptr<CURL, std::function<void(CURL*)>> 
curl(curl_easy_init(),
+                                                           [](CURL* p) { 
curl_easy_cleanup(p); });
+            curl_easy_setopt(curl.get(), CURLOPT_URL, aAPIUrl.getStr());
+            curl_easy_setopt(curl.get(), CURLOPT_FAILONERROR, 1L);
+            std::string response_body;
+            curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, +[](void 
*buffer, size_t size, size_t nmemb, void *userp) -> size_t
+            {
+                if (!userp)
+                    return 0;
+                std::string* response = static_cast<std::string*>(userp);
+                size_t real_size = size * nmemb;
+                response->append(static_cast<char*>(buffer), real_size);
+                return real_size;
+            });
+            curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, 
static_cast<void*>(&response_body));
+            OString aPostData("auth_key=" + aAuthKey + "&target_lang=" + 
targetLang + "&text=" + OString(curl_easy_escape(curl.get(), res.getStr(), 
res.getLength())));
+            curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, 
aPostData.getStr());
+            CURLcode cc = curl_easy_perform(curl.get());
+            if (cc != CURLE_OK)
+            {
+                SAL_WARN("deepl", "CURL perform returned with error: " << 
static_cast<sal_Int32>(cc));
+                return;
+            }
+            tools::Long nStatusCode;
+            curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, 
&nStatusCode);
+            if (nStatusCode != 200)
+            {
+                SAL_WARN("deepl", "CURL request returned with status code: " 
<< nStatusCode);
+                return;
+            }
+            // parse the response
+            boost::property_tree::ptree root;
+            std::stringstream aStream(response_body.data());
+            boost::property_tree::read_json(aStream, root);
+            boost::property_tree::ptree& translations = 
root.get_child("translations");
+            size_t size = translations.size();
+            if (size <= 0)
+            {
+                SAL_WARN("deepl", "API did not return any translations");
+            }
+            // take the first one
+            const boost::property_tree::ptree& translation = 
translations.begin()->second;
+            const std::string text = translation.get<std::string>("text");
+            OString translatedData(text);
+            rtl::Reference<vcl::unohelper::HtmlTransferable> pHtmlTransferable 
= new vcl::unohelper::HtmlTransferable( translatedData );
+            if ( pHtmlTransferable.is() )
+            {
+                TransferableDataHelper aDataHelper( pHtmlTransferable );
+                if( aDataHelper.GetXTransferable().is() && 
SwTransferable::IsPasteSpecial( rWrtSh, aDataHelper ) )
+                {
+                    if (isSelection != true)
+                    {
+                        rWrtSh.SetSelection(*pCursor);
+                    }
+                    SwTransferable::Paste(rWrtSh, aDataHelper);
+                    rWrtSh.KillSelection(nullptr, false);
+                }
+            }
+        };
+        auto exportAndReplace = [&rWrtSh, replacePara] (const OString& 
targetLang, SwPaM *pCursor)
+        {
+            // freeze everything
+            SwWait aWait( *rWrtSh.GetView().GetDocShell(), true );
+            OString aResult;
+            auto const& pNodes = rWrtSh.GetNodes();
+            WriterRef xWrt;
+            GetHTMLWriter( OUString("NoLineLimit,SkipHeaderFooter"), 
OUString(), xWrt );
+            SwNode* pNode = nullptr;
+            if (pCursor != nullptr)
+            {
+                SvMemoryStream aMemoryStream;
+                SwWriter aWriter(aMemoryStream, *pCursor);
+                ErrCode nError = aWriter.Write(xWrt);
+                if (nError.IsError())
+                {
+                    SAL_WARN("deepl", "failed to export selection to HTML");
+                    return;
+                }
+                aResult = OString(static_cast<const 
char*>(aMemoryStream.GetData()), aMemoryStream.GetSize());
+                replacePara(aResult, targetLang, pCursor, true);
+                return;
+            }
+            for (SwNodeOffset n(0); ; ++n)
+            {
+                if (n >= rWrtSh.GetNodes().Count())
+                    break;
+
+                if (!pNodes[n])
+                    break;
+
+                pNode = pNodes[n];
+                if (pNode->IsTextNode())
+                {
+                    if (pNode->GetTextNode()->GetText() == "")
+                        continue;
+                    auto cursor = Writer::NewUnoCursor(*rWrtSh.GetDoc(), 
pNode->GetIndex(), pNode->GetIndex());
+                    SvMemoryStream aMemoryStream;
+                    SwWriter aWriter(aMemoryStream, *cursor);
+                    ErrCode nError = aWriter.Write(xWrt);
+                    if (nError.IsError())
+                    {
+                        SAL_WARN("deepl", "failed to export the paragraph to 
HTML");
+                        continue;
+                    }
+                    aResult = OString(static_cast<const 
char*>(aMemoryStream.GetData()), aMemoryStream.GetSize());
+                    // replace <p> with <scan> to avoid newlines on paste, 
hacky but no other option
+                    aResult = aResult.replaceAll("<p", "<span");
+                    aResult = aResult.replaceAll("</p>", "</span>");
+                    replacePara(aResult, targetLang, cursor.get());
+                }
+            }
+        };
+
+        const SfxPoolItem* pTargetLangStringItem = nullptr;
+        if (pArgs && SfxItemState::SET == 
pArgs->GetItemState(SID_ATTR_TARGETLANG_STR, false, &pTargetLangStringItem))
+        {
+            OString targetLang = OUStringToOString(static_cast<const 
SfxStringItem*>(pTargetLangStringItem)->GetValue(), RTL_TEXTENCODING_UTF8);
+            exportAndReplace(targetLang, pPaM);
+        }
+        else
+        {
+            SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
+            std::shared_ptr<AbstractSwTranslateLangSelectDlg> 
pAbstractDialog(pFact->CreateSwTranslateLangSelectDlg(GetView().GetFrameWeld()));
+            std::shared_ptr<weld::DialogController> 
pDialogController(pAbstractDialog->getDialogController());
+            weld::DialogController::runAsync(pDialogController, 
[exportAndReplace, pAbstractDialog, pPaM] (sal_Int32 nResult)
+            {
+                if (nResult != RET_OK)
+                {
+                    return;
+                }
+                auto languageItem = pAbstractDialog->GetSelectedLanguage();
+                if (!languageItem.has_value())
+                {
+                    return;
+                }
+                const OString targetLang = languageItem->getLanguage();
+                exportAndReplace(targetLang, pPaM);
+            });
+        }
+
+    }
+    break;
     case SID_SPELLCHECK_IGNORE:
     {
         SwPaM *pPaM = rWrtSh.GetCursor();
diff --git a/sw/uiconfig/sglobal/menubar/menubar.xml 
b/sw/uiconfig/sglobal/menubar/menubar.xml
index 38f6708c1a55..709c492df4f3 100644
--- a/sw/uiconfig/sglobal/menubar/menubar.xml
+++ b/sw/uiconfig/sglobal/menubar/menubar.xml
@@ -446,6 +446,7 @@
       <menu:menuseparator/>
       <menu:menuitem menu:id=".uno:PageDialog"/>
       <menu:menuitem menu:id=".uno:TitlePageDialog" menu:style="text"/>
+      <menu:menuitem menu:id=".uno:Translate" menu:style="text"/>
       <menu:menuitem menu:id=".uno:FormatAllNotes" menu:style="text"/>
       <menu:menuitem menu:id=".uno:RubyDialog" menu:style="text"/>
       <menu:menuitem menu:id=".uno:FormatColumns" menu:style="text"/>
diff --git a/sw/uiconfig/swform/menubar/menubar.xml 
b/sw/uiconfig/swform/menubar/menubar.xml
index 0969d09e6ef6..861cded1a732 100644
--- a/sw/uiconfig/swform/menubar/menubar.xml
+++ b/sw/uiconfig/swform/menubar/menubar.xml
@@ -396,6 +396,7 @@
       <menu:menuseparator/>
       <menu:menuitem menu:id=".uno:PageDialog"/>
       <menu:menuitem menu:id=".uno:TitlePageDialog" menu:style="text"/>
+      <menu:menuitem menu:id=".uno:Translate" menu:style="text"/>
       <menu:menuitem menu:id=".uno:FormatAllNotes" menu:style="text"/>
       <menu:menuitem menu:id=".uno:RubyDialog" menu:style="text"/>
       <menu:menuitem menu:id=".uno:FormatColumns" menu:style="text"/>
diff --git a/sw/uiconfig/swriter/menubar/menubar.xml 
b/sw/uiconfig/swriter/menubar/menubar.xml
index 3f257b9f0ebf..4658564da415 100644
--- a/sw/uiconfig/swriter/menubar/menubar.xml
+++ b/sw/uiconfig/swriter/menubar/menubar.xml
@@ -457,6 +457,7 @@
       <menu:menuseparator/>
       <menu:menuitem menu:id=".uno:PageDialog"/>
       <menu:menuitem menu:id=".uno:TitlePageDialog"/>
+      <menu:menuitem menu:id=".uno:Translate"/>
       <menu:menuitem menu:id=".uno:FormatAllNotes" menu:style="text"/>
       <menu:menuitem menu:id=".uno:RubyDialog" menu:style="text"/>
       <menu:menuitem menu:id=".uno:FormatColumns"/>
diff --git a/sw/uiconfig/swriter/ui/translationdialog.ui 
b/sw/uiconfig/swriter/ui/translationdialog.ui
new file mode 100644
index 000000000000..fb2a01b0187e
--- /dev/null
+++ b/sw/uiconfig/swriter/ui/translationdialog.ui
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface domain="sw">
+  <requires lib="gtk+" version="3.20"/>
+  <object class="GtkDialog" id="LanguageSelectDialog">
+    <property name="can_focus">False</property>
+    <property name="title" translatable="yes">Language Selection</property>
+    <property name="resizable">False</property>
+    <property name="type_hint">dialog</property>
+    <child type="titlebar">
+      <placeholder/>
+    </child>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="box1">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="action-area1">
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="cancel">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="translate">
+                <property name="label">gtk-apply</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkGrid" id="grid1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_left">5</property>
+            <property name="margin_right">5</property>
+            <property name="margin_top">5</property>
+            <property name="margin_bottom">25</property>
+            <property name="row_homogeneous">True</property>
+            <property name="column_homogeneous">True</property>
+            <child>
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">start</property>
+                <property name="margin_top">5</property>
+                <property name="margin_bottom">5</property>
+                <property name="label" translatable="yes">Select language to 
translate</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">combobox1</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkComboBoxText" id="combobox1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_left">5</property>
+                <property name="margin_right">5</property>
+                <property name="margin_top">5</property>
+                <property name="margin_bottom">5</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 90d432ee559b..8f3e41c57d81 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -408,6 +408,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
     vcl/source/app/svmain \
     vcl/source/app/timer \
     vcl/source/app/unohelp2 \
+    vcl/source/app/unohelp3 \
     vcl/source/app/unohelp \
     vcl/source/app/vclevent \
     vcl/source/app/watchdog \
diff --git a/vcl/source/app/unohelp3.cxx b/vcl/source/app/unohelp3.cxx
new file mode 100644
index 000000000000..0910de84e64d
--- /dev/null
+++ b/vcl/source/app/unohelp3.cxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/log.hxx>
+#include <vcl/unohelp3.hxx>
+#include <sot/exchange.hxx>
+#include <sot/formats.hxx>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
+#include <cppuhelper/queryinterface.hxx>
+#include <boost/property_tree/json_parser.hpp>
+
+using namespace ::com::sun::star;
+
+namespace vcl::unohelper {
+
+    HtmlTransferable::HtmlTransferable( OString sData ) : data( sData )
+    {
+    }
+
+    HtmlTransferable::~HtmlTransferable()
+    {
+    }
+
+    // css::uno::XInterface
+    uno::Any HtmlTransferable::queryInterface( const uno::Type & rType )
+    {
+        uno::Any aRet = ::cppu::queryInterface( rType, static_cast< 
datatransfer::XTransferable* >(this) );
+        return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ));
+    }
+
+    // css::datatransfer::XTransferable
+    uno::Any HtmlTransferable::getTransferData( const 
datatransfer::DataFlavor& rFlavor )
+    {
+        SotClipboardFormatId nT = SotExchange::GetFormat( rFlavor );
+        if ( nT != SotClipboardFormatId::HTML )
+        {
+            throw datatransfer::UnsupportedFlavorException();
+        }
+        size_t size = data.getLength();
+        uno::Sequence<sal_Int8> sData(size);
+        std::memcpy(sData.getArray(), data.getStr(), size);
+        return uno::Any(sData);
+    }
+
+    uno::Sequence< datatransfer::DataFlavor > 
HtmlTransferable::getTransferDataFlavors(  )
+    {
+        uno::Sequence< datatransfer::DataFlavor > aDataFlavors(1);
+        auto ref = aDataFlavors.getArray()[0];
+        ref.MimeType = "text/html";
+        ref.DataType = cppu::UnoType< uno::Sequence<sal_Int8> >::get();
+        SotExchange::GetFormatDataFlavor( SotClipboardFormatId::HTML, 
aDataFlavors.getArray()[0] );
+        return aDataFlavors;
+    }
+
+    sal_Bool HtmlTransferable::isDataFlavorSupported( const 
datatransfer::DataFlavor& rFlavor )
+    {
+        SotClipboardFormatId nT = SotExchange::GetFormat( rFlavor );
+        return ( nT == SotClipboardFormatId::HTML );
+    }
+
+}  // namespace vcl::unohelper

Reply via email to