Rebased ref, commits from common ancestor:
commit 799a381452337bb007b6efd4d366cf5c4d5ea74e
Author:     Mert Tumer <mert.tu...@collabora.com>
AuthorDate: Tue Jul 5 12:03:27 2022 +0300
Commit:     Mert Tumer <mert.tu...@collabora.com>
CommitDate: Mon Jul 25 19:11:26 2022 +0300

    new uno command uno:Translate with deepl api
    
    New Uno command added for translation
    right now it is only using deepl translation api
    
    There's a section in the options > language settings
    for setting up the api url and auth key
    
    uno:Translate is a menu button under Format tab
    which will bring up Language Selection dialog for translation.
    
    DeepL can accept html as the input for translation, this new
    feature leverages that by exporting paragraphs/selections to
    html and paste them back without losing the formatting (in theory)
    This works good in general but we may lose formatting in very complex
    styled sentences.
    
    Translation works in two ways;
    1) Whole document
    when there is no selection, it assumes that we want to translate whole
    document. Each paragraphs is sent one by one so that the output timeout
    can be minimum for each paragraph.
    2) Selection
    
    Signed-off-by: Mert Tumer <mert.tu...@collabora.com>
    Change-Id: Ia2d3ab2f6757faf565b939e1d670a7dedac33390

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/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/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..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/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..c7c86ab5f3cb
--- /dev/null
+++ b/sw/source/ui/misc/translatelangselect.cxx
@@ -0,0 +1,262 @@
+/* -*- 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>
+
+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;
+
+    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 (m_bCancelTranslation)
+            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
+                = SwTranslateHelper::Translate(aTargetLang, aAPIUrl, aAuthKey, 
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();
+
+    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..7af8541a8186
--- /dev/null
+++ b/sw/source/uibase/inc/translatehelper.hxx
@@ -0,0 +1,34 @@
+/* -*- 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
+{
+SW_DLLPUBLIC extern OString ExportPaMToHTML(SwPaM* pCursor, bool bReplacePTag);
+SW_DLLPUBLIC extern OString Translate(const OString& rTargetLang, const 
OString& rAPIUrl,
+                                      const OString& rAuthKey, const OString& 
rData);
+SW_DLLPUBLIC extern void PasteHTMLToPaM(SwWrtShell& rWrtSh, SwPaM* pCursor, 
const OString& rData,
+                                        bool bSetSelection);
+}
\ 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..8889dfe01ec3 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,40 @@ 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);
+            // SwPaM *pPaM = nullptr;
+            // bool hasSelection = false;
+            // if (rWrtSh.HasSelection())
+            // {
+            //     pPaM = rWrtSh.GetCursor();
+            //     hasSelection = true;
+            // }
+            // const auto aOut = SwTranslateHelper::ExportPaMToHTML(pPaM, 
!hasSelection);
+            // const auto aTranslatedOut = 
SwTranslateHelper::Translate(aTargetLang, aAPIUrl, aAuthKey, aOut);
+            // SwTranslateHelper::PasteHTMLToPaM(rWrtSh, pPaM, aTranslatedOut, 
!hasSelection);
+        }
+        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..c0def9a51bce
--- /dev/null
+++ b/sw/source/uibase/shells/translatehelper.cxx
@@ -0,0 +1,143 @@
+/* -*- 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>
+
+namespace SwTranslateHelper
+{
+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);
+}
+
+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);
+        }
+    }
+}
+}
\ 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
commit 4d1135553d47d627cfc63761818e00d9042f9e18
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Thu Jul 21 13:31:17 2022 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Jul 22 14:31:56 2022 +0200

    Revert "avoid repeated writer layout calls with tiled rendering" 
(tdf#145396)
    
    This was incorrect, the proper fix was my previous Writer commit.
    
    This reverts commit b9c2207e1b5247b4d3184b137be9a75a4b8c6c37.
    
    Change-Id: I829da1633dd11cb0c6e944fbf5acef030fad7dc4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137294
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>
    (cherry picked from commit 9dff8edf97f454f24a40acbed4a9297816f91da6)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137318
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index b2b246e5eb2f..9375ca13cd51 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -2275,16 +2275,7 @@ SwLayIdle::SwLayIdle( SwRootFrame *pRt, SwViewShellImp 
*pI ) :
         {
             --rSh.mnStartAction;
 
-            // When using tiled rendering, idle painting is disabled and 
paints are done
-            // only later by tiled rendering. But paints call 
SwViewShellImp::DeletePaintRegion()
-            // to reset this HasPaintRegion(), and if it's done too late,
-            // SwTiledRenderingTest::testTablePaintInvalidate() will end up in 
an infinite
-            // loop, because the idle layout will call this code repeatedly, 
because there
-            // will be no idle paints to reset HasPaintRegion().
-            // This code dates back to the initial commit, and I find its 
purpose unclear,
-            // so I'm still leaving it here in case it turns out it serves a 
purpose.
-            static const bool blockOnRepaints = true;
-            if (!blockOnRepaints && rSh.Imp()->HasPaintRegion())
+            if ( rSh.Imp()->HasPaintRegion() )
                 bActions = true;
             else
             {
commit 50788a6e27e02fdb49f4e43a82b041e6a2a628db
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Thu Jul 21 13:27:45 2022 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Jul 22 14:31:32 2022 +0200

    Revert "do not draw directly in SwViewShell in LOK mode"
    
    It is actually needed to process SwViewShellImp's paint region,
    as otherwise testTablePaintInvalidate::TestBody from
    CppunitTest_sw_tiledrendering will end up in an infinite loop
    repeatedly calling SwLayIdle ctor. That's what I tried to handle
    in b9c2207e1b5247b4d3184b137be9a75a4b8c6c37 and got it wrong.
    
    This reverts commit 2aa2d03ec4e775d9399420c21cd1f2e972984154.
    
    Change-Id: I25e897ea4e38db48cd969a3c21d677701f75a0aa
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137293
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>
    (cherry picked from commit 94bde29634c095e40bfcf74d27821b48919595da)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137317
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx
index b16b2d042727..7c4b55729ca7 100644
--- a/sw/source/core/view/viewsh.cxx
+++ b/sw/source/core/view/viewsh.cxx
@@ -478,7 +478,7 @@ void SwViewShell::ImplUnlockPaint( bool bVirDev )
     CurrShell aCurr( this );
     if ( GetWin() && GetWin()->IsVisible() )
     {
-        if ( (bInSizeNotify || bVirDev ) && VisArea().HasArea() && 
!comphelper::LibreOfficeKit::isActive())
+        if ( (bInSizeNotify || bVirDev ) && VisArea().HasArea() )
         {
             //Refresh with virtual device to avoid flickering.
             VclPtrInstance<VirtualDevice> pVout( *mpOut );
commit f78588a59efc7813b35e60222efcc76f1116468c
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Thu Jul 21 14:40:54 2022 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Jul 22 06:36:11 2022 +0200

    tdf#144916: expand range to avoid unwanted effects on viewport edges
    
    This also allows to avoid clipping of impBufferDevice to the passed
    OutputDevice, because the expanded range couldn't otherwise be processed
    on the buffer device.
    
    Change-Id: I0d778365b09937c1a2ecee06477b0b17efcce44b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137296
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    (cherry picked from commit 8c15835762f2b16e7c8f5acd2d52f562c7dec9a4)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137322
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>

diff --git a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx 
b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx
index 7f20d094b446..362293438dd8 100644
--- a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx
+++ b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx
@@ -285,18 +285,17 @@ VDevBuffer& getVDevBuffer()
     return *aVDevBuffer.get();
 }
 
-impBufferDevice::impBufferDevice(OutputDevice& rOutDev, const 
basegfx::B2DRange& rRange)
+impBufferDevice::impBufferDevice(OutputDevice& rOutDev, const 
basegfx::B2DRange& rRange, bool bCrop)
     : mrOutDev(rOutDev)
     , mpContent(nullptr)
     , mpAlpha(nullptr)
 {
     basegfx::B2DRange aRangePixel(rRange);
     aRangePixel.transform(mrOutDev.GetViewTransformation());
-    const ::tools::Rectangle aRectPixel(floor(aRangePixel.getMinX()), 
floor(aRangePixel.getMinY()),
-                                        ceil(aRangePixel.getMaxX()), 
ceil(aRangePixel.getMaxY()));
-    const Point aEmptyPoint;
-    maDestPixel = ::tools::Rectangle(aEmptyPoint, 
mrOutDev.GetOutputSizePixel());
-    maDestPixel.Intersection(aRectPixel);
+    maDestPixel = tools::Rectangle(floor(aRangePixel.getMinX()), 
floor(aRangePixel.getMinY()),
+                                   ceil(aRangePixel.getMaxX()), 
ceil(aRangePixel.getMaxY()));
+    if (bCrop)
+        maDestPixel.Intersection({ {}, mrOutDev.GetOutputSizePixel() });
 
     if (!isVisible())
         return;
diff --git a/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx 
b/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx
index 3b5d30415cc2..99585b05b141 100644
--- a/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx
+++ b/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx
@@ -38,7 +38,7 @@ class impBufferDevice
     tools::Rectangle maDestPixel;
 
 public:
-    impBufferDevice(OutputDevice& rOutDev, const basegfx::B2DRange& rRange);
+    impBufferDevice(OutputDevice& rOutDev, const basegfx::B2DRange& rRange, 
bool bCrop = true);
     ~impBufferDevice();
 
     void paint(double fTrans = 0.0);
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx 
b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
index 722cd6362807..087f6bcedb37 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
@@ -1026,13 +1026,29 @@ AlphaMask ProcessAndBlurAlphaMask(const Bitmap& rMask, 
double fErodeDilateRadius
 
     return AlphaMask(mask.GetBitmap());
 }
+
+drawinglayer::geometry::ViewInformation2D
+expandRange(const drawinglayer::geometry::ViewInformation2D& rViewInfo, double 
nAmount)
+{
+    basegfx::B2DRange viewport(rViewInfo.getViewport());
+    viewport.grow(nAmount);
+    return { rViewInfo.getObjectTransformation(),
+             rViewInfo.getViewTransformation(),
+             viewport,
+             rViewInfo.getVisualizedPage(),
+             rViewInfo.getViewTime(),
+             rViewInfo.getReducedDisplayQuality() };
+}
 }
 
 void VclPixelProcessor2D::processGlowPrimitive2D(const 
primitive2d::GlowPrimitive2D& rCandidate)
 {
-    basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D()));
+    const double nGlowRadius(rCandidate.getGlowRadius());
+    // Avoid wrong effect on the cut-off side; so expand by radius
+    const auto aExpandedViewInfo(expandRange(getViewInformation2D(), 
nGlowRadius));
+    basegfx::B2DRange aRange(rCandidate.getB2DRange(aExpandedViewInfo));
     aRange.transform(maCurrentTransformation);
-    basegfx::B2DVector aGlowRadiusVector(rCandidate.getGlowRadius(), 0);
+    basegfx::B2DVector aGlowRadiusVector(nGlowRadius, 0);
     // Calculate the pixel size of glow radius in current transformation
     aGlowRadiusVector *= maCurrentTransformation;
     // Glow radius is the size of the halo from each side of the object. The 
halo is the
@@ -1043,7 +1059,7 @@ void VclPixelProcessor2D::processGlowPrimitive2D(const 
primitive2d::GlowPrimitiv
     // Consider glow transparency (initial transparency near the object edge)
     const sal_uInt8 nAlpha = rCandidate.getGlowColor().GetAlpha();
 
-    impBufferDevice aBufferDevice(*mpOutputDevice, aRange);
+    impBufferDevice aBufferDevice(*mpOutputDevice, aRange, false);
     if (aBufferDevice.isVisible())
     {
         // remember last OutDev and set to content
@@ -1055,9 +1071,8 @@ void VclPixelProcessor2D::processGlowPrimitive2D(const 
primitive2d::GlowPrimitiv
         process(rCandidate);
 
         // Limit the bitmap size to the visible area.
-        basegfx::B2DRange 
viewRange(getViewInformation2D().getDiscreteViewport());
         basegfx::B2DRange bitmapRange(aRange);
-        bitmapRange.intersect(viewRange);
+        bitmapRange.intersect(aExpandedViewInfo.getDiscreteViewport());
         if (!bitmapRange.isEmpty())
         {
             const tools::Rectangle aRect(
@@ -1094,19 +1109,19 @@ void VclPixelProcessor2D::processGlowPrimitive2D(const 
primitive2d::GlowPrimitiv
 void VclPixelProcessor2D::processSoftEdgePrimitive2D(
     const primitive2d::SoftEdgePrimitive2D& rCandidate)
 {
-    // TODO: don't limit the object at view range. This is needed to not blur 
objects at window
-    // borders, where they don't end. Ideally, process the full object once at 
maximal reasonable
-    // resolution, and store the resulting alpha mask in primitive's cache; 
then reuse it later,
-    // applying the transform.
-    basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D()));
+    const double nRadius(rCandidate.getRadius());
+    // Avoid wrong effect on the cut-off side; so expand by diameter
+    const auto aExpandedViewInfo(expandRange(getViewInformation2D(), nRadius * 
2));
+
+    basegfx::B2DRange aRange(rCandidate.getB2DRange(aExpandedViewInfo));
     aRange.transform(maCurrentTransformation);
-    basegfx::B2DVector aRadiusVector(rCandidate.getRadius(), 0);
+    basegfx::B2DVector aRadiusVector(nRadius, 0);
     // Calculate the pixel size of soft edge radius in current transformation
     aRadiusVector *= maCurrentTransformation;
     // Blur radius is equal to soft edge radius
     const double fBlurRadius = aRadiusVector.getLength();
 
-    impBufferDevice aBufferDevice(*mpOutputDevice, aRange);
+    impBufferDevice aBufferDevice(*mpOutputDevice, aRange, false);
     if (aBufferDevice.isVisible())
     {
         // remember last OutDev and set to content
@@ -1117,9 +1132,8 @@ void VclPixelProcessor2D::processSoftEdgePrimitive2D(
         process(rCandidate);
 
         // Limit the bitmap size to the visible area.
-        basegfx::B2DRange 
viewRange(getViewInformation2D().getDiscreteViewport());
         basegfx::B2DRange bitmapRange(aRange);
-        bitmapRange.intersect(viewRange);
+        bitmapRange.intersect(aExpandedViewInfo.getDiscreteViewport());
         if (!bitmapRange.isEmpty())
         {
             const tools::Rectangle aRect(
commit ba00d997ddd6867c3f2bd4909625a91bf4db590b
Author:     Tor Lillqvist <t...@collabora.com>
AuthorDate: Wed Jul 20 16:31:28 2022 +0300
Commit:     Tor Lillqvist <t...@collabora.com>
CommitDate: Thu Jul 21 11:43:16 2022 +0200

    mmap a "downloaded" font in Collabora Online already in the ForKit process
    
    Instead of waiting until it gets used in a Kit process.
    
    Change-Id: I8671fd637837d66002bd5645734e4fee2f07d864
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137266
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Tor Lillqvist <t...@collabora.com>

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 07276ebd1eea..5e9d48b75925 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -42,6 +42,9 @@
 #include <sal/log.hxx>
 #include <vcl/errinf.hxx>
 #include <vcl/lok.hxx>
+#ifdef LINUX
+#include <vcl/unx/freetypemanager.hxx>
+#endif
 #include <o3tl/any.hxx>
 #include <o3tl/unit_conversion.hxx>
 #include <osl/file.hxx>
@@ -4149,13 +4152,22 @@ static void lo_setOption(LibreOfficeKit* /*pThis*/, 
const char *pOption, const c
         else
             sal_detail_set_log_selector(pCurrentSalLogOverride);
     }
