Quick Start

SvelteKit

This page demonstrates the minimal setup of Intor in a SvelteKit project.


Installation

This example is based on the SvelteKit minimal template.
For details, see: SvelteKit

Install Intor:

npm install intor
yarn add intor
pnpm add intor
bun add intor

After installation, update vite.config.ts to ensure Intor is bundled correctly in SSR.

export default defineConfig({
  plugins: [sveltekit()],
  ssr: { noExternal: ["intor"] }, // Ensure Intor is bundled for SSR
});

Project Structure

index.json
U

index.json
U

+layout.server.ts
U
+layout.svelte
M
+page.svelte
M

intor-config.ts
U
app.d.ts
M
app.html
M
hooks.server.ts
U

Integration Steps

♯1 Messages

Create a messages directory in your project, and add a subdirectory for each locale.
Each locale provides an index.json file.

index.json
U

index.json
U
{
  "hello": "Hello, {name}",
  "rich": "A <tag>text</tag>."
}
{
  "hello": "Bonjour, {name}",
  "rich": "Un <tag>texte</tag>."
}

♯2 Config

Create an i18n/ directory under src/lib/, and add an intor-config.ts file inside it.
This example uses the most basic translation loading approach by defining messages directly in the config.

For more details, see: Message Loading

intor-config.ts
U
import { defineIntorConfig } from "intor";
import EN from "../../../messages/en/index.json";
import FR from "../../../messages/fr/index.json";

export const intorConfig = defineIntorConfig({
  defaultLocale: "en",
  supportedLocales: ["en", "fr"],
  messages: {
    en: EN,
    fr: FR,
  },
});

♯3 Initialization

  1. Create hooks.server.ts under src/ to integrate Intor into the request flow.
hooks.server.ts
U
import { createIntorHandler } from "intor/svelte-kit";
import { intorConfig } from "$lib/i18n/intor-config";

export const handle = createIntorHandler(intorConfig);

  1. Update app.d.ts to extend the required type definitions.
app.d.ts
M
import type { InboundContext } from "intor";

declare global {
  namespace App {
    interface Locals {
      intor: InboundContext;
    }
  }
}

export {};

  1. Update app.html to add a placeholder for the document language attribute.
app.html
M
// ...
<html lang="%lang%">
// ...

  1. Create +layout.server.ts under src/routes/ and call intor() to initialize the translation system during SSR.
+layout.server.ts
U
import { intor } from "intor/server";
import { intorConfig } from "$lib/i18n/intor-config";

export const load = async ({ locals, fetch }) => {
  const intorValue = await intor(intorConfig, locals.intor.locale, { fetch });
  return { intorValue };
};

  1. Update +layout.svelte and wrap the application with IntorProvider.
+layout.svelte
M
<script lang="ts">
  import favicon from "$lib/assets/favicon.svg";
  import { IntorProvider } from "intor/svelte";

  let { children, data } = $props();
</script>

<svelte:head>
  <link rel="icon" href={favicon} />
</svelte:head>

<IntorProvider value={data.intorValue}>
  {@render children()}
</IntorProvider>

Usage Example

Use useTranslator to access translation capabilities:

  • t: returns the resolved text
  • tRich: renders structured messages with semantic tags

Use useNavigation to access navigation capabilities:

  • goto: handles navigation and locale switching
+page.svelte
M
<script lang="ts">
  import { useTranslator } from "intor/svelte";
  import { useNavigation } from "intor/svelte-kit";

  const { t, tRich } = useTranslator();
  const { goto } = useNavigation();
</script>

<p>{$t("hello", { name: "Intor" })}</p>

<p>{@html $tRich("rich", { tag: (children) => `<b>${children}</b>` })}</p>

<button onclick={() => goto("/", { locale: "en" })}>English</button>
<button onclick={() => goto("/", { locale: "fr" })}>French</button>

Server-side

On the server side, the same translation capabilities can be accessed via getTranslator().
This can be used for metadata generation, API routes, or other server-only execution environments.

+layout.server.ts
M
import { getTranslator } from "intor/server";

// ...

const { t } = await getTranslator(intorConfig, {
  locale: locals.intor.locale,
});