Merge pull request #713 from Dokploy/fix/build-i18n

refactor(dokploy): add missing next-18next to dockerfile
This commit is contained in:
Mauricio Siu
2024-11-17 11:50:12 -06:00
committed by GitHub
20 changed files with 289 additions and 267 deletions

View File

@@ -99,14 +99,14 @@ workflows:
only: only:
- main - main
- canary - canary
- pull/665 - fix/build-i18n
- build-arm64: - build-arm64:
filters: filters:
branches: branches:
only: only:
- main - main
- canary - canary
- pull/665 - fix/build-i18n
- combine-manifests: - combine-manifests:
requires: requires:
- build-amd64 - build-amd64
@@ -116,4 +116,4 @@ workflows:
only: only:
- main - main
- canary - canary
- pull/665 - fix/build-i18n

View File

@@ -35,6 +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/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

View File

@@ -44,6 +44,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/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

View File

@@ -11,7 +11,7 @@
"build-next": "next build", "build-next": "next build",
"setup": "tsx -r dotenv/config setup.ts && sleep 5 && pnpm run migration:run", "setup": "tsx -r dotenv/config setup.ts && sleep 5 && pnpm run migration:run",
"reset-password": "node -r dotenv/config dist/reset-password.mjs", "reset-password": "node -r dotenv/config dist/reset-password.mjs",
"dev": "tsx -r dotenv/config ./server/server.ts --project tsconfig.server.json ", "dev": "TURBOPACK=1 tsx -r dotenv/config ./server/server.ts --project tsconfig.server.json ",
"studio": "drizzle-kit studio --config ./server/db/drizzle.config.ts", "studio": "drizzle-kit studio --config ./server/db/drizzle.config.ts",
"migration:generate": "drizzle-kit generate --config ./server/db/drizzle.config.ts", "migration:generate": "drizzle-kit generate --config ./server/db/drizzle.config.ts",
"migration:run": "tsx -r dotenv/config migration.ts", "migration:run": "tsx -r dotenv/config migration.ts",

View File

