如何在 Next.js(Pages Router)v16 中实现基于语言环境的路由
使用语言环境片段配置路由
问题
在构建多语言应用时,有一个核心决策会影响后续所有实现:应用如何确定要显示哪种语言?如果没有明确的机制,URL /about 就会变得模糊——它可能对应任何语言的内容。用户无法分享特定语言版本的链接,搜索引擎也难以判断每个版本对应的受众。这种不明确会影响用户体验和 SEO,因为无法清晰地标识或收藏某种语言的内容。
解决方案
通过配置 Next.js 内置的 i18n 路由支持,将语言标识符直接放入 URL 路径。在 Next.js 配置中声明要支持的语言环境(locale)和默认语言环境。Next.js 会自动处理路由,使像 /fr/about 和 /nl-NL/about 这样的路径可用,而默认语言环境则没有前缀。这样每个路径都唯一对应某种语言,消除了用户和搜索引擎的歧义。
步骤
1. 在 next.config.js 中添加 i18n 配置
在 next.config.js 文件中添加 i18n 配置,声明应用支持的语言环境。
module.exports = {
i18n: {
locales: ["en-US", "fr", "nl-NL"],
defaultLocale: "en-US",
},
};
Locale 是 UTS 语言环境标识符,一种标准化格式,通常由语言、地区和脚本组成,并用连字符分隔。defaultLocale 用于访问没有语言前缀的路径时。
2. 在页面中获取语言环境信息
在页面组件中使用 useRouter() hook 获取语言环境信息。
import { useRouter } from "next/router";
export default function AboutPage() {
const router = useRouter();
const { locale, locales, defaultLocale } = router;
return (
<div>
<h1>About Us</h1>
<p>Current locale: {locale}</p>
</div>
);
}
locale 属性包含当前激活的 locale,locales 包含所有已配置的 locale,defaultLocale 包含已配置的默认 locale。
3. 在数据获取函数中访问 locale
在使用 getStaticProps 或 getServerSideProps 进行页面预渲染时,locale 信息会通过 context 提供。
import { GetStaticProps } from "next";
export const getStaticProps: GetStaticProps = async (context) => {
const { locale } = context;
const messages = await import(`../messages/${locale}.json`);
return {
props: {
messages: messages.default,
},
};
};
这样可以根据激活的 locale 在构建时或请求时加载特定于 locale 的数据。
4. locale 之间的链接
使用 next/link 并传递 locale 属性,可以跳转到其他 locale。
import Link from "next/link";
export default function LanguageSwitcher() {
return (
<nav>
<Link href="/about" locale="en-US">
English
</Link>
<Link href="/about" locale="fr">
Français
</Link>
<Link href="/about" locale="nl-NL">
Nederlands
</Link>
</nav>
);
}
如果未提供 locale 属性,则在客户端跳转时会使用当前激活的 locale。locale 属性允许用户在保持同一逻辑页面的同时切换语言。
5. 为所有 locale 生成静态路径
在使用 getStaticPaths 时,已配置的 locales 会通过 context 参数下的 locales 提供,已配置的 defaultLocale 通过 defaultLocale 提供。
import { GetStaticPaths } from "next";
export const getStaticPaths: GetStaticPaths = async (context) => {
const { locales } = context;
const paths = locales.flatMap((locale) => [
{ params: { slug: "getting-started" }, locale },
{ params: { slug: "advanced" }, locale },
]);
return {
paths,
fallback: false,
};
};
这样可以确保所有 locale 版本的动态页面都在构建时预渲染。