hreflang 标签怎么写:三处落点、x-default、与那条会让整组作废的回指规则
hreflang 是一组只能成组生效的标签:每个语言版本都要列出包括自己在内的全部版本,只要缺一条回指,Google 可能把整组一起忽略。这篇讲取值怎么写、三处落点怎么选,以及一条发布前验回指的命令。

hreflang 是一组只能成组生效的标签:它告诉引擎「这一页是写给哪一批语言 / 地区读者的」。它有一条很容易踩的规则 —— 每个语言版本都必须列出包括自己在内的全部版本,只要有一个页面忘了回指,Google 可能把整组注释一起忽略。标签本身不难写,难的是回指。
写之前先确认两件事
你需要同一页至少两个真实版本,而且得先想清楚它们是不是真的语言或地区不同 —— 不是同一段文字换了个域名。语种清单还没定的话,先把「翻哪几个语种、按什么顺序」定下来再写标签,否则你为一个后面会砍掉的版本写的那组注释,全是白写。
再划一条边界。hreflang 不做跳转,也不负责识别语言。Google 自己写得很清楚:判断一个页面是什么语言用的是算法,不是这个标签。它真正买到的东西只有一样 —— 一句机器可读的声明,说清哪个网址是给哪批读者的,好让几份近似的译文被理解成同一页的不同版本,而不是互相竞争的几页。
hreflang 是一句「这页写给谁」的声明。只有当每一页都说了同一句话,它才会被相信。
hreflang 到底管什么、不管什么
Google 那页《Localized versions of your page》给承诺给得很克制。它没有说 hreflang 能抬排名,也没有说这组注释是必须的。它只写了一句更窄、也更有用的话:同一页的本地化版本,只有在正文始终没有被翻译的情况下,才会被当成重复内容。正文一旦真翻了,这组注释就是你把这些版本连起来的方式,而不是让 Google 去猜。
顺着这句话能推出两件事。一个页面九成英文、只把菜单翻译了,不算本地化版本 —— Google 举的例子正是那种只翻模板的论坛。反过来,正文根本没翻却在写注释,是在描述一个并不存在的区别。
hreflang 标签能放在哪三处
声明这一组的方式只有三种,Google 把三者视为等价。你挑一种就行;三种一起上没有任何好处,官方反而提醒说同时维护三套实现比只挑一套难管得多。
| 方式 | 写在哪 | 什么时候用 |
|---|---|---|
| HTML link | 每个版本一条 <link>,放进 <head> | 页面 HTML 由你控制 |
| HTTP 响应头 | 每个版本一条 Link: 头 | 改不了 HTML,或文件是 PDF |
| sitemap | 每个网址一段 xhtml:link | 网址很多、由数据源批量生成 |
HTML 这种是绝大多数站用的,它有一条容易写错的位置规则:那几条 <link> 必须落在一个结构完整的 <head> 里。如果某个框架是在 body 已经开始之后才把它们插进去,那就不在 head 里了,也就不算数。把渲染后的页面丢进 HTML 校验器,确认它们落在哪。
<head>
<link rel="alternate" hreflang="en" href="https://example.com/page" />
<link rel="alternate" hreflang="en-GB" href="https://example.com/en-gb/page" />
<link rel="alternate" hreflang="de" href="https://example.com/de/seite" />
<link rel="alternate" hreflang="x-default" href="https://example.com/" />
</head>
取值怎么写才不会被判无效
一个取值是「一段语言码,可选再加一段地区码」,中间用连字符隔开。第一段是语言,取 ISO 639-1;可选的第二段是地区,取 ISO 3166-1 Alpha 2。只有这两份标准里列出的码才被支持,官方点名的反例是 es-419 —— 看着合理,但不被支持。
两条规则能挡住大部分无效取值。地区码不能单独出现:en-GB 有效,GB 无效,因为第一段永远是语言,Google 不会从国家反推语言。第二段要的是国家码,不是书写系统 —— zh-Hans 这种带 script 的写法不属于 ISO 3166-1 的国家码,所以不该出现在第二段。
| 取值 | 含义 | 有效 |
|---|---|---|
| en | 英文,不限地区 | 是 |
| en-GB | 面向英国的英文 | 是 |
| pt-BR | 面向巴西的葡萄牙文 | 是 |
| GB | 只有地区、没有语言 | 否 |
| es-419 | 拉美,联合国地区码 | 否 |
| x-default | 上面没列出的所有语言 | 是 |
x-default 是兜底页,不是「默认语言」
x-default 匹配的是页面上没有被任何一条 hreflang 明确列出的语言。它指向那一页你打算把「对不上号」的访客送过去的地方 —— 一个语言选择页,或者一个全球首页。它不是主语言的同义词,一组标签没有它也可以是对的。它真正值钱的地方是那种按地区跳转的站:没有兜底页时,语言不在集合里的访客可能一直跳在循环里。
按这个顺序做
五步,每一步都有一个能验证的完成标志。第一次配一组大概一个下午,之后它就是一段可以照抄的模板。
- 先列版本。 把这一页的每一份译文或地区变体都写下来,包括你正在编辑的这一页。完成标志:清单至少两条,且每一条都是真实可访问的网址。
- 给每个版本配一个取值。 语言用 ISO 639-1,只有地区确实重要时才补第二段 ISO 3166-1 Alpha 2。完成标志:没有任何取值是只有地区的,也没有一个取值落在这两份标准之外。
- 把同一组标签贴进每个版本。 每个页面贴的是完全一样的一组,而且每组里都包含指向自己那一页的链接。完成标志:从任意一页复制这组标签,都能在其余每一页里找到同样几行。
- 有跳转或自动识别就补 x-default。 让它指向那个接待其余所有人的页面。完成标志:语言没被列出的访客有地方可落。
- 逐条验回指。 集合里每一个网址都要能打开,而且它自己也要带着这组标签。完成标志:下面那条检查跑完,没有一条缺失的回指。
交付物:一张回指自检表
这一块值得留下。一组 hreflang 其实是一张有向图,让它作废的失败就是缺一条边 —— 某个页面链了出去,却没有被链回来。下表是一组正确标签长什么样,下面那条命令用来验你自己的。
| 页面 | 必须链到 | 常见错法 |
|---|---|---|
| en | en、en-GB、de、x-default | 只列了别人,漏了自己 |
| en-GB | en、en-GB、de、x-default | 指向了 en,但 en 从没指回来 |
| de | en、en-GB、de、x-default | 后来加的版本,集合一直没更新 |
| x-default | 同样这一组 | 被当成一种语言,硬给它配了地区 |
# 把一页上所有 hreflang 链接打出来,再逐条手动核对回指
curl -s -L --compressed -A "Mozilla/5.0" https://example.com/de/seite -o page.html
python3 -c "
import re
html = open('page.html').read()
head = html.split('</head>')[0]
for m in re.finditer(r'hreflang=[\"\']([^\"\']+)[\"\'][^>]*?href=[\"\']([^\"\']+)', head):
print(m.group(1), m.group(2))
"
把输出当成一张图来读:你看到的每一个网址,在它自己那一页上跑同一条命令时,都必须打出一行 href 等于你现在这一页。只要有一条不是,这张图就在那条边断了,而 Google 的原文说的是注释可能被「ignored or not interpreted correctly」—— 不是部分生效,是可能整组不算数。
会出什么错,怎么发现
三种失败几乎能覆盖所有写坏的组,而每一种都藏在一个你当时没在看的页面上。
- 缺一条回指。 最常见,也最不显眼,因为忘了回指的那一页不是你正在看的那一页。只有把集合里每个网址都跑一遍命令,才看得见。
- 拿地区码当语言码用。 有人写
hreflang="uk"想表达乌克兰语,而uk正是英国的国家码。要逐个拿两份标准去对,别凭三字母的直觉。 - 整组标签被放到了 head 外面。 标签管理器或一段前端脚本在加载后才把这几条追加进去。Google 读的是下发的那份 HTML;在那之后由 JavaScript 注入的链接,不在它看到的 head 里。要看源代码,不是渲染后的 DOM。
有一条我们没测:修正一组标签之后多久会被重新读到、之前被忽略的那组会不会被重新考虑。Google 那一页没有给时间窗,本篇也就不写。
常见问题
站只有一种语言,还要不要写 hreflang?
不用。单语站没有东西要连。hreflang 的作用是把同一份内容的不同版本区分开,只有一个版本时就没有需要消解的歧义。
能用 hreflang 代替 canonical 吗?
不能,两者回答的是不同的问题。canonical 说的是同一页被多个网址访问到时要留下哪一个;hreflang 说的是几份不同语言的页面各写给谁。译文不是原文的重复版本,所以它不需要一条指回原文的 canonical。
集合里有一个页面打不开会怎样?
官方原文说,回指缺失时注释可能被忽略或不被正确解读。这是对整组说的话,不是对哪几页存活的保证,所以任何一条缺失的边都该当成「去修」的理由,而不是等等看。
hreflang 能提升排名吗?
Google 那一页把 hreflang 描述成一种标明备选版本的方式,没有把它列为排名信号,我们这次也没量排名。站得住的版本更窄:它帮对的版本触达对的人,也避免几份译文被读成互相竞争。
一组最多能放多少个版本?
官方没有给数字。实际的天花板来自那条规则本身 —— 每个版本都要带上其他所有版本,所以集合会随版本数的平方增长。这也正是「语种别贪多、要真的分得开」的实际理由。
至于哪些版本值得配一组标签,前面那章已经讲过;而真实站上到底有多少首页真的写了这组注释,数字在那份 hreflang 实测里。加第四种语言之前,两篇都值得先看一遍。想知道爬虫到底从每个版本收到了什么,QueryWin 的产品怎么运转是同一件事的产品侧。
本文属于 QueryWin 实操手册 · 第 2 阶


