I18n with Svelte and Jest Tests
Tags: javascript, svelte, tutorial, testing
Published: 2022-07-19 07:30:13

I need to build an app in English, French, and Polish, that's why I want to install and configure these three languages in my Svelte app. 

I [created](https://svelte.dev/) my app and I installed also the [tests](https://dev.to/deotyma/the-jest-configuration-in-the-svelte-application-4dm5)


I will use svelte-i18n 
```
npm i svelte-i18n
```
It's time to configure this package. The file main.js before configuration is like this:
```
import './app.css'
import App from './App.svelte'

const app = new App({
  target: document.getElementById('app')
})

export default app
```
now I add a svelte-i18n import:

```
import './app.css'
import App from './App.svelte'
import { addMessages, init } from 'svelte-i18n'

addMessages('en', {
  hello: 'Hello word!' 
}) // this is my key that I will use after in my App page.

init({
  initialLocale: 'en',
  fallbackLocale: 'en'
}); // here I inicialise and  configure a local language

const app = new App({
  target: document.getElementById('app')
})

export default app
```
Now I import i18n to App.svelte like this:
```
<script>
  import { _ } from 'svelte-i18n'
</script>

<main>
  <h1>{$_('hello')}</h1>
</main>
```
In a browser, it works very well but tests failed. I'll take care of it later. For the moment I add another language in main.js:
```
import './app.css'
import App from './App.svelte'
import { addMessages, init } from 'svelte-i18n'

addMessages('en', {
  hello: 'Hello word!' 
})

addMessages('fr', {
  hello: 'Salut tout le monde!' 
})

addMessages('pl', {
  hello: 'Witajcie w naszej bajce!' 
})

init({
  initialLocale: 'fr',
  fallbackLocale: 'en'
});

const app = new App({
  target: document.getElementById('app')
})

export default app
```
So when you change a local language your text in a browser will change also. 
As I mentioned the tests are broken so I will fix them.
In the first place, I create a folder locale in folder src
```
mkdir locale
cd locale
touch i18n.js
```
from main.js I cut this part of code:
```
import { addMessages, init } from 'svelte-i18n'

addMessages('en', {
  hello: 'Hello word!' 
})

addMessages('fr', {
  hello: 'Salut tout le monde!' 
})

addMessages('pl', {
  hello: 'Witajcie w naszej bajce!' 
})

init({
  initialLocale: 'fr',
  fallbackLocale: 'en'
});
```
to paste it to i18n.js and I import this file in main.js:
```
import './locale/i18n'
```

The translation works in the browser.
I import this file also to the App.spec.js file:
``` 
import '../src/locale/i18n'
```
and tests are green when the local language is English.

To have all languages in the same file so I create a JSON file for each language:

![languages files](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ifvhkhf08dbmxyinrcp7.png)
and in i18n.js I import all these files:
```
import { addMessages, init } from 'svelte-i18n';
import en from './en.json';
import fr from './fr.json';
import pl from './pl.json';

addMessages('en', en)

addMessages('fr', fr)

addMessages('pl', pl)

init({
  initialLocale: 'en',
  fallbackLocale: 'en'
});
```

Now I test if traduction is well displayed

App.spec.js:

```
/**
 * @jest-environment jsdom
 */

 import App from "../src/App.svelte";
 import { render, screen } from "@testing-library/svelte";
 import '../src/locale/i18n'
 import en from '../src/locale/en.json' //here I import a json files 
 import fr from '../src/locale/fr.json'
 import pl from '../src/locale/pl.json'
 
 // I modify a little bit a teste by adding description tag 
 describe("App Page", () =>{
   describe("Layout", () =>{
    it("has Hello header", () =>{
      render(App);
      const header = screen.getAllByText("Hello word!");
      expect(header).toBeTruthy()
    });
   });
   describe("i18n", () =>{
     it("displays text in English", () =>{
       render(App);
       expect(screen.queryByRole('heading', {level: 1, name: en.hello})).toBeInDocument; /here I use from json file key and its value
     });
     it("displays text in French", () =>{
      render(App);
      expect(screen.queryByRole('heading', {level: 1, name: fr.hello})).toBeInDocument;
    });
    it("displays text in Polish", () =>{
      render(App);
      expect(screen.queryByRole('heading', {level: 1, name: pl.hello})).toBeInDocument;
    });
   })
 })
```
For a moment all is by default but I want to change languages so I need to create a little button to toggle between languages. 

In tests I add those 2 tests: 

```
it("displays text in French after clic a FR btn", async () =>{
      render(App);
      const frBtn = screen.getByText('FR');
      await userEvent.click(frBtn);
      expect(screen.queryByRole('heading', {level: 1, name: fr.hello})).toBeInDocument;
    });
    it("displays text in Polish after clic a PL btn", async () =>{
      render(App);
      const plBtn = screen.getByText('PL');
      await userEvent.click(plBtn);
      expect(screen.queryByRole('heading', {level: 1, name: pl.hello})).toBeInDocument;
    });
```

Those tests are correct but it doesn't work because I need to import user event from the library that I installed before.

```
import userEvent from '@testing-library/user-event'
```
Now the tests are broken because in App.svelte I don't have any element to click. So I create 3 languages elements and I add on:click to them. I need also to import a local from i18n. Now App.svelte is like this:
```
<script>
  import { _, locale } from 'svelte-i18n'
</script>

<main>
  <h1>{$_('hello')}</h1>
  <span on:click = {() => locale.set("en")}>EN</span>
  <span on:click = {() => locale.set("fr")}>FR</span>
  <span on:click = {() => locale.set("pl")} >PL</span>
</main>
```
Now all works but I need to know if the EN button works also good than others so I create one more test:
```
it("displays text in English after click from PL btn", async() =>{
      render(App);
      const plBtn = screen.getByText('PL');
      await userEvent.click(plBtn);

      const enBtn = screen.getByText('EN');
      await userEvent.click(enBtn);
      expect(screen.queryByRole('heading', {level: 1, name: en.hello})).toBeInDocument;
    });
```
so all App.spec.js is like this:
```
/**
 * @jest-environment jsdom
 */

 import App from "../src/App.svelte";
 import { render, screen } from "@testing-library/svelte";
 import userEvent from '@testing-library/user-event'
 import '../src/locale/i18n'
 import en from '../src/locale/en.json'
 import fr from '../src/locale/fr.json'
 import pl from '../src/locale/pl.json'
 
 
 describe("App Page", () =>{
   describe("Layout", () =>{
    it("has Hello header", () =>{
      render(App);
      const header = screen.getAllByText("Hello word!");
      expect(header).toBeTruthy()
    });
   });
   describe("i18n", () =>{
     it("displays text in English by default", () =>{
       render(App);
       expect(screen.queryByRole('heading', {level: 1, name: en.hello})).toBeInDocument;
     });
     it("displays text in French after clic a FR btn", async () =>{
      render(App);
      const frBtn = screen.getByText('FR');
      await userEvent.click(frBtn);
      expect(screen.queryByRole('heading', {level: 1, name: fr.hello})).toBeInDocument;
    });
    it("displays text in Polish after clic a PL btn", async () =>{
      render(App);
      const plBtn = screen.getByText('PL');
      await userEvent.click(plBtn);
      expect(screen.queryByRole('heading', {level: 1, name: pl.hello})).toBeInDocument;
    });
    it("displays text in English after click from PL btn", async() =>{
      render(App);
      const plBtn = screen.getByText('PL');
      await userEvent.click(plBtn);

      const enBtn = screen.getByText('EN');
      await userEvent.click(enBtn);
      expect(screen.queryByRole('heading', {level: 1, name: en.hello})).toBeInDocument;
    });
   })
 })
```
When I run the tests all is green.

![working tests](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yaxwwtw40glr6nd7utmd.png)