feat(i18n): add translation for server tab

This commit is contained in:
JiPai
2024-11-09 18:16:06 +08:00
parent 046f0a5c20
commit c09ff25360
9 changed files with 163 additions and 29 deletions

View File

@@ -235,7 +235,7 @@ export function generate(schema: Schema): Template {
5. Add the logo or image of the template to `public/templates/plausible.svg`
### Recomendations
### Recommendations
- Use the same name of the folder as the id of the template.
- The logo should be in the public folder.

View File

@@ -11,10 +11,12 @@ import {
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { api } from "@/utils/api";
import { useTranslation } from "next-i18next";
import { toast } from "sonner";
import { ShowModalLogs } from "../../web-server/show-modal-logs";
export const ShowDokployActions = () => {
const { t } = useTranslation("settings");
const { mutateAsync: reloadServer, isLoading } =
api.settings.reloadServer.useMutation();
@@ -22,11 +24,13 @@ export const ShowDokployActions = () => {
<DropdownMenu>
<DropdownMenuTrigger asChild disabled={isLoading}>
<Button isLoading={isLoading} variant="outline">
Server
{t("settings.server.webServer.server.label")}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56" align="start">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuLabel>
{t("settings.server.webServer.actions")}
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem
@@ -40,10 +44,10 @@ export const ShowDokployActions = () => {
});
}}
>
<span>Reload</span>
<span>{t("settings.server.webServer.reload")}</span>
</DropdownMenuItem>
<ShowModalLogs appName="dokploy">
<span>Watch logs</span>
<span>{t("settings.server.webServer.watchLogs")}</span>
</ShowModalLogs>
</DropdownMenuGroup>
</DropdownMenuContent>

View File

@@ -11,12 +11,14 @@ import {
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { api } from "@/utils/api";
import { useTranslation } from "next-i18next";
import { toast } from "sonner";
interface Props {
serverId?: string;
}
export const ShowStorageActions = ({ serverId }: Props) => {
const { t } = useTranslation("settings");
const { mutateAsync: cleanAll, isLoading: cleanAllIsLoading } =
api.settings.cleanAll.useMutation();
@@ -64,11 +66,13 @@ export const ShowStorageActions = ({ serverId }: Props) => {
}
variant="outline"
>
Space
{t("settings.server.webServer.storage.label")}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-64" align="start">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuLabel>
{t("settings.server.webServer.actions")}
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem
@@ -85,7 +89,9 @@ export const ShowStorageActions = ({ serverId }: Props) => {
});
}}
>
<span>Clean unused images</span>
<span>
{t("settings.server.webServer.storage.cleanUnusedImages")}
</span>
</DropdownMenuItem>
<DropdownMenuItem
className="w-full cursor-pointer"
@@ -101,7 +107,9 @@ export const ShowStorageActions = ({ serverId }: Props) => {
});
}}
>
<span>Clean unused volumes</span>
<span>
{t("settings.server.webServer.storage.cleanUnusedVolumes")}
</span>
</DropdownMenuItem>
<DropdownMenuItem
@@ -118,7 +126,9 @@ export const ShowStorageActions = ({ serverId }: Props) => {
});
}}
>
<span>Clean stopped containers</span>
<span>
{t("settings.server.webServer.storage.cleanStoppedContainers")}
</span>
</DropdownMenuItem>
<DropdownMenuItem
@@ -135,7 +145,9 @@ export const ShowStorageActions = ({ serverId }: Props) => {
});
}}
>
<span>Clean Docker Builder & System</span>
<span>
{t("settings.server.webServer.storage.cleanDockerBuilder")}
</span>
</DropdownMenuItem>
{!serverId && (
<DropdownMenuItem
@@ -150,7 +162,9 @@ export const ShowStorageActions = ({ serverId }: Props) => {
});
}}
>
<span>Clean Monitoring </span>
<span>
{t("settings.server.webServer.storage.cleanMonitoring")}
</span>
</DropdownMenuItem>
)}
@@ -168,7 +182,7 @@ export const ShowStorageActions = ({ serverId }: Props) => {
});
}}
>
<span>Clean all</span>
<span>{t("settings.server.webServer.storage.cleanAll")}</span>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>

View File

