Переменные и переиспользование
Переменные — это то, что превращает один шаблон в сеть сайтов. Правильно спроектированные переменные — и 100 сайтов рендерятся из одного источника. Неправильно — и вы копипастите текст в каждый пресет руками.
Три источника, одна общая область
В момент рендера большинство движков сливают переменные из трёх мест в одну общую таблицу. Когда шаблон читает %SomeName%, резолвер идёт по этой таблице и подставляет значение.
- Локальные помощники шаблона — объявленные через
#setвнутри тела шаблона. - Переменные сайта — заданные для конкретного тенанта, по одной записи на сайт, общие для всех шаблонов этого сайта.
- Runtime-переменные — передаются в резолвер в момент вызова (контекст статьи, системный контекст, пользовательский контекст).
Проектирование сводится к одному вопросу: на каком слое живёт каждый факт.
Локальные помощники через #set
Используйте #set для коротких помощников внутри одного шаблона:
#set %Lead% = {Добро пожаловать|Приветствуем|Здравствуйте},
%Lead% добро пожаловать в %brand_name%!
Хорошие применения:
- помощники одного шаблона, которые иначе захламляли бы тело повторами;
- длинные фразы, используемые несколько раз внутри одного шаблона;
- читаемость, когда вложенность становится слишком глубокой.
Плохие применения:
- специфичные для сайта факты — им место в переменных сайта;
- всё, что уже предоставляет runtime — локальный
#setпроиграет по приоритету.
Синтаксические подводные камни
- Имена переменных регистронезависимы.
- Только ASCII: буквы, цифры, подчёркивания. Никаких пробелов и дефисов.
#setработает только в начале строки.- Комментарии —
/# ... #/, вырезаются до обработки. - Неизвестные переменные остаются буквальными.
%MissingVar%отрендерится как%MissingVar%, а не пустой строкой и не ошибкой. Оставшиеся%...%в результате — QA-фейл.
Переменные сайта — множитель для множества сайтов
Именно переменные сайта позволяют общему шаблону обслуживать множество сайтов, не читаясь одинаково на всех доменах.
Абстрактный пресет сайта выглядит так:
#set %BrandTone% = {практичный|по делу|без воды}
#set %Industry% = SaaS-аналитика
#set %TopFeatures% = [<minsize=3;maxsize=4;sep=", ";lastsep=" и ">дашборды|алерты|аудит-логи|SSO|ролевой доступ]
#set %Audience% = {команды|продакт-лиды|операционщики}
Любой общий шаблон теперь может читать %BrandTone%, %TopFeatures% и т. д., и результат меняется на каждом сайте без единой правки в шаблоне.
Когда заводить переменную сайта
| Сигнал | Действие |
|---|---|
| Фраза встречается в двух и более шаблонах | Вынести в переменную сайта. |
| Факт меняется от сайта к сайту | Обязательно переменная сайта. |
| Список должен перемешиваться или отличаться по сайтам | Переменная сайта с permutation внутри. |
| Используется один раз в одном шаблоне | Обычно оставить inline. |
Runtime-переменные
Runtime-переменные приходят из контекста вызова: из самой статьи, текущего пользователя, системных часов. Они перебивают и переменные сайта, и локальные помощники шаблона при совпадении имени.
Типичные runtime-переменные (конкретные имена зависят от движка):
%year%— текущий год%lang%— код текущего языка%site_domain%— хост текущего сайта%brand_name%,%product_name%— бренд/продукт, о котором статья%article_topic%,%category%— метаданные уровня статьи
Из шаблона их не назначают. Достаточно читать.
Приоритет переменных
Если одно имя встречается на нескольких слоях — побеждает самый сильный. Стандартный порядок от сильнейшего к слабейшему:
- Runtime-переменные
- Переменные сайта
- Системные переменные
- Локальный
#set
Практическое следствие: #set %brand_name% = Demo внутри шаблона не делает ничего, если runtime передаёт %brand_name%. Runtime побеждает. Называйте локальных помощников так, чтобы не пересекаться с runtime.
Соглашения об именах
Внутренняя консистентность одного пресета важнее любого конкретного стиля. Разумный дефолт:
- Runtime-переменные: обычно
lowercase_snake_case. Они живут вне вашего контроля. - Переменные сайта:
PascalCaseдля обычных строк,PascalCaseС_суффиксомдля грамматических вариантов (см. гайд №4 про русские падежи). - Переменные-списки: во множественном числе (
%TopFeatures%,%SupportedLanguages%). - Локальные помощники: короткие и описательные —
%Lead%,%Closing%.
Составные переменные
Переменные сайта могут ссылаться друг на друга. Резолвер пресета подставляет межпеременные ссылки первыми, но оставляет вложенный spintax сырым, чтобы последующие reroll'ы продолжали работать:
#set %FoundedLine% = запущен в %FoundedYear%, база в %HQ%
#set %Pitch% = {быстрый|легковесный|self-hosted} %ProductCategory%
Составные переменные позволяют один раз скомпоновать повторяющиеся факты и переиспользовать их во всех шаблонах.
Ловушка повторного решения
Самый частый источник путаницы у новых авторов. Если переменная содержит сырой spintax, каждое её упоминание решается независимо.
#set %Tone% = {надёжный|проверенный}
%Tone% и %Tone%
Возможный результат:
Надёжный и проверенный
Не рассчитывайте, что %Tone% разрешится один раз и дальше просто повторится. Если нужно точное повторение — перепишите предложение так, чтобы переменная встретилась только один раз. Если нужны два разных прилагательных — заведите две переменные.
Необязательные фрагменты
Пустая ветка в перечислении — это необязательный фрагмент:
{|официальный }сайт
{быстрые|безопасные|} выплаты
Пробел ставьте внутрь необязательной ветки, когда фрагмент может исчезнуть — иначе получите двойные пробелы или слипшиеся слова. Для необязательного списка (permutation, которая может быть пустой) оборачивайте весь список:
{|[<minsize=2;maxsize=3;sep=", ";lastsep=" и ">Slack|Jira|Linear]}
Движок не может выбрать ноль элементов из permutation. Оборачивание — единственный способ сделать «списка совсем нет» возможным исходом.
Коллизии сепараторов
Частая ошибка рендера: список-переменная уже содержит «и», а окружающий текст добавляет ещё одно «и».
%Integrations% и другие инструменты
Если %Integrations% разрешается в Slack, Jira и Linear, итог выглядит так:
Slack, Jira и Linear и другие инструменты
Способы починить:
- поставить запятую:
%Integrations%, и другие инструменты; - перестроить:
{Помимо|Вместе с} %Integrations%, другие инструменты...; - убрать финальный союз и использовать двоеточие или тире.
Та же проблема — у permutation с lastsep=" и ", за которой идёт фиксированный текст, начинающийся с «и». Перед выкаткой посмотрите несколько сэмплов.
Переменные vs inline-spintax
| Использовать переменную | Использовать inline |
|---|---|
| Фраза повторяется между шаблонами | Одноразовый синоним внутри одного предложения |
| Факт меняется от сайта к сайту | Обычный синоним глагола или существительного |
| Список должен отличаться по тенантам | Маленький фиксированный одноразовый список |
| Грамматической форме нужно несколько написаний (см. русские падежи в гайде №4) | Слово используется только в одной грамматической позиции |
Общее правило: сначала выносите в переменные повторяющиеся грамматически чувствительные фразы, и только потом добавляйте маленькие inline-слоты синонимов. Переменная даёт одно место, где чинить ошибки. Inline разбрасывает их по тексту.
Типичные ошибки с переменными
| Не надо | Почему | Вместо этого |
|---|---|---|
| Хардкодить специфичный для сайта факт в общий шаблон | Все сайты выдают одинаковый текст, весь смысл multi-site теряется. | Вынести факт в переменную сайта. |
Через #set пытаться перекрыть runtime-переменную | Runtime всегда побеждает, ваш override молча ничего не делает. | Переименуйте помощника, чтобы не пересекаться с runtime. |
Предполагать, что %X% ... %X% повторяет одно слово | Каждое упоминание решается заново. Можете получить два разных слова. | Перепишите предложение или используйте две разные переменные. |
| Рассчитывать на ошибку при отсутствующей переменной | Она отрендерится буквально как %MissingVar%. | Добавьте preview-проход, который ловит оставшиеся %...%. |
| Склеивать список-переменную с ещё одним «и» | Выходит «A, B и C и другие вещи». | Используйте запятую или перестраивайте фразу. |
| Забывать про пробел в необязательном фрагменте | Получаете двойные пробелы или слипшиеся слова. | Пробел — внутри необязательной ветки. |
Чеклист проектирования переменных
- Каждый факт, специфичный для тенанта, живёт в переменной сайта, а не в общем шаблоне.
- Каждый факт, специфичный для статьи, живёт в runtime, а не в
#set. - Ни одно имя локального
#setне пересекается с именами runtime-переменных. - Имена переменных ASCII, без пробелов и дефисов.
- Каждая повторяющаяся переменная проверена на эффект reroll.
- Каждый необязательный фрагмент обрабатывает пробелы внутри ветки.
- Каждая список-переменная, за которой идёт союз, проверена на коллизию сепараторов.
- Пять сэмплов рендера не содержат оставшихся
%...%.
Структура готова? В следующем гайде — permutations на практике, где и живёт настоящая вариативность.