Post

React (webpack) + electron 환경 다국어 적용기 (i18next)

들어가며

최근에 회사에서 다국어를 처음 적용해 봤다. 우리 프로젝트는

특수하게도 react로 만든 프로젝트를 webpack으로 번들링하여 electron을 실행해 번들링된 파일을 watch하는 방식이다.

그래서 이 글에서는 react에서사용하는 language를 browser에서 detect하는 라이브러리 (i18next-browser-languagedetector)를 사용할 수 없어 Electron에서 language를 detect하고 i18next에 적용하는 과정을 정리하려고한다.

react-i18next

먼저 우리는 react 환경이기 때문에 아래와 같이 i18next를 설치한다.

npm i --save-dev react-i18next

그리고 src 폴더 내에 locales 폴더를 만들고 아래와 같이 구성한다.

folders

  • kr - 한국어로 된 가이드 파일을 넣어놓는다.
  • en - 영어로 된 가이드 파일을 넣어놓는다.

src/locales/kr/common.ts

1
2
3
4
export default {
  create: "생성",
  delete: "삭제"
};

src/locales/en/common.ts

1
2
3
4
export default {
  create: "Create",
  delete: "Delete"
};

나는 파일 명을 일반적으로 common을 기본적으로 쓰이는 값으로 작성한 뒤에 페이지별로 구분하는 편이다. (개취에 맞게 쓰세요)

위와 같이 언어에 맞게 쓸 단어들을 세팅해주면 된다. (json도 상관없음)

여기서 주의할 점은 모든 언어에 key값과 파일명은 동일해야 한다 object key값과 파일명으로 매핑하기 때문이다.

그리고 이제 locales폴더에 있는 index.ts 파일에 i18next 설정을 해줄거다.

src/locales/index.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import * as localeEn from "./en";
import * as localeKr from "./kr";

export const kr = { ...localeKr };

export const en = { ...localeEn };

i18n.use(initReactI18next).init({
  resources: { en, kr },
  fallbackLng: ["en", " kr"],
  interpolation: { escapeValue: false }
});

export default i18n;

이걸로 사실 다국어 준비는 끝이다. 아래와 같이 바로 모듈을 가져와서 사용해도 되고

1
2
3
{
  i18n.t("common:created");
}

아래와 같이 라이브러리에서 제공하는 Hook을 사용해도 된다.

common같은 파일명을 구분하지 않으면 참고하는 resource에서 단어를 알아서 찾아서 매핑한다.

1
2
3
4
5
6
7
8
import { useTranslation } from "react-i18next";
const { t } = useTranslation();

{
  t("common:created");
  // 이렇게도 사용가능하다.
  t("created");
}

electron Language Detector

자 이제 서론에서 얘기했던 electron에서 detector를 설정할 때다.

우리 환경은 react와 Electron이 ipc통신을 사용하고 있어서 아래와 같이 컨트롤러를 만들었다.

electron/src/controllers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { app, BrowserWindow, ipcMain } from "electron";

export default (window: BrowserWindow) => {
  ipcMain.handle("getLocale", async (event, args) => {
    try {
      // 현재 사용자 컴퓨터의 locale을 가져온다.
      const userLocale = app.getLocale();

      return userLocale;
    } catch (error) {
      console.log(error);
    }

    return true;
  });
};

이렇게 electron에서 ipcHandle을 만들어 준 뒤 react에서 이 handle을 호출하는 Detector 모듈을 만들어 주면 된다.

languageDetector.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { electron } from "~/utils/electron";
import { ModuleType } from "i18next";

// i18next에서 module에서 사용할 수 있는 interface 정의
interface LanguageDetector {
  init: () => void;
  async: boolean;
  type: ModuleType;
  detect: () => string;
  cacheUserLanguage: () => void;
}

const languageDetector: LanguageDetector = {
  type: "languageDetector",
  async: true,
  init: () => {},
  // i18next 내부에서 languageDetector로 정의된 모듈의 detect함수를 실행시켜 반환값을 현재 언어로 설정한다.
  detect: () =>
    electron.ipcRenderer.invoke("getLocale", undefined).then((result: any) => {
      return result;
    }),
  // user의 language를 cache할 조건이 있다면 여기에 정의
  cacheUserLanguage: () => {}
};

export default languageDetector;

위와 같이 i18next에서 사용할 모듈이 만들어졌으면 이제 아래처럼 i18next에 detector를 포함해주면 끝이다!

src/locales/index.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import * as localeEn from "./en";
import * as localeKr from "./kr";
import languageDetector from "~/utils/languageDetector";

export const kr = { ...localeKr };

export const en = { ...localeEn };

i18n
  .use(languageDetector)
  .use(initReactI18next)
  .init({
    resources: { en },
    fallbackLng: ["en"],
    interpolation: { escapeValue: false }
  });

export default i18n;

마치며

이상으로 i18next 기본 설정과 electron + React 환경에서 다국어를 설정하는 detector를 만들어 적용해봤다.

보통은 web 환경에서 적용을 하겠지만, 나처럼 브라우저 환경이아닌 pc의 Locale을 가지고 다국어를 적용하려는 분들에게 도움이 되었으면 좋겠다.

This post is licensed under CC BY 4.0 by the author.