如何翻译 Next.js(页面路由)v16 中的页面元数据

为搜索和社交翻译元数据

问题

页面元数据(标题和描述)位于页面内容之外。它显示在浏览器标签、书签、搜索引擎结果和社交媒体预览中。当元数据与页面的语言不匹配时,用户在看到内容之前就会遇到令人不适的一致性问题。例如,一个西班牙语页面却有一个英文标题,这会让访问者感到困惑,并传递出糟糕的本地化质量信号。

搜索引擎将语言不匹配视为低质量本地化的标志,这可能会降低在特定语言搜索结果中的排名。社交媒体平台在链接预览中显示错误的语言,降低了国际受众的参与度。在所有接触点(包括元数据)中保持一致的翻译,对于提供专业的多语言体验至关重要。

解决方案

使用与页面内容相同的翻译资源翻译页面元数据。使用 react-intl 的 useIntl 钩子访问翻译后的字符串,并将它们放置在页面的 <Head> 组件中。这确保了标题和描述在浏览器标签、搜索结果和社交媒体预览中与当前语言环境一致。

通过从与可见内容相同的消息目录中获取元数据,可以保持一致性并避免重复翻译工作。此方法适用于静态页面和元数据依赖于页面特定数据的动态路由。

步骤

1. 将元数据消息添加到翻译文件中

在翻译目录中为页面标题和描述定义消息描述符,使用与其他翻译内容相同的结构。

{
"home.title": "欢迎光临我们的商店",
"home.description": "发现超值的优质商品",
"products.title": "我们的产品",
"products.description": "浏览我们完整的商品目录"
}

每个需要翻译元数据的页面都应有对应的标题和描述的消息 ID。

2. 创建一个翻译后的元数据组件

使用 useIntl 钩子访问 formatMessage 函数,然后在 Head 组件中渲染翻译后的字符串。

import Head from "next/head";
import { useIntl } from "react-intl";

export default function HomePage() {
  const intl = useIntl();

  return (
    <>
      <Head>
        <title>{intl.formatMessage({ id: "home.title" })}</title>
        <meta
          name="description"
          content={intl.formatMessage({ id: "home.description" })}
        />
      </Head>
      <main>
        <h1>{intl.formatMessage({ id: "home.title" })}</h1>
      </main>
    </>
  );
}

Head 组件是 Next.js 内置的一个 React 组件,用于修改页面的 <head> 部分。formatMessage 函数会根据当前语言环境返回翻译后的字符串。

3. 添加 Open Graph 和社交元数据

扩展模式以包含用于社交媒体预览的 Open Graph 和 Twitter Card 元数据。

import Head from "next/head";
import { useIntl } from "react-intl";

export default function ProductsPage() {
  const intl = useIntl();
  const title = intl.formatMessage({ id: "products.title" });
  const description = intl.formatMessage({ id: "products.description" });

  return (
    <>
      <Head>
        <title>{title}</title>
        <meta name="description" content={description} />
        <meta property="og:title" content={title} />
        <meta property="og:description" content={description} />
        <meta name="twitter:title" content={title} />
        <meta name="twitter:description" content={description} />
      </Head>
      <main>
        <h1>{title}</h1>
      </main>
    </>
  );
}

将格式化后的消息存储在变量中可以避免多次调用 formatMessage 来获取相同的翻译,并使 JSX 更加简洁。

4. 处理参数化页面的动态元数据

对于具有动态路由的页面,将路由参数与翻译后的字符串结合起来,创建上下文相关的元数据。

import Head from "next/head";
import { useIntl } from "react-intl";
import { useRouter } from "next/router";

export default function ProductDetailPage() {
  const intl = useIntl();
  const router = useRouter();
  const { id } = router.query;

  const title = intl.formatMessage(
    { id: "product.detail.title" },
    { productId: id },
  );

  return (
    <>
      <Head>
        <title>{title}</title>
      </Head>
      <main>
        <h1>{title}</h1>
      </main>
    </>
  );
}

消息描述符支持变量插值,允许您将动态值(如产品 ID 或名称)注入到翻译后的元数据字符串中。对应的消息可能是 "Product {productId} - Our Store"