Configuración
Todas las opciones de scribe.config.ts: ajustes del proyecto, tipos de contenido, marcadores de campo y enrutamiento por idioma.
View as MarkdownTodo se centraliza en un único archivo, scribe.config.ts, que exporta defineConfig({...}). Tanto el entorno de ejecución (createScribe) como la CLI (que detecta scribe.config.ts en el directorio de trabajo) leen este mismo archivo.
Opciones del proyecto
export default defineConfig({
rootDir: ".",
contentDir: "content", // default
store: ".scribe/store.sqlite", // default
assetsDir: "public", // optional
locales: ["en", "fr", "de"],
defaultLocale: "en", // default
localeRouting: { strategy: "path-prefix", prefixDefaultLocale: false },
localeFallbacks: true, // default
localePresets: { active: ["fr"] },
translate: { /* see the translation page */ },
types: [ /* defineContentType(...) */ ],
});
| Opción | Predeterminado | Descripción |
|---|---|---|
rootDir | Requerido | Directorio raíz del proyecto. Déjalo como ruta relativa (normalmente "."): la CLI lo resuelve respecto a la carpeta del archivo de configuración y createScribe respecto a process.cwd(). No lo construyas a partir de import.meta.url: los empaquetadores insertan esa ruta durante la compilación, lo que causa errores en entornos sin servidor como Vercel. |
contentDir | "content" | Directorio que contiene una carpeta por cada tipo de contenido. |
store | ".scribe/store.sqlite" | Almacén de traducciones SQLite. Añádelo a tu repositorio de control de versiones; no incluyas .scribe/ en tu gitignore. |
assetsDir | Opcional | Raíz de los archivos estáticos (por ejemplo, "public"). Al configurarlo, scribe validate avisa si hay rutas de imágenes en el encabezado o en los cuerpos que no existen en el disco. |
locales | Requerido | Todos los idiomas, incluido el predeterminado. |
defaultLocale | "en" | Idioma de origen canónico. Debe aparecer obligatoriamente en locales. |
localeRouting | path-prefix, unprefixed default | Define cómo aparecen los marcadores de idioma en las URL generadas. path-prefix añade el idioma al principio (omitiendo el predeterminado a menos que prefixDefaultLocale sea true). search-param añade ?param=locale para los idiomas no predeterminados. |
localeFallbacks | true | Genera cadenas de respaldo a partir de las etiquetas de idioma. Si una variante regional no tiene traducción para un documento, se muestra la traducción más cercana en el idioma base (por ejemplo, pt-BR recurre a pt) antes de pasar al idioma predeterminado. Configúralo en false para desactivarlo. Consulta la sección Cadenas de respaldo de idioma. |
localePresets | Opcional | Grupos de idiomas con nombre para usar con scribe translate --preset name. |
translate | Opcional | Valores predeterminados de traducción para todo el proyecto (traducción). |
types | Requerido | Definiciones de los tipos de contenido. |
Las configuraciones se validan desde el primer momento: un defaultLocale desconocido, identificadores de tipo duplicados o una plantilla de path mal formada provocarán un error inmediato con un mensaje claro.
Opciones de tipo de contenido
defineContentType({
id: "blog",
schema: blogSchema,
path: "/blog/{slug}",
contentDir: "blog", // default: the id
slugStrategy: "localized", // default: "fixed"
indexFallback: "en", // default: "en" if path is set, else "none"
orderBy: "-publishedAt", // default: "slug"
label: "Blog", // default: capitalized id (studio UI only)
crossValidate: (data, ctx) => [],
translate: { /* per-type overrides */ },
})
| Opción | Descripción |
|---|---|
id | Identificador único. Se convierte en el método de acceso tipado (scribe.blog) y en el contentDir predeterminado. |
schema | Esquema de objetos Zod para el encabezado (frontmatter), con sus respectivos marcadores de campo (ver más abajo). |
path | Plantilla de URL con exactamente un {slug} (por ejemplo, /blog/{slug}). Omítela para tipos que sean solo de referencia (autores, categorías) y que no tengan páginas propias. |
contentDir | Carpeta dentro del contentDir del proyecto que alberga los archivos .mdx de este tipo. |
slugStrategy | "fixed": todos los idiomas usan el slug en inglés. "localized": el traductor genera un slug específico para cada idioma (/es/blog/hola-mundo). |
indexFallback | Lo que devuelve resolve() cuando un idioma no tiene traducción: "en" sirve el documento en inglés (con actualLocale: "en"), mientras que "none" no devuelve nada. |
orderBy | Orden predeterminado para list(): "slug", "publishedAt", "-publishedAt", "updatedAt", "-updatedAt", o un comparador (a, b) => number sobre documentos con tipado completo. |
crossValidate | Validación adicional ejecutada por scribe validate, que recibe el encabezado analizado (tipado). Devuelve { field, message, level }[]. |
translate | Indicaciones, reglas o modelos de traducción específicos para cada tipo (traducción). |
Marcadores de campo
Cada campo del esquema pertenece a uno de tres tipos. Los campos sin marcar son estructurales por defecto.
import { field } from "scribe-cms";
const schema = z.object({
// Se envía al traductor y se guarda por idioma:
title: field.translatable(z.string().min(1)),
// Solo en inglés; se copia del documento en inglés a todos los idiomas:
heroImage: field.structural(z.string().optional()),
// Referencia(s) del slug en inglés a otro tipo de contenido:
author: field.relation("author"),
relatedPosts: field.relation("blog", { multiple: true, max: 4, optional: true }),
});
Los marcadores traducibles también funcionan en campos anidados dentro de matrices o arreglos sencillos (por ejemplo, sections.*.title). Simplemente asegúrate de no envolver el arreglo contenedor en un field.structural o todo el subárbol quedará únicamente en inglés.
field.relation(typeId, options?)
| Opción | Predeterminado | Descripción |
|---|---|---|
multiple | false | El campo es un arreglo de slugs. |
optional | false | Se puede omitir el campo. related() devolverá null (si es único) o ignorará los elementos que falten (si es múltiple). |
min / max | Opcional | Límites en la cantidad de elementos (solo para multiple: true). |
Las restricciones van dentro del objeto de opciones, no en los métodos encadenados de Zod. Encadenar métodos (.max(8), .optional()) clona el esquema y eliminaría los metadatos de la relación.
Las relaciones siempre guardan slugs en inglés y se verifican mediante scribe validate (una relación requerida huérfana bloquea la compilación con un error, mientras que una opcional solo genera una advertencia). Además, se resuelven en tiempo de ejecución con related(). Consulta la API de tiempo de ejecución.
Cadenas de respaldo de idioma
Por defecto, si un idioma regional no tiene traducción para un documento, se muestra su idioma base antes de pasar al idioma predeterminado. Cada idioma prueba prefijos cada vez más cortos de su propia etiqueta que también estén presentes en locales. Así, fr-CA recurre a fr, y zh-Hant-TW prueba primero con zh-Hant y luego con zh. Configúralo en localeFallbacks: false para desactivarlo. El idioma predeterminado nunca forma parte de esta cadena; sigue siendo el último recurso absoluto y se rige por el indexFallback del tipo de contenido.
Estas cadenas de respaldo se aplican a resolve() (el idioma servido se indica en actualLocale y las redirecciones de slug usan el slug del idioma de respaldo) y a staticParams() (los slugs pre-renderizados coinciden con lo que sirve resolve()). De forma intencionada, no se aplican a get(), list(), translation(), alternates() ni al mapa del sitio (sitemap), que requieren coincidencias exactas.
Tipos de cliente con tipado
Para los alias de tipo en el lado de la aplicación, puedes derivar todo desde la configuración:
import type { ScribeClient, ScribeDocs } from "scribe-cms/runtime";
import config from "./scribe.config";
type MyScribe = ScribeClient<typeof config>;
type BlogDoc = ScribeDocs<typeof config>["blog"];