eric7/Plugins/UiExtensionPlugins/Translator/TranslatorEngines/MicrosoftEngine.py

branch
eric7
changeset 9148
b31f0d894b55
parent 8881
54e42bc2437a
diff -r bbf3af40c223 -r b31f0d894b55 eric7/Plugins/UiExtensionPlugins/Translator/TranslatorEngines/MicrosoftEngine.py
--- a/eric7/Plugins/UiExtensionPlugins/Translator/TranslatorEngines/MicrosoftEngine.py	Sun Jun 12 16:05:27 2022 +0200
+++ b/eric7/Plugins/UiExtensionPlugins/Translator/TranslatorEngines/MicrosoftEngine.py	Mon Jun 13 16:39:53 2022 +0200
@@ -7,7 +7,9 @@
 Module implementing the Microsoft translation engine.
 """
 
-from PyQt6.QtCore import QUrl, QDateTime, QByteArray, QTimer
+import json
+
+from PyQt6.QtCore import QUrl, QByteArray, QTimer
 
 from .TranslationEngine import TranslationEngine
 
@@ -17,18 +19,19 @@
     Class implementing the translation engine for the Microsoft
     translation service.
     """
-    AccessTokenUrl = (
-        "https://api.cognitive.microsoft.com/sts/v1.0/issueToken"
+    TranslatorUrl = (
+        "https://api.cognitive.microsofttranslator.com/translate"
+        "?api-version=3.0"
     )
-    TranslatorUrl = "https://api.microsofttranslator.com/V2/Http.svc/Translate"
-    TextToSpeechUrl = "https://api.microsofttranslator.com/V2/Http.svc/Speak"
     
     def __init__(self, plugin, parent=None):
         """
         Constructor
         
-        @param plugin reference to the plugin object (TranslatorPlugin)
-        @param parent reference to the parent object (QObject)
+        @param plugin reference to the plugin object
+        @type TranslatorPlugin
+        @param parent reference to the parent object
+        @type QObject
         """
         super().__init__(plugin, parent)
         
@@ -43,7 +46,8 @@
         """
         Public method to return the name of the engine.
         
-        @return engine name (string)
+        @return engine name
+        @rtype str
         """
         return "microsoft"
     
@@ -51,7 +55,8 @@
         """
         Public method to get the supported languages.
         
-        @return list of supported language codes (list of string)
+        @return list of supported language codes
+        @rtype list of str
         """
         return ["ar", "bg", "ca", "cs", "da", "de", "en",
                 "es", "et", "fi", "fr", "hi", "hu", "id",
@@ -60,20 +65,14 @@
                 "sv", "th", "tr", "uk", "vi", "zh-CN", "zh-TW",
                 ]
     
-    def hasTTS(self):
-        """
-        Public method indicating the Text-to-Speech capability.
-        
-        @return flag indicating the Text-to-Speech capability (boolean)
-        """
-        return True
-    
     def __mapLanguageCode(self, code):
         """
         Private method to map a language code to the Microsoft code.
         
-        @param code language code (string)
-        @return mapped language code (string)
+        @param code language code
+        @type str
+        @return mapped language code
+        @rtype str
         """
         if code in self.__mappings:
             return self.__mapping[code]
@@ -84,48 +83,14 @@
         """
         Private method to retrieve the client data.
         
-        @return tuple giving the API subscription key and a flag indicating
-            validity
-        @rtype tuple of (str, bool)
+        @return tuple giving the API subscription key, the API subscription
+            region and a flag indicating validity
+        @rtype tuple of (str, str, bool)
         """
         subscriptionKey = self.plugin.getPreferences("MsTranslatorKey")
-        valid = bool(subscriptionKey)
-        return subscriptionKey, valid
-    
-    def __getAccessToken(self, requestObject):
-        """
-        Private slot to get an access token.
-        
-        If the stored token is no longer valid, get a new one and store it.
-        
-        @param requestObject reference to the request object
-            (TranslatorRequest)
-        @return access token (string)
-        """
-        if (
-            self.plugin.getPreferences("MsAuthTokenExpire") >
-            QDateTime.currentDateTime()
-        ):
-            return self.plugin.getPreferences("MsAuthToken")
-        
-        # Token expired, get a new one
-        subscriptionKey, valid = self.__getClientDataAzure()
-        if not valid:
-            return ""
-        
-        subscriptionHeader = (b"Ocp-Apim-Subscription-Key",
-                              subscriptionKey.encode("utf-8"))
-        response, ok = requestObject.post(
-            QUrl(self.AccessTokenUrl), QByteArray(b""),
-            extraHeaders=[subscriptionHeader])
-        if ok:
-            self.plugin.setPreferences("MsAuthToken", response)
-            self.plugin.setPreferences(
-                "MsAuthTokenExpire",
-                QDateTime.currentDateTime().addSecs(8 * 60))
-            return response
-        else:
-            return ""
+        subscriptionRegion = self.plugin.getPreferences("MsTranslatorRegion")
+        valid = bool(subscriptionKey) and bool(subscriptionRegion)
+        return subscriptionKey, subscriptionRegion, valid
     
     def getTranslation(self, requestObject, text, originalLanguage,
                        translationLanguage):
@@ -133,80 +98,61 @@
         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)
