사용자의 선호 언어 감지

신규 방문자를 가장 적합한 언어로 리디렉션

문제

사용자가 애플리케이션의 루트(예: /)를 처음 방문하면 영어와 같은 기본 언어가 표시됩니다. 이는 다른 언어를 사용하는 사용자에게 즉각적인 불편을 초래하며, 브라우저가 이미 선호 언어를 전달하고 있음에도 불구하고 수동으로 언어 전환기를 찾아야 합니다.

해결 방법

미들웨어를 사용하여 루트 경로(/)에 대한 요청을 가로챕니다. 사용자의 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';

// Helper function to find the best language match
function getBestLocale(acceptLangHeader: string | null) {
  if (!acceptLangHeader) {
    return defaultLocale;
  }

  // Use the parser to find the best supported language
  const bestMatch = parser.pick(locales, acceptLangHeader, {
    loose: true,
  });

  return bestMatch || defaultLocale;
}

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

  // 1. Check if the request is for the root path
  if (pathname === '/') {
    // Get the user's preferred language
    const acceptLang = request.headers.get('Accept-Language');
    const bestLocale = getBestLocale(acceptLang);

    // Redirect to the best-matched language path
    request.nextUrl.pathname = `/${bestLocale}`;
    return NextResponse.redirect(request.nextUrl);
  }

  // 2. For all other paths, continue as normal
  return NextResponse.next();
}

export const config = {
  matcher: [
    // Skip all paths that start with:
    // - api (API routes)
    // - _next/static (static files)
    // - _next/image (image optimization files)
    // - favicon.ico (favicon file)
    '/((?!api|_next/static|_next/image|favicon.ico).*)',
  ],
};

이 코드는 루트 경로(/)에 대해서만 로직을 실행합니다. 사용자가 /를 방문하면 Accept-Language 헤더를 확인하고 가장 적합한 항목(예: es)을 찾아 /es로 리디렉션합니다. /en/about와 같은 다른 모든 요청은 이 로직에서 무시되고 통과됩니다.