mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
refactor: improve I18N
This commit is contained in:
parent
a53daed434
commit
64e6919211
@ -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
|
||||||
|
@ -32,30 +32,15 @@ import { useTranslation } from "next-i18next";
|
|||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
import { Languages } from "@/lib/languages";
|
||||||
|
|
||||||
const appearanceFormSchema = z.object({
|
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, {
|
||||||
[
|
required_error: "Please select a language.",
|
||||||
"en",
|
}),
|
||||||
"pl",
|
|
||||||
"ru",
|
|
||||||
"fr",
|
|
||||||
"de",
|
|
||||||
"tr",
|
|
||||||
"zh-Hant",
|
|
||||||
"kz",
|
|
||||||
"zh-Hans",
|
|
||||||
"fa",
|
|
||||||
"ko",
|
|
||||||
"pt-br",
|
|
||||||
],
|
|
||||||
{
|
|
||||||
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" },
|
</SelectItem>
|
||||||
{ 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>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
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,3 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
/** @type {import('next-i18next').UserConfig} */
|
/** @type {import('next-i18next').UserConfig} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
fallbackLng: "en",
|
fallbackLng: "en",
|
||||||
|
@ -10,6 +10,7 @@ import { Inter } from "next/font/google";
|
|||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import Script from "next/script";
|
import Script from "next/script";
|
||||||
import type { ReactElement, ReactNode } from "react";
|
import type { ReactElement, ReactNode } from "react";
|
||||||
|
import { Languages } from "@/lib/languages";
|
||||||
|
|
||||||
const inter = Inter({ subsets: ["latin"] });
|
const inter = Inter({ subsets: ["latin"] });
|
||||||
|
|
||||||
@ -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",
|
||||||
|
@ -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",
|
||||||
|
@ -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 { serverSideTranslations as originalServerSideTranslations } from "next-i18next/serverSideTranslations";
|
import { serverSideTranslations as originalServerSideTranslations } from "next-i18next/serverSideTranslations";
|
||||||
import nextI18NextConfig from "../next-i18next.config.cjs";
|
import { Languages } from "@/lib/languages";
|
||||||
|
|
||||||
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,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user