+        @type TranslatorRequest
+        @param text text to be translated
+        @type str
+        @param originalLanguage language code of the original
+        @type str
+        @param translationLanguage language code of the translation
+        @type str
+        @return tuple of translated text and flag indicating success
+        @rtype tuple of (str, bool)
         """
-        subscriptionKey, valid = self.__getClientDataAzure()
+        subscriptionKey, subscriptionRegion, valid = (
+            self.__getClientDataAzure()
+        )
         if not valid:
             return (self.tr("""You have not registered for the Microsoft"""
-                            """ Translation service."""),
+                            """ Azure Translation service."""),
                     False)
         
-        accessToken = self.__getAccessToken(requestObject)
-        if not accessToken:
-            return (
-                self.tr("MS Translator: No valid access token available."),
-                False
-            )
-        
-        authHeader = (b"Authorization",
-                      "Bearer {0}".format(accessToken).encode("utf-8"))
-        params = "?appid=&from={0}&to={1}&text={2}".format(
+        params = "&from={0}&to={1}".format(
             self.__mapLanguageCode(originalLanguage),
             self.__mapLanguageCode(translationLanguage),
-            text)
+        )
         url = QUrl(self.TranslatorUrl + params)
-        response, ok = requestObject.get(url, extraHeaders=[authHeader])
-        if ok:
-            response = str(response, "utf-8", "replace").strip()
-            if (
-                response.startswith("<string") and
-                response.endswith("</string>")
-            ):
-                result = response.split(">", 1)[1].rsplit("<", 1)[0]
-            else:
-                result = self.tr("MS Translator: No translation available.")
-                ok = False
-        return result, ok
-    
-    def getTextToSpeechData(self, requestObject, text, language):
-        """
-        Public method to pronounce the given text.
+        
+        requestList = [{"Text": text}]
+        request = QByteArray(json.dumps(requestList).encode("utf-8"))
         
-        @param requestObject reference to the request object
-            (TranslatorRequest)
-        @param text text to be pronounced (string)
-        @param language language code of the text (string)
-        @return tuple with pronounce data (QByteArray) or error string (string)
-            and success flag (boolean)
-        """
-        subscriptionKey, valid = self.__getClientDataAzure()
-        if not valid:
-            return (self.tr("""You have not registered for the Microsoft"""
-                            """ Translation service."""),
-                    False)
-        
-        accessToken = self.__getAccessToken(requestObject)
-        if not accessToken:
-            return (
-                self.tr("MS Translator: No valid access token available."),
-                False
-            )
-        
-        params = "?language={0}&format={1}&options={2}&text={3}".format(
-            self.__mapLanguageCode(language),
-            "audio/wav",
-            "MaxQuality",
-            text)
-        authHeader = (b"Authorization",
-                      "Bearer {0}".format(accessToken).encode("utf-8"))
-        url = QUrl(self.TextToSpeechUrl + params)
-        data, ok = requestObject.get(url, extraHeaders=[authHeader])
-        if not ok:
-            data = self.tr("MS Translator: No Text-to-Speech for the selected"
-                           " language available.")
-        return data, ok
+        headers = [
+            (b"Ocp-Apim-Subscription-Key", subscriptionKey.encode("utf8")),
+            (b"Ocp-Apim-Subscription-Region",
+             subscriptionRegion.encode("utf8")),
+            (b"Content-Type", b"application/json; charset=UTF-8"),
+            (b"Content-Length", str(len(request)).encode("utf-8")),
+        ]
+        response, ok = requestObject.post(
+            url, request, dataType="json", extraHeaders=headers
+        )
+        if ok:
+            try:
+                responseList = json.loads(response)
+                responseDict = responseList[0]
+            except ValueError:
+                return (self.tr("MS Translator: Invalid response received"),
+                        False)
+            
+            if "translations" not in responseDict:
+                return (self.tr("MS Translator: No translation available."),
+                        False)
+            
+            result = ""
+            translations = responseDict["translations"]
+            for translation in translations:
+                result += translation["text"]
+                if translation != translations[-1]:
+                    result += "<br/>"
+        else:
+            result = response
+        return result, ok

eric ide

mercurial