From bf9e2cd4046ed1e0cc0ac161c017efdb2e52eb7f Mon Sep 17 00:00:00 2001 From: Steve Repsher Date: Mon, 9 Oct 2023 08:28:16 -0400 Subject: [PATCH] Move polyfill time zone data out of bundles (#18142) --- build-scripts/gulp/locale-data.js | 67 ++++++++++++++++----------- src/resources/intl-polyfill.ts | 9 ++-- src/resources/locale-data-polyfill.ts | 10 ++-- 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/build-scripts/gulp/locale-data.js b/build-scripts/gulp/locale-data.js index c8bd3b3141..4da1d8f218 100755 --- a/build-scripts/gulp/locale-data.js +++ b/build-scripts/gulp/locale-data.js @@ -1,51 +1,54 @@ import { deleteSync } from "del"; import { mkdir, readFile, writeFile } from "fs/promises"; import gulp from "gulp"; -import path from "path"; +import { join, resolve } from "node:path"; import paths from "../paths.cjs"; -const outDir = path.join(paths.build_dir, "locale-data"); +const formatjsDir = join(paths.polymer_dir, "node_modules", "@formatjs"); +const outDir = join(paths.build_dir, "locale-data"); -const INTL_PACKAGES = { - "intl-relativetimeformat": "RelativeTimeFormat", +const INTL_POLYFILLS = { "intl-datetimeformat": "DateTimeFormat", - "intl-numberformat": "NumberFormat", "intl-displaynames": "DisplayNames", "intl-listformat": "ListFormat", + "intl-numberformat": "NumberFormat", + "intl-relativetimeformat": "RelativeTimeFormat", }; -const convertToJSON = async (pkg, lang) => { +const convertToJSON = async ( + pkg, + lang, + subDir = "locale-data", + addFunc = "__addLocaleData", + skipMissing = true +) => { let localeData; try { localeData = await readFile( - path.resolve( - paths.polymer_dir, - `node_modules/@formatjs/${pkg}/locale-data/${lang}.js` - ), + join(formatjsDir, pkg, subDir, `${lang}.js`), "utf-8" ); } catch (e) { // Ignore if language is missing (i.e. not supported by @formatjs) - if (e.code === "ENOENT") { + if (e.code === "ENOENT" && skipMissing) { + console.warn(`Skipped missing data for language ${lang} from ${pkg}`); return; - } else { - throw e; } + throw e; } // Convert to JSON - const className = INTL_PACKAGES[pkg]; - localeData = localeData - .replace( - new RegExp( - `\\/\\*\\s*@generated\\s*\\*\\/\\s*\\/\\/\\s*prettier-ignore\\s*if\\s*\\(Intl\\.${className}\\s*&&\\s*typeof\\s*Intl\\.${className}\\.__addLocaleData\\s*===\\s*'function'\\)\\s*{\\s*Intl\\.${className}\\.__addLocaleData\\(`, - "im" - ), - "" - ) - .replace(/\)\s*}/im, ""); + const obj = INTL_POLYFILLS[pkg]; + const dataRegex = new RegExp( + `Intl\\.${obj}\\.${addFunc}\\((?.*)\\)`, + "s" + ); + localeData = localeData.match(dataRegex)?.groups?.data; + if (!localeData) { + throw Error(`Failed to extract data for language ${lang} from ${pkg}`); + } // Parse to validate JSON, then stringify to minify localeData = JSON.stringify(JSON.parse(localeData)); - await writeFile(path.join(outDir, `${pkg}/${lang}.json`), localeData); + await writeFile(join(outDir, `${pkg}/${lang}.json`), localeData); }; gulp.task("clean-locale-data", async () => deleteSync([outDir])); @@ -53,17 +56,27 @@ gulp.task("clean-locale-data", async () => deleteSync([outDir])); gulp.task("create-locale-data", async () => { const translationMeta = JSON.parse( await readFile( - path.resolve(paths.translations_src, "translationMetadata.json"), + resolve(paths.translations_src, "translationMetadata.json"), "utf-8" ) ); const conversions = []; - for (const pkg of Object.keys(INTL_PACKAGES)) { - await mkdir(path.join(outDir, pkg), { recursive: true }); + for (const pkg of Object.keys(INTL_POLYFILLS)) { + // eslint-disable-next-line no-await-in-loop + await mkdir(join(outDir, pkg), { recursive: true }); for (const lang of Object.keys(translationMeta)) { conversions.push(convertToJSON(pkg, lang)); } } + conversions.push( + convertToJSON( + "intl-datetimeformat", + "add-all-tz", + ".", + "__addTZData", + false + ) + ); await Promise.all(conversions); }); diff --git a/src/resources/intl-polyfill.ts b/src/resources/intl-polyfill.ts index b98fc722b8..24a3135d21 100644 --- a/src/resources/intl-polyfill.ts +++ b/src/resources/intl-polyfill.ts @@ -5,7 +5,10 @@ import { shouldPolyfill as shouldPolyfillPluralRules } from "@formatjs/intl-plur import { shouldPolyfill as shouldPolyfillRelativeTime } from "@formatjs/intl-relativetimeformat/should-polyfill"; import { shouldPolyfill as shouldPolyfillListFormat } from "@formatjs/intl-listformat/should-polyfill"; import { getLocalLanguage } from "../util/common-translation"; -import { polyfillLocaleData } from "./locale-data-polyfill"; +import { + polyfillLocaleData, + polyfillTimeZoneData, +} from "./locale-data-polyfill"; const polyfillIntl = async () => { const locale = getLocalLanguage(); @@ -22,8 +25,8 @@ const polyfillIntl = async () => { } if (shouldPolyfillDateTime(locale)) { polyfills.push( - import("@formatjs/intl-datetimeformat/polyfill-force").then( - () => import("@formatjs/intl-datetimeformat/add-all-tz") + import("@formatjs/intl-datetimeformat/polyfill-force").then(() => + polyfillTimeZoneData() ) ); } diff --git a/src/resources/locale-data-polyfill.ts b/src/resources/locale-data-polyfill.ts index b1de492df7..3aa8908fe3 100644 --- a/src/resources/locale-data-polyfill.ts +++ b/src/resources/locale-data-polyfill.ts @@ -13,16 +13,17 @@ const loadedLocales: Set = new Set(); const addData = async ( obj: (typeof INTL_POLYFILLS)[number], - language: string + language: string, + addFunc = "__addLocaleData" ) => { // Add function will only exist if constructor is polyfilled - if (typeof (Intl[obj] as any)?.__addLocaleData === "function") { + if (typeof (Intl[obj] as any)?.[addFunc] === "function") { const result = await fetch( `${__STATIC_PATH__}locale-data/intl-${obj.toLowerCase()}/${language}.json` ); // Ignore if polyfill data does not exist for language if (result.ok) { - (Intl[obj] as any).__addLocaleData(await result.json()); + (Intl[obj] as any)[addFunc](await result.json()); } } }; @@ -34,3 +35,6 @@ export const polyfillLocaleData = async (language: string) => { loadedLocales.add(language); await Promise.all(INTL_POLYFILLS.map((obj) => addData(obj, language))); }; + +export const polyfillTimeZoneData = () => + addData("DateTimeFormat", "add-all-tz", "__addTZData");