- 발행일
일본어는 도메인, 영어는 경로 — 언어 축이 둘로 갈린 라우팅
일본어는 도메인, 영어는 경로
이 글은 2026년 9월에 당시 코드를 다시 보며 정리한 것입니다. 저장소는 퇴사 전에 스냅샷으로 보관한 것이라 커밋 이력이 없고, 경력기술서와 당시 쓴 이력서에 적은 담당 범위와 코드를 대조해 썼습니다. 날짜는 코드에 남은 시기 단서 기준입니다.
숙박 큐레이션 플랫폼의 고객 웹은 Next.js 12 pages 라우터였고, 언어는 한국어·영어·일본어 셋이었습니다. 2022년 8월에 입사했고 프런트 4명·백엔드 4명 팀이었어요. 일본어 지원은 경력기술서에 제 담당으로 적혀 있고, 당시 이력서에는 담당 역할이 "가격·홍보 관련 프런트엔드 개발"로 적혀 있습니다. 경력기술서에는 "언어 상태를 URL 경로에 두기로 했다"고 적어 뒀는데, 이 라우팅 설정 자체를 누가 세웠는지는 이력이 없어 확인할 수 없습니다. 이 글은 그 설정을 제 담당 범위인 일본어 쪽에서 다시 읽은 것입니다.
그런데 next.config.js를 다시 열어 보니 언어 축이 하나가 아니었습니다.
i18n: {
locales: ["ko", "en", "ja"],
defaultLocale: "ko",
domains: [
{
domain: runtimeConfig.japanDomain,
defaultLocale: "ja",
},
],
},
영어는 Next.js 기본 방식대로 /en/... 경로였습니다. 일본어는 다른 도메인이었어요. 한 서비스 안에서 영어와 일본어가 서로 다른 축에 매달려 있었던 겁니다.
갈라진 결과로 남은 것
축이 둘이면 두 축을 잇는 규칙이 필요합니다. 그게 redirects()에 세 개로 남아 있었습니다.
async redirects() {
const { baseDomain, japanDomain } = runtimeConfig;
return [
{
has: [{ type: "host", value: baseDomain }],
source: "/ja/:path*",
destination: `https://${japanDomain}/:path*`,
permanent: false,
locale: false,
},
{
has: [{ type: "host", value: japanDomain }],
source: "/:locale(ko|en)/:path*",
destination: "/:path*",
permanent: false,
locale: false,
},
첫째 규칙은 한국 도메인에서 /ja/로 들어오면 일본 도메인으로 보냅니다. locales에 ja가 들어 있으니 Next.js는 /ja/...도 정상 주소로 받거든요. 그걸 그냥 두면 같은 일본어 페이지가 두 도메인에서 열립니다. 둘째·셋째 규칙은 반대로, 일본 도메인에서 /ko/나 /en/이 붙으면 떼어 버립니다. 일본 도메인은 일본어만 낸다는 뜻이에요. locale: false는 이 규칙들이 Next.js의 자동 언어 접두어를 타지 않게 하는 옵션입니다.
API 쪽에도 흔적이 있었습니다.
export const convertDomain = (url, req?: IncomingMessage) => {
const siteDomain =
(req
? req.headers["x-forwarded-host"] || req.headers.host // server-side
: typeof window !== "undefined" && window.location.host) || // client-side
"";
if (siteDomain?.includes(config.japanDomain)) {
return url.replace(/\.com|\.co\.kr/gi, ".jp");
}
return url;
};
지금 열린 호스트가 일본 도메인이면 API 주소의 최상위 도메인까지 .jp로 바꿉니다. 화면만 갈린 게 아니라 일본어 화면은 일본 쪽 API를 부르는 구조였어요. 서버가 언어별로 따로 있었는지, 같은 서버를 도메인만 달리 붙였는지는 프런트 저장소만으로는 알 수 없습니다.
왜 일본어만 도메인이었나
코드에는 이유가 없습니다. 주석도 없고, 커밋 이력이 없으니 그 결정이 언제 누구 손에서 났는지도 남아 있지 않아요. 프런트가 넷이었으니 제 손이 아니었을 가능성도 그만큼 있습니다. 경력기술서의 표는 "쿠키·localStorage 대 URL 경로"만 저울에 올렸고, 도메인은 선택지에 없었습니다.
지금 코드만 놓고 읽으면 짚이는 건 하나입니다. convertDomain이 API 도메인까지 바꾸는 걸 보면, 일본 서비스는 주소 체계가 아니라 배포 단위가 달랐을 가능성이 커요. 그러면 프런트 라우팅에서 언어를 고르는 게 아니라 어느 배포에 들어왔느냐로 언어가 정해지고, 그 위에 한국·영어 배포에만 경로 방식이 얹힌 모양이 됩니다. 이건 코드에서 읽히는 구조이지 그때의 판단 근거는 아니에요.
Rails 쪽 마이그레이션에 시기는 남아 있습니다. 2022년 10월 1일에 languages·translation_keys 테이블이 생기고, 10월 7일에 숙소 테이블에 name_ja·address_ja 같은 일본어 컬럼이 붙었어요. 이 글의 날짜는 그 마이그레이션 기준입니다. 그보다 앞선 2021년 3월에도 객실 테이블에 일본어 캐시 컬럼이 넷 있었는데, 그건 제 입사 전이라 다른 사람의 손입니다.
경력기술서와 어긋나는 곳
경력기술서 §1의 표는 이렇게 적혀 있습니다.
| 방법 | 판단 |
|---|---|
| 쿠키 / localStorage | 기각 |
| URL 경로에 언어 코드 | 채택 |
코드는 이렇습니다.
| 언어 | 축 |
|---|---|
| 한국어 | 기본, 접두어 없음 |
| 영어 | 경로 /en/... |
| 일본어 | 별도 도메인, 경로 접두어는 떼어 냄 |
"경로에 언어 코드"는 영어에만 맞는 말이었습니다. 제가 맡은 일본어는 그 표의 어느 행에도 들어가지 않아요. 경력기술서를 쓸 때 코드를 열어 보지 않고 썼다는 뜻입니다.
검증
next.config.js의i18n.domains·redirects()세 규칙,common/urls.ts의convertDomain을 스냅샷에서 직접 읽었습니다.- 날짜 근거: Rails
db/migrate/20221001…create_languages·20221007…add_japanese_fields_to_place. 2021-03-29add_japanese_cashed_tag_list_to_rooms는 입사 전 마이그레이션입니다. - 경력기술서 §1 "URL 경로에 언어 코드 채택"과 대조: 영어 일치, 일본어 불일치.
- 당시 이력서(2023-12)와 대조: 담당 역할 "가격·홍보"에 다국어는 없고, 업무 기간 2022-08 시작은 위 마이그레이션 두 달 전이라 시기는 맞습니다. 라우팅 설계 주체는 두 문서 어디에도 없습니다.
- 그때 어느 환경에서 확인했는지, 리다이렉트를 몇 번 고쳤는지는 기록이 없습니다.
남은 것 · 한계
- 왜 도메인이었는지, 누가 정했는지는 끝내 모릅니다. 커밋 이력이 없어서 결정의 시점과 주체를 확인할 수 없고, 위의 "배포 단위" 이야기는 코드에서 거꾸로 읽은 것입니다.
/ja/경로가 열려 있는 채로 리다이렉트로 막고 있습니다.locales에서ja를 빼면/ja/가 애초에 없어질 텐데, 그러면router.locale이ja를 모르게 됩니다. 두 축을 한 설정에 억지로 얹은 대가예요.- 경력기술서 §1의 표는 고쳐야 합니다. 이 글을 쓰면서 알았고, 그 글 본문은 그대로 두고 정정만 다는 쪽으로 정리할 생각입니다.
- 3년 뒤 SDMS에서 데이터 맵의 탐색 위치를 주소에 남길 때는 무엇을 주소에 넣을지를 표로 저울질했습니다. 여기서는 그 표에 도메인이라는 선택지가 있었다는 것 자체를 적지 않았어요.
관련 글: 숙박 큐레이션 플랫폼 프런트엔드 2022–2024 · 데이터 맵에서 세 단계 들어간 자리를 주소에 남겼다 · 번역 키를 한국어 원문으로 썼다 · 프로모션마다 지원 언어를 두고, 안 되는 언어면 뒤로 보냈다