目录
直接说结论:在这个网站上,只需在 Pages CMS 中发布一篇日语文章,就能逐步让该文章以日语 + 8种其他语言的形式呈现。GitHub Actions 和 GitHub Copilot 负责处理翻译 Issue 创建、翻译 PR 创建、构建、自动合并以及关闭父 Issue。
运营人员日常只需处理日语文章和作者信息。由于不再需要每次手动提交翻译任务或整理 PR,多语言博客的运营负担可以大幅减轻。
此方法的前提条件
此方法假设 Astro 侧已具备以下基础设施。
- 9种语言路由(ja, en, zh-cn, es, pt, fr, ko, de, ru)
- 对于没有翻译的页面,可以回退显示日语内容
- 可以通过 Pages CMS 更新日语文章和作者信息的运营设置
关于如何搭建这套基础设施,请参阅将 Astro 6 网站支持9种语言 — 136篇博客文章的自动翻译与多语言架构。本文仅聚焦于如何在此基础上叠加 Copilot 自动翻译工作流。
能实现什么
从运营角度来看,日常需要操作的界面只有2个。本文直接使用 Pages CMS 的界面,让日常运营中需要操作哪些界面一目了然。

第一个界面是 Pages CMS 的日语博客列表。在这里可以查看发布日期和作者信息,同时只添加或更新日语文章。关键是保持”只接触翻译源日语”的模式,无需每次都进入每种语言的编辑界面。

