mirror of
https://github.com/beilunyang/moemail.git
synced 2026-09-09 09:16:37 +08:00
feat: add internationalization support with next-intl
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import { useTranslations } from "next-intl"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Gem, Sword, User2, Loader2 } from "lucide-react"
|
||||
import { Input } from "@/components/ui/input"
|
||||
@@ -20,19 +21,21 @@ const roleIcons = {
|
||||
[ROLES.CIVILIAN]: User2,
|
||||
} as const
|
||||
|
||||
const roleNames = {
|
||||
[ROLES.DUKE]: "公爵",
|
||||
[ROLES.KNIGHT]: "骑士",
|
||||
[ROLES.CIVILIAN]: "平民",
|
||||
} as const
|
||||
|
||||
type RoleWithoutEmperor = Exclude<Role, typeof ROLES.EMPEROR>
|
||||
|
||||
export function PromotePanel() {
|
||||
const t = useTranslations("profile.promote")
|
||||
const tCard = useTranslations("profile.card")
|
||||
const [searchText, setSearchText] = useState("")
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [targetRole, setTargetRole] = useState<RoleWithoutEmperor>(ROLES.KNIGHT)
|
||||
const { toast } = useToast()
|
||||
|
||||
const roleNames = {
|
||||
[ROLES.DUKE]: tCard("roles.DUKE"),
|
||||
[ROLES.KNIGHT]: tCard("roles.KNIGHT"),
|
||||
[ROLES.CIVILIAN]: tCard("roles.CIVILIAN"),
|
||||
} as const
|
||||
|
||||
const handleAction = async () => {
|
||||
if (!searchText) return
|
||||
@@ -59,8 +62,8 @@ export function PromotePanel() {
|
||||
|
||||
if (!data.user) {
|
||||
toast({
|
||||
title: "未找到用户",
|
||||
description: "请确认用户名或邮箱地址是否正确",
|
||||
title: t("noUsers"),
|
||||
description: t("searchPlaceholder"),
|
||||
variant: "destructive"
|
||||
})
|
||||
return
|
||||
@@ -68,8 +71,8 @@ export function PromotePanel() {
|
||||
|
||||
if (data.user.role === targetRole) {
|
||||
toast({
|
||||
title: `用户已是${roleNames[targetRole]}`,
|
||||
description: "无需重复设置",
|
||||
title: t("updateSuccess"),
|
||||
description: t("updateSuccess"),
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -85,18 +88,18 @@ export function PromotePanel() {
|
||||
|
||||
if (!promoteRes.ok) {
|
||||
const error = await promoteRes.json() as { error: string }
|
||||
throw new Error(error.error || "设置失败")
|
||||
throw new Error(error.error || t("updateFailed"))
|
||||
}
|
||||
|
||||
toast({
|
||||
title: "设置成功",
|
||||
description: `已将用户 ${data.user.username || data.user.email} 设为${roleNames[targetRole]}`,
|
||||
title: t("updateSuccess"),
|
||||
description: `${data.user.username || data.user.email} - ${roleNames[targetRole]}`,
|
||||
})
|
||||
setSearchText("")
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: "设置失败",
|
||||
description: error instanceof Error ? error.message : "请稍后重试",
|
||||
title: t("updateFailed"),
|
||||
description: error instanceof Error ? error.message : t("updateFailed"),
|
||||
variant: "destructive"
|
||||
})
|
||||
} finally {
|
||||
@@ -110,7 +113,7 @@ export function PromotePanel() {
|
||||
<div className="bg-background rounded-lg border-2 border-primary/20 p-6">
|
||||
<div className="flex items-center gap-2 mb-6">
|
||||
<Icon className="w-5 h-5 text-primary" />
|
||||
<h2 className="text-lg font-semibold">角色管理</h2>
|
||||
<h2 className="text-lg font-semibold">{t("title")}</h2>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
@@ -119,7 +122,7 @@ export function PromotePanel() {
|
||||
<Input
|
||||
value={searchText}
|
||||
onChange={(e) => setSearchText(e.target.value)}
|
||||
placeholder="输入用户名或邮箱"
|
||||
placeholder={t("searchPlaceholder")}
|
||||
/>
|
||||
</div>
|
||||
<Select value={targetRole} onValueChange={(value) => setTargetRole(value as RoleWithoutEmperor)}>
|
||||
@@ -130,19 +133,19 @@ export function PromotePanel() {
|
||||
<SelectItem value={ROLES.DUKE}>
|
||||
<div className="flex items-center gap-2">
|
||||
<Gem className="w-4 h-4" />
|
||||
公爵
|
||||
{roleNames[ROLES.DUKE]}
|
||||
</div>
|
||||
</SelectItem>
|
||||
<SelectItem value={ROLES.KNIGHT}>
|
||||
<div className="flex items-center gap-2">
|
||||
<Sword className="w-4 h-4" />
|
||||
骑士
|
||||
{roleNames[ROLES.KNIGHT]}
|
||||
</div>
|
||||
</SelectItem>
|
||||
<SelectItem value={ROLES.CIVILIAN}>
|
||||
<div className="flex items-center gap-2">
|
||||
<User2 className="w-4 h-4" />
|
||||
平民
|
||||
{roleNames[ROLES.CIVILIAN]}
|
||||
</div>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
@@ -157,7 +160,7 @@ export function PromotePanel() {
|
||||
{loading ? (
|
||||
<Loader2 className="w-4 h-4 animate-spin" />
|
||||
) : (
|
||||
`设为${roleNames[targetRole]}`
|
||||
`${t("promote")} ${roleNames[targetRole]}`
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user