nextjs-intl: Next.js 환경에서 다국어 지원하기
2024/8/6
nextjs
로 새로운 프로젝트를 진행하는 중에 다국어를 미리 지원해두면 편할 것 같아서 다국어 지원 라이브러리를 적용하면서 그 방법을 정리해두려고 합니다.
nextjs
로 다국어 지원은 처음이라 다양한 라이브러리를 찾아보았는데 그 중에서도 app router
를 지원하는 라이브러리는 next-intl
이 가장 깔끔해서 해당 라이브러리를 선택하였습니다.
next-intl에서 제공하는 example과 공식 docs를 따라 진행하였습니다.
설치
// npm을 사용하는 경우
npm i next-intl
// yarn을 사용하는 경우
yarn add next-intl
// pnpm을 사용하는 경우
pnpm i next-intl
다음과 같은 두 가지 경우에 해당하는 경우 i18n routing을 설정할 필요가 없습니다.
- 사용자 설정 등에 따라 언어 설정을 제공하는 경우
- 하나의 언어만 지원하는 경우
저희 서비스는 사용자가 서비스 안에서 자유롭게 설정할 수 있도록 만들기 위해 [next-intl]App Router: App Router setup with i18n routing 도움말에 따라 진행하겠습니다.
폴더 구조 설정
├── messages
│ ├── en.json (1)
│ └── ...
├── next.config.mjs (2)
└── src
├── i18n
│ ├── routing.ts (3)
│ └── request.ts (5)
├── middleware.ts (4)
└── app
└── [locale]
├── layout.tsx (6)
└── page.tsx (7)
messages 폴더 생성
next.config.[mjs/js]
가 있는 디렉토리에 messages
폴더를 생성하여 json
파일을 생성합니다.
// en.json
{
"SignUpPage": {
"title": {...}
}
}
// ko.json
{
"SignUpPage": {
"title": {
"verify": "이메일 인증",
"register": "회원 정보 입력"
}
}
}
next config 설정
import createNextIntlPlugin from 'next-intl/plugin';
const withNextIntl = createNextIntlPlugin();
/** @type {import('next').NextConfig} */
const nextConfig = {};
export default withNextIntl(nextConfig);
routing.ts
생성
24년 9월 10일에 추가된 내용입니다.
import {defineRouting} from 'next-intl/routing';
export const routing = defineRouting({
locales: ['en', 'ko'],
defaultLocale: 'ko'
});
middleware.ts
생성
import createMiddleware from 'next-intl/middleware';
import {routing} from "@i18n/routing";
// export default createMiddleware({ => 업데이트: routing으로 변경
// // A list of all locales that are supported
// locales: ['en', 'ko'],
//
// // Used when no locale matches
// defaultLocale: 'ko'
// });
export default createMiddleware(routing);
export const config = {
// Match only internationalized pathnames
matcher: ['/', '/(ko|en)/:path*']
};
request.ts
생성
i18n.ts
에서 i18n/request.ts
으로 변경되었습니다.
import {notFound} from 'next/navigation';
import {getRequestConfig} from 'next-intl/server';
import {routing} from "@i18n/routing";
// Can be imported from a shared config
// export const locales = ['en', 'ko']; => 업데이트: routing으로 변경
export default getRequestConfig(async ({locale}) => {
// Validate that the incoming `locale` parameter is valid
if (!routing.locales.includes(locale as any)) notFound();
return {
messages: (await import(`../messages/${locale}.json`)).default
};
});
app/[locale]/layout.tsx
설정
import {NextIntlClientProvider} from 'next-intl';
import {getMessages} from 'next-intl/server';
export default async function LocaleLayout({
children,
params: {locale}
}: {
children: React.ReactNode;
params: {locale: string};
}) {
// Providing all messages to the client
// side is the easiest way to get started
const messages = await getMessages();
return (
<html lang={locale}>
<body>
<NextIntlClientProvider messages={messages}>
{children}
</NextIntlClientProvider>
</body>
</html>
);
}
사용하기
export default function RegisterPage() {
const t = useTranslations("SignUpPage");
return (
<>
<h1 className={"title"}>{t("title.register")}</h1>
</>
);
}
추가 설정
Navigation APIs
다음과 같이 설정해놓고 사용한다면 pathname에 locale을 입력하지 않고 사용 가능합니다.
routing.ts
import {defineRouting} from 'next-intl/routing';
import {createSharedPathnamesNavigation} from 'next-intl/navigation';
...
export const {Link, redirect, usePathname, useRouter} =
createSharedPathnamesNavigation(routing);
만일 사용언어에 따라 다른 path를 쓴다면 createLocalizedPathnamesNavigation
사용하면 됩니다. 자세한 내용은 공식 문서 참고 바랍니다.