From f922883aa50478bd74c860a2f7edb355d9a965ab Mon Sep 17 00:00:00 2001 From: Pablo Garcia Date: Fri, 7 Aug 2026 15:36:41 +0200 Subject: [PATCH] Determine Turkish casing from the locale name instead of collation TextInfo.NeedsTurkishCasing detected the Turkish dotted/dotless i casing rules by probing whether the culture collates U+0131 equal to 'I' under IgnoreCase. On Android the system ICU does not provide the collation data that probe depends on, so the check returned false for tr-TR and casing silently fell back to the non-Turkish path, making i.ToUpper() yield 'I' instead of U+0130. Fixes #106560 --- .../src/System/Globalization/TextInfo.Icu.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Icu.cs index 0e04fb4dd1e9dd..3c5e215426e3a0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Icu.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Icu.cs @@ -14,7 +14,20 @@ private static bool NeedsTurkishCasing(string localeName) { Debug.Assert(localeName != null); - return CultureInfo.GetCultureInfo(localeName).CompareInfo.Compare("\u0131", "I", CompareOptions.IgnoreCase) == 0; + // ICU applies the Turkish dotted/dotless "i" casing rules to the "tr" and "az" + // languages. This is determined from the locale name rather than by probing the + // collation tailoring, because some platforms (notably Android, which uses the + // system ICU) do not ship the collation data that probe relies on, which would + // silently fall back to non-Turkish casing. + ReadOnlySpan language = localeName.AsSpan(); + int separatorIndex = language.IndexOfAny('-', '_'); + if (separatorIndex >= 0) + { + language = language.Slice(0, separatorIndex); + } + + return language.Equals("tr", StringComparison.OrdinalIgnoreCase) || + language.Equals("az", StringComparison.OrdinalIgnoreCase); } internal unsafe void IcuChangeCase(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper)