mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat(i18n): add i18n support for sidebar
This commit is contained in:
@@ -86,6 +86,7 @@ import { Logo } from "../shared/logo";
|
|||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
import { UpdateServerButton } from "./update-server";
|
import { UpdateServerButton } from "./update-server";
|
||||||
import { UserNav } from "./user-nav";
|
import { UserNav } from "./user-nav";
|
||||||
|
import { useTranslation } from "next-i18next";
|
||||||
|
|
||||||
// The types of the queries we are going to use
|
// The types of the queries we are going to use
|
||||||
type AuthQueryOutput = inferRouterOutputs<AppRouter>["user"]["get"];
|
type AuthQueryOutput = inferRouterOutputs<AppRouter>["user"]["get"];
|
||||||
@@ -93,6 +94,7 @@ type AuthQueryOutput = inferRouterOutputs<AppRouter>["user"]["get"];
|
|||||||
type SingleNavItem = {
|
type SingleNavItem = {
|
||||||
isSingle?: true;
|
isSingle?: true;
|
||||||
title: string;
|
title: string;
|
||||||
|
titleKey: string;
|
||||||
url: string;
|
url: string;
|
||||||
icon?: LucideIcon;
|
icon?: LucideIcon;
|
||||||
isEnabled?: (opts: {
|
isEnabled?: (opts: {
|
||||||
@@ -110,6 +112,7 @@ type NavItem =
|
|||||||
| {
|
| {
|
||||||
isSingle: false;
|
isSingle: false;
|
||||||
title: string;
|
title: string;
|
||||||
|
titleKey: string;
|
||||||
icon: LucideIcon;
|
icon: LucideIcon;
|
||||||
items: SingleNavItem[];
|
items: SingleNavItem[];
|
||||||
isEnabled?: (opts: {
|
isEnabled?: (opts: {
|
||||||
@@ -122,6 +125,7 @@ type NavItem =
|
|||||||
// Represents an external link item (used for the help section)
|
// Represents an external link item (used for the help section)
|
||||||
type ExternalLink = {
|
type ExternalLink = {
|
||||||
name: string;
|
name: string;
|
||||||
|
nameKey: string;
|
||||||
url: string;
|
url: string;
|
||||||
icon: React.ComponentType<{ className?: string }>;
|
icon: React.ComponentType<{ className?: string }>;
|
||||||
isEnabled?: (opts: {
|
isEnabled?: (opts: {
|
||||||
@@ -147,12 +151,14 @@ const MENU: Menu = {
|
|||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "Projects",
|
title: "Projects",
|
||||||
|
titleKey: "common.side.projects",
|
||||||
url: "/dashboard/projects",
|
url: "/dashboard/projects",
|
||||||
icon: Folder,
|
icon: Folder,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "Monitoring",
|
title: "Monitoring",
|
||||||
|
titleKey: "common.side.monitoring",
|
||||||
url: "/dashboard/monitoring",
|
url: "/dashboard/monitoring",
|
||||||
icon: BarChartHorizontalBigIcon,
|
icon: BarChartHorizontalBigIcon,
|
||||||
// Only enabled in non-cloud environments
|
// Only enabled in non-cloud environments
|
||||||
@@ -161,6 +167,7 @@ const MENU: Menu = {
|
|||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "Traefik File System",
|
title: "Traefik File System",
|
||||||
|
titleKey: "common.side.traefik",
|
||||||
url: "/dashboard/traefik",
|
url: "/dashboard/traefik",
|
||||||
icon: GalleryVerticalEnd,
|
icon: GalleryVerticalEnd,
|
||||||
// Only enabled for admins and users with access to Traefik files in non-cloud environments
|
// Only enabled for admins and users with access to Traefik files in non-cloud environments
|
||||||
@@ -173,6 +180,7 @@ const MENU: Menu = {
|
|||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "Docker",
|
title: "Docker",
|
||||||
|
titleKey: "common.side.docker",
|
||||||
url: "/dashboard/docker",
|
url: "/dashboard/docker",
|
||||||
icon: BlocksIcon,
|
icon: BlocksIcon,
|
||||||
// Only enabled for admins and users with access to Docker in non-cloud environments
|
// Only enabled for admins and users with access to Docker in non-cloud environments
|
||||||
@@ -182,6 +190,7 @@ const MENU: Menu = {
|
|||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "Swarm",
|
title: "Swarm",
|
||||||
|
titleKey: "common.side.swarm",
|
||||||
url: "/dashboard/swarm",
|
url: "/dashboard/swarm",
|
||||||
icon: PieChart,
|
icon: PieChart,
|
||||||
// Only enabled for admins and users with access to Docker in non-cloud environments
|
// Only enabled for admins and users with access to Docker in non-cloud environments
|
||||||
@@ -191,6 +200,7 @@ const MENU: Menu = {
|
|||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "Requests",
|
title: "Requests",
|
||||||
|
titleKey: "common.side.requests",
|
||||||
url: "/dashboard/requests",
|
url: "/dashboard/requests",
|
||||||
icon: Forward,
|
icon: Forward,
|
||||||
// Only enabled for admins and users with access to Docker in non-cloud environments
|
// Only enabled for admins and users with access to Docker in non-cloud environments
|
||||||
@@ -259,6 +269,7 @@ const MENU: Menu = {
|
|||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "Web Server",
|
title: "Web Server",
|
||||||
|
titleKey: "common.side.web-server",
|
||||||
url: "/dashboard/settings/server",
|
url: "/dashboard/settings/server",
|
||||||
icon: Activity,
|
icon: Activity,
|
||||||
// Only enabled for admins in non-cloud environments
|
// Only enabled for admins in non-cloud environments
|
||||||
@@ -267,12 +278,14 @@ const MENU: Menu = {
|
|||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "Profile",
|
title: "Profile",
|
||||||
|
titleKey: "common.side.profile",
|
||||||
url: "/dashboard/settings/profile",
|
url: "/dashboard/settings/profile",
|
||||||
icon: User,
|
icon: User,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "Remote Servers",
|
title: "Remote Servers",
|
||||||
|
titleKey: "common.side.remote-servers",
|
||||||
url: "/dashboard/settings/servers",
|
url: "/dashboard/settings/servers",
|
||||||
icon: Server,
|
icon: Server,
|
||||||
// Only enabled for admins
|
// Only enabled for admins
|
||||||
@@ -281,6 +294,7 @@ const MENU: Menu = {
|
|||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "Users",
|
title: "Users",
|
||||||
|
titleKey: "common.side.users",
|
||||||
icon: Users,
|
icon: Users,
|
||||||
url: "/dashboard/settings/users",
|
url: "/dashboard/settings/users",
|
||||||
// Only enabled for admins
|
// Only enabled for admins
|
||||||
@@ -289,6 +303,7 @@ const MENU: Menu = {
|
|||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "SSH Keys",
|
title: "SSH Keys",
|
||||||
|
titleKey: "common.side.ssh-keys",
|
||||||
icon: KeyRound,
|
icon: KeyRound,
|
||||||
url: "/dashboard/settings/ssh-keys",
|
url: "/dashboard/settings/ssh-keys",
|
||||||
// Only enabled for admins and users with access to SSH keys
|
// Only enabled for admins and users with access to SSH keys
|
||||||
@@ -297,6 +312,7 @@ const MENU: Menu = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "AI",
|
title: "AI",
|
||||||
|
titleKey: "common.side.ai",
|
||||||
icon: BotIcon,
|
icon: BotIcon,
|
||||||
url: "/dashboard/settings/ai",
|
url: "/dashboard/settings/ai",
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
@@ -305,6 +321,7 @@ const MENU: Menu = {
|
|||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "Git",
|
title: "Git",
|
||||||
|
titleKey: "common.side.git",
|
||||||
url: "/dashboard/settings/git-providers",
|
url: "/dashboard/settings/git-providers",
|
||||||
icon: GitBranch,
|
icon: GitBranch,
|
||||||
// Only enabled for admins and users with access to Git providers
|
// Only enabled for admins and users with access to Git providers
|
||||||
@@ -314,6 +331,7 @@ const MENU: Menu = {
|
|||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "Registry",
|
title: "Registry",
|
||||||
|
titleKey: "common.side.registry",
|
||||||
url: "/dashboard/settings/registry",
|
url: "/dashboard/settings/registry",
|
||||||
icon: Package,
|
icon: Package,
|
||||||
// Only enabled for admins
|
// Only enabled for admins
|
||||||
@@ -322,6 +340,7 @@ const MENU: Menu = {
|
|||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "S3 Destinations",
|
title: "S3 Destinations",
|
||||||
|
titleKey: "common.side.s3-destinations",
|
||||||
url: "/dashboard/settings/destinations",
|
url: "/dashboard/settings/destinations",
|
||||||
icon: Database,
|
icon: Database,
|
||||||
// Only enabled for admins
|
// Only enabled for admins
|
||||||
@@ -331,6 +350,7 @@ const MENU: Menu = {
|
|||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "Certificates",
|
title: "Certificates",
|
||||||
|
titleKey: "common.side.certificates",
|
||||||
url: "/dashboard/settings/certificates",
|
url: "/dashboard/settings/certificates",
|
||||||
icon: ShieldCheck,
|
icon: ShieldCheck,
|
||||||
// Only enabled for admins
|
// Only enabled for admins
|
||||||
@@ -339,6 +359,7 @@ const MENU: Menu = {
|
|||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "Cluster",
|
title: "Cluster",
|
||||||
|
titleKey: "common.side.cluster",
|
||||||
url: "/dashboard/settings/cluster",
|
url: "/dashboard/settings/cluster",
|
||||||
icon: Boxes,
|
icon: Boxes,
|
||||||
// Only enabled for admins in non-cloud environments
|
// Only enabled for admins in non-cloud environments
|
||||||
@@ -347,6 +368,7 @@ const MENU: Menu = {
|
|||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "Notifications",
|
title: "Notifications",
|
||||||
|
titleKey: "common.side.notifications",
|
||||||
url: "/dashboard/settings/notifications",
|
url: "/dashboard/settings/notifications",
|
||||||
icon: Bell,
|
icon: Bell,
|
||||||
// Only enabled for admins
|
// Only enabled for admins
|
||||||
@@ -355,6 +377,7 @@ const MENU: Menu = {
|
|||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
title: "Billing",
|
title: "Billing",
|
||||||
|
titleKey: "common.side.billing",
|
||||||
url: "/dashboard/settings/billing",
|
url: "/dashboard/settings/billing",
|
||||||
icon: CreditCard,
|
icon: CreditCard,
|
||||||
// Only enabled for admins in cloud environments
|
// Only enabled for admins in cloud environments
|
||||||
@@ -365,16 +388,19 @@ const MENU: Menu = {
|
|||||||
help: [
|
help: [
|
||||||
{
|
{
|
||||||
name: "Documentation",
|
name: "Documentation",
|
||||||
|
nameKey: "common.side.documentation",
|
||||||
url: "https://docs.dokploy.com/docs/core",
|
url: "https://docs.dokploy.com/docs/core",
|
||||||
icon: BookIcon,
|
icon: BookIcon,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Support",
|
name: "Support",
|
||||||
|
nameKey: "common.side.support",
|
||||||
url: "https://discord.gg/2tBnJ3jDJc",
|
url: "https://discord.gg/2tBnJ3jDJc",
|
||||||
icon: CircleHelp,
|
icon: CircleHelp,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Sponsor",
|
name: "Sponsor",
|
||||||
|
nameKey: "common.side.sponsor",
|
||||||
url: "https://opencollective.com/dokploy",
|
url: "https://opencollective.com/dokploy",
|
||||||
icon: ({ className }) => (
|
icon: ({ className }) => (
|
||||||
<HeartIcon
|
<HeartIcon
|
||||||
@@ -493,6 +519,7 @@ function LogoWrapper() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function SidebarLogo() {
|
function SidebarLogo() {
|
||||||
|
const { t } = useTranslation("common");
|
||||||
const { state } = useSidebar();
|
const { state } = useSidebar();
|
||||||
const { data: isCloud } = api.settings.isCloud.useQuery();
|
const { data: isCloud } = api.settings.isCloud.useQuery();
|
||||||
const { data: user } = api.user.get.useQuery();
|
const { data: user } = api.user.get.useQuery();
|
||||||
@@ -689,7 +716,9 @@ function SidebarLogo() {
|
|||||||
side={"right"}
|
side={"right"}
|
||||||
className="w-80"
|
className="w-80"
|
||||||
>
|
>
|
||||||
<DropdownMenuLabel>Pending Invitations</DropdownMenuLabel>
|
<DropdownMenuLabel>
|
||||||
|
{t("common.side.invitations.pending-invitations")}
|
||||||
|
</DropdownMenuLabel>
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
{invitations && invitations.length > 0 ? (
|
{invitations && invitations.length > 0 ? (
|
||||||
invitations.map((invitation) => (
|
invitations.map((invitation) => (
|
||||||
@@ -702,16 +731,23 @@ function SidebarLogo() {
|
|||||||
{invitation?.organization?.name}
|
{invitation?.organization?.name}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-muted-foreground">
|
<div className="text-xs text-muted-foreground">
|
||||||
Expires:{" "}
|
{t("common.side.invitations.expires", {
|
||||||
{new Date(invitation.expiresAt).toLocaleString()}
|
expireDate: new Date(
|
||||||
|
invitation.expiresAt,
|
||||||
|
).toLocaleString(),
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-muted-foreground">
|
<div className="text-xs text-muted-foreground">
|
||||||
Role: {invitation.role}
|
{t("common.side.invitations.role", {
|
||||||
|
role: invitation.role,
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DialogAction
|
<DialogAction
|
||||||
title="Accept Invitation"
|
title={t("common.side.invitations.accept-invitation")}
|
||||||
description="Are you sure you want to accept this invitation?"
|
description={t(
|
||||||
|
"common.side.invitations.confirm-accept-invitation",
|
||||||
|
)}
|
||||||
type="default"
|
type="default"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const { error } =
|
const { error } =
|
||||||
@@ -721,24 +757,31 @@ function SidebarLogo() {
|
|||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error(
|
toast.error(
|
||||||
error.message || "Error accepting invitation",
|
error.message ||
|
||||||
|
t(
|
||||||
|
"common.side.invitations.error-accepting-invitation",
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
toast.success("Invitation accepted successfully");
|
toast.success(
|
||||||
|
t(
|
||||||
|
"common.side.invitations.invitation-accepted",
|
||||||
|
),
|
||||||
|
);
|
||||||
await refetchInvitations();
|
await refetchInvitations();
|
||||||
await refetch();
|
await refetch();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button size="sm" variant="secondary">
|
<Button size="sm" variant="secondary">
|
||||||
Accept Invitation
|
{t("common.side.invitations.accept-invitation")}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogAction>
|
</DialogAction>
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<DropdownMenuItem disabled>
|
<DropdownMenuItem disabled>
|
||||||
No pending invitations
|
{t("common.side.invitations.no-pending-invitations")}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -752,6 +795,8 @@ function SidebarLogo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Page({ children }: Props) {
|
export default function Page({ children }: Props) {
|
||||||
|
const { t } = useTranslation("common");
|
||||||
|
|
||||||
const [defaultOpen, setDefaultOpen] = useState<boolean | undefined>(
|
const [defaultOpen, setDefaultOpen] = useState<boolean | undefined>(
|
||||||
undefined,
|
undefined,
|
||||||
);
|
);
|
||||||
@@ -818,7 +863,7 @@ export default function Page({ children }: Props) {
|
|||||||
</SidebarHeader>
|
</SidebarHeader>
|
||||||
<SidebarContent>
|
<SidebarContent>
|
||||||
<SidebarGroup>
|
<SidebarGroup>
|
||||||
<SidebarGroupLabel>Home</SidebarGroupLabel>
|
<SidebarGroupLabel>{t("common.side.home")}</SidebarGroupLabel>
|
||||||
<SidebarMenu>
|
<SidebarMenu>
|
||||||
{filteredHome.map((item) => {
|
{filteredHome.map((item) => {
|
||||||
const isSingle = item.isSingle !== false;
|
const isSingle = item.isSingle !== false;
|
||||||
@@ -851,7 +896,7 @@ export default function Page({ children }: Props) {
|
|||||||
className={cn(isActive && "text-primary")}
|
className={cn(isActive && "text-primary")}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<span>{item.title}</span>
|
<span>{t(item.titleKey)}</span>
|
||||||
</Link>
|
</Link>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
) : (
|
) : (
|
||||||
@@ -907,7 +952,7 @@ export default function Page({ children }: Props) {
|
|||||||
</SidebarMenu>
|
</SidebarMenu>
|
||||||
</SidebarGroup>
|
</SidebarGroup>
|
||||||
<SidebarGroup>
|
<SidebarGroup>
|
||||||
<SidebarGroupLabel>Settings</SidebarGroupLabel>
|
<SidebarGroupLabel>{t("common.side.settings")}</SidebarGroupLabel>
|
||||||
<SidebarMenu className="gap-2">
|
<SidebarMenu className="gap-2">
|
||||||
{filteredSettings.map((item) => {
|
{filteredSettings.map((item) => {
|
||||||
const isSingle = item.isSingle !== false;
|
const isSingle = item.isSingle !== false;
|
||||||
@@ -940,7 +985,7 @@ export default function Page({ children }: Props) {
|
|||||||
className={cn(isActive && "text-primary")}
|
className={cn(isActive && "text-primary")}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<span>{item.title}</span>
|
<span>{t(item.titleKey)}</span>
|
||||||
</Link>
|
</Link>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
) : (
|
) : (
|
||||||
@@ -996,7 +1041,7 @@ export default function Page({ children }: Props) {
|
|||||||
</SidebarMenu>
|
</SidebarMenu>
|
||||||
</SidebarGroup>
|
</SidebarGroup>
|
||||||
<SidebarGroup className="group-data-[collapsible=icon]:hidden">
|
<SidebarGroup className="group-data-[collapsible=icon]:hidden">
|
||||||
<SidebarGroupLabel>Extra</SidebarGroupLabel>
|
<SidebarGroupLabel>{t("common.side.extra")}</SidebarGroupLabel>
|
||||||
<SidebarMenu>
|
<SidebarMenu>
|
||||||
{help.map((item: ExternalLink) => (
|
{help.map((item: ExternalLink) => (
|
||||||
<SidebarMenuItem key={item.name}>
|
<SidebarMenuItem key={item.name}>
|
||||||
@@ -1010,7 +1055,7 @@ export default function Page({ children }: Props) {
|
|||||||
<span className="mr-2">
|
<span className="mr-2">
|
||||||
<item.icon className="h-4 w-4" />
|
<item.icon className="h-4 w-4" />
|
||||||
</span>
|
</span>
|
||||||
<span>{item.name}</span>
|
<span>{t(item.nameKey)}</span>
|
||||||
</a>
|
</a>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export async function getServerSideProps(
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
trpcState: helpers.dehydrate(),
|
trpcState: helpers.dehydrate(),
|
||||||
...(await serverSideTranslations(locale, ["settings"])),
|
...(await serverSideTranslations(locale, ["common", "settings"])),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ShowBilling } from "@/components/dashboard/settings/billing/show-billin
|
|||||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
|
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
|
import { getLocale, serverSideTranslations } from "@/utils/i18n";
|
||||||
import { IS_CLOUD } from "@dokploy/server/constants";
|
import { IS_CLOUD } from "@dokploy/server/constants";
|
||||||
import { validateRequest } from "@dokploy/server/lib/auth";
|
import { validateRequest } from "@dokploy/server/lib/auth";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
@@ -30,6 +31,7 @@ export async function getServerSideProps(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
|
const locale = getLocale(req.cookies);
|
||||||
const { user, session } = await validateRequest(req);
|
const { user, session } = await validateRequest(req);
|
||||||
if (!user || user.role === "member") {
|
if (!user || user.role === "member") {
|
||||||
return {
|
return {
|
||||||
@@ -59,6 +61,7 @@ export async function getServerSideProps(
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
trpcState: helpers.dehydrate(),
|
trpcState: helpers.dehydrate(),
|
||||||
|
...(await serverSideTranslations(locale, ["common", "settings"])),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ShowCertificates } from "@/components/dashboard/settings/certificates/s
|
|||||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
|
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
|
import { getLocale, serverSideTranslations } from "@/utils/i18n";
|
||||||
import { validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
import type { GetServerSidePropsContext } from "next";
|
import type { GetServerSidePropsContext } from "next";
|
||||||
@@ -24,6 +25,7 @@ export async function getServerSideProps(
|
|||||||
ctx: GetServerSidePropsContext<{ serviceId: string }>,
|
ctx: GetServerSidePropsContext<{ serviceId: string }>,
|
||||||
) {
|
) {
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
|
const locale = await getLocale(req.cookies);
|
||||||
const { user, session } = await validateRequest(req);
|
const { user, session } = await validateRequest(req);
|
||||||
if (!user || user.role === "member") {
|
if (!user || user.role === "member") {
|
||||||
return {
|
return {
|
||||||
@@ -51,6 +53,7 @@ export async function getServerSideProps(
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
trpcState: helpers.dehydrate(),
|
trpcState: helpers.dehydrate(),
|
||||||
|
...(await serverSideTranslations(locale, ["common", "settings"])),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ShowNodes } from "@/components/dashboard/settings/cluster/nodes/show-no
|
|||||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
|
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
|
import { getLocale, serverSideTranslations } from "@/utils/i18n";
|
||||||
import { IS_CLOUD, validateRequest } from "@dokploy/server";
|
import { IS_CLOUD, validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
import type { GetServerSidePropsContext } from "next";
|
import type { GetServerSidePropsContext } from "next";
|
||||||
@@ -25,6 +26,7 @@ export async function getServerSideProps(
|
|||||||
ctx: GetServerSidePropsContext<{ serviceId: string }>,
|
ctx: GetServerSidePropsContext<{ serviceId: string }>,
|
||||||
) {
|
) {
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
|
const locale = await getLocale(req.cookies);
|
||||||
if (IS_CLOUD) {
|
if (IS_CLOUD) {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
@@ -58,6 +60,7 @@ export async function getServerSideProps(
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
trpcState: helpers.dehydrate(),
|
trpcState: helpers.dehydrate(),
|
||||||
|
...(await serverSideTranslations(locale, ["common", "settings"])),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ShowDestinations } from "@/components/dashboard/settings/destination/sh
|
|||||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
|
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
|
import { getLocale, serverSideTranslations } from "@/utils/i18n";
|
||||||
import { validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
import type { GetServerSidePropsContext } from "next";
|
import type { GetServerSidePropsContext } from "next";
|
||||||
@@ -25,6 +26,7 @@ export async function getServerSideProps(
|
|||||||
ctx: GetServerSidePropsContext<{ serviceId: string }>,
|
ctx: GetServerSidePropsContext<{ serviceId: string }>,
|
||||||
) {
|
) {
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
|
const locale = await getLocale(req.cookies);
|
||||||
const { user, session } = await validateRequest(req);
|
const { user, session } = await validateRequest(req);
|
||||||
if (!user || user.role === "member") {
|
if (!user || user.role === "member") {
|
||||||
return {
|
return {
|
||||||
@@ -52,6 +54,7 @@ export async function getServerSideProps(
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
trpcState: helpers.dehydrate(),
|
trpcState: helpers.dehydrate(),
|
||||||
|
...(await serverSideTranslations(locale, ["common", "settings"])),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ShowGitProviders } from "@/components/dashboard/settings/git/show-git-p
|
|||||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
|
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
|
import { getLocale, serverSideTranslations } from "@/utils/i18n";
|
||||||
import { validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
import type { GetServerSidePropsContext } from "next";
|
import type { GetServerSidePropsContext } from "next";
|
||||||
@@ -9,68 +10,72 @@ import type { ReactElement } from "react";
|
|||||||
import superjson from "superjson";
|
import superjson from "superjson";
|
||||||
|
|
||||||
const Page = () => {
|
const Page = () => {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-4 w-full">
|
<div className="flex flex-col gap-4 w-full">
|
||||||
<ShowGitProviders />
|
<ShowGitProviders />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Page;
|
export default Page;
|
||||||
|
|
||||||
Page.getLayout = (page: ReactElement) => {
|
Page.getLayout = (page: ReactElement) => {
|
||||||
return <DashboardLayout metaName="Git Providers">{page}</DashboardLayout>;
|
return <DashboardLayout metaName="Git Providers">{page}</DashboardLayout>;
|
||||||
};
|
};
|
||||||
export async function getServerSideProps(
|
export async function getServerSideProps(
|
||||||
ctx: GetServerSidePropsContext<{ serviceId: string }>,
|
ctx: GetServerSidePropsContext<{ serviceId: string }>
|
||||||
) {
|
) {
|
||||||
const { user, session } = await validateRequest(ctx.req);
|
const { user, session } = await validateRequest(ctx.req);
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
destination: "/",
|
destination: "/",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
const helpers = createServerSideHelpers({
|
const locale = await getLocale(req.cookies);
|
||||||
router: appRouter,
|
const helpers = createServerSideHelpers({
|
||||||
ctx: {
|
router: appRouter,
|
||||||
req: req as any,
|
ctx: {
|
||||||
res: res as any,
|
req: req as any,
|
||||||
db: null as any,
|
res: res as any,
|
||||||
session: session as any,
|
db: null as any,
|
||||||
user: user as any,
|
session: session as any,
|
||||||
},
|
user: user as any,
|
||||||
transformer: superjson,
|
},
|
||||||
});
|
transformer: superjson,
|
||||||
await helpers.user.get.prefetch();
|
});
|
||||||
try {
|
await helpers.user.get.prefetch();
|
||||||
await helpers.project.all.prefetch();
|
try {
|
||||||
await helpers.settings.isCloud.prefetch();
|
await helpers.project.all.prefetch();
|
||||||
if (user.role === "member") {
|
await helpers.settings.isCloud.prefetch();
|
||||||
const userR = await helpers.user.one.fetch({
|
if (user.role === "member") {
|
||||||
userId: user.id,
|
const userR = await helpers.user.one.fetch({
|
||||||
});
|
userId: user.id,
|
||||||
|
});
|
||||||
|
|
||||||
if (!userR?.canAccessToGitProviders) {
|
if (!userR?.canAccessToGitProviders) {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
destination: "/",
|
destination: "/",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
trpcState: helpers.dehydrate(),
|
trpcState: helpers.dehydrate(),
|
||||||
},
|
...(await serverSideTranslations(locale, ["common", "settings"])),
|
||||||
};
|
},
|
||||||
} catch (_error) {
|
};
|
||||||
return {
|
} catch (_error) {
|
||||||
props: {},
|
return {
|
||||||
};
|
props: {
|
||||||
}
|
...(await serverSideTranslations(locale, ["common", "settings"])),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
|
import { getLocale, serverSideTranslations } from "@/utils/i18n";
|
||||||
import { validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
@@ -180,6 +181,7 @@ export async function getServerSideProps(
|
|||||||
ctx: GetServerSidePropsContext<{ serviceId: string }>,
|
ctx: GetServerSidePropsContext<{ serviceId: string }>,
|
||||||
) {
|
) {
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
|
const locale = await getLocale(req.cookies);
|
||||||
const { user, session } = await validateRequest(ctx.req);
|
const { user, session } = await validateRequest(ctx.req);
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return {
|
return {
|
||||||
@@ -214,6 +216,7 @@ export async function getServerSideProps(
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
trpcState: helpers.dehydrate(),
|
trpcState: helpers.dehydrate(),
|
||||||
|
...(await serverSideTranslations(locale, ["common", "settings"])),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ShowNotifications } from "@/components/dashboard/settings/notifications
|
|||||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
|
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
|
import { getLocale, serverSideTranslations } from "@/utils/i18n";
|
||||||
import { validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
import type { GetServerSidePropsContext } from "next";
|
import type { GetServerSidePropsContext } from "next";
|
||||||
@@ -25,6 +26,7 @@ export async function getServerSideProps(
|
|||||||
ctx: GetServerSidePropsContext<{ serviceId: string }>,
|
ctx: GetServerSidePropsContext<{ serviceId: string }>,
|
||||||
) {
|
) {
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
|
const locale = await getLocale(req.cookies);
|
||||||
const { user, session } = await validateRequest(req);
|
const { user, session } = await validateRequest(req);
|
||||||
if (!user || user.role === "member") {
|
if (!user || user.role === "member") {
|
||||||
return {
|
return {
|
||||||
@@ -52,6 +54,7 @@ export async function getServerSideProps(
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
trpcState: helpers.dehydrate(),
|
trpcState: helpers.dehydrate(),
|
||||||
|
...(await serverSideTranslations(locale, ["common", "settings"])),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export async function getServerSideProps(
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
trpcState: helpers.dehydrate(),
|
trpcState: helpers.dehydrate(),
|
||||||
...(await serverSideTranslations(locale, ["settings"])),
|
...(await serverSideTranslations(locale, ["common", "settings"])),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ShowRegistry } from "@/components/dashboard/settings/cluster/registry/s
|
|||||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
|
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
|
import { serverSideTranslations, getLocale } from "@/utils/i18n";
|
||||||
import { validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
import type { GetServerSidePropsContext } from "next";
|
import type { GetServerSidePropsContext } from "next";
|
||||||
@@ -25,6 +26,7 @@ export async function getServerSideProps(
|
|||||||
ctx: GetServerSidePropsContext<{ serviceId: string }>,
|
ctx: GetServerSidePropsContext<{ serviceId: string }>,
|
||||||
) {
|
) {
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
|
const locale = await getLocale(req.cookies);
|
||||||
const { user, session } = await validateRequest(req);
|
const { user, session } = await validateRequest(req);
|
||||||
if (!user || user.role === "member") {
|
if (!user || user.role === "member") {
|
||||||
return {
|
return {
|
||||||
@@ -51,6 +53,7 @@ export async function getServerSideProps(
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
trpcState: helpers.dehydrate(),
|
trpcState: helpers.dehydrate(),
|
||||||
|
...(await serverSideTranslations(locale, ["common", "settings"])),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ export async function getServerSideProps(
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
trpcState: helpers.dehydrate(),
|
trpcState: helpers.dehydrate(),
|
||||||
...(await serverSideTranslations(locale, ["settings"])),
|
...(await serverSideTranslations(locale, ["common", "settings"])),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export async function getServerSideProps(
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
trpcState: helpers.dehydrate(),
|
trpcState: helpers.dehydrate(),
|
||||||
...(await serverSideTranslations(locale, ["settings"])),
|
...(await serverSideTranslations(locale, ["common", "settings"])),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ShowDestinations } from "@/components/dashboard/settings/ssh-keys/show-
|
|||||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
|
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
|
import { getLocale, serverSideTranslations } from "@/utils/i18n";
|
||||||
import { validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
import type { GetServerSidePropsContext } from "next";
|
import type { GetServerSidePropsContext } from "next";
|
||||||
@@ -34,6 +35,7 @@ export async function getServerSideProps(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
|
const locale = await getLocale(req.cookies);
|
||||||
const helpers = createServerSideHelpers({
|
const helpers = createServerSideHelpers({
|
||||||
router: appRouter,
|
router: appRouter,
|
||||||
ctx: {
|
ctx: {
|
||||||
@@ -67,11 +69,14 @@ export async function getServerSideProps(
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
trpcState: helpers.dehydrate(),
|
trpcState: helpers.dehydrate(),
|
||||||
|
...(await serverSideTranslations(locale, ["common", "settings"])),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
} catch (_error) {
|
} catch (_error) {
|
||||||
return {
|
return {
|
||||||
props: {},
|
props: {
|
||||||
|
...(await serverSideTranslations(locale, ["common", "settings"])),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { ShowUsers } from "@/components/dashboard/settings/users/show-users";
|
|||||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
|
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
|
import { getLocale, serverSideTranslations } from "@/utils/i18n";
|
||||||
import { validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
import type { GetServerSidePropsContext } from "next";
|
import type { GetServerSidePropsContext } from "next";
|
||||||
@@ -27,6 +28,7 @@ export async function getServerSideProps(
|
|||||||
ctx: GetServerSidePropsContext<{ serviceId: string }>,
|
ctx: GetServerSidePropsContext<{ serviceId: string }>,
|
||||||
) {
|
) {
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
|
const locale = await getLocale(req.cookies);
|
||||||
const { user, session } = await validateRequest(req);
|
const { user, session } = await validateRequest(req);
|
||||||
|
|
||||||
if (!user || user.role === "member") {
|
if (!user || user.role === "member") {
|
||||||
@@ -55,6 +57,7 @@ export async function getServerSideProps(
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
trpcState: helpers.dehydrate(),
|
trpcState: helpers.dehydrate(),
|
||||||
|
...(await serverSideTranslations(locale, ["common", "settings"])),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,37 @@
|
|||||||
{}
|
{
|
||||||
|
"common.side.home": "Home",
|
||||||
|
"common.side.settings": "Settings",
|
||||||
|
"common.side.extra": "Extra",
|
||||||
|
|
||||||
|
"common.side.projects": "Projects",
|
||||||
|
"common.side.monitoring": "Monitoring",
|
||||||
|
"common.side.traefik": "Traefik File System",
|
||||||
|
"common.side.docker": "Docker",
|
||||||
|
"common.side.swarm": "Swarm",
|
||||||
|
"common.side.requests": "Requests",
|
||||||
|
"common.side.web-server": "Web Server",
|
||||||
|
"common.side.profile": "Profile",
|
||||||
|
"common.side.remote-servers": "Remote Servers",
|
||||||
|
"common.side.users": "Users",
|
||||||
|
"common.side.ssh-keys": "SSH Keys",
|
||||||
|
"common.side.ai": "AI",
|
||||||
|
"common.side.git": "Git",
|
||||||
|
"common.side.registry": "Registry",
|
||||||
|
"common.side.s3-destinations": "S3 Destinations",
|
||||||
|
"common.side.certificates": "Certificates",
|
||||||
|
"common.side.cluster": "Cluster",
|
||||||
|
"common.side.notifications": "Notifications",
|
||||||
|
"common.side.billing": "Billing",
|
||||||
|
"common.side.documentation": "Documentation",
|
||||||
|
"common.side.support": "Support",
|
||||||
|
"common.side.sponsor": "Sponsor",
|
||||||
|
|
||||||
|
"common.side.invitations.pending-invitations": "Pending Invitations",
|
||||||
|
"common.side.invitations.no-pending-invitations": "No pending invitations",
|
||||||
|
"common.side.invitations.accept-invitation": "Accept Invitation",
|
||||||
|
"common.side.invitations.confirm-accept-invitation": "Are you sure you want to accept this invitation?",
|
||||||
|
"common.side.invitations.error-accepting-invitation": "Error accepting invitation",
|
||||||
|
"common.side.invitations.invitation-accepted": "Invitation accepted successfully",
|
||||||
|
"common.side.invitations.expires": "Expires: {{expireDate}}",
|
||||||
|
"common.side.invitations.role": "Role: {{role}}"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1 +1,37 @@
|
|||||||
{}
|
{
|
||||||
|
"common.side.home": "主页",
|
||||||
|
"common.side.settings": "设置",
|
||||||
|
"common.side.extra": "其他",
|
||||||
|
|
||||||
|
"common.side.projects": "项目",
|
||||||
|
"common.side.monitoring": "监控",
|
||||||
|
"common.side.traefik": "Traefik",
|
||||||
|
"common.side.docker": "Docker",
|
||||||
|
"common.side.swarm": "Swarm",
|
||||||
|
"common.side.requests": "请求",
|
||||||
|
"common.side.web-server": "本地配置",
|
||||||
|
"common.side.profile": "个人资料",
|
||||||
|
"common.side.remote-servers": "远程服务器",
|
||||||
|
"common.side.users": "用户",
|
||||||
|
"common.side.ssh-keys": "SSH 密钥",
|
||||||
|
"common.side.ai": "AI",
|
||||||
|
"common.side.git": "Git 集成",
|
||||||
|
"common.side.registry": "注册表",
|
||||||
|
"common.side.s3-destinations": "S3 存储",
|
||||||
|
"common.side.certificates": "证书",
|
||||||
|
"common.side.cluster": "集群",
|
||||||
|
"common.side.notifications": "通知",
|
||||||
|
"common.side.billing": "账单",
|
||||||
|
"common.side.documentation": "文档",
|
||||||
|
"common.side.support": "支持",
|
||||||
|
"common.side.sponsor": "赞助",
|
||||||
|
|
||||||
|
"common.side.invitations.pending-invitations": "待处理邀请",
|
||||||
|
"common.side.invitations.no-pending-invitations": "没有待处理的邀请",
|
||||||
|
"common.side.invitations.accept-invitation": "接受邀请",
|
||||||
|
"common.side.invitations.confirm-accept-invitation": "您确定要接受此邀请吗?",
|
||||||
|
"common.side.invitations.error-accepting-invitation": "接受邀请时出错",
|
||||||
|
"common.side.invitations.invitation-accepted": "邀请已成功接受",
|
||||||
|
"common.side.invitations.expires": "有效期:{{expireDate}}",
|
||||||
|
"common.side.invitations.role": "角色:{{role}}"
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user