Repository navigation
feat/admin UI french i18n - #217
edimitchel wants to merge 4 commits into
Conversation
|
All contributors have signed the CLA. ✅ |
|
I have read the CLA Document and I hereby sign the CLA |
|
recheck |
There was a problem hiding this comment.
Important
The port is thorough — catalog parity, placeholder checks, svelte-check and a production build all pass — but it removes every clickable setup link from the settings pages and regresses pluralization that already worked. Please restore those before merging.
Reviewed changes
- i18n layer — new store-free catalog (
catalog.ts) plus a Svelte locale store and$t/trhelpers (index.ts), withen.jsonas source of truth and a completefr.json; locale resolved fromlocalStorage/navigator.languagesand selected in Settings → Profile. - Admin routes and components — hardcoded English replaced throughout; label arrays (
TABS,LOCATION_TYPES,REASON_LABELS, nav lists) made$derivedso they update on locale change; calendar/date formatting switched to the admin locale. - Tests and tooling — Vitest catalog test (CI) plus a duplicate
node:testvariant (manual command),allowImportingTsExtensions, and a Vitest exclude. - Docs — CHANGELOG, CONTRIBUTING and ARCHITECTURE updated for the admin catalog.
⚠️ Setup guidance lost all its clickable links
The translation replaced sentences that embedded anchors with plain catalog strings, so operator-facing setup pages now name destinations without linking them (Google Cloud console, Stripe dashboard, R2/B2/S3, LiveKit/Deepgram consoles, Zoom marketplace, docs/VIDEO.md). The stale settingsEmailLink / stripeLink keys suggest a link-splitting approach was started and abandoned. This is unrelated to translation and should be restored.
Technical details
# Setup links replaced by plain text
## Affected sites
- `frontend/src/routes/settings/google/+page.svelte:80` — `settings.google.setup.step1` lost the console.cloud.google.com link; `step3Testing` lost "Google's guide".
- `frontend/src/routes/settings/payments/+page.svelte:68` — Stripe Dashboard → API keys link gone.
- `frontend/src/routes/settings/storage/+page.svelte:63` — Cloudflare R2 / Backblaze B2 / AWS S3 links gone.
- `frontend/src/routes/settings/video/+page.svelte:105` — cloud.livekit.io and self-hosted docs links gone; the webhook step lost the LiveKit docs link; the Deepgram console link is gone.
- `frontend/src/routes/settings/zoom/+page.svelte:55` — Zoom App Marketplace, `docs/VIDEO.md` and `docs/ZOOM.md` links gone.
- `frontend/src/routes/event-types/[slug]/+page.svelte:799,836` — the invite hint lost its `Settings → Email` link and the price hint lost its `Stripe` link.
- Unused leftovers: `eventTypeEditor.invite.settingsEmailLink`, `eventTypeEditor.notifications.smtpNotConfiguredLink`, `eventTypeEditor.price.stripeLink`.
## Required outcome
- External and internal anchors are clickable again, with their visible text still translated.
## Suggested approach
- Split each sentence into prefix / link-text / suffix keys and render `<a href="…">{$t(linkKey)}</a>` between them. This keeps markup out of the catalogs and avoids `{@html}` for authored strings.deepseek-v4.1-flash | 𝕏
There was a problem hiding this comment.
Important
The plural, prefix, and date fixes all verify correctly. One item from the previous review is still open: the operator setup pages remain unlinked.
Reviewed changes
- Restored plural handling —
translatenow selects.one/.otherviaIntl.PluralRuleswhen a numeric{count}is passed, withtranslatePlural/translatePluralPairhelpers; the five affected catalog entries became plural objects. - Restored the configured recordings prefix —
settings.storage.recordings.subtitletakes a{prefix}placeholder wired fromrecordings_prefix. - Made date formatting locale-aware —
api-keys,connections,members, andwebhooksnow format throughlocaleTag()instead of the OS locale. - Translated the French Google redirect heading —
settings.google.redirectUris.titleis nowURI de redirection autorisées. - Extended the tests — plural-selection and "no baked
(s)" checks were added to both the Vitest andnode:testsuites (17 passing).
⚠️ Setup pages still have no clickable links
The original commit replaced sentences that embedded anchors with plain catalog strings, and the new commits did not touch those pages: operators reading Google, Stripe, storage, LiveKit, Deepgram, or Zoom setup guidance get destinations named but not linked. This is the outstanding half of the previous review and is unrelated to translation, so it should be restored before merging.
Technical details
# Operator setup links are still plain text
## Affected sites
- `frontend/src/routes/settings/google/+page.svelte` — console.cloud.google.com and Google's guide links
- `frontend/src/routes/settings/payments/+page.svelte` — Stripe Dashboard → API keys
- `frontend/src/routes/settings/storage/+page.svelte` — Cloudflare R2 / Backblaze B2 / AWS S3
- `frontend/src/routes/settings/video/+page.svelte` — cloud.livekit.io, self-hosted docs, LiveKit webhook docs, Deepgram console
- `frontend/src/routes/settings/zoom/+page.svelte` — Zoom App Marketplace, `docs/VIDEO.md`, `docs/ZOOM.md`
- `frontend/src/routes/event-types/[slug]/+page.svelte` — `Settings → Email` and `Stripe` inline links
## Required outcome
- External and internal anchors are clickable again, with their visible text still translated.
## Suggested approach
- Split each sentence into prefix / link-text / suffix catalog keys and render `<a href="…">{$t(linkKey)}</a>` between them; remove the now-unused `settingsEmailLink` / `smtpNotConfiguredLink` / `stripeLink` keys or wire them up.deepseek-v4.1-flash | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
This run reviewed the delta since the prior Pullfrog review (0409035), i.e. commit b21d28a.
- Restored operator setup links — the guidance sentences on the calendar, Google, payments, storage, video, Zoom, and event-type invite/price/notification surfaces render real
<a>tags again instead of plain text. - Added a safe link-splitting layer —
splitLinkedplus theLinkedTextcomponent split a catalog string on named{placeholder}slots, keeping translations plain text and never interpreting catalog content as HTML. - Wired the previously-stale link-text keys —
settingsEmailLink,stripeLinkandsmtpNotConfiguredLinkare now used by the restored links. - Extended the tests — en/fr placeholder parity for linked sentences, plain-text link keys, a no-HTML-anchors guard, and
splitLinkedunit tests, in both the Vitest and node suites. - Documented the convention — CONTRIBUTING now explains that link slots are
{…}placeholders rendered byLinkedText.
Verified on b21d28a: pnpm run check reports 0 errors/warnings, pnpm run build succeeds, and the catalog node suite passes 22/22.
deepseek-v4.1-flash | 𝕏
|
The CLA check is failing because the commits are authored by You signed as @edimitchel, and that signature is fine. But the action works by mapping each commit's author email to a GitHub user, then checking whether that user has signed. To fix it, re-author the commits with the email tied to your GitHub account: git config user.name "Your Name"
git config user.email "you@example.com" # the email on your GitHub account
git rebase --exec 'git commit --amend --no-edit --reset-author' origin/main
git push --force-with-leaseIf you use GitHub's privacy address, This is not a rule aimed at Cursor. It is the same thing we do for our own AI-assisted commits (Claude, OpenCode): the commit author is the human, so the CLA applies to them. Point Cursor at your identity and it will behave the same way. |
b21d28a to
266da5d
Compare
|
Done @shockalotti ! |
shockalotti
left a comment
There was a problem hiding this comment.
Approved the pending CI runs (this fork PR was sitting in `action_required`, so build/check/validate had never executed). They are now green: build ×2, check, validate, arm64-smoke, cla, pullfrog, SBOM. Worth saying plainly since the PR looked reviewed-but-unverified before.
The design holds up on re-read: separate client-side catalog, English as source of truth with per-key fallback, named `{placeholders}` via LinkedText rather than `{@html}`, and adding a locale is copy-the-JSON plus two registrations.
One gap before merge: `CLAUDE.md` still tells future agents the opposite of what this PR does. It is not in the diff, so merging leaves the repo's own guidance contradicting the code — that file is what agents read first.
Current text (CLAUDE.md:137):
```markdown
title/description) are translated. NOT translated: the admin SPA, the LiveKit room
(`livekit-room.html`/`.js`, ~45 hardcoded strings - it has its own asset pipeline and shares
no string plumbing with the Go templates), and admin-authored content (event names,
descriptions, questions, custom email copy).
```
Suggested replacement:
```markdown
title/description) are translated. The admin SPA has its own separate catalog
(`frontend/src/lib/i18n/`, client-side, `en` + `fr`, English fallback per key) — a
different system from the booker locales here; see ARCHITECTURE §23. NOT translated:
the LiveKit room (`livekit-room.html`/`.js`, ~45 hardcoded strings - it has its own
asset pipeline and shares no string plumbing with the Go templates), and admin-authored
content (event names, descriptions, questions, custom email copy).
```
If you'd rather not touch it in this PR, say so and I'll do it as a follow-up immediately after merge — but it does need to land with this change, not later, or it will rot.
Also worth noting for the record: the `/book` Polish locale landed separately in #220. As you say in #218, that gives Polish bookers nothing in the admin — a `pl.json` catalog here would be the follow-up.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
This run re-reviewed the delta since the prior review (266da5d): commit 36c77ef, a documentation-only change touching one file (+6/−4).
CLAUDE.mdnow describes the admin catalog — the i18n section no longer tells readers the admin SPA is untranslated; it points atfrontend/src/lib/i18n/(client-side,en+fr, per-key English fallback) as a distinct system from the booker locales, and defers to ARCHITECTURE §23, whose locale table and prose already document it.
deepseek-v4.1-flash | 𝕏
|
Thank you, this is genuinely strong work. I had it reviewed in depth rather than skimmed, and the verdict is good work, no blocker. One thing I need from you: please rebase onto current What the review verified independently, so you know it was actually read:
Do not act on the following. I am taking these myself after merge so you are not asked for another round:
French corrections I will also apply: Provenance: as with the existing booker locales, we will record in the CHANGELOG and CONTRIBUTING that this is a machine-assisted draft with no native review yet. If you happen to know a French speaker who would read the admin end to end, that would be worth more than any of the fixes above. On the architecture question, I had suggested folding the admin catalogue into the public locale files. The review made a better, quantified case against it and I am persuaded: 169 shared keys across 11 languages against 1,324 admin keys in 2 languages means unification saves roughly 11% of translator effort while forcing a schema migration on both sides and putting admin strings in the binary that is served to the public. We will keep the files separate, standardise terminology with a glossary, and revisit only when a second admin locale lands. Rebase and I will take it from there. |
The SvelteKit admin is no longer English-only. A small client-side catalog (English source of truth, French by a native speaker) drives chrome, list pages, the event-type editor, settings, and auth screens. Locale is chosen in Settings → Profile (localStorage) with a navigator.languages fallback; missing keys fall back to English. Dates and times follow the admin locale. The LiveKit room and booker-facing catalogs are unchanged.
Use Intl.PluralRules (.one/.other) instead of baked "(s)" strings, pass the configured recordings prefix into storage copy, translate the Google redirect-URI heading, and format admin dates with localeTag().
Split catalog sentences on {placeholders} and render real <a> tags via
LinkedText so Google, Stripe, storage, LiveKit, Deepgram, Zoom, and
in-app Settings links work again in both locales without {@html}.
36c77ef to
b9531ac
Compare
|
Rebased onto current I'll be using Calnode personally with the French admin UI, so I'll fix any translation mistakes I run into. Once the catalog has been properly reviewed by a human, we can drop the machine-draft note for French. |

Porting french translation into the application for the back-office interface
First step toward translating the whole admin interface: adds the admin i18n catalog and a complete French translation. Related to #216.
Closes #218