logo
Published on

Next.js에서 다국어를 지원해보자 (feat. 나의 아이돌 타입 테스트,next-i18next)

Authors
  • avatar
    Name
    Bora Choi
    Twitter

내가 해보고싶은 기능 다 ~~ 넣어보자의 끝판왕인 나의 아이돌 타입 테스트!
이번에 추가할 기능은 바로 다국어지원이었다!

Next.js에서 다국어를 지원하는 사이트를 만드는건 굉장히 쉽다. 기본적으로 라우팅에 대한 지원을 해주기때문에 i18n라이브러리와 함께 사용하면 금방 만들 수 있다.

1. next.config.js 파일에 i18n 설정하기

나는 영어를 기본으로하고 한국어, 일본어를 사용자 선호 언어에 따라서 지원에 주는기 위해 아래와 같이 설정했다. 이 외에도 domains를 설정하면 언어별로 다른 도메인으로 라우팅할 수 있다.

// next.config.js
module.exports = {
  ... ,
  i18n: {
    locales: ['en', 'ko', 'ja'],
    defaultLocale: 'en',
    },
}

2. next-i18next 라이브러리 설치 및 세팅

나는 Next.js에서 사용할 수 있는 i18n 라이브러리 중 next-i18next를 사용했다.

npm install --save next-i18next

설치가 끝났으면 next-i18next의 세팅이 필요하다. next-i18next.config.js 파일을 만들어 기본 언어와 지원 언어를 추가한다.

// next-i18next.config.js
module.exports = {
  i18n: {
    locales: ['en', 'ko', 'ja'],
    defaultLocale: 'en',
  },
}

설정 내용이 중복되기 떄문에 next.config.js에서 next-i18next.config를 임포트해주면 한곳에서만 설정을 관리할 수 있다.

// next.config.js
const { i18n } = require('./next-i18next.config')
module.exports = {
    ... ,
    i18n,
}

3. 번역 컨텐츠 추가하기

사실 다국어 지원에서 가장 시간이 걸리는 부분이 바로 이 부분인데, 이건 어쩔수 없이 직접 번역작업을 거쳐 파일을 작성해야한다. next-i18next는 번역 컨텐츠를 pulic/locales/[locale]에서 가져온다. 기본적으로 네임스페이스를 설정하지 않은 요소들은 common.json에서 가져오고 다른 페이지가 있다면 intro.json,result.json과 같이 추가해주면 된다.

  • common.json파일은 없으면 Default namespace Not Found 에러가 발생하니 빈 파일이더라도 존재해야한다.
  └─ public
     └─ locales
        ├─ en
        |  └─ common.json
        |  └─ intro.json
        |  └─ result.json
        ├─ ja
        |  └─ common.json
        |  └─ intro.json
        |  └─ result.json
        └─ ko
           └─ common.json
           └─ intro.json
           └─ result.json

번역 컨텐츠는 json 형태로 만든다. 페이지에서 불러올때 키로 값을 불러오기떄문에 키값을 통일하여 각 파일을 작성한다.

//public/locales/ja/intro.json
{
  "intro-1": "韓国を越えて全世界の人々を魅了した",
  "intro-kpop": "K-POPアイドル!",
  "intro-2": "もし私がデビューしたらどんなアイドルになるかな?アイドルのタイプを確認するには、",
  "intro-start": "テストを始めるボタン",
  "intro-3": "を押してください!",
  "start-button": "テストを始める"
}
//public/locales/ko/intro.json
{
  "intro-1": "한국을 넘어서 전 세계사람들의마음을 사로잡은 ",
  "intro-kpop": "K-pop 아이돌!",
  "intro-2": "내가 만약 데뷔를 한다면 나는 어떤 아이돌일까 ?지금 나의 아이돌 유형을 확인하려면",
  "intro-start": "시작하기",
  "intro-3": "버튼을 눌러주세요!",
  "start-button": "시작하기"
}

4. _app.jsx에서 프로젝트 전체에 적용하기

appWithTranslation함수로 _app의 MyApp 컴포넌트를 감싸주면 페이지에서 사용할 준비는 끝났다!

//_app.jsx
import { appWithTranslation } from 'next-i18next'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default appWithTranslation(MyApp)

5. 페이지에서 적용해보기

Next.js에서 router 객체에서 locale를 가져오는데 getServerSidePropsgetStaticProps를 사용해서 가져올 수 있다. 아이돌 유형 테스트는 서버통신이 없기 떄문에 getStaticProps를 사용했다. serverSideTranslationslocale과 사용할 번역 컨텐츠의 네임스페이스를 전달한후 getStaticProps의 props 로 반환한다.

//home.jsx
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'

export const getStaticProps: GetStaticProps = async ({ locale = 'en' }) => {
  return { props: { ...(await serverSideTranslations(locale, ['intro'])) } }
}

그리고 컴포넌트 내부에서는 useTranslationt를 사용하여 번역컨텐츠를 불러온다. t('컨텐츠:키') 형식으로 사용한다.

//home.jsx
import { useTranslation } from 'next-i18next'

function Home() {
  const { t } = useTranslation()

  return (
    <main>
      <p>
        {t('intro:intro-1')}
        <span>{t('intro:intro-kpop')}</span>
        {t('intro:intro-2')}
        <span> {t('intro:intro-start')}</span>
        {t('intro:intro-3')}
      </p>
      <div>
        <Link href="/test">
          <button type="button">{t('intro:start-button')}</button>
        </Link>
      </div>
    </main>
  )
}

export default Home

동적 라우팅과 함께 사용하기

getStaticProps를 동적 라우팅에서 사용할 경우 getStaticPaths와 함께 사용해야한다. 라우팅할 path를 각 locale별로 만들어줘야하는 번거로움이 있다. 또한 빌드시 각 파일들을 만들어내기때문에 path가 많을 수록 빌드 시간이 늘어날 수 있으니 주의해야한다.

//result.jsx
export const getStaticPaths: GetStaticPaths = async () => {
  return {
    paths: [
      { params: { type: '1' }, locale: 'ko' },
      { params: { type: '1' }, locale: 'ja' },
      { params: { type: '1' }, locale: 'en' },
    ],
    fallback: false,
  }
}

적용 결과물

사용자의 선호 언어에 따라 일본어와 영어를 추가 지원할 수 있도록 만들었다. 언어에 따라서 줄바꿈 속성이 다르기때문에 css를 수정해야하는 새로운 과제가 생겼지만 번역 컨텐츠는 제대로 적용 되었다.

ja

결과 페이지의 경우 동적 라우팅을 사용했는데 getStaticPaths와 함께 사용하여 이 역시도 잘 적용된 모습을 볼 수 있다.

en

아래 링크에서 실제 적용 결과를 확인해 볼 수 있다!

나의아이돌유형테스트해보기

참고

https://nextjs.org/docs/advanced-features/i18n-routing#limits-for-the-i18n-config https://i18nexus.com/nextjs-tutorial/