Загрузка сообщений
Три способа получить сообщения и два паттерна попросить страницу их дождаться. Они сочетаются: то, что нужно каждой странице, — в бандл, остальное — по запросу.
1. На сборке #
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'
});Способ по умолчанию. import.meta.glob читает файлы во время компиляции и подставляет их внутрь — никаких запросов в рантайме, нечего настраивать.
Уберите eager: true из того же глоба — и каждый неймспейс станет своим чанком, который подгружается при первом обращении страницы. Обе формы могут жить в одном объекте messages.
2. По требованию #
Два паттерна дождаться неймспейса перед рендером. Ниже одна страница использует оба — перезагрузите её, чтобы увидеть работу обоих.
В load-функции #
Universal load может вернуть что угодно, включая саму функцию t. Работает на стабильном SvelteKit, без флагов компилятора.
Загружено в load-функции
Этот неймспейс подгружен в universal load-функции, которая вернула саму функцию t. Никаких экспериментальных опций компилятора — это способ для стабильного SvelteKit.
В компоненте #
Ожидание прямо в <script>.
Загружено по требованию
Этого неймспейса нет в бандле страницы. Он приезжает через ваш загрузчик — здесь это динамический импорт, а в вашем приложении с тем же успехом может быть запрос к API.
Доступно на 3 языках
Примечание
Нужны Svelte 5.36+ и compilerOptions.experimental.async.
export const load: PageLoad = async () => await loadTranslations('billing');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. Из своего API #
Remote functions SvelteKit #
query(), вызываемая как локальная функция, внутри вашего загрузчика — не нужно писать эндпоинт и не нужен fetch. Требует kit.experimental.remoteFunctions и compilerOptions.experimental.async.
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)
);createDialect({
defaultLocale: 'en',
locales: ['en', 'ru'],
loader: async ({ locale, namespace }) => getMessages({ locale, namespace })
});Обычный fetch #
Самый переносимый вариант: без экспериментальных флагов, работает при SSR, если URL абсолютный — на сервере нет страницы, относительно которой его строить.
createDialect({
defaultLocale: 'en',
locales: ['en', 'ru'],
loader: async ({ locale, namespace }) => {
const res = await fetch(`https://example.com/i18n/${locale}/${namespace}.json`);
return res.json();
}
});Один вызов, сколько бы ни было запросов #
Параллельные вызовы для одной локали и неймспейса делят один вызов загрузчика в полёте, так что сотня одновременных SSR-запросов запускает один fetch, а не сотню.