Translate English built from template literals in attributes

i18n-literals now flags a template literal in a UI attribute or prop when
there are words between its values: `Remove ${email}`, `${name} — shared by
${owner}`. It cannot be a catalogue key as written, so neither the key
exemption nor the sentence-shape test applies. A template that is only
punctuation around values, like `${name} (${size})`, is left alone.

The twelve it found are now keys with placeholders: the quota bar title,
the address menu's label, a folder's subfolder unread count, a recipient
chip's remove button, the contact editor's title, shared and available
calendars and address books, the date and time fields' labels, the
attachment title's fallback name, and the free/busy bar. The bar showed
the raw JMAP busyStatus ("confirmed") and now says Busy, Tentative or
Unavailable.

11 new keys in all nine catalogues. Remove {address}, Date, Time, Busy and
Tentative already existed.
This commit is contained in:
2026-09-14 08:26:34 -07:00
parent aa57c59703
commit fecae2acd3
21 changed files with 144 additions and 17 deletions
+2 -2
View File
@@ -301,7 +301,7 @@ export function DateTimeField({ value, onChange, className, disabled, required,
disabled={disabled}
required={required}
placeholder={dateInputPlaceholder()}
aria-label={rest["aria-label"] ? `${rest["aria-label"]} (date)` : "Date"}
aria-label={rest["aria-label"] ? translate("{label} (date)", { label: rest["aria-label"] }) : translate("Date")}
aria-haspopup="dialog"
aria-expanded={Boolean(anchor)}
value={dateField.text}
@@ -326,7 +326,7 @@ export function DateTimeField({ value, onChange, className, disabled, required,
spellCheck={false}
disabled={disabled}
placeholder={timeInputPlaceholder()}
aria-label={rest["aria-label"] ? `${rest["aria-label"]} (time)` : "Time"}
aria-label={rest["aria-label"] ? translate("{label} (time)", { label: rest["aria-label"] }) : translate("Time")}
value={timeField.text}
onChange={(e) => { timeField.setEditing(true); timeField.setText(e.target.value); }}
onBlur={timeField.onBlur}