返回 CodeWhale
route-state.tsx
根目录 / web / components / route-state.tsx
1 "use client";
2
3 import Link from "next/link";
4 import { usePathname } from "next/navigation";
5 import { defaultLocale } from "@/lib/i18n/config";
6 import { getStates } from "@/lib/i18n/dictionaries";
7 import { pathLocale } from "@/lib/i18n/path";
8 import { RetryAction } from "./retry-action";
9 import { EmptyState, ErrorState, LoadingState } from "./surface-state";
10
11 /**
12 * Route boundaries — `loading.tsx`, `error.tsx`, `not-found.tsx` — receive
13 * no params, so these thin client shims read the locale from the pathname
14 * and render the shared surface states with dictionary copy.
15 */
16 function useRouteLocale(): string {
17 const pathname = usePathname();
18 return pathLocale(pathname ?? "") ?? defaultLocale;
19 }
20
21 export function LoadingRoute() {
22 const locale = useRouteLocale();
23 return <LoadingState locale={locale} lines={4} />;
24 }
25
26 export function ErrorRoute({ reset, digest }: { reset: () => void; digest?: string }) {
27 const locale = useRouteLocale();
28 const t = getStates(locale);
29 return (
30 <ErrorState
31 locale={locale}
32 titleAs="h1"
33 body={digest ? `${t.errorBody} (${digest})` : t.errorBody}
34 action={
35 <>
36 <RetryAction label={t.retry} onRetry={reset} />
37 <Link href={`/${locale}`} className="portal-button portal-button-secondary">
38 {t.homeLink}
39 </Link>
40 </>
41 }
42 />
43 );
44 }
45
46 export function NotFoundRoute() {
47 const locale = useRouteLocale();
48 const t = getStates(locale);
49 // The plate is the whole page, so its title is the page's <h1>. The body
50 // names the documentation index; the primary action is that index, and
51 // the home link is the secondary way out.
52 return (
53 <EmptyState
54 locale={locale}
55 title={t.notFoundTitle}
56 body={t.notFoundBody}
57 titleAs="h1"
58 action={
59 <>
60 <Link href={`/${locale}/docs`} className="portal-button portal-button-primary">
61 {t.docsIndexLink}
62 </Link>
63 <Link href={`/${locale}`} className="portal-button portal-button-secondary">
64 {t.homeLink}
65 </Link>
66 </>
67 }
68 />
69 );
70 }
71
71 lines Plain Text