Canberk Şenyüz

Dotless

Client
Open source
Year
2024
Role
Author and maintainer
Stack
TypeScript, Vitest
The project summary as it is stored: 89 bytes of UTF-8.

A small library for matching names across languages without breaking Turkish ı and İ.

Context

Case conversion depends on locale. In Turkish, I lowercases to ı and i uppercases to İ, so a case-insensitive search for a city or a surname gives different answers depending on how the server was configured. Names with accents fail the other way: Şenyüz and Senyuz never match.

Idea

Make every step explicit and visible to the caller: Unicode normalization first, then a case fold for a locale the caller passes in, then an optional accent-free key for search. Each step is a pure function with its own tests, and nothing reads the locale from the environment.

RowInputLocalesearchKey
0000ŞENYÜZtrsenyuz
0010Şenyüzundsenyuz
0020ISTANBULtrıstanbul
0030ISTANBULenistanbul
0040İstanbultristanbul
Same letters, different keys. The locale decides what I lowercases to, which is why it is an argument and never a guess.

Details

  1. Normalize first

    Text is converted to NFC before anything else, so a ü typed as one code point and a ü built from u plus a combining mark compare as equal.

  2. Locale is an argument

    The library never guesses. A missing locale means the root locale, and the README shows why that matters with real names.

  3. Tests from real failures

    The test suite is a list of names that other libraries got wrong, each with the expected key. Bug reports become rows in that list.

export function searchKey(input: string, locale = 'und') {  return input    .normalize('NFC')    .toLocaleLowerCase(locale)    .normalize('NFD')    .replace(/\p{Mn}/gu, '');} searchKey('ŞENYÜZ', 'tr'); // 'senyuz'searchKey('ISTANBUL', 'tr'); // 'ıstanbul'
TypeScript The search key: compose, fold for the given locale, then drop the marks.

Outcome

Published as a package with a deliberately tiny API. The interesting part turned out to be the test list, which now doubles as documentation for anyone handling names.