---
title: "Change the case of identifiers without a · Agent Wranglers"
url: https://agentwranglers.se/playbook/localization/text-handling/locale-independent-case
id: LOC-29
level: Required
risk: outage
updated: 2026-10-22
build: a2a6bdfed830
tokens: 921
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Change the case of identifiers without a locale

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Text handling](https://agentwranglers.se/playbook/localization/text-handling.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-22.

- ID: LOC-29
- Level: Required
- Chapter: [Text handling](https://agentwranglers.se/playbook/localization/text-handling.md)
- Rule: Lower-case and upper-case keys, protocol words, file extensions and identifiers with locale-independent functions. Use locale-aware case only for text shown to people.
- Check: Run the test suite with the default locale set to Turkish, such as `-Duser.language=tr` for Java or `LC_ALL=tr_TR.UTF-8`, and it passes. A lint rule finds no locale-dependent case call on a key, header or enum.
- Risk: The app down or unusable
- How: In Turkish and Azeri, "I" lower-cases to dotless "ı" and "i" upper-cases to "İ". A server whose default locale is Turkish turns `TITLE` into `tıtle`, so header names, enum values and lookups stop matching. JavaScript's `toLowerCase()` ignores the locale, while `toLocaleLowerCase()` uses it. Java's `toLowerCase()` uses the default locale, so pass `Locale.ROOT`. In C#, use `ToLowerInvariant()`. Compare user names and email addresses through the canonical key in [Compare email addresses and usernames in one canonical form](https://agentwranglers.se/playbook/accounts/sign-up/identifier-normalisation.md).

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### Java example

```java
import java.util.Locale;
String header = "TITLE";
header.toLowerCase(Locale.ROOT);              // "title" on every server
header.toLowerCase(Locale.forLanguageTag("tr")); // "tıtle", for Turkish display text only
```

### JavaScript example

```js
'TITLE'.toLowerCase();             // "title", never locale-dependent
'TITLE'.toLocaleLowerCase('tr');   // "tıtle", for Turkish display text only
```

### Python example

```python
"TITLE".lower()      # "title", Python's str methods ignore the locale
"Straße".casefold()  # "strasse", for case-insensitive comparison
```

## Sources

- [Unicode SpecialCasing.txt (Turkish and Azeri mappings)](https://www.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt)
- [ECMA-262 (String.prototype.toLowerCase)](https://tc39.es/ecma262/#sec-string.prototype.tolowercase)

## Related rules

- ACC-4 [Compare email addresses and usernames in one canonical form](https://agentwranglers.se/playbook/accounts/sign-up/identifier-normalisation.md) in Accounts and identity
- LOC-54 [Normalise text before you compare or store it](https://agentwranglers.se/playbook/localization/text-handling/unicode-normalisation.md) in Localization

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/localization/text-handling/locale-independent-case">Agent Wranglers localization playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Sort and compare text by locale](https://agentwranglers.se/playbook/localization/text-handling/locale-collation.md)
- Next: [Accept names and addresses from every country](https://agentwranglers.se/playbook/localization/text-handling/international-names-and-addresses.md)
- [Text handling](https://agentwranglers.se/playbook/localization/text-handling.md)
