Skip to main content
Urbicon UI

Lazy Loading

By default a package registers all its locale bundles eagerly. Opt into code-splitting to keep non-base languages out of the initial bundle until they're activated.

When to use it

Eager registration ships every locale's strings in the initial bundle. That's simplest and right for a handful of languages (en/de). Past that, the inactive locales are dead weight on first paint — register them as dynamic-import loaders so only the active language is in the initial bundle, and the rest load on activation.

Registering loaders

Pass options.loaders to createPackageI18n. The bundle in translations (typically en) stays eager as the base/fallback; each listed locale becomes a dynamic import that Vite/Rollup splits into its own chunk.

Loading...
Loading syntax highlighting...

Compile-time key parity is not checked for lazy locales — the chunk isn't visible to the type-checker. Guard parity at runtime with validatePackageTranslations in a test.

Load lifecycle

The provider drives loading automatically:

  • On mount it loads the active locale and the fallback. (Effects don't run during SSR, so a lazy non-base initial locale renders the fallback on the server and the first client paint, then re-resolves reactively once its chunk lands.)
  • On switch, setLocale triggers the target's loader (not awaited) and flips the locale; the $derived reads re-resolve when the chunk arrives.
  • If a load fails and no data exists for that locale, load-failed-no-fallback is reported to the error sink — the loud signal that "the language you switched to can't be rendered."

useI18n().isLoading is true while a lazy load is in flight — wire it to a spinner if a switch is perceptible:

Loading...
Loading syntax highlighting...

Trade-offs

Eager (default)

  • Simplest — no extra config.
  • Compile-time key parity across all locales.
  • No loading state, no flash of fallback.
  • Best for a few locales (en/de).

Lazy (opt-in)

  • Smaller initial bundle — inactive locales excluded.
  • Parity is a runtime/CI check, not compile-time.
  • A lazy non-base initial locale flashes the fallback first.
  • Worth it past a handful of locales.