React Router v7에서 사용자 언어 기본 설정을 감지하는 방법

브라우저 기본 설정에 따른 자동 리디렉션

문제

모든 브라우저는 각 HTTP 요청과 함께 Accept-Language 헤더를 전송하여 사용자가 선호하는 언어를 우선순위대로 나타냅니다. 이 헤더에는 사용자가 보고자 하는 언어에 대한 중요한 정보가 포함되어 있지만, 대부분의 애플리케이션은 이를 완전히 무시합니다. 대신 모든 방문자에게 기본 언어(일반적으로 영어)를 표시하여, 브라우저가 이미 사용자의 기본 설정을 전달했음에도 불구하고 사용자가 수동으로 언어 전환기를 찾도록 강요합니다. 이는 불필요한 마찰과 좋지 않은 첫인상을 만들며, 특히 국제 사용자에게 더욱 그렇습니다.

해결 방법

루트 경로에 대한 로더를 생성하여 들어오는 요청에서 Accept-Language 헤더를 읽습니다. 헤더를 파싱하여 사용자가 선호하는 언어와 품질 값을 추출합니다. 선호 언어를 애플리케이션이 지원하는 로케일과 비교합니다. 일치하는 항목이 발견되면 해당 로케일의 경로로 사용자를 리디렉션합니다. 지원되는 언어가 일치하지 않으면 기본 로케일로 리디렉션합니다. 이를 통해 사용자가 브라우저에 이미 구성한 기본 설정을 기반으로 자동으로 사이트의 현지화된 버전에 도달하도록 보장합니다.

단계

1. Accept-Language 헤더를 파싱하는 라이브러리 설치

Accept-Language 헤더는 신중한 파싱이 필요한 품질 값을 포함한 특정 형식을 가지고 있습니다. 이를 올바르게 처리하기 위해 전용 라이브러리를 사용하세요.

npm install accept-language-parser

이 라이브러리는 헤더 문자열을 정렬된 언어 기본 설정 목록으로 파싱하며, HTTP 사양에 따라 품질 값과 엣지 케이스를 처리합니다.

2. 지원되는 로케일 정의

애플리케이션이 지원하는 로케일을 나열하고 기본 폴백을 지정하는 헬퍼 파일을 생성합니다.

export const supportedLocales = ["en", "fr", "de", "es", "ja"] as const;

export const defaultLocale = "en";

export type Locale = (typeof supportedLocales)[number];

이는 애플리케이션이 제공할 수 있는 언어에 대한 단일 정보 소스를 제공하며 코드베이스 전체에서 타입 안전성을 보장합니다.

3. 로케일 감지 헬퍼 생성

Accept-Language 헤더 값을 받아 가장 일치하는 지원 로케일을 반환하는 함수를 구축합니다.

import parser from "accept-language-parser";
import { supportedLocales, defaultLocale, type Locale } from "./locales";

export function detectLocale(acceptLanguageHeader: string | null): Locale {
  if (!acceptLanguageHeader) {
    return defaultLocale;
  }

  const languages = parser.parse(acceptLanguageHeader);

  for (const lang of languages) {
    const code = lang.code.toLowerCase();
    if (supportedLocales.includes(code as Locale)) {
      return code as Locale;
    }
  }

  return defaultLocale;
}

이 함수는 헤더를 파싱하고, 품질 순서대로 사용자의 언어 기본 설정을 반복하며, 지원 로케일과 일치하는 첫 번째 항목을 반환하거나 기본값으로 폴백합니다.

4. 루트 인덱스 라우트 구성

루트 경로에 대한 요청을 처리할 인덱스 라우트를 라우트 구성에 추가합니다.

import { type RouteConfig, index, route } from "@react-router/dev/routes";

export default [
  index("routes/index.tsx"),
  route(":locale", "routes/locale-root.tsx", []),
] satisfies RouteConfig;

인덱스 라우트는 다른 라우트가 매칭되기 전에 루트 경로 요청을 가로채어 언어 감지 및 리디렉션을 수행할 수 있도록 합니다.

5. 언어 감지를 포함한 인덱스 라우트 로더 구현

Accept-Language 헤더를 읽고 적절한 로케일 경로로 리디렉션하는 인덱스 라우트 모듈을 생성합니다.

import { redirect } from "react-router";
import type { Route } from "./+types/index";
import { detectLocale } from "~/utils/detect-locale";

export async function loader({ request }: Route.LoaderArgs) {
  const acceptLanguage = request.headers.get("Accept-Language");
  const locale = detectLocale(acceptLanguage);
  return redirect(`/${locale}`);
}

사용자가 루트 경로를 방문하면 이 로더는 요청에서 Accept-Language 헤더를 추출하고, 최적의 로케일을 결정하며, 해당 로케일의 루트 경로로 리디렉션하여 첫 페이지 로드부터 선호하는 언어로 콘텐츠를 볼 수 있도록 합니다.