From 3c1e97a3a79399f23ff768bca96a759d518042ae Mon Sep 17 00:00:00 2001 From: yuhldr Date: Sat, 21 Sep 2024 00:15:08 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20ocr=E7=BF=BB=E8=AF=91=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=AF=86=E9=92=A5=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/cool.ldr.lfy.in.gschema.xml | 8 ++ data/resources/lfy.cmb | 31 ++--- data/resources/preference.ui | 20 +++- data/resources/server-preferences.ui | 22 ---- lfy/api/__init__.py | 27 ++--- lfy/api/constant.py | 10 +- lfy/api/server/__init__.py | 6 +- lfy/api/server/baidu.py | 130 --------------------- lfy/api/server/ocr/__init__.py | 0 lfy/api/server/ocr/baidu.py | 162 +++++++++++++++++++++++++++ lfy/api/server/ocr/easyocr.py | 39 +++---- lfy/api/server/ocr/pytesseract.py | 61 ++++------ lfy/preference.py | 27 +++-- lfy/settings.py | 27 +++++ lfy/widgets/server_preferences.py | 55 ++++----- po/POTFILES | 1 + po/lfy.pot | 136 +++++++++++----------- po/zh_CN.po | 150 ++++++++++++++----------- 18 files changed, 487 insertions(+), 425 deletions(-) create mode 100644 lfy/api/server/ocr/__init__.py create mode 100644 lfy/api/server/ocr/baidu.py diff --git a/data/cool.ldr.lfy.in.gschema.xml b/data/cool.ldr.lfy.in.gschema.xml index c178a92..a2f3eec 100644 --- a/data/cool.ldr.lfy.in.gschema.xml +++ b/data/cool.ldr.lfy.in.gschema.xml @@ -46,6 +46,14 @@ "API Key | Secret Key" Baidu API Key and Secret Key for ocr, used in the middle | split + + "chi_sim+eng" + The lang parameters of the pytesseract module, such as Chinese and English by default + + + "ch_sim+en" + The lang parameters of the easyocr module, such as Chinese and English by default, split by + + "" Baidu OCR access_token diff --git a/data/resources/lfy.cmb b/data/resources/lfy.cmb index 31de698..5aaeaea 100644 --- a/data/resources/lfy.cmb +++ b/data/resources/lfy.cmb @@ -65,6 +65,8 @@ (2,92,"GtkListBox","glb_compare",91,None,None,None,None,None,None), (2,93,"AdwPreferencesGroup",None,5,None,None,None,1,None,None), (2,94,"AdwComboRow","acr_server_ocr",93,None,None,None,-1,None,None), + (2,95,"GtkSeparator",None,94,None,None,None,None,None,None), + (2,96,"GtkButton","btn_config_server_ocr",94,None,None,None,1,None,None), (6,1,"GtkShortcutsWindow","help_overlay",None,None,None,None,None,None,None), (6,2,"GtkShortcutsSection",None,1,None,None,None,None,None,None), (6,3,"GtkShortcutsGroup","general",2,None,None,None,None,None,None), @@ -89,10 +91,6 @@ (10,20,"GtkStack","api_key_stack",19,None,None,None,None,None,None), (10,21,"GtkStackPage",None,20,None,None,None,None,None,None), (10,22,"GtkSpinner","api_key_spinner",21,None,None,None,None,None,None), - (10,24,"AdwEntryRow","api_key_ocr_entry",18,None,None,None,2,None,None), - (10,25,"GtkStack","api_key_ocr_stack",24,None,None,None,None,None,None), - (10,26,"GtkStackPage",None,25,None,None,None,None,None,None), - (10,27,"GtkSpinner","api_key_ocr_spinner",26,None,None,None,None,None,None), (10,28,"GtkLinkButton","api_key_link",18,None,None,None,2,None,None), (12,1,"GtkBox","ThemeSwitcher",None,None,None,None,None,None,None), (12,2,"GtkBox","box",1,None,None,None,None,None,None), @@ -164,7 +162,7 @@ (2,15,"AdwActionRow","subtitle","setup API Key for translation Server, click on the right to the details",1,None,None,None,None,None,None,None,None), (2,15,"AdwActionRow","subtitle-lines","3",None,None,None,None,None,None,None,None,None), (2,15,"AdwActionRow","title-lines","1",None,None,None,None,None,None,None,None,None), - (2,15,"AdwPreferencesRow","title","API Key",1,None,None,None,None,None,None,None,None), + (2,15,"AdwPreferencesRow","title","Translation keys",1,None,None,None,None,None,None,None,None), (2,16,"GtkWidget","margin-bottom","12",None,None,None,None,None,None,None,None,None), (2,16,"GtkWidget","margin-start","12",None,None,None,None,None,None,None,None,None), (2,16,"GtkWidget","margin-top","12",None,None,None,None,None,None,None,None,None), @@ -200,6 +198,12 @@ (2,92,"GtkListBox","selection-mode","multiple",None,None,None,None,None,None,None,None,None), (2,94,"AdwActionRow","subtitle","local or cloud, text recognition",1,None,None,None,None,None,None,None,None), (2,94,"AdwPreferencesRow","title","OCR server",1,None,None,None,None,None,None,None,None), + (2,95,"GtkWidget","margin-bottom","12",None,None,None,None,None,None,None,None,None), + (2,95,"GtkWidget","margin-start","12",None,None,None,None,None,None,None,None,None), + (2,95,"GtkWidget","margin-top","12",None,None,None,None,None,None,None,None,None), + (2,96,"GtkButton","icon-name","open-menu-symbolic",None,None,None,None,None,None,None,None,None), + (2,96,"GtkWidget","margin-start","8",None,None,None,None,None,None,None,None,None), + (2,96,"GtkWidget","valign","center",None,None,None,None,None,None,None,None,None), (6,1,"GtkWindow","modal","True",None,None,None,None,None,None,None,None,None), (6,2,"GtkShortcutsSection","max-height","10",None,None,None,None,None,None,None,None,None), (6,2,"GtkShortcutsSection","section-name","shortcuts",None,None,None,None,None,None,None,None,None), @@ -240,12 +244,6 @@ (10,21,"GtkStackPage","child",None,None,None,None,None,22,None,None,None,None), (10,21,"GtkStackPage","name","spinner",None,None,None,None,None,None,None,None,None), (10,22,"GtkWidget","valign","3",None,None,None,None,None,None,None,None,None), - (10,24,"AdwEntryRow","show-apply-button","true",None,None,None,None,None,None,None,None,None), - (10,24,"AdwPreferencesRow","title","API Key for OCR,Pay attention to whether there are dividing lines |",1,None,None,None,None,None,None,None,None), - (10,24,"GtkWidget","tooltip-text","Enter an API Key for the Server with OCR.",1,None,None,None,None,None,None,None,None), - (10,26,"GtkStackPage","child",None,None,None,None,None,27,None,None,None,None), - (10,26,"GtkStackPage","name","spinner",None,None,None,None,None,None,None,None,None), - (10,27,"GtkWidget","valign","3",None,None,None,None,None,None,None,None,None), (10,28,"GtkButton","label","how to get API Key",1,None,None,None,None,None,None,None,None), (10,28,"GtkLinkButton","uri","https://github.com/ldrfy/lfy",None,None,None,None,None,None,None,None,None), (12,1,"GtkWidget","hexpand","true",None,None,None,None,None,None,None,None,None), @@ -276,7 +274,6 @@ (77,12,5,"GObject","notify","_on_color_scheme_changed","active",None,None,None,None), (78,10,16,"GtkButton","clicked","_on_back",None,None,None,None,None), (79,10,19,"AdwEntryRow","apply","_on_api_key_apply",None,None,None,None,None), - (105,10,24,"AdwEntryRow","apply","_on_api_key_ocr_apply",None,None,None,None,None), (106,2,45,"AdwEntryRow","apply","_on_vpn_apply",None,None,None,None,None), (132,1,168,"GtkTextView","copy-clipboard","_set_tv_copy",None,None,None,None,None), (133,1,168,"GtkTextView","cut-clipboard","_set_tv_copy",None,None,None,None,None), @@ -287,7 +284,8 @@ (140,2,87,"GtkButton","clicked","_export_config",None,None,None,None,None), (141,2,88,"GtkButton","clicked","_import_config",None,None,None,None,None), (144,2,91,"GtkPopover","closed","_on_popover_closed",None,None,None,None,None), - (145,2,94,"GObject","notify","_config_select_server_ocr","selected",None,None,None,None) + (145,2,94,"GObject","notify","_config_select_server_ocr","selected",None,None,None,None), + (146,2,96,"GtkButton","clicked","_open_server_ocr",None,None,None,None,None) (2,17,"GtkWidget",1,1,None,None,None,None,None,None), @@ -304,7 +302,9 @@ (12,1,"GtkWidget",1,1,None,None,None,None,None,None), (12,1,"GtkWidget",2,2,None,1,None,None,None,None), (1,113,"(item)",3,1,None,None,None,None,None,None), - (1,113,"(item)",1,2,"theme",1,None,None,None,None) + (1,113,"(item)",1,2,"theme",1,None,None,None,None), + (2,96,"GtkWidget",1,1,None,None,None,None,None,None), + (2,96,"GtkWidget",2,2,None,1,None,None,None,None) (2,17,"GtkWidget",2,2,"name","flat"), @@ -315,6 +315,7 @@ (12,5,"GtkWidget",2,2,"name","theme-selector"), (12,5,"GtkWidget",2,3,"name","dark"), (12,1,"GtkWidget",2,2,"name","themeswitcher"), - (1,113,"(item)",1,2,"name","custom") + (1,113,"(item)",1,2,"name","custom"), + (2,96,"GtkWidget",2,2,"name","flat") diff --git a/data/resources/preference.ui b/data/resources/preference.ui index df1265a..c7761c6 100644 --- a/data/resources/preference.ui +++ b/data/resources/preference.ui @@ -12,7 +12,7 @@ setup API Key for translation Server, click on the right to the details 3 - API Key + Translation keys 1 @@ -44,6 +44,24 @@ local or cloud, text recognition OCR server + + + 12 + 12 + 12 + + + + + open-menu-symbolic + 8 + center + + + + diff --git a/data/resources/server-preferences.ui b/data/resources/server-preferences.ui index aaa31ec..7d7b531 100644 --- a/data/resources/server-preferences.ui +++ b/data/resources/server-preferences.ui @@ -47,28 +47,6 @@ - - - true - API Key for OCR,Pay attention to whether there are dividing lines | - Enter an API Key for the Server with OCR. - - - - - - - - 3 - - - spinner - - - - - - how to get API Key diff --git a/lfy/api/__init__.py b/lfy/api/__init__.py index 3880b38..372a436 100644 --- a/lfy/api/__init__.py +++ b/lfy/api/__init__.py @@ -3,12 +3,9 @@ """ from gi.repository import Gtk -from lfy.api.constant import SERVERS +from lfy.api.constant import SERVERS_O, SERVERS_T from lfy.api.server import Lang, Server -servers_t = None -servers_o = None - def get_servers_t(): """翻译的服务 @@ -16,10 +13,7 @@ def get_servers_t(): Returns: dict: _description_ """ - global servers_t # pylint:disable=W0603 - if servers_t is None: - servers_t = [s for s in SERVERS if s.can_translate] - return servers_t + return SERVERS_T def get_servers_o(): @@ -28,10 +22,7 @@ def get_servers_o(): Returns: dict: _description_ """ - global servers_o # pylint:disable=W0603 - if servers_o is None: - servers_o = [s for s in SERVERS if s.can_ocr] - return servers_o + return SERVERS_O def get_server_names_t(): @@ -68,7 +59,7 @@ def get_servers_api_key(): list: ["百度", "腾讯", ...] """ - return [s for s in SERVERS if s.get_api_key_s() is not None] + return [s for s in SERVERS_T if s.get_api_key_s() is not None] def get_server_names_api_key(): @@ -89,9 +80,10 @@ def get_server(i: int) -> Server: Returns: _type_: _description_ """ - if i >= len(SERVERS): - return SERVERS[0] - return SERVERS[i] + ss = SERVERS_T + SERVERS_O + if i >= len(ss): + return ss[0] + return ss[i] def create_server_t(key) -> Server: @@ -115,6 +107,7 @@ def create_server_o(key) -> Server: _type_: _description_ """ for s in get_servers_o(): + print(s) if s.key == key: return s @@ -145,7 +138,7 @@ def server_key2i(key: str): Returns: int: 在 servers 是第几个 """ - for i, te in enumerate(SERVERS): + for i, te in enumerate(SERVERS_T): if te.key == key: return i return 0 diff --git a/lfy/api/constant.py b/lfy/api/constant.py index 39f5fef..f9aa079 100644 --- a/lfy/api/constant.py +++ b/lfy/api/constant.py @@ -5,11 +5,13 @@ from lfy.api.server.com import AllServer from lfy.api.server.google import GoogleServer from lfy.api.server.huoshan import HuoShanServer +from lfy.api.server.ocr.baidu import BaiduServer as BaiduOCRServer from lfy.api.server.ocr.easyocr import EasyOcrServer from lfy.api.server.ocr.pytesseract import PytesseractServer from lfy.api.server.tencent import TencentServer -SERVERS = [ +# 翻译服务 +SERVERS_T = [ AllServer(), GoogleServer(), BingServer(), @@ -17,7 +19,11 @@ TencentServer(), AliYunServer(), HuoShanServer(), - # ocr +] + +# OCR文本识别服务 +SERVERS_O = [ + BaiduOCRServer(), PytesseractServer(), EasyOcrServer(), ] diff --git a/lfy/api/server/__init__.py b/lfy/api/server/__init__.py index c57501c..a85e6c8 100644 --- a/lfy/api/server/__init__.py +++ b/lfy/api/server/__init__.py @@ -139,14 +139,14 @@ def translate_text(self, text: str, lang_to: str, lang_from: str = "auto"): return True, "test" def get_api_key_s(self): - """字符串apikey + """字符串apikey,翻译的 Returns: _type_: _description_ """ return None - def ocr_image(self, img_path: str, lang_keys=None): + def ocr_image(self, img_path: str): """图片识别 Args: @@ -170,7 +170,7 @@ def check_ocr(self, api_key_ocr_s): """ return True, "success" - def get_ocr_api_key_s(self): + def get_api_key_s_ocr(self): """图片识别的字符串apikey Returns: diff --git a/lfy/api/server/baidu.py b/lfy/api/server/baidu.py index 8d7bc2b..e2d6f9b 100644 --- a/lfy/api/server/baidu.py +++ b/lfy/api/server/baidu.py @@ -1,9 +1,7 @@ """百度翻译接口 """ -import base64 import hashlib import random -import time from gettext import gettext as _ from urllib.parse import quote @@ -49,66 +47,6 @@ def _translate(session, s, api_key_s, lang_to="auto", lang_from="auto"): return False, f'{error_msg}\n\n{result["error_code"]}: {result["error_msg"]}' -def _get_token(session, ocr_api_key_s): - """https://ai.baidu.com/ai-doc/REFERENCE/Ck3dwjhhu - - Returns: - _type_: _description_ - """ - sg = Settings.get() - - expires_in_date = sg.ocr_baidu_token_expires_date - - if expires_in_date - time.time() > 0: - access_token = sg.ocr_baidu_token - if len(access_token) != 0: - return True, access_token - - api_key, secret_key = s2ks(ocr_api_key_s) - # API Key | Secret Key - if api_key is None or api_key == "API Key": - return False, _("please input API Key in preference") + ": OCR" - - ok, access_token, expires_in_date = \ - _get_token_by_url(session, api_key, secret_key) - - if ok: - sg.ocr_baidu_token = access_token - sg.ocr_baidu_token_expires_date = expires_in_date - - return ok, access_token - - -def _get_token_by_url(session, api_key, secret_key): - """获取token - - Args: - api_key (_type_): _description_ - secret_key (_type_): _description_ - - Returns: - _type_: _description_ - """ - ok = False - expires_in_date = -1 - - # client_id 为官网获取的AK, client_secret 为官网获取的SK - url0 = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials" - url = f'{url0}&client_id={api_key}&client_secret={secret_key}' - - request = session.get(url, timeout=TIME_OUT) - - jsons = request.json() - if "access_token" not in jsons: - access_token = "错误:" + jsons["error_description"] - else: - access_token = jsons["access_token"] - expires_in_date = time.time() + jsons["expires_in"] - ok = True - - return ok, str(access_token), expires_in_date - - class BaiduServer(Server): """百度翻译 """ @@ -129,7 +67,6 @@ def __init__(self): "it": 8 } super().__init__("baidu", _("baidu"), lang_key_ns) - self.can_ocr = True self.can_translate = True def check_translate(self, api_key_s): @@ -169,70 +106,3 @@ def get_api_key_s(self): _type_: _description_ """ return Settings.get().server_sk_baidu - - def get_ocr_api_key_s(self): - """图片识别的字符串apikey - - Returns: - _type_: _description_ - """ - return Settings.get().server_sk_baidu_ocr - - def ocr_image(self, img_path): - img_data = open(img_path, 'rb').read() - img = base64.b64encode(img_data) - - # open('./images/lt.png', 'rb').read() - s = "" - request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/" - - request_url += "general_basic" - - ok, token = _get_token(self.session, self.get_ocr_api_key_s()) - if not ok: - return False, token - params = {"image": img} - request_url = request_url + "?access_token=" + token - headers = {'content-type': 'application/x-www-form-urlencoded'} - res = self.session.post(request_url, - data=params, - headers=headers, - timeout=TIME_OUT).json() - - if "error_code" in res: - if 110 == res["error_code"]: - Settings.get().ocr_baidu_token = "" - error_msg = _("something error:") - return False, f'{error_msg}\n\n{res["error_code"]}: {res["error_msg"]}' - - for word in res["words_result"]: - s += word["words"] + '\n' - - s_ = word["words"] - if s_[len(s_) - 1:len(s_)] != "-": - s += " " - - return ok, s - - def check_ocr(self, api_key_ocr_s): - """OCR测试 - - Args: - api_key_ocr_s (str): _description_ - - Returns: - _type_: _description_ - """ - api_key, secret_key = s2ks(api_key_ocr_s) - if api_key is None or api_key == "API Key": - error_msg = _("please input API Key and Secret Key like:") - return False, error_msg + " 121343 | fdsdsdg" - - ok, access_token, expires_in_date = \ - _get_token_by_url(self.session, api_key, secret_key) - if ok: - sg = Settings.get() - sg.server_sk_baidu_ocr = api_key_ocr_s - sg.ocr_baidu_token = access_token - sg.ocr_baidu_token_expires_date = expires_in_date - return ok, "success" diff --git a/lfy/api/server/ocr/__init__.py b/lfy/api/server/ocr/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lfy/api/server/ocr/baidu.py b/lfy/api/server/ocr/baidu.py new file mode 100644 index 0000000..0c7ab26 --- /dev/null +++ b/lfy/api/server/ocr/baidu.py @@ -0,0 +1,162 @@ +"""百度翻译接口 +""" +import base64 +import time +from gettext import gettext as _ + +from lfy.api.server import TIME_OUT, Server +from lfy.api.utils import s2ks +from lfy.settings import Settings + + +def _get_token(session, ocr_api_key_s): + """https://ai.baidu.com/ai-doc/REFERENCE/Ck3dwjhhu + + Returns: + _type_: _description_ + """ + sg = Settings.get() + + expires_in_date = sg.ocr_baidu_token_expires_date + + if expires_in_date - time.time() > 0: + access_token = sg.ocr_baidu_token + if len(access_token) != 0: + return True, access_token + + api_key, secret_key = s2ks(ocr_api_key_s) + # API Key | Secret Key + if api_key is None or api_key == "API Key": + return False, _("please input API Key in preference") + ": OCR" + + ok, access_token, expires_in_date = \ + _get_token_by_url(session, api_key, secret_key) + + if ok: + sg.ocr_baidu_token = access_token + sg.ocr_baidu_token_expires_date = expires_in_date + + return ok, access_token + + +def _get_token_by_url(session, api_key, secret_key): + """获取token + + Args: + api_key (_type_): _description_ + secret_key (_type_): _description_ + + Returns: + _type_: _description_ + """ + ok = False + expires_in_date = -1 + + # client_id 为官网获取的AK, client_secret 为官网获取的SK + url0 = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials" + url = f'{url0}&client_id={api_key}&client_secret={secret_key}' + + request = session.get(url, timeout=TIME_OUT) + + jsons = request.json() + if "access_token" not in jsons: + access_token = "错误:" + jsons["error_description"] + else: + access_token = jsons["access_token"] + expires_in_date = time.time() + jsons["expires_in"] + ok = True + + return ok, str(access_token), expires_in_date + + +class BaiduServer(Server): + """百度翻译 + """ + + def __init__(self): + + # Development documentation + # https://fanyi-api.baidu.com/doc/21 + + super().__init__("baidu_ocr", _("baidu"), {}) + self.can_ocr = True + + def get_api_key_s_ocr(self): + """图片识别的字符串apikey + + Returns: + _type_: _description_ + """ + return Settings.get().server_sk_baidu_ocr + + def ocr_image(self, img_path): + """图文识别 + + Args: + img_path (_type_): _description_ + + Returns: + _type_: _description_ + """ + img_data = None + with open(img_path, 'r', encoding='utf-8') as f: + img_data = f.read() + if img_data is None: + return False, "" + + img = base64.b64encode(img_data) + + # open('./images/lt.png', 'rb').read() + s = "" + request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/" + + request_url += "general_basic" + + ok, token = _get_token(self.session, self.get_api_key_s_ocr()) + if not ok: + return False, token + params = {"image": img} + request_url = request_url + "?access_token=" + token + headers = {'content-type': 'application/x-www-form-urlencoded'} + res = self.session.post(request_url, + data=params, + headers=headers, + timeout=TIME_OUT).json() + + if "error_code" in res: + if 110 == res["error_code"]: + Settings.get().ocr_baidu_token = "" + error_msg = _("something error:") + return False, f'{error_msg}\n\n{res["error_code"]}: {res["error_msg"]}' + + for word in res["words_result"]: + s += word["words"] + '\n' + + s_ = word["words"] + if s_[len(s_) - 1:len(s_)] != "-": + s += " " + + return ok, s + + def check_ocr(self, api_key_ocr_s): + """OCR测试 + + Args: + api_key_ocr_s (str): _description_ + + Returns: + _type_: _description_ + """ + api_key, secret_key = s2ks(api_key_ocr_s) + if api_key is None or api_key == "API Key": + error_msg = _("please input API Key and Secret Key like:") + return False, error_msg + " 121343 | fdsdsdg" + + ok, access_token, expires_in_date = \ + _get_token_by_url(self.session, api_key, secret_key) + if ok: + sg = Settings.get() + sg.server_sk_baidu_ocr = api_key_ocr_s + sg.ocr_baidu_token = access_token + sg.ocr_baidu_token_expires_date = expires_in_date + return ok, "success" diff --git a/lfy/api/server/ocr/easyocr.py b/lfy/api/server/ocr/easyocr.py index 314bb57..1cebc2c 100644 --- a/lfy/api/server/ocr/easyocr.py +++ b/lfy/api/server/ocr/easyocr.py @@ -1,6 +1,7 @@ 'ocr' from lfy.api.server import Server from lfy.api.utils.debug import get_logger +from lfy.settings import Settings class EasyOcrServer(Server): @@ -8,35 +9,29 @@ class EasyOcrServer(Server): """ def __init__(self): - - # Development documentation - # https://fanyi-api.baidu.com/doc/21 - lang_key_ns = { - "auto": 0, - "zh": 1, - "wyw": 2, - "en": 3, - "jp": 4, - "kor": 5, - "de": 6, - "fra": 7, - "it": 8 - } - super().__init__("easyocr", "easyocr", lang_key_ns) + super().__init__("easyocr", "easyocr", {}) self.can_ocr = True - def ocr_image(self, img_path: str, lang_keys=None): + def ocr_image(self, img_path: str): try: import easyocr - if lang_keys is None: - lang_keys = ['ch_sim', 'en'] + lang_keys = self.get_api_key_s_ocr().split('+') reader = easyocr.Reader(lang_keys) - list_ = reader.readtext(img_path, detail=0) - s = "" - for s_ in list_: - s += s_ + " " + s = " ".join(reader.readtext(img_path, detail=0)) return True, s.strip() except ModuleNotFoundError as e: print(e) get_logger().error(e) return False, "请安装 easyocr\n" + str(e) + + def get_api_key_s_ocr(self): + """图片识别的字符串apikey + + Returns: + _type_: _description_ + """ + return Settings.get().server_sk_easyocr_ocr + + def check_ocr(self, api_key_ocr_s): + Settings.get().server_sk_easyocr_ocr = api_key_ocr_s + return True, "success" diff --git a/lfy/api/server/ocr/pytesseract.py b/lfy/api/server/ocr/pytesseract.py index 4acebdb..53ebdb2 100644 --- a/lfy/api/server/ocr/pytesseract.py +++ b/lfy/api/server/ocr/pytesseract.py @@ -1,29 +1,8 @@ 'ocr本地' + from lfy.api.server import Server from lfy.api.utils.debug import get_logger - - -def lib_ok(): - """_summary_ - - Returns: - _type_: _description_ - """ - try: - import pytesseract - return True - except ModuleNotFoundError as e: - print(e) - get_logger().error(e) - return False - - -def main(img_path): - - if lib_ok(): - import pytesseract - return True, pytesseract.image_to_string(img_path, lang='chi_sim+eng') - return False, None +from lfy.settings import Settings class PytesseractServer(Server): @@ -32,31 +11,29 @@ class PytesseractServer(Server): def __init__(self): - # Development documentation - # https://fanyi-api.baidu.com/doc/21 - lang_key_ns = { - "auto": 0, - "zh": 1, - "wyw": 2, - "en": 3, - "jp": 4, - "kor": 5, - "de": 6, - "fra": 7, - "it": 8 - } - super().__init__("pytesseract", "pytesseract", lang_key_ns) + # 获取系统默认语言,英语添加 + + super().__init__("pytesseract", "pytesseract", {}) self.can_ocr = True - def ocr_image(self, img_path: str, lang_keys=None): + def ocr_image(self, img_path: str): try: import pytesseract - s = "en" - if lang_keys is None: - lang_keys = ['ch_sim', 'eng'] - s = '+'.join(lang_keys) + s = self.get_api_key_s_ocr() return True, pytesseract.image_to_string(img_path, lang=s) except ModuleNotFoundError as e: print(e) get_logger().error(e) return False, "请安装 pytesseract\n" + str(e) + + def get_api_key_s_ocr(self): + """图片识别的字符串apikey + + Returns: + _type_: _description_ + """ + return Settings.get().server_sk_pytesseract_ocr + + def check_ocr(self, api_key_ocr_s): + Settings.get().server_sk_pytesseract_ocr = api_key_ocr_s + return True, "success" diff --git a/lfy/preference.py b/lfy/preference.py index 224794c..bd60143 100644 --- a/lfy/preference.py +++ b/lfy/preference.py @@ -1,5 +1,6 @@ '设置' +import time from gettext import gettext as _ from gi.repository import Adw, Gdk, Gio, Gtk @@ -37,24 +38,26 @@ def __init__(self, **kwargs): super().__init__(**kwargs) self.sg = Settings.get() self.server: Server + self.server_ocr: Server # pylint: disable=E1101 self.acr_server.set_model(get_server_names_api_key()) - self.ocr_s = 0 + self.ocr_s_time = time.time() self.acr_server_ocr.set_model(get_server_names_o()) sso = get_servers_o() for i, so in enumerate(sso): if so.key == self.sg.server_ocr_selected_key: self.acr_server_ocr.set_selected(i) + self.server_ocr = so break self.entry_vpn_addr.props.text = self.sg.vpn_addr_port self.sg.bind('auto-check-update', self.auto_check_update, - 'active', Gio.SettingsBindFlags.DEFAULT) + 'active', Gio.SettingsBindFlags.DEFAULT) self.sg.bind('notify-translation-results', self.notify_translation_results, - 'active', Gio.SettingsBindFlags.DEFAULT) + 'active', Gio.SettingsBindFlags.DEFAULT) self._init_pop_compare() self.cb = Gdk.Display.get_default().get_clipboard() @@ -134,16 +137,20 @@ def _on_popover_closed(self, _popover): @Gtk.Template.Callback() def _open_server(self, _btn): - page = ServerPreferences(self.server) - self.present_subpage(page) + self.present_subpage(ServerPreferences(self.server)) + + @Gtk.Template.Callback() + def _open_server_ocr(self, _btn): + self.present_subpage(ServerPreferences(self.server_ocr, True)) @Gtk.Template.Callback() def _config_select_server_ocr(self, arc, _value): - if self.ocr_s > 0: - _k = get_servers_o()[arc.get_selected()].key - self.sg.server_ocr_selected_key = _k - print("ocr ......", arc.get_selected(), _k) - self.ocr_s += 1 + if time.time() - self.ocr_s_time > 0.5: + self.server_ocr = get_servers_o()[arc.get_selected()] + self.sg.server_ocr_selected_key = self.server_ocr.key + + s = _("Using {} for text recognition").format(self.server_ocr.name) + self.get_root().add_toast(Adw.Toast.new(s)) @Gtk.Template.Callback() def _config_select_server(self, arc, _value): diff --git a/lfy/settings.py b/lfy/settings.py index ff951fb..c425b2e 100644 --- a/lfy/settings.py +++ b/lfy/settings.py @@ -104,6 +104,33 @@ def server_sk_baidu_ocr(self): def server_sk_baidu_ocr(self, key): self.set_string('server-sk-baidu-ocr', key) + @property + def server_sk_pytesseract_ocr(self): + """pytesseract模块的lang参数,默认为中文、英文 + + Returns: + str: 如:pytesseract + """ + return self.get_string('server-sk-pytesseract-ocr') + + @server_sk_pytesseract_ocr.setter + def server_sk_pytesseract_ocr(self, key): + self.set_string('server-sk-pytesseract-ocr', key) + + @property + def server_sk_easyocr_ocr(self): + """easyocr模块的lang参数,默认为中文、英文 + + Returns: + str: 如:easyocr + """ + return self.get_string('server-sk-easyocr-ocr') + + @server_sk_easyocr_ocr.setter + def server_sk_easyocr_ocr(self, key): + self.set_string('server-sk-easyocr-ocr', key) + + @property def ocr_baidu_token(self): """百度OCR的服务密钥再次请求得到的token,只是一个字符串 diff --git a/lfy/widgets/server_preferences.py b/lfy/widgets/server_preferences.py index 0cc1425..4d4c919 100644 --- a/lfy/widgets/server_preferences.py +++ b/lfy/widgets/server_preferences.py @@ -4,6 +4,7 @@ import re import threading +from gettext import gettext as _ from gi.repository import Adw, GLib, Gtk @@ -28,24 +29,23 @@ class ServerPreferences(Adw.Bin): api_key_stack = Gtk.Template.Child() api_key_spinner = Gtk.Template.Child() - api_key_ocr_entry = Gtk.Template.Child() - api_key_ocr_stack = Gtk.Template.Child() - api_key_ocr_spinner = Gtk.Template.Child() - api_key_link = Gtk.Template.Child() - def __init__(self, server: Server, **kwargs): + def __init__(self, server: Server, is_ocr=False, **kwargs): super().__init__(**kwargs) self.server = server - self.title.props.subtitle = server.name - # Load saved values - self.api_key_entry.props.text = server.get_api_key_s() + self.is_ocr = is_ocr + s = _("Text translate") + if is_ocr: + s = _("Text recognition") + + self.title.set_title(s) + self.title.set_subtitle(server.name) - ocr_enable = server.get_ocr_api_key_s() is not None - if ocr_enable: - # print(server.get_ocr_api_key_s()) - self.api_key_ocr_entry.set_text(server.get_ocr_api_key_s()) - self.api_key_ocr_entry.set_visible(ocr_enable) + if not self.is_ocr: + self.api_key_entry.set_text(server.get_api_key_s()) + else: + self.api_key_entry.set_text(server.get_api_key_s_ocr()) self.api_key_link.set_uri(server.get_doc_url()) @@ -56,36 +56,23 @@ def _on_back(self, _button): @Gtk.Template.Callback() def _on_api_key_apply(self, _row): - """ Called on self.api_key_entry::apply signal """ api_key = self.api_key_entry.get_text() api_key = re.sub(r'\s*\|\s*', " | ", api_key.strip()) - self.api_key_entry.props.text = api_key - self.api_key_entry.props.sensitive = False - self.api_key_stack.props.visible_child_name = 'spinner' + self.api_key_entry.set_text(api_key) + self.api_key_entry.set_sensitive(False) + self.api_key_stack.set_visible_child_name('spinner') self.api_key_spinner.start() + check_ot = self.server.check_translate + if self.is_ocr: + check_ot = self.server.check_ocr + threading.Thread(target=self.request_text, daemon=True, - args=(self.server.check_translate, api_key, + args=(check_ot, api_key, self.api_key_entry, self.api_key_spinner)).start() - @Gtk.Template.Callback() - def _on_api_key_ocr_apply(self, _row): - """ Called on self.api_key_entry::apply signal """ - - api_key = self.api_key_ocr_entry.get_text() - api_key = re.sub(r'\s*\|\s*', " | ", api_key.strip()) - self.api_key_ocr_entry.set_text(api_key) - self.api_key_ocr_entry.set_sensitive(False) - self.api_key_ocr_stack.set_visible_child_name('spinner') - self.api_key_ocr_spinner.start() - - threading.Thread(target=self.request_text, daemon=True, - args=(self.server.check_ocr, api_key, - self.api_key_ocr_entry, - self.api_key_ocr_spinner)).start() - def update_ui(self, valid, entry, spinner): """更新 diff --git a/po/POTFILES b/po/POTFILES index 5c3bc61..2c5bfb7 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -18,6 +18,7 @@ lfy/api/server/bing.py lfy/api/server/aliyun.py lfy/api/server/com.py lfy/api/server/huoshan.py +lfy/widgets/server_preferences.py data/resources/translate.ui data/resources/server-preferences.ui diff --git a/po/lfy.pot b/po/lfy.pot index 52ab1f2..d2a2b42 100644 --- a/po/lfy.pot +++ b/po/lfy.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: cool.ldr.lfy\n" "Report-Msgid-Bugs-To: yuhldr@gmail.com\n" -"POT-Creation-Date: 2024-09-20 15:16+0800\n" +"POT-Creation-Date: 2024-09-21 00:13+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -31,7 +31,7 @@ msgstr "" msgid "Automatically check the new version of the software upon startup" msgstr "" -#: data/cool.ldr.lfy.in.gschema.xml:14 data/resources/preference.ui:75 +#: data/cool.ldr.lfy.in.gschema.xml:14 data/resources/preference.ui:93 msgid "" "After the translation is completed, a system notification is automatically " "sent" @@ -66,30 +66,42 @@ msgid "Baidu API Key and Secret Key for ocr, used in the middle | split" msgstr "" #: data/cool.ldr.lfy.in.gschema.xml:51 -msgid "Baidu OCR access_token" +msgid "" +"The lang parameters of the pytesseract module, such as Chinese and English " +"by default" msgstr "" #: data/cool.ldr.lfy.in.gschema.xml:55 -msgid "Baidu OCR access_token expires date" +msgid "" +"The lang parameters of the easyocr module, such as Chinese and English by " +"default, split by +" msgstr "" #: data/cool.ldr.lfy.in.gschema.xml:59 -msgid "aliyun AccessKey ID and AccessKey Secret, used in the middle | split" +msgid "Baidu OCR access_token" msgstr "" #: data/cool.ldr.lfy.in.gschema.xml:63 -msgid "huoshan Access Key ID and Secret Access Key, used in the middle | split" +msgid "Baidu OCR access_token expires date" msgstr "" #: data/cool.ldr.lfy.in.gschema.xml:67 -msgid "Tencent secret_id and secret_key, used in the middle | split" +msgid "aliyun AccessKey ID and AccessKey Secret, used in the middle | split" msgstr "" #: data/cool.ldr.lfy.in.gschema.xml:71 +msgid "huoshan Access Key ID and Secret Access Key, used in the middle | split" +msgstr "" + +#: data/cool.ldr.lfy.in.gschema.xml:75 +msgid "Tencent secret_id and secret_key, used in the middle | split" +msgstr "" + +#: data/cool.ldr.lfy.in.gschema.xml:79 msgid "VPN address and port" msgstr "" -#: data/cool.ldr.lfy.in.gschema.xml:75 data/resources/preference.ui:100 +#: data/cool.ldr.lfy.in.gschema.xml:83 data/resources/preference.ui:118 msgid "Which services are available in compare model" msgstr "" @@ -181,77 +193,80 @@ msgstr "" msgid "A translation app for GNOME." msgstr "" -#: lfy/main.py:154 data/resources/help-overlay.ui:20 +#: lfy/main.py:157 data/resources/help-overlay.ui:20 #: data/resources/help-overlay.ui:27 data/resources/help-overlay.ui:34 #: data/resources/help-overlay.ui:53 msgid "Copy detected, translate immediately" msgstr "" -#: lfy/main.py:157 +#: lfy/main.py:160 msgid "Copy detected, not automatically translated" msgstr "" -#: lfy/main.py:181 +#: lfy/main.py:184 msgid "Next translation not remove line breaks" msgstr "" -#: lfy/main.py:182 +#: lfy/main.py:185 msgid "Next translation remove line breaks" msgstr "" -#: lfy/main.py:192 +#: lfy/main.py:195 msgid "Next translation without splicing text" msgstr "" -#: lfy/main.py:193 +#: lfy/main.py:196 msgid "Next translation splicing text" msgstr "" -#: lfy/preference.py:66 lfy/api/server/com.py:72 +#: lfy/preference.py:69 lfy/api/server/com.py:74 msgid "compare" msgstr "" -#: lfy/preference.py:93 lfy/preference.py:133 lfy/preference.py:163 +#: lfy/preference.py:96 lfy/preference.py:136 lfy/preference.py:170 msgid "It takes effect when you restart lfy" msgstr "" -#: lfy/preference.py:101 +#: lfy/preference.py:104 msgid "The clipboard format is incorrect" msgstr "" -#: lfy/preference.py:109 +#: lfy/preference.py:112 msgid "Configuration data has been exported to the clipboard" msgstr "" -#: lfy/translate.py:234 +#: lfy/preference.py:152 +msgid "Using {} for text recognition" +msgstr "" + +#: lfy/translate.py:235 msgid "" "This time the content contains private information and is not translated" msgstr "" -#: lfy/translate.py:285 lfy/translate.py:317 lfy/api/server/baidu.py:42 -#: lfy/api/server/baidu.py:205 lfy/api/server/tencent.py:150 -#: lfy/api/server/aliyun.py:98 lfy/api/server/com.py:28 -#: lfy/api/server/huoshan.py:136 +#: lfy/translate.py:288 lfy/translate.py:321 lfy/api/server/baidu.py:40 +#: lfy/api/server/tencent.py:150 lfy/api/server/aliyun.py:98 +#: lfy/api/server/com.py:29 lfy/api/server/huoshan.py:136 msgid "something error:" msgstr "" -#: lfy/translate.py:301 +#: lfy/translate.py:304 msgid "OCRing.." msgstr "" -#: lfy/translate.py:303 +#: lfy/translate.py:306 msgid "Translating.." msgstr "" -#: lfy/translate.py:315 +#: lfy/translate.py:318 msgid "Translation completed" msgstr "" -#: lfy/api/utils/bak.py:52 +#: lfy/api/utils/bak.py:53 msgid "error with keys: " msgstr "" -#: lfy/api/utils/bak.py:61 +#: lfy/api/utils/bak.py:63 msgid "Please copy the configuration data in json format first" msgstr "" @@ -291,33 +306,28 @@ msgstr "" msgid "Italian" msgstr "" -#: lfy/api/server/baidu.py:30 lfy/api/server/baidu.py:70 -#: lfy/api/server/tencent.py:127 lfy/api/server/aliyun.py:68 -#: lfy/api/server/huoshan.py:67 +#: lfy/api/server/baidu.py:28 lfy/api/server/tencent.py:127 +#: lfy/api/server/aliyun.py:68 lfy/api/server/huoshan.py:67 msgid "please input API Key in preference" msgstr "" -#: lfy/api/server/baidu.py:131 +#: lfy/api/server/baidu.py:69 msgid "baidu" msgstr "" -#: lfy/api/server/baidu.py:144 +#: lfy/api/server/baidu.py:81 msgid "please input app_id and secret_key like:" msgstr "" -#: lfy/api/server/baidu.py:228 -msgid "please input API Key and Secret Key like:" -msgstr "" - -#: lfy/api/server/google.py:44 +#: lfy/api/server/google.py:45 msgid "google" msgstr "" -#: lfy/api/server/google.py:60 lfy/api/server/bing.py:77 +#: lfy/api/server/google.py:61 lfy/api/server/bing.py:78 msgid "something error, try other translate engine?" msgstr "" -#: lfy/api/server/google.py:72 +#: lfy/api/server/google.py:74 msgid "The connection timed out. Maybe there is a network problem" msgstr "" @@ -329,11 +339,11 @@ msgstr "" msgid "please input secret_id and secret_key like:" msgstr "" -#: lfy/api/server/bing.py:60 +#: lfy/api/server/bing.py:61 msgid "bing" msgstr "" -#: lfy/api/server/bing.py:128 +#: lfy/api/server/bing.py:131 #, python-brace-format msgid "1000 characters limit! You send {len_text} characters." msgstr "" @@ -350,6 +360,14 @@ msgstr "" msgid "huoshan" msgstr "" +#: lfy/widgets/server_preferences.py:38 +msgid "Text translate" +msgstr "" + +#: lfy/widgets/server_preferences.py:40 +msgid "Text recognition" +msgstr "" + #: data/resources/translate.ui:71 msgid "Alt + D: Remove symbols such as line breaks" msgstr "" @@ -407,15 +425,7 @@ msgstr "" msgid "Enter an API Key for the Server with Translate." msgstr "" -#: data/resources/server-preferences.ui:53 -msgid "API Key for OCR,Pay attention to whether there are dividing lines |" -msgstr "" - -#: data/resources/server-preferences.ui:54 -msgid "Enter an API Key for the Server with OCR." -msgstr "" - -#: data/resources/server-preferences.ui:74 +#: data/resources/server-preferences.ui:52 msgid "how to get API Key" msgstr "" @@ -424,7 +434,7 @@ msgid "setup API Key for translation Server, click on the right to the details" msgstr "" #: data/resources/preference.ui:15 -msgid "API Key" +msgid "Translation keys" msgstr "" #: data/resources/preference.ui:44 @@ -435,49 +445,49 @@ msgstr "" msgid "OCR server" msgstr "" -#: data/resources/preference.ui:57 +#: data/resources/preference.ui:75 msgid "vpn addr and port, like http://127.0.0.1:7890" msgstr "" -#: data/resources/preference.ui:68 +#: data/resources/preference.ui:86 msgid "Automatically check for updates when opening software" msgstr "" -#: data/resources/preference.ui:69 +#: data/resources/preference.ui:87 msgid "auto check update" msgstr "" -#: data/resources/preference.ui:76 +#: data/resources/preference.ui:94 msgid "Notify translation results" msgstr "" -#: data/resources/preference.ui:86 +#: data/resources/preference.ui:104 msgid "Compare model" msgstr "" -#: data/resources/preference.ui:112 +#: data/resources/preference.ui:130 msgid "backup/restore the settings to/from the clipboard, edit or backup it" msgstr "" -#: data/resources/preference.ui:113 +#: data/resources/preference.ui:131 msgid "Software settings backup and restore" msgstr "" -#: data/resources/preference.ui:116 +#: data/resources/preference.ui:134 msgid "backup" msgstr "" -#: data/resources/preference.ui:118 +#: data/resources/preference.ui:136 msgid "" "Export the configuration to the clipboard, then you can paste it into any " "file and edit it" msgstr "" -#: data/resources/preference.ui:125 +#: data/resources/preference.ui:143 msgid "restore" msgstr "" -#: data/resources/preference.ui:127 +#: data/resources/preference.ui:145 msgid "" "Read the JSON configuration of the clipboard, then import it, and some of " "the configurations will take effect after reopening the software" diff --git a/po/zh_CN.po b/po/zh_CN.po index d508246..8b7d840 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: cool.ldr.lfy\n" "Report-Msgid-Bugs-To: yuhldr@gmail.com\n" -"POT-Creation-Date: 2024-09-20 15:16+0800\n" +"POT-Creation-Date: 2024-09-21 00:13+0800\n" "PO-Revision-Date: 2023-11-12 21:02+0800\n" "Last-Translator: \n" "Language-Team: Chinese (simplified) \n" @@ -31,7 +31,7 @@ msgstr "窗口大小" msgid "Automatically check the new version of the software upon startup" msgstr "软件打开时,自动检查更新" -#: data/cool.ldr.lfy.in.gschema.xml:14 data/resources/preference.ui:75 +#: data/cool.ldr.lfy.in.gschema.xml:14 data/resources/preference.ui:93 msgid "" "After the translation is completed, a system notification is automatically " "sent" @@ -67,30 +67,42 @@ msgid "Baidu API Key and Secret Key for ocr, used in the middle | split" msgstr "百度app_id和secret_key,中间使用 | 分割" #: data/cool.ldr.lfy.in.gschema.xml:51 +msgid "" +"The lang parameters of the pytesseract module, such as Chinese and English " +"by default" +msgstr "pytesseract模块的lang参数,默认为中文、英文" + +#: data/cool.ldr.lfy.in.gschema.xml:55 +msgid "" +"The lang parameters of the easyocr module, such as Chinese and English by " +"default, split by +" +msgstr "easyocr模块的lang参数,默认是中文和英文,用+分割" + +#: data/cool.ldr.lfy.in.gschema.xml:59 msgid "Baidu OCR access_token" msgstr "百度OCR access_token" -#: data/cool.ldr.lfy.in.gschema.xml:55 +#: data/cool.ldr.lfy.in.gschema.xml:63 msgid "Baidu OCR access_token expires date" msgstr "百度OCR access_token 过期时间" -#: data/cool.ldr.lfy.in.gschema.xml:59 +#: data/cool.ldr.lfy.in.gschema.xml:67 msgid "aliyun AccessKey ID and AccessKey Secret, used in the middle | split" msgstr "阿里云 AccessKey ID 和 AccessKey Secret,中间使用 | 分割" -#: data/cool.ldr.lfy.in.gschema.xml:63 +#: data/cool.ldr.lfy.in.gschema.xml:71 msgid "huoshan Access Key ID and Secret Access Key, used in the middle | split" msgstr "火山 AccessKey Key ID 和 Secret Access Key,中间使用 | 分割" -#: data/cool.ldr.lfy.in.gschema.xml:67 +#: data/cool.ldr.lfy.in.gschema.xml:75 msgid "Tencent secret_id and secret_key, used in the middle | split" msgstr "请输入 app_id 和 secret_key,类似:" -#: data/cool.ldr.lfy.in.gschema.xml:71 +#: data/cool.ldr.lfy.in.gschema.xml:79 msgid "VPN address and port" msgstr "VPN地址" -#: data/cool.ldr.lfy.in.gschema.xml:75 data/resources/preference.ui:100 +#: data/cool.ldr.lfy.in.gschema.xml:83 data/resources/preference.ui:118 msgid "Which services are available in compare model" msgstr "在比较模式下哪些服务被选中" @@ -182,77 +194,80 @@ msgstr "yuh , 2023-2023" msgid "A translation app for GNOME." msgstr "一个翻译软件,为gnome桌面设计" -#: lfy/main.py:154 data/resources/help-overlay.ui:20 +#: lfy/main.py:157 data/resources/help-overlay.ui:20 #: data/resources/help-overlay.ui:27 data/resources/help-overlay.ui:34 #: data/resources/help-overlay.ui:53 msgid "Copy detected, translate immediately" msgstr "检测到复制,立刻翻译" -#: lfy/main.py:157 +#: lfy/main.py:160 msgid "Copy detected, not automatically translated" msgstr "检测到复制,不自动翻译" -#: lfy/main.py:181 +#: lfy/main.py:184 msgid "Next translation not remove line breaks" msgstr "下次翻译不移除换行" -#: lfy/main.py:182 +#: lfy/main.py:185 msgid "Next translation remove line breaks" msgstr "下次翻译移除换行" -#: lfy/main.py:192 +#: lfy/main.py:195 msgid "Next translation without splicing text" msgstr "下次翻译不拼接文本" -#: lfy/main.py:193 +#: lfy/main.py:196 msgid "Next translation splicing text" msgstr "下次翻译拼接文本" -#: lfy/preference.py:66 lfy/api/server/com.py:72 +#: lfy/preference.py:69 lfy/api/server/com.py:74 msgid "compare" msgstr "对比" -#: lfy/preference.py:93 lfy/preference.py:133 lfy/preference.py:163 +#: lfy/preference.py:96 lfy/preference.py:136 lfy/preference.py:170 msgid "It takes effect when you restart lfy" msgstr "重新打开lfy时生效" -#: lfy/preference.py:101 +#: lfy/preference.py:104 msgid "The clipboard format is incorrect" msgstr "剪贴板文本格式不正确" -#: lfy/preference.py:109 +#: lfy/preference.py:112 msgid "Configuration data has been exported to the clipboard" msgstr "配置数据已导出到剪贴板" -#: lfy/translate.py:234 +#: lfy/preference.py:152 +msgid "Using {} for text recognition" +msgstr "使用 {} 进行文本识别" + +#: lfy/translate.py:235 msgid "" "This time the content contains private information and is not translated" msgstr "本次内容包含隐私信息,不翻译" -#: lfy/translate.py:285 lfy/translate.py:317 lfy/api/server/baidu.py:42 -#: lfy/api/server/baidu.py:205 lfy/api/server/tencent.py:150 -#: lfy/api/server/aliyun.py:98 lfy/api/server/com.py:28 -#: lfy/api/server/huoshan.py:136 +#: lfy/translate.py:288 lfy/translate.py:321 lfy/api/server/baidu.py:40 +#: lfy/api/server/tencent.py:150 lfy/api/server/aliyun.py:98 +#: lfy/api/server/com.py:29 lfy/api/server/huoshan.py:136 msgid "something error:" msgstr "一些错误发生:" -#: lfy/translate.py:301 +#: lfy/translate.py:304 msgid "OCRing.." msgstr "OCR识别中.." -#: lfy/translate.py:303 +#: lfy/translate.py:306 msgid "Translating.." msgstr "翻译中……" -#: lfy/translate.py:315 +#: lfy/translate.py:318 msgid "Translation completed" msgstr "翻译完成" -#: lfy/api/utils/bak.py:52 +#: lfy/api/utils/bak.py:53 msgid "error with keys: " msgstr "如下key错误: " -#: lfy/api/utils/bak.py:61 +#: lfy/api/utils/bak.py:63 msgid "Please copy the configuration data in json format first" msgstr "请先复制json格式的配置数据" @@ -292,33 +307,28 @@ msgstr "法语" msgid "Italian" msgstr "意大利语" -#: lfy/api/server/baidu.py:30 lfy/api/server/baidu.py:70 -#: lfy/api/server/tencent.py:127 lfy/api/server/aliyun.py:68 -#: lfy/api/server/huoshan.py:67 +#: lfy/api/server/baidu.py:28 lfy/api/server/tencent.py:127 +#: lfy/api/server/aliyun.py:68 lfy/api/server/huoshan.py:67 msgid "please input API Key in preference" msgstr "请在设置中填写 API Key" -#: lfy/api/server/baidu.py:131 +#: lfy/api/server/baidu.py:69 msgid "baidu" msgstr "百度" -#: lfy/api/server/baidu.py:144 +#: lfy/api/server/baidu.py:81 msgid "please input app_id and secret_key like:" msgstr "请输入 app_id 和 secret_key,类似:" -#: lfy/api/server/baidu.py:228 -msgid "please input API Key and Secret Key like:" -msgstr "请输入 app_id 和 secret_key,类似:" - -#: lfy/api/server/google.py:44 +#: lfy/api/server/google.py:45 msgid "google" msgstr "谷歌" -#: lfy/api/server/google.py:60 lfy/api/server/bing.py:77 +#: lfy/api/server/google.py:61 lfy/api/server/bing.py:78 msgid "something error, try other translate engine?" msgstr "出现了一些错误,试试其他翻译引擎?" -#: lfy/api/server/google.py:72 +#: lfy/api/server/google.py:74 msgid "The connection timed out. Maybe there is a network problem" msgstr "连接超时,网络可能有问题(比如需要代理)" @@ -330,11 +340,11 @@ msgstr "腾讯" msgid "please input secret_id and secret_key like:" msgstr "请输入 app_id 和 secret_key,类似:" -#: lfy/api/server/bing.py:60 +#: lfy/api/server/bing.py:61 msgid "bing" msgstr "必应" -#: lfy/api/server/bing.py:128 +#: lfy/api/server/bing.py:131 #, python-brace-format msgid "1000 characters limit! You send {len_text} characters." msgstr "被限制在1000个字符! 你发送了 {len_text} 个字符." @@ -351,6 +361,14 @@ msgstr "请输入 {} 和 {},类似:" msgid "huoshan" msgstr "火山" +#: lfy/widgets/server_preferences.py:38 +msgid "Text translate" +msgstr "翻译服务" + +#: lfy/widgets/server_preferences.py:40 +msgid "Text recognition" +msgstr "文本识别" + #: data/resources/translate.ui:71 msgid "Alt + D: Remove symbols such as line breaks" msgstr "Alt + D: 移除换行符" @@ -408,15 +426,7 @@ msgstr "翻译密钥,注意是否有分割线 |" msgid "Enter an API Key for the Server with Translate." msgstr "输入该服务的翻译密钥" -#: data/resources/server-preferences.ui:53 -msgid "API Key for OCR,Pay attention to whether there are dividing lines |" -msgstr "OCR识别密钥,注意是否有分割线 |" - -#: data/resources/server-preferences.ui:54 -msgid "Enter an API Key for the Server with OCR." -msgstr "输入该服务的OCR识别密钥" - -#: data/resources/server-preferences.ui:74 +#: data/resources/server-preferences.ui:52 msgid "how to get API Key" msgstr "怎么获取密钥" @@ -425,8 +435,8 @@ msgid "setup API Key for translation Server, click on the right to the details" msgstr "为翻译服务设置密钥,点右侧查看细节" #: data/resources/preference.ui:15 -msgid "API Key" -msgstr "密钥" +msgid "Translation keys" +msgstr "翻译密钥" #: data/resources/preference.ui:44 msgid "local or cloud, text recognition" @@ -436,49 +446,49 @@ msgstr "本地或云端,进行文本识别" msgid "OCR server" msgstr "OCR服务" -#: data/resources/preference.ui:57 +#: data/resources/preference.ui:75 msgid "vpn addr and port, like http://127.0.0.1:7890" msgstr "代理地址和端口,比如:http://127.0.0.1:7890" -#: data/resources/preference.ui:68 +#: data/resources/preference.ui:86 msgid "Automatically check for updates when opening software" msgstr "软件打开时,自动检查更新" -#: data/resources/preference.ui:69 +#: data/resources/preference.ui:87 msgid "auto check update" msgstr "自动检查更新" -#: data/resources/preference.ui:76 +#: data/resources/preference.ui:94 msgid "Notify translation results" msgstr "通知翻译结果" -#: data/resources/preference.ui:86 +#: data/resources/preference.ui:104 msgid "Compare model" msgstr "对比模式" -#: data/resources/preference.ui:112 +#: data/resources/preference.ui:130 msgid "backup/restore the settings to/from the clipboard, edit or backup it" msgstr "将设置备份到剪贴板或从剪贴板恢复、编辑或备份" -#: data/resources/preference.ui:113 +#: data/resources/preference.ui:131 msgid "Software settings backup and restore" msgstr "软件设置备份和恢复" -#: data/resources/preference.ui:116 +#: data/resources/preference.ui:134 msgid "backup" msgstr "备份" -#: data/resources/preference.ui:118 +#: data/resources/preference.ui:136 msgid "" "Export the configuration to the clipboard, then you can paste it into any " "file and edit it" msgstr "将配置导出到剪贴板,然后您可以将其粘贴到任何文件中并编辑" -#: data/resources/preference.ui:125 +#: data/resources/preference.ui:143 msgid "restore" msgstr "恢复" -#: data/resources/preference.ui:127 +#: data/resources/preference.ui:145 msgid "" "Read the JSON configuration of the clipboard, then import it, and some of " "the configurations will take effect after reopening the software" @@ -515,6 +525,18 @@ msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "显示快捷键" +#~ msgid "please input API Key and Secret Key like:" +#~ msgstr "请输入 app_id 和 secret_key,类似:" + +#~ msgid "API Key for OCR,Pay attention to whether there are dividing lines |" +#~ msgstr "OCR识别密钥,注意是否有分割线 |" + +#~ msgid "Enter an API Key for the Server with OCR." +#~ msgstr "输入该服务的OCR识别密钥" + +#~ msgid "API Key" +#~ msgstr "密钥" + #~ msgid "Translation software for gnome" #~ msgstr "为gnome设计的翻译软件"