[React] react-i18next 다국어를 위한 JSON 파일 한번에 생성하기
React로 진행하던 웹 프로젝트에서 외국인을 위해서 여러 언어를 지원하는 기능을 도입하자는 얘기가 나왔다. 서비스 주요 대상이 외국인이었기 때문에 한국어, 영어, 중국어, 일본어, 베트남어 등 많은 언어를 지원해야 한다. 그래서 리액트 프로젝트에 국제화 서비스를 도입하기 위해 react-i18next 라이브러리를 사용하기로 하였다.
react-i18next 사용법
react-i18next은 번역을 위한 JSON 파일을 언어별로 준비하고 useTranslation Hook에서 반환해서는 t 함수를 통해 key 값을 넘겨주면 value를 반환하는 방식으로 동작한다.
아래는 각각 한국어, 영어에 해당하는 JSON을 작성한 결과이다.
- 한국어
// locales/ko/common.json
{
"Hello": "안녕하세요",
"welcome": "사이트에 오신걸 환영합니다."
}
- 영어
// locales/en/common.json
{
"Hello": "Hello",
"welcome": "welcome to our site"
}
그리고 아래와 같이 i18n파일을 작성하고 index.tsx 혹은 main.tsx에 import한다.
- i18n
// i18n.ts
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import enCommon from '../locales/en/common.json';
import koCommon from '../locales/ko/common.json';
const resources = {
en: {
common: enCommon,
},
ko: {
common: koCommon,
},
};
i18n.use(initReactI18next).init({
resources,
lng: 'ko',
fallbackLng: 'en',
ns: ['common'],
defaultNS: 'common',
interpolation: {
escapeValue: false,
},
});
export default i18n;
- main.tsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.tsx';
import './global.css';
import '../i18n/i18n.ts';
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
);
- App.tsx
import useTranslation from 'react-i18next';
const App = () => {
const t = useTranslation('common'); // 언어별 common.json을 가져옴
return (
<div>
{/* 한국어일 땐 "안녕하세요.", 영어일 땐 "Hello" */}
<div>{t('Hello')}</div>
</div>
);
};
문제점
많은 언어를 지원해야 되는 서비스에서 기존 방식을 사용하게 되면 여러 개의 JSON 파일을 일일히 작성하게 되면서 특정 key를 빼먹는다거나 key 혹은 value에서 오타가 발생하는 경우가 발생할 확률이 높아진다.
해결 방법
CSV 파일에 모든 언어 key, value 작성
서비스에서 지원하는 언어의 JSON 파일을 생성하기 위해 csv 파일을 작성한다. 첫 열에 key를 작성해주고 그 뒤에 추가하고싶은 언어를 추가한 다음 key값에 대한 번역 텍스트를 value로 작성해준다.
- translations/translations.csv
key,ko,en
Hello,안녕하세요,Hello
welcome,사이트에 오신 것을 환영합니다,welcome to our site
csv-parser 라이브러리 설치
Node.js 환경에서 CSV를 파싱하기 위해 csv-parer 라이브러리를 설치한다.
npm install -D csv-parser
CSV 파일을 읽고 JSON 파일을 생성하는 함수를 구현
csv파일을 읽고 react-i18next에서 사용하기 위한 JSON파일을 생성하는 generateTranslatinos 함수를 구현한다.
- scripts/generateTranslations.js
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import fs from 'fs';
import csv from 'csv-parser';
// __filename, __dirname 대신 사용할 수 있는 ESM 전용 코드
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// CSV 파일 경로 및 출력 디렉터리 설정
const csvFilePath = join(__dirname, '..', 'translations', 'translations.csv');
const localesPath = join(__dirname, '..', 'public', 'locales');
// 언어별 번역 데이터를 담을 객체
const translations = {};
// CSV 파일을 스트림으로 읽고, 각 행(row)을 처리
fs.createReadStream(csvFilePath)
.pipe(csv())
.on('data', row => {
const translationKey = row.key;
for (const lang in row) {
if (lang === 'key') continue;
if (!translations[lang]) {
translations[lang] = {};
}
translations[lang][translationKey] = row[lang];
}
})
.on('end', () => {
console.log('CSV 파일 읽기 완료!');
// 언어별로 common.json 파일 생성
for (const lang of Object.keys(translations)) {
const langDir = join(localesPath, lang);
if (!fs.existsSync(langDir)) {
fs.mkdirSync(langDir, { recursive: true });
}
const jsonFilePath = join(langDir, 'common.json');
fs.writeFileSync(
jsonFilePath,
JSON.stringify(translations[lang], null, 2),
'utf8',
);
console.log(`${lang} -> ${jsonFilePath} 생성 완료`);
}
});
translations[lang][translatinoKey] = row[lang]를 통해 CSV의 해당 언어 텍스트를 JSON으로 매핑한다. 그리고 public/locales/[언어]/common.json에 저장되면 react-i18next가 인식할 수 있게된다.
Node.js 환경에서 generateTranslations 함수 실행
터미널에 아래 명령어를 입력하면 generateTranslations 함수가 실행되어 csv파일을 파싱하여 json파일을 생성후 public/locales/[언어]/common.json에 저장된다.
npm exec scripts/generateTranslations.js
(Optional) JSON 파일 생성 자동화 적용하는 법
깃허브에 push를 했을 경우 translations.csv 파일에 변화가 생기면 자동으로 JSON 파일을 생성하고자 깃허브 액션 워크플로우를 아래와 같이 작성하였다.
- .github/workflows/update-translations.yml
name: Update Translations
on:
push:
paths:
- 'translations/**'
workflow_dispatch:
jobs:
update-translations:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Generate translation JSON
run: npm exec scripts/generateTranslations.js
- name: Commit updated translations
run: |
git config --global user.name "github-actions"
git config --global user.email "github-actions@github.com"
git add public/locales
git diff --cached --quiet || (git commit -m "chore: update translations" && git push)
결과
터미널을 통해 generateTranslations 함수를 실행한 결과 JSON 파일이 잘 생성된 것을 확인할 수 있다.(필자는 mainPage.json도 생성하도록 하였음)