+#ifdef LINUX
     else if (strcmp(pOption, "addfont") == 0)
     {
+        SAL_INFO("vcl.unx.freetype", "Loading and mapping the font '" << 
pValue << "'");
         OutputDevice *pDevice = Application::GetDefaultDevice();
         OutputDevice::ImplClearAllFontData(false);
         pDevice->AddTempDevFont(OUString::fromUtf8(pValue), "");
         OutputDevice::ImplRefreshAllFontData(false);
+        FreetypeManager &rFTManager = FreetypeManager::get();
+        OUString sFontFileName;
+        osl::FileBase::getSystemPathFromFileURL( OUString::fromUtf8(pValue), 
sFontFileName );
+        FreetypeFontFile *pFTFile = 
rFTManager.FindFontFile(OUStringToOString(sFontFileName, 
RTL_TEXTENCODING_UTF8));
+        FreetypeManager::MapFontFile(pFTFile);
+        // Intentionally leak that FreetypeFontFile object
     }
+#endif
 }
 
 static void doc_postUnoCommand(LibreOfficeKitDocument* pThis, const char* 
pCommand, const char* pArguments, bool bNotifyWhenFinished)
diff --git a/include/vcl/unx/freetypemanager.hxx 
b/include/vcl/unx/freetypemanager.hxx
new file mode 100644
index 000000000000..2298ddb1f70c
--- /dev/null
+++ b/include/vcl/unx/freetypemanager.hxx
@@ -0,0 +1,98 @@
+/* -*- 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 <sal/config.h>
+
+class FontAttributes;
+class FreetypeFont;
+class FreetypeFontFile;
+class FreetypeFontInfo;
+class FreetypeFontInstance;
+
+namespace vcl
+{
+namespace font
+{
+class PhysicalFontCollection;
+}
+}
+
+/**
+  * The FreetypeManager caches various aspects of Freetype fonts
+  *
+  * It mainly consists of two std::unordered_map lists, which hold the items 
of the cache.
+  *
+  * They form kind of a tree, with FreetypeFontFile as the roots, referenced 
by multiple FreetypeFontInfo
+  * entries, which are referenced by the FreetypeFont items.
+  *
+  * All of these items have reference counters, but these don't control the 
items life-cycle, but that of
+  * the managed resources.
+  *
+  * The respective resources are:
+  *   FreetypeFontFile = holds the mmapped font file, as long as it's used by 
any FreetypeFontInfo.
+  *   FreetypeFontInfo = holds the FT_FaceRec_ object, as long as it's used by 
any FreetypeFont.
+  *   FreetypeFont     = holds the FT_SizeRec_ and is owned by a 
FreetypeFontInstance
+  *
+  * FreetypeFontInfo therefore is embedded in the Freetype subclass of 
PhysicalFontFace.
+  * FreetypeFont is owned by FreetypeFontInstance, the Freetype subclass of 
LogicalFontInstance.
+  *
+  * Nowadays there is not really a reason to have separate files for the 
classes, as the FreetypeManager
+  * is just about handling of Freetype based fonts, not some abstract glyphs.
+  **/
+class VCL_DLLPUBLIC FreetypeManager final
+{
+public:
+    ~FreetypeManager();
+
+    static FreetypeManager& get();
+
+    void AddFontFile(const OString& rNormalizedName, int nFaceNum, int 
nVariantNum,
+                     sal_IntPtr nFontId, const FontAttributes&);
+
+    void AnnounceFonts(vcl::font::PhysicalFontCollection*) const;
+
+    void ClearFontCache();
+
+    FreetypeFont* CreateFont(FreetypeFontInstance* pLogicalFont);
+
+    FreetypeFontFile* FindFontFile(const OString& rNativeFileName);
+
+    static void MapFontFile(FreetypeFontFile* pFontFile);
+
+private:
+    // to access the constructor (can't use InitFreetypeManager function, 
because it's private?!)
+    friend class GenericUnixSalData;
+    explicit FreetypeManager();
+
+    static void InitFreetype();
+
+    typedef std::unordered_map<sal_IntPtr, std::shared_ptr<FreetypeFontInfo>> 
FontInfoList;
+    typedef std::unordered_map<const char*, std::unique_ptr<FreetypeFontFile>, 
rtl::CStringHash,
+                               rtl::CStringEqual>
+        FontFileList;
+
+    FontInfoList m_aFontInfoList;
+    sal_IntPtr m_nMaxFontId;
+
+    FontFileList m_aFontFileList;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/unx/glyphcache.hxx b/vcl/inc/unx/glyphcache.hxx
index b6120e2899ee..a142c7f2b719 100644
--- a/vcl/inc/unx/glyphcache.hxx
+++ b/vcl/inc/unx/glyphcache.hxx
@@ -31,6 +31,7 @@
 #include <unx/gendata.hxx>
 #include <vcl/dllapi.h>
 #include <vcl/outdev.hxx>
+#include <vcl/unx/freetypemanager.hxx>
 
 #include <fontattributes.hxx>
 #include <fontinstance.hxx>
@@ -38,8 +39,6 @@
 
 #include <unordered_map>
 
-class FreetypeFont;
-class FreetypeFontFile;
 class FreetypeFontInstance;
 class FreetypeFontInfo;
 class FontConfigFontOptions;
@@ -47,69 +46,10 @@ namespace vcl::font
 {
 class PhysicalFontCollection;
 }
-class FreetypeFont;
-class SvpGcpHelper;
 
 namespace basegfx { class B2DPolyPolygon; }
 namespace vcl { struct FontCapabilities; }
 
- /**
-  * The FreetypeManager caches various aspects of Freetype fonts
-  *
-  * It mainly consists of two std::unordered_map lists, which hold the items 
of the cache.
-  *
-  * They form kind of a tree, with FreetypeFontFile as the roots, referenced 
by multiple FreetypeFontInfo
-  * entries, which are referenced by the FreetypeFont items.
-  *
-  * All of these items have reference counters, but these don't control the 
items life-cycle, but that of
-  * the managed resources.
-  *
-  * The respective resources are:
-  *   FreetypeFontFile = holds the mmapped font file, as long as it's used by 
any FreetypeFontInfo.
-  *   FreetypeFontInfo = holds the FT_FaceRec_ object, as long as it's used by 
any FreetypeFont.
-  *   FreetypeFont     = holds the FT_SizeRec_ and is owned by a 
FreetypeFontInstance
-  *
-  * FreetypeFontInfo therefore is embedded in the Freetype subclass of 
PhysicalFontFace.
-  * FreetypeFont is owned by FreetypeFontInstance, the Freetype subclass of 
LogicalFontInstance.
-  *
-  * Nowadays there is not really a reason to have separate files for the 
classes, as the FreetypeManager
-  * is just about handling of Freetype based fonts, not some abstract glyphs.
-  **/
-class VCL_DLLPUBLIC FreetypeManager final
-{
-public:
-    ~FreetypeManager();
-
-    static FreetypeManager& get();
-
-    void                    AddFontFile(const OString& rNormalizedName,
-                                int nFaceNum, int nVariantNum,
-                                sal_IntPtr nFontId,
-                                const FontAttributes&);
-
-    void                    AnnounceFonts( vcl::font::PhysicalFontCollection* 
) const;
-
-    void                    ClearFontCache();
-
-    FreetypeFont*           CreateFont(FreetypeFontInstance* pLogicalFont);
-
-private:
-    // to access the constructor (can't use InitFreetypeManager function, 
because it's private?!)
-    friend class GenericUnixSalData;
-    explicit FreetypeManager();
-
-    static void             InitFreetype();
-    FreetypeFontFile* FindFontFile(const OString& rNativeFileName);
-
-    typedef std::unordered_map<sal_IntPtr, std::shared_ptr<FreetypeFontInfo>> 
FontInfoList;
-    typedef std::unordered_map<const char*, std::unique_ptr<FreetypeFontFile>, 
rtl::CStringHash, rtl::CStringEqual> FontFileList;
-
-    FontInfoList            m_aFontInfoList;
-    sal_IntPtr              m_nMaxFontId;
-
-    FontFileList            m_aFontFileList;
-};
-
 class VCL_DLLPUBLIC FreetypeFont final
 {
 public:
diff --git a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx 
b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
index b19b6bb96446..a466316ae071 100644
--- a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
+++ b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
@@ -125,9 +125,11 @@ bool FreetypeFontFile::Map()
             SAL_WARN("vcl.unx.freetype", "mmap of '" << maNativeFileName << "' 
failed: " << strerror(errno));
             mpFileMap = nullptr;
         }
+        SAL_INFO("vcl.unx.freetype", "Successful mmap of '" << 
maNativeFileName << "'");
         close( nFile );
     }
-
+    else
+        SAL_INFO("vcl.unx.freetype", "Already mmapped: '" << maNativeFileName 
<< "' (" << mnRefCount << ")");
     return (mpFileMap != nullptr);
 }
 
