Skip to content

docs(core): define the internationalization contract - #6048

Merged
nynexman4464 merged 4 commits into
mainfrom
nynexman4464/docs/i18n-contract
Oct 15, 2026
Merged

nynexman4464 merged 4 commits into
mainfrom
nynexman4464/docs/i18n-contract

Conversation

@nynexman4464

@nynexman4464 nynexman4464 commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

Stack

  1. docs(core): define the internationalization contract #6048 — internationalization architecture and provider contract
  2. docs: define RTL audit evidence policy #6046 — RTL audit evidence policy
  3. docs: define bidirectionality design intent #6047 — bidirectionality design intent

Intent

Define Astryx's intended translation, locale, direction, and catalog-delivery boundaries without changing the runtime. Shared helpers own locale-sensitive operations and Gregorian default date behavior. Known consumer inconsistencies remain follow-up conformance work, not exceptions to the contract.

Prerequisite

The owner-validator fix changes the checker's effective approver set from historical schema lists to the current ENGOWNERS list, matching the existing repository approval rules; DESIGNOWNERS remains additive only for design/theme. Membership is unchanged, the immutable schema lists remain historical and ignored by this check, and no approval is inferred. This isolated tooling prerequisite landed first in #7538.

Authority

Both records are promoted to authority: current with approved_by: nynexman4464 and approved_at: 2026-10-15, on the owner's approval of the reviewed claims. The exact-head /approve-spec command on this pull request records that decision for the final head; a later commit invalidates it.

Approval covers the reviewed contract, not conformance of every existing caller. Known implementation gaps stay explicit and uncontracted here:

  • the charts currency() helper follows the host locale when its locale is omitted (recorded under INV9 as a conformance gap, not a default; a separate compatibility change);
  • PowerSearch consumer fixes;
  • the supplied-English fallback for non-Astryx keys (provider OQ1).

Existing authority searched

  • Canonical ids: architecture:internationalization, component:InternationalizationProvider; the existing docs(core): define the internationalization contract #6048 draft is reused rather than replaced.
  • Current boundaries read: architecture:knowledge-contracts INV2/INV10/INV13/INV14/INV19/INV20 and its global-review overlay; public API ownership and compatibility guidance; the repository approval rules in docs/README.md and ENGOWNERS.
  • Paths/symbols: packages/core/src/i18n/, packages/core/locales/, scripts/generate-i18n-runtime.mjs, packages/build/src/vite.ts, the i18n lint rules; InternationalizationProvider, InternationalizationContext, useTranslator, RuntimeCatalog, ProviderMessagesByLocale, and the resolver.
  • Semantic terms: internationalization, i18n, catalog, fallback, ICU, locale, direction, RTL, runtime catalog, Gregorian PlainDate.
  • Refreshed open overlaps: feat(core): wire the translator adapter into i18n #4404 proposes a translator adapter; perf(i18n): let a component carry only its own English strings #7357/perf(i18n): every core component renders with its own English slice #7358 change English-slice delivery and retire part of the direct-context setter path. Those pending changes are not adopted here: this draft records the base behavior, and their public compatibility changes need their own reviewed decision/amendment. The prior runtime-catalog implementation evidence is present on the chosen main snapshot. Component-local localization changes remain with their component owners.

Authority and ownership

The canonical owners remain architecture:internationalization and component:InternationalizationProvider. nynexman4464 is listed first as the responsible maintainer, with cixzhang retained as co-owner. Repository ENGOWNER eligibility, rather than the order of this descriptive list, governs approval.

Cross-cutting review

The existing review-applicability:v1 overlay routes selected shared claims by semantic trigger. Accessibility reviews receive string ownership/catalog-backed text/output rules; behavior reviews additionally receive provider-locale, fallback, formatter-helper, and Gregorian rules. Layout/runtime changes receive the relevant DOM-direction claims. Catalog-generation and provider implementation details are not automatically applied to every component.

Component/module/family records keep their local content semantics, public concepts, states, and evidence. They need not repeat global rules or add a backlink merely to receive them. The provider record remains the local provider contract, not a second universal component spec. The routes become authoritative only once these records land as current.

No schema, runtime, or new Changeset is added for this routing metadata. The existing Changeset is for the shipped provider-doc anatomy addition, not the specs.

Changes

  • Rebase onto current main, which contains generated runtime catalogs, provider normalization, exports, and their tests.
  • Preserve the distinction between catalog-backed text and provider-locale formatting.
  • Make shared helpers the locale-sensitive formatting/parsing boundary; document locale-independent tag/grapheme/validity/machine-field responsibilities without a blanket raw-Intl exemption for components.
  • Require Gregorian default built-in date displays and PlainDate behavior while preserving the existing explicit low-level display-calendar override.
  • Treat helper admission and passing lint as enforcement evidence, not proof that every consumer conforms; PowerSearch code fixes remain separate.
  • Preserve the known supplied-English fallback limitation for non-Astryx keys; no resolver change is included.
  • Refresh the record templates and remove change-history references from standing contracts.
  • Clear stale approval metadata instead of carrying an earlier exact-version approval forward.
  • Record the charts currency() host-default gap under INV9, list the exported Locale, MessageEntry, and Overrides types in the released surface, and add a provider test for one messages value mixing rich and runtime catalogs (addresses the latest automated review; no implementation change).
  • Promote both records to current.

