개발 slecs

홈 화면에 위치 기반 언어 자동 감지 기능 추가

목차

홈 UI에 geo 기반 언어 자동 감지 로직을 붙였다. 파일은 세 개, 건드린 레이어는 라우팅·클라이언트 컴포넌트·i18n 유틸까지 전방위였다.

왜 이 작업이 필요했나

서비스를 글로벌 사용자에게 열어두면서 홈 화면은 여전히 하드코딩된 한국어로 박혀 있었다. 한국어권 사용자한테는 자연스럽지만, 해외 IP로 접근하는 사용자 입장에서는 첫 화면부터 이질감이 생긴다. UX 관점에서 "언어를 선택하게 강제하는 것" 자체가 이탈 포인트가 되는 건 이미 여러 번 확인된 패턴이다.

팀 내부에서는 "일단 KO/EN 두 개만 커버하고, 그 다음을 보자"는 방향으로 합의했다. 지금 당장 i18n 프레임워크를 풀스택으로 올리는 건 오버엔지니어링이고, geo 감지 → KO/EN 분기 정도면 충분히 가치 있는 첫 스텝이라고 봤다.

파일 세 개에 각각 어떤 역할을 맡겼나

파일 역할 이번 변경
src/lib/i18n.ts 언어 로직 코어 geo 감지 + locale 판별 함수 추가
src/app/page.tsx 서버 컴포넌트(라우트 진입점) locale 판별 후 클라이언트로 prop 전달
src/app/home-client.tsx 홈 UI 클라이언트 컴포넌트 locale prop 받아 KO/EN 텍스트 분기 렌더

i18n.ts에 핵심 로직을 몰아넣은 건 의도된 설계다. 나중에 locale 판별 기준이 바뀌더라도 — 예를 들어 브라우저 Accept-Language를 추가로 보거나, 사용자 설정값을 우선하거나 — 건드려야 할 파일이 한 곳이면 리뷰도 쉽고 테스트도 단순해진다. 팀원한테 리뷰 요청할 때 "이 파일 하나가 진실의 원천"이라고 설명할 수 있어야 한다.

page.tsx가 서버 컴포넌트이기 때문에 geo 정보를 여기서 읽어서 내려주는 구조가 자연스럽다. Next.js 기준으로 request header나 edge middleware에서 geo 정보를 뽑아 서버 컴포넌트 레이어에서 처리하고, 클라이언트 컴포넌트는 그 결과만 받는 패턴이 제일 깔끔하다.

// src/lib/i18n.ts (개념 패턴)
export type Locale = 'ko' | 'en';

export function resolveLocale(countryCode: string | undefined): Locale {
  if (countryCode === 'KR') return 'ko';
  return 'en'; // fallback
}
// src/app/page.tsx (개념 패턴)
import { resolveLocale } from '@/lib/i18n';

export default function Page({ params, headers }: ...) {
  const country = headers().get('x-vercel-ip-country') ?? undefined;
  const locale = resolveLocale(country);
  return <HomeClient locale={locale} />;
}

단순해 보이지만 이 구조가 주는 장점은 뚜렷하다. 클라이언트 컴포넌트(home-client.tsx)는 locale을 "받는" 역할만 하면 되니까, Storybook이나 테스트 환경에서 locale="en" 하나만 주입하면 영어 화면을 즉시 확인할 수 있다.

회고 — 트레이드오프와 다음 고려사항

geo 기반 자동 감지에는 명확한 한계가 있다. 한국에 있는 외국인, VPN 쓰는 해외 사용자, 다국어 사용자 등 geo가 실제 언어 선호와 다른 케이스는 항상 존재한다. 지금은 그 케이스를 "감수하는" 선택을 했고, 팀과도 그 트레이드오프를 공유해뒀다.

이런 결정을 팀 리드로서 할 때 중요하게 보는 건 두 가지다.

  • 지금 이 결정이 나중에 되돌리기 얼마나 어려운가: i18n.ts에 로직이 집중돼 있어서, 나중에 사용자 설정 우선 로직을 추가하더라도 resolveLocale 시그니처를 확장하면 된다. 큰 리팩토링 없이 점진적으로 개선 가능한 구조다.
  • 팀원이 이 로직을 유지보수할 수 있는가: locale 판별 로직이 한 파일에 있고, 함수 단위로 분리돼 있으면 신규 팀원도 컨텍스트 파악에 오래 걸리지 않는다.

코드리뷰 때 "왜 middleware에서 처리 안 했냐"는 질문도 나왔다. 지금은 홈 화면 단 한 곳만 적용이라 서버 컴포넌트 레이어로 충분하다는 판단이었다. 미들웨어로 올리는 건 전체 라우트에 locale을 일관되게 적용할 때 자연스러운 타이밍이다. 지금 올리면 오버킬이고, 그 판단을 리뷰어에게 PR 설명에 명시해두었다.

geo localization은 작아 보여도 "글로벌 사용자를 어떻게 대할 것인가"라는 질문의 시작점이다. 이번 커밋은 그 첫 발을 디딘 것.


다음


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.