summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cui/Library_cui.mk1
-rw-r--r--cui/UIConfig_cui.mk1
-rw-r--r--cui/inc/treeopt.hrc3
-rw-r--r--cui/source/options/optdeepl.cxx55
-rw-r--r--cui/source/options/optdeepl.hxx37
-rw-r--r--cui/source/options/treeopt.cxx2
-rw-r--r--cui/uiconfig/ui/deepltabpage.ui124
-rw-r--r--desktop/source/lib/init.cxx24
-rw-r--r--include/linguistic/translate.hxx9
-rw-r--r--include/sfx2/pageids.hxx1
-rw-r--r--include/sfx2/sfxsids.hrc1
-rw-r--r--include/svtools/deeplcfg.hxx50
-rw-r--r--include/svx/svxids.hrc2
-rw-r--r--include/vcl/htmltransferable.hxx50
-rw-r--r--linguistic/Library_lng.mk2
-rw-r--r--linguistic/source/translate.cxx69
-rw-r--r--officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu8
-rw-r--r--officecfg/registry/schema/org/openoffice/Office/Linguistic.xcs22
-rw-r--r--svtools/Library_svt.mk1
-rw-r--r--svtools/source/config/deeplcfg.cxx128
-rw-r--r--svx/sdi/svx.sdi17
-rw-r--r--sw/Library_sw.mk2
-rw-r--r--sw/Library_swui.mk2
-rw-r--r--sw/UIConfig_swriter.mk1
-rw-r--r--sw/inc/strings.hrc1
-rw-r--r--sw/inc/swabstdlg.hxx13
-rw-r--r--sw/sdi/_textsh.sdi6
-rw-r--r--sw/source/ui/dialog/swdlgfact.cxx12
-rw-r--r--sw/source/ui/dialog/swdlgfact.hxx14
-rw-r--r--sw/source/ui/misc/translatelangselect.cxx157
-rw-r--r--sw/source/uibase/inc/translatehelper.hxx42
-rw-r--r--sw/source/uibase/inc/translatelangselect.hxx70
-rw-r--r--sw/source/uibase/shells/textsh1.cxx29
-rw-r--r--sw/source/uibase/shells/translatehelper.cxx209
-rw-r--r--sw/uiconfig/sglobal/menubar/menubar.xml2
-rw-r--r--sw/uiconfig/swriter/menubar/menubar.xml2
-rw-r--r--sw/uiconfig/swriter/ui/translationdialog.ui104
-rw-r--r--vcl/Library_vcl.mk1
-rw-r--r--vcl/jsdialog/enabled.cxx3
-rw-r--r--vcl/source/app/htmltransferable.cxx78
40 files changed, 1352 insertions, 3 deletions
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/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 5e9d48b75925..e912e9e75e5d 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -131,6 +131,7 @@
#include <svtools/ctrltool.hxx>
#include <svtools/langtab.hxx>
#include <svtools/languagetoolcfg.hxx>
+#include <svtools/deeplcfg.hxx>
#include <vcl/fontcharmap.hxx>
#include <vcl/graphicfilter.hxx>
#ifdef IOS
@@ -6609,6 +6610,28 @@ void setLanguageToolConfig()
}
}
+void setDeeplConfig()
+{
+ const char* pAPIUrlString = ::getenv("DEEPL_API_URL");
+ const char* pAuthKeyString = ::getenv("DEEPL_AUTH_KEY");
+ if (pAPIUrlString && pAuthKeyString)
+ {
+ OUString aAPIUrl = OStringToOUString(pAPIUrlString, RTL_TEXTENCODING_UTF8);
+ OUString aAuthKey = OStringToOUString(pAuthKeyString, RTL_TEXTENCODING_UTF8);
+ try
+ {
+ SvxDeeplOptions& rDeeplOptions = SvxDeeplOptions::Get();
+ rDeeplOptions.setAPIUrl(aAPIUrl);
+ rDeeplOptions.setAuthKey(aAuthKey);
+ }
+ catch(uno::Exception const& rException)
+ {
+ SAL_WARN("lok", "Failed to set Deepl API settings: " << rException.Message);
+ }
+ }
+}
+
+
}
static int lo_initialize(LibreOfficeKit* pThis, const char* pAppPath, const char* pUserProfileUrl)
@@ -6924,6 +6947,7 @@ static int lo_initialize(LibreOfficeKit* pThis, const char* pAppPath, const char
setCertificateDir();
setLanguageToolConfig();
+ setDeeplConfig();
if (bNotebookbar)
{
diff --git a/include/linguistic/translate.hxx b/include/linguistic/translate.hxx
new file mode 100644
index 000000000000..985930c74d83
--- /dev/null
+++ b/include/linguistic/translate.hxx
@@ -0,0 +1,9 @@
+#pragma once
+#include <linguistic/lngdllapi.h>
+#include <rtl/string.hxx>
+
+namespace linguistic
+{
+LNG_DLLPUBLIC OString Translate(const OString& rTargetLang, const OString& rAPIUrl,
+ const OString& rAuthKey, const OString& rData);
+} // namespace
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/htmltransferable.hxx b/include/vcl/htmltransferable.hxx
new file mode 100644
index 000000000000..d7f8f71bdb46
--- /dev/null
+++ b/include/vcl/htmltransferable.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 <com/sun/star/datatransfer/XTransferable.hpp>
+#include <cppuhelper/weak.hxx>
+#include <rtl/ustring.hxx>
+#include <vcl/dllapi.h>
+
+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/linguistic/Library_lng.mk b/linguistic/Library_lng.mk
index 517177ec393d..7674a1d026cd 100644
--- a/linguistic/Library_lng.mk
+++ b/linguistic/Library_lng.mk
@@ -51,6 +51,7 @@ $(eval $(call gb_Library_use_externals,lng,\
boost_headers \
icuuc \
icu_headers \
+ curl \
))
$(eval $(call gb_Library_add_exception_objects,lng,\
@@ -72,6 +73,7 @@ $(eval $(call gb_Library_add_exception_objects,lng,\
linguistic/source/spelldsp \
linguistic/source/spelldta \
linguistic/source/thesdsp \
+ linguistic/source/translate \
))
# vim: set noet sw=4 ts=4:
diff --git a/linguistic/source/translate.cxx b/linguistic/source/translate.cxx
new file mode 100644
index 000000000000..c01b5842a61e
--- /dev/null
+++ b/linguistic/source/translate.cxx
@@ -0,0 +1,69 @@
+#include <linguistic/translate.hxx>
+#include <sal/log.hxx>
+#include <curl/curl.h>
+#include <sal/log.hxx>
+#include <rtl/string.h>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/json_parser.hpp>
+#include <vcl/htmltransferable.hxx>
+#include <tools/long.hxx>
+
+namespace linguistic
+{
+OString Translate(const OString& rTargetLang, const OString& rAPIUrl, const OString& rAuthKey,
+ const OString& rData)
+{
+ constexpr tools::Long CURL_TIMEOUT = 10L;
+
+ 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, rAPIUrl.getStr());
+ curl_easy_setopt(curl.get(), CURLOPT_FAILONERROR, 1L);
+ curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT, CURL_TIMEOUT);
+
+ 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=" + rAuthKey + "&target_lang=" + rTargetLang + "&text="
+ + OString(curl_easy_escape(curl.get(), rData.getStr(), rData.getLength())));
+
+ curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, aPostData.getStr());
+ CURLcode cc = curl_easy_perform(curl.get());
+ if (cc != CURLE_OK)
+ {
+ SAL_WARN("translatehelper",
+ "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("translatehelper", "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("translatehelper", "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");
+ return OString(text);
+}
+} \ No newline at end of file
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..5eaf52ed9be7 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,\
@@ -687,6 +688,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\
sw/source/uibase/shells/grfsh \
sw/source/uibase/shells/grfshex \
sw/source/uibase/shells/langhelper \
+ sw/source/uibase/shells/translatehelper \
sw/source/uibase/shells/listsh \
sw/source/uibase/shells/mediash \
sw/source/uibase/shells/navsh \
diff --git a/sw/Library_swui.mk b/sw/Library_swui.mk
index 4c1d9614f56c..532617295808 100644
--- a/sw/Library_swui.mk
+++ b/sw/Library_swui.mk
@@ -77,6 +77,7 @@ $(eval $(call gb_Library_use_libraries,swui,\
utl \
vcl \
drawinglayer \
+ lng \
))
$(eval $(call gb_Library_add_exception_objects,swui,\
@@ -150,6 +151,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/strings.hrc b/sw/inc/strings.hrc
index 25d518d58def..5748ba7122ff 100644
--- a/sw/inc/strings.hrc
+++ b/sw/inc/strings.hrc
@@ -299,6 +299,7 @@
#define STR_DELETE_NOTE_AUTHOR NC_("STR_DELETE_NOTE_AUTHOR", "Delete ~All Comments by $1")
#define STR_HIDE_NOTE_AUTHOR NC_("STR_HIDE_NOTE_AUTHOR", "H~ide All Comments by $1")
#define STR_OUTLINE_NUMBERING NC_("STR_OUTLINE_NUMBERING", "Chapter Numbering")
+#define STR_STATSTR_SWTRANSLATE NC_("STR_STATSTR_SWTRANSLATE", "Translating document...")
/* To translators: $1 == will be replaced by STR_WORDCOUNT_WORDARG, and $2 by STR_WORDCOUNT_COLARG
e.g. Selected: 1 word, 2 characters */
#define STR_WORDCOUNT NC_("STR_WORDCOUNT", "Selected: $1, $2")
diff --git a/sw/inc/swabstdlg.hxx b/sw/inc/swabstdlg.hxx
index 0963de35da21..a841ce5d0ffd 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, SwWrtShell &rSh) = 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..af968ea90cab 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, SwWrtShell &rSh)
+{
+ return std::make_shared<AbstractSwTranslateLangSelectDlg_Impl>(std::make_unique<SwTranslateLangSelectDlg>(pParent, rSh));
+}
+
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..9ea4bc91b6c0 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, SwWrtShell &rSh) 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..fdfac220b0a1
--- /dev/null
+++ b/sw/source/ui/misc/translatelangselect.cxx
@@ -0,0 +1,157 @@
+/* -*- 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>
+#include <ndtxt.hxx>
+#include <shellio.hxx>
+#include <svtools/deeplcfg.hxx>
+#include <vcl/idle.hxx>
+#include <mdiexp.hxx>
+#include <strings.hrc>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <sfx2/viewfrm.hxx>
+#include <com/sun/star/task/XStatusIndicatorFactory.hpp>
+#include <linguistic/translate.hxx>
+
+int SwTranslateLangSelectDlg::selectedLangIdx = -1;
+SwTranslateLangSelectDlg::SwTranslateLangSelectDlg(weld::Window* pParent, SwWrtShell& rSh)
+ : GenericDialogController(pParent, "modules/swriter/ui/translationdialog.ui",
+ "LanguageSelectDialog")
+ , rWrtSh(rSh)
+ , 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_bTranslationStarted(false)
+ , m_bCancelTranslation(false)
+{
+ 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 = rBox.get_active();
+ SwTranslateLangSelectDlg::selectedLangIdx = selected;
+}
+
+IMPL_LINK(SwTranslateLangSelectDlg, LangSelectCancelHdl, weld::Button&, rButton, void)
+{
+ (void)rButton;
+
+ // stop translation first
+ if (m_bTranslationStarted)
+ m_bCancelTranslation = true;
+ else
+ m_xDialog->response(RET_CANCEL);
+}
+
+IMPL_LINK(SwTranslateLangSelectDlg, LangSelectTranslateHdl, weld::Button&, rButton, void)
+{
+ (void)rButton;
+
+ if (SwTranslateLangSelectDlg::selectedLangIdx == -1)
+ {
+ m_xDialog->response(RET_CANCEL);
+ return;
+ }
+
+ SvxDeeplOptions& rDeeplOptions = SvxDeeplOptions::Get();
+ if (rDeeplOptions.getAPIUrl().isEmpty() || rDeeplOptions.getAuthKey().isEmpty())
+ {
+ SAL_WARN("langselectdlg", "API options are not set");
+ m_xDialog->response(RET_CANCEL);
+ return;
+ }
+
+ const OString aAPIUrl
+ = OUStringToOString(OUString(rDeeplOptions.getAPIUrl() + "?tag_handling=html"),
+ RTL_TEXTENCODING_UTF8)
+ .trim();
+ const OString aAuthKey
+ = OUStringToOString(rDeeplOptions.getAuthKey(), RTL_TEXTENCODING_UTF8).trim();
+ const auto aTargetLang
+ = m_xLanguageVec.at(SwTranslateLangSelectDlg::selectedLangIdx).getLanguage();
+
+ m_bTranslationStarted = true;
+
+ SwTranslateHelper::TranslateAPIConfig aConfig({ aAPIUrl, aAuthKey, aTargetLang });
+ SwTranslateHelper::TranslateDocumentCancellable(rWrtSh, aConfig, m_bCancelTranslation);
+ m_xDialog->response(RET_OK);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/inc/translatehelper.hxx b/sw/source/uibase/inc/translatehelper.hxx
new file mode 100644
index 000000000000..d8298b7a289a
--- /dev/null
+++ b/sw/source/uibase/inc/translatehelper.hxx
@@ -0,0 +1,42 @@
+/* -*- 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 "swtypes.hxx"
+
+class SwWrtShell;
+class SwPaM;
+class SwNode;
+class SwTextNode;
+
+namespace SwTranslateHelper
+{
+struct SW_DLLPUBLIC TranslateAPIConfig final
+{
+ const OString m_xAPIUrl;
+ const OString m_xAuthKey;
+ const OString m_xTargetLanguage;
+};
+SW_DLLPUBLIC OString ExportPaMToHTML(SwPaM* pCursor, bool bReplacePTag);
+SW_DLLPUBLIC void PasteHTMLToPaM(SwWrtShell& rWrtSh, SwPaM* pCursor, const OString& rData,
+ bool bSetSelection);
+SW_DLLPUBLIC void TranslateDocument(SwWrtShell& rWrtSh, const TranslateAPIConfig& rConfig);
+SW_DLLPUBLIC void TranslateDocumentCancellable(SwWrtShell& rWrtSh,
+ const TranslateAPIConfig& rConfig,
+ bool& rCancelTranslation);
+} \ No newline at end of file
diff --git a/sw/source/uibase/inc/translatelangselect.hxx b/sw/source/uibase/inc/translatelangselect.hxx
new file mode 100644
index 000000000000..413145fc64d3
--- /dev/null
+++ b/sw/source/uibase/inc/translatelangselect.hxx
@@ -0,0 +1,70 @@
+
+/* -*- 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>
+#include <translatehelper.hxx>
+
+class SwWrtShell;
+
+// SwLanguageListItem Helper class for displaying available languages with their names and tags on the listbox.
+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;
+};
+
+// SwTranslateLangSelectDlg Language selection dialog for translation API.
+// Also responsible for iterating the nodes for translation
+class SwTranslateLangSelectDlg final : public weld::GenericDialogController
+{
+public:
+ static int selectedLangIdx;
+ SwTranslateLangSelectDlg(weld::Window* pParent, SwWrtShell& rSh);
+ std::optional<SwLanguageListItem> GetSelectedLanguage();
+
+private:
+ SwWrtShell& rWrtSh;
+ 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;
+
+ bool m_bTranslationStarted;
+ bool m_bCancelTranslation;
+
+ 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 1fee0e9759d5..c69ab04770a1 100644
--- a/sw/source/uibase/shells/textsh1.cxx
+++ b/sw/source/uibase/shells/textsh1.cxx
@@ -103,6 +103,9 @@
#include <bookmark.hxx>
#include <linguistic/misc.hxx>
#include <authfld.hxx>
+#include <translatelangselect.hxx>
+#include <svtools/deeplcfg.hxx>
+#include <translatehelper.hxx>
using namespace ::com::sun::star;
using namespace com::sun::star::beans;
@@ -1503,6 +1506,32 @@ void SwTextShell::Execute(SfxRequest &rReq)
}
}
break;
+ case SID_FM_TRANSLATE:
+ {
+ const SfxPoolItem* pTargetLangStringItem = nullptr;
+ if (pArgs && SfxItemState::SET == pArgs->GetItemState(SID_ATTR_TARGETLANG_STR, false, &pTargetLangStringItem))
+ {
+ SvxDeeplOptions& rDeeplOptions = SvxDeeplOptions::Get();
+ if (rDeeplOptions.getAPIUrl().isEmpty() || rDeeplOptions.getAuthKey().isEmpty())
+ {
+ SAL_WARN("translate", "API options are not set");
+ break;
+ }
+ const OString aAPIUrl = OUStringToOString(OUString(rDeeplOptions.getAPIUrl() + "?tag_handling=html"), RTL_TEXTENCODING_UTF8).trim();
+ const OString aAuthKey = OUStringToOString(rDeeplOptions.getAuthKey(), RTL_TEXTENCODING_UTF8).trim();
+ OString aTargetLang = OUStringToOString(static_cast<const SfxStringItem*>(pTargetLangStringItem)->GetValue(), RTL_TEXTENCODING_UTF8);
+ SwTranslateHelper::TranslateAPIConfig aConfig({aAPIUrl, aAuthKey, aTargetLang});
+ SwTranslateHelper::TranslateDocument(rWrtSh, aConfig);
+ }
+ else
+ {
+ SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
+ std::shared_ptr<AbstractSwTranslateLangSelectDlg> pAbstractDialog(pFact->CreateSwTranslateLangSelectDlg(GetView().GetFrameWeld(), rWrtSh));
+ std::shared_ptr<weld::DialogController> pDialogController(pAbstractDialog->getDialogController());
+ weld::DialogController::runAsync(pDialogController, [] (sal_Int32 /*nResult*/) { });
+ }
+ }
+ break;
case SID_SPELLCHECK_IGNORE:
{
SwPaM *pPaM = rWrtSh.GetCursor();
diff --git a/sw/source/uibase/shells/translatehelper.cxx b/sw/source/uibase/shells/translatehelper.cxx
new file mode 100644
index 000000000000..a54476c58c0f
--- /dev/null
+++ b/sw/source/uibase/shells/translatehelper.cxx
@@ -0,0 +1,209 @@
+/* -*- 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 <wrtsh.hxx>
+#include <pam.hxx>
+#include <node.hxx>
+#include <ndtxt.hxx>
+#include <translatehelper.hxx>
+#include <sal/log.hxx>
+#include <rtl/string.h>
+#include <shellio.hxx>
+#include <vcl/scheduler.hxx>
+#include <vcl/svapp.hxx>
+#include <curl/curl.h>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/json_parser.hpp>
+#include <vcl/htmltransferable.hxx>
+#include <vcl/transfer.hxx>
+#include <swdtflvr.hxx>
+#include <linguistic/translate.hxx>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <sfx2/viewfrm.hxx>
+#include <com/sun/star/task/XStatusIndicatorFactory.hpp>
+#include <strings.hrc>
+
+namespace SwTranslateHelper
+{
+OString ExportPaMToHTML(SwPaM* pCursor, bool bReplacePTag)
+{
+ SolarMutexGuard gMutex;
+ OString aResult;
+ WriterRef xWrt;
+ GetHTMLWriter(OUString("NoLineLimit,SkipHeaderFooter"), OUString(), xWrt);
+ if (pCursor != nullptr)
+ {
+ SvMemoryStream aMemoryStream;
+ SwWriter aWriter(aMemoryStream, *pCursor);
+ ErrCode nError = aWriter.Write(xWrt);
+ if (nError.IsError())
+ {
+ SAL_WARN("translatehelper", "failed to export selection to HTML");
+ return {};
+ }
+ aResult
+ = OString(static_cast<const char*>(aMemoryStream.GetData()), aMemoryStream.GetSize());
+ if (bReplacePTag)
+ {
+ aResult = aResult.replaceAll("<p", "<span");
+ aResult = aResult.replaceAll("</p>", "</span>");
+ }
+ return aResult;
+ }
+ return {};
+}
+
+void PasteHTMLToPaM(SwWrtShell& rWrtSh, SwPaM* pCursor, const OString& rData, bool bSetSelection)
+{
+ SolarMutexGuard gMutex;
+ rtl::Reference<vcl::unohelper::HtmlTransferable> pHtmlTransferable
+ = new vcl::unohelper::HtmlTransferable(rData);
+ if (pHtmlTransferable.is())
+ {
+ TransferableDataHelper aDataHelper(pHtmlTransferable);
+ if (aDataHelper.GetXTransferable().is()
+ && SwTransferable::IsPasteSpecial(rWrtSh, aDataHelper))
+ {
+ if (bSetSelection)
+ {
+ rWrtSh.SetSelection(*pCursor);
+ }
+ SwTransferable::Paste(rWrtSh, aDataHelper);
+ rWrtSh.KillSelection(nullptr, false);
+ }
+ }
+}
+
+void TranslateDocument(SwWrtShell& rWrtSh, const TranslateAPIConfig& rConfig)
+{
+ bool bCancel = false;
+ TranslateDocumentCancellable(rWrtSh, rConfig, bCancel);
+}
+
+void TranslateDocumentCancellable(SwWrtShell& rWrtSh, const TranslateAPIConfig& rConfig,
+ bool& rCancelTranslation)
+{
+ auto m_pCurrentPam = rWrtSh.GetCursor();
+ bool bHasSelection = rWrtSh.HasSelection();
+
+ if (bHasSelection)
+ {
+ // iteration will start top to bottom
+ if (m_pCurrentPam->GetPoint()->nNode > m_pCurrentPam->GetMark()->nNode)
+ m_pCurrentPam->Exchange();
+ }
+
+ auto const& pNodes = rWrtSh.GetNodes();
+ auto pPoint = SwPosition(*m_pCurrentPam->GetPoint());
+ auto pMark = SwPosition(*m_pCurrentPam->GetMark());
+ auto startNode = bHasSelection ? pPoint.nNode.GetIndex() : SwNodeOffset(0);
+ auto endNode = bHasSelection ? pMark.nNode.GetIndex() : pNodes.Count() - 1;
+
+ sal_Int32 nCount(0);
+ sal_Int32 nProgress(0);
+
+ for (SwNodeOffset n(startNode); n <= endNode; ++n)
+ {
+ if (pNodes[n] && pNodes[n]->IsTextNode())
+ {
+ if (pNodes[n]->GetTextNode()->GetText().isEmpty())
+ continue;
+ nCount++;
+ }
+ }
+
+ SfxViewFrame* pFrame = SfxViewFrame::Current();
+ uno::Reference<frame::XFrame> xFrame = pFrame->GetFrame().GetFrameInterface();
+ uno::Reference<task::XStatusIndicatorFactory> xProgressFactory(xFrame, uno::UNO_QUERY);
+ uno::Reference<task::XStatusIndicator> xStatusIndicator;
+
+ if (xProgressFactory.is())
+ {
+ xStatusIndicator = xProgressFactory->createStatusIndicator();
+ }
+
+ if (xStatusIndicator.is())
+ xStatusIndicator->start(SwResId(STR_STATSTR_SWTRANSLATE), nCount);
+
+ for (SwNodeOffset n(startNode); n <= endNode; ++n)
+ {
+ if (rCancelTranslation)
+ break;
+
+ if (n >= rWrtSh.GetNodes().Count())
+ break;
+
+ if (!pNodes[n])
+ break;
+
+ SwNode* pNode = pNodes[n];
+ if (pNode->IsTextNode())
+ {
+ if (pNode->GetTextNode()->GetText().isEmpty())
+ continue;
+
+ auto cursor
+ = Writer::NewUnoCursor(*rWrtSh.GetDoc(), pNode->GetIndex(), pNode->GetIndex());
+
+ // set edges (start, end) for nodes inside the selection.
+ if (bHasSelection)
+ {
+ if (startNode == endNode)
+ {
+ cursor->SetMark();
+ cursor->GetPoint()->nContent = pPoint.nContent;
+ cursor->GetMark()->nContent = pMark.nContent;
+ }
+ else if (n == startNode)
+ {
+ cursor->SetMark();
+ cursor->GetPoint()->nContent = std::min(pPoint.nContent, pMark.nContent);
+ }
+ else if (n == endNode)
+ {
+ cursor->SetMark();
+ cursor->GetMark()->nContent = pMark.nContent;
+ cursor->GetPoint()->nContent = 0;
+ }
+ }
+
+ const auto aOut = SwTranslateHelper::ExportPaMToHTML(cursor.get(), true);
+ const auto aTranslatedOut = linguistic::Translate(
+ rConfig.m_xTargetLanguage, rConfig.m_xAPIUrl, rConfig.m_xAuthKey, aOut);
+ SwTranslateHelper::PasteHTMLToPaM(rWrtSh, cursor.get(), aTranslatedOut, true);
+
+ if (xStatusIndicator.is())
+ xStatusIndicator->setValue((100 * ++nProgress) / nCount);
+
+ Idle aIdle("ProgressBar::SetValue aIdle");
+ aIdle.SetPriority(TaskPriority::POST_PAINT);
+ aIdle.Start();
+
+ rWrtSh.LockView(true);
+ while (aIdle.IsActive() && !Application::IsQuit())
+ {
+ Application::Yield();
+ }
+ rWrtSh.LockView(false);
+ }
+ }
+
+ if (xStatusIndicator.is())
+ xStatusIndicator->end();
+}
+} \ No newline at end of file
diff --git a/sw/uiconfig/sglobal/menubar/menubar.xml b/sw/uiconfig/sglobal/menubar/menubar.xml
index 38f6708c1a55..4a35c87db398 100644
--- a/sw/uiconfig/sglobal/menubar/menubar.xml
+++ b/sw/uiconfig/sglobal/menubar/menubar.xml
@@ -720,6 +720,8 @@
<menu:menuitem menu:id=".uno:WordCountDialog" menu:style="text"/>
<menu:menuitem menu:id=".uno:AccessibilityCheck"/>
<menu:menuseparator/>
+ <menu:menuitem menu:id=".uno:Translate" menu:style="text"/>
+ <menu:menuseparator/>
<menu:menu menu:id=".uno:AutoFormatMenu">
<menu:menupopup>
<menu:menuitem menu:id=".uno:OnlineAutoFormat"/>
diff --git a/sw/uiconfig/swriter/menubar/menubar.xml b/sw/uiconfig/swriter/menubar/menubar.xml
index 3f257b9f0ebf..eaf8340a47da 100644
--- a/sw/uiconfig/swriter/menubar/menubar.xml
+++ b/sw/uiconfig/swriter/menubar/menubar.xml
@@ -743,6 +743,8 @@
<menu:menuitem menu:id=".uno:WordCountDialog"/>
<menu:menuitem menu:id=".uno:AccessibilityCheck"/>
<menu:menuseparator/>
+ <menu:menuitem menu:id=".uno:Translate"/>
+ <menu:menuseparator/>
<menu:menu menu:id=".uno:AutoFormatMenu">
<menu:menupopup>
<menu:menuitem menu:id=".uno:OnlineAutoFormat"/>
diff --git a/sw/uiconfig/swriter/ui/translationdialog.ui b/sw/uiconfig/swriter/ui/translationdialog.ui
new file mode 100644
index 000000000000..daaeb406aa29
--- /dev/null
+++ b/sw/uiconfig/swriter/ui/translationdialog.ui
@@ -0,0 +1,104 @@
+<?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="border_width">6</property>
+ <property name="title" translatable="yes">Language Selection</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child type="titlebar">
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <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">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">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">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">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">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">5</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="label" translatable="yes">Select language to translate</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="hexpand">True</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">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-5">translate</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 90d432ee559b..fe0e0998ed4e 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/htmltransferable \
vcl/source/app/unohelp \
vcl/source/app/vclevent \
vcl/source/app/watchdog \
diff --git a/vcl/jsdialog/enabled.cxx b/vcl/jsdialog/enabled.cxx
index 8bc49e8bda20..6c6d94e85fa4 100644
--- a/vcl/jsdialog/enabled.cxx
+++ b/vcl/jsdialog/enabled.cxx
@@ -60,7 +60,8 @@ bool isBuilderEnabled(std::u16string_view rUIFile, bool bMobile)
|| rUIFile == u"svx/ui/accessibilitycheckentry.ui"
|| rUIFile == u"cui/ui/widgettestdialog.ui"
|| rUIFile == u"modules/swriter/ui/contentcontroldlg.ui"
- || rUIFile == u"modules/swriter/ui/contentcontrollistitemdlg.ui")
+ || rUIFile == u"modules/swriter/ui/contentcontrollistitemdlg.ui"
+ || rUIFile == u"modules/swriter/ui/translationdialog.ui")
{
return true;
}
diff --git a/vcl/source/app/htmltransferable.cxx b/vcl/source/app/htmltransferable.cxx
new file mode 100644
index 000000000000..24f65fe929b1
--- /dev/null
+++ b/vcl/source/app/htmltransferable.cxx
@@ -0,0 +1,78 @@
+/* -*- 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/htmltransferable.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