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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
11 changes: 10 additions & 1 deletion .claude/memory/ferroui.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: ferroui
description: "Every console draws in FerroUI, pinned exactly; one uniform design, shared components, all four consoles move in lockstep with every FerroUI release, screenshots read and reviewed; owner 2026-10-18"
description: "Every console draws in FerroUI, pinned exactly; one uniform design, shared components, all four consoles move in lockstep with every FerroUI release, screenshots read and reviewed, no user-visible string outside the catalogs; owner 2026-10-18 and 2026-10-19"
metadata:
type: project
---
Expand Down Expand Up @@ -33,3 +33,12 @@ submodule or a path dependency (owner, 2026-10-18).
orchestrator reviews the screenshots before a merge or tag.
- **Theme switch:** FerroEHR's moon and sun icon button in the top bar, the
choice kept in the server cookie written as `data-theme`.
- **No user-visible component string outside the catalogs** (owner,
2026-10-19). English is the one language that ships and the family is
ready for more: a new language is a catalog file and no code change. Every
word a FerroUI component draws is a message of its Fluent catalog
(`locales/en/ferrohealth-ui.ftl`), the locale is chosen once per render
through `i18n::provide_locale` and written as `<html lang>`, and a
console catalogs its own page strings the same way, held by the
stray-literal check (`leptos-ui.md` §13). No Dutch or German catalog is
added.
49 changes: 49 additions & 0 deletions .claude/rules/leptos-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ the Authoring Practices (`spec-adherence.md`).
- **No patient identifier in a URL.** A listing that can show patient data
keeps its page, size and sort in the page (`StateSource::Session`,
`widget::pager::session_pager`).
- **No user-visible string outside the catalogs** (owner, 2026-10-19). Every
word a component draws itself is a message of the library's Fluent
catalog, every word a console draws is a message of the console's, and a
new language is a catalog file with no code change (§13).

## 1. Two tiers

Expand Down Expand Up @@ -237,3 +241,48 @@ bytes, 0.1.1 518566 and 0.1.0 325387; a console's own bundle
carries only the components it uses. A change
that needs more raises it here, in its own pull request, with the measured
size and the reason.

## 13. Strings and locales

The owner's ruling (2026-10-19): English is the one language that ships,
and the family is ready for more, so adding a language later is a catalog
file and no code change. No specification governs the catalog layout or
the lookup order: our own design; the message syntax is Project Fluent's.

- **One crate, one format.** `fluent-templates` (pinned in the workspace
table) embeds every catalog under a crate's `locales/` directory at build
time with `static_loader!`, one directory per BCP 47 tag
(`locales/en/ferrohealth-ui.ftl`), on both halves, with no script and no
runtime file reader. No hand-rolled catalog format, no second crate.
- **`en` is the reference.** It is complete, every lookup falls back to it,
and a test holds every catalog under `locales/` to the full message set
(`i18n::tests`), so a new catalog file is checked with no code change.
Only `en` ships; readiness is shown by a throwaway catalog in the tests
(`tests/it/locales/qaa/`), never by a shipped translation.
- **The locale is chosen once per render.** The console builds an
`i18n::Locale` from its configuration or the request
(`Locale::negotiate` reads `Accept-Language`), hands it to
`i18n::provide_locale` at the root of its page tree on the server and in
the hydrating browser alike (a value the server decided reaches the
browser serialized, `SharedValue`), and writes `Locale::tag` as
`<html lang>` (WCAG 2.2 SC 3.1.1). A page that provides none draws
English.
- **A component reads its words while the page tree is in reach.** A view
function calls the crate's lookup as it builds its view; a widget reads
every word it may draw at setup and moves the strings into its handlers
and tasks, where no owner is in reach.
- **A console catalogs its own strings the same way**: its own
`static_loader!` over its own `locales/`, looked up through
`Locale::lookup` so its words follow the same choice, and the language
switch is `view::theme_switch::locale_switch`.
- **The stray-literal check fails a string outside the catalogs.**
`scripts/checks/stray-literals.sh` reads the components for literals that
read as words (an attribute a reader sees or hears, a text node, any
literal holding words) and fails on each; a literal no reader sees as text
(a key name, a product name, SVG markup) is allowed with its reason in
`scripts/checks/stray-literals.allow`. A console runs the same script over
its own crate with a baseline that only shrinks while its strings move.
- **The layout leaves room for longer words.** No text sits in a fixed
width; the gallery's pseudo-locale (`qps`) draws every library string
accented and two fifths longer, and a change that moves a component's
layout is captured in it at 1440 and 390 px, light and dark.
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,20 @@ jobs:
persist-credentials: false
- run: bash scripts/checks/comment-style.sh --all

