diff --git a/app/main.py b/app/main.py index 19bd889..99925d4 100644 --- a/app/main.py +++ b/app/main.py @@ -2,7 +2,7 @@ # Copyright 2019 (C) Hui Lan # Written permission must be obtained from the author for commercial uses. ########################################################################### -from flask import abort +from flask import abort, jsonify from markupsafe import escape from Login import * from Article import * @@ -11,6 +11,7 @@ from user_service import userService from account_service import accountService from admin_service import adminService, ADMIN_NAME import os +from translate import * app = Flask(__name__) app.secret_key = os.urandom(32) @@ -104,6 +105,15 @@ def mainpage(): yml=Yaml.yml, number_of_essays=number_of_essays) +@app.route("/translate", methods=['POST']) +def translate_word(): + data = request.get_json() + word = data.get('word', '') + from_lang = data.get('from_lang', 'en') # 假设默认源语言是英语 + to_lang = data.get('to_lang', 'zh') # 假设默认目标语言是中文 + result = translate(word, from_lang, to_lang) + return jsonify({'translation': result}) + if __name__ == '__main__': ''' diff --git a/app/static/js/highlight.js b/app/static/js/highlight.js index 9646ff3..d2c37a8 100644 --- a/app/static/js/highlight.js +++ b/app/static/js/highlight.js @@ -17,21 +17,20 @@ function showBtnHandler() { } function getWord() { - return window.getSelection ? window.getSelection() : document.selection.createRange().text; + return window.getSelection ? window.getSelection().toString() : document.selection.createRange().text; } function highLight() { if (!isHighlight) return; - let word = (getWord() + "").trim(); + let word = (getWord() + "").trim().replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, ""); let articleContent = document.getElementById("article").innerHTML; // innerHTML保留HTML标签来保持部分格式,且适配不同的浏览器 let pickedWords = document.getElementById("selected-words"); // words picked to the text area let dictionaryWords = document.getElementById("selected-words2"); // words appearing in the user's new words list let allWords = dictionaryWords === null ? pickedWords.value + " " : pickedWords.value + " " + dictionaryWords.value; - highlightWords = document.getElementById("selected-words3"); + let highlightWords = document.getElementById("selected-words3"); allWords = highlightWords == null ? allWords : allWords + " " + highlightWords.value; const list = allWords.split(" "); // 将所有的生词放入一个list中 if(word !== null && word !== "" && word !== " "){ - let articleContent_fb2 = articleContent; if(localStorage.getItem("nowWords").indexOf(word) !== -1 || localStorage.getItem("nowWords").indexOf(word.toLowerCase()) !== -1){ articleContent = articleContent.replace(new RegExp('' + word + '', "gi"), word); pickedWords.value = localStorage.getItem("nowWords").replace(word,""); @@ -58,6 +57,7 @@ function highLight() { articleContent = articleContent.replace(new RegExp("\\b" + word + "\\b", "g"), "" + word + ""); } document.getElementById("article").innerHTML = articleContent; + addClickEventToHighlightedWords(); } function cancelHighlighting() { @@ -83,7 +83,62 @@ function toggleHighlighting() { isHighlight = true; highLight(); } - localStorage.setItem('highlightChecked', isHighlight); + localStorage.setItem('highlightChecked', isHighlight); +} + +function showWordMeaning(event) { + const word = event.target.innerText.trim().replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, "").toLowerCase(); + const apiUrl = '/translate'; + const rect = event.target.getBoundingClientRect(); + const tooltipX = rect.left + window.scrollX; + const tooltipY = rect.top + window.scrollY + rect.height; + // 发送POST请求 + fetch(apiUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ word: word }), // 发送的JSON数据 + }) + .then(response => { + if (!response.ok) { + throw new Error('Network response was not ok'); + } + return response.json(); // 解析JSON响应 + }) + .then(data => { + // 假设data.translation是翻译结果 + const tooltip = document.getElementById('tooltip'); + if (!tooltip) { + console.error('Tooltip element not found'); + return; + } + + + + tooltip.textContent = data.translation || '没有找到该单词的中文意思'; + tooltip.style.left = `${tooltipX}px`; + tooltip.style.top = `${tooltipY}px`; + tooltip.style.display = 'block'; + + // 可以在这里添加点击事件监听器来隐藏tooltip,但注意避免内存泄漏 + document.addEventListener('click', function handler(e) { + if (!tooltip.contains(e.target)) { + tooltip.style.display = 'none'; + document.removeEventListener('click', handler); + } + }); + }) + .catch(error => { + console.error('There was a problem with your fetch operation:', error); + }); +} + +function addClickEventToHighlightedWords() { + const highlightedWords = document.querySelectorAll('.highlighted'); + highlightedWords.forEach(word => { + word.addEventListener('click', showWordMeaning); + }); } showBtnHandler(); \ No newline at end of file diff --git a/app/translate.py b/app/translate.py new file mode 100644 index 0000000..654fce0 --- /dev/null +++ b/app/translate.py @@ -0,0 +1,52 @@ +import requests +import hashlib +import time +from urllib.parse import urlencode + +# 假设这是从某个配置文件中读取的 +class BaiduContent: + APPID = '20240702002090356' + SECRET = '3CcqcMAJdIIpgG0uMS_f' + +def generate_sign(q, salt): + """生成百度翻译API所需的签名""" + appid = BaiduContent.APPID + secret = BaiduContent.SECRET + appid_with_data = appid + q + salt + secret + md5_obj = hashlib.md5(appid_with_data.encode('utf-8')) + return md5_obj.hexdigest() + +def translate(q, from_lang, to_lang): + """调用百度翻译API进行翻译""" + salt = str(int(time.time())) # 生成一个时间戳作为salt + sign = generate_sign(q, salt) + + # 封装请求参数 + params = { + 'q': q, + 'from': from_lang, + 'to': to_lang, + 'appid': BaiduContent.APPID, + 'salt': salt, + 'sign': sign + } + + # 构造请求URL(百度翻译API使用POST请求,并将参数放在请求体中) + url = "http://api.fanyi.baidu.com/api/trans/vip/translate" + + # 发送POST请求 + headers = {'Content-Type': 'application/x-www-form-urlencoded'} + data = urlencode(params).encode('utf-8') # 注意:需要编码为bytes + + response = requests.post(url, data=data, headers=headers) + + # 检查响应状态码 + if response.status_code == 200: + # 解析并返回JSON响应体中的翻译结果 + try: + return response.json()['trans_result'][0]['dst'] + except (KeyError, IndexError): + return "Invalid response from API" + else: + # 返回错误信息或状态码 + return {"error": f"Failed with status code {response.status_code}"}