GitHub

Ship in any language

Add translations to your Svelte 5 app in under a minute.

pnpm add @nomideusz/svelte-i18n

Live preview

current: en
myapp.com
Welcome back, Jan!
Runes-native

Built on $state. Reactivity just works.

Tiny

Under 150 lines of TypeScript, zero runtime deps.

Flat keys

Simple JSON files your translators will love.

You have 7 new notifications.
Total: 129 PLN
Try it:

1. i18n.t()

lookup · interpolation · missing-key fallback
Result (current locale: en) Welcome back, Jan!
Placeholders the translation needs
name

2. interpolate()

standalone {variable} substitution
Result Hello Jan, you have 3 unread messages.
Placeholders detected
namecount

3. <LocaleSwitcher />

drop-in <select> — style via --asini-* CSS vars
With labels
Without labels (code only)
<script>
  import { LocaleSwitcher } from '@nomideusz/svelte-i18n';
  import { i18n } from '$lib/i18n';
</script>

<LocaleSwitcher {i18n} labels={{ en: 'English', pl: 'Polski' }} />

4. URL routing (SSR)

path-prefix locales — default en bare; uk aliased to /ua (hreflang stays uk)
extractLocale → locale en
extractLocale → pathname /blog/yoga-for-beginners
localizeHref per locale
en: /blog/yoga-for-beginnerspl: /pl/blog/yoga-for-beginnersde: /de/blog/yoga-for-beginnersuk: /ua/blog/yoga-for-beginners
alternates() → <svelte:head> markup
<link rel="alternate" hreflang="en" href="https://example.com/blog/yoga-for-beginners" />
<link rel="alternate" hreflang="pl" href="https://example.com/pl/blog/yoga-for-beginners" />
<link rel="alternate" hreflang="de" href="https://example.com/de/blog/yoga-for-beginners" />
<link rel="alternate" hreflang="uk" href="https://example.com/ua/blog/yoga-for-beginners" />
<link rel="alternate" hreflang="x-default" href="https://example.com/blog/yoga-for-beginners" />

Read the full docs for the complete API.