Skip to main content

SvelteKit i18n: 국제화 설정 가이드

처음부터 다국어 앱까지 ICU 메시지 형식, 로케일 기반 라우팅, 스마트 폴백 체인으로 SvelteKit 앱에 svelte-i18n을 설정하세요.

1

svelte-i18n 설치

svelte-i18n은 Svelte와 SvelteKit의 표준 국제화 라이브러리예요. 반응형 스토어, ICU MessageFormat 지원, 지연 로케일 로드를 기본으로 제공해요.

svelte-i18n은 FormatJS/react-intl과 같은 표준인 ICU MessageFormat을 복수형과 변수에 사용해요. React를 사용해 본 적이 있다면 메시지 구문이 익숙할 거예요.
Terminal
npm install svelte-i18n
2

svelte-i18n 구성

지연 로드 import 함수로 로케일을 등록하는 i18n 구성 파일을 만드세요. svelte-i18n은 해당 로케일이 활성화될 때만 메시지를 가져와요.

src/lib/i18n.ts
// src/lib/i18n.ts
import { register, init, getLocaleFromNavigator } from 'svelte-i18n';

// Register locale loaders (lazy-loaded)
register('en', () => import('../locales/en.json'));
register('de', () => import('../locales/de.json'));
register('ja', () => import('../locales/ja.json'));
register('es', () => import('../locales/es.json'));

init({
  fallbackLocale: 'en',
  initialLocale: getLocaleFromNavigator(),  // Auto-detect browser language
});
컴포넌트가 렌더링되기 전에 +layout.svelte에서 i18n 구성 파일을 가져와야 해요. 번역에 'nav.home' 같은 원시 키가 표시된다면 구성 파일을 충분히 일찍 가져오지 않은 거예요.

SvelteKit 레이아웃 통합

루트 레이아웃에서 i18n 구성을 가져오고 $isLoading 스토어로 렌더링을 제어하세요. 로케일 데이터를 비동기로 로드하는 동안 번역되지 않은 키가 잠깐 표시되는 현상을 막을 수 있어요.

src/routes/+layout.svelte
<!-- src/routes/+layout.svelte -->
<script>
  // Import i18n config — must run before any component renders
  import '../lib/i18n';
  import { isLoading } from 'svelte-i18n';
</script>

