feat(i18n): translate the remaining interface strings into Spanish - #1497
Conversation
|
|
||
| const REPO_ROOT = resolve(import.meta.dirname, '../../../..'); | ||
|
|
||
| /** |
There was a problem hiding this comment.
this test should not be required. can you update libui and then use the new option to require full translations at the type levle
gdevenyi
left a comment
There was a problem hiding this comment.
Thanks — this is careful work: the terminology is consistent across all 517 strings, the type guard is the right replacement for a runtime coverage test, and proving it fails when a key is removed checks out. A few items before this can land:
- The upload error page regressed:
t({ en: d.en ?? '', es: d.es ?? '', fr: d.fr ?? '' })inapps/web/src/routes/_app/upload/$instrumentId.tsxrenders an empty description for Spanish readers (plus aconsole.error), because everyUploadErrorinapps/web/src/utils/upload.tsstill carries onlyen/frand an empty string defeats libui's nullish fallback. Please restore the English fallback (es: d.es ?? d.en ?? '', same forfr) or translate the 41 descriptions inupload.ts— and add a unit test for this path, since the type guard structurally cannot see it and the PR has no unit test otherwise. - In
SeriesInstrumentRenderer.tsx:238,es: completionMessage?.en ?? …is correct but looks like a typo — a one-line comment will stop someone "fixing" it later. packages/react-core/AGENTS.md:42still callsLocalizedText"a partial record"; it is total now.- Three docs still teach
t({ en, fr }), which now failstscin the workspaces you covered:.agents/docs/playbooks/promote-to-react-core.md:41,.agents/docs/playbooks/add-web-data-hook.md:57, and.agents/docs/packages/libui.md:41(which should also mentionrequireCompleteTranslations). - The login and setup pages (
apps/web/src/routes/auth/login.tsx,apps/web/src/routes/setup.tsx) hardcode{ en, fr }toggle options, so an admin can activate Spanish but nobody can select it before logging in, and the setup wizard cannot run in Spanish. react-core'sactiveLanguages-drivenLanguageTogglelooks like the drop-in fix; otherwise document the exclusion the same way you documented playground's. - Two small e2e items in
testing/src/specs/admin-settings.spec.ts: the title at line 51 no longer describes a body that now also asserts Spanish nav rendering, and line 82 should use thenav-button-/admin/settingstestid instead of role+name (testing/AGENTS.mdreserves roles for elements with no testid). - Two minor Spanish fixes:
InstrumentSummary.tsx:95—Resumen de resultados del ${title}forces the masculinedelbefore any title; reorder as the French does.SeriesInstrumentContent.tsx:46-48— the/{${…}}template renders a literal3/{5}; it predates your PR in en/fr, but since the new es copies it, this is the moment to fix all three.
If you hand this to Claude Code, Fable 5 is the right size — the fixes span runtime behavior, react-core, e2e and docs, and the PR touches the workspace catalog.
Reviewed at commit 96e9f1d.
#1442 made Español selectable and translated the namespace JSON files, but left 572 inline `t()` calls naming only `en` and `fr`. libui resolves `obj[resolvedLanguage] ?? obj.en`, so those rendered in English with nothing reporting it — the admin panel and its submenu among them. Adds the missing `es` entry at all 572 sites across apps/web, packages/react-core and apps/gateway, reusing the terminology the completed namespace files already established (Panel de control, Centro de datos, Sujeto, Tarea remota) rather than inventing a second vocabulary. Five strings that carry no words — the `{}: {}` format strings whose `fr` exists only for French's space-before-colon — get an entry identical to English, so the set is complete rather than partly deliberate and partly forgotten. A unit test scans all three frontends and fails on an inline call that names `en` but not `es`, which is what keeps this from decaying; the four AGENTS.md files that taught the `{ en, fr }` shape now teach `{ en, es, fr }` and point at it. apps/playground is untouched: it hard-codes its LanguageToggle options as { en, fr }, so Spanish cannot be selected there at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…nforcement libui 6.12.0 adds `requireCompleteTranslations`, a declaration-merging opt-in that makes `TranslationValue` require every language in `LanguageOptions`. Set it in `packages/react-core/src/types.ts`, which every frontend imports — a missing language in any inline `t()` call is now a type error caught by `pnpm lint`, so the runtime test is redundant. - Bump libui to ^6.12.0 in the catalog - Add `requireCompleteTranslations: true` to the existing UserConfig augmentation - Delete `apps/web/src/__tests__/spanish-coverage.test.ts` - Update AGENTS.md references in root, apps/web, apps/gateway, packages/react-core Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ations Enabling type-level enforcement surfaced t() calls and label objects still missing Spanish: LoginPageEditor constants, about-page metadata, upload error titles, file-instrument store messages, series completion message, and the LocalizedText type. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolve the upload error description through `getValueForLanguage` instead of
`d.<lang> ?? ''`. Every `UploadError` carries only English and French, and an
empty string defeats libui's nullish fallback, so a Spanish reader saw a blank
paragraph. The helper prefers the reader's language and falls back through
LANGUAGES rather than to nothing; covered by a unit test, which the type guard
structurally cannot do.
Wire the login and setup pages to react-core's `activeLanguages`-driven
`LanguageToggle` so an admin who activates Spanish can select it before
logging in. Before setup completes the API returns DEFAULT_ACTIVE_LANGUAGES,
so the wizard still offers English and French — now from the contract rather
than a hardcode.
Explain that `es: completionMessage?.en` is deliberate: `CompletionMessage` is
keyed by runtime-core's `Language`, which is `'en' | 'fr'`, because instruments
are authored in those two while Spanish is an interface language.
Two Spanish fixes: lead the instrument summary with the title so `del` cannot
force a gender onto it, and drop the stray braces that rendered the series
counter as `3/{5}` in all three languages.
Docs: `LocalizedText` is a total record now, not a partial one; the three
playbooks that still taught `t({ en, fr })` teach `{ en, es, fr }`, and the
libui reference describes `requireCompleteTranslations`.
E2e: retitle the language test to cover the Spanish nav assertion it grew, and
select the settings submenu by its `nav-button-/admin/settings` testid.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
96e9f1d to
5ae9241
Compare
joshunrau
left a comment
There was a problem hiding this comment.
This branch no longer merges cleanly into main — GitHub reports the merge as conflicting, so the merge result cannot be built or reviewed. CI itself is green.
Please update the branch against current main and resolve the conflicts. Review resumes once it is mergeable.
Reviewed at commit 5ae9241.
…ranslations # Conflicts: # AGENTS.md # apps/web/src/providers/WalkthroughProvider.tsx # apps/web/src/routes/_app/admin/settings.tsx # apps/web/src/routes/_app/admin/users/index.tsx # pnpm-lock.yaml # pnpm-workspace.yaml
|
Updated against current Conflicts resolved
Strings
The Spanish additions ended up in the merge commit itself rather than a separate commit. All of @gdevenyi's review items and @joshunrau's inline comment on the coverage test were already addressed in 5ae9241. Checks
|
joshunrau
left a comment
There was a problem hiding this comment.
This branch no longer merges cleanly into main — GitHub reports it as conflicting, so it can't be reviewed or merged as it stands. CI on the branch itself is green; main has moved since it was last updated.
Please merge or rebase onto current main, resolve the conflicts, and push. Review picks up again once the branch is mergeable and CI is green.
Reviewed at commit 838e91b.
…ranslations Resolves the conflict in `apps/web/src/routes/_app/admin/users/index.tsx`, which `main` reduced to a table by moving the edit form to `admin/users/$userId.tsx` and `UpdateUserForm`: took `main`'s file and re-added `es` to the three inline calls it still has. `requireCompleteTranslations` then rejected 117 call sites `main` added since the last update — the bulk remote assignment wizard, the user permissions editor, the new user page and its form, and four scattered labels. Each gets its `es` entry, reusing the vocabulary already established: tarea remota, sujeto, instrumento. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5257974 to
4d1f15b
Compare
…ranslations Resolves the conflict in `StartSessionForm.tsx`, where 8a69991 moved every check on the custom identifier into the refinement below — zod v4 drops an optional property that failed its own checks before the refinement sees it, so the inline `.min(1).refine(...)` this branch had added `es` to is gone. Took `main`'s version and translated the `$` message where it now lives. `requireCompleteTranslations` also caught the gateway's new landing page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ranslations `main` rebuilt the instrument row in `group/manage.tsx` as a fixed-column grid — 1560 added a creation-date column and moved the repo badge, eye and delete button into columns of their own — so this branch's translated markup no longer applied. Took `main`'s structure throughout and re-translated against it. `requireCompleteTranslations` then named the twelve calls that needed `es`: the strings `main` moved keep the wording this branch already used for them, and the ones 1560 added (Added, Available to, All groups, Another group, Create series and the series description) are new. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ranslations # Conflicts: # packages/react-core/src/components/ErrorPage/ErrorPage.tsx # testing/src/specs/admin-settings.spec.ts
Summary
#1442 made Español selectable and translated the 11
apps/webnamespace JSON files. It did not touch the inlinet()calls, and there were 572 of them naming onlyenandfr.libui resolves
obj[resolvedLanguage] ?? obj.en, so every one of those rendered in English for a user reading in Spanish, silently. The admin panel and its submenu — reported by @thomasbeaudry — were among them:This adds the missing
esentry at all 572 sites.Scope
apps/webpackages/react-coreapps/gatewayapps/playgroundis deliberately excluded (107 more sites).Header.tsxandIndexPage.tsxhard-code theirLanguageToggleoptions as{ en, fr }— it uses libui's toggle directly rather than react-core'sactiveLanguages-driven one — so Spanish cannot be selected there at all. Translating it means widening that toggle first, which is a behaviour change to a second app and belongs in its own PR.Terminology
The completed namespace files already establish Spanish vocabulary, so the inline strings reuse it rather than inventing a parallel one: Panel de control (Dashboard), Centro de datos (Data Hub), Sujeto (Subject), Tarea remota (Remote Assignment), Iniciar una sesión (Start Session), Administrar instrumento, Comuníquese con el administrador de la plataforma. Register is usted throughout, matching the existing files.
Three strings needed resolving per call site rather than globally, because English collapses distinctions Spanish does not:
'Subject'→ Asunto inEmailTemplateEditor(an email's subject), Sujeto inadmin/usersandInstrumentSummary(the participant — the existingfrthere isClient).'Default'→ Predeterminada on a template row, Predeterminado on a font size.Five strings carry no words: the
'{}: {}'/': 'format strings whosefrvariant exists only because French puts a space before a colon. Spanish follows the English convention, so they get an entry identical toen— explicit rather than left half-deliberate, half-forgotten.Keeping it
Translating 572 strings once is worth little if the 573rd ships untranslated next week.
apps/web/src/__tests__/spanish-coverage.test.tsparses everyt({…})in all three frontends and fails on one that namesenbut notes, reporting the file and the call:It lives in
apps/webbecause that is the only one of the three frontends with a vitest project. The scanner is quote- and comment-aware — a brace inside a string is text, not structure — and two of its three cases assert that directly, so the guard cannot pass by failing to parse.The four
AGENTS.mdfiles that taught the{ en, fr }shape now teach{ en, es, fr }and point at the test, so a contributor learns the rule before the build tells them. (packages/react-core/AGENTS.mdalso still describedLocalizedTextas{ en?, fr? }; it has been keyed byLanguagesince #1442.)Also
Dropzone's'Invalid Input'andUploadProgressBar's upload counter were English-only before this — addingesalone would have left them conspicuously{ en, es }with no French, so both got their missingfrtoo.Test plan
pnpm lint— 33/33 workspaces cleanpnpm test— 657 passed, 1 skipped (3 new)pnpm test:e2e— 142 passed, full suite, forced past turbo's cacheThe e2e in
admin-settings.spec.tsactivates Spanish, switches the toggle to Español, and asserts the nav group reads Panel de administración and its submenu Configuración de la aplicación — the exact reported case. It extends the existing language test rather than adding a new one:activeLanguagesis a single instance-wide document andfullyParallelis on, so a second test mutating it would race the "only one language left" assertion.Both new tests were verified to fail when the translations are removed, rather than assumed to be checking anything.
🤖 Generated with Claude Code