@@ -139,6 +141,7 @@ void FreetypeFontFile::Unmap()
     if (mpFileMap)
     {
         munmap(mpFileMap, mnFileSize);
+        SAL_INFO("vcl.unx.freetype", "Successful munmap of '" << 
maNativeFileName << "'");
         mpFileMap = nullptr;
     }
 }
diff --git a/vcl/unx/generic/glyphs/glyphcache.cxx 
b/vcl/unx/generic/glyphs/glyphcache.cxx
index 79db2d87bdb0..3a86a5436244 100644
--- a/vcl/unx/generic/glyphs/glyphcache.cxx
+++ b/vcl/unx/generic/glyphs/glyphcache.cxx
@@ -66,6 +66,11 @@ FreetypeFontFile* FreetypeManager::FindFontFile(const 
OString& rNativeFileName)
     return pFontFile;
 }
 
+void FreetypeManager::MapFontFile(FreetypeFontFile* pFontFile)
+{
+    pFontFile->Map();
+}
+
 FreetypeFontInstance::FreetypeFontInstance(const vcl::font::PhysicalFontFace& 
rPFF, const vcl::font::FontSelectPattern& rFSP)
     : LogicalFontInstance(rPFF, rFSP)
     , mxFreetypeFont(FreetypeManager::get().CreateFont(this))
