Rebased ref, commits from common ancestor:
commit 9ab279dbb665c2ac60c5b0de45158f17b4118483
Author:     Mert Tumer <mert.tu...@collabora.com>
AuthorDate: Tue Jul 5 12:03:27 2022 +0300
Commit:     Mert Tumer <mert.tu...@collabora.com>
CommitDate: Tue Jul 12 16:26:31 2022 +0300

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

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..2f82b9f1711f 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 Page...</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/svx/sdi/svx.sdi b/svx/sdi/svx.sdi
index 9ab00de7e881..6b5fb5021370 100644
--- a/svx/sdi/svx.sdi
+++ b/svx/sdi/svx.sdi
@@ -1596,6 +1596,22 @@ SfxBoolItem NavigationBar SID_FM_NAVIGATIONBAR
     GroupId = SfxGroupId::Controls;
 ]
 
+SfxBoolItem Translate SID_FM_TRANSLATE
+[
+    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..31d093fdc6c6 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,13 @@
 #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>
 
 using namespace ::com::sun::star;
 using namespace com::sun::star::beans;
@@ -1503,6 +1513,149 @@ void SwTextShell::Execute(SfxRequest &rReq)
         }
     }
     break;
+    case SID_FM_TRANSLATE:
+    {
+        // get url and auth_key from some config
+        // suply args
+        // if no args received, bring up language selection dialog
+        // improve blockingness + progressbar etc
+
+        SwPaM *pPaM = nullptr;
+        if (rWrtSh.HasSelection())
+        {
+            pPaM = rWrtSh.GetCursor();
+        }
+
+        auto replacePara = [&rWrtSh](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, 
"https://api-free.deepl.com/v2/translate?tag_handling=html";);
+            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=&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 request 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", "request returned no 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)
+        {
+            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());
+                }
+            }
+        };
+        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..70a594201e60
--- /dev/null
+++ b/sw/uiconfig/swriter/ui/translationdialog.ui
@@ -0,0 +1,95 @@
+<?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="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="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="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>
+              </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