-
Notifications
You must be signed in to change notification settings - Fork 87
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add LibreTranslate machine translator, documentation and its test cases.
- Loading branch information
Showing
3 changed files
with
157 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import json | ||
|
||
import requests | ||
|
||
from wagtail_localize.machine_translators.base import BaseMachineTranslator | ||
from wagtail_localize.strings import StringValue | ||
|
||
|
||
class LibreTranslator(BaseMachineTranslator): | ||
""" | ||
A machine translator that uses the LibreTranslate API. | ||
""" | ||
|
||
display_name = "LibreTranslate" | ||
|
||
def get_api_endpoint(self): | ||
return self.options["LIBRETRANSLATE_URL"] | ||
|
||
def language_code(self, code): | ||
return code.split("-")[0] | ||
|
||
def translate(self, source_locale, target_locale, strings): | ||
translations = [item.data for item in list(strings)] | ||
response = requests.post( | ||
self.get_api_endpoint() + "/translate", | ||
data=json.dumps( | ||
{ | ||
"q": translations, | ||
"source": self.language_code(source_locale.language_code), | ||
"target": self.language_code(target_locale.language_code), | ||
"api_key": self.options["API_KEY"], | ||
} | ||
), | ||
headers={"Content-Type": "application/json"}, | ||
timeout=10, | ||
) | ||
response.raise_for_status() | ||
|
||
return { | ||
string: StringValue(translation) | ||
for string, translation in zip(strings, response.json()["translatedText"]) | ||
} | ||
|
||
def can_translate(self, source_locale, target_locale): | ||
return self.language_code(source_locale.language_code) != self.language_code( | ||
target_locale.language_code | ||
) |
93 changes: 93 additions & 0 deletions
93
wagtail_localize/machine_translators/tests/test_libretranslate_translator.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
from django.test import TestCase, override_settings | ||
from wagtail.models import Locale | ||
|
||
from wagtail_localize.machine_translators import get_machine_translator | ||
from wagtail_localize.machine_translators.libretranslate import LibreTranslator | ||
|
||
|
||
LIBRETRANSLATE_SETTINGS_ENDPOINT = { | ||
"CLASS": "wagtail_localize.machine_translators.libretranslate.LibreTranslator", | ||
"OPTIONS": { | ||
"LIBRETRANSLATE_URL": "https://libretranslate.org", | ||
"API_KEY": "test-api-key", | ||
}, | ||
} | ||
|
||
|
||
class TestLibreTranslator(TestCase): | ||
@override_settings( | ||
WAGTAILLOCALIZE_MACHINE_TRANSLATOR=LIBRETRANSLATE_SETTINGS_ENDPOINT | ||
) | ||
def setUp(self): | ||
self.english_locale = Locale.objects.get() | ||
self.french_locale = Locale.objects.create(language_code="fr") | ||
self.translator = get_machine_translator() | ||
|
||
def test_api_endpoint(self): | ||
self.assertIsInstance(self.translator, LibreTranslator) | ||
api_endpoint = self.translator.get_api_endpoint() | ||
self.assertEqual(api_endpoint, "https://libretranslate.org") | ||
|
||
# This probably requires a request to use the API but the test works against my local instance | ||
# def test_translate_text(self): | ||
# self.assertIsInstance(self.translator, LibreTranslator) | ||
|
||
# translations = self.translator.translate( | ||
# self.english_locale, | ||
# self.french_locale, | ||
# { | ||
# StringValue("Hello world!"), | ||
# StringValue("This is a sentence. This is another sentence."), | ||
# }, | ||
# ) | ||
|
||
# self.assertEqual( | ||
# translations, | ||
# { | ||
# StringValue("Hello world!"): StringValue("Bonjour !"), | ||
# StringValue( | ||
# "This is a sentence. This is another sentence." | ||
# ): StringValue("C'est une phrase. C'est une autre phrase."), | ||
# }, | ||
# ) | ||
|
||
# This has been commented out because after a while the public API started | ||
# to return different results for the same input. | ||
# This probably requires a request to use the API but the test works against my local instance | ||
# def test_translate_html(self): | ||
# self.assertIsInstance(self.translator, LibreTranslator) | ||
|
||
# string, attrs = StringValue.from_source_html( | ||
# '<a href="https://en.wikipedia.org/wiki/World">Hello !</a>. <b>This is a test</b>.' | ||
# ) | ||
|
||
# translations = self.translator.translate( | ||
# self.english_locale, self.french_locale, [string] | ||
# ) | ||
|
||
# self.assertEqual( | ||
# translations[string].render_html(attrs), | ||
# "Bonjour ! C'est un test enregistré/b.", | ||
# ) | ||
|
||
def test_can_translate(self): | ||
self.assertIsInstance(self.translator, LibreTranslator) | ||
|
||
french_locale = Locale.objects.get(language_code="fr") | ||
|
||
self.assertTrue( | ||
self.translator.can_translate(self.english_locale, self.french_locale) | ||
) | ||
self.assertTrue( | ||
self.translator.can_translate(self.english_locale, french_locale) | ||
) | ||
|
||
# Can't translate the same language | ||
self.assertFalse( | ||
self.translator.can_translate(self.english_locale, self.english_locale) | ||
) | ||
|
||
# Can't translate two variants of the same language | ||
self.assertFalse( | ||
self.translator.can_translate(self.french_locale, french_locale) | ||
) |