architecture2025-03-10·9 min·156/348

Vercel에서 다국어 라우팅 설정

Next.js와 Vercel을 사용하여 다국어 라우팅을 설정하는 방법을 알아봅니다.

Vercel에서 다국어 라우팅 설정

Introduction

글로벌 애플리케이션을 개발할 때 다국어 지원은 필수적입니다. Next.js와 Vercel을 사용하여 효율적인 다국어 라우팅을 구현하는 방법을 알아보겠습니다.

Environment

  • Vercel 프로젝트 (Next.js 14+)
  • next-intl 라이브러리
  • TypeScript
  • React 18+

Problem

다국어 라우팅 설정 시 발생하는 문제:

// 하드코딩된 다국어 처리
export default function Home({ params }) {
  const lang = params.lang;
  
  if (lang === 'ko') {
    return 

안녕하세요

; } else if (lang === 'en') { return

Hello

; } // 유지보수 어려움, 확장성 부족 }

Analysis

Next.js 다국어 라우팅 방식:

  1. Locale in Path: /ko/about, /en/about
  2. Subdomain: ko.example.com, en.example.com
  3. Query Parameter: ?lang=ko

Vercel에서의 고려사항:

  • 미들웨어를 통한 라우팅 처리
  • SEO 최적화 (hreflang 태그)
  • 빌드 시간 최적화

Solution

1. next-intl 설정

npm install next-intl

2. 다국어 설정 파일

// i18n/request.js
import { getRequestConfig } from 'next-intl/server';
import { cookies } from 'next/headers';

export default getRequestConfig(async () => {
  const cookieStore = cookies();
  const locale = cookieStore.get('locale')?.value || 'en';
  
  return {
    locale,
    messages: (await import(`../messages/${locale}.json`)).default,
  };
});

3. 메시지 파일 구조

// messages/en.json
{
  "common": {
    "welcome": "Welcome",
    "hello": "Hello, {name}!"
  },
  "home": {
    "title": "Home Page",
    "description": "Welcome to our application"
  },
  "about": {
    "title": "About Us"
  }
}
// messages/ko.json
{
  "common": {
    "welcome": "환영합니다",
    "hello": "안녕하세요, {name}!"
  },
  "home": {
    "title": "홈 페이지",
    "description": "アプリケーション에 오신 것을 환영합니다"
  },
  "about": {
    "title": "회사 소개"
  }
}

4. 미들웨어 설정

// middleware.js
import createMiddleware from 'next-intl/middleware';
import { locales, defaultLocale } from './i18n/config';

export default createMiddleware({
  locales,
  defaultLocale,
  localeDetection: false,
});

export const config = {
  matcher: ['/((?!api|_next|.*\\..*).*)'],
};

5. i18n 설정

// i18n/config.js
export const locales = ['en', 'ko', 'ja'];
export const defaultLocale = 'en';

export function isValidLocale(locale) {
  return locales.includes(locale);
}

6. 컴포넌트에서 사용

// app/[locale]/page.js
import { useTranslations } from 'next-intl';
import { setRequestLocale } from 'next-intl/server';

export default function HomePage({ params }) {
  setRequestLocale(params.locale);
  
  const t = useTranslations('home');
  const common = useTranslations('common');
  
  return (
    

{t('title')}

{t('description')}

{common('hello', { name: 'World' })}

); } export async function generateStaticParams() { return locales.map((locale) => ({ locale })); }

7. 언어 전환 컴포넌트

// components/LanguageSwitcher.jsx
'use client';

import { useRouter, usePathname } from 'next/navigation';
import { locales } from '@/i18n/config';

export default function LanguageSwitcher({ currentLocale }) {
  const router = useRouter();
  const pathname = usePathname();
  
  const switchLocale = (newLocale) => {
    const segments = pathname.split('/');
    segments[1] = newLocale;
    router.push(segments.join('/'));
  };
  
  return (
    
{locales.map((locale) => ( ))}
); }

8. SEO 메타데이터

// app/[layout]/layout.js
import { getTranslations } from 'next-intl/server';

export async function generateMetadata({ params }) {
  const t = await getTranslations({ locale: params.locale });
  
  return {
    title: t('home.title'),
    description: t('home.description'),
    alternates: {
      languages: {
        en: '/en',
        ko: '/ko',
        ja: '/ja',
      },
    },
  };
}

9. 동적 번역 가져오기

// lib/i18n-utils.js
export async function getTranslation(locale, namespace, key) {
  try {
    const messages = await import(`../messages/${locale}.json`);
    const keys = `${namespace}.${key}`.split('.');
    
    let value = messages.default;
    for (const k of keys) {
      value = value?.[k];
    }
    
    return value || key;
  } catch (error) {
    console.error(`Translation error: ${locale}.${namespace}.${key}`);
    return key;
  }
}

Lessons Learned

  1. 구조화된 번역: 번역 파일을 네임스페이스별로 분리하면 관리가 용이합니다.
  2. SEO 고려: hreflang 태그와 함께 올바른 URL 구조를 설정해야 합니다.
  3. 기본 언어 설정: 사용자의 브라우저 설정이나 위치를 기반으로 기본 언어를 설정하면 좋습니다.
  4. 번역 완성도: 모든 언어에 대한 번역이 완료되어야 합니다.
  5. 테스트: 다양한 언어에서의 렌더링을 테스트해야 합니다.

This blog does not accept any external sponsorships, affiliate marketing, or ad revenue.