Next.js 다국어 처리, 한 회사에서 두 가지 방식을 쓰게 된 이유
같은 회사의 두 프로젝트가 서로 다른 i18n 구조를 사용하고 있었습니다. 단일 JSON 방식과 namespace 분리 방식을 실제 코드로 비교합니다.
같은 회사, 같은 스택, 다른 구조
같은 회사에서 Next.js 기반 프로젝트를 두 개 운영하고 있는데, 다국어(i18n) 처리 방식이 서로 달랐습니다. 둘 다 i18next를 쓰는데 구조가 다릅니다.
이유는 단순합니다. 회사 소개 페이지는 사실상 단일 페이지라 번역 키가 많지 않았고, 서비스 플랫폼은 페이지와 기능이 많아서 번역 파일이 커질 수밖에 없었습니다. 규모가 다르니 자연스럽게 구조도 달라진 거였습니다.
방식 A: 단일 JSON 파일
회사 소개 페이지에서 사용하는 방식입니다. 언어별로 JSON 파일 하나에 모든 번역을 넣습니다.
파일 구조:
src/i18n/
├── locales/
│ ├── en.json ← 영어 번역 전체
│ └── ko.json ← 한국어 번역 전체
├── client.ts
├── settings.ts
└── provider.tsx
client.ts 핵심 코드:
import enJSON from "./locales/en.json";
import koJSON from "./locales/ko.json";
const resources = {
en: { translation: enJSON },
ko: { translation: koJSON },
};
i18next.use(initReactI18next).init({
resources,
lng: defaultLocale,
fallbackLng: defaultLocale,
});
사용:
const { t } = useTranslation();
t("hero.title"); // "AI 데이터 인프라를 구축하세요"
t("contact.sendMessage"); // "메시지 보내기"
정적 import라서 빌드 시점에 모든 번역이 번들에 포함됩니다. 설정이 단순하고, 별도의 로딩 없이 바로 번역을 사용할 수 있습니다.
방식 B: namespace별 JSON 파일
서비스 플랫폼에서 사용하는 방식입니다. 기능(namespace)별로 JSON 파일을 분리합니다.
파일 구조:
src/utils/localization/
├── locales/
│ ├── en/
│ │ ├── common.json
│ │ ├── privacy.json
│ │ ├── service.json
│ │ └── marketing.json
│ └── ko/
│ ├── common.json
│ ├── privacy.json
│ ├── service.json
│ └── marketing.json
├── client.ts
├── server.ts
└── setting.ts
client.ts 핵심 코드:
i18next
.use(initReactI18next)
.use(LanguageDetector)
.use(
resourcesToBackend((language: string, namespace: string) => {
return import(`./locales/${language}/${namespace}.json`);
})
)
.init({
detection: { order: ["path"] },
});
사용:
const { t } = useTranslation(locale, "privacy");
t("sections.01.title"); // "1. 수집하는 정보"
t("lastUpdated"); // "최종 업데이트: 2025.08.22"
동적 import라서 해당 페이지에서 필요한 namespace만 로드합니다. 개인정보처리방침 페이지에서는 privacy.json만 불러오고, 이용약관 페이지에서는 service.json만 불러옵니다.
비교
| 단일 JSON | namespace 분리 | |
|---|---|---|
| 파일 수 | 언어당 1개 | 언어당 N개 |
| 번들 크기 | 전체 번역 포함 | 필요한 것만 로드 |
| 설정 난이도 | 낮음 | 중간 |
| 번역 키 충돌 | 주의 필요 | namespace로 분리됨 |
| 적합한 규모 | 소~중규모 | 중~대규모 |
언제 어떤 걸 쓸까
단일 JSON이 적합한 경우:
- 페이지 수가 10개 이하
- 번역 키가 200개 미만
- 팀원이 적어서 파일 충돌이 잘 안 남
- 빠르게 구축해야 할 때
namespace 분리가 적합한 경우:
- 페이지/기능별로 번역이 명확히 구분됨
- 번역 파일이 커져서 관리가 어려워질 때
- 특정 페이지에서 불필요한 번역까지 로드하고 싶지 않을 때
사실 시작할 때는 단일 JSON으로 시작하고, 파일이 커지면 namespace로 분리하는 게 현실적입니다. 처음부터 namespace로 나누면 파일이 너무 많아져서 오히려 관리가 번거로울 수 있습니다.
결국 어떤 방식이 더 좋다기보다는, 프로젝트의 규모와 성격에 맞게 선택하는 게 맞다고 생각합니다. 소규모 프로젝트에 namespace를 나누면 관리 포인트만 늘어나고, 대규모 프로젝트에 단일 JSON을 고집하면 파일이 감당이 안 됩니다. 정답은 없고, 적재적소에 맞는 선택이 있을 뿐입니다.