Plugins/UiExtensionPlugins/Translator/TranslatorEngines/DeepLEngine.py

changeset 6018
1c858879d3d0
child 6026
4773c9469880
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UiExtensionPlugins/Translator/TranslatorEngines/DeepLEngine.py	Sun Dec 10 16:23:29 2017 +0100
@@ -0,0 +1,147 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2017 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the DeepL translation engine.
+"""
+
+from __future__ import unicode_literals
+try:
+    str = unicode
+except NameError:
+    pass
+
+import json
+import re
+
+from PyQt5.QtCore import QUrl, QByteArray
+
+from .TranslationEngine import TranslationEngine
+
+
+class DeepLEngine(TranslationEngine):
+    """
+    Class implementing the translation engine for the DeepL
+    translation service.
+    """
+    TranslatorUrl = "https://deepl.com/jsonrpc"
+    MaxTranslationTextLen = 5000
+    
+    def __init__(self, plugin, parent=None):
+        """
+        Constructor
+        
+        @param plugin reference to the plugin object
+        @type TranslatorPlugin
+        @param parent reference to the parent object
+        @type QObject
+        """
+        super(DeepLEngine, self).__init__(plugin, parent)
+        
+        self.__splitPattern = re.compile(r"([^\.!\?;]+[\.!\?;]*)")
+    
+    def engineName(self):
+        """
+        Public method to return the name of the engine.
+        
+        @return engine name
+        @rtype str
+        """
+        return "deepl"
+    
+    def supportedLanguages(self):
+        """
+        Public method to get the supported languages.
+        
+        @return list of supported language codes
+        @rtype list of str
+        """
+        return ["de", "en", "es", "fr", "it", "nl", "pl",]
+    
+    def getTranslation(self, requestObject, text, originalLanguage,
+                       translationLanguage):
+        """
+        Public method to translate the given text.
+        
+        @param requestObject reference to the request object
+            (TranslatorRequest)
+        @param text text to be translated (string)
+        @param originalLanguage language code of the original (string)
+        @param translationLanguage language code of the translation (string)
+        @return tuple of translated text (string) and flag indicating
+            success (boolean)
+        """
+        if len(text) > self.MaxTranslationTextLen:
+            return self.tr(
+                "Text to be translated exceeds the translation limit of {0}"
+                " characters.").format(self.MaxTranslationTextLen), False
+        
+        sentences = [s for s in self.__splitPattern.split(text) if len(s) > 0]
+        if originalLanguage in self.supportedLanguages():
+            originalLanguageU = originalLanguage.upper()
+        else:
+            originalLanguageU = "auto"
+        payload = {
+            "jsonrpc": "2.0",
+            "method": "LMT_handle_jobs",
+            "id": 1,
+            "params": {
+                "jobs": [{"kind": "default", "raw_en_sentence": s}
+                         for s in sentences
+                ],
+                "lang": {
+                    "user_preferred_langs": [
+                        originalLanguage.upper(),
+                        translationLanguage.upper(),
+                    ],
+                    "source_lang_user_selected": originalLanguageU,
+                    "target_lang": translationLanguage.upper()
+                },
+                "priority": 1,
+            }
+        }
+        request = QByteArray(json.dumps(payload).encode("utf-8"))
+        response, ok = requestObject.post(QUrl(self.TranslatorUrl), request,
+                                          "json")
+        if ok:
+            try:
+                responseDict = json.loads(response)
+            except ValueError:
+                return self.tr("Invalid response received from DeepL"), False
+            
+            if "error" in responseDict:
+                return self.tr("DeepL reported an error.\nMessage: {0}")\
+                    .format(responseDict["error"]["message"]),  False
+            
+            if "result" not in responseDict:
+                return self.tr("DeepL call returned an unknown result"), False
+            
+            if not responseDict["result"]["source_lang"] or \
+               not responseDict["result"]["target_lang"]:
+                return self.tr(
+                    "Unsupported language code given (source: {0},"
+                    " target: {1}).").format(
+                    originalLanguage, translationLanguage), False
+            
+            translations = responseDict["result"]["translations"]
+            if len(translations) == 0:
+                return self.tr("<p>No translation found</p>"), True
+            
+            # show sentence by sentence separated by a line
+            translationStrings = []
+            for translation in translations:
+                translationStrings.append(
+                    "<br/>".join(
+                        [s["postprocessed_sentence"] for s in sorted(
+                            translation["beams"],
+                            key=lambda b: -1 * b["score"])
+                        ]
+                    )
+                )
+            result = "<p>" + "<hr/>".join(translationStrings) + "</p>"
+        
+        else:
+            result = response
+        return result, ok

eric ide

mercurial