diff --git a/src/uix/eidos/components/words/words.svelte b/src/uix/eidos/components/words/words.svelte index 97a0a7c99..6b5b21caa 100644 --- a/src/uix/eidos/components/words/words.svelte +++ b/src/uix/eidos/components/words/words.svelte @@ -13,6 +13,7 @@ * (builder-style, always visible), a slide-in drawer, a popover, or * none. The same `` body is reused across all of them. */ + import { untrack } from 'svelte'; import { ActiveEidos } from '$uix/eidos'; import * as Words from '$soma/components/words'; import { Button } from '$uix/eidos/components/button'; @@ -47,16 +48,19 @@ // client pass emit different markup and hydration bails. Defer the // editor to the client; SSR + first paint render the empty frame. let mounted = $state(false); - // Client-only activation + one-time langs registration. Reads nothing - // reactive, so this $effect runs exactly once on mount (the Svelte 5 way, - // no lifecycle import). Register the inspector's localized strings into the - // active langs schema — without this every label resolves to the inline - // English fallback regardless of locale. `extend` deep-merges so app-level - // overrides at the same path applied AFTER mount still win. + // Client-only activation + one-time langs registration. `langs.extend` BOTH + // reads and mutates the reactive langs schema, so it MUST run untracked — + // otherwise this $effect tracks that read, the mutation retriggers it, and it + // loops, re-extending the bundle thousands of times (each logging a DEV + // leaf-overwrite warning). untrack ⇒ the effect has no deps ⇒ runs once on + // mount. Registers the inspector's localized strings so labels localize + // instead of falling back to the inline English. $effect(() => { - mounted = true; - eidos.langs.extend('components.words.inspector', WORDS_INSPECTOR_BUNDLE); - eidos.langs.extend('components.words.menu', WORDS_MENU_BUNDLE); + untrack(() => { + mounted = true; + eidos.langs.extend('components.words.inspector', WORDS_INSPECTOR_BUNDLE); + eidos.langs.extend('components.words.menu', WORDS_MENU_BUNDLE); + }); }); let contentEl = $state(null);