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:
MacRimi
2026-05-31 12:41:10 +02:00
parent 875910b4d7
commit 5ca3463bf6
649 changed files with 83958 additions and 11096 deletions
+42 -33
View File
@@ -1,9 +1,6 @@
"use client"
import type React from "react"
import { useState } from "react"
import { Copy, Check } from "lucide-react"
import { codeToHtml } from "shiki"
import { cn } from "@/lib/utils"
import { CopyButton } from "./CopyButton"
interface CopyableCodeProps {
code: string
@@ -11,39 +8,51 @@ interface CopyableCodeProps {
className?: string
}
const CopyableCode: React.FC<CopyableCodeProps> = ({ code, language, className }) => {
const [isCopied, setIsCopied] = useState(false)
const copyToClipboard = async () => {
try {
await navigator.clipboard.writeText(decodeURIComponent(code))
setIsCopied(true)
setTimeout(() => setIsCopied(false), 2000)
} catch (err) {
console.error("Failed to copy text: ", err)
}
/**
* Server-rendered code block with Shiki syntax highlighting.
*
* Shiki runs at build time (Next.js static export pre-renders every
* page) so the resulting HTML carries pre-coloured `<span>` elements
* and the client doesn't have to load any highlighter JS. The copy
* button is the only interactive bit and lives in CopyButton, a tiny
* client component.
*
* Default theme is `github-dark` — matches the Hermes/Docusaurus look
* the user asked us to emulate. Default language is bash because most
* snippets in the docs are shell commands.
*
* Defensive fallback: if Shiki can't tokenize the requested language
* (unknown alias, unsupported grammar) we fall back to a plain
* dark-background <pre> so the page never crashes.
*/
const CopyableCode = async ({ code, language = "bash", className }: CopyableCodeProps) => {
let html: string
try {
html = await codeToHtml(code, {
lang: language,
theme: "github-dark",
})
} catch {
// Unknown lang or grammar error → render as plain text on a dark
// background to preserve the visual style without colour.
const escaped = code
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
html = `<pre class="shiki" style="background-color:#24292e;color:#e1e4e8"><code>${escaped}</code></pre>`
}
return (
<div className={cn("relative w-full", className)}>
<pre
<div className={cn("relative w-full my-4", className)}>
<div
className={cn(
"bg-gray-100 p-2 rounded-md",
"text-base",
"w-full overflow-x-auto",
"flex items-center",
language ? `language-${language}` : "",
"rounded-md overflow-hidden",
"[&_pre]:p-4 [&_pre]:overflow-x-auto [&_pre]:text-sm [&_pre]:leading-relaxed",
"[&_code]:font-mono",
)}
>
<code className="whitespace-pre flex-1 min-w-0">{decodeURIComponent(code)}</code>
</pre>
<button
onClick={copyToClipboard}
className="absolute top-2 right-2 p-1 bg-white rounded-md shadow-sm hover:bg-gray-100 transition-colors"
aria-label="Copy code"
>
{isCopied ? <Check className="h-4 w-4 text-green-500" /> : <Copy className="h-4 w-4 text-gray-500" />}
</button>
dangerouslySetInnerHTML={{ __html: html }}
/>
<CopyButton text={code} />
</div>
)
}