Creating a Multi-Language Website with SvelteKit

Sunday, May 26, 2024
12 min read

If you want to share your content in multiple languages on your website, it’s far easier to do this with SvelteKit. sveltekit-i18n package will handle all the setup for your multi-language website easily.

sveltekit-multi-language

What is i18n?

i18n (internationalization) is a concept that has been used since the early days of HTML and has evolved with various improvements till nowadays. This concept allows web pages to be displayed in different languages. As a result, web pages become more understandable, reachable and usable for users in different languages.

SvelteKit with i18n

First of all, let’s add the sveltekit-i18n package to our project. This package will convert our project into a multi-language website by creating its own configuration files.

npm i sveltekit-i18n

Translations Folder

translations folder will keep the translations of the languages that our project supports.

Let’s create a lang.json for the languages we will include and keep the names and codes of them.

{
  "en": "English",
  "tr": "Türkçe"
}

In the translations folder, let’s create an index.js file that will save the configurations for the sveltekit-i18n package.

import i18n from 'sveltekit-i18n';
import { dev } from '$app/environment';
import lang from './lang.json';

export const defaultLocale = 'en';

/** @type {import('sveltekit-i18n').Config} */
export const config = {
  log: {
    level: dev ? 'warn' : 'error',
  },
  translations: {
    en: { lang },
    tr: { lang },
  },
  loaders: [
    {
      locale: 'en',
      key: 'menu',
      loader: async () => (await import('./en/menu.json')).default,
    },
    {
      locale: 'en',
      key: 'about',
      routes: ['/about'],
      loader: async () => (await import('./en/about.json')).default,
    },
    {
      locale: 'en',
      key: 'home',
      routes: ['/'],
      loader: async () => (await import('./en/home.json')).default,
    },
    {
      locale: 'tr',
      key: 'menu',
      loader: async () => (await import('./tr/menu.json')).default,
    },
    {
      locale: 'tr',
      key: 'about',
      routes: ['/about'],
      loader: async () => (await import('./tr/about.json')).default,
    },
    {
      locale: 'tr',
      key: 'home',
      routes: ['/'],
      loader: async () => (await import('./tr/home.json')).default,
    },
  ],
};

export const { t, loading, locales, locale, translations, loadTranslations, addTranslations, setLocale, setRoute } = new i18n(config);

loading.subscribe(($loading) => $loading && console.log('Loading translations...'));

Here, we point out which languages will be supported, where the translations will be kept, and on which pages the translations will be used.

## Translation Files

Create en and tr folders and add our translation files to them.

about.json (about page)
{
  "title": "Bu uygulama hakkında",
  "text": "<p>Bu bir <a href="https://kit.svelte.dev">SvelteKit</a> uygulamasıdır. Aşağıdaki komutu komut satırına girerek kendi uygulamanızı oluşturabilirsiniz:</p><pre>npm init svelte@next</pre> <p> Bu sayfa tamamen statik HTML'dir ve istemci etkileşimi gerektirmez. Bu nedenle herhangi bir JavaScript yüklemeye gerek yoktur. Sayfanın kaynak kodunu görüntülemeyi veya geliştirici araçlarını açıp sayfayı yeniden yüklemeyi deneyin.</p>"
}
home.json (homepage)
{
  "title": "SvelteKit'e Hoş Geldiniz",
  "text": "Dokümantasyona <a href="{{link}}">kit.svelte.dev</a> adresinden ulaşabilirsiniz."
}
menu.json (menu)
{
  "home": "Ana Sayfa",
  "about": "Hakkımızda"
}
about.json (about page)
{
  "title": "About this app",
  "text": "<p>This is a <a href="https://kit.svelte.dev">SvelteKit</a> app. You can make your own by typing the following into your command line and following the prompts:</p><pre>npm init svelte@next</pre> <p> The page you're looking at is purely static HTML, with no client-side interactivity needed. Because of that, we don't need to load any JavaScript. Try viewing the page's source, or opening the devtools network panel and reloading. </p>"
}
home.json (home page)
{
  "title": "Welcome to SvelteKit",
  "text": "Visit <a href="{{link}}">kit.svelte.dev</a> to read the documentation"
}
menu.json (menu)
{
  "home": "Home",
  "about": "About"
}

We’ll use cookies to store the user’s language preference. We can also do this without storing it in the browser cookie, for instance, by getting the language information from the URL. But in this post, we’ll store the user’s preference via cookies.

SvelteKit’s server-side features will be beneficial for this. Let’s create a +layout.server.js file under the src/routes folder.

import { locales, loadTranslations, translations, defaultLocale } from '$lib/translations';

/** @type {import('@sveltejs/kit').ServerLoad} */
export const load = async ({ url, cookies, request }) => {
  const { pathname } = url;

  // Try to get the locale from cookie
  let locale = (cookies.get('lang') || '').toLowerCase();

  // Get user preferred locale
  if (!locale) {
    locale = `${`${request.headers.get('accept-language')}`.match(/[a-zA-Z]+?(?=-|_|,|;)/)}`.toLowerCase();
  }

  // Get defined locales
  const supportedLocales = locales.get().map((l) => l.toLowerCase());

  // Use default locale if current locale is not supported
  if (!supportedLocales.includes(locale)) {
    locale = defaultLocale;
  }

  await loadTranslations(locale, pathname); // keep this just before the `return`

  return {
    i18n: { locale, route: pathname },
    translations: translations.get(), // `translations` on server contain all translations loaded by different clients
  };
};

Basically, we are checking the language preference stored in user’s browser. If there is no language preference in the user’s browser, we are using our default language.

In SvelteKit’s client-side, we’ll use the translations loaded on the server-side. Now, create a +layout.js file under the src/routes folder. After that, paste the following code into this file.

import { addTranslations, setLocale, setRoute } from '$lib/translations';

/** @type {import('@sveltejs/kit').Load} */
export const load = async ({ data }) => {
  const { i18n, translations } = data;
  const { locale, route } = i18n;

  addTranslations(translations);

  await setRoute(route);
  await setLocale(locale);

  return i18n;
};

Using Translations

We are ready to go! We can now use the translations in our SvelteKit application.

In our home route, create a +page.svelte file and add the followings.

<script>
    import { t } from '$lib/translations';

    const link = 'https://kit.svelte.dev';
</script>

<h1>{$t('home.title')}</h1>
<p>{@html $t('home.text', { link })}</p>

t function is using for getting translations. To use it correctly, we access the translation value by using the key, for example, home.title.

Adding a New Language

To add a new language, create a new folder in the translations folder and add the translation files to the relevant folder, for example, de for German, fr for French. Next, include the file paths in the loader in the translations/index.js file.

Sample Application

Sample Application in Turkish sveltekit--multi-language-1
Sample Application in English sveltekit--multi-language-2

Handling internalization is very easy with SvelteKit! You can easily add new languages to your web application.

If you want your website to reach a global audience, SvelteKit and the sveltekit-i18n package can be a powerful duo. This way, you can share content in multiple languages and reach more users worldwide.

Is your website still in a single language? We can help you with this.

Book Free Consultation