fix(telegram): answer someone who asks for help in their own language

The bot's real commands are slash commands, and `telegram.helpBody`
documents exactly those in all six bundles, so nothing a user is TOLD to
type depended on their language. The undocumented courtesies did: the bare
word "help" and "hilfe" opened the help text and five greetings were
answered, everything else fell through to the intake keyword, failed it,
and returned without sending anything. Someone typing "aide" or "pomoc"
got silence, which is the worst possible answer to a request for help.

Both lists now cover the six shipped languages and are compared against
the folded message, so "cześć" and "czesc" are one entry and a capital
cannot miss. The match stays anchored to the whole message: "help me log
my weight" is prose the later paths should still see.

These are ordinary words rather than app labels, so there is nothing in
the bundles to derive them from.
This commit is contained in:
Marc-André Bombeck committed 2026-08-23 18:06:58 +02:00
1 parent 4d77fe2a43
commit 2d26a6fdfe
2 files changed
+123 -7

No files matched your search

@@ -546,6 +546,67 @@ describe("Telegram webhook — text-message dispatch", () => {
expect(prisma.medicationIntakeEvent.create).not.toHaveBeenCalled();
});
/**
* The bare word is an alias for `/help`. It knew "help" and "hilfe", so the
* four other shipped languages asking for help fell through to the intake
* keyword, failed it, and the handler returned without sending anything —
* silence, not an error. These pin one spelling per shipped language.
*/
it.each([
["help", 210],
["Hilfe", 211],
["aide", 212],
["ayuda", 213],
["aiuto", 214],
["Pomoc", 215],
])("answers the bare help word %s", async (word, updateId) => {
const res = await POST(
tgRequest({
update_id: updateId,
message: { message_id: 20, text: word, chat: { id: 7777 } },
}),
);
expect(res.status).toBe(200);
expect(sendTelegramMessage).toHaveBeenCalledTimes(1);
expect(vi.mocked(sendTelegramMessage).mock.calls[0][2]).toMatch(
/available commands/i,
);
});
it("does not swallow a sentence that merely starts with a help word", async () => {
// The alias matches the WHOLE message; "help me log my weight" is prose
// the later paths should still see, not a command.
const res = await POST(
tgRequest({
update_id: 216,
message: {
message_id: 21,
text: "help me log my weight",
chat: { id: 7777 },
},
}),
);
expect(res.status).toBe(200);
expect(sendTelegramMessage).not.toHaveBeenCalled();
});
it.each([
["bonjour", 220],
["Hola", 221],
["ciao", 222],
["cześć", 223],
])("answers the greeting %s", async (word, updateId) => {
const res = await POST(
tgRequest({
update_id: updateId,
message: { message_id: 22, text: word, chat: { id: 7777 } },
}),
);
expect(res.status).toBe(200);
expect(sendTelegramMessage).toHaveBeenCalledTimes(1);
expect(vi.mocked(sendTelegramMessage).mock.calls[0][2]).toMatch(/👋/);
});
it("greeting like 'hi' echoes a friendly reply", async () => {
const res = await POST(
tgRequest({