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.
| Returns | Signature |
|---|---|
| useTranslate | () => TypedTranslationFunction<T> |
| t | (key, params?) => string |
| exists | (key) => boolean |
| getLocales | () => Locale[] |
| types | CreatePackageTypes<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.
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:
- the package namespace in the active locale,
- the package namespace in the package's base/fallback locale,
- 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.
<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.
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).