Skip to content

[patch] Title-case [IsTitleCase] values with invariant rules, not the thread culture - #403

Merged
matt-edmondson merged 1 commit into
mainfrom
fix/309-title-case-invariant-culture
Oct 9, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
fix/309-title-case-invariant-culture

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #309

What was wrong

IsTitleCaseAttribute lowercased the value with invariant rules, then title-cased it with CultureInfo.CurrentCulture. Under tr-TR or az, i title-cases to İ, so "Istanbul" was valid on an en-US machine and invalid on a Turkish one.

Change (Semantics.Strings/Validation/Attributes/Casing/IsTitleCaseAttribute.cs)

Test project (Semantics.Test/Semantics.Test.csproj), which reviewers should look at

  • ktsu.Sdk sets InvariantGlobalization=true, and in that mode every culture except the invariant one throws CultureNotFoundException when constructed. So no test in this project could set tr-TR, and the bug couldn't be reproduced there. Consumers who don't use ktsu.Sdk still hit it. The test project now sets InvariantGlobalization=false.
  • Turning invariant globalization off enables CA1304/CA1307: 36 hits, all in SemanticStringTests, which calls SemanticString's culture-default overloads on purpose to cover them. Both rules are suppressed in the test project only. No library project changes.

Tests (CasingValidatorsTests.TitleCase_DoesNotDependOnThreadCulture)

  • Runs under en-US, tr-TR and az-Latn-AZ. Each run checks that "Istanbul Is Lovely" validates and "istanbul" is rejected. The original culture is restored in finally.
  • With the fix reverted, the tr-TR and az-Latn-AZ rows fail and en-US passes, which reproduces the issue.
  • With the fix, the full Semantics.Test suite passes under real cultures: 1483 passed, 0 failed, 8 skipped. Semantics.Strings builds for every target framework with no warnings.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Co2rZq6e7TjwF2FMUzNoXu


Generated by Claude Code

… thread culture

IsTitleCaseAttribute lowercased with invariant rules but title-cased with
CultureInfo.CurrentCulture, so "Istanbul" validated under en-US and failed
under tr-TR and az, where "i" title-cases to "İ". It now title-cases with
CultureInfo.InvariantCulture, like the rest of the casing attributes.

The test project turns off the invariant globalization ktsu.Sdk enables, so
the culture test can set tr-TR and az at all. CA1304 and CA1307, which that
switches on, are suppressed there: SemanticStringTests calls the
culture-default overloads deliberately.

Fixes #309

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Co2rZq6e7TjwF2FMUzNoXu
@sonarqubecloud

sonarqubecloud Bot commented Oct 8, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[IsTitleCase] depends on the thread culture: "Istanbul" validates under en-US and fails under tr-TR

2 participants