2026-10-24 11:15:35 +02:00
|
|
|
|
// Package langdetect guesses whether an announcement is German or English.
|
|
|
|
|
|
// It is a pure function over two small word lists, deliberately without any
|
|
|
|
|
|
// ML: announcements are one or two sentences, and the only question is which
|
|
|
|
|
|
// voice should read them.
|
2026-10-18 15:38:42 +02:00
|
|
|
|
package langdetect
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
"unicode"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-10-24 11:15:35 +02:00
|
|
|
|
// Detect returns "de" or "en" for text. Umlauts and ß count as strong German
|
|
|
|
|
|
// signals; otherwise common-word hits decide. English wins only with strictly
|
|
|
|
|
|
// more English than German hits; ties and undecidable text (empty, numbers,
|
|
|
|
|
|
// punctuation) return fallback, which callers take from the configured
|
|
|
|
|
|
// default language.
|
|
|
|
|
|
func Detect(text, fallback string) string {
|
2026-10-18 15:38:42 +02:00
|
|
|
|
var de, en int
|
|
|
|
|
|
for _, r := range text {
|
|
|
|
|
|
switch r {
|
|
|
|
|
|
case 'ä', 'ö', 'ü', 'ß', 'Ä', 'Ö', 'Ü':
|
|
|
|
|
|
de++
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, word := range strings.FieldsFunc(text, func(r rune) bool {
|
|
|
|
|
|
return !unicode.IsLetter(r) && r != '\'' && r != '’'
|
|
|
|
|
|
}) {
|
|
|
|
|
|
word = strings.ToLower(word)
|
|
|
|
|
|
if _, ok := germanWords[word]; ok {
|
|
|
|
|
|
de++
|
|
|
|
|
|
}
|
|
|
|
|
|
if _, ok := englishWords[word]; ok {
|
|
|
|
|
|
en++
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-24 11:15:35 +02:00
|
|
|
|
switch {
|
|
|
|
|
|
case en > de:
|
2026-10-18 15:38:42 +02:00
|
|
|
|
return "en"
|
2026-10-24 11:15:35 +02:00
|
|
|
|
case de > en:
|
|
|
|
|
|
return "de"
|
|
|
|
|
|
default:
|
|
|
|
|
|
return fallback
|
2026-10-18 15:38:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-24 11:15:35 +02:00
|
|
|
|
// germanWords are common German words that do not occur in English
|
|
|
|
|
|
// (ambiguous ones such as "was" and "in" are left out on purpose).
|
2026-10-18 15:38:42 +02:00
|
|
|
|
var germanWords = map[string]struct{}{
|
|
|
|
|
|
"der": {}, "die": {}, "das": {}, "und": {}, "nicht": {}, "ist": {},
|
|
|
|
|
|
"ein": {}, "eine": {}, "einen": {}, "einem": {}, "einer": {},
|
|
|
|
|
|
"mit": {}, "für": {}, "auf": {}, "von": {}, "vom": {}, "zum": {},
|
|
|
|
|
|
"zur": {}, "den": {}, "dem": {}, "des": {}, "wir": {}, "ihr": {},
|
|
|
|
|
|
"sie": {}, "auch": {}, "als": {}, "wie": {}, "bei": {},
|
|
|
|
|
|
"aus": {}, "nach": {}, "noch": {}, "nur": {}, "schon": {},
|
|
|
|
|
|
"wenn": {}, "dann": {}, "aber": {}, "oder": {}, "doch": {},
|
|
|
|
|
|
"mehr": {}, "sehr": {}, "über": {}, "unter": {}, "jetzt": {},
|
|
|
|
|
|
"hier": {}, "heute": {}, "morgen": {}, "danke": {}, "bitte": {},
|
|
|
|
|
|
"erfolgreich": {}, "fehlgeschlagen": {}, "fertig": {},
|
|
|
|
|
|
"gestartet": {}, "beendet": {}, "abgeschlossen": {}, "warten": {},
|
|
|
|
|
|
"läuft": {}, "kannst": {}, "muss": {}, "soll": {},
|
|
|
|
|
|
"kein": {}, "keine": {}, "wieder": {}, "werden": {}, "wurde": {},
|
|
|
|
|
|
"wurden": {}, "haben": {}, "geht": {}, "machen": {},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-24 11:15:35 +02:00
|
|
|
|
// englishWords are common English words that do not occur in German.
|
2026-10-18 15:38:42 +02:00
|
|
|
|
var englishWords = map[string]struct{}{
|
|
|
|
|
|
"the": {}, "is": {}, "not": {}, "and": {}, "with": {}, "for": {},
|
|
|
|
|
|
"on": {}, "of": {}, "to": {}, "from": {}, "by": {}, "at": {},
|
|
|
|
|
|
"or": {}, "but": {}, "if": {}, "then": {}, "when": {}, "how": {},
|
|
|
|
|
|
"what": {}, "why": {}, "who": {}, "done": {}, "failed": {},
|
|
|
|
|
|
"finished": {}, "started": {}, "completed": {}, "error": {},
|
|
|
|
|
|
"warning": {}, "thanks": {}, "you": {}, "your": {},
|
|
|
|
|
|
"we": {}, "it": {}, "this": {}, "that": {}, "these": {},
|
2026-10-18 15:46:20 +02:00
|
|
|
|
"those": {}, "were": {}, "are": {}, "be": {},
|
2026-10-18 15:38:42 +02:00
|
|
|
|
"been": {}, "has": {}, "have": {}, "had": {}, "can": {},
|
|
|
|
|
|
"will": {}, "would": {}, "should": {}, "could": {}, "just": {},
|
|
|
|
|
|
"only": {}, "still": {}, "already": {}, "now": {}, "today": {},
|
|
|
|
|
|
"tomorrow": {}, "waiting": {}, "running": {}, "please": {},
|
|
|
|
|
|
"needs": {}, "need": {}, "succeeded": {},
|
|
|
|
|
|
}
|