Skip to main content
Urbicon UI

Package Integration

Each package registers its own namespaced keys into one shared registry, then exposes a typed hook. Your app can do the same.

Why namespaces

Blocks, table, and auth each ship their own translation keys. Registering them under a namespace (blocks.*, table.*, auth.*) into one shared registry gives consumers a single merged translation surface with no key collisions — and lets your own app keys live alongside the library's.

createPackageI18n

The factory registers the bundles at module init and returns a small typed object. Its signature is createPackageI18n(name, { en, …otherLocales }, options?)en is required (the base), other eager locales are checked against its structure, and options.loaders opts into code-splitting.

Loading...
Loading syntax highlighting...
ReturnsSignature
useTranslate() => TypedTranslationFunction<T>
t(key, params?) => string
exists(key) => boolean
getLocales() => Locale[]
typesCreatePackageTypes<T>

The hook pattern

useTranslate is re-exported as use<Package>I18n and aliased to a two-letter local in components (bt / tt / dt). It reads the context locale at call time, so wrapping it in markup or $derived re-renders on a locale switch.

Loading...
Loading syntax highlighting...

The hook must be called during component initialisation (like every Svelte context read), then reused — don't call useBlocksI18n() inside an event handler or loop body.

Resolution order

For a package hook, a key resolves in this order:

  1. the package namespace in the active locale,
  2. the package namespace in the package's base/fallback locale,
  3. the global namespace (shared keys registered without a package).

A key that resolves nowhere returns the key string itself (fail-honest) — so a missing translation is visible, never silently blank.

The <T> component

For declarative one-off translations in markup, <T> wraps useI18n().t. Props: key, optional params, fallback (shown when the key is missing), package (namespace), and options.

Loading...
Loading syntax highlighting...

<T> is convenient but untyped (its key is a plain string). In library and app components, prefer the typed hook so keys autocomplete and typos fail to compile.

Registering your own package

Your app is just another package. Call createPackageI18n with a unique name and your own bundles, export the hook, and read it exactly like the library packages — all under the same provider.

Loading...
Loading syntax highlighting...

Pick a namespace that won't collide with blocks / table / auth. The docs site you're reading does exactly this under the app namespace.

Parity validation (CI)

validatePackageTranslations does a recursive deep-key diff across a package's locale bundles — a missing nested key is an error, an extra one a warning. Wire it into a vitest test to fail CI on drift. It complements the compile-time parity the generic factory enforces for eager bundles, and covers lazy/dynamic ones (see Type Safety).

Loading...
Loading syntax highlighting...