#!/usr/bin/env python3 """The backend never renders UI-language strings (CLAUDE.md). API errors are `{detail, code}` and the frontend translates by `code`; SSE `state` events carry counts and markers, and the frontend writes the sentence. That contract is only worth anything if it is checked: the moment one German error message ships from the backend, an English interface has a German sentence in it that no message file can reach. This looks for German text in the places that reach a user: `ApiError` messages and `detail` fields. Prompts, template content, the fixture corpus and comments are deliberately out of scope, because those are CONTENT and German is correct there. """ import re import sys from pathlib import Path APP = Path(__file__).resolve().parents[1] / "app" # Words that do not appear in English but are common in German UI copy. # Umlauts alone are too weak (proper nouns), and a full language detector # would be a dependency for a rule this narrow. GERMAN_MARKERS = re.compile( r"\b(" r"nicht|nichts|kein|keine|keinen|wurde|wurden|werden|wird|" r"bitte|erneut|konnte|könnte|müssen|muss|darfst|kannst|" r"deine|deinem|deiner|dein|Ihre|Ihrem|" r"Fehler|Anfrage|Dokument|Abteilung|Benutzer|Gespräch|Vorlage" r")\b", re.IGNORECASE, ) # Only the strings that can reach a user, not every literal in the file. USER_FACING = re.compile( r"""ApiError\s*\(\s*\d+\s*,\s*(?P["'])(?P.*?)(?P=q)""" r"""|detail\s*=\s*(?P["'])(?P.*?)(?P=q2)""", re.DOTALL, ) def main() -> int: problems: list[str] = [] for path in sorted(APP.rglob("*.py")): source = path.read_text(encoding="utf-8") for match in USER_FACING.finditer(source): text = match.group("text") or match.group("text2") or "" if not GERMAN_MARKERS.search(text): continue line = source[: match.start()].count("\n") + 1 relative = path.relative_to(APP.parent) problems.append( f"{relative}:{line}: user-facing string looks German: " f"{text[:70]!r}. The backend returns codes, the frontend " f"writes the sentence (docs/i18n.md)." ) if problems: print("check-no-ui-strings: FAILED", file=sys.stderr) for problem in problems: print(f" {problem}", file=sys.stderr) return 1 print("check-no-ui-strings: no UI-language strings in backend responses") return 0 if __name__ == "__main__": sys.exit(main())