=
commited on
Commit
·
c006992
1
Parent(s):
379334a
added support for yandex
Browse files- README.rst +29 -0
- deep_translator/__init__.py +2 -0
- deep_translator/constants.py +1 -1
- deep_translator/exceptions.py +27 -2
- deep_translator/yandex.py +103 -0
- docs/usage.rst +27 -0
README.rst
CHANGED
|
@@ -91,6 +91,7 @@ Features
|
|
| 91 |
* Support for `Pons translator <https://de.pons.com//>`_
|
| 92 |
* Support for the `Linguee translator <https://www.linguee.com//>`_
|
| 93 |
* Support for the `Mymemory translator <https://mymemory.translated.net//>`_
|
|
|
|
| 94 |
* Automatic single language detection
|
| 95 |
* Batch language detection
|
| 96 |
* Translate directly from a text file
|
|
@@ -149,6 +150,7 @@ Imports
|
|
| 149 |
PonsTranslator,
|
| 150 |
LingueeTranslator,
|
| 151 |
MyMemoryTranslator,
|
|
|
|
| 152 |
single_detection,
|
| 153 |
batch_detection)
|
| 154 |
|
|
@@ -331,6 +333,33 @@ PONS Translator
|
|
| 331 |
|
| 332 |
translated_words = LingueeTranslator(source='english', target='french').translate_words(["good", "awesome"])
|
| 333 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 334 |
Usage from Terminal
|
| 335 |
--------------------
|
| 336 |
|
|
|
|
| 91 |
* Support for `Pons translator <https://de.pons.com//>`_
|
| 92 |
* Support for the `Linguee translator <https://www.linguee.com//>`_
|
| 93 |
* Support for the `Mymemory translator <https://mymemory.translated.net//>`_
|
| 94 |
+
* Support for the `Yandex translator <https://yandex.com/>`_ (version >= 1.2.1)
|
| 95 |
* Automatic single language detection
|
| 96 |
* Batch language detection
|
| 97 |
* Translate directly from a text file
|
|
|
|
| 150 |
PonsTranslator,
|
| 151 |
LingueeTranslator,
|
| 152 |
MyMemoryTranslator,
|
| 153 |
+
YandexTranslator
|
| 154 |
single_detection,
|
| 155 |
batch_detection)
|
| 156 |
|
|
|
|
| 333 |
|
| 334 |
translated_words = LingueeTranslator(source='english', target='french').translate_words(["good", "awesome"])
|
| 335 |
|
| 336 |
+
Yandex Translator
|
| 337 |
+
----------------
|
| 338 |
+
|
| 339 |
+
.. note::
|
| 340 |
+
|
| 341 |
+
You need to require an private api key if you want to use the yandex translator.
|
| 342 |
+
visit the official website for more information about how to get one
|
| 343 |
+
|
| 344 |
+
- Language detection
|
| 345 |
+
|
| 346 |
+
.. code-block:: python
|
| 347 |
+
|
| 348 |
+
lang = YandexTranslator('your_api_key').detect('Hallo, Welt')
|
| 349 |
+
print(f"language detected: {lang}") # output -> language detected: 'de'
|
| 350 |
+
|
| 351 |
+
- Text translation
|
| 352 |
+
|
| 353 |
+
.. code-block:: python
|
| 354 |
+
|
| 355 |
+
# with auto detection | meaning provide only the target language and let yandex detect the source
|
| 356 |
+
translated = YandexTranslator('your_api_key').translate('Hallo, Welt', 'en')
|
| 357 |
+
print(f"translated text: {translated}") # output -> translated text: Hello world
|
| 358 |
+
|
| 359 |
+
# provide source and target language explicitly
|
| 360 |
+
translated = YandexTranslator('your_api_key').translate('Hallo, Welt', 'de-en')
|
| 361 |
+
print(f"translated text: {translated}") # output -> translated text: Hello world
|
| 362 |
+
|
| 363 |
Usage from Terminal
|
| 364 |
--------------------
|
| 365 |
|
deep_translator/__init__.py
CHANGED
|
@@ -4,6 +4,7 @@ from .google_trans import GoogleTranslator
|
|
| 4 |
from .pons import PonsTranslator
|
| 5 |
from .linguee import LingueeTranslator
|
| 6 |
from .mymemory import MyMemoryTranslator
|
|
|
|
| 7 |
from .detection import single_detection, batch_detection
|
| 8 |
|
| 9 |
|
|
@@ -15,5 +16,6 @@ __all__ = [GoogleTranslator,
|
|
| 15 |
PonsTranslator,
|
| 16 |
LingueeTranslator,
|
| 17 |
MyMemoryTranslator,
|
|
|
|
| 18 |
single_detection,
|
| 19 |
batch_detection]
|
|
|
|
| 4 |
from .pons import PonsTranslator
|
| 5 |
from .linguee import LingueeTranslator
|
| 6 |
from .mymemory import MyMemoryTranslator
|
| 7 |
+
from .yandex import YandexTranslator
|
| 8 |
from .detection import single_detection, batch_detection
|
| 9 |
|
| 10 |
|
|
|
|
| 16 |
PonsTranslator,
|
| 17 |
LingueeTranslator,
|
| 18 |
MyMemoryTranslator,
|
| 19 |
+
YandexTranslator,
|
| 20 |
single_detection,
|
| 21 |
batch_detection]
|
deep_translator/constants.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
| 3 |
BASE_URLS = {
|
| 4 |
"GOOGLE_TRANSLATE": "https://translate.google.com/m",
|
| 5 |
"PONS": "https://en.pons.com/translate/",
|
| 6 |
-
"YANDEX": "https://translate.yandex.
|
| 7 |
"LINGUEE": "https://www.linguee.com/",
|
| 8 |
"MYMEMORY": "http://api.mymemory.translated.net/get"
|
| 9 |
}
|
|
|
|
| 3 |
BASE_URLS = {
|
| 4 |
"GOOGLE_TRANSLATE": "https://translate.google.com/m",
|
| 5 |
"PONS": "https://en.pons.com/translate/",
|
| 6 |
+
"YANDEX": "https://translate.yandex.net/api/{version}/tr.json/{endpoint}",
|
| 7 |
"LINGUEE": "https://www.linguee.com/",
|
| 8 |
"MYMEMORY": "http://api.mymemory.translated.net/get"
|
| 9 |
}
|
deep_translator/exceptions.py
CHANGED
|
@@ -1,9 +1,8 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
class BaseError(Exception):
|
| 4 |
"""
|
| 5 |
base error structure class
|
| 6 |
"""
|
|
|
|
| 7 |
def __init__(self, val, message):
|
| 8 |
"""
|
| 9 |
@param val: actual value
|
|
@@ -21,6 +20,7 @@ class LanguageNotSupportedException(BaseError):
|
|
| 21 |
"""
|
| 22 |
exception thrown if the user uses a language that is not supported by the deep_translator
|
| 23 |
"""
|
|
|
|
| 24 |
def __init__(self, val, message="There is no support for the chosen language"):
|
| 25 |
super().__init__(val, message)
|
| 26 |
|
|
@@ -29,6 +29,7 @@ class NotValidPayload(BaseError):
|
|
| 29 |
"""
|
| 30 |
exception thrown if the user enters an invalid payload
|
| 31 |
"""
|
|
|
|
| 32 |
def __init__(self,
|
| 33 |
val,
|
| 34 |
message='text must be a valid text with maximum 5000 character, otherwise it cannot be translated'):
|
|
@@ -39,6 +40,7 @@ class TranslationNotFound(BaseError):
|
|
| 39 |
"""
|
| 40 |
exception thrown if no translation was found for the text provided by the user
|
| 41 |
"""
|
|
|
|
| 42 |
def __init__(self,
|
| 43 |
val,
|
| 44 |
message='No translation was found using the current translator. Try another translator?'):
|
|
@@ -49,6 +51,7 @@ class ElementNotFoundInGetRequest(BaseError):
|
|
| 49 |
"""
|
| 50 |
exception thrown if the html element was not found in the body parsed by beautifulsoup
|
| 51 |
"""
|
|
|
|
| 52 |
def __init__(self,
|
| 53 |
val,
|
| 54 |
message='Required element was not found in the API response'):
|
|
@@ -59,6 +62,7 @@ class NotValidLength(BaseError):
|
|
| 59 |
"""
|
| 60 |
exception thrown if the provided text exceed the length limit of the translator
|
| 61 |
"""
|
|
|
|
| 62 |
def __init__(self, val, min_chars, max_chars):
|
| 63 |
message = "Text length need to be between {} and {} characters".format(min_chars, max_chars)
|
| 64 |
super(NotValidLength, self).__init__(val, message)
|
|
@@ -68,9 +72,30 @@ class RequestError(Exception):
|
|
| 68 |
"""
|
| 69 |
exception thrown if an error occured during the request call, e.g a connection problem.
|
| 70 |
"""
|
|
|
|
| 71 |
def __init__(self, message="Request exception can happen due to an api connection error. "
|
| 72 |
"Please check your connection and try again"):
|
| 73 |
self.message = message
|
| 74 |
|
| 75 |
def __str__(self):
|
| 76 |
return self.message
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
class BaseError(Exception):
|
| 2 |
"""
|
| 3 |
base error structure class
|
| 4 |
"""
|
| 5 |
+
|
| 6 |
def __init__(self, val, message):
|
| 7 |
"""
|
| 8 |
@param val: actual value
|
|
|
|
| 20 |
"""
|
| 21 |
exception thrown if the user uses a language that is not supported by the deep_translator
|
| 22 |
"""
|
| 23 |
+
|
| 24 |
def __init__(self, val, message="There is no support for the chosen language"):
|
| 25 |
super().__init__(val, message)
|
| 26 |
|
|
|
|
| 29 |
"""
|
| 30 |
exception thrown if the user enters an invalid payload
|
| 31 |
"""
|
| 32 |
+
|
| 33 |
def __init__(self,
|
| 34 |
val,
|
| 35 |
message='text must be a valid text with maximum 5000 character, otherwise it cannot be translated'):
|
|
|
|
| 40 |
"""
|
| 41 |
exception thrown if no translation was found for the text provided by the user
|
| 42 |
"""
|
| 43 |
+
|
| 44 |
def __init__(self,
|
| 45 |
val,
|
| 46 |
message='No translation was found using the current translator. Try another translator?'):
|
|
|
|
| 51 |
"""
|
| 52 |
exception thrown if the html element was not found in the body parsed by beautifulsoup
|
| 53 |
"""
|
| 54 |
+
|
| 55 |
def __init__(self,
|
| 56 |
val,
|
| 57 |
message='Required element was not found in the API response'):
|
|
|
|
| 62 |
"""
|
| 63 |
exception thrown if the provided text exceed the length limit of the translator
|
| 64 |
"""
|
| 65 |
+
|
| 66 |
def __init__(self, val, min_chars, max_chars):
|
| 67 |
message = "Text length need to be between {} and {} characters".format(min_chars, max_chars)
|
| 68 |
super(NotValidLength, self).__init__(val, message)
|
|
|
|
| 72 |
"""
|
| 73 |
exception thrown if an error occured during the request call, e.g a connection problem.
|
| 74 |
"""
|
| 75 |
+
|
| 76 |
def __init__(self, message="Request exception can happen due to an api connection error. "
|
| 77 |
"Please check your connection and try again"):
|
| 78 |
self.message = message
|
| 79 |
|
| 80 |
def __str__(self):
|
| 81 |
return self.message
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
class YandexDefaultException(Exception):
|
| 85 |
+
"""
|
| 86 |
+
Default YandexTranslate exception from the official website
|
| 87 |
+
"""
|
| 88 |
+
errors = {
|
| 89 |
+
401: "ERR_KEY_INVALID",
|
| 90 |
+
402: "ERR_KEY_BLOCKED",
|
| 91 |
+
403: "ERR_DAILY_REQ_LIMIT_EXCEEDED",
|
| 92 |
+
404: "ERR_DAILY_CHAR_LIMIT_EXCEEDED",
|
| 93 |
+
413: "ERR_TEXT_TOO_LONG",
|
| 94 |
+
422: "ERR_UNPROCESSABLE_TEXT",
|
| 95 |
+
501: "ERR_LANG_NOT_SUPPORTED",
|
| 96 |
+
503: "ERR_SERVICE_NOT_AVAIBLE",
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
def __init__(self, status_code, *args):
|
| 100 |
+
message = self.errors.get(status_code)
|
| 101 |
+
super(YandexDefaultException, self).__init__(message, *args)
|
deep_translator/yandex.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Yandex translator API
|
| 3 |
+
"""
|
| 4 |
+
import requests
|
| 5 |
+
from requests import exceptions
|
| 6 |
+
from deep_translator.constants import BASE_URLS
|
| 7 |
+
from deep_translator.exceptions import (RequestError,
|
| 8 |
+
YandexDefaultException, TranslationNotFound)
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class YandexTranslator(object):
|
| 12 |
+
"""
|
| 13 |
+
class that wraps functions, which use the yandex translator under the hood to translate word(s)
|
| 14 |
+
"""
|
| 15 |
+
|
| 16 |
+
def __init__(self, api_key=None):
|
| 17 |
+
"""
|
| 18 |
+
@param api_key: your yandex api key
|
| 19 |
+
"""
|
| 20 |
+
if not api_key:
|
| 21 |
+
raise YandexDefaultException(401)
|
| 22 |
+
self.__base_url = BASE_URLS.get("YANDEX")
|
| 23 |
+
|
| 24 |
+
self.api_key = api_key
|
| 25 |
+
self.api_version = "v1.5"
|
| 26 |
+
self.api_endpoints = {
|
| 27 |
+
"langs": "getLangs",
|
| 28 |
+
"detect": "detect",
|
| 29 |
+
"translate": "translate",
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
def get_supported_languages(self):
|
| 33 |
+
return set(x.split("-")[0] for x in self.dirs)
|
| 34 |
+
|
| 35 |
+
@property
|
| 36 |
+
def languages(self):
|
| 37 |
+
return self.get_supported_languages()
|
| 38 |
+
|
| 39 |
+
@property
|
| 40 |
+
def dirs(self, proxies=None):
|
| 41 |
+
|
| 42 |
+
try:
|
| 43 |
+
url = self.__base_url.format(version=self.api_version, endpoint="getLangs")
|
| 44 |
+
print("url: ", url)
|
| 45 |
+
response = requests.get(url, params={"key": self.api_key}, proxies=proxies)
|
| 46 |
+
except requests.exceptions.ConnectionError:
|
| 47 |
+
raise YandexDefaultException(503)
|
| 48 |
+
else:
|
| 49 |
+
data = response.json()
|
| 50 |
+
|
| 51 |
+
if response.status_code != 200:
|
| 52 |
+
raise YandexDefaultException(response.status_code)
|
| 53 |
+
return data.get("dirs")
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def detect(self, text, proxies=None):
|
| 57 |
+
response = None
|
| 58 |
+
params = {
|
| 59 |
+
"text": text,
|
| 60 |
+
"format": "plain",
|
| 61 |
+
"key": self.api_key,
|
| 62 |
+
}
|
| 63 |
+
try:
|
| 64 |
+
url = self.__base_url.format(version=self.api_version, endpoint="detect")
|
| 65 |
+
response = requests.post(url, data=params, proxies=proxies)
|
| 66 |
+
|
| 67 |
+
except RequestError:
|
| 68 |
+
raise
|
| 69 |
+
except ConnectionError:
|
| 70 |
+
raise YandexDefaultException(503)
|
| 71 |
+
except ValueError:
|
| 72 |
+
raise YandexDefaultException(response.status_code)
|
| 73 |
+
else:
|
| 74 |
+
response = response.json()
|
| 75 |
+
language = response['lang']
|
| 76 |
+
status_code = response['code']
|
| 77 |
+
if status_code != 200:
|
| 78 |
+
raise RequestError()
|
| 79 |
+
elif not language:
|
| 80 |
+
raise YandexDefaultException(501)
|
| 81 |
+
return language
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def translate(self, text, lang, proxies=None):
|
| 85 |
+
params = {
|
| 86 |
+
"text": text,
|
| 87 |
+
"format": "plain",
|
| 88 |
+
"lang": lang,
|
| 89 |
+
"key": self.api_key
|
| 90 |
+
}
|
| 91 |
+
try:
|
| 92 |
+
url = self.__base_url.format(version=self.api_version, endpoint="translate")
|
| 93 |
+
response = requests.post(url, data=params, proxies=proxies)
|
| 94 |
+
except ConnectionError:
|
| 95 |
+
raise YandexDefaultException(503)
|
| 96 |
+
else:
|
| 97 |
+
response = response.json()
|
| 98 |
+
if response['code'] != 200:
|
| 99 |
+
raise YandexDefaultException(response['code'])
|
| 100 |
+
if not response['text']:
|
| 101 |
+
raise TranslationNotFound()
|
| 102 |
+
|
| 103 |
+
return response['text']
|
docs/usage.rst
CHANGED
|
@@ -204,6 +204,33 @@ PONS Translator
|
|
| 204 |
|
| 205 |
translated_words = LingueeTranslator(source='english', target='french').translate_words(["good", "awesome"])
|
| 206 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 207 |
Usage from Terminal
|
| 208 |
--------------------
|
| 209 |
|
|
|
|
| 204 |
|
| 205 |
translated_words = LingueeTranslator(source='english', target='french').translate_words(["good", "awesome"])
|
| 206 |
|
| 207 |
+
Yandex Translator
|
| 208 |
+
----------------
|
| 209 |
+
|
| 210 |
+
.. note::
|
| 211 |
+
|
| 212 |
+
You need to require an private api key if you want to use the yandex translator.
|
| 213 |
+
visit the official website for more information about how to get one
|
| 214 |
+
|
| 215 |
+
- Language detection
|
| 216 |
+
|
| 217 |
+
.. code-block:: python
|
| 218 |
+
|
| 219 |
+
lang = YandexTranslator('your_api_key').detect('Hallo, Welt')
|
| 220 |
+
print(f"language detected: {lang}") # output -> language detected: 'de'
|
| 221 |
+
|
| 222 |
+
- Text translation
|
| 223 |
+
|
| 224 |
+
.. code-block:: python
|
| 225 |
+
|
| 226 |
+
# with auto detection | meaning provide only the target language and let yandex detect the source
|
| 227 |
+
translated = YandexTranslator('your_api_key').translate('Hallo, Welt', 'en')
|
| 228 |
+
print(f"translated text: {translated}") # output -> translated text: Hello world
|
| 229 |
+
|
| 230 |
+
# provide source and target language explicitly
|
| 231 |
+
translated = YandexTranslator('your_api_key').translate('Hallo, Welt', 'de-en')
|
| 232 |
+
print(f"translated text: {translated}") # output -> translated text: Hello world
|
| 233 |
+
|
| 234 |
Usage from Terminal
|
| 235 |
--------------------
|
| 236 |
|