commit a6f2daef52ff2aa8af4e7f876ea5f3dd9beb4be1
Author:     Szymon Kłos <szymon.k...@collabora.com>
AuthorDate: Tue Jul 19 12:08:58 2022 +0200
Commit:     Szymon Kłos <szymon.k...@collabora.com>
CommitDate: Thu Jul 21 11:12:13 2022 +0200

    MarkColumns should modify formula if editing is active
    
    Change-Id: I2ad4df0e6ad87bdad689112683bd29babf127502
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137227
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Mert Tumer <mert.tu...@collabora.com>

diff --git a/sc/source/ui/view/tabview3.cxx b/sc/source/ui/view/tabview3.cxx
index 20954d8711cc..a658ac854375 100644
--- a/sc/source/ui/view/tabview3.cxx
+++ b/sc/source/ui/view/tabview3.cxx
@@ -1630,12 +1630,22 @@ void ScTabView::MarkColumns(SCCOL nCol, sal_Int16 
nModifier)
     if ((nModifier & KEY_SHIFT) == KEY_SHIFT)
         bMoveIsShift = true;
 
-    DoneBlockMode( nModifier != 0 );
-    InitBlockMode( nStartCol, 0, nTab, true, true);
-    MarkCursor( nCol, rDoc.MaxRow(), nTab );
-    bMoveIsShift = false;
-    SetCursor( nCol, 0 );
-    SelectionChanged();
+    if ( SC_MOD()->IsFormulaMode() )
+    {
+        DoneRefMode( nModifier != 0 );
+        InitRefMode( nCol, 0, nTab, SC_REFTYPE_REF );
+        UpdateRef( nCol, rDoc.MaxRow(), nTab );
+        bMoveIsShift = false;
+    }
+    else
+    {
+        DoneBlockMode( nModifier != 0 );
+        InitBlockMode( nStartCol, 0, nTab, true, true);
+        MarkCursor( nCol, rDoc.MaxRow(), nTab );
+        bMoveIsShift = false;
+        SetCursor( nCol, 0 );
+        SelectionChanged();
+    }
 }
 
 void ScTabView::MarkRows(SCROW nRow, sal_Int16 nModifier)
