Skip to content

feat(scripts): 新增 notion-i18n 中英双向翻译脚本#3993

Open
LQ458 wants to merge 3 commits into
notionnext-org:mainfrom
LQ458:pr/notion-translator
Open

feat(scripts): 新增 notion-i18n 中英双向翻译脚本#3993
LQ458 wants to merge 3 commits into
notionnext-org:mainfrom
LQ458:pr/notion-translator

Conversation

@LQ458
Copy link
Copy Markdown

@LQ458 LQ458 commented May 3, 2026

为多语言 NotionNext 博客提供两个语言数据库(如英文库与中文库)之间的自动双向同步,避免手工搬运与翻译。

尽量按此模板PR内容,或粘贴相关的ISSUE链接。

已知问题

  1. NotionNext 已支持双语博客(NOTION_PAGE_ID=id1,en:id2 形式),但两个语言数据库之间的内容同步完全靠人工搬运与翻译,篇幅一多维护成本极高。
  2. 仓库内既无任何 issue 提出过此功能,也没有官方/社区脚本来自动化两个语言数据库之间的内容级同步(已搜索 i18n / 翻译 / 双语 / 多语言 / bilingual / translate 等关键词,相关 PR 均集中在 UI 字符串、路由、主题字段层面)。

解决方案

  1. scripts/translate/ 下新增 CLI 翻译模块 notion-i18n-translator,以页面所在数据库判定源语言,将翻译结果写入对端语言数据库。
  2. 数据库 schema 仅新增 3 个属性(中英库均需添加,名称一致):
    • paired_with(Text) 对端孪生页面的 UUID,双向互链
    • translation_locked(Checkbox) 锁定后不再被脚本覆盖
    • source_hash(Text) 源页面可翻译内容的 SHA-256,用于漂移检测
  3. 翻译提供方接入两家国产模型 — DeepSeek(默认,OpenAI 兼容;deepseek-chat ≈ $0.27/M 输入 / $1.10/M 输出)与智谱 GLM-4,providers/ 下接口很小可继续扩展。
  4. 块处理:paragraph / heading_* / 列表项 / quote / callout / toggle / to_do 翻译并保留 rich_text 注释;code / equation / image / embed 等原样保留;mermaid / plantuml 代码块单独走「仅翻译标签、保留语法」的语法保留提示;column_list / table / synced_block 创建接口要求嵌套 children 而扁平 fetch 拿不到,故跳过。
  5. 配置走 Next.js 既有的 .env.local 习惯,新增的零依赖 load-env.js 直接读取项目根目录 .env.local / .env,不引入 dotenv。

改动收益

  1. 双语博客作者可一行命令完成跨库翻译同步,降低人工翻译成本。
  2. 仅作为 CLI 脚本运行,不进入 Next.js 生产构建,对线上博客没有影响(@notionhq/client 仅在 devDependencies)。
  3. 与现有 scripts/ 风格一致(直接读 process.env.*、单一根目录 .env.local、无独立 env 文件),只新增 1 个 devDependency。
  4. 翻译成本可控:单篇 1500 字博客约 $0.02(DeepSeek),并发 8 时 60–90s 完成,并提供 TRANSLATOR_BUDGET_TOKENS_PER_RUN 硬性上限。
  5. 失败重试(429/5xx/超时指数退避)、漂移检测、人工锁定均已内置,长批量任务稳定。
  6. 已在两个 Notion 数据库(中、英各 ~12 篇文章)上完整跑通,批量翻译共 9 篇页面,零失败,包含 mermaid 图表标签翻译。

具体改动

  1. scripts/translate/(新增 13 个文件)
    • index.js — CLI 入口(轻量参数解析)
    • pipeline.js — 主流程:读取 → 比对哈希 → 翻译 → 写入 → 双向链接
    • notion-client.js@notionhq/client 封装,附带指数退避重试
    • block-mapper.js — 按块类型的翻译与字段净化(含 mermaid/plantuml 特例)
    • state.js — SHA-256 与块类型分类集合
    • config.js — 语言↔数据库 解析、分类/标签映射工具
    • backfill.js — 交互式跨库人工翻译配对(token-Jaccard 相似度,含中英文边界切分)
    • diagnose.js — 列出集成可访问的所有数据库,定位权限问题
    • load-env.js — 零依赖 .env.local / .env 加载器
    • glossary.json — 不翻译术语清单
    • category-map.jsonselect / multi_select 双向映射模板(开放式留空)
    • providers/{deepseek,glm,_http,index}.js — 翻译提供方实现
    • README.md — 完整中文使用文档
  2. package.json — 新增 translate / translate:all / translate:check / translate:backfill / translate:diagnose 五个 npm script,新增 @notionhq/client 一个 devDependency
  3. .env.example — 末尾新增 # notion-i18n-translator(CLI 翻译脚本) 段落,列出所有翻译相关环境变量(NOTION_TOKEN / NOTION_DB_EN_ID / NOTION_DB_ZH_ID / DEEPSEEK_API_KEY 等),全部注释默认禁用,遵循上游既有的「单一 .env.example + 按用途分段」习惯
  4. __tests__/scripts/translate/(新增 12 个单元测试)
    • state.test.js:SHA-256 决定性、漂移检测、块类型分类不交叉、column_list 跳过、mermaid 标识(5 用例)
    • block-mapper.test.js:段落翻译、代码块原样保留、mermaid 标签翻译、column_list 跳过、image 透传、rich_text 重建、字符串拼接(7 用例)

