Intlayer와 Next.js 14로 국제화(i18n) 시작하기
Intlayer란 무엇인가요?
Intlayer는 현대 웹 애플리케이션에서 다국어 지원을 단순화하기 위해 설계된 혁신적인 오픈소스 국제화(i18n) 라이브러리입니다. Intlayer는 최신 Next.js 14 프레임워크와 원활하게 통합되며, 강력한 App Router를 포함하고 있습니다. 이는 효율적인 렌더링을 위해 서버 컴포넌트와 함께 작동하도록 최적화되어 있으며, Turbopack (Next.js >= 15)의 완전한 호환성을 제공합니다.
Intlayer를 사용하면:
- 선언형 사전을 사용하여 번역을 쉽게 관리할 수 있습니다.
- 메타데이터, 경로 및 콘텐츠를 동적으로 지역화할 수 있습니다.
- 클라이언트 측 및 서버 측 컴포넌트에서 번역에 접근할 수 있습니다.
- 자동 생성된 TypeScript 지원을 통해 자동 완성과 오류 감지를 개선합니다.
- 동적 로케일 감지 및 전환과 같은 고급 기능의 이점을 누릴 수 있습니다.
Intlayer는 Next.js 12, 13, 14, 15와 호환됩니다. Next.js 페이지 라우터를 사용하고 있다면, 이 가이드를 참조하세요. TurboPack이 있든 없든 Next.js 15에 대한 내용은 이 가이드를 참조하세요.
Next.js 애플리케이션에서 Intlayer 설정을 위한 단계별 가이드
단계 1: 종속성 설치
npm을 통해 필요한 패키지를 설치하세요:
npm install intlayer next-intlayer
intlayer
next-intlayer
Intlayer를 Next.js와 통합하는 패키지입니다. Next.js 국제화를 위한 컨텍스트 프로바이더 및 훅을 제공합니다. 또한 Intlayer를 Webpack 또는 Turbopack과 통합하기 위한 Next.js 플러그인과 사용자의 선호 로케일 감지, 쿠키 관리, URL 리디렉션을 처리하는 미들웨어를 포함합니다.
단계 2: 프로젝트 구성
애플리케이션의 언어를 구성하기 위해 구성 파일을 생성하세요:
import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = { internationalization: { locales: [ Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH, // 다른 로케일 추가 ], defaultLocale: Locales.ENGLISH, },};export default config;
이 구성 파일을 통해 로컬화된 URL, 미들웨어 리디렉션, 쿠키 이름, 콘텐츠 선언의 위치 및 확장, Intlayer 로그 비활성화 등을 설정할 수 있습니다. 사용 가능한 매개변수의 전체 목록은 구성 문서를 참조하세요.
단계 3: Next.js 구성에 Intlayer 통합
Next.js 설정을 Intlayer와 통합하도록 구성하세요:
import { withIntlayer } from "next-intlayer/server";/** @type {import('next').NextConfig} */const nextConfig = {};export default withIntlayer(nextConfig);
withIntlayer() Next.js 플러그인은 Intlayer를 Next.js와 통합하는 데 사용됩니다. 이는 콘텐츠 선언 파일 구축을 보장하고 개발 모드에서 이를 모니터링합니다. 이는 Webpack 또는 Turbopack 환경 내에서 Intlayer 환경 변수를 정의하고, 성능을 최적화하기 위한 별칭을 제공하며, 서버 컴포넌트와의 호환성을 보장합니다.
단계 4: 로케일 감지를 위한 미들웨어 구성
사용자의 선호 로케일을 감지하기 위해 미들웨어를 설정하세요:
export { intlayerMiddleware as middleware } from "next-intlayer/middleware";export const config = { matcher: "/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",};
intlayerMiddleware는 사용자의 선호 로케일을 감지하고, 구성에서 지정한 적절한 URL로 리디렉션합니다. 또한 사용자의 선호 로케일을 쿠키에 저장할 수 있게 합니다.
matcher 매개변수를 애플리케이션의 경로와 일치하도록 조정하세요. 자세한 내용은 Next.js 문서에서 매처 구성하기를 참조하세요.
단계 5: 동적 로케일 경로 정의
RootLayout의 모든 내용을 제거하고 다음 코드를 대신 입력하세요:
import type { PropsWithChildren, FC } from "react";import "./globals.css";const RootLayout: FC<PropsWithChildren> = ({ children }) => children;export default RootLayout;
동적 라우팅을 구현하기 위해 [locale] 디렉토리에 새 레이아웃을 추가하여 로케일 경로를 제공합니다:
import type { Next14LayoutIntlayer } from "next-intlayer";import { Inter } from "next/font/google";import { getHTMLTextDir } from "intlayer";const inter = Inter({ subsets: ["latin"] });const LocaleLayout: Next14LayoutIntlayer = ({ children, params: { locale },}) => ( <html lang={locale} dir={getHTMLTextDir(locale)}> <body className={inter.className}>{children}</body> </html>);export default LocaleLayout;
[locale] 경로 세그먼트는 로케일을 정의하는 데 사용됩니다. 예: /en-US/about는 en-US를 참조하고, /fr/about는 fr을 참조합니다.
그런 다음, 애플리케이션 레이아웃에 generateStaticParams 함수를 구현하세요.
export { generateStaticParams } from "next-intlayer"; // 삽입할 라인const LocaleLayout: Next14LayoutIntlayer = ({ children, params: { locale },}) => { /*... 나머지 코드 */};export default LocaleLayout;
generateStaticParams는 애플리케이션이 모든 로케일에 필요한 페이지를 미리 빌드하도록 보장하여 런타임 계산을 줄이고 사용자 경험을 개선합니다. 자세한 내용은 Next.js에서 generateStaticParams에 대한 문서를 참고하세요.
단계 6: 콘텐츠 선언
번역을 저장하기 위해 콘텐츠 선언을 생성 및 관리하세요:
import { t, type DeclarationContent } from "intlayer";const pageContent = { key: "page", content: { getStarted: { main: t({ en: "Get started by editing", fr: "Commencez par éditer", es: "Comience por editar", }), pageLink: "src/app/page.tsx", }, },} satisfies DeclarationContent;export default pageContent;
콘텐츠 선언은 기본적으로 ./src 내의 contentDir 디렉토리에 포함되면 애플리케이션 내 어디서든 정의될 수 있습니다. 콘텐츠 선언 파일의 확장자와 일치해야 합니다(기본적으로 .content.{ts,tsx,js,jsx,mjs,cjs}). 자세한 내용은 콘텐츠 선언 문서를 참조하세요.
단계 7: 코드에서 콘텐츠 활용
애플리케이션 전반에서 콘텐츠 사전에 접근하세요:
import { ClientComponentExample } from "@components/ClientComponentExample";import { ServerComponentExample } from "@components/ServerComponentExample";import { type Next14PageIntlayer, IntlayerClientProvider } from "next-intlayer";import { IntlayerServerProvider, useIntlayer } from "next-intlayer/server";const Page: Next14PageIntlayer = ({ params: { locale } }) => { const content = useIntlayer("page", locale); return ( <> <p> {content.getStarted.main} <code>{content.getStarted.pageLink}</code> </p> <IntlayerServerProvider locale={locale}> <IntlayerClientProvider locale={locale}> <ServerComponentExample /> <ClientComponentExample /> </IntlayerClientProvider> </IntlayerServerProvider> </> );};export default Page;
- IntlayerClientProvider는 클라이언트 측 컴포넌트에 로케일을 제공하는 데 사용됩니다. 레이아웃을 포함한 모든 부모 컴포넌트에 두는 것이 좋지만, 레이아웃에 두는 것이 더 효율적입니다. 레이아웃에서 IntlayerClientProvider를 사용함으로써 매 페이지마다 재초기화하지 않고도 일관된 지역화 컨텍스트를 유지하여 성능을 개선할 수 있습니다.
IntlayerServerProvider는 서버 자식에게 로케일을 제공하는 데 사용됩니다. 레이아웃에서 설정할 수 없습니다.
레이아웃과 페이지는 공통 서버 컨텍스트를 공유할 수 없습니다. 서버 컨텍스트 시스템은 각 요청 데이터 저장소를 기반으로 하며, 애플리케이션의 다양한 부분에 대한 각 "컨텍스트"가 다시 생성됩니다. 공유된 레이아웃에 프로바이더를 두면 이 격리가 깨져서 서버 컨텍스트 값의 올바른 전파가 방해받습니다.
"use client";import type { FC } from "react";import { useIntlayer } from "next-intlayer";const ClientComponentExample: FC = () => { const content = useIntlayer("client-component-example"); // 관련 콘텐츠 선언 생성 return ( <div> <h2>{content.title} </h2> <p>{content.content}</p> </div> );};
import type { FC } from "react";import { useIntlayer } from "next-intlayer/server";const ServerComponentExample: FC = () => { const content = useIntlayer("server-component-example"); // 관련 콘텐츠 선언 생성 return ( <div> <h2>{content.title} </h2> <p>{content.content}</p> </div> );};
string 속성(예: alt, title, href, aria-label 등)에서 콘텐츠를 사용하려는 경우, 함수의 값을 호출해야 합니다. 예:
jsx<img src={content.image.src.value} alt={content.image.value} />
useIntlayer 훅에 대한 자세한 내용은 문서를 참조하세요.
(선택 사항) 단계 8: 메타데이터의 국제화
페이지 제목과 같은 메타데이터를 국제화하고 싶다면, Next.js에서 제공하는 generateMetadata 함수를 사용할 수 있습니다. 함수 내부에서 getTranslationContent 기능을 사용하여 메타데이터를 번역하세요.
import { type IConfigLocales, getTranslationContent, getMultilingualUrls,} from "intlayer";import type { Metadata } from "next";import type { LocalParams } from "next-intlayer";export const generateMetadata = ({ params: { locale },}: LocalParams): Metadata => { const t = <T>(content: IConfigLocales<T>) => getTranslationContent(content, locale); /** * 각 로케일에 대한 모든 URL을 포함하는 객체를 생성합니다. * * 예시: * ```ts * getMultilingualUrls('/about'); * * // 결과 * // { * // en: '/about', * // fr: '/fr/about', * // es: '/es/about', * // } * ``` */ const multilingualUrls = getMultilingualUrls("/"); return { title: t<string>({ en: "My title", fr: "Mon titre", es: "Mi título", }), description: t({ en: "My description", fr: "Ma description", es: "Mi descripción", }), alternates: { canonical: "/", languages: { ...multilingualUrls, "x-default": "/" }, }, openGraph: { url: multilingualUrls[locale], }, };};// ... 나머지 코드
메타데이터 최적화에 대한 더 자세한 정보는 공식 Next.js 문서에서 확인하세요.
(선택 사항) 단계 9: sitemap.xml 및 robots.txt의 국제화
sitemap.xml 및 robots.txt를 국제화하려면, Intlayer에서 제공하는 getMultilingualUrls 함수를 사용할 수 있습니다. 이 함수는 sitemap에 대한 다국어 URL을 생성할 수 있게 해줍니다.
import { getMultilingualUrls } from "intlayer";import type { MetadataRoute } from "next";const sitemap = (): MetadataRoute.Sitemap => [ { url: "https://example.com", alternates: { languages: getMultilingualUrls("https://example.com"), }, }, { url: "https://example.com/login", alternates: { languages: getMultilingualUrls("https://example.com/login"), }, }, { url: "https://example.com/register", alternates: { languages: getMultilingualUrls("https://example.com/register"), }, },];export default sitemap;
import type { MetadataRoute } from "next";import { getMultilingualUrls } from "intlayer";const getAllMultilingualUrls = (urls: string[]) => urls.flatMap((url) => Object.values(getMultilingualUrls(url)) as string[]);const robots = (): MetadataRoute.Robots => ({ rules: { userAgent: "*", allow: ["/"], disallow: getAllMultilingualUrls(["/login", "/register"]), }, host: "https://example.com", sitemap: `https://example.com/sitemap.xml`,});export default robots;
sitemap 최적화에 대한 더 자세한 정보는 공식 Next.js 문서를 참조하세요. robots.txt 최적화에 대한 정보는 공식 Next.js 문서를 참조하세요.
(선택 사항) 단계 10: 콘텐츠 언어 변경
콘텐츠의 언어를 변경하려면, useLocale 훅에서 제공하는 setLocale 함수를 사용할 수 있습니다. 이 함수는 애플리케이션의 로케일을 설정하고 그에 맞게 콘텐츠를 업데이트할 수 있게 해줍니다.
"use client";import { Locales, getHTMLTextDir, getLocaleName, getLocalizedUrl,} from "intlayer";import { useLocale } from "next-intlayer";import { type FC } from "react";const LocaleSwitcher: FC = () => { const { locale, pathWithoutLocale, availableLocales, setLocale } = useLocale(); return ( <ol> {availableLocales.map((localeItem) => ( <li key={localeItem}> <a href={getLocalizedUrl(pathWithoutLocale, localeItem)} hrefLang={localeItem} aria-current={locale === localeItem ? "page" : undefined} onClick={(e) => { e.preventDefault(); setLocale(localeItem); }} > <span> {/* 해당 로케일의 언어 - 예: Français */} {getLocaleName(localeItem, locale)} </span> <span dir={getHTMLTextDir(localeItem)} lang={localeItem}> {/* 현재 로케일로 설정된 경우의 언어 - 예: Francés */} {getLocaleName(localeItem)} </span> <span dir="ltr" lang={Locales.ENGLISH}> {/* 영어로 된 언어 - 예: French */} {getLocaleName(localeItem, Locales.ENGLISH)} </span> <span> {/* 해당 로케일의 언어 - 예: FR */} {localeItem} </span> </a> </li> ))} </ol> );};
문서 참고:
TypeScript 구성
Intlayer는 TypeScript의 이점을 활용하기 위해 모듈 증강을 사용하고 있으며 코드베이스를 더욱 강력하게 만들어줍니다.
TypeScript 구성이 자동 생성된 타입을 포함하도록 설정되어 있는지 확인하세요.
{ // ... 기존 TypeScript 구성 "include": [ // ... 기존 TypeScript 구성 "types", // 자동 생성된 타입 포함 ],}
Git 구성
Intlayer에 의해 생성된 파일을 무시하는 것이 좋습니다. 이렇게 하면 Git 리포지토리에 이들을 커밋하지 않을 수 있습니다.
이것을 하려면, .gitignore 파일에 다음의 지침을 추가하세요:
# Intlayer에 의해 생성된 파일 무시.intlayer
이 문서를 개선할 아이디어가 있으시면 GitHub에 풀 리퀘스트를 제출하여 자유롭게 기여해 주세요.
문서에 대한 GitHub 링크