번역 로딩하기
메시지 관리를 위한 프로바이더 사용하기
문제
'Hello World'와 같은 텍스트를 애플리케이션 컴포넌트에 직접 하드코딩하면 콘텐츠와 코드가 결합됩니다. 다른 언어를 표시하려면 개발자는 컴포넌트를 복제하거나 if/else 로직을 추가해야 하므로 번역이 확장되지 않고 새로운 텍스트마다 전체 코드 변경이 필요합니다.
해결책
react-intl의 IntlProvider를 사용하여 번역을 제공합니다. 서버의 루트 레이아웃에서 번역 메시지를 로드하고, 클라이언트 측 프로바이더 컴포넌트에 전달한 다음, 다른 클라이언트 컴포넌트에서 useIntl 훅을 사용하여 소비합니다.
단계
1. react-intl 설치
먼저 프로젝트에 react-intl을 의존성으로 추가합니다.
npm install react-intl
2. 플랫 번역 파일 생성
dictionaries 폴더를 생성합니다. 내부에 각 언어별 JSON 파일을 추가합니다. react-intl은 플랫 키-값 구조에서 가장 잘 작동합니다.
// dictionaries/en.json
{
"home.title": "Home Page",
"home.welcome": "Hello, welcome to our site!",
"about.title": "About Us"
}
// dictionaries/es.json
{
"home.title": "Página de Inicio",
"home.welcome": "¡Hola, bienvenido a nuestro sitio!",
"about.title": "Sobre Nosotros"
}
3. 사전을 로드하는 함수 생성
lang 매개변수를 기반으로 서버에서 올바른 사전 파일을 로드하는 헬퍼 함수를 생성합니다.
// app/get-dictionary.ts
import 'server-only';
// 플랫 메시지 객체에 대한 타입 정의
type Messages = Record<string, string>;
const dictionaries: { [key: string]: () => Promise<Messages> } = {
en: () => import('@/dictionaries/en.json').then((module) => module.default),
es: () => import('@/dictionaries/es.json').then((module) => module.default),
// fr: () => import('@/dictionaries/fr.json').then((module) => module.default),
};
export const getDictionary = async (lang: string) => {
const load = dictionaries[lang];
if (load) {
return load();
}
// 영어로 폴백
return dictionaries.en();
};
4. 클라이언트 측 프로바이더 생성하기
IntlProvider는 React의 Context를 사용하는 클라이언트 컴포넌트입니다. 서버에서 로드된 메시지를 받을 수 있는 래퍼를 만들어야 합니다.
// app/components/IntlClientProvider.tsx
'use client';
import { IntlProvider } from 'react-intl';
type Props = {
children: React.ReactNode;
locale: string;
messages: Record<string, string>; // Flat messages object
};
export default function IntlClientProvider({
children,
locale,
messages,
}: Props) {
return (
<IntlProvider messages={messages} locale={locale} defaultLocale="en">
{children}
</IntlProvider>
);
}
5. 루트 레이아웃 업데이트하기
app/[lang]/layout.tsx를 async 컴포넌트로 수정합니다. 이 컴포넌트는 메시지를 로드하고 IntlClientProvider에 전달합니다.
// app/[lang]/layout.tsx
import { getDictionary } from '@/app/get-dictionary';
import IntlClientProvider from '@/app/components/IntlClientProvider';
export async function generateStaticParams() {
return [{ lang: 'en' }, { lang: 'es' }];
}
export default async function RootLayout({
children,
params,
}: {
children: React.ReactNode;
params: { lang: string };
}) {
// Load messages on the server
const messages = await getDictionary(params.lang);
return (
<html lang={params.lang}>
<body>
{/* Pass messages to the client provider */}
<IntlClientProvider locale={params.lang} messages={messages}>
{children}
</IntlClientProvider>
</body>
</html>
);
}
6. 클라이언트 컴포넌트에서 번역 사용하기
이제 모든 클라이언트 컴포넌트에서 useIntl 훅을 사용할 수 있습니다. 서버 컴포넌트에서는 이 훅을 사용할 수 없습니다.
번역된 텍스트를 표시하기 위한 새 클라이언트 컴포넌트를 생성합니다:
// app/components/HomePageContent.tsx
'use client';
import { useIntl } from 'react-intl';
export default function HomePageContent() {
const intl = useIntl();
return (
<div>
<h1>{intl.formatMessage({ id: 'home.title' })}</h1>
<p>{intl.formatMessage({ id: 'home.welcome' })}</p>
</div>
);
}
7. 페이지에 컴포넌트 추가하기
마지막으로, 새로운 클라이언트 컴포넌트를 페이지에 추가하세요.
// app/[lang]/page.tsx
import HomePageContent from '@/app/components/HomePageContent';
export default function Home() {
// 이 페이지는 서버 컴포넌트입니다
return (
<div>
{/* 클라이언트 컴포넌트를 렌더링합니다 */}
<HomePageContent />
</div>
);
}