测试确认

  • 新增的 12 个单元测试通过(__tests__/scripts/translate/,无网络/API 依赖):yarn jest __tests__/scripts/translate
  • 上游已有的 jest 测试套件未做改动
  • yarn build 通过(脚本不进入 Next.js 构建图,对生产构建无影响)
  • node scripts/translate/index.js --help 正常输出全部子命令与参数
  • 已在两个真实 Notion 数据库上完整跑通:诊断 → 配对 → 干跑 → 批量翻译共 9 篇页面,零失败
  • 已搜索现有 issues 与 PRs,本功能与现有任何条目均无重叠

本 PR 由 Claude Code 协助起草,所有代码已在我本人的两个 Notion 数据库上完整验证。

为多语言 NotionNext 博客提供两个语言数据库(如 Leo Qin's Blog 与
LeoQin的博客)之间的自动双向同步,避免手工搬运与翻译。

核心思路
- 以页面所在数据库判定源语言,无需在每篇文章上额外维护 lang 字段
- 通过 paired_with 文本属性记录跨库的孪生页面 UUID(双向链接)
- 通过 source_hash(SHA-256)判定漂移,未变化时跳过,幂等可重入
- translation_locked 复选框可锁定人工已修订的目标页面

数据库 schema 需新增三个属性(中英库均需添加,名称一致)
- paired_with        Text     对端孪生页面的 UUID
- translation_locked Checkbox 锁定后不再被脚本覆盖
- source_hash        Text     源页面可翻译内容的 SHA-256

CLI(package.json scripts)
- yarn translate <pageId|URL>   单页翻译
- yarn translate:all            批量翻译(支持 --from / --include-drafts /
                                --include-paired / --dry-run / --force)
- yarn translate:check          列出已发生漂移的页面
- yarn translate:backfill       交互式跨库人工翻译配对
- yarn translate:diagnose       检查 Notion 集成是否能访问到两个目标库

翻译提供方
- DeepSeek(默认,OpenAI 兼容;deepseek-chat ≈ $0.27/M 输入、$1.10/M 输出)
- 智谱 GLM-4 备选;providers/ 下接口很小({text, sourceLang, targetLang,
  glossary, hint} → {text, inputTokens, outputTokens}),可继续扩展

块处理策略
- 翻译:paragraph、heading_1/2/3、bulleted_list_item、numbered_list_item、
  quote、callout、toggle、to_do(保留 rich_text 上的 bold/italic/链接)
- 原样:code、equation、image、video、file、embed、divider、bookmark 等
- 仅翻译标签:mermaid / plantuml 代码块(向 LLM 注入语法保留提示)
- 跳过:column_list、column、table、table_row、synced_block(创建接口要求
  在 body 中携带子节点,扁平拉取无法包含)

工程细节
- 配置走 Next.js 既有的 .env.local 习惯,零依赖 .env 解析器在 load-env.js
- 单页内块翻译并发可调(TRANSLATOR_CONCURRENCY,默认 8)
- TRANSLATOR_BUDGET_TOKENS_PER_RUN 提供单次运行硬性上限
- Notion API 调用统一附带指数退避(429/5xx/超时),偶发 502 不会中断批量
- category-map.json 提供 select / multi_select 双向映射(开放式留空模板)

测试(__tests__/scripts/translate)
- state.test.js: SHA-256 决定性、漂移检测、块类型分类不交叉
- block-mapper.test.js: 段落翻译、代码块原样保留、mermaid 标签翻译、
  column_list 跳过、image 透传、rich_text 重建(共 12 个用例)

依赖
- 仅新增 @notionhq/client(devDependency),不影响 Next.js 生产构建
@vercel
Copy link
Copy Markdown

vercel Bot commented May 3, 2026

@LQ458 is attempting to deploy a commit to the tangly1024's projects Team on Vercel.

A member of the Team first needs to authorize it.

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.

2 participants