Zum Inhalt springen

Messages laden

Drei Wege, Messages hineinzubekommen, und zwei Muster, um eine Seite darauf warten zu lassen. Sie lassen sich kombinieren: Bündle, was jede Seite braucht, und hol den Rest nach.

1. Zur Build-Zeit #

createDialect({
	messages: {
		// eager: inlined at build time
		...import.meta.glob('./messages/**/*.json', { eager: true }),
		// not eager: fetched the first time a page asks for it
		...import.meta.glob('./messages-lazy/**/*.json')
	},
	defaultLocale: 'en'
});

Der Standard. import.meta.glob liest die Dateien beim Kompilieren und bettet sie ein — kein Request zur Laufzeit, nichts zu konfigurieren.

Lass eager: true im selben Glob weg, und jeder Namespace wird zu einem eigenen Chunk, der beim ersten Zugriff einer Seite geladen wird. Beide Varianten können im selben messages-Objekt stehen.

2. Bei Bedarf #

Zwei Muster, um vor dem Rendern auf einen Namespace zu warten. Unten verwendet je eine Seite eines davon — lade neu, um beide laufen zu sehen.

In einer Load-Funktion #

Eine universelle Load-Funktion darf alles zurückgeben, auch die Funktion t selbst. Funktioniert mit stabilem SvelteKit, ohne Compiler-Flags.

In einer Load-Funktion geladen

Dieser Namespace wurde in einer universellen Load-Funktion geholt, die die Funktion t selbst zurückgegeben hat. Es sind keine experimentellen Compiler-Optionen im Spiel — das ist das Muster für stabiles SvelteKit.

In der Komponente #

Direkt im <script> mit await.

Bei Bedarf geladen

Dieser Namespace ist nicht im Bundle der Seite enthalten. Er kommt über den Loader, den du konfigurierst — hier ein dynamischer Import, in deiner App genauso gut ein fetch an eine API.

In 3 Sprachen verfügbar

Hinweis

Dafür brauchst du Svelte 5.36+ und compilerOptions.experimental.async.

+page.ts
export const load: PageLoad = async () => await loadTranslations('billing');
+page.svelte
const { data }: PageProps = $props();
<h1>{data.t('billing:title')}</h1>
// in the component's script, with experimental.async on
import { loadTranslations } from '#lib/i18n.js';

const { t } = await loadTranslations('dashboard');

// then in the markup
{t('dashboard:title')}

3. Aus deiner eigenen API #

SvelteKit Remote Functions #

Eine query(), die wie eine lokale Funktion aufgerufen und in deinem Loader ausgeführt wird — kein Endpunkt zu schreiben, kein fetch, bei dem etwas schiefgehen kann. Erfordert kit.experimental.remoteFunctions und compilerOptions.experimental.async.

messages.remote.ts
import * as v from 'valibot';
import { query } from '$app/server';

export const getMessages = query(
	v.object({ locale: v.picklist(['en', 'ru']), namespace: v.picklist(['dashboard']) }),
	async ({ locale, namespace }) => db.loadMessages(locale, namespace)
);
lib/i18n.ts
createDialect({
	defaultLocale: 'en',
	locales: ['en', 'ru'],
	loader: async ({ locale, namespace }) => getMessages({ locale, namespace })
});

Einfaches fetch #

Die portable Variante: keine experimentellen Flags, funktioniert beim SSR, sofern die URL absolut ist — auf dem Server gibt es keine Seite, auf die sich eine relative URL beziehen könnte.

createDialect({
	defaultLocale: 'en',
	locales: ['en', 'ru'],
	loader: async ({ locale, namespace }) => {
		const res = await fetch(`https://example.com/i18n/${locale}/${namespace}.json`);
		return res.json();
	}
});

Ein Aufruf, egal wie viele Requests #

Gleichzeitige Aufrufer für dieselbe Locale und denselben Namespace teilen sich einen laufenden Loader-Aufruf, sodass hundert gleichzeitige SSR-Requests einen fetch auslösen, nicht hundert.