40-validation/validate-primary-language.py

#!/usr/bin/env python3
import argparse,json,re
from pathlib import Path
EN={"the","and","for","with","without","from","to","of","validation","overview","purpose","architecture"};DE={"der","die","das","und","für","mit","ohne","von","zu","zweck","validierung","architektur"}
def meta(text):
 if not text.startswith("---"):return {}
 p=text.split("---",2);r={}
 if len(p)<3:return r
 for line in p[1].splitlines():
  k,s,v=line.partition(":")
  if s:r[k.strip()]=v.strip().strip('"')
 return r
def words(text):return re.findall(r"[A-Za-zÄÖÜäöüß]+",text.lower())
def validate(root,config):
 allowed=[re.compile(x) for x in config.get("allowedHeadingPatterns",[])];failed=[];review=[];checked=0
 for path in sorted(root.rglob("*.md")):
  text=path.read_text(encoding="utf-8");rel=path.relative_to(root).as_posix();m=meta(text)
  if m.get("language") not in (None,"de"):failed.append({"code":"PRIMARY_LANGUAGE_NOT_DE","file":rel,"language":m.get("language")})
  for heading in re.findall(r"^#{1,6}\s+(.+?)\s*$",text,re.M):
   checked+=1
   if any(p.fullmatch(heading) for p in allowed):continue
   tokens=words(heading);en=sum(x in EN for x in tokens);de=sum(x in DE for x in tokens)
   if en>=2 and en>de:failed.append({"code":"ENGLISH_HEADING","file":rel,"heading":heading})
   elif tokens and not any(c in heading.lower() for c in "äöüß") and en==de==0:review.append({"code":"AMBIGUOUS_HEADING_LANGUAGE","file":rel,"heading":heading})
 status="FAILED" if failed else ("REVIEW_REQUIRED" if review else "PASSED")
 return {"schemaVersion":"1.0","workItem":"SE-0030","status":status,"files":len(list(root.rglob('*.md'))),"headings":checked,"technicalIdsAllowed":True,"failed":failed,"reviewCases":review}
def main():
 p=argparse.ArgumentParser();p.add_argument("root",type=Path);p.add_argument("--config",type=Path,required=True);p.add_argument("--output",type=Path);a=p.parse_args();r=validate(a.root,json.loads(a.config.read_text()));text=json.dumps(r,ensure_ascii=False,indent=2)+"\n"
 if a.output:a.output.parent.mkdir(parents=True,exist_ok=True);a.output.write_text(text)
 else:print(text,end="")
 raise SystemExit(1 if r["status"]=="FAILED" else 0)
if __name__=="__main__":main()