-
-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use setContext instead of global store #106
Comments
No. |
This worked very well for me:
export function load({ request }) {
return {
languages:
request.headers
.get("accept-language")
?.split(",")
?.map(lang => lang.split(";")[0].trim()) ?? [],
};
}
import { browser } from "$app/environment";
import { loadTranslations } from "$lib/utils/i18n";
export async function load({ url, data }) {
const languages = browser ? navigator.languages : data.languages;
return {
t: await loadTranslations(languages, url.pathname),
};
}
<script lang="ts">
import { setContext } from "svelte";
export let data;
setContext("t", data.t);
</script>
<slot />
declare module "svelte" {
export function getContext(key: "t"): Awaited<ReturnType<typeof import("$lib/utils/i18n")["loadTranslations"]>>;
}
const config: Config = {
loaders: [
// ...
]
};
const availableLanguages = new Set(config.loaders?.map(loader => loader.locale) ?? []);
const defaultLocale = "en";
const defaultLocaleForLanguage: Record<string, string> = {
en: "en-US",
pt: "pt-BR",
};
export async function loadTranslations(languages: readonly string[], route: string) {
const locale =
languages.find(lang =>
availableLanguages.has(
!lang.includes("-") && lang in defaultLocaleForLanguage ? defaultLocaleForLanguage[lang] : lang,
),
) ?? defaultLocale;
const instance = new i18n(config);
await instance.loadTranslations(locale, route);
return instance.t;
} Any page that uses translations: <script lang="ts">
import { getContext } from "svelte";
const t = getContext("t");
</script>
<p>{$t("some-key")}</p> |
Hey @lbguilherme - Thank you so much for your detailed answer. I stand corrected, this does indeed work. Just one thing - It doesn't load any translations for the new route when switching routes on frontend only. I can use |
The solution above (#106 (comment)) seems like a good way to avoid side-effects in load. Shouldn't it be included in the examples? Albeit, my use case is a pretty simple one, and I don't know whether this solution works 100% for more complex setups (e.g. what @Lobidu states here #106 (comment)). P.S. probably all of this would need reworked again after the introduction of runes. |
I currently have the same issue, did you manage to fix it? EDIT: I made it work by passing the setContext in a reactive statement like this: export let data;
$: if ($page) {
setContext("t", data.t);
} |
Hi @CustomEntity, I've come to the same problem with translation loading, and also tried to employ the same solution of sharing the Please text back if you're successful using your reactive setContext solution with dynamic client side language changing (e.g. |
Hello @mtpython, I finally encountered the same problem as yours, the solution worked on a single page but not on multi-page like you. So I've stopped using SvelteKit-i18n until they fix the problem on their side, the other libraries also have the same problem so I've decided to use a temporary DIY solution that works as well as SvelteKit-i18n for my use. |
Thanks for mentioning the "poly-i18n", but for my project the currently missing lazy load feature is more important than the downsides of race conditions, so until a more complete/mature solution is released, I'd resort to just accepting the current state of this library as is... tl;dr: this issue should remain open |
Your solutions seem to work for me as well, but there is type error:
|
Wow, glad I found this issue. I was going crazy about why translations kept doing crazy things on production but always worked locally and on staging. The solution by lbguilherme worked for me. But I had to disable lazy loading for different routes or they wouldn't load in SPA mode. I guess this should be mentioned in the docs. |
Unfortunately I see a fundamental design flaw in the way sveltekit-i18n implements the localisation store: If I see it correctly it uses a global store to manage localisation state. On most SSR environments this means localisation state is unintentionally shared between users.
For most smaller applications this doesn't have any visible effect because localisation state is set at the beginning of the request and the request is completed before another user's request is received.
But in high traffic environments and / or slow rendering pages the following could happen:
en
. State is set, the page starts rendering with localeen
.cn
. This modifies the globallocale
state.cn
!The Sveltekit docs explicitly state to avoid global stores for exactly this reason:
https://kit.svelte.dev/docs/state-management
The better way to solve this would be to utilise
setContext
on the root layout to get a contextualised store. I've tried to do this in my app like this:This is working fine client-side. But server side no translation happens at all, due to the fact that the line
$: i18n.loadTranslations(data.locale, data.path);
returns a promise that isn't resolved before Sveltekit returns the rendered page.await
ing that promise before mounting<slot/>
just makes SSR return no DOM at all for that slot.The idiomatic way to
await
something would be inside theload
function instead. But inside theload
function I can't accesscontext
. I can't load the translations inside the load function and pass theI18n
object as part ofdata
either, because only plain objects are allowed.Any Idea on how to get out of this pickle? The easiest way would be to make
loadTranslations
blocking.The text was updated successfully, but these errors were encountered: