
Product
Socket Now Protects the Chrome Extension Ecosystem
Socket is launching experimental protection for Chrome extensions, scanning for malware and risky permissions to prevent silent supply chain attacks.
@inlang/paraglide-sveltekit
Advanced tools

Install ParaglideJS and Paraglide-SvelteKit.
npx @inlang/paraglide-js init
npm i -D @inlang/paraglide-sveltekit
This will generate a messages/{lang}.json
file for each of your languages. This is where your translation files live.
Add the vite-plugin to your vite.config.js
file. This will make sure to rerun the paraglide compiler when needed and add the link preprocessor.
import { paraglide } from "@inlang/paraglide-sveltekit/vite"
export default defineConfig({
plugins: [
paraglide({
//recommended
project: "./project.inlang",
outdir: "./src/lib/paraglide",
}),
sveltekit(),
],
})
Create a src/lib/i18n.js
file:
// src/lib/i18n.js
import { createI18n } from "@inlang/paraglide-sveltekit"
import * as runtime from "$lib/paraglide/runtime.js"
export const i18n = createI18n(runtime);
createI18n
will be your one-stop shop for configuring i18n routing.
Add the ParaglideJS
component to your layout and pass it the i18n
instance.
If you're using Svelte 4 do it like so:
<!-- src/routes/+layout.svelte -->
<script>
import { ParaglideJS } from '@inlang/paraglide-sveltekit'
import { i18n } from '$lib/i18n.js'
</script>
<ParaglideJS {i18n}>
<slot />
</ParaglideJS>
or if you're using Svelte 5:
<!-- src/routes/+layout.svelte -->
<script>
import { ParaglideJS } from '@inlang/paraglide-sveltekit'
import { i18n } from '$lib/i18n.js'
const { children } = $props()
</script>
<ParaglideJS {i18n}>
{@render children}
</ParaglideJS>
In your src/hooks.js
file, use the i18n
instance to add the reroute
hook:
import { i18n } from '$lib/i18n.js'
export const reroute = i18n.reroute()
The reroute hook was added in SvelteKit 2.3.0
In src/hooks.server.js
add the handle hook.
// src/hooks.server.js
import { i18n } from '$lib/i18n.js'
export const handle = i18n.handle()
This will make the language and text-direction on event.locals.paraglide
.
To set the lang
and dir
attributes on your <html>
tag add placeholders in src/app.html
. These placeholders will be replaced by the handle
hook.
<!-- src/app.html -->
<html lang="%paraglide.lang%" dir="%paraglide.textDirection%">
Visit /
to see your default language, and /{lang}
to see other languages. All links should be translated automatically.
Exclude routes from being translated with the exclude
option.
import { createI18n } from "@inlang/paraglide-sveltekit"
import * as runtime from "$lib/paraglide/runtime.js"
export const i18n = createI18n(runtime, {
// don't include the language or base path
exclude: ["/admin", "/login", /^\/user\/\d+$/],
})
Excluded routes will:
rel="alternate"
links added to themMake sure excluded pages are still wrapped in the <ParaglideJS>
so that outgoing links are still translated.
/en/about
for English/de/uber-uns
for German/fr/a-propos
for FrenchYou can have different paths for each language with the pathnames
option.
Don't include the language or the base path.
import { createI18n } from "@inlang/paraglide-sveltekit"
import * as runtime from "$lib/paraglide/runtime.js"
import * as m from "$lib/paraglide/messages.js"
import { match as int } from "../params/int.js"
export const i18n = createI18n(runtime, {
pathnames: {
"/about" : {
en: "/about",
de: "/uber-uns",
fr: "/a-propos",
},
// You can use parameters
// All translations must use identical parameters and names
"/user/[id=int]/[...rest]" : {
en: "/user/[id=int]/[...rest]",
de: "/benutzer/[id=int]/[...rest]",
fr: "/utilisateur/[id=int]/[...rest]",
},
// Instead of a map, you can also pass a message-function
"/admin" : m.admin_path
}
// If you're using matchers in the pathnames, you need to pass them
matchers: { int }
})
Links are translated automatically using a preprocessor. You can use the normal a
-tag and Paraglide-SvelteKit will translate it for you.
<a href="/about">{m.about()}</a>
<!-- will become on of -->
<a href="/en/about">{m.about()}</a>
<a href="/de/uber-uns">{m.about()}</a>
<a href="/fr/a-propos">{m.about()}</a>
If you want a link to be translated into a specific language set the hreflang
attribute.
<a href="/about" hreflang="de">{m.about()}</a>
<!-- Will always be german, regardless of the current language -->
<a href="/de/uber-uns" hreflang="de">{m.about()}</a>
Opt-out of translation by adding a data-no-translate
attribute.
<!-- this will never be translated -->
<a href="/about" data-no-translate>{m.about()}</a>
Other attributes that are also translated are:
action
attribute on form
elementsformaction
attribute on button
elementsIf you have other attributes that you want to be translated open an issue.
SvelteKit's goto
and redirect
cannot be translated automatically. Localize the URLs you pass to them with i18n.resolveRoute()
.
import { i18n } from '$lib/i18n.js'
import { redirect } from '@sveltejs/kit'
import { goto } from '$app/navigation'
redirect(i18n.resolveRoute("/about", "en"))
//Omitting the language argument uses the current languageTag()
goto(i18n.resolveRoute("/about"))
Language switchers are tricky because we need to dynamically translate the current URL path, which is itself translated. We need to get the untranslated version of the current path & translate it into the target language.
You can get the untranslated path using i18n.route()
// $page.url.pathname = "/base/de/uber-uns"
const route = i18n.route($page.url.pathname)
// route = "/base/about"
Use this to create a language switcher.
<script>
import { availableLanguageTags, languageTag } from "$lib/paraglide/runtime.js"
import { i18n } from '$lib/i18n.js'
import { page } from '$app/stores'
</script>
{#each availableLanguageTags as lang}
<!-- the hreflang attribute decides which language the link points to -->
<a
href={i18n.route($page.url.pathname)}
hreflang={lang}
aria-current={lang === languageTag() ? "page" : undefined}
>
{lang}
</a>
{/each}
Paraglide guesses the text direction using the Intl.Locale
API. This is not supported in all runtimes. Use the textDirection
option to provide the text direction yourself.
import { createI18n } from "@inlang/paraglide-sveltekit"
import * as runtime from "$lib/paraglide/runtime.js"
export const i18n = createI18n(runtime, {
textDirection: {
en: "ltr",
ar: "rtl",
},
})
lang
and textDirection
On the server you can access the current language and text direction on event.locals.paraglide
.
On the client, you can call languageTag()
exported ./paraglide/runtime.js
.
### Using the Language on the Server
#### Avoiding Cross-Talk
SvelteKit does two kinds of work on the server: Loading and Rendering.
load
functions, actions
or server-hooks..svelte
file.Loading is asynchronous & rendering is synchronous.
During the asynchronous loading, there is danger of crosstalk. If you aren't careful it's possible for one request to override the language of another request. You can avoid this by explicitly specifying which language a message should be in.
import * as m from "$lib/paraglide/messages.js"
export async function load({ locals }) {
const translatedText = m.some_message({ ...message_params }, { languageTag: locals.paraglide.lang })
return { translatedText }
}
During rendering there is no danger of crosstalk. You can safely use messages and the langaugeTag()
function.
You can tell a load function to re-run on language changes by calling depends("paraglide:lang")
.
export async function load({ depends }) {
// Paraglide-SvelteKit automatically calls `invalidate("paraglide:lang")` whenever the langauge changes
// This tells SvelteKit to re-run this function whenever that happens
depends("paraglide:lang")
return await myLanguageSpecificData();
}
## Caveats
<ParagldieJS>
will not be translated. This will also log a warning in development.data
will run on language changes even if the data didn't change. If the data is language-dependent the side effect will run twice.+layout.svelte
The language state get's set when the <ParaglideJS>
component is mounted. Since you usually place it inside +layout.svelte
using messages in the layout's <script>
can cause issues.
<script>
import { ParaglideJS } from '@inlang/paraglide-sveltekit'
import { i18n } from '$lib/i18n.js'
//using messages here can cause hydration issues
</script>
<ParaglideJS {i18n}>
<!-- Using messages here is fine -->
<slot />
</ParaglideJS>
SvelteKit's reroute
hook currently doens't play well with Vercel (see sveltejs/kit#11879), which means that we need to slightly adapt the setup to make it work when deployed to Vercel.
reroute
hook from src/hooks.js
routes
into a [[locale]]
folderpathnames
We are working on contributing a fix for sveltejs/kit#11879, so this workaround will hopefully not be needed much longer.
data
changing double triggering on language changes if they depend on the language.Play around with it on StackBlitz
FAQs
--- imports: - https://cdn.jsdelivr.net/npm/@opral/markdown-wc-doc-elements/dist/doc-callout.js ---
The npm package @inlang/paraglide-sveltekit receives a total of 3,795 weekly downloads. As such, @inlang/paraglide-sveltekit popularity was classified as popular.
We found that @inlang/paraglide-sveltekit demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
Socket is launching experimental protection for Chrome extensions, scanning for malware and risky permissions to prevent silent supply chain attacks.
Product
Add secure dependency scanning to Claude Desktop with Socket MCP, a one-click extension that keeps your coding conversations safe from malicious packages.
Product
Socket now supports Scala and Kotlin, bringing AI-powered threat detection to JVM projects with easy manifest generation and fast, accurate scans.