mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-06-01 04:54:42 +00:00
complete i18n migration to /[locale]/ with EN+ES content
Full rewrite of the docs site under app/[locale]/ with next-intl in localePrefix:"always" mode. Every page now exists at both /en/<path> and /es/<path>; the root / shows a meta-refresh + JS redirect to /<defaultLocale>/ so GitHub Pages serves something on the apex URL. Highlights: - 107 doc pages migrated to file-per-page JSON namespaces under messages/en/ and messages/es/. Spanish content is fully translated (no copy-of-English placeholders). - New documentation for the Active Suppressions section in the Settings tab and the per-event Dismiss dropdown in the Health Monitor modal. - New screenshots: dismiss-duration-dropdown.png and an updated health-suppression-settings.png. - Pagefind integrated for client-side search; index is built on every CI deploy (not committed). - RSS feeds: per-locale at /<locale>/rss.xml plus root /rss.xml for backward compat. - Removed the dead app/[locale]/guides/[slug]/ route — every guide now has its own static page and no markdown source remains. - Fixed orphan link /guides/nvidia -> /guides/nvidia-manual in docs/hardware/nvidia-host. - Removed obsolete components (footer2, calendar, drawer). Verified locally with `npm ci && npm run build`: 2804 files in out/, 231 pages indexed by pagefind, root redirect intact, both locale roots and the new Active Suppressions docs render OK.
This commit is contained in:
@@ -1,40 +1,96 @@
|
||||
"use client"
|
||||
|
||||
import Link from "next/link"
|
||||
// Use the locale-aware Link + usePathname from next-intl. With the
|
||||
// plain `next/link` and `next/navigation` imports the hrefs were
|
||||
// emitted without a locale (404s) AND the active-page detection
|
||||
// failed because `pathname` carried the `/en/` prefix while sidebar
|
||||
// items don't, so findIndex always returned -1 → no Previous/Next
|
||||
// buttons. See app/[locale]/docs/layout.tsx for the wider context.
|
||||
import { Link, usePathname } from "@/i18n/navigation"
|
||||
import { ChevronLeft, ChevronRight } from "lucide-react"
|
||||
import { usePathname } from "next/navigation"
|
||||
import { useTranslations } from "next-intl"
|
||||
import { sidebarItems } from "@/components/DocSidebar"
|
||||
|
||||
interface DocNavigationProps {
|
||||
className?: string
|
||||
}
|
||||
|
||||
interface SubMenuItem {
|
||||
title: string
|
||||
i18nKey?: string
|
||||
href: string
|
||||
submenu?: SubMenuItem[]
|
||||
}
|
||||
|
||||
interface FlatPage {
|
||||
title: string
|
||||
i18nKey?: string
|
||||
href: string
|
||||
section?: string
|
||||
sectionI18nKey?: string
|
||||
}
|
||||
|
||||
function walkSubmenu(
|
||||
items: SubMenuItem[],
|
||||
section: string,
|
||||
sectionI18nKey: string | undefined,
|
||||
out: FlatPage[],
|
||||
) {
|
||||
items.forEach((sub) => {
|
||||
out.push({
|
||||
title: sub.title,
|
||||
i18nKey: sub.i18nKey,
|
||||
href: sub.href,
|
||||
section,
|
||||
sectionI18nKey,
|
||||
})
|
||||
if (sub.submenu && sub.submenu.length > 0) {
|
||||
walkSubmenu(sub.submenu, section, sectionI18nKey, out)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function DocNavigation({ className }: DocNavigationProps) {
|
||||
const pathname = usePathname()
|
||||
const tNav = useTranslations("docNav")
|
||||
const tSidebar = useTranslations("docSidebar")
|
||||
|
||||
const flattenSidebarItems = () => {
|
||||
const flatItems: Array<{ title: string; href: string; section?: string }> = []
|
||||
const tItem = (i18nKey: string | undefined, fallback: string) => {
|
||||
if (!i18nKey) return fallback
|
||||
try {
|
||||
return tSidebar(`items.${i18nKey}`)
|
||||
} catch {
|
||||
return fallback
|
||||
}
|
||||
}
|
||||
|
||||
const flattenSidebarItems = (): FlatPage[] => {
|
||||
const flatItems: FlatPage[] = []
|
||||
|
||||
sidebarItems.forEach((item) => {
|
||||
if (item.href) {
|
||||
flatItems.push({ title: item.title, href: item.href })
|
||||
flatItems.push({ title: item.title, i18nKey: item.i18nKey, href: item.href })
|
||||
}
|
||||
|
||||
if (item.submenu) {
|
||||
item.submenu.forEach((subItem) => {
|
||||
flatItems.push({
|
||||
title: subItem.title,
|
||||
href: subItem.href,
|
||||
section: item.title,
|
||||
})
|
||||
})
|
||||
walkSubmenu(item.submenu as SubMenuItem[], item.title, item.i18nKey, flatItems)
|
||||
}
|
||||
})
|
||||
|
||||
return flatItems
|
||||
}
|
||||
|
||||
const allPages = flattenSidebarItems()
|
||||
// Dedupe consecutive entries with the same href. Several sidebar
|
||||
// sections (Post-Install, GPUs, Create VM, Disk Manager, …) have a
|
||||
// parent whose href equals its first child's "Overview" href, so the
|
||||
// flat sequence contains the same page twice in a row. Without dedup,
|
||||
// Previous/Next on the parent would point to itself.
|
||||
const rawPages = flattenSidebarItems()
|
||||
const allPages: FlatPage[] = []
|
||||
for (const p of rawPages) {
|
||||
if (allPages.length > 0 && allPages[allPages.length - 1].href === p.href) continue
|
||||
allPages.push(p)
|
||||
}
|
||||
|
||||
const currentPageIndex = allPages.findIndex((page) => page.href === pathname)
|
||||
|
||||
@@ -57,13 +113,16 @@ export function DocNavigation({ className }: DocNavigationProps) {
|
||||
<ChevronLeft className="h-5 w-5 mr-2 text-gray-500 group-hover:text-blue-500 flex-shrink-0" />
|
||||
<div className="min-w-0 overflow-hidden">
|
||||
<div className="text-sm text-gray-500 group-hover:text-blue-600 truncate">
|
||||
{prevPage.section ? `${prevPage.section}: ` : ""}Previous
|
||||
{prevPage.section ? `${tItem(prevPage.sectionI18nKey, prevPage.section)}: ` : ""}
|
||||
{tNav("previous")}
|
||||
</div>
|
||||
<div className="font-medium group-hover:text-blue-700 truncate">
|
||||
{tItem(prevPage.i18nKey, prevPage.title)}
|
||||
</div>
|
||||
<div className="font-medium group-hover:text-blue-700 truncate">{prevPage.title}</div>
|
||||
</div>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden sm:block sm:w-[calc(50%-0.5rem)]"></div>
|
||||
<div className="hidden sm:block sm:w-[calc(50%-0.5rem)]"></div>
|
||||
)}
|
||||
|
||||
{nextPage ? (
|
||||
@@ -73,14 +132,17 @@ export function DocNavigation({ className }: DocNavigationProps) {
|
||||
>
|
||||
<div className="min-w-0 overflow-hidden">
|
||||
<div className="text-sm text-gray-500 group-hover:text-blue-600 truncate">
|
||||
{nextPage.section ? `${nextPage.section}: ` : ""}Next
|
||||
{nextPage.section ? `${tItem(nextPage.sectionI18nKey, nextPage.section)}: ` : ""}
|
||||
{tNav("next")}
|
||||
</div>
|
||||
<div className="font-medium group-hover:text-blue-700 truncate">
|
||||
{tItem(nextPage.i18nKey, nextPage.title)}
|
||||
</div>
|
||||
<div className="font-medium group-hover:text-blue-700 truncate">{nextPage.title}</div>
|
||||
</div>
|
||||
<ChevronRight className="h-5 w-5 ml-2 text-gray-500 group-hover:text-blue-500 flex-shrink-0" />
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden sm:block sm:w-[calc(50%-0.5rem)]"></div>
|
||||
<div className="hidden sm:block sm:w-[calc(50%-0.5rem)]"></div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user