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 →

常见问题