Download app/renpy/inject.py from Cnass/mtapi: direct link, hf CLI and curl.
- Browser
- Download file 2.54 kB
-
https://huggingface.co/spaces/Cnass/mtapi/resolve/main/app/renpy/inject.py
- Command line
-
hf download hf://spaces/Cnass/mtapi/app/renpy/inject.py
-
curl -L -o inject.py https://huggingface.co/spaces/Cnass/mtapi/resolve/main/app/renpy/inject.py
2.54 kB
| """Write translations back into .rpy scripts. | |
| A translation replaces exactly the characters between one pair of quotes and | |
| nothing else. Spans are applied from the end of the file backwards so that | |
| every offset still refers to the text it was measured against - rewriting | |
| front-to-back would shift each following span by the length the last one | |
| changed. | |
| The script around the strings is never re-indented, re-wrapped or re-parsed, so | |
| a file whose strings all translate to themselves comes back byte-identical. | |
| """ | |
| from __future__ import annotations | |
| from pathlib import Path | |
| from .text import escape | |
| def apply_to_source(source: str, spans: list[tuple[int, int, str, str]]) -> str: | |
| """Replace each (start, end, quote, translation) span in `source`.""" | |
| ordered = sorted(spans, key=lambda item: item[0], reverse=True) | |
| out = source | |
| last_start = len(source) + 1 | |
| for start, end, quote, translated in ordered: | |
| if end > last_start: | |
| # Overlapping spans would corrupt the file. The scanner cannot | |
| # produce them, but a stale units.json against an edited source | |
| # could, so refuse rather than write nonsense. | |
| raise ValueError(f"overlapping span at {start}:{end}") | |
| out = out[:start] + escape(translated, quote) + out[end:] | |
| last_start = start | |
| return out | |
| def apply(project_dir: Path, units: list, translations: dict[str, str]) -> tuple[int, int]: | |
| """Write every translated unit into the scripts under `project_dir`. | |
| Groups by file so each script is read and written once. Returns | |
| (written_spans, skipped_spans). | |
| """ | |
| by_file: dict[str, list[tuple[int, int, str, str]]] = {} | |
| for unit in units: | |
| translated = translations.get(unit.source) | |
| if translated is None: | |
| continue | |
| for slot in unit.slots: | |
| if not slot.writable: | |
| continue | |
| by_file.setdefault(slot.file, []).append( | |
| (slot.start, slot.end, slot.quote, translated) | |
| ) | |
| written = skipped = 0 | |
| for name, spans in by_file.items(): | |
| path = project_dir / name | |
| try: | |
| source = path.read_text(encoding="utf-8") | |
| except OSError: | |
| skipped += len(spans) | |
| continue | |
| try: | |
| updated = apply_to_source(source, spans) | |
| except ValueError: | |
| skipped += len(spans) | |
| continue | |
| path.write_text(updated, encoding="utf-8") | |
| written += len(spans) | |
| return written, skipped | |