language_detection
This library provides lightweight language detection for text represented as atoms, character lists, or character code lists. It currently supports the most common languages and returns the corresponding ISO 639-1 language codes. It requires a backend with Unicode support.
API documentation
Open the ../../apis/library_index.html#language-detection link in a web browser.
Loading
To load all entities in this library, load the loader.lgt file:
| ?- logtalk_load(language_detection(loader)).
Testing
To test this library predicates, load the tester.lgt file:
| ?- logtalk_load(language_detection(tester)).
Tests cover all included languages and detection strategies using the
atom, chars, and codes text representations.
Usage
The language_detector(Representation, Strategy) parametric object
accepts the atom, chars, and codes representations. The
strategy parameter must be an object implementing the
language_detection_strategy_protocol protocol.
To detect the most likely language:
| ?- language_detector(atom, ngram_language_detector)::detect(
'The quick brown fox jumps over the lazy dog.', Language
).
Language = en
yes
To also return a relative detection score:
| ?- language_detector(atom, hybrid_language_detector)::detect(
'Questo testo è scritto in italiano.', Language, Score,
[min_length(10)]
).
Language = it,
Score = ...
yes
The detect_all/2-3 predicates return all candidate languages ordered
by decreasing score and then by increasing language code. The scores are
relative to the selected candidate set; they are not calibrated
probabilities and should not be compared across different candidate
sets.
The input is normalized to NFC, converted to lowercase, stripped of control characters, and normalized for whitespace before detection. Diacritics are preserved because they provide useful language evidence.
Strategies
The library includes the following strategy objects:
ngram_language_detectorcompares character-trigram count vectors using cosine similarity.stopword_language_detectortokenizes the input and scores discriminative stop-word matches.script_language_detectorscores candidates using the Unicode scripts observed in the input. Languages sharing the same script receive the same script evidence and are therefore expected to tie when used alone.hybrid_language_detectorfirst combines the n-gram and stop-word scores using weights of 0.75 and 0.25, respectively, and then combines the result with script scores using weights of 0.80 and 0.20. When all strategies find evidence, the effective weights are therefore 0.60 for n-grams, 0.20 for stop words, and 0.20 for scripts. When either lexical or script evidence is unavailable, the available scores are returned unchanged.
Strategy selection is performed by the second object parameter. It is
not an option of the language_detector(Representation, Strategy)
object.
Script analysis
The language_detection_scripts object exposes the script analysis
used by the script strategy. It accepts normalized character codes and
returns all observed Unicode scripts with ratios ordered by decreasing
ratio:
| ?- atom_codes('abc éè', Codes),
language_detection_scripts::script_ratios(Codes, Ratios).
Ratios = ['Latin'-0.8333333333333334, 'Common'-0.16666666666666666]
yes
Script names are the values provided by the Unicode Character Database,
such as 'Latin', 'Cyrillic', and 'Arabic'. The
scripts_to_languages/2 predicate maps one or more meaningful scripts
to the sorted set of compatible registered languages:
| ?- language_detection_scripts::scripts_to_languages(['Cyrillic'], Languages).
Languages = [bg, ru, uk]
yes
The script strategy ignores the 'Common', 'Inherited',
'Unknown', and 'Zzzz' values when scoring. For mixed-script
text, evidence from every other observed script is retained. If no
meaningful mapped script is observed, the strategy returns no scores and
detection fails normally.
Options
The detect/4 and detect_all/3 predicates accept:
min_length(N), defaulting to20, sets the minimum normalized text length.candidates(all|Languages), defaulting toall, selects either all built-in profiles or a nonempty list of supported ISO 639-1 language codes.min_score(Score), defaulting to0.30, sets the minimum best relative score.min_margin(Margin), defaulting to0.05, sets the minimum difference between the two highest scores.
Duplicate candidate codes, unsupported candidate codes, duplicate options, and invalid option values are rejected.
The detect/2-4 predicates fail when the normalized input is shorter
than the configured minimum or when the available evidence does not
satisfy the score and margin thresholds. The detect_all/2-3
predicates return an empty list in those cases.
Language profiles
The library includes the several profile objects named
XX_language_profile in the profiles sub-directory where XX
is the ISO language code.
The character-trigram vectors are deterministically derived from the vendored stop-word inventories. Words are padded with spaces before trigram extraction so that word boundaries contribute evidence. The stop-word source files record their upstream repositories, commits, licenses, and generated entry counts.
Adding strategies and profiles
A custom strategy implements the
language_detection_strategy_protocol protocol. Its scores/3
predicate receives normalized character codes and a validated list of
candidate language codes and returns one Language-Score pair for
every candidate, or an empty list when it finds no evidence.
A custom profile imports the language_profile_common category.
Profiles are registered by defining the
language_profiles::custom_profile/2 multifile predicate. For
example:
:- multifile(language_profiles::custom_profile/2).
language_profiles::custom_profile(it, it_custom_language_profile).
The profile protocol and registry allow replacing the bundled vectors with corpus-derived profiles without changing the detector or strategy APIs.
A custom profile can override or add its expected scripts by defining
the language_detection_scripts::custom_language_scripts/2 multifile
predicate:
:- multifile(language_detection_scripts::custom_language_scripts/2).
language_detection_scripts::custom_language_scripts(sr, ['Cyrillic', 'Latin']).
Limitations
Accuracy decreases for short, code-switched, transliterated, or highly specialized text. Only the most common languages are currently included. The bundled n-gram profiles are intentionally lightweight and are not a substitute for profiles trained and evaluated on balanced corpora. Script-run segmentation, calibrated probabilities, and runtime profile training are outside the scope of this library.