Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,15 @@ prefer additive, nullable/defaulted columns.

## Translations

Calnode ships 9 locales (`en es fr fr-CA de it pt nl sv`) across the booker-facing surfaces:
Calnode ships 11 locales (`en es fr fr-CA de el it nl pl pt sv`) across the booker-facing surfaces:
booking page, manage/reschedule page, embed widget, the four emails, and the calendar
invite. The admin UI and the built-in video room are English-only.

**Translation PRs are very welcome** - both new languages and corrections to existing
ones. **Every non-English locale is currently a machine draft with no native review**, so
if you speak one of them, fixes are genuinely valuable and will be merged readily. Small,
single-language PRs are easier to review than sweeping ones.
ones. **Most non-English locales are machine drafts with no native review, and none has
had a full native read** (Polish was contributed and grammar-checked by a native
speaker), so if you speak one of them, fixes are genuinely valuable and will be merged
readily. Small, single-language PRs are easier to review than sweeping ones.

**Adding a language is adding one file:** `internal/i18n/locales/<code>.json`. No Go,
template, or frontend change is needed - `init()` globs the directory, and the language
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,14 @@ domains, Resend email, Google & Microsoft OAuth, Litestream backups, troubleshoo
- **Zoom** — per-host OAuth; a Zoom-located booking mints a meeting under the assigned host's account
- **Built-in video meetings (LiveKit)** — in-browser rooms as a booking location (no app or account for guests); host controls (end-for-all, hand-off **and reclaim** host, attendee screen-share toggle), **meeting recording** straight to your own **Litestream backup bucket** (the same one
you already use for DB backup — no extra storage to provision) with in-app downloads, **recording consent** (notice + consent-or-leave), and an **AI notetaker** (Deepgram transcript → LLM notes). Headless-consumable: MCP `get_meeting_notes`/`get_transcript` + `recording.completed`/`transcript.ready`/`notes.ready` webhooks. BYO LiveKit endpoint (Cloud or self-hosted); configured in Settings → Video — see [docs/VIDEO.md](docs/VIDEO.md)
- **9 languages** on every booker-facing surface - booking page, manage/reschedule page,
- **11 languages** on every booker-facing surface - booking page, manage/reschedule page,
embed widget, all four emails, and the calendar invite: **English · Spanish · French ·
Canadian French · German · Italian · Portuguese · Dutch · Swedish**. Picked from
Canadian French · German · Greek · Italian · Dutch · Polish · Portuguese · Swedish**. Picked from
`Accept-Language` with a footer switcher and an operator-set fallback language; the
booker's choice is stored on the booking, so reminders arrive in the language they
booked in. Adding a language is adding one JSON file - no code change. *(The admin UI and the built-in video room are
English-only. Non-English translations are machine drafts without native review -
English-only. Most non-English translations are machine drafts and none has had a full
native review; Polish was contributed and grammar-checked by a native speaker -
corrections by PR are very welcome.)*
- Embeddable booking widget (Shadow-DOM web component; inline + popup)
- Members, roles (owner/admin/member), email-token invitations
Expand Down
16 changes: 11 additions & 5 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -987,11 +987,14 @@ Each account can set `booking_accent` in its profile. The default preserves the
patching. The **public** booking surfaces are unaffected and are verified on mobile;
this is admin-only. Deferred 2026-08-22, not a regression.
- **LiveKit room is not translated** - the booking surfaces, emails and calendar invites
ship in 9 languages (§23), but the in-browser meeting UI is ~45 hardcoded English
ship in 11 languages (§23), but the in-browser meeting UI is ~45 hardcoded English
strings. It has its own vanilla-JS asset pipeline and shares no string plumbing with
the Go templates, so it needs a small runtime `t()` of its own. Separate work, not hard.
- **Plural rules are 2-form only** (§23) - shipping Polish, Russian or Arabic correctly
needs a real CLDR plural-category selector first.
- **Plural rules are 2-form only** (§23) - every plural-bearing key splits on `n == 1` and
nothing else. Polish ships despite that because its keys dodge the missing categories:
durations use invariant abbreviations (`godz.`, `min`), and `hostsLabel`'s
`other`/`others` pair (`inny`/`innych`) is correct for every count. Russian or Arabic
genuinely do need a CLDR plural-category selector first.
- **OAuth app verification** — the Google and Microsoft apps should go through
publisher verification before wide public use to avoid "unverified app" warnings.

Expand Down Expand Up @@ -1329,8 +1332,11 @@ Two traps:

### Translation quality

**Every non-English locale is an LLM draft with no native review.** The structure is
verified by the guards above; the *wording* is not. Register was chosen per language rather
**Most non-English locales are LLM drafts with no native review, and none has had a full
native read.** The structure is
verified by the guards above; the *wording* is not. `pl` is the partial exception: it was
contributed and grammar-checked by a native speaker in #216/#220, though two developer
edits (the CLDR date forms and `innych`) went in on top of his text. Register was chosen per language rather
than uniformly (`fr`/`de`/`it`/`pt` formal, `es`/`nl`/`sv` informal), matching what business
booking pages do in each market, but that too is unreviewed. Corrections via PR are welcome
and are the expected path to improving them. Do not describe a language as production-quality
Expand Down
Loading