JS Intl.Collator Locale-Sensitive String Comparison
The Intl.Collator object in JavaScript provides a
high-performance mechanism for comparing and sorting strings according
to the specific rules of different languages and cultures. Unlike
standard JavaScript comparison operators that sort strings based on
Unicode code point values, Intl.Collator understands
language-specific nuances such as accent marks, case sensitivity, and
unique alphabetizations. This article explains how
Intl.Collator works, its configuration options, and why it
is the preferred approach for locale-aware string operations.
The Limitation of Default Comparisons
Standard JavaScript comparison operators (<,
>, ===) compare strings by their UTF-16
code unit values. This binary comparison often produces incorrect
results when sorting human languages. For example, in Swedish, “ö” comes
after “z”, whereas in German, “ö” is treated similarly to “o”. Binary
comparison places all accented characters after standard ASCII
characters regardless of context, leading to unnatural sorting
orders.
While String.prototype.localeCompare() handles locale
rules, invoking it repeatedly inside an
Array.prototype.sort() callback causes performance overhead
because it must resolve the locale and rules on every comparison.
How Intl.Collator
Works
The Intl.Collator constructor creates a reusable
instance configured with a specific locale and set of collation rules.
Once instantiated, its compare method takes two strings and
returns: - A negative number if the first string comes before the
second. - A positive number if the first string comes after the second.
- 0 if the strings are considered equivalent under the
configured rules.
const germanCollator = new Intl.Collator('de');
const swedishCollator = new Intl.Collator('sv');
console.log(germanCollator.compare('ä', 'z')); // -1 ('ä' comes before 'z' in German)
console.log(swedishCollator.compare('ä', 'z')); // 1 ('ä' comes after 'z' in Swedish)Key Configuration Options
Intl.Collator accepts an options object
that customizes how strings are evaluated:
sensitivity: Defines which differences between characters are significant.'base': Ignores case and accents (e.g.,a=A=á).'accent': Considers base characters and accents, ignores case (e.g.,a=A, buta≠á).'case': Considers base characters and case, ignores accents (e.g.,a=á, buta≠A).'variant': Default setting; considers base characters, accents, and case as distinct.
numeric: A boolean value. When set totrue, strings containing numbers are sorted using natural sorting order (e.g., “item2” comes before “item10”).caseFirst: Determines whether uppercase or lowercase characters take precedence ('upper','lower', or'false').usage: Specifies whether the collator is intended for sorting lists ('sort', default) or for filtering/searching matches ('search').
const naturalSortCollator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
const files = ['file10.txt', 'file2.txt', 'FILE1.txt'];
files.sort(naturalSortCollator.compare);
// Output: ['FILE1.txt', 'file2.txt', 'file10.txt']Performance Optimization
The primary advantage of Intl.Collator over
String.prototype.localeCompare is performance. Initializing
a collation instance is computationally expensive because it loads and
parses the locale data. By instantiating Intl.Collator once
and passing collator.compare directly into
Array.prototype.sort(), the locale setup happens once,
yielding significantly faster sorting times on large datasets.