Skip to content

Commit ccf8c2e

Browse files
committed
fix(localization): use correct language tag format
Replace `getLanguage() || "en"` with `getLocale().toString()` in both `Formatting.getLanguageTag()` and `Localization.getLanguageTag()`. `getLanguage()` returns only a bare language code (e.g. `"en"`, `"de"`), which drops region and script subtags. In contrast, `getLocale()` provides a parsed `Locale` object whose `toString()` reconstructs the full BCP 47 tag (e.g. `"en-US"`, `"zh-Hans-CN"`), aligning with the output of OpenUI5’s `LanguageTag.toString()`. This change ensures that CLDR-based formatting applies the correct locale-specific rules, such as date formats, number separators, and first day of the week. Additionally: * Introduce typed overloads in `DateFormat.ts` for `getDateInstance()`, allowing it to accept either formatting options or a `LocaleWrapped` instance. * Add `Locale.ts` as a typed wrapper around the native `sap/ui/core/Locale` shim. * Export `DateFormatOptions`, covering all supported configuration fields. Related to: #13312
1 parent 3a88b2c commit ccf8c2e

File tree

13 files changed

+82
-41
lines changed

13 files changed

+82
-41
lines changed

packages/localization/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
"resolve": "^1.20.0"
4040
},
4141
"dependencies": {
42-
"@types/openui5": "^1.113.0",
42+
"@types/openui5": "^1.146.0",
4343
"@ui5/webcomponents-base": "2.20.2"
4444
}
4545
}
Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,42 @@
11
import type DateFormatT from "sap/ui/core/format/DateFormat";
22
// @ts-ignore
33
import DateFormatNative from "./sap/ui/core/format/DateFormat.js";
4+
import getLocale from "@ui5/webcomponents-base/dist/locale/getLocale.js";
5+
import LocaleWrapped from "./Locale.js";
6+
import type CalendarWeekNumbering from "sap/base/i18n/date/CalendarWeekNumbering";
7+
import type CalendarType from "sap/base/i18n/date/CalendarType";
8+
9+
type DateFormatOptions = {
10+
calendarWeekNumbering?: CalendarWeekNumbering | keyof typeof CalendarWeekNumbering;
11+
firstDayOfWeek?: int;
12+
minimalDaysInFirstWeek?: int;
13+
format?: string;
14+
pattern?: string;
15+
style?: string;
16+
strictParsing?: boolean;
17+
relative?: boolean;
18+
relativeRange?: int[];
19+
relativeScale?: string;
20+
relativeStyle?: string;
21+
interval?: boolean;
22+
intervalDelimiter?: string;
23+
singleIntervalValue?: boolean;
24+
UTC?: boolean;
25+
calendarType?: CalendarType | keyof typeof CalendarType;
26+
};
427

528
const DateFormatWrapped = DateFormatNative as typeof DateFormatT;
6-
class DateFormat extends DateFormatWrapped {}
29+
30+
class DateFormat extends DateFormatWrapped {
31+
static getDateInstance(oFormatOptions?: DateFormatOptions, oLocale?: LocaleWrapped): DateFormat;
32+
static getDateInstance(oLocale?: LocaleWrapped): DateFormat;
33+
static getDateInstance(oFormatOptionsOrLocale?: DateFormatOptions | LocaleWrapped, oLocale?: LocaleWrapped): DateFormat {
34+
if (oFormatOptionsOrLocale instanceof LocaleWrapped) {
35+
return DateFormatWrapped.getDateInstance(undefined, oFormatOptionsOrLocale);
36+
}
37+
const nativeLocale = oLocale ?? new LocaleWrapped(getLocale().toString());
38+
return DateFormatWrapped.getDateInstance(oFormatOptionsOrLocale, nativeLocale);
39+
}
40+
}
741

842
export default DateFormat;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type LocaleOpenUI5T from "sap/ui/core/Locale";
2+
// @ts-ignore
3+
import LocaleNative from "./sap/ui/core/Locale.js";
4+
5+
const LocaleWrapped = LocaleNative as typeof LocaleOpenUI5T;
6+
class Locale extends LocaleWrapped { }
7+
8+
export default Locale;

