Skip to content

Roadmap: lock §5a locale design; reflect shipped work#20

Merged
mmucklo merged 2 commits intomasterfrom
roadmap-locale-design
Apr 16, 2026
Merged

Roadmap: lock §5a locale design; reflect shipped work#20
mmucklo merged 2 commits intomasterfrom
roadmap-locale-design

Conversation

@mmucklo
Copy link
Copy Markdown
Owner

@mmucklo mmucklo commented Apr 13, 2026

Converts the §5a "Open design questions" into resolved decisions so implementation of v2.1 (locale support + extension APIs) can start without another round-trip.

Key design decisions locked

  • Locale contract — abstract class with protected instance rule tables + shared regex engine. Bare interface deferred.
  • Visibilityprotected rule tables; defaults come from protected const class constants on subclasses. No reintroduction of public static mutable state.
  • Caching — per-instance, not global. Extension methods invalidate the instance cache.
  • Default locale (static API) — always En. No `setDefaultLocale` footgun.
  • Instance API — `new Inflect(Locale|string $locale = 'en')`; `Inflect::registerLocale(name, class-string|Locale)` for third parties; lazy resolution.
  • Back-compat — static methods keep signatures, internally delegate to a lazy shared `En` instance. Proxy extension methods on `Inflect` mutate that shared instance.

Phasing tightened

  • v2.0 ✅ shipped 2026-04-13.
  • v2.1 — items 5 + 5a combined (they share the same API surface — splitting was churn).
  • v2.2 — add at least one non-English locale (candidate: `Es`/`Fr`/`De`) to prove the contract holds.
  • v3.x (conditional) — Path B package split per §5a triggers.

Ship-state annotations

Test plan

  • Confirm the Locale contract shape (abstract class vs interface, protected visibility, constructor-seeding).
  • Confirm the no-`setDefaultLocale` decision.
  • Confirm v2.1 combining §5 and §5a is the right call.

🤖 Generated with Claude Code

Convert the §5a "Open design questions" into resolved decisions so
implementation can start without a round-trip:

- Locale is an abstract class holding rule tables as protected
  instance state, with a concrete regex-rule engine shared across
  subclasses. Bare Locale interface deferred to a later revision if
  needed for exotic morphologies.
- Rule-table visibility: protected (not private — subclasses seed
  them; not public — we moved away from mutable shared state in 2.0).
  Defaults come from protected const class constants on subclasses.
- Caching: per-instance, not global. Extension methods mutate
  instance state and invalidate the instance cache.
- Default locale: the static API always uses En. No global
  setDefaultLocale — avoids action-at-a-distance.
- Instance API: new Inflect(Locale|string $locale = 'en').
  Inflect::registerLocale(name, LocaleOrClassString) for third
  parties. Resolution is lazy.
- Back-compat: static methods keep signatures; internally delegate
  to a lazily-initialized shared En instance. Proxy extension
  methods mutate that shared instance.

Also reflect ship state:
- §6 docs: largely shipped in #19.
- §7 tooling: phpstan + cs-fixer shipped in #18; infection/phpbench
  deferred.
- §8: v2.0.0 tagged 2026-04-13.
- Phasing: v2.1 now merges items 5 + 5a (they share the same API
  surface); v2.2 becomes "add a non-English locale"; v3.x remains
  the conditional Path B split.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.07%. Comparing base (00188a4) to head (b1da2ae).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff            @@
##             master      #20   +/-   ##
=========================================
  Coverage     98.07%   98.07%           
  Complexity       27       27           
=========================================
  Files             1        1           
  Lines            52       52           
=========================================
  Hits             51       51           
  Misses            1        1           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Captures the design space past the Path B package split so future
decisions sit against an explicit menu rather than getting invented
ad hoc:

- §9 CLDR plural categories — lifts the English-binary assumption,
  rides on ext-intl / Unicode CLDR. One new method, locales delegate
  category resolution to MessageFormatter/NumberFormatter.
- §10 Morphology expansion — verb conjugation, indefinite articles,
  ordinals, case/gender. Scope creep; would change the product's
  identity.
- §11 Locale data quality — test corpora (Wiktionary/UniMorph) with
  CI accuracy metrics; optional ML fallback via ONNX/FFI.
- §12 Ecosystem — Symfony/Laravel bridges, composer-plugin locale
  discovery, benchmark-as-identity against Doctrine/Symfony.

Headline recommendation: §9 if we pick one — scoped, ext-intl-based,
doesn't change the library's identity but makes the current product
genuinely multilingual.

Explicitly framed as "not commitments — captured so the decision
space is explicit when we get there."

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@mmucklo mmucklo merged commit 82e3e89 into master Apr 16, 2026
7 checks passed
@mmucklo mmucklo deleted the roadmap-locale-design branch April 16, 2026 05:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant