Skip to content

别让多语言 SEO 白做:hreflang 替代标签在 VitePress 中的正确落地 ​

hreflang 替代标签在 VitePress 中的正确落地示意图

背景:当主语言遇上历史包袱 ​

如果你用 VitePress 搭建了多语言站点,并且辛辛苦苦把内容翻译了一遍,却发现在 Google 或 Bing 里搜不到对应的语言版本,甚至两个版本在互相抢夺排名,那么你大概率漏掉了一个极其关键的 SEO 标签:hreflang。

在展开聊技术之前,我想先聊聊这个博客的“历史包袱”。

我的博客前期只有中文内容,默认无前缀路径就是主语言(https://fishfinal.com/)。后期重构时,为了走向国际化,我引入了 VitePress 的 i18n,增加了英文版(/en/)。

这时就面临一个尴尬的架构问题:如果我此时把主语言(x-default)强行切换为英文,意味着要把所有中文文章移动到 /zh/ 下,不仅建站成本极高,而且会导致搜索引擎前期已经收录的旧中文链接全部 404,彻底打乱现有的 SEO 索引。

因此,为了兼顾历史收录,我依然将中文作为了当前的 x-default(兜底页面)。

💡 给新站长的建议: 如果你的博客是全新站点,准备直接做多语言。强烈建议默认根目录就放英文(/),中文放到 /zh/ 下,并将 x-default 指向英文。这样更符合国际化的通用标准。但如果是像我这样的存量老站,保持原有主语言作为兜底是最稳妥的选择。

今天我们就来聊聊,为什么多语言站必须加 hreflang,它在搜索引擎眼中到底起什么作用,以及如何在 VitePress 中优雅地、动态地落地它。

一、 为什么搜索引擎会“犯傻”? ​

假设你有一篇关于“MinIO 编译部署”的文章,有中文版和英文版。如果你不做任何声明,搜索引擎爬虫抓取到这两个页面时,会面临一个尴尬的局面:

  1. 内容几乎一致:在搜索引擎看来,这两个页面高度相似,可能被判定为“重复内容”。
  2. 自我竞争:中文用户搜相关关键词时,Google 可能把英文页面排在前面;英文用户搜索时,反而展示中文页面。
  3. 互相稀释权重:多个相似的 URL 分散了外链和页面权重,导致谁也排不到前列。

没有 hreflang,搜索引擎只能靠自身的语言检测模型去猜,而猜的准确率并不稳定,尤其是在简繁体、或者地区变体(如 zh-CN 和 zh-TW)上。

二、 hreflang 到底是什么? ​

简单来说,hreflang 替代标签就是告诉搜索引擎:“这个页面还有其他语言/地区的版本,它们的地址在这里,请把它们推荐给对应语言的用户。”

它有三个核心作用:

  1. 精准定向:把中文页推给中文用户,英文页推给英文用户,提升点击率和转化率。
  2. 避免自我竞争:明确告诉搜索引擎“这些是平级的替代版本,不是抄袭”,从而保护页面权重。
  3. 优化目标市场体验:在搜索结果中,直接展示符合用户母语的标题和摘要。

⚠️ 重要提示:hreflang 是信号而不是指令。搜索引擎会参考它,但最终展示哪个版本,仍由搜索引擎的算法决定。

三、 高频误区:canonical 能替代 hreflang 吗? ​

绝对不能。 这是很多开发者最容易踩的坑。

  • canonical(规范标签):它的作用是“合并”。当你网站有多个相同的 URL(比如带 ? 参数的 URL),你用 canonical 告诉搜索引擎:“这些都是同一个页面,请把权重都算在主 URL 上。”
  • hreflang(替代标签):它的作用是“平级替代”。中英文版本是独立且平等的,各自服务不同语言的用户,它们不是互相取代的关系。

如果错误地把中文页的 canonical 指向英文页,会导致中文页彻底从索引中消失。

四、 VitePress 中的正确落地写法 ​

在 VitePress 中配置 hreflang,最直观的做法是在 config.mts 的 head 数组里直接写死;但如果你想一劳永逸,则应该使用 VitePress 提供的钩子动态生成。

1. 基础版:硬编码示例 ​

假设你的主域名是 https://yourdomain.com,文章路径是 /posts/xxx.html。中英文的 URL 结构如下:

  • 中文版:https://yourdomain.com/posts/xxx.html
  • 英文版:https://yourdomain.com/en/posts/xxx.html

你可以在 config.mts 中直接注入:

typescript
// .vitepress/config.mts
export default defineConfig({
  // ... 其他配置
  head: [
    // ... 其他标签(如 favicon 等)
    [
      'link',
      {
        rel: 'alternate',
        hreflang: 'zh-CN',
        href: 'https://yourdomain.com/posts/xxx.html'
      }
    ],
    [
      'link',
      {
        rel: 'alternate',
        hreflang: 'en',
        href: 'https://yourdomain.com/en/posts/xxx.html'
      }
    ],
    [
      'link',
      {
        rel: 'alternate',
        hreflang: 'x-default',
        href: 'https://yourdomain.com/en/posts/xxx.html' // 建议:新站点的兜底页面通常设为英文
      }
    ]
  ]
})

(注:这种方式虽然简单,但如果你的博客有几十上百篇文章,硬编码简直是灾难,每加一篇文章都要改配置。)

2. 进阶版:使用 transformHead 动态生成(生产级) ​

为了解决硬编码的痛点,我们可以使用 VitePress 提供的 transformHead 钩子,根据当前页面的 relativePath 动态生成多语言标签。以下是实际生产环境中的配置方案:

typescript
// .vitepress/config.mts
import { defineConfig, HeadConfig } from 'vitepress';

export default defineConfig({
  // ... 其他配置
  transformHead({ pageData }) {
    const { frontmatter, relativePath } = pageData;
    const metas: HeadConfig[] = [];

    // 1. 判断当前语言环境
    const isEn = relativePath.startsWith('en/');

    // 2. 获取除去语言前缀后的纯路径(比如 'posts/xxx.md')
    const purePath = relativePath.replace(/^(zh|en)\//, '');

    // 3. 构建中文和英文的绝对 URL
    let zhUrl = `https://fishfinal.com/${purePath.replace(/\.md$/, '.html')}`;
    let enUrl = `https://fishfinal.com/en/${purePath.replace(/\.md$/, '.html')}`;

    // 4. 处理首页的特殊情况
    if (purePath === 'index.md') {
      zhUrl = 'https://fishfinal.com/';
      enUrl = 'https://fishfinal.com/en/';
    }

    // 5. 注入 hreflang 标签(双向互指)
    metas.push(['link', { rel: 'alternate', hreflang: 'zh-CN', href: zhUrl }]);
    metas.push(['link', { rel: 'alternate', hreflang: 'en', href: enUrl }]);
    // 注意:这里将 x-default 指向了 en。因为对于世界上非中英语言的用户,英文界面的接受度更高。
    // 如果你想把中文作为兜底,修改为 zhUrl 即可。
    metas.push(['link', { rel: 'alternate', hreflang: 'x-default', href: enUrl }]);

    return metas;
  }
})

必须遵守的 3 条铁律 ​

无论你用哪种方式,都必须满足以下条件:

  • 必须双向互指:中文页里必须声明英文页的链接,英文页里必须声明中文页的链接。单向声明是无效的。(动态方案已自动处理此逻辑)。
  • 必须使用绝对路径:一定要写完整的 https:// 开头的 URL,不要用相对路径。
  • x-default 兜底:当用户的搜索语言既不是中文也不是英文时,搜索引擎会展示 x-default 指向的页面。通常建议设为英文,这样能照顾到全球更多语种的用户。

五、 实战上线避坑指南 ​

当你满怀期待地把加了 hreflang 的代码推送到线上后,接下来的操作也很关键。

1. 不要频繁重新提交 Sitemap! ​

很多站长一改代码,就跑去 Google Search Console (GSC) 或 Bing Webmaster Tools 重新提交 sitemap.xml。这是完全错误的。 Sitemap 只是指路的地图,只负责声明 URL 列表。只要你的 URL 列表没有发生增减,就不需要重新提交。频繁提交反而可能降低搜索引擎对 Sitemap 的信任度。

2. 正确的催更姿势:URL 检查 ​

如果你想让改过标签的页面立刻被收录,不要去折腾 Sitemap,而是去使用“网址检查”:

  1. 打开 Google Search Console (或 Bing)。
  2. 在顶部的“网址检查”输入框里,粘贴你刚改过 hreflang 的具体英文页 URL,点击“请求编入索引”。
  3. 再粘贴对应的中文页 URL,同样操作一次。

这样能强制爬虫在最快时间重新抓取这两个页面,立刻发现你的改动。

3. 验证是否生效 ​

等一两天后,在线上页面右键点击“查看网页源代码”,搜索 hreflang,确认这几行代码是否如预期出现在 <head> 中,并且绝对路径完全正确。

总结 ​

多语言站点的建设成本极高,不要让粗心大意毁了你的 SEO 努力。花 10 分钟把 hreflang 配好,并严格遵守双向互指的原则,你的多语言流量才能真正源源不断。

最后更新2026/11/08 12:57
如果你觉得这篇文章有帮助,或者想聊聊技术、工作,欢迎通过下面方式联系我:
contact fishfinal
京ICP备2024063630号-1