Plugins/UiExtensionPlugins/Translator/TranslatorEngines/MicrosoftEngine.py

changeset 6018
1c858879d3d0
child 6048
82ad8ec9548c
equal deleted inserted replaced
6017:dab01678626d 6018:1c858879d3d0
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2014 - 2017 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
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 def engineName(self):
46 """
47 Public method to return the name of the engine.
48
49 @return engine name (string)
50 """
51 return "microsoft"
52
53 def supportedLanguages(self):
54 """
55 Public method to get the supported languages.
56
57 @return list of supported language codes (list of string)
58 """
59 return ["ar", "bg", "ca", "cs", "da", "de", "en",
60 "es", "et", "fi", "fr", "hi", "hu", "id",
61 "it", "ja", "ko", "lt", "lv", "mt",
62 "nl", "no", "pl", "pt", "ro", "ru", "sk", "sl",
63 "sv", "th", "tr", "uk", "vi", "zh-CN", "zh-TW",
64 ]
65
66 def hasTTS(self):
67 """
68 Public method indicating the Text-to-Speech capability.
69
70 @return flag indicating the Text-to-Speech capability (boolean)
71 """
72 return True
73
74 def __mapLanguageCode(self, code):
75 """
76 Private method to map a language code to the Microsoft code.
77
78 @param code language code (string)
79 @return mapped language code (string)
80 """
81 if code in self.__mappings:
82 return self.__mapping[code]
83 else:
84 return code
85
86 def __getClientDataAzure(self):
87 """
88 Private method to retrieve the client data.
89
90 @return tuple giving the API subscription key and a flag indicating
91 validity
92 @rtype tuple of (str, bool)
93 """
94 subscriptionKey = self.plugin.getPreferences("MsTranslatorKey")
95 valid = bool(subscriptionKey)
96 return subscriptionKey, valid
97
98 def __getAccessToken(self, requestObject):
99 """
100 Private slot to get an access token.
101
102 If the stored token is no longer valid, get a new one and store it.
103
104 @param requestObject reference to the request object
105 (TranslatorRequest)
106 @return access token (string)
107 """
108 if self.plugin.getPreferences("MsAuthTokenExpire") > \
109 QDateTime.currentDateTime():
110 return self.plugin.getPreferences("MsAuthToken")
111
112 # Token expired, get a new one
113 subscriptionKey, valid = self.__getClientDataAzure()
114 if not valid:
115 return ""
116
117 subscriptionHeader = (b"Ocp-Apim-Subscription-Key",
118 subscriptionKey.encode("utf-8"))
119 response, ok = requestObject.post(
120 QUrl(self.AccessTokenUrl), QByteArray(b""),
121 extraHeaders=[subscriptionHeader])
122 if ok:
123 self.plugin.setPreferences("MsAuthToken", response)
124 self.plugin.setPreferences(
125 "MsAuthTokenExpire",
126 QDateTime.currentDateTime().addSecs(8 * 60))
127 return response
128 else:
129 return ""
130
131 def getTranslation(self, requestObject, text, originalLanguage,
132 translationLanguage):
133 """
134 Public method to translate the given text.
135
136 @param requestObject reference to the request object
137 (TranslatorRequest)
138 @param text text to be translated (string)
139 @param originalLanguage language code of the original (string)
140 @param translationLanguage language code of the translation (string)
141 @return tuple of translated text (string) and flag indicating
142 success (boolean)
143 """
144 subscriptionKey, valid = self.__getClientDataAzure()
145 if not valid:
146 return (self.tr("""You have not registered for the Microsoft"""
147 """ Translation service."""),
148 False)
149
150 accessToken = self.__getAccessToken(requestObject)
151 if not accessToken:
152 return (self.tr("No valid access token available."), False)
153
154 authHeader = (b"Authorization",
155 "Bearer {0}".format(accessToken).encode("utf-8"))
156 params = "?appid=&from={0}&to={1}&text={2}".format(
157 self.__mapLanguageCode(originalLanguage),
158 self.__mapLanguageCode(translationLanguage),
159 text)
160 url = QUrl(self.TranslatorUrl + params)
161 response, ok = requestObject.get(url, extraHeaders=[authHeader])
162 response = str(response, "utf-8", "replace")
163 if ok and response.startswith("<string") and \
164 response.endswith("</string>"):
165 result = response.split(">", 1)[1].rsplit("<", 1)[0]
166 else:
167 result = self.tr("No translation available.")
168 ok = False
169 return result, ok
170
171 def getTextToSpeechData(self, requestObject, text, language):
172 """
173 Public method to pronounce the given text.
174
175 @param requestObject reference to the request object
176 (TranslatorRequest)
177 @param text text to be pronounced (string)
178 @param language language code of the text (string)
179 @return tuple with pronounce data (QByteArray) or error string (string)
180 and success flag (boolean)
181 """
182 subscriptionKey, valid = self.__getClientDataAzure()
183 if not valid:
184 return (self.tr("""You have not registered for the Microsoft"""
185 """ Translation service."""),
186 False)
187
188 accessToken = self.__getAccessToken(requestObject)
189 if not accessToken:
190 return (self.tr("No valid access token available."), False)
191
192 params = "?language={0}&format={1}&options={2}&text={3}".format(
193 self.__mapLanguageCode(language),
194 "audio/wav",
195 "MaxQuality",
196 text)
197 authHeader = (b"Authorization",
198 "Bearer {0}".format(accessToken).encode("utf-8"))
199 url = QUrl(self.TextToSpeechUrl + params)
200 data, ok = requestObject.get(url, extraHeaders=[authHeader])
201 if not ok:
202 data = self.tr("No Text-to-Speech for the selected language"
203 " available.")
204 return data, ok

eric ide

mercurial