사용자의 언어 선택 유지하기

선택 사항을 기억하기 위해 쿠키 사용하기

문제

사용자가 사이트에서 수동으로 '프랑스어'를 선택합니다. 브라우저를 닫고 나중에 사이트의 메인 주소(예: example.com)를 입력하면, 애플리케이션은 기본값(예: 영어) 또는 자동 감지된 언어로 되돌아갑니다. 이렇게 선택 내용을 기억하지 못하면 사용자는 새 세션을 시작할 때마다 언어 전환기를 찾아 언어를 다시 선택해야 합니다.

해결책

사용자가 언어를 선택할 때 해당 선택을 쿠키에 저장합니다. 미들웨어에서 사용자가 루트 경로(/)를 방문할 때, Accept-Language 헤더를 확인하기 전에 이 쿠키를 확인합니다. 유효한 쿠키가 발견되면 사용자를 선택한 언어의 루트(예: /fr)로 리디렉션하여 브라우저 기본값을 무시합니다.

단계

1. 언어 구성 정의

지원되는 언어, 기본 언어 및 사용자 환경설정을 저장하는 데 사용할 쿠키 이름을 저장하는 중앙 구성 파일을 생성합니다.

// i18n.config.ts

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

2. 언어 파서 설치

쿠키가 설정되지 않은 경우 폴백으로 사용될 Accept-Language 헤더용 파서가 여전히 필요합니다.

npm install accept-language-parser

3. 미들웨어 생성

프로젝트 루트에 middleware.ts 파일을 생성합니다. 이 미들웨어는 먼저 NEXT_LOCALE 쿠키를 확인합니다. 쿠키가 없으면 Accept-Language 헤더를 확인하는 폴백을 사용합니다. 이 로직은 루트 경로(/)에 대한 요청에만 적용됩니다.

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

function getPreferredLocale(request: NextRequest) {
  // 1. 쿠키 확인
  const cookie = request.cookies.get(localeCookieName);
  if (cookie) {
    const locale = cookie.value;
    if (locales.includes(locale)) {
      return locale;
    }
  }

  // 2. Accept-Language 헤더 확인
  const acceptLang = request.headers.get('Accept-Language');
  if (acceptLang) {
    const bestMatch = parser.pick(locales, acceptLang, {
      loose: true,
    });
    if (bestMatch) {
      return bestMatch;
    }
  }

  // 3. 기본값 반환
  return defaultLocale;
}

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

  // 1. 요청이 루트 경로인지 확인
  if (pathname === '/') {
    // 사용자의 선호 언어 가져오기(쿠키 또는 헤더에서)
    const bestLocale = getPreferredLocale(request);

    // 가장 적합한 언어 경로로 리디렉션
    request.nextUrl.pathname = `/${bestLocale}`;
    return NextResponse.redirect(request.nextUrl);
  }

  // 2. 다른 모든 경로에 대해 정상적으로 계속 진행
  return NextResponse.next();
}

export const config = {
  matcher: [
    // 지금은 루트 경로에서만 실행하려고 합니다
    '/',
    // 비루트 경로도 일치시켜 통과시켜야 합니다
    '/((?!api|_next/static|_next/image|favicon.ico).*)',
  ],
};

이 미들웨어의 로직은 이제 사용자가 사이트 루트를 방문할 때 사용자의 명시적 선택(쿠키)을 암시적 선호도(브라우저 헤더)보다 우선시합니다.