配置
scribe.config.ts 中的所有选项:项目设置、内容类型、字段标记与多语言路由。
View as Markdown所有配置都集中在一个文件里:scribe.config.ts,并通过 defineConfig({...}) 导出。无论是在运行时(通过 createScribe)还是在 CLI 环境中(自动在工作目录中查找 scribe.config.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 可禁用此功能。详见多语言降级链。 |
localePresets | — | 为 scribe translate --preset name 命令定义的语言分组预设。 |
translate | — | 项目级的全局翻译默认配置(翻译)。 |
types | — (必填) | 内容类型定义。 |
配置会在第一时间进行校验:如果出现未知的 defaultLocale、重复的类型 id 或是格式错误的 path 模板,系统会立刻抛出异常并给出清晰的提示信息。
内容类型选项
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 | 特定类型的翻译提示、规则或模型配置(翻译)。 |
字段标记
每一个模式(schema)字段必属于以下三种类型之一。未标注的字段默认视为**结构化(structural)**字段。
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。
多语言降级链
默认情况下,当某篇文档缺少特定区域版本的翻译时,系统会先尝试提供它的基础语言,然后再回退到默认语言。每个区域设置都会在 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),则刻意不应用降级策略,而是坚持精确匹配规则。
强类型客户端类型
在应用端使用类型别名时,您可以直接基于配置推导所有内容:
import type { ScribeClient, ScribeDocs } from "scribe-cms/runtime";
import config from "./scribe.config";
type MyScribe = ScribeClient<typeof config>;
type BlogDoc = ScribeDocs<typeof config>["blog"];