Next.js 国际化的 5 个坑:从 React state 到 next-intl
复盘 Next.js 中英双语网站重构的五个问题:语言状态、路由改造、canonical 与 hreflang、语言切换和旧版示例,并给出排查顺序。
8 min read · 1585 words
我最初以为 Next.js 国际化只是“准备两份翻译文件,再加一个语言按钮”。真正把个人网站从中文改造成中英双语后,我才发现:最难的不是翻译,而是路由、内容组织和 SEO。
这篇文章不重复安装步骤,而是复盘我从错误方案迁移到 next-intl 的过程,以及几个看似能运行、长期却会出问题的选择。
如果你需要从零配置,请直接看《Next.js 国际化教程:用 next-intl 搭建 App Router 多语言网站》。
我的需求其实很简单
- 支持中文和英文
- 博客拥有独立语言内容
- 页面结构保持一致
- URL 可以分享、刷新和被搜索引擎收录
问题在于,我一开始只关注了第一项。
坑一:用 React state 切换文案
最早的做法是在客户端保存 locale,点击按钮后重新渲染:
保存 locale → 切换 state → 渲染另一份文案
视觉上完全正常,但 /blog/post 始终是同一个 URL。结果是:
- 刷新后可能丢失语言状态
- 分享链接无法表达当前语言
- 服务端与客户端容易出现状态差异
- 搜索引擎没有两个稳定入口可抓取
能切换文字,不等于完成了国际化。
真正适合公开内容的结构应当把语言放进路由:
/zh/blog/post
/en/blog/post
坑二:先写完网站,再改语言路由
网站只有三页时,把 /blog/[slug] 改成 /[locale]/blog/[slug] 看起来不难。实际改动会扩散到导航、重定向、动态路由、metadata、sitemap、内容目录和内部链接。
我最后不得不逐层迁移:
如果项目未来大概率会支持多语言,语言 URL 应在第一天决定。
坑三:以为独立 URL 就等于 SEO 完成
有了 /zh 和 /en 只是第一步。搜索引擎还需要一致的信号:
- 当前页面的 canonical 指向自己
- 对应语言页通过 hreflang 互相声明
- title、description、正文与页面语言一致
- sitemap 收录所有可索引语言 URL
- 语言切换链接可以被正常访问
还要注意:两个语言页如果并不互为翻译,就不应该为了“完整”而强行关联。
坑四:语言切换总是跳回首页
早期切换器只会把用户从任何页面送到 /en 或 /zh。用户在读文章时切换语言,却突然回到首页,体验非常割裂。
更合理的方式是保留当前 pathname,只替换 locale:
/zh/blog/nextjs-intl-i18n
↓
/en/blog/nextjs-intl-i18n
如果目标语言没有对应内容,则应明确回退到博客列表或显示提示,而不是制造一个 404 链接。
坑五:照搬旧版或 Pages Router 示例
网上不少代码仍在使用旧路由体系,例如给普通 next/link 传 locale,或在嵌套 layout 里重复输出 <html>。代码可能看起来合理,却不适用于当前 App Router。
我的判断原则变成了:
- 先确认示例针对 App Router
- 核对 Next.js 与 next-intl 的版本
- 优先查官方文档中的当前 API
- 在无缓存的直接访问、刷新和构建环境中测试
为什么最后选择 next-intl
路由就是语言状态
locale 来自 URL,不需要在多个组件之间同步一份全局语言 state。
同时适配服务端与客户端组件
正文可以在服务端完成翻译,交互组件再使用客户端 Hook,不必为了国际化把整页变成 Client Component。
导航规则可以集中管理
通过 routing 与 navigation 封装,Link、redirect、pathname 和语言切换使用同一套 locale 规则,减少字符串拼接。
便于补全 SEO 信号
next-intl 不会自动让排名变好,但稳定的语言路由让 canonical、hreflang 和 sitemap 有了可靠基础。
重构后我会检查什么
- 直接打开任意
/zh、/en深层链接是否正常 - 刷新后语言是否保持
- 不合法 locale 是否正确 404
- 切换语言是否保留当前页面
- metadata 是否与当前正文语言一致
- canonical、hreflang 与 sitemap 是否互相一致
- 缺少翻译或对应文章时是否有明确处理
总结
这次重构让我真正理解了一句话:国际化首先是信息架构问题,然后才是翻译问题。
next-intl 解决了很多实现细节,但最重要的工作仍然是提前设计语言 URL、内容对应关系和索引策略。只要这三件事清楚,后面的翻译和组件开发反而会简单得多。
遇到问题时,我会按什么顺序排查?
| 表现 | 先检查什么 | 验证方式 |
|---|---|---|
| 切换后刷新又变回原语言 | locale 是否只存在 React state | 复制当前 URL,在新窗口直接打开 |
| 文章切换语言后回首页 | 切换器是否丢弃 pathname | 在文章详情页切换,而不是只测首页 |
| 页面出现翻译 key | 消息文件、命名空间、Provider | 核对同一 key 在两种语言中是否存在 |
| 两种语言 canonical 相同 | 是否继承了父布局的首页元数据 | 检查每篇文章最终 HTML 的 canonical |
| 链接正常但没有收录 | 响应码、robots、canonical 和内容 | 用 GSC URL 检查查看抓取与索引状态 |
前四项属于实现排查;最后一项不能靠“装好 next-intl”解决,也不能仅凭没有收录就断定是路由错误。
官方参考与下一步
- next-intl 路由设置:核对当前版本的文件结构与 API。
- Google 多语言网站指南:理解语言 URL 与抓取的关系。
- 本站的完整配置教程:按步骤实现 Next.js 15 与 next-intl 4。
常见问题
- 只用 React state 切换语言有什么问题?
- 页面虽然能切换文案,但 URL 不变,刷新与分享难以保留语言,搜索引擎也无法稳定识别不同语言版本。
- Next.js 国际化最先应该设计什么?
- 应先确定语言 URL、内容对应关系和默认语言策略,再选择翻译工具。翻译文件反而不是最难的部分。
- next-intl 能自动解决所有多语言 SEO 问题吗?
- 不能。它能帮助建立语言路由,但 canonical、hreflang、sitemap、元数据和内容质量仍需要正确配置。