Skip to content

feat(registry): add next-intl localized routes#350

Open
bntvllnt wants to merge 7 commits into
mainfrom
feat/281-i18n
Open

feat(registry): add next-intl localized routes#350
bntvllnt wants to merge 7 commits into
mainfrom
feat/281-i18n

Conversation

@bntvllnt
Copy link
Copy Markdown
Collaborator

@bntvllnt bntvllnt commented May 13, 2026

Summary

  • Add next-intl routing for English and French registry app pages, with localized metadata, hreflang alternates, sitemap entries, and locale-aware navigation/chrome.
  • Move MDX page content to content/pages/<slug>/<locale>.mdx, add French pages, and add a CI translation check for required default-locale MDX.
  • Keep machine endpoints canonical while adding localized llms routes and /r/<name>.<locale>.json description overlays.
  • Remediate the i18n/SEO blocker for comparison routes: /fr/vs and /fr/vs/shadcn now have French metadata and visible French body/table copy, so the advertised French canonical, sitemap, and hreflang alternates no longer point at English-only comparison pages.
  • Reconciled the branch with current origin/main after PR fix(registry): upgrade Next.js to 16.2.6 #357 by preserving the PR's localized-route changes and main's Next.js / @next/mdx 16.2.6 update in apps/registry/package.json and pnpm-lock.yaml.

