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); + + } +}