A sweep for UI text still rendering in English, after the nine catalogues were brought up to date.
What was still hardcoded
Where
What
MailView delete confirmation
entirely — both titles, both messages, the confirm label
FilesTree
Rename
ContactsSidebar
New address book, and its Name placeholder
CalendarSettings
New category, and its Name placeholder
The delete confirmation is the notable one. Its counts read "message(s)" — a parenthesis standing in for grammatical agreement, so every language that inflects got the wrong form regardless of catalogue coverage. Those are plural() calls now.
The New category case shows how these hide: the button that opens the dialog was already translated, so the label read correctly and the dialog it opened did not.
Strings
Rename, New address book, New category, Name and Delete are already in all nine catalogues, so those are fixed by this PR alone. Delete?, Delete forever? and the two plural forms are new and land with each language PR.
Still outstanding — two sentence builders
The sweep found a larger class this PR does not fix, because it needs a design decision rather than a wrapper:
lib/sieve.tsdescribeRule() builds the Sieve rule summaries by string concatenation — `${t.header} ${op} "${t.value}"` joined by " and " / " or ", with actions like move to, forward to, delete. This is exactly the "Sieve rule list — all the summaries" item in #247.
lib/recurrence.tsdescribeRule() does the same for recurrence — Every {n} days, on the ${ordinal}${Weekday}, , {n} times, , until {date} — with English ordinals (1st, 2nd, last) and English weekday names.
Neither is translatable as written: the sentence is assembled from fragments, and word order is not the same in German, Japanese or Ukrainian. Fixing them properly means whole sentences with placeholders rather than concatenation, which changes the string inventory and so needs another pass over all nine catalogues.
WEEKDAYS in recurrence.ts is related: its short forms cannot be catalogue keys because T covers both Tuesday and Thursday and S both Saturday and Sunday. Intl.DateTimeFormat with weekday: "narrow" is the right answer, and lib/datetime.ts already has a locale-aware formatter cache to hang it on.
A sweep for UI text still rendering in English, after the nine catalogues were brought up to date.
## What was still hardcoded
| Where | What |
|---|---|
| `MailView` delete confirmation | **entirely** — both titles, both messages, the confirm label |
| `FilesTree` | `Rename` |
| `ContactsSidebar` | `New address book`, and its `Name` placeholder |
| `CalendarSettings` | `New category`, and its `Name` placeholder |
The delete confirmation is the notable one. Its counts read `"message(s)"` — a parenthesis standing in for grammatical agreement, so every language that inflects got the wrong form regardless of catalogue coverage. Those are `plural()` calls now.
The `New category` case shows how these hide: the button that opens the dialog was already translated, so the label read correctly and the dialog it opened did not.
## Strings
`Rename`, `New address book`, `New category`, `Name` and `Delete` are already in all nine catalogues, so those are fixed by this PR alone. `Delete?`, `Delete forever?` and the two plural forms are new and land with each language PR.
## Still outstanding — two sentence builders
The sweep found a larger class this PR does **not** fix, because it needs a design decision rather than a wrapper:
- **`lib/sieve.ts` `describeRule()`** builds the Sieve rule summaries by string concatenation — `` `${t.header} ${op} "${t.value}"` `` joined by `" and "` / `" or "`, with actions like `move to`, `forward to`, `delete`. This is exactly the "Sieve rule list — all the summaries" item in #247.
- **`lib/recurrence.ts` `describeRule()`** does the same for recurrence — `Every {n} days`, `` on the ${ordinal}${Weekday} ``, `, {n} times`, `, until {date}` — with English ordinals (`1st`, `2nd`, `last`) and English weekday names.
Neither is translatable as written: the sentence is assembled from fragments, and word order is not the same in German, Japanese or Ukrainian. Fixing them properly means whole sentences with placeholders rather than concatenation, which changes the string inventory and so needs another pass over all nine catalogues.
`WEEKDAYS` in `recurrence.ts` is related: its `short` forms cannot be catalogue keys because `T` covers both Tuesday and Thursday and `S` both Saturday and Sunday. `Intl.DateTimeFormat` with `weekday: "narrow"` is the right answer, and `lib/datetime.ts` already has a locale-aware formatter cache to hang it on.
## Checks
Typecheck clean, 99 test files / 1000 tests pass.
**Merged** 2026-09-03 as coffey-labs/ihasmail@bf60fe6157e7
<sub>Rebuilt from: git history, session transcript.</sub>
This repo is archived. You cannot comment on issues.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
A sweep for UI text still rendering in English, after the nine catalogues were brought up to date.
What was still hardcoded
MailViewdelete confirmationFilesTreeRenameContactsSidebarNew address book, and itsNameplaceholderCalendarSettingsNew category, and itsNameplaceholderThe delete confirmation is the notable one. Its counts read
"message(s)"— a parenthesis standing in for grammatical agreement, so every language that inflects got the wrong form regardless of catalogue coverage. Those areplural()calls now.The
New categorycase shows how these hide: the button that opens the dialog was already translated, so the label read correctly and the dialog it opened did not.Strings
Rename,New address book,New category,NameandDeleteare already in all nine catalogues, so those are fixed by this PR alone.Delete?,Delete forever?and the two plural forms are new and land with each language PR.Still outstanding — two sentence builders
The sweep found a larger class this PR does not fix, because it needs a design decision rather than a wrapper:
lib/sieve.tsdescribeRule()builds the Sieve rule summaries by string concatenation —`${t.header} ${op} "${t.value}"`joined by" and "/" or ", with actions likemove to,forward to,delete. This is exactly the "Sieve rule list — all the summaries" item in #247.lib/recurrence.tsdescribeRule()does the same for recurrence —Every {n} days,on the ${ordinal}${Weekday},, {n} times,, until {date}— with English ordinals (1st,2nd,last) and English weekday names.Neither is translatable as written: the sentence is assembled from fragments, and word order is not the same in German, Japanese or Ukrainian. Fixing them properly means whole sentences with placeholders rather than concatenation, which changes the string inventory and so needs another pass over all nine catalogues.
WEEKDAYSinrecurrence.tsis related: itsshortforms cannot be catalogue keys becauseTcovers both Tuesday and Thursday andSboth Saturday and Sunday.Intl.DateTimeFormatwithweekday: "narrow"is the right answer, andlib/datetime.tsalready has a locale-aware formatter cache to hang it on.Checks
Typecheck clean, 99 test files / 1000 tests pass.
Merged 2026-09-03 as coffey-labs/ihasmail@bf60fe6157
Rebuilt from: git history, session transcript.