fix: escape MarkdownV2 reserved chars in Farsi locale strings#872
fix: escape MarkdownV2 reserved chars in Farsi locale strings#872Matobi98 wants to merge 1 commit into
Conversation
WalkthroughThis PR updates the Persian (fa.yaml) locale file, revising sell/buy command format guidance text and escaping Markdown-sensitive characters (parentheses, periods) in several notification templates including dispute, wizard exit, and order-taken messages. ChangesPersian locale updates
Estimated code review effort: 1 (Trivial) | ~5 minutes Possibly related issues
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@locales/fa.yaml`:
- Line 89: Remove the escaped hyphens inside the inline code examples in the
locale strings so MarkdownV2 renders them correctly. Update the affected entries
in the fa.yaml translation where the examples use code spans with `\-`, and
replace them with plain hyphens while keeping the rest of the message unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
|
@Matobi98 @Luquitasjeffrey this is the first time I hear that dots needs to be escaped in MarkDown; it doesn't sound realistic sorry; or are we talking about a different dot, like a weird unicode dot-looking character? |
It's the plain ASCII dot, not a weird unicode one. I looked it up: these strings are sent with parse_mode: 'MarkdownV2' (e.g. bot/messages.ts:576), not legacy Markdown. According to the official docs (https://core.telegram.org/bots/api#markdownv2-style), in MarkdownV2 the characters _ * [ ] ( ) ~ > # + - = | { } . ! must be escaped — so the . is reserved there (it isn't in legacy Markdown, which is probably the source of the confusion). If any reserved char is left unescaped, Telegram rejects the whole message with 400: can't parse entities, which is what caused #871. That's what I found so far — let me know if I'm missing something. |
You're right that escaping dots across every locale isn't sustainable as a long-term strategy — a centralized approach is the correct end state, and this deserves a dedicated follow-up. I'd argue it belongs in a separate PR though, for two reasons:
All three of your suggestions are global changes (they touch parse_mode at the send sites and/or every locale file), so they need their own design + a full re-test across the 10 languages. Concretely:
So none of the three is a drop-in; they're all bot-wide work. This PR, by contrast, is a contained Farsi-only fix for a message that is broken in production right now. My proposal: merge this as the immediate fix, and treat the centralized approach (unifying parse mode → then escaping only interpolated values, or moving off MarkdownV2) as a separate PR where it can get the design and multi-language testing it needs. |


Closes #871
Problem
Farsi (
fa) users received no message at all when taking a sell order. The flow stalled silently and the order was cancelled after the timeout with "no invoice was provided". Reported in production for@farhoudif; it worked for everyone else, and the common factor was the Farsi language setting.Root cause
Several messages are sent with
parse_mode: 'MarkdownV2'. In MarkdownV2 the.(period) is a reserved/special character: to use it as literal text you must put a backslash\in front of it. In the Farsi translations those backslashes were missing (the English/Spanish strings already had them), so Telegram rejected the whole message with:The
.t()calls catch the error and only log it, so the failure is silent — the message (and, foryou_took_someone_order, the follow-up Continue button) is never sent, leaving the buyer with nothing.The subtle part (double backslash)
The translation library (
@grammyjs/i18n) runs strings that contain interpolation like${amount}through a template compiler, and that compiler eats one backslash (it treats\as an escape char):\.→ the compiler turns it into.→ reaches Telegram unescaped → 400 error\\.→ the compiler turns it into\.→ reaches Telegram correctly escaped → worksSo the correct escaping depends on whether the string interpolates a variable:
${...}→ use double backslash:\\.,\\(,\\)${...}→ use single backslash:\.,\(Fix
Escaped the reserved characters in
locales/fa.yamlfor every affected MarkdownV2 key, using the right number of backslashes per the rule above:you_took_someone_order\\.\\(\\)expired_order\\.\\(\\)dispute_started_channel\\.\\(\\)wizard_add_invoice_exit\\.sell_correct_format\.buy_correct_format\.Testing
400 ... Character '.' is reservederror against the running bot (Farsi account taking a sell order → no message received).@grammyjs/i18nlibrary and confirming no unescaped reserved characters remain in the output (not just scanning the YAML source, since the source escaping differs from the rendered result).tscandeslintclean.Note
This is not the missing
ln_address_temporarily_disabledkey (genuinely absent fromfa.yamlbut harmless, since i18n runs withdefaultLanguageOnMissing: trueand falls back to English).Summary by CodeRabbit
0sats, and fiat ranges.