如何在 Next.js(页面路由)v16 中链接替代语言版本
为搜索引擎链接语言替代版本
问题
当一个网站以多种语言提供相同内容时,搜索引擎会为每个版本遇到单独的 URL,而无法理解它们之间的关系。例如,一个法语用户在搜索时可能会看到英文版本的排名高于法语版本,即使两者都存在。同样,英文页面及其法语翻译可能会被视为竞争的重复内容,而不是协调的替代版本。如果没有明确的信号将这些语言版本连接起来,搜索引擎无法根据用户的语言偏好自信地提供最合适的版本,从而导致排名权威的分散和糟糕的用户体验。
解决方案
在每个页面的 head 部分添加带有 hreflang 属性的链接元素,列出所有语言版本,包括页面本身。每个页面变体必须包含一组相同的链接,引用所有可用的语言版本。这种双向链接确保搜索引擎将这些页面识别为翻译版本而非重复内容,从而根据浏览器偏好和搜索上下文为用户提供正确的语言版本。
步骤
1. 创建一个组件以生成备用语言链接
从 next/head 导入 Head 组件以修改页面元数据。通过 useRouter 钩子访问语言环境信息,以构建所有可用语言版本的链接。
import Head from "next/head";
import { useRouter } from "next/router";
interface AlternateLinksProps {
path?: string;
}
export default function AlternateLinks({ path }: AlternateLinksProps) {
const router = useRouter();
const { locales, locale: currentLocale, asPath } = router;
const canonicalPath = path || asPath;
if (!locales) {
return null;
}
return (
<Head>
{locales.map((locale) => (
<link
key={locale}
rel="alternate"
hrefLang={locale}
href={`${process.env.NEXT_PUBLIC_SITE_URL}/${locale}${canonicalPath}`}
/>
))}
</Head>
);
}
该组件从路由器中遍历可用的语言环境,并为所有页面动态生成链接元素。
2. 将组件添加到有翻译的页面
在每个存在多种语言版本的页面组件中包含 AlternateLinks 组件。
import AlternateLinks from "@/components/AlternateLinks";
export default function AboutPage() {
return (
<>
<AlternateLinks />
<main>
<h1>关于我们</h1>
</main>
</>
);
}
该组件确保每个页面都包含完整的备用链接集,满足所有变体相互引用的要求。
3. 为当前语言环境包含一个自引用链接
每个页面必须包含一个指示其自身语言的自引用 hreflang 标签。该组件通过遍历所有语言环境(包括当前语言环境)已经处理了这一点。
export default function AlternateLinks({ path }: AlternateLinksProps) {
const router = useRouter();
const { locales, asPath } = router;
const canonicalPath = path || asPath;
if (!locales) {
return null;
}
return (
<Head>
{locales.map((locale) => (
<link
key={locale}
rel="alternate"
hrefLang={locale}
href={`${process.env.NEXT_PUBLIC_SITE_URL}/${locale}${canonicalPath}`}
/>
))}
</Head>
);
}
现在每个页面都包含指向自身的 hreflang 标签以及指向其他版本的标签。
4. 添加一个 x-default 回退链接
添加一个 x-default 链接,以指定当用户的语言不可用时应显示的版本。
export default function AlternateLinks({ path }: AlternateLinksProps) {
const router = useRouter();
const { locales, defaultLocale, asPath } = router;
const canonicalPath = path || asPath;
if (!locales || !defaultLocale) {
return null;
}
return (
<Head>
{locales.map((locale) => (
<link
key={locale}
rel="alternate"
hrefLang={locale}
href={`${process.env.NEXT_PUBLIC_SITE_URL}/${locale}${canonicalPath}`}
/>
))}
<link
rel="alternate"
hrefLang="x-default"
href={`${process.env.NEXT_PUBLIC_SITE_URL}/${defaultLocale}${canonicalPath}`}
/>
</Head>
);
}
x-default 链接将未匹配语言偏好的用户引导到默认语言环境。