Translate the labels the extractor could not see

Three places built user-visible English out of expressions rather than
writing it as JSX text, so the extraction codemod never found them and
they stayed English in all nine languages — including the five that have
been in production for weeks.

The calendar view switcher was the worst of them: it spelled its labels
as `v[0].toUpperCase() + v.slice(1)`, which is correct English and
untranslatable anywhere else. Day, Week, Month and Agenda were already in
every catalogue, sitting unused, because the buttons never asked for
them. They now come from a Record<View, () => string>, so TypeScript
makes the map exhaustive and adding a view forces adding its label. The
labels are functions rather than values: a module-level object would
capture whichever language happened to load first and keep it.

The other two needed new source strings, added to all nine catalogues:
the composer's title for an untitled draft ("New message"), its status
line ("Sending…", "Saving…", "Error", "Saved {when}", "Unsaved"), and the
agenda view's own title ("Agenda from {date}").

This is not the whole of it. A sweep for the same shape — template
literals, toast arguments, and dialog props rather than JSX text — turns
up roughly a hundred more strings, mostly toasts and confirmation
dialogs. Those are a second extraction pass rather than a fix, and are
left for one.
This commit is contained in:
2026-08-31 13:20:39 -07:00
parent a440e54922
commit f94cc2ce51
11 changed files with 109 additions and 4 deletions
+9
View File
@@ -856,6 +856,15 @@ export const catalog: Catalog = {
"Delete “{name}”?": "「{name}」を削除しますか?",
"Rename folder": "フォルダー名を変更",
"Search: {query}": "検索: {query}",
// ── Composer status, calendar title ────────────────────────────────
"New message": "新規メール",
"Sending…": "送信中…",
"Saving…": "保存中…",
"Error": "エラー",
"Saved {when}": "{when} に保存",
"Unsaved": "未保存",
"Agenda from {date}": "{date} からの予定",
},
plurals: {
/*