Merge branch 'master' into feature/tencent
Browse files- deep_translator/__init__.py +2 -0
- deep_translator/baidu.py +120 -0
- deep_translator/constants.py +359 -0
- deep_translator/deepl.py +2 -2
- deep_translator/exceptions.py +13 -0
- deep_translator/google.py +3 -3
- deep_translator/libre.py +2 -2
- deep_translator/linguee.py +3 -2
- deep_translator/mymemory.py +4 -3
- deep_translator/papago.py +2 -2
- deep_translator/pons.py +2 -2
- deep_translator/qcri.py +2 -1
- deep_translator/validate.py +20 -3
- deep_translator/yandex.py +2 -2
- docs/README.rst +60 -0
- pyproject.toml +1 -1
- tests/test_baidu.py +65 -0
- tests/test_google.py +0 -8
- tests/test_libre.py +0 -3
- tests/test_linguee.py +0 -3
- tests/test_mymemory.py +3 -6
- tests/test_pons.py +0 -3
deep_translator/__init__.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
| 2 |
|
| 3 |
__copyright__ = "Copyright (C) 2020 Nidhal Baccouri"
|
| 4 |
|
|
|
|
| 5 |
from deep_translator.chatgpt import ChatGptTranslator
|
| 6 |
from deep_translator.deepl import DeeplTranslator
|
| 7 |
from deep_translator.detection import batch_detection, single_detection
|
|
@@ -33,6 +34,7 @@ __all__ = [
|
|
| 33 |
"PapagoTranslator",
|
| 34 |
"ChatGptTranslator",
|
| 35 |
"TencentTranslator",
|
|
|
|
| 36 |
"single_detection",
|
| 37 |
"batch_detection",
|
| 38 |
]
|
|
|
|
| 2 |
|
| 3 |
__copyright__ = "Copyright (C) 2020 Nidhal Baccouri"
|
| 4 |
|
| 5 |
+
from deep_translator.baidu import BaiduTranslator
|
| 6 |
from deep_translator.chatgpt import ChatGptTranslator
|
| 7 |
from deep_translator.deepl import DeeplTranslator
|
| 8 |
from deep_translator.detection import batch_detection, single_detection
|
|
|
|
| 34 |
"PapagoTranslator",
|
| 35 |
"ChatGptTranslator",
|
| 36 |
"TencentTranslator",
|
| 37 |
+
"BaiduTranslator",
|
| 38 |
"single_detection",
|
| 39 |
"batch_detection",
|
| 40 |
]
|
deep_translator/baidu.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
baidu translator API
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
__copyright__ = "Copyright (C) 2020 Nidhal Baccouri"
|
| 6 |
+
|
| 7 |
+
import hashlib
|
| 8 |
+
import os
|
| 9 |
+
import random
|
| 10 |
+
from typing import List, Optional
|
| 11 |
+
|
| 12 |
+
import requests
|
| 13 |
+
|
| 14 |
+
from deep_translator.base import BaseTranslator
|
| 15 |
+
from deep_translator.constants import (
|
| 16 |
+
BAIDU_APPID_ENV_VAR,
|
| 17 |
+
BAIDU_APPKEY_ENV_VAR,
|
| 18 |
+
BAIDU_LANGUAGE_TO_CODE,
|
| 19 |
+
BASE_URLS,
|
| 20 |
+
)
|
| 21 |
+
from deep_translator.exceptions import (
|
| 22 |
+
ApiKeyException,
|
| 23 |
+
BaiduAPIerror,
|
| 24 |
+
ServerException,
|
| 25 |
+
TranslationNotFound,
|
| 26 |
+
)
|
| 27 |
+
from deep_translator.validate import is_empty, is_input_valid
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
class BaiduTranslator(BaseTranslator):
|
| 31 |
+
"""
|
| 32 |
+
class that wraps functions, which use the BaiduTranslator translator
|
| 33 |
+
under the hood to translate word(s)
|
| 34 |
+
"""
|
| 35 |
+
|
| 36 |
+
def __init__(
|
| 37 |
+
self,
|
| 38 |
+
source: str = "en",
|
| 39 |
+
target: str = "zh",
|
| 40 |
+
appid: Optional[str] = os.getenv(BAIDU_APPID_ENV_VAR, None),
|
| 41 |
+
appkey: Optional[str] = os.getenv(BAIDU_APPKEY_ENV_VAR, None),
|
| 42 |
+
**kwargs
|
| 43 |
+
):
|
| 44 |
+
"""
|
| 45 |
+
@param appid: your baidu cloud api appid.
|
| 46 |
+
Get one here: https://fanyi-api.baidu.com/choose
|
| 47 |
+
@param appkey: your baidu cloud api appkey.
|
| 48 |
+
@param source: source language
|
| 49 |
+
@param target: target language
|
| 50 |
+
"""
|
| 51 |
+
if not appid:
|
| 52 |
+
raise ApiKeyException(env_var=BAIDU_APPID_ENV_VAR)
|
| 53 |
+
|
| 54 |
+
if not appkey:
|
| 55 |
+
raise ApiKeyException(env_var=BAIDU_APPKEY_ENV_VAR)
|
| 56 |
+
|
| 57 |
+
self.appid = appid
|
| 58 |
+
self.appkey = appkey
|
| 59 |
+
super().__init__(
|
| 60 |
+
base_url=BASE_URLS.get("BAIDU"),
|
| 61 |
+
source=source,
|
| 62 |
+
target=target,
|
| 63 |
+
languages=BAIDU_LANGUAGE_TO_CODE,
|
| 64 |
+
**kwargs
|
| 65 |
+
)
|
| 66 |
+
|
| 67 |
+
def translate(self, text: str, **kwargs) -> str:
|
| 68 |
+
"""
|
| 69 |
+
@param text: text to translate
|
| 70 |
+
@return: translated text
|
| 71 |
+
"""
|
| 72 |
+
if is_input_valid(text):
|
| 73 |
+
if self._same_source_target() or is_empty(text):
|
| 74 |
+
return text
|
| 75 |
+
|
| 76 |
+
# Create the request parameters.
|
| 77 |
+
salt = random.randint(32768, 65536)
|
| 78 |
+
sign = hashlib.md5(
|
| 79 |
+
(self.appid + text + str(salt) + self.appkey).encode("utf-8")
|
| 80 |
+
).hexdigest()
|
| 81 |
+
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
| 82 |
+
payload = {
|
| 83 |
+
"appid": self.appid,
|
| 84 |
+
"q": text,
|
| 85 |
+
"from": self.source,
|
| 86 |
+
"to": self.target,
|
| 87 |
+
"salt": salt,
|
| 88 |
+
"sign": sign,
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
# Do the request and check the connection.
|
| 92 |
+
try:
|
| 93 |
+
response = requests.post(
|
| 94 |
+
self._base_url, params=payload, headers=headers
|
| 95 |
+
)
|
| 96 |
+
except ConnectionError:
|
| 97 |
+
raise ServerException(503)
|
| 98 |
+
if response.status_code != 200:
|
| 99 |
+
raise ServerException(response.status_code)
|
| 100 |
+
# Get the response and check is not empty.
|
| 101 |
+
res = response.json()
|
| 102 |
+
if not res:
|
| 103 |
+
raise TranslationNotFound(text)
|
| 104 |
+
# Process and return the response.
|
| 105 |
+
if "error_code" in res:
|
| 106 |
+
raise BaiduAPIerror(res["error_msg"])
|
| 107 |
+
if "trans_result" in res:
|
| 108 |
+
return "\n".join([s["dst"] for s in res["trans_result"]])
|
| 109 |
+
else:
|
| 110 |
+
raise TranslationNotFound(text)
|
| 111 |
+
|
| 112 |
+
def translate_file(self, path: str, **kwargs) -> str:
|
| 113 |
+
return self._translate_file(path, **kwargs)
|
| 114 |
+
|
| 115 |
+
def translate_batch(self, batch: List[str], **kwargs) -> List[str]:
|
| 116 |
+
"""
|
| 117 |
+
@param batch: list of texts to translate
|
| 118 |
+
@return: list of translations
|
| 119 |
+
"""
|
| 120 |
+
return self._translate_batch(batch, **kwargs)
|
deep_translator/constants.py
CHANGED
|
@@ -9,6 +9,8 @@ QCRI_ENV_VAR = "QCRI_API_KEY"
|
|
| 9 |
YANDEX_ENV_VAR = "YANDEX_API_KEY"
|
| 10 |
TENCENT_SECRET_ID_ENV_VAR = "TENCENT_SECRET_ID"
|
| 11 |
TENCENT_SECRET_KEY_ENV_VAR = "TENCENT_SECRET_KEY"
|
|
|
|
|
|
|
| 12 |
|
| 13 |
|
| 14 |
BASE_URLS = {
|
|
@@ -26,6 +28,7 @@ BASE_URLS = {
|
|
| 26 |
"LIBRE": "https://libretranslate.com/",
|
| 27 |
"LIBRE_FREE": "https://libretranslate.de/",
|
| 28 |
"TENENT": "https://tmt.tencentcloudapi.com",
|
|
|
|
| 29 |
}
|
| 30 |
|
| 31 |
GOOGLE_LANGUAGES_TO_CODES = {
|
|
@@ -219,6 +222,331 @@ LINGUEE_LANGUAGES_TO_CODES = {
|
|
| 219 |
"japanese": "japanese",
|
| 220 |
}
|
| 221 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 222 |
DEEPL_LANGUAGE_TO_CODE = {
|
| 223 |
"bulgarian": "bg",
|
| 224 |
"czech": "cs",
|
|
@@ -303,3 +631,34 @@ TENCENT_LANGUAGE_TO_CODE = {
|
|
| 303 |
"turkish": "tr",
|
| 304 |
"vietnamese": "vi",
|
| 305 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
YANDEX_ENV_VAR = "YANDEX_API_KEY"
|
| 10 |
TENCENT_SECRET_ID_ENV_VAR = "TENCENT_SECRET_ID"
|
| 11 |
TENCENT_SECRET_KEY_ENV_VAR = "TENCENT_SECRET_KEY"
|
| 12 |
+
BAIDU_APPID_ENV_VAR = "BAIDU_APPID"
|
| 13 |
+
BAIDU_APPKEY_ENV_VAR = "BAIDU_APPKEY"
|
| 14 |
|
| 15 |
|
| 16 |
BASE_URLS = {
|
|
|
|
| 28 |
"LIBRE": "https://libretranslate.com/",
|
| 29 |
"LIBRE_FREE": "https://libretranslate.de/",
|
| 30 |
"TENENT": "https://tmt.tencentcloudapi.com",
|
| 31 |
+
"BAIDU": "https://fanyi-api.baidu.com/api/trans/vip/translate",
|
| 32 |
}
|
| 33 |
|
| 34 |
GOOGLE_LANGUAGES_TO_CODES = {
|
|
|
|
| 222 |
"japanese": "japanese",
|
| 223 |
}
|
| 224 |
|
| 225 |
+
MY_MEMORY_LANGUAGES_TO_CODES = {
|
| 226 |
+
"acehnese": "ace-ID",
|
| 227 |
+
"afrikaans": "af-ZA",
|
| 228 |
+
"akan": "ak-GH",
|
| 229 |
+
"albanian": "sq-AL",
|
| 230 |
+
"amharic": "am-ET",
|
| 231 |
+
"antigua and barbuda creole english": "aig-AG",
|
| 232 |
+
"arabic": "ar-SA",
|
| 233 |
+
"arabic egyptian": "ar-EG",
|
| 234 |
+
"aragonese": "an-ES",
|
| 235 |
+
"armenian": "hy-AM",
|
| 236 |
+
"assamese": "as-IN",
|
| 237 |
+
"asturian": "ast-ES",
|
| 238 |
+
"austrian german": "de-AT",
|
| 239 |
+
"awadhi": "awa-IN",
|
| 240 |
+
"ayacucho quechua": "quy-PE",
|
| 241 |
+
"azerbaijani": "az-AZ",
|
| 242 |
+
"bahamas creole english": "bah-BS",
|
| 243 |
+
"bajan": "bjs-BB",
|
| 244 |
+
"balinese": "ban-ID",
|
| 245 |
+
"balkan gipsy": "rm-RO",
|
| 246 |
+
"bambara": "bm-ML",
|
| 247 |
+
"banjar": "bjn-ID",
|
| 248 |
+
"bashkir": "ba-RU",
|
| 249 |
+
"basque": "eu-ES",
|
| 250 |
+
"belarusian": "be-BY",
|
| 251 |
+
"belgian french": "fr-BE",
|
| 252 |
+
"bemba": "bem-ZM",
|
| 253 |
+
"bengali": "bn-IN",
|
| 254 |
+
"bhojpuri": "bho-IN",
|
| 255 |
+
"bihari": "bh-IN",
|
| 256 |
+
"bislama": "bi-VU",
|
| 257 |
+
"borana": "gax-KE",
|
| 258 |
+
"bosnian": "bs-BA",
|
| 259 |
+
"bosnian (cyrillic)": "bs-Cyrl-BA",
|
| 260 |
+
"breton": "br-FR",
|
| 261 |
+
"buginese": "bug-ID",
|
| 262 |
+
"bulgarian": "bg-BG",
|
| 263 |
+
"burmese": "my-MM",
|
| 264 |
+
"catalan": "ca-ES",
|
| 265 |
+
"catalan valencian": "cav-ES",
|
| 266 |
+
"cebuano": "ceb-PH",
|
| 267 |
+
"central atlas tamazight": "tzm-MA",
|
| 268 |
+
"central aymara": "ayr-BO",
|
| 269 |
+
"central kanuri (latin script)": "knc-NG",
|
| 270 |
+
"chadian arabic": "shu-TD",
|
| 271 |
+
"chamorro": "ch-GU",
|
| 272 |
+
"cherokee": "chr-US",
|
| 273 |
+
"chhattisgarhi": "hne-IN",
|
| 274 |
+
"chinese simplified": "zh-CN",
|
| 275 |
+
"chinese trad. (hong kong)": "zh-HK",
|
| 276 |
+
"chinese traditional": "zh-TW",
|
| 277 |
+
"chinese traditional macau": "zh-MO",
|
| 278 |
+
"chittagonian": "ctg-BD",
|
| 279 |
+
"chokwe": "cjk-AO",
|
| 280 |
+
"classical greek": "grc-GR",
|
| 281 |
+
"comorian ngazidja": "zdj-KM",
|
| 282 |
+
"coptic": "cop-EG",
|
| 283 |
+
"crimean tatar": "crh-RU",
|
| 284 |
+
"crioulo upper guinea": "pov-GW",
|
| 285 |
+
"croatian": "hr-HR",
|
| 286 |
+
"czech": "cs-CZ",
|
| 287 |
+
"danish": "da-DK",
|
| 288 |
+
"dari": "prs-AF",
|
| 289 |
+
"dimli": "diq-TR",
|
| 290 |
+
"dutch": "nl-NL",
|
| 291 |
+
"dyula": "dyu-CI",
|
| 292 |
+
"dzongkha": "dz-BT",
|
| 293 |
+
"eastern yiddish": "ydd-US",
|
| 294 |
+
"emakhuwa": "vmw-MZ",
|
| 295 |
+
"english": "en-GB",
|
| 296 |
+
"english australia": "en-AU",
|
| 297 |
+
"english canada": "en-CA",
|
| 298 |
+
"english india": "en-IN",
|
| 299 |
+
"english ireland": "en-IE",
|
| 300 |
+
"english new zealand": "en-NZ",
|
| 301 |
+
"english singapore": "en-SG",
|
| 302 |
+
"english south africa": "en-ZA",
|
| 303 |
+
"english us": "en-US",
|
| 304 |
+
"esperanto": "eo-EU",
|
| 305 |
+
"estonian": "et-EE",
|
| 306 |
+
"ewe": "ee-GH",
|
| 307 |
+
"fanagalo": "fn-FNG",
|
| 308 |
+
"faroese": "fo-FO",
|
| 309 |
+
"fijian": "fj-FJ",
|
| 310 |
+
"filipino": "fil-PH",
|
| 311 |
+
"finnish": "fi-FI",
|
| 312 |
+
"flemish": "nl-BE",
|
| 313 |
+
"fon": "fon-BJ",
|
| 314 |
+
"french": "fr-FR",
|
| 315 |
+
"french canada": "fr-CA",
|
| 316 |
+
"french swiss": "fr-CH",
|
| 317 |
+
"friulian": "fur-IT",
|
| 318 |
+
"fula": "ff-FUL",
|
| 319 |
+
"galician": "gl-ES",
|
| 320 |
+
"gamargu": "mfi-NG",
|
| 321 |
+
"garo": "grt-IN",
|
| 322 |
+
"georgian": "ka-GE",
|
| 323 |
+
"german": "de-DE",
|
| 324 |
+
"gilbertese": "gil-KI",
|
| 325 |
+
"glavda": "glw-NG",
|
| 326 |
+
"greek": "el-GR",
|
| 327 |
+
"grenadian creole english": "gcl-GD",
|
| 328 |
+
"guarani": "gn-PY",
|
| 329 |
+
"gujarati": "gu-IN",
|
| 330 |
+
"guyanese creole english": "gyn-GY",
|
| 331 |
+
"haitian creole french": "ht-HT",
|
| 332 |
+
"halh mongolian": "khk-MN",
|
| 333 |
+
"hausa": "ha-NE",
|
| 334 |
+
"hawaiian": "haw-US",
|
| 335 |
+
"hebrew": "he-IL",
|
| 336 |
+
"higi": "hig-NG",
|
| 337 |
+
"hiligaynon": "hil-PH",
|
| 338 |
+
"hill mari": "mrj-RU",
|
| 339 |
+
"hindi": "hi-IN",
|
| 340 |
+
"hmong": "hmn-CN",
|
| 341 |
+
"hungarian": "hu-HU",
|
| 342 |
+
"icelandic": "is-IS",
|
| 343 |
+
"igbo ibo": "ibo-NG",
|
| 344 |
+
"igbo ig": "ig-NG",
|
| 345 |
+
"ilocano": "ilo-PH",
|
| 346 |
+
"indonesian": "id-ID",
|
| 347 |
+
"inuktitut greenlandic": "kl-GL",
|
| 348 |
+
"irish gaelic": "ga-IE",
|
| 349 |
+
"italian": "it-IT",
|
| 350 |
+
"italian swiss": "it-CH",
|
| 351 |
+
"jamaican creole english": "jam-JM",
|
| 352 |
+
"japanese": "ja-JP",
|
| 353 |
+
"javanese": "jv-ID",
|
| 354 |
+
"jingpho": "kac-MM",
|
| 355 |
+
"k'iche'": "quc-GT",
|
| 356 |
+
"kabiyè": "kbp-TG",
|
| 357 |
+
"kabuverdianu": "kea-CV",
|
| 358 |
+
"kabylian": "kab-DZ",
|
| 359 |
+
"kalenjin": "kln-KE",
|
| 360 |
+
"kamba": "kam-KE",
|
| 361 |
+
"kannada": "kn-IN",
|
| 362 |
+
"kanuri": "kr-KAU",
|
| 363 |
+
"karen": "kar-MM",
|
| 364 |
+
"kashmiri (devanagari script)": "ks-IN",
|
| 365 |
+
"kashmiri (arabic script)": "kas-IN",
|
| 366 |
+
"kazakh": "kk-KZ",
|
| 367 |
+
"khasi": "kha-IN",
|
| 368 |
+
"khmer": "km-KH",
|
| 369 |
+
"kikuyu kik": "kik-KE",
|
| 370 |
+
"kikuyu ki": "ki-KE",
|
| 371 |
+
"kimbundu": "kmb-AO",
|
| 372 |
+
"kinyarwanda": "rw-RW",
|
| 373 |
+
"kirundi": "rn-BI",
|
| 374 |
+
"kisii": "guz-KE",
|
| 375 |
+
"kongo": "kg-CG",
|
| 376 |
+
"konkani": "kok-IN",
|
| 377 |
+
"korean": "ko-KR",
|
| 378 |
+
"northern kurdish": "kmr-TR",
|
| 379 |
+
"kurdish sorani": "ckb-IQ",
|
| 380 |
+
"kyrgyz": "ky-KG",
|
| 381 |
+
"lao": "lo-LA",
|
| 382 |
+
"latgalian": "ltg-LV",
|
| 383 |
+
"latin": "la-XN",
|
| 384 |
+
"latvian": "lv-LV",
|
| 385 |
+
"ligurian": "lij-IT",
|
| 386 |
+
"limburgish": "li-NL",
|
| 387 |
+
"lingala": "ln-LIN",
|
| 388 |
+
"lithuanian": "lt-LT",
|
| 389 |
+
"lombard": "lmo-IT",
|
| 390 |
+
"luba-kasai": "lua-CD",
|
| 391 |
+
"luganda": "lg-UG",
|
| 392 |
+
"luhya": "luy-KE",
|
| 393 |
+
"luo": "luo-KE",
|
| 394 |
+
"luxembourgish": "lb-LU",
|
| 395 |
+
"maa": "mas-KE",
|
| 396 |
+
"macedonian": "mk-MK",
|
| 397 |
+
"magahi": "mag-IN",
|
| 398 |
+
"maithili": "mai-IN",
|
| 399 |
+
"malagasy": "mg-MG",
|
| 400 |
+
"malay": "ms-MY",
|
| 401 |
+
"malayalam": "ml-IN",
|
| 402 |
+
"maldivian": "dv-MV",
|
| 403 |
+
"maltese": "mt-MT",
|
| 404 |
+
"mandara": "mfi-CM",
|
| 405 |
+
"manipuri": "mni-IN",
|
| 406 |
+
"manx gaelic": "gv-IM",
|
| 407 |
+
"maori": "mi-NZ",
|
| 408 |
+
"marathi": "mr-IN",
|
| 409 |
+
"margi": "mrt-NG",
|
| 410 |
+
"mari": "mhr-RU",
|
| 411 |
+
"marshallese": "mh-MH",
|
| 412 |
+
"mende": "men-SL",
|
| 413 |
+
"meru": "mer-KE",
|
| 414 |
+
"mijikenda": "nyf-KE",
|
| 415 |
+
"minangkabau": "min-ID",
|
| 416 |
+
"mizo": "lus-IN",
|
| 417 |
+
"mongolian": "mn-MN",
|
| 418 |
+
"montenegrin": "sr-ME",
|
| 419 |
+
"morisyen": "mfe-MU",
|
| 420 |
+
"moroccan arabic": "ar-MA",
|
| 421 |
+
"mossi": "mos-BF",
|
| 422 |
+
"ndau": "ndc-MZ",
|
| 423 |
+
"ndebele": "nr-ZA",
|
| 424 |
+
"nepali": "ne-NP",
|
| 425 |
+
"nigerian fulfulde": "fuv-NG",
|
| 426 |
+
"niuean": "niu-NU",
|
| 427 |
+
"north azerbaijani": "azj-AZ",
|
| 428 |
+
"sesotho": "nso-ZA",
|
| 429 |
+
"northern uzbek": "uzn-UZ",
|
| 430 |
+
"norwegian bokmål": "nb-NO",
|
| 431 |
+
"norwegian nynorsk": "nn-NO",
|
| 432 |
+
"nuer": "nus-SS",
|
| 433 |
+
"nyanja": "ny-MW",
|
| 434 |
+
"occitan": "oc-FR",
|
| 435 |
+
"occitan aran": "oc-ES",
|
| 436 |
+
"odia": "or-IN",
|
| 437 |
+
"oriya": "ory-IN",
|
| 438 |
+
"urdu": "ur-PK",
|
| 439 |
+
"palauan": "pau-PW",
|
| 440 |
+
"pali": "pi-IN",
|
| 441 |
+
"pangasinan": "pag-PH",
|
| 442 |
+
"papiamentu": "pap-CW",
|
| 443 |
+
"pashto": "ps-PK",
|
| 444 |
+
"persian": "fa-IR",
|
| 445 |
+
"pijin": "pis-SB",
|
| 446 |
+
"plateau malagasy": "plt-MG",
|
| 447 |
+
"polish": "pl-PL",
|
| 448 |
+
"portuguese": "pt-PT",
|
| 449 |
+
"portuguese brazil": "pt-BR",
|
| 450 |
+
"potawatomi": "pot-US",
|
| 451 |
+
"punjabi": "pa-IN",
|
| 452 |
+
"punjabi (pakistan)": "pnb-PK",
|
| 453 |
+
"quechua": "qu-PE",
|
| 454 |
+
"rohingya": "rhg-MM",
|
| 455 |
+
"rohingyalish": "rhl-MM",
|
| 456 |
+
"romanian": "ro-RO",
|
| 457 |
+
"romansh": "roh-CH",
|
| 458 |
+
"rundi": "run-BI",
|
| 459 |
+
"russian": "ru-RU",
|
| 460 |
+
"saint lucian creole french": "acf-LC",
|
| 461 |
+
"samoan": "sm-WS",
|
| 462 |
+
"sango": "sg-CF",
|
| 463 |
+
"sanskrit": "sa-IN",
|
| 464 |
+
"santali": "sat-IN",
|
| 465 |
+
"sardinian": "sc-IT",
|
| 466 |
+
"scots gaelic": "gd-GB",
|
| 467 |
+
"sena": "seh-ZW",
|
| 468 |
+
"serbian cyrillic": "sr-Cyrl-RS",
|
| 469 |
+
"serbian latin": "sr-Latn-RS",
|
| 470 |
+
"seselwa creole french": "crs-SC",
|
| 471 |
+
"setswana (south africa)": "tn-ZA",
|
| 472 |
+
"shan": "shn-MM",
|
| 473 |
+
"shona": "sn-ZW",
|
| 474 |
+
"sicilian": "scn-IT",
|
| 475 |
+
"silesian": "szl-PL",
|
| 476 |
+
"sindhi snd": "snd-PK",
|
| 477 |
+
"sindhi sd": "sd-PK",
|
| 478 |
+
"sinhala": "si-LK",
|
| 479 |
+
"slovak": "sk-SK",
|
| 480 |
+
"slovenian": "sl-SI",
|
| 481 |
+
"somali": "so-SO",
|
| 482 |
+
"sotho southern": "st-LS",
|
| 483 |
+
"south azerbaijani": "azb-AZ",
|
| 484 |
+
"southern pashto": "pbt-PK",
|
| 485 |
+
"southwestern dinka": "dik-SS",
|
| 486 |
+
"spanish": "es-ES",
|
| 487 |
+
"spanish argentina": "es-AR",
|
| 488 |
+
"spanish colombia": "es-CO",
|
| 489 |
+
"spanish latin america": "es-419",
|
| 490 |
+
"spanish mexico": "es-MX",
|
| 491 |
+
"spanish united states": "es-US",
|
| 492 |
+
"sranan tongo": "srn-SR",
|
| 493 |
+
"standard latvian": "lvs-LV",
|
| 494 |
+
"standard malay": "zsm-MY",
|
| 495 |
+
"sundanese": "su-ID",
|
| 496 |
+
"swahili": "sw-KE",
|
| 497 |
+
"swati": "ss-SZ",
|
| 498 |
+
"swedish": "sv-SE",
|
| 499 |
+
"swiss german": "de-CH",
|
| 500 |
+
"syriac (aramaic)": "syc-TR",
|
| 501 |
+
"tagalog": "tl-PH",
|
| 502 |
+
"tahitian": "ty-PF",
|
| 503 |
+
"tajik": "tg-TJ",
|
| 504 |
+
"tamashek (tuareg)": "tmh-DZ",
|
| 505 |
+
"tamasheq": "taq-ML",
|
| 506 |
+
"tamil india": "ta-IN",
|
| 507 |
+
"tamil sri lanka": "ta-LK",
|
| 508 |
+
"taroko": "trv-TW",
|
| 509 |
+
"tatar": "tt-RU",
|
| 510 |
+
"telugu": "te-IN",
|
| 511 |
+
"tetum": "tet-TL",
|
| 512 |
+
"thai": "th-TH",
|
| 513 |
+
"tibetan": "bo-CN",
|
| 514 |
+
"tigrinya": "ti-ET",
|
| 515 |
+
"tok pisin": "tpi-PG",
|
| 516 |
+
"tokelauan": "tkl-TK",
|
| 517 |
+
"tongan": "to-TO",
|
| 518 |
+
"tosk albanian": "als-AL",
|
| 519 |
+
"tsonga": "ts-ZA",
|
| 520 |
+
"tswa": "tsc-MZ",
|
| 521 |
+
"tswana": "tn-BW",
|
| 522 |
+
"tumbuka": "tum-MW",
|
| 523 |
+
"turkish": "tr-TR",
|
| 524 |
+
"turkmen": "tk-TM",
|
| 525 |
+
"tuvaluan": "tvl-TV",
|
| 526 |
+
"twi": "tw-GH",
|
| 527 |
+
"udmurt": "udm-RU",
|
| 528 |
+
"ukrainian": "uk-UA",
|
| 529 |
+
"uma": "ppk-ID",
|
| 530 |
+
"umbundu": "umb-AO",
|
| 531 |
+
"uyghur uig": "uig-CN",
|
| 532 |
+
"uyghur ug": "ug-CN",
|
| 533 |
+
"uzbek": "uz-UZ",
|
| 534 |
+
"venetian": "vec-IT",
|
| 535 |
+
"vietnamese": "vi-VN",
|
| 536 |
+
"vincentian creole english": "svc-VC",
|
| 537 |
+
"virgin islands creole english": "vic-US",
|
| 538 |
+
"wallisian": "wls-WF",
|
| 539 |
+
"waray (philippines)": "war-PH",
|
| 540 |
+
"welsh": "cy-GB",
|
| 541 |
+
"west central oromo": "gaz-ET",
|
| 542 |
+
"western persian": "pes-IR",
|
| 543 |
+
"wolof": "wo-SN",
|
| 544 |
+
"xhosa": "xh-ZA",
|
| 545 |
+
"yiddish": "yi-YD",
|
| 546 |
+
"yoruba": "yo-NG",
|
| 547 |
+
"zulu": "zu-ZA",
|
| 548 |
+
}
|
| 549 |
+
|
| 550 |
DEEPL_LANGUAGE_TO_CODE = {
|
| 551 |
"bulgarian": "bg",
|
| 552 |
"czech": "cs",
|
|
|
|
| 631 |
"turkish": "tr",
|
| 632 |
"vietnamese": "vi",
|
| 633 |
}
|
| 634 |
+
|
| 635 |
+
BAIDU_LANGUAGE_TO_CODE = {
|
| 636 |
+
"arabic": "ara",
|
| 637 |
+
"bulgarian": "bul",
|
| 638 |
+
"chinese (classical)": "wyw",
|
| 639 |
+
"chinese (simplified)": "zh",
|
| 640 |
+
"chinese (traditional)": "cht",
|
| 641 |
+
"czech": "cs",
|
| 642 |
+
"danish": "dan",
|
| 643 |
+
"dutch": "nl",
|
| 644 |
+
"english": "en",
|
| 645 |
+
"estonian": "est",
|
| 646 |
+
"finnish": "fin",
|
| 647 |
+
"french": "fra",
|
| 648 |
+
"german": "de",
|
| 649 |
+
"greek": "el",
|
| 650 |
+
"hungarian": "hu",
|
| 651 |
+
"italian": "it",
|
| 652 |
+
"japanese": "jp",
|
| 653 |
+
"korean": "kor",
|
| 654 |
+
"polish": "pl",
|
| 655 |
+
"portuguese": "pt",
|
| 656 |
+
"romanian": "ro",
|
| 657 |
+
"russian": "ru",
|
| 658 |
+
"slovenian": "slo",
|
| 659 |
+
"spanish": "spa",
|
| 660 |
+
"swedish": "swe",
|
| 661 |
+
"thai": "th",
|
| 662 |
+
"vietnamese": "vie",
|
| 663 |
+
"yueyu": "yue",
|
| 664 |
+
}
|
deep_translator/deepl.py
CHANGED
|
@@ -17,7 +17,7 @@ from deep_translator.exceptions import (
|
|
| 17 |
ServerException,
|
| 18 |
TranslationNotFound,
|
| 19 |
)
|
| 20 |
-
from deep_translator.validate import is_empty, is_input_valid
|
| 21 |
|
| 22 |
|
| 23 |
class DeeplTranslator(BaseTranslator):
|
|
@@ -85,7 +85,7 @@ class DeeplTranslator(BaseTranslator):
|
|
| 85 |
# If the answer is not success, raise server exception.
|
| 86 |
if response.status_code == 403:
|
| 87 |
raise AuthorizationException(self.api_key)
|
| 88 |
-
|
| 89 |
raise ServerException(response.status_code)
|
| 90 |
# Get the response and check is not empty.
|
| 91 |
res = response.json()
|
|
|
|
| 17 |
ServerException,
|
| 18 |
TranslationNotFound,
|
| 19 |
)
|
| 20 |
+
from deep_translator.validate import is_empty, is_input_valid, request_failed
|
| 21 |
|
| 22 |
|
| 23 |
class DeeplTranslator(BaseTranslator):
|
|
|
|
| 85 |
# If the answer is not success, raise server exception.
|
| 86 |
if response.status_code == 403:
|
| 87 |
raise AuthorizationException(self.api_key)
|
| 88 |
+
if request_failed(status_code=response.status_code):
|
| 89 |
raise ServerException(response.status_code)
|
| 90 |
# Get the response and check is not empty.
|
| 91 |
res = response.json()
|
deep_translator/exceptions.py
CHANGED
|
@@ -193,3 +193,16 @@ class TencentAPIerror(Exception):
|
|
| 193 |
|
| 194 |
def __str__(self):
|
| 195 |
return "{}: {}".format(self.message, self.api_message)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 193 |
|
| 194 |
def __str__(self):
|
| 195 |
return "{}: {}".format(self.message, self.api_message)
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
class BaiduAPIerror(Exception):
|
| 199 |
+
"""
|
| 200 |
+
exception thrown if Baidu API returns one of its errors
|
| 201 |
+
"""
|
| 202 |
+
|
| 203 |
+
def __init__(self, api_message):
|
| 204 |
+
self.api_message = str(api_message)
|
| 205 |
+
self.message = "Baidu API returned the following error"
|
| 206 |
+
|
| 207 |
+
def __str__(self):
|
| 208 |
+
return "{}: {}".format(self.message, self.api_message)
|
deep_translator/google.py
CHANGED
|
@@ -16,7 +16,7 @@ from deep_translator.exceptions import (
|
|
| 16 |
TooManyRequests,
|
| 17 |
TranslationNotFound,
|
| 18 |
)
|
| 19 |
-
from deep_translator.validate import is_empty, is_input_valid
|
| 20 |
|
| 21 |
|
| 22 |
class GoogleTranslator(BaseTranslator):
|
|
@@ -54,7 +54,7 @@ class GoogleTranslator(BaseTranslator):
|
|
| 54 |
@param text: desired text to translate
|
| 55 |
@return: str: translated text
|
| 56 |
"""
|
| 57 |
-
if is_input_valid(text):
|
| 58 |
text = text.strip()
|
| 59 |
if self._same_source_target() or is_empty(text):
|
| 60 |
return text
|
|
@@ -70,7 +70,7 @@ class GoogleTranslator(BaseTranslator):
|
|
| 70 |
if response.status_code == 429:
|
| 71 |
raise TooManyRequests()
|
| 72 |
|
| 73 |
-
if response.status_code
|
| 74 |
raise RequestError()
|
| 75 |
|
| 76 |
soup = BeautifulSoup(response.text, "html.parser")
|
|
|
|
| 16 |
TooManyRequests,
|
| 17 |
TranslationNotFound,
|
| 18 |
)
|
| 19 |
+
from deep_translator.validate import is_empty, is_input_valid, request_failed
|
| 20 |
|
| 21 |
|
| 22 |
class GoogleTranslator(BaseTranslator):
|
|
|
|
| 54 |
@param text: desired text to translate
|
| 55 |
@return: str: translated text
|
| 56 |
"""
|
| 57 |
+
if is_input_valid(text, max_chars=5000):
|
| 58 |
text = text.strip()
|
| 59 |
if self._same_source_target() or is_empty(text):
|
| 60 |
return text
|
|
|
|
| 70 |
if response.status_code == 429:
|
| 71 |
raise TooManyRequests()
|
| 72 |
|
| 73 |
+
if request_failed(status_code=response.status_code):
|
| 74 |
raise RequestError()
|
| 75 |
|
| 76 |
soup = BeautifulSoup(response.text, "html.parser")
|
deep_translator/libre.py
CHANGED
|
@@ -20,7 +20,7 @@ from deep_translator.exceptions import (
|
|
| 20 |
ServerException,
|
| 21 |
TranslationNotFound,
|
| 22 |
)
|
| 23 |
-
from deep_translator.validate import is_empty, is_input_valid
|
| 24 |
|
| 25 |
|
| 26 |
class LibreTranslator(BaseTranslator):
|
|
@@ -95,7 +95,7 @@ class LibreTranslator(BaseTranslator):
|
|
| 95 |
|
| 96 |
if response.status_code == 403:
|
| 97 |
raise AuthorizationException(self.api_key)
|
| 98 |
-
elif response.status_code
|
| 99 |
raise ServerException(response.status_code)
|
| 100 |
# Get the response and check is not empty.
|
| 101 |
res = response.json()
|
|
|
|
| 20 |
ServerException,
|
| 21 |
TranslationNotFound,
|
| 22 |
)
|
| 23 |
+
from deep_translator.validate import is_empty, is_input_valid, request_failed
|
| 24 |
|
| 25 |
|
| 26 |
class LibreTranslator(BaseTranslator):
|
|
|
|
| 95 |
|
| 96 |
if response.status_code == 403:
|
| 97 |
raise AuthorizationException(self.api_key)
|
| 98 |
+
elif request_failed(status_code=response.status_code):
|
| 99 |
raise ServerException(response.status_code)
|
| 100 |
# Get the response and check is not empty.
|
| 101 |
res = response.json()
|
deep_translator/linguee.py
CHANGED
|
@@ -19,7 +19,7 @@ from deep_translator.exceptions import (
|
|
| 19 |
TooManyRequests,
|
| 20 |
TranslationNotFound,
|
| 21 |
)
|
| 22 |
-
from deep_translator.validate import is_empty, is_input_valid
|
| 23 |
|
| 24 |
|
| 25 |
class LingueeTranslator(BaseTranslator):
|
|
@@ -72,8 +72,9 @@ class LingueeTranslator(BaseTranslator):
|
|
| 72 |
if response.status_code == 429:
|
| 73 |
raise TooManyRequests()
|
| 74 |
|
| 75 |
-
if response.status_code
|
| 76 |
raise RequestError()
|
|
|
|
| 77 |
soup = BeautifulSoup(response.text, "html.parser")
|
| 78 |
elements = soup.find_all(self._element_tag, self._element_query)
|
| 79 |
response.close()
|
|
|
|
| 19 |
TooManyRequests,
|
| 20 |
TranslationNotFound,
|
| 21 |
)
|
| 22 |
+
from deep_translator.validate import is_empty, is_input_valid, request_failed
|
| 23 |
|
| 24 |
|
| 25 |
class LingueeTranslator(BaseTranslator):
|
|
|
|
| 72 |
if response.status_code == 429:
|
| 73 |
raise TooManyRequests()
|
| 74 |
|
| 75 |
+
if request_failed(status_code=response.status_code):
|
| 76 |
raise RequestError()
|
| 77 |
+
|
| 78 |
soup = BeautifulSoup(response.text, "html.parser")
|
| 79 |
elements = soup.find_all(self._element_tag, self._element_query)
|
| 80 |
response.close()
|
deep_translator/mymemory.py
CHANGED
|
@@ -9,13 +9,13 @@ from typing import List, Optional, Union
|
|
| 9 |
import requests
|
| 10 |
|
| 11 |
from deep_translator.base import BaseTranslator
|
| 12 |
-
from deep_translator.constants import BASE_URLS
|
| 13 |
from deep_translator.exceptions import (
|
| 14 |
RequestError,
|
| 15 |
TooManyRequests,
|
| 16 |
TranslationNotFound,
|
| 17 |
)
|
| 18 |
-
from deep_translator.validate import is_empty, is_input_valid
|
| 19 |
|
| 20 |
|
| 21 |
class MyMemoryTranslator(BaseTranslator):
|
|
@@ -41,6 +41,7 @@ class MyMemoryTranslator(BaseTranslator):
|
|
| 41 |
source=source,
|
| 42 |
target=target,
|
| 43 |
payload_key="q",
|
|
|
|
| 44 |
)
|
| 45 |
|
| 46 |
def translate(
|
|
@@ -70,7 +71,7 @@ class MyMemoryTranslator(BaseTranslator):
|
|
| 70 |
|
| 71 |
if response.status_code == 429:
|
| 72 |
raise TooManyRequests()
|
| 73 |
-
if response.status_code
|
| 74 |
raise RequestError()
|
| 75 |
|
| 76 |
data = response.json()
|
|
|
|
| 9 |
import requests
|
| 10 |
|
| 11 |
from deep_translator.base import BaseTranslator
|
| 12 |
+
from deep_translator.constants import BASE_URLS, MY_MEMORY_LANGUAGES_TO_CODES
|
| 13 |
from deep_translator.exceptions import (
|
| 14 |
RequestError,
|
| 15 |
TooManyRequests,
|
| 16 |
TranslationNotFound,
|
| 17 |
)
|
| 18 |
+
from deep_translator.validate import is_empty, is_input_valid, request_failed
|
| 19 |
|
| 20 |
|
| 21 |
class MyMemoryTranslator(BaseTranslator):
|
|
|
|
| 41 |
source=source,
|
| 42 |
target=target,
|
| 43 |
payload_key="q",
|
| 44 |
+
languages=MY_MEMORY_LANGUAGES_TO_CODES,
|
| 45 |
)
|
| 46 |
|
| 47 |
def translate(
|
|
|
|
| 71 |
|
| 72 |
if response.status_code == 429:
|
| 73 |
raise TooManyRequests()
|
| 74 |
+
if request_failed(status_code=response.status_code):
|
| 75 |
raise RequestError()
|
| 76 |
|
| 77 |
data = response.json()
|
deep_translator/papago.py
CHANGED
|
@@ -12,7 +12,7 @@ import requests
|
|
| 12 |
from deep_translator.base import BaseTranslator
|
| 13 |
from deep_translator.constants import BASE_URLS, PAPAGO_LANGUAGE_TO_CODE
|
| 14 |
from deep_translator.exceptions import TranslationNotFound
|
| 15 |
-
from deep_translator.validate import is_input_valid
|
| 16 |
|
| 17 |
|
| 18 |
class PapagoTranslator(BaseTranslator):
|
|
@@ -67,7 +67,7 @@ class PapagoTranslator(BaseTranslator):
|
|
| 67 |
response = requests.post(
|
| 68 |
self._base_url, headers=headers, data=payload
|
| 69 |
)
|
| 70 |
-
if response.status_code
|
| 71 |
raise Exception(
|
| 72 |
f"Translation error! -> status code: {response.status_code}"
|
| 73 |
)
|
|
|
|
| 12 |
from deep_translator.base import BaseTranslator
|
| 13 |
from deep_translator.constants import BASE_URLS, PAPAGO_LANGUAGE_TO_CODE
|
| 14 |
from deep_translator.exceptions import TranslationNotFound
|
| 15 |
+
from deep_translator.validate import is_input_valid, request_failed
|
| 16 |
|
| 17 |
|
| 18 |
class PapagoTranslator(BaseTranslator):
|
|
|
|
| 67 |
response = requests.post(
|
| 68 |
self._base_url, headers=headers, data=payload
|
| 69 |
)
|
| 70 |
+
if request_failed(status_code=response.status_code):
|
| 71 |
raise Exception(
|
| 72 |
f"Translation error! -> status code: {response.status_code}"
|
| 73 |
)
|
deep_translator/pons.py
CHANGED
|
@@ -19,7 +19,7 @@ from deep_translator.exceptions import (
|
|
| 19 |
TooManyRequests,
|
| 20 |
TranslationNotFound,
|
| 21 |
)
|
| 22 |
-
from deep_translator.validate import is_empty, is_input_valid
|
| 23 |
|
| 24 |
|
| 25 |
class PonsTranslator(BaseTranslator):
|
|
@@ -71,7 +71,7 @@ class PonsTranslator(BaseTranslator):
|
|
| 71 |
if response.status_code == 429:
|
| 72 |
raise TooManyRequests()
|
| 73 |
|
| 74 |
-
if response.status_code
|
| 75 |
raise RequestError()
|
| 76 |
|
| 77 |
soup = BeautifulSoup(response.text, "html.parser")
|
|
|
|
| 19 |
TooManyRequests,
|
| 20 |
TranslationNotFound,
|
| 21 |
)
|
| 22 |
+
from deep_translator.validate import is_empty, is_input_valid, request_failed
|
| 23 |
|
| 24 |
|
| 25 |
class PonsTranslator(BaseTranslator):
|
|
|
|
| 71 |
if response.status_code == 429:
|
| 72 |
raise TooManyRequests()
|
| 73 |
|
| 74 |
+
if request_failed(status_code=response.status_code):
|
| 75 |
raise RequestError()
|
| 76 |
|
| 77 |
soup = BeautifulSoup(response.text, "html.parser")
|
deep_translator/qcri.py
CHANGED
|
@@ -16,6 +16,7 @@ from deep_translator.exceptions import (
|
|
| 16 |
ServerException,
|
| 17 |
TranslationNotFound,
|
| 18 |
)
|
|
|
|
| 19 |
|
| 20 |
|
| 21 |
class QcriTranslator(BaseTranslator):
|
|
@@ -96,7 +97,7 @@ class QcriTranslator(BaseTranslator):
|
|
| 96 |
raise ServerException(503)
|
| 97 |
|
| 98 |
else:
|
| 99 |
-
if response.status_code
|
| 100 |
ServerException(response.status_code)
|
| 101 |
else:
|
| 102 |
res = response.json()
|
|
|
|
| 16 |
ServerException,
|
| 17 |
TranslationNotFound,
|
| 18 |
)
|
| 19 |
+
from deep_translator.validate import request_failed
|
| 20 |
|
| 21 |
|
| 22 |
class QcriTranslator(BaseTranslator):
|
|
|
|
| 97 |
raise ServerException(503)
|
| 98 |
|
| 99 |
else:
|
| 100 |
+
if request_failed(status_code=response.status_code):
|
| 101 |
ServerException(response.status_code)
|
| 102 |
else:
|
| 103 |
res = response.json()
|
deep_translator/validate.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
| 1 |
__copyright__ = "Copyright (C) 2020 Nidhal Baccouri"
|
| 2 |
|
|
|
|
|
|
|
| 3 |
from deep_translator.exceptions import NotValidLength, NotValidPayload
|
| 4 |
|
| 5 |
|
|
@@ -7,8 +9,23 @@ def is_empty(text: str) -> bool:
|
|
| 7 |
return text == ""
|
| 8 |
|
| 9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
def is_input_valid(
|
| 11 |
-
text: str, min_chars: int = 0, max_chars: int =
|
| 12 |
) -> bool:
|
| 13 |
"""
|
| 14 |
validate the target text to translate
|
|
@@ -18,9 +35,9 @@ def is_input_valid(
|
|
| 18 |
@return: bool
|
| 19 |
"""
|
| 20 |
|
| 21 |
-
if not isinstance(text, str)
|
| 22 |
raise NotValidPayload(text)
|
| 23 |
-
if not min_chars <= len(text) < max_chars:
|
| 24 |
raise NotValidLength(text, min_chars, max_chars)
|
| 25 |
|
| 26 |
return True
|
|
|
|
| 1 |
__copyright__ = "Copyright (C) 2020 Nidhal Baccouri"
|
| 2 |
|
| 3 |
+
from typing import Optional
|
| 4 |
+
|
| 5 |
from deep_translator.exceptions import NotValidLength, NotValidPayload
|
| 6 |
|
| 7 |
|
|
|
|
| 9 |
return text == ""
|
| 10 |
|
| 11 |
|
| 12 |
+
def request_failed(status_code: int) -> bool:
|
| 13 |
+
"""Check if a request has failed or not.
|
| 14 |
+
A request is considered successfull if the status code is in the 2** range.
|
| 15 |
+
|
| 16 |
+
Args:
|
| 17 |
+
status_code (int): status code of the request
|
| 18 |
+
|
| 19 |
+
Returns:
|
| 20 |
+
bool: indicates request failure
|
| 21 |
+
"""
|
| 22 |
+
if status_code > 299 or status_code < 200:
|
| 23 |
+
return True
|
| 24 |
+
return False
|
| 25 |
+
|
| 26 |
+
|
| 27 |
def is_input_valid(
|
| 28 |
+
text: str, min_chars: int = 0, max_chars: Optional[int] = None
|
| 29 |
) -> bool:
|
| 30 |
"""
|
| 31 |
validate the target text to translate
|
|
|
|
| 35 |
@return: bool
|
| 36 |
"""
|
| 37 |
|
| 38 |
+
if not isinstance(text, str):
|
| 39 |
raise NotValidPayload(text)
|
| 40 |
+
if max_chars and (not min_chars <= len(text) < max_chars):
|
| 41 |
raise NotValidLength(text, min_chars, max_chars)
|
| 42 |
|
| 43 |
return True
|
deep_translator/yandex.py
CHANGED
|
@@ -18,7 +18,7 @@ from deep_translator.exceptions import (
|
|
| 18 |
TooManyRequests,
|
| 19 |
TranslationNotFound,
|
| 20 |
)
|
| 21 |
-
from deep_translator.validate import is_input_valid
|
| 22 |
|
| 23 |
|
| 24 |
class YandexTranslator(BaseTranslator):
|
|
@@ -75,7 +75,7 @@ class YandexTranslator(BaseTranslator):
|
|
| 75 |
else:
|
| 76 |
data = response.json()
|
| 77 |
|
| 78 |
-
if response.status_code
|
| 79 |
raise ServerException(response.status_code)
|
| 80 |
return data.get("dirs")
|
| 81 |
|
|
|
|
| 18 |
TooManyRequests,
|
| 19 |
TranslationNotFound,
|
| 20 |
)
|
| 21 |
+
from deep_translator.validate import is_input_valid, request_failed
|
| 22 |
|
| 23 |
|
| 24 |
class YandexTranslator(BaseTranslator):
|
|
|
|
| 75 |
else:
|
| 76 |
data = response.json()
|
| 77 |
|
| 78 |
+
if request_failed(status_code=response.status_code):
|
| 79 |
raise ServerException(response.status_code)
|
| 80 |
return data.get("dirs")
|
| 81 |
|
docs/README.rst
CHANGED
|
@@ -694,6 +694,66 @@ TencentTranslator
|
|
| 694 |
|
| 695 |
translated = TencentTranslator(secret_id="your-secret_id", secret_key="your-secret_key" source="en", target="zh").translate_file('path/to/file')
|
| 696 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 697 |
|
| 698 |
Proxy usage
|
| 699 |
-------------
|
|
|
|
| 694 |
|
| 695 |
translated = TencentTranslator(secret_id="your-secret_id", secret_key="your-secret_key" source="en", target="zh").translate_file('path/to/file')
|
| 696 |
|
| 697 |
+
BaiduTranslator
|
| 698 |
+
-----------------
|
| 699 |
+
|
| 700 |
+
.. note::
|
| 701 |
+
|
| 702 |
+
In order to use the BaiduTranslator translator, you need to generate a secret_id and a secret_key.
|
| 703 |
+
deep-translator supports both Pro and free APIs. Just check the examples below.
|
| 704 |
+
Visit http://api.fanyi.baidu.com/product/113 for more information on how to generate your Baidu appid
|
| 705 |
+
and appkey.
|
| 706 |
+
|
| 707 |
+
- Simple translation
|
| 708 |
+
|
| 709 |
+
.. code-block:: python
|
| 710 |
+
|
| 711 |
+
text = 'Hello world'
|
| 712 |
+
translated = BaiduTranslator(appid="your-appid", appkey="your-appkey" source="en", target="zh").translate(text)
|
| 713 |
+
|
| 714 |
+
- Translate batch of texts
|
| 715 |
+
|
| 716 |
+
.. code-block:: python
|
| 717 |
+
|
| 718 |
+
texts = ["Hello world", "How are you?"]
|
| 719 |
+
translated = BaiduTranslator(appid="your-appid", appkey="your-appkey" source="en", target="zh").translate_batch(texts)
|
| 720 |
+
|
| 721 |
+
- Translate from a file:
|
| 722 |
+
|
| 723 |
+
.. code-block:: python
|
| 724 |
+
|
| 725 |
+
translated = BaiduTranslator(appid="your-appid", appkey="your-appkey" source="en", target="zh").translate_file('path/to/file')
|
| 726 |
+
|
| 727 |
+
BaiduTranslator
|
| 728 |
+
-----------------
|
| 729 |
+
|
| 730 |
+
.. note::
|
| 731 |
+
|
| 732 |
+
In order to use the BaiduTranslator translator, you need to generate a secret_id and a secret_key.
|
| 733 |
+
deep-translator supports both Pro and free APIs. Just check the examples below.
|
| 734 |
+
Visit http://api.fanyi.baidu.com/product/113 for more information on how to generate your Baidu appid
|
| 735 |
+
and appkey.
|
| 736 |
+
|
| 737 |
+
- Simple translation
|
| 738 |
+
|
| 739 |
+
.. code-block:: python
|
| 740 |
+
|
| 741 |
+
text = 'Hello world'
|
| 742 |
+
translated = BaiduTranslator(appid="your-appid", appkey="your-appkey" source="en", target="zh").translate(text)
|
| 743 |
+
|
| 744 |
+
- Translate batch of texts
|
| 745 |
+
|
| 746 |
+
.. code-block:: python
|
| 747 |
+
|
| 748 |
+
texts = ["Hello world", "How are you?"]
|
| 749 |
+
translated = BaiduTranslator(appid="your-appid", appkey="your-appkey" source="en", target="zh").translate_batch(texts)
|
| 750 |
+
|
| 751 |
+
- Translate from a file:
|
| 752 |
+
|
| 753 |
+
.. code-block:: python
|
| 754 |
+
|
| 755 |
+
translated = BaiduTranslator(appid="your-appid", appkey="your-appkey" source="en", target="zh").translate_file('path/to/file')
|
| 756 |
+
|
| 757 |
|
| 758 |
Proxy usage
|
| 759 |
-------------
|
pyproject.toml
CHANGED
|
@@ -25,7 +25,7 @@ ensure_newline_before_comments = true
|
|
| 25 |
|
| 26 |
[tool.poetry]
|
| 27 |
name = "deep-translator"
|
| 28 |
-
version = "1.11.
|
| 29 |
description = "A flexible free and unlimited python tool to translate between different languages in a simple way using multiple translators"
|
| 30 |
license = "MIT"
|
| 31 |
authors = ["Nidhal Baccouri <[email protected]>"]
|
|
|
|
| 25 |
|
| 26 |
[tool.poetry]
|
| 27 |
name = "deep-translator"
|
| 28 |
+
version = "1.11.4"
|
| 29 |
description = "A flexible free and unlimited python tool to translate between different languages in a simple way using multiple translators"
|
| 30 |
license = "MIT"
|
| 31 |
authors = ["Nidhal Baccouri <[email protected]>"]
|
tests/test_baidu.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from unittest.mock import Mock, patch
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
from deep_translator import BaiduTranslator
|
| 6 |
+
from deep_translator.exceptions import BaiduAPIerror
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
@patch("deep_translator.baidu.requests")
|
| 10 |
+
def test_simple_translation(mock_requests):
|
| 11 |
+
translator = BaiduTranslator(
|
| 12 |
+
appid="this-is-an-valid-appid",
|
| 13 |
+
appkey="this-is-an-valid-appkey",
|
| 14 |
+
source="en",
|
| 15 |
+
target="zh",
|
| 16 |
+
)
|
| 17 |
+
# Set the request response mock.
|
| 18 |
+
mock_response = Mock()
|
| 19 |
+
mock_response.status_code = 200
|
| 20 |
+
mock_response.json.return_value = {
|
| 21 |
+
"from": "en",
|
| 22 |
+
"to": "zh",
|
| 23 |
+
"trans_result": [{"src": "hello", "dst": "你好"}],
|
| 24 |
+
}
|
| 25 |
+
mock_requests.post.return_value = mock_response
|
| 26 |
+
translation = translator.translate("hello")
|
| 27 |
+
assert translation == "你好"
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
@patch("deep_translator.baidu.requests.get")
|
| 31 |
+
def test_wrong_api_key(mock_requests):
|
| 32 |
+
translator = BaiduTranslator(
|
| 33 |
+
appid="this-is-a-wrong-appid",
|
| 34 |
+
appkey="this-is-a-wrong-appkey",
|
| 35 |
+
source="en",
|
| 36 |
+
target="zh",
|
| 37 |
+
)
|
| 38 |
+
# Set the response status_code only.
|
| 39 |
+
mock_response = Mock()
|
| 40 |
+
mock_response.status_code = 200
|
| 41 |
+
mock_response.json.return_value = {
|
| 42 |
+
"error_code": "54001",
|
| 43 |
+
"error_msg": "Invalid Sign",
|
| 44 |
+
}
|
| 45 |
+
mock_requests.post.return_value = mock_response
|
| 46 |
+
with pytest.raises(BaiduAPIerror):
|
| 47 |
+
translator.translate("Hello")
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
# the remaining tests are actual requests to Baidu translator API and use appid and appkey
|
| 51 |
+
# if appid and appkey variable is None, they are skipped
|
| 52 |
+
|
| 53 |
+
appid = None
|
| 54 |
+
appkey = None
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
@pytest.mark.skipif(
|
| 58 |
+
appid is None or appkey is None,
|
| 59 |
+
reason="appid or appkey is not provided",
|
| 60 |
+
)
|
| 61 |
+
def test_baidu_successful_post_onetarget():
|
| 62 |
+
posted = BaiduTranslator(
|
| 63 |
+
appid=appid, appkey=appkey, source="en", target="zh"
|
| 64 |
+
).translate("Hello! How are you?")
|
| 65 |
+
assert isinstance(posted, str)
|
tests/test_google.py
CHANGED
|
@@ -46,14 +46,6 @@ def test_empty_text(google_translator):
|
|
| 46 |
|
| 47 |
|
| 48 |
def test_payload(google_translator):
|
| 49 |
-
with pytest.raises(exceptions.NotValidPayload):
|
| 50 |
-
google_translator.translate(text="1234")
|
| 51 |
-
google_translator.translate(text="{}")
|
| 52 |
-
google_translator.translate(text="%@")
|
| 53 |
-
|
| 54 |
-
with pytest.raises(exceptions.NotValidPayload):
|
| 55 |
-
google_translator.translate(text=123)
|
| 56 |
-
|
| 57 |
with pytest.raises(exceptions.NotValidPayload):
|
| 58 |
google_translator.translate(text={})
|
| 59 |
|
|
|
|
| 46 |
|
| 47 |
|
| 48 |
def test_payload(google_translator):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
with pytest.raises(exceptions.NotValidPayload):
|
| 50 |
google_translator.translate(text={})
|
| 51 |
|
tests/test_libre.py
CHANGED
|
@@ -32,9 +32,6 @@ def test_abbreviations_and_languages_mapping():
|
|
| 32 |
|
| 33 |
|
| 34 |
def test_payload(libre):
|
| 35 |
-
with pytest.raises(exceptions.NotValidPayload):
|
| 36 |
-
libre.translate(123)
|
| 37 |
-
|
| 38 |
with pytest.raises(exceptions.NotValidPayload):
|
| 39 |
libre.translate({})
|
| 40 |
|
|
|
|
| 32 |
|
| 33 |
|
| 34 |
def test_payload(libre):
|
|
|
|
|
|
|
|
|
|
| 35 |
with pytest.raises(exceptions.NotValidPayload):
|
| 36 |
libre.translate({})
|
| 37 |
|
tests/test_linguee.py
CHANGED
|
@@ -38,9 +38,6 @@ def test_inputs():
|
|
| 38 |
|
| 39 |
|
| 40 |
def test_payload(linguee):
|
| 41 |
-
with pytest.raises(exceptions.NotValidPayload):
|
| 42 |
-
linguee.translate(123)
|
| 43 |
-
|
| 44 |
with pytest.raises(exceptions.NotValidPayload):
|
| 45 |
linguee.translate({})
|
| 46 |
|
|
|
|
| 38 |
|
| 39 |
|
| 40 |
def test_payload(linguee):
|
|
|
|
|
|
|
|
|
|
| 41 |
with pytest.raises(exceptions.NotValidPayload):
|
| 42 |
linguee.translate({})
|
| 43 |
|
tests/test_mymemory.py
CHANGED
|
@@ -9,7 +9,7 @@ from deep_translator import MyMemoryTranslator, exceptions
|
|
| 9 |
|
| 10 |
@pytest.fixture
|
| 11 |
def mymemory():
|
| 12 |
-
return MyMemoryTranslator(source="en", target="fr")
|
| 13 |
|
| 14 |
|
| 15 |
def test_content(mymemory):
|
|
@@ -27,18 +27,15 @@ def test_inputs():
|
|
| 27 |
MyMemoryTranslator(source="auto", target="")
|
| 28 |
|
| 29 |
with pytest.raises(exceptions.InvalidSourceOrTargetLanguage):
|
| 30 |
-
MyMemoryTranslator(source="", target="en")
|
| 31 |
|
| 32 |
-
m1 = MyMemoryTranslator("en", "fr")
|
| 33 |
m2 = MyMemoryTranslator("english", "french")
|
| 34 |
assert m1._source == m2._source
|
| 35 |
assert m1._target == m2._target
|
| 36 |
|
| 37 |
|
| 38 |
def test_payload(mymemory):
|
| 39 |
-
with pytest.raises(exceptions.NotValidPayload):
|
| 40 |
-
mymemory.translate(text=123)
|
| 41 |
-
|
| 42 |
with pytest.raises(exceptions.NotValidPayload):
|
| 43 |
mymemory.translate(text={})
|
| 44 |
|
|
|
|
| 9 |
|
| 10 |
@pytest.fixture
|
| 11 |
def mymemory():
|
| 12 |
+
return MyMemoryTranslator(source="en-GB", target="fr-FR")
|
| 13 |
|
| 14 |
|
| 15 |
def test_content(mymemory):
|
|
|
|
| 27 |
MyMemoryTranslator(source="auto", target="")
|
| 28 |
|
| 29 |
with pytest.raises(exceptions.InvalidSourceOrTargetLanguage):
|
| 30 |
+
MyMemoryTranslator(source="", target="en-GB")
|
| 31 |
|
| 32 |
+
m1 = MyMemoryTranslator("en-GB", "fr-FR")
|
| 33 |
m2 = MyMemoryTranslator("english", "french")
|
| 34 |
assert m1._source == m2._source
|
| 35 |
assert m1._target == m2._target
|
| 36 |
|
| 37 |
|
| 38 |
def test_payload(mymemory):
|
|
|
|
|
|
|
|
|
|
| 39 |
with pytest.raises(exceptions.NotValidPayload):
|
| 40 |
mymemory.translate(text={})
|
| 41 |
|
tests/test_pons.py
CHANGED
|
@@ -36,9 +36,6 @@ def test_inputs():
|
|
| 36 |
|
| 37 |
|
| 38 |
def test_payload(pons):
|
| 39 |
-
with pytest.raises(exceptions.NotValidPayload):
|
| 40 |
-
pons.translate(123)
|
| 41 |
-
|
| 42 |
with pytest.raises(exceptions.NotValidPayload):
|
| 43 |
pons.translate({})
|
| 44 |
|
|
|
|
| 36 |
|
| 37 |
|
| 38 |
def test_payload(pons):
|
|
|
|
|
|
|
|
|
|
| 39 |
with pytest.raises(exceptions.NotValidPayload):
|
| 40 |
pons.translate({})
|
| 41 |
|