Hreflang 没有 return tag,Google 整组忽略

Search Console 报你 hreflang 簇 "No return tags"。A 指向 B,但 B 没指回 A。Google 整组标注作废。

Search Console → “International Targeting” 或 “Pages → Hreflang” 报 “No return tags” 或 “Hreflang annotation has no return tag”。你的英文页正确用 <link rel="alternate" hreflang="zh"> 指向中文译文,但中文页没有指回英文。Google 的 hreflang 规则要求双向确认:A 说”我的译文是 B”,那 B 必须说”我的译文是 A”。否则 Google 当整组标注不可靠,整体忽略。

症状可能很微妙:中文页对英文 query 排名,而英文版本明明存在;或者某国 SERP 里出现错语言版本。修法是让每个 hreflang 引用都是相互的。

常见原因

1. EN 模板输出 hreflang,ZH 模板忘了加

英文页 layout 写了到所有语言版本的 hreflang。中文页 layout 是从单语模板拷过来的,hreflang 代码从没加。

怎么判断curl https://yoursite.com/zh/articles/foo/ | grep hreflang。空就是中文模板完全没 hreflang。

2. Hreflang URL 跟页面实际服务 URL 不一致

EN 页写 <link rel="alternate" hreflang="zh" href="https://yoursite.com/zh/articles/foo/">。ZH 页实际是 https://yoursite.com/zh/articles/foo 没斜杠,或 https://www.yoursite.com/zh/articles/foo/ 不同 host。Google 匹配不上往返。

怎么判断:对比每边声明的 alternate URL 跟该页实际 canonical URL。trailing slash、www 与否、http/https——都重要。

3. Hreflang 语言码不一致

EN 写 hreflang="zh",ZH 写 hreflang="zh-CN"。Google 认为 zhzh-CN 是不同标注,不会配对。

怎么判断:grep 整簇的 hreflang 值。必须完全字符串相等。

4. 一边有 hreflang,另一边 404 / 301

EN 链 ZH。ZH 被删了(404)或重定向(301)。return tag 不可能存在于不存在的页上。

怎么判断:每个 hreflang 目标 curl -I 确认 200 OK。其他状态都打破簇。

5. HTML head 有 hreflang,但 canonical 指向了第三个 URL

ZH 页有指回 EN 的 hreflang,但 ZH 页也有 <link rel="canonical" href="..."> 指向第三个 URL。Google 先按 canonical 走、在 canonical 目标上读 hreflang——而那个目标没有 return tag。

怎么判断:簇里每个成员看它的 canonical。canonical 必须指向自己(或 hreflang 必须放在 canonical 目标上)。

6. 自指 hreflang 缺失

每个语言版本都必须包含指向自己的 hreflang。EN 页同时要有 hreflang="en"(自指)和 hreflang="zh"(其他)。缺自指就打破簇。

怎么判断:view source,数 hreflang 条数。应等于语言版本数,含当前页。

7. Sitemap 里声明了 hreflang,HTML 里也有但不一致

有的团队只把 hreflang 放 sitemap.xml,有的放 HTML <head>。两边都有但不一致时,Google 可能选其一、忽略 return tag。

怎么判断:同一 URL 在 sitemap 里的 hreflang 块和 HTML 里的 hreflang 标签对比。必须完全一致。

最短修复路径

第 1 步:选一种声明方式,不要混用

三种合法方式(只选一种):

  • HTML <head> 标签(最常见)
  • HTTP 响应头Link: header)
  • XML sitemap <xhtml:link>

HTML 方式:每个语言版本都必须包含所有语言(含自己)的 hreflang。

第 2 步:用共享 layout 实现 hreflang

写一个 helper,输入当前文章的 translation key,输出完整簇:

---
const { translationKey, currentLang } = Astro.props;
const translations = await getCollection('articles', a =>
  a.data.translationKey === translationKey
);
---
{translations.map(t => (
  <link rel="alternate" hreflang={t.data.lang}
    href={`https://yoursite.com/${t.data.lang}/articles/${t.data.urlSlug}/`} />
))}
<link rel="alternate" hreflang="x-default"
  href={`https://yoursite.com/en/articles/${currentSlug}/`} />

这样簇里每个页面看到的列表相同,且都链到所有成员(含自己)。

第 3 步:URL 格式完全一致

定一个 canonical URL 形式:https、host 带不带 www、带不带 trailing slash。一致到底:

# bash 跨页面检查
for url in "https://yoursite.com/en/articles/foo/" "https://yoursite.com/zh/articles/foo/"; do
  curl -s "$url" | grep -oE 'hreflang="[^"]+" href="[^"]+"'
done

确认每个 hreflang URL 正好是那个语言版本的 canonical。

第 4 步:语言码统一

ISO 639-1 两字母(enzh),或扩展(en-USzh-CN)。选一种风格永不混用。中文:要区分字体用 zh-Hans(简)和 zh-Hant(繁);否则就 zh

第 5 步:修 canonical

每个 hreflang 簇成员必须 rel=canonical 到自己,不是另一种语言。跨语言 canonical 是经典 bug,会打破 hreflang:

<!-- 错:ZH 页 canonical 到 EN -->
<link rel="canonical" href="https://yoursite.com/en/articles/foo/">

<!-- 对:ZH 页 canonical 到自己 -->
<link rel="canonical" href="https://yoursite.com/zh/articles/foo/">

第 6 步:CI 校验簇完整性

// scripts/check-hreflang.mjs
import fs from 'node:fs';
import { glob } from 'glob';

const errors = [];
const files = glob.sync('src/content/articles/**/*.mdx');
const byKey = {};

for (const f of files) {
  const fm = parseFrontmatter(f);
  byKey[fm.translationKey] ??= [];
  byKey[fm.translationKey].push({ file: f, lang: fm.lang });
}

for (const [key, members] of Object.entries(byKey)) {
  if (members.length < 2) continue;  // 单语跳过
  const langs = members.map(m => m.lang);
  for (const m of members) {
    if (!langs.includes(m.lang)) errors.push(`Missing self: ${m.file}`);
  }
}
if (errors.length) process.exit(1);

第 7 步:重提,观察

Search Console → International Targeting(legacy 报告)和 Pages 报告。重抓 1-2 周内 “No return tags” 警告应消失。

哪些情况可能不是你操作错了

翻译团队手动只发一种语言、另一种延后,hreflang 在缺口期会警告。这是预期的;两边都有后警告自动消。

容易误判的情况

仅当作 canonical 问题。两个会互相影响:canonical 错就让 hreflang 失效。永远先修 canonical 指自己,再修 hreflang。

预防建议

  • 用单个共享 layout helper 输出 hreflang;不要每页手写。
  • CI 校验:同 translationKey 的文件跨语言齐全。
  • 整站统一一种 URL 形式(trailing slash、host、protocol)。
  • 每个语言版本 canonical 指自己。
  • 每季度用 Screaming Frog 或自定义脚本审 hreflang。

FAQ

  • 需要 x-default 吗? 建议有但非必需。带语言选择器的全球落地页有用。
  • Hreflang 能指向不同域名吗? 可以——hreflang="ja" 可指向 yoursite.jp。return-tag 规则同样适用。

相关阅读

标签: #SEO #排查 #收录 #Search Console #hreflang #international