addons-cm/scripts/clean_module_translations.py

91 lines
2.6 KiB
Python

#!/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()