Internationalization with Svelte and SvelteKit - Part 1
Tags: sveltekit, internationalization, svelte, i18n
Published: 2023-06-27 03:25:59

Internationalization support could be an easy task, you can easily create objects and then get the proper language by a key, but if you want to create a solid project in the long run, sooner or later you are going to have to face some challenges.

There are some options to set the proper language of a site, it could be by reading a query param from the URL or getting the browser lang config, or by selecting it from a select or dropdown component.

I played with two different libraries:

1. [https://github.com/sveltekit-i18n/lib](https://github.com/sveltekit-i18n/lib)
    
2. [https://github.com/ivanhofer/typesafe-i18n](https://github.com/ivanhofer/typesafe-i18n)
    

The one I liked was the second one, `typesafe-i18n`, it includes a lot of features out-the-box, so on this occasion, I would like to walk you through the installation of this tool to create a multi-language app.

### First and foremost, create a svelte-kit project:

```bash
npm create svelte@latest i18n-sveltekit
```

Some of the options that I selected are shown in the image below:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1687828474427/da13ce2f-7b32-444f-8266-92c7183b6418.png align="center")

### Installing and configuring typesafe-i18n

```bash
npm install -D typesafe-i18n
```

Next, we need to run the setup process, we can do it by a manual process by answering questions or generating the configuration automatically, so we are going for the automatic setup:

```bash
npx typesafe-i18n --setup-auto
```

That command will generate the file `.typesafe-i18n.json`, we will ensure that we have the key `adapter=svelte`, like so:

```json
{
   "adapter": "svelte",
   "$schema": "https://unpkg.com/typesafe-i18n@5.24.3/schema/typesafe-i18n.json"
}
```

and our `package.json` file was updated with a new script:

```json
"scripts" {
  ...,
  "typesafe-i18n": "typesafe-i18n"
}
```

Let's run it and see what happens:

```bash
npm run typesafe-i18n
```

If we open the project structure again, we are going to find out that we have new folders and files inside of them:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1687830691759/1224711a-b403-47db-a5ed-6204a7825a13.png align="center")

That command/script generated all the configuration we need to support the internationalization feature in our app, but there are still some steps that we need to do to customize how we are going to switch between languages.

### Running the app and typesafe-i18n

`typesafe-i18n` needs to update the files seen above, so it will work in real-time since it generates types, configurations, etc, at the same time we are running our development server, that being said, let's install another package to accomplish that.

```bash
npm install npm-run-all -D
```

Then, we will update our `package.json`

```diff
- "dev": "vite dev",
+ "dev": "npm-run-all --parallel typesafe-i18n vite:dev",
+ "vite:dev": "vite dev",
```

Now, if we run the script `npm run dev` , you will see that our script runs the `typesafe-i18n` configuration and our `development server`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1687831891300/f69f4950-077b-4560-983d-5447a1e76e04.png align="center")

### Let's get down to the nitty-gritty

Now we can start adding support for `english` by default:

1. Head to the file `src/i18n/en/index.ts` and add a new key that says `welcome`:
    
    ```typescript
    {
      ...,
      welcome: 'to your new SvelteKit app'
    }
    ```
    
    When you save it, you will immediately see a change in the file `src/i18n/i18n-types.ts` where our `welcome` key was added, so, that will help us a lot to autocomplete our objects in real-time thanks to `typesafe-i18n` and `typescript`.
    
2. Let's create a `+layout.ts` file inside of `src/routes/` with the following content:
    

```typescript
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 = 'en';
	await loadLocaleAsync(locale);
	setLocale(locale);

	return event.data;
};
```

We set `locale` to `en` manually, but we are going to change it in a few minutes, for now, what we are interested in is being able to load our basic configuration and test if it is working.

1. In our `src/routes/+page.svelte` let's locale the line that says `to your new SvelteKit app` , and we will change with this new line:
    

First, add this import:

```typescript
import { LL } from '../i18n/i18n-svelte';
```

Then, change the line and add this content instead:

```typescript
{$LL.welcome()}
```

With that change placed, you should be able to see the text in a single line in your app:

**Before**:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1687833810034/385f3885-db17-47c9-8774-c9b197f38ebb.png align="center")

**After**:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1687833828181/5edc162d-5d6c-48d5-b950-f84c359ddc12.png align="center")

You will notice that the text now is occupying a single line instead of two, we need to fix that, but what matters here is the fact that our internationalization config is working and we can add a new language, let's add support for `spanish` .

### Adding support for Spanish

1. Remove the unused directory `src/i18n/de` '
    
2. Add this folder and its index file: `src/i18n/es/index.ts`
    
3. Add the following content:
    

```typescript
import type { Translation } from '../i18n-types';

const es = {
	welcome: 'a tu nueva aplicacion en SvelteKit'
} satisfies Translation;

export default es;
```

1. Let's change the `locale` variable of our `src/routes/+layout.ts` file:
    
    ```diff
    - const locale = 'en';
    + const locale = 'es';
    ```
    

Now, you will see that text in our app is shown in Spanish:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1687834514204/3b0dc772-4864-4bd1-9726-8878753cc3f8.png align="center")

Our multi-language app is almost ready, but we still need to add a way to change the language dynamically and allow users to change it manually, since what we have to do to accomplish it is by changing the `locale` variable to switch between `english` and `spanish` , so let's do it in the second part.