场景
为了锻炼英文阅读能力, 在英文文章阅读时还是期望能多读外文, 如果一把梭翻译一遍, 普遍是只读中文不看英文了, 那么也就起不到我们锻炼英文能力的要求了.
需求
如果我遇到了一些不认识或者不确定意思的单词,我希望得到一个贴合当前语境的翻译,这样既能理解文章,又能在语境中学习单词。
需求拆解
如果鼠标在某个单词上方悬浮超过 xx 毫秒, 那么则结合当前语境翻译这个单词及这个句子.
好的, 需求有了, 思路也有了, 具体咋做咱就不知道了, 现在轮到我最强的小弟 ChatGPT 大显身手了
效果图
具体功能点:
[ol]
[/ol]
实现此效果的完整 ChatGPT 对话: 实现沉浸式翻译的核心功能
插播广告:
推荐一个 ChatGPT Plus 拼车服务, 客服wx, 无需科学上网/会话隔离
最终完整代码
import type { PlasmoCSConfig } from "plasmo"
import { generate } from 'short-uuid'
export const config: PlasmoCSConfig = {
matches: [""],
all_frames: true
}
const loading = `
`
const cssCode = `
.ct-loading {
width: 1em;
display: inline-block;
}
.ct-span {
display: inline-block;
margin-right: 2px;
margin-left: 2px;
}
`
var xy = { x: 0, y: 0 }
document.head.insertAdjacentHTML('beforeend', '' + cssCode + '');
// 存储已经翻译过的单词,以避免重复翻译
var translatedWords = new Set(); // 用于存储已翻译的单词及其父元素
var pool = {}
document.addEventListener('mousemove', function (event) {
// 获取鼠标位置
var x = event.clientX, y = event.clientY;
xy = { x, y }
// 获取鼠标位置下的文本范围
var range, textNode, offset;
range = document.caretRangeFromPoint(x, y);
textNode = range.startContainer;
if (!textNode) {
return
}
if (textNode.parentElement.hasAttribute('data-ct-translation')) { // 翻译结果节点
return;
}
if (hasPreOrCodeParent(textNode)) {
return
}
offset = range.startOffset;
var text = textNode.textContent;
var words = text.split(/\s+/);
for (var i = 0; i = rect.left && x = rect.top && y {
for (const wordId in pool) {
const wordElement = document.getElementById(wordId);
if (!wordElement) {
continue;
}
const rect = wordElement.getAttribute('data-ct-rect').split(',').map(Number);
const word = wordElement.getAttribute('data-ct-word');
const pid = wordElement.getAttribute('data-pid');
if (!isMouseOnTranslation({ left: rect[0], right: rect[1], top: rect[2], bottom: rect[3] }, xy.x, xy.y)) {
translatedWords.delete(word + '-' + pid)
wordElement.remove()
delete pool[wordId]
continue
}
wordElement.classList.add('ct-loading')
wordElement.innerHTML = loading
fetch('http://localhost:8787/translate', {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
word: word,
sentence: wordElement.getAttribute('data-ct-parent')
})
}).then(res => res.json()).then(res => {
console.log(res)
wordElement.classList.remove('ct-loading')
wordElement.classList.add('ct-span')
wordElement.innerHTML = `(${res.word_result})`
const p = document.querySelector(`[data-ct-id="${pid}"]`)
const cp = p.cloneNode(true)
cp.textContent = res.sentence_result
p.after(cp)
}).catch(e => console.log)
wordElement.setAttribute('data-ct-translation', '1');
delete pool[wordId]
}
}, 1500)
// 判断鼠标是否在翻译内容上
function isMouseOnTranslation(rect, mouseX, mouseY) {
return rect && mouseX >= rect.left && mouseX = rect.top && mouseY