Skip to content

svelte-intl/core

Repository files navigation

svelte-i18n logo

Why another i18n library?

  • Svelte 5
  • Runes and not stores
  • Easy to use
  • SSR ready
  • No external dependencies

What this is not

svelte-i18n is not intended to replace feature-rich libraries like Wuchale, inlang or Paraglide.js. Those solutions offer advanced capabilities for complex translation needs, such as deeply nested keys or managing large volumes of strings. Instead, svelte-i18n is designed for projects that require straightforward, key-value translations without extensive configuration or overhead.

Getting Started

1. Install the package

npm install @svelte-i18n/core
# or
pnpm add @svelte-i18n/core

2. src/routes/+layout.server.ts

Read the locale cookie on the server so the user's language preference survives a page refresh.

export const load = async ({ cookies }) => {
	const locale = cookies.get('lang');

	return {
		locale: locale ?? 'en'
	};
};

3. src/routes/+layout.ts

Edit the +layout.ts file or create it if it doesn't exist.

import { createI18n } from '@svelte-i18n/core';

export const load = async ({ data }) => {
	const i18n = await createI18n({
		locales: ['en', 'nl'],
		locale: data.locale,
		fallbackLocale: 'en',
		dictionaries: {
			// You can also import them at the top level
			// instead of a dynamic import
			en: async () => {
				return (await import('$lib/locales/en.json')).default;
			},
			nl: async () => {
				return (await import('$lib/locales/nl.json')).default;
			}
		}
	});

	return {
		i18n
	};
};

setLocale stores the active locale in a cookie named lang by default. Override the name with cookieName:

const i18n = await createI18n({
	// ...
	cookieName: 'locale'
});

4. src/app.html and src/hooks.server.ts

Set the HTML lang attribute for SSR:

<!-- src/app.html -->
<html lang="%lang%">
// src/hooks.server.ts
import type { Handle } from '@sveltejs/kit';

export const handle: Handle = async ({ event, resolve }) => {
	const locale = event.cookies.get('lang');

	return resolve(event, {
		transformPageChunk: ({ html }) => html.replace('%lang%', locale ?? 'en')
	});
};

On the client, setLocale also updates document.documentElement.lang when the user switches language.

5. src/routes/+layout.svelte

Export I18nContext so the i18n context type can be shared across the app.

<script lang="ts" module>
	export type I18nContext = LayoutProps['data']['i18n'];
</script>

<script lang="ts">
	import type { LayoutProps } from './$types.d.ts';

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

{@render children?.()}

6. src/lib/i18n.ts

Create a new file called i18n.ts inside src/lib. This sets up and exports the context so it can be reused across the app with full type safety.

import type { I18nContext } from '../routes/+layout.svelte';
import { createContext } from 'svelte';

const [getContext, setContext] = createContext<I18nContext>();

export const useI18n = getContext;
export const createI18n = (i18n: () => I18nContext) => setContext(i18n());

7. Register the context in +layout.svelte

<script lang="ts" module>
	export type I18nContext = LayoutProps['data']['i18n'];
</script>

<script lang="ts">
	import type { LayoutProps } from './$types.d.ts';
	import { createI18n } from '$lib/i18n';

	let { children, data }: LayoutProps = $props();
	createI18n(() => data.i18n);
</script>

{@render children?.()}

8. Use it in any component

<script lang="ts">
	import { useI18n } from '$lib/i18n';

	let user = $state('John Doe');
	let { t, getLocale } = useI18n();
</script>

{t('Current language: {locale}', { locale: getLocale() })}
{t('Welcome, {user}', { user })}

Full documentation: https://svelte-i18n.com

About

The simplest i18n library for Svelte / SvelteKit out there

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors