Rebased ref, commits from common ancestor:
commit 9ab279dbb665c2ac60c5b0de45158f17b4118483
Author: Mert Tumer <[email protected]>
AuthorDate: Tue Jul 5 12:03:27 2022 +0300
Commit: Mert Tumer <[email protected]>
CommitDate: Tue Jul 12 16:26:31 2022 +0300
wip translate
Signed-off-by: Mert Tumer <[email protected]>
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