From b8ad428b5da19e74c65b0060268234cb4e3ca897 Mon Sep 17 00:00:00 2001 From: Kirst <49090957+kirst-n@users.noreply.github.com> Date: Mon, 11 Aug 2025 16:04:11 +1000 Subject: [PATCH 1/3] Load only specified flatpickr locale Dynamically import only the requested flatpickr locale. English locale is bundled by default, so passing null triggers flatpickr's built-in English fallback without an explicit import. --- .../controllers/flatpickr_controller.js | 55 +++++++------------ .../stimulus/flatpickr_controller_test.js | 43 +++++++++++++++ 2 files changed, 63 insertions(+), 35 deletions(-) create mode 100644 spec/javascripts/stimulus/flatpickr_controller_test.js diff --git a/app/webpacker/controllers/flatpickr_controller.js b/app/webpacker/controllers/flatpickr_controller.js index b41786f1d1..e5222b85c8 100644 --- a/app/webpacker/controllers/flatpickr_controller.js +++ b/app/webpacker/controllers/flatpickr_controller.js @@ -1,20 +1,5 @@ // import Flatpickr import Flatpickr from "stimulus-flatpickr"; -import { ar } from "flatpickr/dist/l10n/ar"; -import { cat } from "flatpickr/dist/l10n/cat"; -import { cy } from "flatpickr/dist/l10n/cy"; -import { de } from "flatpickr/dist/l10n/de"; -import { fi } from "flatpickr/dist/l10n/fi"; -import { fr } from "flatpickr/dist/l10n/fr"; -import { it } from "flatpickr/dist/l10n/it"; -import { nl } from "flatpickr/dist/l10n/nl"; -import { pl } from "flatpickr/dist/l10n/pl"; -import { pt } from "flatpickr/dist/l10n/pt"; -import { ru } from "flatpickr/dist/l10n/ru"; -import { sv } from "flatpickr/dist/l10n/sv"; -import { tr } from "flatpickr/dist/l10n/tr"; -import { en } from "flatpickr/dist/l10n/default.js"; -import { hu } from "flatpickr/dist/l10n/hu"; import ShortcutButtonsPlugin from "shortcut-buttons-flatpickr"; import labelPlugin from "flatpickr/dist/plugins/labelPlugin/labelPlugin"; @@ -24,28 +9,11 @@ export default class extends Flatpickr { */ static values = { enableTime: Boolean, mode: String, defaultDate: String }; static targets = ["start", "end"]; - locales = { - ar: ar, - cat: cat, - cy: cy, - de: de, - fi: fi, - fr: fr, - it: it, - nl: nl, - pl: pl, - pt: pt, - ru: ru, - sv: sv, - tr: tr, - en: en, - hu: hu, - }; initialize() { const datetimepicker = this.enableTimeValue === true; const mode = this.modeValue === "range" ? "range" : "single"; - // sets your language (you can also set some global setting for all time pickers) + // configure flatpickr options (locale set dynamically in connect()) this.config = { altInput: true, altFormat: datetimepicker @@ -54,13 +22,18 @@ export default class extends Flatpickr { dateFormat: datetimepicker ? "Y-m-d H:i" : "Y-m-d", enableTime: datetimepicker, time_24hr: datetimepicker, - locale: I18n.base_locale, plugins: this.plugins(mode, datetimepicker), mode, }; } - connect() { + async connect() { + const locale = await this.importFlatpickrLocale(I18n.base_locale); + this.config = { + ...this.config, + locale, + }; + super.connect(); window.addEventListener("flatpickr:change", this.onChangeEvent); window.addEventListener("flatpickr:clear", this.clear); @@ -164,4 +137,16 @@ export default class extends Flatpickr { this.fp.setDate(moment().add(1, "days").startOf("day").format()); } } + + async importFlatpickrLocale(localeCode) { + // null tells flatpickr to fall back to its built-in english locale + if (!localeCode || localeCode === "en") return null; + + try { + const localeModule = await import(`flatpickr/dist/l10n/${localeCode}.js`); + return localeModule.default?.[localeCode] ?? null; + } catch { + return null; + } + } } diff --git a/spec/javascripts/stimulus/flatpickr_controller_test.js b/spec/javascripts/stimulus/flatpickr_controller_test.js new file mode 100644 index 0000000000..ecfdd3c034 --- /dev/null +++ b/spec/javascripts/stimulus/flatpickr_controller_test.js @@ -0,0 +1,43 @@ +/** + * @jest-environment jsdom + */ + +import { Application } from "stimulus"; +import FlatpickrController from "../../../app/webpacker/controllers/flatpickr_controller.js"; + +describe("FlatpickrController", () => { + beforeAll(() => { + const application = Application.start(); + application.register("flatpickr", FlatpickrController); + }); + + describe("#importFlatpickrLocale", () => { + describe("returns null to trigger flatpickr fallback to english", () => { + test.each([ + ["when no base_locale is set", {}], + ["when base_locale doesn't match a Flatpickr locale", { base_locale: "invalid-locale" }], + ["when base_locale is 'en'", { base_locale: "en" }], + ])("%s", async (_description, i18nData) => { + const I18n = i18nData; + const controller = new FlatpickrController(); + const locale = await controller.importFlatpickrLocale(I18n.base_locale); + expect(locale).toBeNull(); + }); + }); + + it("returns locale object for a supported locale (fr)", async () => { + const controller = new FlatpickrController(); + const locale = await controller.importFlatpickrLocale("fr"); + expect(locale).toBeInstanceOf(Object); + expect(locale).toHaveProperty("weekAbbreviation"); + expect(locale.weekAbbreviation).toBe("Sem"); + }); + + it("caches the locale object for repeated calls", async () => { + const controller = new FlatpickrController(); + const locale1 = await controller.importFlatpickrLocale("fr"); + const locale2 = await controller.importFlatpickrLocale("fr"); + expect(locale1).toBe(locale2); + }); + }); +}); From 2936cfebcaca27dcd16f52c078842672a78c0b16 Mon Sep 17 00:00:00 2001 From: Kirst <49090957+kirst-n@users.noreply.github.com> Date: Mon, 11 Aug 2025 20:20:36 +1000 Subject: [PATCH 2/3] Remove I18n assignment from flatpickr controller test from feedback --- spec/javascripts/stimulus/flatpickr_controller_test.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spec/javascripts/stimulus/flatpickr_controller_test.js b/spec/javascripts/stimulus/flatpickr_controller_test.js index ecfdd3c034..a72c1e5222 100644 --- a/spec/javascripts/stimulus/flatpickr_controller_test.js +++ b/spec/javascripts/stimulus/flatpickr_controller_test.js @@ -17,10 +17,9 @@ describe("FlatpickrController", () => { ["when no base_locale is set", {}], ["when base_locale doesn't match a Flatpickr locale", { base_locale: "invalid-locale" }], ["when base_locale is 'en'", { base_locale: "en" }], - ])("%s", async (_description, i18nData) => { - const I18n = i18nData; + ])("%s", async (_description, i18n) => { const controller = new FlatpickrController(); - const locale = await controller.importFlatpickrLocale(I18n.base_locale); + const locale = await controller.importFlatpickrLocale(i18n.base_locale); expect(locale).toBeNull(); }); }); From b06e56242586a0d98ee62e7be889eb5b7b4d830d Mon Sep 17 00:00:00 2001 From: Kirst <49090957+kirst-n@users.noreply.github.com> Date: Mon, 11 Aug 2025 20:23:36 +1000 Subject: [PATCH 3/3] Remove flatpickr controller test that isn't useful based on feedback --- spec/javascripts/stimulus/flatpickr_controller_test.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/spec/javascripts/stimulus/flatpickr_controller_test.js b/spec/javascripts/stimulus/flatpickr_controller_test.js index a72c1e5222..d27e132571 100644 --- a/spec/javascripts/stimulus/flatpickr_controller_test.js +++ b/spec/javascripts/stimulus/flatpickr_controller_test.js @@ -31,12 +31,5 @@ describe("FlatpickrController", () => { expect(locale).toHaveProperty("weekAbbreviation"); expect(locale.weekAbbreviation).toBe("Sem"); }); - - it("caches the locale object for repeated calls", async () => { - const controller = new FlatpickrController(); - const locale1 = await controller.importFlatpickrLocale("fr"); - const locale2 = await controller.importFlatpickrLocale("fr"); - expect(locale1).toBe(locale2); - }); }); });