From a4cf6fe14e814040a715c8026271eb12146f85de Mon Sep 17 00:00:00 2001 From: Sebastian Werner Date: Tue, 7 Jul 2026 00:17:50 +0200 Subject: [PATCH] docs: extend matrix surfaces for Remix --- .github/workflows/deploy-site.yml | 2 +- Containerfile | 9 +-- README.md | 4 +- docs/demo-deployments.md | 69 ++++++++++++------- docs/founder-led-content.md | 2 +- docs/operations/run-examples-container.md | 40 ++++++----- docs/site/index.mdx | 8 +-- docs/site/internal-storyline.md | 2 +- docs/site/posts/README.md | 2 +- ...r-verifying-i18n-across-five-frameworks.md | 15 ++-- docs/site/posts/micro-content-round-1.md | 6 +- ...rd-time-i-built-javascript-i18n-tooling.md | 2 +- docs/site/proof.mdx | 6 +- docs/site/structure/README.md | 6 +- docs/site/structure/components.jsx | 4 +- docs/site/structure/pages/BlogIndexPage.jsx | 4 +- docs/site/structure/pages/FrameworksPage.jsx | 15 ++-- docs/site/structure/pages/HomePage.jsx | 19 ++--- docs/site/structure/pages/ProofPage.jsx | 4 +- examples/README.md | 19 +++-- examples/react-router-cookie/README.md | 2 +- examples/react-router-route/README.md | 2 +- examples/react-router-subdomain/README.md | 2 +- examples/react-router-tld/README.md | 2 +- scripts/verify-site-routes.mjs | 12 ++-- .../components/frameworks/FrameworkMatrix.tsx | 4 +- site/app/components/home/ProofStrip.tsx | 4 +- site/app/components/proof/ScreenshotStrip.tsx | 5 +- site/app/data/matrix.ts | 21 ++++-- site/app/data/posts.ts | 4 +- site/app/hooks/useCountUp.ts | 4 +- site/app/routes.ts | 1 + site/app/routes/frameworks.tsx | 17 ++--- site/app/routes/home.tsx | 8 +-- site/app/routes/proof.tsx | 6 +- 35 files changed, 191 insertions(+), 141 deletions(-) diff --git a/.github/workflows/deploy-site.yml b/.github/workflows/deploy-site.yml index ce5a5706..d27f8be7 100644 --- a/.github/workflows/deploy-site.yml +++ b/.github/workflows/deploy-site.yml @@ -118,7 +118,7 @@ jobs: } check "/" 200 "One translation model." - check "/frameworks" 200 "Five frameworks." + check "/frameworks" 200 "Six frameworks." check "/proof" 200 "Claims you can re-run." check "/get-started" 200 "First working translation" check "/compare" 200 "Narrower than the alternatives." diff --git a/Containerfile b/Containerfile index c7997c62..69728549 100644 --- a/Containerfile +++ b/Containerfile @@ -1,4 +1,4 @@ -# Run all twenty Palamedes example apps side by side in a single container, each +# Run all 24 Palamedes example apps side by side in a single container, each # on its fixed port from scripts/example-matrix.mjs. Built and run with Podman: # # podman build -f Containerfile -t palamedes-examples . @@ -8,6 +8,7 @@ # -p 4030:4030 -p 4031:4031 -p 4032:4032 -p 4033:4033 \ # -p 4040:4040 -p 4041:4041 -p 4042:4042 -p 4043:4043 \ # -p 4050:4050 -p 4051:4051 -p 4052:4052 -p 4053:4053 \ +# -p 4060:4060 -p 4061:4061 -p 4062:4062 -p 4063:4063 \ # palamedes-examples # # (or let the matrix generate the flags: `podman run --init \ @@ -40,7 +41,7 @@ COPY . . RUN pnpm install --frozen-lockfile # `pnpm build` builds the workspace packages and compiles the native addon via -# cargo; `pnpm build:examples` builds all twenty example apps. +# cargo; `pnpm build:examples` builds all 24 example apps. RUN pnpm build RUN pnpm build:examples # Drop build-only artifacts before they reach the runtime image: the compiled @@ -66,13 +67,13 @@ COPY --from=build --chown=node:node /app /app # Global pnpm at the version pinned in package.json (packageManager) so the # unprivileged `node` user can run the example start scripts. RUN npm install -g "pnpm@$(node -p 'require("./package.json").packageManager.split("@")[1].split("+")[0]')" -# Run the twenty public servers as a non-root user (least privilege). +# Run the 24 public servers as a non-root user (least privilege). USER node # Fixed ports — informational only; the authoritative list is # scripts/example-matrix.mjs. Publish them without drift via: # podman run $(node ./scripts/container/print-podman-ports.mjs) palamedes-examples -EXPOSE 4010 4011 4012 4013 4020 4021 4022 4023 4030 4031 4032 4033 4040 4041 4042 4043 4050 4051 4052 4053 +EXPOSE 4010 4011 4012 4013 4020 4021 4022 4023 4030 4031 4032 4033 4040 4041 4042 4043 4050 4051 4052 4053 4060 4061 4062 4063 # tini is the init/reaper (no external `--init` needed). `-s` registers it as a # subreaper so reaping still works if it ends up not as PID 1 (e.g. when the diff --git a/README.md b/README.md index 8a7bae10..72cf214e 100644 --- a/README.md +++ b/README.md @@ -72,14 +72,14 @@ easier to review, and easier to carry from one framework to the next. ## Current Status - Recommended for new projects and teams that want cleaner i18n foundations -- Verified today across Next.js, TanStack Start, SolidStart, Waku, and React Router on Node.js `>=22.22` +- Verified today across Next.js, TanStack Start, SolidStart, Waku, React Router, and server-first Remix v3 on Node.js `>=22.22` - Source-string-first catalogs are stable and powered by `ferrocat`, including structured audits and ICU authoring diagnostics - Placeholder top-level packages exist, but there is no `palamedes` or `create-palamedes` first-run entry yet - 1.0 stability tiers and public API expectations are documented in [Stability and versioning](https://github.com/sebastian-software/palamedes/blob/main/docs/stability.md) ## What Exists Today -- A browser-verified example matrix across five framework families +- A browser-verified example matrix across six framework families - Versioned screenshots generated from the same Playwright-based verifier used in CI - Reproducible benchmark commands for transform, extract, catalog update, compile steps, and end-to-end extract/update workflows - Structured catalog audit and metadata validation APIs backed by `ferrocat` diff --git a/docs/demo-deployments.md b/docs/demo-deployments.md index 8bb652b4..19c5e37f 100644 --- a/docs/demo-deployments.md +++ b/docs/demo-deployments.md @@ -2,26 +2,30 @@ The Palamedes example matrix is verified primarily through local runs and CI. Automatic deployments are not part of the default merge or release path. The -matrix spans twenty examples (five frameworks × four locale strategies). Public -demo URLs are documented as the live reference surface, but reachability depends -on the hosting and DNS notes in this document. The five subdomain demos require -the per-example wildcard DNS records described under Subdomain Locale Hosting. -The five tld demos require the `examples.palamedes-i18n.*` domains described -under TLD Locale Hosting. +matrix spans 24 examples (six frameworks × four locale strategies). Public demo +URLs are documented as the live reference surface where hosting exists, but +reachability depends on the hosting and DNS notes in this document. The five +currently hosted subdomain demos require the per-example wildcard DNS records +described under Subdomain Locale Hosting. The five currently hosted tld demos +require the `examples.palamedes-i18n.*` domains described under TLD Locale +Hosting. Remix v3 is verified locally and in CI, but is not yet a public demo +deployment target. ## Current Policy - the canonical verification path is `pnpm build:examples` plus `pnpm verify:examples` - example deployments do not run automatically on `main` -- the Next.js and SolidStart examples (including their subdomain and tld variants) are excluded from `deploy-examples.yml` +- the Next.js, SolidStart, and Remix examples (including their subdomain and tld variants) are excluded from `deploy-examples.yml` - the `deploy-examples.yml` workflow supports manual deployment of the Vite-based examples (TanStack, Waku, React Router — cookie, route, subdomain, and tld) if an additional hosted URL is needed ## Live Reference URLs -These URLs describe the intended public reference shape — five frameworks, each -in four locale strategies. Switch language in a reachable demo and watch copy, -plural seat counts, currency, and dates change together. The demos are grouped -by framework below, with every locale-specific URL linked directly. +These URLs describe the intended public reference shape — six frameworks, each in +four locale strategies. Switch language in a reachable demo and watch copy, +plural seat counts, currency, and dates change together. The demos are grouped by +framework below, with every locale-specific URL linked directly where public +hosting exists. Remix v3 rows link to source because that beta integration is +currently a local/CI proof surface. How each strategy encodes the locale: @@ -79,14 +83,27 @@ How each strategy encodes the locale: | subdomain | [en](https://en.solidstart-subdomain.examples.palamedes.dev) · [de](https://de.solidstart-subdomain.examples.palamedes.dev) · [es](https://es.solidstart-subdomain.examples.palamedes.dev) | | tld | [en](https://solidstart.examples.palamedes-i18n.com) · [de](https://solidstart.examples.palamedes-i18n.de) · [es](https://solidstart.examples.palamedes-i18n.es) · [fr](https://solidstart.examples.palamedes-i18n.fr) | +### Remix v3 + +Remix v3 examples are verified through the default Remix Node loader path in CI. +They are not public demo deployments yet while the Remix v3 beta hosting and UI +adapter story settles. + +| Strategy | Reference source | +| --------- | ------------------------------------------------------- | +| cookie | [examples/remix-cookie](../examples/remix-cookie) | +| route | [examples/remix-route](../examples/remix-route) | +| subdomain | [examples/remix-subdomain](../examples/remix-subdomain) | +| tld | [examples/remix-tld](../examples/remix-tld) | + ## Subdomain Locale Hosting (DNS And Reverse Proxy) The subdomain demos encode the locale in the leftmost DNS label (`de.nextjs-subdomain.examples.palamedes.dev` renders German). That label sits one level below the existing `*.examples.palamedes.dev` wildcard, which only covers a single label: it resolves `nextjs-subdomain.examples.palamedes.dev` but not -`de.nextjs-subdomain.examples.palamedes.dev`. Each subdomain example therefore -needs its own wildcard record: +`de.nextjs-subdomain.examples.palamedes.dev`. Each public subdomain example +therefore needs its own wildcard record: - `*.nextjs-subdomain.examples.palamedes.dev` - `*.tanstack-subdomain.examples.palamedes.dev` @@ -113,7 +130,9 @@ implies, but it must hold for caching layers too. These records and proxy routes are now in place, so the five subdomain rows above are publicly reachable (each locale host returns 200 and renders its locale). The canonical verification path remains `pnpm verify:examples`, which exercises the -subdomain strategy locally via `*.lvh.me` hosts. +subdomain strategy locally via `*.lvh.me` hosts. Remix subdomain support is +verified the same way, but it is not included in the public DNS/proxy deployment +plan yet. ## TLD Locale Hosting (DNS And Reverse Proxy) @@ -140,10 +159,12 @@ the `Host` in its cache key (or the app must send `Vary: Host`); otherwise a response for one TLD could be served for another. This is the same constraint the per-host routing already implies, but it must hold for caching layers too. -Until these domains are provisioned, the five tld rows in the Live Reference table -are not yet reachable. The canonical verification path runs locally via +Until these domains are provisioned, the five public tld rows in the Live +Reference table are not yet reachable. The canonical verification path runs locally via `pnpm verify:examples`, which exercises the tld strategy using Chromium's -`--host-resolver-rules` flag to simulate the TLD hosts without real DNS. +`--host-resolver-rules` flag to simulate the TLD hosts without real DNS. Remix TLD +support is covered by the same local/CI verification path, not by public TLD +deployment yet. ## Optional Manual Deployments @@ -173,11 +194,12 @@ Supported deployment targets: - `waku-tld` - `react-router-tld` -## Why Next.js Is Not In `deploy-examples.yml` +## Why Next.js, SolidStart, And Remix Are Not In `deploy-examples.yml` -The Next.js examples are part of the verified matrix, but they are excluded from -the `deploy-examples.yml` workflow. That workflow targets the Vite-based examples -(TanStack, Waku, React Router — cookie, route, subdomain, and tld) specifically. +The Next.js, SolidStart, and Remix examples are part of the verified matrix, but +they are excluded from the `deploy-examples.yml` workflow. That workflow targets +the Vite-based examples (TanStack, Waku, React Router — cookie, route, subdomain, +and tld) specifically. For this OSS setup, the guaranteed baseline is: @@ -185,5 +207,6 @@ For this OSS setup, the guaranteed baseline is: - the examples run locally - SSR, locale routing, cookie handling, and localized server actions are covered in browser tests -The hosting mechanism for the Next.js examples is separate from -`deploy-examples.yml` and is not further documented here. +The hosting mechanism for the Next.js and SolidStart examples is separate from +`deploy-examples.yml` and is not further documented here. Remix v3 remains a +server-first beta proof surface until a public hosting target is chosen. diff --git a/docs/founder-led-content.md b/docs/founder-led-content.md index a0a02e8f..bc652be1 100644 --- a/docs/founder-led-content.md +++ b/docs/founder-led-content.md @@ -57,7 +57,7 @@ Drafts included in this round: - [What we delegated to Ferrocat and why](./site/posts/what-we-delegated-to-ferrocat-and-why.md) - [Measuring Palamedes honestly](./site/posts/measuring-palamedes-honestly.md) - [From Lingui to Palamedes without changing how authoring feels](./site/posts/from-lingui-to-palamedes.md) -- [How we browser-verify i18n across five frameworks](./site/posts/browser-verifying-i18n-across-five-frameworks.md) +- [How we browser-verify i18n across six frameworks](./site/posts/browser-verifying-i18n-across-five-frameworks.md) - [The third time I built JavaScript i18n tooling](./site/posts/the-third-time-i-built-javascript-i18n-tooling.md) - [Round 1 micro-content](./site/posts/micro-content-round-1.md) diff --git a/docs/operations/run-examples-container.md b/docs/operations/run-examples-container.md index 0f3eef9b..9a0383e0 100644 --- a/docs/operations/run-examples-container.md +++ b/docs/operations/run-examples-container.md @@ -1,6 +1,6 @@ # Running all examples together in one container -This document describes how to run all twenty Palamedes example apps together in +This document describes how to run all 24 Palamedes example apps together in **one** Podman container – each on its own fixed port. It builds on the `Containerfile` in the repo root and the supervisor `scripts/container/start-all.mjs`. @@ -12,7 +12,7 @@ This document describes how to run all twenty Palamedes example apps together in ## Prerequisites - [Podman](https://podman.io/) installed -- Enough resources for ten concurrent SSR Node servers (several GB of RAM +- Enough resources for two dozen concurrent SSR Node servers (several GB of RAM recommended) A Rust or Node setup on the host is **not** required: the container's build stage @@ -42,7 +42,7 @@ The build is multi-stage: 1. **Build stage** (glibc/Debian): `pnpm install`, `pnpm build` (builds the packages including the native addon via `cargo` in release profile) and - `pnpm build:examples` (builds all twenty apps). The `cargo` compilation makes the + `pnpm build:examples` (builds all 24 apps). The `cargo` compilation makes the first build noticeably longer. 2. **Runtime stage** (slimmer Debian slim): takes over the finished workspace and starts the supervisor. Dev dependencies stay installed because TanStack's @@ -57,7 +57,7 @@ from the ports the servers actually bind: podman run $(node ./scripts/container/print-podman-ports.mjs) palamedes-examples ``` -Spelled out, this is `-p 4010:4010 -p 4011:4011 … -p 4051:4051`. +Spelled out, this is `-p 4010:4010 -p 4011:4011 … -p 4063:4063`. - **Init/reaping:** the image ships `tini` as its entrypoint, so reparented child processes are reaped cleanly with no extra flag (also works later via @@ -70,22 +70,28 @@ Spelled out, this is `-p 4010:4010 -p 4011:4011 … -p 4051:4051`. The supervisor starts all apps from `scripts/example-matrix.mjs`, prefixes their output with the example id (`[nextjs-cookie] …`), and intentionally exits the container with an error code as soon as a server dies unexpectedly (fail-fast). -`podman stop` terminates all twenty servers via forwarded `SIGTERM`. +`podman stop` terminates all 24 servers via forwarded `SIGTERM`. ## Port overview -| Port | Example | Strategy | -| ---- | --------------------- | -------- | -| 4010 | `nextjs-cookie` | cookie | -| 4011 | `nextjs-route` | route | -| 4020 | `tanstack-cookie` | cookie | -| 4021 | `tanstack-route` | route | -| 4030 | `waku-cookie` | cookie | -| 4031 | `waku-route` | route | -| 4040 | `react-router-cookie` | cookie | -| 4041 | `react-router-route` | route | -| 4050 | `solidstart-cookie` | cookie | -| 4051 | `solidstart-route` | route | +| Port | Example | Strategy | +| ---- | ---------------------- | --------- | +| 4010 | `nextjs-cookie` | cookie | +| 4011 | `nextjs-route` | route | +| 4020 | `tanstack-cookie` | cookie | +| 4021 | `tanstack-route` | route | +| 4030 | `waku-cookie` | cookie | +| 4031 | `waku-route` | route | +| 4040 | `react-router-cookie` | cookie | +| 4041 | `react-router-route` | route | +| 4050 | `solidstart-cookie` | cookie | +| 4051 | `solidstart-route` | route | +| 4052 | `solidstart-subdomain` | subdomain | +| 4053 | `solidstart-tld` | tld | +| 4060 | `remix-cookie` | cookie | +| 4061 | `remix-route` | route | +| 4062 | `remix-subdomain` | subdomain | +| 4063 | `remix-tld` | tld | `scripts/example-matrix.mjs` is the single source of truth for the ports. The supervisor binds according to it automatically, and the `print-podman-ports.mjs` diff --git a/docs/site/index.mdx b/docs/site/index.mdx index ebe98596..d0f4ab4d 100644 --- a/docs/site/index.mdx +++ b/docs/site/index.mdx @@ -11,8 +11,8 @@ every time the framework changes. It gives you one runtime model, one message identity model, and one catalog workflow across verified integrations for Next.js, TanStack Start, SolidStart, -Waku, React Router, and Vite. Backend servers use the same runtime model but -are documented as a guide rather than a verified matrix family. +Waku, React Router, Remix v3, and Vite. Backend servers use the same runtime +model but are documented as a guide rather than a verified matrix family. We are not asking you to trust a slogan. The repo shows the work. @@ -25,7 +25,7 @@ working across different app shapes. The repo backs that claim with visible evidence: -- five framework families: Next.js, TanStack Start, SolidStart, Waku, and React Router +- six framework families: Next.js, TanStack Start, SolidStart, Waku, React Router, and Remix v3 - four locale strategies per framework: cookie, route segment, subdomain, and tld - versioned browser screenshots generated from the same Playwright verifier used in CI - reproducible benchmark commands for transform, extract, catalog update, artifact compile, and end-to-end extract/update workflows @@ -96,7 +96,7 @@ Palamedes makes specific claims, and the repo shows the work behind them. Current evidence assets: -- verified example matrix across five framework families +- verified example matrix across six framework families - four locale strategies per framework - browser screenshots generated from the same Playwright-based verifier used in CI - benchmark fixtures and documented methodology diff --git a/docs/site/internal-storyline.md b/docs/site/internal-storyline.md index 10cf80da..ffb21aba 100644 --- a/docs/site/internal-storyline.md +++ b/docs/site/internal-storyline.md @@ -10,7 +10,7 @@ without reinventing the narrative. 3. Why this is rare: most alternatives focus on one framework or carry more historical surface 4. The architectural core: native core, thin adapters, delegated catalog semantics 5. The runtime story: one runtime model, one identity model -6. The confidence story: verified example matrix across five framework families +6. The confidence story: verified example matrix across six framework families 7. The evidence story: screenshots, CI flows, benchmarks, ADRs 8. The comparison story: Lingui closest, `next-intl` different center, GT broader category 9. Why it matters commercially: cleaner migrations, clearer architecture, better foundations for higher-level workflows diff --git a/docs/site/posts/README.md b/docs/site/posts/README.md index e87b248f..c76d142a 100644 --- a/docs/site/posts/README.md +++ b/docs/site/posts/README.md @@ -11,7 +11,7 @@ checkable in the repo or to a public source. - [What we delegated to Ferrocat and why](./what-we-delegated-to-ferrocat-and-why.md) - [Measuring Palamedes honestly](./measuring-palamedes-honestly.md) - [From Lingui to Palamedes without changing how authoring feels](./from-lingui-to-palamedes.md) -- [How we browser-verify i18n across five frameworks](./browser-verifying-i18n-across-five-frameworks.md) +- [How we browser-verify i18n across six frameworks](./browser-verifying-i18n-across-five-frameworks.md) - [The third time I built JavaScript i18n tooling](./the-third-time-i-built-javascript-i18n-tooling.md) - [Round 1 micro-content](./micro-content-round-1.md) diff --git a/docs/site/posts/browser-verifying-i18n-across-five-frameworks.md b/docs/site/posts/browser-verifying-i18n-across-five-frameworks.md index 3ae7e55e..0473cf15 100644 --- a/docs/site/posts/browser-verifying-i18n-across-five-frameworks.md +++ b/docs/site/posts/browser-verifying-i18n-across-five-frameworks.md @@ -2,7 +2,7 @@ date: "2026-07-05" --- -# How We Browser-Verify i18n Across Five Frameworks +# How We Browser-Verify i18n Across Six Frameworks Status: draft @@ -14,21 +14,22 @@ interaction, and server actions all have to agree. Palamedes treats that as a verification problem. -The repo contains an example matrix across five framework families: +The repo contains an example matrix across six framework families: - Next.js - TanStack Start - SolidStart - Waku - React Router +- Remix v3 Each family has four locale strategies: - cookie-based locale persistence - route-segment locale persistence -That gives twenty example apps. Each one has browser-visible checks for the parts -that usually hide i18n bugs: +That gives 24 example apps. Each one has visible checks for the parts that +usually hide i18n bugs: - server-rendered localized text before hydration - client-side locale switching @@ -55,9 +56,9 @@ For Palamedes, the thesis is: The matrix is where that thesis has to survive contact with frameworks. Next.js and React Router do not fail in the same places. TanStack Start, -SolidStart, and Waku each have their own server/client boundaries. Route-based -locale state and cookie-based locale state put pressure on different parts of -the adapter layer. +SolidStart, Waku, and Remix v3 each have their own server/client boundaries. +Route-based locale state and cookie-based locale state put pressure on different +parts of the adapter layer. That is why this kind of verification is stronger than a single starter app. diff --git a/docs/site/posts/micro-content-round-1.md b/docs/site/posts/micro-content-round-1.md index 6c96f534..2cb5a610 100644 --- a/docs/site/posts/micro-content-round-1.md +++ b/docs/site/posts/micro-content-round-1.md @@ -13,9 +13,9 @@ piece of evidence. Cross-framework i18n should not be a README claim. -Palamedes keeps twenty examples in the repo: five framework families, each with -cookie, route, subdomain, and tld locale strategies. The browser screenshots are versioned and -come from the same verification flow used in CI. +Palamedes keeps 24 examples in the repo: six framework families, each with +cookie, route, subdomain, and tld locale strategies. The screenshots are +versioned and come from the same verification flow used in CI. Evidence: `docs/example-screenshots` diff --git a/docs/site/posts/the-third-time-i-built-javascript-i18n-tooling.md b/docs/site/posts/the-third-time-i-built-javascript-i18n-tooling.md index 6f5769ee..2f02c9ff 100644 --- a/docs/site/posts/the-third-time-i-built-javascript-i18n-tooling.md +++ b/docs/site/posts/the-third-time-i-built-javascript-i18n-tooling.md @@ -59,7 +59,7 @@ trying to protect. The current proof is visible: -- five framework families in the example matrix +- six framework families in the example matrix - cookie, route, subdomain, and tld locale strategies - versioned browser screenshots - reproducible benchmark commands diff --git a/docs/site/proof.mdx b/docs/site/proof.mdx index 44e50971..8aef8dc9 100644 --- a/docs/site/proof.mdx +++ b/docs/site/proof.mdx @@ -11,7 +11,7 @@ message is positive, but the repo still shows the work behind it. ## What We Can Safely Claim - the stack stays consistent across verified integrations for Next.js, TanStack - Start, SolidStart, Waku, and React Router + Start, SolidStart, Waku, React Router, and Remix v3 - the runtime model is stable around `getI18n()` - message identity is stable around `message + context` - macro transform, extraction, catalog update, audit, and compile paths are @@ -26,7 +26,7 @@ message is positive, but the repo still shows the work behind it. The strongest repo-level evidence is the framework matrix: -- five framework families +- six framework families - cookie, route, subdomain, and tld locale strategies - SSR-visible output - localized server actions or server functions @@ -70,7 +70,7 @@ The design docs and ADRs matter because they explain why the product is credible Use language like: -- "verified across five framework families" +- "verified across six framework families" - "one runtime model across modern frameworks" - "verified, not demo-only" - "reproducible local benchmark commands" diff --git a/docs/site/structure/README.md b/docs/site/structure/README.md index c6d27b30..e4e43988 100644 --- a/docs/site/structure/README.md +++ b/docs/site/structure/README.md @@ -80,7 +80,7 @@ must be resolved before implementation: ## Facts the copy relies on (verify before shipping) -- 20 browser-verified example apps: 5 framework families × 4 locale +- 24 browser-verified example apps: 6 framework families × 4 locale strategies (cookie, route, subdomain, TLD) — see `examples/`. - Demo links are **explicit per matrix cell with a hosting status** (`FRAMEWORK_MATRIX_CELLS` in `components.jsx`), mirroring the per-strategy @@ -89,8 +89,8 @@ must be resolved before implementation: Subdomain/tld cells carry status `provisioning` and render no demo link until the hosting story is reconciled (#306). Never derive demo URLs from a single naming pattern. -- E2E extract/update benchmark medians: 33.58 ms (small), 47.77 ms (medium); - 21.00× vs Lingui, 15.68× vs i18next-parser on the checked machine-local run +- E2E extract/update benchmark: 12.99× vs Lingui and 9.00× vs i18next-parser + on the checked 1,500-file machine-local run — see `benchmarks/e2e-workflow/results/latest.md`. - 16 ADRs in `adr/`. - CLI binary is `pmds`; recommended install is the scoped `@palamedes/*` diff --git a/docs/site/structure/components.jsx b/docs/site/structure/components.jsx index d72b0063..1d29f37a 100644 --- a/docs/site/structure/components.jsx +++ b/docs/site/structure/components.jsx @@ -141,7 +141,7 @@ export function CodeShowcase(props) {} export function FeatureGrid(props) {} /** - * The 5×4 framework/strategy matrix as an interactive table. + * The 6×4 framework/strategy matrix as an interactive table. * Rows: framework families. Columns: locale strategies. * * Cells carry EXPLICIT links and a per-cell status — never a generated URL @@ -158,7 +158,7 @@ export function FeatureGrid(props) {} * - strategies: Array<{ name, slug }> * - cells: Array<{ * framework, strategy, - * verified: true, // all 20 are CI browser-verified + * verified: true, // all 24 are CI verified * status: "live" | "provisioning", // public hosting state * demoLinks?: Array<{ label, href }>, // explicit, only when live * sourceHref, // example source in the repo diff --git a/docs/site/structure/pages/BlogIndexPage.jsx b/docs/site/structure/pages/BlogIndexPage.jsx index 58628e88..6c0864a9 100644 --- a/docs/site/structure/pages/BlogIndexPage.jsx +++ b/docs/site/structure/pages/BlogIndexPage.jsx @@ -48,9 +48,9 @@ export function BlogIndexPage() { /> +

