diff --git a/next.config.ts b/next.config.ts index 65c102b..a18b38e 100644 --- a/next.config.ts +++ b/next.config.ts @@ -2,6 +2,7 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { output: "export", + trailingSlash: true, }; export default nextConfig; diff --git a/public/error/404-messages.yml b/public/error/404-messages.yml index 0253210..0540354 100644 --- a/public/error/404-messages.yml +++ b/public/error/404-messages.yml @@ -1,10 +1,10 @@ # Random 404 messages grouped by locale. -zh-CN: +zh-Hans: - 人与人的悲欢不尽相同 - 此处没有列车经过 - 这条线路还没有开通 - 你抵达了地图之外的地方 -zh-TW: +zh-Hant: - 人與人的悲歡並不相同 - 此處沒有列車經過 - 這條路線尚未通車 @@ -14,7 +14,7 @@ en: - No train stops here - This line has not opened yet - You have reached the edge of the map -ja: +jp: - 人それぞれ、喜びも悲しみも違う - ここを通る列車はありません - この路線はまだ開通していません diff --git a/src/app/403/page.tsx b/src/app/(legacy)/403/page.tsx similarity index 100% rename from src/app/403/page.tsx rename to src/app/(legacy)/403/page.tsx diff --git a/src/app/500/page.tsx b/src/app/(legacy)/500/page.tsx similarity index 100% rename from src/app/500/page.tsx rename to src/app/(legacy)/500/page.tsx diff --git a/src/app/502/page.tsx b/src/app/(legacy)/502/page.tsx similarity index 100% rename from src/app/502/page.tsx rename to src/app/(legacy)/502/page.tsx diff --git a/src/app/503/page.tsx b/src/app/(legacy)/503/page.tsx similarity index 100% rename from src/app/503/page.tsx rename to src/app/(legacy)/503/page.tsx diff --git a/src/app/504/page.tsx b/src/app/(legacy)/504/page.tsx similarity index 100% rename from src/app/504/page.tsx rename to src/app/(legacy)/504/page.tsx diff --git a/src/app/(legacy)/layout.tsx b/src/app/(legacy)/layout.tsx new file mode 100644 index 0000000..7fbebd9 --- /dev/null +++ b/src/app/(legacy)/layout.tsx @@ -0,0 +1 @@ +export { default, metadata, viewport } from "@/components/layout/site-document"; diff --git a/src/app/news/[slug]/page.tsx b/src/app/(legacy)/news/[slug]/page.tsx similarity index 75% rename from src/app/news/[slug]/page.tsx rename to src/app/(legacy)/news/[slug]/page.tsx index 5242baf..117c8f9 100644 --- a/src/app/news/[slug]/page.tsx +++ b/src/app/(legacy)/news/[slug]/page.tsx @@ -1,6 +1,7 @@ import type { Metadata } from "next"; import { getNewsBySlug, getNewsCatalog, getNewsList } from "@/data/news"; import { NewsDetailClient } from "@/components/news/news-detail-client"; +import { isLocale } from "@/lib/i18n"; export async function generateStaticParams() { const news = await getNewsList(); @@ -11,10 +12,10 @@ export async function generateStaticParams() { export async function generateMetadata({ params, }: { - params: Promise<{ slug: string }>; + params: Promise<{ slug: string; locale?: string }>; }): Promise { - const { slug } = await params; - const item = await getNewsBySlug(slug); + const { slug, locale } = await params; + const item = await getNewsBySlug(slug, isLocale(locale) ? locale : "zh-Hans"); return { title: item?.title ?? "新闻", diff --git a/src/app/news/page.tsx b/src/app/(legacy)/news/page.tsx similarity index 52% rename from src/app/news/page.tsx rename to src/app/(legacy)/news/page.tsx index 027f424..f46fcee 100644 --- a/src/app/news/page.tsx +++ b/src/app/(legacy)/news/page.tsx @@ -3,12 +3,16 @@ import { getNewsCatalog } from "@/data/news"; import { PageBreadcrumb } from "@/components/layout/page-breadcrumb"; import { NewsList } from "@/components/news/news-list"; import { NewsPageHeading } from "@/components/news/news-page-heading"; +import { getLocaleMessages, isLocale } from "@/lib/i18n"; -export const metadata: Metadata = { - title: "新闻", -}; +export async function generateMetadata({ params }: { params: Promise<{ locale?: string }> }): Promise { + const { locale } = await params; + return { title: getLocaleMessages(isLocale(locale) ? locale : "zh-Hans").common.news }; +} -export default async function NewsPage() { +export default async function NewsPage({ params }: { params: Promise<{ locale?: string }> }) { + const { locale } = await params; + const messages = getLocaleMessages(isLocale(locale) ? locale : "zh-Hans"); const catalog = await getNewsCatalog(); return ( @@ -22,7 +26,7 @@ export default async function NewsPage() {
- +
diff --git a/src/app/not-found.tsx b/src/app/(legacy)/not-found.tsx similarity index 100% rename from src/app/not-found.tsx rename to src/app/(legacy)/not-found.tsx diff --git a/src/app/page.tsx b/src/app/(legacy)/page.tsx similarity index 100% rename from src/app/page.tsx rename to src/app/(legacy)/page.tsx diff --git a/src/app/policy/[slug]/page.tsx b/src/app/(legacy)/policy/[slug]/page.tsx similarity index 73% rename from src/app/policy/[slug]/page.tsx rename to src/app/(legacy)/policy/[slug]/page.tsx index b527d99..528b537 100644 --- a/src/app/policy/[slug]/page.tsx +++ b/src/app/(legacy)/policy/[slug]/page.tsx @@ -2,6 +2,7 @@ import type { Metadata } from "next"; import { notFound } from "next/navigation"; import { PolicyPageContent } from "@/components/policy/policy-page-content"; import { getPolicyCatalog, getPolicySlugs } from "@/data/policy"; +import { isLocale } from "@/lib/i18n"; export const dynamicParams = false; @@ -9,16 +10,16 @@ export function generateStaticParams() { return getPolicySlugs(); } -export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }): Promise { - const { slug } = await params; +export async function generateMetadata({ params }: { params: Promise<{ slug: string; locale?: string }> }): Promise { + const { slug, locale } = await params; const catalog = await getPolicyCatalog(slug); - return { title: catalog["zh-CN"]?.title ?? "法律信息" }; + return { title: catalog[isLocale(locale) ? locale : "zh-Hans"]?.title ?? "法律信息" }; } export default async function PolicyPage({ params }: { params: Promise<{ slug: string }> }) { const { slug } = await params; const catalog = await getPolicyCatalog(slug); - if (!catalog["zh-CN"]) notFound(); + if (!catalog["zh-Hans"]) notFound(); return (
@@ -27,4 +28,4 @@ export default async function PolicyPage({ params }: { params: Promise<{ slug: s
); -} \ No newline at end of file +} diff --git a/src/app/[locale]/403/page.tsx b/src/app/[locale]/403/page.tsx new file mode 100644 index 0000000..bb689c6 --- /dev/null +++ b/src/app/[locale]/403/page.tsx @@ -0,0 +1 @@ +export { default } from "@/app/(legacy)/403/page"; diff --git a/src/app/[locale]/500/page.tsx b/src/app/[locale]/500/page.tsx new file mode 100644 index 0000000..f8856cb --- /dev/null +++ b/src/app/[locale]/500/page.tsx @@ -0,0 +1 @@ +export { default } from "@/app/(legacy)/500/page"; diff --git a/src/app/[locale]/502/page.tsx b/src/app/[locale]/502/page.tsx new file mode 100644 index 0000000..351a22a --- /dev/null +++ b/src/app/[locale]/502/page.tsx @@ -0,0 +1 @@ +export { default } from "@/app/(legacy)/502/page"; diff --git a/src/app/[locale]/503/page.tsx b/src/app/[locale]/503/page.tsx new file mode 100644 index 0000000..3c6fa7b --- /dev/null +++ b/src/app/[locale]/503/page.tsx @@ -0,0 +1 @@ +export { default } from "@/app/(legacy)/503/page"; diff --git a/src/app/[locale]/504/page.tsx b/src/app/[locale]/504/page.tsx new file mode 100644 index 0000000..336c8ef --- /dev/null +++ b/src/app/[locale]/504/page.tsx @@ -0,0 +1 @@ +export { default } from "@/app/(legacy)/504/page"; diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx new file mode 100644 index 0000000..490d8c0 --- /dev/null +++ b/src/app/[locale]/layout.tsx @@ -0,0 +1,43 @@ +import { notFound } from "next/navigation"; +import SiteDocument from "@/components/layout/site-document"; +import { getLocaleMessages, locales, matchLocale } from "@/lib/i18n"; + +export { viewport } from "@/components/layout/site-document"; +export const dynamicParams = false; + +export function generateStaticParams() { + return [ + ...locales, + "zh-hans", + "zh-hant", + "zh-CN", + "zh-cn", + "zh-SG", + "zh-sg", + "zh-TW", + "zh-tw", + "zh-HK", + "zh-hk", + "zh-MO", + "zh-mo", + "ja", + ].map((locale) => ({ locale })); +} + +export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) { + const { locale } = await params; + const canonicalLocale = matchLocale(locale); + if (!canonicalLocale) notFound(); + const title = getLocaleMessages(canonicalLocale).common.siteTitle; + return { title: { default: title, template: `%s | ${title}` }, icons: { icon: "/icon/icon.svg" } }; +} + +export default async function LocaleLayout({ children, params }: { + children: React.ReactNode; + params: Promise<{ locale: string }>; +}) { + const { locale } = await params; + const canonicalLocale = matchLocale(locale); + if (!canonicalLocale) notFound(); + return {children}; +} diff --git a/src/app/[locale]/news/[slug]/page.tsx b/src/app/[locale]/news/[slug]/page.tsx new file mode 100644 index 0000000..2e7c43e --- /dev/null +++ b/src/app/[locale]/news/[slug]/page.tsx @@ -0,0 +1 @@ +export { default, generateMetadata, generateStaticParams } from "@/app/(legacy)/news/[slug]/page"; diff --git a/src/app/[locale]/news/page.tsx b/src/app/[locale]/news/page.tsx new file mode 100644 index 0000000..9fd541a --- /dev/null +++ b/src/app/[locale]/news/page.tsx @@ -0,0 +1 @@ +export { default, generateMetadata } from "@/app/(legacy)/news/page"; diff --git a/src/app/[locale]/not-found.tsx b/src/app/[locale]/not-found.tsx new file mode 100644 index 0000000..643f134 --- /dev/null +++ b/src/app/[locale]/not-found.tsx @@ -0,0 +1 @@ +export { default } from "@/app/(legacy)/not-found"; diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx new file mode 100644 index 0000000..a1d4b8a --- /dev/null +++ b/src/app/[locale]/page.tsx @@ -0,0 +1 @@ +export { default } from "@/app/(legacy)/page"; diff --git a/src/app/[locale]/policy/[slug]/page.tsx b/src/app/[locale]/policy/[slug]/page.tsx new file mode 100644 index 0000000..0ebb270 --- /dev/null +++ b/src/app/[locale]/policy/[slug]/page.tsx @@ -0,0 +1 @@ +export { default, generateMetadata, generateStaticParams } from "@/app/(legacy)/policy/[slug]/page"; diff --git a/src/app/layout.tsx b/src/app/layout.tsx deleted file mode 100644 index c9b22bb..0000000 --- a/src/app/layout.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import type { Metadata, Viewport } from "next"; -import "./globals.css"; -import { SiteFooter } from "@/components/layout/site-footer"; -import { SiteHeader } from "@/components/layout/site-header"; - -export const metadata: Metadata = { - title: { - default: "基沃托斯铁道公团 KivotosRailway", - template: "%s | 基沃托斯铁道公团 KivotosRailway", - }, - description: "Kivotos Railway website", - icons: { - icon: "/icon/icon.svg", - }, -}; - -export const viewport: Viewport = { - width: "device-width", - initialScale: 1, -}; - -export default function RootLayout({ - children, -}: Readonly<{ children: React.ReactNode }>) { - return ( - - - {/* Run during HTML parsing, before the body can paint. */} -