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

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

eric ide

mercurial