@@ -23,6 +23,7 @@ import { api } from "@/utils/api";
import { toast } from "sonner";
import { cn } from "@/lib/utils";
import { useTranslation } from "next-i18next";
import { EditTraefikEnv } from "../../web-server/edit-traefik-env";
import { ShowModalLogs } from "../../web-server/show-modal-logs";
@@ -30,6 +31,7 @@ interface Props {
serverId?: string;
}
export const ShowTraefikActions = ({ serverId }: Props) => {
const { t } = useTranslation("settings");
const { mutateAsync: reloadTraefik, isLoading: reloadTraefikIsLoading } =
api.settings.reloadTraefik.useMutation();
@@ -51,11 +53,13 @@ export const ShowTraefikActions = ({ serverId }: Props) => {
isLoading={reloadTraefikIsLoading || toggleDashboardIsLoading}
variant="outline"
>
Traefik
{t("settings.server.webServer.traefik.label")}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56" align="start">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuLabel>
{t("settings.server.webServer.actions")}
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem
@@ -71,17 +75,17 @@ export const ShowTraefikActions = ({ serverId }: Props) => {
});
}}
>
<span>Reload</span>
<span>{t("settings.server.webServer.reload")}</span>
</DropdownMenuItem>
<ShowModalLogs appName="dokploy-traefik" serverId={serverId}>
<span>Watch logs</span>
<span>{t("settings.server.webServer.watchLogs")}</span>
</ShowModalLogs>
<EditTraefikEnv serverId={serverId}>
<DropdownMenuItem
onSelect={(e) => e.preventDefault()}
className="w-full cursor-pointer space-x-3"
>
<span>Modify Env</span>
<span>{t("settings.server.webServer.traefik.modifyEnv")}</span>
</DropdownMenuItem>
</EditTraefikEnv>

View File

