prerender: initialise i18n for SSR; example pages mounted under their route

Now that SSR bodies are actually injected, two more prerender defects
showed: every t() rendered as its key (i18next was never initialised in
entry-server — the English bundle is imported now, plus the overlay's
"pro" namespace on pro builds, with an OSS stub), and every example
detail page rendered "404 Example not found" because ExampleDetailPage
was mounted without a Route so useParams() was empty. Verified locally:
/examples/blink-led SSRs breadcrumb, h1, description and JSON-LD; the
gallery and editor summary render translated copy.
This commit is contained in:
David Montero 2026-08-18 18:35:01 +02:00
parent 2c43c638a1
commit 13a19c127a
2 changed files with 24 additions and 2 deletions

View File

@ -0,0 +1,5 @@
/**
* OSS stub for the overlay's i18n registration (see entry-server.tsx).
* The real module adds the "pro" namespace; here there is nothing to add.
*/
export function registerProI18n(): void {}

View File

@ -8,7 +8,12 @@
import React from 'react';
import { renderToString } from 'react-dom/server';
import { MemoryRouter } from 'react-router-dom';
// Initialise i18next with the bundled English resources before any page
// renders: without this every t() call in the SSR output came back as its
// KEY ("landing.hero.titleLine1"), which is what the prerendered bodies
// shipped once they were actually injected.
import './i18n';
import { MemoryRouter, Routes, Route } from 'react-router-dom';
import { SEO_ROUTES } from './seoRoutes';
// ── SEO page components ─────────────────────────────────────────────────────
@ -56,6 +61,14 @@ export async function loadRouteComponents(): Promise<Record<string, React.FC>> {
if (import.meta.env.VITE_PRO_BUILD) {
const m = await import('@pro/pages/marketing');
routeComponents = { ...OSS_ROUTE_COMPONENTS, ...m.MARKETING_ROUTE_COMPONENTS };
// The overlay's own namespace ("pro": landing sections, pricing...),
// else its t() calls render as keys too.
try {
const reg = await import('@pro/i18n/register');
reg.registerProI18n?.();
} catch (err) {
console.warn(' ⚠ pro i18n not registered for SSR:', (err as Error).message);
}
}
return routeComponents;
}
@ -103,9 +116,13 @@ export function getPrerenderedExampleRoutes() {
*/
export function renderExample(exampleId: string): string {
try {
// Mounted under its real route so useParams() sees exampleId; rendered
// bare it had no params and every example page SSR'd as "not found".
return renderToString(
<MemoryRouter initialEntries={[`/examples/${exampleId}`]}>
<ExampleDetailPage />
<Routes>
<Route path="/examples/:exampleId" element={<ExampleDetailPage />} />
</Routes>
</MemoryRouter>,
);
} catch (err) {