Skip to content

Commit e210a60

Browse files
tarekghkasperk81
andauthored
Fix Creating Cultures with Sort Names (#63386)
Co-authored-by: kasperk81 <83082615+kasperk81@users.noreply.github.com>
1 parent c49c65d commit e210a60

File tree

6 files changed

+30
-4
lines changed

6 files changed

+30
-4
lines changed

src/libraries/System.Globalization/tests/CultureInfo/CultureInfoCtor.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,5 +439,14 @@ public void TestCreationWithTemporaryLCID(int lcid)
439439

440440
Assert.NotEqual(lcid, new CultureInfo(lcid).LCID);
441441
}
442+
443+
[InlineData("zh-TW-u-co-zhuyin")]
444+
[InlineData("de-DE-u-co-phoneb")]
445+
[InlineData("de-u-co-phonebk")]
446+
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization))]
447+
public void TestCreationWithMangledSortName(string cultureName)
448+
{
449+
Assert.True(CultureInfo.GetCultureInfo(cultureName).CompareInfo.Name.Equals(cultureName, StringComparison.OrdinalIgnoreCase));
450+
}
442451
}
443452
}

src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public partial class CompareInfo
1414
[NonSerialized]
1515
private bool _isAsciiEqualityOrdinal;
1616

17-
private void IcuInitSortHandle()
17+
private void IcuInitSortHandle(string interopCultureName)
1818
{
1919
if (GlobalizationMode.Invariant)
2020
{
@@ -23,6 +23,7 @@ private void IcuInitSortHandle()
2323
else
2424
{
2525
Debug.Assert(!GlobalizationMode.UseNls);
26+
Debug.Assert(interopCultureName != null);
2627

2728
// Inline the following condition to avoid potential implementation cycles within globalization
2829
//
@@ -31,7 +32,7 @@ private void IcuInitSortHandle()
3132
_isAsciiEqualityOrdinal = _sortName.Length == 0 ||
3233
(_sortName.Length >= 2 && _sortName[0] == 'e' && _sortName[1] == 'n' && (_sortName.Length == 2 || _sortName[2] == '-'));
3334

34-
_sortHandle = SortHandleCache.GetCachedSortHandle(_sortName);
35+
_sortHandle = SortHandleCache.GetCachedSortHandle(interopCultureName);
3536
}
3637
}
3738

src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ private void InitSort(CultureInfo culture)
191191
}
192192
else
193193
{
194-
IcuInitSortHandle();
194+
IcuInitSortHandle(culture.InteropName!);
195195
}
196196
}
197197

src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Icu.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ private bool InitIcuCultureDataCore()
5050
index = _sWindowsName.IndexOf(ICU_COLLATION_KEYWORD, StringComparison.Ordinal);
5151
if (index >= 0)
5252
{
53-
_sName = string.Concat(_sWindowsName.AsSpan(0, index), "_", alternateSortName);
53+
// Use original culture name if alternateSortName is not set, which is possible even if the normalized
54+
// culture name has "@collation=".
55+
// "zh-TW-u-co-zhuyin" is a good example. The term "u-co-" means the following part will be the sort name
56+
// and it will be treated in ICU as "zh-TW@collation=zhuyin".
57+
_sName = alternateSortName.Length == 0 ? realNameBuffer : string.Concat(_sWindowsName.AsSpan(0, index), "_", alternateSortName);
5458
}
5559
else
5660
{

src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,12 @@ internal sealed partial class CultureData
413413
private static volatile Dictionary<string, CultureData>? s_cachedRegions;
414414
private static volatile Dictionary<string, string>? s_regionNames;
415415

416+
/// <summary>
417+
/// The culture name to use to interop with the underlying native globalization libraries like ICU or Windows NLS APIs.
418+
/// For example, we can have the name de_DE@collation=phonebook when using ICU for the German culture de-DE with the phonebook sorting behavior.
419+
/// </summary>
420+
internal string? InteropName => _sWindowsName;
421+
416422
internal static CultureData? GetCultureDataForRegion(string? cultureName, bool useUserOverride)
417423
{
418424
// First do a shortcut for Invariant

src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,12 @@ public static CultureInfo[] GetCultures(CultureTypes types)
580580
/// </summary>
581581
internal string SortName => _sortName ??= _cultureData.SortName;
582582

583+
/// <summary>
584+
/// The culture name to use to interop with the underlying native globalization libraries like ICU or Windows NLS APIs.
585+
/// For example, we can have the name de_DE@collation=phonebook when using ICU for the German culture de-DE with the phonebook sorting behavior.
586+
/// </summary>
587+
internal string? InteropName => _cultureData.InteropName;
588+
583589
public string IetfLanguageTag =>
584590
// special case the compatibility cultures
585591
Name switch

0 commit comments

Comments
 (0)