Determine Turkish casing from the locale name instead of collation - #132002
Determine Turkish casing from the locale name instead of collation#132002MsfPablo wants to merge 2 commits into
Conversation
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 dotnet#106560
These ToLower/ToUpper cases were skipped on Android and LinuxBionic because the collation-based Turkish detection did not work there. The casing path no longer depends on collation data, so they can run.
|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
Tagging subscribers to 'arch-android': @vitek-karas, @simonrozsival, @steveisok, @akoeplinger |
|
@MsfPablo please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.
Contributor License AgreementContribution License AgreementThis Contribution License Agreement ( “Agreement” ) is agreed to by the party signing below ( “You” ), 1. Definitions. “Code” means the computer software code, whether in human-readable or machine-executable form, “Project” means any of the projects owned or managed by .NET Foundation and offered under a license “Submit” is the act of uploading, submitting, transmitting, or distributing code or other content to any “Submission” means the Code and any other copyrightable material Submitted by You, including any 2. Your Submission. You must agree to the terms of this Agreement before making a Submission to any 3. Originality of Work. You represent that each of Your Submissions is entirely Your 4. Your Employer. References to “employer” in this Agreement include Your employer or anyone else 5. Licenses. a. Copyright License. You grant .NET Foundation, and those who receive the Submission directly b. Patent License. You grant .NET Foundation, and those who receive the Submission directly or c. Other Rights Reserved. Each party reserves all rights not expressly granted in this Agreement. 6. Representations and Warranties. You represent that You are legally entitled to grant the above 7. Notice to .NET Foundation. You agree to notify .NET Foundation in writing of any facts or 8. Information about Submissions. You agree that contributions to Projects and information about 9. Governing Law/Jurisdiction. This Agreement is governed by the laws of the State of Washington, and 10. Entire Agreement/Assignment. This Agreement is the entire agreement between the parties, and .NET Foundation dedicates this Contribution License Agreement to the public domain according to the Creative Commons CC0 1. |
|
/azp run runtime-extra-platforms |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
Fixes #106560
Problem
On Android,
"i".ToUpper(new CultureInfo("tr-TR"))returnsI(U+0049) instead ofİ(U+0130), and"I".ToLower(...)returnsiinstead ofı. The same code is correct on Windows/Linux/macOS.Cause
TextInfo.NeedsTurkishCasingdoes not look at the locale at all — it infers the need for Turkish casing by probing the collation tailoring:Android uses the system ICU, which does not carry the
tr/azcollation tailoring that makes U+0131 compare equal toIunderIgnoreCase(the same underlying gap tracked by #60568). The probe therefore returnsfalsefortr-TR,IcuChangeCasetakes theChangeCasepath instead ofChangeCaseTurkish, and the dotted/dotlessimapping is silently lost.GlobalizationNative_ChangeCaseTurkishitself is fine and is already built for Android — it is simply never called.Fix
Decide from the locale's language subtag instead, which is what ICU itself does (
ustrcase_getCaseLocaleselectsUCASE_LOC_TURKISHfor languagestrandaz). This removes the dependency on collation data and makes the behavior identical on every ICU platform.This should be behavior-preserving elsewhere:
trandazare exactly the languages whose collation tailoring made the old probe returntrue, and the root collation does not equate U+0131 withI. The existingen-US-POSIXregression case — which exists precisely because the old check was collation-based — still passes, since its language subtag isen.Tests
The Turkish
ToUpper/ToLowercases inTextInfoTestswere skipped onAndroid/LinuxBionicwith the comment "Android has its own ICU, which doesn't work well with tr". Those guards are removed so the cases now run on those platforms and cover this fix. They exercisetr,tr-TR,azandaz-Latn-AZ.Verification
I want to be upfront: I have not built or run this locally. Building dotnet/runtime for Android and running the globalization suite on a device/emulator was not something I could do in my environment, so I am relying on CI (including the Android legs) to validate it. The change is small and self-contained, and the re-enabled test cases are the intended proof. Happy to iterate if CI shows anything unexpected — in particular if some locale I have not considered relied on the old collation-derived answer.
cc @matouskozak @tarekgh @ilonatommy