From a394dcfae63aa708baa4ec795a3f0a065c60cbfe Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2026 11:22:40 +0000 Subject: [PATCH] =?UTF-8?q?fix(not-found):=20=E6=94=B9=20Server=20Componen?= =?UTF-8?q?t=20=E4=BF=AE=20Server=20Action=20=E8=B7=AF=E5=BE=84=E4=B8=8B?= =?UTF-8?q?=20useTranslations=20=E5=B4=A9=E6=BA=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 爬虫向 / POST 时 Next 走 Server Action 路径,未匹配到 action 后渲染 not-found.tsx 不经过 root layout,NextIntlClientProvider 不在 React 树里, useTranslations 抛 "No intl context" 直接 500 上报 Sentry。 改用 next-intl/server 的 getTranslations,绕开 client provider 依赖。 umami 埋点拆到 not-found-tracker.tsx 作为 client 子组件挂载。 Sentry: SENTRY-BOLE-NOTEBOOK-2 --- app/not-found-tracker.tsx | 22 ++++++++++++++++++++++ app/not-found.tsx | 26 +++++++++----------------- 2 files changed, 31 insertions(+), 17 deletions(-) create mode 100644 app/not-found-tracker.tsx diff --git a/app/not-found-tracker.tsx b/app/not-found-tracker.tsx new file mode 100644 index 0000000..e30ffae --- /dev/null +++ b/app/not-found-tracker.tsx @@ -0,0 +1,22 @@ +"use client"; + +import { useEffect } from "react"; +import { usePathname } from "next/navigation"; + +// 从 not-found.tsx 拆出来的 umami 404 埋点。 +// 拆分原因:not-found.tsx 必须保持 Server Component(见同目录 not-found.tsx 注释), +// useEffect / usePathname / window.umami 只能在 client。 +export default function NotFoundTracker() { + const pathname = usePathname(); + + useEffect(() => { + if (window.umami) { + window.umami.track("error_404", { + path: pathname, + referrer: document.referrer || "direct", + }); + } + }, [pathname]); + + return null; +} diff --git a/app/not-found.tsx b/app/not-found.tsx index 7364fa6..2d74202 100644 --- a/app/not-found.tsx +++ b/app/not-found.tsx @@ -1,23 +1,14 @@ -"use client"; - import Link from "next/link"; -import { useEffect } from "react"; -import { usePathname } from "next/navigation"; -import { useTranslations } from "next-intl"; +import { getTranslations } from "next-intl/server"; import { Button } from "@/app/components/ui/button"; +import NotFoundTracker from "./not-found-tracker"; -export default function NotFound() { - const pathname = usePathname(); - const t = useTranslations("notFound"); - - useEffect(() => { - if (window.umami) { - window.umami.track("error_404", { - path: pathname, - referrer: document.referrer || "direct", - }); - } - }, [pathname]); +// 必须是 Server Component:爬虫向 / 发 POST 时 Next 走 Server Action 路径, +// not-found 渲染不经过 layout,NextIntlClientProvider 不在树里, +// useTranslations 会抛 "No intl context"。getTranslations 走 server, +// 直接读 i18n/request.ts,没有 provider 依赖。 +export default async function NotFound() { + const t = await getTranslations("notFound"); return (
@@ -32,6 +23,7 @@ export default function NotFound() { {t("cta")}
+ ); }