Fix TextInfo.ToTitleCase Dutch IJ digraph and U+2019 apostrophe handling - #133042
Open
tarekgh wants to merge 2 commits into
Open
Fix TextInfo.ToTitleCase Dutch IJ digraph and U+2019 apostrophe handling#133042tarekgh wants to merge 2 commits into
tarekgh wants to merge 2 commits into
Conversation
ToTitleCase gated the Dutch ij->IJ digraph titlecasing on
CultureName.StartsWith("nl-"), which never matched the neutral Dutch
culture whose name is exactly "nl". As a result
GetCultureInfo("nl").TextInfo.ToTitleCase("de ijsvogel") returned
"De Ijsvogel" instead of "De IJsvogel".
Match the neutral name exactly or the "nl-" prefix. The check remains a
single StartsWith over a 2-char literal plus a length/index check,
evaluated once per call, so there is no performance impact.
Added neutral nl cases to the existing DutchTitleCaseInfo_TestData theory.
Fixes dotnet#133032.
|
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. |
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
Pull request overview
Fixes Dutch TextInfo.ToTitleCase handling for the neutral Dutch culture ("nl") by treating it as Dutch for the IJ digraph titlecasing rule, aligning behavior with specific Dutch cultures like "nl-NL".
Changes:
- Update the Dutch-culture detection in
TextInfo.ToTitleCaseto match"nl"and"nl-*"(case-insensitive). - Extend existing Dutch titlecasing test data to cover the neutral
"nl"culture, including a repro-style phrase case.
File summaries
| File | Description |
|---|---|
| src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.cs | Broadens the Dutch-culture gate so the IJ digraph rule applies to neutral "nl" in addition to "nl-*" cultures. |
| src/libraries/System.Runtime/tests/System.Globalization.Tests/System/Globalization/TextInfoTests.cs | Adds neutral "nl" cases to existing Dutch titlecasing theory data, covering both token and sentence inputs. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 0
- Review effort level: Lite
TextInfo.ToTitleCase only treated the ASCII apostrophe (U+0027) as an in-word character, so U+2019 (typographic curly apostrophe) and similar characters were classified as word separators, producing output like 'Grandma'S Pictures'. Add an IsApostrophe helper covering U+0027, U+2019, U+2018 and U+FF07 (all Word_Break=MidNumLet) and add tests. Fixes dotnet#133034
Comment on lines
+858
to
+864
| // Characters that behave like an apostrophe within a word (e.g. contractions such | ||
| // as "can't" or possessives such as "Grandma's") and therefore must not be treated | ||
| // as a word separator during titlecasing. These share Unicode's Word_Break=MidNumLet | ||
| // property with the ASCII apostrophe (U+0027): | ||
| // U+2019 RIGHT SINGLE QUOTATION MARK - the typographic curly apostrophe | ||
| // U+2018 LEFT SINGLE QUOTATION MARK | ||
| // U+FF07 FULLWIDTH APOSTROPHE |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR fixes two independent
TextInfo.ToTitleCasebugs.1. Dutch IJ digraph for the neutral
nlcultureTextInfo.ToTitleCasespecial-cases Dutch to capitalize theijdigraph toIJ. The check gated this onCultureName.StartsWith("nl-"), which matches specific cultures (nl-NL,nl-BE, ...) but never the neutral Dutch culture, whose name is exactly"nl"with no trailing-. As a result the neutral culture fell through to the generic path:Fix
Match the neutral name exactly or the
nl-prefix:The
ijdigraph rule is a property of the Dutch language, not of a specific region, so everynl*culture (neutral and specific alike) should apply it.Tests
Added neutral
nlcases to the existingDutchTitleCaseInfo_TestDatatheory inTextInfoTests, including the issue's repro ("de ijsvogel"->"De IJsvogel").Fixes #133032.
2. U+2019 (and related quotes) treated as apostrophes
ToTitleCaseonly treated the ASCII apostrophe'(U+0027) as an in-word character. The typographic curly apostrophe’(U+2019) and similar characters have punctuation categories that are classified as word separators, so the letter after them was treated as the start of a new word:Fix
Introduce an
IsApostrophehelper and use it in the word scan. It covers the ASCII apostrophe plus the characters that share Unicode'sWord_Break=MidNumLetproperty and are used as apostrophes:U+2019RIGHT SINGLE QUOTATION MARK (the curly apostrophe)U+2018LEFT SINGLE QUOTATION MARKU+FF07FULLWIDTH APOSTROPHEModifier-letter apostrophes such as
U+02BCalready work because their category (Lm) is not a word separator. Dot/colon-styleMidLetterjoiners (.,:,·, ...) are intentionally left out of scope to avoid changing titlecasing of dotted tokens.Tests
Added a
ToTitleCase_Apostrophetheory coveringU+0027,U+2019,U+2018, andU+FF07, plus a control case ("Grandma-s"->"Grandma-S") confirming genuine separators still end the word.Fixes #133034.
Performance
No impact. The Dutch check remains a single
StartsWithover a 2-character literal plus one length/index check, evaluated once per call.IsApostropheis a small constant-time comparison replacing the previous single-character equality in the same loop position.Note
This PR description was drafted with GitHub Copilot.