Logo
Published on
·9 min read

Next.js - 다국어(i18n) 설정 및 static html로 내보내기 Part 1

개요

다국어가 지원되는 static html 웹 사이트를 만들기로 했습니다.
페이지는 단 2개로, 각 페이지는 영문한글을 지원하도록 할 계획이었습니다.

순수 html로 작성할까도 생각했지만, SEO 작업과 다국어 지원을 위해 일일이 눈으로 한국어와 영문 버전으로 작성하기에는 휴먼 에러가 발생할 듯 하여 Next.js를 사용하기로 했습니다.

내용이 길어져 Part 1, Part 2로 나누어 정리했습니다.

  • Part 1: Next.js 프로젝트 생성, 다국어(i18n) 설정
  • Part 2: 다국어 Static Export 적용

Next.js 신규 프로젝트 생성

아래 명령어로 신규 프로젝트를 생성합니다.

npx create-next-app@latest

프로젝트 생성 시 선택은 아래와 같이 했습니다.

√ What is your project named? ... sample-i18n-static-export
√ Would you like to use TypeScript? ... No
√ Would you like to use ESLint? ... Yes
√ Would you like to use Tailwind CSS? ... No
√ Would you like to use `src/` directory? ... No
√ Would you like to use App Router? (recommended) ... No
√ Would you like to customize the default import alias? ... No
  • TypeScript를 선택하지 않은 이유는 다국어 처리 참고 문서가 JavaScript로 설명되어있었기 때문입니다.(저는 TypeScript에 익숙하지 않기에 위험 부담을 최소화하기로 했습니다.)

  • App Router를 사용안함으로 지정한 이유는 다국어 처리 참고 문서가 pages router 기준으로 설명이 되어있었기 때문입니다.

    • Yes 선택: 기본 생성 파일이 app 폴더 기준으로 생성
    • No 선택: 기본 생성 파일이 pages 폴더 기준으로 생성
  • 더 자세한 내용은 Next.js Installation을 참고하세요.

브라우저에서 확인

생성한 프로젝트에서 아래 명령어를 실행합니다.

npm run dev