- All 20 apps are verified in CI with the same Playwright-driven browser flow: SSR output, - locale switching, localized server actions. Screenshots are versioned in the repo. Cookie - and route demos are publicly hosted today; subdomain and TLD hosting is being provisioned - — until then those cells link the verified source instead. + All 24 apps are verified in CI: SSR output, locale switching, localized server actions or + server handlers. Screenshots are versioned in the repo. Cookie and route demos are + publicly hosted for the established adapters today; subdomain, TLD, and Remix v3 public + hosting are being provisioned — until then those cells link the verified source instead.

diff --git a/docs/site/structure/pages/HomePage.jsx b/docs/site/structure/pages/HomePage.jsx index 2932aa88..2615ae55 100644 --- a/docs/site/structure/pages/HomePage.jsx +++ b/docs/site/structure/pages/HomePage.jsx @@ -14,10 +14,10 @@ export function HomePage() { headline="One translation model. Every framework." subline="Write messages where your UI happens. Keep source-string-first .po catalogs your translators can actually read. Ship the same - runtime model across Next.js, TanStack Start, SolidStart, Waku, and - React Router — with a Rust core that ran the checked small-corpus - extract/update benchmark 21.0× faster than Lingui on the recorded - machine-local run." + runtime model across Next.js, TanStack Start, SolidStart, Waku, + React Router, and Remix v3 — with a Rust core that ran a checked + extract/update benchmark across a real-app-shaped 1,500-file corpus + 12.99× faster than Lingui on the recorded machine-local run." primary={{ label: "Get started in 5 minutes", href: "/get-started" }} secondary={{ label: "See it live", @@ -33,18 +33,19 @@ export function HomePage() { -

20 apps, verified in a real browser, on every change.

+

24 apps, verified in a real browser, on every change.

live demo · ◌ provisioning (#306) · ✓ CI - browser-verified — all 20 apps run the same Playwright flow + browser-verified — all 24 apps run the same verification flow

) diff --git a/site/app/components/home/ProofStrip.tsx b/site/app/components/home/ProofStrip.tsx index 1f5c6b9d..546a0044 100644 --- a/site/app/components/home/ProofStrip.tsx +++ b/site/app/components/home/ProofStrip.tsx @@ -12,8 +12,8 @@ interface Stat { } const STATS: Stat[] = [ - { value: "20", label: "browser-verified example apps", href: "/frameworks" }, - { value: "5 × 4", label: "frameworks × locale strategies", href: "/frameworks" }, + { value: "24", label: "verified example apps", href: "/frameworks" }, + { value: "6 × 4", label: "frameworks × locale strategies", href: "/frameworks" }, { value: "12.99×", label: "faster than Lingui — realistic 1,500-file extract/update benchmark, machine-local run", diff --git a/site/app/components/proof/ScreenshotStrip.tsx b/site/app/components/proof/ScreenshotStrip.tsx index e5829104..b9d95463 100644 --- a/site/app/components/proof/ScreenshotStrip.tsx +++ b/site/app/components/proof/ScreenshotStrip.tsx @@ -23,7 +23,8 @@ const SHOTS: Shot[] = [ /* * Filmstrip of real, versioned Playwright captures — the "diffable artifact" - * the copy talks about. Four of the twenty; the link leads to the full set. + * the copy talks about. Four of the established UI-adapter set; the link leads + * to the full screenshot set. */ export function ScreenshotStrip() { return ( @@ -55,7 +56,7 @@ export function ScreenshotStrip() { href={docsHref("example-screenshots")} className="mono-nums mt-3 inline-block text-[13px] text-accent" > - All 20 versioned screenshots → + All versioned screenshots → ) diff --git a/site/app/data/matrix.ts b/site/app/data/matrix.ts index 57e5fc1c..b9025e91 100644 --- a/site/app/data/matrix.ts +++ b/site/app/data/matrix.ts @@ -36,6 +36,7 @@ export const FRAMEWORKS: MatrixAxis[] = [ { name: "SolidStart", slug: "solidstart" }, { name: "Waku", slug: "waku" }, { name: "React Router", slug: "react-router" }, + { name: "Remix v3", slug: "remix" }, ] export const STRATEGIES: MatrixAxis[] = [ @@ -45,24 +46,30 @@ export const STRATEGIES: MatrixAxis[] = [ { name: "TLD", slug: "tld" }, ] +const HOSTED_FRAMEWORKS = new Set(["nextjs", "tanstack", "solidstart", "waku", "react-router"]) + export const MATRIX_CELLS: MatrixCell[] = FRAMEWORKS.flatMap(({ slug: framework }) => [ { framework, strategy: "cookie", verified: true as const, - status: "live" as const, - demoLinks: [{ label: "open", href: `https://${framework}-cookie.examples.palamedes.dev` }], + status: HOSTED_FRAMEWORKS.has(framework) ? ("live" as const) : ("provisioning" as const), + demoLinks: HOSTED_FRAMEWORKS.has(framework) + ? [{ label: "open", href: `https://${framework}-cookie.examples.palamedes.dev` }] + : undefined, sourceHref: repoHref(`examples/${framework}-cookie`, "tree"), }, { framework, strategy: "route", verified: true as const, - status: "live" as const, - demoLinks: ["en", "de", "es"].map((locale) => ({ - label: locale, - href: `https://${framework}-route.examples.palamedes.dev/${locale}`, - })), + status: HOSTED_FRAMEWORKS.has(framework) ? ("live" as const) : ("provisioning" as const), + demoLinks: HOSTED_FRAMEWORKS.has(framework) + ? ["en", "de", "es"].map((locale) => ({ + label: locale, + href: `https://${framework}-route.examples.palamedes.dev/${locale}`, + })) + : undefined, sourceHref: repoHref(`examples/${framework}-route`, "tree"), }, { diff --git a/site/app/data/posts.ts b/site/app/data/posts.ts index 5836db2c..c57b7082 100644 --- a/site/app/data/posts.ts +++ b/site/app/data/posts.ts @@ -32,9 +32,9 @@ export const POSTS: Post[] = [ readMinutes: 7, }, { - title: "Browser-verifying i18n across five frameworks", + title: "Browser-verifying i18n across six frameworks", excerpt: - "How 20 example apps get driven by the same Playwright flow in CI — and why versioned screenshots beat compatibility tables.", + "How 24 example apps get driven by the same verification flow in CI — and why versioned screenshots beat compatibility tables.", href: blogHref("browser-verifying-i18n-across-five-frameworks"), readMinutes: 6, }, diff --git a/site/app/hooks/useCountUp.ts b/site/app/hooks/useCountUp.ts index a774ad7a..439979e9 100644 --- a/site/app/hooks/useCountUp.ts +++ b/site/app/hooks/useCountUp.ts @@ -3,8 +3,8 @@ import { useEffect, useState } from "react" import { usePrefersReducedMotion } from "./usePrefersReducedMotion" /* - * Animates the leading number of a stat string ("21.0×" → 0.0×…21.0×, - * "5 × 4" animates only the first number). Returns the final string during + * Animates the leading number of a stat string ("12.99×" → 0.00×…12.99×, + * "6 × 4" animates only the first number). Returns the final string during * prerender, under reduced motion, and while inactive — the baked HTML always * shows the true value. */ diff --git a/site/app/routes.ts b/site/app/routes.ts index 5fb1c563..638b1bd3 100644 --- a/site/app/routes.ts +++ b/site/app/routes.ts @@ -46,6 +46,7 @@ export default [ route("docs/api/extractor", "routes/docs/api/extractor/index.md"), route("docs/api/next-plugin", "routes/docs/api/next-plugin/index.md"), route("docs/api/react", "routes/docs/api/react/index.md"), + route("docs/api/remix", "routes/docs/api/remix/index.md"), route("docs/api/runtime", "routes/docs/api/runtime/index.md"), route("docs/api/solid", "routes/docs/api/solid/index.md"), route("docs/api/transform", "routes/docs/api/transform/index.md"), diff --git a/site/app/routes/frameworks.tsx b/site/app/routes/frameworks.tsx index b519eb66..54202628 100644 --- a/site/app/routes/frameworks.tsx +++ b/site/app/routes/frameworks.tsx @@ -13,9 +13,9 @@ export const handle = { layout: "bare" } export function meta() { return pageMeta({ - title: "Palamedes — one i18n model across five framework families", + title: "Palamedes — one i18n model across six framework families", description: - "Five frameworks, four locale strategies, one mental model: the browser-verified Palamedes example matrix across Next.js, TanStack Start, SolidStart, Waku, and React Router.", + "Six frameworks, four locale strategies, one mental model: the browser-verified Palamedes example matrix across Next.js, TanStack Start, SolidStart, Waku, React Router, and Remix v3.", path: "/frameworks", }) } @@ -26,7 +26,7 @@ export default function Frameworks() {

Framework matrix

- Five frameworks. Four locale strategies. One mental model. + Six frameworks. Four locale strategies. One mental model.

Every cell below is a real application — the same booking UI, the same catalogs, the same @@ -41,13 +41,14 @@ export default function Frameworks() {

-
+

- All 20 apps are verified in CI with the same Playwright-driven browser flow: SSR output, - locale switching, localized server actions. Screenshots are versioned in the repo. Cookie - and route demos are publicly hosted today; subdomain and TLD hosting is being provisioned - — until then those cells link the verified source instead. + All 24 apps are verified in CI: SSR output, locale switching, localized server actions or + server handlers. Screenshots cover the established UI-adapter matrix and are versioned in + the repo. Cookie and route demos are publicly hosted for the established adapters today; + subdomain, TLD, and Remix v3 public hosting are being provisioned — until then those cells + link the verified source instead.

diff --git a/site/app/routes/home.tsx b/site/app/routes/home.tsx index 92d36049..66a17a97 100644 --- a/site/app/routes/home.tsx +++ b/site/app/routes/home.tsx @@ -24,7 +24,7 @@ export function meta() { return pageMeta({ title: "Palamedes — i18n that survives your next framework migration", description: - "Open-source i18n tooling for JavaScript & TypeScript: one translation model across Next.js, TanStack Start, SolidStart, Waku, and React Router, with a Rust core and source-string-first .po catalogs.", + "Open-source i18n tooling for JavaScript & TypeScript: one translation model across Next.js, TanStack Start, SolidStart, Waku, React Router, and Remix v3, with a Rust core and source-string-first .po catalogs.", path: "/", }) } @@ -50,9 +50,9 @@ export default function Home() {

Write messages where your UI happens. Keep source-string-first .po catalogs your translators can actually read. Ship the same runtime model across Next.js, TanStack - Start, SolidStart, Waku, and React Router — with a Rust core that ran a checked - extract/update benchmark across a real-app-shaped 1,500-file corpus 12.99× faster than - Lingui on the recorded machine-local run. + Start, SolidStart, Waku, React Router, and Remix v3 — with a Rust core that ran a + checked extract/update benchmark across a real-app-shaped 1,500-file corpus 12.99× + faster than Lingui on the recorded machine-local run.

Get started in 5 minutes diff --git a/site/app/routes/proof.tsx b/site/app/routes/proof.tsx index c3dfd76d..06d15d6e 100644 --- a/site/app/routes/proof.tsx +++ b/site/app/routes/proof.tsx @@ -16,7 +16,7 @@ export function meta() { return pageMeta({ title: "Palamedes — benchmarks, verification, and the decision trail", description: - "Claims you can re-run: checked-in extract/update benchmarks against Lingui and i18next-parser, 20 browser-verified example apps, and 16 architecture decision records.", + "Claims you can re-run: checked-in extract/update benchmarks against Lingui and i18next-parser, 24 browser-verified example apps, and 16 architecture decision records.", path: "/proof", }) } @@ -24,7 +24,7 @@ export function meta() { const VERIFICATION_STEPS = [ { title: "Build", - body: "All 20 example apps build against the workspace packages — no mocked integrations.", + body: "All 24 example apps build against the workspace packages — no mocked integrations.", }, { title: "Drive", @@ -83,7 +83,7 @@ export default function Proof() {
{VERIFICATION_STEPS.map((step, index) => (