How to add missing locale to Intl.DateTimeFormat (ES2020) if browser doesn't support required locale?

1.3k views Asked by At

Unfortunately some browsers don't support some locales using Intl.DateTimeFormat. In my case 'kk' locale in Chrome (https://source.chromium.org/chromium/chromium/src/+/master:third_party/icu/scripts/chrome_ui_languages.list). You can test your locale in console:

Intl.DateTimeFormat.supportedLocalesOf('kk')

If it returns empty array [] it means that it doesn't support.

My question is how to add missing locale? I mean may be there is a Polyfill for that? I'm using Vuejs 2

2

There are 2 answers

1
Eazy On

Finally found solution to use Polyfill:

npm i @formatjs/intl-datetimeformat

Then in your code:

import '@formatjs/intl-datetimeformat/polyfill-force’ // Using force to use our polyfill
import '@formatjs/intl-datetimeformat/locale-data/kk’ // Add locales you want
import '@formatjs/intl-datetimeformat/locale-data/ru’ // Add locales you want
import '@formatjs/intl-datetimeformat/add-all-tz' // Add ALL tz data
0
sqrtsanta On

Have a solution to only polyfill those locales that aren't already present in Intl.DateTimeFormat. In my case browsers are missing only kk locale. Therefore I only want to polyfill kk with @formatjs and use en & ru via original Intl.DateTimeFormat.

import {
  DateTimeFormat as PolyfillDateTimeFormat,
} from "@formatjs/intl-datetimeformat";

const LOCALES_THAT_ARE_POLYFILLED = ["kk"];

const OriginalDateTimeFormat = Intl.DateTimeFormat;

const DynamicDateTimeFormat = new Proxy(PolyfillDateTimeFormat, {
  construct(target, args) {
    if (LOCALES_THAT_ARE_POLYFILLED.includes(args[0])) {
      return new target(...args);
    } else {
      return OriginalDateTimeFormat(...args);
    }
  },
  get(target, prop) {
    if (prop === "supportedLocalesOf") {
      return (value: string | string[], options?: Pick<Intl.DateTimeFormatOptions, "localeMatcher">) => {
        if (typeof value === "string") {
          if (LOCALES_THAT_ARE_POLYFILLED.includes(value)) {
            return target.supportedLocalesOf(value, options);
          } else {
            return OriginalDateTimeFormat.supportedLocalesOf(value, options);
          }
        } else {
          return value.map((locale) => {
            if (LOCALES_THAT_ARE_POLYFILLED.includes(locale)) {
              return target.supportedLocalesOf(locale, options)[0];
            } else {
              return OriginalDateTimeFormat.supportedLocalesOf(locale, options)[0];
            }
          });
        }
      }
    } else {
      // @ts-ignore
      return target[prop];
    }
  }
});

// also keep in mind to monkey-patch toLocaleString, toLocaleTimeString, toLocaleDateString
Object.defineProperty(Intl, "DateTimeFormat", {
  value: DynamicDateTimeFormat,
  configurable: true,
  enumerable: false,
  writable: true,
});

const _promise = Promise.all([
  import("@formatjs/intl-datetimeformat/locale-data/kk"), // need to be statically defined for bundlers
]);