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

branch
eric7
changeset 8312
800c432b34c8
parent 8218
7c09585bd960
child 8318
962bce857696
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2014 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the Microsoft translation engine.
8 """
9
10 from PyQt5.QtCore import QUrl, QDateTime, QByteArray, QTimer
11
12 from .TranslationEngine import TranslationEngine
13
14
15 class MicrosoftEngine(TranslationEngine):
16 """
17 Class implementing the translation engine for the Microsoft
18 translation service.
19 """
20 AccessTokenUrl = (
21 "https://api.cognitive.microsoft.com/sts/v1.0/issueToken"
22 )
23 TranslatorUrl = "https://api.microsofttranslator.com/V2/Http.svc/Translate"
24 TextToSpeechUrl = "https://api.microsofttranslator.com/V2/Http.svc/Speak"
25
26 def __init__(self, plugin, parent=None):
27 """
28 Constructor
29
30 @param plugin reference to the plugin object (TranslatorPlugin)
31 @param parent reference to the parent object (QObject)
32 """
33 super().__init__(plugin, parent)
34
35 self.__mappings = {
36 "zh-CN": "zh-CHS",
37 "zh-TW": "zh-CHT",
38 }
39
40 QTimer.singleShot(0, self.availableTranslationsLoaded.emit)
41
42 def engineName(self):
43 """
44 Public method to return the name of the engine.
45
46 @return engine name (string)
47 """
48 return "microsoft"
49
50 def supportedLanguages(self):
51 """
52 Public method to get the supported languages.
53
54 @return list of supported language codes (list of string)
55 """
56 return ["ar", "bg", "ca", "cs", "da", "de", "en",
57 "es", "et", "fi", "fr", "hi", "hu", "id",
58 "it", "ja", "ko", "lt", "lv", "mt",
59 "nl", "no", "pl", "pt", "ro", "ru", "sk", "sl",
60 "sv", "th", "tr", "uk", "vi", "zh-CN", "zh-TW",
61 ]
62
63 def hasTTS(self):
64 """
65 Public method indicating the Text-to-Speech capability.
66
67 @return flag indicating the Text-to-Speech capability (boolean)
68 """
69 return True
70
71 def __mapLanguageCode(self, code):
72 """
73 Private method to map a language code to the Microsoft code.
74
75 @param code language code (string)
76 @return mapped language code (string)
77 """
78 if code in self.__mappings:
79 return self.__mapping[code]
80 else:
81 return code
82
83 def __getClientDataAzure(self):
84 """
85 Private method to retrieve the client data.
86
87 @return tuple giving the API subscription key and a flag indicating
88 validity
89 @rtype tuple of (str, bool)
90 """
91 subscriptionKey = self.plugin.getPreferences("MsTranslatorKey")
92 valid = bool(subscriptionKey)
93 return subscriptionKey, valid
94
95 def __getAccessToken(self, requestObject):
96 """
97 Private slot to get an access token.
98
99 If the stored token is no longer valid, get a new one and store it.
100
101 @param requestObject reference to the request object
102 (TranslatorRequest)
103 @return access token (string)
104 """
105 if (
106 self.plugin.getPreferences("MsAuthTokenExpire") >
107 QDateTime.currentDateTime()
108 ):
109 return self.plugin.getPreferences("MsAuthToken")
110
111 # Token expired, get a new one
112 subscriptionKey, valid = self.__getClientDataAzure()
113 if not valid:
114 return ""
115
116 subscriptionHeader = (b"Ocp-Apim-Subscription-Key",
117 subscriptionKey.encode("utf-8"))
118 response, ok = requestObject.post(
119 QUrl(self.AccessTokenUrl), QByteArray(b""),
120 extraHeaders=[subscriptionHeader])
121 if ok:
122 self.plugin.setPreferences("MsAuthToken", response)
123 self.plugin.setPreferences(
124 "MsAuthTokenExpire",
125 QDateTime.currentDateTime().addSecs(8 * 60))
126 return response
127 else:
128 return ""
129
130 def getTranslation(self, requestObject, text, originalLanguage,
131 translationLanguage):
132 """
133 Public method to translate the given text.
134
135 @param requestObject reference to the request object
136 (TranslatorRequest)
137 @param text text to be translated (string)
138 @param originalLanguage language code of the original (string)
139 @param translationLanguage language code of the translation (string)
140 @return tuple of translated text (string) and flag indicating
141 success (boolean)
142 """
143 subscriptionKey, valid = self.__getClientDataAzure()
144 if not valid:
145 return (self.tr("""You have not registered for the Microsoft"""
146 """ Translation service."""),
147 False)
148
149 accessToken = self.__getAccessToken(requestObject)
150 if not accessToken:
151 return (
152 self.tr("MS Translator: No valid access token available."),
153 False
154 )
155
156 authHeader = (b"Authorization",
157 "Bearer {0}".format(accessToken).encode("utf-8"))
158 params = "?appid=&from={0}&to={1}&text={2}".format(
159 self.__mapLanguageCode(originalLanguage),
160 self.__mapLanguageCode(translationLanguage),
161 text)
162 url = QUrl(self.TranslatorUrl + params)
163 response, ok = requestObject.get(url, extraHeaders=[authHeader])
164 if ok:
165 response = str(response, "utf-8", "replace").strip()
166 if (
167 response.startswith("<string") and
168 response.endswith("</string>")
169 ):
170 result = response.split(">", 1)[1].rsplit("<", 1)[0]
171 else:
172 result = self.tr("MS Translator: No translation available.")
173 ok = False
174 return result, ok
175
176 def getTextToSpeechData(self, requestObject, text, language):
177 """
178 Public method to pronounce the given text.
179
180 @param requestObject reference to the request object
181 (TranslatorRequest)
182 @param text text to be pronounced (string)
183 @param language language code of the text (string)
184 @return tuple with pronounce data (QByteArray) or error string (string)
185 and success flag (boolean)
186 """
187 subscriptionKey, valid = self.__getClientDataAzure()
188 if not valid:
189 return (self.tr("""You have not registered for the Microsoft"""
190 """ Translation service."""),
191 False)
192
193 accessToken = self.__getAccessToken(requestObject)
194 if not accessToken:
195 return (
196 self.tr("MS Translator: No valid access token available."),
197 False
198 )
199
200 params = "?language={0}&format={1}&options={2}&text={3}".format(
201 self.__mapLanguageCode(language),
202 "audio/wav",
203 "MaxQuality",
204 text)
205 authHeader = (b"Authorization",
206 "Bearer {0}".format(accessToken).encode("utf-8"))
207 url = QUrl(self.TextToSpeechUrl + params)
208 data, ok = requestObject.get(url, extraHeaders=[authHeader])
209 if not ok:
210 data = self.tr("MS Translator: No Text-to-Speech for the selected"
211 " language available.")
212 return data, ok

eric ide

mercurial