From 79f13f43d5a3f3dceafdbd888f3ebcf19a0514e9 Mon Sep 17 00:00:00 2001 From: Vladislav Tasev Date: Thu, 5 Nov 2020 13:50:45 +0200 Subject: [PATCH 1/5] fix: Several date/time components use locales correctly --- packages/base/src/locale/getLocale.js | 14 ++++++++-- .../src/getCachedLocaleDataInstance.js | 13 +++++++++ packages/main/src/Calendar.js | 10 +++---- packages/main/src/DatePicker.js | 5 ++-- packages/main/src/DateTimePicker.js | 5 ++-- packages/main/src/DayPicker.js | 27 +++++++++++-------- packages/main/src/MonthPicker.js | 12 +++++---- packages/main/src/TimePicker.js | 5 ++-- packages/main/src/YearPicker.js | 6 +++-- packages/main/test/pages/Simple.html | 11 ++------ 10 files changed, 68 insertions(+), 40 deletions(-) create mode 100644 packages/localization/src/getCachedLocaleDataInstance.js diff --git a/packages/base/src/locale/getLocale.js b/packages/base/src/locale/getLocale.js index d80470fd36eb..cb53e89ba24e 100644 --- a/packages/base/src/locale/getLocale.js +++ b/packages/base/src/locale/getLocale.js @@ -2,10 +2,20 @@ import detectNavigatorLanguage from "../util/detectNavigatorLanguage.js"; import { getLanguage as getConfigLanguage } from "../config/Language.js"; import Locale from "./Locale.js"; +const cache = new Map(); + +const getLocaleInstance = lang => { + if (!cache.has(lang)) { + cache.set(lang, new Locale(lang)); + } + + return cache.get(lang); +}; + const convertToLocaleOrNull = lang => { try { if (lang && typeof lang === "string") { - return new Locale(lang); + return getLocaleInstance(lang); } } catch (e) { // ignore @@ -22,7 +32,7 @@ const getLocale = lang => { } if (getConfigLanguage()) { - return new Locale(getConfigLanguage()); + return getLocaleInstance(getConfigLanguage()); } return convertToLocaleOrNull(detectNavigatorLanguage()); diff --git a/packages/localization/src/getCachedLocaleDataInstance.js b/packages/localization/src/getCachedLocaleDataInstance.js new file mode 100644 index 000000000000..007488b9db03 --- /dev/null +++ b/packages/localization/src/getCachedLocaleDataInstance.js @@ -0,0 +1,13 @@ +import LocaleData from "./LocaleData.js"; + +const cache = new Map(); + +const getCachedLocaleDataInstance = locale => { + if (!cache.has(locale)) { + cache.set(locale, LocaleData.getInstance(locale)); + } + + return cache.get(locale); +}; + +export default getCachedLocaleDataInstance; diff --git a/packages/main/src/Calendar.js b/packages/main/src/Calendar.js index e42b4a9c2c52..d181c3541f8b 100644 --- a/packages/main/src/Calendar.js +++ b/packages/main/src/Calendar.js @@ -4,7 +4,7 @@ import { fetchCldr } from "@ui5/webcomponents-base/dist/asset-registries/LocaleD import { getCalendarType } from "@ui5/webcomponents-base/dist/config/CalendarType.js"; import getLocale from "@ui5/webcomponents-base/dist/locale/getLocale.js"; import DateFormat from "@ui5/webcomponents-localization/dist/DateFormat.js"; -import LocaleData from "@ui5/webcomponents-localization/dist/LocaleData.js"; +import getCachedLocaleDataInstance from "@ui5/webcomponents-localization/dist/getCachedLocaleDataInstance.js"; import CalendarDate from "@ui5/webcomponents-localization/dist/dates/CalendarDate.js"; import CalendarType from "@ui5/webcomponents-base/dist/types/CalendarType.js"; import Integer from "@ui5/webcomponents-base/dist/types/Integer.js"; @@ -209,8 +209,6 @@ class Calendar extends UI5Element { constructor() { super(); - this._oLocale = getLocale(); - this._oLocaleData = new LocaleData(this._oLocale); this._header = {}; this._header.onPressPrevious = this._handlePrevious.bind(this); this._header.onPressNext = this._handleNext.bind(this); @@ -235,6 +233,7 @@ class Calendar extends UI5Element { } onBeforeRendering() { + const localeData = getCachedLocaleDataInstance(getLocale()); const oYearFormat = DateFormat.getDateInstance({ format: "y", calendarType: this._primaryCalendarType }); const firstDayOfCalendarTimeStamp = this._getMinCalendarDate(); @@ -252,7 +251,7 @@ class Calendar extends UI5Element { this._oMonth.primaryCalendarType = this._primaryCalendarType; this._oMonth.minDate = this.minDate; this._oMonth.maxDate = this.maxDate; - this._header.monthText = this._oLocaleData.getMonths("wide", this._primaryCalendarType)[this._month]; + this._header.monthText = localeData.getMonths("wide", this._primaryCalendarType)[this._month]; this._header.yearText = oYearFormat.format(this._localDate, true); // month picker @@ -352,7 +351,8 @@ class Calendar extends UI5Element { } get _primaryCalendarType() { - return this.primaryCalendarType || getCalendarType() || LocaleData.getInstance(getLocale()).getPreferredCalendarType(); + const localeData = getCachedLocaleDataInstance(getLocale()); + return this.primaryCalendarType || getCalendarType() || localeData.getPreferredCalendarType(); } get _formatPattern() { diff --git a/packages/main/src/DatePicker.js b/packages/main/src/DatePicker.js index f412825a6460..60f6d4c3106f 100644 --- a/packages/main/src/DatePicker.js +++ b/packages/main/src/DatePicker.js @@ -4,7 +4,7 @@ import { fetchCldr } from "@ui5/webcomponents-base/dist/asset-registries/LocaleD import { getCalendarType } from "@ui5/webcomponents-base/dist/config/CalendarType.js"; import getLocale from "@ui5/webcomponents-base/dist/locale/getLocale.js"; import { getFeature } from "@ui5/webcomponents-base/dist/FeaturesRegistry.js"; -import LocaleData from "@ui5/webcomponents-localization/dist/LocaleData.js"; +import getCachedLocaleDataInstance from "@ui5/webcomponents-localization/dist/getCachedLocaleDataInstance.js"; import DateFormat from "@ui5/webcomponents-localization/dist/DateFormat.js"; import CalendarType from "@ui5/webcomponents-base/dist/types/CalendarType.js"; import CalendarDate from "@ui5/webcomponents-localization/dist/dates/CalendarDate.js"; @@ -761,7 +761,8 @@ class DatePicker extends UI5Element { } get _primaryCalendarType() { - return this.primaryCalendarType || getCalendarType() || LocaleData.getInstance(getLocale()).getPreferredCalendarType(); + const localeData = getCachedLocaleDataInstance(getLocale()); + return this.primaryCalendarType || getCalendarType() || localeData.getPreferredCalendarType(); } get _formatPattern() { diff --git a/packages/main/src/DateTimePicker.js b/packages/main/src/DateTimePicker.js index c3548661f55f..aee390969d7b 100644 --- a/packages/main/src/DateTimePicker.js +++ b/packages/main/src/DateTimePicker.js @@ -1,6 +1,6 @@ import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; import getLocale from "@ui5/webcomponents-base/dist/locale/getLocale.js"; -import LocaleData from "@ui5/webcomponents-localization/dist/LocaleData.js"; +import getCachedLocaleDataInstance from "@ui5/webcomponents-localization/dist/getCachedLocaleDataInstance.js"; import CalendarDate from "@ui5/webcomponents-localization/dist/dates/CalendarDate.js"; import "@ui5/webcomponents-icons/dist/date-time.js"; import { @@ -532,7 +532,8 @@ class DateTimePicker extends DatePicker { const hasHours = !!pattern.match(/H/i); const fallback = !pattern || !hasHours; - return fallback ? LocaleData.getInstance(getLocale()).getCombinedDateTimePattern("medium", "medium", this._primaryCalendarType) : pattern; + const localeData = getCachedLocaleDataInstance(getLocale()); + return fallback ? localeData.getCombinedDateTimePattern("medium", "medium", this._primaryCalendarType) : pattern; } /** diff --git a/packages/main/src/DayPicker.js b/packages/main/src/DayPicker.js index eab2b87d98e7..b4f7d77fabb1 100644 --- a/packages/main/src/DayPicker.js +++ b/packages/main/src/DayPicker.js @@ -4,7 +4,7 @@ import { fetchCldr } from "@ui5/webcomponents-base/dist/asset-registries/LocaleD import getLocale from "@ui5/webcomponents-base/dist/locale/getLocale.js"; import { getFirstDayOfWeek } from "@ui5/webcomponents-base/dist/config/FormatSettings.js"; import DateFormat from "@ui5/webcomponents-localization/dist/DateFormat.js"; -import LocaleData from "@ui5/webcomponents-localization/dist/LocaleData.js"; +import getCachedLocaleDataInstance from "@ui5/webcomponents-localization/dist/getCachedLocaleDataInstance.js"; import { getCalendarType } from "@ui5/webcomponents-base/dist/config/CalendarType.js"; import ItemNavigation from "@ui5/webcomponents-base/dist/delegate/ItemNavigation.js"; import { @@ -56,6 +56,7 @@ const monthDiff = (startDate, endDate) => { */ const metadata = { tag: "ui5-daypicker", + languageAware: true, properties: /** @lends sap.ui.webcomponents.main.DayPicker.prototype */ { /** * A UNIX timestamp - seconds since 00:00:00 UTC on Jan 1, 1970. @@ -212,8 +213,6 @@ class DayPicker extends UI5Element { constructor() { super(); - this._oLocale = getLocale(); - this._oLocaleData = new LocaleData(this._oLocale); this._itemNav = new ItemNavigation(this, { rowSize: 7, @@ -249,6 +248,8 @@ class DayPicker extends UI5Element { } onBeforeRendering() { + const localeData = getCachedLocaleDataInstance(getLocale()); + let oCalDate, day, timestamp, @@ -261,7 +262,7 @@ class DayPicker extends UI5Element { let week = []; this._weekNumbers = []; let weekday; - const _monthsNameWide = this._oLocaleData.getMonths("wide", this._calendarDate._oUDate.sCalendarType); + const _monthsNameWide = localeData.getMonths("wide", this._calendarDate._oUDate.sCalendarType); this._minDateObject = new Date(this._minDate); this._maxDateObject = new Date(this._maxDate); @@ -335,7 +336,7 @@ class DayPicker extends UI5Element { if (day.classes.indexOf("ui5-dp-wday6") !== -1 || _aVisibleDays.length - 1 === i) { - const weekNumber = calculateWeekNumber(getFirstDayOfWeek(), oCalDate.toUTCJSDate(), oCalDate.getYear(), this._oLocale, this._oLocaleData); + const weekNumber = calculateWeekNumber(getFirstDayOfWeek(), oCalDate.toUTCJSDate(), oCalDate.getYear(), getLocale(), localeData); if (lastWeekNumber !== weekNumber) { const weekNum = { weekNum: weekNumber, @@ -358,8 +359,8 @@ class DayPicker extends UI5Element { this._itemNav.current = todayIndex; } - const aDayNamesWide = this._oLocaleData.getDays("wide", this._primaryCalendarType); - const aDayNamesAbbreviated = this._oLocaleData.getDays("abbreviated", this._primaryCalendarType); + const aDayNamesWide = localeData.getDays("wide", this._primaryCalendarType); + const aDayNamesAbbreviated = localeData.getDays("abbreviated", this._primaryCalendarType); const aUltraShortNames = aDayNamesAbbreviated.map(n => n); let dayName; @@ -607,7 +608,8 @@ class DayPicker extends UI5Element { } get _primaryCalendarType() { - return this.primaryCalendarType || getCalendarType() || LocaleData.getInstance(getLocale()).getPreferredCalendarType(); + const localeData = getCachedLocaleDataInstance(getLocale()); + return this.primaryCalendarType || getCalendarType() || localeData.getPreferredCalendarType(); } get focusableDays() { @@ -793,9 +795,11 @@ class DayPicker extends UI5Element { } _isWeekend(oDate) { + const localeData = getCachedLocaleDataInstance(getLocale()); + const iWeekDay = oDate.getDay(), - iWeekendStart = this._oLocaleData.getWeekendStart(), - iWeekendEnd = this._oLocaleData.getWeekendEnd(); + iWeekendStart = localeData.getWeekendStart(), + iWeekendEnd = localeData.getWeekendEnd(); return (iWeekDay >= iWeekendStart && iWeekDay <= iWeekendEnd) || (iWeekendEnd < iWeekendStart && (iWeekDay >= iWeekendStart || iWeekDay <= iWeekendEnd)); @@ -926,8 +930,9 @@ class DayPicker extends UI5Element { } _getFirstDayOfWeek() { + const localeData = getCachedLocaleDataInstance(getLocale()); const confFirstDayOfWeek = getFirstDayOfWeek(); - return Number.isInteger(confFirstDayOfWeek) ? confFirstDayOfWeek : this._oLocaleData.getFirstDayOfWeek(); + return Number.isInteger(confFirstDayOfWeek) ? confFirstDayOfWeek : localeData.getFirstDayOfWeek(); } get styles() { diff --git a/packages/main/src/MonthPicker.js b/packages/main/src/MonthPicker.js index 4d51d8ec6d9b..6cf5b5198f8e 100644 --- a/packages/main/src/MonthPicker.js +++ b/packages/main/src/MonthPicker.js @@ -2,7 +2,7 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import { getCalendarType } from "@ui5/webcomponents-base/dist/config/CalendarType.js"; import DateFormat from "@ui5/webcomponents-localization/dist/DateFormat.js"; -import LocaleData from "@ui5/webcomponents-localization/dist/LocaleData.js"; +import getCachedLocaleDataInstance from "@ui5/webcomponents-localization/dist/getCachedLocaleDataInstance.js"; import ItemNavigation from "@ui5/webcomponents-base/dist/delegate/ItemNavigation.js"; import Integer from "@ui5/webcomponents-base/dist/types/Integer.js"; import { isSpace, isEnter } from "@ui5/webcomponents-base/dist/Keys.js"; @@ -19,6 +19,7 @@ import styles from "./generated/themes/MonthPicker.css.js"; */ const metadata = { tag: "ui5-monthpicker", + languageAware: true, properties: /** @lends sap.ui.webcomponents.main.MonthPicker.prototype */ { /** * A UNIX timestamp - seconds since 00:00:00 UTC on Jan 1, 1970. @@ -133,8 +134,6 @@ class MonthPicker extends UI5Element { constructor() { super(); - this._oLocale = getLocale(); - this._oLocaleData = new LocaleData(this._oLocale); this._itemNav = new ItemNavigation(this, { pageSize: 12, @@ -164,6 +163,8 @@ class MonthPicker extends UI5Element { } onBeforeRendering() { + const localeData = getCachedLocaleDataInstance(getLocale()); + const quarters = []; const oCalDate = CalendarDate.fromTimestamp(new Date().getTime(), this._primaryCalendarType); let timestamp; @@ -175,7 +176,7 @@ class MonthPicker extends UI5Element { const month = { timestamp: timestamp.toString(), id: `${this._id}-m${i}`, - name: this._oLocaleData.getMonths("wide", this._primaryCalendarType)[i], + name: localeData.getMonths("wide", this._primaryCalendarType)[i], classes: "ui5-mp-item", }; @@ -221,7 +222,8 @@ class MonthPicker extends UI5Element { } get _primaryCalendarType() { - return this.primaryCalendarType || getCalendarType() || LocaleData.getInstance(getLocale()).getPreferredCalendarType(); + const localeData = getCachedLocaleDataInstance(getLocale()); + return this.primaryCalendarType || getCalendarType() || localeData.getPreferredCalendarType(); } get _isPattern() { diff --git a/packages/main/src/TimePicker.js b/packages/main/src/TimePicker.js index fb9f7aa9ae6e..c6a6bfb878dd 100644 --- a/packages/main/src/TimePicker.js +++ b/packages/main/src/TimePicker.js @@ -4,7 +4,7 @@ import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18 import getLocale from "@ui5/webcomponents-base/dist/locale/getLocale.js"; import ValueState from "@ui5/webcomponents-base/dist/types/ValueState.js"; import DateFormat from "@ui5/webcomponents-localization/dist/DateFormat.js"; -import LocaleData from "@ui5/webcomponents-localization/dist/LocaleData.js"; +import getCachedLocaleDataInstance from "@ui5/webcomponents-localization/dist/getCachedLocaleDataInstance.js"; import "@ui5/webcomponents-localization/dist/features/calendar/Gregorian.js"; // default calendar for bundling import { fetchCldr } from "@ui5/webcomponents-base/dist/asset-registries/LocaleData.js"; import { isPhone } from "@ui5/webcomponents-base/dist/Device.js"; @@ -345,7 +345,8 @@ class TimePicker extends UI5Element { onBeforeRendering() { if (!this.formatPattern) { - this.formatPattern = LocaleData.getInstance(getLocale()).getTimePattern(this.getFormat().oFormatOptions.style); + const localeData = getCachedLocaleDataInstance(getLocale()); + this.formatPattern = localeData.getTimePattern(this.getFormat().oFormatOptions.style); } if (this.value === undefined) { diff --git a/packages/main/src/YearPicker.js b/packages/main/src/YearPicker.js index 55b1f6f1974e..2a6774479208 100644 --- a/packages/main/src/YearPicker.js +++ b/packages/main/src/YearPicker.js @@ -1,6 +1,6 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; -import LocaleData from "@ui5/webcomponents-localization/dist/LocaleData.js"; +import getCachedLocaleDataInstance from "@ui5/webcomponents-localization/dist/getCachedLocaleDataInstance.js"; import DateFormat from "@ui5/webcomponents-localization/dist/DateFormat.js"; import { getCalendarType } from "@ui5/webcomponents-base/dist/config/CalendarType.js"; import { isEnter, isSpace } from "@ui5/webcomponents-base/dist/Keys.js"; @@ -20,6 +20,7 @@ import styles from "./generated/themes/YearPicker.css.js"; */ const metadata = { tag: "ui5-yearpicker", + languageAware: true, properties: /** @lends sap.ui.webcomponents.main.YearPicker.prototype */ { /** * A UNIX timestamp - seconds since 00:00:00 UTC on Jan 1, 1970. @@ -244,7 +245,8 @@ class YearPicker extends UI5Element { } get _primaryCalendarType() { - return this.primaryCalendarType || getCalendarType() || LocaleData.getInstance(getLocale()).getPreferredCalendarType(); + const localeData = getCachedLocaleDataInstance(getLocale()); + return this.primaryCalendarType || getCalendarType() || localeData.getPreferredCalendarType(); } get _isPattern() { diff --git a/packages/main/test/pages/Simple.html b/packages/main/test/pages/Simple.html index 22c679393e4f..4267bb4b36f9 100644 --- a/packages/main/test/pages/Simple.html +++ b/packages/main/test/pages/Simple.html @@ -7,15 +7,7 @@ Button - + @@ -26,6 +18,7 @@ + From 37c535e26bafc667ebf676c9f60d86e3096d1bd1 Mon Sep 17 00:00:00 2001 From: Vladislav Tasev Date: Thu, 5 Nov 2020 14:39:19 +0200 Subject: [PATCH 2/5] retrigger build --- packages/localization/src/getCachedLocaleDataInstance.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/localization/src/getCachedLocaleDataInstance.js b/packages/localization/src/getCachedLocaleDataInstance.js index 007488b9db03..fe3a6966cc5f 100644 --- a/packages/localization/src/getCachedLocaleDataInstance.js +++ b/packages/localization/src/getCachedLocaleDataInstance.js @@ -6,7 +6,6 @@ const getCachedLocaleDataInstance = locale => { if (!cache.has(locale)) { cache.set(locale, LocaleData.getInstance(locale)); } - return cache.get(locale); }; From d688d4d5f9008d6d934a8506389a4aeb80770a79 Mon Sep 17 00:00:00 2001 From: Vladislav Tasev Date: Fri, 6 Nov 2020 08:17:50 +0200 Subject: [PATCH 3/5] build --- packages/localization/src/getCachedLocaleDataInstance.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/localization/src/getCachedLocaleDataInstance.js b/packages/localization/src/getCachedLocaleDataInstance.js index fe3a6966cc5f..007488b9db03 100644 --- a/packages/localization/src/getCachedLocaleDataInstance.js +++ b/packages/localization/src/getCachedLocaleDataInstance.js @@ -6,6 +6,7 @@ const getCachedLocaleDataInstance = locale => { if (!cache.has(locale)) { cache.set(locale, LocaleData.getInstance(locale)); } + return cache.get(locale); }; From 1551fa73d51b53343fcfb91d8bb06371abac241d Mon Sep 17 00:00:00 2001 From: Vladislav Tasev Date: Fri, 6 Nov 2020 09:47:06 +0200 Subject: [PATCH 4/5] try to fix failing test --- packages/main/test/specs/MultiComboBox.spec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/main/test/specs/MultiComboBox.spec.js b/packages/main/test/specs/MultiComboBox.spec.js index 929f9191cb4f..68fdc8c1732a 100644 --- a/packages/main/test/specs/MultiComboBox.spec.js +++ b/packages/main/test/specs/MultiComboBox.spec.js @@ -25,10 +25,12 @@ describe("MultiComboBox general interaction", () => { assert.ok(mcb.getProperty("focused"), "MultiComboBox should be focused."); input.keys("ArrowLeft"); + browser.pause(500); assert.notOk(mcb.getProperty("focused"), "MultiComboBox should no longer be focused."); input.keys("ArrowRight"); + browser.pause(500); assert.ok(mcb.getProperty("focused"), "MultiComboBox should be focused again."); }); From df0b959960d458491314b2e7f006fc3f3ea23fb4 Mon Sep 17 00:00:00 2001 From: Vladislav Tasev Date: Fri, 6 Nov 2020 10:31:28 +0200 Subject: [PATCH 5/5] again --- packages/main/test/specs/MultiComboBox.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/main/test/specs/MultiComboBox.spec.js b/packages/main/test/specs/MultiComboBox.spec.js index 68fdc8c1732a..3147a53f7107 100644 --- a/packages/main/test/specs/MultiComboBox.spec.js +++ b/packages/main/test/specs/MultiComboBox.spec.js @@ -25,12 +25,12 @@ describe("MultiComboBox general interaction", () => { assert.ok(mcb.getProperty("focused"), "MultiComboBox should be focused."); input.keys("ArrowLeft"); - browser.pause(500); + browser.pause(100); assert.notOk(mcb.getProperty("focused"), "MultiComboBox should no longer be focused."); input.keys("ArrowRight"); - browser.pause(500); + browser.pause(100); assert.ok(mcb.getProperty("focused"), "MultiComboBox should be focused again."); });