Dependency tradeoff

  • Adds next-intl to the registry app only. This brings next-intl, use-intl, and @formatjs/* runtime packages, but avoids a bespoke i18n router/message loader and matches the issue request.

Current head

  • fb51552cf235dd918bc90baf58fb8bda1add1a61

Validation

Latest not-found fix validation on fb51552cf235dd918bc90baf58fb8bda1add1a61:

  • PASS: tsc --noEmit --project tsconfig.json (0 errors)
  • PASS: targeted ESLint for app/[locale]/not-found.tsx, app/[locale]/llms.txt/route.ts, app/[locale]/llms-full.txt/route.ts
  • FIX: not-found.tsx converted from sync client component to async server component; useLocale/useTranslations replaced with getLocale/getTranslations from next-intl/server — resolves metadata + client-hook conflict that caused Next.js build error
  • FIX: functional/no-loop-statements eslint-disable removed from both llms route files; loops replaced with map+spread (llms.txt) and reduce (llms-full.txt)

Latest reconciliation validation on fb51552cf235dd918bc90baf58fb8bda1add1a61:

  • PASS: git diff --check
  • PASS: pnpm -F @vllnt/ui-registry check:translations
  • PASS: pnpm -F @vllnt/ui-registry exec tsc --noEmit --project tsconfig.json
  • PASS: pnpm -F @vllnt/ui-registry registry:build

Latest remediation validation on earlier head d66a08c69581cfc3ff69cd0213461890be0c4bc9:

  • PASS: pnpm -F @vllnt/ui-registry exec tsc --noEmit --project tsconfig.json
  • PASS: targeted ESLint for edited comparison route files: pnpm -F @vllnt/ui-registry exec eslint 'app/[locale]/vs/page.tsx' 'app/[locale]/vs/shadcn/page.tsx'
  • PASS: git diff --check
  • FAIL baseline/unrelated: pnpm -F @vllnt/ui-registry lint exited 1 with 221 existing errors outside the edited comparison files, including app/manifest.ts, app/mcp/route.ts, app/robots.ts, lib/jsonld.ts, registry scripts, and types/registry.ts.

Prior branch validation retained from earlier HEAD:

  • pnpm install --frozen-lockfile
  • pnpm -F @vllnt/ui lint
  • pnpm -F @vllnt/ui exec tsc --noEmit --project tsconfig.build.json
  • pnpm -F @vllnt/ui-registry exec tsc --noEmit --project tsconfig.json
  • pnpm build
  • pnpm test:once
  • pnpm -F @vllnt/ui-registry check:translations
  • pnpm -F @vllnt/ui check:use-client
  • pnpm -F @vllnt/ui exec tsx scripts/check-story-coverage.ts
  • pnpm -F @vllnt/ui exec tsx scripts/verify-stories.ts
  • pnpm -F @vllnt/ui build-storybook
  • git diff --check
  • Targeted registry ESLint over touched runtime route/component/lib files, including localized routes and llms routes.

Runtime smoke

After the earlier pnpm build, ran pnpm -F @vllnt/ui-registry exec next start -p 3011 and verified:

  • curl -I http://localhost:3011/en/llms.txt -> 308 to http://localhost:3011/llms.txt
  • curl -I http://localhost:3011/en/llms-full.txt -> 308 to http://localhost:3011/llms-full.txt
  • curl -I http://localhost:3011/request-component -> 200 with rewrite to /en/request-component and NEXT_LOCALE=en
  • curl http://localhost:3011/r/button.fr.json -> localized overlay JSON with locale: "fr", sourceLocale: "en", and canonical /r/button.json
  • curl http://localhost:3011/fr/llms.txt | head -8 -> French llms header/content

CI status

Current head fb51552cf235dd918bc90baf58fb8bda1add1a61 after the main-reconciliation push:

  • PASS: GitHub Actions checks are terminal/success: Analyze (actions), Analyze (javascript-typescript), CodeQL, Enforce issue-linked PRs, Quality Gates, Scan codebase health, Vercel Preview Comments.
  • PASS: Vercel – storybook deployed successfully.
  • BLOCKED: Vercel – ui.vllnt.ai is still failure on the current head with description Canceled from the Vercel Dashboard (target: https://vercel.com/vllnt/ui.vllnt.ai/CwXDsXZDRZ7Beqd4f6FAkrYURMuz).
  • REST PR state after push: mergeable=true, mergeable_state=unstable; not dirty/conflicting anymore, but still blocked by the failed ui.vllnt.ai status.

Closes #281

@bntvllnt bntvllnt added documentation Improvements or additions to documentation enhancement New feature or request seo Search engine optimization discoverability Site/library discoverability labels May 13, 2026
@bntvllnt bntvllnt self-assigned this May 13, 2026
# Conflicts:
#	apps/registry/package.json
#	pnpm-lock.yaml
Copy link
Copy Markdown
Collaborator Author

@bntvllnt bntvllnt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bntvllnt Review verdict: APPROVE recommended for reviewer triage — no source blockers found

Head reviewed: 053e00a11db6b02a688a887b3cf27b41be84bd71

No code blockers found after full changed-file review of the localized registry route/content implementation.

Evidence checked:

  • PR body references Closes #281 and names the current head.
  • CI includes pnpm -F @vllnt/ui-registry check:translations; local check:translations passed and en/fr message key parity is clean.
  • Locale routing, canonical/hreflang helpers, localized sitemap entries, machine route redirects, and localized overlay registry handling are internally consistent in the changed files.

STATUS

  • GitHub Actions/code checks are green and Vercel – storybook is SUCCESS.
  • Vercel – ui.vllnt.ai: FAILURE is eligible for the PM stale-Vercel reviewer-triage waiver only; it is not merge/release approval.
  • Validation gap: local registry TypeScript could not be reproduced because this local workspace lacks next-intl in node_modules; live GitHub Quality Gates are green.

@vllnt-pilot vllnt-pilot Bot had a problem deploying to Preview · pr-350-storybook May 18, 2026 17:14 Failure
@vllnt-pilot vllnt-pilot Bot had a problem deploying to Preview · pr-350-storybook May 18, 2026 17:21 Failure
@bntvllnt bntvllnt had a problem deploying to Preview · pr-350-ui-registry May 18, 2026 18:24 Failure
@vllnt-pilot
Copy link
Copy Markdown

vllnt-pilot Bot commented May 18, 2026

Preview ready · Updated 2026-05-20T14:43:12Z

Service Status Preview
ui-registry Ready https://pr-350-ui-registry.preview.vllnt.ai
Inspect
  • Tailnet-only by default (not reachable from public internet)
  • Cert: real Let's Encrypt wildcard
  • Reply with /clean to destroy this preview now

…e loops

- Replace useLocale/useTranslations (client hooks) with getLocale/getTranslations
  from next-intl/server so metadata export can coexist in the same file
- Remove functional/no-loop-statements eslint-disable from llms.txt and
  llms-full.txt routes; refactor for-loops to map+spread and reduce
Copy link
Copy Markdown
Collaborator Author

@bntvllnt bntvllnt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — 1 blocking finding

BLOCKING

  • C1 — French 404 still ships English metadata and CTA copy
    • Evidence: apps/registry/app/[locale]/not-found.tsx:8-11 exports static English metadata (Page not found, We couldn't find...) for every locale, and apps/registry/app/[locale]/not-found.tsx:52-65 hardcodes Read the docs / Request a component instead of using the existing common.readDocs / common.requestComponent messages.
    • Why it matters: this PR's core contract is localized registry routes. On /fr/... misses, the page body partly uses French via getTranslations, but the route still renders English CTA text and English document metadata while the layout declares html lang="fr". That leaves the French localized surface visibly incomplete and contradicts the PR's stated localization remediation.
    • Fix: replace the hardcoded CTA labels with translated messages and move the 404 metadata behind locale-aware generateMetadata/translation lookup (or otherwise return locale-specific metadata for [locale]).

WARN

  • None beyond the blocker above.

VERIFIED CLEAN

  • Re-fetched the live PR before publication: PR #350 is open/non-draft at fb51552cf235dd918bc90baf58fb8bda1add1a61, base main, merge state CLEAN.
  • Confirmed current checks are green for issue-link, Quality Gates, CodeQL, react-doctor, registry/storybook build/deploy, and preview deploy.
  • Reviewed the localized App Router migration, i18n request/routing/proxy setup, machine-readable llms routes, /r/[name] locale response behavior, sitemap/SEO helpers, content/sidebar loaders, translation messages, registry metadata/scripts, CI/package/lockfile changes, and generated registry artifacts. No additional blocking issue was found in those areas.
  • PR body includes Closes #281 and references the current head SHA.

VALIDATION

  • Ran/read: gh pr view 350 --repo vllnt/ui --json ... and gh pr checks 350 --repo vllnt/ui --json name,state,bucket,link,workflow.
  • Inspected diff artifacts from detached worktree /home/ubuntu/ui/.worktrees/pr-350-review-t43617508 at fb51552cf235dd918bc90baf58fb8bda1add1a61 against origin/main.
  • Attempted local pnpm -F @vllnt/ui-registry check:translations; it could not run in the detached worktree because local node_modules/tsx are missing (spawn ENOENT). I did not treat that environment failure as PR code evidence.

Note: authenticated reviewer appears to be the PR author, so this is a blocking COMMENT review rather than an autonomous approval or merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

discoverability Site/library discoverability documentation Improvements or additions to documentation enhancement New feature or request seo Search engine optimization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: i18n with next-intl + per-locale MDX content (content/<slug>/<locale>.mdx)

1 participant