---
order: 2
section: guides
title: 配置
description: scribe.config.ts 中的所有选项：项目设置、内容类型、字段标记与多语言路由。
noindex: false
canonicalPath: /zh-CN/docs/configuration
---
所有配置都集中在一个文件里：`scribe.config.ts`，并通过 `defineConfig({...})` 导出。无论是在运行时（通过 `createScribe`）还是在 CLI 环境中（自动在工作目录中查找 `scribe.config.ts`），读取的都是这份相同的配置文件。

## 项目选项

```ts
export default defineConfig({
  rootDir: ".",
  contentDir: "content",             // 默认值
  store: ".scribe/store.sqlite",     // 默认值
  assetsDir: "public",               // 选填
  locales: ["en", "fr", "de"],
  defaultLocale: "en",               // 默认值
  localeRouting: { strategy: "path-prefix", prefixDefaultLocale: false },
  localeFallbacks: true,             // 默认值
  localePresets: { active: ["fr"] },
  translate: { /* 详见翻译页面 */ },
  types: [ /* defineContentType(...) */ ],
});
```

| 选项 | 默认值 | 说明 |
| --- | --- | --- |
| `rootDir` | — (必填) | 项目根目录。请保持相对路径（通常是 `"."`）：CLI 会相对于配置文件的所在目录进行解析，而 `createScribe` 则相对于 `process.cwd()` 解析。不要通过 `import.meta.url` 动态构建：打包工具会在构建时将该路径内联，这会导致在 Vercel 等 Serverless 托管平台上运行失败。 |
| `contentDir` | `"content"` | 存放内容的目录，每种内容类型对应一个子文件夹。 |
| `store` | `".scribe/store.sqlite"` | SQLite 翻译存储库。**请务必将其提交到代码库，不要在 `.gitignore` 中忽略 `.scribe/`。** |
| `assetsDir` | — | 静态资产的根目录（例如 `"public"`）。设置后，若前置数据或正文中引用的图片路径在磁盘上不存在，`scribe validate` 将发出警告。 |
| `locales` | — (必填) | 包含默认语言在内的所有语言区域（Locale）。 |
| `defaultLocale` | `"en"` | 权威源语言。必须包含在 `locales` 列表中。 |
| `localeRouting` | path-prefix，默认语言无前缀 | 语言标记在生成 URL 中的呈现方式。`path-prefix` 会在路径前添加语言前缀（除非开启了 `prefixDefaultLocale`，否则默认语言会省略前缀）。`search-param` 会通过 `?param=locale` 的形式为非默认语言追加查询参数。 |
| `localeFallbacks` | `true` | 根据语言标签推导降级链：如果某个文档没有特定区域变体（如 `pt-BR`）的翻译，系统会在回退到默认语言之前，先提供最接近的基础语言版本（如 `pt`）。设置为 `false` 可禁用此功能。详见[多语言降级链](#locale-fallback-chains)。 |
| `localePresets` | — | 为 `scribe translate --preset name` 命令定义的语言分组预设。 |
| `translate` | — | 项目级的全局翻译默认配置（[翻译](/docs/translation)）。 |
| `types` | — (必填) | 内容类型定义。 |

配置会在第一时间进行校验：如果出现未知的 `defaultLocale`、重复的类型 id 或是格式错误的 `path` 模板，系统会立刻抛出异常并给出清晰的提示信息。

## 内容类型选项

```ts
defineContentType({
  id: "blog",
  schema: blogSchema,
  path: "/blog/{slug}",
  contentDir: "blog",          // 默认值：同 id
  slugStrategy: "localized",   // 默认值："fixed"
  indexFallback: "en",         // 默认值：若设置了 path 则为 "en"，否则为 "none"
  orderBy: "-publishedAt",     // 默认值："slug"
  label: "Blog",               // 默认值：首字母大写的 id（仅用于 Studio UI）
  crossValidate: (data, ctx) => [],
  translate: { /* 针对该类型的覆盖配置 */ },
})
```

| 选项 | 说明 |
| --- | --- |
| `id` | 唯一标识符。将作为类型化访问器（如 `scribe.blog`）及默认的 `contentDir`。 |
| `schema` | 前置数据（Frontmatter）的 Zod 对象模式，包含下文提到的字段标记。 |
| `path` | 包含且仅包含一个 `{slug}` 的 URL 模板（例如 `/blog/{slug}`）。对于没有独立页面、**仅供引用**的内容类型（如作者、分类），请省略此项。 |
| `contentDir` | 位于项目 `contentDir` 下的子文件夹，存放该类型的 `.mdx` 文件。 |
| `slugStrategy` | `"fixed"` 表示所有语言都使用英文 slug。`"localized"` 表示翻译人员会为不同语言生成专属的 slug（例如 `/fr/blog/bonjour-le-monde`）。 |
| `indexFallback` | 当某种语言缺乏对应的翻译时，`resolve()` 的返回策略：`"en"` 会提供英文文档（并标注 `actualLocale: "en"`），`"none"` 则不返回任何内容。 |
| `orderBy` | `list()` 的默认排序方式：可选用 `"slug"`、`"publishedAt"`、`"-publishedAt"`、`"updatedAt"`、`"-updatedAt"`，或者传入一个对强类型文档进行比较的 `(a, b) => number` 函数。 |
| `crossValidate` | 由 `scribe validate` 执行的额外验证规则，接收解析后的强类型前置数据。需返回 `{ field, message, level }[]`。 |
| `translate` | 特定类型的翻译提示、规则或模型配置（[翻译](/docs/translation)）。 |

## 字段标记

每一个模式（schema）字段必属于以下三种类型之一。未标注的字段默认视为**结构化（structural）**字段。

```ts
import { field } from "scribe-cms";

const schema = z.object({
  // 发送给翻译人员，按语言区域分别存储：
  title: field.translatable(z.string().min(1)),

  // 仅限英文，从英文文档直接复制到所有其他语言版本中：
  heroImage: field.structural(z.string().optional()),

  // 指向其他内容类型的英文 slug 引用：
  author: field.relation("author"),
  relatedPosts: field.relation("blog", { multiple: true, max: 4, optional: true }),
});
```

可翻译标记同样适用于普通数组或对象内嵌套的字段（例如 `sections.*.title`）。需要注意的是，千万不要用 `field.structural` 去包裹外层数组，否则整个子树都会变成仅限英文。

### `field.relation(typeId, options?)`

| 选项 | 默认值 | 说明 |
| --- | --- | --- |
| `multiple` | `false` | 该字段包含的是 slug 数组。 |
| `optional` | `false` | 该字段可省略。省略时，单值引用的 `related()` 会返回 `null`，而多值引用会跳过缺失的项目。 |
| `min` / `max` | — | 限制项目数量（仅在 `multiple: true` 时有效）。 |

所有的约束条件都应当写在 options 对象里，**不要**使用 Zod 的链式调用。诸如 `.max(8)` 或 `.optional()` 的链式调用会克隆模式结构，从而导致关系元数据丢失。

关系字段始终存储**英文 slug**。`scribe validate` 会对它们进行检查（如果是必填项出现悬空引用，将引发阻断构建的错误，而选填项则会触发警告）。在运行时可以通过 `related()` 解引用，具体请参阅 [运行时 API](/docs/runtime-api)。

## 多语言降级链

默认情况下，当某篇文档缺少特定区域版本的翻译时，系统会先尝试提供它的基础语言，然后再回退到默认语言。每个区域设置都会在 `locales` 列表中依次寻找自身语言标签较短的前缀，例如 `fr-CA` 会降级到 `fr`，而 `zh-Hant-TW` 则会先找 `zh-Hant`，再找 `zh`。若要禁用该行为，可设置 `localeFallbacks: false`。默认语言永远不会出现在降级链中，它始终是最终的兜底选项，并受类型的 `indexFallback` 设置控制。

降级策略适用于 `resolve()`（系统会在 `actualLocale` 中说明实际采用的语言，且 slug 重定向也会使用降级语言的 slug）以及 `staticParams()`（预渲染的 slug 与 `resolve()` 提供的结果保持一致）。而对于 `get()`、`list()`、`translation()`、`alternates()` 或是站点地图（sitemap），则刻意**不**应用降级策略，而是坚持精确匹配规则。

## 强类型客户端类型

在应用端使用类型别名时，您可以直接基于配置推导所有内容：

```ts
import type { ScribeClient, ScribeDocs } from "scribe-cms/runtime";
import config from "./scribe.config";

type MyScribe = ScribeClient<typeof config>;
type BlogDoc = ScribeDocs<typeof config>["blog"];
```
