react에 다국어 기능 적용하기(i18next)

react에 다국어 기능 적용하기

react 프로젝트에 i18next를 사용하여 다국어 기능을 구현해보자.

일단 패키지 설치

i18next와 react-i18next 두가지를 설치해준다.

npm install react-i18next i18next

타입스크립트에 적용할때 설치

npm i i18next @types/i18next react-i18next @types/react-i18next

자동으로 사용자의 브라우저 언어를 인식하기 위한 모듈도 설치해준다. i18next-browser-languagedetector

npm install i18next-browser-languagedetector

최상단 루트에 i18n.tsx를 생성한다.

i18n.tsx

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import enTranslation from './locales/en.json'; // 바로 밑에서 만들어줄 언어시트
import koTranslation from './locales/ko.json'; // 바로 밑에서 만들어줄 언어시트

const resources = {
  en: {
    translation: enTranslation,
  },
  ko: {
    translation: koTranslation,
  },
};
i18n
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    resources,
    fallbackLng: 'ko',
    interpolation: {
      escapeValue: false,
    },
  });
export default i18n;

/src/locales 폴더를 생성 후 en.json, ko.json 파일을 생성한다.

/src/locales/en.json

{
  "test":"lang test"
}

/src/locales/ko.json

{
  "test":"언어 테스트"
}

_app.js에 적용

SSR 프로젝트에서는 <I18nextProvider>로 랩핑해줘야 한다.

_app.js에서 <I18nextProvider>로 감싸고 위에서 만든 i18n.tsx를 불러와 props로 내려준다.

import React, { useEffect, useState } from 'react';
import { AppProps } from 'next/app';
import { GlobalStyle } from '../styles/grobal-style';
import i18n from '@i18n';
import { I18nextProvider } from 'react-i18next';
function MyApp({ Component, pageProps }: AppProps) {
  const [isMounted, setIsMounted] = useState<boolean>(false);
  useEffect(() => {
    setIsMounted(true);
  }, []);
  return (
    <>
      {isMounted && (
        <I18nextProvider i18n={i18n}>
          <GlobalStyle />
          <Component {...pageProps} />
        </I18nextProvider>
      )}
    </>
  );
}
export default MyApp;

여기까지 언어변환을 사용할 기본적인 셋팅을 끝냈다.

여기서 세가지 방법으로 적용할 수가 있다.

  1. render props인 Translate 사용
  2. hook사용
  3. hoc 사용

방법 1 - render props인 Translate

공식문서

import React from 'react';
import Head from 'next/head';
import { Translation } from 'react-i18next';
function Main() {
  return (
    <div>
      <Head>
        <title>Web Admin Skeleton</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main>
        <TranslationButton />
        <Translation>{(t) => <p>{t('test')}</p>}</Translation>
        index
      </main>
    </div>
  );
}
export default Main;

Translation을 사용해서 번역할 부분을 감싸준다.

언어변환 버튼 컴포넌트 Translation.tsx

import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import i18next from 'i18next';
const Translation = () => {
  const [language, setLanguage] = useState('ko');
  useEffect(() => {
    const initLang =
      (window.localStorage.i18nextLng.substring(0, 2) === 'ko' && 'ko') || 'en';
    setLanguage(initLang);
  });
  const toggleTrans = (lang) => {
    setLanguage(lang);
    if (language != lang) {
      i18next.changeLanguage(lang, (err) => {
        if (err) return console.log('something went wrong loading', err);
      });
    }
  };
  return (
    <div>
      <TransBox>
        <TransButton onClick={() => toggleTrans('ko')}>
          <p>KO</p>
        </TransButton>
        <span>&nbsp;|&nbsp;</span>
        <TransButton onClick={() => toggleTrans('en')}>
          <p>EN</p>
        </TransButton>
      </TransBox>
    </div>
  );
};
const TransBox = styled.div`
  display: flex;
  flex-direction: row;
`;
const TransButton = styled.button``;
export default Translation;

방법 2 - hook 사용

공식문서

import React from 'react';
import Head from 'next/head';
import TranslationButton from './translation/translation';
import { useTranslation } from 'react-i18next';
function Main() {
  const { t } = useTranslation();
  return (
    <div>
      <Head>
        <title>Web Admin Skeleton</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main>
        <TranslationButton />
        <p>{t('test')}</p>
        main
      </main>
    </div>
  );
}
export default Main;

언어변환 버튼 컴포넌트 Translation.tsx

import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import { useTranslation } from 'react-i18next';

const Translation = () => {
  const { i18n } = useTranslation();
  const [language, setLanguage] = useState('ko');
  useEffect(() => {
    const initLang =
      (window.localStorage.i18nextLng.substring(0, 2) === 'ko' && 'ko') || 'en';
    i18n.changeLanguage(initLang);
    setLanguage(initLang);
  }, []);
  const onChangeLang = (lang: string) => {
    i18n.changeLanguage(lang);
    setLanguage(lang);
  };
  return (
    <div>
      <TransBox>
        {language}
        <TransButton onClick={() => onChangeLang('ko')}>
          <p>KO</p>
        </TransButton>
        <span>&nbsp;|&nbsp;</span>
        <TransButton onClick={() => onChangeLang('en')}>
          <p>EN</p>
        </TransButton>
      </TransBox>
    </div>
  );
};
const TransBox = styled.div`
  display: flex;
  flex-direction: row;
`;
const TransButton = styled.button``;
export default Translation;

방법 3 - hoc 사용

공식문서

Discussion and feedback