import type { Metadata } from "next" import { getTranslations, getMessages, setRequestLocale } from "next-intl/server" import { Link } from "@/i18n/navigation" import { ExternalLink } from "lucide-react" import { DocHeader } from "@/components/ui/doc-header" import { Callout } from "@/components/ui/callout" import CopyableCode from "@/components/CopyableCode" export async function generateMetadata({ params, }: { params: Promise<{ locale: string }> }): Promise { const { locale } = await params const t = await getTranslations({ locale, namespace: "docs.about.contributing.meta" }) return { title: t("title"), description: t("description"), keywords: [ "proxmenux contributing", "proxmenux pull request", "proxmenux branch model", "proxmenux develop branch", "proxmenux script template", "proxmenux script header", "proxmox bash contribution", ], alternates: { canonical: "https://proxmenux.com/docs/about/contributing" }, openGraph: { title: t("ogTitle"), description: t("ogDescription"), type: "article", url: "https://proxmenux.com/docs/about/contributing", }, twitter: { card: "summary", title: t("title"), description: "How to contribute scripts, dialogs and improvements to the ProxMenux project.", }, } } type BranchingRow = { branch: string; purposeRich: string } type PhaseRow = { phaseRich: string; purposeRich: string; screenRich: string } type DialogRow = { toolRich: string; whenRich: string; effectRich: string } type MsgRow = { function: string; whenRich: string; spinner: string } type WhereNextItem = | { kind: "external"; url: string; label: string; tail: string } | { kind: "internal"; href: string; label: string; tail: string } export default async function ContributingPage({ params, }: { params: Promise<{ locale: string }> }) { const { locale } = await params setRequestLocale(locale) const t = await getTranslations({ locale, namespace: "docs.about.contributing" }) const messages = (await getMessages({ locale })) as unknown as { docs: { about: { contributing: { branching: { rows: BranchingRow[] } scriptHeader: { bullets: string[] } twoPhase: { rows: PhaseRow[]; phase1Rules: string[] } dialogVsWhiptail: { rows: DialogRow[] } messageFunctions: { rows: MsgRow[] } dialogConventions: { bullets: string[] } translation: { bullets: string[] } variableStyle: { bullets: string[] } dosAndDonts: { doBullets: string[]; dontBullets: string[] } submitting: { steps: string[] } whereNext: { items: WhereNextItem[] } } } } } const block = messages.docs.about.contributing const branchingRows = block.branching.rows const scriptHeaderBullets = block.scriptHeader.bullets const twoPhaseRows = block.twoPhase.rows const phase1Rules = block.twoPhase.phase1Rules const dialogRows = block.dialogVsWhiptail.rows const msgRows = block.messageFunctions.rows const dialogBullets = block.dialogConventions.bullets const translationBullets = block.translation.bullets const variableStyleBullets = block.variableStyle.bullets const doBullets = block.dosAndDonts.doBullets const dontBullets = block.dosAndDonts.dontBullets const submittingSteps = block.submitting.steps const whereNextItems = block.whereNext.items const code = (chunks: React.ReactNode) => {chunks} const strong = (chunks: React.ReactNode) => {chunks} const em = (chunks: React.ReactNode) => {chunks} const contributorsLink = (chunks: React.ReactNode) => ( {chunks} ) const cocLink = (chunks: React.ReactNode) => ( {chunks} ) const licenseLink = (chunks: React.ReactNode) => ( {chunks} ) const securityLink = (chunks: React.ReactNode) => ( {chunks} ) return (
{t.rich("twoPagesCallout.body", { contributorsLink, em })}

{t("branching.heading")}

{t("branching.intro")}

{branchingRows.map((row, idx) => ( ))}
{t("branching.headerBranch")} {t("branching.headerPurpose")}
{row.branch} {t.rich(`branching.rows.${idx}.purposeRich`, { code })}
{t.rich("branching.calloutBody", { code })}

{t("workflow.heading")}

{t("workflow.intro")}

  1. {t.rich("workflow.step1Lead", { code, strong })} {t.rich("workflow.step1Trail", { code })}
  2. {t.rich("workflow.step2Lead", { strong })}
  3. {t.rich("workflow.step3", { code, strong })}
  4. {t.rich("workflow.step4", { code, strong })}
  5. {t.rich("workflow.step5", { code, strong })}

{t("scriptHeader.heading")}

{t.rich("scriptHeader.intro", { strong })}

    {scriptHeaderBullets.map((_, idx) => (
  • {t.rich(`scriptHeader.bullets.${idx}`, { strong, em })}
  • ))}
{t.rich("scriptHeader.licenseCalloutBody", { strong, code, licenseLink })}

{t.rich("scriptHeader.optionalNote", { code })}

{t("scriptHeader.whyCalloutBody")}

{t("structure.heading")}

{t("structure.intro")}

{t.rich("structure.outro", { code })}

{t("twoPhase.heading")}

{t.rich("twoPhase.intro", { strong })}

{twoPhaseRows.map((_, idx) => ( ))}
{t("twoPhase.headerPhase")} {t("twoPhase.headerPurpose")} {t("twoPhase.headerScreen")}
{t.rich(`twoPhase.rows.${idx}.phaseRich`, { strong })} {t.rich(`twoPhase.rows.${idx}.purposeRich`, { code })} {t.rich(`twoPhase.rows.${idx}.screenRich`, { code })}

{t.rich("twoPhase.principle", { strong })}

{t("twoPhase.phase1Heading")}

{t.rich("twoPhase.phase1RulesIntro", { strong })}

    {phase1Rules.map((_, idx) => (
  • {t.rich(`twoPhase.phase1Rules.${idx}`, { code })}
  • ))}

{t("twoPhase.phase2Heading")}

{t.rich("twoPhase.phase2Rules", { strong, code })}

{t.rich("dialogVsWhiptail.headingRich", { code })}

{t("dialogVsWhiptail.intro")}

{dialogRows.map((_, idx) => ( ))}
{t("dialogVsWhiptail.headerTool")} {t("dialogVsWhiptail.headerWhen")} {t("dialogVsWhiptail.headerEffect")}
{t.rich(`dialogVsWhiptail.rows.${idx}.toolRich`, { strong, code })} {t.rich(`dialogVsWhiptail.rows.${idx}.whenRich`, { strong, code })} {t.rich(`dialogVsWhiptail.rows.${idx}.effectRich`, { code, em })}
{t.rich("dialogVsWhiptail.calloutBody", { code })}

{t("dialogVsWhiptail.rebootHeading")}

{t.rich("dialogVsWhiptail.rebootIntro", { code })}

{t("messageFunctions.heading")}

{t.rich("messageFunctions.intro", { code })}

{msgRows.map((row, idx) => ( ))}
{t("messageFunctions.headerFunction")} {t("messageFunctions.headerWhen")} {t("messageFunctions.headerSpinner")}
{row.function} {t.rich(`messageFunctions.rows.${idx}.whenRich`, { em })} {row.spinner}

{t("dialogConventions.heading")}

    {dialogBullets.map((_, idx) => (
  • {t.rich(`dialogConventions.bullets.${idx}`, { code })}
  • ))}

{t("dialogConventions.exampleIntro")}

{t("translation.heading")}

{t.rich("translation.intro", { code })}

    {translationBullets.map((_, idx) => (
  • {t.rich(`translation.bullets.${idx}`, { strong })}
  • ))}

{t("variableStyle.heading")}

    {variableStyleBullets.map((_, idx) => (
  • {t.rich(`variableStyle.bullets.${idx}`, { code })}
  • ))}

{t("variableStyle.standardNamesIntro")}

{t("variableStyle.redirectHeading")}

{t.rich("variableStyle.redirectIntro", { code })}

{t.rich("variableStyle.withoutRedirectIntro", { strong })}

{t.rich("variableStyle.withRedirectIntro", { strong })}

{t("variableStyle.twoPatternsIntro")}

  • {t.rich("variableStyle.discardLead", { strong })}
  • {t.rich("variableStyle.logLead", { strong })}

{t.rich("variableStyle.referenceOutro", { code })}

{t("dosAndDonts.heading")}

{t("dosAndDonts.doHeading")}

    {doBullets.map((_, idx) => (
  • {t.rich(`dosAndDonts.doBullets.${idx}`, { code })}
  • ))}

{t("dosAndDonts.dontHeading")}

    {dontBullets.map((_, idx) => (
  • {t.rich(`dosAndDonts.dontBullets.${idx}`, { code })}
  • ))}

{t("submitting.heading")}

    {submittingSteps.map((_, idx) => (
  1. {t.rich(`submitting.steps.${idx}`, { code, em, strong, cocLink })}
  2. ))}

{t.rich("submitting.securityOutro", { securityLink })}

{t("whereNext.heading")}

    {whereNextItems.map((item, idx) => (
  • {item.kind === "external" ? ( {item.label} ) : ( {item.label} )} {item.tail}
  • ))}
) }