@@ -1647,12 +1657,22 @@ void ScTabView::MarkRows(SCROW nRow, sal_Int16 
nModifier)
     if ((nModifier & KEY_SHIFT) == KEY_SHIFT)
         bMoveIsShift = true;
 
-    DoneBlockMode( nModifier != 0 );
-    InitBlockMode( 0, nStartRow, nTab, true, false, true );
-    MarkCursor( rDoc.MaxCol(), nRow, nTab );
-    bMoveIsShift = false;
-    SetCursor( 0, nRow );
-    SelectionChanged();
+    if ( SC_MOD()->IsFormulaMode() )
+    {
+        DoneRefMode( nModifier != 0 );
+        InitRefMode( 0, nRow, nTab, SC_REFTYPE_REF );
+        UpdateRef( rDoc.MaxCol(), nRow, nTab );
+        bMoveIsShift = false;
+    }
+    else
+    {
+        DoneBlockMode( nModifier != 0 );
+        InitBlockMode( 0, nStartRow, nTab, true, false, true );
+        MarkCursor( rDoc.MaxCol(), nRow, nTab );
+        bMoveIsShift = false;
+        SetCursor( 0, nRow );
+        SelectionChanged();
+    }
 }
 
 void ScTabView::MarkDataArea( bool bIncludeCursor )
