diff --git a/locale/zh_Hans/LC_MESSAGES/django.po b/locale/zh_Hans/LC_MESSAGES/django.po index ee5a624..c2478c4 100644 --- a/locale/zh_Hans/LC_MESSAGES/django.po +++ b/locale/zh_Hans/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-19 06:24+0000\n" +"POT-Creation-Date: 2024-07-22 02:22+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -301,8 +301,8 @@ msgid "Deloyment Name" msgstr "" #: translator/models/base.py:88 translator/models/claude.py:18 -#: translator/models/deepl.py:11 translator/models/gemini.py:15 -#: translator/models/microsoft_translate.py:12 +#: translator/models/deepl.py:11 translator/models/doubao.py:13 +#: translator/models/gemini.py:15 translator/models/microsoft_translate.py:12 msgid "API Key" msgstr "" @@ -313,18 +313,18 @@ msgid "API URL" msgstr "" #: translator/models/base.py:96 translator/models/claude.py:22 -#: translator/models/gemini.py:22 +#: translator/models/doubao.py:18 translator/models/gemini.py:22 msgid "Title Translate Prompt" msgstr "标题翻译提示词" #: translator/models/base.py:99 translator/models/claude.py:25 -#: translator/models/gemini.py:25 +#: translator/models/doubao.py:21 translator/models/gemini.py:25 msgid "Content Translate Prompt" msgstr "内容翻译提示词" #: translator/models/claude.py:28 translator/models/deepl.py:14 #: translator/models/deeplweb.py:13 translator/models/free_translators.py:12 -#: translator/models/google_translate_web.py:14 +#: translator/models/google_translate_web.py:13 msgid "Proxy(optional)" msgstr "" @@ -334,25 +334,40 @@ msgstr "" #: translator/models/deeplweb.py:12 translator/models/deeplx.py:16 #: translator/models/dev.py:11 translator/models/gemini.py:32 -#: translator/models/google_translate_web.py:15 +#: translator/models/google_translate_web.py:14 msgid "Request Interval(s)" msgstr "请求间隔" -#: translator/models/google_translate_web.py:12 +#: translator/models/doubao.py:25 translator/models/doubao.py:26 +msgid "Doubao" +msgstr "" + +#: translator/models/google_translate_web.py:11 msgid "URL" msgstr "" -#: translator/models/google_translate_web.py:12 +#: translator/models/google_translate_web.py:11 msgid "" "It is recommended to leave this blank in order to automatically select the " "best server" msgstr "建议留空,以自动选择最佳服务器" -#: utils/modelAdmin_utils.py:46 utils/modelAdmin_utils.py:74 +#: translator/models/openl.py:17 +msgid "Translate Service Name" +msgstr "翻译服务代码名" + +#: translator/models/openl.py:17 +msgid "" +"Please get it from https://docs.openl." +"club/#/API/format?" +"id=%e7%bf%bb%e8%af%91%e6%9c%8d%e5%8a%a1%e4%bb%a3%e7%a0%81%e5%90%8d" +msgstr "请从官网中获取: https://docs.openl.club/#/API/format?id=%e7%bf%bb%e8%af%91%e6%9c%8d%e5%8a%a1%e4%bb%a3%e7%a0%81%e5%90%8d" + +#: utils/modelAdmin_utils.py:65 utils/modelAdmin_utils.py:107 msgid "Export selected feeds as OPML" msgstr "导出为 OPML" -#: utils/modelAdmin_utils.py:88 utils/modelAdmin_utils.py:102 +#: utils/modelAdmin_utils.py:121 utils/modelAdmin_utils.py:135 msgid "Force update" msgstr "强制更新" diff --git a/translator/admin.py b/translator/admin.py index fda2269..543acf5 100644 --- a/translator/admin.py +++ b/translator/admin.py @@ -356,6 +356,22 @@ class DoubaoTranslatorAdmin(BaseTranslatorAdmin): "max_tokens", ] +class OpenlTranslatorAdmin(BaseTranslatorAdmin): + fields = [ + "name", + "api_key", + "url", + "service_name", + "max_characters", + ] + list_display = [ + "name", + "is_valid", + "masked_api_key", + "url", + "max_characters", + ] + class Translated_ContentAdmin(admin.ModelAdmin): fields = [ "original_content", @@ -402,6 +418,7 @@ class TestTranslatorAdmin(BaseTranslatorAdmin): core_admin_site.register(GroqTranslator, GroqTranslatorAdmin) core_admin_site.register(FreeTranslators, FreeTranslatorsAdmin) core_admin_site.register(DoubaoTranslator, DoubaoTranslatorAdmin) +core_admin_site.register(OpenlTranslator, OpenlTranslatorAdmin) if settings.DEBUG: core_admin_site.register(Translated_Content, Translated_ContentAdmin) diff --git a/translator/migrations/0038_openltranslator.py b/translator/migrations/0038_openltranslator.py new file mode 100644 index 0000000..e66af72 --- /dev/null +++ b/translator/migrations/0038_openltranslator.py @@ -0,0 +1,31 @@ +# Generated by Django 5.0.6 on 2024-07-22 02:11 + +import encrypted_model_fields.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('translator', '0037_doubaotranslator'), + ] + + operations = [ + migrations.CreateModel( + name='OpenlTranslator', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100, unique=True, verbose_name='Name')), + ('valid', models.BooleanField(null=True, verbose_name='Valid')), + ('is_ai', models.BooleanField(default=False, editable=False)), + ('api_key', encrypted_model_fields.fields.EncryptedCharField()), + ('url', models.URLField(default='https://api.openl.club', max_length=255)), + ('service_name', models.CharField(default='deepl', help_text='Please get it from https://docs.openl.club/#/API/format?id=%e7%bf%bb%e8%af%91%e6%9c%8d%e5%8a%a1%e4%bb%a3%e7%a0%81%e5%90%8d', max_length=50, verbose_name='Translate Service Name')), + ('max_characters', models.IntegerField(default=5000)), + ], + options={ + 'verbose_name': 'Openl', + 'verbose_name_plural': 'Openl', + }, + ), + ] diff --git a/translator/models/__init__.py b/translator/models/__init__.py index 5a5240d..386cb79 100644 --- a/translator/models/__init__.py +++ b/translator/models/__init__.py @@ -15,5 +15,6 @@ from .groq import GroqTranslator from .free_translators import FreeTranslators from .doubao import DoubaoTranslator +from .openl import OpenlTranslator from .dev import TestTranslator diff --git a/translator/models/openl.py b/translator/models/openl.py new file mode 100644 index 0000000..5a91681 --- /dev/null +++ b/translator/models/openl.py @@ -0,0 +1,75 @@ +import uuid +import logging +import json +import httpx +from .base import TranslatorEngine +from django.utils.translation import gettext_lazy as _ +from django.db import models +from encrypted_model_fields.fields import EncryptedCharField + + +class OpenlTranslator(TranslatorEngine): + # https://docs.openl.club/ + api_key = EncryptedCharField(max_length=255) + url = models.URLField( + max_length=255, default="https://api.openl.club" + ) + service_name = models.CharField(_("Translate Service Name"), max_length=50, default="deepl",help_text=_('Please get it from https://docs.openl.club/#/API/format?id=%e7%bf%bb%e8%af%91%e6%9c%8d%e5%8a%a1%e4%bb%a3%e7%a0%81%e5%90%8d')) + max_characters = models.IntegerField(default=5000) + language_code_map = { + "English": "en", + "Chinese Simplified": "zh", + "Japanese": "ja", + "Spanish": "es", + "French": "fr", + "Russian": "ru", + "Danish": "de", + "Italian": "it", + "Spanish": "es", + "Polish": "pl", + "Portuguese": "pt", + "Russian": "ru", + } + + class Meta: + verbose_name = "Openl" + verbose_name_plural = "Openl" + + def validate(self) -> bool: + try: + resp = httpx.post( + url=self.url + "/user/info", + headers={"content-type": "application/json"}, + data=json.dumps({"apikey": self.api_key}), + timeout=10, + ) + resp.raise_for_status() + results = resp.json() + return results.get("status") is True + except Exception as e: + logging.error("OpenlTranslator->%s", e) + return False + + def translate(self, text: str, target_language: str, **kwargs) -> dict: + logging.info(">>> Openl Translate [%s]: %s", target_language, text) + target_code = self.language_code_map.get(target_language, None) + translated_text = "" + try: + if target_code is None: + logging.error( + "OpenlTranslator->Not support target language:%s", target_language + ) + + resp = httpx.post( + url=self.url + f"/services/{self.service_name}/translate", + headers={"content-type": "application/json"}, + data=json.dumps({"apikey": self.api_key, "text": text, "target_lang": target_code}), + timeout=10, + ) + resp.raise_for_status() + results = resp.json() + translated_text = results.get("result") if results.get("status") is True else "" + except Exception as e: + logging.error("OpenlTranslator->%s: %s", e, text) + finally: + return {"text": translated_text, "characters": len(text)}