这篇只讲「怎么做」,不讲代码原理。你只需要会建文件夹、建文件、敲命令、点按钮。跟着做完,你就能搭出这个插件的完整骨架,核心逻辑文件每个都标了「负责什么、注意什么」,照着写即可。
0. 开始前,准备四样东西
| 准备项 | 要求 | 怎么准备 |
|---|---|---|
| ① Node.js | 20.19 及以上(推荐 22 LTS) | 去 nodejs.org 下载 LTS 版,双击安装,一路「下一步」 |
| ② 编辑器 | 推荐 VS Code | 去 code.visualstudio.com 下载安装 |
| ③ 浏览器 | Chrome 或 Edge | 较新版本(Chrome 114+) |
| ④ 一个 AI Key | DeepSeek 等 | 到 platform.deepseek.com 注册 → 控制台 →「API Keys」→ 创建,复制那串 sk-... 保存好 |
确认 Node 装好了 :按
Win + R,输入cmd回车,黑窗口里输入node -v,能打印版本号(如v22.x.x)即可;再输入npm -v确认 npm 也在。
1. 创建项目文件夹
- 电脑任意位置新建文件夹
chrome-ai-translation(英文、别带中文和空格)。 - VS Code 菜单「文件 → 打开文件夹」,选中它。
2. 先看最终要建哪些文件
一共 17 个文件:4 个配置文件 + 13 个源码文件。先照这个结构把文件夹建出来:
text
chrome-ai-translation/
├── package.json # 配置文件(下面照抄)
├── tsconfig.json # 配置文件(下面照抄)
├── vite.config.ts # 配置文件(下面照抄)
├── manifest.json # 配置文件(下面照抄)
└── src/
├── shared/ # 跨上下文复用
│ ├── constants.ts
│ ├── types.ts
│ ├── messages.ts
│ └── storage.ts
├── content/ # 从网页提取正文
│ ├── extractor.ts
│ └── index.ts
├── background/ # 编排 + 调用 AI
│ ├── translator.ts
│ └── index.ts
├── components/ # 通用组件
│ └── MarkdownView.tsx
└── panel/ # 侧边栏界面
├── index.html
├── main.tsx
├── App.tsx
└── style.css
建文件夹方法 :VS Code 左侧资源管理器里右键 →「新建文件夹」,先建
src,再在src里建shared、content、background、components、panel五个子文件夹;「新建文件」来建文件。
3. 四个配置文件(完整照抄)
这 4 个是「配置文件」,必须精确,直接复制粘贴即可。
文件 1/17:package.json(项目根目录)
json
{
"name": "chrome-ai-translation",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"clean": "node --input-type=module -e \"import { rmSync } from 'node:fs'; rmSync('dist', { recursive: true, force: true })\"",
"build": "npm run clean && tsc --noEmit && vite build",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@mozilla/readability": "^0.6.0",
"dompurify": "^3.4.14",
"md-wx": "^1.0.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"turndown": "^7.2.4"
},
"devDependencies": {
"@crxjs/vite-plugin": "^2.7.1",
"@types/chrome": "^0.2.7",
"@types/react": "^18.3.31",
"@types/react-dom": "^18.3.7",
"@types/turndown": "^5.0.6",
"@vitejs/plugin-react": "^5.2.0",
"typescript": "^5.9.3",
"vite": "^7.3.6"
}
}
文件 2/17:tsconfig.json
json
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"types": ["chrome"]
},
"include": ["src"]
}
文件 3/17:vite.config.ts
ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { crx } from '@crxjs/vite-plugin'
import manifest from './manifest.json'
export default defineConfig({
plugins: [react(), crx({ manifest })],
build: {
emptyOutDir: true,
},
})
文件 4/17:manifest.json
json
{
"manifest_version": 3,
"name": "英文网页 AI 翻译",
"version": "0.1.0",
"description": "一键提取英文网页正文,调用 AI 模型翻译并转为 Markdown",
"action": {
"default_title": "英文网页 AI 翻译"
},
"background": {
"service_worker": "src/background/index.ts",
"type": "module"
},
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": ["src/content/index.ts"],
"run_at": "document_idle"
}
],
"side_panel": {
"default_path": "src/panel/index.html"
},
"permissions": ["activeTab", "scripting", "storage", "sidePanel"],
"host_permissions": ["https://api.deepseek.com/*", "http://*/*", "https://*/*"]
}
这一份最关键 :
side_panel字段让插件从右侧打开侧边栏(而不是传统弹窗),action里也没有default_popup。想做成侧边栏就靠这里。
4. 十三个源码文件(只列职责,不贴代码)
这 13 个是「逻辑源码」,按职责自己实现即可。每个文件都标了「干什么 + 注意什么」,照着写。
4.1 src/shared/ ------ 跨上下文复用的基础(4 个)
| 文件 | 负责什么 |
|---|---|
constants.ts |
常量:默认 API 地址 https://api.deepseek.com、默认模型 deepseek-chat、存储 key、侧边栏通信端口名 panel |
types.ts |
领域类型:ExtractPayload(markdown/title/author/url)、TranslationResult、Settings(apiKey/baseUrl/model)、状态枚举(idle/extracting/translating/done/error) |
messages.ts |
消息协议:后台 / 内容脚本 / 侧边栏三方之间所有消息的强类型定义(提取请求与结果、翻译请求与流式分片、设置读写) |
storage.ts |
存储层:封装对 chrome.storage.local 的读写------「最近一次翻译结果」和「设置项」,设置项读取时合并默认值 |
4.2 src/content/ ------ 从网页提取正文(2 个)
| 文件 | 负责什么 |
|---|---|
extractor.ts |
提取核心管线:克隆 DOM → 归一化懒加载图片地址(data-src/srcset → 绝对 src)→ Readability 识别正文 → 长度校验(正文 < 50 字走选择器兜底)→ DOMPurify 消毒 → Turndown 转 Markdown → 取标题 / 作者 |
index.ts |
内容脚本入口:监听后台「提取正文」消息,调用 extractor 返回结果 |
4.3 src/background/ ------ 编排 + 调用 AI(2 个)
| 文件 | 负责什么 |
|---|---|
translator.ts |
翻译核心:用原生 fetch 调 OpenAI 兼容流式接口(stream: true),逐行解析 SSE 增量(data: 开头、[DONE] 结束);System Prompt 约束「只翻译正文、保留 Markdown 结构和图片」;组装 # 标题 / > 作者 / > 链接 / 正文 |
index.ts |
后台入口:点击图标打开侧边栏、管理 Port 连接、编排「提取 → 翻译 → 流式推送 → 存储」全流程;内容脚本未注入时用 scripting.executeScript 兜底注入 |
4.4 src/components/ + src/panel/ ------ 界面(5 个)
| 文件 | 负责什么 |
|---|---|
components/MarkdownView.tsx |
用 md-wx 的 MarkdownRenderer 渲染 Markdown,关闭设置 / 复制 / 主题切换等多余 UI |
panel/index.html |
侧边栏入口 HTML,挂载 #root + 引入 main.tsx |
panel/main.tsx |
React 挂载入口,渲染 App |
panel/App.tsx |
主界面:翻译按钮 + 设置面板(Key / Base URL / 模型)+ 流式打字机展示(60ms 节流)+ 下载 .md / 复制;连接 Port 接收后台推送 |
panel/style.css |
侧边栏样式(头部工具栏、按钮、状态条、错误条、正文区) |
实现要点(写逻辑时注意这几条)
- 三个上下文用一套强类型消息 :后台 / 内容脚本 / 侧边栏之间的消息都在
messages.ts里定义,改协议时 TypeScript 直接报错,少踩隐性的坑。 - 正文提取先「克隆 DOM」再处理:别污染用户正在看的原页面;图片一定要做懒加载归一化,否则正文图会全丢。
- 翻译接口走 OpenAI 兼容协议 :只改
base_url/api_key/model三处,就能在 DeepSeek / Qwen / GLM 之间自由切换,不绑死一家。 - API Key 只放后台:内容脚本和页面共享上下文,绝不能碰 Key;页面 HTML 一律当不可信数据,提取后必须 DOMPurify 消毒。
- 侧边栏高度自动撑满、宽度需手动拖 :点击图标直接打开侧边栏靠
setPanelBehavior({ openPanelOnActionClick: true })。
5. 安装依赖
VS Code 里按 ``Ctrl + ```(反引号)打开终端,粘贴回车:
bash
npm install
等 1~3 分钟,看到 added N packages 就成功。报网络错误就换国内镜像:
bash
npm install --registry=https://registry.npmmirror.com
6. 构建
bash
npm run build
看到 ✓ built in xx.xxs 即成功。重点 :产物在项目根目录新生成的 dist 文件夹里------待会儿要加载的是 dist,不是 src,也不是项目根目录。
7. 加载到浏览器
- 地址栏输入
chrome://extensions(Edge 输edge://extensions),回车。 - 打开右上角「开发者模式」开关。
- 点左上角「加载已解压的扩展程序」。
- 进入项目文件夹,选中里面的
dist文件夹,点「选择文件夹」。
出现「英文网页 AI 翻译」卡片即装好。
8. 配置 API Key 并首次使用
- 点浏览器工具栏的插件图标(可能收在拼图 🧩 图标里,点开它可「固定」到工具栏)。
- 右侧滑出侧边栏。
- 展开「设置(API Key / 模型) 」,填入:
- API Key :第 0 步在 DeepSeek 创建的那串
sk-...; - Base URL :保持默认
https://api.deepseek.com; - 模型 :保持默认
deepseek-chat。
- API Key :第 0 步在 DeepSeek 创建的那串
- 点「保存设置」。
- 打开任意英文文章 → 点插件图标 → 点「翻译当前页面」。
- 译文逐字蹦出,完成后可「下载 .md 」或「复制」。
搞定 🎉
9. 常见问题(FAQ)
| 问题 | 原因 & 解决 |
|---|---|
没有 dist 文件夹 |
先执行 npm run build,成功后它才出现 |
| 加载报「manifest 无效」 | 选错文件夹了,要选 dist/,不是 src/ 或项目根目录 |
| 点了图标没反应 / 侧边栏不打开 | 浏览器版本太旧(需 Chrome 114+);或在扩展页点「重新加载」再试 |
| 翻译报 HTTP 403 | API Key 填错 / 过期,或模型名填错(要用 chat 模型如 deepseek-chat,不是 embedding 类) |
| 提示「无法读取当前页面」 | 刷新网页再点翻译;确认打开的是 http/https 网页 |
| 提示「请先在插件设置中填写 API Key」 | 第 8 步的「保存设置」没点,或没填 Key |
| 侧边栏太窄 | 手动拖侧边栏左边缘调宽(高度会自动撑满) |
10. 想改成你自己的?
- 改插件名 :打开
manifest.json,把两处"英文网页 AI 翻译"换成你的名字,重新npm run build并「重新加载」。 - 换 AI 服务商:不用改代码,侧边栏「设置」里改 Base URL / 模型 / Key 即可(只要是 OpenAI 兼容接口都能用)。
到这里你就从零搭出了这个插件的完整骨架。核心逻辑文件(正文提取、流式翻译、侧边栏 UI)按第 4 节的职责描述实现即可。想了解背后实现原理和开发踩坑,可以再看技术复盘篇。