Skip to main content

SvelteKit i18n:國際化設定指南

從零到多語言:在 SvelteKit 應用程式中設定 svelte-i18n,使用 ICU 訊息格式、基於語言的路由和智能回退鏈。

1

安裝 svelte-i18n

svelte-i18n 是 Svelte 和 SvelteKit 的標準國際化庫,開箱即用地提供響應式 store、ICU MessageFormat 支援和語言延遲載入。

svelte-i18n 使用 ICU MessageFormat 處理複數和變數,與 FormatJS/react-intl 使用相同標準。如果你從 React 遷移而來,會對這種訊息語法很熟悉。
Terminal
npm install svelte-i18n
2

設定 svelte-i18n

建立 i18n 設定檔案,通過延遲載入的 import 函數註冊語言。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 store 控制渲染。這樣可防止語言數據非同步載入時短暫顯示未翻譯的鍵。

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}}"
  }
}
按鍵所描述的內容而非顯示位置命名:'cart.itemCount' 優於 'homepageCartLabel'。即使重新設計 UI,鍵也應繼續有效。
3

在元件中使用譯文

從 svelte-i18n 匯入 $_ store(或 $format),並在 Svelte 範本中使用。store 具有響應性,語言變化時所有翻譯字串都會自動更新。

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 store,必須在範本中使用 $ 前綴。省略美元符號寫成 _('key') 會傳回 store 物件,而不是翻譯字串。

語言切換

構建與 $locale store 綁定的語言選擇器。值變化時,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 使用 ICU MessageFormat 處理複數,這是覆蓋全部 CLDR 複數類別的國際標準。阿拉伯語有 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-BR 用戶會看到英語,而不是完全可用的 pt-PT 譯文。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 store 是單例。在 SvelteKit SSR 中,併發請求共享同一個 store,一個用戶的語言可能串入另一個用戶的響應。解決方法:在 handle hook 或佈局 load 函數中呼叫 locale.set(),讓每個請求獲得正確的語言上下文。

將 register() 與 svelte-i18n-locale-chain 一起使用

使用 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 →

常見問題