From 0541e00259652df97e7f213012adf08851ef0b13 Mon Sep 17 00:00:00 2001 From: JK Date: Wed, 17 Jun 2026 20:52:01 +0900 Subject: [PATCH 1/2] Expose an internal review route without publishing test content Constraint: The user requested an App Router page.tsx rather than MDX content, with only a title and description visible for now. Rejected: MDX content page | It would route through the documentation content pipeline instead of an independent app route. Confidence: high Scope-risk: narrow Directive: Keep /{locale}/internal as a sparse internal landing surface until concrete test pages are intentionally added. Tested: npm run test:run -- 'src/app/[lang]/internal/page.test.tsx'; npm run lint -- 'src/app/[lang]/internal/page.tsx' 'src/app/[lang]/internal/page.test.tsx'; npx tsc --noEmit; git diff --check Not-tested: Browser rendering against a deployed preview URL is pending PR deployment. Co-Authored-By: Atlas --- src/app/[lang]/internal/page.test.tsx | 31 ++++++++++ src/app/[lang]/internal/page.tsx | 88 +++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 src/app/[lang]/internal/page.test.tsx create mode 100644 src/app/[lang]/internal/page.tsx diff --git a/src/app/[lang]/internal/page.test.tsx b/src/app/[lang]/internal/page.test.tsx new file mode 100644 index 000000000..15a8ee16f --- /dev/null +++ b/src/app/[lang]/internal/page.test.tsx @@ -0,0 +1,31 @@ +import { render, within } from '@testing-library/react'; +import { describe, expect, it } from 'vitest'; + +import InternalPage, { generateMetadata, generateStaticParams } from './page'; + +describe('/[lang]/internal page', () => { + it('generates locale params for internal test pages', () => { + expect(generateStaticParams()).toEqual([{ lang: 'en' }, { lang: 'ja' }, { lang: 'ko' }]); + }); + + it('renders the Korean internal page title and description only', async () => { + const container = document.createElement('div'); + const result = render(await InternalPage({ params: Promise.resolve({ lang: 'ko' }) }), { + baseElement: container, + container, + }); + + expect(within(result.container).getByRole('heading', { level: 1, name: '내부 페이지' })).toBeTruthy(); + expect( + within(result.container).getByText('검토와 구현 참고를 위해 유지 중인 내부 컴포넌트 및 페이지 예시 목록입니다.'), + ).toBeTruthy(); + expect(within(result.container).queryByRole('list')).not.toBeInTheDocument(); + }); + + it('uses the same copy for route metadata', async () => { + await expect(generateMetadata({ params: Promise.resolve({ lang: 'ko' }) })).resolves.toMatchObject({ + description: '검토와 구현 참고를 위해 유지 중인 내부 컴포넌트 및 페이지 예시 목록입니다.', + title: '내부 페이지', + }); + }); +}); diff --git a/src/app/[lang]/internal/page.tsx b/src/app/[lang]/internal/page.tsx new file mode 100644 index 000000000..a7ea29871 --- /dev/null +++ b/src/app/[lang]/internal/page.tsx @@ -0,0 +1,88 @@ +import type { Metadata } from 'next'; + +type InternalPageParams = { + lang: string; +}; + +type InternalPageProps = { + params: Promise; +}; + +type InternalPageCopy = { + description: string; + title: string; +}; + +const internalPageCopy: Record = { + en: { + description: 'A list of internal component and page examples maintained for review and implementation reference.', + title: 'Internal Pages', + }, + ja: { + description: 'レビューと実装参考のために維持している内部コンポーネントおよびページ例の一覧です。', + title: '内部ページ', + }, + ko: { + description: '검토와 구현 참고를 위해 유지 중인 내부 컴포넌트 및 페이지 예시 목록입니다.', + title: '내부 페이지', + }, +}; + +const locales = Object.keys(internalPageCopy); + +function getInternalPageCopy(lang: string) { + return internalPageCopy[lang] ?? internalPageCopy.en; +} + +export function generateStaticParams() { + return locales.map(lang => ({ lang })); +} + +export async function generateMetadata({ params }: InternalPageProps): Promise { + const { lang } = await params; + const copy = getInternalPageCopy(lang); + + return { + description: copy.description, + title: copy.title, + }; +} + +export default async function InternalPage({ params }: InternalPageProps) { + const { lang } = await params; + const copy = getInternalPageCopy(lang); + + return ( +
+

+ {copy.title} +

+

+ {copy.description} +

+
+ ); +} From 8ae376931fe807d68bf1872c108fc50114a5bd28 Mon Sep 17 00:00:00 2001 From: JK Date: Wed, 17 Jun 2026 21:37:42 +0900 Subject: [PATCH 2/2] Keep internal route metadata safe during static generation Constraint: Next/Nextra static generation invoked the new internal route metadata with missing params. Rejected: Disabling metadata generation | The route still needs localized metadata and a safe fallback. Confidence: high Scope-risk: narrow Directive: Keep App Router metadata functions tolerant of omitted params when they can be called by static generation. Tested: npm run test:run -- 'src/app/[lang]/internal/page.test.tsx'; npm run lint -- 'src/app/[lang]/internal/page.tsx' 'src/app/[lang]/internal/page.test.tsx'; npx tsc --noEmit; npm run build; git diff --check Not-tested: Preview deployment rerun result pending after push. Co-Authored-By: Atlas --- src/app/[lang]/internal/page.test.tsx | 7 +++++++ src/app/[lang]/internal/page.tsx | 12 +++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/app/[lang]/internal/page.test.tsx b/src/app/[lang]/internal/page.test.tsx index 15a8ee16f..a49590d99 100644 --- a/src/app/[lang]/internal/page.test.tsx +++ b/src/app/[lang]/internal/page.test.tsx @@ -28,4 +28,11 @@ describe('/[lang]/internal page', () => { title: '내부 페이지', }); }); + + it('falls back to English metadata when static generation omits params', async () => { + await expect(generateMetadata({})).resolves.toMatchObject({ + description: 'A list of internal component and page examples maintained for review and implementation reference.', + title: 'Internal Pages', + }); + }); }); diff --git a/src/app/[lang]/internal/page.tsx b/src/app/[lang]/internal/page.tsx index a7ea29871..b5e94accd 100644 --- a/src/app/[lang]/internal/page.tsx +++ b/src/app/[lang]/internal/page.tsx @@ -5,7 +5,7 @@ type InternalPageParams = { }; type InternalPageProps = { - params: Promise; + params?: Promise; }; type InternalPageCopy = { @@ -34,12 +34,18 @@ function getInternalPageCopy(lang: string) { return internalPageCopy[lang] ?? internalPageCopy.en; } +async function getInternalPageLang(params: InternalPageProps['params']) { + const resolvedParams = await params; + + return resolvedParams?.lang ?? 'en'; +} + export function generateStaticParams() { return locales.map(lang => ({ lang })); } export async function generateMetadata({ params }: InternalPageProps): Promise { - const { lang } = await params; + const lang = await getInternalPageLang(params); const copy = getInternalPageCopy(lang); return { @@ -49,7 +55,7 @@ export async function generateMetadata({ params }: InternalPageProps): Promise