The Complete Guide to Text Case Conversion
Case conversion looks trivial until you hit Unicode edge cases, locale-dependent rules, and the dozen competing conventions across programming ecosystems. This guide covers what matters.
Case conventions in programming
Every naming convention exists for a reason — usually readability within a specific context:
- camelCase — JavaScript/TypeScript variables, Java methods. First word lowercase, subsequent words capitalized:
getUserName,isVisible. - PascalCase — Classes, React components, TypeScript types. Every word capitalized:
UserProfile,HttpClient. - snake_case — Python, Ruby, Rust functions and variables. Words separated by underscores:
get_user_name,is_visible. - SCREAMING_SNAKE_CASE — Constants across most languages:
MAX_RETRIES,API_BASE_URL. - kebab-case — CSS classes, URLs, CLI flags, npm package names:
font-size,my-project,--dry-run. - Title Case — UI headings, button labels: "Create New Project".
Mixing conventions within a codebase isn't just ugly — linters will flag it, and it makes grep-based refactoring unreliable.
Unicode and case mapping
"hello".toUpperCase() works fine. But case conversion is not a simple ASCII lookup table.
German ß: Uppercasing ß produces SS — a one-to-many mapping. "straße".toUpperCase() returns "STRASSE". There's no round-trip: lowercasing "STRASSE" gives "strasse", not "straße".
Turkish İ/i: Turkish has two distinct letters — dotted İ/i and dotless I/ı. Standard toUpperCase() converts i → I, which is wrong in Turkish (it should be İ). Use locale-aware methods:
"title".toLocaleUpperCase("tr"); // "TİTLE"
"TITLE".toLocaleLowerCase("tr"); // "tıtle"
Greek final sigma: Lowercase sigma has two forms — σ (medial) and ς (final, appears at the end of a word). Proper lowercasing of "ΟΔΟΣ" produces "οδός" with the final sigma.
These aren't obscure edge cases — they affect real users in production.
Case conversion in code
JavaScript/TypeScript:
str.toUpperCase(); // locale-independent (usually fine)
str.toLocaleUpperCase("tr"); // locale-aware
Libraries for programming cases:
// lodash
_.camelCase("user name"); // "userName"
_.snakeCase("userName"); // "user_name"
_.kebabCase("userName"); // "user-name"
_.startCase("userName"); // "User Name"
CSS (display-only, doesn't change the DOM):
text-transform: uppercase;
text-transform: capitalize; /* Title Case */
text-transform: lowercase;
Regex-based conversion for custom logic:
// snake_case → camelCase
str.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
// camelCase → snake_case
str.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
Naming conventions by ecosystem
| Language/Tool | Variables & Functions | Types & Classes | Constants | Files |
|---|---|---|---|---|
| JavaScript/TS | camelCase | PascalCase | SCREAMING_SNAKE | camelCase or kebab-case |
| Python | snake_case | PascalCase | SCREAMING_SNAKE | snake_case |
| Go | camelCase (unexported), PascalCase (exported) | PascalCase | PascalCase or SCREAMING_SNAKE | snake_case |
| Rust | snake_case | PascalCase | SCREAMING_SNAKE | snake_case |
| CSS/SCSS | kebab-case | — | — | kebab-case |
| SQL | snake_case (columns) | — | — | UPPERCASE keywords |
| Ruby | snake_case | PascalCase | SCREAMING_SNAKE | snake_case |
Go is unusual — capitalization controls visibility. UserName is exported (public); userName is unexported (private). Getting this wrong means compilation errors, not just style violations.
SEO and readability
Case choices affect search and scannability:
- URL slugs — always lowercase kebab-case:
/tools/case-converter, not/tools/CaseConverter. Search engines treat URLs as case-sensitive; mixed case causes duplicate content issues. - Page titles and H1s — Title Case is standard for English headings. Sentence case works too and feels less formal.
- Body text — Sentence case. ALL CAPS reads as shouting and reduces reading speed by ~10% (studies on letter shape recognition).
- Meta descriptions — Sentence case. No reason to capitalize beyond normal grammar rules.
Troubleshooting
Turkish locale produces unexpected results — Turkish has special casing rules for i/İ and ı/I. If your app runs with a Turkish locale, "TITLE".toLowerCase() may produce "tıtle". Use toLocaleLowerCase("en") when you need English-standard behavior regardless of runtime locale.
Acronyms become mangled in Title Case ("API" → "Api") — Most naive Title Case implementations lowercase everything first, then capitalize the first letter of each word. To preserve acronyms, maintain an allow-list of terms that should stay uppercase (API, URL, HTML, CSS, ID) and skip them during conversion.
Unicode characters don't convert — Not all Unicode code points have case mappings. Symbols, numbers, and many scripts (CJK, Arabic) have no uppercase/lowercase distinction. If toUpperCase() returns the input unchanged, the character likely has no case variant.
Converting between programming cases loses word boundaries — Going from kebab-case to camelCase is reliable because hyphens mark boundaries. Going from camelCase to snake_case requires splitting on uppercase letters, which breaks on acronyms: parseHTML splits as parse_h_t_m_l instead of parse_html. Use a library like lodash or change-case that handles these edge cases with dictionaries.