--- url: /templates/advanced/functions.md description: >- Все функции шаблонного движка Astral Moderation — логические, математика, строки, списки, дата и время, кнопки, разметка и медиа — с примерами. --- # Функции

Функция принимает значения и возвращает результат: upper('привет') → ПРИВЕТ. Функцию можно вызвать обычно — round(x) — или через pipe — x | round.

Новые функции отмечены значком . ## Логические { #logic } | Функция | Возвращает `true`, когда | |---|---| | `defined(x)` | `x` определено (не `Undefined`) | | `empty(x)` | `x` пусто: `null`, `Undefined`, `''`, пустой список или карта, `0` | | `even(n)`, `odd(n)` | `n` четное, нечетное | | `iterable(x)` | `x` — список, карта или страница индекса | | `number(x)` | `x` — число или текст, похожий на число | Эти же функции работают как [тесты](./expressions#tests): `x is empty`, `x is number`. ## Математика { #math } | Функция | Что делает | Пример → результат | |---|---|---| | `abs(n)` | Модуль числа | `abs(-5)` → `5` | | `round(n, режим?)` | Округление. Режим `'CEIL'` — вверх, `'FLOOR'` — вниз, без режима — до ближайшего | `round(1.3, 'CEIL')` → `2` | | `min(…)`, `max(…)` | Наименьшее или наибольшее из аргументов или из списка | `max([3, 9, 4])` → `9` | | `random(…)` | Случайное значение — см. ниже | | ### random { #random } | Запись | Результат | |---|---| | `random(10)` | Случайное целое от 0 до 10 включительно | | `random(1, 6)` | Случайное целое от 1 до 6 включительно | | `random(['раз', 'два', 'три'])` | Случайный элемент списка | | `random(['раз', 'два', 'три'], [10, 50, 40])` | Элемент с весами: 10%, 50% и 40% | Если вес не указан или некорректен, он считается нулем — элемент не выпадет. Если некорректны все веса, элементы равновероятны. ```template 🎱 {{ random(['Да', 'Нет', 'Возможно', 'Спроси позже']) }} ``` ## Строки { #strings } | Функция | Что делает | Пример → результат | |---|---|---| | `lower(s)` | В нижний регистр | `lower('ПРИВЕТ')` → `привет` | | `upper(s)` | В верхний регистр | `upper('abcd12')` → `ABCD12` | | `capitalize(s)` | Первая буква заглавная | `capitalize('привет мир')` → `Привет мир` | | `title(s)` | Каждое слово с заглавной | `title('клуб astral')` → `Клуб Astral` | | `trim(s)` | Убрать пробелы по краям | `trim(' да ')` → `да` | | `truncate(s, длина, окончание?)` | Обрезать слишком длинный текст и поставить в конце `…` (или свое окончание) | `truncate(member.name, 12)` → имя не длиннее 12 символов | | `split(s, разделитель)` | Разбить на список | `split('a,b,c', ',')` → `[a, b, c]` | | `startsWith(s, начало, безРегистра?)` | Начинается ли с | `startsWith('#TAG', '#')` → `true` | | `endsWith(s, конец, безРегистра?)` | Заканчивается ли на | | | `contains(s, что, безРегистра?)` | Есть ли подстрока. `что` может быть списком — тогда хотя бы одна из | `contains('Hey there!', ['there', 'heh'])` → `true` | | `replace(s, карта, безРегистра?)` | Заменить все ключи карты на значения | `replace('Привет, %n%', { '%n%': 'Анна' })` → `Привет, Анна` | | `replace(s, что, на_что)` | Заменить все вхождения строки | `replace('#AB12', '#', '')` → `AB12` | | `format(шаблон, …)` | Подставить значения: `%s` — строка, `%d` — целое, `%f`, `%.2f` — дробное, `%%` — знак процента | `format('%s: %.1f%%', 'Побед', 62.54)` → `Побед: 62.5%` | | `concat(…)`, `concatenate(…)` | Склеить строки | `concat('1', '+', '1')` → `1+1` | | `escape_html(s)` | Заменить `& < > "` на HTML-сущности | | | `url_encode(s)` | Закодировать для ссылки | `url_encode('клуб astral')` → `%D0%BA…` | ### number\_format { #number\_format } `number_format(число, знаков?, разделитель_дроби?, разделитель_тысяч?)` — красивое число. | Запись | Результат | |---|---| | `number_format(12480)` | `12 480` (по языку чата: для русского — пробел и запятая) | | `number_format(11000.136, 2)` | `11 000,14` | | `number_format(11000.136, 2, '.', ' ')` | `11 000.14` | ### plural { #plural } `plural(число, язык, …формы)` выбирает правильную форму слова. Для русского — четыре формы: для 1 (1 день), для 2–4 (2 дня), для 0 и 5–20 (5 дней) и для дробных (1,5 дня): ```template {{ n }} {{ plural(n, 'ru', 'участник', 'участника', 'участников', 'участника') }} ``` Для английского — две формы: `plural(n, 'en', 'day', 'days')`. ## Списки и смешанные { #collections } | Функция | Что делает | Пример → результат | |---|---|---| | `length(x)` | Длина списка, карты или строки. Для `null` — 0 | `length([1, 2])` → `2` | | `first(x)`, `last(x)` | Первый или последний элемент (символ строки) | `first([5, 6])` → `5` | | `reverse(x)` | Развернуть список или строку | `reverse('abc')` → `cba` | | `default(x, запасное)` | `запасное`, если `x` — `null` или `Undefined` | `default(null, 0)` → `0` | | `join(список, разделитель?)` | Склеить в строку, `null` пропускаются. По умолчанию разделитель `, ` | `join([1, null, 2], ' / ')` → `1 / 2` | | `slice(x, начало, длина)` | Кусок списка или строки. Начало — с 0. Безопасна к выходу за границы | `slice([1, 2, 3], 0, 2)` → `[1, 2]` | | `batch(список, размер)` | Разбить на группы | `batch([1, 2, 3], 2)` → `[[1, 2], [3]]` | | `keys(x)`, `values(x)` | Ключи или значения карты (у списка ключи — номера) | `keys(['A', 'B'])` → `[0, 1]` | | `sort(список, режим?)` | Сортировка: `ASC`, `DESC` — как строки, `NUM_ASC`, `NUM_DESC` — как числа (не-числа отбрасываются) | `sort(['2', '1', '10'], 'NUM_ASC')` → `[1, 2, 10]` | | `sort_by(список, свойство, режим?)` | Сортировка объектов или карт по свойству | `club.members \| sort_by('trophies', 'DESC')` | | `shuffle(список)` | Перемешать | | | `unique(список)` | Убрать повторы | `unique([1, 1, 2])` → `[1, 2]` | | `typeof(x)` | Название типа | `typeof(9)` → `Number` | ::: warning `sort` сравнивает как строки `sort(['2', '1', '10'])` даст `[1, 10, 2]` — строки сравниваются посимвольно. Для чисел используйте `NUM_ASC` или `NUM_DESC`. ::: ## Дата и время { #datetime-functions } | Функция | Что делает | |---|---| | `now()` | Текущий момент (DateTime) в часовом поясе чата | | `calendar(значение?, пояс?)` | Создать DateTime из `'now'`, Unix-времени в миллисекундах или строки ISO 8601 | | `date(значение, формат?, пояс?)` | Дата текстом в нужном формате — см. ниже | | `datetime(значение, формат?)` | Дата, которую каждый увидит в своем поясе и на своем языке — см. ниже | | `duration(мс, единиц?)` | Длительность текстом: `duration(3650)` → `3 сек. 650 мс` | | `parse_duration(текст)` | Текст в миллисекунды: `parse_duration('1ч30м')` → `5400000` | Методы дат (`plusDays`, `isBefore`…) — в справочнике [DateTime](/reference/datetime). ### date { #date } `date(значение, формат, пояс)` форматирует дату. Значение — DateTime, Unix-время в миллисекундах или `'now'`. Пояс по умолчанию — часовой пояс чата из раздела **«Общие»**. ```template {{ date('now', 'EEE, d MMM yyyy HH:mm:ss z', 'Europe/Moscow') }} ``` Результат: `сб, 11 апр. 2026 15:27:38 MSK`. | Буквы | Что это | Пример | |---|---|---| | `yyyy`, `yy` | Год | `2026`, `26` | | `MM`, `M` | Месяц числом | `04`, `4` | | `MMM` | Месяц кратко | `апр.` | | `MMMM` | Месяц полностью, в родительном падеже | `апреля` | | `LLLL` | Месяц полностью, в именительном падеже | `апрель` | | `dd`, `d` | День месяца | `09`, `9` | | `EEE`, `EEEE` | День недели кратко и полностью | `сб`, `суббота` | | `HH`, `H` | Часы (0–23) | `05`, `5` | | `hh`, `h`, `a` | Часы (1–12) и AM/PM | | | `mm` | Минуты | `07` | | `ss` | Секунды | `38` | | `SSS` | Миллисекунды | `042` | | `z`, `Z`, `X` | Часовой пояс | `MSK`, `+0300` | | `D`, `w`, `u` | День года, неделя года, день недели числом | | Текст внутри формата берется в одинарные кавычки: `date(now(), "d MMMM 'в' HH:mm")` → `11 апреля в 15:27`. ### datetime { #datetime } `datetime(значение, формат)` выводит дату специальной разметкой Telegram: каждый участник увидит ее **в своем часовом поясе и на своем языке**. Удобно для анонсов турниров, когда в чате люди из разных стран. | Формат | Что покажет | |---|---| | `''` | Дату как есть, по нажатию — в поясе зрителя | | `'r'` | Относительно: «через 2 часа», «вчера» | | `'d'`, `'D'` | Дату кратко и полностью | | `'t'`, `'T'` | Время кратко и полностью | | `'w'` | День недели | Буквы можно сочетать: `'wDT'` — день недели, полная дата и время. ```template Турнир начнется {{ datetime(calendar('2026-10-03T15:00:00Z'), 'wDt') }} — это {{ datetime(calendar('2026-10-03T15:00:00Z'), 'r') }}. ``` ## Кнопки и взаимодействия { #interactions } | Функция | Что делает | |---|---| | `button(стиль, id_или_ссылка, надпись, эмодзи?, действие?, неактивная?)` | Кнопка под сообщением — подробно в статье [Кнопки и меню выбора](/commands/components#button) | | `url_button(надпись, ссылка)` | Кнопка-ссылка. То же, что `button('LINK', ссылка, надпись)` | | `copy_button(надпись, текст)` | Кнопка «скопировать текст» | | `row()`, `components_row()` | Начать новый ряд кнопок | | `button_row(кнопки, выравнивание?)` | Ряд из 1–8 кнопок внутри rich-сообщения | | `inline_button(…)` | Кнопка прямо в строке rich-текста. Аргументы — как у `button` | | `select_menu(тип, id, подсказка, действие, неактивное?)` | Меню выбора — см. [Кнопки и меню](/commands/components#select-menu) | | `reaction(эмодзи)` | Реакция бота на свое сообщение. Одна на сообщение, эмодзи — из разрешенных Telegram | Кнопки с действиями и меню работают только в [пользовательских командах](/commands/). ## Разметка { #markup } Функции разметки возвращают **готовую безопасную разметку**: движок не экранирует ее повторно, а текст внутри экранирует сам. Поэтому ими удобно оформлять данные — `bold(member.name)` не сломается, даже если в имени есть звездочки. Все функции работают и в Markdown, и в HTML. ### Строчные { #inline } | Функция | Результат | |---|---| | `bold(t)`, `italic(t)`, `underline(t)`, `strike(t)` | Жирный, курсив, подчеркнутый, зачеркнутый | | `spoiler(t)` | Спойлер | | `mark(t)` | Маркер (выделение) | | `sup(t)`, `sub(t)` | Верхний и нижний индекс | | `code(t)` | Моноширинный текст | | `link(текст, ссылка)` | Ссылка | | `mention(участник_или_id, текст?)` | Упоминание | | `custom_emoji(id, запасной)` | Кастомный эмодзи. Работает, если у владельца бота Telegram Premium, иначе выводится запасной | | `math(выражение)` | Формула в строке | ### Блоки { #blocks } | Функция | Результат | |---|---| | `heading(текст, размер)` | Заголовок размера 1–6 | | `quote(текст, автор?, раскрывающаяся?)` | Цитата; `true` третьим аргументом — раскрывается по нажатию | | `pullquote(текст, автор?)` | Цитата-выноска | | `details(заголовок, содержимое, открыт?)` | Сворачиваемый блок | | `divider()` | Горизонтальная линия | | `footer(текст)` | Подвал — мелкая строка внизу | | `list(элементы, вид?)` | Список. `'ordered'` — нумерованный | | `checklist(элементы)` | Чек-лист | | `pre(текст, язык?)` | Блок кода | | `math_block(выражение)` | Формула отдельным блоком | | `anchor(имя)` | Якорь для ссылки внутри сообщения | Все блочные функции новые . В режиме Text блоки [упрощаются](./rich#text-mode), а редактор предупреждает об этом. ### table { #table } `table(строки, настройки?)` строит таблицу из списка списков. Значения ячеек экранируются, поэтому таблица не сломается, какими бы ни были данные. ```template {{ table([ ['Игрок', 'Кубки'], ['Анна', 24510], ['Иван', 19870] ], { header: true, striped: true }) }} ``` | Настройка | Что делает | |---|---| | `header` | Первая строка — заголовки столбцов | | `bordered` | Рамки у ячеек | | `striped` | Полосы через строку | | `compact` | Компактные строки | | `caption` | Подпись под таблицей | | `index` | Добавить первый столбец с номером строки; значение — его заголовок, например `'#'` | `table_of(объекты, столбцы, настройки?)` строит таблицу из списка объектов: `столбцы` — карта «свойство → заголовок». ```template {{ table_of(club.members | sort_by('trophies', 'DESC') | slice(0, 10), { name: 'Игрок', trophies: 'Кубки' }, { header: true, index: '#' }) }} ``` В таблице — до 20 столбцов. В режиме Text таблица станет моноширинным текстом. ### Медиа { #media } | Функция | Что вставляет | |---|---| | `photo(ссылка, подпись?, спойлер?)` | Фото. `true` третьим аргументом — скрыть под спойлер | | `video(…)`, `animation(…)` | Видео, GIF — аргументы как у `photo` | | `audio(…)`, `voice(…)` | Аудио, голосовое сообщение | | `document(ссылка, подпись?)` | Файл | | `collage(медиа, подпись?)` | Коллаж из нескольких медиа | | `slideshow(медиа, подпись?)` | Слайдшоу | | `map(широта, долгота, масштаб?, подпись?)` | Карта с точкой | Ссылки на медиа — только `https://`. Все медиафункции новые , подробнее — [Rich-сообщения](./rich#media). ## Данные Astral { #astral } Клубы, игроки, рейтинги и черный список доступны не функциями, а через объект `astral`: `astral.club('#TAG')`, `astral.player('#TAG')`. См. [Пространство astral](../astral).