Next.js(ページルーター)v16で代替言語バージョンをリンクする方法

検索エンジン向けに言語の代替バージョンをリンクする

問題

ウェブサイトが複数の言語で同じコンテンツを提供する場合、検索エンジンはそれらの関係を理解せずに各バージョンの別々のURLに遭遇します。フランス語ユーザーが検索すると、フランス語版が存在するにもかかわらず、英語版の方が上位にランク付けされる可能性があります。同様に、英語ページとそのフランス語訳は、連携した代替版ではなく、競合する重複として扱われる可能性があります。これらの言語バージョンを接続する明示的な信号がなければ、検索エンジンはユーザーの言語設定に基づいて最適なバージョンを確実に提供することができず、ランキング権限の断片化と不適切なユーザーエクスペリエンスにつながります。

解決策

各ページのheadセクションにhreflang属性を持つlink要素を追加し、ページ自体を含むすべての言語バージョンをリストアップします。各ページバリアントには、利用可能なすべての言語バージョンを参照する同一のリンクセットを含める必要があります。この双方向リンキングにより、検索エンジンはページを重複ではなく翻訳として認識し、ブラウザの設定や検索コンテキストに基づいて正しい言語バージョンをユーザーに提供できるようになります。

ステップ

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>
  );
}

このコンポーネントはルーターから利用可能なロケールを取得し、すべてのページに対して動的にlink要素を生成します。

2. 翻訳がある各ページにコンポーネントを追加する

複数の言語で存在する各ページコンポーネントにAlternateLinksコンポーネントを含めます。

import AlternateLinks from "@/components/AlternateLinks";

export default function AboutPage() {
  return (
    <>
      <AlternateLinks />
      <main>
        <h1>About Us</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リンクは、言語設定が一致しないユーザーをデフォルトロケールに誘導します。