0a7076d5b9
Rewrites the i18n system introduced in PR #94 to use Next.js App Router [locale] dynamic segments with SSR-rendered translations and proper middleware locale routing. - Add middleware locale detection: / rewrites to /zh-CN/ internally, /en and /ja pass through, /zh-CN/... redirects to bare path - Move all 7 pages under app/[locale]/ with SSR translation injection - Fix server→client serialization: pre-evaluate function-valued translations (makeSerializable) to eliminate hydration flash - Fix language switch key flash: use hard navigation with localStorage- only persistence, avoiding React state update before page reload - Add <link rel="alternate" hreflang> tags for multilingual SEO - Fix Supabase setAll overwriting locale rewrite response - Trim locales from 22 to 3 (zh-CN/en/ja), delete 19 incomplete files - LLM-translate 240 firstact game preset JSONs (en + ja, landscape + portrait) and story titles via gemini-3.5-flash - Delete 11 one-off migration scripts and outdated i18n docs - Add useLocalePath hook and navigation utilities Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
69 lines
2.6 KiB
TypeScript
69 lines
2.6 KiB
TypeScript
import Link from "next/link";
|
||
import { CustomForm } from "@/components/CustomForm";
|
||
import { localePath } from "@/lib/i18n/navigation";
|
||
import { isValidLocale } from "@/lib/i18n/utils";
|
||
import { DEFAULT_LOCALE, type Locale } from "@/lib/i18n/config";
|
||
|
||
export default async function NewPage({
|
||
params,
|
||
}: {
|
||
params: Promise<{ locale: string }>;
|
||
}) {
|
||
const { locale: rawLocale } = await params;
|
||
const locale: Locale = isValidLocale(rawLocale) ? rawLocale : DEFAULT_LOCALE;
|
||
const lp = (path: string) => localePath(path, locale);
|
||
|
||
return (
|
||
<div className="min-h-screen flex flex-col">
|
||
<header className="px-6 md:px-16 pt-7 md:pt-10 flex items-center justify-between">
|
||
<Link
|
||
href={lp("/")}
|
||
className="text-[10px] smallcaps text-clay-700 hover:text-clay-900 transition-colors flex items-center gap-2"
|
||
>
|
||
<i className="fa-solid fa-arrow-left text-[9px]" />
|
||
InfiPlot
|
||
</Link>
|
||
<span className="text-[10px] smallcaps text-clay-500">
|
||
编 织 一 个 世 界
|
||
</span>
|
||
</header>
|
||
|
||
<section className="px-6 md:px-16 pt-20 md:pt-32 pb-20 md:pb-24 flex-1">
|
||
<div className="grid grid-cols-12 gap-8 md:gap-16 max-w-6xl">
|
||
<div className="col-span-12 md:col-span-4 animate-fade-in">
|
||
<p className="text-[10px] smallcaps text-clay-500 mb-6">
|
||
Ⅳ · 无 题
|
||
</p>
|
||
<h1 className="font-serif text-[44px] md:text-[64px] text-clay-900 leading-[0.96] mb-8">
|
||
写下
|
||
<br />
|
||
<em className="italic text-clay-600">两段</em>
|
||
<br />
|
||
文字。
|
||
</h1>
|
||
<div className="hairline w-12 mb-6" />
|
||
<p className="font-serif text-base text-clay-700 leading-[1.7]">
|
||
第一段,勾勒故事所在的世界。第二段,描述世界应是什么模样 —
|
||
它的介质、氛围、颗粒感。
|
||
</p>
|
||
<p className="font-serif italic text-sm text-clay-500 mt-5 leading-relaxed">
|
||
两栏皆可任意语言。越具体,回报越具体。
|
||
</p>
|
||
</div>
|
||
<div className="col-span-12 md:col-span-7 md:col-start-6">
|
||
<CustomForm />
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<footer className="px-6 md:px-16 pb-8">
|
||
<div className="hairline-full w-full mb-4" />
|
||
<div className="flex items-center justify-between text-[10px] smallcaps text-clay-500">
|
||
<span>MMXXVI</span>
|
||
<span className="num">Ⅰ · Ⅳ</span>
|
||
</div>
|
||
</footer>
|
||
</div>
|
||
);
|
||
}
|