Scribe

Модель данных

Файлы, frontmatter, встроенные поля, редиректы и проверки, которые выполняет scribe validate.

View as Markdown

Файлы

Один документ — это один файл .mdx (или .md) в папке типа контента:

content/
  blog/
    hello-world.mdx        → слаг "hello-world"
    _redirects.json        → правила редиректов для этого типа (опционально)
  authors/
    jane.mdx               → слаг "jane"
  • Имя файла является английским слагом. Слаги пишутся строчными буквами через дефис (kebab-case).
  • На диске хранятся только английские файлы. Локализованные версии живут в базе SQLite.
  • Файлы, имя которых начинается с _ или заглавной буквы (например, PUBLISHING.md), игнорируются. Вы можете хранить в них заметки прямо рядом с контентом.

Frontmatter

Frontmatter пишется на YAML и проверяется на соответствие схеме Zod вашего типа контента:

---
title: "Привет, мир"
description: "Достаточно длинное описание для схемы."
author: jane
publishedAt: "2026-01-15"
updatedAt: "2026-02-01"
---

Основной текст в формате MDX.

Валидация frontmatter подчиняется вашей схеме Zod: при обычном z.object неизвестные ключи просто отбрасываются. Если хотите, чтобы опечатки в названиях полей вызывали ошибку, используйте .strict().

Встроенные поля frontmatter

Эти поля доступны для любого типа контента, и их не нужно объявлять в схеме. Они извлекаются из frontmatter до запуска вашей схемы, поэтому добавлять их в схему Zod бессмысленно:

ПолеТипОписание
publishedAtДата ISOДата публикации.
updatedAtДата ISOДата последнего значимого обновления. По умолчанию совпадает с publishedAt. Используется для lastModified в sitemap.
noindexbooleanИсключает документ из sitemap. Выведите это значение как метатег robots на ваших страницах.
canonicalPathstringРучное переопределение канонического URL-пути.

Локализованные документы наследуют publishedAt, updatedAt, noindex и canonicalPath от английского оригинала. Переводчики не могут их менять.

Каждый загруженный документ также содержит свойства slug, enSlug (слаг английского оригинала, который совпадает с slug для английских документов), locale, frontmatter и content.

Типы контента без тела документа

Справочные коллекции (типы вроде model или category, схема которых носит исключительно структурный характер) часто вообще не имеют MDX-тела. Чтобы явно указать это, добавьте body: false в настройках типа:

defineContentType({
  id: "model",
  contentDir: "models",
  schema: modelSchema,
  body: false, // записи содержат только frontmatter
});

По умолчанию используется body: true, что обеспечивает полную обратную совместимость. Для типа с body: false наличие любого текста кроме пробелов в теле документа вызовет ошибку валидации, загрузчик пропустит парсинг MDX, а статический экспорт не будет генерировать тело. Тип без тела документа, у которого нет переводимых полей, вообще исключается из процесса перевода (никакого лишнего шума о пропущенных или устаревших переводах). Если же у типа с body: false есть хотя бы одно переводимое поле, он остается в списке задач с данными только из frontmatter. Правила переводимости описаны в разделе Перевод.

Больше, чем frontmatter

MDX позволяет делать больше, чем просто писать текст:

  • Встроенные токены внедряют ссылки, URL-адреса ресурсов и непереводимые строковые литералы прямо в текст, разрешая их для каждой локали при чтении.
  • Ресурсы, объявленные через field.asset(), проверяются на диске и преобразуются в публичные URL-адреса во время загрузки.

Редиректы: _redirects.json

В папку любого типа контента можно добавить файл _redirects.json, чтобы объявить правила изменения слагов или перенаправления для удаленных документов. Редиректы продолжают работать даже после удаления исходного MDX-файла. Слаги переведенных версий автоматически извлекаются из SQLite.

{
  "redirects": [
    { "from": "hello-world", "toSlug": "hello-scribe" },
    { "from": ["old-a", "old-b"], "toSlug": "hello-scribe" },
    { "from": "moved-post", "toType": "glossary", "toSlug": "virtual-try-on" },
    { "from": "retired-page", "toUrl": "/pricing" },
    { "from": "retired-ext", "toUrl": "https://example.com/app" }
  ]
}

Существует три типа редиректов (для каждой записи указывается ровно одна цель):

ТипПоляОписание
Тот же типtoSlugЦелевой английский слаг в том же типе контента. URL формируется на основе path этого типа и локализуется для каждого языка.
Другой типtoType + toSlugЦелевой английский слаг в другом типе контента с маршрутизацией (должен иметь path).
Произвольный URLtoUrlОтносительный путь от корня на том же сайте или абсолютный внешний URL, одинаковый для всех локалей.
  • from: только английские слаги. Слаги переведенных исходников извлекаются из SQLite.
  • Необязательный параметр permanent (по умолчанию true).

Чтобы удалить или переименовать документ, добавьте запись в _redirects.json, удалите (или переименуйте) исходный MDX-файл, затем запустите scribe validate и выполните сборку. Правила редиректов генерируются функцией buildAllContentRedirects() для конфигурации вашего прокси-сервера или фреймворка.

Валидация

scribe validate

Проверяет каждый английский файл: соответствие схеме, формат встроенных полей, ваш хук crossValidate и компиляцию MDX. Если тело не парсится как MDX, сборка блокируется с ошибкой — это касается как английских оригиналов, так и сохраненных переводов.

В масштабе всего проекта также проверяются: целостность связей (отсутствие обязательной связи — ошибка, отсутствие необязательной связи — предупреждение), правила в _redirects.json (корректные цели, отсутствие дублирующихся источников или цепочек редиректов), правила суффиксов для локализованных слагов, объявленные поля ресурсов (наличие файлов, formats, maxKB), встроенные токены (некорректные теги span, отсутствующие связи, :href на типы без маршрутизации, пропущенные ключи vars, отсутствующие файлы ресурсов), типы с body: false, которые по-прежнему содержат текст, отсутствие изображений при заданной директории ресурсов и наличие базы переводов.

Код возврата не равен нулю, если найдена хотя бы одна ошибка. Запускайте эту команду перед сборкой:

{
  "scripts": {
    "build": "scribe validate && <команда сборки вашего фреймворка>"
  }
}
Модель данных · Scribe