개요
회사에서 “Next.js에서 서버사이드로 다국어를 어떻게 처리하는지, SEO까지 포함해서 실제로 동작하는지” 확인해달라는 요청을 받았다.
우리 회사 환경은 다르지만 Next.js에서 관례적으로 어떻게 하는지를 먼저 정리하고, 최소 규모로 PoC(검증용 데모)를 만들어서 직접 테스트해봤다.
1. 회사 요청사항을 내가 이해한 방식
요구사항을 “검증 가능한 체크리스트”로 바꾸면 아래 정도였다.
- 서버사이드 렌더링(SSR) 시점에 이미 해당 언어 콘텐츠가 HTML로 내려오는가?
- 검색엔진(특히 Google)이 언어별 페이지를 각각 인덱싱할 수 있는 구조인가?
- 같은 페이지라도 언어가 다르면 URL이 다르게 존재해야 한다.
hreflang/canonical/ sitemap 같은 SEO 신호가 제대로 나가는지 확인
- 클라이언트에서 언어를 바꿔도 하이드레이션 불일치(언어 깜빡임)가 없어야 한다.
특히 “SEO 친화적”이 핵심이라서, 언어를 쿠키/헤더로만 바꾸는 방식보다는 언어별 고유 URL을 만드는 쪽이 안전하다고 봤다.
자료조사 중에 인상 깊었던 포인트: Googlebot은 보통 Accept-Language 헤더를 보내지 않는다는 명시가 있고, locale-adaptive(같은 URL에서 언어가 바뀌는) 페이지는 모든 변형이 크롤링/색인되지 않을 수 있다는 경고가 있다. 그래서 언어별 URL + hreflang이 사실상 정석으로 보였다.
2. 내가 선택한 최소 구현 전략
언어 구성
- 테스트 언어 2개만
- Default: 영어(EN)
- Secondary: 다른 언어 1개(예: Hindi, NL 등)
URL 정책(내가 원했던 형태)
이번 PoC에서 내가 의도한 라우팅 규칙은 next-intl의 localePrefix: 'as-needed'와 같은 방향이다.
- 기본 언어(EN)는 URL에 접두사를 붙이지 않음
- 영어:
//about/seo
- 영어:
- 다른 언어는 locale prefix를 붙임
- 힌디:
/hi/hi/about/hi/seo
- 힌디:
즉, “기본 언어는 prefix 없이, 나머지만 prefix” 패턴.
참고: /en으로 접근하면(사용자가 직접 입력하거나 외부 링크가 그렇게 걸려 있거나)
미들웨어에서 /로 리다이렉트시키는 정책을 두었다.
이 설계 이유는 단순하다.
- URL만 봐도 어떤 언어인지 확실해야 하고
- 검색엔진이 언어별 페이지를 서로 다른 문서로 인식하기 쉽다.
next-intl/Next.js 공식 i18n 가이드가 제안하는 대표 패턴도 결국 “URL 기반 locale” 쪽으로 수렴한다는 점이 계속 반복된다.
3) 구현 흐름: ‘자료조사 → 파일화 → Claude Code로 구현’
이번 건은 “프로덕션 코드”가 아니라 검증용 데모가 목적이었다.
그래서 규모를 최대한 줄이고, 구현은 AI를 적극적으로 활용했다.
- 구글링 + 공식문서 위주로 “서버사이드 i18n + SEO” 패턴을 조사
- next-intl이 App Router와 궁합이 좋아 보였고(서버 컴포넌트 중심), 이걸 기준으로 기획
- 내가 원하는 조건(기본 언어는 prefix 없이
/, 다른 언어는/{locale})을 포함해서- Gemini
- GPT
에게 자료조사를 시키고 가이드 문서를 파일로 정리
- 그 문서들을 그대로 Claude Code에게 전달해서 구현 요청
- 결과물을 내가 읽고, 필요한 부분만 손봐서
- Vercel로 배포
- 마지막으로 SEO 테스트까지
자료조사 문서에서는 “Next.js 최신 안정 라인(당시 기준)”과 i18n 구성 요소(라우팅/리다이렉트/메타데이터/하이드레이션 이슈)를 한 번에 정리해둔 게 도움이 됐다.
4. 핵심 구현 포인트(내가 체크한 것들)
4-1. 서버에서 번역이 끝난 HTML을 내려주기
내가 원한 건 “클라에서 번역 JSON 로딩해서 바꾸는 i18n”이 아니라,
서버에서 이미 번역된 HTML을 내려주는 구조였다.
- App Router 기준으로 서버 컴포넌트에서 번역을 처리하면
클라이언트 번들에 번역 리소스가 과하게 섞이는 문제도 줄일 수 있다(설계상 이점).
4-2. hreflang / canonical이 실제로 붙는지
언어별 URL을 만들었으면, 검색엔진이 “이 페이지의 다른 언어 버전”을 알아야 한다.
그래서 아래를 꼭 확인했다.
<link rel="alternate" hreflang="..."><link rel="canonical" ...>- (가능하면) sitemap에도 alternates
4-3. 하이드레이션 이슈(언어 깜빡임) 방지
다국어에서 제일 피곤한 게 “서버는 A언어로 렌더했는데, 클라는 첫 렌더 때 B언어로 렌더해서 mismatch 나는” 상황이다.
내 결론은 간단했다.
- 언어 결정의 단일 기준을 URL로 고정한다.
- 언어 변경은 “상태 변경”이 아니라 URL 이동으로 처리한다.
서버/클라 로케일 판단 로직이 다르면 하이드레이션 불일치가 쉽게 발생한다는 점이 정리돼 있었고, URL 기반을 단일 소스 오브 트루스로 삼는 게 가장 안정적이라고 적혀 있었다.
5) 검증: Google ‘리치 검색결과 테스트’로 확인
배포 후에 바로 Google 리치 검색결과 테스트(Rich Results Test)로 확인했다.
내가 확인한 포인트는 두 가지:
- HTML 탭에서
- 페이지의 주요 텍스트/헤더/메타가
언어별로 제대로 렌더링된 상태로 내려오는지




