@umbraculum/i18n-keys
v0.2.0
Published
Umbraculum i18n-keys SDK — namespace conventions and key helpers for module-owned message keys (module message roots, nav label keys, reserved platform roots). Platform-classified per sub-plan #9 §1.1; published as a peer of @umbraculum/module-sdk per PLA
Readme
@umbraculum/i18n-keys
Namespace conventions and key helpers for module-owned message keys in Umbraculum locale bundles.
[!NOTE] Part of Umbraculum — an open-source toolset for building workspace-shaped operational applications. Greenfield SDK package landed 2026-05-27; realizes the published-SDK commitment in
docs/PLATFORM-ARCHITECTURE.md§4.4. This is not a carve-out from@umbraculum/i18n— that package keeps locale machinery and message content. Splitting brewery-flavored strings into a future vertical bundle is deferred perdocs/design/brewery-scope-migration-plan.md§1.4.
Install
npm install @umbraculum/i18n-keys@^0.1.0Public alpha — see third-party-module.md.
What this is
The MIT-licensed contract third-party and canonical module authors use to name message keys consistently across web (next-intl) and native (useTranslator). It encodes three rules the platform already follows in production:
- Module UI copy lives under a top-level namespace equal to the module
code(pim.*,automation.*,mrp.*,crp.*). - Primary navigation labels use the
nav.*prefix (nav.pim,nav.automation, …). The usual pattern isnav.<moduleCode>viadefaultModuleNavLabelKey(code), but tier-6 verticals may use a different suffix (brewery today usesnav.recipes, notnav.brewery). - Platform-owned roots (
common,auth,math,nav, …) are reserved — modules must not claim them as their message root.
Zero locale JSON, zero React, zero next-intl — only types and small pure helpers.
Scope
- Contains:
ModuleNavLabelKey,ModuleScopedMessageKey,RESERVED_PLATFORM_MESSAGE_ROOTS, validation helpers (assertValidModuleMessageRoot,moduleMessageRoot,defaultModuleNavLabelKey,composeModuleMessageKey), and error types for invalid or reserved roots. - Does not contain: locale files (
en.json/it.jsonlive in@umbraculum/i18n); React bindings (@umbraculum/i18n-react); proof that a key exists at runtime (apps merge bundles at load time — a future CI check may audit bundles separately).
Conventions (authoritative for v0)
Module message root
| Rule | Detail |
|------|--------|
| Shape | Same as registerModule({ code }): lowercase, starts with a letter, [a-z0-9_]*. |
| Locale tree | Top-level key in en.json / it.json equals code. |
| Web usage | useTranslations("pim") then t("products.title") resolves pim.products.title. |
| Native usage | Same namespace via useTranslator / merged messages from @umbraculum/i18n. |
Navigation label keys
| Rule | Detail |
|------|--------|
| Shape | ModuleNavLabelKey = `nav.${string}` (Option A — v0). |
| Default | defaultModuleNavLabelKey("pim") → "nav.pim". |
| Registration | Pass to registerWebModule({ navEntry: { labelKey: … } }) or registerNativeModule({ tabEntry: { labelKey: … } }) on @umbraculum/module-sdk. |
| Exception | When the product nav label is not named after code, use any nav.<suffix> that exists in the bundle (e.g. nav.recipes for brewery). |
Reserved platform roots
Modules must not call moduleMessageRoot() with any value in RESERVED_PLATFORM_MESSAGE_ROOTS (common, nav, auth, math, …). Canonical module codes (pim, automation, …) are valid roots and are not on that list.
Exports
| Symbol | Purpose |
|--------|---------|
| ModuleNavLabelKey | Branded nav.* key type for primary nav / tab labels. |
| ModuleScopedMessageKey<Root> | `${Root}.${string}` helper type for documentation. |
| RESERVED_PLATFORM_MESSAGE_ROOTS | Platform-owned top-level namespaces modules must not claim. |
| moduleMessageRoot(code) | Validated module root string. |
| defaultModuleNavLabelKey(code) | nav.<code> with validation on code. |
| composeModuleMessageKey(root, …segments) | Builds root.seg1.seg2 with segment validation. |
| assertValidModuleMessageRoot(root) | Pattern + reserved-root check. |
Usage
Registering web navigation (API module boot):
import { registerWebModule } from "@umbraculum/module-sdk";
import { defaultModuleNavLabelKey } from "@umbraculum/i18n-keys";
registerWebModule({
code: "pim",
ownedUrlSegments: ["products", "categories"],
navEntry: {
primarySegment: "products",
labelKey: defaultModuleNavLabelKey("pim"),
order: 5,
},
});Authoring locale entries (in your module's bundle or the monorepo's @umbraculum/i18n until external bundles land):
{
"pim": {
"title": "Product Information Management",
"products": { "listTitle": "Products" }
},
"nav": {
"pim": "Products"
}
}Composing a nested key in TypeScript:
import { composeModuleMessageKey, moduleMessageRoot } from "@umbraculum/i18n-keys";
const root = moduleMessageRoot("pim");
const key = composeModuleMessageKey(root, "products", "listTitle");
// "pim.products.listTitle"Build / test / lint (local)
Commands (run from repo root, container-friendly per the node-npm-container-only skill):
- Build:
npm run build:packages(builds@umbraculum/i18n-keysbefore@umbraculum/module-sdk) - Test:
npm run test --workspace=@umbraculum/i18n-keys - Lint:
npm run lint --workspace=@umbraculum/i18n-keys - Typecheck: per-workspace CI gate; see
docs/TYPING.md
How it fits in
- Consumed by:
@umbraculum/module-sdk(navEntry.labelKey,tabEntry.labelKeytyped asModuleNavLabelKey); third-party module repos (peer dependency); canonical module authors documenting key layout. - Depends on: nothing. Peer of
@umbraculum/ai-tool-sdkon the MIT SDK surface. - Sibling packages:
@umbraculum/i18n(bundles +getSharedMessages);@umbraculum/i18n-react(React hook).
Status
v0.1.0 is intentionally minimal: conventions + helpers, no bundle merger and no key-existence CI yet. Breaking changes follow PLATFORM-ARCHITECTURE §10 semver discipline at the SDK boundary. Published on the public npm registry — see docs/design/npm-sdk-publish-execution-plan.md.
Further reading
docs/design/i18n-keys-sdk-surface.md— normative v0 conventions, dependency graph, maintainer checklistdocs/PLATFORM-ARCHITECTURE.md§4.2 + §4.4 — module-owned i18n namespace + SDK surfacedocs/LICENSING.md§6.2 — MIT SDK posturedocs/I18N-AUDIT.md— web UI i18n migration auditdocs/modules/contribute/third-party-module.md— stable surfaces to pinpackages/sdk/module-sdk/README.md—registerWebModule/registerNativeModulepackages/platform/i18n/README.md— where locale JSON lives today
