diff --git a/app/(main)/ClientComponents/ServerListClient.tsx b/app/[locale]/(main)/ClientComponents/ServerListClient.tsx similarity index 77% rename from app/(main)/ClientComponents/ServerListClient.tsx rename to app/[locale]/(main)/ClientComponents/ServerListClient.tsx index cc82121..756c5ca 100644 --- a/app/(main)/ClientComponents/ServerListClient.tsx +++ b/app/[locale]/(main)/ClientComponents/ServerListClient.tsx @@ -1,18 +1,15 @@ "use client"; -import { ServerApi } from "@/app/types/nezha-api"; -import ServerCard from "@/components/ServerCard"; -import { nezhaFetcher } from "@/lib/utils"; +import { ServerApi } from "../../types/nezha-api"; +import ServerCard from "../../../../components/ServerCard"; +import { nezhaFetcher } from "../../../../lib/utils"; import useSWR from "swr"; -import getEnv from "@/lib/env-entry"; - +import getEnv from "../../../../lib/env-entry"; export default function ServerListClient() { const { data } = useSWR("/api/server", nezhaFetcher, { refreshInterval: Number(getEnv("NEXT_PUBLIC_NezhaFetchInterval")) || 2000, }); - if (!data) return null; - const sortedServers = data.result.sort((a, b) => { if (a.display_index && b.display_index) { return b.display_index - a.display_index; @@ -21,7 +18,6 @@ export default function ServerListClient() { if (b.display_index) return 1; return a.id - b.id; }); - return (
{sortedServers.map((serverInfo) => ( diff --git a/app/(main)/ClientComponents/ServerOverviewClient.tsx b/app/[locale]/(main)/ClientComponents/ServerOverviewClient.tsx similarity index 92% rename from app/(main)/ClientComponents/ServerOverviewClient.tsx rename to app/[locale]/(main)/ClientComponents/ServerOverviewClient.tsx index 1450765..85a6af6 100644 --- a/app/(main)/ClientComponents/ServerOverviewClient.tsx +++ b/app/[locale]/(main)/ClientComponents/ServerOverviewClient.tsx @@ -1,25 +1,26 @@ "use client"; -import { Card, CardContent } from "@/components/ui/card"; -import blogMan from "@/public/blog-man.webp"; +import { useTranslations } from "next-intl"; +import { Card, CardContent } from "../../../../components/ui/card"; +import blogMan from "../../../../public/blog-man.webp"; import Image from "next/image"; import useSWR from "swr"; -import { formatBytes, nezhaFetcher } from "@/lib/utils"; -import { Loader } from "@/components/loading/Loader"; -import { ServerApi } from "@/app/types/nezha-api"; -import getEnv from "@/lib/env-entry"; - +import { formatBytes, nezhaFetcher } from "../../../../lib/utils"; +import { Loader } from "../../../../components/loading/Loader"; +import { ServerApi } from "../../types/nezha-api"; +import getEnv from "../../../../lib/env-entry"; export default function ServerOverviewClient() { + const t = useTranslations("ServerOverviewClient"); const { data } = useSWR("/api/server", nezhaFetcher); - const disableCartoon = getEnv("NEXT_PUBLIC_DisableCartoon") === "true"; - return (
-

Total servers

+

+ {t("p_816-881_Totalservers")} +

@@ -40,7 +41,9 @@ export default function ServerOverviewClient() {
-

Online servers

+

+ {t("p_1610-1676_Onlineservers")} +

@@ -62,7 +65,9 @@ export default function ServerOverviewClient() {
-

Offline servers

+

+ {t("p_2532-2599_Offlineservers")} +

@@ -84,7 +89,9 @@ export default function ServerOverviewClient() {
-

Total bandwidth

+

+ {t("p_3463-3530_Totalbandwidth")} +

{data ? (

{formatBytes(data?.total_bandwidth)} diff --git a/app/(main)/footer.tsx b/app/[locale]/(main)/footer.tsx similarity index 69% rename from app/(main)/footer.tsx rename to app/[locale]/(main)/footer.tsx index 5f8a5e3..4bfcffc 100644 --- a/app/(main)/footer.tsx +++ b/app/[locale]/(main)/footer.tsx @@ -1,20 +1,23 @@ +import { useTranslations } from "next-intl"; export default function Footer() { + const t = useTranslations("Footer"); return (

diff --git a/app/(main)/header.tsx b/app/[locale]/(main)/header.tsx similarity index 76% rename from app/(main)/header.tsx rename to app/[locale]/(main)/header.tsx index 9be6e09..53a5a0e 100644 --- a/app/(main)/header.tsx +++ b/app/[locale]/(main)/header.tsx @@ -1,12 +1,14 @@ "use client"; +import { useTranslations } from "next-intl"; import React, { useEffect, useRef, useState } from "react"; import Image from "next/image"; -import { Separator } from "@/components/ui/separator"; +import { Separator } from "../../../components/ui/separator"; import { DateTime } from "luxon"; -import { ModeToggle } from "@/components/ThemeSwitcher"; - +import { ModeToggle } from "../../../components/ThemeSwitcher"; +import { LanguageSwitcher } from "@/components/LanguageSwitcher"; function Header() { + const t = useTranslations("Header"); return (
@@ -27,10 +29,13 @@ function Header() { className="mx-2 hidden h-4 w-[1px] md:block" />

- Simple and beautiful dashboard + {t("p_1079-1199_Simpleandbeautifuldashbo")}

- +
+ + +
@@ -40,22 +45,19 @@ function Header() { // https://github.com/streamich/react-use/blob/master/src/useInterval.ts const useInterval = (callback: Function, delay?: number | null) => { const savedCallback = useRef(() => {}); - useEffect(() => { savedCallback.current = callback; }); - useEffect(() => { if (delay !== null) { const interval = setInterval(() => savedCallback.current(), delay || 0); return () => clearInterval(interval); } - return undefined; }, [delay]); }; - function Overview() { + const t = useTranslations("Overview"); const [mouted, setMounted] = useState(false); useEffect(() => { setMounted(true); @@ -65,16 +67,16 @@ function Overview() { const [timeString, setTimeString] = useState( DateTime.now().setLocale("en-US").toLocaleString(timeOption), ); - useInterval(() => { setTimeString(DateTime.now().setLocale("en-US").toLocaleString(timeOption)); }, 1000); - return (
-

👋 Overview

+

{t("p_2277-2331_Overview")}

-

where the time is

+

+ {t("p_2390-2457_wherethetimeis")} +

{mouted && (

{timeString}

)} @@ -82,5 +84,4 @@ function Overview() {
); } - export default Header; diff --git a/app/(main)/layout.tsx b/app/[locale]/(main)/layout.tsx similarity index 90% rename from app/(main)/layout.tsx rename to app/[locale]/(main)/layout.tsx index 6a77ce3..137532e 100644 --- a/app/(main)/layout.tsx +++ b/app/[locale]/(main)/layout.tsx @@ -1,12 +1,10 @@ import React from "react"; - -import Header from "@/app/(main)/header"; +import Header from "@/app/[locale]/(main)/header"; import Footer from "./footer"; type DashboardProps = { children: React.ReactNode; }; - export default function MainLayout({ children }: DashboardProps) { return (
diff --git a/app/(main)/page.tsx b/app/[locale]/(main)/page.tsx similarity index 61% rename from app/(main)/page.tsx rename to app/[locale]/(main)/page.tsx index 86719a1..e6b1cf1 100644 --- a/app/(main)/page.tsx +++ b/app/[locale]/(main)/page.tsx @@ -1,18 +1,14 @@ -import ServerList from "@/components/ServerList"; -import ServerOverview from "@/components/ServerOverview"; -import getEnv from "@/lib/env-entry"; -import { GetNezhaData } from "@/lib/serverFetch"; - +import ServerList from "../../../components/ServerList"; +import ServerOverview from "../../../components/ServerOverview"; +import getEnv from "../../../lib/env-entry"; +import { GetNezhaData } from "../../../lib/serverFetch"; import { SWRConfig } from "swr"; - const disablePrefetch = getEnv("ServerDisablePrefetch") === "true"; - const fallback = disablePrefetch ? {} : { - "/api/server": GetNezhaData(), - }; - + "/api/server": GetNezhaData(), + }; export default function Home() { return ( + @@ -53,7 +58,9 @@ export default function RootLayout({ children }: RootLayoutProps) { enableSystem disableTransitionOnChange > - {children} + + {children} + diff --git a/app/not-found.tsx b/app/[locale]/not-found.tsx similarity index 71% rename from app/not-found.tsx rename to app/[locale]/not-found.tsx index 3c78834..ad0c9a7 100644 --- a/app/not-found.tsx +++ b/app/[locale]/not-found.tsx @@ -1,7 +1,8 @@ +import { useTranslations } from "next-intl"; import Image from "next/image"; import Link from "next/link"; - export default function NotFoundPage() { + const t = useTranslations("NotFoundPage"); return (
@@ -14,11 +15,13 @@ export default function NotFoundPage() { />

- 404 Not Found + {t("h1_490-590_404NotFound")}

-

TARDIS ERROR!

+

+ {t("p_601-665_TARDISERROR")} +

- Doctor? + {t("Link_676-775_Doctor")}
diff --git a/app/types/nezha-api.ts b/app/[locale]/types/nezha-api.ts similarity index 100% rename from app/types/nezha-api.ts rename to app/[locale]/types/nezha-api.ts diff --git a/app/types/utils.ts b/app/[locale]/types/utils.ts similarity index 100% rename from app/types/utils.ts rename to app/[locale]/types/utils.ts diff --git a/auto-i18n-config.json b/auto-i18n-config.json new file mode 100644 index 0000000..bbf5176 --- /dev/null +++ b/auto-i18n-config.json @@ -0,0 +1,10 @@ +{ + "defaultLang": "en", + "translatorServerName": "azure", + "needLangs": ["en", "zh", "zh-t", "ja"], + "brandWords": [], + "unMoveToLocaleDirFiles": [], + "enableStaticRendering": false, + "enableSubPageRedirectToLocale": false, + "disableDefaultLangRedirect": true +} diff --git a/bun.lockb b/bun.lockb index 4a5a2aa..0667cb3 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/components/LanguageSwitcher.tsx b/components/LanguageSwitcher.tsx new file mode 100644 index 0000000..0d5fb51 --- /dev/null +++ b/components/LanguageSwitcher.tsx @@ -0,0 +1,70 @@ +"use client"; + +import { useLocale } from "next-intl"; +import { localeItems } from "../i18n-metadata"; +import { useRouter, usePathname } from "next/navigation"; +import * as React from "react"; + +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; + +export function LanguageSwitcher() { + const locale = useLocale(); + const router = useRouter(); + const pathname = usePathname(); + + const handleChange = (code: string) => { + const newLocale = code; + + const rootPath = "/"; + const currentLocalePath = `/${locale}`; + const newLocalePath = `/${newLocale}`; + + // Function to construct new path with locale prefix + const constructLocalePath = (path: string, newLocale: string) => { + if (path.startsWith(currentLocalePath)) { + return path.replace(currentLocalePath, `/${newLocale}`); + } else { + return `/${newLocale}${path}`; + } + }; + + if (pathname === rootPath || !pathname) { + router.push(newLocalePath); + } else if ( + pathname === currentLocalePath || + pathname === `${currentLocalePath}/` + ) { + router.push(newLocalePath); + } else { + const newPath = constructLocalePath(pathname, newLocale); + router.push(newPath); + } + }; + + return ( + + + + + + {localeItems.map((item) => ( + handleChange(item.code)} + > + {item.name} + + ))} + + + ); +} diff --git a/components/ServerCard.tsx b/components/ServerCard.tsx index b0f63aa..666e158 100644 --- a/components/ServerCard.tsx +++ b/components/ServerCard.tsx @@ -1,4 +1,5 @@ -import { NezhaAPISafe } from "@/app/types/nezha-api"; +import { useTranslations } from "next-intl"; +import { NezhaAPISafe } from "../app/[locale]/types/nezha-api"; import ServerUsageBar from "@/components/ServerUsageBar"; import { Card } from "@/components/ui/card"; import { @@ -16,6 +17,7 @@ export default function ServerCard({ }: { serverInfo: NezhaAPISafe; }) { + const t = useTranslations("ServerCard"); const { name, country_code, online, cpu, up, down, mem, stg, ...props } = formatNezhaInfo(serverInfo); @@ -55,36 +57,46 @@ export default function ServerCard({
-
-

CPU

+
+ {" "} + {/* 设置固定宽度 */} +

{t("CPU")}

{cpu.toFixed(2)}%
-
-

Mem

+
+ {" "} + {/* 设置固定宽度 */} +

{t("Mem")}

{mem.toFixed(2)}%
-
-

STG

+
+ {" "} + {/* 设置固定宽度 */} +

{t("STG")}

{stg.toFixed(2)}%
-
-

Upload

+
+ {" "} + {/* 设置固定宽度 */} +

{t("Upload")}

{up.toFixed(2)} Mb/s
-
-

Download

+
+ {" "} + {/* 设置固定宽度 */} +

{t("Download")}

{down.toFixed(2)} Mb/s @@ -122,7 +134,7 @@ export default function ServerCard({
-

Offline

+

{t("Offline")}

diff --git a/components/ServerCardPopover.tsx b/components/ServerCardPopover.tsx index d678c3b..b886ec5 100644 --- a/components/ServerCardPopover.tsx +++ b/components/ServerCardPopover.tsx @@ -1,4 +1,5 @@ -import { NezhaAPISafe } from "@/app/types/nezha-api"; +import { useTranslations } from "next-intl"; +import { NezhaAPISafe } from "../app/[locale]/types/nezha-api"; import { cn, formatBytes } from "@/lib/utils"; export function ServerCardPopoverCard({ @@ -31,39 +32,40 @@ export default function ServerCardPopover({ host: NezhaAPISafe["host"]; status: NezhaAPISafe["status"]; }) { + const t = useTranslations("ServerCardPopover"); return (
item).join(", ")}`} />
diff --git a/components/ServerList.tsx b/components/ServerList.tsx index 14c28d2..9448640 100644 --- a/components/ServerList.tsx +++ b/components/ServerList.tsx @@ -1,6 +1,6 @@ import React from "react"; -import ServerListClient from "@/app/(main)/ClientComponents/ServerListClient"; +import ServerListClient from "../app/[locale]/(main)/ClientComponents/ServerListClient"; export default async function ServerList() { return ; diff --git a/components/ServerOverview.tsx b/components/ServerOverview.tsx index 2e61c79..359dc63 100644 --- a/components/ServerOverview.tsx +++ b/components/ServerOverview.tsx @@ -1,4 +1,4 @@ -import ServerOverviewClient from "@/app/(main)/ClientComponents/ServerOverviewClient"; +import ServerOverviewClient from "../app/[locale]/(main)/ClientComponents/ServerOverviewClient"; export default async function ServerOverview() { return ; diff --git a/components/ThemeSwitcher.tsx b/components/ThemeSwitcher.tsx index 5830ade..d98794e 100644 --- a/components/ThemeSwitcher.tsx +++ b/components/ThemeSwitcher.tsx @@ -1,5 +1,6 @@ "use client"; +import { useTranslations } from "next-intl"; import { Moon, Sun } from "lucide-react"; import { useTheme } from "next-themes"; import * as React from "react"; @@ -14,7 +15,7 @@ import { export function ModeToggle() { const { setTheme } = useTheme(); - + const t = useTranslations("ThemeSwitcher"); return ( @@ -26,13 +27,13 @@ export function ModeToggle() { setTheme("light")}> - Light + {t("Light")} setTheme("dark")}> - Dark + {t("Dark")} setTheme("system")}> - System + {t("System")} diff --git a/i18n-metadata.ts b/i18n-metadata.ts new file mode 100644 index 0000000..acf3a7c --- /dev/null +++ b/i18n-metadata.ts @@ -0,0 +1,24 @@ +// @auto-i18n-check. Please do not delete the line. + +export const localeItems = [ + { code: "en", name: "English" }, + { code: "ja", name: "日本語" }, + { code: "zh-t", name: "中文繁體" }, + { code: "zh", name: "中文简体" }, + //{code: 'ar', name: 'العربية'}, + //{code: 'de', name: 'Deutsch'}, + //{code: 'es', name: 'Español'}, + //{code: 'fr', name: 'Français'}, + //{code: 'hi', name: 'हिन्दी'}, + //{code: 'id', name: 'Bahasa Indonesia'}, + //{code: 'it', name: 'Italiano'}, + //{code: 'ko', name: '한국어'}, + //{code: 'ms', name: 'Bahasa Melayu'}, + //{code: 'pt', name: 'Português'}, + //{code: 'ru', name: 'Русский'}, + //{code: 'th', name: 'ไทย'}, + //{code: 'vi', name: 'Tiếng Việt'}, +]; + +export const locales = localeItems.map((item) => item.code); +export const defaultLocale = "en"; diff --git a/i18n.ts b/i18n.ts new file mode 100644 index 0000000..2c40c0d --- /dev/null +++ b/i18n.ts @@ -0,0 +1,14 @@ +// @auto-i18n-check. Please do not delete the line. + +import { notFound } from "next/navigation"; +import { getRequestConfig } from "next-intl/server"; +import { locales } from "./i18n-metadata"; + +export default getRequestConfig(async ({ locale }) => { + // Validate that the incoming `locale` parameter is valid + if (!locales.includes(locale as any)) notFound(); + + return { + messages: (await import(`./messages/${locale}.json`)).default, + }; +}); diff --git a/lib/serverFetch.tsx b/lib/serverFetch.tsx index 020f162..51687a8 100644 --- a/lib/serverFetch.tsx +++ b/lib/serverFetch.tsx @@ -1,7 +1,7 @@ "use server"; -import { NezhaAPI, ServerApi } from "@/app/types/nezha-api"; -import { MakeOptional } from "@/app/types/utils"; +import { NezhaAPI, ServerApi } from "../app/[locale]/types/nezha-api"; +import { MakeOptional } from "../app/[locale]/types/utils"; import { error } from "console"; import { unstable_noStore as noStore } from "next/cache"; import getEnv from "./env-entry"; diff --git a/lib/utils.ts b/lib/utils.ts index ed8ba08..b60052f 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -1,4 +1,4 @@ -import { NezhaAPISafe } from "@/app/types/nezha-api"; +import { NezhaAPISafe } from "../app/[locale]/types/nezha-api"; import { type ClassValue, clsx } from "clsx"; import { twMerge } from "tailwind-merge"; diff --git a/messages/en.json b/messages/en.json new file mode 100644 index 0000000..0b7e0f4 --- /dev/null +++ b/messages/en.json @@ -0,0 +1,50 @@ +{ + "ServerOverviewClient": { + "p_816-881_Totalservers": "Total servers", + "p_1610-1676_Onlineservers": "Online servers", + "p_2532-2599_Offlineservers": "Offline servers", + "p_3463-3530_Totalbandwidth": "Total bandwidth" + }, + "ServerCard": { + "CPU": "CPU", + "Mem": "Mem", + "STG": "STG", + "Upload": "Upload", + "Download": "Download", + "Offline": "Offline" + }, + "ServerCardPopover": { + "System": "System", + "CPU": "CPU", + "Mem": "Mem", + "STG": "STG", + "Swap": "Swap", + "Network": "Network", + "Load": "Load", + "Online": "Online", + "Offline": "Offline" + }, + "ThemeSwitcher": { + "Light": "Light", + "Dark": "Dark", + "System": "System" + }, + "Footer": { + "p_146-598_Findthecodeon": "Find the code on", + "a_303-585_GitHub": "GitHub", + "section_607-869_2020": "© 2020-", + "a_800-850_Hamster1963": "@Hamster1963" + }, + "Header": { + "p_1079-1199_Simpleandbeautifuldashbo": "Simple and beautiful dashboard" + }, + "Overview": { + "p_2277-2331_Overview": "👋 Overview", + "p_2390-2457_wherethetimeis": "where the time is" + }, + "NotFoundPage": { + "h1_490-590_404NotFound": "404 Not Found", + "p_601-665_TARDISERROR": "TARDIS ERROR!", + "Link_676-775_Doctor": "Doctor?" + } +} diff --git a/messages/ja.json b/messages/ja.json new file mode 100644 index 0000000..ec840dd --- /dev/null +++ b/messages/ja.json @@ -0,0 +1,50 @@ +{ + "ServerOverviewClient": { + "p_816-881_Totalservers": "サーバーの総数", + "p_1610-1676_Onlineservers": "オンラインサーバー", + "p_2532-2599_Offlineservers": "オフラインサーバー", + "p_3463-3530_Totalbandwidth": "総流量" + }, + "ServerCard": { + "CPU": "CPU", + "Mem": "Mem", + "STG": "STG", + "Upload": "Upload", + "Download": "Download", + "Offline": "Offline" + }, + "ServerCardPopover": { + "System": "システム", + "CPU": "CPU", + "Mem": "メモリ", + "STG": "ストレージ", + "Swap": "スワップ", + "Network": "ネットワーク", + "Load": "負荷", + "Online": "オンライン時間", + "Offline": "オフライン" + }, + "ThemeSwitcher": { + "Light": "ライト", + "Dark": "ダーク", + "System": "システム" + }, + "Footer": { + "p_146-598_Findthecodeon": "コードのオープンソース", + "a_303-585_GitHub": "GitHub", + "section_607-869_2020": "© 2020〜", + "a_800-850_Hamster1963": "@Hamster1963" + }, + "Header": { + "p_1079-1199_Simpleandbeautifuldashbo": "シンプルで美しいダッシュボード" + }, + "Overview": { + "p_2277-2331_Overview": "👋 概要", + "p_2390-2457_wherethetimeis": "現在の時間" + }, + "NotFoundPage": { + "h1_490-590_404NotFound": "404 見つかりませんでした", + "p_601-665_TARDISERROR": "ターディスエラー!", + "Link_676-775_Doctor": "Doctor?" + } +} diff --git a/messages/zh-t.json b/messages/zh-t.json new file mode 100644 index 0000000..a8027b6 --- /dev/null +++ b/messages/zh-t.json @@ -0,0 +1,50 @@ +{ + "ServerOverviewClient": { + "p_816-881_Totalservers": "伺服器總數", + "p_1610-1676_Onlineservers": "在線伺服器", + "p_2532-2599_Offlineservers": "離線伺服器", + "p_3463-3530_Totalbandwidth": "總流量" + }, + "ServerCard": { + "CPU": "CPU", + "Mem": "記憶體", + "STG": "儲存", + "Upload": "上傳", + "Download": "下載", + "Offline": "離線" + }, + "ServerCardPopover": { + "System": "系統", + "CPU": "CPU", + "Mem": "記憶體", + "STG": "儲存", + "Swap": "虛擬記憶體", + "Network": "網路", + "Load": "負載", + "Online": "在線時間", + "Offline": "離線" + }, + "ThemeSwitcher": { + "Light": "亮色", + "Dark": "暗色", + "System": "系統" + }, + "Footer": { + "p_146-598_Findthecodeon": "程式碼開源", + "a_303-585_GitHub": "GitHub", + "section_607-869_2020": "© 2020-", + "a_800-850_Hamster1963": "@Hamster1963" + }, + "Header": { + "p_1079-1199_Simpleandbeautifuldashbo": "簡單美觀的儀錶板" + }, + "Overview": { + "p_2277-2331_Overview": "👋 概覽", + "p_2390-2457_wherethetimeis": "當前時間" + }, + "NotFoundPage": { + "h1_490-590_404NotFound": "404 未找到", + "p_601-665_TARDISERROR": "TARDIS 錯誤!", + "Link_676-775_Doctor": "Doctor?" + } +} diff --git a/messages/zh.json b/messages/zh.json new file mode 100644 index 0000000..166ac55 --- /dev/null +++ b/messages/zh.json @@ -0,0 +1,50 @@ +{ + "ServerOverviewClient": { + "p_816-881_Totalservers": "服务器总数", + "p_1610-1676_Onlineservers": "在线服务器", + "p_2532-2599_Offlineservers": "离线服务器", + "p_3463-3530_Totalbandwidth": "总流量" + }, + "ServerCard": { + "CPU": "CPU", + "Mem": "内存", + "STG": "存储", + "Upload": "上传", + "Download": "下载", + "Offline": "离线" + }, + "ServerCardPopover": { + "System": "系统", + "CPU": "CPU", + "Mem": "内存", + "STG": "存储", + "Swap": "虚拟内存", + "Network": "网络", + "Load": "负载", + "Online": "在线时间", + "Offline": "离线" + }, + "ThemeSwitcher": { + "Light": "亮色", + "Dark": "暗色", + "System": "系统" + }, + "Footer": { + "p_146-598_Findthecodeon": "代码开源在", + "a_303-585_GitHub": "GitHub", + "section_607-869_2020": "© 2020-", + "a_800-850_Hamster1963": "@Hamster1963" + }, + "Header": { + "p_1079-1199_Simpleandbeautifuldashbo": "简单美观的仪表板" + }, + "Overview": { + "p_2277-2331_Overview": "👋 概览", + "p_2390-2457_wherethetimeis": "当前时间" + }, + "NotFoundPage": { + "h1_490-590_404NotFound": "404 未找到", + "p_601-665_TARDISERROR": "TARDIS 错误!", + "Link_676-775_Doctor": "Doctor?" + } +} diff --git a/middleware.ts b/middleware.ts new file mode 100644 index 0000000..a4b787c --- /dev/null +++ b/middleware.ts @@ -0,0 +1,21 @@ +// @auto-i18n-check. Please do not delete the line. + +import createMiddleware from "next-intl/middleware"; +import { locales } from "./i18n-metadata"; + +export default createMiddleware({ + // A list of all locales that are supported + locales: locales, + + // Used when no locale matches + defaultLocale: "en", + + // 'always': This is the default, The home page will also be redirected to the default language, such as www.abc.com to www.abc.com/en + // 'as-needed': The default page is not redirected. For example, if you open www.abc.com, it is still www.abc.com + localePrefix: "as-needed", +}); + +export const config = { + // Match only internationalized pathnames + matcher: ["/", "/(en|zh|zh-t|ja)/:path*"], +}; diff --git a/next.config.mjs b/next.config.mjs index 66a8f20..5234c22 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,5 +1,6 @@ +import createNextIntlPlugin from "next-intl/plugin"; +const withNextIntl = createNextIntlPlugin(); import withPWAInit from "@ducanh2912/next-pwa"; - const withPWA = withPWAInit({ dest: "public", cacheOnFrontEndNav: true, @@ -16,5 +17,4 @@ const nextConfig = { output: "standalone", reactStrictMode: true, }; - -export default withPWA(nextConfig); +export default withPWA(withNextIntl(nextConfig)); diff --git a/package.json b/package.json index bee0364..0f6a9e7 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,9 @@ "dev": "next dev -p 3020", "start": "node .next/standalone/server.js", "lint": "next lint", - "build": "next build && cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/" + "build": "next build && cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/", + "build-dev": "next build", + "start-dev": "next start" }, "dependencies": { "@ducanh2912/next-pwa": "^10.2.9", @@ -20,7 +22,7 @@ "@radix-ui/react-tooltip": "^1.1.2", "@types/luxon": "^3.4.2", "@typescript-eslint/eslint-plugin": "^7.18.0", - "caniuse-lite": "^1.0.30001663", + "caniuse-lite": "^1.0.30001664", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "country-flag-icons": "^1.5.13", @@ -28,6 +30,7 @@ "lucide-react": "^0.414.0", "luxon": "^3.5.0", "next": "^14.2.13", + "next-intl": "^3.20.0", "next-runtime-env": "^3.2.2", "next-themes": "^0.3.0", "react": "^18.3.1", @@ -44,7 +47,7 @@ "eslint-plugin-turbo": "^2.1.2", "eslint-plugin-unused-imports": "^4.1.4", "@next/bundle-analyzer": "^14.2.13", - "@types/node": "^22.7.0", + "@types/node": "^22.7.2", "@types/react": "^18.3.9", "@types/react-dom": "^18.3.0", "autoprefixer": "^10.4.20", diff --git a/public/swe-worker-5c72df51bb1f6ee0.js b/public/swe-worker-5c72df51bb1f6ee0.js deleted file mode 100644 index 36e6e59..0000000 --- a/public/swe-worker-5c72df51bb1f6ee0.js +++ /dev/null @@ -1 +0,0 @@ -self.onmessage=async e=>{switch(e.data.type){case"__START_URL_CACHE__":{let t=e.data.url,a=await fetch(t);if(!a.redirected)return(await caches.open("start-url")).put(t,a);return Promise.resolve()}case"__FRONTEND_NAV_CACHE__":{let t=e.data.url,a=await caches.open("pages");if(await a.match(t,{ignoreSearch:!0}))return;let s=await fetch(t);if(!s.ok)return;if(a.put(t,s.clone()),e.data.shouldCacheAggressively&&s.headers.get("Content-Type")?.includes("text/html"))try{let e=await s.text(),t=[],a=await caches.open("static-style-assets"),r=await caches.open("next-static-js-assets"),c=await caches.open("static-js-assets");for(let[s,r]of e.matchAll(//g))/rel=['"]stylesheet['"]/.test(s)&&t.push(a.match(r).then(e=>e?Promise.resolve():a.add(r)));for(let[,a]of e.matchAll(//g)){let e=/\/_next\/static.+\.js$/i.test(a)?r:c;t.push(e.match(a).then(t=>t?Promise.resolve():e.add(a)))}return await Promise.all(t)}catch{}return Promise.resolve()}default:return Promise.resolve()}}; \ No newline at end of file