Skip to content

feat: 整章翻译功能改进 — 独立显隐、UI 优化、自动恢复#9

Merged
codedogQBY merged 8 commits into
mainfrom
feat/chapter-translation-ux
Mar 27, 2026
Merged

feat: 整章翻译功能改进 — 独立显隐、UI 优化、自动恢复#9
codedogQBY merged 8 commits into
mainfrom
feat/chapter-translation-ux

Conversation

@codedogQBY
Copy link
Copy Markdown
Owner

@codedogQBY codedogQBY commented Mar 27, 2026

Summary

  • 原文/译文独立显隐:翻译完成后可分别隐藏原文或译文,支持纯译文阅读模式(译文独显时样式继承原文,含段落间距)
  • 桌面端 UI:翻译控制改为工具栏 DropdownMenu,不再占用独立栏位
  • 移动端 UI:翻译控制改为底部 ActionSheet,替代直接触发模式
  • 自动恢复已缓存翻译:打开已翻译章节时自动检测缓存并恢复(等待 relocate 事件确保 CFI 导航完成后再注入)
  • 记住翻译语言:用户选择的语言自动保存,下次默认使用
  • 修复移动端翻译失败:WebView bridge 函数暴露到 window 对象,解决作用域问题
  • 译文排除 AI/TTS 读取:getVisibleText TreeWalker 过滤 .readany-translation 节点
  • 译文可选中复制但不支持高亮笔记:CFI 体系不覆盖动态注入的 DOM

Test plan

  • 桌面端:打开书 → 工具栏 Languages 下拉菜单 → 选择语言 → 翻译 → 验证渐进展示
  • 桌面端:翻译完成后切换显示/隐藏原文、译文
  • 桌面端:关闭书再打开,验证自动恢复已缓存翻译(不崩溃)
  • 移动端:Languages 按钮 → 底部 ActionSheet → 翻译 → 验证渐进展示
  • 移动端:翻译完成后切换显示/隐藏原文、译文
  • 两端:纯译文模式下验证段落间距正常
  • 两端:TTS 不朗读译文内容
  • 两端:译文可选中复制,但高亮笔记不会作用于译文
  • 两端:切换语言翻译,缓存命中秒完成

🤖 Generated with Claude Code

bealqiu and others added 8 commits March 26, 2026 16:45
三个 bug 共同导致移动端导入 GBK/GB18030 编码的 TXT 文件显示乱码:

1. text-encoding polyfill 未生效:Hermes 原生 TextDecoder 已存在于
   globalThis,导致 text-encoding 跳过安装自己的全编码版本,非 UTF-8
   解码全部失败。修复:require 前临时隐藏原生 TextDecoder/TextEncoder,
   强制 polyfill 安装,之后恢复原生版本。

2. UTF-8 验证在多字节字符边界误判:ensureUtf8Bytes 用 64KB subarray
   做 fatal 模式验证,但截断点可能落在多字节 UTF-8 字符中间,导致
   合法 UTF-8 文件被误判为非 UTF-8,再被错误地用 GB18030 解码。
   修复:对 sample 边界做 UTF-8 continuation byte 回退对齐。

3. Shift-JIS 检测误判 GB18030:原逻辑只要找到一个符合 Shift-JIS
   字节范围的字节对就判定为 Shift-JIS,但 GB18030 的 0xE0-0xFC 开头
   双字节与 Shift-JIS 大量重叠。修复:改为统计型判断,分别计数 GBK
   典型对和 Shift-JIS 独有对,只有后者明显多于前者才判定为 Shift-JIS。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 原文/译文独立显隐:翻译完成后可分别隐藏原文或译文,支持纯译文/纯原文阅读
- 桌面端:翻译控制改为工具栏下拉菜单(DropdownMenu),不再占用独立栏位
- 移动端:翻译控制改为底部弹出 ActionSheet,替代直接触发模式
- 修复移动端翻译失败(No text to translate):WebView bridge 函数暴露到 window 对象
- 修复移动端翻译不渐进展示:injectChapterTranslations 同样修复作用域问题
- 三个 WebView handler 均添加 iframe fallback 兼容路径

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 桌面端和移动端 getVisibleText 的 TreeWalker 过滤 .readany-translation 后代节点
- 译文元素添加 user-select: none 禁止选中/高亮/笔记
- 翻译时自动保存所选语言到 settings store,下次默认使用

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 打开已翻译章节时自动检测缓存并恢复翻译(桌面端+移动端)
- hook 新增 ready 参数,确保 DOM 就绪后再恢复
- 隐藏原文只显示译文时,译文样式继承原文(去除灰色、缩进、边框)
- CSS 新增 data-solo 属性控制译文独显样式

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
startTranslation 因内联函数每次 render 重建,导致 useEffect cleanup
取消 timer,翻译永远不触发。改用 ref 存最新 startTranslation 引用,
从 useEffect 依赖中移除。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- translationReady 改为在 relocate 事件后设置,确保 CFI 导航完成后再注入翻译
- 之前在 handleLoaded + 500ms timer 设置,但 CFI 解析在 load 事件后仍在进行
- 译文独显模式 (data-solo) 添加 margin-bottom: 0.8em 段落间距

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
译文不应禁止选中——只是不支持高亮笔记(因为 CFI 不覆盖注入的 DOM)。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant