Skip to content

i18n(spanish-baseline): centralize Spanish copy + audit + translator skeleton - #3

Merged
Baruch4413 merged 5 commits into
mainfrom
002-i18n-spanish-baseline
May 17, 2026
Merged

i18n(spanish-baseline): centralize Spanish copy + audit + translator skeleton#3
Baruch4413 merged 5 commits into
mainfrom
002-i18n-spanish-baseline

Conversation

@Baruch4413

Copy link
Copy Markdown
Owner

Summary

  • Centralize all user-facing copy under lang/<locale>/ (Spanish primary, English override scaffold).
  • Add tools/i18n/audit.mjs Node ESM binary that detects hard-coded literals in PHP/Blade/TS/TSX with config at tools/i18n/audit.config.json; wire it into .githooks/pre-commit and CI (lint.yml).
  • Ship runtime translator skeleton: PHP via Laravel __()/@lang/trans_choice, React via @/lib/i18n (t() / tChoice()) reading Inertia shared translations prop with locale-aware MessageFormat-lite parity.
  • Add Artisan commands i18n:scaffold-en (mirror es→en, preserve overrides, --copy/--force/--dry-run) and i18n:report (per-locale untranslated counts, --strict, --format=json).
  • TDD coverage across phases 3–7: audit script tests, translator runtime tests (PHP + Vitest), pre-commit hook integration test, parity test, scaffold/report command tests, English-override-rendering test, full-repo clean-audit test (->group('slow')).
  • Docs: CONTRIBUTING.md "Adding a new string" section + CLAUDE.md convention line pointing to specs/002-i18n-spanish-baseline/quickstart.md.

