| """Export the translated language pack (e.g. German_JSON/) from review records. |
| |
| Every file from the source pack is deep-copied with translations substituted at |
| the recorded key paths; structure, IDs, and untranslatable values stay intact. |
| Per string the best available text is used: reviewer-final > toned > machine |
| translation > English source. A review-status summary is printed at the end. |
| |
| Usage: |
| python -m pipeline.export_pack |
| """ |
|
|
| import json |
| import sys |
| from pathlib import Path |
|
|
| sys.path.insert(0, str(Path(__file__).parent.parent)) |
| import config |
| from pipeline.rules import get_at, set_many |
|
|
|
|
| def best_text(item: dict) -> str | None: |
| return item.get("final") or item.get("toned") or item.get("mt") |
|
|
|
|
| def export_file(source_data, record: dict) -> tuple[dict, dict]: |
| """Return (translated copy of source_data, status counts).""" |
| counts = {"approved": 0, "edited": 0, "rejected": 0, "pending": 0, "untranslated": 0} |
| updates = [] |
| for item in record["items"]: |
| path = tuple(item["path"]) |
| text = best_text(item) |
| if text is None: |
| counts["untranslated"] += 1 |
| continue |
| if get_at(source_data, path) != item["source"]: |
| raise ValueError(f"source drift at {item['key']}: rerun translate_pack") |
| updates.append((path, text)) |
| counts[item["status"]] += 1 |
| return set_many(source_data, updates), counts |
|
|
|
|
| def main() -> None: |
| if not config.TRANSLATIONS_DIR.exists(): |
| sys.exit("No review records found - run pipeline/translate_pack.py first.") |
|
|
| totals = {"approved": 0, "edited": 0, "rejected": 0, "pending": 0, "untranslated": 0} |
| exported = 0 |
| for source_file in sorted(config.SOURCE_DIR.rglob("*.json")): |
| rel = str(source_file.relative_to(config.SOURCE_DIR)) |
| source_data = json.loads(source_file.read_text(encoding="utf-8")) |
| record_path = config.TRANSLATIONS_DIR / rel |
|
|
| if record_path.exists(): |
| record = json.loads(record_path.read_text(encoding="utf-8")) |
| translated, counts = export_file(source_data, record) |
| for key, n in counts.items(): |
| totals[key] += n |
| else: |
| translated = source_data |
|
|
| out_path = config.PACK_DIR / rel |
| out_path.parent.mkdir(parents=True, exist_ok=True) |
| out_path.write_text( |
| json.dumps(translated, indent=2, ensure_ascii=False), encoding="utf-8" |
| ) |
| exported += 1 |
|
|
| reviewed = totals["approved"] + totals["edited"] |
| translated_n = sum(totals.values()) - totals["untranslated"] |
| print(f"Exported {exported} files to {config.PACK_DIR.name}/") |
| print( |
| f"Strings: {translated_n} translated " |
| f"({totals['approved']} approved, {totals['edited']} edited, " |
| f"{totals['rejected']} rejected*, {totals['pending']} pending*, " |
| f"{totals['untranslated']} still English)." |
| ) |
| print("* rejected/pending strings ship with the unreviewed machine translation.") |
| if translated_n: |
| print(f"Human-reviewed: {reviewed / translated_n:.0%}") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|