-
Notifications
You must be signed in to change notification settings - Fork 39
/
__init__.py
231 lines (193 loc) · 8.63 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# -*- coding: utf-8 -*-
"""
__init__
A translator using the micrsoft translation engine documented here:
http://msdn.microsoft.com/en-us/library/ff512419.aspx
:copyright: © 2011 by Openlabs Technologies & Consulting (P) Limited
:license: BSD, see LICENSE for more details.
"""
__all__ = ['Translator', 'TranslateApiException']
try:
import simplejson as json
except ImportError:
import json
import requests
import six
import warnings
import logging
class ArgumentOutOfRangeException(Exception):
def __init__(self, message):
self.message = message.replace('ArgumentOutOfRangeException: ', '')
super(ArgumentOutOfRangeException, self).__init__(self.message)
class TranslateApiException(Exception):
def __init__(self, message, *args):
self.message = message.replace('TranslateApiException: ', '')
super(TranslateApiException, self).__init__(self.message, *args)
class Translator(object):
"""Implements AJAX API for the Microsoft Translator service
:param app_id: A string containing the Bing AppID. (Deprecated)
"""
base_url = "http://api.microsofttranslator.com/V2/Ajax.svc"
def __init__(
self, client_id, client_secret,
scope="http://api.microsofttranslator.com",
grant_type="client_credentials", app_id=None, debug=False):
"""
:param client_id: The client ID that you specified when you registered
your application with Azure DataMarket.
:param client_secret: The client secret value that you obtained when
you registered your application with Azure
DataMarket.
:param scope: Defaults to http://api.microsofttranslator.com
;param grant_type: Defaults to "client_credentials"
:param app_id: Deprecated
:param debug: If true, the logging level will be set to debug
.. versionchanged: 0.4
Bing AppID mechanism is deprecated and is no longer supported.
See: http://msdn.microsoft.com/en-us/library/hh454950
"""
if app_id is not None:
warnings.warn("""app_id is deprected since v0.4.
See: http://msdn.microsoft.com/en-us/library/hh454950
""", DeprecationWarning, stacklevel=2)
self.client_id = client_id
self.client_secret = client_secret
self.scope = scope
self.grant_type = grant_type
self.access_token = None
self.debug = debug
self.logger = logging.getLogger("microsofttranslator")
if self.debug:
self.logger.setLevel(level=logging.DEBUG)
def get_access_token(self):
"""Bing AppID mechanism is deprecated and is no longer supported.
As mentioned above, you must obtain an access token to use the
Microsoft Translator API. The access token is more secure, OAuth
standard compliant, and more flexible. Users who are using Bing AppID
are strongly recommended to get an access token as soon as possible.
.. note::
The value of access token can be used for subsequent calls to the
Microsoft Translator API. The access token expires after 10
minutes. It is always better to check elapsed time between time at
which token issued and current time. If elapsed time exceeds 10
minute time period renew access token by following obtaining
access token procedure.
:return: The access token to be used with subsequent requests
"""
args = {
'client_id': self.client_id,
'client_secret': self.client_secret,
'scope': self.scope,
'grant_type': self.grant_type
}
response = requests.post(
'https://datamarket.accesscontrol.windows.net/v2/OAuth2-13',
data=args
).json()
self.logger.debug(response)
if "error" in response:
raise TranslateApiException(
response.get('error_description', 'No Error Description'),
response.get('error', 'Unknown Error')
)
return response['access_token']
def call(self, path, params):
"""Calls the given path with the params urlencoded
:param path: The path of the API call being made
:param params: The parameters dictionary
"""
if not self.access_token:
self.access_token = self.get_access_token()
resp = requests.get(
"/".join([self.base_url, path]),
params=params,
headers={'Authorization': 'Bearer %s' % self.access_token}
)
resp.encoding = 'UTF-8-sig'
rv = resp.json()
if isinstance(rv, six.string_types) and \
rv.startswith("ArgumentOutOfRangeException"):
raise ArgumentOutOfRangeException(rv)
if isinstance(rv, six.string_types) and \
rv.startswith("TranslateApiException"):
raise TranslateApiException(rv)
if isinstance(rv, six.string_types) and \
rv.startswith(("ArgumentException: "
"The incoming token has expired")):
self.access_token = None
return self.call(path, params)
return rv
def translate(
self, text, to_lang, from_lang=None,
content_type='text/plain', category='general'):
"""Translates a text string from one language to another.
:param text: A string representing the text to translate.
:param to_lang: A string representing the language code to
translate the text into.
:param from_lang: A string representing the language code of the
translation text. If left None the response will include the
result of language auto-detection. (Default: None)
:param content_type: The format of the text being translated.
The supported formats are "text/plain" and "text/html". Any HTML
needs to be well-formed.
:param category: The category of the text to translate. The only
supported category is "general".
"""
params = {
'text': text.encode('utf8'),
'to': to_lang,
'contentType': content_type,
'category': category,
}
if from_lang is not None:
params['from'] = from_lang
return self.call("Translate", params)
def translate_array(self, texts, to_lang, from_lang=None, **options):
"""Translates an array of text strings from one language to another.
:param texts: A list containing texts for translation.
:param to_lang: A string representing the language code to
translate the text into.
:param from_lang: A string representing the language code of the
translation text. If left None the response will include the
result of language auto-detection. (Default: None)
:param options: A TranslateOptions element containing the values below.
They are all optional and default to the most common settings.
Category: A string containing the category (domain) of the
translation. Defaults to "general".
ContentType: The format of the text being translated. The
supported formats are "text/plain" and "text/html". Any
HTML needs to be well-formed.
Uri: A string containing the content location of this
translation.
User: A string used to track the originator of the submission.
State: User state to help correlate request and response. The
same contents will be returned in the response.
"""
options = {
'Category': "general",
'Contenttype': "text/plain",
'Uri': '',
'User': 'default',
'State': ''
}.update(options)
params = {
'texts': json.dumps(texts),
'to': to_lang,
'options': json.dumps(options),
}
if from_lang is not None:
params['from'] = from_lang
return self.call("TranslateArray", params)
def get_languages(self):
"""Fetches the languages supported by Microsoft Translator
Returns list of languages
"""
return self.call('GetLanguagesForTranslate', '')
def detect_language(self, text):
"""Detects language of given string
Returns two letter language - Example : fr
"""
params = {
'text': text.encode('utf8')
}
return self.call('Detect', params)