Skip to content

zpano/Sapling

Repository files navigation

Sapling - 沉浸式语言学习 Chrome 插件

Sapling Logo

智能替换网页词汇,创造沉浸式双语学习环境,在日常浏览中自然习得语言。
基于「可理解性输入」理论,让语言学习融入日常生活

Sapling Preview


核心优势

  • 精准的翻译与筛词:AI提示词严格 JSON 输出,并按照规则进行过滤,当原文与译文一致时跳过,减少无效处理。
  • 智能的语言判断与分词:使用 LanguageDetector 并配合正则进行语言判断,其中中文分词采用 segmentit
  • 丰富的词典与发音:学习语言为英语时优先使用 Wiktionary,展示音标 / 词性 / 释义 / 例句;支持多种发音源(Chrome内置TTS/有道API/谷歌API)可选,点击单词左键发音。
  • 更优的性能:批量段落翻译(单次API请求处理多段落)+ 滚动渲染(仅处理可见区域)+ LRU 热词缓存,减少 API 调用次数。
  • 更好的交互体验:单词卡片集成 发音 / 记忆 / 已学会 按钮;支持右键菜单和快捷键处理/还原页面。

核心设计理念

Sapling 基于语言学家 Stephen Krashen 的「可理解性输入 (Comprehensible Input)」理论设计:

语言习得发生在我们理解比当前水平稍高一点的输入时 (i+1)

核心逻辑:在用户浏览母语内容时,将部分词汇智能替换为学习语言,反之亦然。这种方式:

  • 保持内容可理解性(大部分词汇保持原文)
  • 在上下文中接触新词汇(自然语境记忆)
  • 控制语言接触压力(细水长流,避免认知负荷)

项目灵感与致敬

Sapling 从VocabMeld二次开发而来(使用了早期代码),并从以下优秀项目中汲取灵感,并在多个维度上进行了显著改进:

参考项目对比

项目 核心优势 主要局限性
Ries 综合效果优秀,单词难度划分合理 闭源架构、无法使用自定义大模型 API
illa-helper 类似 Ries 开源版本 翻译质量一般、经常误译短语、难度划分不准、不支持标记已学单词
qiayi 较早出现的沉浸式局部翻译插件 长期未维护、无 AI 能力、整体效果一般

安装方法

