主網站與子網站的設置 === ###### With Next.js App Router + next-intl :::info :radio_button: [回到目錄攻略](https://hackmd.io/@hJJ8etrATgudRfKA1gryew/BJiplPwMC) ::: 0.先看成果 --- ![20240514_094548](https://hackmd.io/_uploads/Hy3qzrx70.gif) 隨著點選各個子項目(北部、中部、南部、東部),其網址也會跟著變動,連結到各自的子網站頁面!~~所謂的有關係又沒關係~~:grin: 1.建立子網站的資料夾 --- 建立目錄如下截圖: ![image](https://hackmd.io/_uploads/SkmQvBemA.png) 除了原有的主網站`main`之外,額外再建立`east`、`middle`、`north`、`south`資料夾,每個資料夾底下再各自建立`layout.tsx`與`page.tsx`。 > 資料夾底下page.tsx的作用? 這就是`Next.js` `App router`在使用者建立路由時,超方便的一大機制 -- 只要新建資料夾,並在其底下`page.tsx`作為主要呈現畫面的檔案,醬子就能幫你自動生成網址路徑啦! 2.page資料初步寫入 --- > @locale/east/page.tsx > @locale/middle/page.tsx > @locale/north/page.tsx > @locale/south/page.tsx ```typescript= // ${AREA}為變數,可再自行做調整 import { getTranslations, unstable_setRequestLocale } from "next-intl/server"; type Props = { params: { locale: string }; }; const ${AREA}Page = async ({ params: { locale } }: Props) => { unstable_setRequestLocale(locale); const t = await getTranslations(); return ( <div> <h2>{t("${AREA}")}</h2> </div> ); }; export default ${AREA}Page; ``` 3.components初步建立 --- 每個子網站都會各自有共用的`header`或`footer`,常用到的元件就要包進`components`裡面了呀!初步先建置`Header.tsx`: > @locale/east/components/Header.tsx > @locale/middle/components/Header.tsx > @locale/north/components/Header.tsx > @locale/south/components/Header.tsx ```typescript= // ${AREA}、${CITY}為變數,可再自行做調整 import { Link } from "@lib/navigation"; import { getTranslations } from "next-intl/server"; export default async function ${AREA}Header() { const t = await getTranslations(); return ( <header> <p>{t("${AREA}-header")}</p> <nav> <ul> <li> <Link href="/main">{t("home")}</Link> </li> <li> <Link href="/${AREA}/${CITY}">{t("${CITY}")}</Link> </li> ... </ul> </nav> <hr /> </header> ); } ``` 4.新創網址寫入config.ts --- 還記得[在地化路徑配置](https://hackmd.io/XBHzsZN5REq9P81CcWCTyg#4%E5%88%9D%E8%A8%AD%E5%9C%A8%E5%9C%B0%E5%8C%96%E8%AA%9E%E8%A8%80%E8%B7%AF%E5%BE%91%E9%85%8D%E7%BD%AE)這段文嗎? 在每個子網站中,又延伸出許多地點/縣市的網頁,雖然在建立資料夾與`page.tsx`的同時,已自動升成可到達的網址,但多國語言套件不知道呀!所以就必須把設置好的網址一一寫入congig.ts-- > @src/lib/config.ts ```typescript= import { Pathnames } from "next-intl/navigation"; export const locales = ["en", "zh"] as const; export const pathnames = { "/main": "/main", //接續往下加入新的網址 "/north": "/north", "/middle": "/middle", "/south": "/south", "/east": "/east", "/east/yilan": "/east/yilan", "/middle/miaoli": "/middle/miaoli", "/north/newpei": "/north/newpei", "/south/chiayi": "/south/chiayi", } satisfies Pathnames<typeof locales>; export const localePrefix = "always"; export type AppPathnames = keyof typeof pathnames; ``` 5.layout初步寫入 --- 要讓各子網站的`header`重複出現,當然少不了透過`layout`來排兵部陣! > @locale/east/layout.tsx > @locale/middle/layout.tsx > @locale/north/layout.tsx > @locale/south/layout.tsx ```typescript= import ${AREA}Header from "@/src/app/[locale]/${AREA}/components/Header"; import { locales } from "@lib/config"; import { NextIntlClientProvider, useMessages } from "next-intl"; import { unstable_setRequestLocale } from "next-intl/server"; import React from "react"; export function generateStaticParams() { return locales.map((locale) => ({ locale })); } type Props = { children: React.ReactNode; params: { locale: string } }; export default function ${AREA}Layout({ children, params: { locale } }: Props) { const messages = useMessages(); unstable_setRequestLocale(locale); return ( <> <NextIntlClientProvider messages={messages}> <${AREA}Header /> // 重複的header底家 <main>{children}</main> </NextIntlClientProvider> </> ); } ```