Test plan

  • php artisan test passes (Feature + Unit suites, including tests/Feature/I18n/*)
  • bun run test (Vitest) passes, including tests/js/lib/i18nKeyShape.test.ts
  • bun run i18n:audit reports zero findings on main
  • php artisan i18n:report --strict exits 0
  • Pre-commit hook blocks staged PHP with hard-coded literals (covered by PreCommitHookTest)
  • CI workflows lint.yml and tests.yml green

Baruch Espinoza added 3 commits May 5, 2026 23:34
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.
Translates UI surface to Spanish via lang/es/* dictionaries and
@/lib/i18n helper. DB-persisted enum values translated; case names
remain English. Settings section components renamed to English
(ProfileSection, SecuritySection, NotificationsSection, PrivacySection).

- lang/es: auth, layout, settings, profile, projects, validation,
  errors, accessibility, common, notifications, mailers, passwords,
  pagination, canary
- React pages/components wrapped with t() for all user-facing strings
- TranslationLoader support class
- i18n audit + parity tests under tools/i18n and tests/Feature/I18n
- 216 tests pass; 3 pre-existing failures unchanged
  (ValidationMessageParityTest x2, ProjectTimelineComposerTest browser)
Wraps up feature 002 by extracting every user-facing literal into lang/es/,
mirroring the key set into lang/en/, and locking the centralization invariant
behind an audit + pre-commit + CI gate.

Phase 4 (US2 — centralization invariant):
  - tests/Feature/I18n/AuditCleanRepoTest.php — full-repo audit returns 0 findings
  - tests/Feature/I18n/CopyEditFlowTest.php — Lang::addLines / TranslationLoader stub prove copy edits propagate without code changes
  - tests/js/lib/i18nKeyShape.test.ts — t() returns key + console.error on a constructed-key miss
  - CONTRIBUTING.md — "Adding a new string" entry pointing to the quickstart
  - CLAUDE.md — i18n helper noted as the only sanctioned source of user-facing copy

Phase 5 (US3 — guardrail):
  - .githooks/pre-commit stage 2 runs the i18n audit on staged user-facing files; staged paths matching the audit-config exclude list (tests/, fixtures, vendored bundles, the i18n helper itself) are filtered before invocation
  - .github/workflows/lint.yml runs `npm run i18n:audit` after the frontend lint
  - tests/Feature/I18n/PreCommitHookTest.php — staged-violation, staged-clean, no-staged cases (violation/clean fixtures copied into non-excluded surface paths so the hook filter still routes them to the audit)
  - tests/Feature/I18n/AuditPerformanceTest.php — full-repo audit under the 30s budget (ci-perf group)
  - phpunit.xml excludes ci-perf from the default suite

Phase 6 (US4 — translator skeleton):
  - app/Console/Commands/I18nScaffoldEn.php — mirrors lang/es/ into lang/en/, --copy/--force/--dry-run flags
  - app/Console/Commands/I18nReport.php — lists untranslated keys (text/json), --strict exit code, deterministic sort
  - lang/en/{accessibility,canary,common,errors,layout,mailers,notifications,profile,projects,settings,validation,passwords,pagination,auth}.php scaffolded to full key parity with lang/es/
  - tests/Feature/I18n/{TranslationParityTest,ScaffoldEnCommandTest,ReportCommandTest,EnglishOverrideRendersTest}.php cover parity, scaffold flags, report shape, and locale-switch rendering

Phase 7 (polish):
  - Pint clean, Prettier+ESLint clean on changed JS/TS, full Pest Feature/Unit + Vitest green, audit reports 0 findings
  - quickstart walk-through (synthetic key → scaffold-en → audit → revert) confirmed

Audit configuration grew a `note` field for allow-list entries (single entry
documents the brand "Tekitl"). Audit binary's PHP/Blade/JSX scanners and the
fixtures (including the new violation.php) round out the surface coverage
referenced by the pre-commit and CI gates.
@coderabbitai

coderabbitai Bot commented May 8, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 177 files, which is 27 over the limit of 150.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: eb3c704e-b8b8-47c2-8846-7c0775c94375

📥 Commits

Reviewing files that changed from the base of the PR and between 0a0771e and cfdefc7.

⛔ Files ignored due to path filters (1)
  • tests/Browser/Screenshots/it_clears_the_textarea_and_refreshes_the_timeline_after_posting_a_status_update.png is excluded by !**/*.png
📒 Files selected for processing (177)
  • .env.example
  • .githooks/pre-commit
  • .github/workflows/lint.yml
  • .specify/feature.json
  • CLAUDE.md
  • CONTRIBUTING.md
  • app/ConfidenceLevel.php
  • app/Console/Commands/I18nReport.php
  • app/Console/Commands/I18nScaffoldEn.php
  • app/Http/Controllers/PostController.php
  • app/Http/Controllers/ProjectController.php
  • app/Http/Controllers/ProjectVolunteerController.php
  • app/Http/Controllers/UserProfileController.php
  • app/Http/Middleware/HandleInertiaRequests.php
  • app/Http/Requests/StoreCommentRequest.php
  • app/Http/Requests/TransitionProjectStageRequest.php
  • app/Observers/ReactionObserver.php
  • app/ProjectStage.php
  • app/ReactionType.php
  • app/Support/I18n/TranslationLoader.php
  • config/app.php
  • lang/en/accessibility.php
  • lang/en/auth.php
  • lang/en/canary.php
  • lang/en/common.php
  • lang/en/errors.php
  • lang/en/layout.php
  • lang/en/mailers.php
  • lang/en/notifications.php
  • lang/en/pagination.php
  • lang/en/passwords.php
  • lang/en/profile.php
  • lang/en/projects.php
  • lang/en/settings.php
  • lang/en/validation.php
  • lang/es/accessibility.php
  • lang/es/auth.php
  • lang/es/canary.php
  • lang/es/common.php
  • lang/es/errors.php
  • lang/es/layout.php
  • lang/es/mailers.php
  • lang/es/notifications.php
  • lang/es/pagination.php
  • lang/es/passwords.php
  • lang/es/profile.php
  • lang/es/projects.php
  • lang/es/settings.php
  • lang/es/validation.php
  • package.json
  • phpunit.xml
  • resources/js/app.tsx
  • resources/js/components/app-header.tsx
  • resources/js/components/app-logo.tsx
  • resources/js/components/app-sidebar.tsx
  • resources/js/components/appearance-tabs.tsx
  • resources/js/components/delete-user.tsx
  • resources/js/components/examples/ComboBox.tsx
  • resources/js/components/examples/bento.tsx
  • resources/js/components/examples/comments.tsx
  • resources/js/components/examples/grid-list.tsx
  • resources/js/components/examples/our-team.tsx
  • resources/js/components/examples/profile-heading.tsx
  • resources/js/components/examples/project-history.tsx
  • resources/js/components/nav-main.tsx
  • resources/js/components/two-factor-recovery-codes.tsx
  • resources/js/components/two-factor-setup-modal.tsx
  • resources/js/components/ui/CoverPhoto.tsx
  • resources/js/components/ui/LoginModal.tsx
  • resources/js/components/ui/MobileSidebar.tsx
  • resources/js/components/ui/WelcomeSidebar.tsx
  • resources/js/components/ui/breadcrumb.tsx
  • resources/js/components/ui/comments/Textarea.tsx
  • resources/js/components/ui/dialog.tsx
  • resources/js/components/ui/dropdown-menu.tsx
  • resources/js/components/ui/feed/CommentForm.tsx
  • resources/js/components/ui/feed/FeedPost.tsx
  • resources/js/components/ui/feed/PostActions.tsx
  • resources/js/components/ui/feed/PostComments.tsx
  • resources/js/components/ui/profile/ExperienceSlider.tsx
  • resources/js/components/ui/profile/GooglePlacesAutocomplete.tsx
  • resources/js/components/ui/profile/InformacionTab.tsx
  • resources/js/components/ui/profile/LanguageTagInput.tsx
  • resources/js/components/ui/profile/PostsTab.tsx
  • resources/js/components/ui/profile/ProfileAvatar.tsx
  • resources/js/components/ui/profile/TalentosTab.tsx
  • resources/js/components/ui/proyectos/ImageGallery.tsx
  • resources/js/components/ui/proyectos/ProjectHeader.tsx
  • resources/js/components/ui/proyectos/ProjectRoles.tsx
  • resources/js/components/ui/proyectos/ProjectStageActions.tsx
  • resources/js/components/ui/proyectos/ProjectStageBadge.tsx
  • resources/js/components/ui/proyectos/ProjectTeam.tsx
  • resources/js/components/ui/proyectos/ProjectTimeline.tsx
  • resources/js/components/ui/proyectos/ProjectTimelineEntry.tsx
  • resources/js/components/ui/proyectos/ProjectTimelinePostUpdate.tsx
  • resources/js/components/ui/settings/AvatarUpload.tsx
  • resources/js/components/ui/settings/NotificacionesSection.tsx
  • resources/js/components/ui/settings/NotificationsSection.tsx
  • resources/js/components/ui/settings/PrivacidadSection.tsx
  • resources/js/components/ui/settings/PrivacySection.tsx
  • resources/js/components/ui/settings/ProfileSection.tsx
  • resources/js/components/ui/settings/SecuritySection.tsx
  • resources/js/components/ui/settings/SettingsNav.tsx
  • resources/js/components/ui/settings/SettingsRow.tsx
  • resources/js/components/ui/sheet.tsx
  • resources/js/components/ui/sidebar.tsx
  • resources/js/components/ui/spinner.tsx
  • resources/js/components/user-menu-content.tsx
  • resources/js/hooks/use-two-factor-auth.ts
  • resources/js/layouts/auth/auth-simple-layout.tsx
  • resources/js/layouts/auth/auth-split-layout.tsx
  • resources/js/layouts/constrained-three-column.tsx
  • resources/js/layouts/settings/layout.tsx
  • resources/js/lib/i18n.ts
  • resources/js/pages/auth/confirm-password.tsx
  • resources/js/pages/auth/forgot-password.tsx
  • resources/js/pages/auth/login.tsx
  • resources/js/pages/auth/register.tsx
  • resources/js/pages/auth/reset-password.tsx
  • resources/js/pages/auth/two-factor-challenge.tsx
  • resources/js/pages/auth/verify-email.tsx
  • resources/js/pages/configuracion.tsx
  • resources/js/pages/dashboard.tsx
  • resources/js/pages/proyectos/show.tsx
  • resources/js/pages/settings/appearance.tsx
  • resources/js/pages/settings/password.tsx
  • resources/js/pages/settings/profile.tsx
  • resources/js/pages/settings/two-factor.tsx
  • resources/js/pages/users/show.tsx
  • resources/js/pages/welcome.tsx
  • resources/js/types/global.d.ts
  • resources/views/auth/popup-callback.blade.php
  • routes/web.php
  • specs/002-i18n-spanish-baseline/checklists/requirements.md
  • specs/002-i18n-spanish-baseline/contracts/audit-cli.md
  • specs/002-i18n-spanish-baseline/contracts/shared-payload.md
  • specs/002-i18n-spanish-baseline/contracts/translation-helper.md
  • specs/002-i18n-spanish-baseline/data-model.md
  • specs/002-i18n-spanish-baseline/plan.md
  • specs/002-i18n-spanish-baseline/quickstart.md
  • specs/002-i18n-spanish-baseline/research.md
  • specs/002-i18n-spanish-baseline/spec.md
  • specs/002-i18n-spanish-baseline/tasks.md
  • storage/i18n-extraction/audit-auth.json
  • storage/i18n-extraction/audit-layout.json
  • storage/i18n-extraction/audit-pre.json
  • storage/i18n-extraction/audit-profile.json
  • storage/i18n-extraction/audit-projects.json
  • storage/i18n-extraction/audit-settings.json
  • tests/Browser/ProjectTimelineComposerTest.php
  • tests/Feature/I18n/AuditCleanRepoTest.php
  • tests/Feature/I18n/AuditPerformanceTest.php
  • tests/Feature/I18n/AuditScriptTest.php
  • tests/Feature/I18n/CopyEditFlowTest.php
  • tests/Feature/I18n/EnglishOverrideRendersTest.php
  • tests/Feature/I18n/LocaleConfigTest.php
  • tests/Feature/I18n/MissingKeyFailsTest.php
  • tests/Feature/I18n/PreCommitHookTest.php
  • tests/Feature/I18n/ReportCommandTest.php
  • tests/Feature/I18n/ScaffoldEnCommandTest.php
  • tests/Feature/I18n/SharedTranslationsTest.php
  • tests/Feature/I18n/TranslationParityTest.php
  • tests/Feature/I18n/ValidationMessageParityTest.php
  • tests/Feature/PostTest.php
  • tests/Feature/Project/ProjectTimelineAutomaticEventsTest.php
  • tests/Unit/CoinReactionAggregationTest.php
  • tests/js/components/ProjectTimeline.test.tsx
  • tests/js/components/ProjectTimelinePostUpdate.test.tsx
  • tests/js/components/i18n-a11y-labels.test.tsx
  • tests/js/lib/i18n.test.ts
  • tests/js/lib/i18nKeyShape.test.ts
  • tools/i18n/audit.config.json
  • tools/i18n/audit.mjs
  • tools/i18n/fixtures/.gitkeep
  • tools/i18n/fixtures/developer-strings.php
  • tools/i18n/fixtures/violation.php
  • tools/i18n/fixtures/violation.tsx

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 002-i18n-spanish-baseline

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Comment @coderabbitai help to get the list of available commands and usage tips.

Baruch Espinoza added 2 commits May 8, 2026 20:02
LoginModal calls t() -> usePage(); rendered as a sibling of <App />,
the hook threw "usePage must be used within the Inertia component"
on every mount, unmounting the React root and blanking the page.

Move both into <App>'s children render-prop so they share the same
PageContext.Provider as the resolved page component.
ValidationMessageParityTest passed the Post model to
proyectos.comments.store, whose route binding expects a Project. CI
runs surfaced the latent bug because cross-test AUTO_INCREMENT drift
made post.id != project.id, so route model binding 404'd before
validation ran and the session held no errors.

ProjectTimelineComposerTest pressed the English "Log in" button,
which no longer exists after the Spanish baseline localization.
The login submit is now "Iniciar sesión" (lang/es/auth.php:24).
@Baruch4413
Baruch4413 merged commit 403d680 into main May 17, 2026
3 checks passed
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