第二个界面是作者信息表单。对于作者数据,只需在 CMS 中更新日语基础字段,翻译用的 i18n 字段由 GitHub 自动化流程处理,这样运营职责的分离就会非常清晰。
此方法最适合的场景
首先,以下类型的团队和网站特别适合使用此方法。
- 希望以日语作为翻译源
- 博客基于 Markdown 进行管理
- 每次手动提交翻译任务很麻烦
- 可以在一定程度上将翻译质量交给 AI
- 但希望阻止构建失败或保持草稿状态的 PR
反之,如果各语言有完全独立的编辑体制,其他工作流可能更合适。
Step 1. 将日语文章固定为翻译源
首先需要决定的是”以哪个文件作为翻译源”。这里模糊不清会破坏自动化。
本文中所说的翻译源是指最先编辑、作为各语言文章和派生数据基准的日语文件。
在这套配置中,源文件和目标文件的划分如下。
- 博客文章翻译源:
src/content/blog/{slug}.md - 博客文章翻译目标:
src/content/blog/{locale}/{slug}.md - 作者信息翻译源:
src/content/authors/{authorId}.json - 作者信息翻译目标:
src/content/authors/{authorId}.json中的i18n字段 - 标签定义翻译源:
src/content/tags/{tagId}.json - 标签定义翻译目标:
src/content/tags/{tagId}.json中的i18n字段
目录结构大致如下,比较容易管理。
src/content/blog/
my-post.md
another-post.md
en/
my-post.md
zh-cn/
my-post.md
fr/
my-post.md
关键是将翻译文件的 slug 与源日语文章的 slug 保持一致。仅此一点就能轻松从源路径自动识别翻译目标。
在这个仓库中,即使翻译文件尚不存在,每个语言的 URL 也会通过日语回退生成。这意味着可以采用”先发布日语文章,之后让翻译 PR 跟进”的运营方式。
Step 2. 将日语文章的推送转换为翻译 Issue
下一步是使用 GitHub Actions 检测日语文章的变更,并自动创建翻译 Issue。
最低要求如下。
- 监控对
main分支的推送 - 仅将
src/content/blog/*.md作为常规自动创建 Issue 的目标 - 只在文章正文发生变化时创建 Issue,而不是仅 frontmatter 变化时
- 如果存在相同源路径的开放 Issue,则更新而不是创建新 Issue
- 在 Issue 正文中嵌入源路径作为标记
作者信息和标签定义虽然也是翻译目标,但在普通推送时不自动创建 Issue。仅在必要时通过 workflow_dispatch 明确触发,可以避免不必要的 Issue 积累。
例如,在 Issue 正文中加入这样的注释,可以在后续自动化中复用。
<!-- translation-source:src/content/blog/my-post.md -->
<!-- translation-kind:blog-post -->
workflow 侧的基本过滤配置如下。
on:
push:
branches:
- main
paths:
- src/content/blog/*.md
此外,通过仅比较 Markdown 正文来决定是否创建翻译 Issue,可以避免因更新发布日期或标签等小修改而大量生成翻译 Issue 的问题。
这里重要的是不要”直接创建翻译”,而是先创建 Issue。通过插入 Issue,可以将源路径、目标语言和翻译条件以人和 AI 都可见的形式固定下来。
Step 3. 将翻译 Issue 自动分配给 Copilot
仅创建 Issue 还留有手动工作,因此这一步将 Issue 自动分配给 Copilot。
需要做2件事。
- 将
COPILOT_AGENT_TOKEN添加为仓库 secret - 在创建 Issue 后调用分配 API
概念上是通过 patch Issue 将 Copilot 设置为受让人。
{
"assignees": ["copilot-swe-agent[bot]"],
"agent_assignment": {
"target_repo": "OWNER/REPO",
"base_branch": "main",
"custom_instructions": "Translate the Japanese source article..."
}
}
此时,将常规自动创建范围仅限于文章,仅在必要时通过手动 dispatch 处理作者信息和标签定义,可以使运营更加稳定。明确说明规则 — 作者信息的 i18n 字段位于 src/content/authors/{authorId}.json,标签定义的 i18n.name 字段位于 src/content/tags/{tagId}.json,文章则在 src/content/blog/{locale}/ 下创建同名文件 — 可以减少错误。
Step 4. 构建翻译 PR 并自动合并
这里不应无条件自动化。建议仅将满足以下所有条件的 PR 作为合并目标。
- 由 Copilot 创建的 PR
- 标题以
[translation]开头 - 目标为
main分支 - 非草稿状态
- 构建成功
在这套配置中,流程分为2个阶段。
Translation PR BuildMerge Translation PR
在 PR 变为 ready for review 时构建 PR head,成功后直接进行 squash merge。由于不依赖 GitHub 的分支保护,即使在小型仓库中也易于管理。
自动合并应强制执行的条件
添加自动合并时,以下是最低推荐条件。
- 排除非翻译 PR
- 构建失败时停止
- 草稿状态时停止
- 排除非 Copilot 创建的 PR
有了这4个条件,就可以大大避免将普通开发 PR 纳入自动合并范围的问题。
Step 5. 合并后自动关闭父翻译 Issue
最后,加入以下机制可以使运营更加整洁:合并后自动关闭父 Issue。
方法很简单,对已合并的翻译 PR 执行以下操作。
- 获取 PR 的变更文件
- 同时读取 PR 正文中的源路径
- 搜索与
translation-source:标记对应的开放 Issue - 添加评论并关闭
同时查看 PR 正文源路径的原因是,仅依赖 Copilot 创建的 PR 的变更文件,在某些情况下源文件的反向查找可能不够稳定。同时使用变更文件和 PR 正文可以保持稳定性。
补充说明
将 Copilot 创建的 PR 和 Issue 的语言引导为日语
如果希望在 GitHub 侧稳定 Copilot 的输出语言,使用仓库级别的指令是最直接的方法。
即,放置 .github/copilot-instructions.md 文件。
This repository is an Astro static site for Acecore, deployed on Cloudflare Pages.
- For GitHub issues, pull requests, issue comments, pull request descriptions, review summaries, and other user-facing GitHub text, write in Japanese by default unless the task explicitly requires another language.
- For multilingual content work, treat Japanese source files as canonical and keep translated frontmatter aligned with the Japanese source.
仅凭这一个文件,Copilot coding agent 在创建 Issue 和 PR 时的默认语言和上下文就会相当稳定。
总结
这套配置的核心是将翻译从”每次都需要人工请求的工作”转变为从属于日语源文件推送的例行处理。
再次总结流程如下。
- 只撰写日语文章
- 推送时自动创建翻译 Issue
- 自动分配给 Copilot
- 构建翻译 PR 并自动合并
- 自动关闭父 Issue
完成这套配置后,从运营角度来看感觉相当自然。只需推送日语文章,其他语言的文章就会在 GitHub 侧依次生成。
当然,实际上会经历 Issue 创建、Copilot 执行、PR 创建、构建和合并等异步步骤,所以并非”瞬间全部完成”。但是,运营人员不再需要每次手动提交翻译任务或忘记关闭 PR。
本文本身也构建成可以以日语版为基准流入这一流程的结构。如果要持续运营多语言网站,首先从这种程度的自动化开始是最合适的。
从1篇日语文章到9种语言运营的流程
更新日语源文件
仅通过 Pages CMS 或 Markdown 编辑日语文章,并推送到 main 分支。
自动创建翻译 Issue
GitHub Actions 创建内嵌了源路径和目标语言的 Issue。
Copilot 创建翻译 PR
收到 Issue 后,Copilot 生成翻译文件并提交翻译 PR。
构建、合并并关闭 Issue
构建成功后自动合并,并自动关闭父翻译 Issue。
手动翻译工作流
- 文章发布后由人工创建翻译任务
- 按语言分配负责人
- 构建和合并决策也由人工完成
- 父 Issue 容易被遗忘,长期未关闭
自动翻译工作流
- 推送日语文章即触发整个流程
- 自动分配给 Copilot
- 翻译 PR 在构建成功后自动合并
- 合并后父 Issue 也自动关闭
- 已完成: 以日语为翻译源的内容结构
- 已完成: 如 src/content/blog/{locale}/{slug}.md 的翻译文件布局规则
- 已完成: 具有 issues write 权限的 GitHub Actions
- 已完成: 能够调用 Copilot 分配 API 的 COPILOT_AGENT_TOKEN
- 已完成: 稳定的构建命令,如 npm run build