Collation & text¶
Locale-aware comparison, sorting, substring search, word/sentence segmentation,
truncation, case mapping, and quotation — all backed by ICU's collator and break
iterators. These replace the byte-order operations (<, strcmp, sort,
strpos, strtoupper) that quietly mis-order or mis-match non-English text.
| Method | Use it for |
|---|---|
compare(a, b, options?) |
A locale-correct comparator for sorting two strings |
sort(items, key?, options?) |
Sort a whole list (optionally by a field) |
contains(haystack, needle, sensitivity?, options?) |
Accent/case-insensitive substring search |
splitWords / splitSentences / splitGraphemes |
Break text on the locale's boundaries |
ellipsize(text, max, ellipsis?) |
Grapheme-safe truncation |
upper(text) / lower(text) |
Locale-aware case mapping |
quote(text) |
Wrap in the locale's quotation marks |
Availability
Everything on this page works identically in JavaScript, PHP, Python, Java,
and C# — except quote(), which is JS-blocked (see the last section). (The
collation and segmentation methods landed in PHP in v3.)
Compare & sort¶
compare() returns a negative number, 0, or a positive number — exactly what a
sort callback wants. sort() does the whole list for you and returns a new
array (it never mutates the input).
The same input sorts differently per locale — å is a distinct letter sorting last
in Swedish, but an accented a in German. That is the whole reason to use a
collator instead of byte order.
Collation options¶
Both compare() and sort() (and contains()) take a final options bag to
tailor the collator:
| Key | Values | What it does |
|---|---|---|
numeric |
true / false |
Sort embedded numbers by value, so "file2" < "file10" (natural sort). |
caseFirst |
upper · lower · false |
Whether upper- or lower-case sorts first within a letter. |
Substring search¶
Collation-aware contains() can ignore case and accents — so a search box matches
"café" when the user types "cafe". The sensitivity argument controls how
forgiving the match is:
sensitivity |
Ignores | contains("Café", needle) matches |
|---|---|---|
base (default) |
case and accents | "cafe", "CAFÉ", "café" |
accent |
case only | "café", "CAFÉ" — but not "cafe" |
case |
accents only | "cafe", "café" — but not "CAFÉ" |
variant |
nothing (exact) | "Café" only |
The search is grapheme-aware, so it never matches across a combining sequence. An
empty needle returns true (every string contains the empty string).
Word & sentence segmentation¶
Splitting on whitespace fails for Thai, Japanese, and Chinese, which don't put spaces between words. ICU's break iterators handle every script correctly.
splitWords()keeps only word-like segments — whitespace and punctuation are dropped. Ideal for a word count or building a search index.splitSentences()breaks on sentence boundaries (knows that "Mr." isn't the end of a sentence in English).splitGraphemes()breaks on user-perceived characters, so an emoji ZWJ sequence (👨👩👧) or a combining accent stays a single element — the correct way to count or reverse "characters".
Grapheme-safe truncation¶
ellipsize() truncates to at most N graphemes, prefers to break on a word
boundary, and appends an ellipsis. The ellipsis counts toward the budget and
defaults to … (pass your own as the third argument).
Because it counts graphemes (not bytes or UTF-16 code units), it never cuts a multi-byte character or an emoji in half. Text that already fits is returned unchanged.
Locale-aware case¶
Unlike a plain strtoupper/toUpperCase, these honour locale rules — Turkish
dotted/dotless I, German ß, Lithuanian accents, and so on. Always upper/lower-case
in the content's locale, not the UI's, or you'll mangle Turkish names.
Quotation marks¶
Wrap text in the locale's own quotation marks, straight from CLDR delimiter data —
no need to hardcode ”…” vs „…” vs « … ».
=== “C#”
```csharp
new Cosmo(“en”).Quote(“hello”); // “”hello””
new Cosmo(“de”).Quote(“hallo”); // “„hallo””
new Cosmo(“fr”).Quote(“bonjour”); // “« bonjour »”
```
=== “C#”
```csharp
new Cosmo(“en”).Quote(“hello”); // “”hello””
new Cosmo(“de”).Quote(“hallo”); // “„hallo””
new Cosmo(“fr”).Quote(“bonjour”); // “« bonjour »”
```
=== “C#”
```csharp
new Cosmo(“en”).Quote(“hello”); // “”hello””
new Cosmo(“de”).Quote(“hallo”); // “„hallo””
new Cosmo(“fr”).Quote(“bonjour”); // “« bonjour »”
```
=== “C#”
```csharp
new Cosmo(“en”).Quote(“hello”); // “”hello””
new Cosmo(“de”).Quote(“hallo”); // “„hallo””
new Cosmo(“fr”).Quote(“bonjour”); // “« bonjour »”
```
!!! info “quote() is PHP, Python, Java & C#”
The CLDR delimiter data isn't exposed by the JavaScript Intl API, so quote()
is omitted there (these tabs show no JS). See
Platform notes.
Practical examples¶
A natural-sorted file list. Combine the numeric collation option with a key
accessor so versioned filenames order the way a human reads them:
An accent-insensitive autocomplete filter. base sensitivity matches across
accents and case in one call: