#!/usr/bin/env python3 """Block near-variant translation terms (case/trailing-punctuation duplicates). Unlike a term freeze, new terms are always allowed. This only fails when two terms collapse to the same string after lowercasing and stripping trailing ".:?! " punctuation - e.g. "Signal" vs "Signal:", "Reset to Default?" vs "Reset to default". Build punctuation outside tr() instead: I18n.tr("Signal") + ":" "Term" vs "Term..." pairs are NOT flagged: a trailing ellipsis is meaningful (progress states, opens-a-dialog affordances). """ import sys from collections import defaultdict from extract_translations import extract_qstr_strings from pathlib import Path ROOT_DIR = Path(__file__).parent.parent # Intentional pairs that survive normalization on purpose. ALLOWED = [ {"PIN", "Pin"}, # WPS PIN acronym vs the verb "pin" {"Device", "device"}, # label vs inline generic-noun fallback {"Until %1", "until %1"}, # sentence-initial vs mid-sentence position ] def normalize(term): t = term.replace("…", "...") ellipsis = t.rstrip().endswith("...") t = t.lower().rstrip(".:?! ") return t + "..." if ellipsis else t def main(): translations = extract_qstr_strings(ROOT_DIR) groups = defaultdict(set) for term in translations: groups[normalize(term)].add(term) failures = [] for variants in groups.values(): if len(variants) < 2 or any(variants == a for a in ALLOWED): continue # term vs term+"..." is allowed; flag only same-ellipsis-class variants plain = {v for v in variants if not v.replace("…", "...").rstrip().endswith("...")} dotted = variants - plain for cls in (plain, dotted): if len(cls) > 1: failures.append(sorted(cls)) if not failures: print(f"No term variants ({len(translations)} terms checked)") return 0 print("Near-variant terms found - reuse one exact term (or add to ALLOWED " "in check_term_variants.py if genuinely intentional):", file=sys.stderr) for variants in sorted(failures): print(f" {variants}", file=sys.stderr) for v in variants: for occ in translations[v]["occurrences"][:3]: print(f" {v!r}: {occ['file']}:{occ['line']}", file=sys.stderr) return 1 if __name__ == "__main__": sys.exit(main())