지식 정리 📝

React i18n 다국어 처리 빌드 크기 최적화 2

엄성준 2025. 12. 30. 20:25
728x90

기존에 작성했던 React i18n 다국어 처리 빌드 크기 최적화 1 글에 이어지는 내용입니다.

 

이전 글에서는 프로젝트 내 src 하위에서 관리하던 다국어 파일을 public 디렉터리로 분리하고, i18next-http-backend를 활용해 런타임 시 필요한 언어만 로드하도록 개선하면서 JS 번들 크기와 초기 로딩 성능을 개선한 경험을 공유했습니다.

 

이번 글에서는 그 다음 단계로, Google Sheet로 관리하던 다국어 데이터를 페이지 단위로 분리해 각 페이지에서 정말 필요한 다국어만 로드하도록 최적화한 과정을 정리해보려고 합니다.


key 설계 배경: namespace.key 구조를 미리 선택한 이유

이번 최적화는 갑자기 구조를 바꿔서 진행한 작업은 아니었습니다. 실제로 다국어를 처음 설계할 당시부터, 추후 페이지 단위 분리를 염두에 두고 key 구조를 설계해두었기 때문입니다.

 

아래는 Autowini 서비스에서 실제로 사용 중인 다국어 관리 Google Sheet 구조입니다.

Autowini 다국어 관리 sheet

다국어 key는 다음과 같은 기준으로 작성했습니다.

  • 여러 페이지에서 공통으로 사용될 가능성이 높은 단어는 search 처럼 단일 key로 선언
  • 특정 페이지나 UI 영역에만 종속되는 문구는 myWini.saved, shippingSchedule.title, userSideMenu.username 처럼
    namespace.key 형태로 명확하게 분리

Google Sheet → 네임스페이스별 JSON 분리

이번 개선에서는 언어별로 하나의 번역 파일을 생성하던 방식 대신, key 기준 네임스페이스 분리를 통해 페이지 단위 JSON 파일을 생성하도록 로직을 확장했습니다. 이를 통해 번역 리소스를 페이지(기능) 단위로 관리할 수 있도록 구조를 한 단계 더 개선했습니다.

 

동작 방식은 다음과 같습니다.

  • Google Sheet에서 다국어 데이터를 조회
  • key에 .이 포함된 경우 → . 앞을 네임스페이스로 판단
  • .이 없는 key는 → 공통 번역으로 간주해 common 네임스페이스로 분류
  • 언어별 · 네임스페이스별로 JSON 파일 생성

전체 로직은 비교적 단순하며, 핵심이 되는 부분만 보면 아래와 같은 구조입니다.

const keyParts = key.split('.');
const namespace = keyParts.length > 1 ? keyParts[0] : 'common';
const actualKey = keyParts.length > 1 ? keyParts.slice(1).join('.') : key;

 

이 구조를 통해 결과적으로 다음과 같은 형태의 파일이 생성됩니다.

  • /locales/ko/common.json
  • /locales/ko/myWini.json
  • /locales/ko/shippingSchedule.json
  • /locales/ko/userSideMenu.json

실제 다국어 .json 파일 구축 화면


네임스페이스 분리 후 i18n .ts설정

i18n
  .use(HttpBackend)
  .use(initReactI18next)
  .init({
    supportedLngs: supportLanguages,
    fallbackLng: false,
    ns: ['common', 'seo'],
    lng: supportLanguages.includes(getCookieValue(PROPERTY_LANGUAGE) ?? '')
      ? getCookieValue(PROPERTY_LANGUAGE)!
      : fallbackLng,
    debug: false,
    backend: {
      loadPath: '/w/react-route/locales/{{lng}}/{{ns}}.json',
    },
    interpolation: {
      escapeValue: false,
    },
  });

export default i18n;

 

loadPath 경로를 언어 + 네임스페이스 단위 구조에 맞게 수정했고, 모든 페이지에서 공통으로 사용되는 common, seo 네임스페이스는 초기 로딩 시 함께 로드되도록 설정했습니다.

 

이렇게 구성함으로써 페이지 진입 시 반드시 필요한 공통 번역은 즉시 사용할 수 있고, 페이지별로 필요한 나머지 네임스페이스는 이후 필요한 시점에만 로드할 수 있도록 구조를 분리했습니다.


느낀 점

이전에는 설정된 언어에 해당하는 다국어 .json 파일만 로드하도록 최적화했다면, 이번 개선에서는 한 단계 더 나아가 필요한 페이지의 다국어 .json 파일만 로드하도록 구조를 최적화했습니다. 이 덕분에 추후 모든 레거시 JSP 페이지를 React로 분리하더라도, 빌드 사이즈 증가나 초기 렌더링 성능 저하와 같은 문제를 미리 보완할 수 있었다고 생각합니다.