svelte-i18n: Cannot format a message without first setting the initial locale when open _error route

Describe the bug When I try open _error route with some translate in it or in _layout, library throw error

Logs image

To Reproduce

  1. Clone i18n example repo
  2. Add some translate in _error OR _layout ({$_('title.index', { default: 'Sapper project template!' })}, for example)
  3. Open dont exist page (http://localhost:3000/ds)

Information about your project:

  • Browser: Chrome 82.0.4067.0

  • OS: Windows 10

  • svelte-i18n version: latest

  • Bundler: Rollup

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 9
  • Comments: 15 (3 by maintainers)

Most upvoted comments

For everyone coming across this issue using svelte@next. Here is my solution for now. Note that this is not prerendered at build-time.

routes/$layout.svelte

<script context="module">
  // is not working atm for routes/* and on reload with snowpack
  // export async function preload() {
  //   return waitLocale();
  // }
</script>

<script>
  import NavBar from "../components/navbar/Navbar.svelte";

  import {
    register,
    t,
    init,
    getLocaleFromNavigator,
    isLoading,
  } from "svelte-i18n";

  // note it's ending is .json, while the filename in static/ is  .json.js
  register("en", () => import("/lang/en.json"));

  init({ initialLocale: getLocaleFromNavigator(), fallbackLocale: "en" });
</script>

{#if $isLoading}
  Please wait...
{:else}
  {$t("test")}
    <NavBar />
    <main>
      <slot />
    </main>
{/if}

routes/index.svelte

<script>
  import { t } from "svelte-i18n";
</script>

{$t("test")

static/lang/en.json.js

export default {
  test: "test",
};

For me it was a problem that I use i18n-keys before they where actually initialized, so I needed to await the result:

<script>
    import {
        register,
        init,
        _
    } from 'svelte-i18n'
    
    async function setup() {
      register('en', () => import('@/i18n/en.json'))
      
      return await Promise.allSettled([
        // TODO: add some more stuff you want to init ...
        init({ initialLocale: 'en', fallbackLocale: 'en' })
      ])
    }

    const setupResult = setup()
</script>

{#await setupResult}
	<!-- <p>...show loading animation</p> -->
{:then}
  <h1>{$_('setup.max_players')}</h1>
{:catch error}
	<!-- <p style="color: red">{error.message}</p> -->
{/await}

As @jayk09 stated, the current solution is to use the isLoading store to check if the library is still loading the messages while we don’t have preload support in error pages. You can also wrap your _layout.svelte content with a loading state.

Hey @aksenovdev and @AlexanderBelkevich 👋 It seems that when going to an error page, the _layout.svelte preload method is not accounted for. This is happening because the locale lazy loading is ending AFTER the error page is rendered. Will try to get back to you if I find some solution to this. I’m not sure if this is a known sapper behavior or a bug.

I had the same issue, adding this worked for me:

import { dictionary, locale, _, init} from 'svelte-i18n';

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

Note that I have only one locale for now.

For me it was a problem that I use i18n-keys before they where actually initialized, so I needed to await the result:

<script>
    import {
        register,
        init,
        _
    } from 'svelte-i18n'
    
    async function setup() {
      register('en', () => import('@/i18n/en.json'))
      
      return await Promise.allSettled([
        // TODO: add some more stuff you want to init ...
        init({ initialLocale: 'en', fallbackLocale: 'en' })
      ])
    }

    const setupResult = setup()
</script>

{#await setupResult}
	<!-- <p>...show loading animation</p> -->
{:then}
  <h1>{$_('setup.max_players')}</h1>
{:catch error}
	<!-- <p style="color: red">{error.message}</p> -->
{/await}

The best solution for me. Otherwise it will have too much duplicated code.

For everyone coming across this issue using svelte@next. Here is my solution for now. Note that this is not prerendered at build-time.

routes/$layout.svelte

<script context="module">
  // is not working atm for routes/* and on reload with snowpack
  // export async function preload() {
  //   return waitLocale();
  // }
</script>

<script>
  import NavBar from "../components/navbar/Navbar.svelte";

  import {
    register,
    t,
    init,
    getLocaleFromNavigator,
    isLoading,
  } from "svelte-i18n";

  // note it's ending is .json, while the filename in static/ is  .json.js
  register("en", () => import("/lang/en.json"));

  init({ initialLocale: getLocaleFromNavigator(), fallbackLocale: "en" });
</script>

{#if $isLoading}
  Please wait...
{:else}
  {$t("test")}
    <NavBar />
    <main>
      <slot />
    </main>
{/if}

routes/index.svelte

<script>
  import { t } from "svelte-i18n";
</script>

{$t("test")

static/lang/en.json.js

export default {
  test: "test",
};

Can you explain why can’t we load it async instead of waiting for all the translations to be ready at this point?

I’m seeing the same issue, with sapper, on first load of a page. The first time I open the app in my browser I get this error, when reloading or even closing the browser & reoping the page everything works as expected.

Can’t reproduce in dev on a local machine, only when running as a google App Engine.