React Router v7でページメタデータを翻訳する方法
検索とソーシャルメディア向けのメタデータを翻訳する
問題
ページのメタデータ(タイトルや説明文)は、ページ自体の外部、つまりブラウザのタブ、ブックマーク、検索結果、ソーシャルメディアのプレビューなどに表示されます。このメタデータがページの言語と一致しない場合、不自然な不一致が生じます。スペイン語のページに英語のタイトルがあると、ユーザーはコンテンツを見る前に混乱します。検索エンジンはこの不一致を、ページのローカライズが不十分または品質が低いという信号として解釈し、言語固有の検索結果でのランキングが下がる可能性があります。ユーザーは、自分の言語ではないと思い込み、ページが読み込まれる前に離脱してしまうかもしれません。
解決策
ルートモジュールからmeta関数をエクスポートして、ページのメタデータを現在の言語に合わせて翻訳します。react-intlのformatMessage APIをメッセージディスクリプタと共に使用して、タイトルと説明文の文字列を翻訳し、メタデータがページコンテンツと同じ翻訳リソースを使用するようにします。これにより、ブラウザのタブ、検索結果、ページ自体に表示される内容の一貫性が保たれます。
手順
1. コンポーネント外でintlにアクセスするためのヘルパーを作成する
intlオブジェクトはformatMessageを提供し、コンポーネント内ではuseIntlフックを通じて、または非Reactの環境ではcreateIntlを使って直接アクセスできます。meta関数はReactコンポーネントツリーの外部で実行されるため、メッセージからintlインスタンスを構築するヘルパーを作成します。
import { createIntl, createIntlCache } from "react-intl";
const cache = createIntlCache();
export function createIntlForLocale(
locale: string,
messages: Record<string, string>,
) {
return createIntl(
{
locale,
messages,
},
cache,
);
}
このヘルパーは、Reactコンポーネントだけでなく、任意の関数でメッセージをフォーマットできるintlインスタンスを作成します。
2. 親ルートローダーでメッセージを読み込む
ルートローダーはコンポーネントがloaderDataプロップを介してアクセスするデータを返します。翻訳メッセージを親ルートで読み込むことで、子ルートでも利用できるようになります。
import type { Route } from "./+types/root";
export async function loader({ request }: Route.LoaderArgs) {
const url = new URL(request.url);
const locale = url.pathname.split("/")[1] || "en";
const messages = await import(`../translations/${locale}.json`);
return {
locale,
messages: messages.default,
};
}
メタ関数はマッチしたすべてのルートからローダーデータを含むmatchesパラメータを受け取り、親ローダーデータを子ルートのメタ関数からアクセスできるようにします。
3. メタデータを翻訳するメタ関数をエクスポートする
ルートモジュールからメタ記述子オブジェクトの配列を返すメタ関数をエクスポートします。matchesから親ローダーデータにアクセスし、intlヘルパーを使用して文字列を翻訳します。
import type { Route } from "./+types/product";
import { createIntlForLocale } from "~/utils/intl";
export function meta({ matches }: Route.MetaArgs) {
const rootMatch = matches.find((match) => match.id === "root");
const { locale, messages } = rootMatch?.data || {
locale: "en",
messages: {},
};
const intl = createIntlForLocale(locale, messages);
return [
{
title: intl.formatMessage({
id: "product.meta.title",
defaultMessage: "Product Details",
}),
},
{
name: "description",
content: intl.formatMessage({
id: "product.meta.description",
defaultMessage: "View detailed information about this product",
}),
},
];
}
formatMessage関数はidとdefaultMessageを持つメッセージ記述子を受け取り、現在のロケールに対応する翻訳された文字列を返します。
4. 翻訳されたメタデータ文字列をメッセージファイルに追加する
各ロケールのメッセージファイルにメタデータ翻訳キーを追加して、formatMessageが見つけられるようにします。
{
"product.meta.title": "Détails du produit",
"product.meta.description": "Voir les informations détaillées sur ce produit"
}
ユーザーがこのルートにナビゲートすると、ルートレイアウトのMetaコンポーネントがルートメタエクスポートによって作成されたすべてのメタタグをレンダリングし、ページの言語に一致する翻訳されたタイトルと説明を表示します。