Big_Boulard
Big_Boulard

Reputation: 1355

select value binding and svelte-i18n integration problem

I'm dealing with something that seems to be a bit beyond my ken here ...

It's about select value binding. Here below, it's a simple peace of code that is working perfectly in a classic svelte SPA.

<script>
  let countrySelected = {
    code: 'BE',
    name: 'Belgium',
  };

  const countries = [
    {
      code: 'FR',
      name: 'France',
    },
    {
      code: 'BE',
      name: 'Belgium',
    },
    {
      code: 'GA',
      name: 'Gabon',
    },
  ];
</script>

<select bind:value={countrySelected}>
  {#each countries as country}
    <option value={country} selected={country.code === countrySelected.code}>
      {country.name}
    </option>
  {/each}
</select>

But for whatever reason, it doesn't work anymore when it's working in a sveltekit app which uses the svelte-i18n npm package.

/src/routes/__layout.svelte

<script>
  import { setupI18n, isLocaleLoaded } from '$lib/services/i18n.js';

  $: if (!$isLocaleLoaded) {
    setupI18n({ withLocale: 'fr-FR' });
  }
</script>

{#if !$isLocaleLoaded}
  Please wait...
{:else}
  <main>
    <slot />
  </main>
{/if}

/src/lib/services/i18n.js

The code of /src/lib/services/i18n.js comes from:

https://phrase.com/blog/posts/how-to-localize-a-svelte-app-with-svelte-i18n/ & https://lokalise.com/blog/svelte-i18n/

import { derived } from 'svelte/store';
import { dictionary, locale, _, date, time, number } from 'svelte-i18n';

const MESSAGE_FILE_URL_TEMPLATE = 'http://localhost:3000/lang/{locale}.json';

let cachedLocale;

async function setupI18n({ withLocale: _locale } = { withLocale: 'en-GB' }) {
  const messsagesFileUrl = MESSAGE_FILE_URL_TEMPLATE.replace(
    '{locale}',
    _locale
  );

  const res = await fetch(messsagesFileUrl);
  const messages = await res.json();
  dictionary.set({ [_locale]: messages });
  cachedLocale = _locale;
  locale.set(_locale);
}


// Before any locale is set, svelte-i18n will give locale an object type.
// Once it is correctly set, the libray will set locale
// to the code of the active locale, e.g. "en", a string type.
// We check for this in our devired store, and make sure that isLocaleLoaded‘s value
// is true only after i18n initialization is successful.
const isLocaleLoaded = derived(locale, $locale => typeof $locale === 'string');


export { _, locale, setupI18n, isLocaleLoaded, date, time, number };

Problem:

The <select> element in the index.svelte file should show "Belgium" because:

countrySelected = { code: 'BE', name: 'Belgium', }

The problem is that in __layout.svelte, svelte-i18n makes a kind of refresh just after the item has been selected so it looks nothing is selected. It's probably because of the way I've integrated svelte-i18n in my project as I only understood the broad strokes but once again ... the devil is in the detail :D

Thank you so much for your help. You can clone this repos, it gonna be easier to understand:

git clone https://github.com/BigBoulard/sveltekit-sveltei18n
npm i
npm run dev

Upvotes: 1

Views: 755

Answers (1)

miwin
miwin

Reputation: 1215

With your example, if you inspect the select element in a browser, the selected attribute is not set on any option.

Svelte has a very easy to use and straight forward way to set the initial selected value.

It automatically handles the required attribute on the option element when binding a value to the select element. The issue in your example is, that countrySelected looks the same as the object/dictionary inside your countries array, but is actually a new object and therefore Svelte can not select it.

This example should work:

<script>
  const countries = [
    {
      code: 'FR',
      name: 'France',
    },
    {
      code: 'BE',
      name: 'Belgium',
    },
    {
      code: 'GA',
      name: 'Gabon',
    },
  ];

  let countrySelected = countries.find(x => x.code === 'BE');
</script>

<select bind:value={countrySelected}>
  {#each countries as country}
    <option value={country}>
      {country.name}
    </option>
  {/each}
</select>

Upvotes: 1

Related Questions