@@ -24,6 +24,7 @@ import {
} from "@/components/ui/select";
import { api } from "@/utils/api";
import { zodResolver } from "@hookform/resolvers/zod";
import { useTranslation } from "next-i18next";
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
@@ -49,6 +50,7 @@ const addServerDomain = z
type AddServerDomain = z.infer<typeof addServerDomain>;
export const WebDomain = () => {
const { t } = useTranslation("settings");
const { data: user, refetch } = api.admin.one.useQuery();
const { mutateAsync, isLoading } =
api.settings.assignDomainServer.useMutation();
@@ -89,9 +91,11 @@ export const WebDomain = () => {
<div className="w-full">
<Card className="bg-transparent">
<CardHeader>
<CardTitle className="text-xl">Server Domain</CardTitle>
<CardTitle className="text-xl">
{t("settings.server.domain.title")}
</CardTitle>
<CardDescription>
Add a domain to your server application.
{t("settings.server.domain.description")}
</CardDescription>
</CardHeader>
<CardContent className="flex w-full flex-col gap-4">
@@ -106,7 +110,9 @@ export const WebDomain = () => {
render={({ field }) => {
return (
<FormItem>
<FormLabel>Domain</FormLabel>
<FormLabel>
{t("settings.server.domain.form.domain")}
</FormLabel>
<FormControl>
<Input
className="w-full"
@@ -126,7 +132,9 @@ export const WebDomain = () => {
render={({ field }) => {
return (
<FormItem>
<FormLabel>Letsencrypt Email</FormLabel>
<FormLabel>
{t("settings.server.domain.form.letsEncryptEmail")}
</FormLabel>
<FormControl>
<Input
className="w-full"
@@ -145,20 +153,32 @@ export const WebDomain = () => {
render={({ field }) => {
return (
<FormItem className="md:col-span-2">
<FormLabel>Certificate</FormLabel>
<FormLabel>
{t("settings.server.domain.form.certificate.label")}
</FormLabel>
<Select
onValueChange={field.onChange}
value={field.value}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select a certificate" />
<SelectValue
placeholder={t(
"settings.server.domain.form.certificate.placeholder",
)}
/>
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value={"none"}>None</SelectItem>
<SelectItem value={"none"}>
{t(
"settings.server.domain.form.certificateOptions.none",
)}
</SelectItem>
<SelectItem value={"letsencrypt"}>
Letsencrypt (Default)
{t(
"settings.server.domain.form.certificateOptions.letsencrypt",
)}
</SelectItem>
</SelectContent>
</Select>
@@ -169,7 +189,7 @@ export const WebDomain = () => {
/>
<div>
<Button isLoading={isLoading} type="submit">
Save
{t("settings.common.save")}
</Button>
</div>
</form>

View File

@@ -7,6 +7,7 @@ import {
} from "@/components/ui/card";
import { cn } from "@/lib/utils";
import { api } from "@/utils/api";
import { useTranslation } from "next-i18next";
import React from "react";
import { ShowDokployActions } from "./servers/actions/show-dokploy-actions";
import { ShowStorageActions } from "./servers/actions/show-storage-actions";
@@ -18,6 +19,7 @@ interface Props {
className?: string;
}
export const WebServer = ({ className }: Props) => {
const { t } = useTranslation("settings");
const { data } = api.admin.one.useQuery();
const { data: dokployVersion } = api.settings.getDokployVersion.useQuery();
@@ -25,8 +27,12 @@ export const WebServer = ({ className }: Props) => {
return (
<Card className={cn("rounded-lg w-full bg-transparent p-0", className)}>
<CardHeader>
<CardTitle className="text-xl">Web server settings</CardTitle>
<CardDescription>Reload or clean the web server.</CardDescription>
<CardTitle className="text-xl">
{t("settings.server.webServer.title")}
</CardTitle>
<CardDescription>
{t("settings.server.webServer.description")}
</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-4 ">
<div className="grid md:grid-cols-2 gap-4">

View File

@@ -3,9 +3,11 @@ import { WebServer } from "@/components/dashboard/settings/web-server";
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
import { SettingsLayout } from "@/components/layouts/settings-layout";
import { appRouter } from "@/server/api/root";
import { getLocale } from "@/utils/i18n";
import { IS_CLOUD, validateRequest } from "@dokploy/server";
import { createServerSideHelpers } from "@trpc/react-query/server";
import type { GetServerSidePropsContext } from "next";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import React, { type ReactElement } from "react";
import superjson from "superjson";
@@ -31,6 +33,7 @@ export async function getServerSideProps(
ctx: GetServerSidePropsContext<{ serviceId: string }>,
) {
const { req, res } = ctx;
const locale = await getLocale(req.cookies);
if (IS_CLOUD) {
return {
redirect: {
@@ -73,6 +76,7 @@ export async function getServerSideProps(
return {
props: {
trpcState: helpers.dehydrate(),
...(await serverSideTranslations(locale, ["settings"])),
},
};
}

View File

@@ -3,6 +3,47 @@
"common": {
"save": "Save"
},
"server": {
"domain": {
"title": "Server Domain",
"description": "Add a domain to your server application.",
"form": {
"domain": "Domain",
"letsEncryptEmail": "Let's Encrypt Email",
"certificate": {
"label": "Certificate",
"placeholder": "Select a certificate"
},
"certificateOptions": {
"none": "None",
"letsencrypt": "Let's Encrypt (Default)"
}
}
},
"webServer": {
"title": "Web Server",
"description": "Reload or clean the web server.",
"actions": "Actions",
"reload": "Reload",
"watchLogs": "Watch logs",
"server": {
"label": "Server"
},
"traefik": {
"label": "Traefik",
"modifyEnv": "Modify Env"
},
"storage": {
"label": "Space",
"cleanUnusedImages": "Clean unused images",
"cleanUnusedVolumes": "Clean unused volumes",
"cleanStoppedContainers": "Clean stopped containers",
"cleanDockerBuilder": "Clean Docker Builder & System",
"cleanMonitoring": "Clean Monitoring",
"cleanAll": "Clean all"
}
}
},
"profile": {
"title": "Account",
"description": "Change the details of your profile here.",

View File

@@ -3,6 +3,47 @@
"common": {
"save": "保存"
},
"server": {
"domain": {
"title": "服务器域名",
"description": "添加一个域名到您的服务器。",
"form": {
"domain": "域名",
"letsEncryptEmail": "Let's Encrypt 邮箱",
"certificate": {
"label": "证书",
"placeholder": "选择一个证书"
},
"certificateOptions": {
"none": "无",
"letsencrypt": "Let's Encrypt (默认)"
}
}
},
"webServer": {
"title": "Web 服务器",
"description": "管理 Web 服务器。",
"actions": "操作",
"reload": "重新加载",
"watchLogs": "查看日志",
"server": {
"label": "服务器"
},
"traefik": {
"label": "Traefik",
"modifyEnv": "修改环境变量"
},
"storage": {
"label": "磁盘空间",
"cleanUnusedImages": "清理未使用的镜像",
"cleanUnusedVolumes": "清理未使用的卷",
"cleanStoppedContainers": "清理停止的容器",
"cleanDockerBuilder": "清理 Docker Builder 和系统缓存",
"cleanMonitoring": "Clean Monitoring",
"cleanAll": "清理所有"
}
}
},
"profile": {
"title": "账户偏好",
"description": "更改您的个人资料详情。",