HomeSandboxShowcaseAppDocBlog
    • EnglishEnglish
      EN
    • русскийRussian
      RU
    • 日本語Japanese
      JA
    • françaisFrench
      FR
    • 한국어Korean
      KO
    • 中文Chinese
      ZH
    • españolSpanish
      ES
    • DeutschGerman
      DE
    • العربيةArabic
      AR
    • italianoItalian
      IT
    • British EnglishBritish English
      EN-GB
    • portuguêsPortuguese
      PT
    • हिन्दीHindi
      HI
    • TürkçeTurkish
      TR
    • polskiPolish
      PL
    • IndonesiaIndonesian
      ID
    • Tiếng ViệtVietnamese
      VI
    • українськаUkrainian
      UK
    /
    Filter docs by framework
    Alt+←
    Why Intlayer ?
    Get Started
    Concept
    • How Intlayer Works
    • Configuration
    • TestFillBuildWatchExtractLoginPushPullConfigurationListVersionEditorLiveDebugDoc ReviewDoc TranslateSDK
    • Visual Editor
    • CMS
    • CI/CD Integration
    • TranslationPluralEnumerationConditionGenderInsertionFileNestingMarkdownHTMLFunction Fetching
    • Per Locale File
    • Compiler
    • Auto Fill
    • Testing
    • Bundle Optimization
    Environment
    • Next.js 14 and App Router
      Next.js 15
      Next.js no locale path
      Next.js and Page Router
      Compiler
    • Tanstack Start Solid
    • Astro and React
      Astro and Svelte
      Astro and Vue
      Astro and Solid
      Astro and Preact
      Astro and Lit
      Astro and Vanilla JS
    • React Router v7
      React Router v7 (fs-routes)
      Compiler
    • Nuxt and Vue
    • Vite and Solid
    • SvelteKit
    • Vite and Preact
    • Vite and Vanilla JS
    • Vite and Lit
    • Angular 19 (Webpack)
      Analog
    • React CRA
    • React Native and Expo
    • Express.js
      NestJS
      Fastify
      Hono
      Adonis
    • Lynx and React
    Plugins
    • JSON
    • gettext (.po)
    VS Code Extension
    Agent
    • MCP Server
    • Agent skills
    Releases
    • v8
    • v7
    • v6
    Benchmark
    • Next.js
    • TanStack
    • Vue
    • Solid
    • Svelte
    Blog
    Ask a question
    1. Documentation
    2. Environment
    3. Sveltekit
    \n\n\n

    {$content.title}

    \n\n

    {@const Title = $content.title}</h1>\n<!-- To render the content as a string -->\n<div aria-label={$content.title.value}></div>\n<div aria-label={$content.title.toString()}></div>\n<div aria-label={String($content.title)}></div>\n```\n\n### (Optional) Step 6: Set up routing\n\nThe following steps show how to set up locale-based routing in SvelteKit. This allows your URLs to include the locale prefix (e.g., `/en/about`, `/fr/about`) for better SEO and user experience.\n\n```bash\n.\n└─── src\n ├── app.d.ts # Define the locale type\n ├── hooks.server.ts # Manage locale routing\n ├── lib\n │   └── getLocale.ts # Check the locale from the header, cookies\n ├── params\n │   └── locale.ts # Define the locale parameter\n └── routes\n ├── [[locale=locale]] # Wrap in a route group to set the locale\n │   ├── +layout.svelte # Local layout for the route\n │   ├── +layout.ts\n │   ├── +page.svelte\n │   ├── +page.ts\n │   └── about\n │      ├── +page.svelte\n │      └── +page.ts\n └── +layout.svelte # Root layout for fonts and global styles\n```\n\n### Step 7: Handle Server-Side Locale Detection (Hooks)\n\nIn SvelteKit, the server needs to know the user's locale to render the correct content during SSR. We use `hooks.server.ts` to detect the locale from the URL or cookies.\n\nCreate or modify `src/hooks.server.ts`:\n\n```typescript fileName=\"src/hooks.server.ts\"\nimport type { Handle } from \"@sveltejs/kit\";\nimport { getLocalizedUrl } from \"intlayer\";\nimport { getLocale } from \"$lib/getLocale\";\n\nexport const handle: Handle = async ({ event, resolve }) => {\n const detectedLocale = getLocale(event);\n\n // Check if the current path already starts with a locale (e.g. /fr, /en)\n const pathname = event.url.pathname;\n const targetPathname = getLocalizedUrl(pathname, detectedLocale);\n\n // If NO locale is present in the URL (e.g. user visits \"/\"), redirect them\n if (targetPathname !== pathname) {\n return new Response(undefined, {\n headers: { Location: targetPathname },\n status: 307, // Temporary redirect\n });\n }\n\n return resolve(event, {\n transformPageChunk: ({ html }) => html.replace(\"%lang%\", detectedLocale),\n });\n};\n```\n\nThen, create a helper to get the user's locale from the request event:\n\n```typescript fileName=\"src/lib/getLocale.ts\"\nimport {\n configuration,\n getLocaleFromStorage,\n localeDetector,\n type Locale,\n} from \"intlayer\";\nimport type { RequestEvent } from \"@sveltejs/kit\";\n\n/**\n * Retrieve the user's locale from the request event.\n * This function is utilised in the `handle` hook within `src/hooks.server.ts`.\n *\n * It initially attempts to obtain the locale from the Intlayer storage (cookies or custom headers).\n * If the locale is not found, it defaults to the browser's \"Accept-Language\" negotiation.\n *\n * @param event - The request event from SvelteKit\n * @returns The user's locale\n */\nexport const getLocale = (event: RequestEvent): Locale => {\n const defaultLocale = configuration?.internationalization?.defaultLocale;\n\n // Attempt to retrieve locale from Intlayer storage (Cookies or headers)\n const storedLocale = getLocaleFromStorage({\n // SvelteKit cookies access\n getCookie: (name: string) => event.cookies.get(name) ?? null,\n // SvelteKit headers access\n getHeader: (name: string) => event.request.headers.get(name) ?? null,\n });\n\n if (storedLocale) {\n return storedLocale;\n }\n\n // Fallback to Browser \"Accept-Language\" negotiation\n const negotiatorHeaders: Record<string, string> = {};\n\n // Convert SvelteKit Headers object to a plain Record<string, string>\n event.request.headers.forEach((value, key) => {\n negotiatorHeaders[key] = value;\n });\n\n // Check the locale from the `Accept-Language` header\n const userFallbackLocale = localeDetector(negotiatorHeaders);\n\n if (userFallbackLocale) {\n return userFallbackLocale;\n }\n\n // Return default locale if no match is found\n return defaultLocale;\n};\n```\n\n> `getLocaleFromStorage` will check the locale from header or cookie depending on your configuration. See [Configuration](https://intlayer.org/doc/configuration) for more details.\n\n> The `localeDetector` function will process the `Accept-Language` header and return the best match.\n\nIf the locale is not configured, we want to return a 404 error. To simplify this, we can create a `match` function to verify if the locale is valid:\n\n```ts fileName=\"/src/params/locale.ts\"\nimport { defaultLocale, locales, type Locale } from \"intlayer\";\n\nexport const match = (param: Locale = defaultLocale): boolean =>\n locales.includes(param);\n```\n\n> **Note:** Ensure your `src/app.d.ts` includes the locale definition:\n>\n> ```typescript\n> declare global {\n> namespace App {\n> interface Locals {\n> locale: import(\"intlayer\").Locale;\n> }\n> }\n> }\n> ```\n\nFor the `+layout.svelte` file, we can remove everything, to keep only static content, not related to i18n:\n\n```svelte fileName=\"src/+layout.svelte\"\n<script lang=\"ts\">\n\t import './layout.css';\n\n let { children } = $props();\n</script>\n\n<div class=\"app\">\n\t{@render children()}\n</div>\n\n<style>\n\t.app {\n /* */\n\t}\n</style>\n```\n\nThen, create a new page and layout under the `[[locale=locale]]` group:\n\n```ts fileName=\"src/routes/[[locale=locale]]/+layout.ts\"\nimport type { Load } from \"@sveltejs/kit\";\nimport { defaultLocale, type Locale } from \"intlayer\";\n\nexport const prerender = true;\n\n// Use the generic Load type\nexport const load: Load = ({ params }) => {\n const locale: Locale = (params.locale as Locale) ?? defaultLocale;\n\n return {\n locale,\n };\n};\n```\n\n```svelte fileName=\"src/routes/[[locale=locale]]/+layout.svelte\"\n<script lang=\"ts\">\n\timport type { Snippet } from 'svelte';\n\timport { useIntlayer, setupIntlayer } from \"svelte-intlayer\";\n\timport Header from './Header.svelte';\n\timport type { LayoutData } from './$types';\n\n\tlet { children, data }: { children: Snippet, data: LayoutData } = $props();\n\n\t// Initialise Intlayer with the locale from the route\n $effect(() => {\n setupIntlayer(data.locale);\n });\n\t// Use the layout content dictionary\n\tconst layoutContent = useIntlayer('layout');\n</script>\n\n<Header />\n\n<main>\n\t{@render children()}\n</main>\n\n<footer>\n\t<p>\n\t\t{$layoutContent.footer.prefix.value}{' '}\n\t\t<a href=\"https://svelte.dev/docs/kit\">{$layoutContent.footer.linkLabel.value}</a>{' '}\n\t\t{$layoutContent.footer.suffix.value}\n\t</p>\n</footer>\n\n<style>\n /* */\n</style>\n```\n\n```ts fileName=\"src/routes/[[locale=locale]]/+page.ts\"\nexport const prerender = true;\n```\n\n```svelte fileName=\"src/routes/[[locale=locale]]/+page.svelte\"\n<script lang=\"ts\">\n\timport { useIntlayer } from \"svelte-intlayer\";\n\n\t// Use the home content dictionary\n\tconst homeContent = useIntlayer('home');\n</script>\n\n<svelte:head>\n\t<title>{$homeContent.title.value}\n\n\n
    \n\t

    \n\t\t{$homeContent.title}\n\t

    \n
    \n\n\n```\n\n### (Optional) Step 8: Internationalised Links\n\nFor SEO, it is recommended to prefix your routes with the locale (e.g., `/en/about`, `/fr/about`). This component automatically prefixes any link with the current locale.\n\n```svelte fileName=\"src/lib/components/LocalizedLink.svelte\"\n\n\n\n \n\n```\n\nIf you use `goto` from SvelteKit, you can use the same logic with `getLocalizedUrl` to navigate to the localised URL:\n\n```typescript\nimport { goto } from \"$app/navigation\";\nimport { getLocalizedUrl } from \"intlayer\";\nimport { useLocale } from \"svelte-intlayer\";\n\nconst { locale } = useLocale();\nconst localizedPath = getLocalizedUrl(\"/about\", $locale);\ngoto(localizedPath); // Navigates to /en/about or /fr/about depending on locale\n```\n\n### (Optional) Step 9: Language Switcher\n\nTo allow users to switch languages, update the URL.\n\n```svelte fileName=\"src/lib/components/LanguageSwitcher.svelte\"\n\n\n
      \n {#each availableLocales as localeEl}\n
    • \n {\n e.preventDefault();\n setLocale(localeEl); // Will set the locale in the store and trigger onLocaleChange\n }}\n class:active={$locale === localeEl}\n >\n {getLocaleName(localeEl)}\n \n
    • \n {/each}\n
    \n\n\n```\n\n### (Optional) Step 10: Add backend proxy\n\nTo add a backend proxy to your SvelteKit application, you can use the `intlayerProxy` function provided by the `vite-intlayer` plugin. This plugin will automatically detect the best locale for the user based on the URL, cookies, and browser language preferences.\n\n```ts fileName=\"vite.config.ts\"\nimport { defineConfig } from \"vite\";\nimport { intlayer, intlayerProxy } from \"vite-intlayer\";\nimport { sveltekit } from \"@sveltejs/kit/vite\";\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n plugins: [\n intlayerProxy(), // should be placed first\n intlayer(),\n sveltekit(),\n ],],\n});\n```\n\n### (Optional) Step 11: Set up the intlayer editor / CMS\n\nTo set up the intlayer editor, you must follow the [intlayer editor documentation](/en-GB/doc/concept/editor).\n\nTo set up the intlayer CMS, you must follow the [intlayer CMS documentation](/en-GB/doc/concept/cms).\n\nTo be able to visualise the intlayer editor selector, you will have to use the component syntax in your intlayer content.\n\n```svelte fileName=\"Component.svelte\"\n\n\n
    \n\n \n

    {$content.title}

    \n\n \n {@const Component = $content.component}\n
    \n```\n\n### Git Configuration\n\nIt is recommended to ignore the files generated by Intlayer.\n\n```plaintext fileName=\".gitignore\"\n# Ignore the files generated by Intlayer\n.intlayer\n```\n\n---\n\n### Go Further\n\n- **Visual Editor**: Integrate the [Intlayer Visual Editor](/en-GB/doc/concept/editor) to edit translations directly from the UI.\n- **CMS**: Externalise your content management using the [Intlayer CMS](/en-GB/doc/concept/cms).\n\n```\n\n```\n","about":"Discover how to make your SvelteKit website multilingual. Follow the documentation to internationalise (i18n) and translate it using Server-Side Rendering (SSR).","url":"https://intlayer.org/en-GB/doc/environment/sveltekit","datePublished":"20-11-2025","dateModified":"06-05-2026","keywords":"Internationalisation, Documentation, Intlayer, SvelteKit, JavaScript, SSR","license":"https://raw.githubusercontent.com/aymericzip/intlayer/refs/heads/main/LICENSE","audience":{"@type":"Audience","audienceType":"Developers, Content Managers"}}
    Creation:2025-11-20Last update:2026-05-06
    See the application template on GitHub

    This page has an application template available.

    See the showcase application

    This page links to a live demo of the template.

    Reference this doc to your favorite AI assistant
    ChatGPT
    Claude
    DeepSeek
    Google AI mode
    Gemini
    Perplexity
    Mistral
    Grok

    Ask your question and get a summary of the document by referencing this page and the AI provider of your choice

    Version History

    1. "Update Solid useIntlayer API usage to direct property access"
      v8.9.004/05/2026
    2. "Add init command"
      v7.5.930/12/2025
    3. "Initial history"
      v7.1.1020/11/2025

    The content of this page was translated using an AI.

    See the last version of the original content in English
    Edit this doc

    If you have an idea for improving this documentation, please feel free to contribute by submitting a pull request on GitHub.

    GitHub link to the documentation
    Copy

    Copy doc Markdown to clipboard

    Translate your SvelteKit website using Intlayer | Internationalisation (i18n)

    ide.intlayer.org
    intlayer-sveltekit-template.vercel.app

    Table of Contents

    What is Intlayer?

    Intlayer is an innovative, open-source internationalisation (i18n) library designed to simplify multilingual support in modern web applications. It works seamlessly with SvelteKit's Server-Side Rendering (SSR) capabilities.

    With Intlayer, you can:

    • Easily manage translations using declarative dictionaries at the component level.
    • Dynamically localise metadata, routes, and content.
    • Ensure TypeScript support with autogenerated types.
    • Leverage SvelteKit's SSR for SEO-friendly internationalisation.

    Step-by-Step Guide to Set Up Intlayer in a SvelteKit Application

    To get started, create a new SvelteKit project. Here is the final structure that we will make:

    bash
    Copy code

    Copy the code to the clipboard

    .├── intlayer.config.ts├── package.json├── src│   ├── app.d.ts│   ├── app.html│   ├── hooks.server.ts│   ├── lib│   │   ├── getLocale.ts│   │   ├── LocaleSwitcher.svelte│   │   └── LocalizedLink.svelte│   ├── params│   │   └── locale.ts│   └── routes│       ├── [[locale=locale]]│       │   ├── +layout.svelte│       │   ├── +layout.ts│       │   ├── +page.svelte│       │   ├── +page.ts│       │   ├── about│       │   │   ├── +page.svelte│       │   │   ├── +page.ts│       │   │   └── page.content.ts│       │   ├── Counter.content.ts│       │   ├── Counter.svelte│       │   ├── Header.content.ts│       │   ├── Header.svelte│       │   ├── home.content.ts│       │   └── layout.content.ts│       ├── +layout.svelte│       └── layout.css├── static│   ├── favicon.svg│   └── robots.txt├── svelte.config.js├── tsconfig.json└── vite.config.ts

    Step 1: Install Dependencies

    Install the necessary packages using npm:

    bash
    Copy code

    Copy the code to the clipboard

    npm install intlayer svelte-intlayernpm install vite-intlayer --save-devnpx intlayer init
    • intlayer: The core i18n package.
    • svelte-intlayer: Provides context providers and stores for Svelte/SvelteKit.
    • vite-intlayer: The Vite plugin to integrate content declarations with the build process.

    Step 2: Configuration of your project

    Create a config file in your project root:

    intlayer.config.ts
    Copy code

    Copy the code to the clipboard

    import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],    defaultLocale: Locales.ENGLISH,  },};export default config;

    Step 3: Integrate Intlayer in Your Vite Configuration

    Update your vite.config.ts to include the Intlayer plugin. This plugin manages the transpilation of your content files.

    vite.config.ts
    Copy code

    Copy the code to the clipboard

    import { sveltekit } from "@sveltejs/kit/vite";import { defineConfig } from "vite";import { intlayer } from "vite-intlayer";export default defineConfig({  plugins: [intlayer(), sveltekit()], // order matters, Intlayer should be placed before SvelteKit});

    Step 4: Declare Your Content

    Create your content declaration files anywhere in your src folder (e.g., src/lib/content or alongside your components). These files define the translatable content for your application using the t() function for each locale.

    Step 5: Utilise Intlayer in Your Components

    Now you can use the useIntlayer function in any Svelte component. It returns a reactive store that automatically updates when the locale changes. The function will automatically respect the current locale (both during SSR and client-side navigation).

    Note: useIntlayer returns a Svelte store, so you need to use the `--- createdAt: 2025-11-20 updatedAt: 2026-05-06 title: How to translate an SvelteKit app – i18n guide 2026 description: Discover how to make your SvelteKit website multilingual. Follow the documentation to internationalise (i18n) and translate it using Server-Side Rendering (SSR). keywords:

    • Internationalisation
    • Documentation
    • Intlayer
    • SvelteKit
    • JavaScript
    • SSR slugs:
    • doc
    • environment
    • sveltekit applicationTemplate: https://github.com/aymericzip/intlayer-sveltekit-template history:
    • version: 7.1.10 date: 2025-11-20 changes: Init history

    Translate your SvelteKit website using Intlayer | Internationalisation (i18n)

    Table of Contents

    What is Intlayer?

    Intlayer is an innovative, open-source internationalisation (i18n) library designed to simplify multilingual support in modern web applications. It works seamlessly with SvelteKit's Server-Side Rendering (SSR) capabilities.

    With Intlayer, you can:

    • Easily manage translations using declarative dictionaries at the component level.
    • Dynamically localise metadata, routes, and content.
    • Ensure TypeScript support with autogenerated types.
    • Leverage SvelteKit's SSR for SEO-friendly internationalisation.

    Step-by-Step Guide to Set Up Intlayer in a SvelteKit Application

    To get started, create a new SvelteKit project. Here is the final structure that we will make:

    bash
    Copy code

    Copy the code to the clipboard

    .├── intlayer.config.ts├── package.json├── src│   ├── app.d.ts│   ├── app.html│   ├── hooks.server.ts│   ├── lib│   │   ├── getLocale.ts│   │   ├── LocaleSwitcher.svelte│   │   └── LocalizedLink.svelte│   ├── params│   │   └── locale.ts│   └── routes│       ├── [[locale=locale]]│       │   ├── +layout.svelte│       │   ├── +layout.ts│       │   ├── +page.svelte│       │   ├── +page.ts│       │   ├── about│       │   │   ├── +page.svelte│       │   │   ├── +page.ts│       │   │   └── page.content.ts│       │   ├── Counter.content.ts│       │   ├── Counter.svelte│       │   ├── Header.content.ts│       │   ├── Header.svelte│       │   ├── home.content.ts│       │   └── layout.content.ts│       ├── +layout.svelte│       └── layout.css├── static│   ├── favicon.svg│   └── robots.txt├── svelte.config.js├── tsconfig.json└── vite.config.ts

    Step 1: Install Dependencies

    Install the necessary packages using npm:

    bash
    Copy code

    Copy the code to the clipboard

    npm install intlayer svelte-intlayernpm install vite-intlayer --save-devnpx intlayer init
    • intlayer: The core i18n package.
    • svelte-intlayer: Provides context providers and stores for Svelte/SvelteKit.
    • vite-intlayer: The Vite plugin to integrate content declarations with the build process.

    Step 2: Configuration of your project

    Create a config file in your project root:

    intlayer.config.ts
    Copy code

    Copy the code to the clipboard

    import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],    defaultLocale: Locales.ENGLISH,  },};export default config;

    Step 3: Integrate Intlayer in Your Vite Configuration

    Update your vite.config.ts to include the Intlayer plugin. This plugin manages the transpilation of your content files.

    vite.config.ts
    Copy code

    Copy the code to the clipboard

    import { sveltekit } from "@sveltejs/kit/vite";import { defineConfig } from "vite";import { intlayer } from "vite-intlayer";export default defineConfig({  plugins: [intlayer(), sveltekit()], // order matters, Intlayer should be placed before SvelteKit});

    Step 4: Declare Your Content

    Create your content declaration files anywhere in your src folder (e.g., src/lib/content or alongside your components). These files define the translatable content for your application using the t() function for each locale.

    Step 5: Utilise Intlayer in Your Components

    prefix to access its reactive value (e.g., $content.title).

    src/lib/components/Component.svelte
    Copy code

    Copy the code to the clipboard

    <script lang="ts">  import { useIntlayer } from "svelte-intlayer";  // "hero-section" corresponds to the key defined in Step 4  const content = useIntlayer("hero-section");</script><!-- Render content as simple content  --><h1>{$content.title}</h1><!-- To render the content editable using the editor --><h1>{@const Title = $content.title}<Title /></h1><!-- To render the content as a string --><div aria-label={$content.title.value}></div><div aria-label={$content.title.toString()}></div><div aria-label={String($content.title)}></div>

    (Optional) Step 6: Set up routing

    The following steps show how to set up locale-based routing in SvelteKit. This allows your URLs to include the locale prefix (e.g., /en/about, /fr/about) for better SEO and user experience.

    bash
    Copy code

    Copy the code to the clipboard

    .└─── src    ├── app.d.ts                  # Define the locale type    ├── hooks.server.ts           # Manage locale routing    ├── lib    │   └── getLocale.ts          # Check the locale from the header, cookies    ├── params    │   └── locale.ts             # Define the locale parameter    └── routes        ├── [[locale=locale]]     # Wrap in a route group to set the locale        │   ├── +layout.svelte    # Local layout for the route        │   ├── +layout.ts        │   ├── +page.svelte        │   ├── +page.ts        │   └── about        │       ├── +page.svelte        │       └── +page.ts        └── +layout.svelte         # Root layout for fonts and global styles

    Step 7: Handle Server-Side Locale Detection (Hooks)

    In SvelteKit, the server needs to know the user's locale to render the correct content during SSR. We use hooks.server.ts to detect the locale from the URL or cookies.

    Create or modify src/hooks.server.ts:

    src/hooks.server.ts
    Copy code

    Copy the code to the clipboard

    import type { Handle } from "@sveltejs/kit";import { getLocalizedUrl } from "intlayer";import { getLocale } from "$lib/getLocale";export const handle: Handle = async ({ event, resolve }) => {  const detectedLocale = getLocale(event);  // Check if the current path already starts with a locale (e.g. /fr, /en)  const pathname = event.url.pathname;  const targetPathname = getLocalizedUrl(pathname, detectedLocale);  // If NO locale is present in the URL (e.g. user visits "/"), redirect them  if (targetPathname !== pathname) {    return new Response(undefined, {      headers: { Location: targetPathname },      status: 307, // Temporary redirect    });  }  return resolve(event, {    transformPageChunk: ({ html }) => html.replace("%lang%", detectedLocale),  });};

    Then, create a helper to get the user's locale from the request event:

    src/lib/getLocale.ts
    Copy code

    Copy the code to the clipboard

    import {  configuration,  getLocaleFromStorage,  localeDetector,  type Locale,} from "intlayer";import type { RequestEvent } from "@sveltejs/kit";/** * Retrieve the user's locale from the request event. * This function is utilised in the `handle` hook within `src/hooks.server.ts`. * * It initially attempts to obtain the locale from the Intlayer storage (cookies or custom headers). * If the locale is not found, it defaults to the browser's "Accept-Language" negotiation. * * @param event - The request event from SvelteKit * @returns The user's locale */export const getLocale = (event: RequestEvent): Locale => {  const defaultLocale = configuration?.internationalization?.defaultLocale;  // Attempt to retrieve locale from Intlayer storage (Cookies or headers)  const storedLocale = getLocaleFromStorage({    // SvelteKit cookies access    getCookie: (name: string) => event.cookies.get(name) ?? null,    // SvelteKit headers access    getHeader: (name: string) => event.request.headers.get(name) ?? null,  });  if (storedLocale) {    return storedLocale;  }  // Fallback to Browser "Accept-Language" negotiation  const negotiatorHeaders: Record<string, string> = {};  // Convert SvelteKit Headers object to a plain Record<string, string>  event.request.headers.forEach((value, key) => {    negotiatorHeaders[key] = value;  });  // Check the locale from the `Accept-Language` header  const userFallbackLocale = localeDetector(negotiatorHeaders);  if (userFallbackLocale) {    return userFallbackLocale;  }  // Return default locale if no match is found  return defaultLocale;};
    getLocaleFromStorage will check the locale from header or cookie depending on your configuration. See Configuration for more details.
    The localeDetector function will process the Accept-Language header and return the best match.

    If the locale is not configured, we want to return a 404 error. To simplify this, we can create a match function to verify if the locale is valid:

    /src/params/locale.ts
    Copy code

    Copy the code to the clipboard

    import { defaultLocale, locales, type Locale } from "intlayer";export const match = (param: Locale = defaultLocale): boolean =>  locales.includes(param);

    Note: Ensure your src/app.d.ts includes the locale definition:

    typescript
    Copy code

    Copy the code to the clipboard

    declare global {  namespace App {    interface Locals {      locale: import("intlayer").Locale;    }  }}

    For the +layout.svelte file, we can remove everything, to keep only static content, not related to i18n:

    src/+layout.svelte
    Copy code

    Copy the code to the clipboard

    <script lang="ts">     import './layout.css';    let { children } = $props();</script><div class="app">    {@render children()}</div><style>    .app {    /*  */    }</style>

    Then, create a new page and layout under the [[locale=locale]] group:

    src/routes/[[locale=locale]]/+layout.ts
    Copy code

    Copy the code to the clipboard

    import type { Load } from "@sveltejs/kit";import { defaultLocale, type Locale } from "intlayer";export const prerender = true;// Use the generic Load typeexport const load: Load = ({ params }) => {  const locale: Locale = (params.locale as Locale) ?? defaultLocale;  return {    locale,  };};
    src/routes/[[locale=locale]]/+layout.svelte
    Copy code

    Copy the code to the clipboard

    <script lang="ts">    import type { Snippet } from 'svelte';    import { useIntlayer, setupIntlayer } from "svelte-intlayer";    import Header from './Header.svelte';    import type { LayoutData } from './$types';    let { children, data }: { children: Snippet, data: LayoutData } = $props();    // Initialise Intlayer with the locale from the route  $effect(() => {      setupIntlayer(data.locale);  });    // Use the layout content dictionary    const layoutContent = useIntlayer('layout');</script><Header /><main>    {@render children()}</main><footer>    <p>        {$layoutContent.footer.prefix.value}{' '}        <a href="https://svelte.dev/docs/kit">{$layoutContent.footer.linkLabel.value}</a>{' '}        {$layoutContent.footer.suffix.value}    </p></footer><style>  /*  */</style>
    src/routes/[[locale=locale]]/+page.ts
    Copy code

    Copy the code to the clipboard

    export const prerender = true;
    src/routes/[[locale=locale]]/+page.svelte
    Copy code

    Copy the code to the clipboard

    <script lang="ts">    import { useIntlayer } from "svelte-intlayer";    // Use the home content dictionary    const homeContent = useIntlayer('home');</script><svelte:head>    <title>{$homeContent.title.value}</title></svelte:head><section>    <h1>        {$homeContent.title}    </h1></section><style>  /*  */</style>

    (Optional) Step 8: Internationalised Links

    For SEO, it is recommended to prefix your routes with the locale (e.g., /en/about, /fr/about). This component automatically prefixes any link with the current locale.

    src/lib/components/LocalizedLink.svelte
    Copy code

    Copy the code to the clipboard

    <script lang="ts">  import { getLocalizedUrl } from "intlayer";  import { useLocale } from "svelte-intlayer";  let { href = "" } = $props();  const { locale } = useLocale();  // Helper to prefix URL with current locale  $: localizedHref = getLocalizedUrl(href, $locale);</script><a href={localizedHref}>  <slot /></a>

    If you use goto from SvelteKit, you can use the same logic with getLocalizedUrl to navigate to the localised URL:

    typescript
    Copy code

    Copy the code to the clipboard

    import { goto } from "$app/navigation";import { getLocalizedUrl } from "intlayer";import { useLocale } from "svelte-intlayer";const { locale } = useLocale();const localizedPath = getLocalizedUrl("/about", $locale);goto(localizedPath); // Navigates to /en/about or /fr/about depending on locale

    (Optional) Step 9: Language Switcher

    To allow users to switch languages, update the URL.

    src/lib/components/LanguageSwitcher.svelte
    Copy code

    Copy the code to the clipboard

    <script lang="ts">  import { getLocalizedUrl, getLocaleName } from 'intlayer';  import { useLocale } from "svelte-intlayer";  import { page } from '$app/stores';  import { goto } from '$app/navigation';  const { locale, setLocale, availableLocales } = useLocale({    onLocaleChange: (newLocale) => {      const localizedPath = getLocalizedUrl($page.url.pathname, newLocale);      goto(localizedPath);    },  });</script><ul class="locale-list">  {#each availableLocales as localeEl}    <li>      <a        href={getLocalizedUrl($page.url.pathname, localeEl)}        onclick={(e) => {          e.preventDefault();          setLocale(localeEl); // Will set the locale in the store and trigger onLocaleChange        }}        class:active={$locale === localeEl}      >        {getLocaleName(localeEl)}      </a>    </li>  {/each}</ul><style>  /* */</style>

    (Optional) Step 10: Add backend proxy

    To add a backend proxy to your SvelteKit application, you can use the intlayerProxy function provided by the vite-intlayer plugin. This plugin will automatically detect the best locale for the user based on the URL, cookies, and browser language preferences.

    vite.config.ts
    Copy code

    Copy the code to the clipboard

    import { defineConfig } from "vite";import { intlayer, intlayerProxy } from "vite-intlayer";import { sveltekit } from "@sveltejs/kit/vite";// https://vitejs.dev/config/export default defineConfig({  plugins: [    intlayerProxy(), // should be placed first    intlayer(),    sveltekit(),  ],],});

    (Optional) Step 11: Set up the intlayer editor / CMS

    To set up the intlayer editor, you must follow the intlayer editor documentation.

    To set up the intlayer CMS, you must follow the intlayer CMS documentation.

    To be able to visualise the intlayer editor selector, you will have to use the component syntax in your intlayer content.

    Component.svelte
    Copy code

    Copy the code to the clipboard

    <script lang="ts">  import { useIntlayer } from "svelte-intlayer";  const content = useIntlayer("component");</script><div>  <!-- Render content as simple content  -->  <h1>{$content.title}</h1>  <!-- Render content as a component (required by the editor) -->  {@const Component = $content.component}<Component /></div>

    Git Configuration

    It is recommended to ignore the files generated by Intlayer.

    .gitignore
    Copy code

    Copy the code to the clipboard

    # Ignore the files generated by Intlayer.intlayer

    Go Further

    • Visual Editor: Integrate the Intlayer Visual Editor to edit translations directly from the UI.
    • CMS: Externalise your content management using the Intlayer CMS.
    plaintext
    Copy code

    Copy the code to the clipboard

    Vite and Svelte
    Vite and Preact

    Alt+→

    On this page

      Discussions are anonymous and regularly reviewed to address common issues. Feel free to share feature ideas, feedback on the documentation, or anything related to Intlayer, we use this input to shape our roadmap and improve the product.

      .├── intlayer.config.ts├── package.json├── src│   ├── app.d.ts│   ├── app.html│   ├── hooks.server.ts│   ├── lib│   │   ├── getLocale.ts│   │   ├── LocaleSwitcher.svelte│   │   └── LocalizedLink.svelte│   ├── params│   │   └── locale.ts│   └── routes│       ├── [[locale=locale]]│       │   ├── +layout.svelte│       │   ├── +layout.ts│       │   ├── +page.svelte│       │   ├── +page.ts│       │   ├── about│       │   │   ├── +page.svelte│       │   │   ├── +page.ts│       │   │   └── page.content.ts│       │   ├── Counter.content.ts│       │   ├── Counter.svelte│       │   ├── Header.content.ts│       │   ├── Header.svelte│       │   ├── home.content.ts│       │   └── layout.content.ts│       ├── +layout.svelte│       └── layout.css├── static│   ├── favicon.svg│   └── robots.txt├── svelte.config.js├── tsconfig.json└── vite.config.ts
      npm install intlayer svelte-intlayernpm install vite-intlayer --save-devnpx intlayer init
      import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],    defaultLocale: Locales.ENGLISH,  },};export default config;
      import { sveltekit } from "@sveltejs/kit/vite";import { defineConfig } from "vite";import { intlayer } from "vite-intlayer";export default defineConfig({  plugins: [intlayer(), sveltekit()], // order matters, Intlayer should be placed before SvelteKit});
      .├── intlayer.config.ts├── package.json├── src│   ├── app.d.ts│   ├── app.html│   ├── hooks.server.ts│   ├── lib│   │   ├── getLocale.ts│   │   ├── LocaleSwitcher.svelte│   │   └── LocalizedLink.svelte│   ├── params│   │   └── locale.ts│   └── routes│       ├── [[locale=locale]]│       │   ├── +layout.svelte│       │   ├── +layout.ts│       │   ├── +page.svelte│       │   ├── +page.ts│       │   ├── about│       │   │   ├── +page.svelte│       │   │   ├── +page.ts│       │   │   └── page.content.ts│       │   ├── Counter.content.ts│       │   ├── Counter.svelte│       │   ├── Header.content.ts│       │   ├── Header.svelte│       │   ├── home.content.ts│       │   └── layout.content.ts│       ├── +layout.svelte│       └── layout.css├── static│   ├── favicon.svg│   └── robots.txt├── svelte.config.js├── tsconfig.json└── vite.config.ts
      npm install intlayer svelte-intlayernpm install vite-intlayer --save-devnpx intlayer init
      import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],    defaultLocale: Locales.ENGLISH,  },};export default config;
      import { sveltekit } from "@sveltejs/kit/vite";import { defineConfig } from "vite";import { intlayer } from "vite-intlayer";export default defineConfig({  plugins: [intlayer(), sveltekit()], // order matters, Intlayer should be placed before SvelteKit});
      <script lang="ts">  import { useIntlayer } from "svelte-intlayer";  // "hero-section" corresponds to the key defined in Step 4  const content = useIntlayer("hero-section");</script><!-- Render content as simple content  --><h1>{$content.title}</h1><!-- To render the content editable using the editor --><h1>{@const Title = $content.title}<Title /></h1><!-- To render the content as a string --><div aria-label={$content.title.value}></div><div aria-label={$content.title.toString()}></div><div aria-label={String($content.title)}></div>
      .└─── src    ├── app.d.ts                  # Define the locale type    ├── hooks.server.ts           # Manage locale routing    ├── lib    │   └── getLocale.ts          # Check the locale from the header, cookies    ├── params    │   └── locale.ts             # Define the locale parameter    └── routes        ├── [[locale=locale]]     # Wrap in a route group to set the locale        │   ├── +layout.svelte    # Local layout for the route        │   ├── +layout.ts        │   ├── +page.svelte        │   ├── +page.ts        │   └── about        │       ├── +page.svelte        │       └── +page.ts        └── +layout.svelte         # Root layout for fonts and global styles
      import type { Handle } from "@sveltejs/kit";import { getLocalizedUrl } from "intlayer";import { getLocale } from "$lib/getLocale";export const handle: Handle = async ({ event, resolve }) => {  const detectedLocale = getLocale(event);  // Check if the current path already starts with a locale (e.g. /fr, /en)  const pathname = event.url.pathname;  const targetPathname = getLocalizedUrl(pathname, detectedLocale);  // If NO locale is present in the URL (e.g. user visits "/"), redirect them  if (targetPathname !== pathname) {    return new Response(undefined, {      headers: { Location: targetPathname },      status: 307, // Temporary redirect    });  }  return resolve(event, {    transformPageChunk: ({ html }) => html.replace("%lang%", detectedLocale),  });};
      import {  configuration,  getLocaleFromStorage,  localeDetector,  type Locale,} from "intlayer";import type { RequestEvent } from "@sveltejs/kit";/** * Retrieve the user's locale from the request event. * This function is utilised in the `handle` hook within `src/hooks.server.ts`. * * It initially attempts to obtain the locale from the Intlayer storage (cookies or custom headers). * If the locale is not found, it defaults to the browser's "Accept-Language" negotiation. * * @param event - The request event from SvelteKit * @returns The user's locale */export const getLocale = (event: RequestEvent): Locale => {  const defaultLocale = configuration?.internationalization?.defaultLocale;  // Attempt to retrieve locale from Intlayer storage (Cookies or headers)  const storedLocale = getLocaleFromStorage({    // SvelteKit cookies access    getCookie: (name: string) => event.cookies.get(name) ?? null,    // SvelteKit headers access    getHeader: (name: string) => event.request.headers.get(name) ?? null,  });  if (storedLocale) {    return storedLocale;  }  // Fallback to Browser "Accept-Language" negotiation  const negotiatorHeaders: Record<string, string> = {};  // Convert SvelteKit Headers object to a plain Record<string, string>  event.request.headers.forEach((value, key) => {    negotiatorHeaders[key] = value;  });  // Check the locale from the `Accept-Language` header  const userFallbackLocale = localeDetector(negotiatorHeaders);  if (userFallbackLocale) {    return userFallbackLocale;  }  // Return default locale if no match is found  return defaultLocale;};
      import { defaultLocale, locales, type Locale } from "intlayer";export const match = (param: Locale = defaultLocale): boolean =>  locales.includes(param);
      declare global {  namespace App {    interface Locals {      locale: import("intlayer").Locale;    }  }}
      <script lang="ts">     import './layout.css';    let { children } = $props();</script><div class="app">    {@render children()}</div><style>    .app {    /*  */    }</style>
      import type { Load } from "@sveltejs/kit";import { defaultLocale, type Locale } from "intlayer";export const prerender = true;// Use the generic Load typeexport const load: Load = ({ params }) => {  const locale: Locale = (params.locale as Locale) ?? defaultLocale;  return {    locale,  };};
      <script lang="ts">    import type { Snippet } from 'svelte';    import { useIntlayer, setupIntlayer } from "svelte-intlayer";    import Header from './Header.svelte';    import type { LayoutData } from './$types';    let { children, data }: { children: Snippet, data: LayoutData } = $props();    // Initialise Intlayer with the locale from the route  $effect(() => {      setupIntlayer(data.locale);  });    // Use the layout content dictionary    const layoutContent = useIntlayer('layout');</script><Header /><main>    {@render children()}</main><footer>    <p>        {$layoutContent.footer.prefix.value}{' '}        <a href="https://svelte.dev/docs/kit">{$layoutContent.footer.linkLabel.value}</a>{' '}        {$layoutContent.footer.suffix.value}    </p></footer><style>  /*  */</style>
      export const prerender = true;
      <script lang="ts">    import { useIntlayer } from "svelte-intlayer";    // Use the home content dictionary    const homeContent = useIntlayer('home');</script><svelte:head>    <title>{$homeContent.title.value}</title></svelte:head><section>    <h1>        {$homeContent.title}    </h1></section><style>  /*  */</style>
      <script lang="ts">  import { getLocalizedUrl } from "intlayer";  import { useLocale } from "svelte-intlayer";  let { href = "" } = $props();  const { locale } = useLocale();  // Helper to prefix URL with current locale  $: localizedHref = getLocalizedUrl(href, $locale);</script><a href={localizedHref}>  <slot /></a>
      import { goto } from "$app/navigation";import { getLocalizedUrl } from "intlayer";import { useLocale } from "svelte-intlayer";const { locale } = useLocale();const localizedPath = getLocalizedUrl("/about", $locale);goto(localizedPath); // Navigates to /en/about or /fr/about depending on locale
      <script lang="ts">  import { getLocalizedUrl, getLocaleName } from 'intlayer';  import { useLocale } from "svelte-intlayer";  import { page } from '$app/stores';  import { goto } from '$app/navigation';  const { locale, setLocale, availableLocales } = useLocale({    onLocaleChange: (newLocale) => {      const localizedPath = getLocalizedUrl($page.url.pathname, newLocale);      goto(localizedPath);    },  });</script><ul class="locale-list">  {#each availableLocales as localeEl}    <li>      <a        href={getLocalizedUrl($page.url.pathname, localeEl)}        onclick={(e) => {          e.preventDefault();          setLocale(localeEl); // Will set the locale in the store and trigger onLocaleChange        }}        class:active={$locale === localeEl}      >        {getLocaleName(localeEl)}      </a>    </li>  {/each}</ul><style>  /* */</style>
      import { defineConfig } from "vite";import { intlayer, intlayerProxy } from "vite-intlayer";import { sveltekit } from "@sveltejs/kit/vite";// https://vitejs.dev/config/export default defineConfig({  plugins: [    intlayerProxy(), // should be placed first    intlayer(),    sveltekit(),  ],],});
      <script lang="ts">  import { useIntlayer } from "svelte-intlayer";  const content = useIntlayer("component");</script><div>  <!-- Render content as simple content  -->  <h1>{$content.title}</h1>  <!-- Render content as a component (required by the editor) -->  {@const Component = $content.component}<Component /></div>
      # Ignore the files generated by Intlayer.intlayer