Reputation: 1355
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
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