docs/handover.md
Last updated: 2026-07-16. This document hands off two related, in-flight pieces of work to a fresh agent with no prior context.
Super Productivity's ISO 8601 date-format option stores dateTimeLocale = 'sv'
as a backward-compatible sync sentinel (it yields YYYY-MM-DD + a 24h clock).
Any code that renders spelled-out weekday/month names (e.g. Wed, July) using
that configured locale therefore prints them in Swedish (ons, juli),
regardless of the app's UI language. The correct behavior: spelled-out names follow
the UI language; numeric dates and clock times keep the configured locale (so ISO
stays YYYY-MM-DD and 24h is preserved).
There are two branches:
| Branch | PR | Scope | State |
|---|---|---|---|
feat/https-github-com-super-productivity-su-726a40 | #9055 | Recurring-task cluster (start-date value, quick-setting weekday, repeat-info util, add-task-bar chips) | Pushed, browser-verified, awaiting CI + merge |
fix/iso-spelled-out-date-leaks (current) | not opened yet | 5 more leak sites found during #9055 verification | Committed locally, needs push + PR + verify |
DateTimeFormatService.isoTextLocale().<mat-calendar> app-wide by overriding
CustomDateAdapter.getDayOfWeekNames/getMonthNames/format to swap to isoTextLocale().DateTimeFormatService API (in src/app/core/date-time-format/)currentLocale() → the configured locale (the sv sentinel under ISO). Use for
numeric dates and clock times.isoTextLocale() → string | null. Returns the UI language only when the ISO
(sv) option is active, else null. This is the shared primitive (on master).textLocale() → isoTextLocale() ?? currentLocale(). Added by #9055, NOT on master.
It is the canonical "spelled-out names" locale.Why this branch inlines isoTextLocale() ?? currentLocale() instead of using
textLocale(): textLocale only exists on the #9055 branch. To keep this PR
independent and conflict-free with #9055 (no shared files, no DateTimeFormatService
change, mergeable in any order), it inlines the same expression — consistent with how
#8991/#9013 already inline isoTextLocale checks. After both merge, these inline
expressions could be simplified to textLocale(), but that is optional cleanup.
fix/iso-spelled-out-date-leaks, based on master)All follow the rule spelled-out → UI language (isoTextLocale() ?? currentLocale());
numeric → currentLocale():
src/app/pages/scheduled-list-page/scheduled-list-page.component.ts — the locale
signal now prefers isoTextLocale(). All 6 localeDate usages in its template are
spelled-out (EE, d MMM), so this one change fixes all of them. This is the leak that
was reproduced on screen: "ons, 15 juli" under German UI..../metric/dialog-focus-session-edit/dialog-focus-session-edit.component.ts —
formatSelectedDate() (weekday long + month long) → UI language..../simple-counter/habit-tracker/habit-tracker.component.ts — dateRangeLabel
(month short) → UI language. (The habit-tracker weekday column was already guarded
by #8991; only this range label leaked.)src/app/ui/pipes/scheduled-date-group.pipe.ts — work-view group-header [title]
tooltip (weekday short + numeric). Low-visibility; applies UI language to the whole
compact formatter (documented tradeoff: the numeric part also follows UI language here
rather than splitting and losing the locale-native separator).src/app/features/worklog/worklog.service.ts — passes UI language into
mapArchiveToWorklog → formatDayStr (weekday short worklog day headers). Verified
that locale param feeds only the spelled-out weekday there.Spec mocks updated so the new isoTextLocale() calls don't throw
(TypeError: isoTextLocale is not a function): scheduled-date-group.pipe.spec.ts (+ a new
ISO regression test) and worklog.service.spec.ts. The habit-tracker spec already mocked
isoTextLocale.
NOT leaks (verified guarded / different mechanism — do not touch): habit-tracker weekday
column, planner-day dayLabel, schedule-week/month (all isoTextLocale-guarded); the
formatMonthDay-based pipes (short-planned-at, local-date-str, short-date2) and the
focus-session chart label are numeric; planner-calendar-nav uses the browser locale
(toLocaleDateString(undefined, …)) — a separate, pre-existing, non-sv concern.
A single-line grep toLocaleDateString … currentLocale is insufficient — leaks hide
behind the localeDate pipe, multi-line Intl.DateTimeFormat(locale, …) where locale
is assigned earlier, and util indirection (formatDayStr, getWeekdaysMin). Search
instead for the spelled-out format tokens and then trace the locale source:
# spelled-out Intl options in .ts
grep -rEn "weekday: *'(long|short|narrow)'|month: *'(long|short|narrow)'" src/app --include='*.ts' | grep -v spec
# spelled-out localeDate pipe usages in templates (E / MMM / EEEE / MMMM)
grep -rEn "localeDate: *'[^']*(E|MMM)" src/app --include='*.html'
For each hit, confirm whether the locale is isoTextLocale()-guarded (safe), the browser
default undefined (separate concern), or raw currentLocale()/locale() (a leak).
feat/https-…-726a40): browser-verified against the Cloudflare PR
preview — recur dialog start-date value shows French mer. 15 juil. 2026 / German
Mi., 15. Juli 2026 (not Swedish), and the quick-setting dropdown shows German
Jede Woche am Mittwoch. Unit tests green; awaiting CI + merge.scheduled-date-group.pipe 15 incl. new ISO test;
habit-tracker 4; worklog.service 4). Not yet browser-verified. No dedicated spec
for scheduled-list-page (routed page, heavy TestBed); rely on browser verification.master):
# push is blocked in the sandbox; the user runs it via the `! ` prefix:
! git push -u origin fix/iso-spelled-out-date-leaks
gh pr create --repo super-productivity/super-productivity --base master \
--head fix/iso-spelled-out-date-leaks \
--title "fix(locale): localize remaining ISO 8601 spelled-out date names (#8987)" \
--body-file <a body summarizing the 5 sites>
/#/scheduled-list) date labels
read German Mi., 15. Juli not ons, 15 juli; (b) habit-tracker range label; (c) a
focus-session-edit dialog date; (d) worklog day headers.textLocale(), do it after #9055 merges.getTaskRepeatInfoText repeat-info text +
add-task-bar date/deadline chips) on #9055's latest preview — the first verification
only covered its commit 1. These are unit-tested and mechanism-proven, so this is
confirmation, not a blocker.src/assets/i18n/fr.json uses single-brace placeholders ({weekdayStr},
{dateDayStr}, {dayAndMonthStr}) where ngx-translate needs double {{ }} — so the
French recurring quick-setting labels render the literal placeholder
("Chaque semaine le {weekdayStr}"). en.json and de.json are correct. Project rule:
only edit en.json (other locales come from the translation pipeline), so this should
be reported upstream, not fixed in code here.
npm run checkFile <file> # prettier + lint one file (run on every changed .ts)
npm run test:file <spec> # single Karma spec (~real Chrome)
git push # blocked in sandbox — user runs `! git push`