diff --git a/frontend/ui/translator.lua b/frontend/ui/translator.lua index 6ae338cf3..80effcbfb 100644 --- a/frontend/ui/translator.lua +++ b/frontend/ui/translator.lua @@ -174,7 +174,8 @@ ALT_LANGUAGE_CODES["iw"] = "he" local Translator = { trans_servers = { "https://translate.googleapis.com/", - -- "http://translate.google.cn", + "https://translate.google.cn", + "https://fanyi.youdao.com", }, trans_path = "/translate_a/single", trans_params = { @@ -206,10 +207,16 @@ local Translator = { default_lang = "en", } +local TRANS_FUNCS = {} + function Translator:getTransServer() return G_reader_settings:readSetting("trans_server") or self.trans_servers[1] end +function Translator:getTransFunc(server) + return TRANS_FUNCS[server] or Translator.loadPageByGoogle +end + function Translator:getLanguageName(lang, default_string) if SUPPORTED_LANGUAGES[lang] then return SUPPORTED_LANGUAGES[lang], true @@ -223,27 +230,38 @@ end -- Will be called by ReaderHighlight to make it available in Reader menu function Translator:genSettingsMenu() - local function genLanguagesItems(setting_name, default_checked_item) + local function genItems(items, setting_name, default_checked_item) local items_table = {} - for lang_key, lang_name in ffiutil.orderedPairs(SUPPORTED_LANGUAGES) do + for key, value in ffiutil.orderedPairs(items) do table.insert(items_table, { text_func = function() - return T("%1 (%2)", lang_name, lang_key) + return T("%1 (%2)", value, key) end, checked_func = function() if G_reader_settings:has(setting_name) then - return lang_key == G_reader_settings:readSetting(setting_name) + return key == G_reader_settings:readSetting(setting_name) else - return lang_key == default_checked_item + return key == default_checked_item end end, callback = function() - G_reader_settings:saveSetting(setting_name, lang_key) + G_reader_settings:saveSetting(setting_name, key) end, }) end return items_table end + local function genLanguagesItems(setting_name, default_checked_item) + return genItems(SUPPORTED_LANGUAGES, setting_name, default_checked_item) + end + local function genServersItems(setting_name, default_checked_item) + local servers = {} + for _, value in ipairs(self.trans_servers) do + servers[value] = "" + end + return genItems(servers, setting_name, default_checked_item) + end + return { text = _("Translation settings"), sub_item_table = { @@ -302,6 +320,14 @@ This is useful: sub_item_table = genLanguagesItems("translator_to_language", self:getTargetLanguage()), keep_menu_open = true, }, + { + text_func = function() + local value = self:getTransServer() + return T(_("Translation server: %1"), value) + end, + sub_item_table = genServersItems("trans_server", self:getTransServer()), + keep_menu_open = true, + }, }, } end @@ -373,6 +399,120 @@ Returns decoded JSON table from translate server. @treturn string result, or nil --]] function Translator:loadPage(text, target_lang, source_lang) + local trans_server = self:getTransServer() + local trans_func = self:getTransFunc(trans_server) + return trans_func(self, text, target_lang, source_lang) +end + +local function http_request(s_url, method, headers, request) + local socket = require("socket") + local socketutil = require("socketutil") + local http = require("socket.http") + local ltn12 = require("ltn12") + + local sink = {} + if request == nil then + request = {} + end + socketutil:set_timeout() + + request["url"] = s_url + request["method"] = method + request["sink"] = ltn12.sink.table(sink) + request["headers"] = headers + + http.TIMEOUT = 5 + http.USERAGENT = "Mozilla/5.0 (X11; Linux i686 (x86_64)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2950.0 Iron Safari/537.36" + local httpRequest = http.request + + local code, response_headers, status = socket.skip( + 1, httpRequest(request)) + + socketutil:reset_timeout() + if response_headers == nil then + return { + code = code, + response_headers = response_headers, + status = status, + response_body = nil + } + end + local xml = table.concat(sink) + + return { + code = code, + response_headers = response_headers, + status = status, + response_body = xml + } +end + +--[[-- +Returns decoded JSON table from translate server. + +@string text +@string target_lang +@string source_lang +@treturn string result, or nil +--]] + +function Translator:loadPageByYoudao(text, target_lang, source_lang) + local ltn12 = require("ltn12") + local headers = {} + headers['content-type'] = 'application/x-www-form-urlencoded' + local query = string.format( + 'from=%s&to=%s&i=%s&doctype=json&xmlVersion=1.4&keyfrom=fanyi.web&ue=UTF-8&typoResult=true&flag=false', + source_lang, target_lang, text) + logger.dbg("query", query) + headers["content-length"] = string.len(query) + local request = { + source = ltn12.source.string(query) + } + + local s_url = "https://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&smartresult=ugc&sessionFrom=dict.top" + local resp = http_request(s_url, "POST", headers, request) + local ok, youdao_result = pcall(JSON.decode, resp.response_body, JSON.decode.simple) + if ok and youdao_result then + logger.dbg("translator json:", youdao_result) + else + logger.warn("translator error:", youdao_result) + end + local resultAlternative = {} + local translateResult = {} + for _, v1 in ipairs(youdao_result.translateResult) do + for _, v2 in ipairs(v1) do + table.insert(translateResult, + { v2.tgt, v2.src } + ) + table.insert(resultAlternative, + { + [1] = v2.src, + [3] = { + [1] = { + [1] = v2.tgt, + [2] = 0, + } + } + }) + end + end + local resultAsGoogleTranslate = {} + resultAsGoogleTranslate[1] = translateResult + resultAsGoogleTranslate[6] = resultAlternative + logger.dbg("translator json as google translate format:", resultAsGoogleTranslate) + return resultAsGoogleTranslate +end +TRANS_FUNCS["https://fanyi.youdao.com"] = Translator.loadPageByYoudao + +--[[-- +Returns decoded JSON table from translate server. + +@string text +@string target_lang +@string source_lang +@treturn string result, or nil +--]] +function Translator:loadPageByGoogle(text, target_lang, source_lang) local socket = require("socket") local socketutil = require("socketutil") local url = require("socket.url") @@ -437,6 +577,7 @@ function Translator:loadPage(text, target_lang, source_lang) logger.warn("not JSON in translator response:", content) end end + -- The JSON result is a list of 9 to 15 items: -- 1: translation -- 2: all-translations