Fix calendar event recurrence UI in non-English locales - #2657
Open
qiyana-ratchet wants to merge 1 commit into
Open
Fix calendar event recurrence UI in non-English locales#2657qiyana-ratchet wants to merge 1 commit into
qiyana-ratchet wants to merge 1 commit into
Conversation
Two defects in the calendar event recurrence UI only reproduce when the user
locale is not English.
First, opening "More Options" for an event that has a recurrence renders an
error block instead of the frequency picker, and the page never recovers.
EditEventView writes the start date into the date field with the active locale
via Intl.DateTimeFormat(ENV.LOCALE), then reads it back with the hard coded
English pattern 'MMM D, YYYY'. In English the two formats happen to agree, so
the round trip works. In ko the field holds "2026년 3월 6일", the English
pattern fails to parse it, and date becomes undefined. FrequencyPicker
deliberately throws when it has no date and a frequency other than not-repeat,
so the error surfaces only for events that repeat.
Parsing now goes through tz.parse from @instructure/moment-utils, which already
resolves both the Moment locale formats and the Canvas i18n date formats and is
what DatetimeField itself uses. Routing all three call sites through one helper
makes the view agree with the field it reads from, and removes the locale
assumption rather than adding another format to the list. Clearing the start
date hits the same throw condition in every locale, so while the date is
unknown the picker is rendered disabled and non repeating, and its change
notifications are ignored so the stored rrule is not silently reset.
Second, the "Ends:" radio labels in the custom recurrence modal stack one
character per line. Their grid column is sized min-content, which resolves to
the narrowest wrappable width. English words do not break mid-word, so the word
itself becomes that minimum, but CJK text allows breaks between characters and
the column collapses to a single character. The label column is now max-content.
Capping the break from the outside does not work here because the InstUI radio
label resets inherited properties with all: initial.
Test Plan:
- Set your user language to a non-English locale whose date format differs
from English. Korean is a good case because "2026년 3월 6일" shares no
tokens with 'MMM D, YYYY', and its labels are short enough to make the
stacking obvious.
- Go to the calendar, click a day, and fill in a title and a date.
- Set Frequency to a repeating value, for example Weekly.
- Click "More Options".
- Verify the frequency picker renders with the frequency you selected, and
that no "There was an error rendering." block is present.
- Change the start date and verify the frequency picker labels update to the
new date, for example the weekday named in the weekly option.
- Clear the start date entirely. Verify the picker becomes disabled and shows
"Does not repeat", and that no error block appears.
- Re-enter a start date. Verify the picker becomes selectable again.
- Open the frequency picker and choose "Custom" to open the recurrence modal.
Verify the "Ends:" radio labels each render on a single line.
- Save the event and verify the recurring events are created on the expected
dates.
- Repeat the whole flow with the user language set to English and verify
nothing changed from current behavior, including the modal layout.
- Also verify an event without any recurrence still opens "More Options"
normally in both locales.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two defects in the calendar event recurrence UI only reproduce when the user
locale is not English, which is why they have gone unnoticed. Both are still
present on master as of today.
1. The frequency picker fails to render for recurring events
Opening the "More Options" page for an event that has a recurrence renders an
error block where the frequency picker should be:
The page never recovers, because the error boundary has no reset path. The event
is still editable, but the recurrence can no longer be seen or changed.
EditEventViewwrites the start date into the date field with the activelocale, and then reads it back with a hard coded English pattern:
In English the two formats happen to agree, so the round trip works. In
kothe field holds
2026년 3월 6일, the English pattern fails to parse it, anddatebecomesundefined.FrequencyPickerdeliberately throws when it has nodate and a frequency other than
not-repeat, so the error surfaces only forevents that repeat. Events without a recurrence never meet that throw
condition, which is why the page looks fine for them.
The same round trip is done in three places in
EditEventView.jsx: computingthe initial frequency, rendering the frequency picker, and handling start date
changes.
Approach. Parse with the locale aware parser instead of a fixed pattern.
tz.parsefrom@instructure/moment-utilsalready resolves both the Momentlocale formats and the Canvas i18n date formats, and it is what the date field
itself (
DatetimeField#parseValue) uses. Routing all three call sites throughone helper makes the view agree with the field it reads from, and removes the
locale assumption rather than adding another format to the list.
A second, related case is fixed as well. Clearing the start date on an event
that repeats produces the identical error in every locale, because
datebecomes
undefinedwhileinitialFrequencyis still a repeating value. Whilethe start date is unknown the picker is now rendered disabled and non
repeating, and its change notifications are ignored so the stored
rruleisnot silently reset to
not-repeatand lost on save.2. The "Ends:" labels stack one character per line
In the custom recurrence modal, the
OnandAfterradio labels are laid outin a grid whose columns are sized
min-content:min-contentresolves to the narrowest wrappable width. English words do notbreak mid-word, so the whole word becomes that minimum and the label stays on
one line. CJK text allows breaks between characters, so the minimum is a single
character and the column collapses to that width, stacking the label
vertically. In Korean the labels read as one character per row.
Approach. Size the label column
max-contentso it is as wide as the labelneeds. Capping the break from the outside with
white-space: nowrapdoes notwork here, because the InstUI radio label element resets inherited properties
with
all: initial. Only the two labels live in that column, so widening itdoes not affect the rest of the modal.
I am happy to reshape this however the review prefers. If you take the fixes, I would
appreciate having this commit merged rather than reimplemented, and if it has to land
through your internal review instead, please consider keeping attribution with:
Test Plan:
from English. Korean is a good case because
2026년 3월 6일shares notokens with
MMM D, YYYY, and its labels are short enough to make thestacking obvious.
that no "There was an error rendering." block is present.
new date, for example the weekday named in the weekly option.
"Does not repeat", and that no error block appears.
Verify the "Ends:" radio labels each render on a single line.
dates.
nothing changed from current behavior, including the modal layout.
normally in both locales.