import json import pytest from app import translation as tr from app.config import get_settings from app.converter.pipeline import convert_archive from tests.make_sample import build @pytest.fixture def manifest(tmp_path, monkeypatch): monkeypatch.setenv("DATA_DIR", str(tmp_path / "data")) get_settings.cache_clear() archive = build(tmp_path / "sample.zip") yield convert_archive(archive, "sample.zip", tmp_path / "work", lambda _: None).manifest get_settings.cache_clear() def test_index_has_context(manifest): idx = tr.text_index(manifest) first = idx.lines[0] assert first.label == "start" and first.scene == "images/bg room.webp" assert idx.lines[1].who == "Эйлин" and idx.lines[1].prev == first.source assert idx.strings["Пойдём гулять"] == "menu" and idx.strings["Эйлин"] == "name" def test_edit_new_language_and_outdated(manifest): idx = tr.text_index(manifest) tid = idx.lines[0].tid m = tr.apply_changes(manifest, "de", lines={tid: {"t": "Willkommen", "state": "approved"}}, strings={"Эйлин": {"t": "Eileen"}}, meta={"glossary": [{"src": "Эйлин", "t": "Eileen"}]}) lines, strings, meta = tr.locale_tables(m, "de") assert lines[tid]["t"] == "Willkommen" and lines[tid]["state"] == "translated" # no approve right assert strings["Эйлин"]["t"] == "Eileen" and meta["glossary"][0]["t"] == "Eileen" game = tr.file_json(m, "game.json") assert game["locales"]["de"]["renpy"] == "german" and game["locales"]["de"]["lines"] == 1 # the original line changed in a mod: the translation is kept but marked outdated info = idx.by_tid[tid] changed = tr.LineInfo(**{**info.__dict__, "source": "другой текст"}) assert tr.line_state(lines[tid], changed) == "outdated" # removing an entry m2 = tr.apply_changes(m, "de", lines={tid: None}) assert tid not in tr.locale_tables(m2, "de")[0] with pytest.raises(ValueError): tr.apply_changes(manifest, "ru", lines={tid: {"t": "x"}}) # source language def test_merge_languages_keeps_target_untouched(manifest): tid = tr.text_index(manifest).lines[0].tid fork = tr.apply_changes(manifest, "de", lines={tid: {"t": "Hallo"}}) assert tr.changed_languages(fork, manifest) == ["de"] merged = tr.merge_languages(manifest, fork, ["de"]) assert tr.locale_tables(merged, "de")[0][tid]["t"] == "Hallo" assert tr.locale_tables(merged, "en")[0] == tr.locale_tables(manifest, "en")[0] assert "de" not in (tr.file_json(manifest, "game.json").get("locales") or {}) def test_three_way_publication_keeps_independent_lines(manifest): a, b = [line.tid for line in tr.text_index(manifest).lines[:2]] left = tr.apply_changes(manifest, "de", lines={a: {"t": "One"}}) right = tr.apply_changes(manifest, "de", lines={b: {"t": "Two"}}) merged, conflicts = tr.merge_translation(manifest, left, right) assert not conflicts lines = tr.locale_tables(merged, "de")[0] assert lines[a]["t"] == "One" and lines[b]["t"] == "Two" conflict = tr.apply_changes(manifest, "de", lines={a: {"t": "Other"}}) _, conflicts = tr.merge_translation(manifest, left, conflict) assert conflicts and any(a in c["path"] for c in conflicts) def test_po_and_csv_roundtrip(manifest): tid = tr.text_index(manifest).lines[0].tid m = tr.apply_changes(manifest, "de", lines={tid: {"t": "Zeile 1\nZeile \"2\""}}, strings={"Эйлин": {"t": "Eileen"}}) lines, strings = tr.parse_po(tr.export_po(m, "de", "Test")) assert lines[tid]["t"] == "Zeile 1\nZeile \"2\"" and strings["Эйлин"]["t"] == "Eileen" lines, strings = tr.parse_csv(tr.export_csv(m, "de")) assert lines[tid]["t"] == "Zeile 1\nZeile \"2\"" and strings["Эйлин"]["t"] == "Eileen" st = tr.stats(m, "de") assert st["translated"] == 1 and st["stringsTranslated"] == 1 assert json.dumps(st)