From 284794afd5789c16661f8e272134c588709badc7 Mon Sep 17 00:00:00 2001 From: Baruch Espinoza Date: Tue, 5 May 2026 23:34:33 +0000 Subject: [PATCH 1/5] docs(specs): plan i18n Spanish baseline (002) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add /speckit-plan artifacts for the i18n foundation feature: spec, plan, research, data-model, contracts (translation helper, shared payload, audit CLI), quickstart, requirements checklist, and TDD-ordered tasks.md (71 tasks, 7 phases). No production code changes — planning only. Constitution v1.2.0 check passes; no Complexity Tracking entries. Repoints CLAUDE.md SPECKIT block and .specify/feature.json to the new feature directory. --- .specify/feature.json | 2 +- CLAUDE.md | 2 +- .../checklists/requirements.md | 37 +++ .../contracts/audit-cli.md | 156 ++++++++++ .../contracts/shared-payload.md | 62 ++++ .../contracts/translation-helper.md | 109 +++++++ specs/002-i18n-spanish-baseline/data-model.md | 209 ++++++++++++++ specs/002-i18n-spanish-baseline/plan.md | 129 +++++++++ specs/002-i18n-spanish-baseline/quickstart.md | 196 +++++++++++++ specs/002-i18n-spanish-baseline/research.md | 195 +++++++++++++ specs/002-i18n-spanish-baseline/spec.md | 152 ++++++++++ specs/002-i18n-spanish-baseline/tasks.md | 272 ++++++++++++++++++ 12 files changed, 1519 insertions(+), 2 deletions(-) create mode 100644 specs/002-i18n-spanish-baseline/checklists/requirements.md create mode 100644 specs/002-i18n-spanish-baseline/contracts/audit-cli.md create mode 100644 specs/002-i18n-spanish-baseline/contracts/shared-payload.md create mode 100644 specs/002-i18n-spanish-baseline/contracts/translation-helper.md create mode 100644 specs/002-i18n-spanish-baseline/data-model.md create mode 100644 specs/002-i18n-spanish-baseline/plan.md create mode 100644 specs/002-i18n-spanish-baseline/quickstart.md create mode 100644 specs/002-i18n-spanish-baseline/research.md create mode 100644 specs/002-i18n-spanish-baseline/spec.md create mode 100644 specs/002-i18n-spanish-baseline/tasks.md diff --git a/.specify/feature.json b/.specify/feature.json index 477be2f..76d2093 100644 --- a/.specify/feature.json +++ b/.specify/feature.json @@ -1 +1 @@ -{"feature_directory":"specs/001-project-lifecycle-timeline"} +{"feature_directory":"specs/002-i18n-spanish-baseline"} diff --git a/CLAUDE.md b/CLAUDE.md index b317345..f06f81a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -293,6 +293,6 @@ Wayfinder generates TypeScript functions for Laravel routes. Import from `@/acti -Active feature plan: [specs/001-project-lifecycle-timeline/plan.md](specs/001-project-lifecycle-timeline/plan.md) +Active feature plan: [specs/002-i18n-spanish-baseline/plan.md](specs/002-i18n-spanish-baseline/plan.md) Read the plan for technical context, project structure, and constitutional compliance for the in-flight feature. diff --git a/specs/002-i18n-spanish-baseline/checklists/requirements.md b/specs/002-i18n-spanish-baseline/checklists/requirements.md new file mode 100644 index 0000000..8a025fb --- /dev/null +++ b/specs/002-i18n-spanish-baseline/checklists/requirements.md @@ -0,0 +1,37 @@ +# Specification Quality Checklist: Internationalization Foundation (Spanish Baseline) + +**Purpose**: Validate specification completeness and quality before proceeding to planning +**Created**: 2026-05-05 +**Feature**: [spec.md](../spec.md) + +## Content Quality + +- [x] No implementation details (languages, frameworks, APIs) +- [x] Focused on user value and business needs +- [x] Written for non-technical stakeholders +- [x] All mandatory sections completed + +## Requirement Completeness + +- [x] No [NEEDS CLARIFICATION] markers remain +- [x] Requirements are testable and unambiguous +- [x] Success criteria are measurable +- [x] Success criteria are technology-agnostic (no implementation details) +- [x] All acceptance scenarios are defined +- [x] Edge cases are identified +- [x] Scope is clearly bounded +- [x] Dependencies and assumptions identified + +## Feature Readiness + +- [x] All functional requirements have clear acceptance criteria +- [x] User scenarios cover primary flows +- [x] Feature meets measurable outcomes defined in Success Criteria +- [x] No implementation details leak into specification + +## Notes + +- Items marked incomplete require spec updates before `/speckit-clarify` or `/speckit-plan`. +- Spec includes four prioritized user stories (Spanish parity, centralized translations, regression guardrail, English skeleton) with independent test descriptions. +- Spec records assumptions in lieu of clarification markers: framework-native translation mechanism, no third-party i18n library, no runtime locale switching in this feature, mechanical extraction (no rewording), pre-commit + CI lint gate, English directory generated as a skeleton. +- Translation key naming, file layout (PHP arrays vs JSON), and the exact lint tool are intentionally deferred to `/speckit-plan` because they are implementation choices that the spec template forbids embedding here. diff --git a/specs/002-i18n-spanish-baseline/contracts/audit-cli.md b/specs/002-i18n-spanish-baseline/contracts/audit-cli.md new file mode 100644 index 0000000..d9e11b1 --- /dev/null +++ b/specs/002-i18n-spanish-baseline/contracts/audit-cli.md @@ -0,0 +1,156 @@ +# Contract — i18n Audit CLI + +**Feature**: 002-i18n-spanish-baseline +**Binary**: `tools/i18n/audit.mjs` (Node ESM, no dependencies beyond Node 20 built-ins) +**Wrapper**: `bun run i18n:audit` (npm script) + +--- + +## Invocation + +```bash +# Default: scan all files matching audit.config.json include globs +bun run i18n:audit + +# Restrict to a list of paths (used by the pre-commit hook on staged files) +bun run i18n:audit -- path/to/file.tsx path/to/another.php + +# Emit machine-readable findings +bun run i18n:audit -- --format=json + +# Use a non-default config file (testing only) +bun run i18n:audit -- --config=tests/fixtures/audit.test-config.json +``` + +### Arguments + +| Flag | Type | Default | Purpose | +|-----------------------|-------------|----------------------------------|------------------------------------------------------| +| positional paths | `string[]` | `[]` (use config globs) | Restrict scan to this set | +| `--format` | `text\|json`| `text` | Output format | +| `--config` | `string` | `tools/i18n/audit.config.json` | Path to ruleset | +| `--allow-list-add` | (excluded) | — | Editing the allow-list goes through code review only | + +--- + +## Exit Codes + +| Code | Meaning | +|------|------------------------------------------------------------------------| +| `0` | No findings; all scanned files clean | +| `1` | One or more findings (literal user-facing strings outside translations)| +| `2` | Configuration error (config missing/invalid, glob fails) | +| `3` | Internal error (file read failure, regex compile failure) | + +--- + +## Output + +### Text (default) + +``` +resources/js/components/ProjectCard.tsx:42:25 literal in JSX child: "Iniciar proyecto" +resources/js/components/ProjectCard.tsx:48:42 literal in aria-label: "Cerrar formulario" +app/Http/Requests/StoreProjectRequest.php:18:13 literal in messages(): "El título es obligatorio." + +3 finding(s). Extract these into lang/es/.php and reference via __() / t(). +``` + +Lines have the shape `path:line:col : `. The trailing summary line is mandatory. + +### JSON (`--format=json`) + +```json +{ + "findings": [ + { + "path": "resources/js/components/ProjectCard.tsx", + "line": 42, + "column": 25, + "surface": "jsx-child", + "literal": "Iniciar proyecto" + } + ], + "total": 1, + "config": "tools/i18n/audit.config.json" +} +``` + +--- + +## Surface Detection + +The audit recognizes three categories. A literal is flagged iff it lands in a "user-facing" surface AND is not whitelisted by `allowList` AND is not already wrapped in a translation helper. + +### PHP + +| Surface | Detection | +|------------------|------------------------------------------------------------------------------------------------------------------------| +| `controller-render` | Argument to `view(…, [...])` data array, `Inertia::render(…, [...])` props array — string-typed values flag | +| `request-messages` | Return value of `messages()` method on a `FormRequest` subclass | +| `mailer-subject` | Argument to `->subject(…)` on `Mailable` subclasses | +| `mailer-body` | Static text in mail Markdown views (handled via Blade scanner, see below) | +| `notification` | Static strings in `toMail`/`toDatabase`/`toArray` array values on `Notification` subclasses | +| `flash` | Argument to `flash()`, `session()->flash()`, `back()->with()`, `redirect()->with()` when the value is a string literal | + +### Blade + +Any non-whitespace text node in `*.blade.php` that: +- is not inside a `{{ __('…') }}` / `@lang(…)` / `` component slot, and +- is not inside a comment, and +- is not inside a `