# How to Translate a Svelte or SvelteKit App | Vitra.ai

> Svelte has no official i18n library, so the pattern is yours to choose. SvelteKit's routing is what makes the SEO half straightforward in practice.

**Canonical URL**: https://www.vitra.ai/general/translate-a-svelte-app
**Source**: This is the Markdown rendering of https://www.vitra.ai/general/translate-a-svelte-app, generated at build time from that page.

---

4 min read

# How to Translate a Svelte or SvelteKit App

Svelte has no official i18n library, so the pattern is yours to choose. SvelteKit's routing is what makes the SEO half straightforward in practice.

[Samhitha J Bhatt](https://www.vitra.ai/author/samhitha)
Senior Product Manager , Vitra.ai
Updated Aug 17, 2026

![How to Translate a Svelte or SvelteKit App](https://www.vitra.ai/static/images/blog/translate-a-svelte-app.jpg)

Table of contents

[No official library, which is the Svelte way](#no-official-library-which-is-the-svelte-way)

[Reactivity does the hard work](#reactivity-does-the-hard-work)

[SvelteKit routing gives you the URLs](#sveltekit-routing-gives-you-the-urls)

[What to get right in the load function](#what-to-get-right-in-the-load-function)

[Metadata per language](#metadata-per-language)

[Static adapter and prerendering](#static-adapter-and-prerendering)

[Beyond the interface](#beyond-the-interface)

[Stores and server-side rendering](#stores-and-server-side-rendering)

[Progressive enhancement](#progressive-enhancement)

[Choosing a library versus rolling your own](#choosing-a-library-versus-rolling-your-own)

[Where to start](#where-to-start)

[FAQ](#faq)

Contributors

[Samhitha J Bhatt](https://www.vitra.ai/author/samhitha)
Senior Product Manager

Subscribe to our newsletter

Subscribe

> **Quick answer —** Svelte ships no official internationalisation library, so teams pick a community one or build a store-based pattern. SvelteKit's server rendering and route parameters handle the harder half — making translated pages crawlable.

## No official library, which is the Svelte way

The framework stays small and the ecosystem fills gaps. For i18n that means several community options with different trade-offs, or a straightforward store-based approach of your own.

A writable store holding the current locale, a derived store resolving keys against a message object, and a helper in templates gets a small app a long way without a dependency.

## Reactivity does the hard work

Because a derived store recomputes when the locale changes, switching language updates the whole interface with no reload and no manual re-render.

That is genuinely simpler than the equivalent in most frameworks, and it is the reason a hand-rolled solution is defensible here in a way it would not be elsewhere.

## SvelteKit routing gives you the URLs

A `[lang]` route parameter produces `/fr/pricing` — a distinct, crawlable URL per language, which is the requirement everything in multilingual SEO rests on.

Load the right messages in the `load` function so they arrive with the server render rather than after hydration. That is the difference between a crawler seeing French and seeing a shell.

## What to get right in the load function

Fetch messages server-side, return them as page data, and let the component read them synchronously. Fetching them in `onMount` means the first paint is untranslated and the crawler never sees the translation at all.

## Metadata per language

Title, description and Open Graph tags set in the page's head, generated from the same locale the body uses. A translated page with English metadata competes as an English page.

hreflang needs to reciprocate across every language version, emitted from one place rather than written per route.

## Static adapter and prerendering

Prerendering a multilingual SvelteKit site multiplies routes by languages. Manageable, and worth deciding deliberately which languages are prerendered rather than accepting whatever the default produces.

## Beyond the interface

Content from a CMS is a separate pipeline from interface strings, and [website translation](https://www.vitra.ai/features/website-translation) covers the rendered output where the two combine. [translation memory](https://www.vitra.ai/features/translation-memory) keeps recurring cost proportional to what actually changed.

Setup notes are on the [Svelte integration](https://www.vitra.ai/integration/svelte) page.

## Stores and server-side rendering

A module-level store is shared across requests on the server. Setting the locale in a shared store means one user's language can leak into another user's response under concurrent load. Keep the locale in page data rather than a module-level store, or scope the store per request. This is the single most important correctness detail in a hand-rolled SvelteKit i18n setup.

## Progressive enhancement

Forms and actions that work without JavaScript need their responses localized server-side too, since there is no client to do it.

## Choosing a library versus rolling your own

A hand-rolled store works well for a small app with a few hundred strings. Past that, the things a library gives you — [plural rules](https://www.vitra.ai/general/internationalization-vs-localization), interpolation, message formatting, extraction tooling — are exactly the things that are tedious and error-prone to write yourself. The switching point is usually plural handling. The moment a string depends on a count, a library earns its place.

## Where to start

Render one page in the target language and view source. If the translated text is in the HTML, search engines can read it. If it only appears after hydration, it is a client-side render and needs the server side solved first.

## FAQ

**Does Svelte have an official i18n library?** No. Teams use a community library or build a store-based pattern: a writable store for the locale, a derived store resolving keys, and a template helper. Reactivity makes the hand-rolled version defensible here.

**How do I get language URLs in SvelteKit?** With a [lang] route parameter, which produces paths like /fr/pricing. That gives each language a distinct crawlable URL, which everything else in multilingual SEO depends on.

**Where should messages be loaded?** In the load function, so they arrive with the server render. Fetching them in onMount means the first paint is untranslated and a crawler never sees the translated text at all.

**Does prerendering work with multiple languages?** Yes, though it multiplies routes by languages. Decide deliberately which languages are prerendered rather than accepting whatever the default configuration produces.

Our blog

## Lastest blog posts

Tool and strategies modern teams need to help their companies grow.

Automotive

[Automotive Brochure Localization by Market](https://www.vitra.ai/automotive/automotive-brochure-localization)
A car brochure is a spec grid, a legal footer and a photo library, all market-specific. What actually has to change, and why the layout decides the schedule.

[Samhitha J Bhatt](https://www.vitra.ai/author/samhitha)
Aug 18, 2026

Automotive

[Automotive Campaign Localization Across Markets](https://www.vitra.ai/automotive/automotive-campaign-localization)
Campaigns run through national companies and dealer networks, so one master becomes hundreds of files. Where the offer text and the disclaimers actually break.

[Samhitha J Bhatt](https://www.vitra.ai/author/samhitha)
Aug 18, 2026

Automotive

[Car Service Manual Translation for Technicians](https://www.vitra.ai/automotive/automotive-service-manual-translation)
A workshop manual is read mid-repair by someone with the car on a lift. What that demands of procedures, torque figures and fault codes, in every language.

[Samhitha J Bhatt](https://www.vitra.ai/author/samhitha)
Aug 18, 2026

[View all posts](https://www.vitra.ai/blog/page/1)

---

## Structured data

```json
{
  "@context": "https://schema.org",
  "@type": "Article",
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://www.vitra.ai/general/translate-a-svelte-app"
  },
  "headline": "How to Translate a Svelte or SvelteKit App",
  "image": [
    {
      "@type": "ImageObject",
      "url": "https://www.vitra.ai/static/images/blog/translate-a-svelte-app.jpg"
    }
  ],
  "datePublished": "2026-08-17T00:00:00.000Z",
  "dateModified": "2026-08-17T00:00:00.000Z",
  "author": [
    {
      "@type": "Person",
      "name": "Samhitha J Bhatt"
    }
  ],
  "publisher": {
    "@type": "Organization",
    "name": "Vitra.ai",
    "logo": {
      "@type": "ImageObject",
      "url": "https://www.vitra.ai/static/images/vitra-v-logo.png"
    }
  },
  "description": "Svelte has no official i18n library, so the pattern is yours to choose. SvelteKit's routing is what makes the SEO half straightforward in practice."
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Home",
      "item": "https://www.vitra.ai"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "General",
      "item": "https://www.vitra.ai/general"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "How to Translate a Svelte or SvelteKit App",
      "item": "https://www.vitra.ai/general/translate-a-svelte-app"
    }
  ]
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "Does Svelte have an official i18n library?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "No. Teams use a community library or build a store-based pattern: a writable store for the locale, a derived store resolving keys, and a template helper. Reactivity makes the hand-rolled version defensible here."
      }
    },
    {
      "@type": "Question",
      "name": "How do I get language URLs in SvelteKit?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "With a [lang] route parameter, which produces paths like /fr/pricing. That gives each language a distinct crawlable URL, which everything else in multilingual SEO depends on."
      }
    },
    {
      "@type": "Question",
      "name": "Where should messages be loaded?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "In the load function, so they arrive with the server render. Fetching them in onMount means the first paint is untranslated and a crawler never sees the translated text at all."
      }
    },
    {
      "@type": "Question",
      "name": "Does prerendering work with multiple languages?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes, though it multiplies routes by languages. Decide deliberately which languages are prerendered rather than accepting whatever the default configuration produces."
      }
    }
  ]
}
```
