DEV Community

Cover image for I18n with Svelte and Jest Tests
Deotyma
Deotyma

Posted on

5 1

I18n with Svelte and Jest Tests

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 my app and I installed also the tests

I will use svelte-i18n

npm i svelte-i18n
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Now I import i18n to App.svelte like this:

<script>
  import { _ } from 'svelte-i18n'
</script>

<main>
  <h1>{$_('hello')}</h1>
</main>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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'
});
Enter fullscreen mode Exit fullscreen mode

to paste it to i18n.js and I import this file in main.js:

import './locale/i18n'
Enter fullscreen mode Exit fullscreen mode

The translation works in the browser.
I import this file also to the App.spec.js file:

import '../src/locale/i18n'
Enter fullscreen mode Exit fullscreen mode

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
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'
});
Enter fullscreen mode Exit fullscreen mode

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;
    });
   })
 })
Enter fullscreen mode Exit fullscreen mode

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;
    });
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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;
    });
Enter fullscreen mode Exit fullscreen mode

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;
    });
   })
 })
Enter fullscreen mode Exit fullscreen mode

When I run the tests all is green.

working tests

SurveyJS custom survey software

JavaScript UI Libraries for Surveys and Forms

SurveyJS lets you build a JSON-based form management system that integrates with any backend, giving you full control over your data and no user limits. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay