refactor(telegram): every user-facing string lives in TelegramTexts with English defaults

This commit is contained in:
hh
2026-09-02 00:16:38 +02:00
parent 9aaddbed75
commit 3915ab48f9
6 changed files with 227 additions and 120 deletions
+19 -17
View File
@@ -293,7 +293,7 @@ async def test_general_is_master_and_reply_has_no_thread(stack: Stack) -> None:
assert all(o[0] != "draft" for o in stack.bot.order[final:])
last = stack.bot.drafts[-1]
assert last["text"] == reply["text"] and last["parse_mode"] == "HTML"
assert stack.bot.drafts[0]["text"] == "думаю"
assert stack.bot.drafts[0]["text"] == "thinking"
rows = await stack.world.conversations.queue.recent(master.id)
assert [r.origin for r in rows] == ["telegram"]
@@ -377,7 +377,7 @@ async def test_reply_from_another_window_is_mirrored_with_marker(stack: Stack) -
await stack.world.conversations.post(master, "from panel", origin="user")
await stack.until(lambda: stack.sent_with("ok:from panel"), what="mirrored reply")
texts = [m["text"] for m in stack.bot.sent]
marker = next(i for i, t in enumerate(texts) if t.startswith("📝 из панели:"))
marker = next(i for i, t in enumerate(texts) if t.startswith("📝 from the panel:"))
assert "from panel" in texts[marker]
assert texts[marker + 1] == "ok:from panel"
@@ -456,7 +456,7 @@ async def test_question_timeout_renders_text_and_free_text_answers(
assert result is None
assert "did not answer" in stack.world.conversations.answer_text(None)
await stack.until(
lambda: any("время вышло" in e.get("text", "") for e in stack.bot.edits),
lambda: any("time is up" in e.get("text", "") for e in stack.bot.edits),
what="timeout edit",
)
stack.world.conversations._question_timeout = 5.0 # noqa: SLF001
@@ -474,7 +474,7 @@ async def test_question_timeout_renders_text_and_free_text_answers(
async def test_commands_status_merge_and_new(stack: Stack) -> None:
stack.bot.message("/status")
status = await stack.until(lambda: stack.sent_with("master · open"), what="status")
assert "пул:" in status["text"]
assert "pool:" in status["text"]
stack.bot.message("work", thread=11)
await stack.until(lambda: stack.sent_with("work"), what="branch reply")
branch = await stack.world.conversations.find_bound(
@@ -490,14 +490,14 @@ async def test_commands_status_merge_and_new(stack: Stack) -> None:
),
)
stack.bot.message("/merge", thread=11)
await stack.until(lambda: stack.sent_with("слито в мастер"), what="merged")
await stack.until(lambda: stack.sent_with("merged into the master"), what="merged")
branch = await stack.world.conversations.find_bound(
frontend="telegram", external_id=f"{USER}/11"
)
assert branch.status == "merged"
assert stack.bot.topics == ["🦫 General", "edit:11:✅ work"]
stack.bot.message("/new отчёт")
await stack.until(lambda: stack.sent_with("в новом топике"), what="new topic")
await stack.until(lambda: stack.sent_with("in a new topic"), what="new topic")
assert stack.bot.topics == ["🦫 General", "edit:11:✅ work", "отчёт"]
child = await stack.world.conversations.find_bound(
frontend="telegram", external_id=f"{USER}/902"
@@ -646,7 +646,7 @@ def test_render_helpers() -> None:
parts = chunks("абв\n\n" + "г" * 30 + "\n\n" + "д" * 30, limit=40)
assert parts == ["абв\n\n" + "г" * 30, "д" * 30]
assert chunks(" \n ") == []
assert status_label("Read", {"file_path": "/x"}) == "читаю vault"
assert status_label("Read", {"file_path": "/x"}) == "reading"
assert status_label("mcp__firefly__list_accounts", None) == "firefly: list_accounts"
assert status_label("Foo", {"command": "ls -la"}) == "Foo ls -la"
@@ -779,14 +779,14 @@ async def test_attachments_land_in_day_folder_with_keep_note(stack: Stack) -> No
(saved,) = list(day.iterdir())
assert saved.read_bytes() == b"data" and saved.name.endswith("-u1.jpg")
assert prompt.endswith(
f"смотри\n\n[вложение: фото {saved}, 2 КБ; хранится 3 дн., "
"перенеси в vault, если нужно]"
f"смотри\n\n[attachment: photo {saved}, 2 KB; kept 3 days, "
"move it into the vault if it matters]"
)
stack.tg.attachments = Attachments(dir=root, keep_days=None)
stack.bot.media(_photo("ещё"))
await stack.until(lambda: stack.sent_with("ещё"), what="second reply")
prompt = next(p for c in ScriptedClient.instances for p in c.prompts if "ещё" in p)
assert prompt.endswith(" КБ]") and "хранится" not in prompt
assert prompt.endswith(" KB]") and "kept" not in prompt
async def test_sticker_alone_becomes_an_unsupported_note(stack: Stack) -> None:
@@ -803,11 +803,11 @@ async def test_sticker_alone_becomes_an_unsupported_note(stack: Stack) -> None:
}
}
)
await stack.until(lambda: stack.sent_with("стикер"), what="reply")
await stack.until(lambda: stack.sent_with("sticker"), what="reply")
prompt = next(
p for c in ScriptedClient.instances for p in c.prompts if "стикер" in p
p for c in ScriptedClient.instances for p in c.prompts if "sticker" in p
)
assert prompt.endswith("[вложение: стикер - не поддерживается]")
assert prompt.endswith("[attachment: sticker - not supported]")
def test_sweep_drops_old_files_and_empty_day_folders() -> None:
@@ -878,13 +878,15 @@ async def test_failed_background_turn_is_reported_once(stack: Stack) -> None:
await stack.tg._on_event(event) # noqa: SLF001
await stack.tg._on_event(event) # noqa: SLF001
await stack.until(
lambda: stack.sent_with("фоновый тёрн (крон) упал"), what="notice"
lambda: stack.sent_with("a background turn (крон) failed"), what="notice"
)
await asyncio.sleep(0.2)
assert len([m for m in stack.bot.sent if "упал" in m["text"]]) == 1
assert len([m for m in stack.bot.sent if "failed" in m["text"]]) == 1
await stack.tg._on_event({**event, "turn_id": "t-user", "origin": "user"}) # noqa: SLF001
notice = await stack.until(lambda: stack.sent_with("⚠️ тёрн упал"), what="user")
assert "фоновый" not in notice["text"]
notice = await stack.until(
lambda: stack.sent_with("⚠️ the turn failed"), what="user"
)
assert "background" not in notice["text"]
async def test_gone_topic_unbinds_and_the_next_message_starts_afresh(