本文约 4,159 字,预计阅读 11 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:标签写了,却完全没生效
多语言站点最常见的 hreflang 事故是:标签写得满满当当,Google 的「国际定位」报告却一条都没识别。原因通常是三类硬伤——没有自引用、语言代码写成 en-UK(英国的正确代码是 en-GB)、或者各语言版本之间没有互相指向(单向而非双向)。hreflang 的规则非常机械,任何一条不满足,整组标签都会被忽略。
原理分析:hreflang 的三条硬规则
hreflang 的作用是告诉搜索引擎「这个页面的其他语言/地区版本在这里」,用于把正确版本展示给对应地区的用户。Google 明确要求三件事:
| 规则 | 说明 | 常见违反 |
|---|---|---|
| 自引用 | 每个页面必须在 hreflang 组中包含自己 | 只列出其他语言 |
| 双向确认 | A 指向 B,B 也必须指回 A | 单向指向 |
| 代码合规 | 语言用 ISO 639-1,地区用 ISO 3166-1 Alpha-2 | en-UK、zh-CN 大小写混用 |
语言代码必须单独可用,地区代码是可选的补充。只写地区不写语言是无效的(如 rel="alternate" hreflang="US" 不合规)。x-default 用于指定「未匹配任何其他语言时的兜底页」,不是必需的,但对语言选择页很有用。
三种实现方式各有适用场景:
| 方式 | 适用 | 限制 |
|---|---|---|
HTML <link> |
绝大多数站点 | 需在 <head> 内 |
HTTP Link 头 |
PDF、非 HTML 资源 | 配置复杂 |
| XML 站点地图 | 页面数量大、组关系复杂 | 维护成本高 |
三者不要混用,混用容易出现互相矛盾的声明。
保姆级实操
步骤一:确定 URL 与代码方案
先定语言与地区映射,例如 zh-Hans(简体)、zh-Hant(繁体)、en-US、ja-JP。注意中文可用 zh-Hans/zh-Hant 脚本子标签,也可用 zh-CN/zh-TW,但同一站点内必须统一风格。
步骤二:在 WordPress 里自动输出完整组
下面这段以自定义字段 mmf_translations(JSON,键为 hreflang 值、值为 URL)为数据源,自动补上自引用:
add_action( 'wp_head', 'mmf_output_hreflang', 2 );
function mmf_output_hreflang() {
if ( ! is_singular( array( 'post', 'page' ) ) ) {
return;
}
$id = get_queried_object_id();
$json = get_post_meta( $id, 'mmf_translations', true );
$map = json_decode( $json, true );
if ( ! is_array( $map ) ) {
$map = array();
}
// 自引用:必须包含当前页面自身
$self = get_post_meta( $id, 'mmf_lang_code', true ) ?: 'zh-Hans';
$map[ $self ] = get_permalink( $id );
foreach ( $map as $code => $url ) {
printf(
'<link rel="alternate" hreflang="%s" href="%s" />' . "\n",
esc_attr( $code ),
esc_url( $url )
);
}
if ( ! empty( $map['x-default'] ) ) {
printf( '<link rel="alternate" hreflang="x-default" href="%s" />' . "\n", esc_url( $map['x-default'] ) );
}
}
步骤三:输出到站点地图
如果语言版本很多,改用 XML 站点地图声明更清晰:
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://mimangfei.com/hreflang-guide/</loc>
<xhtml:link rel="alternate" hreflang="zh-Hans" href="https://mimangfei.com/hreflang-guide/"/>
<xhtml:link rel="alternate" hreflang="en-US" href="https://mimangfei.com/en/hreflang-guide/"/>
<xhtml:link rel="alternate" hreflang="ja-JP" href="https://mimangfei.com/ja/hreflang-guide/"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://mimangfei.com/en/"/>
</url>
</urlset>
步骤四:非 HTML 资源用 HTTP 头声明
PDF 之类无法写 HTML 标签的资源,用响应头:
location ~* \.pdf$ {
add_header Link '<https://mimangfei.com/en/report.pdf>; rel="alternate"; hreflang="en-US", <https://mimangfei.com/report.pdf>; rel="alternate"; hreflang="zh-Hans"' always;
}
步骤五:用命令验证输出
检查页面里是否包含自身、代码是否合规:
curl -s https://mimangfei.com/hreflang-guide/ \
| grep -o '<link rel="alternate" hreflang="[^"]*" href="[^"]*" />'
# 检查是否存在非法的地区-only 代码或错误地区码
curl -s https://mimangfei.com/hreflang-guide/ \
| grep -oE 'hreflang="[a-z]{2}-[A-Za-z]{2}"' | sort -u
步骤六:在 Search Console 里复核
旧版 Search Console 曾有「国际定位」报告,新版主要依靠「网址检查 → 国际化和本地化」部分查看 hreflang 是否被识别。识别不到时按步骤五的规则逐项排查。
步骤七:同步 canonical
canonical 必须指向自身语言版本的 URL,不能所有语言版本都 canonical 到主语言,那会直接抵消 hreflang 的作用。
常见踩坑
- 忘记自引用,整组标签被判不完整。
- 只做单向指向,A 指向 B 但 B 没指回 A。
- 把英国写成
en-UK,正确代码是en-GB。 - 只写地区(
hreflang="US")不写语言,格式不合规。 - 所有语言版本的 canonical 都指向主语言页,hreflang 被抵消。
- 案例:某外贸站用插件生成 hreflang,插件在翻译缺失的页面仍输出了指向空 URL 的标签,导致整站被判定标签无效。清理缺失项后,日文版页面的展示量在四周内上涨约两倍。
- HTML 与站点地图同时声明且内容不一致,形成矛盾信号。
总结
判断 hreflang 是否写对的三条标准:每个页面都包含指向自己的标签、所有版本之间双向互指、语言与地区代码符合 ISO 规范。落地时要统一代码风格(zh-Hans 与 zh-CN 不要混用),canonical 必须与 hreflang 一致指向自身版本,三种声明方式不要混用。验证用 curl 直接看输出,比在后台猜要快得多。若还在选型阶段,URL 结构决策(ccTLD、子域、子目录)请参考 国际站点URL结构;标签生效后,可用 服务器日志分析 观察各语言版本的 Googlebot 抓取分布;如果跨版本出现索引异常,还可结合 抓取预算优化 排查优先级问题。
