Internationalization (i18n)
Svelar integrates with paraglide-js 2.x for type-safe, URL-based internationalization. The framework provides helpers that wire paraglide into SvelteKit's hooks system and a ready-to-use language switcher component.
i18n is opt-in. New projects scaffolded with
npx svelar newship in English with no i18n overhead. When you're ready to add multi-language support, follow the steps below — Svelar's Vite aliases for@beeblock/svelar/i18nare already pre-configured.
Setup
1. Install paraglide-js
npm install @inlang/paraglide-js
npx @inlang/paraglide-js init
The init command creates the project.inlang/ configuration directory. When prompted, select your base locale (e.g., en) and any additional locales you want to support.
2. Configure the Vite Plugin
Add the paraglide plugin to your existing vite.config.ts (the file is already scaffolded by npx svelar new):
// vite.config.ts
import { paraglideVitePlugin } from '@inlang/paraglide-js';
export default defineConfig({
plugins: [
sveltekit(),
paraglideVitePlugin({
project: './project.inlang',
outdir: './src/lib/paraglide',
strategy: ['url', 'cookie', 'baseLocale'],
outputStructure: 'message-modules',
}),
tailwindcss(),
],
});
The outputStructure: 'message-modules' setting is required — it generates the full runtime with getLocale, localizeHref, deLocalizeUrl, and other exports that Svelar's i18n helpers depend on.
3. Create Translation Files
messages/
├── en.json # English (base locale)
└── pt.json # Portuguese
// messages/en.json
{
"app_name": "My App",
"nav_dashboard": "Dashboard",
"nav_login": "Sign In",
"nav_register": "Register",
"nav_logout": "Sign Out"
}
// messages/pt.json
{
"app_name": "Meu App",
"nav_dashboard": "Painel",
"nav_login": "Entrar",
"nav_register": "Cadastrar",
"nav_logout": "Sair"
}
4. Wire the Server Hooks
Your scaffolded hooks.server.ts already uses createSvelarApp. Add the i18n option to enable locale detection:
// src/hooks.server.ts
import { createSvelarApp } from '@beeblock/svelar/hooks';
import { paraglideMiddleware } from '$lib/paraglide/server';
import { getTextDirection } from '$lib/paraglide/runtime';
import { auth } from './app.js';
export const { handle, handleError } = createSvelarApp({
auth,
i18n: { paraglideMiddleware, getTextDirection },
});
Or, if you prefer manual control, use createI18nHandle:
// src/hooks.server.ts
import { sequence } from '@sveltejs/kit/hooks';
import { createI18nHandle } from '@beeblock/svelar/i18n';
import { createSvelarHooks } from '@beeblock/svelar/hooks';
import { paraglideMiddleware } from '$lib/paraglide/server';
import { getTextDirection } from '$lib/paraglide/runtime';
const i18nHandle = createI18nHandle({ paraglideMiddleware, getTextDirection });
const svelarHandle = createSvelarHooks({ /* ... */ });
export const handle = sequence(i18nHandle, svelarHandle);
5. Wire the Client Reroute Hook
// src/hooks.ts
import { createReroute } from '@beeblock/svelar/i18n';
import { deLocalizeUrl } from '$lib/paraglide/runtime';
export const reroute = createReroute({ deLocalizeUrl });
6. Update app.html
Replace hardcoded lang and dir with paraglide placeholders:
<!doctype html>
<html lang="%lang%" dir="%dir%">
<head>...</head>
<body>...</body>
</html>
Using Translations in Components
Import message functions and localizeHref in every component:
<script>
import * as m from '$lib/paraglide/messages';
import { localizeHref } from '$lib/paraglide/runtime';
</script>
<h1>{m.app_name()}</h1>
<a href={localizeHref('/dashboard')}>{m.nav_dashboard()}</a>
Every internal <a href> must use localizeHref() to maintain the locale prefix across navigation. Without it, clicking a link drops the /pt/ prefix and resets to the base locale.
Language Switcher
Svelar includes a ready-to-use LanguageSwitcher component:
<script>
import LanguageSwitcher from '@beeblock/svelar/i18n/LanguageSwitcher.svelte';
import { page } from '$app/state';
import { locales, getLocale, localizeHref } from '$lib/paraglide/runtime';
</script>
<LanguageSwitcher
{locales}
{getLocale}
{localizeHref}
pathname={page.url.pathname}
labels={{ en: 'EN', pt: 'PT', es: 'ES' }}
/>
The component renders locale buttons that trigger a full page reload (data-sveltekit-reload) so the server middleware picks up the new locale.
Props
locales— Array of available locale codes (from paraglide runtime)getLocale— Function returning the current locale (from paraglide runtime)localizeHref— Function to localize a path for a given locale (from paraglide runtime)pathname— Current page pathname (typicallypage.url.pathname)labels— Optional display labels per locale (defaults to uppercase code)class— Extra CSS class for the container
Adding a New Language
- Create
messages/es.jsonwith translations - Update
project.inlang/settings.jsonto add"es"to the locales list - Add the label to your LanguageSwitcher:
labels={{ en: 'EN', pt: 'PT', es: 'ES' }} - Restart the dev server — paraglide auto-generates the new runtime
Locale-Aware Dates
Svelar ships with @beeblock/svelar/dates — a timezone-safe date utility built on date-fns. To make dates follow the active paraglide locale automatically, create a thin wrapper in your app:
// src/lib/dates.ts
import { formatDate as svelarFormat, formatRelative as svelarRelative, timeAgo as svelarTimeAgo } from '@beeblock/svelar/dates';
import { getLocale } from '$lib/paraglide/runtime';
import { enUS, pt, es } from 'date-fns/locale';
const localeMap: Record<string, Locale> = { en: enUS, pt, es };
function getDateLocale(): Locale {
return localeMap[getLocale()] ?? enUS;
}
export function formatDate(input: DateInput, pattern = 'PP'): string {
return svelarFormat(input, pattern, { locale: getDateLocale() });
}
export function timeAgo(input: DateInput): string {
return svelarTimeAgo(input, { locale: getDateLocale() });
}
Then use formatDate and timeAgo from $lib/dates in your components — they automatically pick up the current locale from paraglide.
See the full Date Utilities guide for all available functions.
Next Steps
- Explore Date Utilities for timezone-safe formatting
- Explore Forms for server-side validation with Superforms
- Learn about UI Components for the component library
- Check Middleware for request processing
Svelar i18n Guide © 2026