#!/usr/bin/env python """Filter .po files to keep only entries for a specific module.""" from __future__ import annotations import argparse from pathlib import Path from typing import Iterable import polib def _extract_modules_from_comment(entry: polib.POEntry) -> set[str]: """Return module names declared in translator comments (#.).""" tcomment = entry.tcomment or "" modules: set[str] = set() for line in tcomment.splitlines(): stripped = line.strip() lowered = stripped.lower() if lowered.startswith("module:") or lowered.startswith("modules:"): _, _, tail = stripped.partition(":") for module in tail.split(","): module_name = module.strip() if module_name: modules.add(module_name) return modules def belongs_to_module(entry: polib.POEntry, module_name: str) -> bool: """Return True if the entry references ONLY the target module.""" declared_modules = _extract_modules_from_comment(entry) if declared_modules: return declared_modules == {module_name} locations = [occ[0] for occ in entry.occurrences if occ and occ[0]] if locations: return all(module_name in location for location in locations) return False def filter_po_file(path: Path, module_name: str, dry_run: bool = False) -> None: po = polib.pofile(str(path)) kept_entries: list[polib.POEntry] = [] removed = 0 for entry in po: if entry.msgid == "": kept_entries.append(entry) continue if belongs_to_module(entry, module_name): kept_entries.append(entry) else: removed += 1 if dry_run: print( f"[DRY-RUN] {path}: would keep {len(kept_entries)} entries, remove {removed} entries" ) return new_po = polib.POFile() new_po.metadata = po.metadata for entry in kept_entries: new_po.append(entry) new_po.save(str(path)) print( f"Filtered {path}: kept {len(kept_entries)} entries, removed {removed} entries" ) def parse_args(args: Iterable[str] | None = None) -> argparse.Namespace: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("module", help="Module technical name to keep") parser.add_argument("files", nargs="+", type=Path, help=".po files to filter") parser.add_argument("--dry-run", action="store_true", help="Only report counts") return parser.parse_args(args) def main() -> None: args = parse_args() for file_path in args.files: filter_po_file(file_path, args.module, dry_run=args.dry_run) if __name__ == "__main__": main()