mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
Merge pull request #829 from Dokploy/refactor/enhancement-languages
refactor: improve I18N
This commit is contained in:
@@ -99,14 +99,14 @@ workflows:
|
|||||||
only:
|
only:
|
||||||
- main
|
- main
|
||||||
- canary
|
- canary
|
||||||
- fix/build-i18n
|
- refactor/enhancement-languages
|
||||||
- build-arm64:
|
- build-arm64:
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- main
|
- main
|
||||||
- canary
|
- canary
|
||||||
- fix/build-i18n
|
- refactor/enhancement-languages
|
||||||
- combine-manifests:
|
- combine-manifests:
|
||||||
requires:
|
requires:
|
||||||
- build-amd64
|
- build-amd64
|
||||||
@@ -116,4 +116,4 @@ workflows:
|
|||||||
only:
|
only:
|
||||||
- main
|
- main
|
||||||
- canary
|
- canary
|
||||||
- fix/build-i18n
|
- refactor/enhancement-languages
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ RUN apt-get update && apt-get install -y curl unzip apache2-utils && rm -rf /var
|
|||||||
COPY --from=build /prod/dokploy/.next ./.next
|
COPY --from=build /prod/dokploy/.next ./.next
|
||||||
COPY --from=build /prod/dokploy/dist ./dist
|
COPY --from=build /prod/dokploy/dist ./dist
|
||||||
COPY --from=build /prod/dokploy/next.config.mjs ./next.config.mjs
|
COPY --from=build /prod/dokploy/next.config.mjs ./next.config.mjs
|
||||||
COPY --from=build /prod/dokploy/next-i18next.config.cjs ./next-i18next.config.cjs
|
# COPY --from=build /prod/dokploy/next-i18next.config.cjs ./next-i18next.config.cjs
|
||||||
COPY --from=build /prod/dokploy/public ./public
|
COPY --from=build /prod/dokploy/public ./public
|
||||||
COPY --from=build /prod/dokploy/package.json ./package.json
|
COPY --from=build /prod/dokploy/package.json ./package.json
|
||||||
COPY --from=build /prod/dokploy/drizzle ./drizzle
|
COPY --from=build /prod/dokploy/drizzle ./drizzle
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ if (typeof window === "undefined") {
|
|||||||
|
|
||||||
const baseApp: ApplicationNested = {
|
const baseApp: ApplicationNested = {
|
||||||
applicationId: "",
|
applicationId: "",
|
||||||
|
herokuVersion: "",
|
||||||
applicationStatus: "done",
|
applicationStatus: "done",
|
||||||
appName: "",
|
appName: "",
|
||||||
autoDeploy: true,
|
autoDeploy: true,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { expect, test } from "vitest";
|
|||||||
|
|
||||||
const baseApp: ApplicationNested = {
|
const baseApp: ApplicationNested = {
|
||||||
applicationId: "",
|
applicationId: "",
|
||||||
|
herokuVersion: "",
|
||||||
applicationStatus: "done",
|
applicationStatus: "done",
|
||||||
appName: "",
|
appName: "",
|
||||||
autoDeploy: true,
|
autoDeploy: true,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const Terminal = dynamic(
|
|||||||
() => import("./docker-terminal").then((e) => e.DockerTerminal),
|
() => import("./docker-terminal").then((e) => e.DockerTerminal),
|
||||||
{
|
{
|
||||||
ssr: false,
|
ssr: false,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -75,7 +75,9 @@ export const DockerTerminalModal = ({
|
|||||||
<Dialog open={confirmDialogOpen} onOpenChange={setConfirmDialogOpen}>
|
<Dialog open={confirmDialogOpen} onOpenChange={setConfirmDialogOpen}>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Are you sure you want to close the terminal?</DialogTitle>
|
<DialogTitle>
|
||||||
|
Are you sure you want to close the terminal?
|
||||||
|
</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
By clicking the confirm button, the terminal will be closed.
|
By clicking the confirm button, the terminal will be closed.
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
|
import { Languages } from "@/lib/languages";
|
||||||
import useLocale from "@/utils/hooks/use-locale";
|
import useLocale from "@/utils/hooks/use-locale";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
@@ -37,25 +38,9 @@ const appearanceFormSchema = z.object({
|
|||||||
theme: z.enum(["light", "dark", "system"], {
|
theme: z.enum(["light", "dark", "system"], {
|
||||||
required_error: "Please select a theme.",
|
required_error: "Please select a theme.",
|
||||||
}),
|
}),
|
||||||
language: z.enum(
|
language: z.nativeEnum(Languages, {
|
||||||
[
|
|
||||||
"en",
|
|
||||||
"pl",
|
|
||||||
"ru",
|
|
||||||
"fr",
|
|
||||||
"de",
|
|
||||||
"tr",
|
|
||||||
"zh-Hant",
|
|
||||||
"kz",
|
|
||||||
"zh-Hans",
|
|
||||||
"fa",
|
|
||||||
"ko",
|
|
||||||
"pt-br",
|
|
||||||
],
|
|
||||||
{
|
|
||||||
required_error: "Please select a language.",
|
required_error: "Please select a language.",
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
type AppearanceFormValues = z.infer<typeof appearanceFormSchema>;
|
type AppearanceFormValues = z.infer<typeof appearanceFormSchema>;
|
||||||
@@ -63,7 +48,7 @@ type AppearanceFormValues = z.infer<typeof appearanceFormSchema>;
|
|||||||
// This can come from your database or API.
|
// This can come from your database or API.
|
||||||
const defaultValues: Partial<AppearanceFormValues> = {
|
const defaultValues: Partial<AppearanceFormValues> = {
|
||||||
theme: "system",
|
theme: "system",
|
||||||
language: "en",
|
language: Languages.English,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function AppearanceForm() {
|
export function AppearanceForm() {
|
||||||
@@ -188,25 +173,15 @@ export function AppearanceForm() {
|
|||||||
<SelectValue placeholder="No preset selected" />
|
<SelectValue placeholder="No preset selected" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{[
|
{Object.keys(Languages).map((preset) => {
|
||||||
{ label: "English", value: "en" },
|
const value =
|
||||||
{ label: "Polski", value: "pl" },
|
Languages[preset as keyof typeof Languages];
|
||||||
{ label: "Русский", value: "ru" },
|
return (
|
||||||
{ label: "Français", value: "fr" },
|
<SelectItem key={value} value={value}>
|
||||||
{ label: "Deutsch", value: "de" },
|
{preset}
|
||||||
{ label: "繁體中文", value: "zh-Hant" },
|
|
||||||
{ label: "简体中文", value: "zh-Hans" },
|
|
||||||
{ label: "Türkçe", value: "tr" },
|
|
||||||
{ label: "Қазақ", value: "tr" },
|
|
||||||
{ label: "Kazakh", value: "kz" },
|
|
||||||
{ label: "Persian", value: "fa" },
|
|
||||||
{ label: "한국어", value: "ko" },
|
|
||||||
{ label: "Português", value: "pt-br" },
|
|
||||||
].map((preset) => (
|
|
||||||
<SelectItem key={preset.label} value={preset.value}>
|
|
||||||
{preset.label}
|
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ import { useEffect, useState } from "react";
|
|||||||
const Terminal = dynamic(
|
const Terminal = dynamic(
|
||||||
() =>
|
() =>
|
||||||
import("@/components/dashboard/docker/terminal/docker-terminal").then(
|
import("@/components/dashboard/docker/terminal/docker-terminal").then(
|
||||||
(e) => e.DockerTerminal
|
(e) => e.DockerTerminal,
|
||||||
),
|
),
|
||||||
{
|
{
|
||||||
ssr: false,
|
ssr: false,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -48,7 +48,7 @@ export const DockerTerminalModal = ({ children, appName, serverId }: Props) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !!appName,
|
enabled: !!appName,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
const [containerId, setContainerId] = useState<string | undefined>();
|
const [containerId, setContainerId] = useState<string | undefined>();
|
||||||
const [mainDialogOpen, setMainDialogOpen] = useState(false);
|
const [mainDialogOpen, setMainDialogOpen] = useState(false);
|
||||||
|
|||||||
16
apps/dokploy/lib/languages.ts
Normal file
16
apps/dokploy/lib/languages.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
export enum Languages {
|
||||||
|
English = "en",
|
||||||
|
Polish = "pl",
|
||||||
|
Russian = "ru",
|
||||||
|
French = "fr",
|
||||||
|
German = "de",
|
||||||
|
ChineseTraditional = "zh-Hant",
|
||||||
|
ChineseSimplified = "zh-Hans",
|
||||||
|
Turkish = "tr",
|
||||||
|
Kazakh = "kz",
|
||||||
|
Persian = "fa",
|
||||||
|
Korean = "ko",
|
||||||
|
Portuguese = "pt-br",
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Language = keyof typeof Languages;
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import "@/styles/globals.css";
|
import "@/styles/globals.css";
|
||||||
|
|
||||||
import { Toaster } from "@/components/ui/sonner";
|
import { Toaster } from "@/components/ui/sonner";
|
||||||
|
import { Languages } from "@/lib/languages";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import type { NextPage } from "next";
|
import type { NextPage } from "next";
|
||||||
import { appWithTranslation } from "next-i18next";
|
import { appWithTranslation } from "next-i18next";
|
||||||
@@ -71,20 +72,7 @@ export default api.withTRPC(
|
|||||||
{
|
{
|
||||||
i18n: {
|
i18n: {
|
||||||
defaultLocale: "en",
|
defaultLocale: "en",
|
||||||
locales: [
|
locales: Object.values(Languages),
|
||||||
"en",
|
|
||||||
"pl",
|
|
||||||
"ru",
|
|
||||||
"fr",
|
|
||||||
"de",
|
|
||||||
"tr",
|
|
||||||
"kz",
|
|
||||||
"zh-Hant",
|
|
||||||
"zh-Hans",
|
|
||||||
"fa",
|
|
||||||
"ko",
|
|
||||||
"pt-br",
|
|
||||||
],
|
|
||||||
localeDetection: false,
|
localeDetection: false,
|
||||||
},
|
},
|
||||||
fallbackLng: "en",
|
fallbackLng: "en",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { extractCommitMessage, extractHash } from "./[refreshToken]";
|
|||||||
|
|
||||||
export default async function handler(
|
export default async function handler(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
res: NextApiResponse
|
res: NextApiResponse,
|
||||||
) {
|
) {
|
||||||
const signature = req.headers["x-hub-signature-256"];
|
const signature = req.headers["x-hub-signature-256"];
|
||||||
const githubBody = req.body;
|
const githubBody = req.body;
|
||||||
@@ -40,7 +40,7 @@ export default async function handler(
|
|||||||
|
|
||||||
const verified = await webhooks.verify(
|
const verified = await webhooks.verify(
|
||||||
JSON.stringify(githubBody),
|
JSON.stringify(githubBody),
|
||||||
signature as string
|
signature as string,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!verified) {
|
if (!verified) {
|
||||||
@@ -65,14 +65,13 @@ export default async function handler(
|
|||||||
const deploymentHash = extractHash(req.headers, req.body);
|
const deploymentHash = extractHash(req.headers, req.body);
|
||||||
const owner = githubBody?.repository?.owner?.name;
|
const owner = githubBody?.repository?.owner?.name;
|
||||||
|
|
||||||
|
|
||||||
const apps = await db.query.applications.findMany({
|
const apps = await db.query.applications.findMany({
|
||||||
where: and(
|
where: and(
|
||||||
eq(applications.sourceType, "github"),
|
eq(applications.sourceType, "github"),
|
||||||
eq(applications.autoDeploy, true),
|
eq(applications.autoDeploy, true),
|
||||||
eq(applications.branch, branchName),
|
eq(applications.branch, branchName),
|
||||||
eq(applications.repository, repository),
|
eq(applications.repository, repository),
|
||||||
eq(applications.owner, owner)
|
eq(applications.owner, owner),
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -97,7 +96,7 @@ export default async function handler(
|
|||||||
{
|
{
|
||||||
removeOnComplete: true,
|
removeOnComplete: true,
|
||||||
removeOnFail: true,
|
removeOnFail: true,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +106,7 @@ export default async function handler(
|
|||||||
eq(compose.autoDeploy, true),
|
eq(compose.autoDeploy, true),
|
||||||
eq(compose.branch, branchName),
|
eq(compose.branch, branchName),
|
||||||
eq(compose.repository, repository),
|
eq(compose.repository, repository),
|
||||||
eq(compose.owner, owner)
|
eq(compose.owner, owner),
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -133,7 +132,7 @@ export default async function handler(
|
|||||||
{
|
{
|
||||||
removeOnComplete: true,
|
removeOnComplete: true,
|
||||||
removeOnFail: true,
|
removeOnFail: true,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
"settings.profile.password": "Senha",
|
"settings.profile.password": "Senha",
|
||||||
"settings.profile.avatar": "Avatar",
|
"settings.profile.avatar": "Avatar",
|
||||||
|
|
||||||
"settings.appearance.title": "Aparência",
|
"settings.appearance.title": "Aparencia",
|
||||||
"settings.appearance.description": "Personalize o tema do seu dashboard.",
|
"settings.appearance.description": "Personalize o tema do seu dashboard.",
|
||||||
"settings.appearance.theme": "Tema",
|
"settings.appearance.theme": "Tema",
|
||||||
"settings.appearance.themeDescription": "Selecione um tema para o dashboard",
|
"settings.appearance.themeDescription": "Selecione um tema para o dashboard",
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ export const notificationRouter = createTRPCRouter({
|
|||||||
await sendDiscordNotification(input, {
|
await sendDiscordNotification(input, {
|
||||||
title: "> `🤚` - Test Notification",
|
title: "> `🤚` - Test Notification",
|
||||||
description: "> Hi, From Dokploy 👋",
|
description: "> Hi, From Dokploy 👋",
|
||||||
color: 0xf3f7f4
|
color: 0xf3f7f4,
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -29,61 +29,61 @@ export function generate(schema: Schema): Template {
|
|||||||
];
|
];
|
||||||
|
|
||||||
const envs = [
|
const envs = [
|
||||||
`NODE_ENV=production`,
|
"NODE_ENV=production",
|
||||||
`RUNTIME_PLATFORM=docker-compose`,
|
"RUNTIME_PLATFORM=docker-compose",
|
||||||
`V3_ENABLED=true`,
|
"V3_ENABLED=true",
|
||||||
|
|
||||||
`# Domain configuration`,
|
"# Domain configuration",
|
||||||
`TRIGGER_DOMAIN=${triggerDomain}`,
|
`TRIGGER_DOMAIN=${triggerDomain}`,
|
||||||
`TRIGGER_PROTOCOL=http`,
|
"TRIGGER_PROTOCOL=http",
|
||||||
|
|
||||||
`# Database configuration with secure credentials`,
|
"# Database configuration with secure credentials",
|
||||||
`POSTGRES_USER=${dbUser}`,
|
`POSTGRES_USER=${dbUser}`,
|
||||||
`POSTGRES_PASSWORD=${dbPassword}`,
|
`POSTGRES_PASSWORD=${dbPassword}`,
|
||||||
`POSTGRES_DB=${dbName}`,
|
`POSTGRES_DB=${dbName}`,
|
||||||
`DATABASE_URL=postgresql://${dbUser}:${dbPassword}@postgres:5432/${dbName}`,
|
`DATABASE_URL=postgresql://${dbUser}:${dbPassword}@postgres:5432/${dbName}`,
|
||||||
|
|
||||||
`# Secrets`,
|
"# Secrets",
|
||||||
`MAGIC_LINK_SECRET=${magicLinkSecret}`,
|
`MAGIC_LINK_SECRET=${magicLinkSecret}`,
|
||||||
`SESSION_SECRET=${sessionSecret}`,
|
`SESSION_SECRET=${sessionSecret}`,
|
||||||
`ENCRYPTION_KEY=${encryptionKey}`,
|
`ENCRYPTION_KEY=${encryptionKey}`,
|
||||||
`PROVIDER_SECRET=${providerSecret}`,
|
`PROVIDER_SECRET=${providerSecret}`,
|
||||||
`COORDINATOR_SECRET=${coordinatorSecret}`,
|
`COORDINATOR_SECRET=${coordinatorSecret}`,
|
||||||
|
|
||||||
`# TRIGGER_TELEMETRY_DISABLED=1`,
|
"# TRIGGER_TELEMETRY_DISABLED=1",
|
||||||
`INTERNAL_OTEL_TRACE_DISABLED=1`,
|
"INTERNAL_OTEL_TRACE_DISABLED=1",
|
||||||
`INTERNAL_OTEL_TRACE_LOGGING_ENABLED=0`,
|
"INTERNAL_OTEL_TRACE_LOGGING_ENABLED=0",
|
||||||
|
|
||||||
`DEFAULT_ORG_EXECUTION_CONCURRENCY_LIMIT=300`,
|
"DEFAULT_ORG_EXECUTION_CONCURRENCY_LIMIT=300",
|
||||||
`DEFAULT_ENV_EXECUTION_CONCURRENCY_LIMIT=100`,
|
"DEFAULT_ENV_EXECUTION_CONCURRENCY_LIMIT=100",
|
||||||
|
|
||||||
`DIRECT_URL=\${DATABASE_URL}`,
|
"DIRECT_URL=${DATABASE_URL}",
|
||||||
`REDIS_HOST=redis`,
|
"REDIS_HOST=redis",
|
||||||
`REDIS_PORT=6379`,
|
"REDIS_PORT=6379",
|
||||||
`REDIS_TLS_DISABLED=true`,
|
"REDIS_TLS_DISABLED=true",
|
||||||
|
|
||||||
`# If this is set, emails that are not specified won't be able to log in`,
|
"# If this is set, emails that are not specified won't be able to log in",
|
||||||
`# WHITELISTED_EMAILS="authorized@yahoo.com|authorized@gmail.com"`,
|
'# WHITELISTED_EMAILS="authorized@yahoo.com|authorized@gmail.com"',
|
||||||
`# Accounts with these emails will become admins when signing up and get access to the admin panel`,
|
"# Accounts with these emails will become admins when signing up and get access to the admin panel",
|
||||||
`# ADMIN_EMAILS="admin@example.com|another-admin@example.com"`,
|
'# ADMIN_EMAILS="admin@example.com|another-admin@example.com"',
|
||||||
|
|
||||||
`# If this is set, your users will be able to log in via GitHub`,
|
"# If this is set, your users will be able to log in via GitHub",
|
||||||
`# AUTH_GITHUB_CLIENT_ID=`,
|
"# AUTH_GITHUB_CLIENT_ID=",
|
||||||
`# AUTH_GITHUB_CLIENT_SECRET=`,
|
"# AUTH_GITHUB_CLIENT_SECRET=",
|
||||||
|
|
||||||
`# E-mail settings`,
|
"# E-mail settings",
|
||||||
`# Ensure the FROM_EMAIL matches what you setup with Resend.com`,
|
"# Ensure the FROM_EMAIL matches what you setup with Resend.com",
|
||||||
`# If these are not set, emails will be printed to the console`,
|
"# If these are not set, emails will be printed to the console",
|
||||||
`# FROM_EMAIL=`,
|
"# FROM_EMAIL=",
|
||||||
`# REPLY_TO_EMAIL=`,
|
"# REPLY_TO_EMAIL=",
|
||||||
`# RESEND_API_KEY=`,
|
"# RESEND_API_KEY=",
|
||||||
|
|
||||||
`# Worker settings`,
|
"# Worker settings",
|
||||||
`HTTP_SERVER_PORT=9020`,
|
"HTTP_SERVER_PORT=9020",
|
||||||
`COORDINATOR_HOST=127.0.0.1`,
|
"COORDINATOR_HOST=127.0.0.1",
|
||||||
`COORDINATOR_PORT=\${HTTP_SERVER_PORT}`,
|
"COORDINATOR_PORT=${HTTP_SERVER_PORT}",
|
||||||
`# REGISTRY_HOST=\${DEPLOY_REGISTRY_HOST}`,
|
"# REGISTRY_HOST=${DEPLOY_REGISTRY_HOST}",
|
||||||
`# REGISTRY_NAMESPACE=\${DEPLOY_REGISTRY_NAMESPACE}`,
|
"# REGISTRY_NAMESPACE=${DEPLOY_REGISTRY_NAMESPACE}",
|
||||||
];
|
];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,26 +1,10 @@
|
|||||||
|
import type { Languages } from "@/lib/languages";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
|
|
||||||
const SUPPORTED_LOCALES = [
|
|
||||||
"en",
|
|
||||||
"pl",
|
|
||||||
"ru",
|
|
||||||
"fr",
|
|
||||||
"de",
|
|
||||||
"tr",
|
|
||||||
"kz",
|
|
||||||
"zh-Hant",
|
|
||||||
"zh-Hans",
|
|
||||||
"fa",
|
|
||||||
"ko",
|
|
||||||
"pt-br",
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
type Locale = (typeof SUPPORTED_LOCALES)[number];
|
|
||||||
|
|
||||||
export default function useLocale() {
|
export default function useLocale() {
|
||||||
const currentLocale = (Cookies.get("DOKPLOY_LOCALE") ?? "en") as Locale;
|
const currentLocale = (Cookies.get("DOKPLOY_LOCALE") ?? "en") as Languages;
|
||||||
|
|
||||||
const setLocale = (locale: Locale) => {
|
const setLocale = (locale: Languages) => {
|
||||||
Cookies.set("DOKPLOY_LOCALE", locale, { expires: 365 });
|
Cookies.set("DOKPLOY_LOCALE", locale, { expires: 365 });
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,11 +5,19 @@ export function getLocale(cookies: NextApiRequestCookies) {
|
|||||||
return locale;
|
return locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
// libs/i18n.js
|
import { Languages } from "@/lib/languages";
|
||||||
import { serverSideTranslations as originalServerSideTranslations } from "next-i18next/serverSideTranslations";
|
import { serverSideTranslations as originalServerSideTranslations } from "next-i18next/serverSideTranslations";
|
||||||
import nextI18NextConfig from "../next-i18next.config.cjs";
|
|
||||||
|
|
||||||
export const serverSideTranslations = (
|
export const serverSideTranslations = (
|
||||||
locale: string,
|
locale: string,
|
||||||
namespaces = ["common"],
|
namespaces = ["common"],
|
||||||
) => originalServerSideTranslations(locale, namespaces, nextI18NextConfig);
|
) =>
|
||||||
|
originalServerSideTranslations(locale, namespaces, {
|
||||||
|
fallbackLng: "en",
|
||||||
|
keySeparator: false,
|
||||||
|
i18n: {
|
||||||
|
defaultLocale: "en",
|
||||||
|
locales: Object.values(Languages),
|
||||||
|
localeDetection: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|||||||
@@ -95,7 +95,9 @@ export const sendDatabaseBackupNotifications = async ({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "`❓`・Type",
|
name: "`❓`・Type",
|
||||||
value: type.replace("error", "Failed").replace("success", "Successful"),
|
value: type
|
||||||
|
.replace("error", "Failed")
|
||||||
|
.replace("success", "Successful"),
|
||||||
inline: true,
|
inline: true,
|
||||||
},
|
},
|
||||||
...(type === "error" && errorMessage
|
...(type === "error" && errorMessage
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ export const sendDockerCleanupNotifications = async (
|
|||||||
title: "> `✅` - Docker Cleanup",
|
title: "> `✅` - Docker Cleanup",
|
||||||
color: 0x57f287,
|
color: 0x57f287,
|
||||||
fields: [
|
fields: [
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "`📅`・Date",
|
name: "`📅`・Date",
|
||||||
value: date.toLocaleDateString(),
|
value: date.toLocaleDateString(),
|
||||||
|
|||||||
Reference in New Issue
Block a user