Skip to content

Commit c2906b4

Browse files
ArthurDEV44claude
andcommitted
feat(web): add i18n support with French and English languages
- Move app structure to src/ directory - Add Fumadocs i18n configuration (French default, English secondary) - Add language switcher components for docs and landing page - Translate all documentation to French - Configure Next.js 16 proxy for locale handling - Hide default locale (fr) in URLs for cleaner paths 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 46e5b11 commit c2906b4

File tree

102 files changed

+1685
-57
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+1685
-57
lines changed

apps/web/app/docs/layout.tsx

Lines changed: 0 additions & 31 deletions
This file was deleted.

apps/web/components.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"tsx": true,
66
"tailwind": {
77
"config": "",
8-
"css": "app/globals.css",
8+
"css": "src/app/globals.css",
99
"baseColor": "neutral",
1010
"cssVariables": true,
1111
"prefix": ""

apps/web/source.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { defineDocs, defineConfig } from "fumadocs-mdx/config";
22

33
export const docs = defineDocs({
4-
dir: "content/docs",
4+
dir: "src/content/docs",
55
});
66

77
export default defineConfig({
File renamed without changes.
File renamed without changes.

apps/web/app/docs/[[...slug]]/page.tsx renamed to apps/web/src/app/[lang]/docs/[[...slug]]/page.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ interface ExtendedPageData {
1717
}
1818

1919
export default async function Page(props: {
20-
params: Promise<{ slug?: string[] }>;
20+
params: Promise<{ slug?: string[]; lang: string }>;
2121
}) {
2222
const params = await props.params;
23-
const page = source.getPage(params.slug);
23+
const page = source.getPage(params.slug, params.lang);
2424
if (!page) notFound();
2525

2626
const data = page.data as unknown as ExtendedPageData;
@@ -42,10 +42,10 @@ export async function generateStaticParams() {
4242
}
4343

4444
export async function generateMetadata(props: {
45-
params: Promise<{ slug?: string[] }>;
45+
params: Promise<{ slug?: string[]; lang: string }>;
4646
}) {
4747
const params = await props.params;
48-
const page = source.getPage(params.slug);
48+
const page = source.getPage(params.slug, params.lang);
4949
if (!page) notFound();
5050

5151
return {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { DocsLayout } from "fumadocs-ui/layouts/docs";
2+
import type { ReactNode } from "react";
3+
import { source } from "@/lib/source";
4+
import { RootProvider } from "fumadocs-ui/provider/next";
5+
import { DocsLanguageSwitcher } from "@/components/DocsLanguageSwitcher";
6+
import "fumadocs-ui/style.css";
7+
8+
export default async function Layout({
9+
children,
10+
params,
11+
}: {
12+
children: ReactNode;
13+
params: Promise<{ lang: string }>;
14+
}) {
15+
const { lang } = await params;
16+
17+
return (
18+
<RootProvider
19+
i18n={{
20+
locale: lang,
21+
locales: [
22+
{ locale: "fr", name: "Français" },
23+
{ locale: "en", name: "English" },
24+
],
25+
}}
26+
>
27+
<DocsLayout
28+
tree={source.pageTree[lang]!}
29+
nav={{
30+
title: "Distill",
31+
url: `/${lang === "fr" ? "" : lang}`,
32+
children: <DocsLanguageSwitcher />,
33+
}}
34+
sidebar={{
35+
defaultOpenLevel: 1,
36+
}}
37+
links={[
38+
{
39+
text: "GitHub",
40+
url: "https://github.com/ArthurDEV44/distill",
41+
external: true,
42+
},
43+
]}
44+
>
45+
{children}
46+
</DocsLayout>
47+
</RootProvider>
48+
);
49+
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type { Metadata } from "next";
2-
import { Toaster } from "sonner";
3-
import "./globals.css";
2+
import type { ReactNode } from "react";
43

54
export const metadata: Metadata = {
65
title: {
@@ -26,28 +25,19 @@ export const metadata: Metadata = {
2625
url: "https://distill.dev",
2726
siteName: "Distill",
2827
title: "Distill - Context Engineering for LLMs",
29-
description:
30-
"Open source MCP server for LLM token optimization.",
28+
description: "Open source MCP server for LLM token optimization.",
3129
},
3230
twitter: {
3331
card: "summary_large_image",
3432
title: "Distill - Context Engineering for LLMs",
35-
description:
36-
"Open source MCP server for LLM token optimization.",
33+
description: "Open source MCP server for LLM token optimization.",
3734
},
3835
};
3936

40-
export default function RootLayout({
37+
export default async function LangLayout({
4138
children,
42-
}: Readonly<{
43-
children: React.ReactNode;
44-
}>) {
45-
return (
46-
<html lang="en" className="dark" suppressHydrationWarning>
47-
<body className="min-h-screen antialiased">
48-
{children}
49-
<Toaster position="bottom-right" />
50-
</body>
51-
</html>
52-
);
39+
}: {
40+
children: ReactNode;
41+
}) {
42+
return <>{children}</>;
5343
}

apps/web/src/app/layout.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import "./globals.css";
2+
import { Toaster } from "sonner";
3+
4+
export default function RootLayout({
5+
children,
6+
}: {
7+
children: React.ReactNode;
8+
}) {
9+
return (
10+
<html lang="fr" className="dark" suppressHydrationWarning>
11+
<body className="min-h-screen antialiased">
12+
{children}
13+
<Toaster position="bottom-right" />
14+
</body>
15+
</html>
16+
);
17+
}

0 commit comments

Comments
 (0)