TIL 80 | react-i18next로 다국어처리 해보기

meow·2020년 12월 1일
15

React

목록 보기
26/33

처음 일을 시작하고 jsx나 tsx 파일에 텍스트를 직접 마크업하지 않은 것을 보고 멘붕이 왔었다. t( '...' ) 이런 식으로 내용을 적용한 것을 볼 수 있었는데, 이게 i18n을 사용해서 국제화 작업을 한 것임을 알아냈을때 유레카를 외치고 싶을 정도였다. ㅋㅋㅋㅋㅋ 적응되니 너무너무 편하고 좋은 라이브러리! 다시 한번 정리해보자.

i18next

i18next는 자바스크립트에서 국제화 프레임워크로 쓰인다. Node.js, PHP, iOS, Android 및 기타 플랫폼과 함께 i18next를 사용할 수도 있다.

react-i18next 라이브러리 시작하기

프로젝트에 패키지를 설치한다.

# npm
$ npm install react-i18next --save
# yarn
$ yarn add react-i18next

Example

import React from "react";
import ReactDOM from "react-dom";
import i18n from "i18next";
import { useTranslation, initReactI18next } from "react-i18next";

i18n
  .use(initReactI18next) // passes i18n down to react-i18next
  .init({
    resources: { // 여기에 사용할 언어와 키와 번역될 키 값을 넣으면 된다.
      en: {
        translation: {
          "Welcome to React": "Welcome to React and react-i18next"
        }
      }
    },
    lng: "en",
    fallbackLng: "en",

    interpolation: {
      escapeValue: false
    }
  });

function App() {
  const { t } = useTranslation();

  return <h2>{t('Welcome to React')}</h2>; // 이렇게 지정된 키를 적어 사용한다.
}

// append app to dom
ReactDOM.render(
  <App />,
  document.getElementById("root")
);

App이 실행되면 <h2>Welcome to React and react-i18next</h2> 가 나온다! 보통은 번역할 내용이 많기 때문에 따로 파일을 빼서 import 하여 사용하는 것이 일반적이다. 위 코드를 하나씩 뜯어보자.

i18next.use(module)

use 함수는 i18next에 추가적인 플러그인을 적용할때 사용된다.

import i18next from 'i18next';
import Backend from 'i18next-http-backend';
import Cache from 'i18next-localstorage-cache';
import postProcessor from 'i18next-sprintf-postprocessor';
import LanguageDetector from 'i18next-browser-languagedetector';

i18next
  .use(Backend)
  .use(Cache)
  .use(LanguageDetector)
  .use(postProcessor)
  .init(options, callback);

위 플러그인 중에서 LanguageDetector 만 사용해봤는데, 여기서 자세한 내용을 볼 수 있다. 대략 유저가 브라우저에서 어떤 언어를 쓰고 있는지 detect 하는 플러그인이라고 생각하면 된다. path를 1순위로, 그 다음 브라우저의 세팅을 2순위로 언어를 detect 한다면 아래와 같이 사용할 수 있을 것이다.

import i18next from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';

i18next.use(LanguageDetector).init({
  detection: { order: ['path', 'navigator'] }
});

위 두가지 옵션 외에도 쿠키나 스토리지, html 태그 등으로 언어를 detect 할 수 있다.

import i18n from "i18next";
import detector from "i18next-browser-languagedetector";
import { reactI18nextModule } from "react-i18next";

import translationEN from '../public/locales/en/translation.json';
import translationDE from '../public/locales/de/translation.json';

// the translations
const resources = {
  en: {
    translation: translationEN
  },
  de: {
    translation: translationDE
  }
};

