Skip to content

Commit

Permalink
Add more options to the DeepL settings (#835)
Browse files Browse the repository at this point in the history
- Add the ability to configure glossaries by (source, target)
  language pairs.
- Add the ability to configure the timeout instead of having it
  hardcoded to 30.
  • Loading branch information
alexkiro authored Dec 20, 2024
1 parent f791117 commit 97c2970
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 9 deletions.
7 changes: 7 additions & 0 deletions docs/how-to/integrations/machine-translation.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@ WAGTAILLOCALIZE_MACHINE_TRANSLATOR = {
# Optional DeepL API setting. Accepts "default", "prefer_more" or "prefer_less".\
# For more information see the API docs https://www.deepl.com/docs-api/translate-text/
"FORMALITY": "<Your DeepL formality preference here>",
# Optional DeepL Glossary IDs by (source, target) language pairs
"GLOSSARY_IDS": {
("EN", "ES"): "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
("EN", "FR"): "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
},
# Optional timeout for the request to the DeepL API
"TIMEOUT": 30,
},
}
```
Expand Down
34 changes: 25 additions & 9 deletions wagtail_localize/machine_translators/deepl.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,43 @@ def get_api_endpoint(self):
return "https://api-free.deepl.com/v2/translate"
return "https://api.deepl.com/v2/translate"

def translate(self, source_locale, target_locale, strings):
def get_parameters(self, source_locale, target_locale, strings):
source_lang = language_code(source_locale.language_code)
target_lang = language_code(target_locale.language_code, is_target=True)

parameters = {
"auth_key": self.options["AUTH_KEY"],
"text": [string.data for string in strings],
"tag_handling": "xml",
"source_lang": language_code(source_locale.language_code),
"target_lang": language_code(target_locale.language_code, is_target=True),
"source_lang": source_lang,
"target_lang": target_lang,
}

if self.options.get("FORMALITY"):
if self.options["FORMALITY"] in SUPPORTED_FORMALITY_OPTIONS:
parameters["formality"] = self.options["FORMALITY"]
if formality := self.options.get("FORMALITY"):
if formality in SUPPORTED_FORMALITY_OPTIONS:
parameters["formality"] = formality
else:
warnings.warn(
f"Unsupported formality option '{formality}'. "
f"Supported options are: {', '.join(SUPPORTED_FORMALITY_OPTIONS)}"
)

if glossaries := self.options.get("GLOSSARY_IDS"):
lang_pair = (source_lang, target_lang)
if glossary_id := glossaries.get(lang_pair):
parameters["glossary_id"] = glossary_id
else:
warnings.warn(
f"Unsupported formality option '{self.options['FORMALITY']}'. Supported options are: {', '.join(SUPPORTED_FORMALITY_OPTIONS)}"
f"No glossary defined for (source, target) pair: {lang_pair}"
)

return parameters

def translate(self, source_locale, target_locale, strings):
response = requests.post(
self.get_api_endpoint(),
parameters,
timeout=30,
self.get_parameters(source_locale, target_locale, strings),
timeout=int(self.options.get("TIMEOUT", 30)),
)

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,28 @@
},
}

DEEPL_SETTINGS_WITH_GLOSSARY_IDS = {
"CLASS": "wagtail_localize.machine_translators.deepl.DeepLTranslator",
"OPTIONS": {
"AUTH_KEY": "asd-23-ssd-243-adsf-dummy-auth-key:bla",
"GLOSSARY_IDS": {
("EN", "DE"): "test-id-de",
("EN", "FR"): "test-id-fr",
},
},
}

DEEPL_SETTINGS_WITH_MISSING_GLOSSARY_IDS = {
"CLASS": "wagtail_localize.machine_translators.deepl.DeepLTranslator",
"OPTIONS": {
"AUTH_KEY": "asd-23-ssd-243-adsf-dummy-auth-key:bla",
"GLOSSARY_IDS": {
("EN", "FR"): "test-id-fr",
("EN", "DE"): "test-id-de",
},
},
}


class TestDeeplTranslator(TestCase):
@override_settings(WAGTAILLOCALIZE_MACHINE_TRANSLATOR=DEEPL_SETTINGS_FREE_ENDPOINT)
Expand Down Expand Up @@ -120,3 +142,36 @@ def test_language_code_as_target(self):
for code, expected_value in mapping.items():
with self.subTest(f"Testing language_code with {code} as target"):
self.assertEqual(expected_value, language_code(code, is_target=True))

@override_settings(
WAGTAILLOCALIZE_MACHINE_TRANSLATOR=DEEPL_SETTINGS_WITH_GLOSSARY_IDS
)
@patch("requests.post")
def test_translate_with_glossary_ids(self, mock_post):
translator = get_machine_translator()
source_locale = Mock(language_code="en")
target_locale = Mock(language_code="de")
strings = [StringValue("Test string")]

translator.translate(source_locale, target_locale, strings)

mock_post.assert_called_once()
called_args, called_kwargs = mock_post.call_args
self.assertIn("glossary_id", called_args[1])
self.assertEqual(called_args[1]["glossary_id"], "test-id-de")

@override_settings(
WAGTAILLOCALIZE_MACHINE_TRANSLATOR=DEEPL_SETTINGS_WITH_MISSING_GLOSSARY_IDS
)
@patch("requests.post")
def test_translate_with_missing_glossary_ids(self, mock_post):
translator = get_machine_translator()
source_locale = Mock(language_code="en")
target_locale = Mock(language_code="es")
strings = [StringValue("Test string")]

translator.translate(source_locale, target_locale, strings)

mock_post.assert_called_once()
called_args, called_kwargs = mock_post.call_args
self.assertNotIn("glossary_id", called_args[1])

0 comments on commit 97c2970

Please sign in to comment.