@senspond
>
NextJS App router 방식으로 다국어 설정 하기 next-intl 를 통해 간단하게 적용
국내뿐 아니라 해외 시장을 공략하고 마케팅을 하려면 다국어 지원이 가능하도록 개발해야만 할 것 같았다.
그런데, 이전에 다국어 지원 사이트를 개발해본 적이 없어서 여러가지 방법들을 찾아보고 적용해보다가 next-intl 를 통한 방법이 간단하면서 적용하기 쉬운것 같아 이 방법으로 진행해보기로 했다. 그리고 블로그에 정리를 해본다.
npm install next-intl
next.config.mjs
import createNextIntlPlugin from 'next-intl/plugin';
const withNextIntl = createNextIntlPlugin();
const nextConfig = {};
export default withNextIntl(nextConfig);
tsconfig.json
{
"compilerOptions": {
(...생략...)
"paths": {
"@/*": ["./src/*"]
}
},
}
src/i18n/routing.ts
import {createLocalizedPathnamesNavigation} from 'next-intl/navigation';
import {defineRouting} from 'next-intl/routing';
export const routing = defineRouting({
locales: ['en', 'ko'], // 지원 가능한 언어목록
defaultLocale: 'en', // 기본 언어
pathnames: {
'/': '/',
}
});
export type Locale = (typeof routing.locales)[number];
export const {Link, getPathname, redirect, usePathname, useRouter} =
createLocalizedPathnamesNavigation(routing);
src/i18n/request.ts
import {notFound} from 'next/navigation';
import {getRequestConfig} from 'next-intl/server';
import {routing} from './routing';
export default getRequestConfig(async ({locale}) => {
if (!routing.locales.includes(locale as any)) notFound();
return {
messages: (await (import(`@/i18n/messages/${locale}.json`))).default
};
});
src/app/[locale]/layout.tsx
import { getMessages, unstable_setRequestLocale} from "next-intl/server";
import {NextIntlClientProvider} from "next-intl";
import {routing} from '@/i18n/routing';
export function generateStaticParams() {
return routing.locales.map((locale) => ({locale}));
}
export default async function LocaleLayout({ children, params: { locale } }) {
const messages = await getMessages();
unstable_setRequestLocale(locale);
return (
<html lang={locale}>
<body>
<NextIntlClientProvider locale={locale} messages={messages}>
{children}
</NextIntlClientProvider>
</body>
</html>
);
}
unstable_setRequestLocale 는 빌드를 할 때 정적 사이트 생성(SSG) 로 언어별 페이지를 따로 만들어줍니다.
src/i18n/messages/en.json
{
"homePage": {
"title": "Hello World!"
}
}
src/i18n/messages/ko.json
{
"homePage": {
"title": "안녕하세요!"
}
}
src/app/[locale]/page.tsx
import { useTranslations } from 'next-intl';
export default function Home(params: { locale } ) {
unstable_setRequestLocale(locale);
const t = useTranslations('homePage'); // json key 값
return (
<div>
{t('title')}
</div>
);
}
src/app/layout.tsx
import {ReactNode} from 'react';
export default function RootLayout({children}: ReactNode) {
return children;
}
앞으로 [locale] 의 layout과 page 를 사용한다.
그런데 app 디렉토리에 있는 layout이 없으면 not-found exception이 발생한다.
그러니까 껍데기만 만들어주자
이제 기존의 page 들은 다 [locale] 안으로 옮겨준다.
검색엔진 최적화(SEO)에 유리하도록 메타데이터 또한 다국어 세팅이 가능하다.
"metadata": {
"title": "홈페이지",
"description": "홈페이지 설명",
"openGraph": {
"title": "",
"description": ".",
"siteName": "",
"locale": "ko_KR",
},
"twitter": {
"card": "",
"site": "",
"title": "",
"description": "."
}
},
src/app/[locale]/layout.tsx
import {getMessages, getTranslations, unstable_setRequestLocale} from "next-intl/server";
import {NextIntlClientProvider} from "next-intl";
import {routing} from '@/i18n/routing';
import {ReactNode} from "react";
export function generateStaticParams() {
return routing.locales.map((locale) => ({locale}));
}
type Props = {
children: ReactNode;
params: {locale: string};
};
export async function generateMetadata({
params: {locale}
}: Omit<Props, 'children'>) {
const t = await getTranslations({locale, namespace: 'metadata'});
return {
title: t("title"),
description: t("description"),
icons: {
icon: '/favicon.ico',
},
openGraph: {
title: t("openGraph.title"),
description: t("openGraph.title"),
url: 'https://www.example.com',
siteName: t("openGraph.siteName"),
type: 'website',
// ...
},
twitter: {
// ...
},
};
}
export default async function LocaleLayout({ children, params: { locale } }) {
const messages = await getMessages();
unstable_setRequestLocale(locale);
return (
<html lang={locale}>
<body>
<NextIntlClientProvider locale={locale} messages={messages}>
{children}
</NextIntlClientProvider>
</body>
</html>
);
}
안녕하세요. Red, Green, Blue 가 만나 새로운 세상을 만들어 나가겠다는 이상을 가진 개발자의 개인공간입니다.
현재글에서 작성자가 발행한 같은 카테고리내 이전, 다음 글들을 보여줍니다
@senspond
>