- 스크린샷 탭에서
- Google이 렌더링한 화면이
언어별로 분리되어 보이는지




결과적으로,
/(영어)와/{locale}(다른 언어)가
서버사이드에서 각각 다른 콘텐츠로 렌더링되는 걸 확인했다.- 스크린샷에서도 언어가 바뀐 화면이 정상적으로 잡혔다.
즉, “Next.js에서 서버사이드 다국어 처리 구현이 실제로 가능한지”는
PoC 수준에서 확인 완료.
6. 내가 중간에 표현을 잘못할 뻔한 부분(정리하면서 수정)
SSR = 실시간 갱신?
처음에는 SSR을 “사용자가 접근할 때마다 데이터가 실시간으로 갱신되는 것”처럼 표현할 뻔했는데,
이건 반쯤만 맞는 말이다.
- SSR은 “요청 시 서버가 HTML을 만들어서 내려준다”는 의미고
- 데이터가 항상 실시간인지 여부는
- 매 요청 SSR
- ISR(재검증)
- 캐싱 전략
- 백엔드 데이터 업데이트 주기
같은 운영 설계에 의해 달라진다.
자료조사 문서에서도 “SSG/SSR/ISR은 신선도·비용·성능 트레이드오프”로 정리돼 있었고, 특히 다국어는 페이지 수가 로케일만큼 늘어나서 빌드/캐시 전략이 중요하다고 강조한다.
7. 결론: 회사에 공유할 메시지(한 줄 요약)
- Next.js(App Router) + next-intl 기준으로
URL 기반 locale(언어별 고유 URL)을 만들고
서버에서 번역 완료된 HTML을 내려주는 구조를 잡으면
SEO/하이드레이션 측면에서 가장 안전하게 “서버사이드 다국어”를 구현할 수 있다.
참고
'FrontEnd > Next.js' 카테고리의 다른 글
| Vercel 자동 배포 실패 – ERR_PNPM_LOCKFILE_CONFIG_MISMATCH (0) | 2025.12.12 |
|---|---|
| Next.js 15에서 params와 searchParams 비동기 처리하기 (0) | 2024.11.23 |