方式一:从 GitHub Releases 下载(推荐)

  1. 访问 Releases 页面
  2. 下载最新的 Sapling-nightly-YYYYMMDD.zip 文件(如 Sapling-nightly-20250101.zip
  3. 解压下载的文件
  4. 打开 Chrome 浏览器,访问 chrome://extensions/
  5. 开启右上角的"开发者模式"
  6. 点击"加载已解压的扩展程序"
  7. 选择解压后的文件夹

方式二:从源码安装(开发者)

  1. 克隆本仓库:git clone https://github.com/zpano/Sapling.git
  2. 进入项目目录:cd Sapling
  3. 安装依赖并构建:npm install && npm run build
  4. 打开 Chrome 浏览器,访问 chrome://extensions/
  5. 开启右上角的"开发者模式"
  6. 点击"加载已解压的扩展程序"
  7. 选择 Sapling 文件夹

2. 配置 API

  1. 点击扩展图标,进入设置页面
  2. 选择预设服务(推荐 DeepSeek)或自定义配置
  3. 填入 API 密钥
  4. 点击"测试连接"确认配置正确

完整功能清单

1. AI 智能翻译引擎

1.1 LLM 集成

  • OpenAI 兼容 API:支持任何 OpenAI 格式的 API(OpenAI、DeepSeek、Moonshot、Groq、Ollama 等)
  • 自定义配置:用户可配置 API 端点、密钥、模型名称
  • 连接测试:提供一键测试 API 连通性功能
  • 提示词优化:英文prompt + JSON 严格输出,减少误译与格式偏差

1.2 智能词汇选择

LLM 根据以下规则选择替换词汇:

  • 避免替换:专有名词、数字、代码、URL
  • 优先选择:常用词汇、有学习价值的词汇
  • 难度评估:为每个词汇标注 CEFR 等级(A1-C2)
  • 语言上下文:将母语/学习语言注入选择逻辑,减少误判
  • 动态数量:根据用户设置的单词量(低/中/高)动态调整翻译数量
  • 一致性过滤:原文与译文一致(英文忽略大小写)时自动跳过替换

1.3 双向翻译

  • 母语页面:将母语词汇替换为学习语言(如 中文 → English)
  • 学习语言页面:将学习语言词汇替换为母语(如 English → 中文)
  • 自动检测:根据页面主要语言自动决定翻译方向

2. CEFR 六级难度系统

等级 描述 词汇特征
A1 入门级 最基础的日常词汇,如 hello, thank you
A2 初级 简单日常交流词汇,如 weather, family
B1 中级 一般性话题词汇,如 opinion, experience
B2 中高级 抽象概念词汇,如 consequence, implement
C1 高级 专业/学术词汇,如 ubiquitous, paradigm
C2 精通级 罕见/文学词汇,如 ephemeral, quintessential

难度过滤逻辑:用户选择 B2 时,仅显示 B2、C1、C2 难度的词汇(即该等级及以上),跳过过于简单的词汇。

3. 替换强度控制

三档强度设置:

强度 每段最大替换数 使用场景
较少 4 词 轻度学习,保持阅读流畅
适中 8 词 日常学习,平衡阅读与学习
较多 14 词 强化学习,最大化词汇接触

4. 热词缓存系统

4.1 缓存机制

  • 容量:默认 2048,范围 2048-8192(每 1024 为一档,可在设置页滑块/输入框调整)
  • 存储格式原文:源语言:目标语言 作为键
  • 持久化:使用 storage.local(Chrome Storage Local)存储,跨会话保留
  • 淘汰策略:达到上限时淘汰最旧的缓存
  • 配置同步:缓存上限使用 storage.remote(Chrome Storage Sync)保存

4.2 缓存命中逻辑

  1. 发送 API 请求前,检查文本中是否有已缓存词汇
  2. 已缓存词汇直接使用缓存结果,不发送给 API
  3. 只将未缓存的词汇发送给 LLM 处理
  4. 新词汇处理完成后加入缓存

4.3 缓存统计与管理

  • 缓存词汇数量(上限由用户设置)
  • 命中率百分比
  • 搜索功能:支持按单词或翻译搜索
  • 难度筛选:按 CEFR 等级(A1-C2)筛选
  • 难度显示:每个单词显示难度标签
  • 可在设置页面查看和清空
  • 智能缓存策略:优先使用缓存结果,大幅提升响应速度

4.4 优化后的翻译流程

  • 先展示缓存:缓存结果立即显示,无需等待 API
  • 异步处理:未缓存词汇后台异步处理,不阻塞页面
  • 避免重复:已替换的词汇不会被重复替换

5. 已学会词汇(白名单)

5.1 功能说明

用户可将已掌握的词汇加入白名单,这些词汇:

  • 不再被替换:浏览时保持原文显示
  • 不发送给 API:从请求文本中预先移除
  • 持久存储:使用 storage.local 存储(避免 sync 配额限制)
  • 难度记录:保存词汇的难度信息,便于管理

5.2 添加方式

  • 页面交互:悬停提示框点击“已学会”,或右键点击译词标记
  • 自动恢复:标记后可恢复当前词或同词全部替换(设置可选)

5.3 已学会词汇管理

  • 搜索功能:支持按单词或翻译搜索
  • 难度筛选:按 CEFR 等级(A1-C2)筛选
  • 难度显示:每个单词显示难度标签
  • 删除功能:支持单个删除已学会的词汇

6. 需记忆词汇列表

6.1 功能说明

用户可将页面上的生词加入"需记忆"列表,便于后续复习。

6.2 添加方式

  • 悬停提示框:在已替换词汇上点击“记忆”
  • 右键菜单:选中文本后右键“添加到需记忆列表”
  • 自动翻译:添加到记忆列表后,立即触发翻译并更新页面,走缓存流程

6.3 记忆列表管理

  • 搜索功能:支持按单词或翻译搜索
  • 难度筛选:按 CEFR 等级(A1-C2)筛选
  • 难度显示:每个单词显示难度标签
  • 清空功能:一键清空记忆列表

7. 页面内容处理

7.1 文本过滤规则

  • 跳过明显的代码文本(变量声明、命令行等)
  • 跳过特定 HTML 标签(script, style, code, pre 等)
  • 跳过隐藏元素;默认跳过可编辑区域(contenteditable),但可对特定只读/预览区域做白名单处理

7.2 按需处理

  • 默认只处理可见区域及 30% 缓冲区的内容
  • 滚动时按需处理新进入可见区域的内容

7.3 内容指纹去重

  • 为每段文本生成指纹(取内容前100字符的哈希)
  • 已处理的指纹存入 Set,避免重复处理
  • 页面重新处理时清空指纹缓存

7.4 分词优化

  • 中文分词采用 segmentit,提升词边界准确度与替换质量

8. 用户交互

8.1 替换词汇样式

支持三种显示样式(可在设置中选择):

样式 显示格式 说明
译文(原文) translated(original) 默认样式
仅译文 translated 只显示译文,悬停查看原文
原文(译文) original(translated) 原文在前,译文在后

所有样式都支持:

  • 翻译词以高亮显示,带虚线下划线
  • 原文以灰色显示(在括号中或通过悬停查看)

8.2 悬停提示框

鼠标悬停在替换词汇上时显示:

  • 音标(永远展示学习语言的发音)
  • 难度等级徽章(如 B2)
  • 词性与释义(英语学习词优先 Wiktionary,可展示例句)
  • 操作按钮:发音 / 记忆 / 已学会

9. 快捷键支持

9.1 快捷键

  • Windows/Linux:Alt+T;macOS:Option+T:快速切换处理/还原当前页面
  • 也可通过点击扩展的“处理当前页面”按钮或页面右键菜单“处理/还原当前页面”,状态自动切换并同步显示

10. 学习统计

10.1 统计项目

指标 说明 统计规则
累计接触 总共接触的新词汇数 只计算未命中缓存的词汇
今日接触 当天接触的新词汇数 每日 0 点重置
已学会 白名单中的词汇数 用户手动标记
需记忆 需记忆列表中的词汇数 用户手动添加
已缓存 热词缓存中的词汇数 自动管理
命中率 缓存命中百分比 hits / (hits + misses)

11. 设置项

11.1 API 配置

  • API 端点 URL
  • API 密钥(安全存储)
  • 模型名称
  • 预设快捷选择(OpenAI/DeepSeek/Moonshot/Groq/Ollama)

11.2 学习偏好

  • 母语语言(zh-CN, zh-TW, en, ja, ko)
  • 学习语言(en, zh-CN, zh-TW, ja, ko, fr, de, es)
  • 难度等级(A1-C2)
  • 替换强度(较少/适中/较多)

11.3 行为设置

  • 插件启用开关(Popup 中一键启用/禁用)
  • 自动处理开关(开启后自动处理新页面)
  • 音标显示开关
  • 左键发音开关:开启后点击译词直接发音
  • 发音来源:Wiktionary / 有道翻译(英语) / Google 翻译 TTS(多语言)
  • 有道口音(type=1 英音 / type=2 美音;仅在学习语言为英语时生效)
  • 翻译显示样式:三种样式可选
    • 译文(原文) - 默认样式
    • 仅译文 - 只显示译文,悬停查看原文
    • 原文(译文) - 原文在前,译文在后
  • 保存方式:修改后自动保存;同时提供右上角“手动保存”按钮,右下角提示保存成功/失败

11.4 词汇管理

  • 已学会词汇:查看、搜索、筛选、删除已学会的词汇
  • 需记忆词汇:查看、搜索、筛选需记忆的词汇
  • 已缓存词汇:查看、搜索、筛选已缓存的词汇
  • 所有列表都支持:
    • 搜索功能(按单词或翻译)
    • 难度筛选(A1-C2)
    • 难度标签显示
    • 清空功能

11.5 站点规则

  • 黑名单:永不处理的域名列表
  • 白名单:始终处理的域名列表

11.6 缓存设置

  • 缓存容量上限:滑块/输入框调节(范围 2048-8192,每 1024 为一档;调小会自动删除最旧缓存)

11.7 高级设置

  • 并发上限(1-20,默认 5):同时发起的 API 请求数
  • 每次请求最大段落数(1-10,默认 3):单次 API 请求中包含的段落数量,越大越省 API 调用
  • 处理完整页面开关:关闭时只处理可见区域及 30% 缓冲区(默认),开启时处理整个页面

支持的 API 服务

服务商 端点 推荐模型
OpenAI https://api.openai.com/v1/chat/completions gpt-4o-mini
DeepSeek https://api.deepseek.com/chat/completions deepseek-chat
Moonshot https://api.moonshot.cn/v1/chat/completions moonshot-v1-8k
Groq https://api.groq.com/openai/v1/chat/completions llama-3.1-8b-instant
Ollama http://localhost:11434/v1/chat/completions qwen2.5:7b

项目结构

Sapling/
Sapling/
├── _locales/               # 国际化文件
│   ├── en/
│   │   └── messages.json
│   └── zh_CN/
│       └── messages.json
├── css/                    # 样式文件
│   ├── content.css         # 注入页面的样式
│   ├── options.css         # 设置页面样式
│   └── popup.css           # 弹出窗口样式
├── dist/                   # 构建产物(content script bundle)
│   ├── content.js
│   └── content.js.map
├── icons/                  # 图标文件
│   ├── icon.svg
│   └── generate_icons.html # 图标生成工具
├── js/                     # JavaScript 源码
│   ├── background.js       # 后台脚本
│   ├── content.js          # 内容脚本 (核心逻辑)
│   ├── offscreen-audio.js  # Offscreen 音频播放
│   ├── options.js          # 设置页面脚本
│   ├── popup.js            # 弹出窗口脚本
│   ├── config/             # 配置常量
│   │   └── constants.js
│   ├── core/               # 核心模块
│   │   ├── config.js       # 配置管理
│   │   └── storage/        # 存储抽象层
│   │       ├── IStorageAdapter.js      # 存储适配器接口
│   │       ├── ChromeStorageAdapter.js # Chrome Storage 实现
│   │       ├── StorageNamespace.js     # 存储命名空间(回调/Promise 双风格)
│   │       └── StorageService.js       # 存储服务门面
│   ├── prompts/            # 提示词模板
│   │   └── ai-prompts.js
│   ├── services/           # 服务模块
│       ├── api-service.js  # API 服务
│       ├── cache-service.js # 缓存服务
│       ├── content-segmenter.js # 内容分段
│       └── text-replacer.js # 文本替换
│   ├── ui/                 # UI 组件(Toast/Tooltip/发音等)
│   └── utils/              # 工具函数(分词/过滤/语言检测等)
├── vendor/                 # 第三方依赖打包
│   ├── segmentit.bundle.js
│   └── segmentit.bundle.js.map
├── manifest.json           # Chrome 扩展配置
├── offscreen.html          # Offscreen Document
├── options.html            # 设置页面
├── popup.html              # 弹出窗口
├── package.json            # 项目配置
├── scripts/                # 构建脚本
│   └── build.js
└── README.md               # 项目说明

核心算法流程

页面处理流程

  1. 智能分段与按需加载

    • 通过 ContentSegmenter 对页面 DOM 进行遍历,将内容按"语义单元"智能分段
    • 默认只处理可见区域及 30% 缓冲区的内容,滚动时按需加载后续段落
    • 为每个内容段落生成唯一指纹,防止重复处理
  2. 批量翻译与语言队列

    • 同语言方向的段落自动分组,合并为单次 API 请求(默认 3 段落/请求)
    • 2 秒 debounce 收集段落,或达到批量阈值时立即发送
    • 缓存命中的词汇立即显示,未缓存部分异步请求,不阻塞页面
  3. 精准且高效的 DOM 替换

    • 采用原生 Range API 精确定位和替换文本节点,保持页面结构完整
    • 自动排除代码块、脚本、样式、已处理内容等
    • 动态内容采用防抖优化,MutationObserver 监听 DOM 变化
  4. 智能缓存与状态管理

    • 缓存机制:默认 2048 词容量(可调至 8192),达到上限时淘汰最旧的缓存
    • 并发控制:默认 5 个并发请求(可在设置中调节至 1-20)
    • 状态追踪:防止重复处理,优化用户体验

难度过滤算法

const CEFR_LEVELS = ['A1', 'A2', 'B1', 'B2', 'C1', 'C2'];

function isDifficultyCompatible(wordDifficulty, userDifficulty) {
  const wordIdx = CEFR_LEVELS.indexOf(wordDifficulty);
  const userIdx = CEFR_LEVELS.indexOf(userDifficulty);
  // 只显示大于等于用户选择难度的词汇
  return wordIdx >= userIdx;
}

使用技巧

  1. 推荐配置:母语中文 + 学习英语 + B1难度 + 适中强度
  2. 快捷键:Windows/Linux Alt+T;macOS Option+T 快速切换处理/还原当前页面(推荐)
  3. 已学会标记:悬停译词点击“已学会”或右键标记,可选择恢复同词
  4. 记忆按钮:悬停译词点击“记忆”,或选中文本右键添加到需记忆
  5. 缓存加速:第二次访问同一页面,响应速度显著提升(毫秒级)
  6. 智能过滤:自动跳过停用词和已缓存词汇,节省 API 调用
  7. 自动/手动保存:设置会自动保存;右上角可手动保存;右下角会提示保存成功/失败

开发说明

技术栈

  • Chrome Extension Manifest V3
  • Vanilla JavaScript (ES6+)
  • CSS Variables + Modern CSS
  • esbuild(用于打包 dist/content.jsvendor/segmentit.bundle.js

存储抽象架构

项目使用分层存储架构:

┌─────────────────────────────────────┐
│         StorageService              │  高级API
│  storage.remote / storage.local     │
├─────────────────────────────────────┤
│         StorageNamespace            │  低级 API(get/set/remove/onChanged)
│    回调风格 + Promise 风格           │  支持 DEFAULT_CONFIG 合并
├─────────────────────────────────────┤
│         IStorageAdapter             │  适配器接口
│   ChromeStorageAdapter (当前)       │  未来可替换为 WebDAVAdapter
└─────────────────────────────────────┘
  • storage.remote:配置数据(Chrome Storage Sync),支持跨设备同步
  • storage.local:大容量数据(Chrome Storage Local),如词汇缓存、已学会词汇

本地开发

  1. 修改 options.html/js/options.jspopup.html/js/popup.jsjs/background.js 等:在 chrome://extensions/ 点击刷新即可
  2. 修改内容脚本相关代码(js/content.js 及其依赖模块):先运行 npm run build(或 npm run watch),再到 chrome://extensions/ 刷新扩展

发布流程

项目使用 GitHub Actions 自动构建和发布:

Nightly Build(每日自动构建)

  • 触发条件: 每天 UTC 0:00(北京时间 8:00)自动运行,也支持手动触发
  • 构建条件: 仅在过去 24 小时内有新提交时才会构建
  • 文件名格式: Sapling-nightly-20250101.zip(日期格式)
  • Release 标签: nightly-20250101
  • 状态: Pre-release(开发预览版)
  • Release 内容: 包含过去 24 小时内所有 commit 的简短信息
  • 用途: 用于测试和预览最新功能

手动触发 Nightly Build

  1. 访问 GitHub 仓库的 Actions 页面
  2. 选择 "Nightly Build" workflow
  3. 点击 "Run workflow" 按钮

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •