Skip to content

feat(ui): calendar type preference with Jalali/Persian support - #478

Merged
stefan-ernst merged 10 commits into
Windshiftapp:mainfrom
mrtfn:feature/persian-calendar-support
Nov 9, 2026
Merged

stefan-ernst merged 10 commits into
Windshiftapp:mainfrom
mrtfn:feature/persian-calendar-support

Conversation

@mrtfn

@mrtfn mrtfn commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Lets users choose the calendar system (Gregorian or Persian/Jalali) from the profile's Regional Settings tab, with the interface language driving month names independently of the calendar system.

What changed

Calendar preference plumbing

  • frontend/src/lib/stores/calendar.svelte.js — resolveCalendar(locale, override) returns persian when the interface locale starts with fa and calendar is auto; otherwise honors the explicit gregory/persian choice. Defaults to auto.
  • frontend/src/lib/profile/ProfileRegionalSettingsTab.svelte — calendar picker (Automatic / Gregorian / Persian (Jalali)) alongside the timezone and language pickers. On Save, persists the calendar preference via userPreferences.update({ calendar }), updates the in-memory store, and re-applies the locale so all date displays re-format reactively.

Calendar-aware date formatting

  • frontend/src/lib/utils/dateFormatter.js — getCalendarOption() resolves the calendar from the preference + interface locale, and every formatter (formatInstant, formatDateOnly, formatDateShort, formatDateTimeLocale, formatHistoryTimestamp, formatRelativeCompact, formatDateSimple, formatDateWithOptions, etc.) passes { calendar: getCalendarOption() } to Intl.DateTimeFormat. This decouples calendar system from interface language: Persian calendar + English UI → Aban; Persian calendar + Persian UI → آaban.

Calendar-aware date inputs/pickers

  • frontend/src/lib/pickers/DatePicker.svelte — resolves the calendar via resolveCalendar(resolvedLocale, calendar). Gregorian keeps the native <input type="date">; non-Gregorian loads CalendarDateField lazily.
  • frontend/src/lib/pickers/CalendarDateField.svelte — non-Gregorian field built on @internationalized/date DateFormatter with the resolved calendar; emits Gregorian YYYY-MM-DD strings for storage/API.
  • frontend/src/lib/components/Input.svelte — type="date" fields route through DatePicker so the calendar preference applies to all date inputs.

Calendar-aware roadmap

  • frontend/src/lib/features/collections/roadmapCalendar.js — calendarDate, calendarMonthStart, calendarMonthPosition, calendarDateAtPosition operate on @internationalized/date CalendarDates in the chosen calendar, so roadmap positioning is correct for Persian dates.

Calendar-aware date picker popover heading

  • frontend/src/lib/pickers/CalendarGrid.svelte — Melt UI's headingValue converted the CalendarDate to a plain JS Date via toDate() (stripping calendar info) and formatted with Intl but no calendar option, so a Persian grid showed "October" instead of "Aban". Replaced with a calendar-aware calendarHeading that passes { calendar: calendarId } to Intl.DateTimeFormat, so the popover heading month name follows the interface language regardless of calendar.

mrtfn added 7 commits November 9, 2026 22:33
# Conflicts:
#	frontend/src/lib/pickers/CalendarDateField.svelte
#	frontend/src/lib/pickers/DatePicker.svelte
Melt's headingValue converts CalendarDate to a plain JS Date via
toDate() and formats with Intl but no calendar option, so a Persian
grid showed 'October' instead of 'Aban'. Render the calendar heading
using the resolved calendar and interface locale so the month name
follows the interface language regardless of the chosen calendar.
@github-actions

github-actions Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@mrtfn

mrtfn commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

I have read the CLA Document and I hereby sign the CLA

github-actions Bot added a commit that referenced this pull request Nov 9, 2026
The calendar-aware heading formatted a UTC-midnight Date with an
Intl.DateTimeFormat that had no timeZone, so west of UTC the month name
could fall back to the previous month (a March grid showed "February
2025" whenever the anchor day was the 1st). Use getLocalTimeZone() so
the Date and the formatter agree.
Quote the German recurrence key so it matches the file's key style, and
add the new calendar and recurrence strings to Polish, which must keep
full coverage.
Replace the inline color styles added with the recurrence hint and the
calendar field error with the text-ds-* utilities so the inline-style
guard stays clean.
@stefan-ernst

Copy link
Copy Markdown
Contributor

@mrtfn thanks a lot! I will merge this in as part of the persian locale + rtl fixes in 0.9.4

@mrtfn

mrtfn commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

Actually there are a ton of enhancements remaining here and there, but i was concerned about fixing them first or waiting to see your approval on my approach.
I'll be happy to fix the problems that comes my way when i have the time in near and far future.

@stefan-ernst
stefan-ernst merged commit 5685ed6 into Windshiftapp:main Nov 9, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants