背景
很难受,上学的时候英语没好好学,现在搞到编程这一行来了,时常会查看翻阅一些资料、文章,打开一看,又是一片全英文,好吧,一个窗口看文章,一个窗口打开google翻译,cvcv,一遍又一遍,又开始了。前段时间开始搞一下谷歌浏览器插件,发现可以很方便的往浏览器每个网站注入脚本,很棒,稀奇古怪的思路这不就来了。先来搞一个英译中的谷歌翻译插件。
效果
- 鼠标选中需要翻译的英文,通过标签title属性显示其翻译后的中文
- 话不多说,先来看效果
- 本来是想window+G上次录屏效果的,发现浏览器title效果录屏录不下来,这就只上两张图片效果了(>-<)
插件基础
google插件内容主要由以下几部分组成
- manifest.json 配置文件
- content_script 注入到网页的脚本
- background 插件脚本
- popup/options页面,插件配置页面
- 以及插件内置的许多功能
这篇只用到了前面三个,先来上一个翻译插件全部文件目录文件结构
原理
通过浏览器插件,注入脚本到网站,在脚本钟添加selectionchange事件获取鼠标选中的文本,然后调用翻译API,翻译选中的英文,将翻译的结果添加到当前选中标签的title属性中进行展示。
开撸
新建项目
- 新建一个空文件夹,用于存放插件项目:translate
- 进入translate文件夹
创建manifest.json文件
- google插件必须文件
manifest.json,实际使用的时候需要把注释代码去掉
// 这些项属于每个浏览器插件必备项
{
"manifest_version": 3, // 插件版本
"name": "解放英语", // 插件名称
"version": "1.0.0", // 发布到google应用上的版本
"description": "阅读英语文档老大难的伙计们的福音", // 插件描述
"icons": { // 插件图标
"16": "assets/1.jpg",
"32": "assets/1.jpg",
"48": "assets/1.jpg",
"128": "assets/1.jpg"
},
}
创建浏览器脚本文件
/content-script/translate.js
console.log('浏览器脚本translate.js文件')
配置manifest.json文件,添加content_scripts配置
{
"content_scripts": [ // content_scripts中注册的js脚本会注入到网页中
{
"matches": ["https://*/*", "http://*/*"], // 匹配到的URL会注入脚本
"js": ["content-script/translate.js"]
}
],
}
插件调试
- google浏览器输入chrome://extensions/ 进入插件页
- 打开开发者模式,点击加载已解压的扩展程序,选择刚创建的translate文件夹
- ok,插件已经成功引入了
- 开启插件
- 任意进入到一个https或http的网页
- 打开console,查看translate.js中的代码是否执行
- ok,一个简单的浏览器插件已经创建成功
添加translate.js内容
插件已经成功引入,接下来当时是添加功能
let str = ''
// 添加 mouseup 事件监听器
document.addEventListener('mouseup', handleMouseUp);
// 添加 selectionchange 事件监听器
document.addEventListener('selectionchange', handleSelectionChange);
// 处理 selectionchange 事件的回调函数
function handleSelectionChange(event) {
const selection = window.getSelection();
if (selection && selection.toString().length != 0) {
str = selection.toString()
}
}
// mouseup时,去调用翻译API,翻译选中的文本
async function handleMouseUp(event) {
if(str.length!==0){
if (str) {
// content_script脚本和插件脚本间的通信方式,可以在插件脚本通过固定方法接收
const res = await chrome.runtime.sendMessage({
action: 'translate',
str
})
str = ''
// 将翻译结果添加到标签的title属性查看
event.target.setAttribute('title', res.join(' '))
}
}
}
创建background 插件脚本
- 翻译API选择在插件脚本中调用(内容脚本中调用存在各种各样的问题)
background/service_worker.js
// 监听content_script脚本中sendMessage过来的信息
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.action === 'translate') {
// 在这调用翻译API,翻译文本
}
return true // 允许异步sendResponse
})
翻译API选型
百度翻译、google翻译、有道翻译都有翻译API,这选的有道翻译API,为啥选这个呢,问就是勤俭节约(>-<)
有道翻译API文档:ai.youdao.com/doc.s#guide
调用翻译API
修改service_worker.js文件
// 两个key可以根据有道API文档获取
const APP_KEY = ''
const KEY = ''
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.action === 'translate') {
getTraslateRes(request.str).then(res => {
sendResponse(res.translation) // 将翻译的结果返回给content_script
})
}
return true
})
function getTraslateRes(query) {
const data = generateTranslateParams(query);
const formData = new FormData()
Object.keys(data).forEach((key) => {
formData.append(key, data[key])
})
return new Promise((resolve) => {
fetch('https://openapi.youdao.com/api', {
method: 'POST',
body: formData,
}).then((res) => {
if (res.ok) {
const jsonData = res.json()
resolve(jsonData)
}
})
})
}
function generateTranslateParams(query) {
const salt = new Date().getTime()
const curtime = Math.round(new Date().getTime() / 1000)
// 多个query可以用\n连接 如 query='apple\norange\nbanana\npear'
const from = 'en'
const to = 'zh-CHS'
const str1 = APP_KEY + truncate(query) + salt + curtime + KEY
const sign = CryptoJS.SHA256(str1).toString(CryptoJS.enc.Hex)
const params = {
q: query,
appKey: APP_KEY,
salt: salt,
from: from,
to: to,
sign: sign,
signType: 'v3',
curtime: curtime,
vocabId: APP_KEY
}
return params
}
function truncate(q) {
const len = q.length
if (len <= 20) return q
return q.substring(0, 10) + len + q.substring(len - 10, len)
}
结语
ok,就是这么简单,可以更加方便的阅读网页英文文档了,再也不用开两个窗口,然后cvcv,(>-<)
补充
翻译API毕竟免费额度有限,可以通过添加缓存进行优化,已经翻译过的就不要再去调用翻译API了,直接从缓存里面获取就ok。
后续打算的是会通过使用indexDB进行一个英文词句的缓存,通过indexDb的导入导出,逐渐收录壮大一个key-value的英译中字典,到一定程度后,就再也不担心翻译API的免费额度不够用了(>-<)
indexDb的增删改查
原文链接:https://juejin.cn/post/7353561676090490895 作者:开荒人