1010 :license: BSD, see LICENSE for more details.
1111"""
1212
13- __all__ = ['Translator' ]
13+ __all__ = ['Translator' , 'TranslateApiException' ]
1414
1515try :
1616 import simplejson as json
@@ -21,38 +21,111 @@ class JSONDecodeError(Exception): pass
2121 # Ugly: No alternative because this exception class doesnt seem to be there
2222 # in the standard python module
2323import urllib
24+ import urllib2
25+ import warnings
26+ import logging
2427
2528
26- class ArgumentOutOfRangeException (Exception ):
29+ class ArgumentOutOfRangeException (Exception ):
2730 def __init__ (self , message ):
2831 self .message = message .replace ('ArgumentOutOfRangeException: ' , '' )
2932 super (ArgumentOutOfRangeException , self ).__init__ (self .message )
3033
3134
3235class TranslateApiException (Exception ):
33- def __init__ (self , message ):
36+ def __init__ (self , message , * args ):
3437 self .message = message .replace ('TranslateApiException: ' , '' )
35- super (TranslateApiException , self ).__init__ (self .message )
38+ super (TranslateApiException , self ).__init__ (self .message , * args )
3639
3740
3841class Translator (object ):
3942 """Implements AJAX API for the Microsoft Translator service
4043
41- :param app_id: A string containing the Bing AppID.
44+ :param app_id: A string containing the Bing AppID. (Deprecated)
4245 """
4346
44- def __init__ (self , app_id ):
47+ def __init__ (self , client_id , client_secret ,
48+ scope = "http://api.microsofttranslator.com" ,
49+ grant_type = "client_credentials" , app_id = None , debug = False ):
50+ """
51+
52+
53+ :param client_id: The client ID that you specified when you registered
54+ your application with Azure DataMarket.
55+ :param client_secret: The client secret value that you obtained when
56+ you registered your application with Azure
57+ DataMarket.
58+ :param scope: Defaults to http://api.microsofttranslator.com
59+ ;param grant_type: Defaults to "client_credentials"
60+ :param app_id: Deprecated
61+ :param debug: If true, the logging level will be set to debug
62+
63+ .. versionchanged: 0.4
64+ Bing AppID mechanism is deprecated and is no longer supported.
65+ See: http://msdn.microsoft.com/en-us/library/hh454950
4566 """
46- :param app_id: A string containing the Bing AppID.
67+ if app_id is not None :
68+ warnings .warn ("""app_id is deprected since v0.4.
69+ See: http://msdn.microsoft.com/en-us/library/hh454950
70+ """ , DeprecationWarning , stacklevel = 2 )
71+
72+ self .client_id = client_id
73+ self .client_secret = client_secret
74+ self .scope = scope
75+ self .grant_type = grant_type
76+ self .access_token = None
77+ self .debug = debug
78+ self .logger = logging .getLogger ("microsofttranslator" )
79+ if self .debug :
80+ self .logger .setLevel (level = logging .DEBUG )
81+
82+ def get_access_token (self ):
83+ """Bing AppID mechanism is deprecated and is no longer supported.
84+ As mentioned above, you must obtain an access token to use the
85+ Microsoft Translator API. The access token is more secure, OAuth
86+ standard compliant, and more flexible. Users who are using Bing AppID
87+ are strongly recommended to get an access token as soon as possible.
88+
89+ .. note::
90+ The value of access token can be used for subsequent calls to the
91+ Microsoft Translator API. The access token expires after 10
92+ minutes. It is always better to check elapsed time between time at
93+ which token issued and current time. If elapsed time exceeds 10
94+ minute time period renew access token by following obtaining
95+ access token procedure.
96+
97+ :return: The access token to be used with subsequent requests
4798 """
48- self .app_id = app_id
99+ args = urllib .urlencode ({
100+ 'client_id' : self .client_id ,
101+ 'client_secret' : self .client_secret ,
102+ 'scope' : self .scope ,
103+ 'grant_type' : self .grant_type
104+ })
105+ response = json .loads (urllib .urlopen (
106+ 'https://datamarket.accesscontrol.windows.net/v2/OAuth2-13' , args
107+ ).read ())
108+
109+ self .logger .debug (response )
110+
111+ if "error" in response :
112+ raise TranslateApiException (
113+ response .get ('error_description' , 'No Error Description' ),
114+ response .get ('error' , 'Unknown Error' )
115+ )
116+ return response ['access_token' ]
49117
50118 def call (self , url , params ):
51119 """Calls the given url with the params urlencoded
52120 """
53- params ['appId' ] = self .app_id
54- response = urllib .urlopen (
55- "%s?%s" % (url , urllib .urlencode (params ))).read ()
121+ if not self .access_token :
122+ self .access_token = self .get_access_token ()
123+
124+ request = urllib2 .Request (
125+ "%s?%s" % (url , urllib .urlencode (params )),
126+ headers = {'Authorization' : 'Bearer %s' % self .access_token }
127+ )
128+ response = urllib2 .urlopen (request ).read ()
56129 rv = json .loads (response .decode ("UTF-8-sig" ))
57130
58131 if isinstance (rv , basestring ) and \
@@ -65,20 +138,20 @@ def call(self, url, params):
65138
66139 return rv
67140
68- def translate (self , text , to_lang , from_lang = None ,
141+ def translate (self , text , to_lang , from_lang = None ,
69142 content_type = 'text/plain' , category = 'general' ):
70143 """Translates a text string from one language to another.
71144
72145 :param text: A string representing the text to translate.
73- :param to_lang: A string representing the language code to
146+ :param to_lang: A string representing the language code to
74147 translate the text into.
75- :param from_lang: A string representing the language code of the
76- translation text. If left None the response will include the
148+ :param from_lang: A string representing the language code of the
149+ translation text. If left None the response will include the
77150 result of language auto-detection. (Default: None)
78- :param content_type: The format of the text being translated.
79- The supported formats are "text/plain" and "text/html". Any HTML
151+ :param content_type: The format of the text being translated.
152+ The supported formats are "text/plain" and "text/html". Any HTML
80153 needs to be well-formed.
81- :param category: The category of the text to translate. The only
154+ :param category: The category of the text to translate. The only
82155 supported category is "general".
83156 """
84157 params = {
0 commit comments