위 명령어를 실행하면 로컬 웹 서버가 실행되면서 접속할 url(http://localhost:3000)을 알려줍니다.
(이미 사용중인 포트가 있다면 다른 포트로 변경될 수 있습니다. 저는 이미 3000 포트를 사용중이어서 3001 포트로 실행되었습니다.)

http://localhost:3000에 접속해 페이지가 정상적으로 나오는지 확인합니다.

페이지 생성

  • pages/index.js 파일을 열어서 아래와 같이 수정합니다.
export default function Home() {
  return (
    <div>
      <h1>첫 번째 화면</h1>
    </div>
  )
}
  • pages/second.js 파일을 생성하고 아래와 같이 작성합니다.
export default function Second() {
    return (
        <div>
            <h1>두 번째 화면</h1>
        </div>
    )
}

브라우저에서 확인

http://localhost:3000http://localhost:3000/second 에 접속해서 각 페이지가 정상적으로 나오는지 확인합니다.

여기까지가 기본 Next.js 프로젝트 생성과 페이지 생성입니다. 다음은 다국어 설정으로 넘어가보겠습니다.


다국어(i18n) 설정

기본 라우팅 기능

Next.js에는 i18n 다국어 라우팅 처리 기능이 내장되어 있습니다. 라우팅을 처리하는 것이지 언어 설정에 따른 번역 언어 매핑을 해주지는 않습니다.

아래와 같이 각 URL로 라우팅 처리를 해주는 것입니다.

<Link href={'/'} locale={'en'}>to English</Link> <!-- /en -->
<Link href={'/'} locale={'ko'}>한국어로</Link> <!-- /ko -->

언어별 URL로 접속했을 때, 각 언어에 맞는 번역을 해주기 위해 타사 라이브러리 next-i18next를 사용하기로 했습니다.

기본 라우팅 기능에 대한 자세한 내용은 Next.js Internationalization (i18n) Routing을 참고하세요.

이 단계에서는 기본 라우팅 제공 기능이 있다 정도로 넘어가고, 바로 이어지는 다음 단계(next-i18next 설정)에서 설정을 진행하겠습니다.

next-i18next 설치

next-i18next에서 설치 및 설정 방법을 확인할 수 있습니다.

위 문서대로 진행했던 부분을 정리하면 아래와 같습니다.

먼저, 아래 명령어를 입력하여 설치합니다.

npm install next-i18next react-i18next i18next

번역 파일 추가

  • public 폴더 하위에 locales 폴더를 생성합니다.

  • locales 폴더 하위에 enko 폴더를 생성합니다.

  • public/locales/en/common.json 파일을 생성하고 아래와 같이 작성합니다.

{
    "first": "First Page",
    "second": "Second Page"
}
  • public/locales/ko/common.json 파일을 생성하고 아래와 같이 작성합니다.
{
    "first": "첫 번째 화면",
    "second": "두 번째 화면"
}

프로젝트 설정

  • 최상위 폴더에 next-i18next.config.js 파일을 생성하고 원하는 언어 설정을 추가합니다.
    (저는 아래 코드와 같이 기본 언어는 한국어로, 제공 언어는 한국어와 영어로 설정했습니다.)
/** @type {import('next-i18next').UserConfig} */
module.exports = {
    i18n: {
        defaultLocale: 'ko',
        locales: ['ko', 'en']
    }
}
  • next.config.js 파일을 열어서 i18n 설정을 추가합니다. (재실행이 필요합니다.)
/** @type {import('next').NextConfig} */
const { i18n } = require('./next-i18next.config')

const nextConfig = {
  reactStrictMode: true,
  i18n
}

module.exports = nextConfig
  • pages/_app.js 파일을 열어서 아래와 같이 수정합니다.
import { appWithTranslation } from 'next-i18next'

const MyApp = ({ Component, pageProps }) => (
    <Component {...pageProps} />
)

export default appWithTranslation(MyApp)

페이지에 다국어 적용

설정은 끝났습니다. 이제 페이지만 수정하면 다국어로 사용할 수 있습니다.

  • pages/index.js 파일을 열어서 아래와 같이 수정합니다. (동작 확인을 위한 Link 태그도 추가했습니다.)
import {useTranslation} from "next-i18next";
import {serverSideTranslations} from "next-i18next/serverSideTranslations";
import Link from "next/link";

// 이 부분이 빠지면 t('...') 동작 안함
export async function getStaticProps({locale}) {
    return {
        props: {
            ...(await serverSideTranslations(locale, ['common'])),
        },
    };
}

export default function Home() {
    const {t} = useTranslation(['common']);

    return (
        <div>
            <h1>
                {t('first')}
            </h1>
            <div>
                <p><Link href={'/second'}>{t('second')}</Link></p>
                <p><Link href={'/'} locale={'en'}>to English</Link> | <Link href={'/'} locale={'ko'}>한국어로</Link></p>
            </div>
        </div>
    )
}
  • pages/second.js 파일을 열어서 아래와 같이 수정합니다.
import {useTranslation} from "next-i18next";
import {serverSideTranslations} from "next-i18next/serverSideTranslations";
import Link from "next/link";

// 이 부분이 빠지면 t('...') 동작 안함
export async function getStaticProps({locale}) {
    return {
        props: {
            ...(await serverSideTranslations(locale, ['common'])),
        },
    };
}

export default function Second() {
    const {t} = useTranslation(['common']);

    return (
        <div>
            <h1>
                {t('second')}
            </h1>
            <div>
                <p><Link href={'/'}>{t('first')}</Link></p>
                <p><Link href={'/second'} locale={'en'}>to English</Link> | <Link href={'/second'} locale={'ko'}>한국어로</Link></p>
            </div>
        </div>
    )
}

브라우저에서 확인

  • http://localhost:3000http://localhost:3000/en 에 접속해서 설정된 언어로 정상적으로 나오는지 확인합니다.
  • http://localhost:3000/secondhttp://localhost:3000/en/second 에 접속해서 설정된 언어로 정상적으로 나오는지 확인합니다.

아래 이미지는 브라우저에서 확인한 캡쳐 화면입니다. (참고로 저는 다른 프로젝트에서 3000 포트를 사용중이라 3001 포트로 접속했습니다.)

브라우저 확인

정리

Vercel, Netlify 또는 Docker를 사용하여 배포한다면 여기까지 설정해도 되는 것으로 보입니다.

하지만 저는 CloudFlare Pages에 배포할 예정입니다. 그렇다면 static export로 html 결과물을 생성해야 합니다.


Static Export

next.config.js 설정

  • next.config.js 파일을 열어서 output: 'export'를 추가합니다.
const { i18n } = require('./next-i18next.config')

const nextConfig = {
  output: 'export', // 추가
  reactStrictMode: true,
  i18n
}

module.exports = nextConfig

Export 를 위해 다음 명령어를 실행합니다.

npm run build

아래와 같은 오류가 발생합니다.

> Build error occurred
Error: Specified "i18n" cannot be used with "output: export". See more info here: https://nextjs.org/docs/messages/export-no-i18n

Next.js - Internationalization (i18n) Routing 문서의 내용 중 아래와 같은 부분을 확인할 수 있습니다.
(이 글을 작성하는 2023.09.19 기준 내용이고 이후 변경될 수도 있습니다.)

How does this work with Static Generation?

Note that Internationalized Routing does not integrate with output: 'export' as it does not leverage the Next.js routing layer. Hybrid Next.js applications that do not use output: 'export' are fully supported.

해석해 보면

정적 생성에서는 어떻게 동작하나요?

Internationalized Routing은 output: 'export'와 통합되지 않습니다. Next.js 라우팅 레이어를 활용하지 않기 때문입니다. output: 'export'를 사용하지 않는 하이브리드 Next.js 애플리케이션에는 완벽하게 지원됩니다.

해결 방법?

다행히 next-i18next - Static HTML Export SSG 부분에 해결 방법 링크가 안내되어있습니다.

next-language-detector 라이브러리 설치, 설정 및 소스 추가/수정이 필요합니다.

이제 하나씩 진행해 보겠습니다.

하지만, 내용이 이미 길어졌기에 Part 2로 이어서 작성하겠습니다.


참고 URL

실전에서 바로 쓰는 Next.js:SSR부터 SEO 배포까지 확장성 높은 풀스택 서비스 구축 가이드, 한빛미디어  타입스크립트 리액트 Next.js로 배우는 실전 웹 애플리케이션 개발, 위키북스  모두의 구글 애널리틱스4:GA4로 하는 디지털 마케팅 데이터 분석, 길벗  트래픽을 쓸어 담는 검색엔진 최적화:검색엔진이 가장 좋아하는 사이트 만들기, e비즈북스
(위 링크는 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.)