方案A:镜像型双语站 — 实施计划(修正版)
现状梳理
已有(不用动):
缺失(需要新建):
移动端 vs 桌面端
┌──────────┬──────────────────────────────────────┬────────────────────────────────────────────────────────────┐
│ │ 桌面端 │ 移动端 │
├──────────┼──────────────────────────────────────┼────────────────────────────────────────────────────────────┤
│ 模板 │ 静态 .njk 文件 │ 没有静态模板 │
├──────────┼──────────────────────────────────────┼────────────────────────────────────────────────────────────┤
│ 生成方式 │ Eleventy 直接渲染 │ .eleventy.js 的 processArticleHtml() 在构建后动态重写 HTML │
├──────────┼──────────────────────────────────────┼────────────────────────────────────────────────────────────┤
│ 处理对象 │ *.njk 文件(首页/栏目/文章) │ 遍历 _site/ 里所有 HTML,注入 .m-header、.m-bottom-nav 等 │
└──────────┴──────────────────────────────────────┴────────────────────────────────────────────────────────────┘
结论:桌面端新建7个模板 + 1个文章模板 + 1个RSS + 1个base模板 + 1个栏目模板 + 1个搜索页 = 11个文件,移动端全部由 processArticleHtml() 自动处理,不需要单独建模板。
实施步骤
第1步:英文版文章页模板
新建文件:en/article.njk
为什么先建这个:英文版文章(content/articles/en/*.md)的 frontmatter 当前 layout 指向 article.njk(中文版模板),
导致英文版文章页显示中文侧边栏、中文热门推荐。需要英文版模板替换所有中文字符串:
结构:
├── 继承 _includes/base.njk
├── 覆盖 content block:面包屑 → 文章头 → 文章正文 → 分享按钮 → 上下篇 → 相关推荐 → 评论占位
└── 侧边栏:TOC + 相关推荐 + 热门 + 资源
然后在 .eleventy.js 中,让 content/articles/en/.md 的 layout 指向 en/article.njk:
现有英文 collection 已经扫 content/articles/en/.md,只需确保 Eleventy 能识别 en/ 下的 layout 目录。
第2步:英文版首页
新建文件:en/index.njk
结构:
├── 继承 _includes/base.njk
├── 用 siteEn.name、siteEn.categories 渲染英文版 Banner
├── 用 en_tutorials、en_tools 等 collection 渲染文章列表
└── 侧边栏用 en_allArticles 渲染热门推荐
移动端版本由 processArticleHtml() 自动处理(已支持 isEn),不需要单独建 m-index.njk。
第3步:英文版栏目页(6个)
新建文件:
en/tools/index.njk
en/tutorials/index.njk
en/tips/index.njk
en/software/index.njk
en/news/index.njk
en/resources/index.njk
每个文件结构:
继承 base.njk
用对应 en_{category} collection 渲染文章列表
用 siteEn.categories 渲染栏目导航(与中文版 category.njk 对应)
第4步:英文版 RSS
新建文件:en/rss.njk
复制 rss.njk 内容,替换:
第5步:语言切换器接通
桌面端 — _includes/base.njk 第120行附近:
注意:用 '/en' in page.url 而不是 starts with '/en/',因为栏目页 /en/tools/、首页 /en/ 不以 /en/ 结尾但包含 /en。
移动端 — .eleventy.js 的 processArticleHtml() 函数(约第615行):
const isEn = outputPath.includes('/en/');
const langHref = isEn
? outputPath.replace('/en/', '/')
: '/en' + outputPath;
// 把 langHref 写入 .m-header-lang 的 href
// 按钮文字:isEn ? '中文' : 'English'
第6步:文章页翻译链接
_includes/article.njk 底部(相关推荐之前)加:
通过 translation-pairs.json 查找对应英文版 URL,显示 "Read this article in English" 链接。
如果是中文原创(无英文版),显示 "English version coming soon" 或不显示。
en/article.njk 同理显示 "阅读中文版"。
第7步:hreflang 互指
_includes/base.njk 的
中:注意:URL 动态计算,不硬编码路径,因为文章 URL 有 /tools/xxx/、/article/xxx/ 两种格式。
第8步:搜索索引拆分
修改 generate-search-index.js:
修改 js/search.js:
第9步:翻译对匹配(解决审计误报)
新建 config/translation-pairs.json:
{
"pairs": [
{
"zh": "/tools/ai-tools-navigation-2026/",
"en": "/en/article/ai-tools-navigation-2026/",
"method": "title-match"
}
],
"zh-only": ["/news/2026-05-29-news-article/", ...],
"en-only": ["/en/article/some-english-only-article/", ...]
}
匹配方法:用日期 + 分类 + 标签重合度来自动匹配,人工确认边界case。
有了这个映射表后:
文件变更清单
┌──────┬──────────────────────────────────┬─────────────────────────────────────────────┐
│ 操作 │ 文件 │ 端 │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 新建 │ en/article.njk │ 桌面端(英文版文章页模板) │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 新建 │ en-base.njk │ 桌面端(英文版 base 模板) │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 新建 │ en-category.njk │ 桌面端(英文版栏目模板) │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 新建 │ en/index.njk │ 桌面端(英文版首页) │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 新建 │ en/tools/index.njk │ 桌面端(英文版栏目页 ×6) │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 新建 │ en/tutorials/index.njk │ 桌面端 │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 新建 │ en/tips/index.njk │ 桌面端 │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 新建 │ en/software/index.njk │ 桌面端 │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 新建 │ en/news/index.njk │ 桌面端 │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 新建 │ en/resources/index.njk │ 桌面端 │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 新建 │ en/rss.njk │ 桌面端(英文版 RSS) │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 删除 │ en/search.html │ 与 en/search/index.njk 冲突,会导致构建失败 │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 修改 │ _includes/base.njk │ 桌面端(语言切换器双向逻辑 + hreflang) │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 修改 │ _includes/article.njk │ 桌面端(文章翻译链接) │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 修改 │ .eleventy.js │ 移动端(processArticleHtml 语言切换器接通) │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 修改 │ scripts/generate-search-index.js │ 两端共用(拆分中英文索引) │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 修改 │ js/search.js │ 两端共用(按语言加载索引) │
├──────┼──────────────────────────────────┼─────────────────────────────────────────────┤
│ 新建 │ config/translation-pairs.json │ 两端共用(翻译对映射表) │
└──────┴──────────────────────────────────┴─────────────────────────────────────────────┘
移动端不需要新建任何模板文件,全部靠 processArticleHtml() 动态生成机制。
实施顺序建议
第1步(en/article.njk)→ 第5步(语言切换器)→ 第7步(hreflang)→ 第2步(en/index.njk)
→ 第3步(栏目页)→ 第4步(RSS)→ 第8步(搜索拆分)→ 第9步(翻译对匹配)
先接通基础设施(模板、切换器、hreflang),再建页面(首页、栏目页),最后做数据层(搜索、翻译对)。
实施进度
┌───────┬──────────────┬───────────────────────┐
│ 步骤 │ 内容 │ 状态 │
├───────┼──────────────┼───────────────────────┤
│ 第1步 │ 英文版文章页模板 en/article.njk │ ✅ 已完成 │
├───────┼──────────────┼───────────────────────┤
│ 第2步 │ 英文版首页 en/index.njk │ ✅ 已完成(已存在) │
├───────┼──────────────┼───────────────────────┤
│ 第3步 │ 6个英文版栏目页 │ ✅ 已完成(已存在) │
├───────┼──────────────┼───────────────────────┤
│ 第4步 │ 英文版 RSS en/rss.njk │ ✅ 已完成(已存在) │
├───────┼──────────────┼───────────────────────┤
│ 第5步 │ 语言切换器双向(桌面+移动) │ ✅ 已完成 │
├───────┼──────────────┼───────────────────────┤
│ 第6步 │ 文章页翻译链接 │ ✅ 已完成 │
├───────┼──────────────┼───────────────────────┤
│ 第7步 │ hreflang 互指 │ ✅ 已完成 │
├───────┼──────────────┼───────────────────────┤
│ 第8步 │ 搜索索引拆分 │ ✅ 已完成(search-zh.json + search-en.json 各238条) │
├───────┼──────────────┼───────────────────────┤
│ 第9步 │ 翻译对匹配 │ ✅ 已完成(215对匹配 + 23中文原创 + 23英文原创) │
└───────┴──────────────┴───────────────────────┘
额外创建的文件(实施过程中发现需要,文档中原本没提到):
构建验证:npx @11ty/eleventy → 716 files written in 7.36s,无错误无冲突