From 927868e5e416d7b07fa5246ab5985fcc84f2630d Mon Sep 17 00:00:00 2001
From: Helmi Akermi <70575401+hakermi@users.noreply.github.com>
Date: Thu, 12 Oct 2023 13:33:33 +0100
Subject: [PATCH] feat: Add DeepL translate connector - EXO-66770 (#44)
Add DeepL trasnlate connector
---
services/impl/pom.xml | 5 ++
.../connectors/DeepLTranslateConnector.java | 81 +++++++++++++++++++
.../resources/conf/portal/configuration.xml | 6 ++
.../DeepLTranslateConnectorTest.java | 79 ++++++++++++++++++
4 files changed, 171 insertions(+)
create mode 100644 services/impl/src/main/java/org/exoplatform/automatic/translation/impl/connectors/DeepLTranslateConnector.java
create mode 100644 services/impl/src/test/java/org/exoplatform/automatic/translation/impl/connectors/DeepLTranslateConnectorTest.java
diff --git a/services/impl/pom.xml b/services/impl/pom.xml
index a69d8165..416418a8 100644
--- a/services/impl/pom.xml
+++ b/services/impl/pom.xml
@@ -32,6 +32,11 @@
analytics-api
provided
+
+ com.deepl.api
+ deepl-java
+ 1.3.0
+
junit
junit
diff --git a/services/impl/src/main/java/org/exoplatform/automatic/translation/impl/connectors/DeepLTranslateConnector.java b/services/impl/src/main/java/org/exoplatform/automatic/translation/impl/connectors/DeepLTranslateConnector.java
new file mode 100644
index 00000000..755f8b1d
--- /dev/null
+++ b/services/impl/src/main/java/org/exoplatform/automatic/translation/impl/connectors/DeepLTranslateConnector.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 eXo Platform SAS.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.exoplatform.automatic.translation.impl.connectors;
+
+import com.deepl.api.*;
+import org.exoplatform.automatic.translation.api.AutomaticTranslationComponentPlugin;
+import org.exoplatform.commons.api.settings.SettingService;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+import java.util.Locale;
+
+public class DeepLTranslateConnector extends AutomaticTranslationComponentPlugin {
+
+ private static final Log LOG = ExoLogger.getLogger(DeepLTranslateConnector.class);
+
+ private static final String DEEPL_TRANSLATE_SERVICE = "deepl-translate";
+
+ private Translator translator;
+
+ private final TextTranslationOptions textTranslationOptions;
+
+ public DeepLTranslateConnector(SettingService settingService) {
+ super(settingService);
+ textTranslationOptions = new TextTranslationOptions();
+ textTranslationOptions.setTagHandling("html");
+ textTranslationOptions.setPreserveFormatting(true);
+ textTranslationOptions.setSentenceSplittingMode(SentenceSplittingMode.All);
+ }
+
+ @Override
+ public String translate(String message, Locale targetLocale) {
+ long startTime = System.currentTimeMillis();
+ try {
+ return getDeeplTranslator().translateText(message, null, getLocaleLanguage(targetLocale), textTranslationOptions).getText();
+ } catch (DeepLException e) {
+ LOG.error("remote_service={} operation={} parameters=\"message length:{},targetLocale:{}\" status=ko "
+ + "duration_ms={} error_msg=\"{}\"",
+ DEEPL_TRANSLATE_SERVICE,
+ "translate",
+ message.length(),
+ targetLocale.getLanguage(),
+ System.currentTimeMillis() - startTime,
+ e.getMessage());
+ } catch (InterruptedException e) {
+ LOG.error("DeepL API translation thread has been interrupted", e);
+ Thread.currentThread().interrupt();
+ }
+ return null;
+ }
+
+ private String getLocaleLanguage(Locale locale) {
+ if (locale.getLanguage().equalsIgnoreCase("en")) {
+ return "en-US";
+ } else if (locale.getLanguage().equalsIgnoreCase("pt")) {
+ return "pt-PT";
+ } else {
+ return locale.getLanguage();
+ }
+ }
+
+ private Translator getDeeplTranslator() {
+ if (translator == null) {
+ translator = new Translator(getApiKey());
+ }
+ return translator;
+ }
+}
diff --git a/services/impl/src/main/resources/conf/portal/configuration.xml b/services/impl/src/main/resources/conf/portal/configuration.xml
index 0c482352..8c5e05d0 100644
--- a/services/impl/src/main/resources/conf/portal/configuration.xml
+++ b/services/impl/src/main/resources/conf/portal/configuration.xml
@@ -20,6 +20,12 @@
org.exoplatform.automatic.translation.impl.connectors.GoogleTranslateConnector
Google Translate
+
+ deepl
+ addConnector
+ org.exoplatform.automatic.translation.impl.connectors.DeepLTranslateConnector
+ DeepL Translate
+
diff --git a/services/impl/src/test/java/org/exoplatform/automatic/translation/impl/connectors/DeepLTranslateConnectorTest.java b/services/impl/src/test/java/org/exoplatform/automatic/translation/impl/connectors/DeepLTranslateConnectorTest.java
new file mode 100644
index 00000000..63bea61e
--- /dev/null
+++ b/services/impl/src/test/java/org/exoplatform/automatic/translation/impl/connectors/DeepLTranslateConnectorTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 eXo Platform SAS.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.exoplatform.automatic.translation.impl.connectors;
+
+import com.deepl.api.*;
+import org.exoplatform.commons.api.settings.SettingService;
+import org.exoplatform.commons.api.settings.SettingValue;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Locale;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DeepLTranslateConnectorTest {
+
+ @Mock
+ private SettingService settingService;
+
+ @Mock
+ private Translator translator;
+
+ private DeepLTranslateConnector deepLTranslateConnector;
+
+ @Before
+ public void setUp() {
+ deepLTranslateConnector = new DeepLTranslateConnector(settingService);
+ }
+
+ @Test
+ public void translate() throws NoSuchFieldException, IllegalAccessException, DeepLException, InterruptedException {
+ // Need real auth-key to have a real result
+ TextTranslationOptions textTranslationOptions = new TextTranslationOptions();
+ textTranslationOptions.setTagHandling("html");
+ textTranslationOptions.setPreserveFormatting(true);
+ textTranslationOptions.setSentenceSplittingMode(SentenceSplittingMode.All);
+ TextResult textResult = new TextResult("Hello
", "fr");
+ Field textTranslationOptionsField = deepLTranslateConnector.getClass().getDeclaredField("textTranslationOptions");
+ textTranslationOptionsField.setAccessible(true);
+ textTranslationOptionsField.set(deepLTranslateConnector, textTranslationOptions);
+ when(translator.translateText("Bonjour
", null, "en-US", textTranslationOptions)).thenReturn(textResult);
+ Field field = deepLTranslateConnector.getClass().getDeclaredField("translator");
+ field.setAccessible(true);
+ field.set(deepLTranslateConnector, translator);
+ String text = deepLTranslateConnector.translate("Bonjour
", new Locale("en"));
+ assertNotNull(text);
+ when(translator.translateText("Bonjour
",
+ null,
+ "en-US",
+ textTranslationOptions)).thenThrow(new DeepLException("error"));
+ text = deepLTranslateConnector.translate("Bonjour
", new Locale("en"));
+ assertNull(text);
+
+ }
+}