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 y con seguridad de tipos, con búsqueda integrada, soporte de internacionalización y una interfaz de usuario atractiva.

¿Qué es Lingo.dev CLI?

Lingo.dev es una plataforma de traducción impulsada por IA. La CLI de Lingo.dev lee archivos de origen, envía contenido traducible a modelos de lenguaje de gran tamaño 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 crear un proyecto con Fumadocs, configurar un pipeline de traducción y ver los resultados.

Paso 1. Configurar un proyecto de Fumadocs

  1. Crea una nueva aplicación de Fumadocs:

    npm create fumadocs-app
    
  2. Sigue las indicaciones para configurar el proyecto con los ajustes preferidos.

  3. 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 le indican a Fumadocs cómo manejar múltiples idiomas.

  1. 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",
    });
    
  2. 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";
    
    // See https://fumadocs.vercel.app/docs/headless/source-api for more info
    export const source = loader({
      // it assigns a URL to your pages
      baseUrl: "/docs",
      source: docs.toFumadocsSource(),
      i18n,
    });
    
  3. 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 ignoring `/_next/` and `/api/`
      // You may need to adjust it to ignore static assets in `/public` folder
      matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
    };
    

Paso 3. Actualizar la estructura de la aplicación para múltiples idiomas

  1. Crea un directorio de parámetro de idioma en la carpeta app/:

    mkdir app/[lang]
    
  2. Mueve tus páginas existentes al directorio del parámetro de idioma:

    • app/docs/app/[lang]/docs/
    • app/(home)/app/[lang]/(home)/
  3. 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

  1. Crea un archivo lib/layout.shared.tsx para las configuraciones de diseño compartidas:

    // lib/layout.shared.tsx
    import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared";
    import { i18n } from "@/lib/i18n";
    
    /**
     * Shared layout configurations
     *
     * you can customise layouts individually from:
     * Home Layout: app/(home)/layout.tsx
     * Docs Layout: 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
            </>
          ),
        },
        // see https://fumadocs.dev/docs/ui/navigation/links
        links: [],
      };
    }
    
  2. 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>
      );
    }
    
  3. 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 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 contenido para traducción

  1. Crea directorios específicos de idioma para el contenido:

    mkdir -p content/docs/en
    
  2. Mueve los archivos MDX existentes al directorio de inglés:

    • content/docs/index.mdxcontent/docs/en/index.mdx
    • content/docs/test.mdxcontent/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.10",
  "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. Garantiza 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). Deberás crear patrones include 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

  1. Regístrate para obtener una cuenta de Lingo.dev.

  2. Inicia sesión en Lingo.dev a través de la CLI:

    npx lingo.dev@latest login
    
  3. Ejecuta el pipeline de traducción:

    npx lingo.dev@latest run
    

    La CLI creará un directorio content/docs/es/ para almacenar el contenido traducido y un archivo i18n.lock para realizar un seguimiento de lo que se ha traducido (para evitar retraducciones innecesarias).

Paso 9. Ver la documentación traducida

  1. Inicia el servidor de desarrollo:

    npm run dev
    
  2. Navega a las siguientes URL: