Use With SvelteKit

In SvelteKit we eliminate race conditions by not sharing state using a store server-side. So we must create a getTranslator function per request based on locale.

Get desired locales from cookies and request headers on server

There are three common methods employed to detect a user's desired locale. On the server you can use a root +layout.server.ts to first check the language settings for the user's browser found in the accept-language header and also check for a locale cookie (you set this when users switch the language in your app).

routes/+layout.server.ts
ts
import type { LayoutServerLoad } from './$types'
export const load: LayoutServerLoad = ({ cookies, request }) => {
const acceptedLanguage = request.headers.get('accept-language')?.split(',')[0].trim()
const chosenLocale = cookies.get('locale')
return { acceptedLanguage, chosenLocale }
}

Get desired locale from url on server/client

Pass that information to the +layout.ts which runs both on server and client. Here you check the URL if your app stores the locale in the URL. Then you can use the locale information gathered to selected the appropriate locale that you support and create an instance of the translator functions using the methods you previously created.

routes/+layout.ts
ts
import type { LayoutLoad } from './$types'
import { getSupportedLocale } from '$lib/poly-i18n/locales'
import { getTranslator } from '$lib/poly-i18n'
export const load: LayoutLoad = async ({ data: { acceptedLanguage, chosenLocale }, url: { searchParams } }) => {
const urlLocale = searchParams.get('lang')
const locale = getSupportedLocale(urlLocale || chosenLocale || acceptedLanguage)
const t = await getTranslator({ locale })
return { locale, t }
}

This order of preference is important. The URL is the most important, then a cookie which indicates a previous user decision, and finally the browser's language settings.

Type your $page store

src/app.d.ts
ts
declare global {
namespace App {
interface PageData {
locale: import('$lib/poly-i18n/locales').LocaleCode;
t: Awaited<ReturnType<typeof import('$lib/poly-i18n').getTranslator>>;
}
}
}

Use from page data store

Now you can use $page.data.t and $page.data.locale in Svelte files:

svelte
<script>
import { page } from '$app/stores'
</script>
{$page.data.locale}, {$page.data.t('hello.world')}

In +page.svelte and +layout.svelte files you also could use data.t and data.locale:

+page.svelte
svelte
<script>
export let data
</script>
{data.locale}, {data.t('hello.world')}

And in TS/JS files:

ts
import { get } from 'svelte/store'
import { page } from '$app/stores'
export function sayHi() {
const { data: { t } } = get(page)
alert(t('hello.world'))
}

If you base locale off the url that's all you need for basic i18n in SvelteKit. If you only rely on cookies when a user [changes the locale] then you need to reload the page on locale change.

If you don't want to use $page.data.t, but want something simple like $t you can check out this idea from robertadamsonsmith that uses a store passed down by context.

Our last item to set up is to allow users to [Change locale].

Edit page in GitHub