ユーザーの優先言語を検出する

新規訪問者を最も適した言語にリダイレクトする

問題

ユーザーがアプリケーションのルート(例:/)に初めてアクセスすると、英語などのデフォルト言語が表示されます。これにより、他の言語を話すユーザーにとって即座に摩擦が生じ、ブラウザが既に彼らの言語設定を伝えているにもかかわらず、手動で言語切り替えを探す必要があります。

解決策

ミドルウェアを使用してルートパス(/)へのリクエストを傍受します。ユーザーのAccept-Language HTTPヘッダーを確認して、彼らの優先言語を見つけます。その言語がアプリケーションでサポートされている場合、ユーザーをその言語のルート(例:/fr)にリダイレクトします。サポートされていない場合は、デフォルト言語(例:/en)にリダイレクトします。

手順

1. 言語パーサーをインストールする

Accept-Languageヘッダーは複雑な場合があります(例:fr-CH, fr;q=0.9, en;q=0.8)。小さなライブラリを使用すると、このヘッダーを解析し、サポートしている言語リストから最適なマッチを見つけることができます。

ターミナルで次のコマンドを実行します:

npm install accept-language-parser

2. 言語とデフォルトを定義する

サポートしている言語のリストを保存し、デフォルトを定義する中央設定ファイルを作成します。このデフォルトは、ユーザーのブラウザ設定がサポートしている言語と一致しない場合に使用されます。

// i18n.config.ts

export const locales = ['en', 'es', 'fr'];
export const defaultLocale = 'en';

3. ミドルウェアを作成する

プロジェクトのルートにmiddleware.tsファイルを作成します。このファイルは受信リクエストで実行され、パスとヘッダーを確認できるようにします。

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import parser from 'accept-language-parser';
import { locales, defaultLocale } from './i18n.config';

// 最適な言語マッチを見つけるヘルパー関数
function getBestLocale(acceptLangHeader: string | null) {
  if (!acceptLangHeader) {
    return defaultLocale;
  }

  // パーサーを使用して最適なサポート言語を見つける
  const bestMatch = parser.pick(locales, acceptLangHeader, {
    loose: true,
  });

  return bestMatch || defaultLocale;
}

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  // 1. リクエストがルートパスかどうかを確認
  if (pathname === '/') {
    // ユーザーの優先言語を取得
    const acceptLang = request.headers.get('Accept-Language');
    const bestLocale = getBestLocale(acceptLang);

    // 最適な言語パスにリダイレクト
    request.nextUrl.pathname = `/${bestLocale}`;
    return NextResponse.redirect(request.nextUrl);
  }

  // 2. その他のパスについては通常通り続行
  return NextResponse.next();
}

export const config = {
  matcher: [
    // 以下で始まるすべてのパスをスキップ:
    // - api (APIルート)
    // - _next/static (静的ファイル)
    // - _next/image (画像最適化ファイル)
    // - favicon.ico (ファビコンファイル)
    '/((?!api|_next/static|_next/image|favicon.ico).*)',
  ],
};

このコードはルートパス(/)に対してのみロジックを実行します。ユーザーが/にアクセスすると、Accept-Languageヘッダーを確認し、最適なマッチ(例:es)を見つけて、/esにリダイレクトします。/en/aboutのような他のリクエストは、このロジックでは無視され、そのまま通過します。