-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmicrosofttranslator.py
209 lines (176 loc) · 8.14 KB
/
microsofttranslator.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
# -*- 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
from simplejson import JSONDecodeError
except ImportError:
import json
class JSONDecodeError(Exception): pass
# Ugly: No alternative because this exception class doesnt seem to be there
# in the standard python module
import urllib
import urllib2
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)
"""
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 = urllib.urlencode({
'client_id': self.client_id,
'client_secret': self.client_secret,
'scope': self.scope,
'grant_type': self.grant_type
})
response = json.loads(urllib.urlopen(
'https://datamarket.accesscontrol.windows.net/v2/OAuth2-13', args
).read())
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, url, params):
"""Calls the given url with the params urlencoded
"""
if not self.access_token:
self.access_token = self.get_access_token()
request = urllib2.Request(
"%s?%s" % (url, urllib.urlencode(params)),
headers={'Authorization': 'Bearer %s' % self.access_token}
)
response = urllib2.urlopen(request).read()
rv = json.loads(response.decode("UTF-8-sig"))
if isinstance(rv, basestring) and \
rv.startswith("ArgumentOutOfRangeException"):
raise ArgumentOutOfRangeException(rv)
if isinstance(rv, basestring) and \
rv.startswith("TranslateApiException"):
raise TranslateApiException(rv)
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(
"http://api.microsofttranslator.com/V2/Ajax.svc/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(
"http://api.microsofttranslator.com/V2/Ajax.svc/TranslateArray",
params)