---
order: 3
section: guides
title: 内容模型
description: 文件、frontmatter、内置字段、重定向以及 scribe validate 的检查项。
noindex: false
canonicalPath: /zh-CN/docs/content-model
---
## 文件

一个文档等于该类型文件夹中的一个 `.mdx`（或 `.md`）文件：

```text
content/
  blog/
    hello-world.mdx        → slug 为 "hello-world"
    _redirects.json        → 该类型的重定向规则（可选）
  authors/
    jane.mdx               → slug 为 "jane"
```

- **文件名即为英语版本的 slug**。Slug 采用小写，并且使用连字符分隔（kebab-case）。
- 磁盘上只存在英语文件；其他语言版本的数据保存在 SQLite 数据库中。
- 如果文件名以 `_` 或大写字母开头（例如 `PUBLISHING.md`），系统会忽略它们，因此你可以把笔记跟内容文件放在一起。

## Frontmatter

Frontmatter 使用 YAML 编写，并根据该类型的 Zod schema 进行验证：

```mdx
---
title: "Hello, world"
description: "满足 schema 要求的长度足够的描述。"
author: jane
publishedAt: "2026-01-15"
updatedAt: "2026-02-01"
---

正文使用 MDX 格式。
```

Schema 验证遵循你的 Zod schema：对于普通的 `z.object`，未知的键会被静默丢弃；如果你希望字段名称拼写错误时能触发验证失败，请使用 `.strict()`。

## 内置的 frontmatter 字段

以下字段在**每个**内容类型中都可用，无需在 schema 中声明。这些字段会在你的 schema 运行前从 frontmatter 中提取，因此在 Zod schema 中声明它们没有任何作用：

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `publishedAt` | ISO 日期 | 发布日期。 |
| `updatedAt` | ISO 日期 | 最后一次重要更新的日期。默认与 `publishedAt` 相同。用于生成站点地图的 `lastModified`。 |
| `noindex` | 布尔值 | 从站点地图中排除该页面；你可以在页面中将其作为 robots meta 标签输出。 |
| `canonicalPath` | 字符串 | 手动覆盖规范（canonical）URL 路径。 |

多语言文档会从它们的英语源文档继承 `publishedAt`、`updatedAt`、`noindex` 和 `canonicalPath`；翻译人员无法更改这些字段。

每一个加载的文档都会附带 `slug`、`enSlug`（英语源文档的 slug，在英语文档中与 `slug` 相同）、`locale`、`frontmatter` 以及 `content` 属性。

## 无正文（Bodyless）类型

那些仅供引用的集合（例如 `model` 或 `category` 类型，其 schema 完全是结构化的数据）通常根本没有 MDX 正文。你可以在该类型上声明 `body: false` 来明确指出这一点：

```ts
defineContentType({
  id: "model",
  contentDir: "models",
  schema: modelSchema,
  body: false, // 条目仅包含 frontmatter
});
```

默认值为 `body: true`，所以这是完全向后兼容的。对于 `body: false` 的类型，包含除空白字符以外的任何正文内容都会导致验证错误。加载器会跳过 MDX 解析，并且静态导出不会输出正文。如果一个无正文类型同时具有**零个**可翻译字段，那么它将不会进入任何翻译流程（不会产生未翻译或内容已旧的干扰信息）；如果无正文类型仍包含可翻译字段，它将带着仅有 frontmatter 的有效负载保留在待办事项列表中。关于可翻译性的规则，请参见 [翻译](/docs/translation)。

## 超越 Frontmatter

MDX 正文不仅能用于编写普通的纯文本：

- [行内标记（Inline tokens）](/docs/inline-tokens) 可以将链接、资源 URL 以及不可翻译的字面量直接嵌入正文中，这些标记在读取时会根据具体语言进行解析。
- 通过 `field.asset()` 声明的 [资源（Assets）](/docs/assets) 会在磁盘上进行验证，并在加载时解析为公开 URL。

## 重定向：`_redirects.json`

在每个内容类型文件夹中，你可以添加一个可选的 `_redirects.json` 文件来声明 slug 的变更和已停用的文档。删除源 MDX 文件后，重定向规则依然生效；被翻译的源 slug 会自动通过 SQLite 展开。

```json
{
  "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` | 相同内容类型下的目标英文 slug。URL 根据该类型的 `path` 生成，并随语言本地化。 |
| 跨类型 | `toType` + `toSlug` | 另一个可路由内容类型（必须有 `path`）下的目标英文 slug。 |
| 任意位置 | `toUrl` | 基于站点根目录的相对路径，或外部的绝对 URL。不同语言环境的目标相同。 |

- `from`：仅限英文 slug。翻译的源 slug 会从 SQLite 解析。
- 可选字段 `permanent`（默认为 `true`）。

要停用或重命名文档：请在 `_redirects.json` 中添加相应的条目，删除（或重命名）源 MDX 文件，然后运行 `scribe validate` 并重新构建项目。重定向规则由 `buildAllContentRedirects()` 输出，供你的代理服务器或框架配置使用。

## 验证

```bash
scribe validate
```

针对每个英文文件执行以下检查：schema 解析、内置字段的格式、你编写的 `crossValidate` 钩子，以及**对正文进行 MDX 编译**。无论是英文原文还是存储的翻译内容，如果正文无法作为 MDX 成功解析，都会产生阻断构建的错误。

在整个项目级别，它还会检查以下内容：关系完整性（缺失必填关系 = 错误，缺失可选关系 = 警告）、`_redirects.json` 规则（目标是否有效、源是否重复、是否存在重定向链）、本地化 slug 后缀规则、[声明的资源字段](/docs/assets)（文件是否存在、`formats`、`maxKB`）、[行内正文标记](/docs/inline-tokens)（格式错误的 span、缺失关系、对不可路由类型的 `:href` 引用、缺失的 `vars` 键、缺失的资源文件）、声明为 `body: false` 但仍带有正文内容的类型、当设置了资源目录时缺失的图片资源，以及翻译存储库是否存在。

如果发现任何错误，退出状态码将非零。请在构建项目前运行它：

```json
{
  "scripts": {
    "build": "scribe validate && <your framework build>"
  }
}
```
