From a9363bf0b8844f8ce34018c3c53ebb0b3096a3dc Mon Sep 17 00:00:00 2001
From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com>
Date: Mon, 7 Aug 2023 22:51:42 +0200
Subject: [PATCH] [browser][non-icu] `HybridGlobalization` calendar data
(#89255)
* Calendar WIP.
* Genitive months.
* Short pattern.
* NativeCalendarName does not exist on WebAPI - use EnglishCalendarName.
* Fix failures in Locales caused by calendars data removal.
* Fix to previous commit.
* Whitespace.
* Implemented Eras.
* Populate NativeName with EnglishName.
* Fix tests.
* Typos + comments removal + block failing test.
* AM/PM designators are not in ICU anymore.
* ShortTimePattern is ready.
* Fix some failing tests.
* LongTimePatterns is ready.
* Ask about all culture info from JS at once.
* Fix remaining tests.
* Calendar Globalization tests fixed.
* Adding test files to projects.
* Build fix.
* Fix the fix.
* .
* Fix tests.
* Load locale info on request + fix Browser scenario tests.
* Fix test on v8.
* Forgotten clean-up.
* Small cleanup in ts.
* V8 11 is behaves more like browser.
* Fixed skipped failing tests.
* Syntax
* V8 returns the same as Browser.
* This API is not affected, no need to test. + Add documentation.
* Revert unintentional change.
* Feedback.
* @radical's feedback + fix after removing unnecessary set.
* Fix.
* Feedback.
* Fix tests.
---
docs/design/features/globalization-hybrid-mode.md | 55 +++
.../Common/src/Interop/Browser/Interop.Calendar.cs | 14 +
.../Common/src/Interop/Browser/Interop.Locale.cs | 17 +
.../TestUtilities/System/PlatformDetection.cs | 1 +
...lobalization.Calendars.Hybrid.WASM.Tests.csproj | 109 ++++++
.../tests/System/Globalization/CalendarTestBase.cs | 5 +-
.../tests/CultureInfo/CultureInfoCtor.cs | 4 +-
.../DateTimeFormatInfoAMDesignator.cs | 199 +++++++++++
.../DateTimeFormatInfoAbbreviatedDayNames.cs | 65 ++++
...eTimeFormatInfoAbbreviatedMonthGenitiveNames.cs | 204 ++++++++++-
.../DateTimeFormatInfoAbbreviatedMonthNames.cs | 201 ++++++++++-
.../DateTimeFormatInfoCalendarWeekRule.cs | 190 ++++++++++
.../DateTimeFormatInfoDayNames.cs | 57 +++
.../DateTimeFormatInfoFirstDayOfWeek.cs | 197 ++++++++++-
.../DateTimeFormatInfoFullDateTimePattern.cs | 196 +++++++++++
.../DateTimeFormatInfoGetAbbreviatedEraName.cs | 191 ++++++++++
.../DateTimeFormatInfoGetEraName.cs | 392 ++++++++++++++++++++-
.../DateTimeFormatInfoLongDatePattern.cs | 199 ++++++++++-
.../DateTimeFormatInfoLongTimePattern.cs | 198 +++++++++++
.../DateTimeFormatInfoMonthDayPattern.cs | 200 ++++++++++-
.../DateTimeFormatInfoMonthGenitiveNames.cs | 191 ++++++++++
.../DateTimeFormatInfoMonthNames.cs | 199 +++++++++++
.../DateTimeFormatInfoNativeCalendarName.cs | 210 +++++++++++
.../DateTimeFormatInfoPMDesignator.cs | 199 +++++++++++
.../DateTimeFormatInfoShortDatePattern.cs | 199 +++++++++++
.../DateTimeFormatInfoShortTimePattern.cs | 198 +++++++++++
.../DateTimeFormatInfoShortestDayNames.cs | 61 ++++
.../DateTimeFormatInfo/DateTimeFormatInfoTests.cs | 2 +-
.../DateTimeFormatInfoYearMonthPattern.cs | 24 ++
.../System.Globalization.Hybrid.WASM.Tests.csproj | 36 ++
.../src/System.Private.CoreLib.Shared.projitems | 8 +
.../System/Globalization/CalendarData.Browser.cs | 56 +++
.../src/System/Globalization/CalendarData.Icu.cs | 1 +
.../src/System/Globalization/CalendarData.Unix.cs | 12 +-
.../src/System/Globalization/CalendarData.cs | 14 +-
.../System/Globalization/CultureData.Browser.cs | 57 +++
.../src/System/Globalization/CultureData.cs | 31 +-
.../src/System/Globalization/DateTimeParse.cs | 18 +-
src/mono/wasm/runtime/corebindings.c | 10 +-
src/mono/wasm/runtime/es6/dotnet.es6.lib.js | 6 +-
src/mono/wasm/runtime/exports-linker.ts | 9 +-
.../wasm/runtime/hybrid-globalization/calendar.ts | 380 ++++++++++++++++++++
.../runtime/hybrid-globalization/culture-info.ts | 130 +++++++
.../wasm/runtime/hybrid-globalization/helpers.ts | 27 ++
.../wasm/runtime/hybrid-globalization/locales.ts | 114 ++++++
45 files changed, 4861 insertions(+), 25 deletions(-)
create mode 100644 src/libraries/Common/src/Interop/Browser/Interop.Calendar.cs
create mode 100644 src/libraries/Common/src/Interop/Browser/Interop.Locale.cs
create mode 100644 src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.Hybrid.WASM.Tests.csproj
create mode 100644 src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoNativeCalendarName.cs
create mode 100644 src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs
create mode 100644 src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs
create mode 100644 src/mono/wasm/runtime/hybrid-globalization/calendar.ts
create mode 100644 src/mono/wasm/runtime/hybrid-globalization/culture-info.ts
create mode 100644 src/mono/wasm/runtime/hybrid-globalization/helpers.ts
create mode 100644 src/mono/wasm/runtime/hybrid-globalization/locales.ts
diff --git a/docs/design/features/globalization-hybrid-mode.md b/docs/design/features/globalization-hybrid-mode.md
index 7f7b3bb..373804a 100644
--- a/docs/design/features/globalization-hybrid-mode.md
+++ b/docs/design/features/globalization-hybrid-mode.md
@@ -272,6 +272,61 @@ Using `IgnoreNonSpace` for these two with `HybridGlobalization` off, also return
new CultureInfo("de-DE").CompareInfo.IndexOf("strasse", "stra\u00DFe", 0, CompareOptions.IgnoreNonSpace); // 0 or -1
```
+**Calandars**
+
+Affected public APIs:
+- DateTimeFormatInfo.AbbreviatedDayNames
+- DateTimeFormatInfo.GetAbbreviatedDayName()
+- DateTimeFormatInfo.AbbreviatedMonthGenitiveNames
+- DateTimeFormatInfo.AbbreviatedMonthNames
+- DateTimeFormatInfo.GetAbbreviatedMonthName()
+- DateTimeFormatInfo.AMDesignator
+- DateTimeFormatInfo.CalendarWeekRule
+- DateTimeFormatInfo.DayNames
+- DateTimeFormatInfo.GetDayName
+- DateTimeFormatInfo.GetAbbreviatedEraName()
+- DateTimeFormatInfo.GetEraName()
+- DateTimeFormatInfo.FirstDayOfWeek
+- DateTimeFormatInfo.FullDateTimePattern
+- DateTimeFormatInfo.LongDatePattern
+- DateTimeFormatInfo.LongTimePattern
+- DateTimeFormatInfo.MonthDayPattern
+- DateTimeFormatInfo.MonthGenitiveNames
+- DateTimeFormatInfo.MonthNames
+- DateTimeFormatInfo.GetMonthName()
+- DateTimeFormatInfo.NativeCalendarName
+- DateTimeFormatInfo.PMDesignator
+- DateTimeFormatInfo.ShortDatePattern
+- DateTimeFormatInfo.ShortestDayNames
+- DateTimeFormatInfo.GetShortestDayName()
+- DateTimeFormatInfo.ShortTimePattern
+- DateTimeFormatInfo.YearMonthPattern
+
+
+The Hybrid responses may differ because they use Web API functions. To better ilustrate the mechanism we provide an example for each endpoint. All exceptions cannot be listed, for reference check the response of specific version of Web API on your host.
+| **API** | **Functions used** | **Example of difference for locale** | **non-Hybrid** | **Hybrid** |
+|:-----------------------------:|:----------------------------------------------------------------------------------------------------------------------------------:|:------------------------------------:|:------------------:|:-----------------:|
+| AbbreviatedDayNames | `Date.prototype.toLocaleDateString(locale, { weekday: "short" })` | en-CA | Sun. | Sun |
+| AbbreviatedMonthGenitiveNames | `Date.prototype.toLocaleDateString(locale, { month: "short", day: "numeric"})` | kn-IN | à²à² | à²à²à²¸à³à²à³ |
+| AbbreviatedMonthNames | `Date.prototype.toLocaleDateString(locale, { month: "short" })` | lt-LT | saus. | 01 |
+| AMDesignator | `Date.prototype.toLocaleTimeString(locale, { hourCycle: "h12"})`; `Date.prototype.toLocaleTimeString(locale, { hourCycle: "h24"})` | sr-Cyrl-RS | пÑе подне | AM |
+| CalendarWeekRule | `Intl.Locale.prototype.getWeekInfo().minimalDay` | none | - | - |
+| DayNames | `Date.prototype.toLocaleDateString(locale, { weekday: "long" })` | none | - | - |
+| GetAbbreviatedEraName() | `Date.prototype.toLocaleDateString(locale, { era: "narrow" })` | bn-IN | à¦à§à¦·à§à¦à¦¾à¦¬à§à¦¦ | à¦à§à¦°à¦¿à¦ |
+| GetEraName() | `Date.prototype.toLocaleDateString(locale, { era: "short" })` | vi-VI | sau CN | CN |
+| FirstDayOfWeek | `Intl.Locale.prototype.getWeekInfo().firstDay` | zn-CN | Sunday | Monday |
+| FullDateTimePattern | `LongDatePattern` and `LongTimePattern` | - | | |
+| LongDatePattern | `Intl.DateTimeFormat(locale, { weekday: "long", year: "numeric", month: "long", day: "numeric"}).format(date)` | en-BW | dddd, dd MMMM yyyy | dddd, d MMMM yyyy |
+| LongTimePattern | `Intl.DateTimeFormat(locale, { timeStyle: "medium" })` | zn-CN | tth:mm:ss | HH:mm:ss |
+| MonthDayPattern | `Date.prototype.toLocaleDateString(locale, { month: "long", day: "numeric"})` | en-PH | d MMMM | MMMM d |
+| MonthGenitiveNames | `Date.prototype.toLocaleDateString(locale, { month: "long", day: "numeric"})` | ca-AD | de gener | gener |
+| MonthNames | `Date.prototype.toLocaleDateString(locale, { month: "long" })` | el-GR | ÎανοÏ
αÏίοÏ
| ÎανοÏ
άÏÎ¹Î¿Ï |
+| NativeCalendarName | `Intl.Locale.prototype.getCalendars()` | for all locales it has English names | Gregorian Calendar | gregory |
+| PMDesignator | `Date.prototype.toLocaleTimeString(locale, { hourCycle: "h12"})`; `Date.prototype.toLocaleTimeString(locale, { hourCycle: "h24"})` | mr-IN | म.à¤. | PM |
+| ShortDatePattern | `Date.prototype.toLocaleDateString(locale, {dateStyle: "short"})` | en-CH | dd.MM.yyyy | dd/MM/yyyy |
+| ShortestDayNames | `Date.prototype.toLocaleDateString(locale, { weekday: "narrow" })` | none | - | - |
+| ShortTimePattern | `Intl.DateTimeFormat(locale, { timeStyle: "medium" })` | bg-BG | HH:mm | H:mm |
+| YearMonthPattern | `Date.prototype.toLocaleDateString(locale, { year: "numeric", month: "long" })` | ar-SA | MMMM yyyy | MMMM yyyy g |
### OSX
diff --git a/src/libraries/Common/src/Interop/Browser/Interop.Calendar.cs b/src/libraries/Common/src/Interop/Browser/Interop.Calendar.cs
new file mode 100644
index 0000000..2a7b1d0
--- /dev/null
+++ b/src/libraries/Common/src/Interop/Browser/Interop.Calendar.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Globalization;
+using System.Runtime.CompilerServices;
+
+internal static partial class Interop
+{
+ internal static unsafe partial class JsGlobalization
+ {
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern unsafe int GetCalendarInfo(in string culture, CalendarId calendarId, char* buffer, int bufferLength, out int exceptionalResult, out object result);
+ }
+}
diff --git a/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs b/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs
new file mode 100644
index 0000000..c882d88
--- /dev/null
+++ b/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.CompilerServices;
+
+internal static partial class Interop
+{
+ internal static unsafe partial class JsGlobalization
+ {
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern unsafe int GetCultureInfo(in string culture, char* buffer, int bufferLength, out int exceptionalResult, out object result);
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern unsafe int GetFirstDayOfWeek(in string culture, out int exceptionalResult, out object result);
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern unsafe int GetFirstWeekOfYear(in string culture, out int exceptionalResult, out object result);
+ }
+}
diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
index da450c0..c0bbcaa 100644
--- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
+++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
@@ -366,6 +366,7 @@ namespace System
public static bool IsNotHybridGlobalizationOnBrowser => !IsHybridGlobalizationOnBrowser;
public static bool IsNotInvariantGlobalization => !IsInvariantGlobalization;
public static bool IsIcuGlobalization => ICUVersion > new Version(0, 0, 0, 0);
+ public static bool IsIcuGlobalizationAndNotHybridOnBrowser => IsIcuGlobalization && IsNotHybridGlobalizationOnBrowser;
public static bool IsNlsGlobalization => IsNotInvariantGlobalization && !IsIcuGlobalization;
public static bool IsSubstAvailable
diff --git a/src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.Hybrid.WASM.Tests.csproj b/src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.Hybrid.WASM.Tests.csproj
new file mode 100644
index 0000000..5b89836
--- /dev/null
+++ b/src/libraries/System.Globalization.Calendars/tests/Hybrid/System.Globalization.Calendars.Hybrid.WASM.Tests.csproj
@@ -0,0 +1,109 @@
+
+
+ $(NetCoreAppCurrent)-browser
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/libraries/System.Globalization.Calendars/tests/System/Globalization/CalendarTestBase.cs b/src/libraries/System.Globalization.Calendars/tests/System/Globalization/CalendarTestBase.cs
index 62e1b36..c99b883 100644
--- a/src/libraries/System.Globalization.Calendars/tests/System/Globalization/CalendarTestBase.cs
+++ b/src/libraries/System.Globalization.Calendars/tests/System/Globalization/CalendarTestBase.cs
@@ -430,7 +430,10 @@ namespace System.Globalization.Tests
Assert.All(DateTime_TestData(calendar), dt =>
{
// JapaneseCalendar throws on ICU, but not on NLS
- if ((calendar is JapaneseCalendar && PlatformDetection.IsNlsGlobalization) || calendar is HebrewCalendar || calendar is TaiwanLunisolarCalendar || calendar is JapaneseLunisolarCalendar)
+ if ((calendar is JapaneseCalendar && PlatformDetection.IsNlsGlobalization) ||
+ calendar is HebrewCalendar ||
+ calendar is TaiwanLunisolarCalendar ||
+ calendar is JapaneseLunisolarCalendar)
{
calendar.GetEra(dt);
}
diff --git a/src/libraries/System.Globalization/tests/CultureInfo/CultureInfoCtor.cs b/src/libraries/System.Globalization/tests/CultureInfo/CultureInfoCtor.cs
index f1af25e..3717560 100644
--- a/src/libraries/System.Globalization/tests/CultureInfo/CultureInfoCtor.cs
+++ b/src/libraries/System.Globalization/tests/CultureInfo/CultureInfoCtor.cs
@@ -442,7 +442,7 @@ namespace System.Globalization.Tests
[InlineData("de-DE-u-co-phonebk-t-xx", "de-DE-t-xx", "de-DE-t-xx_phoneboo")]
[InlineData("de-DE-u-co-phonebk-t-xx-u-yy", "de-DE-t-xx-u-yy", "de-DE-t-xx-u-yy_phoneboo")]
[InlineData("de-DE", "de-DE", "de-DE")]
- [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization))]
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalizationAndNotHybridOnBrowser))]
public void TestCreationWithMangledSortName(string cultureName, string expectedCultureName, string expectedSortName)
{
CultureInfo ci = CultureInfo.GetCultureInfo(cultureName);
@@ -457,7 +457,7 @@ namespace System.Globalization.Tests
[InlineData("qps-plocm", "qps-PLOCM")] // ICU normalize this name to "qps--plocm" which we normalize it back to "qps-plocm"
[InlineData("zh_CN", "zh_cn")]
[InlineData("km_KH", "km_kh")]
- [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization), nameof(PlatformDetection.IsNotWindowsServerCore))]
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalizationAndNotHybridOnBrowser), nameof(PlatformDetection.IsNotWindowsServerCore))]
public void TestCreationWithICUNormalizedNames(string cultureName, string expectedCultureName)
{
CultureInfo ci = CultureInfo.GetCultureInfo(cultureName);
diff --git a/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoAMDesignator.cs b/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoAMDesignator.cs
index 5c284c5..0eeb6d9 100644
--- a/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoAMDesignator.cs
+++ b/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoAMDesignator.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using Xunit;
+using System.Collections.Generic;
namespace System.Globalization.Tests
{
@@ -13,6 +14,204 @@ namespace System.Globalization.Tests
Assert.Equal("AM", DateTimeFormatInfo.InvariantInfo.AMDesignator);
}
+ public static IEnumerable