import type { Metadata } from "next" import { getTranslations, getMessages, setRequestLocale } from "next-intl/server" import { Link } from "@/i18n/navigation" import Image from "next/image" import { ArrowRight, Disc, Package, RefreshCw, ArrowUpCircle, Upload, Download, Wrench, Boxes, ArrowLeftRight, } from "lucide-react" import { DocHeader } from "@/components/ui/doc-header" import { Callout } from "@/components/ui/callout" export async function generateMetadata({ params, }: { params: Promise<{ locale: string }> }): Promise { const { locale } = await params const t = await getTranslations({ locale, namespace: "docs.utils.meta" }) return { title: t("title"), description: t("description"), keywords: [ "proxmox utilities", "proxmox update", "pve 8 to 9 upgrade", "pve9 upgrade", "proxmox ova export", "proxmox ovf import", "uup dump proxmox", "windows iso proxmox", "vmware to proxmox", "virtualbox to proxmox", ], alternates: { canonical: "https://proxmenux.com/docs/utils" }, openGraph: { title: t("ogTitle"), description: t("ogDescription"), type: "article", url: "https://proxmenux.com/docs/utils", }, twitter: { card: "summary", title: t("twitterTitle"), description: t("twitterDescription"), }, } } type StringItem = string type OptionItem = { title: string; description: string; href: string } interface OptionProps { title: string description: string Icon: React.ComponentType<{ className?: string; "aria-hidden"?: boolean }> href: string } function OptionCard({ title, description, Icon, href }: OptionProps) { return (
{title}
{description}
) } export default async function UtilitiesOverviewPage({ params, }: { params: Promise<{ locale: string }> }) { const { locale } = await params setRequestLocale(locale) const t = await getTranslations({ locale, namespace: "docs.utils" }) const messages = (await getMessages({ locale })) as unknown as { docs: { utils: { groups: { iso: { bullets: StringItem[] } maintenance: { bullets: StringItem[] } portability: { bullets: StringItem[] } } isoSection: { options: OptionItem[] } maintenanceSection: { options: OptionItem[] } portabilitySection: { options: OptionItem[] } } } } const block = messages.docs.utils const isoBullets = block.groups.iso.bullets const maintBullets = block.groups.maintenance.bullets const portBullets = block.groups.portability.bullets const isoOptions = block.isoSection.options const maintOptions = block.maintenanceSection.options const portOptions = block.portabilitySection.options const code = (chunks: React.ReactNode) => {chunks} const strong = (chunks: React.ReactNode) => {chunks} const em = (chunks: React.ReactNode) => {chunks} const isoIcons: React.ComponentType<{ className?: string; "aria-hidden"?: boolean }>[] = [Disc] const maintIcons: React.ComponentType<{ className?: string; "aria-hidden"?: boolean }>[] = [Package, RefreshCw, ArrowUpCircle] const portIcons: React.ComponentType<{ className?: string; "aria-hidden"?: boolean }>[] = [Upload, Download] return (
{t.rich("intro.body", { strong })}

{t("opening.heading")}

{t.rich("opening.body", { strong })}

{t("opening.imageAlt")}

{t("groups.heading")}

{t("groups.intro")}

{t("groups.iso.title")}

{t("groups.iso.body")}

    {isoBullets.map((_, idx) => (
  • {t(`groups.iso.bullets.${idx}`)}
  • ))}

{t("groups.maintenance.title")}

{t("groups.maintenance.body")}

    {maintBullets.map((_, idx) => (
  • {t(`groups.maintenance.bullets.${idx}`)}
  • ))}

{t("groups.portability.title")}

{t("groups.portability.body")}

    {portBullets.map((_, idx) => (
  • {t(`groups.portability.bullets.${idx}`)}
  • ))}
{t.rich("upgradeWarn.body", { strong })}

{t("isoSection.heading")}

{t.rich("isoSection.body", { code })}

{isoOptions.map((o, idx) => ( ))}

{t("maintenanceSection.heading")}

{t.rich("maintenanceSection.body", { strong })}

{maintOptions.map((o, idx) => ( ))}

{t("portabilitySection.heading")}

{t("portabilitySection.body")}

{portOptions.map((o, idx) => ( ))}
{t.rich("diskSpaceCallout.body", { code, strong })}

{t("fitsTogether.heading")}

{t.rich("fitsTogether.body", { code, em })}

) }