使用您最喜欢的AI助手总结文档,并引用此页面和AI提供商
此页面的内容已使用 AI 翻译。
查看英文原文的最新版本如果您有改善此文档的想法,请随时通过在GitHub上提交拉取请求来贡献。
文档的 GitHub 链接复制文档 Markdown 到剪贴板
Hreflang:多语言 SEO 指南
你翻译了你的应用。你发布了 /en、/fr、/es。但法语用户仍然登录到英文页面。
翻译很容易。困难的一半是告诉搜索引擎这些页面是同一页面的其他语言版本,而不是三个相互竞争的文档。这就是 hreflang 的作用,也是大多数多语言网站悄悄失去流量的地方。
hreflang 实际上是什么
一个页面上的注释,说:这个 URL 在那里有等效的版本,适用于那些语言。
复制代码到剪贴板
它为你争取两样东西:为合适的用户展示正确的版本,以及将你的多语言版本合并到一个集群中,而不是作为重复内容互相蚕食。
需要明确的是它不是什么。它不是重定向——它是一个提示,Google 可能会覆盖它。它不是排名提升——它改变的是哪个版本排名,而不是是否排名。而且 Bing 完全忽略它,而是依赖 content-language 和地理定位。
在哪里声明它
三种放置方式,都有效。选择一种并坚持——同一个集群在两个地方声明是集合漂移的原因。
HTML <head> 是通常的选择。一个需要注意的问题:水合后注入的标签是不可靠的。如果你的框架只在客户端添加它们,爬虫可能永远看不到它们。
XML sitemap 在大规模使用中更有优势。十个语言版本跨越 5,000 页面意味着需要向浏览器发送 50,000 个 <link> 元素,而这些元素对页面毫无用处;在 sitemap 中它不会占用页面的任何字节。
HTTP Link header 是唯一适用于 PDF 等非 HTML 文件的选项。
规则
自我引用和互惠性
设置在 /fr/about 上必须包含指向 /fr/about 的 hreflang="fr"。如果 /about 指向 /fr/about,那么 /fr/about 也必须指回去。Google 将单向引用称为"no return tag"并将其丢弃。
实际上这意味着集群中的每一页都必须发送相同的链接集。从一个共享的语言列表生成它们不仅仅是一种便利,一旦你拥有超过两个语言版本,这是保持正确性的唯一方式。
始终使用绝对 URL
复制代码到剪贴板
这个原因值得理解而不仅仅是记忆。hreflang 是一个跨文档引用:搜索引擎构建一个由 URL 键值的集群,在集群中的每一页都共享这个集群。相对路径只有相对于它所在的文档才有意义,因此它无法表达这一点。它也无法跨越主机——而替代版本通常会这样做,当一个语言版本存在于 example.fr 或 fr.example.com 时。在 sitemap 或 HTTP 头中,根本没有可以用来解析的基础文档。
这在代码中有直接的后果。getLocalizedUrl("/about", "fr") 返回 /fr/about — 相对路径输入,相对路径输出。对于 hreflang,你必须向其提供绝对 URL:
复制代码到剪贴板
唯一的例外是一个框架在渲染之前为你解析相对值:Next.js 根据 metadataBase 展开相对的 alternates。没问题 — 但规则适用于发出的 HTML,所以用 curl 检查,而不是 DevTools 检查器。
语言代码
ISO 639-1 用于语言,ISO 3166-1 Alpha 2 用于可选的地区:fr、fr-CA、pt-BR。
两个陷阱几乎会困住每个人。单独的地区代码是无效的——hreflang="ca" 表示加泰罗尼亚语,而不是加拿大;你需要 en-CA 或 fr-CA。而 en-UK 不存在:英国的国家代码是 GB,所以是 en-GB。
只有在你确实为该地区提供不同内容时才添加地区——不同的价格、不同的法律声明。fr 和 fr-FR 在相同内容上是冗余的。
x-default
复制代码到剪贴板
最容易被遗忘且最容易被误解的一个概念是 x-default——少于 30% 的应用正确实现它。
这是用户语言与你的集合中任何内容都不匹配时的回退方案。荷兰语使用者访问仅提供英语、法语和西班牙语的网站时无法匹配任何条目;没有 x-default,Google 会为你做出选择。
人们经常误解的是它的含义。x-default 不是"英文版本" 也 不是"默认 locale",尽管它通常指向那里。它的意思是 这个集合不覆盖的用户的页面。这就是为什么让它指向语言选择器或地理重定向登陆页面是合理的,通常也更好——而不是指向 /en。如果你没有这样的页面,你的主要语言是明智的选择。
两件事需要区分清楚:x-default 是该集合中的一个额外条目,而不是自引用条目的替代品,而且像其他每个条目一样,它必须在集群中的每个页面上完全相同地出现。
canonical 陷阱
每个本地化页面必须是它自己的 canonical:
复制代码到剪贴板
将每个语言版本的 canonical 都指向英文版本反而会这样做:
复制代码到剪贴板
表示法语页面是不应被索引的重复内容,而 hreflang 则表示这是应该提供给法语用户的页面。这些信号相互矛盾,canonical 优先级更高,结果是你的法语页面会被从索引中移除。
Canonical 在每个语言版本中是自引用的。hreflang 描述的是整个集群。
选择 URL 结构
hreflang 对 URL 进行注释,所以结构应该优先考虑。
在弹窗中打开表格以清晰地查看所有数据
| 结构 | 示例 | 权衡 |
|---|---|---|
| 子目录 | example.com/fr/ | 一个域名,权限共享 — 地理信号较弱 |
| 子域名 | fr.example.com | 易于添加或删除语言版本 — 可能看起来像一个独立网站 |
| ccTLDs | example.fr | 最强的国家信号 — 每个域名建立权限 |
对大多数项目来说,子目录是正确的默认选择。只有当你真正以独立的国家业务运营时,才应该考虑使用 ccTLDs。
应该避免的一个结构是:基于 Accept-Language 或 IP 在同一 URL 上提供不同的语言。爬虫会看到一个版本并索引一个版本;其他所有内容都是不可见的。
Intlayer 通过routing.mode和routing.domains支持这三种方式。参见自定义域名和配置参考。
实现
手动编写这些标签无法在添加第二种语言时保持一致。应该从你的语言列表中派生它们。
在每个页面上发出集群
相同的集合到处都有,每个语言环境的规范链接,绝对URL,包括
x-default。Metadata API 暴露
alternates.languages,而getMultilingualUrls从你配置的语言环境构建整个记录:src/app/[locale]/about/page.tsx复制代码复制代码到剪贴板
完整设置: Next.js 16 i18n 指南。
路由的
head函数构建链接。localeMap遍历你配置的语言环境,所以向配置中添加一个语言环境会在所有地方同时添加它:src/routes/{-$locale}/about.tsx复制代码复制代码到剪贴板
head在服务器上运行,因此标签会被插入初始 HTML 中。完整配置:TanStack Start i18n 指南。或将其全部移至站点地图
大规模应用时,将注解完全从页面中移出。
generateSitemap根据配置读取 locale 和路由模式,为每个条目生成xhtml:link备用链接:src/routes/sitemap[.]xml.ts复制代码复制代码到剪贴板
两个值得了解的选项:
xhtmlLinks(默认值true) — 只有在 locale URL 实际不同时,才会发出交替链接。在no-prefix模式下,每个 locale 共享一个 URL,因此除非routing.domains为 locale 分配自己的主机名,否则会被跳过。entryPerLocale(默认值false)—— 默认情况下,一个<url>条目包含所有的备用语言版本。两种形式都是有效的,但只有列在<loc>中的 URL 才会在 Search Console 中被计算为已提交;仅作为备用语言的区域设置会保持可发现性但不会被归属到任何 sitemap。启用此选项会为每个本地化 URL 提供其自己的条目,并重复完整的备用语言集。这会按区域设置计数增加条目,因此需要注意 50,000 个 URL / 50 MB 的限制,超过后应分割为 sitemap 索引。
验证爬虫接收到的内容
hreflang会无声地失败,因此应该检查它而不是假设它有效。读取源代码,而不是检查器 —
curl https://example.com/fr/about | grep hreflang显示爬虫获取的内容;DevTools 显示 JavaScript 运行后的 DOM。然后跟随每个备用链接,确认它使用相同的集合指向回来,并且它们都不重定向。Search Console 的国际定位报告捕获整个站点中的其余部分。对于多语言特定的爬取,Intlayer SEO Scanner 检查本地化页面中的缺失标签、损坏的备用链接和规范冲突。
检查清单
- 每个地区都有一个独特的、可爬取的 URL
- 每个页面自引用,并且每个引用都是相互的
- 相同的集合在集群中的每个页面上发布
- 所有
href值在生成的 HTML 中都是绝对路径 - 代码遵循 ISO 639-1 + ISO 3166-1 Alpha 2 标准(
en-GB,而非en-UK) -
x-default存在,并指向未匹配用户应访问的位置 - 规范标签在每个 locale 中自引用
- 标签是服务端渲染的,不是 hydration 后注入的
- 在恰好一个位置声明
- 没有跨 locale 的重定向
总结
hreflang 简单但容不得半点差错。一个缺失的返回标签、一个相对 URL、一个跨 locale 的规范标签,整个集群就会被丢弃且不会报错。这些问题通常都源于手工编写标签。
从单个 locale 列表派生集合,进行服务器端渲染,保持 canonical 自引用,并给予 x-default 应有的重视。做好这一次,正确性就不再是你需要维护的东西。
深入了解
- SEO 和国际化 — 更广泛的多语言 SEO 图景
- Next.js 中的 SEO 和 i18n —
next-intlvsnext-i18nextvs Intlayer - Next.js 16 i18n 指南
- TanStack Start i18n 指南
- 每个区域的自定义域名
- 配置参考
评论
暂无评论。成为第一个分享您想法的人吧。
