Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Internationalization support for Calendar #1804

Merged
merged 3 commits into from
Jul 15, 2021
Merged

Internationalization support for Calendar #1804

merged 3 commits into from
Jul 15, 2021

Conversation

devongovett
Copy link
Member

This implements i18n support for the Calendar and RangeCalendar components, including support for non-Gregorian calendars used in various countries around the world, and proper support for time zones.

I18n for Calendar involves more than just formatting, which is already handled by the Intl.DateTimeFormat API. It also involves determining how many days are in a given month, date arithmetic, and the ability to convert dates between different calendars (i.e. to/from ISO8601 for storage). The JavaScript Date object does not support any of this – it operates only in the Gregorian calendar, and also only in the current system time zone. The Temporal proposal currently in TC39 will eventually address these shortcomings in the language, but for now we are on our own. Existing libraries like date-fns and moment do not handle international dates at all, they are mostly wrappers around the existing Date object.

This PR introduces an @internationalized/date package, which handles i18n date manipulation, including support for multiple calendars, time zones, and general manipulation utilities. It is inspired by the date-fns API but focused around i18n support. Much of the code is based on the ICU Java library. The objects provided are:

  • Calendar - an interface which provides calendar conversion and metadata like number of days in month, and number of months in year. Several implementations are provided.
  • CalendarDate - an immutable object that stores a date associated with a particular calendar, regardless of time zone.
  • Time - an immutable object that stores a time, regardless of the time zone.
  • CalendarDateTime - an immutable object that stores a date and a time on a particular calendar, regardless of time zone.

Features:

  • Tree shakeable - all objects are immutable and do not provide any methods. Instead, each function can be imported separately and accepts one or more of the above objects as arguments. This means that only the functions that are used are included in a final build. In addition, only the calendars that you want to support are included.
  • Conversion - to and from JS Date objects (i.e. absolute time) in a certain time zone, as well as between different calendars.
  • Manipulation - adding and subtracting days, weeks, months, and years, as well as setting each of these fields to a particular value and balancing the others accordingly.
  • Queries - determining whether two dates have the same day, month, year, etc. regardless of which calendar they are in. Additionally, determining the day of week, and comparing dates to see which is before another is supported.

The Calendar component now also accepts a timeZone prop to allow the user to control what time zone it is displayed in, as well as the time zone of the dates that are selected by the user. It defaults to the current system time zone.

In order to preserve the tree-shakeability, and because not everyone will need support for every calendar, useCalendarState now requires a createCalendar function to be passed which constructs a calendar based on the calendar name retrieved from the current locale. There is a default implementation of this method that includes all calendars and which is passed by React Spectrum, but aria and stately users will need to either use this default or implement it themselves with only the calendars they wish to support.

The whole date library is ~5KB min + gzipped, so already a lot smaller than other libraries, but with tree shaking it should be even smaller.

The stories have been updated to add a picker with additional locales that are not generally listed in our storybook. This is because the calendar component varies a lot by region rather than just language. i.e. Arabic in one country may use the Gregorian calendar and the Islamic calendar in another. You can also switch between calendars within any locale, and the preferred calendars for that locale are listed in a separate picker.

When an item moved from one section to another, cached nodes and layout infos were not updated properly.
@adobe-bot
Copy link

Build successful! 🎉

year: namedParts.era === 'BC' ? -namedParts.year + 1 : +namedParts.year,
month: +namedParts.month,
day: +namedParts.day,
hour: namedParts.hour === '24' ? 0 : +namedParts.hour, // bugs.chromium.org/p/chromium/issues/detail?id=1045791
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the external bugs list?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it came from one of the libraries I ported but I will add it

@@ -3498,6 +3498,10 @@ describe('ComboBox', function () {
triggerPress(clearButton);
});

act(() => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume it was related to the list layout bugfix

@adobe-bot
Copy link

Build successful! 🎉

@devongovett devongovett merged commit d705916 into main Jul 15, 2021
@devongovett devongovett deleted the calendar-i18n branch July 15, 2021 00:04
@jrmyio jrmyio mentioned this pull request Sep 10, 2021
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.

3 participants