mirror of
https://github.com/MCV-Software/TWBlue.git
synced 2024-11-22 19:28:09 -06:00
Feat: Replaced old translator module. The new translator can translate by using LibreTranslate or DeepL with an user provided API key
This commit is contained in:
parent
a1eb546f23
commit
ee4f254825
@ -13,11 +13,13 @@ cx-Freeze==7.0.0
|
|||||||
cx-Logging==3.2.0
|
cx-Logging==3.2.0
|
||||||
decorator==5.1.1
|
decorator==5.1.1
|
||||||
demoji==1.1.0
|
demoji==1.1.0
|
||||||
|
deepl==1.18.0
|
||||||
future==1.0.0
|
future==1.0.0
|
||||||
idna==3.7
|
idna==3.7
|
||||||
importlib-metadata==7.1.0
|
importlib-metadata==7.1.0
|
||||||
iniconfig==2.0.0
|
iniconfig==2.0.0
|
||||||
libloader @ git+https://github.com/accessibleapps/libloader@bc94811c095b2e57a036acd88660be9a33260267
|
libloader @ git+https://github.com/accessibleapps/libloader@bc94811c095b2e57a036acd88660be9a33260267
|
||||||
|
libretranslatepy==2.1.4
|
||||||
lief==0.14.1
|
lief==0.14.1
|
||||||
Markdown==3.6
|
Markdown==3.6
|
||||||
Mastodon.py==1.8.1
|
Mastodon.py==1.8.1
|
||||||
|
@ -29,3 +29,8 @@ server = string(default="")
|
|||||||
port = integer(default=8080)
|
port = integer(default=8080)
|
||||||
user = string(default="")
|
user = string(default="")
|
||||||
password = string(default="")
|
password = string(default="")
|
||||||
|
|
||||||
|
[translator]
|
||||||
|
engine=string(default="deepl")
|
||||||
|
translator_api_url=string(default="https://translate.nvda.es")
|
||||||
|
translator_api_key=string(default="")
|
||||||
|
@ -1,26 +1,21 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import widgetUtils
|
import widgetUtils
|
||||||
import output
|
import output
|
||||||
|
import config
|
||||||
from extra import SpellChecker
|
from extra import SpellChecker
|
||||||
|
from extra.translator import TranslatorController
|
||||||
|
|
||||||
class basicMessage(object):
|
class basicMessage(object):
|
||||||
def translate(self, event=None):
|
def translate(self, event=None):
|
||||||
pass
|
t = TranslatorController(self.message.text.GetValue())
|
||||||
# dlg = translator.gui.translateDialog()
|
if t.response == False:
|
||||||
# if dlg.get_response() == widgetUtils.OK:
|
return
|
||||||
# text_to_translate = self.message.text.GetValue()
|
msg = t.translate()
|
||||||
# language_dict = translator.translator.available_languages()
|
self.message.text.ChangeValue(msg)
|
||||||
# for k in language_dict:
|
self.message.text.SetInsertionPoint(len(self.message.text.GetValue()))
|
||||||
# if language_dict[k] == dlg.dest_lang.GetStringSelection():
|
self.text_processor()
|
||||||
# dst = k
|
self.message.text.SetFocus()
|
||||||
# msg = translator.translator.translate(text=text_to_translate, target=dst)
|
output.speak(_(u"Translated"))
|
||||||
# self.message.text.ChangeValue(msg)
|
|
||||||
# self.message.text.SetInsertionPoint(len(self.message.text.GetValue()))
|
|
||||||
# self.text_processor()
|
|
||||||
# self.message.text.SetFocus()
|
|
||||||
# output.speak(_(u"Translated"))
|
|
||||||
# else:
|
|
||||||
# return
|
|
||||||
|
|
||||||
def text_processor(self, *args, **kwargs):
|
def text_processor(self, *args, **kwargs):
|
||||||
pass
|
pass
|
||||||
|
@ -1,5 +1,2 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import absolute_import
|
from .translator import TranslatorController
|
||||||
from __future__ import unicode_literals
|
|
||||||
from . import translator
|
|
||||||
from . import wx_ui as gui
|
|
||||||
|
1
src/extra/translator/engines/__init__.py
Normal file
1
src/extra/translator/engines/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
14
src/extra/translator/engines/deep_l.py
Normal file
14
src/extra/translator/engines/deep_l.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import config
|
||||||
|
from deepl import Translator
|
||||||
|
|
||||||
|
def translate(text: str, target_language: str) -> str:
|
||||||
|
key = config.app["translator"]["translator_api_key"]
|
||||||
|
t = Translator(key)
|
||||||
|
return t.translate_text(text, target_lang=target_language).text
|
||||||
|
|
||||||
|
def languages():
|
||||||
|
key = config.app["translator"]["translator_api_key"]
|
||||||
|
t = Translator(key)
|
||||||
|
langs = t.get_target_languages()
|
||||||
|
return langs
|
45
src/extra/translator/engines/libre_translate.py
Normal file
45
src/extra/translator/engines/libre_translate.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
""" Modified Libretranslatepy module which adds an user agent for making requests against more instances. """
|
||||||
|
import json
|
||||||
|
from typing import Any, Dict
|
||||||
|
from urllib import request, parse
|
||||||
|
from libretranslatepy import LibreTranslateAPI
|
||||||
|
|
||||||
|
class CustomLibreTranslateAPI(LibreTranslateAPI):
|
||||||
|
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
||||||
|
|
||||||
|
def _create_request(self, url: str, method: str, data: Dict[str, str]) -> request.Request:
|
||||||
|
url_params = parse.urlencode(data)
|
||||||
|
req = request.Request(url, method=method, data=url_params.encode())
|
||||||
|
req.add_header("User-Agent", self.USER_AGENT)
|
||||||
|
return req
|
||||||
|
|
||||||
|
def translate(self, q: str, source: str = "en", target: str = "es", timeout: int | None = None) -> Any:
|
||||||
|
url = self.url + "translate"
|
||||||
|
params: Dict[str, str] = {"q": q, "source": source, "target": target}
|
||||||
|
if self.api_key is not None:
|
||||||
|
params["api_key"] = self.api_key
|
||||||
|
req = self._create_request(url=url, method="POST", data=params)
|
||||||
|
response = request.urlopen(req, timeout=timeout)
|
||||||
|
response_str = response.read().decode()
|
||||||
|
return json.loads(response_str)["translatedText"]
|
||||||
|
|
||||||
|
def detect(self, q: str, timeout: int | None = None) -> Any:
|
||||||
|
url = self.url + "detect"
|
||||||
|
params: Dict[str, str] = {"q": q}
|
||||||
|
if self.api_key is not None:
|
||||||
|
params["api_key"] = self.api_key
|
||||||
|
req = self._create_request(url=url, method="POST", data=params)
|
||||||
|
response = request.urlopen(req, timeout=timeout)
|
||||||
|
response_str = response.read().decode()
|
||||||
|
return json.loads(response_str)
|
||||||
|
|
||||||
|
def languages(self, timeout: int | None = None) -> Any:
|
||||||
|
url = self.url + "languages"
|
||||||
|
params: Dict[str, str] = dict()
|
||||||
|
if self.api_key is not None:
|
||||||
|
params["api_key"] = self.api_key
|
||||||
|
req = self._create_request(url=url, method="GET", data=params)
|
||||||
|
response = request.urlopen(req, timeout=timeout)
|
||||||
|
response_str = response.read().decode()
|
||||||
|
return json.loads(response_str)
|
@ -1,116 +1,61 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import logging
|
import logging
|
||||||
from googletrans import Translator, LANGUAGES
|
import threading
|
||||||
|
import wx
|
||||||
|
import config
|
||||||
|
from pubsub import pub
|
||||||
|
from . engines import libre_translate, deep_l
|
||||||
|
from .wx_ui import translateDialog
|
||||||
|
|
||||||
log = logging.getLogger("extras.translator")
|
log = logging.getLogger("extras.translator")
|
||||||
|
|
||||||
# create a single translator instance
|
class TranslatorController(object):
|
||||||
# see https://github.com/ssut/py-googletrans/issues/234
|
def __init__(self, text):
|
||||||
t = None
|
super(TranslatorController, self).__init__()
|
||||||
|
self.text = text
|
||||||
|
self.languages = []
|
||||||
|
self.response = False
|
||||||
|
self.dialog = translateDialog()
|
||||||
|
pub.subscribe(self.on_engine_changed, "translator.engine_changed")
|
||||||
|
if config.app["translator"]["engine"] == "libretranslate":
|
||||||
|
self.dialog.engine_select.SetSelection(0)
|
||||||
|
elif config.app["translator"]["engine"] == "deepl":
|
||||||
|
self.dialog.engine_select.SetSelection(1)
|
||||||
|
threading.Thread(target=self.load_languages).start()
|
||||||
|
if self.dialog.ShowModal() == wx.ID_OK:
|
||||||
|
self.response = True
|
||||||
|
for k in self.language_dict:
|
||||||
|
if self.language_dict[k] == self.dialog.dest_lang.GetStringSelection():
|
||||||
|
self.target_language= k
|
||||||
|
pub.unsubscribe(self.on_engine_changed, "translator.engine_changed")
|
||||||
|
|
||||||
def translate(text="", target="en"):
|
def load_languages(self):
|
||||||
global t
|
self.language_dict = self.get_languages()
|
||||||
log.debug("Received translation request for language %s, text=%s" % (target, text))
|
self.languages = [self.language_dict[k] for k in self.language_dict]
|
||||||
if t == None:
|
self.dialog.set_languages(self.languages)
|
||||||
t = Translator()
|
|
||||||
vars = dict(text=text, dest=target)
|
|
||||||
return t.translate(**vars).text
|
|
||||||
|
|
||||||
supported_langs = None
|
def on_engine_changed(self, engine):
|
||||||
|
if engine == "LibreTranslate":
|
||||||
|
config.app["translator"]["engine"] = engine.lower()
|
||||||
|
elif engine == "DeepL":
|
||||||
|
config.app["translator"]["engine"] = engine.lower()
|
||||||
|
config.app.write()
|
||||||
|
threading.Thread(target=self.load_languages).start()
|
||||||
|
|
||||||
languages = {
|
def translate(self):
|
||||||
"af": _(u"Afrikaans"),
|
log.debug("Received translation request for language %s, text=%s" % (self.target_language, self.text))
|
||||||
"sq": _(u"Albanian"),
|
if config.app["translator"].get("engine") == "libretranslate":
|
||||||
"am": _(u"Amharic"),
|
translator = libre_translate.CustomLibreTranslateAPI(config.app["translator"]["translator_api_url"])
|
||||||
"ar": _(u"Arabic"),
|
vars = dict(q=self.text, target=self.target_language)
|
||||||
"hy": _(u"Armenian"),
|
return translator.translate(**vars)
|
||||||
"az": _(u"Azerbaijani"),
|
elif config.app["translator"]["engine"] == "deepl" and config.app["translator"]["translator_api_key"] != "":
|
||||||
"eu": _(u"Basque"),
|
return deep_l.translate(text=self.text, target_language=self.target_language)
|
||||||
"be": _(u"Belarusian"),
|
|
||||||
"bn": _(u"Bengali"),
|
|
||||||
"bh": _(u"Bihari"),
|
|
||||||
"bg": _(u"Bulgarian"),
|
|
||||||
"my": _(u"Burmese"),
|
|
||||||
"ca": _(u"Catalan"),
|
|
||||||
"chr": _(u"Cherokee"),
|
|
||||||
"zh": _(u"Chinese"),
|
|
||||||
"zh-CN": _(u"Chinese_simplified"),
|
|
||||||
"zh-TW": _(u"Chinese_traditional"),
|
|
||||||
"hr": _(u"Croatian"),
|
|
||||||
"cs": _(u"Czech"),
|
|
||||||
"da": _(u"Danish"),
|
|
||||||
"dv": _(u"Dhivehi"),
|
|
||||||
"nl": _(u"Dutch"),
|
|
||||||
"en": _(u"English"),
|
|
||||||
"eo": _(u"Esperanto"),
|
|
||||||
"et": _(u"Estonian"),
|
|
||||||
"tl": _(u"Filipino"),
|
|
||||||
"fi": _(u"Finnish"),
|
|
||||||
"fr": _(u"French"),
|
|
||||||
"gl": _(u"Galician"),
|
|
||||||
"ka": _(u"Georgian"),
|
|
||||||
"de": _(u"German"),
|
|
||||||
"el": _(u"Greek"),
|
|
||||||
"gn": _(u"Guarani"),
|
|
||||||
"gu": _(u"Gujarati"),
|
|
||||||
"iw": _(u"Hebrew"),
|
|
||||||
"hi": _(u"Hindi"),
|
|
||||||
"hu": _(u"Hungarian"),
|
|
||||||
"is": _(u"Icelandic"),
|
|
||||||
"id": _(u"Indonesian"),
|
|
||||||
"iu": _(u"Inuktitut"),
|
|
||||||
"ga": _(u"Irish"),
|
|
||||||
"it": _(u"Italian"),
|
|
||||||
"ja": _(u"Japanese"),
|
|
||||||
"kn": _(u"Kannada"),
|
|
||||||
"kk": _(u"Kazakh"),
|
|
||||||
"km": _(u"Khmer"),
|
|
||||||
"ko": _(u"Korean"),
|
|
||||||
"ku": _(u"Kurdish"),
|
|
||||||
"ky": _(u"Kyrgyz"),
|
|
||||||
"lo": _(u"Laothian"),
|
|
||||||
"lv": _(u"Latvian"),
|
|
||||||
"lt": _(u"Lithuanian"),
|
|
||||||
"mk": _(u"Macedonian"),
|
|
||||||
"ms": _(u"Malay"),
|
|
||||||
"ml": _(u"Malayalam"),
|
|
||||||
"mt": _(u"Maltese"),
|
|
||||||
"mr": _(u"Marathi"),
|
|
||||||
"mn": _(u"Mongolian"),
|
|
||||||
"ne": _(u"Nepali"),
|
|
||||||
"no": _(u"Norwegian"),
|
|
||||||
"or": _(u"Oriya"),
|
|
||||||
"ps": _(u"Pashto"),
|
|
||||||
"fa": _(u"Persian"),
|
|
||||||
"pl": _(u"Polish"),
|
|
||||||
"pt": _(u"Portuguese"),
|
|
||||||
"pa": _(u"Punjabi"),
|
|
||||||
"ro": _(u"Romanian"),
|
|
||||||
"ru": _(u"Russian"),
|
|
||||||
"sa": _(u"Sanskrit"),
|
|
||||||
"sr": _(u"Serbian"),
|
|
||||||
"sd": _(u"Sindhi"),
|
|
||||||
"si": _(u"Sinhalese"),
|
|
||||||
"sk": _(u"Slovak"),
|
|
||||||
"sl": _(u"Slovenian"),
|
|
||||||
"es": _(u"Spanish"),
|
|
||||||
"sw": _(u"Swahili"),
|
|
||||||
"sv": _(u"Swedish"),
|
|
||||||
"tg": _(u"Tajik"),
|
|
||||||
"ta": _(u"Tamil"),
|
|
||||||
"tl": _(u"Tagalog"),
|
|
||||||
"te": _(u"Telugu"),
|
|
||||||
"th": _(u"Thai"),
|
|
||||||
"bo": _(u"Tibetan"),
|
|
||||||
"tr": _(u"Turkish"),
|
|
||||||
"uk": _(u"Ukrainian"),
|
|
||||||
"ur": _(u"Urdu"),
|
|
||||||
"uz": _(u"Uzbek"),
|
|
||||||
"ug": _(u"Uighur"),
|
|
||||||
"vi": _(u"Vietnamese"),
|
|
||||||
"cy": _(u"Welsh"),
|
|
||||||
"yi": _(u"Yiddish")
|
|
||||||
}
|
|
||||||
|
|
||||||
def available_languages():
|
def get_languages(self):
|
||||||
|
languages = {}
|
||||||
|
if config.app["translator"].get("engine") == "libretranslate":
|
||||||
|
translator = libre_translate.CustomLibreTranslateAPI(config.app["translator"]["translator_api_url"])
|
||||||
|
languages = {l.get("code"): l.get("name") for l in translator.languages()}
|
||||||
|
elif config.app["translator"]["engine"] == "deepl" and config.app["translator"]["translator_api_key"] != "":
|
||||||
|
languages = {language.code: language.name for language in deep_l.languages()}
|
||||||
return dict(sorted(languages.items(), key=lambda x: x[1]))
|
return dict(sorted(languages.items(), key=lambda x: x[1]))
|
||||||
|
@ -16,23 +16,26 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
############################################################
|
############################################################
|
||||||
from . import translator
|
|
||||||
import wx
|
import wx
|
||||||
|
from pubsub import pub
|
||||||
from wxUI.dialogs import baseDialog
|
from wxUI.dialogs import baseDialog
|
||||||
|
|
||||||
class translateDialog(baseDialog.BaseWXDialog):
|
class translateDialog(baseDialog.BaseWXDialog):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
languages = []
|
|
||||||
language_dict = translator.available_languages()
|
|
||||||
for k in language_dict:
|
|
||||||
languages.append(language_dict[k])
|
|
||||||
super(translateDialog, self).__init__(None, -1, title=_(u"Translate message"))
|
super(translateDialog, self).__init__(None, -1, title=_(u"Translate message"))
|
||||||
|
self.engines = ["LibreTranslate", "DeepL"]
|
||||||
panel = wx.Panel(self)
|
panel = wx.Panel(self)
|
||||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
staticEngine = wx.StaticText(panel, -1, _(u"Translation engine"))
|
||||||
|
self.engine_select = wx.ComboBox(panel, -1, choices=self.engines, style=wx.CB_READONLY)
|
||||||
|
self.engine_select.Bind(wx.EVT_COMBOBOX, lambda event: pub.sendMessage("translator.engine_changed", engine=self.engine_select.GetValue()))
|
||||||
staticDest = wx.StaticText(panel, -1, _(u"Target language"))
|
staticDest = wx.StaticText(panel, -1, _(u"Target language"))
|
||||||
self.dest_lang = wx.ComboBox(panel, -1, choices=languages, style = wx.CB_READONLY)
|
self.dest_lang = wx.ComboBox(panel, -1, style = wx.CB_READONLY)
|
||||||
self.dest_lang.SetFocus()
|
self.dest_lang.SetFocus()
|
||||||
self.dest_lang.SetSelection(0)
|
self.dest_lang.SetSelection(0)
|
||||||
|
engineSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
engineSizer.Add(staticEngine)
|
||||||
|
engineSizer.Add(self.engine_select)
|
||||||
listSizer = wx.BoxSizer(wx.HORIZONTAL)
|
listSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
listSizer.Add(staticDest)
|
listSizer.Add(staticDest)
|
||||||
listSizer.Add(self.dest_lang)
|
listSizer.Add(self.dest_lang)
|
||||||
@ -40,6 +43,14 @@ class translateDialog(baseDialog.BaseWXDialog):
|
|||||||
ok.SetDefault()
|
ok.SetDefault()
|
||||||
cancel = wx.Button(panel, wx.ID_CANCEL)
|
cancel = wx.Button(panel, wx.ID_CANCEL)
|
||||||
self.SetEscapeId(wx.ID_CANCEL)
|
self.SetEscapeId(wx.ID_CANCEL)
|
||||||
|
sizer.Add(engineSizer, 0, wx.EXPAND | wx.ALL, 5)
|
||||||
|
sizer.Add(listSizer, 0, wx.EXPAND | wx.ALL, 5)
|
||||||
|
sizer.Add(ok, 0, wx.ALIGN_CENTER | wx.ALL, 5)
|
||||||
|
sizer.Add(cancel, 0, wx.ALIGN_CENTER | wx.ALL, 5)
|
||||||
|
panel.SetSizer(sizer)
|
||||||
|
|
||||||
|
def set_languages(self, languages):
|
||||||
|
wx.CallAfter(self.dest_lang.SetItems, languages)
|
||||||
|
|
||||||
def get(self, control):
|
def get(self, control):
|
||||||
return getattr(self, control).GetSelection()
|
return getattr(self, control).GetSelection()
|
||||||
|
Loading…
Reference in New Issue
Block a user