i18n
  .use(detector)
  .use(reactI18nextModule) // passes i18n down to react-i18next
  .init({
    resources,
    lng: "en",
    fallbackLng: "en", // detected lng이 불가능 할때 en을 사용하겠다.

    keySeparator: false, // 'messages.welcome' 와 같은 키 형식의 form을 사용할지 여부

    interpolation: {
      escapeValue: false // react already safes from xss
      // xss가 스크립트 코드를 삽입하여 사용자를 대상으로 한 공격이라고 하는데 이건 잘 모르겠다. 흠...
    }
  });

export default i18n;

useTranslation(hook)

import React from 'react';
import { useTranslation } from 'react-i18next';

export function MyComponent() {
  const { t, i18n } = useTranslation();
  // or const [t, i18n] = useTranslation();

  return <p>{t('my translated text')}</p>
}

함수형 컴포넌트에서 t function 이나 i18n 인스턴스를 사용할 수 있게 해주는 훅이다. t function은 위에서 봤듯이 컨텐츠에 국제화 작업을 하기 위해 사용되고, i18n 인스턴스는 언어를 바꾸기 위해 사용되기도 한다.

i18n.changeLanguage('en-US');

또는 아래와 같이 언어에 따라 스타일 값이 달라져야 할때도 사용할 수 있다. 언어를 detect하기 때문!

const Title = styled.p`
  background-image: url(${imgPathPrefix}/intro-title${i18n.language === 'en' ? '-en' : ''}.png);
  background-size: ${i18n.language === 'en' ? '15vw auto' : '18vw auto'};
  background-repeat: no-repeat;
  width: ${i18n.language === 'en' ? '15vw' : '18vw'};
  height: ${i18n.language === 'en' ? '25.6vw' : '19.2vw'};
`;

코드로 다시 한번 정리하기

i18n을 사용할 때 디렉토리 트리를 단순화한 다이어그램이다.

1) i18n.js

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import { kr, en } from './locales';

i18n
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    resources: { kr, en },
    fallbackLng: ['kr', 'en'],
    interpolation: { escapeValue: false },
    detection: { order: ['path', 'navigator'] }
  });

export default i18n;

2) locales/index.js

import * as localeKr from './kr';
import * as localeEn from './en';

export const kr = { ...localeKr };
export const en = { ...localeEn };

export default { kr, en };

3) locales/en/index.js & .../kr/index.js

export { default as main } from './main';
export { default as header } from './header';
export { default as footer } from './footer';

4) locales/en/main.js

export default {
  mode: 'en',
  add: 'Add',
  cancel: 'Cancel',
  placeholder: {
    login: 'Please log in first',
    comment: 'Leave a comment',
  },
}

4) locales/kr/main.js

export default {
  mode: 'kr',
  add: '장바구니에 담기',
  cancel: '취소하기',
  placeholder: {
    login: '로그인해주세요',
    comment: '댓글을 남겨주세요',
  },
}

5) components/main.js

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

export default function Main() {
  const { t } = useTranslation('main');

  return <h2>{t('placeholder.login')}</h2>; 
  // '로그인해주세요' 또는 'Please log in first'가 컨텐츠로 적용
}

참고자료 : https://react.i18next.com/

profile
🌙`、、`ヽ`ヽ`、、ヽヽ、`、ヽ`ヽ`ヽヽ` ヽ`、`ヽ`、ヽ``、ヽ`ヽ`、ヽヽ`ヽ、ヽ `ヽ、ヽヽ`ヽ`、``ヽ`ヽ、ヽ、ヽ`ヽ`ヽ 、ヽ`ヽ`ヽ、ヽ、ヽ`ヽ`ヽ 、ヽ、ヽ、ヽ``、ヽ`、ヽヽ 🚶‍♀ ヽ``ヽ``、ヽ`、

2개의 댓글

comment-user-thumbnail
2021년 4월 6일

감사합니다 자꾸 언어 감지가 안 되었는데 이 글 보고 해결했어요!

답글 달기
comment-user-thumbnail
2021년 10월 26일

정말 도움이 많이 됐어요~~ 앞으로도 글 많이 써주세요!!

답글 달기