summaryrefslogtreecommitdiff
path: root/linguistic
diff options
context:
space:
mode:
authorMert Tumer <mert.tumer@collabora.com>2022-07-05 12:03:27 +0300
committerMert Tumer <mert.tumer@collabora.com>2022-09-13 00:02:16 +0200
commitf0b4db7355cffa1f22ed5063db829b1f1f285a72 (patch)
treecb42d1443c05b3f789c70de29d5f25c7605b09b3 /linguistic
parentd896ad282b6d09666b87442863c2de9ac06daa06 (diff)
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.tumer@collabora.com> Change-Id: Ia2d3ab2f6757faf565b939e1d670a7dedac33390 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137199 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Diffstat (limited to 'linguistic')
-rw-r--r--linguistic/Library_lng.mk2
-rw-r--r--linguistic/source/translate.cxx70
2 files changed, 72 insertions, 0 deletions
diff --git a/linguistic/Library_lng.mk b/linguistic/Library_lng.mk
index 517177ec393d..7674a1d026cd 100644
--- a/linguistic/Library_lng.mk
+++ b/linguistic/Library_lng.mk
@@ -51,6 +51,7 @@ $(eval $(call gb_Library_use_externals,lng,\
boost_headers \
icuuc \
icu_headers \
+ curl \
))
$(eval $(call gb_Library_add_exception_objects,lng,\
@@ -72,6 +73,7 @@ $(eval $(call gb_Library_add_exception_objects,lng,\
linguistic/source/spelldsp \
linguistic/source/spelldta \
linguistic/source/thesdsp \
+ linguistic/source/translate \
))
# vim: set noet sw=4 ts=4:
diff --git a/linguistic/source/translate.cxx b/linguistic/source/translate.cxx
new file mode 100644
index 000000000000..316e3a8dbdcb
--- /dev/null
+++ b/linguistic/source/translate.cxx
@@ -0,0 +1,70 @@
+#include <linguistic/translate.hxx>
+#include <sal/log.hxx>
+#include <curl/curl.h>
+#include <sal/log.hxx>
+#include <rtl/string.h>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/json_parser.hpp>
+#include <vcl/htmltransferable.hxx>
+#include <tools/long.hxx>
+
+namespace linguistic
+{
+OString Translate(const OString& rTargetLang, const OString& rAPIUrl, const OString& rAuthKey,
+ const OString& rData)
+{
+ constexpr tools::Long CURL_TIMEOUT = 10L;
+
+ std::unique_ptr<CURL, std::function<void(CURL*)>> curl(curl_easy_init(),
+ [](CURL* p) { curl_easy_cleanup(p); });
+ curl_easy_setopt(curl.get(), CURLOPT_URL, rAPIUrl.getStr());
+ curl_easy_setopt(curl.get(), CURLOPT_FAILONERROR, 1L);
+ curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT, CURL_TIMEOUT);
+
+ std::string response_body;
+ curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION,
+ +[](void* buffer, size_t size, size_t nmemb, void* userp) -> size_t {
+ if (!userp)
+ return 0;
+ std::string* response = static_cast<std::string*>(userp);
+ size_t real_size = size * nmemb;
+ response->append(static_cast<char*>(buffer), real_size);
+ return real_size;
+ });
+ curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, static_cast<void*>(&response_body));
+ OString aLang(curl_easy_escape(curl.get(), rTargetLang.getStr(), rTargetLang.getLength()));
+ OString aAuthKey(curl_easy_escape(curl.get(), rAuthKey.getStr(), rAuthKey.getLength()));
+ OString aData(curl_easy_escape(curl.get(), rData.getStr(), rData.getLength()));
+ OString aPostData("auth_key=" + aAuthKey + "&target_lang=" + aLang + "&text=" + aData);
+
+ curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, aPostData.getStr());
+ CURLcode cc = curl_easy_perform(curl.get());
+ if (cc != CURLE_OK)
+ {
+ SAL_WARN("translatehelper",
+ "CURL perform returned with error: " << static_cast<sal_Int32>(cc));
+ return {};
+ }
+ tools::Long nStatusCode;
+ curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &nStatusCode);
+ if (nStatusCode != 200)
+ {
+ SAL_WARN("translatehelper", "CURL request returned with status code: " << nStatusCode);
+ return {};
+ }
+ // parse the response
+ boost::property_tree::ptree root;
+ std::stringstream aStream(response_body.data());
+ boost::property_tree::read_json(aStream, root);
+ boost::property_tree::ptree& translations = root.get_child("translations");
+ size_t size = translations.size();
+ if (size <= 0)
+ {
+ SAL_WARN("translatehelper", "API did not return any translations");
+ }
+ // take the first one
+ const boost::property_tree::ptree& translation = translations.begin()->second;
+ const std::string text = translation.get<std::string>("text");
+ return OString(text);
+}
+} \ No newline at end of file