i18n 이란?
i18n(국제화)이란 응용 프로그램을 다양한 지역에 맞게 조정하는 시스템이다. 여기서는 한국어, 영어 정도의 번역만 다룬다.
기본 동작 원리
next-i18next.config.js 파일을 통해 next-i18next에 대한 구성 환경을 제공한다. 환경 세팅 후 appWithTranslation을 useTranslation 훅에 있는 메서드(?)인 t를 통해서 해당 url에 맞는 번역 기능을 제공한다.
next-i18next 설치
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,
};
locale 파일 생성
public/locales 에 만들어주면 된다.
public
/locales
/en
/about.json
/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"
}
about 페이지
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
- 경로가 default인 경우
- 경로가 en인 경우
사용 사례
리액트는 컴포넌트화를 많이 하는데 같은 페이지 내에서 prop으로 넘길 필요없이 useTranslation 훅을 사용할 수 있다.
- about page
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
- about component
components/about/
index.tsx
useGetUlElement.tsx
-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
- index.tsx
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 메서드를 넘길 필요가 없다.
물론 넘길 수도 있다.
브라우저 언어설정(locale)에 따른 i18적용 예시
_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에 대한 고민이 사실 많지는 않았는데 이번 프로젝트에 적용을 하면서 사용법도 보고 글도 정리해서 좋았다.
강력하고 좋은 라이브러리인데 아쉬운 점도 있었다.
- next-i18next.config.js 파일에서
defaultLocale
이라는 key 값의 value로 단순하게 'ko' 또는 'en'을 넣기보다는 브라우저 언어설정에 따라가고 싶은데 그 부분이 없어서(?) 아쉬웠고, 조금 헤맸던 거 같다. - 주소창에 defaultLocale 언어가 아니면 해당 언어가 남아서 조금 별로였다. 이건 어떻게 해줄 수 있을 거 같은데 나중에 깊게 다루게 된다면 보면 좋을 거 같다.
'FrontEnd' 카테고리의 다른 글
[Typescript] satisfies (0) | 2024.11.20 |
---|---|
[TypeScript] keyof/typeof 팁 (0) | 2024.02.21 |
[css] 아래에서 위로 올라오는 애니메이션(?) (0) | 2022.08.23 |
브라우저 렌더링 (0) | 2022.07.23 |
next.js 에서 _middleware.ts의 역할과 최근 활용 예시 (0) | 2022.05.22 |
댓글