---
# System prepended metadata

title: 主網站與子網站的設置
tags: [Next.Js 14 with APP Router]

---

主網站與子網站的設置
===

###### 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>
    </>
  );
}

```
