Technical Specification

betto_lang_detector

1 Purpose and scope

A pure-Dart, zero-runtime-dependency language detector. It serves three narrow purposes for downstream consumers (originally kmdb’s vault search roadmap, WI-5): lexical analyzer selection, document metadata, and cheap script-based tokenizer routing. It is not designed for high-accuracy NLP-grade classification, and does not participate in semantic/embedding search pipelines (those are served by a shared multilingual embedding model elsewhere, which needs no language label).

2 Algorithm

Two independent stages, composed by CompositeBackend:

  1. Script pre-filter. A generated, sorted Unicode codepoint-range table (from the Unicode Character Database’s Scripts.txt and PropertyValueAliases.txt) resolves dominantScript() — the most common Unicode script among a text’s letter codepoints — via binary search. Seven scripts in the target language set (Bengali, Gujarati, Armenian, Greek, Hebrew, Thai, Hangul) map to exactly one supported language each and short-circuit detection immediately. Han-script text is split into Japanese/Chinese via a kana-presence check (any Hiragana/Katakana codepoint present → Japanese; Han-only → Chinese) rather than by dominant script count alone, since Japanese text is often Han-majority by raw codepoint count.

  2. Character n-gram model. For the remaining four scripts (Latin, Cyrillic, Arabic, Devanagari — spanning 49 of the 58 supported languages), a classic Cavnar & Trenkle “N-Gram-Based Text Categorization” (1994) model disambiguates. Each language has a generated profile: its top-300 character n-grams (orders 1-5, word-boundary-padded, e.g. "the""_the_"{"_","_t","_th",...,"_the_"}), ranked by frequency in a reference corpus (UDHR translations). At detection time, the input’s own ranked n-gram list is compared against each candidate language’s profile via an “out-of-place” distance (sum of rank differences for shared n-grams; a fixed maximum penalty for n-grams absent from the profile). Confidence is a linear rescaling of that distance across the candidate set being compared — a heuristic, not a calibrated probability, so the same input can score differently depending on which languages are being distinguished between (see restrictTo on LanguageDetector).

The tool/generate_scripts.dart and tool/generate_ngram_profiles.dart scripts produce the two .g.dart data files this algorithm depends on; both require network access at codegen time only, never at runtime.

3 Language coverage

58 ISO 639-1 codes, matching betto_lexical’s Stopwords enum exactly (so LanguageDetector.detect() output composes directly with getStopWords(Locale) with no code-translation layer):

Script Languages Resolution
Latin af, br, ca, cs, da, de, en, eo, es, et, eu, fi, fr, ga, gl, ha, hr, hu, id, it, ku, la, lt, lv, ms, nl, no, pl, pt, ro, sk, sl, so, st, sv, sw, tl, tr, vi, yo, zu n-gram stage
Cyrillic bg, ru, uk n-gram stage
Arabic ar, fa, ur n-gram stage
Devanagari hi, mr n-gram stage
Bengali bn script-exclusive
Gujarati gu script-exclusive
Armenian hy script-exclusive
Greek el script-exclusive
Hebrew he script-exclusive
Thai th script-exclusive
Hangul ko script-exclusive
Han + kana ja (kana present), zh (Han only) script-exclusive

4 Known limitations