github olivierlambert/calrs v1.8.0
calrs 1.8.0 — internationalization (i18n)

5 hours ago

Internationalization release. The public booking flow and the highest-volume guest emails (confirmation, reminder, cancellation) are translated. Six locales ship out of the box, with English as the source, French human-translated by maintainers, and Spanish / Polish / German / Italian AI-seeded as starting points for native-speaker refinement on Hosted Weblate.

Added

  • Six-language UI — public booking flow (slot picker, booking form, confirmation, cancel/decline/approve/claim/reschedule pages, theme-toggle chrome) renders in English, French, Spanish, Polish, German, or Italian. Translations live in Fluent .ftl files under i18n/{lang}/main.ftl, embedded into the binary at compile time. Single-binary deploy preserved.
  • Automatic language detection — guests get their browser's Accept-Language (RFC 7231 with q-weights honoured); logged-in users override via a Language dropdown in Profile & Settings (migration 047_user_language).
  • Translated guest emails — confirmation, reminder, and cancellation emails render in the language captured at booking time. Migration 048_booking_language adds bookings.language TEXT. The reminder background task already loads it, so a reminder fired days after the booking still picks the right language.
  • Server-side date localizationformat_month_year and format_long_date helpers render dates with locale-specific patterns: Tuesday, March 12, 2026 (EN), mardi 12 mars 2026 (FR), martes, 12 de marzo de 2026 (ES), Montag, 12. März 2026 (DE), lunedì 12 marzo 2026 (IT). The format pattern itself is a Fluent message, so word order is a translation choice.
  • Hosted Weblate integration — translators contribute via hosted.weblate.org/projects/calrs without git or Rust knowledge. Commits flow back to the long-lived i18n branch via the Weblate GitHub App.
  • Translation-quality table in README — explicitly distinguishes human-translated French from AI-seeded locales and points readers at Weblate as the contribution path.

Fixed

  • Docker image build broken by the i18n scaffolding — the multi-stage Dockerfile didn't COPY i18n/, so include_str! on the embedded .ftl files failed at release-image build time even though local cargo build worked. One-line fix landed before this release.

Internal

  • Migrations 047_user_language and 048_booking_language
  • New src/i18n.rs: concurrent FluentBundle per locale in OnceLock, Accept-Language parser with q-weight sort, minijinja t(key, **kwargs) global, is_supported / resolve / supported_with_labels helpers, date-formatter pair
  • 30 templates and ~25 web handlers wired through, each handler computes lang once via crate::i18n::detect_from_headers and threads it into render contexts
  • BookingDetails and CancellationDetails gain guest_language and host_language fields; both derive Default so existing call sites use ..Default::default()
  • 569 tests total (up from 545 in 1.7.0), including coverage for Accept-Language parsing, date-formatter output across locales, and full-locale parity for Spanish, Polish, German, Italian
  • Long-lived i18n branch documented in CLAUDE.md as the working branch for translator commits and new translatable-string features

Known limitations

  • Host-side emails (notification, reminder, cancellation, approval-request, decline) remain English. Infrastructure (host_language field) is in place; translation pass scheduled for a follow-up.
  • Pending-notice / decline-notice / reschedule guest emails not yet translated.
  • decline_booking_by_token and dashboard-host-cancel paths don't yet load bookings.language; cancellation emails sent from those paths fall back to English.
  • Polish month names are nominative, so date contexts read informally (27 kwiecień 2026 instead of grammatical 27 kwietnia 2026). Native-speaker refinement on Weblate is welcome.
  • Dashboard, admin panel, and CLI command output remain English.

Full changelog: https://github.com/olivierlambert/calrs/blob/v1.8.0/CHANGELOG.md#180---2026-04-26

Don't miss a new calrs release

NewReleases is sending notifications on new releases.