Kirill
added microsoft.py for microsoft translator and updated constants.py and exceptions.py for microsoft translator
8d368b7
| # -*- coding: utf-8 -*- | |
| import requests | |
| # import uuid | |
| import logging | |
| import sys | |
| from deep_translator.constants import BASE_URLS, MICROSOFT_CODES_TO_LANGUAGES | |
| from deep_translator.exceptions import LanguageNotSupportedException, ServerException, MicrosoftAPIerror | |
| class MicrosoftTranslator: | |
| """ | |
| the class that wraps functions, which use the Microsoft translator under the hood to translate word(s) | |
| """ | |
| _languages = MICROSOFT_CODES_TO_LANGUAGES | |
| supported_languages = list(_languages.values()) | |
| def __init__(self, api_key=None, region=None, source=None, target=None, **kwargs): | |
| """ | |
| @params api_key and target are the required params | |
| @param api_key: your Microsoft API key | |
| @param region: your Microsoft Location | |
| """ | |
| if not api_key: | |
| raise ServerException(401) | |
| else: | |
| self.api_key = api_key | |
| self.headers = { | |
| "Ocp-Apim-Subscription-Key": self.api_key, | |
| "Content-type": "application/json", | |
| } | |
| # region is not required but very common and goes to headers if passed | |
| if region: | |
| self.region = region | |
| self.headers["Ocp-Apim-Subscription-Region"] = self.region | |
| if not target: | |
| raise ServerException(401) | |
| else: | |
| if type(target) is str: | |
| self.target = target.lower() | |
| else: | |
| self.target = [i.lower() for i in target] | |
| if self.is_language_supported(self.target): | |
| self.target = self._map_language_to_code(self.target) | |
| self.url_params = {'to': self.target, **kwargs} | |
| if source: | |
| self.source = source.lower() | |
| if self.is_language_supported(self.source): | |
| self.source = self._map_language_to_code(self.source) | |
| self.url_params['from'] = self.source | |
| self.__base_url = BASE_URLS.get("MICROSOFT_TRANSLATE") | |
| def get_supported_languages(as_dict=False): | |
| """ | |
| return the languages supported by the microsoft translator | |
| @param as_dict: if True, the languages will be returned as a dictionary mapping languages to their abbreviations | |
| @return: list or dict | |
| """ | |
| return MicrosoftTranslator.supported_languages if not as_dict else MicrosoftTranslator._languages | |
| def _map_language_to_code(self, language): | |
| """ | |
| map the language to its corresponding code (abbreviation) if the language was passed by its full name by the user | |
| @param languages: a string (if 1 lang) or a list (if multiple langs) | |
| @return: mapped value of the language or raise an exception if the language is not supported | |
| """ | |
| if type(language) is str: | |
| language = [language] | |
| for lang in language: | |
| if lang in self._languages.values(): | |
| yield lang | |
| elif lang in self._languages.keys(): | |
| yield self._languages[lang] | |
| else: | |
| raise LanguageNotSupportedException(lang) | |
| def is_language_supported(self, language): | |
| """ | |
| check if the language is supported by the translator | |
| @param languages: a string (if 1 lang) or a list (if multiple langs) | |
| @return: bool or raise an Exception | |
| """ | |
| if type(language) is str: | |
| language = [language] | |
| for lang in language: | |
| if lang not in self._languages.keys(): | |
| if lang not in self._languages.values(): | |
| raise LanguageNotSupportedException(lang) | |
| return True | |
| def translate(self, text): | |
| """ | |
| function that uses microsoft translate to translate a text | |
| @param text: desired text to translate | |
| @return: str: translated text | |
| """ | |
| # a body must be a list of dicts to process multiple texts; | |
| # I have not added multiple text processing here since it is covered by the translate_batch method | |
| valid_microsoft_json = [{'text': text}] | |
| try: | |
| requested = requests.post(self.__base_url, params=self.url_params, headers=self.headers, json=valid_microsoft_json) | |
| except requests.exceptions.RequestException: | |
| exc_type, value, traceback = sys.exc_info() | |
| logging.warning(f"Returned error: {exc_type.__name__}") | |
| # Where Microsoft API responds with an api error, it returns a dict in response.json() | |
| if type(requested.json()) is dict: | |
| error_message = requested.json()['error'] | |
| raise MicrosoftAPIerror(error_message) | |
| # Where it responds with a translation, its response.json() is a list e.g. [{'translations': [{'text': 'Hello world!', 'to': 'en'}]}] | |
| elif type(requested.json()) is list: | |
| all_translations = [i['text'] for i in requested.json()[0]['translations']] | |
| return "\n".join(all_translations) | |
| def translate_file(self, path): | |
| """ | |
| translate from a file | |
| @param path: path to file | |
| @return: translated text | |
| """ | |
| try: | |
| with open(path) as f: | |
| text = f.read() | |
| return self.translate(text) | |
| except Exception as e: | |
| raise e | |
| def translate_batch(self, batch): | |
| """ | |
| translate a batch of texts | |
| @param batch: list of texts to translate | |
| @return: list of translations | |
| """ | |
| return [self.translate(text) for text in batch] | |