Evidence

  • pnpm check:repo passes.
  • All 297 selected locale/helper tests pass, including the 70 i18n tests plus PlainDate, date-parser, PowerSearch shared formatting, and Timestamp zone-validation tests. These do not assert that the deferred PowerSearch consumers are fixed.
  • The new mixed-catalog test fails when provider normalization is mutated to run only when every locale is a string map, and passes on the shipped provider; no other i18n test catches that mutation.
  • The charts formatter tests (6) pass unchanged; currency() is not modified.
  • The metadata-free runtime projection check covers all 31 locale catalogs.
  • Knowledge-record validation, formatting, and git diff --check pass.
  • All 121 knowledge-validator tests pass on current main, which includes the fix(specs): use current repository approver membership #7538 approver fix; synthetic in-memory route tests verify selective claims, nonmatching triggers, draft exclusion, and provenance. The base-pinned router treats these records as authority only after they land as current.

Writing rubric results

R1 narration: removed the RFC-origin narrative from the architecture purpose; standing text describes the system. Promotion removed draft-readiness wording rather than narrating the approval.
R2 research: no surveys, benchmarks, or options research in the records.
R3 evidence: replaced the provider fallback row's RFC citation with the current resolver and focused tests.
R4 rejected alternatives: narrowed the parallel-runtime rejection to one compact statement of the ownership boundary.
R5 change references: removed RFC and PR references from the records; implementation and prior review history remain here.
R6 open questions: retained unresolved supplied-English fallback, malformed-locale, adapter, and server-runtime boundaries without changing their outcomes.

@vercel

vercel Bot commented Sep 4, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
astryx Ready Ready Preview Oct 15, 2026 6:05pm UTC

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Sep 4, 2026
@nynexman4464
nynexman4464 force-pushed the nynexman4464/docs/i18n-contract branch from b16fd6c to 8b4f2b9 Compare September 4, 2026 20:25
github-actions Bot added a commit that referenced this pull request Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

PR Analysis Report

Previews ready: Storybook and Sandbox were built with this PR's docsite. CI evidence will be added when available.

View Storybook for this PR · View Sandbox for this PR

@cixzhang

cixzhang commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

/approve-spec 8b4f2b9

@cixzhang cixzhang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for documenting the shared internationalization architecture and the provider-specific contract together. Approved at exact head 8b4f2b9853fae7dafb3bd4d72877301bfa489366.

@astracat-bot

astracat-bot Bot commented Sep 9, 2026 •

Copy link
Copy Markdown

AI review status for this pull request.

Review status Updated
🔄 In progress (for maintainers only) Oct 15, 2026, 6:06 PM UTC

@nynexman4464
nynexman4464 force-pushed the nynexman4464/docs/i18n-contract branch from 8b4f2b9 to 77b995b Compare September 14, 2026 23:59
@github-actions github-actions Bot added the needs:spec-owner-review Current knowledge records await owner approval label Sep 15, 2026
github-actions Bot added a commit that referenced this pull request Sep 15, 2026
github-actions Bot added a commit that referenced this pull request Sep 15, 2026
@nynexman4464
nynexman4464 force-pushed the nynexman4464/docs/i18n-contract branch from 8b74366 to 1884b30 Compare September 21, 2026 19:37
github-actions Bot added a commit that referenced this pull request Sep 21, 2026
@nynexman4464
nynexman4464 force-pushed the nynexman4464/docs/i18n-contract branch 2 times, most recently from d2abcb7 to 64cffde Compare September 29, 2026 20:03
github-actions Bot added a commit that referenced this pull request Sep 29, 2026
@nynexman4464
nynexman4464 force-pushed the nynexman4464/docs/i18n-contract branch from 64cffde to a205918 Compare September 30, 2026 15:41
@nynexman4464
nynexman4464 force-pushed the nynexman4464/docs/i18n-contract branch 2 times, most recently from 0a2ca4c to d43af9b Compare September 30, 2026 15:56
github-actions Bot added a commit that referenced this pull request Sep 30, 2026
@nynexman4464
nynexman4464 marked this pull request as ready for review September 30, 2026 16:38

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for consolidating the internationalization contract — the released fallback, direction, and provider-update behavior is well captured, and the new test now proves rerenders on messages, overrides, and dir changes plus nested-provider replacement.

