Skip to content

wire up i18n - #22

Merged
codevardhan merged 8 commits into
mainfrom
wire-up-i18n
Oct 29, 2026
Merged

codevardhan merged 8 commits into
mainfrom
wire-up-i18n

Conversation

@codevardhan

Copy link
Copy Markdown
Owner
  • Resolve the user-facing strings through Fluent
  • Clear the clippy warnings in the binary
  • Run the checks on every push
  • Clear the clippy warnings in the test module
  • Hold the tests to the same lint bar as the binary

The i18n scaffolding was already wired into main, but nothing ever called fl!.
The loader was initialised and then ignored, and i18n/en/caffeine_applet.ftl
still held the cosmic-app-template boilerplate, none of whose keys appeared
anywhere in the code. Every visible string now resolves through the language
loader, so a locale can be added without touching Rust.

Pluralisation moves into the .ftl with it. Rust decides only whether a preset
reads as hours or as minutes; the .ftl picks the form. Languages with more than
English's two plural categories can add the ones they need without a code change.

Fluent wraps every placeable in U+2068/U+2069 by default. Those marks are
invisible but real: they survive into the String handed to the widgets, where
they widen text measurement and break exact comparison. Nothing here mixes
writing directions mid-sentence, so isolation is switched off - twice, because
select() rebuilds the bundles and they do not inherit the loader's setting.
A regression test pins that second call, which is easy to delete by accident.
Eight of them, four introduced by the Fluent change: the new match arms are
blocks rather than expressions, so they need a semicolon, and err is already a
String, which makes err.to_string() a clone with extra steps.

The rest predate it. with_root took a PathBuf it never consumed, so it borrows
now. countdown's hand-rolled modulo check becomes is_multiple_of. default_choice
folds map().unwrap_or() into map_or.

Only the binary is clean; the test module still carries 36 warnings.
There was no CI. The 0.1.3 release shipped with every store screenshot URL
pinned to the previous tag, and just check-release exists precisely to catch
that class of mistake - but nothing ran it, so it only ever helped someone who
remembered to type it.

Three jobs: format, lint and test; release metadata; and a Flatpak build, which
catches manifest and cargo-sources.json drift that has broken a release before.

Two splits were needed to make the gate honest. check-release refuses to re-tag
a published version, which is right before tagging and guaranteed to fail at
every other point in the cycle, so the metadata checks move to check-metadata
and check-release builds on top. And just check only warns, so dropping it into
a workflow would report success no matter how many lints fired; check-strict
denies instead. It covers the binary only, because gating on the test module's
36 warnings today would just teach everyone to ignore a red build.
Four groups, none of which changed what any test asserts:

- 23 discarded `Task`s now go through a `dispatch()` helper. No test runs a
  COSMIC runtime, so there is no one to hand the Task to; naming that once
  beats 13 bare calls tripping unused_must_use and 10 inconsistent `let _ =`.
- 5 `Instant` subtractions became `checked_sub`. Instant has no guaranteed
  epoch, so on a freshly booted machine `now - 1s` can genuinely underflow.
- `fn registered()` moved above the mutex guard. An item after a statement
  reads as though it runs there when it is really hoisted.
- 17 `default()`-then-assign blocks became struct literals with
  `..Default::default()`.
check-strict was scoped to the binary because the test module still had 36
warnings; those are gone, so fold --all-targets in and drop the advisory
continue-on-error step that was standing in for it. Keeping the tests clean
is cheaper than letting warnings accumulate behind a step nobody reads.
Eight test `Duration::from_secs(N * 60)` become `from_mins(N)`. Test-only, so
no MSRV change for the binary. The two sites that are not whole minutes keep
from_secs.

The metainfo dropped `<category>COSMIC</category>`: not a freedesktop menu
category, and already said properly by `<project_group>` above it. The desktop
file keeps `Categories=COSMIC;`, which every stock System76 applet also sets.
Also dropped the deprecated `<developer_name>`, which the `<developer>` block
below it already supersedes.
check-strict runs clippy with -D warnings, so @stable meant every clippy
release could redden a PR that touched none of the offending code. The
justfile called check-strict "the lint gate CI enforces" while CI ran a
different clippy than any dev machine, which made that claim false.

The metadata job stays unpinned on purpose, for the opposite reason: Flathub
validates with current appstreamcli, so a newer one objecting is a real
finding rather than churn.
libcosmic 1.0 sets rust-version 1.93, the highest floor in the tree, so that
is the real minimum however little our own code needs. Stating it turns an
older rustc into one clear line instead of a wall of errors from inside a
dependency.
@codevardhan
codevardhan merged commit 844ec67 into main Oct 29, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant