Skip to content

[WKP-36] Add Romanian localization#57

Open
SteadfastKnight wants to merge 17 commits into
mainfrom
feature/WKP-36-Add-Romanian-localization
Open

[WKP-36] Add Romanian localization#57
SteadfastKnight wants to merge 17 commits into
mainfrom
feature/WKP-36-Add-Romanian-localization

Conversation

@SteadfastKnight

Copy link
Copy Markdown
Owner

WKP-36 — Romanian localization

Adds full Romanian (ro) localization alongside English (en) across the WordKeep app — Angular client and Laravel API.

Client (Angular + Transloco)

  • Localized all feature pages, dialogs, shell, auth/profile, recent-activity, sort/rename dialogs, and home variants.
  • Lazy Transloco scopes per feature + an always-loaded root bundle; ICU plurals for count-sensitive strings.
  • Localized genres, language names, and confirmation dialogs.
  • Locale-aware timestamps (RO 24h + day-first; EN unchanged) via a shared formatDateTime/formatLocaleDate helper.
  • Fixed the IGNORED page overlay (was hardcoded in CSS content) and dialog button styling leaks.
  • Console layout: badges (status/renamed/type/lang/wrong-lang) redesigned as borderless lowercase ANSI-dot tokens (distinct from scriptorium); status bar shows localized palette + theme labels; RO nav tokens.
  • Localized document status badge; personalisation subtitle now mentions language; fixed dictionary word/badge alignment.

Server (Laravel)

  • Localized transactional emails, API response messages, and validation field names.
  • Queued mailables stamped with the request locale so emails send in the user's language.

Tooling

  • scripts/check-i18n.mjs (npm run check:i18n) — guards against hardcoded template text.
  • scripts/translate-i18n.mjs (npm run i18n:translate) — seeds missing ro.json keys from en.json via Gemini (merge mode; never overwrites reviewed strings).

Verification

  • Client: npm test (1082 passing), npm run check:i18n, npm run build — all green.
  • npm run i18n:translate -- --dry-run reports all 13 scopes up to date (full RO key coverage).

🤖 Generated with Claude Code

SteadfastKnight and others added 17 commits June 2, 2026 14:46
Frontend: Transloco runtime i18n with lazy per-route scopes; locale signal on
UserPreferencesService persisted to localStorage + /api/preferences;
Accept-Language interceptor; locale->Transloco bridge in app.config. Language
switchers (profile dropdown + personalisation). Charter landing English layer
locale-aware + EN/RO swallowtail flags. Locale-aware numeric dates.

Backend: nullable user_preferences.locale + migration; SetLocale middleware;
lang/ro for auth/validation/passwords/pagination + emails; 6 mailables and
blades localized; User implements HasLocalePreference.

Tooling: scripts/translate-i18n.mjs (Gemini), check-i18n.mjs CI guard +
allowlist. Tests: PHPUnit LocalizationTest, preferences locale cases,
interceptor/prefs unit specs, landing + locale-switch e2e.

Phase 6 (per-template string extraction) deferred; pending templates allowlisted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract strings from the 6 auth pages (login, register, forgot/reset
password, verify-email, verify-email-change) into a new `auth` Transloco
scope (EN + RO), and the profile shell + personalisation page into the
`profile` scope. Components use the scoped t() directive; client-side error
messages go through TranslocoService.translate / reactive error keys.

Harden check-i18n.mjs to ignore Angular control-flow (@if/@switch/@case) —
this also revealed home/layout/confirmation-dialog/user-menu-dropdown were
already clean. Allowlist trimmed 45 -> 33; specs updated with the Transloco
testing module.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduce a `shared` Transloco scope for reusable cross-page components,
provided at the component level so it overrides the ambient route scope.
Migrate sort-dropdown and rename-dialog; update the 5 list-page specs that
render sort-dropdown to include the Transloco testing module. Allowlist 33 -> 31.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the dashboard recent-activity strings into the `shared` scope, including
the TS-computed work-type badges and relative-time labels (via
TranslocoService.translate, reactive under the scoped directive). Update home +
recent-activity specs for the cascade. Allowlist 31 -> 30.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ants (Phase 6)

