React Router v7で多言語サイトマップを作成する方法

スケールに対応した言語別サイトマップの整理

課題

サイトマップは、検索エンジンがサイト上のすべてのページを発見してクロールするのに役立ちます。言語ごとに数百または数千のページを持つ多言語サイトでは、すぐに巨大なサイトマップが生成される可能性があります。すべての言語のすべてのURLを記載した単一ファイルは扱いにくくなり、50,000URLまたは50MBのサイズ制限を超える可能性があり、メンテナンスが困難になります。1つの言語の構造を更新する場合、ファイル全体を再生成して再検証する必要があります。このアプローチは、サイトが成長するにつれてスケールしません。

解決策

サイトマップを階層構造に分割し、個別の言語固有のサイトマップを指すトップレベルのサイトマップインデックスを作成します。各言語は、その言語のURLのみを含む独自のサイトマップファイルを取得します。インデックスファイルはディレクトリとして機能し、各言語サイトマップの場所をリストします。これにより、個々のファイルが管理しやすくなり、各言語を独立して更新でき、新しい言語やページを追加する際にも適切にスケールします。検索エンジンは最初にインデックスをクロールし、次に各言語サイトマップへのリンクをたどります。

手順

1. サイトマップインデックスルートを作成する

すべての言語固有のサイトマップをリストするXMLレスポンスを返すリソースルートを作成します。

import type { Route } from "./+types/sitemap";

const LOCALES = ["en", "es", "fr", "de"];

export function loader({ request }: Route.LoaderArgs) {
const { origin } = new URL(request.url);

const sitemapIndex = `<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${LOCALES.map(locale => `  <sitemap>
  <loc>${origin}/sitemap-${locale}.xml</loc>
</sitemap>`).join("
")}
</sitemapindex>`;

return new Response(sitemapIndex, {
  headers: {
    "Content-Type": "application/xml",
  },
});
}

このルートは、XMLレスポンスを返すことでAPIエンドポイントとして機能します。インデックスは言語ごとに1つのサイトマップをリストし、LOCALES配列を更新することで言語の追加または削除が簡単に行えます。

2. 言語固有のサイトマップルートを作成する

動的セグメントを持つリソースルートを定義して、各言語の個別のサイトマップを生成します。

import type { Route } from "./+types/sitemap.$locale";

export async function loader({ params }: Route.LoaderArgs) {
const locale = params.locale;
const urls = await getUrlsForLocale(locale);

const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls.map(url => `  <url>
  <loc>${url}</loc>
</url>`).join("
")}
</urlset>`;

return new Response(sitemap, {
  headers: {
    "Content-Type": "application/xml",
  },
});
}

async function getUrlsForLocale(locale: string): Promise<string[]> {
return [];
}

ルートパスの動的セグメントが解析され、params.localeとして提供されます。各言語のサイトマップには、その特定のロケールのURLのみが含まれます。

3. 各言語のページを取得する

データソースから指定されたロケールのすべてのページを取得するヘルパー関数を実装します。

async function getUrlsForLocale(locale: string): Promise<string[]> {
  const pages = await db.pages.findMany({
    where: { locale, published: true },
    select: { slug: true },
  });

  return pages.map((page) => `https://example.com/${locale}/${page.slug}`);
}

この関数は、データベースまたはコンテンツソースに対して、要求された言語で公開されているページをクエリし、完全なURLを構築します。アプリケーションに合わせてクエリとURL構造を調整してください。

4. サイトマップルートを登録する

ルート設定ファイルにサイトマップルートを追加します。

import { type RouteConfig, route } from "@react-router/dev/routes";

export default [
  route("sitemap.xml", "./routes/sitemap.tsx"),
  route("sitemap-:locale.xml", "./routes/sitemap.$locale.tsx"),
] satisfies RouteConfig;

各ルートには、マッチするURLパターンとルートモジュールへのファイルパスがあります。インデックスルートは/sitemap.xmlで応答し、言語ルートは/sitemap-en.xml/sitemap-es.xmlなどで応答します。

5. robots.txtにサイトマップインデックスを追加する

publicディレクトリのルートにあるrobots.txtファイルで、検索エンジンにサイトマップインデックスを指定します。

User-agent: *
Allow: /

Sitemap: https://example.com/sitemap.xml

各サイトマップをリストアップしたサイトマップインデックスにより、検索エンジンは単一のエントリーポイントからすべての言語固有のサイトマップを検出できます。検索エンジンはインデックスをクロールし、各言語のサイトマップへのリンクを自動的にたどります。