Fumadocs
Traducción con IA para Fumadocs con Lingo.dev CLI
¿Qué es Fumadocs?
Fumadocs es un framework de documentación de código abierto. Proporciona un sitio de documentación rápido, con seguridad de tipos, búsqueda integrada, soporte para internacionalización y una interfaz de usuario atractiva.
¿Qué es Lingo.dev CLI?
Lingo.dev es una plataforma de traducción impulsada por IA. El CLI de Lingo.dev lee archivos fuente, envía contenido traducible a modelos de lenguaje de gran escala y escribe los archivos traducidos de vuelta a tu proyecto.
Acerca de esta guía
Esta guía explica cómo configurar Lingo.dev CLI en un sitio de documentación de Fumadocs. Aprenderás cómo estructurar un proyecto con Fumadocs, configurar un pipeline de traducción y ver los resultados.
Paso 1. Configurar un proyecto de Fumadocs
-
Crea una nueva aplicación de Fumadocs:
npm create fumadocs-app
-
Sigue las indicaciones para configurar el proyecto con los ajustes preferidos.
-
Navega al directorio del proyecto:
cd <project-name>
Paso 2. Configurar el soporte de internacionalización
Fumadocs necesita saber qué idiomas soportará tu documentación. Crearás archivos de configuración que indiquen a Fumadocs cómo manejar múltiples idiomas.
-
Crea un archivo
lib/i18n.ts
para definir los idiomas soportados:import { defineI18n } from 'fumadocs-core/i18n'; export const i18n = defineI18n({ defaultLanguage: 'en', languages: ['en', 'es'], parser: "dir", });
-
Actualiza el archivo
lib/source.ts
para usar la configuración de i18n:import { docs } from "@/.source"; import { loader } from "fumadocs-core/source"; import { i18n } from "@/lib/i18n"; // Ver https://fumadocs.vercel.app/docs/headless/source-api para más información export const source = loader({ // asigna una URL a tus páginas baseUrl: "/docs", source: docs.toFumadocsSource(), i18n, });
-
Crea un middleware para detectar y redirigir a los usuarios según su preferencia de idioma:
// middleware.ts import { createI18nMiddleware } from 'fumadocs-core/i18n/middleware'; import { i18n } from '@/lib/i18n'; export default createI18nMiddleware(i18n); export const config = { // Matcher que ignora `/_next/` y `/api/` // Es posible que necesites ajustarlo para ignorar activos estáticos en la carpeta `/public` matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'], };
Paso 3. Actualizar la estructura de la aplicación para múltiples idiomas
-
Crea un directorio de parámetros de idioma en la carpeta
app/
:mkdir app/[lang]
-
Mueve tus páginas existentes al directorio de parámetros de idioma:
app/docs/
→app/[lang]/docs/
app/(home)/
→app/[lang]/(home)/
-
Crea un archivo
app/[lang]/layout.tsx
para envolver todas tus páginas específicas de idioma:import { RootProvider } from "fumadocs-ui/provider"; import { defineI18nUI } from "fumadocs-ui/i18n"; import { i18n } from "@/lib/i18n"; const { provider } = defineI18nUI(i18n, { translations: { en: { displayName: "English", }, es: { displayName: "Español", }, }, }); export default async function RootLayout({ params, children, }: LayoutProps<"/[lang]">) { const lang = (await params).lang; return ( <html lang={lang}> <body> <RootProvider i18n={provider(lang)}>{children}</RootProvider> </body> </html> ); }
Paso 4. Crear opciones de diseño compartidas
-
Crea un archivo
lib/layout.shared.tsx
para configuraciones de diseño compartidas:// lib/layout.shared.tsx import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared"; import { i18n } from "@/lib/i18n"; /** * Configuraciones de diseño compartidas * * puedes personalizar los diseños individualmente desde: * Diseño de inicio: app/(home)/layout.tsx * Diseño de documentación: app/docs/layout.tsx */ export function baseOptions(locale: string): BaseLayoutProps { return { i18n, nav: { title: ( <> <svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" aria-label="Logo" > <circle cx={12} cy={12} r={12} fill="currentColor" /> </svg> My App </> ), }, // ver https://fumadocs.dev/docs/ui/navigation/links links: [], }; }
-
Actualiza el archivo
app/[lang]/docs/layout.tsx
para usar las opciones compartidas:// app/[lang]/docs/layout.tsx import type { ReactNode } from "react"; import { source } from "@/lib/source"; import { DocsLayout } from "fumadocs-ui/layouts/docs"; import { baseOptions } from "@/lib/layout.shared"; export default async function Layout({ params, children, }: LayoutProps<"/[lang]/docs">) { const { lang } = await params; return ( <DocsLayout {...baseOptions(lang)} tree={source.pageTree[lang]}> {children} </DocsLayout> ); }
-
Actualiza el archivo
app/[lang]/(home)/layout.tsx
para usar las opciones compartidas:// app/[lang]/(home)/layout.tsx import { HomeLayout } from "fumadocs-ui/layouts/home"; import { baseOptions } from "@/lib/layout.shared"; export default async function Layout({ children, params, }: LayoutProps<"/[lang]">) { const { lang } = await params; return <HomeLayout {...baseOptions(lang)}>{children}</HomeLayout>; }
Paso 5. Actualizar los componentes de página
Actualiza los componentes de página (por ejemplo, app/[lang]/docs/[[...slug]]/page.tsx
) para manejar el parámetro de idioma:
import { source } from "@/lib/source";
import {
DocsBody,
DocsDescription,
DocsPage,
DocsTitle,
} from "fumadocs-ui/page";
import type { Metadata } from "next";
import { notFound } from "next/navigation";
import { createRelativeLink } from "fumadocs-ui/mdx";
import { getMDXComponents } from "@/mdx-components";
export default async function Page(
props: PageProps<"/[lang]/docs/[[...slug]]">,
) {
const params = await props.params;
const page = source.getPage(params.slug, params.lang);
if (!page) notFound();
const MDXContent = page.data.body;
return (
<DocsPage toc={page.data.toc} full={page.data.full}>
<DocsTitle>{page.data.title}</DocsTitle>
<DocsDescription>{page.data.description}</DocsDescription>
<DocsBody>
<MDXContent
components={getMDXComponents({
// this allows you to link to other pages with relative file paths
a: createRelativeLink(source, page),
})}
/>
</DocsBody>
</DocsPage>
);
}
export async function generateStaticParams() {
return source.generateParams();
}
export async function generateMetadata(
props: PageProps<"/[lang]/docs/[[...slug]]">,
): Promise<Metadata> {
const params = await props.params;
const page = source.getPage(params.slug, params.lang);
if (!page) notFound();
return {
title: page.data.title,
description: page.data.description,
};
}
Paso 6. Organizar el contenido para traducción
-
Crea directorios específicos para cada idioma para el contenido:
mkdir -p content/docs/en
-
Mueve los archivos MDX existentes al directorio de inglés:
content/docs/index.mdx
→content/docs/en/index.mdx
content/docs/test.mdx
→content/docs/en/test.mdx
Paso 7. Configurar la CLI
En la raíz del proyecto, crea un archivo i18n.json
:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": 1.8,
"locale": {
"source": "en",
"targets": ["es"]
},
"buckets": {
"mdx": {
"include": ["content/docs/[locale]/*.mdx"]
}
}
}
Este archivo define:
- los archivos que la CLI de Lingo.dev debe traducir
- los idiomas entre los que traducir
En este caso, la configuración traduce archivos MDX del inglés al español.
Es importante tener en cuenta que:
[locale]
es un marcador de posición que se reemplaza en tiempo de ejecución. Asegura que el contenido se lea desde una ubicación (por ejemplo,src/content/docs/en/index.mdx
) y se escriba en una ubicación diferente (por ejemplo,src/content/docs/es/index.mdx
).- La CLI de Lingo.dev no admite patrones glob recursivos (por ejemplo,
**/*.mdx
). Necesitarás crear patronesinclude
adicionales para traducir archivos que existan dentro de directorios anidados.
Para obtener más información, consulta configuración de i18n.json.
Paso 8. Traducir el contenido
-
Inicia sesión en Lingo.dev a través de la CLI:
npx lingo.dev@latest login
-
Ejecuta el proceso de traducción:
npx lingo.dev@latest run
La CLI creará un directorio
content/docs/es/
para almacenar el contenido traducido y un archivoi18n.lock
para realizar un seguimiento de lo que se ha traducido (para evitar retraducciones innecesarias).
Paso 9. Visualizar la documentación traducida
-
Inicia el servidor de desarrollo:
npm run dev
-
Navega a las siguientes URLs:
- http://localhost:3000/en/docs para el contenido en inglés
- http://localhost:3000/es/docs para el contenido en español