From 26871521d86c7a87fff33464f65f099a55a467a0 Mon Sep 17 00:00:00 2001 From: hamster1963 <1410514192@qq.com> Date: Sun, 24 Nov 2024 20:51:43 +0800 Subject: [PATCH] feat: init i18n --- bun.lockb | Bin 159867 -> 161495 bytes package.json | 2 + src/components/Header.tsx | 8 ++-- src/components/LanguageSwitcher.tsx | 56 ++++++++++++++++++++++++++++ src/components/ThemeSwitcher.tsx | 12 ++++-- src/components/ui/dropdown-menu.tsx | 4 +- src/i18n.js | 29 ++++++++++++++ src/locales/en/translation.json | 13 +++++++ src/locales/zh-CN/translation.json | 13 +++++++ src/locales/zh-TW/translation.json | 13 +++++++ src/main.tsx | 1 + 11 files changed, 143 insertions(+), 8 deletions(-) create mode 100644 src/components/LanguageSwitcher.tsx create mode 100644 src/i18n.js create mode 100644 src/locales/en/translation.json create mode 100644 src/locales/zh-CN/translation.json create mode 100644 src/locales/zh-TW/translation.json diff --git a/bun.lockb b/bun.lockb index 4c2db6cc1924eecdeaf4663b03051e62032688f4..5d3ebef784f7962fbda37e56758189fc2f43820d 100755 GIT binary patch delta 27171 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 delta 26211 zcmeHwcYIVu_xGJk7IGs=2qlFiBmsidND|UW+$EGiva|ppp|g+$0)bR|*#$)jiUOmK zARtjuiXeyx2q;wzN{RFiA_$6fqzSy=b4$X*gFZg*=l6U6dA%RL_sltSX6DS9GjrQ! zIP{xx|FkkQtU)9HUDdC*Jh@goQ*}vl4n%G>(D@KO1G=e#B>8|gbde+v$}cFe7Yvl7rI3?e15gEYtZjHU z)iM`+74WZul74PZK_SXWVHG9G9efhxZlEJg^1(PLG+dzAPB#j17@=c&*h$ob(#}T@|;elZABp+_iA8e11 zB%|S~C`29^WGg7lgQ5BMkp*P)J`X8cb>SPH61C|(4T^tGSuZefNY1dVOk4h-0{bZY zh{A%8Q41Lm%^S!;j+s^U{$}Od3SsB)apVO_%E72mzYB-hM^H2AIzIrEy6HeUFHqGP z(2uAgN#5XVgOZt7K&kvsIvqVEYv2&*Wfj=R*g;1@8CE)+$p{OoFxOT%q{%S*SRcJW z17F<_StGJ?Z3P7$kdt3dK~CLk=BIVTq|0}Kr-nC!Qhn=dYWlB&lHW7^HQEC_x#<>o zAITv(e?fvQ4bNxpsH5L

K}=n(G51hOLdTuMLCG5rAt!o8 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 diff --git a/package.json b/package.json index fb2182d..58c36f1 100644 --- a/package.json +++ b/package.json @@ -27,10 +27,12 @@ "clsx": "^2.1.1", "country-flag-icons": "^1.5.13", "framer-motion": "^11.11.17", + "i18next": "^24.0.0", "lucide-react": "^0.460.0", "luxon": "^3.5.0", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-i18next": "^15.1.1", "react-router-dom": "^6.28.0", "react-use-websocket": "^4.11.1", "recharts": "^2.13.3", diff --git a/src/components/Header.tsx b/src/components/Header.tsx index ee204c7..ce1372c 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,4 +1,3 @@ -// import { LanguageSwitcher } from "@/components/LanguageSwitcher"; import { ModeToggle } from "@/components/ThemeSwitcher"; import { Separator } from "@/components/ui/separator"; import { Skeleton } from "@/components/ui/skeleton"; @@ -6,6 +5,8 @@ import { fetchLoginUser } from "@/lib/nezha-api"; import { useQuery } from "@tanstack/react-query"; import { DateTime } from "luxon"; import { useEffect, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { LanguageSwitcher } from "./LanguageSwitcher"; function Header() { return ( @@ -32,7 +33,7 @@ function Header() {

- {/* */} +
@@ -80,6 +81,7 @@ const useInterval = (callback: () => void, delay: number | null) => { }, [delay]); }; function Overview() { + const { t } = useTranslation(); const [mouted, setMounted] = useState(false); useEffect(() => { setMounted(true); @@ -94,7 +96,7 @@ function Overview() { }, 1000); return (
-

👋 Overview

+

👋 {t("overview")}

where the time is

{mouted ? ( diff --git a/src/components/LanguageSwitcher.tsx b/src/components/LanguageSwitcher.tsx new file mode 100644 index 0000000..872ebe1 --- /dev/null +++ b/src/components/LanguageSwitcher.tsx @@ -0,0 +1,56 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; + +import { CheckCircleIcon } from "@heroicons/react/20/solid"; +import { useTranslation } from "react-i18next"; + +export function LanguageSwitcher() { + const { t, i18n } = useTranslation(); + + const locale = i18n.language; + + const handleSelect = (e: Event, newLocale: string) => { + e.preventDefault(); // 阻止默认的关闭行为 + i18n.changeLanguage(newLocale); + }; + + const localeItems = [ + { name: t("language.zh-CN"), code: "zh-CN" }, + { name: t("language.zh-TW"), code: "zh-TW" }, + { name: t("language.en"), code: "en" }, + ]; + + return ( + + + + + + {localeItems.map((item) => ( + handleSelect(e, item.code)} + className={locale === item.code ? "bg-muted gap-3" : ""} + > + {item.name}{" "} + {locale === item.code && } + + ))} + + + ); +} diff --git a/src/components/ThemeSwitcher.tsx b/src/components/ThemeSwitcher.tsx index b8b1384..2926e14 100644 --- a/src/components/ThemeSwitcher.tsx +++ b/src/components/ThemeSwitcher.tsx @@ -9,8 +9,11 @@ import { cn } from "@/lib/utils"; import { Moon, Sun } from "lucide-react"; import { Theme } from "@/components/ThemeProvider"; import { useTheme } from "../hooks/use-theme"; +import { CheckCircleIcon } from "@heroicons/react/20/solid"; +import { useTranslation } from 'react-i18next'; export function ModeToggle() { + const {t} = useTranslation(); const { setTheme, theme } = useTheme(); const handleSelect = (e: Event, newTheme: Theme) => { @@ -36,19 +39,22 @@ export function ModeToggle() { className={cn({ "gap-3 bg-muted": theme === "light" })} onSelect={(e) => handleSelect(e, "light")} > - Light + {t("theme.light")} + {theme === "light" && } handleSelect(e, "dark")} > - Dark + {t("theme.dark")} + {theme === "dark" && } handleSelect(e, "system")} > - System + {t("theme.system")} + {theme === "system" && } diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx index e209caa..702e290 100644 --- a/src/components/ui/dropdown-menu.tsx +++ b/src/components/ui/dropdown-menu.tsx @@ -63,7 +63,7 @@ const DropdownMenuContent = React.forwardRef< ref={ref} sideOffset={sideOffset} className={cn( - "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", + "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-2xl data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className, )} {...props} @@ -81,7 +81,7 @@ const DropdownMenuItem = React.forwardRef<