mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat(i18n):add i18n for auth page
This commit is contained in:
@@ -153,7 +153,7 @@ export function AddOrganization({ organizationId }: Props) {
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder={t(
|
||||
"common.side.organizations.name.placeHolder",
|
||||
"common.side.organizations.name.placeholder",
|
||||
)}
|
||||
{...field}
|
||||
className="col-span-3"
|
||||
|
||||
@@ -1111,7 +1111,7 @@ export default function Page({ children }: Props) {
|
||||
href={activeItem?.url || "/"}
|
||||
className="flex items-center gap-1.5"
|
||||
>
|
||||
{activeItem?.title}
|
||||
{activeItem?.titleKey ? t(activeItem.titleKey) : ""}
|
||||
</Link>
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
|
||||
@@ -23,11 +23,13 @@ import { ChevronsUpDown } from "lucide-react";
|
||||
import { useRouter } from "next/router";
|
||||
import { ModeToggle } from "../ui/modeToggle";
|
||||
import { SidebarMenuButton } from "../ui/sidebar";
|
||||
import { useTranslation } from "next-i18next";
|
||||
|
||||
const _AUTO_CHECK_UPDATES_INTERVAL_MINUTES = 7;
|
||||
|
||||
export const UserNav = () => {
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation("common");
|
||||
const { data } = api.user.get.useQuery();
|
||||
const { data: isCloud } = api.settings.isCloud.useQuery();
|
||||
|
||||
@@ -49,7 +51,9 @@ export const UserNav = () => {
|
||||
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="grid flex-1 text-left text-sm leading-tight">
|
||||
<span className="truncate font-semibold">Account</span>
|
||||
<span className="truncate font-semibold">
|
||||
{t("common.account")}
|
||||
</span>
|
||||
<span className="truncate text-xs">{data?.user?.email}</span>
|
||||
</div>
|
||||
<ChevronsUpDown className="ml-auto size-4" />
|
||||
@@ -63,7 +67,7 @@ export const UserNav = () => {
|
||||
>
|
||||
<div className="flex items-center justify-between px-2 py-1.5">
|
||||
<DropdownMenuLabel className="flex flex-col">
|
||||
My Account
|
||||
{t("common.account.mine")}
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
{data?.user?.email}
|
||||
</span>
|
||||
@@ -78,7 +82,7 @@ export const UserNav = () => {
|
||||
router.push("/dashboard/settings/profile");
|
||||
}}
|
||||
>
|
||||
Profile
|
||||
{t("common.side.profile")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
className="cursor-pointer"
|
||||
@@ -86,7 +90,7 @@ export const UserNav = () => {
|
||||
router.push("/dashboard/projects");
|
||||
}}
|
||||
>
|
||||
Projects
|
||||
{t("common.side.projects")}
|
||||
</DropdownMenuItem>
|
||||
{!isCloud ? (
|
||||
<>
|
||||
@@ -96,7 +100,7 @@ export const UserNav = () => {
|
||||
router.push("/dashboard/monitoring");
|
||||
}}
|
||||
>
|
||||
Monitoring
|
||||
{t("common.side.monitoring")}
|
||||
</DropdownMenuItem>
|
||||
{(data?.role === "owner" || data?.canAccessToTraefikFiles) && (
|
||||
<DropdownMenuItem
|
||||
@@ -105,7 +109,7 @@ export const UserNav = () => {
|
||||
router.push("/dashboard/traefik");
|
||||
}}
|
||||
>
|
||||
Traefik
|
||||
{t("common.side.traefik")}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
{(data?.role === "owner" || data?.canAccessToDocker) && (
|
||||
@@ -117,7 +121,7 @@ export const UserNav = () => {
|
||||
});
|
||||
}}
|
||||
>
|
||||
Docker
|
||||
{t("common.side.docker")}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
|
||||
@@ -128,7 +132,7 @@ export const UserNav = () => {
|
||||
router.push("/dashboard/settings");
|
||||
}}
|
||||
>
|
||||
Settings
|
||||
{t("common.side.settings")}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</>
|
||||
@@ -141,7 +145,7 @@ export const UserNav = () => {
|
||||
router.push("/dashboard/settings/servers");
|
||||
}}
|
||||
>
|
||||
Servers
|
||||
{t("common.side.remote-servers")}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
|
||||
@@ -152,7 +156,7 @@ export const UserNav = () => {
|
||||
router.push("/dashboard/settings");
|
||||
}}
|
||||
>
|
||||
Settings
|
||||
{t("common.side.settings")}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</>
|
||||
@@ -165,7 +169,7 @@ export const UserNav = () => {
|
||||
router.push("/dashboard/settings/billing");
|
||||
}}
|
||||
>
|
||||
Billing
|
||||
{t("common.side.billing")}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
<DropdownMenuSeparator />
|
||||
@@ -181,7 +185,7 @@ export const UserNav = () => {
|
||||
// });
|
||||
}}
|
||||
>
|
||||
Log out
|
||||
{t("common.account.logout")}
|
||||
</DropdownMenuItem>
|
||||
<div className="w-32">
|
||||
<Select
|
||||
@@ -190,7 +194,7 @@ export const UserNav = () => {
|
||||
value={locale}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select Language" />
|
||||
<SelectValue placeholder={t("common.account.selectLanguage")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{Object.values(Languages).map((language) => (
|
||||
|
||||
@@ -32,6 +32,7 @@ export async function getServerSideProps(
|
||||
}
|
||||
const { req, res } = ctx;
|
||||
const locale = getLocale(req.cookies);
|
||||
|
||||
const { user, session } = await validateRequest(req);
|
||||
if (!user || user.role === "member") {
|
||||
return {
|
||||
|
||||
@@ -26,11 +26,13 @@ import {
|
||||
} from "@/components/ui/input-otp";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
import { getLocale, serverSideTranslations } from "@/utils/i18n";
|
||||
import { IS_CLOUD, isAdminPresent } from "@dokploy/server";
|
||||
import { validateRequest } from "@dokploy/server/lib/auth";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { REGEXP_ONLY_DIGITS } from "input-otp";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { type ReactElement, useState } from "react";
|
||||
@@ -54,6 +56,8 @@ interface Props {
|
||||
}
|
||||
export default function Home({ IS_CLOUD }: Props) {
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation("auth");
|
||||
|
||||
const [isLoginLoading, setIsLoginLoading] = useState(false);
|
||||
const [isTwoFactorLoading, setIsTwoFactorLoading] = useState(false);
|
||||
const [isBackupCodeLoading, setIsBackupCodeLoading] = useState(false);
|
||||
@@ -106,7 +110,7 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
const onTwoFactorSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (twoFactorCode.length !== 6) {
|
||||
toast.error("Please enter a valid 6-digit code");
|
||||
toast.error(t("auth.invalidTwoFactorCode"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -118,14 +122,14 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
|
||||
if (error) {
|
||||
toast.error(error.message);
|
||||
setError(error.message || "An error occurred while verifying 2FA code");
|
||||
setError(error.message || t("auth.twoFactorVerificationError"));
|
||||
return;
|
||||
}
|
||||
|
||||
toast.success("Logged in successfully");
|
||||
router.push("/dashboard/projects");
|
||||
} catch (_error) {
|
||||
toast.error("An error occurred while verifying 2FA code");
|
||||
toast.error(t("auth.twoFactorVerificationError"));
|
||||
} finally {
|
||||
setIsTwoFactorLoading(false);
|
||||
}
|
||||
@@ -134,7 +138,7 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
const onBackupCodeSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (backupCode.length < 8) {
|
||||
toast.error("Please enter a valid backup code");
|
||||
toast.error(t("auth.invalidBackupCode"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -147,7 +151,7 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
if (error) {
|
||||
toast.error(error.message);
|
||||
setError(
|
||||
error.message || "An error occurred while verifying backup code",
|
||||
error.message || t("auth.backupCodeVerificationError"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -155,7 +159,7 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
toast.success("Logged in successfully");
|
||||
router.push("/dashboard/projects");
|
||||
} catch (_error) {
|
||||
toast.error("An error occurred while verifying backup code");
|
||||
toast.error(t("auth.backupCodeVerificationError"));
|
||||
} finally {
|
||||
setIsBackupCodeLoading(false);
|
||||
}
|
||||
@@ -173,8 +177,8 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error("An error occurred while signing in with GitHub", {
|
||||
description: error instanceof Error ? error.message : "Unknown error",
|
||||
toast.error(t("auth.githubSignInError"), {
|
||||
description: error instanceof Error ? error.message : t("auth.unknownError"),
|
||||
});
|
||||
} finally {
|
||||
setIsGithubLoading(false);
|
||||
@@ -193,8 +197,8 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error("An error occurred while signing in with Google", {
|
||||
description: error instanceof Error ? error.message : "Unknown error",
|
||||
toast.error(t("auth.googleSignInError"), {
|
||||
description: error instanceof Error ? error.message : t("auth.unknownError"),
|
||||
});
|
||||
} finally {
|
||||
setIsGoogleLoading(false);
|
||||
@@ -206,11 +210,11 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
<h1 className="text-2xl font-semibold tracking-tight">
|
||||
<div className="flex flex-row items-center justify-center gap-2">
|
||||
<Logo className="size-12" />
|
||||
Sign in
|
||||
{t("auth.signIn")}
|
||||
</div>
|
||||
</h1>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Enter your email and password to sign in
|
||||
{t("auth.signInDescription")}
|
||||
</p>
|
||||
</div>
|
||||
{error && (
|
||||
@@ -235,7 +239,7 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
d="M409.132 114.573c-19.608-33.596-46.205-60.194-79.798-79.8-33.598-19.607-70.277-29.408-110.063-29.408-39.781 0-76.472 9.804-110.063 29.408-33.596 19.605-60.192 46.204-79.8 79.8C9.803 148.168 0 184.854 0 224.63c0 47.78 13.94 90.745 41.827 128.906 27.884 38.164 63.906 64.572 108.063 79.227 5.14.954 8.945.283 11.419-1.996 2.475-2.282 3.711-5.14 3.711-8.562 0-.571-.049-5.708-.144-15.417a2549.81 2549.81 0 01-.144-25.406l-6.567 1.136c-4.187.767-9.469 1.092-15.846 1-6.374-.089-12.991-.757-19.842-1.999-6.854-1.231-13.229-4.086-19.13-8.559-5.898-4.473-10.085-10.328-12.56-17.556l-2.855-6.57c-1.903-4.374-4.899-9.233-8.992-14.559-4.093-5.331-8.232-8.945-12.419-10.848l-1.999-1.431c-1.332-.951-2.568-2.098-3.711-3.429-1.142-1.331-1.997-2.663-2.568-3.997-.572-1.335-.098-2.43 1.427-3.289 1.525-.859 4.281-1.276 8.28-1.276l5.708.853c3.807.763 8.516 3.042 14.133 6.851 5.614 3.806 10.229 8.754 13.846 14.842 4.38 7.806 9.657 13.754 15.846 17.847 6.184 4.093 12.419 6.136 18.699 6.136 6.28 0 11.704-.476 16.274-1.423 4.565-.952 8.848-2.383 12.847-4.285 1.713-12.758 6.377-22.559 13.988-29.41-10.848-1.14-20.601-2.857-29.264-5.14-8.658-2.286-17.605-5.996-26.835-11.14-9.235-5.137-16.896-11.516-22.985-19.126-6.09-7.614-11.088-17.61-14.987-29.979-3.901-12.374-5.852-26.648-5.852-42.826 0-23.035 7.52-42.637 22.557-58.817-7.044-17.318-6.379-36.732 1.997-58.24 5.52-1.715 13.706-.428 24.554 3.853 10.85 4.283 18.794 7.952 23.84 10.994 5.046 3.041 9.089 5.618 12.135 7.708 17.705-4.947 35.976-7.421 54.818-7.421s37.117 2.474 54.823 7.421l10.849-6.849c7.419-4.57 16.18-8.758 26.262-12.565 10.088-3.805 17.802-4.853 23.134-3.138 8.562 21.509 9.325 40.922 2.279 58.24 15.036 16.18 22.559 35.787 22.559 58.817 0 16.178-1.958 30.497-5.853 42.966-3.9 12.471-8.941 22.457-15.125 29.979-6.191 7.521-13.901 13.85-23.131 18.986-9.232 5.14-18.182 8.85-26.84 11.136-8.662 2.286-18.415 4.004-29.263 5.146 9.894 8.562 14.842 22.077 14.842 40.539v60.237c0 3.422 1.19 6.279 3.572 8.562 2.379 2.279 6.136 2.95 11.276 1.995 44.163-14.653 80.185-41.062 108.068-79.226 27.88-38.161 41.825-81.126 41.825-128.906-.01-39.771-9.818-76.454-29.414-110.049z"
|
||||
/>
|
||||
</svg>
|
||||
Sign in with GitHub
|
||||
{t("auth.signInWithGithub")}
|
||||
</Button>
|
||||
)}
|
||||
{IS_CLOUD && (
|
||||
@@ -264,7 +268,7 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
|
||||
/>
|
||||
</svg>
|
||||
Sign in with Google
|
||||
{t("auth.signInWithGoogle")}
|
||||
</Button>
|
||||
)}
|
||||
<Form {...loginForm}>
|
||||
@@ -278,7 +282,7 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<FormLabel>{t("auth.email")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="john@example.com" {...field} />
|
||||
</FormControl>
|
||||
@@ -291,11 +295,11 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Password</FormLabel>
|
||||
<FormLabel>{t("auth.password")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder="Enter your password"
|
||||
placeholder={t("auth.password.placeholder")}
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
@@ -308,7 +312,7 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
type="submit"
|
||||
isLoading={isLoginLoading}
|
||||
>
|
||||
Login
|
||||
{t("auth.login")}
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
@@ -322,7 +326,7 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
autoComplete="off"
|
||||
>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label>2FA Code</Label>
|
||||
<Label>{t("auth.twoFactorCode")}</Label>
|
||||
<InputOTP
|
||||
value={twoFactorCode}
|
||||
onChange={setTwoFactorCode}
|
||||
@@ -340,14 +344,14 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
<CardDescription>
|
||||
Enter the 6-digit code from your authenticator app
|
||||
{t("auth.twoFactorCodeDescription")}
|
||||
</CardDescription>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsBackupCodeModalOpen(true)}
|
||||
className="text-sm text-muted-foreground hover:underline self-start mt-2"
|
||||
>
|
||||
Lost access to your authenticator app?
|
||||
{t("auth.lostAuthenticator")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -361,14 +365,14 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
setTwoFactorCode("");
|
||||
}}
|
||||
>
|
||||
Back
|
||||
{t("auth.back")}
|
||||
</Button>
|
||||
<Button
|
||||
className="w-full"
|
||||
type="submit"
|
||||
isLoading={isTwoFactorLoading}
|
||||
>
|
||||
Verify
|
||||
{t("auth.verify")}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -379,24 +383,23 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Enter Backup Code</DialogTitle>
|
||||
<DialogTitle>{t("auth.enterBackupCode")}</DialogTitle>
|
||||
<DialogDescription>
|
||||
Enter one of your backup codes to access your account
|
||||
{t("auth.enterBackupCodeDescription")}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<form onSubmit={onBackupCodeSubmit} className="space-y-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label>Backup Code</Label>
|
||||
<Label>{t("auth.backupCode")}</Label>
|
||||
<Input
|
||||
value={backupCode}
|
||||
onChange={(e) => setBackupCode(e.target.value)}
|
||||
placeholder="Enter your backup code"
|
||||
placeholder={t("auth.backupCode.placeholder")}
|
||||
className="font-mono"
|
||||
/>
|
||||
<CardDescription>
|
||||
Enter one of the backup codes you received when setting up
|
||||
2FA
|
||||
{t("auth.backupCodeDescription")}
|
||||
</CardDescription>
|
||||
</div>
|
||||
|
||||
@@ -410,14 +413,14 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
setBackupCode("");
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
{t("auth.cancel")}
|
||||
</Button>
|
||||
<Button
|
||||
className="w-full"
|
||||
type="submit"
|
||||
isLoading={isBackupCodeLoading}
|
||||
>
|
||||
Verify
|
||||
{t("auth.verify")}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -433,7 +436,7 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
className="hover:underline text-muted-foreground"
|
||||
href="/register"
|
||||
>
|
||||
Create an account
|
||||
{t("auth.createAccount")}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
@@ -444,7 +447,7 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
className="hover:underline text-muted-foreground"
|
||||
href="/send-reset-password"
|
||||
>
|
||||
Lost your password?
|
||||
{t("auth.forgetPassword")}
|
||||
</Link>
|
||||
) : (
|
||||
<Link
|
||||
@@ -452,7 +455,7 @@ export default function Home({ IS_CLOUD }: Props) {
|
||||
href="https://docs.dokploy.com/docs/core/reset-password"
|
||||
target="_blank"
|
||||
>
|
||||
Lost your password?
|
||||
{t("auth.forgetPassword")}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
@@ -467,6 +470,9 @@ Home.getLayout = (page: ReactElement) => {
|
||||
return <OnboardingLayout>{page}</OnboardingLayout>;
|
||||
};
|
||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
const { req } = context;
|
||||
const locale = getLocale(req.cookies);
|
||||
|
||||
if (IS_CLOUD) {
|
||||
try {
|
||||
const { user } = await validateRequest(context.req);
|
||||
@@ -511,6 +517,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
return {
|
||||
props: {
|
||||
hasAdmin,
|
||||
...(await serverSideTranslations(locale, ["auth"])),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
30
apps/dokploy/public/locales/en/auth.json
Normal file
30
apps/dokploy/public/locales/en/auth.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"auth.signIn": "Sign In",
|
||||
"auth.signInDescription": "Enter your email and password to sign in",
|
||||
"auth.signInWithGoogle": "Sign in with Google",
|
||||
"auth.signInWithGithub": "Sign in with GitHub",
|
||||
"auth.email": "Email",
|
||||
"auth.password": "Password",
|
||||
"auth.password.placeholder": "Enter your password",
|
||||
"auth.login": "Login",
|
||||
"auth.forgetPassword": "Lost your password?",
|
||||
"auth.createAccount": "Create an account",
|
||||
"auth.twoFactorCode": "2FA Code",
|
||||
"auth.twoFactorCodeDescription": "Enter the 6-digit code from your authenticator app",
|
||||
"auth.lostAuthenticator": "Lost access to your authenticator app?",
|
||||
"auth.back": "Back",
|
||||
"auth.verify": "Verify",
|
||||
"auth.enterBackupCode": "Enter Backup Code",
|
||||
"auth.enterBackupCodeDescription": "Enter one of your backup codes to access your account",
|
||||
"auth.backupCode": "Backup Code",
|
||||
"auth.backupCode.placeholder": "Enter your backup code",
|
||||
"auth.backupCodeDescription": "Enter one of the backup codes you received when setting up 2FA",
|
||||
"auth.cancel": "Cancel",
|
||||
"auth.invalidTwoFactorCode": "Please enter a valid 6-digit code",
|
||||
"auth.twoFactorVerificationError": "An error occurred while verifying 2FA code",
|
||||
"auth.invalidBackupCode": "Please enter a valid backup code",
|
||||
"auth.backupCodeVerificationError": "An error occurred while verifying backup code",
|
||||
"auth.githubSignInError": "An error occurred while signing in with GitHub",
|
||||
"auth.googleSignInError": "An error occurred while signing in with Google",
|
||||
"auth.unknownError": "Unknown error"
|
||||
}
|
||||
@@ -46,10 +46,15 @@
|
||||
"common.side.organizations.createOrganizationDescription": "Create a new organization to manage your projects.",
|
||||
"common.side.organizations.updateOrganizationDescription": "Update the organization name and logo",
|
||||
"common.side.organizations.name": "Name",
|
||||
"common.side.organizations.name.placeHolder": "Organization name",
|
||||
"common.side.organizations.name.placeholder": "Organization name",
|
||||
"common.side.organizations.logoURL": "Logo URL",
|
||||
"common.side.organizations.createSuccess": "Organization created successfully",
|
||||
"common.side.organizations.updateSuccess": "Organization updated successfully",
|
||||
"common.side.organizations.createFailed": "Failed to create organization",
|
||||
"common.side.organizations.updateFailed": "Failed to update organization"
|
||||
"common.side.organizations.updateFailed": "Failed to update organization",
|
||||
|
||||
"common.account": "Account",
|
||||
"common.account.mine": "My Account",
|
||||
"common.account.logout": "Logout",
|
||||
"common.account.selectLanguage": "Select Language"
|
||||
}
|
||||
|
||||
30
apps/dokploy/public/locales/zh-Hans/auth.json
Normal file
30
apps/dokploy/public/locales/zh-Hans/auth.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"auth.signIn": "登录",
|
||||
"auth.signInDescription": "请输入您的邮箱和密码登录",
|
||||
"auth.signInWithGoogle": "使用 Google 登录",
|
||||
"auth.signInWithGithub": "使用 GitHub 登录",
|
||||
"auth.email": "邮箱",
|
||||
"auth.password": "密码",
|
||||
"auth.password.placeholder": "请输入密码",
|
||||
"auth.login": "登录",
|
||||
"auth.forgetPassword": "忘记密码?",
|
||||
"auth.createAccount": "创建账号",
|
||||
"auth.twoFactorCode": "两步认证",
|
||||
"auth.twoFactorCodeDescription": "请输入您的认证器应用中的6位数字验证码",
|
||||
"auth.lostAuthenticator": "无法访问认证器应用?",
|
||||
"auth.back": "返回",
|
||||
"auth.verify": "验证",
|
||||
"auth.enterBackupCode": "输入备用码",
|
||||
"auth.enterBackupCodeDescription": "输入备用码以访问您的账户",
|
||||
"auth.backupCode": "备用码",
|
||||
"auth.backupCode.placeholder": "请输入您的备用码",
|
||||
"auth.backupCodeDescription": "输入您在设置两步认证时收到的备用码",
|
||||
"auth.cancel": "取消",
|
||||
"auth.invalidTwoFactorCode": "请输入有效的6位数字验证码",
|
||||
"auth.twoFactorVerificationError": "验证两步认证码时发生错误",
|
||||
"auth.invalidBackupCode": "请输入有效的备用码",
|
||||
"auth.backupCodeVerificationError": "验证备用码时发生错误",
|
||||
"auth.githubSignInError": "使用 GitHub 登录时发生错误",
|
||||
"auth.googleSignInError": "使用 Google 登录时发生错误",
|
||||
"auth.unknownError": "未知错误"
|
||||
}
|
||||
@@ -46,10 +46,15 @@
|
||||
"common.side.organizations.createOrganizationDescription": "创建一个新组织来管理您的项目。",
|
||||
"common.side.organizations.updateOrganizationDescription": "更新组织名称和标志",
|
||||
"common.side.organizations.name": "名称",
|
||||
"common.side.organizations.name.placeHolder": "请输入组织名称",
|
||||
"common.side.organizations.name.placeholder": "请输入组织名称",
|
||||
"common.side.organizations.logoURL": "Logo 图片地址",
|
||||
"common.side.organizations.createSuccess": "组织创建成功",
|
||||
"common.side.organizations.updateSuccess": "组织更新成功",
|
||||
"common.side.organizations.createFailed": "创建组织失败",
|
||||
"common.side.organizations.updateFailed": "更新组织失败"
|
||||
"common.side.organizations.updateFailed": "更新组织失败",
|
||||
|
||||
"common.account": "账户",
|
||||
"common.account.mine": "我的账户",
|
||||
"common.account.logout": "注销",
|
||||
"common.account.selectLanguage": "选择语言"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user