opral / inlang-paraglide-js

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

SvelteKit `languageTag()` is not set in client-side `load` functions #165

Open Yoone opened 4 months ago

Yoone commented 4 months ago

My setup looks like this:

// +page.ts

import { languageTag } from '$lib/paraglide/runtime.js';
import { loadEntry } from '$lib/entries.js';

async function loadEntry(fetch, id) {
    return fetch(`https://my-api/v1/entries/${id}?lang=${languageTag()}`).then((res) => res.json());
}

export async function load({ fetch, params }) {
    return {
        entry: await loadEntry(fetch, params.id);
    }
}

The SvelteKit load() function gets executed both on the server and the browser:

My "fix" while waiting for a real solution was to modify the src/hooks.ts file generated by the CLI, to look this like:

 import { i18n } from "$lib/i18n"
+import { browser } from '$app/environment';
+import { setLanguageTag } from '$lib/paraglide/runtime.js';

 export const reroute = i18n.reroute()
+
+if (browser) {
+    const lang = i18n.strategy.getLanguageFromLocalisedPath(location.pathname);
+    setLanguageTag(lang);
+}

Am I doing things wrong or is this a bug?

micschwarz commented 4 months ago

I also noticed this behavior

LorisSigrist commented 4 months ago

The language is not automatically set in load functions in +page.ts, only in +page.server.ts. In load functions in +page.ts you need to manually determine the language based on the URL.

import { i18n } from "$lib/i18n"
import * as m from "$lib/paraglide/messages"

export function load({ url }) {
  const lang = i18n.getLanguageFromUrl(url)
  const msg = m.my_message(null, { languageTag: lang })
}

Why?

The load function is +page.ts can run on the client. They are triggered when hover a link to a page, not just when you navigate.

This creates a problem since the language needed in the load function may be different than the language of the page you're currently on. You would need to have two different languages present in the app at once.

We're looking for solutions here.

Yoone commented 4 months ago

Thank you for the context @LorisSigrist!

Since load functions have access to a url parameter, could we simply have a helper that the documentation advises using within load functions instead of the regular languageTag? It could also be the same helper function, which could take an optional url parameter.

It could look like this:

import { languageTag } from '$lib/paraglide/runtime.js';

export async function load({ fetch, params, url }) {
    // url.pathname contains the locale, e.g. /fr/entries/123
    const lang = languageTag(url); // returns 'fr'
    // ... use it
}

What do you think?

LorisSigrist commented 4 months ago

Passing an argument to the languageTag function unfortunately isn't sufficient. languageTag is also called insider every message function, where it would be impossible to pass it any arguments.

TBH this feature is likely blocked by AsyncLocalStorage being added to the browser

janvotava commented 3 months ago

What if I need to get the language in the layout's load function? Calling i18n.getLanguageFromUrl(url) there will make load refresh on every page click.