지원되지 않는 언어 코드 처리하기

문제

애플리케이션이 URL 경로(예: /en/, /fr/)를 사용하여 언어를 결정하지만, 사용자는 /xx/about과 같은 값을 수동으로 입력할 수 있습니다. 이 값이 지원되는 언어와 일치하지 않으면 애플리케이션이 충돌하거나, 일반적인 오류를 표시하거나, 번역되지 않은 콘텐츠를 표시하여 사용자를 유효한 경험으로 안내하지 못할 수 있습니다.

해결책

모든 수신 요청을 가로채는 미들웨어를 사용합니다. 이 미들웨어는 URL의 언어 코드를 지원되는 언어의 명확한 목록과 비교하여 검증합니다. 코드가 지원되지 않는 경우, 요청이 애플리케이션 로직에 도달하기 전에 "찾을 수 없음" 페이지로 재작성됩니다.

단계

1. 지원되는 언어 정의하기

유효한 언어 코드(로케일) 목록을 저장할 중앙 구성 파일을 만듭니다. 이렇게 하면 미들웨어와 앱의 다른 부분에서 목록을 재사용할 수 있습니다.

// i18n.config.ts
export const locales = ['en', 'es', 'fr'];

2. 미들웨어 파일 생성하기

프로젝트 루트(또는 src/ 디렉토리)에 middleware.ts라는 새 파일을 생성합니다. Next.js는 이 파일을 자동으로 감지하고 요청에서 실행합니다.

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { locales } from './i18n.config';

export function middleware(request: NextRequest) {
  // 다음 단계에서 로직이 여기에 들어갑니다
}

3. 유효성 검사 로직 추가하기

middleware 함수 내에서 요청에서 pathname을 가져옵니다. 경로의 첫 번째 세그먼트(예: /en/about에서 en)를 확인하고 유효하고 지원되는 언어인지 확인해야 합니다.

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { locales } from './i18n.config';

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

  // 1. 루트 경로를 별도로 처리합니다
  // (이것은 다음 레시피에서 처리됩니다: "사용자의 선호 언어 감지").
  // 지금은 그냥 통과시킵니다.
  if (pathname === '/') {
    return NextResponse.next();
  }

  // 2. 경로에서 언어 코드 추출
  const langCode = pathname.split('/')[1];

  // 3. 언어 코드가 목록에 있는지 확인
  if (locales.includes(langCode)) {
    // 언어가 유효하면 요청된 페이지로 계속 진행
    return NextResponse.next();
  }

  // 4. 언어가 유효하지 않으면 404 페이지로 재작성
  // 이렇게 하면 브라우저 주소창에 유효하지 않은 URL이 유지됩니다
  const url = request.nextUrl.clone();
  url.pathname = `/404`; // app/404.tsx 파일이 있다고 가정
  return NextResponse.rewrite(url);
}

이 로직은 모든 요청을 확인합니다. URL이 /fr/about인 경우, langCodefr이고, locales에서 찾아지면 요청이 계속됩니다. URL이 /xx/about인 경우, langCodexx이고, 찾아지지 않으면 앱이 유효하지 않은 요청을 처리하려고 시도하지 않고 사용자에게 404 페이지가 표시됩니다.

4. 미들웨어 매처 구성하기

미들웨어를 더 효율적으로 만들기 위해, 어떤 경로에서 실행할지 지정해야 합니다. 페이지 요청에서는 실행되지만 정적 파일과 API 라우트에서는 건너뛰도록 하고 싶습니다.

middleware.ts 파일 하단에 config 객체를 추가하세요.

// middleware.ts

// ... (위에서 작성한 미들웨어 함수)

export const config = {
  matcher: [
    // 다음으로 시작하는 모든 경로 건너뛰기:
    // - api (API 라우트)
    // - _next/static (정적 파일)
    // - _next/image (이미지 최적화 파일)
    // - favicon.ico (파비콘 파일)
    '/((?!api|_next/static|_next/image|favicon.ico).*)',
  ],
};

이 정규식은 일반적으로 정적 에셋이나 API 호출을 위한 경로를 제외한 모든 경로에서 미들웨어를 실행하도록 지시합니다. 이렇게 하면 모든 이미지, 폰트 또는 데이터 요청에 불필요한 유효성 검사가 실행되는 것을 방지할 수 있습니다.