개발/🟦 React
[CRA/Plain React SPA] 다국어 설정 i18n.js
비니_
2025. 11. 14. 14:21
728x90
📂/src/i18n.js
import * as i18n from 'i18next'; // 다국어 핵심 라이브러리
import { initReactI18next } from 'react-i18next'; // react용 다국어 초기화
import Backend from 'i18next-http-backend'; // json파일을 HTTP로 불러오는 기능
import LanguageDetector from 'i18next-browser-languagedetector'; // 브라우저에서 언어 감지(navigator, localStorage, cookie 등)
import { getCurrentLang } from './helpers/locales'; // 프로젝트에서 현재 언어 가져오는 커스텀 함수
const defaultNS = 'translation'; // 기본 다국어 json 파일 명
const fallbackNS = [
'menus',
// 등등 폴더 내에 있는 파일들 써줘야 가져다가 쓸 수 있음
];
const ns = [defaultNS, ...fallbackNS]; // 실제 i18n 초기화 시 전체 등록할 네임스페이스 목록
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
lng: getCurrentLang(), // 초기 언어 설정
debug: false,
returnObjects: false,
returnEmptyString: false,
ns, // 등록할 모든 네임스페이스 배열
defaultNS, // 기본 참조 네임스페이스
fallbackNS, // 기본 참조에 없으면 순서대로 검색할 네임스페이스
backend: {
loadPath: `/locales/{{lng}}/{{ns}}.json?ts=${Date.now()}`, // json 파일 경로 // ts=${Date.now() 캐시 방지
},
compatibilityJSON: 'v3',
interpolation: {
escapeValue: false,
},
react: {
useSuspense: false, // suspense 없이 렌더링
transSupportBasicHtmlNodes: true, // <strong>, <br> 등 HTML 태그 번역 지원
},
saveMissing: false,
missingKeyHandler: false,
saveMissingTo: 'current',
parseMissingKeyHandler: (key) => key, // 키가 없으면 그대로 반환 ex: t('없음') -> '없음'
reloadResources: true, // 런타임에서 JSON으로 다시 로드 가능
cleanCode: true,
partialBundledLanguages: false,
});
export default i18n;
📂/src/index.js
import React from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter as Router } from 'react-router-dom';
import './styles/styles.scss';
import '@nosferatu500/react-sortable-tree/style.css';
import './i18n'; // 다국어 import
import App from './App';
import { ThemeContextProvider } from './contexts/themeContext'; // 테마 사용할 시
window.progressbar = null;
const container = document.getElementById('root');
const root = createRoot(container);
moment.tz.setDefault('Asia/Seoul');
root.render(
<Router>
<React.StrictMode>
<ThemeContextProvider>
<App />
</ThemeContextProvider>
</React.StrictMode>
</Router>,
);
-- index.js (상위 페이지)에서 import 해주면 하위 페이지에 알아서 다국어 적용 가능
- i18n.js에서 i18next.init()가 실행되면서 전역(i18next singleton) 설정이 완료됨
- 이 시점 이후에 어떤 컴포넌트에서 useTranslation()을 호출해도 동일한 i18n 인스턴스를 참조함
- 하위 컴포넌트는 useTranslation()만 쓰면 번역 가능
** 하위 컴포넌트 다국어 사용 방법
import { useTranslation } from 'react-i18next';
export default function Header(){
const { t } = useTranslation();
return(
<div>{t('test')}</div> // 기본 다국어.json에서 찾아서 나옴
<div>{t('menu.test')}</div> // menu.json에서 찾아서 나옴
)
}
** 기본 json, json 경로 등 설정 custom 컴포넌트 예시
import { useContext } from 'react';
import { useTranslation } from 'react-i18next';
import moment from 'moment';
import ThemeContext from '../contexts/themeContext';
import { getItem, setItem } from '../lib/localstorage';
const LANG_KEY = 'i18nextLng';
const LANGUAGE_LIST = {
en: {
text: 'English',
lng: 'en',
icon: 'CustomUsa',
},
ko: {
text: '한국어',
lng: 'ko',
icon: 'CustomKor',
},
};
export const getCurrentLang = () => getItem(LANG_KEY) ? getItem(LANG_KEY) : 'ko';
export const setCurrentLang = (lang) => setItem(LANG_KEY, lang);
export const getLangWithKey = (key) =>
LANGUAGE_LIST[key];
export const useChangeLanguage = () => {
const { i18n } = useTranslation();
const { setLang } = useContext(ThemeContext);
const updateLanguage = async (lang) => {
i18n.services.resourceStore.data = {};
await i18n.changeLanguage(lang);
moment.locale(lang);
setLang(lang);
setCurrentLang(lang);
}
return { updateLanguage };
}
728x90