Complete Phase 6 via a multi-agent workflow: extract every remaining template
into Transloco scopes (EN + RO) — documents, extraction, page-linking, book-view,
translation (each + reader), dictionary, profile-info/security, the 4 shared
dialogs, the 6 layout shell variants, and the 6 home dashboard variants. Each
component uses a component-level provideTranslocoScope; new scopes registered in
the testing module; cascade specs (layout dispatcher, readers) updated.

Harden check-i18n.mjs: handle Angular control-flow conditions containing </>
comparisons and @else-if, and skip attribute/expression leakage. Allowlist now
holds only 3 intentional templates (charter + console/scriptorium decorative
Latin/CLI). All 1073 unit tests pass; guard green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Install/configure @jsverse/transloco-messageformat so ICU plural syntax works;
the extraction scope already used it (was rendering literally). Convert the
bookView documentCount/pageCount from the English {{plural}} suffix hack to
proper ICU one/few/other Romanian forms.

Add a global languages.<code> map (EN + RO) and repoint every per-component
language-name lookup (document-detail, book-view(+reader), translation(+reader),
new-translation-dialog, recent-activity) at it via translate(), replacing the
duplicated English maps. Translate document genres via the documents scope.

All 1073 unit tests pass; i18n guard green (3 intentional templates allowlisted).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ds + personalisation options

- Stamp request locale on all queued mailables (verify/reset/password-changed/email-change/2FA)
- Add lang/{en,ro}/messages.php; replace hardcoded controller literals with __() (full sweep, 9 controllers)
- Populate validation attributes array (RO field names) so :attribute localizes
- Localize layout + palette label/blurb via transloco (profile/{en,ro}.json + template)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Localize ConfirmationService helpers (delete + OCR/extract overrides) via global confirmations.* keys; add localization-guard spec
- Fix dialog confirm/cancel buttons inheriting global auth .btn-primary/.btn-secondary styles (uppercase, letter-spacing, width:100%, margin-top) — reset in rename/confirmation/new-translation/avatar-crop dialogs
- Rename dialog: group cancel+save, widen card so restore+cancel+save fit one row

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Overlay hid its localized text (font-size:0) + painted a ::after with
hardcoded content:'IGNORED'. Render t() in a .ignored-overlay__badge span
(uppercase via CSS) so RO shows IGNORATĂ. extraction + page-linking readers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Card formatDate + profile expiry + compendium header date hardcoded
en-US (AM/PM, month-first). Add formatLocaleDate/formatDateTime helpers
(en->en-US, ro->ro-RO) driven by transloco.getActiveLang(). RO now 24h +
RO month/order; EN unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Badges (status/renamed/type/lang/wrong-lang) become borderless lowercase mono tokens with a currentColor dot, distinct from scriptorium cartouches. Status bar shows localized palette + theme labels; RO nav tokens (doc/extr/leg/viz/trad/dicț).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ry alignment

Document status badge now localized (uploaded/processing/ready/failed). Personalisation subtitle mentions language. Dictionary word/badge vertically aligned (align-items: center).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wire scripts/translate-i18n.mjs (Gemini en->ro seeding) as npm run i18n:translate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
playwright install hung at 100% (download done, extraction stalled) due to a yauzl regression on Node 24.16+/26.x; fixed in Playwright 1.60.0. Was pinned to 1.58.2. Affected CI (node lts/*) and local (Node 26). Verified chromium install now completes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The test created a lone page (page_number=1) expecting link_to_next_page to stay null, but DocumentFactory's page_count is random (1-50). When page_count==1, DocumentPage's creating hook stamps the last page with DOCUMENT_END, making the page linked and flaking the assertion (~2% of runs). Pin page_count=2 so page 1 is never the last page.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Required <lang> arg + self-contained LANG_NAMES map; parameterize prompt,
output paths and logs. Adapt ICU plural categories to target CLDR; make
placeholder parity ICU-aware. Retry transient Gemini failures (429/5xx,
network, bad body) with backoff. Update README + memory mirror.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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