i18n(국제화)이란 응용 프로그램을 다양한 지역에 맞게 조정하는 시스템이다. 여기서는 한국어, 영어 정도의 번역만 다룬다.
next-i18next.config.js 파일을 통해 next-i18next에 대한 구성 환경을 제공한다. 환경 세팅 후 appWithTranslation을 useTranslation 훅에 있는 메서드(?)인 t를 통해서 해당 url에 맞는 번역 기능을 제공한다.
npm i next-i18next // yarn add next-i18next
// next-i18next.config.js
module.exports = {
i18n: {
defaultLocale: "ko",
locales: ["en", "ko"],
},
};
// next.config.js
const { i18n } = require("./next-i18next.config");
module.exports = {
i18n,
};
public/locales 에 만들어주면 된다.
public/locales/en/about.json
public/locales/ko/about.json
// public/locales/ko/about.json
{
"h1": "어바웃 페이지",
"description": "안녕하세요 어바웃 페이지입니다.",
"currentUrl": "현재 url"
}
// public/locales/en/about.json
{
"h1": "About Page",
"description": "Hello this is about page",
"currentUrl": "current url"
}
serverSideTranslations 통해서 locale 정보를 넘겨주고
useTranslation 훅을 통해서 해당 json 에 값을 반환한다.
// /pages/about.tsx
import React from 'react'
import { useRouter } from 'next/router'
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import { useTranslation } from 'next-i18next'
export const getStaticProps = async ({ locale }: any) => ({
props: {
...(await serverSideTranslations(locale, ['about'])),
},
})
const AboutPage: React.FC = () => {
const router = useRouter()
const { t } = useTranslation('about')
return (
<div>
<h1>{t('h1')}</h1>
<ul>
<li>
{t('currentUrl')} : http://localhost:3000
{router.locale !== 'ko' && '/' + router.locale}
{router.pathname}
</li>
<li>locale: {router.locale}</li>
<li>pathname: {router.pathname}</li>
</ul>
</div>
)
}
export default AboutPage
리액트는 컴포넌트화를 많이 하는데 같은 페이지 내에서 prop으로 넘길 필요없이 useTranslation 훅을 사용할 수 있다.
import React from 'react'
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import { AboutHeader, AboutUrlInfo } from '@components/about'
export const getStaticProps = async ({ locale }: any) => ({
props: {
...(await serverSideTranslations(locale, ['about'])),
},
})
const AboutPage: React.FC = () => {
return (
<div>
<AboutHeader />
<AboutUrlInfo />
</div>
)
}
export default AboutPage
components/about/
-useGetUlElement.tsx
import React from 'react'
import { useRouter } from 'next/router'
import { useTranslation } from 'next-i18next'
const useCurrentUrl = () => {
const router = useRouter()
const { t } = useTranslation('about')
const ulElement = (
<ul>
<li>
{t('currentUrl')} : http://localhost:3000
{router.locale !== 'ko' && '/' + router.locale}
{router.pathname}
</li>
<li>locale: {router.locale}</li>
<li>pathname: {router.pathname}</li>
</ul>
)
return { ulElement }
}
export default useCurrentUrl
import { useTranslation } from 'next-i18next'
import useCurrentUrl from './useGetUlElement'
export const AboutHeader = () => {
const { t } = useTranslation('about')
return <h1>{t('h1')}</h1>
}
export const AboutUrlInfo = () => {
const { ulElement } = useCurrentUrl()
return ulElement
}
위 파일에서 알 수 있듯이 prop으로 t 메서드를 넘길 필요가 없다.
물론 넘길 수도 있다.
_app.tsx 파일에서 localStorage를 활용해서 적용해보았다.
간편한 사용예시라 더 세심하게는 만들지 못했지만
이 부분은 당연히 custom hook으로 만드는 게 더 좋을 거 같다.
// pages/_app.tsx
...
React.useEffect(() => {
if (router.isReady) return
const lang = document.documentElement.lang
const locale = window.localStorage.getItem('locale')
const { pathname } = router
if (['en', 'ko'].includes(lang) && !locale) {
window.localStorage.setItem('locale', lang)
router.replace(`/${lang}${pathname}`)
} else {
window.localStorage.setItem('locale', `${router.locale}`)
router.replace(`/${locale}${pathname}`)
}
}, [router.isReady])
...
i18에 대한 고민이 사실 많지는 않았는데 이번 프로젝트에 적용을 하면서 사용법도 보고 글도 정리해서 좋았다.
강력하고 좋은 라이브러리인데 아쉬운 점도 있었다.
defaultLocale
이라는 key 값의 value로 단순하게 'ko' 또는 'en'을 넣기보다는 브라우저 언어설정에 따라가고 싶은데 그 부분이 없어서(?) 아쉬웠고, 조금 헤맸던 거 같다.
localeDetection: true 설정하시면 next.js 에서 browser header를 체크해서 사용자가 사용중인 언어를 감지합니다,