canvas-lms/packages/intl-polyfills
Charley Kline 3af92969b2 Redo the locale polyfiller using new features from @formatjs
Fixes FOO-2330
flag=none

Canvas supports locales that not all browsers support, so we have
to check for those cases and pull in a polyfilled version of the
Intl functions that we use (DateTimeFormat, NumberFormat, and
RelativeTimeFormat) when a locale is called for that the browser
does not support.

The first time the locale polyfiller was implemented, a lot of
tests had to be done to see if there was an available polyfill for
the given locale; this somehow broke Chrome after Version 92 so it
was disabled for Chrome. However, latest versions of the @formatjs
polyfillers are much smarter and can perform those checks and
fallbacks themselves, which makes the Canvas polyfiller code way
simpler and more stable.

An additional issue was uncovered: when the locale is being polyfilled,
NONE of the native locales can be accessed any more, so code relying on
being able to get at, say, 'en-US' to do date arithmetic was failing.
So when a polyfill loads, we save the browser's version as Native*
(so Intl.DateTimeFormat --> Intl.NativeDateTimeFormat) so it can
be accessed if needed (shouldn't be anywhere except in the ui/shared
datetime support code).

Another issue uncovered is that when a polyfill is necessary, it
seems to take a long time... it can be SECONDS before it is fully
loaded and its Promises resolve, at least in dev. Unfortunately a
lot of front-end code can start up and begin to use Intl functions
during that time, possibly with unpredictable results. The only real
answer is to make the execution of immediate bundles, and the call
to ready() to finish front-end initialization, wait pending the
resolution of the Promise indicating that the locales have loaded.
This is a bit unfortunate as it delays the execution of front-end
code, but will only be noticeable in locales that need polyfilling
because if a native locale is detected, the bundle loading and
call to ready() will happen immediately as before.

This commit does the following:

  - changes the Rails js_env to include LOCALES instead of LOCALE.
    LOCALES is a full list of locale strings in fallback order, so
    that if `sv-SE-x-k12` isn't found, it will try `sv-SE` and
    `sv-x-k12` and `sv` before finally falling back to `en`.
    The front-end startup code backfills ENV.LOCALE to ENV.LOCALES[0]
    for backward compatibility.

  - up-revs @formatjs to a more recent version that implements the
    check if a polyfill is available and leverages the LOCALES list
    to find an available polyfill.

  - Rewrites intl-polyfills to be smarter about detecting when a
    polyfill is necessary and whether it is possible.

  - Makes it easier to add new Intl subsystems to the polyfill code
    should they start getting used in the Canvas code somewhere.

  - Fixes up the helpers that relied upon the 'en-US' locale
    specifically.  They now specifically check for the Native version
    of an Intl subsystem first.

  - Fixes up the changeTimezone helpers in ui/shared/datetime because
    they relied on the `en-US` locale always being available, which
    is not true when the locale has been polyfilled. That was kind of
    sketchy anyway because it relied on new Date() parsing a fairly
    free-form English date and time string; it now constructs an
    ISO8601 string which is much more supported as an argument to
    new Date().

Test plan:
* Try some different locale scenarios and observe the behavior of
  Canvas in that language in general, and also specifically how it
  formats dates and times (this may be faster to do in console).
* Pay particular attention to places where datepickers are used,
  specifically, create a new assignment and fiddle with the due
  dates down near the bottom.
* Locale scenarios to try:
  a native locale like de or es
    -should just work
  a native locale with an extension like sv-x-k12
    -should just work
  a polyfillable locale like cy or nn
    -should work with a console message saying it is polyfilled
  the one non-polyfillable locale: Kreyòl Ayisyen
    -should work via a fallback all the way to 'en' on console

Change-Id: I93a1f2c3f0b3002747f564aba24c93d77244383e
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/284509
Reviewed-by: Ahmad Amireh <ahmad@instructure.com>
QA-Review: Charley Kline <ckline@instructure.com>
Product-Review: Charley Kline <ckline@instructure.com>
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
2022-02-15 17:53:56 +00:00
..
__tests__ rename some things 2021-04-06 01:12:49 +00:00
index.js Redo the locale polyfiller using new features from @formatjs 2022-02-15 17:53:56 +00:00
package.json Redo the locale polyfiller using new features from @formatjs 2022-02-15 17:53:56 +00:00