























@@ -14,6 +14,7 @@ const TELEGRAM_MAX_COMMANDS = 100;
1414export const TELEGRAM_TOTAL_COMMAND_TEXT_BUDGET = 5700;
1515const TELEGRAM_COMMAND_RETRY_RATIO = 0.8;
1616const TELEGRAM_MIN_COMMAND_DESCRIPTION_LENGTH = 1;
17+const TELEGRAM_MAX_COMMAND_DESCRIPTION_LENGTH = 256;
1718const TELEGRAM_MENU_RESULT_CACHE_MAX = 128;
18191920export type TelegramMenuCommand = {
@@ -101,7 +102,10 @@ function fitTelegramCommandsWithinTextBudget(
101102);
102103let descriptionTrimmed = false;
103104const fittedCommands = candidateCommands.map((command) => {
104-const description = truncateTelegramCommandText(command.description, descriptionCap);
105+const description = truncateTelegramCommandText(
106+command.description,
107+Math.min(descriptionCap, TELEGRAM_MAX_COMMAND_DESCRIPTION_LENGTH),
108+);
105109if (description !== command.description) {
106110descriptionTrimmed = true;
107111return Object.assign({}, command, { description });
@@ -278,6 +282,7 @@ function buildTelegramMenuResultCacheKey(params: {
278282for (const command of params.allCommands) {
279283updateTelegramCommandDigestField(digest, command.command);
280284updateTelegramCommandDigestField(digest, command.description);
285+updateTelegramCommandLocalizationDigest(digest, command.descriptionLocalizations);
281286}
282287return digest.digest("hex").slice(0, 16);
283288}
@@ -291,6 +296,18 @@ function updateTelegramCommandDigestField(
291296digest.update(value);
292297}
293298299+function updateTelegramCommandLocalizationDigest(
300+digest: ReturnType<typeof createHash>,
301+localizations: Record<string, string> | undefined,
302+): void {
303+const entries = Object.entries(localizations ?? {}).toSorted(([a], [b]) => a.localeCompare(b));
304+updateTelegramCommandDigestField(digest, String(entries.length));
305+for (const [locale, description] of entries) {
306+updateTelegramCommandDigestField(digest, locale);
307+updateTelegramCommandDigestField(digest, description);
308+}
309+}
310+294311function rememberCappedTelegramMenuResult(
295312key: string,
296313result: ReturnType<typeof buildUncachedCappedTelegramMenuCommands>,
@@ -331,24 +348,74 @@ function writeCachedCommandHash(
331348syncedCommandHashes.set(key, hash);
332349}
333350334-function buildLocalizedCommandVariants(
335-commands: TelegramMenuCommand[],
336-): Array<{ languageCode: string; commands: TelegramMenuCommand[] }> {
351+function normalizeTelegramLanguageCode(languageCode: string): string | null {
352+const normalized = languageCode.trim().toLowerCase();
353+return /^[a-z]{2}$/.test(normalized) ? normalized : null;
354+}
355+356+function readLocalizedDescription(
357+command: TelegramMenuCommand,
358+languageCode: string,
359+): string | undefined {
360+for (const [rawLanguageCode, rawDescription] of Object.entries(
361+command.descriptionLocalizations ?? {},
362+)) {
363+if (normalizeTelegramLanguageCode(rawLanguageCode) !== languageCode) {
364+continue;
365+}
366+const description = normalizeOptionalString(rawDescription);
367+if (description) {
368+return description;
369+}
370+}
371+return undefined;
372+}
373+374+function toTelegramBotCommands(commands: TelegramMenuCommand[]): Array<{
375+command: string;
376+description: string;
377+}> {
378+return commands.map((command) => ({
379+command: command.command,
380+description: command.description,
381+}));
382+}
383+384+function buildLocalizedCommandVariants(commands: TelegramMenuCommand[]): {
385+variants: Array<{ languageCode: string; commands: TelegramMenuCommand[] }>;
386+unsupportedLanguageCodes: string[];
387+} {
337388const locales = new Set<string>();
389+const unsupportedLanguageCodes = new Set<string>();
338390for (const cmd of commands) {
339391if (cmd.descriptionLocalizations) {
340392for (const lang of Object.keys(cmd.descriptionLocalizations)) {
341-locales.add(lang);
393+const normalized = normalizeTelegramLanguageCode(lang);
394+if (normalized) {
395+locales.add(normalized);
396+} else {
397+unsupportedLanguageCodes.add(lang);
398+}
342399}
343400}
344401}
345-return [...locales].toSorted().map((languageCode) => ({
346- languageCode,
347-commands: commands.map((cmd) => ({
402+const variants = [...locales].toSorted().map((languageCode) => {
403+const localizedCommands = commands.map((cmd) => ({
348404command: cmd.command,
349-description: cmd.descriptionLocalizations?.[languageCode] ?? cmd.description,
350-})),
351-}));
405+description: readLocalizedDescription(cmd, languageCode) ?? cmd.description,
406+}));
407+return {
408+ languageCode,
409+commands: fitTelegramCommandsWithinTextBudget(
410+localizedCommands,
411+TELEGRAM_TOTAL_COMMAND_TEXT_BUDGET,
412+).commands,
413+};
414+});
415+return {
416+ variants,
417+unsupportedLanguageCodes: [...unsupportedLanguageCodes].toSorted(),
418+};
352419}
353420354421function formatTelegramCommandScopeOperation(
@@ -398,13 +465,14 @@ async function setTelegramMenuCommandsForScopes(params: {
398465 runtime,
399466 shouldLog,
400467fn: () => {
468+const botCommands = toTelegramBotCommands(commands);
401469const opts = {
402470 ...scope.options,
403471 ...(languageCode ? { language_code: languageCode as LanguageCode } : undefined),
404472};
405473return Object.keys(opts).length > 0
406- ? bot.api.setMyCommands(commands, opts)
407- : bot.api.setMyCommands(commands);
474+ ? bot.api.setMyCommands(botCommands, opts)
475+ : bot.api.setMyCommands(botCommands);
408476},
409477});
410478}
@@ -446,6 +514,7 @@ export function syncTelegramMenuCommands(params: {
446514}
447515448516let retryCommands = commandsToRegister;
517+let acceptedCommands: TelegramMenuCommand[] | null = null;
449518const initialCommandCount = commandsToRegister.length;
450519while (retryCommands.length > 0) {
451520try {
@@ -463,6 +532,7 @@ export function syncTelegramMenuCommands(params: {
463532}),
464533);
465534}
535+acceptedCommands = retryCommands;
466536break;
467537} catch (err) {
468538if (!isBotCommandsTooMuchError(err)) {
@@ -484,7 +554,18 @@ export function syncTelegramMenuCommands(params: {
484554}
485555}
486556487-for (const variant of buildLocalizedCommandVariants(commandsToRegister)) {
557+if (!acceptedCommands) {
558+return;
559+}
560+561+const { variants, unsupportedLanguageCodes } = buildLocalizedCommandVariants(acceptedCommands);
562+if (unsupportedLanguageCodes.length > 0) {
563+runtime.log?.(
564+`Telegram command menu ignored unsupported description localization codes: ${unsupportedLanguageCodes.join(", ")}.`,
565+);
566+}
567+568+for (const variant of variants) {
488569await setTelegramMenuCommandsForScopes({
489570 bot,
490571 runtime,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。