@@ -2,13 +2,13 @@ import { AppearanceForm } from "@/components/dashboard/settings/appearance-form"
import { DashboardLayout } from "@/components/layouts/dashboard-layout"; import { DashboardLayout } from "@/components/layouts/dashboard-layout";
import { SettingsLayout } from "@/components/layouts/settings-layout"; import { SettingsLayout } from "@/components/layouts/settings-layout";
import { appRouter } from "@/server/api/root"; import { appRouter } from "@/server/api/root";
import { getLocale } from "@/utils/i18n"; 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";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import React, { type ReactElement } from "react"; import React, { type ReactElement } from "react";
import superjson from "superjson"; import superjson from "superjson";
import nextI18NextConfig from "../../../next-i18next.config.cjs";
const Page = () => { const Page = () => {
return ( return (

View File

@@ -4,11 +4,10 @@ import { DashboardLayout } from "@/components/layouts/dashboard-layout";
import { SettingsLayout } from "@/components/layouts/settings-layout"; import { SettingsLayout } from "@/components/layouts/settings-layout";
import { appRouter } from "@/server/api/root"; import { appRouter } from "@/server/api/root";
import { api } from "@/utils/api"; import { api } from "@/utils/api";
import { getLocale } from "@/utils/i18n"; 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";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import React, { type ReactElement } from "react"; import React, { type ReactElement } from "react";
import superjson from "superjson"; import superjson from "superjson";

View File

@@ -3,11 +3,10 @@ import { WebServer } from "@/components/dashboard/settings/web-server";
import { DashboardLayout } from "@/components/layouts/dashboard-layout"; import { DashboardLayout } from "@/components/layouts/dashboard-layout";
import { SettingsLayout } from "@/components/layouts/settings-layout"; import { SettingsLayout } from "@/components/layouts/settings-layout";
import { appRouter } from "@/server/api/root"; import { appRouter } from "@/server/api/root";
import { getLocale } from "@/utils/i18n"; 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";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import React, { type ReactElement } from "react"; import React, { type ReactElement } from "react";
import superjson from "superjson"; import superjson from "superjson";

View File

@@ -24,7 +24,7 @@ import { setupTerminalWebSocketServer } from "./wss/terminal";
config({ path: ".env" }); config({ path: ".env" });
const PORT = Number.parseInt(process.env.PORT || "3000", 10); const PORT = Number.parseInt(process.env.PORT || "3000", 10);
const dev = process.env.NODE_ENV !== "production"; const dev = process.env.NODE_ENV !== "production";
const app = next({ dev }); const app = next({ dev, turbopack: dev });
const handle = app.getRequestHandler(); const handle = app.getRequestHandler();
void app.prepare().then(async () => { void app.prepare().then(async () => {
try { try {

View File

@@ -1,40 +1,44 @@
import { import {
type DomainSchema, type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generateRandomDomain, generateRandomDomain,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainDomain = generateRandomDomain(schema); const mainDomain = generateRandomDomain(schema);
const apiKey = Array.from({length: 32}, () => const apiKey = Array.from({ length: 32 }, () =>
Math.floor(Math.random() * 16).toString(16)).join(''); Math.floor(Math.random() * 16).toString(16),
const encryptionKey = Array.from({length: 32}, () => ).join("");
Math.floor(Math.random() * 16).toString(16)).join(''); const encryptionKey = Array.from({ length: 32 }, () =>
const jwtSecret = Array.from({length: 32}, () => Math.floor(Math.random() * 16).toString(16),
Math.floor(Math.random() * 16).toString(16)).join(''); ).join("");
const postgresPassword = Array.from({length: 32}, () => const jwtSecret = Array.from({ length: 32 }, () =>
Math.floor(Math.random() * 16).toString(16)).join(''); Math.floor(Math.random() * 16).toString(16),
).join("");
const postgresPassword = Array.from({ length: 32 }, () =>
Math.floor(Math.random() * 16).toString(16),
).join("");
const domains: DomainSchema[] = [ const domains: DomainSchema[] = [
{ {
host: mainDomain, host: mainDomain,
port: 80, port: 80,
serviceName: "activepieces", serviceName: "activepieces",
}, },
]; ];
const envs = [ const envs = [
`AP_HOST=${mainDomain}`, `AP_HOST=${mainDomain}`,
`AP_API_KEY=${apiKey}`, `AP_API_KEY=${apiKey}`,
`AP_ENCRYPTION_KEY=${encryptionKey}`, `AP_ENCRYPTION_KEY=${encryptionKey}`,
`AP_JWT_SECRET=${jwtSecret}`, `AP_JWT_SECRET=${jwtSecret}`,
`AP_POSTGRES_PASSWORD=${postgresPassword}`, `AP_POSTGRES_PASSWORD=${postgresPassword}`,
]; ];
return { return {
domains, domains,
envs, envs,
}; };
} }

View File

@@ -1,46 +1,47 @@
import { import {
type DomainSchema, type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generatePassword, generatePassword,
generateRandomDomain, generateRandomDomain,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainDomain = generateRandomDomain(schema); const mainDomain = generateRandomDomain(schema);
const mysqlPassword = generatePassword(); const mysqlPassword = generatePassword();
const mysqlRootPassword = generatePassword(); const mysqlRootPassword = generatePassword();
const mysqlUser = "tickets"; const mysqlUser = "tickets";
const mysqlDatabase = "tickets"; const mysqlDatabase = "tickets";
// Generate encryption key in the format they use // Generate encryption key in the format they use
const encryptionKey = Array.from({length: 48}, () => const encryptionKey = Array.from({ length: 48 }, () =>
Math.floor(Math.random() * 16).toString(16)).join(''); Math.floor(Math.random() * 16).toString(16),
).join("");
const domains: DomainSchema[] = [ const domains: DomainSchema[] = [
{ {
host: mainDomain, host: mainDomain,
port: 8169, port: 8169,
serviceName: "bot", serviceName: "bot",
}, },
]; ];
const envs = [ const envs = [
`TICKETS_HOST=${mainDomain}`, `TICKETS_HOST=${mainDomain}`,
`MYSQL_DATABASE=${mysqlDatabase}`, `MYSQL_DATABASE=${mysqlDatabase}`,
`MYSQL_PASSWORD=${mysqlPassword}`, `MYSQL_PASSWORD=${mysqlPassword}`,
`MYSQL_ROOT_PASSWORD=${mysqlRootPassword}`, `MYSQL_ROOT_PASSWORD=${mysqlRootPassword}`,
`MYSQL_USER=${mysqlUser}`, `MYSQL_USER=${mysqlUser}`,
`ENCRYPTION_KEY=${encryptionKey}`, `ENCRYPTION_KEY=${encryptionKey}`,
// These need to be set by the user through the UI // These need to be set by the user through the UI
`# Follow the guide at: https://discordtickets.app/self-hosting/installation/docker/#creating-the-discord-application`, "# Follow the guide at: https://discordtickets.app/self-hosting/installation/docker/#creating-the-discord-application",
`DISCORD_SECRET=`, "DISCORD_SECRET=",
`DISCORD_TOKEN=`, "DISCORD_TOKEN=",
`SUPER_USERS=YOUR_DISCORD_USER_ID`, // Default super user "SUPER_USERS=YOUR_DISCORD_USER_ID", // Default super user
]; ];
return { return {
domains, domains,
envs, envs,
}; };
} }

View File

@@ -1,34 +1,34 @@
import { import {
type DomainSchema, type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generatePassword, generatePassword,
generateRandomDomain, generateRandomDomain,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainDomain = generateRandomDomain(schema); const mainDomain = generateRandomDomain(schema);
const dbPassword = generatePassword(); const dbPassword = generatePassword();
const dbUsername = "invoiceshelf"; const dbUsername = "invoiceshelf";
const dbDatabase = "invoiceshelf"; const dbDatabase = "invoiceshelf";
const domains: DomainSchema[] = [ const domains: DomainSchema[] = [
{ {
host: mainDomain, host: mainDomain,
port: 80, port: 80,
serviceName: "invoiceshelf", serviceName: "invoiceshelf",
}, },
]; ];
const envs = [ const envs = [
`INVOICESHELF_HOST=${mainDomain}`, `INVOICESHELF_HOST=${mainDomain}`,
`DB_PASSWORD=${dbPassword}`, `DB_PASSWORD=${dbPassword}`,
`DB_USERNAME=${dbUsername}`, `DB_USERNAME=${dbUsername}`,
`DB_DATABASE=${dbDatabase}`, `DB_DATABASE=${dbDatabase}`,
]; ];
return { return {
domains, domains,
envs, envs,
}; };
} }

View File

@@ -1,43 +1,43 @@
import { import {
type DomainSchema, type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generateBase64, generateBase64,
generatePassword, generatePassword,
generateRandomDomain, generateRandomDomain,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
// Generate domains and secrets // Generate domains and secrets
const mainDomain = generateRandomDomain(schema); const mainDomain = generateRandomDomain(schema);
const apiDomain = generateRandomDomain(schema); const apiDomain = generateRandomDomain(schema);
const postgresPassword = generatePassword(); const postgresPassword = generatePassword();
const secret = generateBase64(32); const secret = generateBase64(32);
// Configure domain routing // Configure domain routing
const domains: DomainSchema[] = [ const domains: DomainSchema[] = [
{ {
host: mainDomain, host: mainDomain,
port: 3000, port: 3000,
serviceName: "peppermint", serviceName: "peppermint",
}, },
{ {
host: apiDomain, host: apiDomain,
port: 5003, port: 5003,
serviceName: "peppermint", serviceName: "peppermint",
}, },
]; ];
// Set environment variables // Set environment variables
const envs = [ const envs = [
`MAIN_DOMAIN=${mainDomain}`, `MAIN_DOMAIN=${mainDomain}`,
`API_DOMAIN=${apiDomain}`, `API_DOMAIN=${apiDomain}`,
`POSTGRES_PASSWORD=${postgresPassword}`, `POSTGRES_PASSWORD=${postgresPassword}`,
`SECRET=${secret}`, `SECRET=${secret}`,
]; ];
return { return {
domains, domains,
envs, envs,
}; };
} }

View File

@@ -1,37 +1,37 @@
import { import {
type DomainSchema, type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generatePassword, generateBase64,
generateRandomDomain, generatePassword,
generateBase64, generateRandomDomain,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainDomain = generateRandomDomain(schema); const mainDomain = generateRandomDomain(schema);
const dbPassword = generatePassword(); const dbPassword = generatePassword();
const dbUser = "postiz"; const dbUser = "postiz";
const dbName = "postiz"; const dbName = "postiz";
const jwtSecret = generateBase64(32); const jwtSecret = generateBase64(32);
const domains: DomainSchema[] = [ const domains: DomainSchema[] = [
{ {
host: mainDomain, host: mainDomain,
port: 5000, port: 5000,
serviceName: "postiz", serviceName: "postiz",
}, },
]; ];
const envs = [ const envs = [
`POSTIZ_HOST=${mainDomain}`, `POSTIZ_HOST=${mainDomain}`,
`DB_PASSWORD=${dbPassword}`, `DB_PASSWORD=${dbPassword}`,
`DB_USER=${dbUser}`, `DB_USER=${dbUser}`,
`DB_NAME=${dbName}`, `DB_NAME=${dbName}`,
`JWT_SECRET=${jwtSecret}`, `JWT_SECRET=${jwtSecret}`,
]; ];
return { return {
domains, domains,
envs, envs,
}; };
} }

View File

@@ -1,33 +1,33 @@
import { import {
type DomainSchema, type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generatePassword, generatePassword,
generateRandomDomain, generateRandomDomain,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainDomain = generateRandomDomain(schema); const mainDomain = generateRandomDomain(schema);
const dbPassword = generatePassword(); const dbPassword = generatePassword();
const dbUser = "slash"; const dbUser = "slash";
const dbName = "slash"; const dbName = "slash";
const domains: DomainSchema[] = [ const domains: DomainSchema[] = [
{ {
host: mainDomain, host: mainDomain,
port: 5231, port: 5231,
serviceName: "slash", serviceName: "slash",
}, },
]; ];
const envs = [ const envs = [
`DB_USER=${dbUser}`, `DB_USER=${dbUser}`,
`DB_PASSWORD=${dbPassword}`, `DB_PASSWORD=${dbPassword}`,
`DB_NAME=${dbName}`, `DB_NAME=${dbName}`,
]; ];
return { return {
domains, domains,
envs, envs,
}; };
} }

View File

@@ -706,12 +706,13 @@ export const templates: TemplateData[] = [
id: "peppermint", id: "peppermint",
name: "Peppermint", name: "Peppermint",
version: "latest", version: "latest",
description: "Peppermint is a modern, open-source API development platform that helps you build, test and document your APIs.", description:
"Peppermint is a modern, open-source API development platform that helps you build, test and document your APIs.",
logo: "peppermint.svg", logo: "peppermint.svg",
links: { links: {
github: "https://github.com/Peppermint-Lab/peppermint", github: "https://github.com/Peppermint-Lab/peppermint",
website: "https://peppermint.sh/", website: "https://peppermint.sh/",
docs: "https://docs.peppermint.sh/" docs: "https://docs.peppermint.sh/",
}, },
tags: ["api", "development", "documentation"], tags: ["api", "development", "documentation"],
load: () => import("./peppermint/index").then((m) => m.generate), load: () => import("./peppermint/index").then((m) => m.generate),
@@ -720,7 +721,8 @@ export const templates: TemplateData[] = [
id: "windmill", id: "windmill",
name: "Windmill", name: "Windmill",
version: "latest", version: "latest",
description: "A developer platform to build production-grade workflows and internal apps. Open-source alternative to Airplane, Retool, and GitHub Actions.", description:
"A developer platform to build production-grade workflows and internal apps. Open-source alternative to Airplane, Retool, and GitHub Actions.",
logo: "windmill.svg", logo: "windmill.svg",
links: { links: {
github: "https://github.com/windmill-labs/windmill", github: "https://github.com/windmill-labs/windmill",
@@ -734,7 +736,8 @@ export const templates: TemplateData[] = [
id: "activepieces", id: "activepieces",
name: "Activepieces", name: "Activepieces",
version: "0.35.0", version: "0.35.0",
description: "Open-source no-code business automation tool. An alternative to Zapier, Make.com, and Tray.", description:
"Open-source no-code business automation tool. An alternative to Zapier, Make.com, and Tray.",
logo: "activepieces.svg", logo: "activepieces.svg",
links: { links: {
github: "https://github.com/activepieces/activepieces", github: "https://github.com/activepieces/activepieces",
@@ -748,21 +751,23 @@ export const templates: TemplateData[] = [
id: "invoiceshelf", id: "invoiceshelf",
name: "InvoiceShelf", name: "InvoiceShelf",
version: "latest", version: "latest",
description: "InvoiceShelf is a self-hosted open source invoicing system for freelancers and small businesses.", description:
logo: "invoiceshelf.png", "InvoiceShelf is a self-hosted open source invoicing system for freelancers and small businesses.",
links: { logo: "invoiceshelf.png",
github: "https://github.com/InvoiceShelf/invoiceshelf", links: {
website: "https://invoiceshelf.com", github: "https://github.com/InvoiceShelf/invoiceshelf",
docs: "https://github.com/InvoiceShelf/invoiceshelf#readme", website: "https://invoiceshelf.com",
}, docs: "https://github.com/InvoiceShelf/invoiceshelf#readme",
tags: ["invoice", "business", "finance"], },
load: () => import("./invoiceshelf/index").then((m) => m.generate), tags: ["invoice", "business", "finance"],
load: () => import("./invoiceshelf/index").then((m) => m.generate),
}, },
{ {
id: "postiz", id: "postiz",
name: "Postiz", name: "Postiz",
version: "latest", version: "latest",
description: "Postiz is a modern, open-source platform for managing and publishing content across multiple channels.", description:
"Postiz is a modern, open-source platform for managing and publishing content across multiple channels.",
logo: "postiz.png", logo: "postiz.png",
links: { links: {
github: "https://github.com/gitroomhq/postiz", github: "https://github.com/gitroomhq/postiz",
@@ -776,7 +781,8 @@ export const templates: TemplateData[] = [
id: "slash", id: "slash",
name: "Slash", name: "Slash",
version: "latest", version: "latest",
description: "Slash is a modern, self-hosted bookmarking service and link shortener that helps you organize and share your favorite links.", description:
"Slash is a modern, self-hosted bookmarking service and link shortener that helps you organize and share your favorite links.",
logo: "slash.png", logo: "slash.png",
links: { links: {
github: "https://github.com/yourselfhosted/slash", github: "https://github.com/yourselfhosted/slash",
@@ -790,7 +796,8 @@ export const templates: TemplateData[] = [
id: "discord-tickets", id: "discord-tickets",
name: "Discord Tickets", name: "Discord Tickets",
version: "4.0.21", version: "4.0.21",
description: "An open-source Discord bot for creating and managing support ticket channels.", description:
"An open-source Discord bot for creating and managing support ticket channels.",
logo: "discord-tickets.png", logo: "discord-tickets.png",
links: { links: {
github: "https://github.com/discord-tickets/bot", github: "https://github.com/discord-tickets/bot",
@@ -799,8 +806,8 @@ export const templates: TemplateData[] = [
}, },
tags: ["discord", "tickets", "support"], tags: ["discord", "tickets", "support"],
load: () => import("./discord-tickets/index").then((m) => m.generate), load: () => import("./discord-tickets/index").then((m) => m.generate),
}, },
{ {
id: "nextcloud-aio", id: "nextcloud-aio",
name: "Nextcloud All in One", name: "Nextcloud All in One",
version: "30.0.2", version: "30.0.2",
@@ -814,8 +821,8 @@ export const templates: TemplateData[] = [
}, },
tags: ["file", "sync"], tags: ["file", "sync"],
load: () => import("./nextcloud-aio/index").then((m) => m.generate), load: () => import("./nextcloud-aio/index").then((m) => m.generate),
}, },
{ {
id: "blender", id: "blender",
name: "Blender", name: "Blender",
version: "latest", version: "latest",

View File

@@ -1,43 +1,43 @@
import { import {
type DomainSchema, type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generatePassword, generatePassword,
generateRandomDomain, generateRandomDomain,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainDomain = generateRandomDomain(schema); const mainDomain = generateRandomDomain(schema);
const postgresPassword = generatePassword(); const postgresPassword = generatePassword();
const domains: DomainSchema[] = [ const domains: DomainSchema[] = [
{ {
host: mainDomain, host: mainDomain,
port: 80, port: 80,
serviceName: "caddy", serviceName: "caddy",
}, },
]; ];
const envs = [ const envs = [
`WINDMILL_HOST=${mainDomain}`, `WINDMILL_HOST=${mainDomain}`,
`POSTGRES_PASSWORD=${postgresPassword}`, `POSTGRES_PASSWORD=${postgresPassword}`,
`DATABASE_URL=postgres://postgres:${postgresPassword}@db/windmill?sslmode=disable`, `DATABASE_URL=postgres://postgres:${postgresPassword}@db/windmill?sslmode=disable`,
]; ];
const mounts: Template["mounts"] = [ const mounts: Template["mounts"] = [
{ {
filePath: "Caddyfile", filePath: "Caddyfile",
content: `:80 { content: `:80 {
bind 0.0.0.0 bind 0.0.0.0
reverse_proxy /ws/* http://lsp:3001 reverse_proxy /ws/* http://lsp:3001
reverse_proxy /* http://windmill_server:8000 reverse_proxy /* http://windmill_server:8000
}`, }`,
}, },
]; ];
return { return {
domains, domains,
envs, envs,
mounts, mounts,
}; };
} }

View File

@@ -39,7 +39,8 @@
"**/*.js", "**/*.js",
".next/types/**/*.ts", ".next/types/**/*.ts",
"env.js", "env.js",
"next.config.mjs" "next.config.mjs",
"next-i18next.config.mjs"
], ],
"exclude": [ "exclude": [
"node_modules", "node_modules",

View File

@@ -4,3 +4,12 @@ export function getLocale(cookies: NextApiRequestCookies) {
const locale = cookies.DOKPLOY_LOCALE ?? "en"; const locale = cookies.DOKPLOY_LOCALE ?? "en";
return locale; return locale;
} }
// libs/i18n.js
import { serverSideTranslations as originalServerSideTranslations } from "next-i18next/serverSideTranslations";
import nextI18NextConfig from "../next-i18next.config.cjs";
export const serverSideTranslations = (
locale: string,
namespaces = ["common"],
) => originalServerSideTranslations(locale, namespaces, nextI18NextConfig);

26
pnpm-lock.yaml generated
View File

@@ -249,7 +249,7 @@ importers:
version: 0.5.1(drizzle-orm@0.30.10(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0))(zod@3.23.8) version: 0.5.1(drizzle-orm@0.30.10(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0))(zod@3.23.8)
i18next: i18next:
specifier: ^23.16.4 specifier: ^23.16.4
version: 23.16.4 version: 23.16.5
input-otp: input-otp:
specifier: ^1.2.4 specifier: ^1.2.4
version: 1.2.4(react-dom@18.2.0(react@18.2.0))(react@18.2.0) version: 1.2.4(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -276,7 +276,7 @@ importers:
version: 15.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) version: 15.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
next-i18next: next-i18next:
specifier: ^15.3.1 specifier: ^15.3.1
version: 15.3.1(i18next@23.16.4)(next@15.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-i18next@15.1.0(i18next@23.16.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0) version: 15.3.1(i18next@23.16.5)(next@15.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-i18next@15.1.1(i18next@23.16.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0)
next-themes: next-themes:
specifier: ^0.2.1 specifier: ^0.2.1
version: 0.2.1(next@15.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) version: 0.2.1(next@15.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -306,7 +306,7 @@ importers:
version: 7.52.1(react@18.2.0) version: 7.52.1(react@18.2.0)
react-i18next: react-i18next:
specifier: ^15.1.0 specifier: ^15.1.0
version: 15.1.0(i18next@23.16.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) version: 15.1.1(i18next@23.16.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
recharts: recharts:
specifier: ^2.12.7 specifier: ^2.12.7
version: 2.12.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0) version: 2.12.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -4734,8 +4734,8 @@ packages:
i18next-fs-backend@2.3.2: i18next-fs-backend@2.3.2:
resolution: {integrity: sha512-LIwUlkqDZnUI8lnUxBnEj8K/FrHQTT/Sc+1rvDm9E8YvvY5YxzoEAASNx+W5M9DfD5s77lI5vSAFWeTp26B/3Q==} resolution: {integrity: sha512-LIwUlkqDZnUI8lnUxBnEj8K/FrHQTT/Sc+1rvDm9E8YvvY5YxzoEAASNx+W5M9DfD5s77lI5vSAFWeTp26B/3Q==}
i18next@23.16.4: i18next@23.16.5:
resolution: {integrity: sha512-9NIYBVy9cs4wIqzurf7nLXPyf3R78xYbxExVqHLK9od3038rjpyOEzW+XB130kZ1N4PZ9inTtJ471CRJ4Ituyg==} resolution: {integrity: sha512-KTlhE3EP9x6pPTAW7dy0WKIhoCpfOGhRQlO+jttQLgzVaoOjWwBWramu7Pp0i+8wDNduuzXfe3kkVbzrKyrbTA==}
iconv-lite@0.4.24: iconv-lite@0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
@@ -5771,8 +5771,8 @@ packages:
peerDependencies: peerDependencies:
react: ^16.8.0 || ^17 || ^18 || ^19 react: ^16.8.0 || ^17 || ^18 || ^19
react-i18next@15.1.0: react-i18next@15.1.1:
resolution: {integrity: sha512-zj3nJynMnZsy2gPZiOTC7XctCY5eQGqT3tcKMmfJWC9FMvgd+960w/adq61j8iPzpwmsXejqID9qC3Mqu1Xu2Q==} resolution: {integrity: sha512-R/Vg9wIli2P3FfeI8o1eNJUJue5LWpFsQePCHdQDmX0Co3zkr6kdT8gAseb/yGeWbNz1Txc4bKDQuZYsC0kQfw==}
peerDependencies: peerDependencies:
i18next: '>= 23.2.3' i18next: '>= 23.2.3'
react: '>= 16.8.0' react: '>= 16.8.0'
@@ -10946,7 +10946,7 @@ snapshots:
i18next-fs-backend@2.3.2: {} i18next-fs-backend@2.3.2: {}
i18next@23.16.4: i18next@23.16.5:
dependencies: dependencies:
'@babel/runtime': 7.25.0 '@babel/runtime': 7.25.0
@@ -11450,17 +11450,17 @@ snapshots:
neotraverse@0.6.18: {} neotraverse@0.6.18: {}
next-i18next@15.3.1(i18next@23.16.4)(next@15.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-i18next@15.1.0(i18next@23.16.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0): next-i18next@15.3.1(i18next@23.16.5)(next@15.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-i18next@15.1.1(i18next@23.16.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0):
dependencies: dependencies:
'@babel/runtime': 7.25.0 '@babel/runtime': 7.25.0
'@types/hoist-non-react-statics': 3.3.5 '@types/hoist-non-react-statics': 3.3.5
core-js: 3.39.0 core-js: 3.39.0
hoist-non-react-statics: 3.3.2 hoist-non-react-statics: 3.3.2
i18next: 23.16.4 i18next: 23.16.5
i18next-fs-backend: 2.3.2 i18next-fs-backend: 2.3.2
next: 15.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) next: 15.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0 react: 18.2.0
react-i18next: 15.1.0(i18next@23.16.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react-i18next: 15.1.1(i18next@23.16.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
next-themes@0.2.1(next@15.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): next-themes@0.2.1(next@15.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies: dependencies:
@@ -11951,11 +11951,11 @@ snapshots:
dependencies: dependencies:
react: 18.2.0 react: 18.2.0
react-i18next@15.1.0(i18next@23.16.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): react-i18next@15.1.1(i18next@23.16.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies: dependencies:
'@babel/runtime': 7.25.0 '@babel/runtime': 7.25.0
html-parse-stringify: 3.0.1 html-parse-stringify: 3.0.1
i18next: 23.16.4 i18next: 23.16.5
react: 18.2.0 react: 18.2.0
optionalDependencies: optionalDependencies:
react-dom: 18.2.0(react@18.2.0) react-dom: 18.2.0(react@18.2.0)