diff --git a/rfcs/0024-localization-runtime-and-coverage.md b/rfcs/0024-localization-runtime-and-coverage.md index dd0cb533..8aa82dbf 100644 --- a/rfcs/0024-localization-runtime-and-coverage.md +++ b/rfcs/0024-localization-runtime-and-coverage.md @@ -3,7 +3,7 @@ title: Localization Runtime and Product Coverage authors: - Gio Della-Libera created: 2026-07-16 -last_updated: 2026-07-23 +last_updated: 2026-07-24 status: accepted issue: https://github.com/openclaw/openclaw/issues/113105 rfc_pr: https://github.com/openclaw/rfcs/pull/42 @@ -13,1022 +13,338 @@ rfc_pr: https://github.com/openclaw/rfcs/pull/42 ## Summary -OpenClaw will adopt one localization contract across runtime, CLI/TUI, Gateway, -channels, metadata, UI, native apps, and docs without replacing the translation -pipelines that already work. +OpenClaw will support one 22-locale product target across its 15 required +product surfaces: English is the reviewed source locale and the other 21 are +translation targets. That is 315 translation-target cells. Coverage lands +progressively, but a full product claim requires every cell to be complete. -Core owns locale identity, resolution precedence, catalog validation, and -generic coverage semantics. Gateway-owned descriptors live in the shared -Gateway protocol boundary. Each user-facing owner publishes its coverage -declarations and continues to own its catalogs and final rendering. Existing -codes, commands, identifiers, structured output, and reviewed English messages -remain compatible. +Each surface still owns its English copy, catalogs, renderer, translation +workflow, and review policy. Shared infrastructure provides locale identity, +`LocalizationContext`, ICU formatting through `intl-messageformat`, fallback, +validation, inventory, CI gates, generated-PR automation, and coverage +reporting. Codes, commands, identifiers, structured output, user data, and +model-generated content are never translated by this system. -For JavaScript and TypeScript runtime catalogs, `intl-messageformat` owns ICU -message parsing and formatting. The OpenClaw-specific layer owns the locale -context, catalog and parameter validation, protected literals, compatibility, -fallback, and safety rules around that formatter. - -Supporting material: +The detailed contracts are normative and live in these focused sidecars: - [Localization Runtime v1 specification](0024/localization-runtime-v1-spec.md) - [Localization Coverage v1 specification](0024/localization-coverage-v1-spec.md) - [Localized Metadata v1 specification](0024/localized-metadata-v1-spec.md) -- [GitHub issue catalog](0024/issue-catalog.md) - [Implementation plan](0024/implementation-plan.md) - [Projected owner slice registry](0024/projected-owner-slice-registry.md) +- [GitHub issue catalog](0024/issue-catalog.md) -## Decision - -Accepting this RFC approves these product contracts: - -1. OpenClaw resolves locale through one immutable `LocalizationContext`. - Explicit user and recipient choices outrank request, surface, operator, and - platform inference; unsupported explicit values fail safely to English. -2. Product-owned runtime copy is represented as a stable message key, typed - literal parameters, and a reviewed English fallback template. The surface - that presents the message owns the catalog and final rendering. Shared - JavaScript and TypeScript runtime rendering delegates ICU formatting to - `intl-messageformat` rather than implementing a second message formatter. -3. Subject to Gateway-owner approval, Gateway errors retain their existing code - and English `message` while reviewed errors may add bounded localization - metadata under `details.localization`. Shared descriptor identities live in - `packages/gateway-protocol`, capable clients render them, and legacy clients - ignore them. -4. Subject to the command, skill, and plugin owners approving each additive - public schema, capability identities remain stable while locale-keyed - presentation metadata may be projected to Gateway and client surfaces. -5. Localization core defines generic maturity and scoped-evidence semantics - rather than owning a closed product-surface union. Once release aggregation - is enabled, surface owners publish declarations and the product layer - generates locale/surface maturity, revision, review, and blocker evidence. - Missing required portfolio declarations fail the release claim, not the - runtime kernel. -6. A migrated surface satisfies the localization-ready ownership standard: - semantic meaning, locale authority, catalog/rendering, compatibility, - privacy, conformance evidence, and deletion of the superseded presentation - path all have named owners and proof. -7. Owner workflows may publish one source-pinned translation-run evidence - contract: - exact source revision, locale, source and glossary revisions, generator and - workflow identity, provider/model identity, generated artifact revision, - and validation result. Extraction, publication, and review policy remain - owner-specific. - -This RFC does not authorize broad exception/log extraction, runtime model -translation, translation of commands or protocol values, AI self-review, or a -new external plugin runtime-catalog API. - -The five open foundation drafts are the first bounded entries in the projected -owner slice registry. Their review deltas now isolate the minimal kernel, -updater dry-run, contributor guidance, TUI status, and one Gateway approval -descriptor. `F02` through `F05` now branch independently from `F01`; none -carries another follow-up owner's runtime or documentation delta. Each is -reviewed and landed only by its named semantic and rendering owners. - -Accepting the RFC changes no runtime by itself. If `F01` lands and the four -independent owner slices follow, OpenClaw has the internal locale/context and -formatting -foundation, the existing wizard consumer, localized updater dry-run and TUI -status families, one reviewed Gateway/Control UI approval-error edge, and the -contributor guide. The coverage specification then defines how adopted owners -can report language-by-surface state, but these drafts do not install a closed -global matrix or claim that other cells are localized. Owner declarations and -aggregate product reporting remain the later `E43` and `E44` slices. - -The five runtime drafts do not install the reusable authoring gate or -asynchronous translation lane. Draft OpenClaw PR -[#112784](https://github.com/openclaw/openclaw/pull/112784) implements `G45` -and `G46` together as the bounded core/tooling exemplar: a routine English -source edit trips deterministic CI, then a trusted exact-source workflow -generates and validates a locale candidate and opens a generated pull request. -Each later surface opts in only for its owner-declared families, namespaces, or -directories and must bring both halves of that loop. - -The current delivery audit identifies 47 projected owner slices. The first -audit had 44; owner review exposed the authoring-gate and generated-refresh -obligations now explicit as `G45` and `G46`, and follow-up review exposed the -new-surface adoption obligation now explicit as `G47`. This is the proposed -queue to work down over time, using the same planning pattern as Doctor's -structured rule registry. The count is planning evidence, not a required -pull-request count or acceptance gate. A slice is deleted when source audit -proves that no migration is needed and split when it crosses an owner, -locale-authority, public-contract, or publication boundary. Coverage and -release state consume only landed owner declarations; the planning registry is -never loaded by the runtime. - -### Acceptance and delivery milestones - -RFC 0024 separates architecture acceptance from implementation and product -completion: - -1. **Architecture accepted:** owners approve the locale, descriptor, fallback, - and minimum coverage semantics. Any Gateway, command, skill, plugin, or - recipient-locale surface remains gated on its named owner. -2. **Foundation shipped:** a minimal kernel and one existing owner-controlled - consumer land with accepted, fallback, compatibility, privacy, and deletion - proof. -3. **Owner cohorts complete:** operator, runtime-safety, channel/capability, and - native/docs owners migrate bounded message families through independent, - reviewable PRs and generated catalog waves tracked in the projected owner - slice registry. -4. **Product claim promoted:** the release report evaluates only landed, - owner-declared evidence and may make a qualified or full localization claim. - -The execution target is a product-completion decision on September 1, 2026. -The projected registry groups all 47 current entries into 16 dependency-safe -delivery packages from July 22 through September 1, at roughly three completed -packages per full week. This is a delivery forecast, not a change to normative -runtime behavior. A package may contain several small source, consumer, or -generated-catalog pull requests; it reuses shared per-repository gates rather -than creating a separate automation system for each slice. - -The current 15-surface, 315-cell portfolio is a delivery target and release -policy snapshot. It is not an RFC-acceptance condition, a localization-core -type restriction, or a requirement that one PR fill an entire cohort. - -## Motivation - -OpenClaw already has substantial localization: - -- the Control UI has English plus 20 lazy-loaded locale bundles; -- onboarding has an English, Simplified Chinese, and Traditional Chinese - catalog selected from `OPENCLAW_LOCALE` and process locale variables; -- bundled plugin setup can reuse the onboarding translator; -- Android and Apple apps have generated runtime locale inventories; -- documentation has a dedicated translation workflow and glossaries. - -These systems do not yet form a complete product contract. Runtime and package -code still constructs English text at the point where errors occur. Gateway -clients receive a stable error code plus an English `message`, and Control UI -surfaces commonly display that raw message. Channel safety messages such as -exec approvals are assembled from hardcoded English labels. Most CLI help, -status, validation, and failure output is English. Command descriptions and -skill metadata do not have one cross-channel locale model. Translation -completeness is measured differently, or not at all, across surfaces. - -The user-visible result is inconsistent: - -- a localized Control UI can display an English Gateway failure; -- a user can select Chinese in the UI and receive an English approval request - in Telegram; -- onboarding can be localized while later CLI commands remain English; -- command and skill descriptions can remain English inside an otherwise - localized UI; -- shipped locale bundles can contain untranslated fallback strings without a - clear product-level completeness claim; and -- runtime code sometimes matches English operating-system error text, which - fails on localized hosts. - -This is not solved by extracting every string into one catalog. OpenClaw has -different renderers, security boundaries, packaging constraints, and release -cadences. The missing invariant is: - -```text -resolved locale context -+ stable product-owned message identity -+ typed literal parameters -+ surface-owned catalog --> deterministic localized rendering --> English compatibility fallback --> measurable coverage +## Current state + +The 315-cell matrix is the product target, not a claim about the current +release. Control UI, native apps, documentation, and the onboarding wizard +already have owner-specific localization systems at different maturity levels; +the wizard currently covers English, Simplified Chinese, and Traditional +Chinese. Many CLI, TUI, runtime, Gateway, channel, and metadata families remain +English-only, partial, or unsupported. Until aggregate reporting lands in +`E43` and `E44`, the live implementation tracker—not this RFC—is the delivery +status source. + +## System at a glance + +Each product surface enrolls independently. An adopted shared-catalog surface +updates three code locations in the same slice: its owner source, +`localization/surfaces.json`, and `localization/catalogs.json`. A surface with +an existing conforming pipeline names that workflow instead. The same slice +also updates the public workflow index and nearest owner guidance. + +```mermaid +flowchart TB + subgraph SURFACES["1. Choose one release-coverage surface"] + direction TB + subgraph OPERATOR["Operator surfaces"] + direction LR + WIZARD["cli-onboarding"] + SETUP["channel-plugin-setup"] + CLI["cli"] + TUI["tui"] + end + subgraph RUNTIME["Runtime and metadata surfaces"] + direction LR + CORE["runtime"] + GATEWAY["gateway-errors"] + CHANNELS["server-rendered-channels"] + COMMAND["command-metadata"] + SKILL["skill-metadata"] + end + subgraph CLIENTS["Client and publication surfaces"] + direction LR + CONTROL["control-ui"] + TELEGRAM["telegram-command-menu"] + DISCORD["discord-command-menu"] + ANDROID["android"] + APPLE["apple"] + DOCS["docs"] + end + end + + ADOPT["Adopt this surface"] + WIZARD --> ADOPT + SETUP --> ADOPT + CLI --> ADOPT + TUI --> ADOPT + CORE --> ADOPT + GATEWAY --> ADOPT + CHANNELS --> ADOPT + COMMAND --> ADOPT + SKILL --> ADOPT + CONTROL --> ADOPT + TELEGRAM --> ADOPT + DISCORD --> ADOPT + ANDROID --> ADOPT + APPLE --> ADOPT + DOCS --> ADOPT + + subgraph REGISTRATION["2. Register it in the same slice"] + direction LR + SOURCE["A. Owner source
reviewed English + owner renderer/catalog"] + INVENTORY["B. localization/surfaces.json
id • owner • source • disposition"] + DISPOSITION{"C. Disposition"} + CATALOG["adopted
localization/catalogs.json
source • targets • protected literals"] + PIPELINE["conforming-pipeline
named owner workflow"] + EXCEPTION["deferred / english-only / platform-constrained
named rationale and blocker"] + GUIDANCE["Same slice
docs/reference/localization.md
nearest AGENTS.md + CLAUDE.md alias"] + + INVENTORY --> DISPOSITION + DISPOSITION --> CATALOG + DISPOSITION --> PIPELINE + DISPOSITION --> EXCEPTION + end + + ADOPT --> SOURCE + ADOPT --> INVENTORY + ADOPT --> GUIDANCE + + subgraph MAINTENANCE["3. Enforce and maintain"] + direction LR + SURFACE_CHECK["localization:surfaces:check"] + CATALOG_CHECK["CI job: localization-catalogs
catalogs:check / catalogs:detect"] + REFRESH["Localization Catalog Refresh
same PR when possible • generated PR fallback"] + OWNER_FLOW["owner pipeline
check + refresh"] + RESULT["Owner renderer + coverage evidence
machine semantics unchanged"] + end + + SOURCE --> SURFACE_CHECK + INVENTORY --> SURFACE_CHECK + CATALOG --> CATALOG_CHECK + SURFACE_CHECK --> CATALOG_CHECK + CATALOG_CHECK --> REFRESH --> RESULT + PIPELINE --> OWNER_FLOW --> RESULT + EXCEPTION --> SURFACE_CHECK + GUIDANCE --> RESULT ``` -### Evidence from existing issues - -The detailed mapping is in [the issue catalog](0024/issue-catalog.md). The -highest-signal gaps are: - -| Issue | Gap | RFC implication | -| --- | --- | --- | -| [openclaw#81253](https://github.com/openclaw/openclaw/issues/81253) | Exec approval prompts are hardcoded English. | Safety messages need structured, locale-aware edge rendering. | -| [openclaw#66056](https://github.com/openclaw/openclaw/issues/66056) | Gateway/runtime failures have no locale-aware message contract. | Preserve error codes and English messages while adding localization metadata. | -| [openclaw#88570](https://github.com/openclaw/openclaw/issues/88570) | CLI, runtime, channel, and UI coverage remains incomplete. | Coverage needs a product-level manifest and release report. | -| [openclaw#79458](https://github.com/openclaw/openclaw/issues/79458) | Slash-command descriptions lack a shared localization model. | Command metadata needs locale-keyed descriptions. | -| [openclaw#55239](https://github.com/openclaw/openclaw/issues/55239) | Telegram command menus remain English. | Channel projections must consume the command metadata contract. | -| [openclaw#89971](https://github.com/openclaw/openclaw/issues/89971) | Skill names and descriptions remain raw English metadata. | Package-owned metadata needs locale-keyed fields and fallback. | -| [openclaw#28303](https://github.com/openclaw/openclaw/issues/28303) | Public Chinese locale IDs use region rather than script semantics. | Locale aliases and migration must be explicit and backward compatible. | -| [openclaw#90608](https://github.com/openclaw/openclaw/issues/90608) | Browser locale inference can select an unwanted UI language. | Explicit user choice must outrank inferred locale and remain easy to reset. | -| [openclaw#105266](https://github.com/openclaw/openclaw/issues/105266) | Locale-rendering tests can become nondeterministic. | Localization state and test isolation are release infrastructure. | -| [openclaw#106576](https://github.com/openclaw/openclaw/issues/106576) | Runtime behavior matches English host error text. | Host behavior must not depend on localized prose. | - -Broad earlier requests were often closed as duplicate, superseded, or too -general. That history argues for one RFC and issue-to-slice map instead of more -independent language requests. - -### Target locales - -RFC 0024 v1 starts with the union of existing shipped product locales: the 21 -Control UI locales plus Swedish, which already has a native-app catalog: - -```text -en -zh-CN -zh-TW -pt-BR -de -es -ja-JP -ko -fr -hi -ar -it -tr -uk -id -pl -th -vi -nl -fa -ru -sv +Control UI, native, and documentation surfaces keep their existing formats and +owner workflows while satisfying the same inventory, evidence, and coverage +contract. A deferred or platform-constrained disposition remains visible as a +product-completion blocker; it is not counted as localized. + +These are release-reporting rows, not delivery-slice names. For example, +updater and Doctor work rolls into `cli`; approval work can affect `runtime`, +`gateway-errors`, and `server-rendered-channels`; and adapter-specific evidence +feeds the appropriate channel row. Adding an implementation slice does not +silently add another row to the 315-cell product denominator. + +### Example: one English wizard string, end to end + +The wizard authoring exemplar in OpenClaw PR +[#112784](https://github.com/openclaw/openclaw/pull/112784), together with the +surface-inventory follow-up +[#112801](https://github.com/openclaw/openclaw/pull/112801), shows the complete +path with an actual message: + +```mermaid +flowchart TB + EN["1. Author opens a ready English source PR
src/wizard/i18n/catalogs/en.json
wizard.completion.enable"] + DETECT["2. Credential-free PR gate fails on drift
localization:surfaces:check confirms ownership
localization:catalogs:detect --fail-on-drift names zh-CN + zh-TW"] + ACTION["3. Maintainer runs Localization Catalog Refresh
against that PR's exact head
trusted main tooling owns provider credentials"] + UPDATE["4. Automation commits translations to the same PR
generated/zh-CN.json + generated/zh-TW.json
an exact-head lease rejects a moved branch"] + CHECK["5. The same PR reruns strict checks and review
localization:catalogs:check
keys • ICU • placeholders • protected literals"] + MERGE["6. A maintainer merges the complete review unit
same-repo: English + translations together
fallback: generated follow-up after English"] + SHIP["7. The owner artifact ships
the catalog becomes available to that surface"] + RENDER["8. The owner renders at its presentation edge
LocalizationContext(locale = zh-CN)
为 openclaw 启用 zsh shell completion?"] + FORK["Fork or cross-repository source PR
merge reviewed English first
trusted main refresh opens one generated follow-up PR"] + FAIL["Failure or rejection
publish nothing • English fallback stays live
target cells remain partial and visible"] + + EN --> DETECT --> ACTION --> UPDATE --> CHECK --> MERGE --> SHIP --> RENDER + EN -. cannot update source branch .-> FORK --> CHECK + ACTION -. generation or validation fails .-> FAIL + CHECK -. checks or review reject .-> FAIL ``` -English is the source locale and the other 21 are translation targets. Every -locale is registered by the minimal foundation, but completeness remains -measured per surface. -For example, Swedish begins with native-app coverage and remains unsupported on -other surfaces until their catalogs exist. OpenClaw must not claim full -22-locale product coverage -until every product-owned surface is complete for every target locale. - -This is a baseline, not a claim of comprehensive world-language coverage. It -has strong East Asian coverage through Simplified Chinese, Traditional -Chinese, Japanese, and Korean; partial South and Southeast Asian coverage -through Hindi, Indonesian, Thai, and Vietnamese; and two right-to-left -languages through Arabic and Persian. It does not yet cover several major -language communities, including Bengali, Urdu, Tamil, Telugu, Malay, Filipino, -Hebrew, or Swahili. - -Engineering coverage is broader than the release-locale list. The conformance -suite must exercise representative direction, script, shaping, segmentation, -plural, expansion, and interpolation behavior. The initial set already covers -Latin, Cyrillic, Arabic-derived scripts, Simplified and Traditional Han, -Japanese, Hangul, Devanagari, and Thai. Additional fixtures should cover Hebrew -RTL behavior, another major Indic script, Khmer or Myanmar segmentation, and -Ethiopic shaping even before OpenClaw has owned translations for those -languages. - -A representative fixture or pseudo-locale is not a supported-language claim. -New user-visible locales still require demand, language ownership, and review -capacity. - -The contract is not limited to 22 locales, but RFC 0024 does not adopt an -external product's language list or set a locale-count goal. OpenClaw adds a -release locale when it has user demand, catalog ownership, review capacity, -fallback behavior, direction and formatting support, and an explicit initial -maturity state. Pseudo-locales remain useful test assets for expansion, -interpolation, truncation, and right-to-left behavior. - -### Required localization depth - -OpenClaw localization follows the user journey rather than one frontend: - -| Experience | Required product-owned surfaces | +| Point in the path | Actual value | | --- | --- | -| Discover and install | Documentation, installation guidance, first-run failures | -| Configure and onboard | CLI wizard, channel and plugin setup, validation and recovery guidance | -| Operate | CLI and TUI help/status, Control UI, native apps, configuration and task output | -| Interact | Server-rendered channel messages, notifications, command menus, and core/bundled command and skill metadata | -| Approve and recover | Approval prompts, Gateway errors, authentication failures, doctor and repair guidance | - -Logs, protocol codes, command tokens, config keys, paths, IDs, provider/model -names, upstream prose, and model-generated responses are not part of the -product-localization completeness claim. - -A locale is product-complete only when all required product-owned surfaces are -complete. OpenClaw should deepen coverage for the existing locale set before -adding languages that are present only in one catalog. - -### Translation production and review - -OpenClaw already uses model-assisted automation to refresh Control UI, native -app, and documentation catalogs. That is an authoring pipeline, not runtime -translation: deterministic product text is generated into reviewed, -version-controlled catalogs before release. - -The current implementation is already partially shared: - -- `openclaw/docs` orchestrates documentation translation and publication, but - checks out an exact `openclaw/openclaw` source revision and runs the - source-owned `scripts/docs-i18n` translator; -- native translation imports the Control UI translation client instead of - maintaining another provider implementation; and -- docs, Control UI, and native workflows use aligned provider-secret naming - and source-pinned execution. - -RFC 0024 formalizes that alignment without creating another repository or -translation service. Every generated translation run emits the same bounded -evidence: - -```text -source repository + exact source revision -+ locale + source/glossary revisions -+ generator/workflow + provider/model identity -+ generated artifact revision + validation result --> reviewable candidate translation evidence -``` - -Owner workflows keep their native extraction and publication models. Docs -continue publishing through `openclaw/docs`; Control UI, native, CLI/TUI, and -runtime catalogs publish through their owning `openclaw/openclaw` workflows. -Safety catalogs may use the same candidate-generation evidence while retaining -stricter review and auto-merge policy. - -Model-generated output does not establish completeness by itself: - -- generated catalogs retain source, workflow, model/provider, glossary, and - revision provenance where the surface supports it; -- key, placeholder, fallback, and generated-artifact checks remain mandatory; -- approval, authentication, authorization, destructive-action, privacy, and - recovery text requires full human review in each complete locale; -- lower-risk generated copy may use owner-defined linguistic sampling, but a - named language owner remains accountable for the completeness claim; and -- runtime model calls must not translate deterministic product messages. - -OpenClaw extends its existing Control UI, native-app, and docs refresh -automation into one continuous catalog-maintenance contract: - -1. **Detect:** trusted CI compares English source revisions with registered - target catalogs and reports missing, fallback, or stale entries. -2. **Refresh:** a trusted `main`, scheduled, or manually dispatched workflow - uses an approved model/provider and glossary to generate candidate locale - artifacts. -3. **Validate:** key, placeholder, protected-literal, formatting, script, - direction, fallback, and generated-artifact checks run before publication. -4. **Publish:** the generated changes are committed to a reviewable automation - branch and opened or updated as a pull request through the existing - generated-PR application flow. -5. **Enforce:** CI blocks a `complete` claim while source drift, fallback, - missing artifacts, or required review remains unresolved. - -Validate and publish are sub-steps of the trusted refresh phase. Failed -generation or validation aborts publication and leaves the detected drift -visible. Detection and enforcement failures fail closed. - -Translation-provider credentials never run against untrusted pull-request -code. Pull requests run deterministic detection and enforcement only. AI fills -candidate gaps; it does not approve its output or change maturity by itself. - -The projected registry names the reusable implementation proof explicitly: -`G45` installs the owner-scoped deterministic authoring/drift gate, `G46` -installs the trusted asynchronous refresh-to-generated-PR lane, and `G47` -prevents newly introduced product-string surfaces from remaining unclassified. -The first two begin with one routine core exemplar; existing Control UI, native, -and docs owners keep their current workflows, while later CLI/TUI/runtime owners -adopt the reference contract without surrendering catalog or review ownership. - -`G47` is a build-time adoption gate, not a heuristic scan of every string -literal. Owner adapters enumerate product-surface registrations or declared -product-facing source roots. A newly added scope must identify its semantic -owner and either enroll in the catalog contract, point to a conforming existing -pipeline, or record an explicit English-only, platform-constrained, or deferred -disposition with rationale. Existing unclassified scopes are baselined as -legacy backlog; tests, logs, developer diagnostics, and model-authored text do -not become product surfaces merely because they contain strings. - -After that exemplar lands, each slice that adds or migrates deterministic -product strings brings its area fully onto the contract: a blocking, -credential-free gate for its declared scope plus a trusted owner-owned refresh, -validation, evidence, and generated-PR path. Existing Control UI, native, and -docs workflows may demonstrate conformance instead of being replaced. - -## Goals - -- Define one BCP 47-compatible locale identity and alias contract. -- Make the existing 22-locale OpenClaw union the concrete v1 baseline. -- Define product-wide localization depth across OpenClaw's user journey. -- Define deterministic locale-resolution precedence for UI, CLI, channel, and - server-rendered messages. -- Define structured user-facing message descriptors with stable keys, typed - parameters, and required English fallback. -- Preserve stable protocol codes, command names, config keys, IDs, paths, - provider IDs, model IDs, and code blocks as untranslated literals. -- Extend Gateway errors compatibly so capable clients can localize known - failures without breaking existing clients. -- Localize exec approval and other safety messages without allowing - translations to alter executable commands or decision tokens. -- Define locale-keyed command and skill metadata that channels and UI surfaces - can project. -- Keep catalogs current through trusted AI-assisted generated pull requests and - a deterministic detect/refresh/enforce drift gate. -- Share one source-pinned translation-run evidence contract across docs, - Control UI, native, CLI/TUI, runtime, channel, and metadata workflows without - forcing one extractor, catalog format, or publication policy. -- Keep model-generated content language separate from product UI localization - so it can use the locale registry in a post-v1 extension without blocking the - runtime localization contract. -- Define owner-published surface declarations, a checked-in generated - surface/locale coverage manifest, and CI checks for key parity, placeholders, - untranslated fallback, and hardcoded product text. -- Preserve the existing Control UI, native-app, docs, and onboarding pipelines - and migrate them incrementally. -- Produce a dependency-ordered implementation plan of small reviewable slices. - -## Non-Goals - -- Translate logs, stack traces, protocol traces, or developer-only diagnostics. -- Translate model/provider names, plugin IDs, tool names, command tokens, - config keys, paths, URLs, or opaque external-service errors. -- Infer the preferred language of model-generated content solely from the UI - locale. -- Require one file format or localization library for every surface. -- Load executable translation logic or unsigned remote catalogs at runtime. -- Replace platform-native string catalogs on Apple or Android. -- Translate community plugin or skill content without publisher participation. -- Claim that machine translation alone is sufficient for safety, security, or - high-quality release localization. -- Complete every locale in one pull request. -- Implement generated-content language selection in v1. - -## Proposal - -### Product localization model - -OpenClaw distinguishes four categories: - -| Category | Examples | Localization rule | -| --- | --- | --- | -| Product-owned text | UI labels, CLI help, approval labels, known validation guidance | Must use a stable message key at a supported rendering boundary. | -| Stable machine identity | Error codes, command names, config keys, provider IDs, model IDs | Never translated. | -| User or operator data | Paths, workspace names, commands, agent names, user text | Preserved literally, with escaping appropriate to the renderer. | -| External or generated prose | Provider errors, model output, third-party plugin text | Preserved or safely summarized; not silently machine-translated by core. | - -This classification prevents localization from weakening protocol stability or -changing executable content. - -### Localization-ready ownership - -Localization separates ownership rather than transferring it to localization -core: - -- the semantic owner defines the message meaning, stable key, allowed - parameters, reviewed English fallback, and any safety or recovery semantics; -- the rendering owner selects the legitimate locale context, owns the catalog - and renderer, and preserves literal values and platform constraints; -- localization core owns generic context, validation, fallback, and rendering - primitives, but does not invent message meaning or recipient locale; and -- the coverage owner aggregates owner-published evidence without becoming the - source of message or translation truth. - -One team may fill multiple roles, but every adopted message family or surface -must identify them explicitly. A renderer must not reinterpret an error, -decision, finding, status, or recovery action merely to make it translatable. - -A localization-ready adoption has: - -1. a named semantic owner and authoritative descriptor-construction boundary; -2. a named rendering/catalog owner and authoritative locale-resolution - boundary; -3. stable machine identity, typed parameters, and a reviewed English fallback - template rendered by the same edge renderer as translated templates; -4. one immutable locale context and catalog snapshot per operation; -5. explicit literal, presentation, sensitivity, and safety classification; -6. locale-invariant codes, commands, decisions, structured output, and policy; -7. deterministic accepted, fallback, invalid-input, and rollback behavior; -8. compatibility proof for every affected protocol or automation consumer; -9. coverage and required human-review evidence bound to the exact message - family, source, locale-specific reviewed-content, and review-policy - revisions; and -10. deletion of the hardcoded, duplicated, parsed-prose, or edge-invented - presentation path that the descriptor replaces. - -Each implementation slice records this evidence in its PR description, focused -fixture, or owner-local design note. This is review evidence, not a runtime -registry or new manifest schema. - -Stop rather than broaden the localization framework when: - -- no semantic owner can approve a stable meaning and parameter schema; -- no legitimate recipient or operator locale is available; -- a generic exception or external prose has no bounded product-owned - descriptor; -- required safety or linguistic review is absent; -- compatibility requires changing stable machine output; or -- the old presentation authority cannot be removed or clearly bounded. - -In those cases OpenClaw preserves stable machine output and reviewed English -fallback, records the surface as incomplete where applicable, and leaves the -underlying operation unchanged. - -### Locale identity and compatibility - -Locale identifiers follow BCP 47. OpenClaw maintains a central registry of -supported locale IDs, aliases, display names, fallback chains, writing -direction. The coverage manifest is the sole source of per-surface availability -and maturity. - -V1 keeps `zh-CN` and `zh-TW` as canonical IDs and accepts `zh-Hans` and -`zh-Hant` as aliases. A future canonical-ID change requires a separate -compatibility proposal with stored-preference, environment, config, and plugin -metadata migration; it is not part of RFC 0024. - -An unknown locale in a validated config field, request field, or core/bundled -package manifest is an actionable validation error. A stale stored user -preference is nonfatal: the surface records a bounded finding, follows normal -precedence, and exposes a reset path. -External package localized metadata may use exact valid BCP 47 tags under its -package-owned rules without extending the product registry. Browser, -operating-system, and host process locales are inferred inputs: they fall -through language defaults and registered aliases without failing startup. -`OPENCLAW_LOCALE` remains an explicit nonfatal override: an unsupported value -produces a diagnostic and reviewed English fallback rather than silently using -a lower-precedence host locale. - -### Locale context and precedence - -Localization is resolved at the rendering edge, not in deep business logic. -Each renderer receives a resolved locale context with provenance: - -```ts -type LocalizationContext = { - locale: string; - fallbackLocales: readonly string[]; - source: - | "explicit-user" - | "explicit-recipient" - | "request" - | "surface-preference" - | "operator-default" - | "platform" - | "english-default"; - audience: "user" | "operator"; -}; -``` - -The general precedence is: - -```text -explicit user or recipient preference -> explicit request/session locale -> persisted surface preference -> operator default -> process/browser/platform locale -> English -``` - -Each surface documents which inputs it can legitimately observe. A Gateway -must not guess a channel recipient's locale from message text. A Control UI -selection must not silently change the language of model-generated content. - -V1 server-rendered channel messages use a recipient locale only when the -surface already has an explicit recipient/account preference or the request -carries an owner-approved validated locale. Until an owner approves a new -preference store, all other channel recipients receive reviewed English -fallback. Locale is never inferred from message text, user name, phone number, -channel identity, IP geography, or model output. - -The existing optional Gateway `ConnectParams.locale` belongs to the connected -client experience. It can describe the Control UI connection that supplied it, -but it does not establish the locale of a separate channel recipient or -approval reviewer. - -The RFC introduces the context contract. Any new config key, request field, -plugin field, or channel preference store remains a separately reviewable -public surface and requires the owning maintainer's approval. - -`audience=user` covers end-user chat, approval, and interactive UI text. -`audience=operator` covers human-readable CLI status, health, recovery, and -administrative guidance. Logs and machine-readable output are not localized by -either audience. - -One user-visible operation captures one immutable context at its owning surface -entry point and passes that context through every nested renderer. A CLI command -must not re-read process locale variables in each helper, and a request renderer -must not change locale midway through one response. Compatibility defaults for -shared helpers may resolve a context only when no owning entry point can inject -one; production orchestration must inject the captured context. - -### Foundational localization kernel - -The first implementation slice introduces one small internal localization -kernel at the lowest dependency layer shared by browser and server code. The -exact package path is an implementation decision, but the kernel owns: - -- locale registration, normalization, aliases, inferred matching, fallback, - display names, and direction; -- immutable `LocalizationContext`; -- the `LocalizedMessage` and scalar parameter types; -- catalog lookup and reviewed English fallback; -- ICU message parsing and formatting delegated to `intl-messageformat` for - shared JavaScript and TypeScript runtime catalogs; -- key, parameter, namespace, and catalog validation primitives; and -- renderer-safe bidirectional isolation helpers for literal data. - -The kernel is synchronous after startup, browser-safe, server-safe, and free of -filesystem, network, environment, storage, translation-provider, and model -dependencies. It has no process-global current locale. Callers pass an -immutable context into lookup or rendering. - -Surface adapters depend on the kernel: +| English source PR | `"wizard.completion.enable": "Enable {shell} shell completion for {cli}?"` | +| PR gate | Fails with `zh-CN/wizard-core` and `zh-TW/wizard-core` stale | +| Trusted action | Maintainer dispatch against the ready same-repository, default-base PR's resolved exact head | +| In-place update | `"wizard.completion.enable": "为 {cli} 启用 {shell} shell completion?"` plus source-pinned evidence is committed to the source PR | +| Shipped runtime output | After that PR merges and the owner artifact ships, `t("wizard.completion.enable", { shell: "zsh", cli: "openclaw" })` → `为 openclaw 启用 zsh shell completion?` | + +The checked-in `zh-CN` exemplar is marked `bootstrap-reviewed` with a human +provider. The first credentialed in-place refresh is therefore still a +supervised rollout gate. Once that gate succeeds, no contributor manually +creates translation commits: the failing check tells them to request the +trusted action, automation updates the same branch, and the check turns green. +Fork and cross-repository sources use the post-merge generated-PR fallback. +The same control loop applies to every one of the 15 +product surfaces, but not necessarily through the same files or workflow name: +Control UI, native, and docs keep their conforming owner workflows. + +## Product target + +RFC 0024 starts with the union of locales already shipped by OpenClaw: ```text -Control UI adapter -CLI/runtime adapter -Gateway wire projection -channel message renderer -command/skill metadata projection - | - v -internal localization kernel -``` - -The dependency never points from the kernel back into a surface. Existing UI, -native-app, documentation, and wizard catalogs remain surface-owned. The slice -proves the kernel through one selected existing consumer plus browser/server -conformance fixtures; it does not land a type-only framework. - -This is not a public localization-provider plugin API in v1. Translation -providers remain build-time authoring tools. A public plugin seam is considered -only when external package requirements cannot be met by namespaced catalogs -and localized metadata. - -### Structured localized messages - -Known product-owned runtime messages use descriptors: - -```ts -type LocalizedMessage = { - key: string; - params?: Readonly>; - fallback: string; -}; -``` - -This is the single internal descriptor. Gateway `message` plus optional -`details.localization` metadata are a compatibility wire projection of it, not -a second message model. Both projections use the same key and parameter -validator. - -The key is stable machine identity for catalog lookup, telemetry, tests, and -coverage. `fallback` is a reviewed English template for old clients, missing -translations, diagnostics, and emergency recovery. The renderer interpolates -that template with the same validated parameters and literal-isolation rules as -a translated template; descriptor construction sites never pre-render it. -Parameters are literal values; translators cannot introduce executable tokens -or reinterpret parameter types. - -Not every enum-like value is literal product identity. Product-owned -presentation categories such as install-kind labels, update-kind labels, status -names, and other human classifications must use catalog-backed labels or a -catalog `select`. Passing raw values such as `package` into otherwise translated -prose creates mixed-language output and is non-conforming. Stable protocol -codes, reason codes, command tokens, IDs, paths, versions, and raw upstream -errors remain literal. - -Catalogs must validate: - -- key presence and uniqueness; -- placeholder name and type parity with English; -- locale and alias validity; -- forbidden or unknown markup; -- preserved literal tokens where required; and -- deterministic fallback. - -Complex safety output is assembled from translated labels and literal -structured parts. Translators do not own Markdown fences, slash commands, -approval IDs, shell commands, or decision tokens. - -### Gateway error compatibility - -Gateway errors retain the current `code` and English `message` fields. Known -user-facing errors may add optional localization metadata: - -```ts -type ErrorShape = { - code: string; - message: string; - details?: { - localization?: { - messageKey: string; - messageParams?: Record; - }; - [key: string]: unknown; - }; - retryable?: boolean; - retryAfterMs?: number; -}; +en, zh-CN, zh-TW, pt-BR, de, es, ja-JP, ko, fr, hi, ar, +it, tr, uk, id, pl, th, vi, nl, fa, ru, sv ``` -Localization metadata uses the existing opaque `details` envelope because -supported strict validators reject additive top-level error fields. Old clients -continue to show `message`. New clients localize recognized -`details.localization.messageKey` values when they have a matching catalog and -fall back to `message` otherwise. Clients must not branch on translated text. -Server-rendered channel messages use the same descriptor with the recipient's -resolved locale context. - -Producer and client share one reviewed message-key registry. Metadata is -bounded to 16 flat scalar parameters, 64-character parameter names, -4096-character string values, and finite numeric values. Each key declares an -allowed parameter schema and sensitivity classification. Projection is -idempotent and never overwrites existing localization metadata. - -Unknown exceptions remain sanitized English fallbacks. This RFC does not make -arbitrary exception strings translatable. - -### Safety-message rendering - -Exec approvals are the first runtime slice. The current renderer already has -structured values for approval ID, command, decisions, host, node, CWD, and -expiry. - -The localized renderer must: - -- translate labels and explanatory prose; -- preserve `/approve`, decision tokens, IDs, commands, paths, and code blocks; -- preserve the same allowed-decision set and ordering; -- produce the current English output for English and fallback; -- avoid locale-sensitive parsing of the rendered result; and -- pass the same payload through all channel routes. - -If the selected safety message family is missing, invalid, incomplete, or lacks -the required scoped human-review attestation, the renderer uses one reviewed -English snapshot for the complete approval presentation. It does not mix -translated labels with English fallback fragments. - -Security-sensitive copy requires human review for each release-complete locale. -Machine-generated translation can seed drafts but cannot alone mark the -security surface complete. - -Security catalogs reject translator-authored Unicode bidirectional controls, -including direction marks, embeddings, overrides, isolates, and deprecated -formatting controls. Renderers own the minimum Unicode isolation around literal -commands, IDs, paths, numbers, and decision tokens when surrounding text is -right-to-left. Legitimate script characters are not rewritten or removed. - -### Catalog ownership - -This RFC does not create a monolithic catalog: - -- Control UI continues to own its TypeScript locale bundles. -- Apple and Android continue to use native generated catalogs. -- Docs continue to use the docs translation workflow and glossaries. -- Documentation orchestration and generated locale trees remain in - `openclaw/docs`, while the source-pinned translator implementation remains - owned by `openclaw/openclaw`. -- CLI and server-rendered runtime messages use core runtime catalogs. -- Bundled plugins may use namespaced runtime catalogs through an internal - activation adapter. -- External plugins and skills may package localized display metadata. - -Shared infrastructure owns locale IDs, aliases, fallback, message descriptor -validation, placeholder rules, and coverage reporting. - -The intended extension path lets external plugins package declarative, -namespaced runtime catalogs that are validated and activation-pinned with the -plugin snapshot. Plugins cannot override core or another plugin's namespace, -register a translation provider, mutate global catalogs after activation, or -make runtime model calls for deterministic product text. - -That external runtime-catalog seam is post-v1. V1 external support is localized -metadata only while bundled plugins prove the catalog mechanism. Any future -public manifest field or Plugin SDK registration method is a new semi-public -surface requiring explicit plugin-owner approval. - -Catalog keys are namespaced by owner, for example: +This is 22 locales, not 22 translated languages: English is the source and the +other 21 are translation targets. The current portfolio has 15 required +product surfaces, so the terminal target is: ```text -core.approvals.exec.required -core.gateway.invalidRequest -cli.agent.messageFile.empty -plugin.memory-core.dreaming.journal.title +15 required surfaces × 21 translation targets = 315 target cells ``` -Keys describe stable meaning, not English wording or source line. - -### Localized command and skill metadata +Every cell reports `complete`, `partial`, `experimental`, +`platform-constrained`, or `unsupported`. Only `complete` counts toward the +full product claim. A constraint can explain an incomplete cell but cannot +silently remove it from the denominator. -Command names remain stable literals. Command descriptions may provide a -locale-keyed map: - -```ts -type LocalizedText = { - default: string; - localizations?: Record; -}; -``` +The 22-locale registry is a v1 baseline, not a permanent cap or a claim of +world-language coverage. Adding a locale requires demand, catalog ownership, +review capacity, fallback behavior, direction and formatting support, and an +explicit initial maturity state. -The command catalog proposed by RFC 0017 is the preferred owner for command -identity and description metadata. Discord, Telegram, Control UI, TUI, and CLI -help project the same catalog through platform-specific locale capabilities. - -Skill manifests may use the same `LocalizedText` shape for display name and -description. Package IDs, folder names, invocation names, and tool identifiers -remain unchanged. Unknown locale keys fail package validation or are excluded -with an explicit finding; they are never silently treated as executable names. - -### Post-v1 generated content language - -Product localization and generated content language are related but distinct. -Features such as Dreaming may accept an explicit content-language preference, -but must not assume that a German UI means memories or assistant replies should -be rewritten in German. - -The first generated-content contract is: - -- an explicit feature or workspace content-language input; -- a stable BCP 47 value with the same alias registry; -- no automatic translation of existing user content; -- no change to product UI locale; and -- clear provenance in generated artifacts when language affects output. - -This contract is not required for v1 acceptance. It allows later Dreaming work -to reuse locale identity without coupling model behavior to the Control UI -language selector. - -### Coverage manifest and release claims - -Localization core defines the generic manifest schema, maturity semantics, -derived checks, and promotion-blocker rules. It does not enumerate every UI, -channel, plugin, skill, native, or documentation surface. - -Each product owner may publish a build-time declaration once it has an adopted -message family or artifact. The declaration contains its stable surface ID, -owner, artifact, source/catalog paths, migration state, validation command, -message-family classifications, and locale artifact discovery. A root product -aggregator includes every declaration, orders the generated report -deterministically, and fails on duplicate surface IDs or order claims. Adding a -new owner surface changes its declaration and the product portfolio, not the -generic localization-core validator. - -The product aggregation layer may check in a generated localization coverage -manifest describing: - -- supported locales and aliases; -- locale maturity; -- required human review for safety surfaces; -- surface ownership; -- source and generated catalog paths; -- key counts and fallback counts; -- required validation commands; -- catalog revision identity; and -- whether a locale/surface combination is `source`, `complete`, `partial`, - `experimental`, `platform-constrained`, or `unsupported`. - -CI produces a localization report and enforces: - -- key and placeholder parity; -- valid locale IDs and aliases; -- no missing required English source strings; -- no untranslated English fallback in a `complete` locale unless allowlisted; -- deterministic generated artifacts; -- locale-change test isolation; -- advisory hardcoded-string inventory initially; and -- blocking hardcoded-string checks only for explicitly migrated message - families, key namespaces, or narrowly owned directories. - -OpenClaw must not advertise a surface as complete for a locale unless the -manifest and checks support that claim. - -### Locale-safe runtime behavior - -Program logic must not match localized operating-system or dependency prose -when a code, exit status, structured field, or deterministic probe is -available. Locale-sensitive parsing is tracked separately from translation -coverage but reported by the same program because it breaks localized hosts. - -### Migration and compatibility - -Migration is incremental: - -1. Add shared contracts without changing output. -2. Capture one immutable locale context at the owning surface entry. -3. Confirm the semantic owner, rendering owner, and authoritative descriptor - and locale-resolution boundaries. -4. Give current English messages stable keys and descriptors. -5. Classify every parameter as literal data or product-owned presentation, - including sensitivity and safety treatment. -6. Localize one bounded renderer without changing structured output. -7. Add optional protocol metadata where the owner approves it. -8. Prove accepted, fallback, compatibility, privacy, and rollback behavior. -9. Delete or explicitly bound the superseded hardcoded or duplicated - presentation path. -10. Migrate clients and surfaces and raise coverage gates by owned message - family, key namespace, or narrowly owned directory. - -English remains the source and compatibility fallback. Existing locale IDs, -environment variables, persisted preferences, Gateway error messages, command -names, and plugin manifests remain valid until an explicit migration is -accepted. - -Every migrated renderer retains an emergency English-fallback path. A bad -translation can be removed or the affected key can fall back to English without -changing error codes, action semantics, or the underlying operation. Invalid -core catalogs fail the owning artifact build; invalid optional plugin catalogs -are rejected without disabling unrelated core catalogs. - -### Implementation evidence and refinements - -The five foundation drafts have provided cross-cutting implementation evidence -across the shared kernel, runtime safety, process-scoped CLI/TUI rendering, -updater and service presentation, Gateway/UI errors, channel approvals, -metadata, native/docs convergence, RTL interpolation, and product-level release -reporting. - -The evidence changed the implementation guidance in these concrete ways: - -- locale resolution occurs once per command or request and the immutable - context is threaded through nested rendering boundaries; -- exact reviewed English remains the compatibility default for existing shared - callers while localized production entry points inject their context; -- human presentation and structured automation payloads are separate - projections of the same operation, so localization cannot rewrite JSON - fields, status/reason codes, or stable arrays; -- commands, flags, paths, IDs, PIDs, versions, stderr, and upstream error text - remain literal, while product-owned wrappers and labels are localized; -- raw internal enums are not automatically literal: when they appear as human - labels, they require catalog-backed presentation names; -- partial locale support remains reported as partial even when a migrated - command group has complete English and Simplified Chinese catalogs; and -- service, plugin, Gateway, channel-recipient, and safety-copy ownership - boundaries remain separate slices rather than being hidden inside a broad - extraction change; -- Gateway localization descriptor identities are shared from - `packages/gateway-protocol` rather than imported from private Gateway source; - and -- the 15-surface release portfolio is composed from owner/domain declarations - while localization-core remains generic and accepts future valid surface IDs. -- documentation translation already consumes an exact source revision and - source-owned translator from `openclaw/openclaw`, while native reuses the - Control UI translation client; completion work should standardize their run - evidence rather than introduce another translation service. - -The current product-policy snapshot contains 15 English source rows plus 15 -owner-declared surfaces across 21 translation targets. Release completion is -calculated over those 315 translation-target cells. Independent owner cohorts -may fill the remaining cells. The terminal product target is all 313 -OpenClaw-controlled target cells complete, with `docs/fa` and `docs/th` either -completed through an approved publishing path or disclosed as the only -external platform constraints. - -Conformance tests for a migrated renderer therefore include exact English -compatibility, one non-English rendering, protected-literal preservation, -structured-output equality across locales, unsupported-locale fallback, and a -mixed-language interpolation case for product-owned presentation labels. - -## Rationale - -### Why render at the edge - -Deep exception sites often do not know the recipient, user preference, or -surface. Passing translators through all core logic would couple business logic -to presentation and make logs harder to diagnose. Stable descriptors preserve -meaning until the final renderer has legitimate locale context. - -### Why preserve English messages - -Gateway clients, scripts, screenshots, support workflows, and logs already -observe English `message` values. Optional localization metadata provides a -gradual migration path and keeps old clients usable. - -### Why one formatter does not imply one localization system - -Control UI, Swift, Kotlin, docs tooling, CLI, and server-rendered channel -messages have different build and runtime constraints. Shared semantics are -more valuable than forcing one file format. The shared JavaScript and -TypeScript runtime kernel uses `intl-messageformat` for ICU formatting instead -of maintaining a custom formatter, while native, UI, and documentation owners -retain their existing formats and publication workflows. - -### Why typed parameters and stable keys - -Unicode MessageFormat demonstrates the value of separating message identity, -variables, and language-specific rendering. OpenClaw v1 stores ICU message -strings and delegates parsing and rendering to `intl-messageformat`. OpenClaw -still validates a deliberately bounded v1 profile: scalar parameters, simple -interpolation, and at most one top-level plural or select. Nested selectors and -general number/date formatting remain future extensions. - -### Why BCP 47 aliases rather than renaming immediately - -BCP 47 supports language, script, and region subtags, but shipped identifiers -also become compatibility data. Aliases allow OpenClaw to improve semantic -accuracy without invalidating environment variables, stored preferences, or -plugin metadata. - -### Why coverage is part of the RFC - -Locale files alone do not prove a localized product. Missing keys, English -fallback, untranslated server messages, stale generated assets, and test -isolation failures all produce incomplete experiences. A product-level claim -needs a product-level report. - -The RFC standardizes the meaning of maturity and evidence. The current surface -portfolio, reviewer roster, completion schedule, and generated report layout -remain delivery and release policy so they can evolve without changing the -runtime contract. - -## Unresolved questions +## Decision -- Which owner approves the first public locale preference surface for +RFC 0024 establishes six rules: + +1. **One locale context.** Each user-visible operation captures one immutable + `LocalizationContext` at its owning presentation edge. Explicit user or + recipient preference outranks request, surface, operator, and platform + inference; unsupported values fall back safely to English. +2. **Stable product messages.** Product-owned text uses a stable key, typed + literal parameters, and a reviewed English fallback. Shared JavaScript and + TypeScript rendering delegates ICU formatting to `intl-messageformat`. +3. **Surface ownership.** The presenting surface owns message meaning, + catalogs, rendering, translation workflow, and review. Shared core owns + locale, validation, fallback, and evidence semantics—not product copy. +4. **Machine semantics never change.** Error codes, commands, config keys, + IDs, paths, structured output, user data, upstream prose, and model output + remain literal. +5. **Compatibility is additive.** Known Gateway errors keep their stable code + and reviewed English `message`; owner-approved messages may add bounded + `details.localization` metadata that capable clients render and old clients + ignore. +6. **Coverage is evidence-based.** Every adopted surface publishes inventory, + validation, catalog revision, maturity, and required-review evidence. A + release claim is generated only from landed owner declarations. + +The exact runtime types, validation bounds, locale precedence, Gateway wire +shape, metadata fields, maturity meanings, and conformance requirements live +in the linked normative sidecar specifications. + +## What gets localized + +| Content | Rule | +| --- | --- | +| Product-owned presentation | Localize through a stable key at the owning renderer. | +| Product-owned labels and enum presentation | Use catalog labels or ICU `select`; do not leak raw English labels. | +| Codes, commands, config keys, IDs, paths, URLs, versions | Preserve literally. | +| User/operator data and executable content | Preserve literally with renderer-safe isolation. | +| Provider errors, third-party prose, model output | Preserve or safely summarize; never silently runtime-translate. | +| Logs, traces, and developer diagnostics | Outside the product-localization claim. | + +Safety-sensitive families such as approvals, authentication, authorization, +destructive actions, privacy, and recovery require scoped human review before +a locale can be complete. If a required safety catalog is missing, invalid, or +unreviewed, the whole presentation falls back to one reviewed English snapshot +rather than mixing languages. + +## How delivery works + +The project uses shared per-repository gates and workflows, not a new gate or +translation system for every slice: + +1. Land the locale/context/runtime foundation and one real consumer. +2. Enroll one owner surface by updating its source, inventory, catalog or + conforming-pipeline disposition, and owner guidance in the same slice. +3. Run credential-free detection on pull requests; fail a ready + same-repository PR targeting the default branch when its adopted source + makes targets stale. +4. Let the maintainer-authorized owner workflow update that same PR from + trusted tooling, or open one post-merge generated PR when it cannot update + the source branch. +5. Validate keys, placeholders, protected literals, provenance, formatting, + fallback, and required human review. +6. Land the source and generated artifacts, then update the coverage report. + +The source and generated catalogs normally share one PR. Fork and +cross-repository paths may use a separate generated-catalog PR, but the +adoption slice is not complete until all required artifacts and review land. +Translation credentials never run against pull-request code, and AI-generated +copy never approves itself. + +The current source audit contains 47 projected slices grouped into 16 +dependency-safe delivery packages, with a product-completion decision targeted +for September 1, 2026. These are planning units, not 47 required PRs or runtime +identifiers. Slices may combine or split at owner and publication boundaries. +The live delivery state is tracked in +[openclaw#113105](https://github.com/openclaw/openclaw/issues/113105). + +## Completion milestones + +1. **Architecture accepted:** locale, ownership, fallback, compatibility, and + coverage contracts are approved. +2. **Foundation shipped:** the shared kernel, reusable gates, trusted refresh, + inventory, and one end-to-end consumer are landed and supervised. +3. **Owner cohorts complete:** each required surface adopts the contract or + proves its existing pipeline conforms, with generated catalogs and review. +4. **Product claim promoted:** all 315 target cells are complete. Any remaining + partial, unsupported, deferred, or constrained cell blocks the unqualified + 22-locale product claim. + +## Compatibility boundaries + +- Existing English output, locale IDs, environment variables, stored + preferences, Gateway error fields, command names, and plugin manifests remain + valid unless a separately approved migration changes them. +- `zh-CN` and `zh-TW` remain canonical in v1; `zh-Hans` and `zh-Hant` are + accepted aliases. +- The optional Gateway `ConnectParams.locale` describes that connected client; + it does not establish a different channel recipient's or approval reviewer's + locale. +- Server-rendered channel text stays English until its owner has a legitimate + recipient locale source. +- Existing Control UI, native, docs, and wizard pipelines are preserved and + brought under the shared evidence contract rather than replaced. +- A bad or withdrawn translation falls back to English without changing the + underlying operation or machine-readable result. + +## Non-goals + +- Bulk-extract every string, exception, or log. +- Translate at runtime with a model. +- Translate commands, codes, identifiers, structured output, or executable + content. +- Force one catalog format or renderer on UI, native, docs, CLI, and channels. +- Create a public external-plugin runtime catalog API in v1. +- Treat generated translation as linguistic or safety approval. +- Couple model-generated content language to the product UI locale. + +## Unresolved owner decisions + +- Who approves the first public recipient-locale preference for server-rendered channel messages? -- How should third-party plugin catalogs declare review quality and fallback - without implying OpenClaw endorsement? -- What human-review standard is required before approval, authentication, or - destructive-operation text is marked complete? -- Who owns the named reviewer roster for all 21 translation targets? -- Do Persian and Thai documentation use another publishing path, or remain - explicit external platform constraints? +- What review standard and reviewer roster are required for safety-sensitive + copy in all 21 translation targets? +- How should third-party localized metadata report review quality without + implying OpenClaw endorsement? +- Which publishing path completes Persian and Thai documentation catalogs? diff --git a/rfcs/0024/implementation-plan.md b/rfcs/0024/implementation-plan.md index 9ccf979f..52fff99f 100644 --- a/rfcs/0024/implementation-plan.md +++ b/rfcs/0024/implementation-plan.md @@ -17,12 +17,13 @@ follow-up review added the new-surface adoption gate as `G47`. The number is not fixed. Source audit may delete, split, or add entries without changing the runtime contract. -## Existing Drafts +## Existing Implementation PRs -The five current drafts have been reduced to bounded intended deltas. They -remain draft implementation evidence until their named owners approve them: +The five current implementation PRs have been reduced to bounded intended +deltas. They remain implementation evidence until their named owners approve +and land them: -| Registry entry | Draft | Intended review delta | Delivery disposition | +| Registry entry | PR | Intended review delta | Delivery disposition | | --- | --- | --- | --- | | `F01` | [#111541](https://github.com/openclaw/openclaw/pull/111541) | Minimal kernel and onboarding consumer | Land only after core and wizard owner review; no coverage or public metadata contract. | | `F02` | [#111542](https://github.com/openclaw/openclaw/pull/111542) | Updater human dry-run preview | Preserve JSON and operational literals; updater owner approves the final edge. | @@ -30,7 +31,7 @@ remain draft implementation evidence until their named owners approve them: | `F04` | [#111544](https://github.com/openclaw/openclaw/pull/111544) | TUI status summary and relative ages | Keep other TUI, CLI, Gateway, metadata, and channel families separate. | | `F05` | [#111545](https://github.com/openclaw/openclaw/pull/111545) | One protocol-owned approval-not-found descriptor and Control UI edge | Generated target catalogs follow separately through the Control UI workflow; product readiness remains deferred. | -## End State Of RFC Acceptance And The Five Drafts +## End State Of RFC Acceptance And The Five Implementation PRs RFC acceptance approves contracts and owner gates; it does not change runtime behavior. Landing `F01`, then independently landing owner-approved `F02` @@ -44,24 +45,26 @@ through `F05`, provides: - contributor guidance for adding later owner-scoped families. The coverage specification defines the eventual language-by-surface reporting -shape, but these drafts neither install a closed global reporting matrix nor +shape, but these PRs neither install a closed global reporting matrix nor claim completion for unadopted surfaces. Owner declarations and aggregate reporting begin later in `E43`; review evidence and release promotion follow in `E44`. -The five runtime drafts do not prove the reusable CI and translation-authoring -loop. Draft OpenClaw PR +The five runtime PRs do not prove the reusable CI and translation-authoring +loop. OpenClaw PR [#112784](https://github.com/openclaw/openclaw/pull/112784) implements `G45` -and `G46` together: change one routine English source message, observe -deterministic CI detect the stale target, run trusted asynchronous generation -and validation, and open a generated pull request. Later owners adopt that lane -only for their declared families, namespaces, or directories, with both the -scoped gate and owner-owned refresh configured in the same adoption slice. +and `G46` together: change one routine English source message, observe the +credential-free ready-PR gate fail on stale targets, run the maintainer-authorized +refresh against the exact PR head, and observe automation update that same PR so +strict validation can turn green. Fork and cross-repository sources retain the +trusted post-merge generated-PR fallback. Later owners adopt that lane only for their +declared families, namespaces, or directories, with both the scoped gate and +owner-owned refresh configured in the same adoption slice. Its review branch contains `F01`, the exact five-file `F03` ownership delta, and the 17-file exemplar; unrelated updater, TUI, Gateway, and approval runtime ancestry is excluded. Because the branch shares the exact `F03` head, that dependency collapses normally after the documentation slice merges. -Draft OpenClaw PR +OpenClaw PR [#112801](https://github.com/openclaw/openclaw/pull/112801) implements `G47` as a separate build-time guard so a newly introduced product-string surface cannot bypass that decision by never entering an owner registry. @@ -141,10 +144,39 @@ one semantic owner + one deleted presentation workaround + one scoped authoring gate and owner-owned generated refresh path when the slice adds or migrates deterministic product strings ++ one updated checked-in inventory entry, public workflow-index entry, and + nearest owner-internal guidance, plus any additional public contract guidance ``` The PR description or focused tests record the corresponding conformance -evidence. Shared localization machinery is not acceptance by itself. +evidence. Guidance and inventory land progressively with the owning slice; +they are not deferred to product completion. Every adopted surface is indexed +in the public contributor workflow guide. A slice may record that no additional +public contract documentation changes when it introduces no public contract, +but it still updates the nearest owner guidance when maintainers gain a new +obligation. +Shared localization machinery is not acceptance by itself. + +### Gate responsibility by change type + +The repository reuses shared checks and workflows. A slice adds owner-scoped +registry/configuration rows and fixtures; it does not create a new CI system or +translation service for every message family. + +| Change in an adopted or newly introduced scope | Required enforcement | Boundary | +| --- | --- | --- | +| Add or change a reviewed English catalog key | `G45` credential-free authoring/drift gate | Drafts do not run the lane. Once ready, fail a same-repository PR targeting the default branch on stale targets; reject invalid ICU, placeholder or protected-literal drift, and hand-edited generated output. Keep non-updatable or non-default-base branches advisory. | +| Add a product-facing source registration, file family, or declared source root | `G47` disposition gate | Require adoption, a conforming existing owner pipeline, or a named English-only, platform-constrained, or deferred disposition. | +| Add a raw product-owned literal inside a family, namespace, or narrow directory already declared migrated | Owner-scoped hardcoded-string inventory such as blocking `L10N001` | Block only for the declared migrated scope. `G47` does not heuristically scan every repository literal. | +| Generate or publish a translation candidate | `G46` trusted exact-source workflow | Run only protected-base tooling with trusted credentials, validate before publication, then update the exact same-repository PR head or open/update one generated fallback PR. | +| Reuse Control UI, native, or docs automation | Owner-pipeline conformance record | Map its detection, generation, validation, evidence, publication, and review behavior to `G45`/`G46`; do not replace a conforming pipeline. | +| Promote a locale/surface maturity or product claim | `E43`/`E44` aggregation and review evidence | Consume only landed declarations, generated artifacts, and current required review evidence. | + +One logical slice normally keeps source/adoption and generated catalogs in one +pull request. A fork or cross-repository path may span a source PR and a +generated fallback PR. Landing only the source half can enroll the scope, but +it does not complete an entry whose exit bar requires generated artifacts or +named language/security review. Stop the slice when no owner can approve stable meaning, no legitimate locale exists, safety review is missing, stable machine output would change, or the @@ -161,7 +193,7 @@ Completion names are tracking cohorts, not single PRs or a linear stack: | Runtime safety | Bounded user-facing runtime and Gateway errors | `F05` and `R16`-`R24` use owner-approved descriptors, edge rendering, and compatible English fallback. | | Channels and capabilities | Server-rendered channels, command menus, command metadata, and skill/plugin metadata | `M25`-`M36` land each public contract and locale authority independently. | | Native and docs | Android, Apple, and documentation | `P39`-`P42` extend existing owner pipelines and record the Persian/Thai disposition. | -| Authoring automation | Shared tooling plus each adopting owner | `G45`-`G46` prove scoped deterministic enforcement and trusted generated-PR refresh; `G47` requires a disposition for newly introduced product-string surfaces. | +| Authoring automation | Shared tooling plus each adopting owner | `G45`-`G46` prove scoped deterministic enforcement, trusted in-place refresh, and generated-PR fallback; `G47` requires a disposition for newly introduced product-string surfaces. | | Release promotion | Product-wide | `E43`-`E44` aggregate only landed scoped evidence and produce an honest release claim. | ### September 1 delivery target @@ -178,11 +210,11 @@ The schedule front-loads public-contract, safety, platform, and publication owner decisions. Missing owner approval may reorder independent work, but it does not count the blocked entry as complete or permit a schedule-only deferral. -The current product-policy target is all 313 OpenClaw-controlled cells complete. -`docs/fa` and `docs/th` must either gain an approved publishing path or remain -the only two disclosed external platform constraints. An unqualified -`fully-localized` claim requires all 315 cells to be complete. None of these -counts is an RFC-acceptance condition. +The product-completion target is all 315 translation-target cells complete. +`docs/fa` and `docs/th` need an approved publishing path to reach that target. +If either remains platform-constrained at the September 1 decision, the report +must disclose the blocker and remain qualified; the cell does not count as +complete. This target is not an RFC-acceptance condition. ## Continuous Translation Maintenance @@ -209,17 +241,19 @@ Provider secrets are never exposed to untrusted pull-request code. `G45` and `G46` establish the reusable reference path before broad owner adoption. One routine, non-safety message family must prove: -1. an English source edit is detected on an untrusted pull request without +1. an English source edit is detected on a pull request without provider credentials; -2. the migrated scope fails its deterministic gate while the target catalog is - missing, stale, malformed, or violates ICU/placeholders/protected literals; -3. a trusted exact-source workflow generates one locale candidate; -4. validation succeeds before publication and records source-pinned generation - evidence; -5. the existing generated-PR publisher opens or updates a reviewable pull - request rather than pushing directly; and -6. failed or stale generation publishes nothing and leaves the affected cell - partial. +2. a ready same-repository, default-base pull-request check fails with the exact stale target catalogs while + blocking malformed registration, source, ICU, placeholder, or + protected-literal changes; +3. a maintainer dispatch starts protected-`main` workflow and generator code + against the source PR's resolved exact head, without executing PR-owned code; +4. that workflow generates locale candidates and commits them to the unchanged + source branch under an exact-head lease; +5. strict generated-catalog validation succeeds before publication and records + source-pinned generation evidence; +6. failed or stale generation publishes nothing, while fork or cross-repository + sources use one trusted post-merge generated follow-up PR. The exemplar proves plumbing, not linguistic completion. Its generated output does not approve itself, and safety families require their stricter owner and @@ -245,11 +279,15 @@ passes after a valid disposition is added. After the exemplar lands, every subsequent slice that adds or migrates deterministic product strings must leave its area enrolled end to end. The PR defines the adopted family, namespace, or directory; enables its blocking -credential-free gate; and configures the area's trusted asynchronous refresh, -validation, evidence, and generated-PR path. Existing Control UI, native, or -docs pipelines satisfy this requirement by proving conformance, not by being -replaced. A schema-only, explicitly English-only, or deferred slice records why -no translated catalog is enrolled. +credential-free gate; and configures the area's trusted in-place refresh plus +post-merge generated-PR fallback, validation, and evidence. The same slice updates its +checked-in inventory disposition, public contributor workflow index, nearest +owner-internal guidance, and any additional public contract documentation so +the new maintenance contract is usable at merge time. Existing Control UI, +native, or docs pipelines satisfy this +requirement by proving conformance, not by being replaced. A schema-only, +explicitly English-only, or deferred slice records why no translated catalog +is enrolled and documents the resulting owner obligation. ## Workstream 1: Minimal Localization Core @@ -502,15 +540,25 @@ The foundation is shipped when: - reviewed English fallback templates are rendered at the edge; - right-to-left literal isolation and missing-key fallback are proven; - adopted slices include accepted, fallback/failure, compatibility, privacy, - rollback, and deletion evidence; and + rollback, and deletion evidence; +- `G47`/`PK0` registers its pre-inventory PK0 entries, indexes their workflows + publicly, and backfills their nearest owner-internal guidance; `F02`, `F04`, + `F05`, and every later slice land those artifacts in their own adoption + packages; and - public diagnostics remain bounded and content-free by default. ### Product completion The delivery target is a product-completion decision on September 1, 2026. It requires an honest coverage report, current generated artifacts, scoped named -review, disclosure of any accepted platform constraints, and the chosen -313/315 or 315/315 target. Every current registry entry must be landed, deleted -by source proof, or covered by a conforming existing owner pipeline; drafts, -open generated follow-ups, and schedule-only deferrals do not count. Product -completion is not required to accept the RFC or ship the runtime foundation. +review, and all 315 translation-target cells at `complete`. Every current +registry entry must be landed, deleted by source proof, or covered by a +conforming existing owner pipeline; drafts, open generated follow-ups, +platform constraints, and schedule-only deferrals do not count as complete. +If blockers remain, publish the qualified report and keep product completion +open. Product completion is not required to accept the RFC or ship the runtime +foundation. + +The `P41`-`P42` documentation cohort localizes documentation as a product +surface. It is not a catch-all phase for documenting earlier runtime slices; +those slices must already have landed their contributor and owner guidance. diff --git a/rfcs/0024/localization-coverage-v1-spec.md b/rfcs/0024/localization-coverage-v1-spec.md index 1b913439..3898d968 100644 --- a/rfcs/0024/localization-coverage-v1-spec.md +++ b/rfcs/0024/localization-coverage-v1-spec.md @@ -3,7 +3,26 @@ This document defines the product-level inventory, maturity, validation, and release-reporting contract for RFC 0024. -Status: draft, tied to RFC 0024. +Status: accepted as part of RFC 0024; implementation lands progressively. + +## Contract At A Glance + +Use this specification to decide whether OpenClaw may claim a surface or the +product is localized. The v1 release portfolio has 15 rows and 21 non-English +targets, producing 315 target cells. Every required row is present even when +its maturity is `unsupported`; only `complete` counts toward the unqualified +product claim. + +Owner declarations may be more granular than release rows. Message families, +packages, and channel adapters publish their own evidence, then the product +aggregator derives the applicable release-row state. Adding a delivery slice +or owner declaration does not silently change the 315-cell denominator; +changing the required release-row set is an explicit product-policy decision. + +Runtime rendering rules live in the +[runtime specification](localization-runtime-v1-spec.md). Locale-aware command, +skill, and capability fields live in the +[metadata specification](localized-metadata-v1-spec.md). ## Coverage Manifest @@ -103,11 +122,11 @@ or declared locale support without a corresponding artifact. The generated manifest does not persist the declaration order field; order only makes the checked report deterministic. -The current RFC 0024 release portfolio contains 15 owner-declared product -surfaces. That portfolio and its 315 target cells are product release policy, -not a closed type restriction in localization core. A future owner can publish -a valid new surface without modifying generic core validation, while changing -the required release portfolio remains an explicit product-policy change. +The current RFC 0024 release portfolio contains 15 required release rows. That +portfolio and its 315 target cells are product release policy, not a closed type +restriction in localization core. A future owner can publish a valid granular +declaration without modifying generic core validation, while changing the +required release-row set remains an explicit product-policy change. `manifestRevision` is computed from the canonical checked-in manifest bytes and is not stored inside that manifest. Release reports and packaged status expose @@ -162,29 +181,31 @@ string. ## Surface Set -The initial product report covers: - -- Control UI; -- CLI onboarding; -- channel and plugin setup flows; -- remaining CLI commands and help; -- TUI human-readable output; -- core runtime messages, approvals, authentication, validation, and recovery - guidance; -- Gateway errors; -- server-rendered channel messages and notifications; -- core and bundled command metadata; -- bundled channel command-menu projections, tracked separately for each - adapter such as Telegram and Discord; -- core and bundled skill metadata; -- Android; -- Apple platforms; -- documentation. - -Surfaces can have different catalogs and supported locale sets. A shared -metadata catalog and each product-owned platform projection are separate -coverage surfaces because platform limits, locale support, and reconcile -behavior can independently reject or drop localized text. +The initial product report uses these exact 15 release rows: + +| Surface ID | Includes | +| --- | --- | +| `control-ui` | Browser UI copy and client-rendered known Gateway failures | +| `cli-onboarding` | CLI onboarding wizard | +| `channel-plugin-setup` | Channel and bundled-plugin setup flows | +| `cli` | Remaining CLI commands, help, validation, and recovery copy | +| `tui` | Human-readable terminal UI output | +| `runtime` | Core runtime, approval, authentication, validation, and recovery copy | +| `gateway-errors` | Protocol-owned known Gateway error descriptors | +| `server-rendered-channels` | Channel messages, notifications, and approval presentation | +| `command-metadata` | Core and bundled command display metadata | +| `telegram-command-menu` | Telegram-native command-menu projection | +| `discord-command-menu` | Discord-native command-menu projection | +| `skill-metadata` | Core and bundled skill display metadata | +| `android` | Android product catalogs | +| `apple` | Apple-platform product catalogs | +| `docs` | Published documentation | + +Rows can have different catalogs and supported locale sets. More granular +owner declarations feed these rows. For example, Telegram and Discord retain +separate projection rows because their locale limits and reconcile behavior +can fail independently; other adapter-specific message evidence contributes to +`server-rendered-channels` until product policy adds another required row. Generated-content language is post-v1 and is not part of this initial coverage report or the product-localization completeness claim. @@ -224,11 +245,10 @@ locale additions can be prioritized by OpenClaw users and maintainers. The initial release-policy snapshot contains 15 English source rows plus 15 product surfaces across 21 translation targets. Release completion is calculated over those 315 translation-target cells. This is not an -RFC-acceptance gate. The product completion target is all 313 OpenClaw-controlled -target cells at `complete`. `docs/fa` and `docs/th` must -either gain an approved publishing path or remain the only disclosed -`platform-constrained` cells. An unqualified `fully-localized` claim requires -all 315 target cells to be complete. +RFC-acceptance gate. The product-completion target and the unqualified +`fully-localized` claim both require all 315 target cells to be `complete`. +`docs/fa` and `docs/th` need an approved publishing path to reach that target; +a `platform-constrained` row explains a blocker but does not count as complete. Pseudo-locales and bounded script fixtures are declared under `testFixtures`, not the release locale registry. They support expansion, @@ -364,15 +384,27 @@ The maintenance workflow follows a dependency-guard-style state machine: | Phase | Trigger | Behavior | | --- | --- | --- | -| `detect` | Pull request | Runs without provider credentials. Reports changed English source, missing targets, stale revisions, fallback, and review drift. | -| `refresh` | Trusted `main`, schedule, or manual dispatch | Generates candidate translations per locale, validates isolated artifacts, and opens or updates a generated pull request. Failed generation or validation aborts publication. | +| `detect` | Ready English source pull request | Runs without provider credentials. For a same-repository PR targeting the default branch, fails with the exact missing or stale targets until refresh output is present. Non-default bases and branches the repository cannot update remain advisory. Drafts do not run this lane. It never publishes translations from pull-request code. | +| `refresh` | Maintainer dispatch for a ready same-repository, default-base PR, or trusted `main` push after a fork/cross-repository source merge | Runs protected-base tooling against an exact source revision, generates and validates all affected locale candidates as one batch, then either commits them to the unchanged source branch under an exact-head lease or opens/updates one generated fallback PR. Failed generation or validation aborts publication. | | `enforce` | Pull request and release | Blocks invalid catalogs and any `complete` claim whose source, artifacts, or required review are stale. | -The refresh workflow must check out a trusted exact source revision reachable -from a protected base-repository ref, keep provider credentials unavailable to -untrusted pull-request code, and publish through a scoped generated-PR -application identity. Generated changes retain source, glossary, workflow, -provider/model, and catalog-revision provenance. +The refresh workflow must execute workflow and generator code from a protected +base-repository revision. A source PR's registry and English catalogs are read +only as validated data; its scripts, actions, dependencies, and hooks are never +executed with provider or publisher credentials. Before an in-place push the +workflow rechecks that the PR is open, ready, same-repository, targets the +default branch, and is still at the +resolved source SHA, then uses a scoped application identity and an exact-head +lease. Generated changes retain source, glossary, workflow, provider/model, +and catalog-revision provenance. + +The normal same-repository path keeps one review unit: a ready source PR fails +the scoped gate, tells the author to request the maintainer-authorized refresh, +receives one bot commit containing every affected target, and reruns to green. +The original author and reviewers remain responsible for the now-complete PR; +automation never approves or merges it. Fork and cross-repository paths merge +reviewed English first, then use one generated follow-up PR. A trusted `main` +refresh also reconciles residual drift as a recovery path. Detection and enforcement fail closed on malformed manifests, tool failure, or unreadable required evidence. A failed refresh leaves the prior catalogs and @@ -381,7 +413,8 @@ maturity state unchanged while reporting the unresolved drift. The projected delivery registry proves this contract with three explicit slices. `G45` adds deterministic, credential-free detect/enforce checks for one owner-declared routine message family. `G46` adds the trusted exact-source -refresh, validation, evidence, and generated-PR path for the same fixture. They +refresh, validation, evidence, in-place update, and generated-PR fallback for +the same fixture. They may land together in one bounded core/tooling exemplar PR, after which each surface adopts the checks only for its own declared families, namespaces, or directories. `G47` adds a build-time disposition gate for newly enumerated @@ -393,12 +426,12 @@ informative; the state-machine contract above remains normative. After the exemplar exists, a migrated string-bearing area does not satisfy the maintenance contract until both phases are wired for its declared scope: -credential-free detect/enforce on pull requests and trusted refresh through a -generated pull request. Existing owner workflows may provide this evidence; +credential-free detect/enforce on pull requests and trusted in-place refresh +with a generated-PR fallback. Existing owner workflows may provide this evidence; the RFC does not require replacing a conforming pipeline. -The gate may automatically repair missing low-risk catalog entries in a -generated pull request. It must not: +The trusted refresh may repair missing low-risk catalog entries in the source +PR or a generated fallback PR. It must not: - push generated translations directly to a protected branch; - promote its own output to `complete`; diff --git a/rfcs/0024/localization-runtime-v1-spec.md b/rfcs/0024/localization-runtime-v1-spec.md index 9be4dd21..e0c7a9ff 100644 --- a/rfcs/0024/localization-runtime-v1-spec.md +++ b/rfcs/0024/localization-runtime-v1-spec.md @@ -4,7 +4,26 @@ This document is the implementer-facing runtime specification for RFC 0024. It defines locale identity, resolution, message descriptors, rendering, fallback, Gateway error compatibility, and safety-message constraints. -Status: draft, tied to RFC 0024. +Status: accepted as part of RFC 0024; implementation lands progressively. + +## Contract At A Glance + +Use this specification when adding deterministic product-owned text to a +runtime renderer. One operation resolves one immutable `LocalizationContext`, +looks up a stable message key in an owner catalog, validates literal +parameters, formats through the owner renderer, and falls back to reviewed +English without changing machine semantics. + +| Responsibility | Owner | +| --- | --- | +| Locale identity, context, validation, and fallback primitives | Shared localization kernel | +| Message meaning, stable key, parameters, and reviewed English | Semantic owner | +| Catalog, locale authority, final rendering, and translation workflow | Presenting surface owner | +| Surface/locale maturity and release claims | [Coverage specification](localization-coverage-v1-spec.md) | +| Command, skill, and capability display fields | [Metadata specification](localized-metadata-v1-spec.md) | + +This specification does not enumerate the 15-row release portfolio or move +copy ownership into the shared kernel. ## Scope diff --git a/rfcs/0024/localized-metadata-v1-spec.md b/rfcs/0024/localized-metadata-v1-spec.md index 0dfab811..859992c8 100644 --- a/rfcs/0024/localized-metadata-v1-spec.md +++ b/rfcs/0024/localized-metadata-v1-spec.md @@ -3,13 +3,28 @@ This document defines locale-aware display metadata for commands, skills, and other cataloged OpenClaw capabilities. -Status: draft, tied to RFC 0024. +Status: accepted as part of RFC 0024; each public schema still requires its +owning maintainer's activation approval. This specification defines the reusable additive shape. It does not by itself authorize a command-catalog, skill-manifest, plugin SDK, or platform adapter schema change. Each owning maintainer must approve that public surface and its compatibility plan before activation. +## Contract At A Glance + +Use this specification for localized display names and descriptions of stable +capabilities. The capability identity and executable name never change; +`LocalizedText` adds English-default presentation plus locale-keyed display +values. Capability owners approve meaning, consuming surfaces own projection +and fallback, and external package translations remain package-owned. + +This specification does not authorize a schema change by itself, register +runtime message catalogs, or add external packages to OpenClaw's 315-cell +product target. Runtime messages use the +[runtime specification](localization-runtime-v1-spec.md); release maturity uses +the [coverage specification](localization-coverage-v1-spec.md). + ## Scope V1 covers: diff --git a/rfcs/0024/projected-owner-slice-registry.md b/rfcs/0024/projected-owner-slice-registry.md index 58808e86..3fc20c68 100644 --- a/rfcs/0024/projected-owner-slice-registry.md +++ b/rfcs/0024/projected-owner-slice-registry.md @@ -29,18 +29,32 @@ Each entry tracks: - accepted, fallback/failure, compatibility, and privacy evidence; - the hardcoded, duplicated, or parsed-prose authority it deletes; and - a live state such as `projected`, `audited`, `owner-approved`, `draft`, - `landed`, `generated-follow-up`, `blocked`, `deferred`, or `deleted`. + `ready-for-review`, `source-enrolled`, `candidate-ready`, `landed`, + `blocked`, `deferred`, or `deleted`. + +The implementation tracker +[openclaw#113105](https://github.com/openclaw/openclaw/issues/113105) is the +live delivery ledger. State values in this planning document are a reviewed +snapshot and should not be treated as a substitute for live PR and generated +artifact state. The registry lives in RFC and project planning. Runtime lookup remains in surface-owned catalogs and protocol-owned descriptor registries. Coverage aggregation reads landed owner declarations; it does not make this planning file executable. +Owner registries below are delivery boundaries, not necessarily release-report +rows. Updater and Doctor slices, for example, contribute to the `cli` release +row; approval slices may contribute to `runtime`, `gateway-errors`, and +`server-rendered-channels`. The exact 15-row product denominator is defined by +the [coverage specification](localization-coverage-v1-spec.md#surface-set). + After `G45` and `G46` land, every slice that adds or migrates deterministic product strings must also onboard its area to both halves of the maintenance contract before that area is complete: its declared scope runs the blocking, credential-free authoring/drift gate, and its owner workflow runs trusted -asynchronous generation, validation, and generated-PR publication. An owner +asynchronous generation and validation with an in-place update for an unchanged +same-repository, default-base PR or a generated-PR fallback. An owner with an existing pipeline may prove that pipeline satisfies the contract rather than replace it. Schema-only, English-only, or deferred slices record why no translated catalog is being enrolled. `G47` separately ensures that newly @@ -48,6 +62,45 @@ enumerated product-string surfaces receive one of those dispositions at introduction time; platform-constrained dispositions also identify their owner and reason. +Adoption is documented progressively. Each slice updates its checked-in +inventory disposition, the public contributor workflow index, and nearest +owner-internal guidance, plus additional public documentation when it changes +a public authoring or compatibility contract. These are part of that slice's +done bar. `G47`/`PK0` registers its PK0 entries that predate the inventory, +indexes their workflows publicly, and backfills their nearest owner-internal +guidance rather than expanding their already-reviewed runtime scopes. `F02`, +`F04`, `F05`, and later slices carry those artifacts in their own packages. The +later `P41`-`P42` documentation package localizes documentation as a user-facing +product surface; +it does not defer documentation of earlier owner obligations. + +## Slice Lifecycle + +The normal delivery path is: + +```text +projected -> audited -> owner-approved -> ready-for-review + -> source-enrolled -> candidate-ready -> landed +``` + +- `ready-for-review` means the bounded source or contract PR is prepared; it + does not advance product coverage. +- `source-enrolled` means the source/runtime change plus its inventory, shared + gate configuration, workflow index, and owner guidance have landed, while a + required generated artifact or review is still outstanding. +- `candidate-ready` means the trusted owner workflow has updated the source PR + in place or opened/updated the required fallback PR. Passing structure checks + or an open generated PR is not done without required review. +- `landed` means every source, generated-artifact, compatibility, deletion, and + named review requirement in that registry entry's exit bar is present in + accepted history. +- `blocked`, `deferred`, `platform-constrained`, and `deleted` are explicit + exits with the owner and evidence required elsewhere in this registry. + +Source and generated changes may use separate PRs when the source branch cannot +be updated, without becoming separate planning slices. The slice remains +incomplete until its full exit bar is met. + ## Owner Registries | Registry | Owns | Does not own | @@ -65,17 +118,17 @@ and reason. ## A. Current Foundation Evidence -These five drafts are the first registry entries. `F02` through `F05` branch -independently from `F01`, so each review contains the shared foundation plus -only its own owner-bounded delta. +These five implementation PRs are the first registry entries. `F02` through +`F05` branch independently from `F01`, so each review contains the shared +foundation plus only its own owner-bounded delta. | ID | Owner registry | Slice and edge | State | Exit and deletion proof | | --- | --- | --- | --- | --- | -| `F01` | `core-locale` + `wizard` | Minimal kernel and onboarding consumer ([#111541](https://github.com/openclaw/openclaw/pull/111541)) | `draft` | Kernel/catalog tests, unchanged English wizard behavior, missing-key fallback, no runtime I/O; replaces wizard-local resolution duplication where adopted. | -| `F02` | `updater` | Human `update --dry-run` preview ([#111542](https://github.com/openclaw/openclaw/pull/111542)) | `draft` | JSON equality, literal command/path/version preservation, English and non-English proof; deletes updater-owned hardcoded preview labels. | -| `F03` | contributor/docs owners | Ownership and contribution guide ([#111543](https://github.com/openclaw/openclaw/pull/111543)) | `draft` | Docs map, glossary, source-safe validation, and working links; replaces undocumented cross-surface guesswork, not owner workflows. | -| `F04` | `tui` | TUI status summary and relative ages ([#111544](https://github.com/openclaw/openclaw/pull/111544)) | `draft` | Formatter and PTY proof, documented `OPENCLAW_LOCALE`/host-locale/English precedence, literal IDs/paths/models/events, exact English compatibility; deletes status-owned English assembly. | -| `F05` | `gateway-error` + `control-ui` + `approval` | `APPROVAL_NOT_FOUND` descriptor and approval-page edge ([#111545](https://github.com/openclaw/openclaw/pull/111545)) | `draft` | Stable tuple, bounded metadata, legacy English, unknown-key denial, protocol/UI tests; deletes the two Gateway emitter variants as independent descriptor authorities. | +| `F01` | `core-locale` + `wizard` | Minimal kernel and onboarding consumer ([#111541](https://github.com/openclaw/openclaw/pull/111541)) | `ready-for-review` | Kernel/catalog tests, unchanged English wizard behavior, missing-key fallback, no runtime I/O; replaces wizard-local resolution duplication where adopted. | +| `F02` | `updater` | Human `update --dry-run` preview ([#111542](https://github.com/openclaw/openclaw/pull/111542)) | `ready-for-review` | JSON equality, literal command/path/version preservation, English and non-English proof; deletes updater-owned hardcoded preview labels. | +| `F03` | contributor/docs owners | Ownership and contribution guide ([#111543](https://github.com/openclaw/openclaw/pull/111543)) | `ready-for-review` | Docs map, glossary, source-safe validation, and working links; replaces undocumented cross-surface guesswork, not owner workflows. | +| `F04` | `tui` | TUI status summary and relative ages ([#111544](https://github.com/openclaw/openclaw/pull/111544)) | `ready-for-review` | Formatter and PTY proof, documented `OPENCLAW_LOCALE`/host-locale/English precedence, literal IDs/paths/models/events, exact English compatibility; deletes status-owned English assembly. | +| `F05` | `gateway-error` + `control-ui` + `approval` | `APPROVAL_NOT_FOUND` descriptor and approval-page edge ([#111545](https://github.com/openclaw/openclaw/pull/111545)) | `ready-for-review` | Stable tuple, bounded metadata, legacy English, unknown-key denial, protocol/UI tests; deletes the two Gateway emitter variants as independent descriptor authorities. | ## B. Operator Surface Follow-Ups @@ -147,7 +200,7 @@ PRs remain separate where the repository policy requires it. | `P39` | `native.android` | Android catalog completeness and blocking quality advisories | Native workflow owner | Generated inventory/artifact parity, platform UI tests, named review; platform-native resources remain authoritative. | | `P40` | `native.apple` | Apple catalog completeness and blocking quality advisories | Native workflow owner | Generated inventory/artifact parity, platform UI tests, named review; platform-native resources remain authoritative. | | `P41` | `docs` | Swedish documentation source/navigation and generated publication | Docs owner and `openclaw/docs` workflow | Exact source/tool revision, glossary, links/anchors, published artifact evidence; no second docs translator. | -| `P42` | `docs` | Persian and Thai publishing-path decision and implementation | Docs platform owner decision | Either verified artifacts or explicit `platform-constrained` rows with fallback and platform evidence. | +| `P42` | `docs` | Persian and Thai publishing-path decision and implementation | Docs platform owner decision | Verified published artifacts; any interim `platform-constrained` row must carry fallback and platform evidence and remains a product-completion blocker. | ## F. Authoring Gates And Translation Automation @@ -156,16 +209,16 @@ together in one bounded core exemplar PR because they share tooling ownership and one test fixture, but adopted surfaces opt in independently and retain their own source, catalog, generation, review, and publication policy. -Draft OpenClaw PR +OpenClaw PR [#112784](https://github.com/openclaw/openclaw/pull/112784) is the reference implementation for both slices, using the wizard completion family as the first -adopted area. Its draft status is implementation evidence, not a claim that the +adopted area. Its open status is implementation evidence, not a claim that the slices have landed. | ID | Owner registry | Projected slice | Gate | Required proof and deletion target | | --- | --- | --- | --- | --- | -| `G45` | `catalog-automation` + first adopting owner | Deterministic authoring and drift gate for explicitly migrated families, namespaces, or directories | `F01` and `F03`; one routine core/wizard fixture | A changed English product string fails until it is registered; invalid ICU, placeholder mismatch, protected-literal drift, stale catalog evidence, and hand-edited generated paths fail without provider credentials. Unmigrated legacy scopes remain advisory. Replaces ad hoc or manual adopted-scope checks. | -| `G46` | `catalog-automation` + first adopting owner | Trusted async catalog refresh and generated-PR reference lane | `G45`; approved provider secret on trusted `main`, schedule, or manual dispatch | One English fixture change produces an isolated locale candidate, validates it, records source-pinned generation evidence, and opens or updates a generated PR through the existing publisher. Stale input or validation failure publishes nothing and leaves coverage partial. No direct protected-branch push, AI self-review, or automatic safety-copy promotion. Replaces hand-copied translation updates for the adopted fixture. | +| `G45` | `catalog-automation` + first adopting owner | Deterministic authoring and drift gate for explicitly migrated families, namespaces, or directories | `F01` and `F03`; one routine core/wizard fixture | A changed English product string fails until its source area is registered. Invalid source ICU, placeholder or protected-literal rules fail without provider credentials. Drafts do not run the lane. Once ready, a same-repository PR targeting the default branch fails with the exact stale targets until refreshed; non-default bases and branches the repository cannot update remain advisory. Any PR that changes generated paths runs the strict catalog check. Unmigrated legacy scopes remain advisory. Replaces ad hoc or manual adopted-scope checks. | +| `G46` | `catalog-automation` + first adopting owner | Trusted async catalog refresh with in-place and generated-PR publication | `G45`; approved provider secret on protected-`main` workflow code | A maintainer dispatch resolves a ready same-repository, default-base PR head, runs only trusted generator code, produces and validates all affected locale candidates, and commits one batch to that unchanged branch under an exact-head lease. Fork/cross-repository merges and recovery runs open or update one generated follow-up PR. Stale input or validation failure publishes nothing. No protected-branch push, AI self-review, or automatic safety-copy promotion. Replaces hand-copied translation updates for the adopted fixture. | | `G47` | `catalog-automation` + surface-registry owners | [New product-string surface disposition gate](https://github.com/openclaw/openclaw/pull/112801) | `G45` and `G46`; one owner adapter that enumerates real surface registrations or declared product-facing source roots | Adding an enumerated surface or expanding a declared product-facing scope fails until it is adopted, mapped to a conforming owner pipeline, or explicitly English-only, platform-constrained, or deferred with a named owner and rationale. Existing unclassified scopes are baselined as legacy debt. No repository-wide literal heuristic, runtime registry, or classification requirement for tests, logs, developer diagnostics, or model-authored text. Replaces review-only discovery of newly introduced localization debt. | The exemplar is deliberately routine product copy. Safety catalogs may reuse @@ -193,7 +246,7 @@ F01 kernel F01 kernel + F03 contributor contract -> G45 scoped authoring gate - -> G46 trusted async refresh exemplar + -> G46 trusted in-place refresh + generated-PR fallback exemplar -> G47 new-surface disposition gate F05 Gateway approval descriptor @@ -217,6 +270,8 @@ artifacts or adapter projections. Once the core exemplar lands, every later string-bearing area slice includes its scoped `G45` gate and `G46` refresh adoption (or evidence that its existing owner workflow already conforms), while `G47` prevents newly enumerated surfaces from remaining outside that decision. +The slice's inventory and applicable public/internal guidance land alongside +that adoption rather than in the final evidence or documentation packages. ## September 1, 2026 Delivery Packages @@ -233,13 +288,13 @@ discovered in the scheduled implementation week. | Window | Delivery packages | Registry entries | Required outcome | | --- | --- | --- | --- | -| July 22-24 | `PK0` architecture, foundation, and automation | `F01`, `F03`, `G45`, `G46`, `G47` | Accept RFC direction; land the kernel, contributor contract, shared per-repo gates, trusted refresh exemplar, and new-surface disposition gate; supervise the first credentialed generated-PR run. | -| July 27-31 | `PK1` initial operator consumers; `PK2` first Gateway edge; `PK3` wizard/setup | `F02`, `F04`, `O07`, `O15`; `F05`, `O06`; `O08`, `O09` | Finish updater and TUI families, approval-not-found plus its generated UI catalog, and remaining owner-bounded wizard/setup families. | +| July 22-24 | `PK0` architecture, foundation, and automation | `F01`, `F03`, `G45`, `G46`, `G47` | Accept RFC direction; land the kernel, contributor contract, shared per-repo gates, trusted refresh exemplar, and new-surface disposition gate; backfill foundation inventory, public workflow indexing, and nearest owner guidance; supervise the first credentialed in-place run and generated-PR fallback. | +| July 27-31 | `PK1` initial operator consumers; `PK2` first Gateway edge; `PK3` wizard/setup | `F02`, `F04`, `O07`, `O15`; `F05`, `O06`; `O08`, `O09` | Finish updater and TUI families, approval-not-found plus its generated UI catalog, and remaining owner-bounded wizard/setup families; land each slice's inventory, public workflow index, and nearest owner guidance. | | August 3-7 | `PK4` CLI shell/agent; `PK5` sessions/tasks/Doctor; `PK6` Gateway families | `O10`, `O11`; `O12`, `O13`, `O14`; `R16`, `R17`, `R18`, `R19` | Land reusable CLI adapters and bounded consumers, then expand only reviewed Gateway discriminator tuples. | | August 10-14 | `PK7` runtime safety; `PK8` command metadata; `PK9` skill/plugin metadata | `R20`, `R21`, `R22`, `R23`, `R24`; `M25`, `M26`, `M27`, `M28`; `M29`, `M30`, `M31`, `M32` | Complete approval/runtime safety boundaries and land public metadata contracts before their projections. | | August 17-21 | `PK10` channel notices; `PK11` Control UI; `PK12` native apps | `M33`, `M34`, `M35`, `M36`; `P37`, `P38`; `P39`, `P40` | Finish adapter-owned channel dispositions and extend existing UI/native owner pipelines without replacing them. | -| August 24-28 | `PK13` documentation; `PK14` coverage aggregation and catch-up | `P41`, `P42`; `E43` | Land or prove the docs publishing paths, close any slipped package, and publish coverage from landed owner declarations. | -| August 31-September 1 | `PK15` evidence promotion | `E44` | Ingest current named-review evidence and generated artifacts, disclose accepted platform constraints, and make the qualified or full product claim. | +| August 24-28 | `PK13` documentation product surface; `PK14` coverage aggregation and catch-up | `P41`, `P42`; `E43` | Land or prove the localized docs publishing paths, close any slipped package, and publish coverage from landed owner declarations; earlier slice guidance is already required at each slice's merge. | +| August 31-September 1 | `PK15` evidence promotion | `E44` | Ingest current named-review evidence and generated artifacts; make the full claim only at 315/315, otherwise publish the qualified blocker report and keep product completion open. | The packages cover all 47 current entries exactly once. The target operating cadence is roughly three completed packages per full week with no more than