packages/localization/src/dates/convertMonthNumbersToMonthNames.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import getCachedLocaleDataInstance from "../getCachedLocaleDataInstance.js";
1515
const convertMonthNumbersToMonthNames = (firstMonth: number, lastMonth: number, calendarType?: `${CalendarType}`) => {
1616
const localeData = getCachedLocaleDataInstance(getLocale());
1717
const pattern = localeData.getIntervalPattern("");
18-
const secondaryMonthsNames = localeData.getMonthsStandAlone("abbreviated", calendarType) as Array<string>;
19-
const secondaryMonthsNamesWide = localeData.getMonthsStandAlone("wide", calendarType) as Array<string>;
18+
const secondaryMonthsNames = localeData.getMonthsStandAlone("abbreviated", calendarType);
19+
const secondaryMonthsNamesWide = localeData.getMonthsStandAlone("wide", calendarType);
2020

2121
if (firstMonth === lastMonth) {
2222
return {

packages/localization/src/getCachedLocaleDataInstance.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ const cache = new Map<Locale, LocaleData>();
66

77
const getCachedLocaleDataInstance = (locale: Locale) => {
88
if (!cache.has(locale)) {
9+
// @ts-expect-error - The LocaleData constructor expects a LocaleT, but we are passing a Locale. This is a known issue and can be ignored for now.
10+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
911
cache.set(locale, new LocaleData(locale as unknown as LocaleT));
1012
}
1113

packages/localization/src/locale/getLocaleData.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ const getLocaleData = async (lang: string): Promise<LocaleData> => {
1919

2020
if (!instances.has(localeLang)) {
2121
await fetchCldr(locale.getLanguage(), locale.getRegion(), locale.getScript());
22+
// @ts-expect-error - The LocaleData constructor expects a LocaleT, but we are passing a Locale. This is a known issue and can be ignored for now.
23+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
2224
instances.set(localeLang, new LocaleData(locale as unknown as LocaleT));
2325
}
2426

packages/localization/src/sap/base/i18n/Formatting.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import { getLegacyDateCalendarCustomizing } from "@ui5/webcomponents-base/dist/config/FormatSettings.js";
2-
import { getLanguage } from "@ui5/webcomponents-base/dist/config/Language.js";
32
import { getCalendarType } from "@ui5/webcomponents-base/dist/config/CalendarType.js";
3+
import getLocale from "@ui5/webcomponents-base/dist/locale/getLocale.js";
44

5-
const emptyFn = () => {};
5+
const emptyFn = () => { };
66

77
/**
88
* OpenUI5 Formatting Shim
99
*/
1010
const Formatting = {
1111
getABAPDateFormat: emptyFn,
1212
getCustomIslamicCalendarData: getLegacyDateCalendarCustomizing,
13-
getLanguageTag: () => getLanguage() || "en",
13+
getLanguageTag: () => getLocale().toString(),
1414
getCalendarType,
1515
getTrailingCurrencyCode: () => true,
1616
getCustomLocaleData: () => ({}),

packages/localization/src/sap/base/i18n/Localization.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { getLanguage } from "@ui5/webcomponents-base/dist/config/Language.js";
21
import { getTimezone as getConfigTimezone } from "@ui5/webcomponents-base/dist/config/Timezone.js";
2+
import getLocale from "@ui5/webcomponents-base/dist/locale/getLocale.js";
33

44
const M_ISO639_OLD_TO_NEW = {
55
"iw": "he",
@@ -12,7 +12,7 @@ const getModernLanguage = (sLanguage: string) => {
1212

1313
const Localization = {
1414
getModernLanguage,
15-
getLanguageTag: () => getLanguage() || "en",
15+
getLanguageTag: () => getLocale().toString(),
1616
getTimezone: () => getConfigTimezone() || Intl.DateTimeFormat().resolvedOptions().timeZone,
1717
setTimezone: () => {},
1818
};

packages/main/src/DayPicker.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,8 @@ class DayPicker extends CalendarPart implements ICalendarPicker {
233233

234234
const firstDayOfWeek = this._getFirstDayOfWeek();
235235
const specialCalendarDates = this._specialCalendarDates;
236-
const monthsNames = localeData.getMonths("wide", this._primaryCalendarType) as Array<string>;
237-
const secondaryMonthsNames = this.hasSecondaryCalendarType ? localeData.getMonths("wide", this.secondaryCalendarType) as Array<string> : [];
236+
const monthsNames = localeData.getMonths("wide", this._primaryCalendarType);
237+
const secondaryMonthsNames = this.hasSecondaryCalendarType ? localeData.getMonths("wide", this.secondaryCalendarType) : [];
238238
const nonWorkingDayLabel = DayPicker.i18nBundle.getText(DAY_PICKER_NON_WORKING_DAY);
239239
const todayLabel = DayPicker.i18nBundle.getText(DAY_PICKER_TODAY);
240240
const tempDate = this._getFirstDay(); // date that will be changed by 1 day 42 times
@@ -385,12 +385,12 @@ class DayPicker extends CalendarPart implements ICalendarPicker {
385385

386386
let dayOfTheWeek;
387387

388-
const aDayNamesWide = localeData.getDays("wide", this._primaryCalendarType) as Array<string>;
389-
let aDayNamesAbbreviated = localeData.getDays("abbreviated", this._primaryCalendarType) as Array<string>;
388+
const aDayNamesWide = localeData.getDays("wide", this._primaryCalendarType);
389+
let aDayNamesAbbreviated = localeData.getDays("abbreviated", this._primaryCalendarType);
390390
let dayName;
391391

392392
if (this.namesTooLong(aDayNamesAbbreviated)) {
393-
aDayNamesAbbreviated = localeData.getDays("narrow", this._primaryCalendarType) as Array<string>;
393+
aDayNamesAbbreviated = localeData.getDays("narrow", this._primaryCalendarType);
394394
}
395395

396396
this._dayNames = [];

packages/main/src/MonthPicker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ type Month = {
4646
selected: boolean,
4747
ariaSelected: boolean,
4848
name: string,
49-
nameInSecType: string,
49+
nameInSecType: string | undefined,
5050
disabled: boolean,
5151
ariaDisabled: boolean | undefined,
5252
classes: string,
@@ -191,7 +191,7 @@ class MonthPicker extends CalendarPart implements ICalendarPicker {
191191
selected: isSelected || isSelectedBetween,
192192
ariaSelected: isSelected || isSelectedBetween,
193193
name: monthsNames[i],
194-
nameInSecType: this.hasSecondaryCalendarType && this._getDisplayedSecondaryMonthText(timestamp).text,
194+
nameInSecType: this.hasSecondaryCalendarType ? this._getDisplayedSecondaryMonthText(timestamp).text : undefined,
195195
disabled: isDisabled,
196196
ariaDisabled: isDisabled,
197197
classes: "ui5-mp-item",

0 commit comments

Comments
 (0)