feat(i18n): Fluent + Askama localization framework (LC-100) #233
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/lc-100-i18n"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The i18n framework for LC-100: Fluent message catalogs + an Askama filter, per-user locale, locale-resolution middleware, a CI key-gate, and contributor docs. Validated end-to-end on the auth (login) and settings pages with English + Spanish.
Externalizing the remaining ~150 templates' strings + completing the Spanish catalog is a large mechanical follow-on tracked separately (see the new issue). The CI gate only checks keys that are referenced, so it stays green as externalization proceeds incrementally.
What lands
server/src/i18n.rs): catalogs embedded at compile time viafluent-templates::static_loader!(single-binary preserved);t/tn(count)Askama filters that read atokio::task_local!current locale;resolve()picks user pref ->Accept-Language-> English, with unknown-locale fallback (a render never breaks). Catalogs atserver/locales/{en,es}/*.ftl- Fluent merges every.ftlper locale, so the catalog can be split by area.resolve_localeinserver/src/auth.rs), layered insideinject_user, scopesCURRENT_LOCALEfor the request. Templates localize with{{ "key"|t }}(note: no space before the pipe - Askama parses"x" | tas bitwise-or) without threading a locale through every view struct. Each view module with such a template doesuse crate::i18n::filters;.users.localecolumn (auth migration 0024) threaded throughUserRecord/User+set_user_locale; Settings -> Language dropdown +POST /settings/language(empty = use browser language).server/tests/i18n_catalog.rs): fails if a template references a key absent from English; fails if any locale's key set differs from English (full-coverage check).docs/i18n.md- how to add a locale, key conventions, the filter-import rule, v1 scope.Acceptance criteria (this framework PR)
users.locale).Accept-Language.Verification
cargo fmt --allclean; i18n unit tests +i18n_cataloggate pass;just test+just test-saasgreen (incl. migration-list drift fix: auth0024added to 22 hand-rolled test pools).Core i18n machinery for the server-rendered UI. String externalization across all templates continues on this branch; this commit lands the framework + first externalized pages (auth login, settings) with the CI gate green. - i18n module (server/src/i18n.rs): Fluent catalogs embedded via fluent-templates static_loader!; `t` / `tn(count)` Askama filters reading a tokio task-local current locale; resolve() picks user pref -> Accept-Language -> English with unknown-locale fallback. Catalogs at server/locales/{en,es}/*.ftl (Fluent merges all .ftl per locale, so they can be split by area). - resolve_locale middleware (server/src/auth.rs), layered inside inject_user, scopes CURRENT_LOCALE for the request so templates localize with `{{ "key"|t }}` (no-space pipe; Askama parses `"x" | t` as bitor) without threading a locale through view structs. - users.locale column (auth migration 0024) threaded through UserRecord/User + set_user_locale; Settings -> Language dropdown + POST /settings/language. - CI gate (server/tests/i18n_catalog.rs): every template-referenced key must exist in English; every locale must match English's key set exactly. - docs/i18n.md: contributor guide (add a locale, key conventions, the filter-import requirement). - Migration-list drift: 0024 added to the 22 hand-rolled auth-pool test files. just test + just test-saas green; cargo fmt --all + i18n unit/catalog tests pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>