From b6059c917eaac93e5a5c57db0074a533e0728ad8 Mon Sep 17 00:00:00 2001 From: dida-80b Date: Tue, 30 Jun 2026 19:14:29 +0200 Subject: [PATCH 1/3] feat(de): add de_abbrevs section with 43 German abbreviation pronunciations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit espeak-ng mispronounces many German abbreviations (reads them as words instead of spelling them letter-by-letter). The new de_abbrevs override section covers common Tagesschau/ARD news abbreviations: EU, USA, ARD, AKW, EZB, WHO, ADAC, IT, AFP, ÖPNV, OSZE, UEFA, FPÖ, etc. - Added de_overrides.json: de_abbrevs section (43 entries) - Updated _load_overrides() in de.py: includes de_abbrevs between en and de_foreign --- misaki/data/de_overrides.json | 48 ++++++++++++++++++++++++++++++++++- misaki/de.py | 4 +-- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/misaki/data/de_overrides.json b/misaki/data/de_overrides.json index 85623b7..53ae760 100644 --- a/misaki/data/de_overrides.json +++ b/misaki/data/de_overrides.json @@ -1,5 +1,5 @@ { - "_comment": "German pronunciation overrides for DEG2P. Phonemes bypass espeak-ng and go straight to the model. Priority on lookup collisions: brand > en > de_foreign. Keys are matched after normalize_for_lookup() (casefold, NFKD, strip combining marks, + -> plus, & -> and, @ -> at, keep alphanumerics). Ported from kikiri-tts PR #28 (dida-80b).", + "_comment": "German pronunciation overrides for DEG2P. Phonemes bypass espeak-ng and go straight to the model. Priority on lookup collisions: brand > en > de_abbrevs > de_foreign. Keys are matched after normalize_for_lookup() (casefold, NFKD, strip combining marks, + -> plus, & -> and, @ -> at, keep alphanumerics). Ported from kikiri-tts PR #28 (dida-80b).", "brand": { "bark": "bˈaːɐk", "claude": "klˈoːt", @@ -82,6 +82,52 @@ "wsl": "dˌʌbəljˌuːˌɛsˈɛl", "zero-shot": "zˈiːɹo ʃˈɔt" }, + "de_abbrevs": { + "_comment": "German abbreviations/acronyms mispronounced by espeak-ng. Letter names: A=aː B=beː C=tseː D=deː E=eː F=ɛf G=ɡeː H=haː I=iː K=kaː L=ɛl M=ɛm N=ɛn O=oː P=peː R=ɛɾ S=ɛs T=teː U=uː V=fW(=faʊ) W=veː X=ɪks Z=tsɛt", + "ADAC": "ˌaːˌdeːˌaːˈtseː", + "AFP": "ˌaːˌɛfˈpeː", + "AKW": "ˌaːˌkaːˈveː", + "AOK": "ˌaːˌoːˈkaː", + "AP": "ˌaːˈpeː", + "ARD": "ˌaːˌɛɾˈdeː", + "AfD": "ˌaːˌɛfˈdeː", + "BA": "ˌbeːˈaː", + "BASF": "ˌbeːˌaːˌɛsˈɛf", + "CEO": "ˌtseːˌeːˈoː", + "CGT": "ˌtseːˌɡeːˈteː", + "CIA": "ˌtseːˌiːˈaː", + "CO": "ˌtseːˈoː", + "CO2": "ˌtseːˌoːˈtsvai", + "ESA": "ˌeːˌɛsˈaː", + "EU": "ˌeːˈuː", + "EVG": "ˌeːˌfWˈɡeː", + "EZB": "ˌeːˌtsɛtˈbeː", + "FAZ": "ˌɛfˌaːˈtsɛt", + "FPÖ": "ˌɛfˌpeːˈøː", + "IAEA": "ˌiːˌaːˌeːˈaː", + "ICE": "ˌiːˌtseːˈeː", + "IG": "ˌiːˈɡeː", + "IS": "ˌiːˈɛs", + "IT": "ˌiːˈteː", + "IW": "ˌiːˈveː", + "IWF": "ˌiːˌveːˈɛf", + "KI": "ˌkaːˈiː", + "OECD": "ˌoːˌeːˌtseːˈdeː", + "OPEC": "ˈoːpɛk", + "OSZE": "ˌoːˌɛsˌtsɛtˈeː", + "SDAX": "ˌɛsˌdeːˌaːˈɪks", + "UBS": "ˌuːˌbeːˈɛs", + "UEFA": "ˌuːˌeːˈfa", + "UK": "ˌuːˈkaː", + "UN": "ˌuːˈɛn", + "US": "ˌuːˈɛs", + "USA": "ˌuːˌɛsˈaː", + "UV": "ˌuːˈfW", + "WHO": "ˌveːˌhaːˈoː", + "ZEW": "ˌtsɛtˌeːˈveː", + "ÖPNV": "ˌøːˌpeːˌɛnˈfW", + "ÖVP": "ˌøːˌfWˈpeː" + }, "de_foreign": { "diathese": "diaˈteːzə", "ekstase": "ɛkstˈaːzə", diff --git a/misaki/de.py b/misaki/de.py index dfe9085..f5c2eb2 100644 --- a/misaki/de.py +++ b/misaki/de.py @@ -409,14 +409,14 @@ def normalize_for_lookup(text: str) -> str: def _load_overrides(): """Load de_overrides.json and build the normalized lookup table. - Priority on key collisions: brand > en > de_foreign (first writer wins). + Priority on key collisions: brand > en > de_abbrevs > de_foreign (first writer wins). Returns (lookup, aliases) where lookup maps normalized keys to phonemes and aliases maps one normalized key to another. """ with importlib.resources.open_text(data, "de_overrides.json") as r: raw = json.load(r) lookup = {} - for section in ("brand", "en", "de_foreign"): + for section in ("brand", "en", "de_abbrevs", "de_foreign"): for key, value in raw.get(section, {}).items(): lookup.setdefault(normalize_for_lookup(key), value) aliases = { From 4c668d53dea3c3c5aec137d27f2b8737996de9c4 Mon Sep 17 00:00:00 2001 From: dida-80b Date: Tue, 30 Jun 2026 19:46:44 +0200 Subject: [PATCH 2/3] =?UTF-8?q?fix(de):=20correct=20UK=20pronunciation=20t?= =?UTF-8?q?o=20English=20/ju=CB=90=CB=88ke=C9=AA/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UK is an English abbreviation that German speakers pronounce English-style ("ju-kej"), not with German letter names ("uː-kaː"). --- misaki/data/de_overrides.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misaki/data/de_overrides.json b/misaki/data/de_overrides.json index 53ae760..a3d0d3f 100644 --- a/misaki/data/de_overrides.json +++ b/misaki/data/de_overrides.json @@ -118,7 +118,7 @@ "SDAX": "ˌɛsˌdeːˌaːˈɪks", "UBS": "ˌuːˌbeːˈɛs", "UEFA": "ˌuːˌeːˈfa", - "UK": "ˌuːˈkaː", + "UK": "ˌjuːˈkeɪ", "UN": "ˌuːˈɛn", "US": "ˌuːˈɛs", "USA": "ˌuːˌɛsˈaː", From 75ee991f025e89c35bad8e9398591fb9ee8bb762 Mon Sep 17 00:00:00 2001 From: dida-80b Date: Tue, 30 Jun 2026 19:52:12 +0200 Subject: [PATCH 3/3] fix(de): correct CIA and CEO to mixed/English pronunciation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CIA: German C (tseː) but English I (aɪ) and A (eɪ) → ˌtseːˌaɪˈeɪ - CEO: fully English → ˌsiːˌiːˈoː --- misaki/data/de_overrides.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/misaki/data/de_overrides.json b/misaki/data/de_overrides.json index a3d0d3f..da67f23 100644 --- a/misaki/data/de_overrides.json +++ b/misaki/data/de_overrides.json @@ -93,9 +93,9 @@ "AfD": "ˌaːˌɛfˈdeː", "BA": "ˌbeːˈaː", "BASF": "ˌbeːˌaːˌɛsˈɛf", - "CEO": "ˌtseːˌeːˈoː", + "CEO": "ˌsiːˌiːˈoː", "CGT": "ˌtseːˌɡeːˈteː", - "CIA": "ˌtseːˌiːˈaː", + "CIA": "ˌtseːˌaɪˈeɪ", "CO": "ˌtseːˈoː", "CO2": "ˌtseːˌoːˈtsvai", "ESA": "ˌeːˌɛsˈaː",