opral / inlang-paraglide-js

Tree-shakable i18n library build on the inlang ecosystem.
https://inlang.com/m/gerre34r/library-inlang-paraglideJs
34 stars 0 forks source link

`<a>` tags aren't reliably rewritten in `+layout.svelte` #180

Closed elron closed 1 week ago

elron commented 1 month ago

I used this code from this tutorial

{#each availableLanguageTags as lang}
    <!-- the hreflang attribute decides which language the link points to -->
    <a
        href={i18n.route($page.url.pathname)}
        hreflang={lang}
        aria-current={lang === languageTag() ? 'page' : undefined}
    >
        {lang}
    </a>
{/each}

and the href="" is not the language's code

image

so basically when I click on he/en, it doesn't change the language (it stays on the same page because "/" is the same page).

im using "@inlang/paraglide-js": "1.11.2" and "@inlang/paraglide-sveltekit": "0.11.0"

LorisSigrist commented 1 month ago

I tried to reproduce this with the exact code & version but it seems to work fine

elron commented 1 month ago
  1. yes (code below)
  2. all pages
  3. these are installed:

    "@inlang/paraglide-js": "1.11.2", "@inlang/paraglide-sveltekit": "0.11.0",

<script lang="ts">
    import { ParaglideJS } from '@inlang/paraglide-sveltekit';
    import { i18n } from '$lib/i18n';

    import '../app.scss';
    import { availableLanguageTags, languageTag } from '$lib/paraglide/runtime';
    import { page } from '$app/stores';
    import * as m from '$lib/paraglide/messages';

    $: currentPathWithoutLanguage = i18n.route($page.url.pathname);

    function getLanguageNameByCode(code) {
        const displayNames = new Intl.DisplayNames([code], { type: 'language' });
        return displayNames.of(code);
    }
</script>

<svelte:head>
    <script defer data-domain="glyphsmap.com" src="https://plausible.io/js/script.js"></script>
</svelte:head>

<ParaglideJS {i18n}>
    <div class="px-6 mx-auto max-w-4xl">
        <header class="mt-4 border-b-slate-300 border-b-2 pb-10">
            <nav class="flex flex-wrap gap-x-4 mb-3 justify-end">
                {#if languageTag() === 'he'}
                    <a href="https://fontools.co.il">כלים נוספים למעצבי פונטים</a>
                    <a href="https://fontdesign.co.il">איך ליצור פונט</a>
                {:else}
                    <a href="https://funweb.io">More useful tools</a>
                {/if}

                <!--
                This {#each} code doesnt work
                Bug: https://github.com/opral/inlang-paraglide-js/issues/180#issuecomment-2265183310 
                -->
                {#each availableLanguageTags as lang}
                    {#if languageTag() !== lang}
                        <a href={currentPathWithoutLanguage} hreflang={lang}>{getLanguageNameByCode(lang)}</a>
                    {/if}
                {/each}

                <!-- 
                Temporary fix
                -->
                <!-- {#each availableLanguageTags as lang}
                    {#if languageTag() !== lang}
                        <a
                            href={languageTag() === 'en' ? '/he' : '/'}
                            hreflang={lang}
                            aria-current={lang === languageTag() ? 'page' : undefined}
                        >
                            {getLanguageNameByCode(lang)}
                        </a>
                    {/if}
                {/each} -->

            </nav>
            <h1>GlyphsMap.com</h1>
            <h2>{m.slogen()}</h2>
        </header>

        <main>
            <slot />
        </main>

        <footer class="py-14 text-center text-sm">
            © GlyphsMap 2024 <span class="px-2">•</span>
            <a target="_blank" href={m.credit_href()}>{m.credit()}</a>
        </footer>
    </div>
</ParaglideJS>
elron commented 1 month ago

I've added you to my private repo so you can re-produce the problem (run bun dev): https://github.com/elron/glyphsmap-sveltekit

LorisSigrist commented 1 month ago

Hi, I've been able to reproduce this thanks to your repo


It seems like the link-translation is broken inside the +layout.svelte file. href attributes on <a> tags do not get rewritten. Moving the switcher into a separate file fixes it

I'm still not entirely sure why this is happening, but definitely a bug in paraglide-sveltekit. Thanks for reporting it!

elron commented 1 month ago

Interesting.

Just a guess: Maybe update some values using {#key}?

LorisSigrist commented 1 month ago

That shouldn't be necessary, it should ideally just work

elron commented 1 month ago

Okay I also wonder if it behaves differently in svelte 4 and svelte 5 (runes)

LorisSigrist commented 1 month ago

After some investigating this is unfortunately unfixable in Svelte 4. The reason is that we need to access a svelte-context in order to rewrite <a tags. This context is provided by the <ParagldieJS component.

However, we can't access that context in the same component as <ParaglideJS> is being used, since the script tag would be outside the scope of the contex.

The rewritten result looks something like this

<script>
  // access the paraglide context before it's created
  const translateHref = getContext("paraglide-sveltekit")
</script>

<!-- Creates the context -->
<ParaglideJS>
  <!-- translateHref does not work since it's supposed to come from the context -->
  <a href={translateHref("/")}>Link</a>
</ParaglideJS>

It's not possible to side-step this by calling getContext only at the link, since it has to be called during the initial component-mount.

The workaround is simple though. Just move the <a tag into a different .svelte file and use the component.

It might be possible to fix this limitation in svelte 5

elron commented 1 month ago

The workaround worked in svelte 5 (moved links to a different .svelte file ``), tested with these two lines:

// regular svelte worked
$: currentPathWithoutLanguage = i18n.route($page.url.pathname);

// runes worked too
const currentPathWithoutLanguage = $derived(i18n.route($page.url.pathname));
elron commented 1 month ago

However! it looks like the workaround doesn't work well in SSR.

So when I hit "source code" it gives me this:

<a href="/" hreflang="he">עברית</a>

while in the inspect, the DOM renders <a href="/he/" hreflang="he">עברית</a>

--- edit ----

I can't replicate the SSR issue anymore (and its working fine). so you can ignore this message.

samuelstroschein commented 1 week ago

Closing the issue given that the SSR issue can't be replicated anymore.