Files
multica/apps/docs/middleware.ts
Naiyuan Qing e395fb8744 docs: four-language documentation overhaul with verified facts and product screenshots (MUL-5057) (#5714)
Complete rework of the docs site, in three passes squashed into one change:

1. P0 fact corrections across the core-loop pages (agent access model,
   comment triggers and coalescing, issue lifecycle, offline/queue
   semantics, task states and retries, dispatch via realtime push).
2. Chinese rewrite as the authoring language: final 12-group IA, new
   "Core concepts" and "Put agents to work" pages, curated welcome page,
   permanent-UI quickstart (no onboarding-wizard dependency), operator
   reference restored (CLI command reference, webhook response codes,
   task state/timeout tables, config set keys, upgrade notes).
3. Verification and sync: every load-bearing claim re-checked against
   current main with file:line evidence (migration 103 auto-backfill,
   CLI-only trigger toggling, duplication semantics, COOKIE_DOMAIN,
   GitHub App variables, Qwen Code as the 17th provider); register
   standards applied to all 39 pages; en/ja/ko synced from zh with
   same-language heading anchors (verified, zero dead links);
   17 product screenshots plus 2 diagrams wired in.

Supporting fixes: i18n middleware no longer swallows /images assets,
sidebar folder indent survives custom link padding, unused editorial
components removed.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 14:09:41 +08:00

57 lines
2.5 KiB
TypeScript

import { NextResponse, type NextRequest } from "next/server";
import { i18n } from "@/lib/i18n";
const BASE_PATH = "/docs";
// Self-contained i18n middleware. We don't use fumadocs-core's built-in
// middleware because it isn't basePath-aware — both its rewrite targets
// and redirect Location headers are built from the basePath-stripped path,
// leaving URLs like `/en/agents` or `/` that Next then fails to resolve
// inside a basePath-mounted app. Logic mirrors fumadocs's default-locale
// flavor: hide `/en` prefix for the default language, keep `/zh` prefix
// for other languages.
export default function middleware(request: NextRequest) {
const pathname = request.nextUrl.pathname;
const pathLocale = i18n.languages.find(
(loc) => pathname === `/${loc}` || pathname.startsWith(`/${loc}/`),
);
if (!pathLocale) {
// No locale in URL → rewrite to the default-language route. Build the
// target from `request.url` (which includes basePath); `new URL(path,
// base)` replaces only the pathname, so we emit the full prefixed path
// once and Next does not double-add basePath.
const target = `${BASE_PATH}/${i18n.defaultLanguage}${pathname === "/" ? "" : pathname}`;
return NextResponse.rewrite(new URL(target, request.url));
}
if (pathLocale === i18n.defaultLanguage) {
// Explicit default-language prefix → strip it so the canonical URL
// is prefix-less. Use the same `new URL(target, request.url)` pattern
// as the rewrite branch above, then explicitly carry the search string
// through — otherwise marketing UTMs / referral params silently
// disappear on the locale strip.
const stripped = pathname.slice(`/${pathLocale}`.length);
const target = `${BASE_PATH}${stripped || "/"}`;
const url = new URL(target, request.url);
url.search = request.nextUrl.search;
return NextResponse.redirect(url);
}
// Non-default locale in URL → let it through; Next matches on the
// `[lang]` segment directly.
return NextResponse.next();
}
export const config = {
// Run on every path except static/api and root metadata routes. Includes
// the bare `/` root so `/docs/` lands on the English home. `sitemap.xml`
// and `robots.txt` MUST be excluded — they're not under `[lang]/`, so
// routing them through the locale rewrite would 404 the sitemap that
// robots.txt advertises to crawlers.
matcher: [
"/((?!api|_next/static|_next/image|images|favicon.ico|sitemap.xml|robots.txt).*)",
"/",
],
};