@senspond

>

개발>프론트 엔드

NextJS App router 방식으로 다국어 설정 간단하게 하기 next-intl

등록일시 : 2024-09-18 (수) 03:38
업데이트 : 2024-09-19 (목) 12:33
오늘 조회수 : 6
총 조회수 : 370

    NextJS App router 방식으로 다국어 설정 하기 next-intl 를 통해 간단하게 적용

    국내뿐 아니라 해외 시장을 공략하고 마케팅을 하려면 다국어 지원이 가능하도록 개발해야만 할 것 같았다.

    그런데, 이전에 다국어 지원 사이트를 개발해본 적이 없어서 여러가지 방법들을 찾아보고 적용해보다가 next-intl 를 통한 방법이 간단하면서 적용하기 쉬운것 같아 이 방법으로 진행해보기로 했다. 그리고 블로그에 정리를 해본다.


    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>
        );
    }



    senspond

    안녕하세요. Red, Green, Blue 가 만나 새로운 세상을 만들어 나가겠다는 이상을 가진 개발자의 개인공간입니다.

    댓글 ( 0 )

    카테고리내 관련 게시글

    현재글에서 작성자가 발행한 같은 카테고리내 이전, 다음 글들을 보여줍니다

    @senspond

    >

    개발>프론트 엔드

    • NextJS useSearchParams() should be wrapped in a suspense boundary at page 오류해결

      NextJS useSearchParams() should be wrapped in a suspense boundary at page 오류해결
        2025-02-28 (금) 01:59
      1. 타입스크립트의 클로저, 클래스, 데코레이터로 싱글톤 패턴 구현하기

        타입스크립트의 클로저, 클래스, 데코레이터로 싱글톤 패턴 구현하기 정리를 해봤습니다.
          2024-05-22 (수) 07:59
        1. [현재글] NextJS App router 방식으로 다국어 설정 간단하게 하기 next-intl

          NextJS App router 방식으로 다국어 설정 하기 next-intl 를 통해 간단하게 적용
            2024-09-18 (수) 03:38
          1. Fetch API 사용시 파일업로드 Multipart: Boundary not found 에러 해결 방법, 수동전송 방법(JAVA)

            Fetch API 사용시 파일업로드 Multipart: Boundary not found 에러 해결 방법을 정리하고 multipart/formdata 수동전송 방법을 정리한 내용입니다.
              2024-02-23 (금) 02:46