Fumadocs
AI-перевод для Fumadocs с помощью Lingo.dev CLI
Что такое Fumadocs?
Fumadocs — это open-source фреймворк для документации. Он обеспечивает быструю, типобезопасную документацию с встроенным поиском, поддержкой интернационализации и стильным интерфейсом.
Что такое Lingo.dev CLI?
Lingo.dev — это платформа для перевода на базе искусственного интеллекта. Lingo.dev CLI читает исходные файлы, отправляет переводимый контент в большие языковые модели и записывает переведённые файлы обратно в ваш проект.
О данном гайде
В этом гайде рассказывается, как настроить Lingo.dev CLI на сайте документации Fumadocs. Вы узнаете, как создать проект на Fumadocs, настроить pipeline для перевода и посмотреть результат.
Шаг 1. Создайте проект Fumadocs
-
Создайте новое приложение на Fumadocs:
npm create fumadocs-app -
Следуйте подсказкам, чтобы настроить проект с нужными параметрами.
-
Перейдите в директорию проекта:
cd <project-name>
Шаг 2. Настройте поддержку интернационализации
Fumadocs нужно знать, на каких языках будет ваша документация. Для этого создайте конфигурационные файлы, которые подскажут Fumadocs, как работать с несколькими языками.
-
Создайте файл
lib/i18n.ts, чтобы указать поддерживаемые языки:import { defineI18n } from "fumadocs-core/i18n"; export const i18n = defineI18n({ defaultLanguage: "en", languages: ["en", "es"], parser: "dir", }); -
Обновите файл
lib/source.ts, чтобы использовать настройки 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, }); -
Создайте middleware для определения и перенаправления пользователей в зависимости от их языковых предпочтений:
// 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).*)"], };
Шаг 3. Обновите структуру приложения для поддержки нескольких языков
-
Создайте директорию для языкового параметра в папке
app/:mkdir app/[lang] -
Переместите ваши существующие страницы в директорию с языковым параметром:
app/docs/→app/[lang]/docs/app/(home)/→app/[lang]/(home)/
-
Создайте файл
app/[lang]/layout.tsx, чтобы обернуть все ваши страницы для конкретного языка: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> ); }
Шаг 4. Создайте общие параметры макета
-
Создайте файл
lib/layout.shared.tsxдля общих настроек макета:// 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: [], }; } -
Обновите файл
app/[lang]/docs/layout.tsx, чтобы использовать общие параметры:// 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> ); } -
Обновите файл
app/[lang]/(home)/layout.tsx, чтобы использовать общие параметры:// 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>; }
Шаг 5. Обновите компоненты страниц
Обновите компоненты страниц (например, app/[lang]/docs/[[...slug]]/page.tsx), чтобы они поддерживали языковой параметр:
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,
};
}
Шаг 6. Организуйте контент для перевода
-
Создайте отдельные директории для контента на каждом языке:
mkdir -p content/docs/en -
Переместите существующие MDX-файлы в директорию для английского языка:
content/docs/index.mdx→content/docs/en/index.mdxcontent/docs/test.mdx→content/docs/en/test.mdx
Шаг 7. Настройте CLI
В корне проекта создайте файл i18n.json:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.10",
"locale": {
"source": "en",
"targets": ["es"]
},
"buckets": {
"mdx": {
"include": ["content/docs/[locale]/*.mdx"]
}
}
}
Этот файл определяет:
- файлы, которые должен переводить Lingo.dev CLI
- языки, между которыми будет происходить перевод
В этом случае конфигурация переводит MDX-файлы с английского на испанский.
Важно отметить:
[locale]— это плейсхолдер, который заменяется во время выполнения. Он гарантирует, что контент читается из одного места (например,src/content/docs/en/index.mdx) и записывается в другое (например,src/content/docs/es/index.mdx).- Lingo.dev CLI не поддерживает рекурсивные glob-шаблоны (например,
**/*.mdx). Нужно создать дополнительные шаблоныinclude, чтобы переводить файлы во вложенных директориях.
Подробнее см. в разделе Конфигурация i18n.json.
Шаг 8. Переведите контент
-
Войдите в Lingo.dev через CLI:
npx lingo.dev@latest login -
Запустите pipeline перевода:
npx lingo.dev@latest runCLI создаст директорию
content/docs/es/для хранения переведённого контента и файлi18n.lockдля отслеживания переведённого (чтобы избежать лишних повторных переводов).
Шаг 9. Просмотрите переведённую документацию
-
Запустите dev-сервер:
npm run dev -
Перейдите по следующим URL:
- http://localhost:3000/en/docs — для английского контента
- http://localhost:3000/es/docs — для испанского контента