BackTranslation 0.4.0__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {backtranslation-0.4.0 → backtranslation-0.5.0}/BackTranslation/languages.py +1 -0
- {backtranslation-0.4.0 → backtranslation-0.5.0}/BackTranslation/translated.py +4 -5
- {backtranslation-0.4.0 → backtranslation-0.5.0}/BackTranslation/translation.py +55 -37
- {backtranslation-0.4.0 → backtranslation-0.5.0}/BackTranslation/translation_Baidu.py +42 -0
- {backtranslation-0.4.0 → backtranslation-0.5.0}/BackTranslation.egg-info/PKG-INFO +56 -7
- {backtranslation-0.4.0 → backtranslation-0.5.0}/PKG-INFO +56 -7
- {backtranslation-0.4.0 → backtranslation-0.5.0}/README.md +56 -7
- {backtranslation-0.4.0 → backtranslation-0.5.0}/tests/test_translated.py +13 -0
- {backtranslation-0.4.0 → backtranslation-0.5.0}/tests/test_translation.py +107 -0
- {backtranslation-0.4.0 → backtranslation-0.5.0}/tests/test_translation_baidu.py +82 -0
- {backtranslation-0.4.0 → backtranslation-0.5.0}/BackTranslation/__init__.py +0 -0
- {backtranslation-0.4.0 → backtranslation-0.5.0}/BackTranslation.egg-info/SOURCES.txt +0 -0
- {backtranslation-0.4.0 → backtranslation-0.5.0}/BackTranslation.egg-info/dependency_links.txt +0 -0
- {backtranslation-0.4.0 → backtranslation-0.5.0}/BackTranslation.egg-info/requires.txt +0 -0
- {backtranslation-0.4.0 → backtranslation-0.5.0}/BackTranslation.egg-info/top_level.txt +0 -0
- {backtranslation-0.4.0 → backtranslation-0.5.0}/LICENSE +0 -0
- {backtranslation-0.4.0 → backtranslation-0.5.0}/setup.cfg +0 -0
- {backtranslation-0.4.0 → backtranslation-0.5.0}/setup.py +0 -0
- {backtranslation-0.4.0 → backtranslation-0.5.0}/tests/__init__.py +0 -0
|
@@ -2,23 +2,22 @@ class Translated(object):
|
|
|
2
2
|
"""
|
|
3
3
|
Save the translated result
|
|
4
4
|
"""
|
|
5
|
-
def __init__(self, src_lang, tmp_lang, text, trans_text, back_text):
|
|
5
|
+
def __init__(self, src_lang, tmp_lang, text, trans_text, back_text, dst_lang=None, mode='back_translation'):
|
|
6
6
|
self.source_text = text
|
|
7
7
|
self.src = src_lang
|
|
8
8
|
self.tmp = tmp_lang
|
|
9
|
+
self.dst = dst_lang if dst_lang is not None else tmp_lang
|
|
10
|
+
self.mode = mode
|
|
9
11
|
self.tran_text = trans_text
|
|
10
12
|
self.result_text = back_text
|
|
11
13
|
|
|
12
|
-
|
|
13
14
|
def __str__(self):
|
|
14
15
|
return self.__unicode__()
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
17
|
def __unicode__(self):
|
|
19
18
|
if len(self.result_text.split(' ')) > 30:
|
|
20
19
|
show_text = ' '.join(self.result_text.split(' ')[:30])
|
|
21
20
|
show_text += '...'
|
|
22
21
|
else:
|
|
23
22
|
show_text = self.result_text
|
|
24
|
-
return u'Translated(src={src}, tmp={tmp}, result_text={text})'.format(src=self.src, tmp=self.tmp, text=show_text)
|
|
23
|
+
return u'Translated(src={src}, tmp={tmp}, result_text={text})'.format(src=self.src, tmp=self.tmp, text=show_text)
|
|
@@ -31,12 +31,8 @@ class BackTranslation(object):
|
|
|
31
31
|
self.MAX_LENGTH = 5000
|
|
32
32
|
|
|
33
33
|
def translate(self, text, src=None, tmp=None, sleeping=0):
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
src = self.translator.detect(text).lang
|
|
37
|
-
|
|
38
|
-
if src.lower() not in self.Languages:
|
|
39
|
-
raise ValueError("'{}': INVALID source language.".format(src))
|
|
34
|
+
src = self._resolve_src(text, src)
|
|
35
|
+
self._validate_language(src, 'source')
|
|
40
36
|
|
|
41
37
|
# if tmp is null, set a default language for tmp.
|
|
42
38
|
if not tmp:
|
|
@@ -45,52 +41,74 @@ class BackTranslation(object):
|
|
|
45
41
|
else:
|
|
46
42
|
tmp = 'en'
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if src == tmp:
|
|
52
|
-
raise ValueError("Transited language ({tmp}) should different from source language ({src}).".format(
|
|
53
|
-
tmp=tmp, src=src))
|
|
44
|
+
self._validate_language(tmp, 'transited')
|
|
45
|
+
self._validate_different(src, tmp, 'Transited')
|
|
54
46
|
|
|
55
47
|
# check the length of text
|
|
56
48
|
if len(text) > self.MAX_LENGTH:
|
|
57
49
|
original_sentences = self._split_segement(sent_tokenize(text))
|
|
58
50
|
|
|
59
|
-
|
|
60
|
-
t_text = self.translator.translate(original_sentences, src=src, dest=tmp)
|
|
61
|
-
except httpcore.ConnectTimeout:
|
|
62
|
-
raise httpcore.ConnectTimeout("Connection timed out. If you are blocked by Google, try using the 'proxies' parameter or a different 'url'.")
|
|
63
|
-
except Exception as e:
|
|
64
|
-
raise Exception("Translation failed (try increasing the 'sleeping' parameter): {}".format(e))
|
|
51
|
+
t_text = self._translate_with_google(original_sentences, src, tmp, 'Translation')
|
|
65
52
|
tran_text = ' '.join([t.text for t in t_text])
|
|
66
53
|
time.sleep(sleeping)
|
|
67
|
-
|
|
68
|
-
r_text = self.translator.translate([t.text for t in t_text], src=tmp, dest=src)
|
|
69
|
-
except httpcore.ConnectTimeout:
|
|
70
|
-
raise httpcore.ConnectTimeout("Connection timed out. If you are blocked by Google, try using the 'proxies' parameter or a different 'url'.")
|
|
71
|
-
except Exception as e:
|
|
72
|
-
raise Exception("Back-translation failed (try increasing the 'sleeping' parameter): {}".format(e))
|
|
54
|
+
r_text = self._translate_with_google([t.text for t in t_text], tmp, src, 'Back-translation')
|
|
73
55
|
back_text = ' '.join([r.text for r in r_text])
|
|
74
56
|
back_text.rstrip()
|
|
75
57
|
else:
|
|
76
|
-
|
|
77
|
-
mid_text = self.translator.translate(text, src=src, dest=tmp)
|
|
78
|
-
except httpcore.ConnectTimeout:
|
|
79
|
-
raise httpcore.ConnectTimeout("Connection timed out. If you are blocked by Google, try using the 'proxies' parameter or a different 'url'.")
|
|
80
|
-
except Exception as e:
|
|
81
|
-
raise Exception("Translation failed (try increasing the 'sleeping' parameter): {}".format(e))
|
|
58
|
+
mid_text = self._translate_with_google(text, src, tmp, 'Translation')
|
|
82
59
|
tran_text = mid_text.text
|
|
83
60
|
time.sleep(sleeping) # Sleep between translation
|
|
84
|
-
|
|
85
|
-
result_text = self.translator.translate(tran_text, src=tmp, dest=src)
|
|
86
|
-
except httpcore.ConnectTimeout:
|
|
87
|
-
raise httpcore.ConnectTimeout("Connection timed out. If you are blocked by Google, try using the 'proxies' parameter or a different 'url'.")
|
|
88
|
-
except Exception as e:
|
|
89
|
-
raise Exception("Back-translation failed (try increasing the 'sleeping' parameter): {}".format(e))
|
|
61
|
+
result_text = self._translate_with_google(tran_text, tmp, src, 'Back-translation')
|
|
90
62
|
back_text = result_text.text
|
|
91
|
-
result = Translated(src_lang=src, tmp_lang=tmp, text=text, trans_text=tran_text, back_text=back_text
|
|
63
|
+
result = Translated(src_lang=src, tmp_lang=tmp, text=text, trans_text=tran_text, back_text=back_text,
|
|
64
|
+
dst_lang=tmp, mode='back_translation')
|
|
92
65
|
return result
|
|
93
66
|
|
|
67
|
+
def direct_translate(self, text, src=None, dst=None, sleeping=0):
|
|
68
|
+
if not dst:
|
|
69
|
+
raise ValueError("destination language is required")
|
|
70
|
+
|
|
71
|
+
src = self._resolve_src(text, src)
|
|
72
|
+
|
|
73
|
+
self._validate_language(src, 'source')
|
|
74
|
+
self._validate_language(dst, 'destination')
|
|
75
|
+
self._validate_different(src, dst, 'Destination')
|
|
76
|
+
|
|
77
|
+
if len(text) > self.MAX_LENGTH:
|
|
78
|
+
original_sentences = self._split_segement(sent_tokenize(text))
|
|
79
|
+
translated_text = self._translate_with_google(original_sentences, src, dst, 'Translation')
|
|
80
|
+
result_text = ' '.join([t.text for t in translated_text])
|
|
81
|
+
else:
|
|
82
|
+
translated_text = self._translate_with_google(text, src, dst, 'Translation')
|
|
83
|
+
result_text = translated_text.text
|
|
84
|
+
|
|
85
|
+
result = Translated(src_lang=src, tmp_lang=dst, text=text, trans_text=result_text, back_text=result_text,
|
|
86
|
+
dst_lang=dst, mode='direct')
|
|
87
|
+
return result
|
|
88
|
+
|
|
89
|
+
def _resolve_src(self, text, src):
|
|
90
|
+
if not src:
|
|
91
|
+
return self.translator.detect(text).lang
|
|
92
|
+
return src
|
|
93
|
+
|
|
94
|
+
def _validate_language(self, language, language_type):
|
|
95
|
+
if language.lower() not in self.Languages:
|
|
96
|
+
raise ValueError("'{}': INVALID {} language.".format(language, language_type))
|
|
97
|
+
|
|
98
|
+
def _validate_different(self, src, dst, dst_label):
|
|
99
|
+
if src == dst:
|
|
100
|
+
raise ValueError("{} language ({dst}) should different from source language ({src}).".format(
|
|
101
|
+
dst_label, dst=dst, src=src))
|
|
102
|
+
|
|
103
|
+
def _translate_with_google(self, text, src, dst, action):
|
|
104
|
+
try:
|
|
105
|
+
return self.translator.translate(text, src=src, dest=dst)
|
|
106
|
+
except httpcore.ConnectTimeout:
|
|
107
|
+
raise httpcore.ConnectTimeout(
|
|
108
|
+
"Connection timed out. If you are blocked by Google, try using the 'proxies' parameter or a different 'url'.")
|
|
109
|
+
except Exception as e:
|
|
110
|
+
raise Exception("{} failed (try increasing the 'sleeping' parameter): {}".format(action, e))
|
|
111
|
+
|
|
94
112
|
def _split_segement(self, sentences):
|
|
95
113
|
"""
|
|
96
114
|
Split the long sentences into multiple sentences whose lengths are less than MAX_LENGTH.
|
|
@@ -72,6 +72,48 @@ class BackTranslation_Baidu(object):
|
|
|
72
72
|
result = Translated(src_lang=src, tmp_lang=tmp, text=text, trans_text=tran_text, back_text=back_text)
|
|
73
73
|
return result
|
|
74
74
|
|
|
75
|
+
def direct_translate(self, text, src='auto', dst=None, sleeping=1):
|
|
76
|
+
if not dst:
|
|
77
|
+
raise ValueError("destination language is required")
|
|
78
|
+
|
|
79
|
+
if src == dst:
|
|
80
|
+
raise ValueError(
|
|
81
|
+
"Destination language ({dst}) should different from source language ({src}).".format(dst=dst, src=src))
|
|
82
|
+
|
|
83
|
+
if len(text.encode('utf-8')) > self.MAX_LENGTH:
|
|
84
|
+
original_sentences = [
|
|
85
|
+
sentence for sentence in self._split_segement(sent_tokenize(text))
|
|
86
|
+
if sentence != ""
|
|
87
|
+
]
|
|
88
|
+
tran_text = []
|
|
89
|
+
resolved_src = src
|
|
90
|
+
for index, sentence in enumerate(original_sentences):
|
|
91
|
+
result = self._sendRequest(sentence, resolved_src, dst)
|
|
92
|
+
if resolved_src == 'auto':
|
|
93
|
+
resolved_src = self._get_srcLang(result)
|
|
94
|
+
if resolved_src == dst:
|
|
95
|
+
raise ValueError(
|
|
96
|
+
"Destination language ({dst}) should different from source language ({src}).".format(
|
|
97
|
+
dst=dst, src=resolved_src))
|
|
98
|
+
tran_text.append(self._get_translatedText(result))
|
|
99
|
+
if index < len(original_sentences) - 1:
|
|
100
|
+
time.sleep(sleeping)
|
|
101
|
+
tran_text = ' '.join(tran_text)
|
|
102
|
+
src = resolved_src
|
|
103
|
+
else:
|
|
104
|
+
result = self._sendRequest(text, src, dst)
|
|
105
|
+
if src == 'auto':
|
|
106
|
+
src = self._get_srcLang(result)
|
|
107
|
+
if src == dst:
|
|
108
|
+
raise ValueError(
|
|
109
|
+
"Destination language ({dst}) should different from source language ({src}).".format(
|
|
110
|
+
dst=dst, src=src))
|
|
111
|
+
tran_text = self._get_translatedText(result)
|
|
112
|
+
|
|
113
|
+
result = Translated(src_lang=src, tmp_lang=dst, text=text, trans_text=tran_text, back_text=tran_text,
|
|
114
|
+
dst_lang=dst, mode='direct')
|
|
115
|
+
return result
|
|
116
|
+
|
|
75
117
|
def _sendRequest(self, text, src, tmp):
|
|
76
118
|
salt = random.randint(32768, 65536)
|
|
77
119
|
sign = hashlib.md5((self.appid + text + str(salt) + self.secretKey).encode()).hexdigest()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: BackTranslation
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Back translation for Natural Language Processing (NLP) using Google Translate
|
|
5
5
|
Home-page: https://github.com/hhhwwwuuu/BackTranslation
|
|
6
6
|
Author: Zhiqiang Wu
|
|
@@ -30,11 +30,11 @@ Dynamic: requires-python
|
|
|
30
30
|
Dynamic: summary
|
|
31
31
|
|
|
32
32
|
# BackTranslation
|
|
33
|
-
[](https://pypi.org/project/BackTranslation/#description)
|
|
34
34
|
[](https://pepy.tech/project/backtranslation)
|
|
35
35
|
[](https://github.com/hhhwwwuuu/BackTranslation/blob/main/LICENSE)
|
|
36
36
|
|
|
37
|
-
BackTranslation is a python library that
|
|
37
|
+
BackTranslation is a python library that implements back translation and direct translation among languages. It utilizes the [googletrans](https://py-googletrans.readthedocs.io/en/latest/) library and [Baidu Translation API](http://api.fanyi.baidu.com/) to translate text.
|
|
38
38
|
|
|
39
39
|
Since there is an error in current verison of googletrans, you have to create only one instance to do back-translation for your work. Otherwise, it is easy to cause a bug from multi-requests. We will keep implementing this library with other translator libraries soon.
|
|
40
40
|
|
|
@@ -49,6 +49,37 @@ $ pip install BackTranslation
|
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
## Usage
|
|
52
|
+
### Direct translation with googletrans
|
|
53
|
+
Translate text from language A directly to language B without translating it back.
|
|
54
|
+
|
|
55
|
+
Parameters:
|
|
56
|
+
* **url**: option. provide a list of services urls for translation if need. Default url is _translate.google.com_.
|
|
57
|
+
* **proxies**: Optional. Proxies configuration. Dictionary mapping protocol or protocol and host to the URL of the proxy.
|
|
58
|
+
i.e. proxies = {'http': '127.0.0.1:1234', 'http://host.name': '127.0.0.1:4012'}
|
|
59
|
+
* **text**: required. Original text that need to translate.
|
|
60
|
+
* **src**: option. Source language code of original text. If this parameter is None, the method will detect the language of text automatically. (Default: None)
|
|
61
|
+
* **dst**: required. Destination language code.
|
|
62
|
+
* **sleeping**: option. Kept for API consistency. Direct translation only sends the A-to-B request. (Default: 0)
|
|
63
|
+
|
|
64
|
+
Return parameter: object _Translated_.
|
|
65
|
+
|
|
66
|
+
Attributes:
|
|
67
|
+
* source_text: original sentence.
|
|
68
|
+
* src: the language of original sentence.
|
|
69
|
+
* dst: the target language.
|
|
70
|
+
* tmp: the same as dst for direct translation.
|
|
71
|
+
* tran_text: translated result in dst language.
|
|
72
|
+
* result_text: translated result in dst language.
|
|
73
|
+
* mode: _direct_.
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from BackTranslation import BackTranslation
|
|
77
|
+
trans = BackTranslation()
|
|
78
|
+
result = trans.direct_translate('hello', src='en', dst='zh-cn')
|
|
79
|
+
print(result.result_text)
|
|
80
|
+
# '你好'
|
|
81
|
+
```
|
|
82
|
+
|
|
52
83
|
### Backtranslation with googletrans
|
|
53
84
|
Translate the original text to other language and translate back to augment the diversity of data in NLP research.
|
|
54
85
|
|
|
@@ -67,8 +98,10 @@ Attributes:
|
|
|
67
98
|
* source_text: original sentence.
|
|
68
99
|
* src: the language of original sentence
|
|
69
100
|
* tmp: the target language as middle man
|
|
70
|
-
*
|
|
71
|
-
*
|
|
101
|
+
* dst: the same as tmp for back-translation
|
|
102
|
+
* tran_text: intermediate result
|
|
103
|
+
* result_text: back-translated result
|
|
104
|
+
* mode: _back_translation_
|
|
72
105
|
|
|
73
106
|
```python
|
|
74
107
|
from BackTranslation import BackTranslation
|
|
@@ -113,7 +146,9 @@ Parameters:
|
|
|
113
146
|
from BackTranslation import BackTranslation
|
|
114
147
|
trans = BackTranslation()
|
|
115
148
|
trans.searchLanguage('Chinese')
|
|
116
|
-
# {'chinese (simplified)': 'zh-cn', 'chinese (traditional)': 'zh-tw'}
|
|
149
|
+
# {'chinese (simplified)': 'zh-cn', 'chinese (traditional)': 'zh-tw', 'chinese (cantonese)': 'yue'}
|
|
150
|
+
trans.searchLanguage('Cantonese')
|
|
151
|
+
# {'chinese (cantonese)': 'yue'}
|
|
117
152
|
```
|
|
118
153
|
### Backtranslation_Baidu with Baidu Translation API
|
|
119
154
|
To use this stable translation, you are required to register in [Baidu Translation API]((http://api.fanyi.baidu.com/)) for getting your own appID.
|
|
@@ -121,6 +156,16 @@ It supports 2 million chacters per day for free.
|
|
|
121
156
|
_Note: Currently, they only support Chinese phone number to register the accout._
|
|
122
157
|
* **sleeping**: option. Baidu standard API allows only 1 request per second (QPS limit). Set `sleeping=1` (default) to stay within the limit. Increase if you encounter errors. (Default: 1)
|
|
123
158
|
|
|
159
|
+
Direct translation:
|
|
160
|
+
````python
|
|
161
|
+
from BackTranslation import BackTranslation_Baidu
|
|
162
|
+
trans = BackTranslation_Baidu(appid='YOUR APPID', secretKey='YOUR SECRETKEY')
|
|
163
|
+
result = trans.direct_translate('hello', src='en', dst='zh')
|
|
164
|
+
print(result.result_text) # direct translated result
|
|
165
|
+
trans.closeHTTP()
|
|
166
|
+
````
|
|
167
|
+
|
|
168
|
+
Back-translation:
|
|
124
169
|
````python
|
|
125
170
|
from BackTranslation import BackTranslation_Baidu
|
|
126
171
|
trans = BackTranslation_Baidu(appid='YOUR APPID', secretKey='YOUR SECRETKEY')
|
|
@@ -134,7 +179,11 @@ Since Baidu provides the different language code, it will be updated soon.
|
|
|
134
179
|
|
|
135
180
|
|
|
136
181
|
## Version Information
|
|
137
|
-
**Version 0.
|
|
182
|
+
**Version 0.5.0: add direct translation APIs for Google and Baidu translators, keep existing back-translation behavior compatible, extend `Translated` with `dst` and `mode`, add Cantonese (`yue`) language support, and update tests and documentation.**
|
|
183
|
+
|
|
184
|
+
Version 0.4.0: fix bugs (#1 #2 #3 #4 #6), add automated tests and CI/CD pipeline.
|
|
185
|
+
|
|
186
|
+
Version 0.3.1: fix some bugs for Baidu translator.
|
|
138
187
|
|
|
139
188
|
Version 0.2.2: fix the services url for Google Translator.
|
|
140
189
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: BackTranslation
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Back translation for Natural Language Processing (NLP) using Google Translate
|
|
5
5
|
Home-page: https://github.com/hhhwwwuuu/BackTranslation
|
|
6
6
|
Author: Zhiqiang Wu
|
|
@@ -30,11 +30,11 @@ Dynamic: requires-python
|
|
|
30
30
|
Dynamic: summary
|
|
31
31
|
|
|
32
32
|
# BackTranslation
|
|
33
|
-
[](https://pypi.org/project/BackTranslation/#description)
|
|
34
34
|
[](https://pepy.tech/project/backtranslation)
|
|
35
35
|
[](https://github.com/hhhwwwuuu/BackTranslation/blob/main/LICENSE)
|
|
36
36
|
|
|
37
|
-
BackTranslation is a python library that
|
|
37
|
+
BackTranslation is a python library that implements back translation and direct translation among languages. It utilizes the [googletrans](https://py-googletrans.readthedocs.io/en/latest/) library and [Baidu Translation API](http://api.fanyi.baidu.com/) to translate text.
|
|
38
38
|
|
|
39
39
|
Since there is an error in current verison of googletrans, you have to create only one instance to do back-translation for your work. Otherwise, it is easy to cause a bug from multi-requests. We will keep implementing this library with other translator libraries soon.
|
|
40
40
|
|
|
@@ -49,6 +49,37 @@ $ pip install BackTranslation
|
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
## Usage
|
|
52
|
+
### Direct translation with googletrans
|
|
53
|
+
Translate text from language A directly to language B without translating it back.
|
|
54
|
+
|
|
55
|
+
Parameters:
|
|
56
|
+
* **url**: option. provide a list of services urls for translation if need. Default url is _translate.google.com_.
|
|
57
|
+
* **proxies**: Optional. Proxies configuration. Dictionary mapping protocol or protocol and host to the URL of the proxy.
|
|
58
|
+
i.e. proxies = {'http': '127.0.0.1:1234', 'http://host.name': '127.0.0.1:4012'}
|
|
59
|
+
* **text**: required. Original text that need to translate.
|
|
60
|
+
* **src**: option. Source language code of original text. If this parameter is None, the method will detect the language of text automatically. (Default: None)
|
|
61
|
+
* **dst**: required. Destination language code.
|
|
62
|
+
* **sleeping**: option. Kept for API consistency. Direct translation only sends the A-to-B request. (Default: 0)
|
|
63
|
+
|
|
64
|
+
Return parameter: object _Translated_.
|
|
65
|
+
|
|
66
|
+
Attributes:
|
|
67
|
+
* source_text: original sentence.
|
|
68
|
+
* src: the language of original sentence.
|
|
69
|
+
* dst: the target language.
|
|
70
|
+
* tmp: the same as dst for direct translation.
|
|
71
|
+
* tran_text: translated result in dst language.
|
|
72
|
+
* result_text: translated result in dst language.
|
|
73
|
+
* mode: _direct_.
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from BackTranslation import BackTranslation
|
|
77
|
+
trans = BackTranslation()
|
|
78
|
+
result = trans.direct_translate('hello', src='en', dst='zh-cn')
|
|
79
|
+
print(result.result_text)
|
|
80
|
+
# '你好'
|
|
81
|
+
```
|
|
82
|
+
|
|
52
83
|
### Backtranslation with googletrans
|
|
53
84
|
Translate the original text to other language and translate back to augment the diversity of data in NLP research.
|
|
54
85
|
|
|
@@ -67,8 +98,10 @@ Attributes:
|
|
|
67
98
|
* source_text: original sentence.
|
|
68
99
|
* src: the language of original sentence
|
|
69
100
|
* tmp: the target language as middle man
|
|
70
|
-
*
|
|
71
|
-
*
|
|
101
|
+
* dst: the same as tmp for back-translation
|
|
102
|
+
* tran_text: intermediate result
|
|
103
|
+
* result_text: back-translated result
|
|
104
|
+
* mode: _back_translation_
|
|
72
105
|
|
|
73
106
|
```python
|
|
74
107
|
from BackTranslation import BackTranslation
|
|
@@ -113,7 +146,9 @@ Parameters:
|
|
|
113
146
|
from BackTranslation import BackTranslation
|
|
114
147
|
trans = BackTranslation()
|
|
115
148
|
trans.searchLanguage('Chinese')
|
|
116
|
-
# {'chinese (simplified)': 'zh-cn', 'chinese (traditional)': 'zh-tw'}
|
|
149
|
+
# {'chinese (simplified)': 'zh-cn', 'chinese (traditional)': 'zh-tw', 'chinese (cantonese)': 'yue'}
|
|
150
|
+
trans.searchLanguage('Cantonese')
|
|
151
|
+
# {'chinese (cantonese)': 'yue'}
|
|
117
152
|
```
|
|
118
153
|
### Backtranslation_Baidu with Baidu Translation API
|
|
119
154
|
To use this stable translation, you are required to register in [Baidu Translation API]((http://api.fanyi.baidu.com/)) for getting your own appID.
|
|
@@ -121,6 +156,16 @@ It supports 2 million chacters per day for free.
|
|
|
121
156
|
_Note: Currently, they only support Chinese phone number to register the accout._
|
|
122
157
|
* **sleeping**: option. Baidu standard API allows only 1 request per second (QPS limit). Set `sleeping=1` (default) to stay within the limit. Increase if you encounter errors. (Default: 1)
|
|
123
158
|
|
|
159
|
+
Direct translation:
|
|
160
|
+
````python
|
|
161
|
+
from BackTranslation import BackTranslation_Baidu
|
|
162
|
+
trans = BackTranslation_Baidu(appid='YOUR APPID', secretKey='YOUR SECRETKEY')
|
|
163
|
+
result = trans.direct_translate('hello', src='en', dst='zh')
|
|
164
|
+
print(result.result_text) # direct translated result
|
|
165
|
+
trans.closeHTTP()
|
|
166
|
+
````
|
|
167
|
+
|
|
168
|
+
Back-translation:
|
|
124
169
|
````python
|
|
125
170
|
from BackTranslation import BackTranslation_Baidu
|
|
126
171
|
trans = BackTranslation_Baidu(appid='YOUR APPID', secretKey='YOUR SECRETKEY')
|
|
@@ -134,7 +179,11 @@ Since Baidu provides the different language code, it will be updated soon.
|
|
|
134
179
|
|
|
135
180
|
|
|
136
181
|
## Version Information
|
|
137
|
-
**Version 0.
|
|
182
|
+
**Version 0.5.0: add direct translation APIs for Google and Baidu translators, keep existing back-translation behavior compatible, extend `Translated` with `dst` and `mode`, add Cantonese (`yue`) language support, and update tests and documentation.**
|
|
183
|
+
|
|
184
|
+
Version 0.4.0: fix bugs (#1 #2 #3 #4 #6), add automated tests and CI/CD pipeline.
|
|
185
|
+
|
|
186
|
+
Version 0.3.1: fix some bugs for Baidu translator.
|
|
138
187
|
|
|
139
188
|
Version 0.2.2: fix the services url for Google Translator.
|
|
140
189
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# BackTranslation
|
|
2
|
-
[](https://pypi.org/project/BackTranslation/#description)
|
|
3
3
|
[](https://pepy.tech/project/backtranslation)
|
|
4
4
|
[](https://github.com/hhhwwwuuu/BackTranslation/blob/main/LICENSE)
|
|
5
5
|
|
|
6
|
-
BackTranslation is a python library that
|
|
6
|
+
BackTranslation is a python library that implements back translation and direct translation among languages. It utilizes the [googletrans](https://py-googletrans.readthedocs.io/en/latest/) library and [Baidu Translation API](http://api.fanyi.baidu.com/) to translate text.
|
|
7
7
|
|
|
8
8
|
Since there is an error in current verison of googletrans, you have to create only one instance to do back-translation for your work. Otherwise, it is easy to cause a bug from multi-requests. We will keep implementing this library with other translator libraries soon.
|
|
9
9
|
|
|
@@ -18,6 +18,37 @@ $ pip install BackTranslation
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
## Usage
|
|
21
|
+
### Direct translation with googletrans
|
|
22
|
+
Translate text from language A directly to language B without translating it back.
|
|
23
|
+
|
|
24
|
+
Parameters:
|
|
25
|
+
* **url**: option. provide a list of services urls for translation if need. Default url is _translate.google.com_.
|
|
26
|
+
* **proxies**: Optional. Proxies configuration. Dictionary mapping protocol or protocol and host to the URL of the proxy.
|
|
27
|
+
i.e. proxies = {'http': '127.0.0.1:1234', 'http://host.name': '127.0.0.1:4012'}
|
|
28
|
+
* **text**: required. Original text that need to translate.
|
|
29
|
+
* **src**: option. Source language code of original text. If this parameter is None, the method will detect the language of text automatically. (Default: None)
|
|
30
|
+
* **dst**: required. Destination language code.
|
|
31
|
+
* **sleeping**: option. Kept for API consistency. Direct translation only sends the A-to-B request. (Default: 0)
|
|
32
|
+
|
|
33
|
+
Return parameter: object _Translated_.
|
|
34
|
+
|
|
35
|
+
Attributes:
|
|
36
|
+
* source_text: original sentence.
|
|
37
|
+
* src: the language of original sentence.
|
|
38
|
+
* dst: the target language.
|
|
39
|
+
* tmp: the same as dst for direct translation.
|
|
40
|
+
* tran_text: translated result in dst language.
|
|
41
|
+
* result_text: translated result in dst language.
|
|
42
|
+
* mode: _direct_.
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from BackTranslation import BackTranslation
|
|
46
|
+
trans = BackTranslation()
|
|
47
|
+
result = trans.direct_translate('hello', src='en', dst='zh-cn')
|
|
48
|
+
print(result.result_text)
|
|
49
|
+
# '你好'
|
|
50
|
+
```
|
|
51
|
+
|
|
21
52
|
### Backtranslation with googletrans
|
|
22
53
|
Translate the original text to other language and translate back to augment the diversity of data in NLP research.
|
|
23
54
|
|
|
@@ -36,8 +67,10 @@ Attributes:
|
|
|
36
67
|
* source_text: original sentence.
|
|
37
68
|
* src: the language of original sentence
|
|
38
69
|
* tmp: the target language as middle man
|
|
39
|
-
*
|
|
40
|
-
*
|
|
70
|
+
* dst: the same as tmp for back-translation
|
|
71
|
+
* tran_text: intermediate result
|
|
72
|
+
* result_text: back-translated result
|
|
73
|
+
* mode: _back_translation_
|
|
41
74
|
|
|
42
75
|
```python
|
|
43
76
|
from BackTranslation import BackTranslation
|
|
@@ -82,7 +115,9 @@ Parameters:
|
|
|
82
115
|
from BackTranslation import BackTranslation
|
|
83
116
|
trans = BackTranslation()
|
|
84
117
|
trans.searchLanguage('Chinese')
|
|
85
|
-
# {'chinese (simplified)': 'zh-cn', 'chinese (traditional)': 'zh-tw'}
|
|
118
|
+
# {'chinese (simplified)': 'zh-cn', 'chinese (traditional)': 'zh-tw', 'chinese (cantonese)': 'yue'}
|
|
119
|
+
trans.searchLanguage('Cantonese')
|
|
120
|
+
# {'chinese (cantonese)': 'yue'}
|
|
86
121
|
```
|
|
87
122
|
### Backtranslation_Baidu with Baidu Translation API
|
|
88
123
|
To use this stable translation, you are required to register in [Baidu Translation API]((http://api.fanyi.baidu.com/)) for getting your own appID.
|
|
@@ -90,6 +125,16 @@ It supports 2 million chacters per day for free.
|
|
|
90
125
|
_Note: Currently, they only support Chinese phone number to register the accout._
|
|
91
126
|
* **sleeping**: option. Baidu standard API allows only 1 request per second (QPS limit). Set `sleeping=1` (default) to stay within the limit. Increase if you encounter errors. (Default: 1)
|
|
92
127
|
|
|
128
|
+
Direct translation:
|
|
129
|
+
````python
|
|
130
|
+
from BackTranslation import BackTranslation_Baidu
|
|
131
|
+
trans = BackTranslation_Baidu(appid='YOUR APPID', secretKey='YOUR SECRETKEY')
|
|
132
|
+
result = trans.direct_translate('hello', src='en', dst='zh')
|
|
133
|
+
print(result.result_text) # direct translated result
|
|
134
|
+
trans.closeHTTP()
|
|
135
|
+
````
|
|
136
|
+
|
|
137
|
+
Back-translation:
|
|
93
138
|
````python
|
|
94
139
|
from BackTranslation import BackTranslation_Baidu
|
|
95
140
|
trans = BackTranslation_Baidu(appid='YOUR APPID', secretKey='YOUR SECRETKEY')
|
|
@@ -103,7 +148,11 @@ Since Baidu provides the different language code, it will be updated soon.
|
|
|
103
148
|
|
|
104
149
|
|
|
105
150
|
## Version Information
|
|
106
|
-
**Version 0.
|
|
151
|
+
**Version 0.5.0: add direct translation APIs for Google and Baidu translators, keep existing back-translation behavior compatible, extend `Translated` with `dst` and `mode`, add Cantonese (`yue`) language support, and update tests and documentation.**
|
|
152
|
+
|
|
153
|
+
Version 0.4.0: fix bugs (#1 #2 #3 #4 #6), add automated tests and CI/CD pipeline.
|
|
154
|
+
|
|
155
|
+
Version 0.3.1: fix some bugs for Baidu translator.
|
|
107
156
|
|
|
108
157
|
Version 0.2.2: fix the services url for Google Translator.
|
|
109
158
|
|
|
@@ -118,4 +167,4 @@ Welcome to contribute BackTranslation library!
|
|
|
118
167
|
|
|
119
168
|
## reference
|
|
120
169
|
- [googletrans](https://py-googletrans.readthedocs.io/en/latest/)
|
|
121
|
-
- [Baidu Translation API](http://api.fanyi.baidu.com/)
|
|
170
|
+
- [Baidu Translation API](http://api.fanyi.baidu.com/)
|
|
@@ -11,10 +11,23 @@ def test_attributes():
|
|
|
11
11
|
assert r.source_text == 'hello'
|
|
12
12
|
assert r.src == 'en'
|
|
13
13
|
assert r.tmp == 'zh-cn'
|
|
14
|
+
assert r.dst == 'zh-cn'
|
|
15
|
+
assert r.mode == 'back_translation'
|
|
14
16
|
assert r.tran_text == '你好'
|
|
15
17
|
assert r.result_text == 'hello there'
|
|
16
18
|
|
|
17
19
|
|
|
20
|
+
def test_direct_attributes():
|
|
21
|
+
r = Translated(src_lang='en', tmp_lang='zh-cn', text='hello', trans_text='你好',
|
|
22
|
+
back_text='你好', dst_lang='zh-cn', mode='direct')
|
|
23
|
+
assert r.src == 'en'
|
|
24
|
+
assert r.tmp == 'zh-cn'
|
|
25
|
+
assert r.dst == 'zh-cn'
|
|
26
|
+
assert r.mode == 'direct'
|
|
27
|
+
assert r.tran_text == '你好'
|
|
28
|
+
assert r.result_text == '你好'
|
|
29
|
+
|
|
30
|
+
|
|
18
31
|
def test_str_short():
|
|
19
32
|
r = make_result('hello there')
|
|
20
33
|
s = str(r)
|
|
@@ -46,6 +46,32 @@ def test_basic_translation():
|
|
|
46
46
|
assert result.result_text == 'Hello there'
|
|
47
47
|
|
|
48
48
|
|
|
49
|
+
def test_direct_translation():
|
|
50
|
+
trans, mock_translator = _build_trans()
|
|
51
|
+
mock_translator.translate.return_value = _make_translate_result('你好')
|
|
52
|
+
result = trans.direct_translate('hello', src='en', dst='zh-cn')
|
|
53
|
+
assert result.src == 'en'
|
|
54
|
+
assert result.tmp == 'zh-cn'
|
|
55
|
+
assert result.dst == 'zh-cn'
|
|
56
|
+
assert result.mode == 'direct'
|
|
57
|
+
assert result.source_text == 'hello'
|
|
58
|
+
assert result.tran_text == '你好'
|
|
59
|
+
assert result.result_text == '你好'
|
|
60
|
+
mock_translator.translate.assert_called_once_with('hello', src='en', dest='zh-cn')
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_direct_translation_to_cantonese():
|
|
64
|
+
trans, mock_translator = _build_trans()
|
|
65
|
+
mock_translator.translate.return_value = _make_translate_result('你好')
|
|
66
|
+
result = trans.direct_translate('hello', src='en', dst='yue')
|
|
67
|
+
assert result.src == 'en'
|
|
68
|
+
assert result.tmp == 'yue'
|
|
69
|
+
assert result.dst == 'yue'
|
|
70
|
+
assert result.mode == 'direct'
|
|
71
|
+
assert result.result_text == '你好'
|
|
72
|
+
mock_translator.translate.assert_called_once_with('hello', src='en', dest='yue')
|
|
73
|
+
|
|
74
|
+
|
|
49
75
|
def test_auto_detect_src():
|
|
50
76
|
trans, mock_translator = _build_trans()
|
|
51
77
|
mock_translator.translate.side_effect = [
|
|
@@ -56,6 +82,14 @@ def test_auto_detect_src():
|
|
|
56
82
|
assert result.src == 'en'
|
|
57
83
|
|
|
58
84
|
|
|
85
|
+
def test_direct_auto_detect_src():
|
|
86
|
+
trans, mock_translator = _build_trans()
|
|
87
|
+
mock_translator.translate.return_value = _make_translate_result('你好')
|
|
88
|
+
result = trans.direct_translate('hello', dst='zh-cn')
|
|
89
|
+
assert result.src == 'en'
|
|
90
|
+
mock_translator.detect.assert_called_once_with('hello')
|
|
91
|
+
|
|
92
|
+
|
|
59
93
|
def test_default_tmp_when_src_en():
|
|
60
94
|
trans, mock_translator = _build_trans()
|
|
61
95
|
mock_translator.translate.side_effect = [
|
|
@@ -76,24 +110,62 @@ def test_default_tmp_when_src_not_en():
|
|
|
76
110
|
assert result.tmp == 'en'
|
|
77
111
|
|
|
78
112
|
|
|
113
|
+
def test_back_translation_with_cantonese_tmp():
|
|
114
|
+
trans, mock_translator = _build_trans()
|
|
115
|
+
mock_translator.translate.side_effect = [
|
|
116
|
+
_make_translate_result('你好'),
|
|
117
|
+
_make_translate_result('Hello there'),
|
|
118
|
+
]
|
|
119
|
+
result = trans.translate('hello', src='en', tmp='yue')
|
|
120
|
+
assert result.src == 'en'
|
|
121
|
+
assert result.tmp == 'yue'
|
|
122
|
+
assert result.dst == 'yue'
|
|
123
|
+
assert result.tran_text == '你好'
|
|
124
|
+
assert result.result_text == 'Hello there'
|
|
125
|
+
|
|
126
|
+
|
|
79
127
|
def test_invalid_src_raises():
|
|
80
128
|
trans, _ = _build_trans()
|
|
81
129
|
with pytest.raises(ValueError, match='INVALID source language'):
|
|
82
130
|
trans.translate('hello', src='xx')
|
|
83
131
|
|
|
84
132
|
|
|
133
|
+
def test_direct_missing_dst_raises():
|
|
134
|
+
trans, _ = _build_trans()
|
|
135
|
+
with pytest.raises(ValueError, match='destination language is required'):
|
|
136
|
+
trans.direct_translate('hello', src='en')
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def test_direct_invalid_src_raises():
|
|
140
|
+
trans, _ = _build_trans()
|
|
141
|
+
with pytest.raises(ValueError, match='INVALID source language'):
|
|
142
|
+
trans.direct_translate('hello', src='xx', dst='zh-cn')
|
|
143
|
+
|
|
144
|
+
|
|
85
145
|
def test_invalid_tmp_raises():
|
|
86
146
|
trans, _ = _build_trans()
|
|
87
147
|
with pytest.raises(ValueError, match='INVALID transited language'):
|
|
88
148
|
trans.translate('hello', src='en', tmp='xx')
|
|
89
149
|
|
|
90
150
|
|
|
151
|
+
def test_direct_invalid_dst_raises():
|
|
152
|
+
trans, _ = _build_trans()
|
|
153
|
+
with pytest.raises(ValueError, match='INVALID destination language'):
|
|
154
|
+
trans.direct_translate('hello', src='en', dst='xx')
|
|
155
|
+
|
|
156
|
+
|
|
91
157
|
def test_same_src_tmp_raises():
|
|
92
158
|
trans, _ = _build_trans()
|
|
93
159
|
with pytest.raises(ValueError, match='should different'):
|
|
94
160
|
trans.translate('hello', src='en', tmp='en')
|
|
95
161
|
|
|
96
162
|
|
|
163
|
+
def test_direct_same_src_dst_raises():
|
|
164
|
+
trans, _ = _build_trans()
|
|
165
|
+
with pytest.raises(ValueError, match='should different'):
|
|
166
|
+
trans.direct_translate('hello', src='en', dst='en')
|
|
167
|
+
|
|
168
|
+
|
|
97
169
|
def test_sleeping_is_called(mocker):
|
|
98
170
|
trans, mock_translator = _build_trans()
|
|
99
171
|
mock_translator.translate.side_effect = [
|
|
@@ -112,6 +184,13 @@ def test_connect_timeout_raises_friendly_message():
|
|
|
112
184
|
trans.translate('hello', src='en', tmp='zh-cn')
|
|
113
185
|
|
|
114
186
|
|
|
187
|
+
def test_direct_connect_timeout_raises_friendly_message():
|
|
188
|
+
trans, mock_translator = _build_trans()
|
|
189
|
+
mock_translator.translate.side_effect = httpcore.ConnectTimeout()
|
|
190
|
+
with pytest.raises(httpcore.ConnectTimeout, match='proxies'):
|
|
191
|
+
trans.direct_translate('hello', src='en', dst='zh-cn')
|
|
192
|
+
|
|
193
|
+
|
|
115
194
|
def test_general_exception_raises_with_hint():
|
|
116
195
|
trans, mock_translator = _build_trans()
|
|
117
196
|
mock_translator.translate.side_effect = Exception('some googletrans error')
|
|
@@ -119,10 +198,24 @@ def test_general_exception_raises_with_hint():
|
|
|
119
198
|
trans.translate('hello', src='en', tmp='zh-cn')
|
|
120
199
|
|
|
121
200
|
|
|
201
|
+
def test_direct_general_exception_raises_with_hint():
|
|
202
|
+
trans, mock_translator = _build_trans()
|
|
203
|
+
mock_translator.translate.side_effect = Exception('some googletrans error')
|
|
204
|
+
with pytest.raises(Exception, match="sleeping"):
|
|
205
|
+
trans.direct_translate('hello', src='en', dst='zh-cn')
|
|
206
|
+
|
|
207
|
+
|
|
122
208
|
def test_search_language():
|
|
123
209
|
trans, _ = _build_trans()
|
|
124
210
|
result = trans.searchLanguage('Chinese')
|
|
125
211
|
assert 'zh-cn' in result.values()
|
|
212
|
+
assert 'yue' in result.values()
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def test_search_cantonese_language():
|
|
216
|
+
trans, _ = _build_trans()
|
|
217
|
+
result = trans.searchLanguage('Cantonese')
|
|
218
|
+
assert result == {'chinese (cantonese)': 'yue'}
|
|
126
219
|
|
|
127
220
|
|
|
128
221
|
def test_search_language_not_found():
|
|
@@ -146,3 +239,17 @@ def test_long_text_split(mocker):
|
|
|
146
239
|
result = trans.translate(long_text, src='en', tmp='zh-cn')
|
|
147
240
|
assert result.src == 'en'
|
|
148
241
|
assert mock_sleep.called
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def test_direct_long_text_split(mocker):
|
|
245
|
+
trans, mock_translator = _build_trans()
|
|
246
|
+
long_text = 'Hello world. ' * 500
|
|
247
|
+
sentences = ['Hello world. ' * 250, 'Hello world. ' * 250]
|
|
248
|
+
mock_translator.translate.return_value = [
|
|
249
|
+
_make_translate_result('你好一'),
|
|
250
|
+
_make_translate_result('你好二'),
|
|
251
|
+
]
|
|
252
|
+
mocker.patch('BackTranslation.translation.sent_tokenize', return_value=sentences)
|
|
253
|
+
result = trans.direct_translate(long_text, src='en', dst='zh-cn')
|
|
254
|
+
assert result.result_text == '你好一 你好二'
|
|
255
|
+
mock_translator.translate.assert_called_once_with([s.rstrip() for s in sentences], src='en', dest='zh-cn')
|
|
@@ -32,6 +32,29 @@ def test_basic_translation(trans):
|
|
|
32
32
|
assert result.result_text == 'Hello there'
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
def test_direct_translation(trans):
|
|
36
|
+
trans._sendRequest.return_value = _mock_response('en', '你好')
|
|
37
|
+
result = trans.direct_translate('hello', src='en', dst='zh')
|
|
38
|
+
assert result.src == 'en'
|
|
39
|
+
assert result.tmp == 'zh'
|
|
40
|
+
assert result.dst == 'zh'
|
|
41
|
+
assert result.mode == 'direct'
|
|
42
|
+
assert result.tran_text == '你好'
|
|
43
|
+
assert result.result_text == '你好'
|
|
44
|
+
trans._sendRequest.assert_called_once_with('hello', 'en', 'zh')
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_direct_translation_to_cantonese(trans):
|
|
48
|
+
trans._sendRequest.return_value = _mock_response('en', '你好')
|
|
49
|
+
result = trans.direct_translate('hello', src='en', dst='yue')
|
|
50
|
+
assert result.src == 'en'
|
|
51
|
+
assert result.tmp == 'yue'
|
|
52
|
+
assert result.dst == 'yue'
|
|
53
|
+
assert result.mode == 'direct'
|
|
54
|
+
assert result.result_text == '你好'
|
|
55
|
+
trans._sendRequest.assert_called_once_with('hello', 'en', 'yue')
|
|
56
|
+
|
|
57
|
+
|
|
35
58
|
def test_back_translation_uses_tran_text_not_original(trans):
|
|
36
59
|
"""Issue #6: back-translation must use tran_text, not the original text."""
|
|
37
60
|
calls = []
|
|
@@ -49,6 +72,23 @@ def test_back_translation_uses_tran_text_not_original(trans):
|
|
|
49
72
|
assert calls[1][0] == '你好', "Back-translation must use intermediate text, not original"
|
|
50
73
|
|
|
51
74
|
|
|
75
|
+
def test_back_translation_with_cantonese_tmp(trans):
|
|
76
|
+
trans._sendRequest.side_effect = [
|
|
77
|
+
_mock_response('en', '你好'),
|
|
78
|
+
_mock_response('yue', 'Hello there'),
|
|
79
|
+
]
|
|
80
|
+
result = trans.translate('hello', src='en', tmp='yue')
|
|
81
|
+
assert result.src == 'en'
|
|
82
|
+
assert result.tmp == 'yue'
|
|
83
|
+
assert result.dst == 'yue'
|
|
84
|
+
assert result.tran_text == '你好'
|
|
85
|
+
assert result.result_text == 'Hello there'
|
|
86
|
+
assert trans._sendRequest.call_args_list == [
|
|
87
|
+
call('hello', 'en', 'yue'),
|
|
88
|
+
call('你好', 'yue', 'en'),
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
|
|
52
92
|
def test_auto_detect_src(trans):
|
|
53
93
|
trans._sendRequest.side_effect = [
|
|
54
94
|
_mock_response('en', 'detected'),
|
|
@@ -59,6 +99,19 @@ def test_auto_detect_src(trans):
|
|
|
59
99
|
assert result.src == 'en'
|
|
60
100
|
|
|
61
101
|
|
|
102
|
+
def test_direct_auto_detect_src(trans):
|
|
103
|
+
trans._sendRequest.return_value = _mock_response('en', '你好')
|
|
104
|
+
result = trans.direct_translate('hello', src='auto', dst='zh')
|
|
105
|
+
assert result.src == 'en'
|
|
106
|
+
trans._sendRequest.assert_called_once_with('hello', 'auto', 'zh')
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_direct_auto_detect_same_src_dst_raises(trans):
|
|
110
|
+
trans._sendRequest.return_value = _mock_response('en', 'hello')
|
|
111
|
+
with pytest.raises(ValueError, match='should different'):
|
|
112
|
+
trans.direct_translate('hello', src='auto', dst='en')
|
|
113
|
+
|
|
114
|
+
|
|
62
115
|
def test_default_tmp_when_src_en(trans):
|
|
63
116
|
trans._sendRequest.side_effect = [
|
|
64
117
|
_mock_response('en', '你好'),
|
|
@@ -82,6 +135,16 @@ def test_same_src_tmp_raises(trans):
|
|
|
82
135
|
trans.translate('hello', src='en', tmp='en')
|
|
83
136
|
|
|
84
137
|
|
|
138
|
+
def test_direct_missing_dst_raises(trans):
|
|
139
|
+
with pytest.raises(ValueError, match='destination language is required'):
|
|
140
|
+
trans.direct_translate('hello', src='en')
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_direct_same_src_dst_raises(trans):
|
|
144
|
+
with pytest.raises(ValueError, match='should different'):
|
|
145
|
+
trans.direct_translate('hello', src='en', dst='en')
|
|
146
|
+
|
|
147
|
+
|
|
85
148
|
def test_invalid_appid():
|
|
86
149
|
with patch('BackTranslation.translation_Baidu.http.client.HTTPConnection'):
|
|
87
150
|
with pytest.raises(ValueError, match='INVALID appid'):
|
|
@@ -113,3 +176,22 @@ def test_default_sleeping_is_one(trans, mocker):
|
|
|
113
176
|
mock_sleep = mocker.patch('BackTranslation.translation_Baidu.time.sleep')
|
|
114
177
|
trans.translate('hello', src='en', tmp='zh')
|
|
115
178
|
mock_sleep.assert_called_with(1)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def test_direct_long_text_split(trans, mocker):
|
|
182
|
+
long_text = 'Hello world. ' * 600
|
|
183
|
+
mocker.patch('BackTranslation.translation_Baidu.sent_tokenize', return_value=['ignored'])
|
|
184
|
+
mocker.patch.object(trans, '_split_segement', return_value=['hello one', 'hello two'])
|
|
185
|
+
trans._sendRequest.side_effect = [
|
|
186
|
+
_mock_response('en', '你好一'),
|
|
187
|
+
_mock_response('en', '你好二'),
|
|
188
|
+
]
|
|
189
|
+
mock_sleep = mocker.patch('BackTranslation.translation_Baidu.time.sleep')
|
|
190
|
+
result = trans.direct_translate(long_text, src='auto', dst='zh')
|
|
191
|
+
assert result.src == 'en'
|
|
192
|
+
assert result.result_text == '你好一 你好二'
|
|
193
|
+
assert trans._sendRequest.call_args_list == [
|
|
194
|
+
call('hello one', 'auto', 'zh'),
|
|
195
|
+
call('hello two', 'en', 'zh'),
|
|
196
|
+
]
|
|
197
|
+
mock_sleep.assert_called_once_with(1)
|
|
File without changes
|
|
File without changes
|
{backtranslation-0.4.0 → backtranslation-0.5.0}/BackTranslation.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|