mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-11 16:05:47 +01:00
♻️ Add translations for board customize page
This commit is contained in:
5
public/locales/en/boards/common.json
Normal file
5
public/locales/en/boards/common.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"header": {
|
||||||
|
"customize": "Customize board"
|
||||||
|
}
|
||||||
|
}
|
||||||
26
public/locales/en/boards/customize.json
Normal file
26
public/locales/en/boards/customize.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"metaTitle": "Customize {{name}} Board",
|
||||||
|
"pageTitle": "Customization for {{name}} Board",
|
||||||
|
"backToBoard": "Back to board",
|
||||||
|
"settings": {
|
||||||
|
"appearance": {
|
||||||
|
"primaryColor": "Primary color",
|
||||||
|
"secondaryColor": "Secondary color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"save": "Save changes",
|
||||||
|
"notifications": {
|
||||||
|
"pending": {
|
||||||
|
"title": "Saving customization",
|
||||||
|
"message": "Please wait while we save your customization"
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"title": "Customization saved",
|
||||||
|
"message": "Your customization has been saved successfully"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"title": "Error",
|
||||||
|
"message": "Unable to save changes"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"label": "App Width"
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"colors": "Colors",
|
|
||||||
"suffix": "{{color}} color"
|
|
||||||
}
|
|
||||||
@@ -23,8 +23,5 @@
|
|||||||
"description": "Further, customize your dashboard using CSS, only recommended for experienced users",
|
"description": "Further, customize your dashboard using CSS, only recommended for experienced users",
|
||||||
"placeholder": "Custom CSS will be applied last",
|
"placeholder": "Custom CSS will be applied last",
|
||||||
"applying": "Applying CSS..."
|
"applying": "Applying CSS..."
|
||||||
},
|
|
||||||
"buttons": {
|
|
||||||
"submit": "Submit"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"label": "Switch to {{scheme}} mode"
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"label": "Switch to {{theme}} mode"
|
|
||||||
}
|
|
||||||
@@ -18,11 +18,7 @@ import Editor from 'react-simple-code-editor';
|
|||||||
import { useBoardCustomizationFormContext } from '../form';
|
import { useBoardCustomizationFormContext } from '../form';
|
||||||
|
|
||||||
export const AppearanceCustomization = () => {
|
export const AppearanceCustomization = () => {
|
||||||
const { t } = useTranslation([
|
const { t } = useTranslation('settings/customization/page-appearance');
|
||||||
'settings/customization/page-appearance',
|
|
||||||
'settings/customization/color-selector',
|
|
||||||
]);
|
|
||||||
const theme = useMantineTheme();
|
|
||||||
const form = useBoardCustomizationFormContext();
|
const form = useBoardCustomizationFormContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -45,7 +41,7 @@ type ColorSelectorProps = {
|
|||||||
type: 'primaryColor' | 'secondaryColor';
|
type: 'primaryColor' | 'secondaryColor';
|
||||||
};
|
};
|
||||||
const ColorSelector = ({ type }: ColorSelectorProps) => {
|
const ColorSelector = ({ type }: ColorSelectorProps) => {
|
||||||
const { t } = useTranslation('settings/customization/color-selector');
|
const { t } = useTranslation('boards/customize');
|
||||||
const theme = useMantineTheme();
|
const theme = useMantineTheme();
|
||||||
const form = useBoardCustomizationFormContext();
|
const form = useBoardCustomizationFormContext();
|
||||||
|
|
||||||
@@ -55,7 +51,7 @@ const ColorSelector = ({ type }: ColorSelectorProps) => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Input.Wrapper label={type}>
|
<Input.Wrapper label={t(`settings.appearance.${type}`)}>
|
||||||
<Group>
|
<Group>
|
||||||
{colors.map(({ color, swatch }) => (
|
{colors.map(({ color, swatch }) => (
|
||||||
<ColorSwatch
|
<ColorSwatch
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Button, Checkbox, Grid, Stack } from '@mantine/core';
|
import { Checkbox, Grid, Stack } from '@mantine/core';
|
||||||
import { IconDeviceFloppy } from '@tabler/icons-react';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
|
|
||||||
import { useBoardCustomizationFormContext } from '../form';
|
import { useBoardCustomizationFormContext } from '../form';
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ import { Trans, useTranslation } from 'next-i18next';
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useEditModeStore } from '~/components/Dashboard/Views/useEditModeStore';
|
import { useEditModeStore } from '~/components/Dashboard/Views/useEditModeStore';
|
||||||
import { useNamedWrapperColumnCount } from '~/components/Dashboard/Wrappers/gridstack/store';
|
import { useNamedWrapperColumnCount } from '~/components/Dashboard/Wrappers/gridstack/store';
|
||||||
|
import { BoardHeadOverride } from '~/components/layout/Meta/BoardHeadOverride';
|
||||||
|
import { HeaderActionButton } from '~/components/layout/header/ActionButton';
|
||||||
import { useConfigContext } from '~/config/provider';
|
import { useConfigContext } from '~/config/provider';
|
||||||
import { env } from '~/env';
|
import { env } from '~/env';
|
||||||
import { api } from '~/utils/api';
|
import { api } from '~/utils/api';
|
||||||
|
|
||||||
import { HeaderActionButton } from '~/components/layout/header/ActionButton';
|
|
||||||
import { BoardHeadOverride } from '~/components/layout/Meta/BoardHeadOverride';
|
|
||||||
import { MainLayout } from './MainLayout';
|
import { MainLayout } from './MainLayout';
|
||||||
|
|
||||||
type BoardLayoutProps = {
|
type BoardLayoutProps = {
|
||||||
@@ -68,10 +68,10 @@ const DockerButton = () => {
|
|||||||
|
|
||||||
const CustomizeBoardButton = () => {
|
const CustomizeBoardButton = () => {
|
||||||
const { name } = useConfigContext();
|
const { name } = useConfigContext();
|
||||||
console.log('name', name);
|
const { t } = useTranslation('boards/common');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip label="Customize board">
|
<Tooltip label={t('header.customize')}>
|
||||||
<HeaderActionButton component={Link} href={`/board/${name}/customize`}>
|
<HeaderActionButton component={Link} href={`/board/${name}/customize`}>
|
||||||
<IconSettings size={20} stroke={1.5} />
|
<IconSettings size={20} stroke={1.5} />
|
||||||
</HeaderActionButton>
|
</HeaderActionButton>
|
||||||
@@ -158,7 +158,7 @@ const ToggleEditModeButton = () => {
|
|||||||
if (enabled) {
|
if (enabled) {
|
||||||
return (
|
return (
|
||||||
<Button.Group>
|
<Button.Group>
|
||||||
<Tooltip label={t('button.disabled')}>
|
<Tooltip label={t('button.enabled')}>
|
||||||
<HeaderActionButton onClick={save}>
|
<HeaderActionButton onClick={save}>
|
||||||
<IconEditCircleOff size={20} stroke={1.5} />
|
<IconEditCircleOff size={20} stroke={1.5} />
|
||||||
</HeaderActionButton>
|
</HeaderActionButton>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { useInitConfig } from '~/config/init';
|
|||||||
import { configExists } from '~/tools/config/configExists';
|
import { configExists } from '~/tools/config/configExists';
|
||||||
import { getFrontendConfig } from '~/tools/config/getFrontendConfig';
|
import { getFrontendConfig } from '~/tools/config/getFrontendConfig';
|
||||||
import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations';
|
import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations';
|
||||||
import { dashboardNamespaces } from '~/tools/server/translation-namespaces';
|
import { boardNamespaces } from '~/tools/server/translation-namespaces';
|
||||||
import { ConfigType } from '~/types/config';
|
import { ConfigType } from '~/types/config';
|
||||||
|
|
||||||
export default function BoardPage({
|
export default function BoardPage({
|
||||||
@@ -52,7 +52,7 @@ export const getServerSideProps: GetServerSideProps<BoardGetServerSideProps> = a
|
|||||||
}
|
}
|
||||||
|
|
||||||
const config = await getFrontendConfig(routeParams.data.slug);
|
const config = await getFrontendConfig(routeParams.data.slug);
|
||||||
const translations = await getServerSideTranslations(dashboardNamespaces, locale, req, res);
|
const translations = await getServerSideTranslations(boardNamespaces, locale, req, res);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
import { GetServerSideProps } from 'next';
|
import { GetServerSideProps } from 'next';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import Head from 'next/head';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
@@ -28,7 +29,8 @@ import { MainLayout } from '~/components/layout/Templates/MainLayout';
|
|||||||
import { createTrpcServersideHelpers } from '~/server/api/helper';
|
import { createTrpcServersideHelpers } from '~/server/api/helper';
|
||||||
import { getServerAuthSession } from '~/server/auth';
|
import { getServerAuthSession } from '~/server/auth';
|
||||||
import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations';
|
import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations';
|
||||||
import { dashboardNamespaces } from '~/tools/server/translation-namespaces';
|
import { boardNamespaces } from '~/tools/server/translation-namespaces';
|
||||||
|
import { firstUpperCase } from '~/tools/shared/strings';
|
||||||
import { api } from '~/utils/api';
|
import { api } from '~/utils/api';
|
||||||
import { useI18nZodResolver } from '~/utils/i18n-zod-resolver';
|
import { useI18nZodResolver } from '~/utils/i18n-zod-resolver';
|
||||||
import { boardCustomizationSchema } from '~/validations/dashboards';
|
import { boardCustomizationSchema } from '~/validations/dashboards';
|
||||||
@@ -41,6 +43,7 @@ export default function CustomizationPage() {
|
|||||||
const { data: config } = api.config.byName.useQuery({ name: query.slug });
|
const { data: config } = api.config.byName.useQuery({ name: query.slug });
|
||||||
const { mutateAsync: saveCusomization, isLoading } = api.config.saveCusomization.useMutation();
|
const { mutateAsync: saveCusomization, isLoading } = api.config.saveCusomization.useMutation();
|
||||||
const { i18nZodResolver } = useI18nZodResolver();
|
const { i18nZodResolver } = useI18nZodResolver();
|
||||||
|
const { t } = useTranslation('boards/customize');
|
||||||
const form = useBoardCustomizationForm({
|
const form = useBoardCustomizationForm({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
layout: {
|
layout: {
|
||||||
@@ -75,8 +78,8 @@ export default function CustomizationPage() {
|
|||||||
if (isLoading) return;
|
if (isLoading) return;
|
||||||
showNotification({
|
showNotification({
|
||||||
id: notificationId,
|
id: notificationId,
|
||||||
title: 'Saving customization',
|
title: t('notifications.pending.title'),
|
||||||
message: 'Please wait while we save your customization',
|
message: t('notifications.pending.message'),
|
||||||
loading: true,
|
loading: true,
|
||||||
});
|
});
|
||||||
await saveCusomization(
|
await saveCusomization(
|
||||||
@@ -91,8 +94,8 @@ export default function CustomizationPage() {
|
|||||||
onSuccess() {
|
onSuccess() {
|
||||||
updateNotification({
|
updateNotification({
|
||||||
id: notificationId,
|
id: notificationId,
|
||||||
title: 'Customization saved',
|
title: t('notifications.success.title'),
|
||||||
message: 'Your customization has been saved',
|
message: t('notifications.success.message'),
|
||||||
color: 'green',
|
color: 'green',
|
||||||
icon: <IconCheck />,
|
icon: <IconCheck />,
|
||||||
});
|
});
|
||||||
@@ -100,8 +103,8 @@ export default function CustomizationPage() {
|
|||||||
onError() {
|
onError() {
|
||||||
updateNotification({
|
updateNotification({
|
||||||
id: notificationId,
|
id: notificationId,
|
||||||
title: 'Error',
|
title: t('notifications.error.title'),
|
||||||
message: 'Unable to save customization',
|
message: t('notifications.error.message'),
|
||||||
color: 'red',
|
color: 'red',
|
||||||
icon: <IconX />,
|
icon: <IconX />,
|
||||||
});
|
});
|
||||||
@@ -110,20 +113,31 @@ export default function CustomizationPage() {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const metaTitle = `${t('metaTitle', {
|
||||||
|
name: firstUpperCase(query.slug),
|
||||||
|
})} • Homarr`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
|
<Head>
|
||||||
|
<title>{metaTitle}</title>
|
||||||
|
</Head>
|
||||||
<Container>
|
<Container>
|
||||||
<Paper p="xl" py="sm" mih="100%" withBorder>
|
<Paper p="xl" py="sm" mih="100%" withBorder>
|
||||||
<Stack>
|
<Stack>
|
||||||
<Group position="apart">
|
<Group position="apart">
|
||||||
<Title order={2}>Customization for {query.slug} Board</Title>
|
<Title order={2}>
|
||||||
|
{t('pageTitle', {
|
||||||
|
name: firstUpperCase(query.slug),
|
||||||
|
})}
|
||||||
|
</Title>
|
||||||
<Button
|
<Button
|
||||||
component={Link}
|
component={Link}
|
||||||
href={`/board/${query.slug}`}
|
href={`/board/${query.slug}`}
|
||||||
variant="light"
|
variant="light"
|
||||||
leftIcon={<IconArrowLeft size={16} />}
|
leftIcon={<IconArrowLeft size={16} />}
|
||||||
>
|
>
|
||||||
Back to Board
|
{t('backToBoard')}
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
<BoardCustomizationFormProvider form={form}>
|
<BoardCustomizationFormProvider form={form}>
|
||||||
@@ -146,7 +160,7 @@ export default function CustomizationPage() {
|
|||||||
<AppearanceCustomization />
|
<AppearanceCustomization />
|
||||||
</Stack>
|
</Stack>
|
||||||
<Button type="submit" loading={isLoading}>
|
<Button type="submit" loading={isLoading}>
|
||||||
Save changes
|
{t('save')}
|
||||||
</Button>
|
</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
</form>
|
</form>
|
||||||
@@ -200,7 +214,20 @@ export const getServerSideProps: GetServerSideProps = async ({ req, res, locale,
|
|||||||
|
|
||||||
helpers.config.byName.prefetch({ name: routeParams.data.slug });
|
helpers.config.byName.prefetch({ name: routeParams.data.slug });
|
||||||
|
|
||||||
const translations = await getServerSideTranslations(dashboardNamespaces, locale, req, res);
|
const translations = await getServerSideTranslations(
|
||||||
|
[
|
||||||
|
'boards/customize',
|
||||||
|
'settings/common',
|
||||||
|
'settings/customization/general',
|
||||||
|
'settings/customization/page-appearance',
|
||||||
|
'settings/customization/shade-selector',
|
||||||
|
'settings/customization/opacity-selector',
|
||||||
|
'settings/customization/gridstack',
|
||||||
|
],
|
||||||
|
locale,
|
||||||
|
req,
|
||||||
|
res
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { getServerAuthSession } from '~/server/auth';
|
|||||||
import { prisma } from '~/server/db';
|
import { prisma } from '~/server/db';
|
||||||
import { getFrontendConfig } from '~/tools/config/getFrontendConfig';
|
import { getFrontendConfig } from '~/tools/config/getFrontendConfig';
|
||||||
import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations';
|
import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations';
|
||||||
import { dashboardNamespaces } from '~/tools/server/translation-namespaces';
|
import { boardNamespaces } from '~/tools/server/translation-namespaces';
|
||||||
import { ConfigType } from '~/types/config';
|
import { ConfigType } from '~/types/config';
|
||||||
|
|
||||||
export default function BoardPage({
|
export default function BoardPage({
|
||||||
@@ -36,7 +36,7 @@ export const getServerSideProps: GetServerSideProps<BoardGetServerSideProps> = a
|
|||||||
});
|
});
|
||||||
|
|
||||||
const translations = await getServerSideTranslations(
|
const translations = await getServerSideTranslations(
|
||||||
dashboardNamespaces,
|
boardNamespaces,
|
||||||
ctx.locale,
|
ctx.locale,
|
||||||
ctx.req,
|
ctx.req,
|
||||||
ctx.res
|
ctx.res
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import ContainerActionBar from '~/modules/Docker/ContainerActionBar';
|
|||||||
import DockerTable from '~/modules/Docker/DockerTable';
|
import DockerTable from '~/modules/Docker/DockerTable';
|
||||||
import { getServerAuthSession } from '~/server/auth';
|
import { getServerAuthSession } from '~/server/auth';
|
||||||
import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations';
|
import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations';
|
||||||
import { dashboardNamespaces } from '~/tools/server/translation-namespaces';
|
import { boardNamespaces } from '~/tools/server/translation-namespaces';
|
||||||
import { api } from '~/utils/api';
|
import { api } from '~/utils/api';
|
||||||
|
|
||||||
export default function DockerPage() {
|
export default function DockerPage() {
|
||||||
@@ -42,7 +42,7 @@ export const getServerSideProps: GetServerSideProps = async ({ locale, req, res
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const translations = await getServerSideTranslations(dashboardNamespaces, locale, req, res);
|
const translations = await getServerSideTranslations(boardNamespaces, locale, req, res);
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
...translations,
|
...translations,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export const dashboardNamespaces = [
|
export const boardNamespaces = [
|
||||||
'common',
|
'common',
|
||||||
'zod',
|
'zod',
|
||||||
'layout/element-selector/selector',
|
'layout/element-selector/selector',
|
||||||
@@ -9,18 +9,10 @@ export const dashboardNamespaces = [
|
|||||||
'layout/header/actions/toggle-edit-mode',
|
'layout/header/actions/toggle-edit-mode',
|
||||||
'layout/mobile/drawer',
|
'layout/mobile/drawer',
|
||||||
'settings/common',
|
'settings/common',
|
||||||
'settings/general/theme-selector',
|
|
||||||
'settings/general/config-changer',
|
'settings/general/config-changer',
|
||||||
'settings/general/internationalization',
|
'settings/general/internationalization',
|
||||||
'settings/general/search-engine',
|
'settings/general/search-engine',
|
||||||
'settings/general/widget-positions',
|
'settings/general/widget-positions',
|
||||||
'settings/customization/general',
|
|
||||||
'settings/customization/color-selector',
|
|
||||||
'settings/customization/page-appearance',
|
|
||||||
'settings/customization/shade-selector',
|
|
||||||
'settings/customization/app-width',
|
|
||||||
'settings/customization/opacity-selector',
|
|
||||||
'settings/customization/gridstack',
|
|
||||||
'modules/common',
|
'modules/common',
|
||||||
'modules/date',
|
'modules/date',
|
||||||
'modules/calendar',
|
'modules/calendar',
|
||||||
@@ -46,6 +38,7 @@ export const dashboardNamespaces = [
|
|||||||
'widgets/error-boundary',
|
'widgets/error-boundary',
|
||||||
'widgets/draggable-list',
|
'widgets/draggable-list',
|
||||||
'widgets/location',
|
'widgets/location',
|
||||||
|
'boards/common',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const manageNamespaces = ['user/preferences', 'zod'];
|
export const manageNamespaces = ['user/preferences', 'zod'];
|
||||||
|
|||||||
Reference in New Issue
Block a user