# No string a reader sees in a component outside the catalogs
# (.claude/rules/leptos-ui.md §13).
stray-literals:
name: stray-literals
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- run: bash scripts/checks/stray-literals.sh crates/ferrohealth-ui/src

# Every TODO(#N) names an open issue.
todo-issues:
name: todo-issues
Expand Down Expand Up @@ -430,6 +444,7 @@ jobs:
- workflow-lint
- shellcheck
- comment-style
- stray-literals
- todo-issues
- contribution-licence
- detect
Expand Down
47 changes: 46 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,50 @@ and this project adheres to

## [Unreleased]

## [0.1.7] - 2026-10-19

The family is ready for more languages, with English the one that ships:
every word a component draws itself comes from a Fluent catalog, a new
language is a catalog file with no code change, and the locale is chosen
once per render and reachable by a console for `<html lang>`. The
English words and the markup they draw in are unchanged.

### Added

- `i18n`: the locale and the catalogs. `Locale` (from a BCP 47 tag, or
negotiated from `Accept-Language` among the languages the library ships
or, with `negotiate_with`, a console's catalog holds, falling back to the
console's configured locale),
`provide_locale` and `locale` to choose it once per render and read it,
`Locale::tag` for `<html lang>`, `Locale::lookup` for a console's own
catalog, and `Locale::with_catalog` for a catalog the library does not
ship. The catalogs are embedded at build time from `locales/` by
`fluent-templates` 0.15.1, on both halves and with no script; `en` is the
reference catalog every lookup falls back to (FerroHEALTH/FerroUI#112).
- `view::theme_switch::locale_switch`: the language switch, a plain form
whose choices are each named in their own language and marked with it in
`lang` (FerroHEALTH/FerroUI#112).
- `view::layout::keyed_field_row`: a row of fields with an id, for a row a
console adds, removes or finds, such as one value of a list.
- `scripts/checks/stray-literals.sh`, in CI: fails on a string a reader
sees in a component outside the catalogs (FerroHEALTH/FerroUI#112).
- The gallery's language switch on the overview's settings, and its
pseudo-locale, which draws every library string accented and two fifths
longer to check the layout (FerroHEALTH/FerroUI#112).

### Changed

- Every string a component draws itself is a message of
`locales/en/ferrohealth-ui.ftl`, looked up in the page's locale. The
words that were `&'static str` return values are `String` now:
`theme::Theme::label`, `theme::Density::label`,
`table::view::Step::label`, `view::refusal::Severity::word` and
`view::button::Variant::name` (FerroHEALTH/FerroUI#112).
- `view::button::label` and `widget::copy::copy_button` take their label as
anything that converts into `Oco<'static, str>`, a `&'static str` as
before or a `String` from a catalog.
- The gallery writes the locale its cookie names as `<html lang>`.

## [0.1.6] - 2026-10-19

The shared form fields every console needs so no field is built by hand: a
Expand Down Expand Up @@ -481,7 +525,8 @@ FerroHEALTH consoles.
component in every product theme, light and dark, with browser journeys,
a painted-colour check and the screenshots under `docs/screenshots/`.

[Unreleased]: https://github.com/FerroHEALTH/FerroUI/compare/v0.1.6...HEAD
[Unreleased]: https://github.com/FerroHEALTH/FerroUI/compare/v0.1.7...HEAD
[0.1.7]: https://github.com/FerroHEALTH/FerroUI/compare/v0.1.6...v0.1.7
[0.1.6]: https://github.com/FerroHEALTH/FerroUI/compare/v0.1.5...v0.1.6
[0.1.5]: https://github.com/FerroHEALTH/FerroUI/compare/v0.1.4...v0.1.5
[0.1.4]: https://github.com/FerroHEALTH/FerroUI/compare/v0.1.3...v0.1.4
Expand Down
Loading
Loading