DEV Community

Cover image for Internationalization with Svelte and SvelteKit - Part 2
Enmanuel Jarquín
Enmanuel Jarquín

Posted on • Originally published at enmanueljarquin.com

Internationalization with Svelte and SvelteKit - Part 2

This is the second part of our previous article, you could find it here if you haven't seen it, yet.

Well, we have the locale variable with a hardcoded value, now we'll add a new file at the same level of the +layout.ts called +.layout.server.ts , here we will write the following content:

// +layout.server.ts
import type { LayoutServerLoad } from './$types';

export const load: LayoutServerLoad = () => {
    return { locale: 'en' };
};

Enter fullscreen mode Exit fullscreen mode

Then, we will change the content of the file +layout.ts to read the value that we are returning from +layout.server.ts

// +layout.ts
import type { LayoutLoad } from './$types';
import { loadLocaleAsync } from '../i18n/i18n-util.async';
import { setLocale } from '../i18n/i18n-svelte';

export const load: LayoutLoad = async (event) => {
- const locale = 'es';    
+ const locale = event.data.locale;
    await loadLocaleAsync(locale);
    setLocale(locale);

    return event.data;
};

Enter fullscreen mode Exit fullscreen mode

Our app should work as always, but we are still using a hardcoded value, but the difference is that it comes from our second file.

What we want now is to read a locale from the URL or from the browser directly, then pass it to the file +layout.server.ts and this in turn will pass it to the +.layout.ts .

To accomplish the mentioned above, we need to add another file called hooks.server.ts but in this case in the src directory: src/hooks.server.ts

We are going to do something quite similar to what we did when we created the file +layout.server.ts, we are going to hardcode the lang but now in the file hooks.server.ts and within a function called handle that we should return.

// src/hooks.server.ts
import type { Handle } from '@sveltejs/kit';

export const handle: Handle = async ({ event, resolve }) => {
    event.locals.locale = 'es';
    return resolve(event);
};

Enter fullscreen mode Exit fullscreen mode

And in the file +layout.server.ts we need to read the object locals and its property locale:

// src/routes/+layout.server.ts
export const load: LayoutServerLoad = ({ locals }) => {
    return { locale: locals.locale };
};

Enter fullscreen mode Exit fullscreen mode

If we change from es to en and vice-versa, everything should work as always.

Now to remove the hardcoded lang, we will make use of the params in the URL, one more time, go ahead to our file hooks.server.ts

// src/hooks.server.ts
import type { Handle } from '@sveltejs/kit';

export const handle: Handle = async ({ event, resolve }) => {
- event.locals.locale = 'es';
+ const lang = event.url.searchParams.get('lang');
+ event.locals.locale = lang || 'en';
    return resolve(event);
};

Enter fullscreen mode Exit fullscreen mode

To test it, we should modify the URL in the browser: http://localhost:5173/?lang=es, if any lang is passed, then it will show the default language, in this case english .

Perfect, now we can pass what language we want to use by specifying it in the URL

Reading the browser language

Now, we want to do is remove the default hardcoded language set as english and replace it with the default language from the browser, we should use the function initAcceptLanguageHeaderDetector in the file hooks.server.ts, so, let's do it:

// src/hooks.server.ts
const getPreferredLocale = ({ request }: RequestEvent) => {
  const acceptLanguageDetector = initAcceptLanguageHeaderDetector(request);
  return detectLocale(acceptLanguageDetector);
};

Enter fullscreen mode Exit fullscreen mode

We must add some imports as well:

// src/hooks.server.ts
// import type { Handle } from '@sveltejs/kit';
+ import type { Handle, RequestEvent } from '@sveltejs/kit';
+ import { detectLocale, i18n, isLocale } from './i18n/i18n-util';
+ import { initAcceptLanguageHeaderDetector } from 'typesafe-i18n/detectors';

Enter fullscreen mode Exit fullscreen mode

Then, we need to update the function handle:

// src/hooks.server.ts
export const handle: Handle = async ({ event, resolve }) => {
    const lang = event.url.searchParams.get('lang');

// event.locals.locale = lang || 'en';
+ event.locals.locale = lang || getPreferredLocale(event);

    return resolve(event);
}

Enter fullscreen mode Exit fullscreen mode

Now in my case, I have Spanish as my default language in Chrome:Settings/Languages

Default Chrome Language

If I don't pass any language in the URL, it will read this default language from the browser directly.

Cool!, We are almost done, but there is still an improvement that we could do, for example, if I pass the lang param via the URL but it doesn't exist in my configuration, it won't read the default browser language because the param lang in the URL was set, but it is an invalid lang, if we leave it as it is so right now we will get a pretty 500 error:

http://localhost:5173/?lang=ed

Well to fix that we could add validation for the lang that was provided to us:

// src/hooks.server.ts
import type { Locales } from './i18n/i18n-types';

export const handle: Handle = async ({ event, resolve }) => {
    ...    
    const locale = isLocale(lang as Locales) ? (lang as Locales) : getPreferredLocale(event);
    event.locales.locale = locale;
    ....
}
Enter fullscreen mode Exit fullscreen mode

And that's how we fixed it, we use isLocale to validate the lang, if it is a valid lang, then we use it as a value of locale if not, then we read it from the default browser lang.

In our next post, we are going to add a button or link to switch the language, that will be our third option to use this feature. See you there and happy coding!

Top comments (0)