├── .coveragerc ├── .gitignore ├── .travis.yml ├── CHANGELOG ├── LICENSE ├── MANIFEST.in ├── README.rst ├── __init__.py ├── setup.cfg ├── setup.py └── test.py /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | source = microsofttranslator 3 | 4 | [report] 5 | omit = */tests/*, */fabfile.py 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | microsofttranslator.egg-info 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | sudo: false 3 | python: 4 | - "2.7" 5 | - "3.4" 6 | install: 7 | - pip install flake8 8 | - python setup.py install 9 | - pip install coveralls 10 | script: 11 | - coverage run setup.py test 12 | - flake8 . 13 | after_success: 14 | coveralls 15 | notifications: 16 | email: 17 | - ci-notify@fulfil.io 18 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | Version 0.9 5 | ----------- 6 | 7 | * Added support for version 3 of the API (Thanks to @newearthmartin) 8 | * Removed legacy code from version 1 and 2 9 | * This release is not backwards compatible: 10 | - Methods take now an array of texts instead a single text 11 | - API calls return more information in JSON format 12 | 13 | Version 0.8 14 | ----------- 15 | 16 | * Added support for version 2 of the API (Thanks to @flyinactor91) 17 | * Added new way of instantiating Translator using only Azure Translator Key (for V2) 18 | 19 | Version 0.7 20 | ----------- 21 | * Add support for language detection and finding supported languages (Thanks 22 | to Karthik Balakrishnan) 23 | 24 | Version 0.6 25 | ----------- 26 | * Handle token expiry (Thanks to @ScreenDriver) 27 | 28 | Version 0.4 29 | ----------- 30 | * Updated to use the Oauth based token issued by Bing 31 | * This release is not backward compatible as the class signature has changed 32 | 33 | Version 0.3 34 | ----------- 35 | * Encode text as UTF-8 before sending to translator 36 | * Improved JSON Error handling 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Fulfil.IO 2 | Copyright (c) 2011-2015, Openlabs Technologies & Consulting (P) Limited 3 | 4 | Some rights reserved. 5 | 6 | Redistribution and use in source and binary forms of the software as well 7 | as documentation, with or without modification, are permitted provided 8 | that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above 14 | copyright notice, this list of conditions and the following 15 | disclaimer in the documentation and/or other materials provided 16 | with the distribution. 17 | 18 | * The names of the contributors may not be used to endorse or 19 | promote products derived from this software without specific 20 | prior written permission. 21 | 22 | THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND 23 | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 24 | NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 26 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 29 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | DAMAGE. 34 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.rst 3 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Microsoft Translator V3 -- Python API 2 | ===================================== 3 | 4 | :Version: 0.9 5 | :Web: http://fulfil.io/ 6 | :keywords: Microsoft Translator 7 | :copyright: Fulfil.IO, Openlabs Technologies & Consulting (P) LTD 8 | :license: BSD 9 | 10 | .. image:: https://secure.travis-ci.org/fulfilio/Microsoft-Translator-Python-API.png?branch=master 11 | :target: http://travis-ci.org/#!/fulfilio/Microsoft-Translator-Python-API 12 | 13 | .. image:: https://coveralls.io/repos/fulfilio/Microsoft-Translator-Python-API/badge.png?branch=master 14 | :target: https://coveralls.io/r/fulfilio/Microsoft-Translator-Python-API 15 | 16 | 17 | This python API implements the Microsoft Translator services which can be used 18 | in web or client applications to perform language translation operations. The 19 | services support users who are not familiar with the default language of a page 20 | or application, or those desiring to communicate with people of a different 21 | language group. 22 | 23 | 24 | Create your Azure translation key 25 | --------------------------------- 26 | 27 | To sign up for Translator Text API, please follow instructions here 28 | https://docs.microsoft.com/en-us/azure/cognitive-services/translator/translator-text-how-to-signup 29 | 30 | Installing 31 | ---------- 32 | 33 | :: 34 | 35 | pip install microsofttranslator 36 | 37 | 38 | Features 39 | -------- 40 | 41 | 42 | Translation 43 | +++++++++++ 44 | 45 | :: 46 | 47 | >>> from microsofttranslator import Translator 48 | >>> translator = Translator('') 49 | >>> print translator.translate(['hello'], 'es') 50 | [['Hola']] 51 | 52 | 53 | Translate multiple phrases and multiple languages at once 54 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 55 | 56 | :: 57 | 58 | >>> from microsofttranslator import Translator 59 | >>> translator = Translator('') 60 | >>> print translator.translate(['hello', 'good bye'], 'de,it') 61 | [ 62 | ['Hallo', 'Ciao'], 63 | ['Auf Wiedersehen', 'Arrivederci'] 64 | ] 65 | 66 | Get supported languages 67 | +++++++++++++++++++++++ 68 | 69 | :: 70 | 71 | >>> from microsofttranslator import Translator 72 | >>> translator = Translator('') 73 | >>> print translator.get_languages() 74 | { 75 | ... 76 | 'en': {'nativeName': 'English', 'name': 'English', 'dir': 'ltr'}, 77 | 'es': {'nativeName': 'Espa\xf1ol', 'name': 'Spanish', 'dir': 'ltr'}, 78 | 'et': {'nativeName': 'Eesti', 'name': 'Estonian', 'dir': 'ltr'}, 79 | 'fa': {'nativeName': 'Persian', 'name': 'Persian', 'dir': 'rtl'}, 80 | 'fi': {'nativeName': 'Suomi', 'name': 'Finnish', 'dir': 'ltr'}, 81 | ... 82 | } 83 | 84 | Detect Language 85 | +++++++++++++++ 86 | 87 | :: 88 | 89 | >>> from microsofttranslator import Translator 90 | >>> translator = Translator('') 91 | >>> translator.detect_language('how are you?') 92 | { 93 | 'language': 'en', 94 | 'score': 1.0, 95 | 'isTranslationSupported': True, 96 | 'isTransliterationSupported': False, 97 | 'alternatives': [ 98 | {'score': 1.0, 'isTranslationSupported': True, 'isTransliterationSupported': False, 'language': 'ro'}, 99 | {'score': 1.0, 'isTranslationSupported': True, 'isTransliterationSupported': False, 'language': 'fil'} 100 | ] 101 | } 102 | 103 | 104 | 105 | Bugs and Development on Github 106 | ------------------------------ 107 | 108 | https://github.com/fulfilio/Microsoft-Translator-Python-API 109 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | __init__ 4 | A translator using the micrsoft translation engine documented here: 5 | https://docs.microsoft.com/en-us/azure/cognitive-services/translator/ 6 | """ 7 | 8 | __all__ = ['Translator', 'TranslatorException'] 9 | 10 | try: 11 | import simplejson as json 12 | except ImportError: 13 | import json 14 | 15 | import requests 16 | import logging 17 | from datetime import datetime, timedelta 18 | 19 | logger = logging.getLogger('microsofttranslator') 20 | 21 | class AzureAuthToken: 22 | """ Class to make sure that .value is always a valid 10-min auth token """ 23 | _token = None 24 | last_fetched = None 25 | 26 | def __init__(self, api_key): 27 | self.azure_api_key = api_key 28 | 29 | @property 30 | def value(self): 31 | """ The value of the current auth token """ 32 | if self._token is None or self.outdated: 33 | self.update() 34 | return self._token 35 | 36 | @property 37 | def outdated(self): 38 | """ Returns True if a new token value must be fetched """ 39 | return self.last_fetched is None or \ 40 | datetime.utcnow() > self.last_fetched+timedelta(minutes=9) 41 | 42 | def update(self): 43 | url = 'https://api.cognitive.microsoft.com/sts/v1.0/issueToken' 44 | headers = {'Ocp-Apim-Subscription-Key': self.azure_api_key} 45 | resp = requests.post(url, headers=headers) 46 | self._token = resp.text 47 | self.last_fetched = datetime.utcnow() 48 | 49 | class TranslatorException(Exception): 50 | def __init__(self, code, message, *args): 51 | self.code = code 52 | self.message = message 53 | super(TranslatorException, self).__init__('%d-%s' % (self.code, self.message), *args) 54 | 55 | class Translator(object): 56 | """ Implements the Azure Cognitive Services - Translator REST API """ 57 | 58 | base_url = 'https://api.cognitive.microsofttranslator.com' 59 | 60 | def __init__(self, client_key): 61 | self.auth_token = AzureAuthToken(client_key) 62 | 63 | def call(self, path, params, json=None): 64 | """ 65 | Calls the given path with the params urlencoded. 66 | Will be POST if json is defined, otherwise a GET. 67 | 68 | :param path: The path of the API call being made 69 | :param params: The parameters dictionary for the query string 70 | :param json: JSON data for POST body. 71 | """ 72 | params = params.copy() 73 | params.update({'api-version': '3.0'}) 74 | url = self.base_url + '/' + path 75 | 76 | headers = {'Authorization': 'Bearer %s' % self.auth_token.value} 77 | if json: 78 | query_params = map(lambda e: '%s=%s' % e, params.items()) 79 | url += '?' + '&'.join(query_params) 80 | resp = requests.post(url, json=json, headers=headers) 81 | else: 82 | resp = requests.get(url, params=params, headers=headers) 83 | resp.encoding = 'UTF-8-sig' 84 | rv = resp.json() 85 | 86 | if 'error' in rv: 87 | error = rv['error'] 88 | raise TranslatorException(error['code'], error['message']) 89 | 90 | return rv 91 | 92 | @staticmethod 93 | def texts_as_json(texts): 94 | return [{'Text': text.encode('utf8')} for text in texts] 95 | 96 | def get_languages(self): 97 | """ 98 | Fetches the languages supported by Microsoft Translator 99 | Returns list of languages 100 | """ 101 | return self.call('languages', {})['translation'] 102 | 103 | def translate( 104 | self, texts, 105 | to_lang, from_lang=None, 106 | text_type='plain', category='general'): 107 | """ 108 | Translates one or more text strings from one language to another. 109 | 110 | :param texts: 111 | A string array representing the texts to translate. 112 | :param to_lang: 113 | A string representing the language code to translate the text into. 114 | Can be many languages separated by comma. 115 | :param from_lang: 116 | A string representing the language code of the translation text. 117 | If left None the response will include 118 | the result of language auto-detection. (Default: None) 119 | :param text_type: 120 | The format of the text being translated. 121 | The supported formats are "plain" and "html". 122 | Any HTML needs to be well-formed. 123 | :param category: 124 | The category of the text to translate. 125 | The only supported category is "general". 126 | """ 127 | params = { 128 | 'to': to_lang, 129 | 'textType': text_type, 130 | 'category': category, 131 | } 132 | if from_lang: params['from'] = from_lang 133 | translated = self.call('translate', params, json=Translator.texts_as_json(texts)) 134 | translated = [[inner['text'] for inner in outer['translations']] for outer in translated] 135 | return translated 136 | 137 | def detect_language(self, texts): 138 | """ 139 | Detects language of given string 140 | Returns two letter language - Example : fr 141 | :param texts: A string array representing the texts to detect language. 142 | """ 143 | return self.call('detect', {}, json=Translator.texts_as_json(texts)) 144 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | exclude=.svn,CVS,.bzr,.hg,.git,__pycache__,build,dist,upload.py,doc,scripts,*.egg 3 | max-complexity=15 4 | max-line-length=80 5 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Microsoft translator API 4 | 5 | The Microsoft Translator services can be used in web or client 6 | applications to perform language translation operations. The services 7 | support users who are not familiar with the default language of a page or 8 | application, or those desiring to communicate with people of a different 9 | language group. 10 | 11 | This module implements the AJAX API for the Microsoft Translator service. 12 | 13 | An example:: 14 | 15 | >>> from microsofttranslator import Translator 16 | >>> translator = Translator('') 17 | >>> print translator.translate('Hello', 'pt') 18 | [['Olá']] 19 | 20 | The documentation for the service can be obtained here: 21 | https://docs.microsoft.com/en-us/azure/cognitive-services/translator/ 22 | 23 | The project is hosted on GitHub where your could fork the project or report 24 | issues. Visit https://github.com/fulfilio/Microsoft-Translator-Python-API 25 | """ 26 | 27 | import codecs 28 | from setuptools import setup 29 | 30 | setup( 31 | name='microsofttranslator', 32 | version='0.9', 33 | packages=[ 34 | 'microsofttranslator', 35 | ], 36 | package_dir={ 37 | 'microsofttranslator': '.' 38 | }, 39 | author='Fulfil.IO Inc., Openlabs Technologies & Consulting (P) Limited', 40 | author_email='info@fulfil.io', 41 | description='Microsoft Translator V3 - Python API', 42 | long_description=codecs.open( 43 | 'README.rst', encoding='UTF-8' 44 | ).read(), 45 | license='BSD', 46 | keywords='translation microsoft', 47 | url='https://www.fulfil.io/', 48 | include_package_data=True, 49 | classifiers=[ 50 | 'Development Status :: 5 - Production/Stable', 51 | 'Intended Audience :: Developers', 52 | 'License :: OSI Approved :: BSD License', 53 | 'Natural Language :: English', 54 | 'Operating System :: OS Independent', 55 | 'Topic :: Software Development :: Internationalization', 56 | 'Topic :: Utilities', 57 | 'Programming Language :: Python :: 3', 58 | 'Programming Language :: Python :: 2', 59 | ], 60 | test_suite='microsofttranslator.test.test_all', 61 | install_requires=[ 62 | 'requests >= 1.2.3', 63 | 'six', 64 | ] 65 | ) 66 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | test 4 | Test the translator 5 | """ 6 | import os 7 | import unittest 8 | from . import Translator, TranslatorException 9 | 10 | azure_translator_key = os.environ['AZURE_TRANSLATOR_KEY'] 11 | 12 | default_languages = ['en', 'fr', 'de'] 13 | 14 | class TestTranslator(unittest.TestCase): 15 | def test_translate(self): 16 | client = Translator(azure_translator_key) 17 | translated = client.translate(['hello', 'how are you?'], 'pt,fr') 18 | self.assertEqual(translated, [ 19 | [u'Ol\xe1', u'Bonjour'], 20 | [u'Como est\xe1?', u'Comment vas-tu?'], 21 | ]) 22 | 23 | def test_invalid_translator_key(self): 24 | client = Translator('invalid_translator_key') 25 | with self.assertRaises(TranslatorException): 26 | client.translate(['hello'], 'pt') 27 | 28 | def test_invalid_language(self): 29 | client = Translator(azure_translator_key) 30 | with self.assertRaises(TranslatorException): 31 | client.translate(['hello'], 'abcd') 32 | 33 | def test_get_languages(self): 34 | client = Translator(azure_translator_key) 35 | languages = client.get_languages() 36 | for language in default_languages: 37 | self.assertIn(language, languages) 38 | 39 | def test_detect_language(self): 40 | client = Translator(azure_translator_key) 41 | detected_language = client.detect_language(['how are you?'])[0] 42 | self.assertEqual(detected_language['language'], 'en') 43 | 44 | def test_all(): 45 | loader = unittest.TestLoader() 46 | suite = unittest.TestSuite() 47 | suite.addTests(loader.loadTestsFromTestCase(TestTranslator)) 48 | return suite 49 | 50 | 51 | if __name__ == '__main__': 52 | unittest.main() 53 | --------------------------------------------------------------------------------