diff --git a/rosetta/conf/__init__.py b/rosetta/conf/__init__.py index 862c63b..c44947c 100644 --- a/rosetta/conf/__init__.py +++ b/rosetta/conf/__init__.py @@ -20,32 +20,34 @@ class RosettaSettings(object): SETTINGS = { 'ROSETTA_MESSAGES_PER_PAGE': ('MESSAGES_PER_PAGE', 10), 'ROSETTA_ENABLE_TRANSLATION_SUGGESTIONS': ( - 'ENABLE_TRANSLATION_SUGGESTIONS', False + 'ENABLE_TRANSLATION_SUGGESTIONS', + False, ), 'YANDEX_TRANSLATE_KEY': ('YANDEX_TRANSLATE_KEY', None), 'AZURE_CLIENT_SECRET': ('AZURE_CLIENT_SECRET', None), - 'GOOGLE_APPLICATION_CREDENTIALS_PATH': ('GOOGLE_APPLICATION_CREDENTIALS_PATH', None), - 'GOOGLE_PROJECT_ID': ('GOOGLE_PROJECT_ID', None), - 'ROSETTA_MAIN_LANGUAGE': ('MAIN_LANGUAGE', None), - 'ROSETTA_MESSAGES_SOURCE_LANGUAGE_CODE': ( - 'MESSAGES_SOURCE_LANGUAGE_CODE', 'en' + 'GOOGLE_APPLICATION_CREDENTIALS_PATH': ( + 'GOOGLE_APPLICATION_CREDENTIALS_PATH', + None, ), + 'GOOGLE_PROJECT_ID': ('GOOGLE_PROJECT_ID', None), + 'DEEPL_AUTH_KEY': ('DEEPL_AUTH_KEY', None), + 'ROSETTA_MAIN_LANGUAGE': ('MAIN_LANGUAGE', None), + 'ROSETTA_MESSAGES_SOURCE_LANGUAGE_CODE': ('MESSAGES_SOURCE_LANGUAGE_CODE', 'en'), 'ROSETTA_MESSAGES_SOURCE_LANGUAGE_NAME': ( - 'MESSAGES_SOURCE_LANGUAGE_NAME', 'English' + 'MESSAGES_SOURCE_LANGUAGE_NAME', + 'English', ), 'ROSETTA_ACCESS_CONTROL_FUNCTION': ('ACCESS_CONTROL_FUNCTION', None), 'ROSETTA_WSGI_AUTO_RELOAD': ('WSGI_AUTO_RELOAD', False), 'ROSETTA_UWSGI_AUTO_RELOAD': ('UWSGI_AUTO_RELOAD', False), 'ROSETTA_EXCLUDED_APPLICATIONS': ('EXCLUDED_APPLICATIONS', ()), 'ROSETTA_POFILE_WRAP_WIDTH': ('POFILE_WRAP_WIDTH', 78), - 'ROSETTA_STORAGE_CLASS': ( - 'STORAGE_CLASS', 'rosetta.storage.CacheRosettaStorage' - ), + 'ROSETTA_STORAGE_CLASS': ('STORAGE_CLASS', 'rosetta.storage.CacheRosettaStorage'), 'ROSETTA_ENABLE_REFLANG': ('ENABLE_REFLANG', False), 'ROSETTA_POFILENAMES': ('POFILENAMES', ('django.po', 'djangojs.po')), 'ROSETTA_CACHE_NAME': ( 'ROSETTA_CACHE_NAME', - 'rosetta' if 'rosetta' in dj_settings.CACHES else 'default' + 'rosetta' if 'rosetta' in dj_settings.CACHES else 'default', ), 'ROSETTA_REQUIRES_AUTH': ('ROSETTA_REQUIRES_AUTH', True), 'ROSETTA_EXCLUDED_PATHS': ('ROSETTA_EXCLUDED_PATHS', ()), @@ -53,9 +55,15 @@ class RosettaSettings(object): 'ROSETTA_AUTO_COMPILE': ('AUTO_COMPILE', True), 'ROSETTA_SHOW_AT_ADMIN_PANEL': ('SHOW_AT_ADMIN_PANEL', False), 'ROSETTA_LOGIN_URL': ('LOGIN_URL', dj_settings.LOGIN_URL), - 'ROSETTA_LANGUAGES': ('ROSETTA_LANGUAGES', dj_settings.LANGUAGES), 'ROSETTA_SHOW_OCCURRENCES': ('SHOW_OCCURRENCES', True), + # Deepl API language codes are different then those of django, so if this is not set according to your desired languages, + # We use the first 2 letters of django language code. + # In which case it would work fine for most of the languages, + # But for 'en' if you want "EN-GB" for example, please set it in this dictionary. + # you can find the supported languages list of DeepL API here: https://www.deepl.com/docs-api/translating-text/request/ + # ex: DEEPL_LANGUAGES = {"fr": "FR", "en": "EN-GB", "zh_Hans": "ZH"} + 'DEEPL_LANGUAGES': ('DEEPL_LANGUAGES', {}), } def __init__(self): @@ -66,25 +74,19 @@ class RosettaSettings(object): def load(self): for user_setting, (rosetta_setting, default) in self.SETTINGS.items(): - self._settings[rosetta_setting] = getattr( - dj_settings, user_setting, default - ) + self._settings[rosetta_setting] = getattr(dj_settings, user_setting, default) def reload(self): self.__init__() def __getattr__(self, attr): if attr not in self._settings: - raise AttributeError( - "'RosettaSettings' object has not attribute '%s'" % attr - ) + raise AttributeError("'RosettaSettings' object has not attribute '%s'" % attr) return self._settings[attr] def __setattr__(self, attr, value): if attr not in self._settings: - raise AttributeError( - "'RosettaSettings' object has not attribute '%s'" % attr - ) + raise AttributeError("'RosettaSettings' object has not attribute '%s'" % attr) self._settings[attr] = value diff --git a/rosetta/templates/rosetta/js/rosetta.js b/rosetta/templates/rosetta/js/rosetta.js index bd45b20..8e65f78 100644 --- a/rosetta/templates/rosetta/js/rosetta.js +++ b/rosetta/templates/rosetta/js/rosetta.js @@ -10,8 +10,40 @@ $(document).ready(function() { {% if rosetta_settings.ENABLE_TRANSLATION_SUGGESTIONS %} + {% if rosetta_settings.DEEPL_AUTH_KEY %} - {% if rosetta_settings.AZURE_CLIENT_SECRET or rosetta_settings.GOOGLE_APPLICATION_CREDENTIALS_PATH %} + $('a.suggest').click(function(e){ + e.preventDefault(); + var a = $(this); + var str = a.html(); + var orig = $('.original .message', a.parents('tr')).html(); + var trans=$('textarea',a.parent()); + var apiUrl = "https://api-free.deepl.com/v2/translate"; + {% if deepl_language_code %} + var destLangRoot = '{{ deepl_language_code }}'; + {% else %} + var destLangRoot = '{{ rosetta_i18n_lang_code_normalized }}'.substring(0, 2); + {% endif %} + var sourceLang = '{{ rosetta_settings.MESSAGES_SOURCE_LANGUAGE_CODE }}'.substring(0, 2); + let authKey = '{{ rosetta_settings.DEEPL_AUTH_KEY }}:fx'; + + a.attr('class','suggesting').html('...'); + fetch(apiUrl, { + method: 'POST', + headers: { + "Content-Type": "application/x-www-form-urlencoded" + }, + body: `auth_key=${authKey}&text=${orig}&source_lang=${sourceLang}&target_lang=${destLangRoot}` + }).then(response => { + if(response.ok) { + return response.json(); + } + }).then(data => { + trans.val(data.translations[0].text.replace(/
/g, '\n').replace(/<\/?code>/g, '').replace(/</g, '<').replace(/>/g, '>')); + }) + .catch(error => console.log(error)); + }); + {% elif rosetta_settings.AZURE_CLIENT_SECRET or rosetta_settings.GOOGLE_APPLICATION_CREDENTIALS_PATH %} $('a.suggest').click(function(e){ e.preventDefault(); var a = $(this); diff --git a/rosetta/tests/tests.py b/rosetta/tests/tests.py index bdd8e76..21b42a9 100644 --- a/rosetta/tests/tests.py +++ b/rosetta/tests/tests.py @@ -943,8 +943,7 @@ class RosettaTestCase(TestCase): self.assertContains(r, 'Lorem') def test_45_issue186_plural_msg_search(self): - """Confirm that search of the .po file works for plurals. - """ + """Confirm that search of the .po file works for plurals.""" self.copy_po_file_from_template('./django.po.issue186.template') url = self.xx_form_url + '?query=%s' @@ -972,8 +971,7 @@ class RosettaTestCase(TestCase): self.assertContains(r, 'Child') def test_46_search_string_with_unicode_symbols(self): - """Confirm that search works with unicode symbols - """ + """Confirm that search works with unicode symbols""" url = self.xx_form_url + '?' + urlencode({'query': force_bytes(u'Лорем')}) # It shouldn't raise @@ -985,6 +983,7 @@ class RosettaTestCase(TestCase): match_on=['method', 'scheme', 'host', 'port', 'path', 'query', 'raw_body'], record_mode='new_episodes', ) + @override_settings(DEEPL_AUTH_KEY=None, AZURE_CLIENT_SECRET="FAKE") def test_47_azure_ajax_translation(self): r = self.client.get( reverse('rosetta.translate_text') + '?from=en&to=fr&text=hello%20world' @@ -1032,6 +1031,36 @@ class RosettaTestCase(TestCase): self.assertTrue('foo language' in r.content.decode()) self.assertTrue('bar language' in r.content.decode()) + def test_52_deepl_languages_handled_correctly(self): + """ + If DEEPL_LANGUAGES set in settings, we use that one, if not, we use django's language code. + """ + if settings.DEEPL_AUTH_KEY: + with self.settings(DEEPL_LANGUAGES={"fr_FR.utf8": "FR"}): + r = self.client.get( + reverse( + "rosetta-form", + kwargs={ + "po_filter": "project", + "lang_id": "fr_FR.utf8", + "idx": "0", + }, + ) + ) + self.assertContains(r, "var destLangRoot = 'FR'") + with self.settings(DEEPL_LANGUAGES=None): + r = self.client.get( + reverse( + "rosetta-form", + kwargs={ + "po_filter": "project", + "lang_id": "fr_FR.utf8", + "idx": "0", + }, + ) + ) + self.assertContains(r, "var destLangRoot = 'fr-FR.utf8'.substring(0, 2)") + def test_198_embed_in_admin_access_control(self): resp = self.client.get(reverse('admin:index')) self.assertContains(resp, 'rosetta-content-main') diff --git a/rosetta/views.py b/rosetta/views.py index 77c7956..cf04c49 100644 --- a/rosetta/views.py +++ b/rosetta/views.py @@ -531,6 +531,12 @@ class TranslationFormView(RosettaFileLevelMixin, TemplateView): {k: v for k, v in query_string_args.items() if k == 'ref_lang'} ) + deepl_language_code = None + if rosetta_settings.DEEPL_LANGUAGES: + deepl_language_code = rosetta_settings.DEEPL_LANGUAGES.get( + self.language_id, None + ) + context.update( { 'version': get_rosetta_version(), @@ -554,6 +560,7 @@ class TranslationFormView(RosettaFileLevelMixin, TemplateView): 'paginator': paginator, 'rosetta_i18n_pofile': self.po_file, 'ref_lang': self.ref_lang, + 'deepl_language_code': deepl_language_code, } )