Internationalization with Svelte and SvelteKit - Part 2
Published: 2023-07-04 04:02:08

---
title: Internationalization with Svelte and SvelteKit - Part 2
published: true
tags: 
canonical_url: https://enmanueljarquin.com/internationalization-with-svelte-and-sveltekit-part-2
---

This is the second part of our previous article, you could find it [here](https://enmanueljarquin.com/internationalization-with-svelte-and-sveltekit-part-1) 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' };
};

```

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;
};

```

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);
};

```

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 };
};

```

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);
};

```

To test it, we should modify the URL in the browser: [http://localhost:5173/?lang=es](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);
};

```

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';

```

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);
}

```

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

![Default Chrome Language](https://cdn.hashnode.com/res/hashnode/image/upload/v1688441037858/294d12e5-a077-4ecf-9068-9bb28c7a2b33.png)

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](http://localhost:5173/?lang=ed)

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

```typescript
// 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;
    ....
}
```

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!