Next.js 국제화 Internationalization 설정하기 (feat. next-intl, next.js v15)
Next.js를 사용한 웹사이트에서 국제화 (Internationalization) 설정하는 방법을 알아보겠습니다. next-intl 라이브러리를 사용하여 간단하게 다국어 지원을 구현할 수 있습니다.
소개
웹 애플리케이션을 개발할 때 다국어 지원은 글로벌 사용자를 위한 필수적인 기능입니다. Next.js에서는 국제화(i18n)를 구현하기 위한 여러 가지 방법이 있는데, next-intl 라이브러리를 사용하여 효율적으로 다국어 지원을 구현하는 방법을 알아보겠습니다.
목차
- next-intl 소개
- 프로젝트 폴더 구조
- 프로젝트 설정
- routing.ts 파일 설정
- request.ts 파일 설정
- middleware.ts 파일 설정
- layout 파일 설정
- 메시지 파일 구성
- 번역 사용하기
- useTranslations 훅
- 동적 콘텐츠 처리
- 페이지간 이동 Link 사용하기
- 마치며
- Github Repository
- 참고
1. next-intl 소개
next-intl은 Next.js 애플리케이션에서 국제화를 구현하기 위한 강력한 라이브러리입니다. 다음과 같은 주요 기능을 제공합니다.
- 타입스크립트 지원
- 메시지 포맷팅
- 날짜, 시간, 숫자의 지역화
- SEO 최적화
- 서버 컴포넌트 지원
- 경량화된 번들 사이즈
2. 프로젝트 폴더 구조
다음은 next-intl을 사용하여 국제화를 구현하기 위한 프로젝트 폴더 구조입니다.
root
├── messages
│ ├── en.json (1)
│ ├── ko.json
│ ├── ja.json
│ └── ...
├── next.config.mjs (2)
├── i18n
│ ├── routing.ts (3)
│ └── request.ts (5)
├── middleware.ts (4)
└── app
└── [locale]
├── layout.tsx (6)
└── page.tsx (7)
messages
폴더: 메시지 파일을 저장하는 디렉토리입니다.en.json
,ko.json
등의 파일로 구성됩니다.next.config.mjs
: next-intl 플러그인을 설정하는 파일입니다.i18n
폴더: 국제화 설정을 위한 파일을 저장하는 디렉토리입니다.middleware.ts
: 라우팅 구성을 참고하여 미들웨어를 설정하는 파일입니다.i18n/request.ts
: 요청을 처리하는 파일입니다.app/[locale]/layout.tsx
: 국제화 번역을 적용한 레이아웃 컴포넌트입니다.app/[locale]/page.tsx
: 국제화 번역을 적용한 페이지 컴포넌트입니다.
3. 프로젝트 설정
먼저 next-intl 라이브러리를 설치합니다.
npm install next-intl
또한, next.config.mjs
파일을 생성하여 next-intl 플러그인을 설정합니다.
import createNextIntlPlugin from 'next-intl/plugin';
const withNextIntl = createNextIntlPlugin('./i18n/request.ts'); // app 폴더를 사용하는 경우 경로 설정
// -> src 폴더를 사용하는 경우 인자를 생략합니다.
/** @type {import('next').NextConfig} */
const nextConfig = {};
export default withNextIntl(nextConfig);
위 코드는 module 형식의
next.config.mjs
파일입니다. CommonJS 형식의next.config.js
파일을 사용할 경우, 다음과 같이 설정합니다.
const createNextIntlPlugin = require('next-intl/plugin');
const withNextIntl = createNextIntlPlugin('./i18n/request.ts'); // app 폴더를 사용하는 경우 경로 설정
// -> src 폴더를 사용하는 경우 인자를 생략합니다.
/** @type {import('next').NextConfig} */
const nextConfig = {};
module.exports = withNextIntl(nextConfig);
import createNextIntlPlugin from 'next-intl/plugin';
const withNextIntl = createNextIntlPlugin(); // src 폴더를 사용하는 경우 인자를 생략합니다.
// ... 생략
4. routing.ts 파일 설정
다음으로, 라우팅 설정을 위한 i18n/routing.ts
파일을 생성합니다.
import { defineRouting } from 'next-intl/routing';
import { createNavigation } from 'next-intl/navigation';
export const routing = defineRouting({
// 지원하는 로케일 설정
locales: ['ko', 'en', 'ja'],
// 기본 로케일 설정
defaultLocale: 'ko',
});
// Next.js 탐색 API에 대한 경량 래퍼
// 라우팅 구성 설정
// 기존 next js에서 제공하는 Link, redirect, usePathname, useRouter를 대체합니다.
export const { Link, redirect, usePathname, useRouter } =
createNavigation(routing);
export const { Link, redirect, usePathname, useRouter } = createNavigation(routing)
; 코드는 Next.js의 Link
, redirect
, usePathname
, useRouter
를 사용할 수 있도록 래핑한 것입니다. 이를 사용하여 기존 next j에서 제공하는 API를 대체할 수 있습니다.
Link 예시로 import 할때
import { Link } from "@/i18n/routing";
이렇게 사용할 수 있습니다.기존
import Link from 'next/link';
는 사용하지 않음.
5. request.ts 파일 설정
다음으로, 요청을 처리하는 i18n/request.ts
파일을 생성합니다.
import { getRequestConfig } from 'next-intl/server';
import { routing } from './routing';
export default getRequestConfig(async ({ requestLocale }) => {
// 이는 일반적으로 `[locale]` 세그먼트에 해당합니다.
let locale = await requestLocale;
// 유효한 로캘이 사용되었는지 확인하세요.
if (!locale || !routing.locales.includes(locale as never)) {
locale = routing.defaultLocale;
}
return {
locale,
messages: (await import(`../messages/${locale}.json`)).default, // 상대 경로 확인, messages 폴더에 JSON 파일이 있어야 함
};
});
locale을 설정하고, 해당 locale에 맞는 메시지 파일을 불러옵니다.
6. middleware.ts 파일 설정
// root
// ├── middleware.ts
import createMiddleware from 'next-intl/middleware';
import { routing } from './i18n/routing'; // 경로를 잘 설정해주세요.
export default createMiddleware(routing);
export const config = {
// 국제화된 경로명만 일치
matcher: ['/', '/(ko|ja|en)/:path*'], // "/" 경로와 "/:path*" 경로를 지원합니다.
};
7. layout 파일 설정
app/[locale]/layout.tsx
파일을 생성하여 레이아웃을 구성합니다.
import { NextIntlClientProvider } from 'next-intl';
import { getMessages } from 'next-intl/server';
import { notFound } from 'next/navigation';
import { routing } from '@/i18n/routing';
type Params = Promise<{ locale: never }>;
export default async function LocaleLayout({
children,
params,
}: {
children: React.ReactNode;
params: Params;
}) {
const { locale } = await params; // next js 15버전부터 Params 사용시 비동기로 변경됨
// https://nextjs.org/docs/messages/sync-dynamic-apis
// 들어오는 `로케일`이 유효한지 확인하세요.
if (!routing.locales.includes(locale)) {
notFound();
}
// 클라이언트에게 모든 메시지 제공
const messages = await getMessages();
return (
<html lang={locale}>
<NextIntlClientProvider messages={messages}>
<body>{children}</body>
</NextIntlClientProvider>
</html>
);
}
app/[locale]/page.tsx
파일은 기존 하던것과 동일하게 사용하면 됩니다.
export default function Home() {
return (
<main>
<h1>Hello, World!</h1>
</main>
);
}
npm run dev
를 실행하고 http://localhost:3000/
로 접속하여 http://localhost:3000/ko
로 이동되면(기본 ko 설정) 기본 세팅은 완료된 것입니다.
8. 메시지 파일 구성
messages
폴더에 메시지 파일을 생성합니다. 메시지 파일은 JSON 형식으로 작성하며, 다음과 같이 구성합니다.
{
"Home": {
"title": "Home",
"description": "Welcome to the home page."
}
}
{
"Home": {
"title": "홈",
"description": "홈 페이지에 오신 것을 환영합니다."
}
}
{
"Home": {
"title": "ホーム",
"description": "ホームページへようこそ。"
}
}
각 *.json 파일은 /ko
, /en
, /ja
등의 :path
이름과 일치 해야합니다.
9. 번역 사용하기
app/[locale]/page.tsx
파일에서 번역을 사용하려면 useTranslations
훅을 사용합니다.
import { useTranslations } from 'next-intl';
export default function Home() {
const t = useTranslations('Home');
return (
<main>
<h1>{t('title')}</h1>
<p>{t('description')}</p>
</main>
);
}
해당 코드를 실행하면, http://localhost:3000/ko
로 접속하면 ko.json
파일의 번역이 적용되어 화면에 출력됩니다.
각 path 별로 이동하여 번역이 잘 적용되는지 확인합니다.
10. useTranslations 훅
useTranslations
훅은 정적 메세지를 가져오는 훅입니다.
메세지 구성 예시
{
"Home": {
"title": "Home",
"description": "Welcome to the home page."
}
}
위 메세지를 가정하에 인수(argument)로 Home
을 넣어서 사용하면 해당 메세지를 가져옵니다.
const t = useTranslations('Home');
return (
<main>
<h1>{t('title')}</h1>
<p>{t('description')}</p>
</main>
);
t 변수는 메시지를 가져오는 함수입니다. t('title')은 'Home' 메시지 파일에서 'title' 키에 해당하는 값을 가져옵니다.
또는 다음과 같이 인수(argument)없이 사용할 수 있습니다.
const t = useTranslations();
return (
<main>
<h1>{t('Home.title')}</h1>
<p>{t('Home.description')}</p>
</main>
);
11. 동적 콘텐츠 처리
동적 콘텐츠를 처리할 때는 useTranslations
훅을 사용하여 동적으로 메시지를 가져올 수 있습니다.
우선 message에서 보간
을 사용하여 동적으로 메시지를 가져오는 방법을 알아보겠습니다.
보간은 문자열에서 {}
중괄호를 사용하여 동적으로 값을 삽입하는 방법입니다.
{
"Home": {
"title": "Home",
"description": "Welcome to the home page, {name}."
}
}
const t = useTranslations('Home');
return (
<main>
<h1>{t('title')}</h1>
<p>{t('description', { name: 'John' })}</p>
</main>
);
위 코드처럼 { name: 'John' }
객체를 전달하여 {name}
부분에 동적으로 값을 삽입할 수 있습니다.
next-intl은 이외에도 다양한 기능을 제공합니다. 자세한 내용은 `next-intl 메시지 사용법`을 참고하세요.
12. 페이지간 이동 Link 사용하기
앞서 말씀드린 바와 같이 routing.ts
파일에서 설정한 Link
를 사용하여 페이지간 이동을 할 수 있습니다.
import { Link } from '@/i18n/routing';
<Link href="/about">About Page</Link>;
@/i18n/routing
Link를 사용하면 현재 사용중인 번역(국제화) 페이지 언어에 맞게 해당 링크로 이동합니다.
단, 기본 Next Link
를 사용하면 국제화가 적용되지 않습니다. 따라서 @/i18n/routing
Link를 사용하는 것을 권장합니다.
또한, 가끔 Next Link
와 @/i18n/routing
Link를 혼용하여 사용할 경우가 있는데,
다음과 같이 이름을 변경하여 사용할 수 있습니다.
import { Link as I18bLink } from '@/i18n/routing';
import Link from 'next/link';
<I18bLink href="/about">About Page</I18bLink>;
<Link href="/ko">한국어</Link>
<Link href="/en">English</Link>
<Link href="/ja">日本語</Link>
위 코드와 같이 Link as I18bLink
를 사용하여 이름을 변경하면 I18bLink
로 사용할 수 있습니다.
마치며
이상으로 Next.js에서 국제화를 구현하는 방법을 알아보았습니다. next-intl 라이브러리를 사용하면 간단하게 다국어 지원을 구현할 수 있습니다.
라이브러리 특성상 messages 폴더에 JSON 파일을 생성하여 번역을 적용하므로, 번역이 필요한 페이지에 대한 메시지 파일을 작성하여 국제화를 구현할 수 있습니다. (다소 노가다가 필요할 수 있습니다.)
이런 방법이 번거롭다면 Google Translate API를 사용하여 번역을 적용하는 방법과 번역을 위한 다른 라이브러리를 사용하는 방법도 있습니다.
또는 제가 포스팅한 google 무료 번역 api 사용법을 참고하시면 번역을 쉽게 적용할 수 있습니다.
`Next.js에서 Google 무료 번역 API 사용하기`하지만 next-intl
라이브러리를 글로벌 SEO 최적화 및 경량화된 번들 사이즈를 제공하므로, API를 사용하는 것보다 더 효율적으로 국제화를 구현할 수 있습니다.
내용이 길었습니다. 다음에는 Next.js에서 국제화를 구현할 때 주의할 점과 추가적인 설정 방법에 대해 알아보겠습니다.