Skip to main content

i18n SvelteKit: руководство по настройке интернационализации

От нуля до многоязычного приложения: настройте svelte-i18n в приложении SvelteKit с форматом сообщений ICU, маршрутизацией по локалям и умными цепочками резервных локалей.

1

Установить svelte-i18n

svelte-i18n — стандартная библиотека интернационализации для Svelte и SvelteKit. Она сразу предоставляет реактивные хранилища, поддержку ICU MessageFormat и отложенную загрузку локалей.

svelte-i18n использует ICU MessageFormat для форм множественного числа и переменных — тот же стандарт, что и FormatJS/react-intl. Если Вы переходите с React, синтаксис сообщений будет знаком.
Terminal
npm install svelte-i18n
2

Настроить svelte-i18n

Создайте файл конфигурации 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
});
Необходимо импортировать файл конфигурации i18n в +layout.svelte до отрисовки любого компонента. Если для переводов отображаются исходные ключи вроде '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

Для удобных для SEO URL вроде /en/about и /de/about используйте параметр маршрута [lang]. Задайте локаль svelte-i18n в функции load макета на основе параметра URL.

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 поддерживает вложенные ключи и синтаксис 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'. Ключи должны сохраняться при изменении дизайна интерфейса.
3

Использовать переводы в компонентах

Импортируйте хранилище $_ или $format из svelte-i18n и используйте его в шаблонах 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 использует 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 управляет всей загрузкой сообщений внутри себя. Не используйте одновременно функцию register() из svelte-i18n: initLocaleChain выполняет регистрацию, загрузку и глубокое объединение.

Автоматизировать перевод

После завершения настройки i18n переведите файлы локалей с помощью ИИ. Попросите ИИ-помощника перевести исходный файл в своей IDE или используйте CLI i18n Agent в конвейере CI/CD.

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, пока настоящие переводы ещё не готовы.

Распространённые ошибки

Смешение локалей при SSR в SvelteKit

Хранилища svelte-i18n являются одиночками. При SSR в SvelteKit параллельные запросы используют одно хранилище, поэтому локаль одного пользователя может попасть в ответ другому. Решение: вызывайте locale.set() в хуке handle или функции load макета, чтобы каждый запрос получал правильный контекст локали.

Использование register() с svelte-i18n-locale-chain

Не используйте функцию register() из svelte-i18n вместе с svelte-i18n-locale-chain. initLocaleChain выполняет всю загрузку сообщений внутри себя. Их сочетание приводит к дублирующейся или конфликтующей загрузке.

Ошибки синтаксиса ICU происходят без уведомления

Несогласованная скобка или отсутствующая категория множественного числа в строках ICU MessageFormat вызывает сбой без уведомления: вместо форматированного результата отображается исходная строка сообщения. Проверяйте синтаксис ICU в конвейере CI.

Кратковременное появление непереведённого содержимого

Если отрисовать компоненты до завершения загрузки переводов, пользователи увидят исходные ключи. Защитите макет с помощью {#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 →

Часто задаваемые вопросы