feat(telegram): localized /start welcome with channel & chat follow links
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 15s
CI / ui (pull_request) Has been skipped
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m17s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 15s
CI / ui (pull_request) Has been skipped
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m17s
The main bot answered /start with a single English line ("Tap to open Scrabble.").
Localize it: Russian or English by the sender's reported Telegram language
(Message.from.language_code, which the Bot API carries on the message itself — there is
no separate user-update event — English fallback), with the longer welcome copy and a
localized launch button ("Открыть «Эрудит»" / "Open “Erudite”").
The welcome links the game channel and the discussion chat by their public @username,
resolved once at startup from the configured TELEGRAM_GAME_CHANNEL_ID / TELEGRAM_CHAT_ID
via getChat and cached. A handle that is unset, private, or unreadable degrades to a
generic noun ("the channel" / "our chat") rather than a dangling "@", so the paragraph
always reads cleanly (the bot's info screen still lists the real links). Adds
GameChannelID to bot.Config (wired from the existing config) for the channel handle.
Tests: startText localization + handle embedding + per-slot generic fallback; handleStart
language selection; resolveWelcomeHandles. README updated.
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
package bot
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStartTextLocalizesByLanguage(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
lang string
|
||||
wantButton string
|
||||
wantSubstr string // a phrase unique to the chosen language body
|
||||
}{
|
||||
{"russian", "ru", "Открыть «Эрудит»", "Привет!"},
|
||||
{"russian region tag", "ru-RU", "Открыть «Эрудит»", "Первая партия"},
|
||||
{"english", "en", "Open “Erudite”", "Hi!"},
|
||||
{"other language falls back to english", "de", "Open “Erudite”", "Hi!"},
|
||||
{"absent language falls back to english", "", "Open “Erudite”", "no more talking"},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
text, button := startText(tc.lang, "erudit", "erudite_chat")
|
||||
if button != tc.wantButton {
|
||||
t.Errorf("button = %q, want %q", button, tc.wantButton)
|
||||
}
|
||||
if !strings.Contains(text, tc.wantSubstr) {
|
||||
t.Errorf("text %q does not contain %q", text, tc.wantSubstr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartTextEmbedsFollowHandles(t *testing.T) {
|
||||
for _, lang := range []string{"ru", "en"} {
|
||||
text, _ := startText(lang, "erudit", "erudite_chat")
|
||||
if !strings.Contains(text, "@erudit") || !strings.Contains(text, "@erudite_chat") {
|
||||
t.Errorf("lang %q: follow paragraph missing the handles: %q", lang, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartTextFallsBackToGenericWhenHandleMissing(t *testing.T) {
|
||||
// An unresolved handle degrades to a generic noun rather than a dangling "@" — and
|
||||
// only that slot degrades; a resolved sibling still shows its "@username".
|
||||
t.Run("both missing leaves no @", func(t *testing.T) {
|
||||
for _, lang := range []string{"ru", "en"} {
|
||||
text, _ := startText(lang, "", "")
|
||||
if strings.Contains(text, "@") {
|
||||
t.Errorf("lang %q: text shows a dangling @: %q", lang, text)
|
||||
}
|
||||
}
|
||||
// The generic nouns are present in each language.
|
||||
ru, _ := startText("ru", "", "")
|
||||
if !strings.Contains(ru, "на канал") || !strings.Contains(ru, "в нашем чате") {
|
||||
t.Errorf("russian generic fallback missing: %q", ru)
|
||||
}
|
||||
en, _ := startText("en", "", "")
|
||||
if !strings.Contains(en, "Follow the channel") || !strings.Contains(en, "in our group chat") {
|
||||
t.Errorf("english generic fallback missing: %q", en)
|
||||
}
|
||||
})
|
||||
t.Run("only the missing slot degrades", func(t *testing.T) {
|
||||
// Channel resolved, chat missing: the channel keeps its @handle, the chat is generic.
|
||||
en, _ := startText("en", "erudit", "")
|
||||
if !strings.Contains(en, "@erudit") || strings.Contains(en, "@erudite") {
|
||||
t.Errorf("channel handle not shown / chat handle leaked: %q", en)
|
||||
}
|
||||
if !strings.Contains(en, "in our group chat") {
|
||||
t.Errorf("chat slot did not degrade to a generic noun: %q", en)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user