{#if $isLoading}
  <p>Loading translations...</p>
{:else}
  <slot />
{/if}

SvelteKit의 로케일 기반 라우팅

/en/about, /de/about 같은 SEO 친화적 URL에는 [lang] 경로 매개변수를 사용하세요. URL 매개변수를 기준으로 레이아웃의 load 함수에서 svelte-i18n 로케일을 설정하세요.

SvelteKit locale routing
// src/routes/[lang]/+layout.ts
import { locale } from 'svelte-i18n';

export function load({ params }) {
  // Set the active locale from the URL parameter
  locale.set(params.lang);
  return {};
}

// src/routes/[lang]/+layout.svelte
<script>
  import '../../lib/i18n';
  import { isLoading } from 'svelte-i18n';
</script>

{#if $isLoading}
  <p>Loading...</p>
{:else}
  <slot />
{/if}

번역 파일 형식

로케일마다 JSON 파일을 하나씩 만드세요. svelte-i18n은 복수형, 변수, select 표현식에 중첩 키와 ICU MessageFormat 구문을 지원해요.

Translation files
// src/locales/en.json
{
  "nav": {
    "home": "Home",
    "about": "About",
    "settings": "Settings"
  },
  "greeting": "Hello, {name}!",
  "cart": {
    "itemCount": "{count, plural, one {# item} other {# items}}"
  }
}

// src/locales/de.json
{
  "nav": {
    "home": "Startseite",
    "about": "Uber uns",
    "settings": "Einstellungen"
  },
  "greeting": "Hallo, {name}!",
  "cart": {
    "itemCount": "{count, plural, one {# Artikel} other {# Artikel}}"
  }
}
키가 표시되는 위치가 아니라 설명하는 내용에 따라 이름을 정하세요. 'homepageCartLabel'보다 'cart.itemCount'가 더 좋아요. UI를 다시 설계해도 키는 계속 사용할 수 있어야 해요.
3

컴포넌트에서 번역 사용

svelte-i18n에서 $_ 스토어(또는 $format)를 가져와 Svelte 템플릿에서 사용하세요. 스토어는 반응형이므로 로케일이 바뀌면 번역된 모든 문자열이 자동으로 업데이트돼요.

Component.svelte
<script>
  import { _ } from 'svelte-i18n';
</script>

<h1>{$_('greeting', { values: { name: 'World' } })}</h1>

<nav>
  <a href="/">{$_('nav.home')}</a>
  <a href="/about">{$_('nav.about')}</a>
</nav>
Formatting helpers
<script>
  import { _, date, number, time } from 'svelte-i18n';
</script>

<!-- Simple string -->
<p>{$_('greeting', { values: { name: userName } })}</p>

<!-- ICU plurals — handled automatically -->
<p>{$_('cart.itemCount', { values: { count: 3 } })}</p>

<!-- Date formatting -->
<p>{$date(new Date(), { format: 'long' })}</p>

<!-- Number formatting -->
<p>{$number(1999.99, { style: 'currency', currency: 'USD' })}</p>
$_는 Svelte 스토어이므로 템플릿에서 $ 접두사를 사용해야 해요. 달러 기호 없이 _('key')를 작성하면 번역된 문자열이 아니라 스토어 객체를 반환해요.

언어 전환

$locale 스토어에 바인딩되는 언어 선택기를 만드세요. 값이 바뀌면 svelte-i18n이 새 로케일의 메시지를 로드하고 번역된 모든 문자열을 반응형으로 업데이트해요.

LanguageSwitcher.svelte
<script>
  import { locale, locales } from 'svelte-i18n';

  const LANGUAGE_NAMES = {
    en: 'English',
    de: 'Deutsch',
    ja: '日本語',
    es: 'Espanol',
  };
</script>

<select bind:value={$locale}>
  {#each $locales as loc}
    <option value={loc}>{LANGUAGE_NAMES[loc] ?? loc}</option>
  {/each}
</select>
4

ICU MessageFormat으로 복수형 처리

svelte-i18n은 모든 CLDR 복수형 범주를 처리하는 국제 표준인 ICU MessageFormat을 복수형 처리에 사용해요. 아랍어에는 6가지, 러시아어에는 4가지, 일본어에는 1가지 형식이 있어요. 대상 언어에 필요한 형식을 정의하면 svelte-i18n이 올바른 형식을 자동으로 선택해요.

ICU plural forms by language
// svelte-i18n uses ICU MessageFormat for plurals
// English:
{
  "items": "{count, plural, one {# item} other {# items}}"
}

// Arabic (6 forms):
{
  "items": "{count, plural, zero {no items} one {item} two {two items} few {# items} many {# items} other {# items}}"
}

// Japanese (1 form):
{
  "items": "{count, plural, other {#個のアイテム}}"
}
컴포넌트에 단수형/복수형 로직을 하드코딩하지 마세요. 프랑스어 같은 언어는 0을 단수로 취급해요. 아랍어, 러시아어, 폴란드어에는 영어에 없는 복수형이 있어요. ICU 복수형 구문에 맡기세요.

svelte-i18n-locale-chain을 활용한 스마트 로케일 폴백

svelte-i18n은 키가 없으면 중간 폴백 없이 fallbackLocale로 바로 폴백해요. 쓸 수 있는 pt-PT 번역이 있어도 pt-BR 사용자에게 영어가 표시돼요. svelte-i18n-locale-chain은 지역 변형의 메시지를 딥 머지하는 스마트 폴백 체인으로 이 문제를 해결해요.

Terminal
npm install svelte-i18n-locale-chain svelte-i18n
src/lib/i18n.ts
// src/lib/i18n.ts
import { initLocaleChain, setLocale } from 'svelte-i18n-locale-chain';

// Replace svelte-i18n's init + register with initLocaleChain
await initLocaleChain({
  loadMessages: (locale) =>
    import(`../locales/${locale}.json`).then(m => m.default),
  defaultLocale: 'en',
  initialLocale: 'pt-BR',
});

// Later, to change locale:
await setLocale('fr-CA');
// fr-CA user sees: fr-CA messages -> fr messages -> en messages
// No missing keys — deep-merged automatically
svelte-i18n-locale-chain은 모든 메시지 로드를 내부에서 관리해요. svelte-i18n의 register() 함수와 함께 사용하지 마세요. initLocaleChain이 등록, 로드, 딥 머지를 처리해요.

번역 자동화

i18n 설정을 마쳤다면 AI로 로케일 파일을 번역하세요. IDE에서 AI 어시스턴트에게 원문 파일 번역을 요청하거나 CI/CD 파이프라인에서 i18n Agent CLI를 사용하세요.

Terminal
# In your IDE, ask your AI assistant:
> Translate src/locales/en.json to German, Japanese, and Spanish

✓ de.json created (1.2s)
✓ ja.json created (1.5s)
✓ es.json created (1.1s)

# Or use the CLI in CI/CD:
npx i18n-agent translate src/locales/en.json --lang de,ja,es
번역은 점진적으로 진행하세요. 원문 파일에 새 키를 추가하면 모든 파일을 다시 생성하지 말고 변경된 부분만 번역하세요. 사람이 검토한 기존 번역을 유지할 수 있어요.

번역 품질 자동화

i18n-validate를 사용해 누락된 키와 손상된 플레이스홀더를 배포 전에 찾아내세요. 실제 번역이 준비되기 전에 i18n-pseudo의 의사 번역으로 UI를 테스트하세요.

흔한 실수

SvelteKit의 SSR 로케일 누출

svelte-i18n 스토어는 싱글턴이에요. SvelteKit SSR에서는 동시 요청이 같은 스토어를 공유하므로 한 사용자의 로케일이 다른 사용자의 응답에 섞일 수 있어요. 각 요청이 올바른 로케일 문맥을 사용하도록 handle 훅이나 레이아웃 load 함수에서 locale.set()을 호출하세요.

svelte-i18n-locale-chain과 register() 함께 사용

svelte-i18n-locale-chain을 사용한다면 svelte-i18n의 register() 함수를 사용하지 마세요. initLocaleChain이 모든 메시지 로드를 내부에서 처리해요. 둘을 섞으면 메시지를 중복 로드하거나 충돌할 수 있어요.

ICU 구문 오류의 무음 실패

ICU MessageFormat 문자열의 중괄호가 맞지 않거나 복수형 범주가 없으면 오류 표시 없이 실패해 서식 적용 결과 대신 원시 메시지 문자열이 표시돼요. CI 파이프라인에서 ICU 구문을 검증하세요.

번역되지 않은 콘텐츠 깜박임

번역 로드가 끝나기 전에 컴포넌트를 렌더링하면 사용자에게 원시 키가 보여요. 메시지가 준비될 때까지 로드 상태를 표시하도록 {#if $isLoading}...{:else}...{/if}로 레이아웃을 제어하세요.

권장 파일 구조

Project Structure
my-sveltekit-app/
├── src/
│   ├── lib/
│   │   └── i18n.ts              # i18n configuration
│   ├── locales/
│   │   ├── en.json              # Source language
│   │   ├── de.json              # German
│   │   ├── ja.json              # Japanese
│   │   └── es.json              # Spanish
│   └── routes/
│       ├── +layout.svelte       # Import i18n, guard isLoading
│       ├── +page.svelte
│       └── [lang]/              # Optional: locale-based routing
│           ├── +layout.ts       # Set locale from URL param
│           ├── +layout.svelte
│           └── +page.svelte
├── svelte.config.js
└── package.json

지금 i18n Agent 사용해 보기

번역 파일을 여기에 드롭

JSON, YAML, PO, XML, CSV, Markdown, Properties

또는 클릭하여 파일 선택

대상 언어

가입 불필요즉시 견적

svelte-i18n-locale-chain을 활용한 로케일 폴백

pt-BR 같은 지역 로케일에 번역 키가 없으면 svelte-i18n은 상위 로케일 pt를 먼저 확인하지 않고 기본 로케일로 바로 이동해요.

Terminal
npm install svelte-i18n-locale-chain
Configuration
import { initLocaleChain } from 'svelte-i18n-locale-chain';

initLocaleChain({
  fallbacks: {
    'pt-BR': ['pt', 'en'],
    'zh-Hant-HK': ['zh-Hant', 'zh', 'en'],
  },
  defaultLocale: 'en',
});

지원 프레임워크와 내장 체인 75개의 전체 목록은 로케일 폴백 가이드에서 확인하세요. Learn more →

자주 묻는 질문