多语言 SEO · Case 02
这事的起点是一个看起来很简单的判断:「多语言页做得还不够好,先留着 noindex,等内容真正本地化了再放开。」判断是对的。但它底下压着更硬的一层——那批页面的 canonical 全部指向英文版。在这种情况下,放开 noindex 完全无效,两个信号互相抵消。
写了个扫描器把每个页面的 canonical、hreflang、robots 全提出来对照,输出按目录和错误码聚合:
| 错误码 | 数量 | 成因 |
|---|---|---|
| HL_BROKEN | 111 | hreflang 指向已删语种 /ar/ /ru/,或指向不存在的同语种页 |
| CANON_FOREIGN | 30 | ja/es 全部工具页 canonical 指向英文版 |
| HL_DUP | 26 | 同一语言重复声明,全在 tools/ |
| CANON_MISSING | 4 | examples/ 下演示页缺 canonical |
171 条里没有一条是「玄学」,四类各有明确成因。这决定了修复方式:不需要逐页手改,可以写确定性修复器。
ja/tools/age-calculator.html → canonical: /tools/age-calculator.html ← 英文版
es/tools/calculadora.html → canonical: /tools/calculator.html ← 英文版
de/tools/calculator.html → canonical: /de/tools/calculator.html ← 自指,正确
canonical 是一个「告诉搜索引擎哪个版本是正本」的指令。指向英文版,等于明确说「别收我,收那篇英文的」。这与 noindex 的效果方向一致:两者都在阻止这个页面被单独收录。所以对 ja/es 这 30 个页面来说,放开 noindex 只是拆掉了一道门,另一道门还锁着。
de 的写法是对的,这也解释了为什么同样是「内容较薄的语言页」,de 的 11 个工具页能过闸门,ja/es 一个都过不了。
111 条 hreflang 指向 /ar/ 和 /ru/——这两个目录早就不存在了。hreflang 指向 404,等于向搜索引擎声明「这个语言版本在这儿」,实际打开是错误页。搜索引擎处理这种不一致的方式通常是:整组 hreflang 都不再被信任,包括那些本身写对的条目。
另外 tools/ 下 26 处同一语言重复声明(en/de/ja 各出现两次),这属于格式错误,同样会削弱整组信号。
修复器做了三件事,都是确定性的、可重跑的:
一共涉及 87 个页面、165 处。落盘前留了两层回滚:git,以及一个 .head-backup/ 目录。
第一版修复器把 hreflang="zh-cn" 当成弃用语种删掉了。zh-cn 是合法标签,与 zh 同属中文,只是带地区子标签。判断逻辑写成了「完整字符串是否在列表里」,正确写法是「取主语言前缀再比较」。这类错误如果不做 dry-run 直接落盘,会在几百个页面上同时生效。
| 指标 | 修前 | 修后 |
|---|---|---|
| error | 171 | 0 |
| es 可放开页 | 1 | 14 |
| ja 可放开页 | 0 | 11 |
| sitemap 收录 | 163 | 189 |
关键在第二、三行:同一批内容,一个字没改,只是把信号修正了,可放开页从 1 变成 14、从 0 变成 11。这说明之前的「内容不够本地化」只是部分原因,更早生效的阻断在 head 里。
第一版闸门用「德语虚词占比」判断一页是不是真德语,结果把 de/tools/calculator.html 判成 FAIL:lang:28% < 35%。而这页是真德语、零英文残留。原因是工具页术语多、正文短、按钮文字多,德语虚词天然占比低。改用「英文残留率」后,这页 0.0% 直接通过。
德语 word-counter 被判成空壳,理由是「没有交互逻辑」。实际它写的是 t.oninput = upd,内联属性绑定,功能完整。判据补上 oninput / onchange / fetch / Intl / setInterval 之后才正确。
两次都是同一个方向:判据把「能用但写法不同」误判成「不行」。这类错误的代价不是漏报,而是把好页面当成坏页面处理——加厚、封索引,做的都是无用功,还会掩盖真正的问题。
静态托管上「同名文件 + 同名目录」会怎么解析?用站内 tools/text-diff 实测(两种形态同时存在):
/tools/text-diff → text-diff.html (无斜杠:文件优先)
/tools/text-diff/ → text-diff/index.html (带斜杠:目录优先)
这意味着新开一个栏目目录时,如果根目录正好有一个同名 .html,无斜杠访问会打到那个文件而不是栏目。新建栏目页里的内链必须全部带斜杠,否则用户点进去看到的是另一个页面。