From 2a6abaed23248876c099eebeff240e545ae4e3e6 Mon Sep 17 00:00:00 2001 From: zhanghuan Date: Tue, 24 Sep 2024 11:33:22 +0800 Subject: [PATCH] feat: docs support multi lang --- src/app/[locale]/(docs)/docs/layout.tsx | 38 ++++-- src/app/[locale]/(docs)/layout.tsx | 6 +- src/app/[locale]/(marketing)/layout.tsx | 6 +- src/components/docs/pager.tsx | 19 +-- src/components/layout/mobile-nav-client.tsx | 139 -------------------- src/components/layout/mobile-nav.tsx | 15 ++- src/components/layout/navbar.tsx | 6 +- src/config/docs.ts | 69 ++++++++++ src/locales/en.json | 21 +++ src/locales/zh.json | 21 +++ 10 files changed, 169 insertions(+), 171 deletions(-) delete mode 100644 src/components/layout/mobile-nav-client.tsx diff --git a/src/app/[locale]/(docs)/docs/layout.tsx b/src/app/[locale]/(docs)/docs/layout.tsx index 88691e57b..5d75d095d 100644 --- a/src/app/[locale]/(docs)/docs/layout.tsx +++ b/src/app/[locale]/(docs)/docs/layout.tsx @@ -1,7 +1,10 @@ -import { ScrollArea } from "@/components/ui/scroll-area"; import { DocsSidebarNav } from "@/components/docs/sidebar-nav"; -import {unstable_setRequestLocale} from 'next-intl/server'; - +import { NavMobile } from "@/components/layout/mobile-nav"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { getDocsConfig } from "@/config/docs"; +import { getMarketingConfig } from "@/config/marketing"; +import { useTranslations } from "next-intl"; +import { unstable_setRequestLocale } from 'next-intl/server'; interface DocsLayoutProps { children: React.ReactNode; @@ -10,15 +13,28 @@ interface DocsLayoutProps { export default function DocsLayout({ children, params: {locale}}: DocsLayoutProps) { unstable_setRequestLocale(locale); + const t = useTranslations(); + const marketingConfig = getMarketingConfig(t); + const docsConfig = getDocsConfig(t); + + const translations = { + adminPanel: t('Dashboard.sidebar.adminPanel'), + dashboard: t('Dashboard.sidebar.dashboard'), + login: t('Marketing.login'), + signUp: t('Marketing.signUp'), + }; return ( -
- - {children} -
+ <> + +
+ + {children} +
+ ); } diff --git a/src/app/[locale]/(docs)/layout.tsx b/src/app/[locale]/(docs)/layout.tsx index 3bc833981..a975ca488 100644 --- a/src/app/[locale]/(docs)/layout.tsx +++ b/src/app/[locale]/(docs)/layout.tsx @@ -2,6 +2,7 @@ import { NavMobile } from "@/components/layout/mobile-nav"; import { NavBar } from "@/components/layout/navbar"; import { SiteFooter } from "@/components/layout/site-footer"; import MaxWidthWrapper from "@/components/shared/max-width-wrapper"; +import { getDocsConfig } from "@/config/docs"; import { getMarketingConfig } from "@/config/marketing"; import { useTranslations } from "next-intl"; import {unstable_setRequestLocale} from 'next-intl/server'; @@ -16,6 +17,7 @@ export default function DocsLayout({ children, params: {locale} }: DocsLayoutPro const t = useTranslations(); const marketingConfig = getMarketingConfig(t); + const docsConfig = getDocsConfig(t); const translations = { adminPanel: t('Dashboard.sidebar.adminPanel'), @@ -26,8 +28,8 @@ export default function DocsLayout({ children, params: {locale} }: DocsLayoutPro return (
- - + + {children} diff --git a/src/app/[locale]/(marketing)/layout.tsx b/src/app/[locale]/(marketing)/layout.tsx index 280180b1d..86890091a 100644 --- a/src/app/[locale]/(marketing)/layout.tsx +++ b/src/app/[locale]/(marketing)/layout.tsx @@ -5,6 +5,7 @@ import { NavBar } from "@/components/layout/navbar"; import { SiteFooter } from "@/components/layout/site-footer"; import { getMarketingConfig } from "@/config/marketing"; import { useTranslations } from "next-intl"; +import { getDocsConfig } from "@/config/docs"; interface MarketingLayoutProps { children: React.ReactNode; @@ -19,6 +20,7 @@ export default function MarketingLayout({ const t = useTranslations(); const marketingConfig = getMarketingConfig(t); + const docsConfig = getDocsConfig(t); const translations = { adminPanel: t('Dashboard.sidebar.adminPanel'), @@ -29,8 +31,8 @@ export default function MarketingLayout({ return (
- - + +
{children}
diff --git a/src/components/docs/pager.tsx b/src/components/docs/pager.tsx index 3433a8e5b..c95724c50 100644 --- a/src/components/docs/pager.tsx +++ b/src/components/docs/pager.tsx @@ -1,17 +1,21 @@ import Link from "@/components/link/link"; -import { Doc } from "contentlayer/generated" +import { Doc } from "contentlayer/generated"; -import { docsConfig } from "@/config/docs" -import { cn } from "@/lib/utils" -import { buttonVariants } from "@/components/ui/button" -import { Icons } from "@/components/shared/icons" +import { Icons } from "@/components/shared/icons"; +import { buttonVariants } from "@/components/ui/button"; +import { getDocsConfig } from "@/config/docs"; +import { cn } from "@/lib/utils"; +import { DocsConfig } from "@/types"; +import { useTranslations } from "next-intl"; interface DocsPagerProps { doc: Doc } export function DocsPager({ doc }: DocsPagerProps) { - const pager = getPagerForDoc(doc) + const t = useTranslations(); + const docsConfig = getDocsConfig(t); + const pager = getPagerForDoc(doc, docsConfig) if (!pager) { return null @@ -40,8 +44,7 @@ export function DocsPager({ doc }: DocsPagerProps) {
) } - -export function getPagerForDoc(doc: Doc) { +export function getPagerForDoc(doc: Doc, docsConfig: DocsConfig) { const flattenedLinks = [null, ...flatten(docsConfig.sidebarNav), null] const activeIndex = flattenedLinks.findIndex( (link) => doc.slug === link?.href diff --git a/src/components/layout/mobile-nav-client.tsx b/src/components/layout/mobile-nav-client.tsx deleted file mode 100644 index 2f5724c14..000000000 --- a/src/components/layout/mobile-nav-client.tsx +++ /dev/null @@ -1,139 +0,0 @@ -"use client"; - -import Link from "@/components/link/link"; -import { Menu, X } from "lucide-react"; -import { useSession } from "next-auth/react"; -import { useTranslations } from "next-intl"; -import { useSelectedLayoutSegment } from "next/navigation"; -import { useEffect, useState } from "react"; - -import { DocsSidebarNav } from "@/components/docs/sidebar-nav"; -import { Icons } from "@/components/shared/icons"; -import { siteConfig } from "@/config/site"; -import { cn } from "@/lib/utils"; - -import { ModeToggle } from "./mode-toggle"; - -interface NavMobileClientProps { - links: any[]; - documentation: boolean; -} - -export function NavMobileClient({ links, documentation }: NavMobileClientProps) { - const { data: session } = useSession(); - const [open, setOpen] = useState(false); - const selectedLayout = useSelectedLayoutSegment(); - const t = useTranslations('Navigation'); - - // prevent body scroll when modal is open - useEffect(() => { - if (open) { - document.body.style.overflow = "hidden"; - } else { - document.body.style.overflow = "auto"; - } - }, [open]); - - return ( - <> - - - - - ); -} \ No newline at end of file diff --git a/src/components/layout/mobile-nav.tsx b/src/components/layout/mobile-nav.tsx index ce58453b8..a56872e39 100644 --- a/src/components/layout/mobile-nav.tsx +++ b/src/components/layout/mobile-nav.tsx @@ -1,21 +1,22 @@ "use client"; -import { useEffect, useState } from "react"; import Link from "@/components/link/link"; -import { useSelectedLayoutSegment } from "next/navigation"; import { Menu, X } from "lucide-react"; import { useSession } from "next-auth/react"; +import { useSelectedLayoutSegment } from "next/navigation"; +import { useEffect, useState } from "react"; -import { docsConfig } from "@/config/docs"; -import { siteConfig } from "@/config/site"; -import { cn } from "@/lib/utils"; import { DocsSidebarNav } from "@/components/docs/sidebar-nav"; import { Icons } from "@/components/shared/icons"; +import { siteConfig } from "@/config/site"; +import { cn } from "@/lib/utils"; +import { DocsConfig, MarketingConfig } from "@/types"; import { ModeToggle } from "./mode-toggle"; interface NavMobileProps { - marketingConfig: any; + marketingConfig: MarketingConfig; + docsConfig: DocsConfig; translations: { adminPanel: string; dashboard: string; @@ -24,7 +25,7 @@ interface NavMobileProps { }; } -export function NavMobile({ marketingConfig, translations }: NavMobileProps) { +export function NavMobile({ marketingConfig, translations, docsConfig }: NavMobileProps) { const { data: session } = useSession(); const [open, setOpen] = useState(false); const selectedLayout = useSelectedLayoutSegment(); diff --git a/src/components/layout/navbar.tsx b/src/components/layout/navbar.tsx index e1be459c0..0fdeaf18c 100644 --- a/src/components/layout/navbar.tsx +++ b/src/components/layout/navbar.tsx @@ -2,7 +2,7 @@ import { useContext } from "react"; import { useSelectedLayoutSegment } from "next/navigation"; -import { MarketingConfig } from "@/types"; +import { DocsConfig, MarketingConfig } from "@/types"; import { useSession } from "next-auth/react"; import { useLocale } from "next-intl"; @@ -21,6 +21,7 @@ import MaxWidthWrapper from "@/components/shared/max-width-wrapper"; interface NavBarProps { scroll?: boolean; marketingConfig: MarketingConfig; + docsConfig: DocsConfig; translations: { adminPanel: string; dashboard: string; @@ -32,6 +33,7 @@ interface NavBarProps { export function NavBar({ scroll = false, marketingConfig, + docsConfig, translations, }: NavBarProps) { const locale = useLocale(); @@ -144,4 +146,4 @@ export function NavBar({ ); -} +} \ No newline at end of file diff --git a/src/config/docs.ts b/src/config/docs.ts index be45770fb..40aedd41b 100644 --- a/src/config/docs.ts +++ b/src/config/docs.ts @@ -1,5 +1,74 @@ import { DocsConfig } from "@/types"; +export const getDocsConfig = (t: (key: string) => string): DocsConfig => ({ + mainNav: [ + { + title: t("Docs.mainNav.documentation"), + href: "/docs", + }, + { + title: t("Docs.mainNav.guides"), + href: "/guides", + }, + ], + sidebarNav: [ + { + title: t("Docs.sidebarNav.gettingStarted"), + items: [ + { + title: t("Docs.sidebarNav.introduction"), + href: "/docs", + }, + { + title: t("Docs.sidebarNav.installation"), + href: "/docs/installation", + }, + ], + }, + { + title: t("Docs.sidebarNav.configuration"), + items: [ + { + title: t("Docs.sidebarNav.authentification"), + href: "/docs/configuration/authentification", + }, + { + title: t("Docs.sidebarNav.blog"), + href: "/docs/configuration/blog", + }, + { + title: t("Docs.sidebarNav.components"), + href: "/docs/configuration/components", + }, + { + title: t("Docs.sidebarNav.configFiles"), + href: "/docs/configuration/config-files", + }, + { + title: t("Docs.sidebarNav.database"), + href: "/docs/configuration/database", + }, + { + title: t("Docs.sidebarNav.email"), + href: "/docs/configuration/email", + }, + { + title: t("Docs.sidebarNav.layouts"), + href: "/docs/configuration/layouts", + }, + { + title: t("Docs.sidebarNav.markdownFiles"), + href: "/docs/configuration/markdown-files", + }, + { + title: t("Docs.sidebarNav.subscriptions"), + href: "/docs/configuration/subscriptions", + }, + ], + }, + ], +}); + export const docsConfig: DocsConfig = { mainNav: [ { diff --git a/src/locales/en.json b/src/locales/en.json index bbf6a0483..d7dd424ed 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -380,5 +380,26 @@ "enterProjectDescription": "Enter project description", "create": "Create", "createProjectError": "Failed to create project" + }, + "Docs": { + "mainNav": { + "documentation": "Documentation", + "guides": "Guides" + }, + "sidebarNav": { + "gettingStarted": "Getting Started", + "introduction": "Introduction", + "installation": "Installation", + "configuration": "Configuration", + "authentification": "Authentification", + "blog": "Blog", + "components": "Components", + "configFiles": "Config files", + "database": "Database", + "email": "Email", + "layouts": "Layouts", + "markdownFiles": "Markdown files", + "subscriptions": "Subscriptions" + } } } diff --git a/src/locales/zh.json b/src/locales/zh.json index 6f7de88df..c065e31ed 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -380,5 +380,26 @@ "enterProjectDescription": "输入项目描述", "create": "创建", "createProjectError": "创建项目失败" + }, + "Docs": { + "mainNav": { + "documentation": "文档", + "guides": "指南" + }, + "sidebarNav": { + "gettingStarted": "入门", + "introduction": "介绍", + "installation": "安装指南", + "configuration": "配置", + "authentification": "认证", + "blog": "博客", + "components": "组件", + "configFiles": "配置文件", + "database": "数据库", + "email": "电子邮件", + "layouts": "布局", + "markdownFiles": "Markdown 文件", + "subscriptions": "订阅" + } } }