#!/usr/bin/env python3 import argparse import json import os import re from datetime import datetime from pathlib import Path def flatten(d, prefix=""): for k, v in d.items(): key = f"{prefix}.{k}" if prefix else k if isinstance(v, dict): yield from flatten(v, key) else: yield key def gather_files(src_dir, exts=(".ts", ".tsx", ".js", ".jsx", ".html", ".vue", ".json")): for root, _, files in os.walk(src_dir): parts = root.split(os.sep) if "node_modules" in parts or ".git" in parts: continue for fn in files: if fn.endswith(exts): yield Path(root) / fn def find_usages(keys, files): usages = {k: [] for k in keys} # Precompile patterns for speed patterns = {k: re.compile(r"\bm\." + re.escape(k) + r"\s*\(") for k in keys} for file in files: try: text = file.read_text(encoding="utf-8") except Exception: continue lines = text.splitlines() for i, line in enumerate(lines, start=1): for k, pat in patterns.items(): if pat.search(line): usages[k].append({ "file": str(file), "line": i, "text": line.strip() }) return usages def main(): p = argparse.ArgumentParser(description="Generate JSON report of localization key usage (m.key_name_here()).") p.add_argument("--en", default="../ui/localization/messages/en.json", help="path to en.json") p.add_argument("--src", default="../ui", help="root source directory to scan") p.add_argument("--out", default="../reports/localization_report.json", help="output report file") args = p.parse_args() en_path = Path(args.en) if not en_path.is_file(): print(f"en.json not found: {en_path}", flush=True) raise SystemExit(2) with en_path.open(encoding="utf-8") as f: payload = json.load(f) keys = sorted(list(flatten(payload))) files = list(gather_files(args.src)) usages = find_usages(keys, files) report = { "generated_at": datetime.utcnow().isoformat() + "Z", "en_json": str(en_path), "src_root": args.src, "total_keys": len(keys), "keys": {} } unused_count = 0 for k in keys: occ = usages.get(k, []) used = bool(occ) if not used: unused_count += 1 report["keys"][k] = { "used": used, "occurrences": occ } report["unused_count"] = unused_count report["unused_keys"] = [k for k, v in report["keys"].items() if not v["used"]] out_path = Path(args.out) out_path.parent.mkdir(parents=True, exist_ok=True) with out_path.open("w", encoding="utf-8") as f: json.dump(report, f, indent=2, ensure_ascii=False) print(f"Report written to {out_path}") print(f"Total keys: {report['total_keys']}, Unused: {report['unused_count']}") if __name__ == "__main__": main()