快速开始
npm create fumadocs-app
pnpm create fumadocs-app
yarn create fumadocs-app
全部都可默认,按需选择即可。
Use /src
directory?
yes如下,反之则没有。
开始i18n
在ilb目录下创建i18n.ts
我这里默认使用中文,默认语言不显示前缀,即默认中文路径:/docs,英文:/en/docs。
import type { I18nConfig } from 'fumadocs-core/i18n';
export const i18n: I18nConfig = {
defaultLanguage: 'cn',
languages: ['en', 'cn'],
hideLocale: 'default-locale',
};
在ilb目录下source.ts中引入i18n
import { i18n } from '@/lib/i18n';
import { docs } from '@/.source';
import { loader } from 'fumadocs-core/source';
// See https://fumadocs.vercel.app/docs/headless/source-api for more info
export const source = loader({
// it assigns a URL to your pages
i18n,
baseUrl: '/docs',
source: docs.toFumadocsSource(),
});
app/layout.config.tsx
import '@/app/global.css';
import { i18n } from '@/lib/i18n';
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
/**
* 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
</>
),
},
links: [
{
text: 'Documentation',
url: '/docs',
active: 'nested-url',
},
],
};
}
在根目录下创建middleware.ts,如果使用了src则创建在src目录下。
import { createI18nMiddleware } from 'fumadocs-core/i18n';
import { i18n } from '@/lib/i18n';
export default createI18nMiddleware(i18n);
export const config = {
// Matcher ignoring `/_next/` and `/api/`
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};
在app目录下创建[lang]目录,将下方的文件移动到[lang]下。
src\app\[lang]\layout.tsx
import { RootProvider } from 'fumadocs-ui/provider';
import type { Translations } from 'fumadocs-ui/i18n';
const cn: Partial<Translations> = {
search: '搜索',
searchNoResult: '搜索无结果',
toc: '目录',
tocNoHeadings: '目录无标题',
lastUpdate: '最后更新',
chooseLanguage: '选择语言',
nextPage: '下一页',
previousPage: '上一页',
chooseTheme: '选择主题',
editOnGithub: '在GitHub上编辑'
};
// available languages that will be displayed on UI
// make sure `locale` is consistent with your i18n config
const locales = [
{
name: 'English',
locale: 'en',
},
{
name: '简体中文',
locale: 'cn',
},
];
export default async function RootLayout({
params,
children,
}: {
params: Promise<{ lang: string }>;
children: React.ReactNode;
}) {
const lang = (await params).lang;
return (
<html lang={lang}>
<body>
<RootProvider
i18n={{
locale: lang,
// available languages
locales,
// translations for UI
translations: { cn }[lang],
}}
>
{children}
</RootProvider>
</body>
</html>
);
}
src\app\[lang]\(home)\layout.tsx
import type { ReactNode } from 'react';
import { HomeLayout } from 'fumadocs-ui/layouts/home';
import { baseOptions } from '@/app/[lang]/layout.config';
export default function Layout({ children }: { children: ReactNode }) {
return <HomeLayout {...baseOptions}>{children}</HomeLayout>;
}
src\app\[lang]\(home)\layout.tsx
import type { ReactNode } from 'react';
import { HomeLayout } from 'fumadocs-ui/layouts/home';
import { baseOptions } from '@/app/[lang]/layout.config';
export default async function Layout({
params,
children,
}: {
params: Promise<{ lang: string }>;
children: ReactNode;
}) {
const { lang } = await params;
return <HomeLayout {...baseOptions(lang)}>{children}</HomeLayout>;
}
src\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 '@/app/[lang]/layout.config';
export default async function Layout({
params,
children,
}: {
params: Promise<{ lang: string }>;
children: ReactNode;
}) {
const { lang } = await params;
return (
<DocsLayout {...baseOptions(lang)} tree={source.pageTree[lang]}>
{children}
</DocsLayout>
);
}
src\app\[lang]\docs\[[...slug]]\page.tsx
import { source } from '@/lib/source';
import {
DocsPage,
DocsBody,
DocsDescription,
DocsTitle,
} from 'fumadocs-ui/page';
import { notFound } from 'next/navigation';
import { createRelativeLink } from 'fumadocs-ui/mdx';
import { getMDXComponents } from '@/mdx-components';
export default async function Page(props: {
params: Promise<{ lang: string; slug?: string[] }>;
}) {
const params = await props.params;
const { slug, lang } = await params;
const page = source.getPage(slug, 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: {
params: Promise<{ lang: string; slug?: string[] }>;
}) {
const params = await props.params;
const { slug, lang } = await params;
const page = source.getPage(slug, lang);
if (!page) notFound();
return {
title: page.data.title,
description: page.data.description,
};
}
到此为止页面已完成i18n,接下来完成搜索功能的i18n。
src\app\api\search\route.ts
npm install @orama/orama @orama/tokenizers
import { source } from '@/lib/source';
import { createFromSource } from 'fumadocs-core/search/server';
import { createTokenizer } from '@orama/tokenizers/mandarin';
export const { GET } = createFromSource(source, {
localeMap: {
// you can customise search configs for specific locales, like:
// [locale]: Orama options
cn: {
components: {
tokenizer: createTokenizer(),
},
search: {
threshold: 0,
tolerance: 0,
},
},
},
});
新建文档
如图所示,如果不写语言后缀在后面则默认为默认语言。