#!/usr/bin/env python3 """The voice check of aac-core's keyboard/letter_names.json: each language's letter names read by espeak-ng (where it has a voice for the language), and any two keys whose names it reads alike reported. A collision is not proof (espeak-ng's voices are rougher than a device's), but every one is a name to look at before a language's table is marked agreed. usage: python3 tools/keyboard/check_letter_names.py (from aac/aac-rs; needs espeak-ng) """ import json import subprocess from pathlib import Path TABLE = Path(__file__).resolve().parents[2] / "crates/aac-core/src/keyboard/letter_names.json" VOICE = {"en": "en-us", "fr": "fr-fr", "zh": "cmn"} def main(): table = json.loads(TABLE.read_text(encoding="utf-8")) listed = subprocess.run(["espeak-ng", "--voices"], capture_output=True, text=True, check=True).stdout voices = {line.split()[1] for line in listed.splitlines()[1:] if len(line.split()) > 1} for code, names in sorted(table["languages"].items()): voice = VOICE.get(code, code) if voice not in voices: print(f"{code}: no espeak-ng voice") continue heard = {} for key, said in {**names["letters"], **{f"form {k}": v for k, v in names["forms"].items()}}.items(): ph = subprocess.run(["espeak-ng", "-v", voice, "-q", "-x", said], capture_output=True, text=True).stdout.strip() heard.setdefault(ph, []).append(key) alike = [keys for keys in heard.values() if len(keys) > 1] print(f"{code}: {'alike ' + str(alike) if alike else 'all distinct'} ({names['review']['status']})") if __name__ == "__main__": main()