commit 3cb565539288596483817ecc01828db377190e26
Author:     Szymon Kłos <szymon.k...@collabora.com>
AuthorDate: Thu Jul 14 16:52:23 2022 +0200
Commit:     Szymon Kłos <szymon.k...@collabora.com>
CommitDate: Thu Jul 21 10:23:18 2022 +0200

    lok: formulabar: handle mobile IME
    
    Change-Id: I7cb69efaebb42020353133e590a161b2e4bc5210
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137086
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Mert Tumer <mert.tu...@collabora.com>

diff --git a/sc/source/ui/app/inputhdl.cxx b/sc/source/ui/app/inputhdl.cxx
index 94e68ac4c00c..6eb949725c37 100644
--- a/sc/source/ui/app/inputhdl.cxx
+++ b/sc/source/ui/app/inputhdl.cxx
@@ -4125,7 +4125,7 @@ void ScInputHandler::InputCommand( const CommandEvent& 
rCEvt )
             {
                 if (pTableView)
                     pTableView->Command( rCEvt );
-                if (pTopView && !comphelper::LibreOfficeKit::isActive())
+                if (pTopView)
                     pTopView->Command( rCEvt );
 
                 if ( rCEvt.GetCommand() == CommandEventId::EndExtTextInput )
diff --git a/sc/source/ui/app/inputwin.cxx b/sc/source/ui/app/inputwin.cxx
index 531d5c5d9a17..34d72d49481a 100644
--- a/sc/source/ui/app/inputwin.cxx
+++ b/sc/source/ui/app/inputwin.cxx
@@ -413,9 +413,18 @@ void ScInputWindow::StartFormula()
         EditView* pView = mxTextWindow->GetEditView();
         if (pView)
         {
+            sal_Int32 nStartPara = 0, nEndPara = 0;
             if (comphelper::LibreOfficeKit::isActive())
+            {
                 TextGrabFocus();
-            pView->SetSelection( ESelection(0, nStartPos, 0, nEndPos) );
+                if (pViewSh && !pViewSh->isLOKDesktop())
+                {
+                    nStartPara = nEndPara = 
pView->GetEditEngine()->GetParagraphCount() ?
+                        (pView->GetEditEngine()->GetParagraphCount() - 1) : 0;
+                    nStartPos = nEndPos = 
pView->GetEditEngine()->GetTextLen(nStartPara);
+                }
+            }
+            pView->SetSelection(ESelection(nStartPara, nStartPos, nEndPara, 
nEndPos));
             pScMod->InputChanged(pView);
             SetOkCancelMode();
             pView->SetEditEngineUpdateLayout(true);
@@ -1729,10 +1738,26 @@ bool ScTextWnd::Command( const CommandEvent& rCEvt )
         // see vcl/jsdialog/executor.cxx "textselection" event
         const Point* pParaPoint = static_cast<const 
Point*>(rCEvt.GetEventData());
         Point aSelectionStartEnd = rCEvt.GetMousePosPixel();
-        m_xEditView->SetSelection(
-            ESelection((pParaPoint ? pParaPoint->X() : 0), 
aSelectionStartEnd.X(),
-                       (pParaPoint ? pParaPoint->Y() : 0), 
aSelectionStartEnd.Y()));
 
+        sal_Int32 nParaStart, nParaEnd, nPosStart, nPosEnd;
+
+        ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+        if (pViewSh && pViewSh->isLOKMobilePhone())
+        {
+            // We use IME - do not select anything, put cursor at the end
+            nParaStart = nParaEnd = 
m_xEditView->GetEditEngine()->GetParagraphCount() ?
+                (m_xEditView->GetEditEngine()->GetParagraphCount() - 1) : 0;
+            nPosStart = nPosEnd = 
m_xEditView->GetEditEngine()->GetTextLen(nParaStart);
+        }
+        else
+        {
+            nParaStart = pParaPoint ? pParaPoint->X() : 0;
+            nParaEnd = pParaPoint ? pParaPoint->Y() : 0;
+            nPosStart = aSelectionStartEnd.X();
+            nPosEnd = aSelectionStartEnd.Y();
+        }
+
+        m_xEditView->SetSelection(ESelection(nParaStart, nPosStart, nParaEnd, 
nPosEnd));
         SC_MOD()->InputSelection( m_xEditView.get() );
 
         bConsumed = true;
@@ -1894,12 +1919,6 @@ static sal_Int32 findFirstNonMatchingChar(const 
OUString& rStr1, const OUString&
 
 void ScTextWnd::SetTextString( const OUString& rNewString )
 {
-    if (comphelper::LibreOfficeKit::isActive())
-    {
-        ESelection aSel = m_xEditView ? m_xEditView->GetSelection() : 
ESelection();
-        ScInputHandler::LOKSendFormulabarUpdate(SfxViewShell::Current(), 
rNewString, aSel);
-    }
-
     // Ideally it would be best to create on demand the EditEngine/EditView 
here, but... for
     // the initialisation scenario where a cell is first clicked on we end up 
with the text in the
     // inputbar window scrolled to the bottom if we do that here ( because the 
tableview and topview
@@ -1974,6 +1993,12 @@ void ScTextWnd::SetTextString( const OUString& 
rNewString )
         bInputMode = false;
     }
 
+    if (comphelper::LibreOfficeKit::isActive())
+    {
+        ESelection aSel = m_xEditView ? m_xEditView->GetSelection() : 
ESelection();
+        ScInputHandler::LOKSendFormulabarUpdate(SfxViewShell::Current(), 
rNewString, aSel);
+    }
+
     SetScrollBarRange();
     DoScroll();
 }
commit 8742557ec4e4361fe726c6274cd01afa3a8ea080
Author:     Szymon Kłos <szymon.k...@collabora.com>
AuthorDate: Thu Jul 14 16:51:28 2022 +0200
Commit:     Szymon Kłos <szymon.k...@collabora.com>
CommitDate: Thu Jul 21 10:22:52 2022 +0200

    jsdialog: handle grab_focus action
    

... etc. - the rest is truncated

Reply via email to