Folder names follow the language, and three bugs that found #150

Closed
opened 2026-08-31 18:24:45 +00:00 by jcoffey-dev · 0 comments
Owner

Answering "can we ask Stalwart to serve German folder names?" — no, and it wouldn't help if we could.

The account locale exists in x:AccountSettings, and ihasmail already reads it (that's what "Your mail server reports German" comes from). But writing it needs sysAccountSettingsSet, which the built-in user role doesn't carry — only an admin could. And even then it would change nothing: folder names are stored data, written once when the account is provisioned. No server renames them afterwards, because every other client has them mapped.

The role is the way through

JMAP tags the standard folders, and ihasmail already trusts the role over the name everywhere it matters — so the displayed name can follow the interface language with nothing written to the server. Folders somebody made keep their own names: "Newsletters" is their word, and translating it would name a folder they never created.

The cost, stated plainly: Thunderbird on the same account still shows "Deleted Items". Inside ihasmail it stays consistent — everything that names a folder goes through one function, including the "moved to …" toast, which exists precisely so that message doesn't name somewhere the reader can't find. Renaming still edits the server's own name, never the localised one.

Three bugs this found

The message list refreshed for ever after a language change — the one that got noticed. The root keys its tree on the language version, so a publish remounts everything; remounting re-runs the effect that loads the account settings, which calls applyLang, which called setCatalog again with an identical tag and catalogue — and publishing that non-change went round again. setCatalog now returns early when nothing changed.

Measured rather than assumed: three consecutive five-second windows with zero JMAP calls, against a pre-change count that never settled.

Calendar months and weekdays stayed English. Formatting locale and interface language are separate settings and only the first feeds Intl. Keeping them separate is right — German dates with an English interface is a real preference — but somebody who picks German and is shown "September" hasn't got what they asked for. A chosen interface language now joins the automatic chain, ahead of the server and browser. An explicit formatting locale still wins, and English isn't counted, so an English interface on a German browser keeps German dates exactly as before.

The Archive folder read "Archivieren" — the verb. English uses one word for the button and the folder; German doesn't, and neither does "Important", which is also a priority tag. tc(context, source) keys the catalogue on both and falls back to plain English. The gettext approach, control-character separator included, so no real string can collide.

The checker needed teaching twice

First it reported the eight contextual entries as stale; then it asked for the plain fallbacks as though they were a second obligation. A check that reports work which doesn't exist gets switched off, which is worse than not having one.

Verification

459 tests, typecheck, build clean. Verified in the browser: folders read Posteingang / Archiv / Papierkorb / Entwürfe / Spam / Gesendet with Newsletters and Work untouched; calendar shows "31. Aug. – 6. Sept. 2026" and MO/DI/MI/DO/FR/SA/SO; and the refresh loop is gone.

Merged 2026-08-31 as coffey-labs/ihasmail@8cbc04e730

Rebuilt from: git history, session transcript.

Answering **"can we ask Stalwart to serve German folder names?"** — no, and it wouldn't help if we could. The account locale exists in `x:AccountSettings`, and ihasmail already *reads* it (that's what "Your mail server reports German" comes from). But writing it needs `sysAccountSettingsSet`, which the built-in user role doesn't carry — only an admin could. And even then it would change nothing: folder names are stored data, written once when the account is provisioned. No server renames them afterwards, because every other client has them mapped. ## The role is the way through JMAP tags the standard folders, and ihasmail already trusts the role over the name everywhere it matters — so the *displayed* name can follow the interface language with nothing written to the server. Folders somebody made keep their own names: "Newsletters" is their word, and translating it would name a folder they never created. **The cost, stated plainly:** Thunderbird on the same account still shows "Deleted Items". Inside ihasmail it stays consistent — everything that names a folder goes through one function, including the "moved to …" toast, which exists precisely so that message doesn't name somewhere the reader can't find. Renaming still edits the server's own name, never the localised one. ## Three bugs this found **The message list refreshed for ever after a language change** — the one that got noticed. The root keys its tree on the language version, so a publish remounts everything; remounting re-runs the effect that loads the account settings, which calls `applyLang`, which called `setCatalog` again with an *identical* tag and catalogue — and publishing that non-change went round again. `setCatalog` now returns early when nothing changed. Measured rather than assumed: three consecutive five-second windows with **zero** JMAP calls, against a pre-change count that never settled. **Calendar months and weekdays stayed English.** Formatting locale and interface language are separate settings and only the first feeds `Intl`. Keeping them separate is right — German dates with an English interface is a real preference — but somebody who picks German and is shown "September" hasn't got what they asked for. A chosen interface language now joins the **automatic** chain, ahead of the server and browser. An explicit formatting locale still wins, and English isn't counted, so an English interface on a German browser keeps German dates exactly as before. **The Archive folder read "Archivieren"** — the verb. English uses one word for the button and the folder; German doesn't, and neither does "Important", which is also a priority tag. `tc(context, source)` keys the catalogue on both and falls back to plain English. The gettext approach, control-character separator included, so no real string can collide. ## The checker needed teaching twice First it reported the eight contextual entries as stale; then it asked for the plain fallbacks as though they were a second obligation. A check that reports work which doesn't exist gets switched off, which is worse than not having one. ## Verification 459 tests, typecheck, build clean. Verified in the browser: folders read Posteingang / **Archiv** / Papierkorb / Entwürfe / Spam / Gesendet with Newsletters and Work untouched; calendar shows "31. Aug. – 6. Sept. 2026" and MO/DI/MI/DO/FR/SA/SO; and the refresh loop is gone. **Merged** 2026-08-31 as coffey-labs/ihasmail@8cbc04e73058 <sub>Rebuilt from: git history, session transcript.</sub>
This repo is archived. You cannot comment on issues.