Introduction | react-i18next documentation
Last updated 2 months ago
react.i18next.com
1단계: 기본 설정 및 번역 시스템 이해
목표
- 번역 키를 관리하는 JSON 구조를 익히고
- react-i18next를 사용해 컴포넌트에서 번역하는 흐름을 완전히 이해
1. i18n이란?
- i18n = internationalization의 줄임말 (i와 n 사이에 18글자)
- 앱을 여러 언어로 지원할 수 있도록 구성하는 기술
- 문자열, 날짜, 단위 등을 사용자 언어에 맞게 자동 출력하도록 지원
2. i18next와 react-i18next
- i18next: 국제화 핵심 엔진 (JS 기반)
- react-i18next: i18next를 React에서 쉽게 쓰도록 만든 래퍼 라이브러리
3. 설치
npm install i18next react-i18next
4. 디렉토리 구조
src/
├── i18n/
│ └── config.ts
├── locales/
│ ├── en/
│ │ └── translation.json
│ └── ko/
│ └── translation.json
5. 번역 JSON 파일 구조
locales/en/translation.json
{
"greeting": "Hello, {{name}}!",
"user": {
"profile": {
"name": "Name",
"email": "Email"
}
},
"button": {
"save": "Save",
"cancel": "Cancel"
}
}
locales/ko/translation.json
{
"greeting": "안녕하세요, {{name}}님!",
"user": {
"profile": {
"name": "이름",
"email": "이메일"
}
},
"button": {
"save": "저장",
"cancel": "취소"
}
}
6. i18n 초기화 (src/i18n/config.ts)
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import en from '../locales/en/translation.json';
import ko from '../locales/ko/translation.json';
i18n
.use(initReactI18next) // React에 연결
.init({
resources: {
en: { translation: en },
ko: { translation: ko },
},
lng: 'ko', // 초기 언어
fallbackLng: 'en', // 없는 경우 대체
interpolation: {
escapeValue: false, // React에선 XSS 방지 불필요
},
});
export default i18n;
7. i18n 초기화 연결 (src/main.tsx 또는 index.tsx)
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './i18n/config'; // 반드시 App보다 먼저 import
const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render(<App />);
8. 컴포넌트에서 번역 사용 예시
import { useTranslation } from 'react-i18next';
function Profile() {
const { t } = useTranslation();
return (
<div>
<h1>{t('user.profile.name')}</h1>
<p>{t('user.profile.email')}</p>
<button>{t('button.save')}</button>
</div>
);
}
9. 폴더 구조/네이밍 팁
- 도메인 단위로 분리 가능 (예: auth.json, dashboard.json)
- 통합형 translation.json vs. 모듈별 네임스페이스 방식 선택 가능 (→ 2단계에서 다룸)
2단계: 언어 전환 및 커스텀 설정
목표
- 사용자가 직접 언어를 선택할 수 있게 만들고
- 브라우저 설정, 로컬스토리지, URL 등 다양한 방식으로 언어 상태를 감지하고 반영하기
1. 언어 변경 및 확인
언어 변경
import i18n from 'i18next';
i18n.changeLanguage('ko'); // 즉시 한국어로 전환
현재 언어 확인
console.log(i18n.language); // 예: "en"
2. 컴포넌트
import { useTranslation } from 'react-i18next';
export const LanguageSelector = () => {
const { i18n } = useTranslation();
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
i18n.changeLanguage(e.target.value);
};
return (
<select onChange={handleChange} value={i18n.language}>
<option value="en">English</option>
<option value="ko">한국어</option>
</select>
);
};
이 컴포넌트를 헤더나 앱의 상단에 배치하면 됩니다.
3. 기본 언어, fallback 언어 설정
i18n.init({
lng: 'ko', // 기본 언어
fallbackLng: 'en', // 번역 키가 없을 경우 대체 언어
// ...
});
4. 브라우저 언어 감지 (i18next-browser-languagedetector)
설치
npm install i18next-browser-languagedetector
설정 (i18n/config.ts)
import LanguageDetector from 'i18next-browser-languagedetector';
i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
// ...
detection: {
order: ['localStorage', 'cookie', 'navigator', 'htmlTag'],
caches: ['localStorage'], // 설정한 언어를 localStorage에 저장
},
});
- 순서대로 감지합니다: localStorage → 쿠키 → 브라우저 → <html lang="">
- 캐시 저장을 통해 사용자가 선택한 언어를 유지
5. 다국어 URL 설계 (/en/about, /ko/about 등)
방식 1: react-router나 wouter에서 경로를 언어별로 구성
<Route path="/:lang/about">
<AboutPage />
</Route>
방식 2: 언어에 따라 리디렉션
const { lang } = useParams();
i18n.changeLanguage(lang); // URL에서 언어를 읽어 설정
정리
| i18n.changeLanguage() | 언어 수동 전환 |
| i18n.language | 현재 설정된 언어 반환 |
| LanguageDetector | 브라우저/쿠키/로컬스토리지에서 감지 가능 |
| LanguageSelector | 사용자 언어 선택 UI |
| fallbackLng | 번역 누락 시 대체 언어 설정 |
| 다국어 URL 지원 | URL 경로에서 언어 구분 |
3단계: 복잡한 번역 처리
목적: 실제 UI에서 동적 데이터 및 HTML 포함된 텍스트를 정확하고 안전하게 처리하기
1. 문자열 보간 (Interpolation)
변수값을 문자열에 삽입
JSON:
{
"greeting": "Hello, {{name}}!"
}
사용:
t('greeting', { name: userName });
2. 조건부 번역 (Plural Forms)
단수/복수 등 숫자에 따라 다르게 번역
JSON:
{
"item": "{{count}} item",
"item_plural": "{{count}} items"
}
사용:
t('item', { count: 1 }); // "1 item"
t('item', { count: 5 }); // "5 items"
3. <Trans> 컴포넌트 사용법
HTML 태그나 리액트 컴포넌트를 번역에 포함할 때 사용
JSON:
{
"welcome": "Welcome to <strong>{{siteName}}</strong>!"
}
사용:
import { Trans } from 'react-i18next';
<Trans i18nKey="welcome" values={{ siteName: 'MySite' }} components={{ strong: <strong /> }} />
※ components 안에 들어간 태그가 <strong>처럼 그대로 번역문에 적용됩니다.
4. React 요소 포함된 텍스트 안전하게 출력
- <br />, <strong>, 링크 같은 마크업 포함
- <Trans>로 안전하게 구성
- dangerouslySetInnerHTML은 지양 (XSS 위험)
5. 다국어 폼 에러 메시지 대응
JSON:
{
"errors": {
"required": "This field is required.",
"email": "Please enter a valid email address."
}
}
사용:
t('errors.required');
실제 react-hook-form이나 Zod의 에러 메시지 매핑 시 유용
6. 공통 메시지 분리
- 단일 JSON에 몰아서 관리하지 않기
- 기능별, 영역별로 나눔
예:
└── locales/
├── en/
│ ├── common.json
│ ├── buttons.json
│ └── errors.json
└── ko/
├── common.json
├── buttons.json
└── errors.json
초기화 예시:
resources: {
en: {
common: require('./locales/en/common.json'),
buttons: require('./locales/en/buttons.json'),
errors: require('./locales/en/errors.json')
}
}
사용:
t('buttons.save'); // buttons.json에서 "save" 키 사용
t('errors.email'); // errors.json에서 이메일 에러
| 문자열 보간 | 사용자 이름, 날짜 등 동적 데이터 출력 |
| 복수형 처리 | 1 item vs 2 items |
| <Trans> | <strong>, <br />, <a> 등 포함한 텍스트 번역 |
| 안전한 요소 출력 | XSS 걱정 없는 방식으로 UI에 번역 삽입 |
| 에러 메시지 대응 | 폼 유효성 에러 다국어 대응 |
| 공통 JSON 파일 분리 | 메시지 재사용성과 유지 보수 향상 |
4단계: 최적화 및 고급 설정
목적: 성능 최적화, 비동기 번역 로딩, SSR 등 실무 확장 적용
1. resources 대신 backend 비동기 로딩
기본 개념
- 모든 번역 JSON을 초기 번들에 포함하면 비효율적
- i18next-http-backend를 이용해 필요할 때 번역 파일을 가져옴
설정 예시:
import i18n from 'i18next';
import HttpBackend from 'i18next-http-backend';
import { initReactI18next } from 'react-i18next';
i18n
.use(HttpBackend)
.use(initReactI18next)
.init({
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json', // 언어, namespace별 경로
},
fallbackLng: 'en',
ns: ['common', 'auth'],
defaultNS: 'common',
});
2. 언어 변경 시 Flash 방지
문제: i18n.changeLanguage() 직후 빈 화면이나 영어가 보이는 순간 발생
해결:
- useSuspense: true 설정
- <Suspense fallback={<Loading />} /> 사용으로 딜레이 처리
import { Suspense } from 'react';
<Suspense fallback={<div>Loading translations...</div>}>
<App />
</Suspense>
3. 번역 캐싱
브라우저에 번역 결과를 저장하여 재방문 시 빠르게 로딩
i18next-localstorage-backend 사용
- 번역을 localStorage에 저장해 불필요한 요청 방지
import LocalStorageBackend from 'i18next-localstorage-backend';
i18n
.use(LocalStorageBackend)
.init({
backend: {
prefix: 'i18next_res_',
expirationTime: 7 * 24 * 60 * 60 * 1000, // 7일
}
});
4. Lazy Load (언어별 코드 분할)
- 초기 로딩 시 ko/common.json만 불러오고, 다른 언어/네임스페이스는 이후 로딩
- 코드 스플리팅 + 성능 최적화
i18n.init({
ns: ['common'],
defaultNS: 'common',
preload: ['en', 'ko'], // 사전 로딩하고 싶은 언어
});
5. SSR 대응 (Next.js 등)
클라이언트 이전에 서버에서 번역된 결과를 내려줌
핵심 이슈:
- 번역 준비 전 렌더링 → mismatch 발생
- hydration 오류 등
6. next-i18next 활용 (Next.js 공식 통합 모듈)
기능:
- SSR 자동 처리
- 페이지별 namespace 지정
- getStaticProps로 사전 번역 fetch
구조 예시:
/public/locales/en/common.json
/public/locales/ko/common.json
사용 예시:
// pages/index.tsx
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
export async function getStaticProps({ locale }) {
return {
props: {
...(await serverSideTranslations(locale, ['common', 'home'])),
},
};
}
7. namespace 모듈화
- JSON 파일을 기능 단위로 분할 (auth, profile, settings 등)
- 유지보수성과 협업 효율 향상
사용 예:
t('auth.login'); // auth.json
t('profile.name'); // profile.json
i18n.init({
ns: ['common', 'auth', 'profile'],
defaultNS: 'common',
});
| 비동기 로딩 | 서버에서 JSON 파일을 fetch로 불러옴 |
| Flash 방지 | Suspense로 로딩 처리 |
| 번역 캐싱 | localStorage 백엔드 사용 |
| Lazy load | 필요한 언어만 나중에 로딩 |
| SSR | 서버에서 번역 처리 (Next.js) |
| next-i18next | SSR + 번역 통합 지원 |
| namespace 모듈화 | 기능별 JSON 분할 |
5단계: 다국어 프로젝트 실전 적용 예시
목적: 실무 수준의 다국어 시스템을 실제 프로젝트에 통합 적용
1. 실시간 언어 전환 가능한 Header 구현
- useTranslation()과 i18n.changeLanguage() 사용
- 드롭다운/버튼으로 언어 선택 UI 구성
- 선택 언어를 상태로 저장 (예: localStorage)
const LanguageSelector = () => {
const { i18n } = useTranslation();
const changeLanguage = (lng: string) => {
i18n.changeLanguage(lng);
localStorage.setItem('lng', lng);
};
return (
<select onChange={(e) => changeLanguage(e.target.value)} value={i18n.language}>
<option value="en">English</option>
<option value="ko">한국어</option>
</select>
);
};
2. 각 페이지 별 다국어 대응
- 페이지 제목, 버튼 텍스트, 메시지 전부 t() 함수로 처리
- 공통 키는 common.json, 기능별로 auth.json, dashboard.json 등 분리
const { t } = useTranslation(['auth']);
return <button>{t('auth.login_button')}</button>;
3. Zustand / Recoil 과 연계한 언어 상태 관리
- i18n.language → 전역 상태로 저장
- 앱 전반에서 현재 언어를 참조하거나 조건 처리 가능
// Zustand 예시
import { create } from 'zustand';
export const useLanguageStore = create((set) => ({
language: 'en',
setLanguage: (lng: string) => {
i18n.changeLanguage(lng);
set({ language: lng });
},
}));
4. <title> 태그 등 메타정보 번역 (SEO 대응)
- react-helmet or next/head와 t() 결합
- 페이지마다 다국어로 타이틀/설명 표시
import { Helmet } from 'react-helmet';
<Helmet>
<title>{t('page.home.title')}</title>
<meta name="description" content={t('page.home.desc')} />
</Helmet>
5. SEO 대응 (Next.js or SSG 환경)
- next-i18next와 getStaticProps() 사용
- SSR로 미리 번역된 HTML 렌더링 → 크롤러 최적화
export async function getStaticProps({ locale }) {
return {
props: {
...(await serverSideTranslations(locale, ['home'])),
},
};
}
- hreflang 태그로 언어별 SEO 강화
<Head>
<link rel="alternate" hrefLang="en" href="https://example.com/en" />
<link rel="alternate" hrefLang="ko" href="https://example.com/ko" />
</Head>
6. 마이크로 프론트엔드(MFE)에서 공유된 다국어 시스템 설계
- 각 마이크로 앱에서 공통 i18n 인스턴스를 참조하거나 공유 모듈화
- 글로벌 i18n 설정은 컨테이너 앱이 주입하거나 CDN 기반으로 통합
// 공통 i18n.ts
export const initI18n = (lng = 'en') =>
i18n
.use(initReactI18next)
.init({
lng,
fallbackLng: 'en',
resources: {
en: { translation: en },
ko: { translation: ko },
},
});
- 상태 공유를 위해 zustand, redux, 또는 event bus 사용
실전 적용 시 주요 체크리스트
| 실시간 언어 전환 | UX 개선, 글로벌 유저 지원 |
| 페이지별 번역 | 기능별 모듈화 및 가독성 |
| 전역 상태 연동 | 동기화된 앱 환경 구성 |
| 메타 번역 | SEO 대응 및 접근성 |
| SSR/SSG 대응 | 검색엔진 최적화 |
| MFE 구조 설계 | 대규모 시스템 확장 대비 |
'JavaScript > React' 카테고리의 다른 글
| npm React 라이브러리 배포 (0) | 2025.06.13 |
|---|---|
| template 자동화 (0) | 2025.06.12 |
| 상태 관리 라이브러리 valtio (0) | 2025.06.09 |
| wouter (0) | 2025.06.09 |
| React-Spring (3) | 2025.05.23 |