Approval needs a maintainer decision first. These records are proposed as current authority, but the owner approval on file is for an earlier draft head and the exact-head spec-owner approval is still pending. A maintainer needs to approve these exact records at the current head, including whether the runtime-catalog contract should become current before its implementation lands.

One actionable correction is tied to that decision: the records currently present generated runtime catalogs, the generated locale export, and string-map catalog input as shipped and test-covered, but at this head there is no generator, generated export, runtime-catalog type, or resolver support for that shape, and the cited runtime-catalog tests do not exist here. Please either land that implementation first or correct those claims and their verification map to match shipped behavior — or, if spec-first recording is the maintainer's intent, make the proposed (not shipped) state explicit.

The authored size, checks, and released-behavior coverage are otherwise in good shape.

[Automated review]

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the thorough internationalization contract — the fallback, runtime-catalog and direction behavior it records matches the shipped provider, and the new tests pass. Approval waits on a maintainer decision: both records add normative requirements that no current spec states — the architecture invariants with their review routes, and the provider's FR, ORD, AR, PR and DEC-1 rules — so a maintainer needs to approve them as the governing spec at this head or identify the spec that should govern instead. Separately, please fix these before approval:

  • INV9 and the System behavior row say optional-locale pure helpers default to English, but currency() in @astryxdesign/charts follows the host locale when locale is omitted, so record that exception or settle a separate change to the helper.
  • The released-surface list in the System model leaves out the exported Locale, MessageEntry and Overrides types.
  • FR9's verification row lists a mixed rich-plus-string-map state that no test exercises.

[Automated review]

Comment on lines +239 to +243
- **INV9 — Pure helpers have deterministic compatibility defaults.** A public pure
formatter that predates provider threading may keep an optional locale for
compatibility, but its omitted value resolves deterministically to English.
Astryx-owned call sites pass the provider locale explicitly. New pure helpers
require an explicit locale unless a current contract records another default.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

INV9 (and the System behavior row on line 82) says an omitted locale resolves deterministically to English, but the shipped currency(symbol, locale?) in @astryxdesign/charts passes an omitted locale straight to Intl.NumberFormat and toLocaleString: currency('€')(999.5) gives €999,5 on a de-DE host and €999.5 on an en-US host. Please name that exception here, or settle changing currency() as its own compatibility change.

Comment on lines +154 to +159
`@astryxdesign/core/i18n` is the canonical public entry point. The released
surface consists of `InternationalizationProvider`, `InternationalizationContext`,
their public value/prop types, `useTranslator`, `TranslatorFn`, `useLocale`,
`useCollator`, `useDirection`, `getLocaleDirection`, the catalog types `Catalog`,
`RuntimeCatalog`, `MessagesByLocale`, and `ProviderMessagesByLocale`, and the
`Translator` interface. Shipped catalogs are published under

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reads as the complete released surface, but @astryxdesign/core/i18n also exports Locale, MessageEntry and Overrides (the type of the released overrides prop). Please add them, or make the list non-exhaustive, so INV2's compatibility protection clearly covers them.

| FR6 | `useTranslator.test.tsx`, `useLocale.test.tsx`, `useDirection.test.tsx` | no provider | Host locale or missing English output fails | `audit:InternationalizationProvider/behavior` |
| FR7, AR1, AR2 | component translation tests and hardcoded-string lint | visible text, aria label, announcement, missing translation | Non-string output or untranslated owned text fails tests/lint | `audit:InternationalizationProvider/accessibility` |
| FR8 | `InternationalizationProvider.test.tsx` | parent plus child provider | Parent messages, overrides, or direction leaking into the child fails | `audit:InternationalizationProvider/behavior` |
| FR9, ORD1a | `useTranslator.test.tsx`, `resolve.test.ts` runtime-catalog cases | generated string map, rich catalog, mixed | A rejected string map, a string-map entry on the context, or divergent output between shapes fails | `audit:InternationalizationProvider/behavior` |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This row lists a mixed state, but no case in useTranslator.test.tsx or resolve.test.ts passes rich and string-map catalogs in one messages value. Please add one mixed-shape case, or drop mixed from the row.

…ypes

Name the known charts currency() host-default gap under INV9 without
treating it as a recorded default, list the exported Locale, MessageEntry,
and Overrides types in the released surface, and cover a messages value
that mixes rich and runtime catalogs.
@nynexman4464
nynexman4464 force-pushed the nynexman4464/docs/i18n-contract branch from d48cd04 to 4ba4dec Compare October 15, 2026 17:58
@nynexman4464

Copy link
Copy Markdown
Contributor Author

/approve-spec 4ba4dec

@nynexman4464
nynexman4464 merged commit 2d92213 into main Oct 15, 2026
53 checks passed
@github-actions
github-actions Bot deleted the nynexman4464/docs/i18n-contract branch October 16, 2026 06:22

This branch was successfully deployed

1 active deployment
Preview — 4ba4dec2 Deployed Oct 15, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants