Next.js(Pages Router)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リンクは、言語設定が一致しないユーザーをデフォルトロケールに誘導します。