mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-10 15:35:55 +01:00
✨ Add translation for module, fix language changer
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"states": {
|
||||
"online": "Online {{response}}",
|
||||
"offline": "Offline {{response}}",
|
||||
"loading": "Loading..."
|
||||
}
|
||||
}
|
||||
11
public/locales/en/modules/ping.json
Normal file
11
public/locales/en/modules/ping.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"descriptor": {
|
||||
"name": "Ping",
|
||||
"description": "Allows you to check if the service is up or returns a specific HTTP status code."
|
||||
},
|
||||
"states": {
|
||||
"online": "Online {{response}}",
|
||||
"offline": "Offline {{response}}",
|
||||
"loading": "Loading..."
|
||||
}
|
||||
}
|
||||
@@ -126,7 +126,7 @@ const AppShelf = (props: any) => {
|
||||
const noCategory = config.services.filter(
|
||||
(e) => e.category === undefined || e.category === null
|
||||
);
|
||||
const downloadEnabled = config.modules?.[DownloadsModule.title]?.enabled ?? false;
|
||||
const downloadEnabled = config.modules?.[DownloadsModule.id]?.enabled ?? false;
|
||||
// Create an item with 0: true, 1: true, 2: true... For each category
|
||||
return (
|
||||
// TODO: Style accordion so that the bar is transparent to the user settings
|
||||
|
||||
@@ -4,14 +4,17 @@ import { showNotification } from '@mantine/notifications';
|
||||
import { forwardRef, useState } from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useRouter } from 'next/router';
|
||||
import { getCookie, setCookie } from 'cookies-next';
|
||||
import { getLanguageByCode, Language } from '../../languages/language';
|
||||
|
||||
export default function LanguageSwitch() {
|
||||
const { t, i18n } = useTranslation('settings/general/internationalization');
|
||||
const { changeLanguage } = i18n;
|
||||
|
||||
const configLocale = getCookie('config-locale');
|
||||
const { locale, locales } = useRouter();
|
||||
const [selectedLanguage, setSelectedLanguage] = useState<string | null | undefined>(locale);
|
||||
const [selectedLanguage, setSelectedLanguage] = useState<string | undefined>(
|
||||
(configLocale as string) ?? locale
|
||||
);
|
||||
|
||||
const data = locales
|
||||
? locales.map((localeItem) => ({
|
||||
@@ -26,9 +29,13 @@ export default function LanguageSwitch() {
|
||||
setSelectedLanguage(value);
|
||||
|
||||
const newLanguage = getLanguageByCode(value);
|
||||
|
||||
changeLanguage(value)
|
||||
.then(() => {
|
||||
setCookie('config-locale', value, {
|
||||
maxAge: 60 * 60 * 24 * 30,
|
||||
sameSite: 'strict',
|
||||
});
|
||||
|
||||
showNotification({
|
||||
title: 'Language changed',
|
||||
message: `You changed the language to '${newLanguage.originalName}'`,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Checkbox, Popover, SimpleGrid, Stack, Text, Title } from '@mantine/core';
|
||||
import { useDisclosure } from '@mantine/hooks';
|
||||
import { Checkbox, HoverCard, SimpleGrid, Stack, Text, Title } from '@mantine/core';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import * as Modules from '../../modules';
|
||||
import { IModule } from '../../modules/ModuleTypes';
|
||||
@@ -11,9 +10,9 @@ export default function ModuleEnabler(props: any) {
|
||||
return (
|
||||
<Stack>
|
||||
<Title order={4}>{t('title')}</Title>
|
||||
<SimpleGrid cols={3} spacing="xs">
|
||||
<SimpleGrid cols={3} spacing="sm">
|
||||
{modules.map((module) => (
|
||||
<ModuleToggle module={module} />
|
||||
<ModuleToggle key={module.id} module={module} />
|
||||
))}
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
@@ -22,39 +21,36 @@ export default function ModuleEnabler(props: any) {
|
||||
|
||||
const ModuleToggle = ({ module }: { module: IModule }) => {
|
||||
const { config, setConfig } = useConfig();
|
||||
const { t: translationModules } = useTranslation(module.translationNamespace);
|
||||
const [opened, { close, open }] = useDisclosure(false);
|
||||
const { t } = useTranslation(`modules/${module.id}`);
|
||||
|
||||
return (
|
||||
<Popover opened={opened} withArrow withinPortal width={200}>
|
||||
<Popover.Target>
|
||||
<div onMouseEnter={open} onMouseLeave={close}>
|
||||
<Checkbox
|
||||
key={module.title}
|
||||
size="md"
|
||||
checked={config.modules?.[module.title]?.enabled ?? false}
|
||||
label={translationModules('descriptor.name', {
|
||||
defaultValue: 'Unknown',
|
||||
})}
|
||||
onChange={(e) => {
|
||||
setConfig({
|
||||
...config,
|
||||
modules: {
|
||||
...config.modules,
|
||||
[module.title]: {
|
||||
...config.modules?.[module.title],
|
||||
enabled: e.currentTarget.checked,
|
||||
},
|
||||
<HoverCard withArrow withinPortal width={200} shadow="md" openDelay={200}>
|
||||
<HoverCard.Target>
|
||||
<Checkbox
|
||||
key={module.id}
|
||||
size="md"
|
||||
checked={config.modules?.[module.id]?.enabled ?? false}
|
||||
label={t('descriptor.name', {
|
||||
defaultValue: 'Unknown',
|
||||
})}
|
||||
onChange={(e) => {
|
||||
setConfig({
|
||||
...config,
|
||||
modules: {
|
||||
...config.modules,
|
||||
[module.id]: {
|
||||
...config.modules?.[module.id],
|
||||
enabled: e.currentTarget.checked,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Popover.Target>
|
||||
<Popover.Dropdown>
|
||||
<Text weight="bold">{translationModules('descriptor.name')}</Text>
|
||||
<Text>{translationModules('descriptor.description')}</Text>
|
||||
</Popover.Dropdown>
|
||||
</Popover>
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</HoverCard.Target>
|
||||
<HoverCard.Dropdown>
|
||||
<Title order={4}>{t('descriptor.name')}</Title>
|
||||
<Text size="sm">{t('descriptor.description')}</Text>
|
||||
</HoverCard.Dropdown>
|
||||
</HoverCard>
|
||||
);
|
||||
};
|
||||
|
||||
2
src/modules/ModuleTypes.d.ts
vendored
2
src/modules/ModuleTypes.d.ts
vendored
@@ -6,11 +6,11 @@ import { TablerIcon } from '@tabler/icons';
|
||||
|
||||
// Note: Maybe use context to keep track of the modules
|
||||
export interface IModule {
|
||||
id: string;
|
||||
title: string;
|
||||
icon: TablerIcon;
|
||||
component: React.ComponentType;
|
||||
options?: Option;
|
||||
translationNamespace: string;
|
||||
}
|
||||
|
||||
interface Option {
|
||||
|
||||
@@ -34,7 +34,7 @@ export const CalendarModule: IModule = {
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
translationNamespace: 'modules/calendar-module',
|
||||
id: 'calendar',
|
||||
};
|
||||
|
||||
export default function CalendarComponent(props: any) {
|
||||
@@ -127,7 +127,7 @@ export default function CalendarComponent(props: any) {
|
||||
}, [config.services]);
|
||||
|
||||
const weekStartsAtSunday =
|
||||
(config?.modules?.[CalendarModule.title]?.options?.sundaystart?.value as boolean) ?? false;
|
||||
(config?.modules?.[CalendarModule.id]?.options?.sundaystart?.value as boolean) ?? false;
|
||||
return (
|
||||
<Calendar
|
||||
firstDayOfWeek={weekStartsAtSunday ? 'sunday' : 'monday'}
|
||||
|
||||
@@ -160,7 +160,7 @@ export function SonarrMediaDisplay(props: any) {
|
||||
export function MediaDisplay({ media }: { media: IMedia }) {
|
||||
const [opened, setOpened] = useState(false);
|
||||
const { secondaryColor } = useColorTheme();
|
||||
const { t } = useTranslation('modules/common-media-cards-module');
|
||||
const { t } = useTranslation('modules/common-media-cards');
|
||||
|
||||
return (
|
||||
<Group mr="xs" align="stretch" noWrap style={{ maxHeight: 200 }}>
|
||||
|
||||
@@ -41,7 +41,7 @@ export const DashdotModule = asModule({
|
||||
value: '',
|
||||
},
|
||||
},
|
||||
translationNamespace: 'modules/dashdot-module',
|
||||
id: 'dashdot',
|
||||
});
|
||||
|
||||
const useStyles = createStyles((theme, _params) => ({
|
||||
@@ -126,7 +126,7 @@ export function DashdotComponent() {
|
||||
const { classes } = useStyles();
|
||||
const { colorScheme } = useMantineColorScheme();
|
||||
|
||||
const dashConfig = config.modules?.[DashdotModule.title]
|
||||
const dashConfig = config.modules?.[DashdotModule.id]
|
||||
.options as typeof DashdotModule['options'];
|
||||
const isCompact = dashConfig?.useCompactView?.value ?? false;
|
||||
const dashdotService: serviceItem | undefined = config.services.filter(
|
||||
@@ -148,7 +148,7 @@ export function DashdotComponent() {
|
||||
const totalSize =
|
||||
(info?.storage?.layout as any[])?.reduce((acc, curr) => (curr.size ?? 0) + acc, 0) ?? 0;
|
||||
|
||||
const { t } = useTranslation('modules/dashdot-module');
|
||||
const { t } = useTranslation('modules/dashdot');
|
||||
|
||||
const graphs = [
|
||||
{
|
||||
|
||||
@@ -16,14 +16,14 @@ export const DateModule: IModule = {
|
||||
value: true,
|
||||
},
|
||||
},
|
||||
translationNamespace: 'modules/date-module',
|
||||
id: 'date',
|
||||
};
|
||||
|
||||
export default function DateComponent(props: any) {
|
||||
const [date, setDate] = useState(new Date());
|
||||
const setSafeInterval = useSetSafeInterval();
|
||||
const { config } = useConfig();
|
||||
const isFullTime = config?.modules?.[DateModule.title]?.options?.full?.value ?? true;
|
||||
const isFullTime = config?.modules?.[DateModule.id]?.options?.full?.value ?? true;
|
||||
const formatString = isFullTime ? 'HH:mm' : 'h:mm A';
|
||||
// Change date on minute change
|
||||
// Note: Using 10 000ms instead of 1000ms to chill a little :)
|
||||
|
||||
@@ -22,7 +22,7 @@ function sendDockerCommand(
|
||||
containerName: string,
|
||||
reload: () => void
|
||||
) {
|
||||
const { t } = useTranslation('modules/docker-module');
|
||||
const { t } = useTranslation('modules/docker');
|
||||
|
||||
showNotification({
|
||||
id: containerId,
|
||||
@@ -64,7 +64,7 @@ export interface ContainerActionBarProps {
|
||||
|
||||
export default function ContainerActionBar({ selected, reload }: ContainerActionBarProps) {
|
||||
const [opened, setOpened] = useState<boolean>(false);
|
||||
const { t } = useTranslation('modules/docker-module');
|
||||
const { t } = useTranslation('modules/docker');
|
||||
|
||||
return (
|
||||
<Group>
|
||||
|
||||
@@ -9,7 +9,7 @@ export interface ContainerStateProps {
|
||||
export default function ContainerState(props: ContainerStateProps) {
|
||||
const { state } = props;
|
||||
|
||||
const { t } = useTranslation('modules/docker-module');
|
||||
const { t } = useTranslation('modules/docker');
|
||||
|
||||
const options: {
|
||||
size: MantineSize;
|
||||
|
||||
@@ -15,7 +15,7 @@ export const DockerModule: IModule = {
|
||||
title: 'Docker',
|
||||
icon: IconBrandDocker,
|
||||
component: DockerMenuButton,
|
||||
translationNamespace: 'modules/docker-module',
|
||||
id: 'docker',
|
||||
};
|
||||
|
||||
export default function DockerMenuButton(props: any) {
|
||||
@@ -23,9 +23,9 @@ export default function DockerMenuButton(props: any) {
|
||||
const [containers, setContainers] = useState<Docker.ContainerInfo[]>([]);
|
||||
const [selection, setSelection] = useState<Docker.ContainerInfo[]>([]);
|
||||
const { config } = useConfig();
|
||||
const moduleEnabled = config.modules?.[DockerModule.title]?.enabled ?? false;
|
||||
const moduleEnabled = config.modules?.[DockerModule.id]?.enabled ?? false;
|
||||
|
||||
const { t } = useTranslation('modules/docker-module');
|
||||
const { t } = useTranslation('modules/docker');
|
||||
|
||||
useEffect(() => {
|
||||
reload();
|
||||
@@ -54,7 +54,7 @@ export default function DockerMenuButton(props: any) {
|
||||
);
|
||||
}, 300);
|
||||
}
|
||||
const exists = config.modules?.[DockerModule.title]?.enabled ?? false;
|
||||
const exists = config.modules?.[DockerModule.id]?.enabled ?? false;
|
||||
if (!exists) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ export default function DockerTable({
|
||||
const { classes, cx } = useStyles();
|
||||
const [search, setSearch] = useState('');
|
||||
|
||||
const { t } = useTranslation('modules/docker-module');
|
||||
const { t } = useTranslation('modules/docker');
|
||||
|
||||
useEffect(() => {
|
||||
setContainers(containers);
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
Skeleton,
|
||||
ScrollArea,
|
||||
Center,
|
||||
Stack,
|
||||
} from '@mantine/core';
|
||||
import { IconDownload as Download } from '@tabler/icons';
|
||||
import { useEffect, useState } from 'react';
|
||||
@@ -32,7 +33,7 @@ export const DownloadsModule: IModule = {
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
translationNamespace: 'modules/downloads-module',
|
||||
id: 'torrents-status',
|
||||
};
|
||||
|
||||
export default function DownloadComponent() {
|
||||
@@ -46,12 +47,12 @@ export default function DownloadComponent() {
|
||||
service.type === 'Deluge'
|
||||
) ?? [];
|
||||
const hideComplete: boolean =
|
||||
(config?.modules?.[DownloadsModule.title]?.options?.hidecomplete?.value as boolean) ?? false;
|
||||
(config?.modules?.[DownloadsModule.id]?.options?.hidecomplete?.value as boolean) ?? false;
|
||||
const [torrents, setTorrents] = useState<NormalizedTorrent[]>([]);
|
||||
const setSafeInterval = useSetSafeInterval();
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
const { t } = useTranslation('modules/downloads-module');
|
||||
const { t } = useTranslation(`modules/${DownloadsModule.id}`);
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true);
|
||||
@@ -85,13 +86,13 @@ export default function DownloadComponent() {
|
||||
|
||||
if (downloadServices.length === 0) {
|
||||
return (
|
||||
<Group>
|
||||
<Stack>
|
||||
<Title order={3}>{t('card.errors.noDownloadClients.title')}</Title>
|
||||
<Group>
|
||||
<Text>{t('card.errors.noDownloadClients.text')}</Text>
|
||||
<AddItemShelfButton />
|
||||
</Group>
|
||||
</Group>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ export const TotalDownloadsModule: IModule = {
|
||||
title: 'Download Speed',
|
||||
icon: Download,
|
||||
component: TotalDownloadsComponent,
|
||||
translationNamespace: 'modules/total-downloads-module',
|
||||
id: 'dlspeed',
|
||||
};
|
||||
|
||||
interface torrentHistory {
|
||||
@@ -37,7 +37,7 @@ export default function TotalDownloadsComponent() {
|
||||
service.type === 'Transmission' ||
|
||||
service.type === 'Deluge'
|
||||
) ?? [];
|
||||
const { t } = useTranslation('modules/downloads-module');
|
||||
const { t } = useTranslation(`modules/${TotalDownloadsModule.id}`);
|
||||
|
||||
const [torrentHistory, torrentHistoryHandlers] = useListState<torrentHistory>([]);
|
||||
const [torrents, setTorrents] = useState<NormalizedTorrent[]>([]);
|
||||
|
||||
@@ -18,7 +18,7 @@ import { IModule } from './ModuleTypes';
|
||||
|
||||
function getItems(module: IModule) {
|
||||
const { config, setConfig } = useConfig();
|
||||
const { t } = useTranslation(module.translationNamespace);
|
||||
const { t } = useTranslation([module.id, 'common']);
|
||||
|
||||
const items: JSX.Element[] = [];
|
||||
if (module.options) {
|
||||
@@ -28,8 +28,8 @@ function getItems(module: IModule) {
|
||||
const types = values.map((v) => typeof v.value);
|
||||
// Loop over all the types with a for each loop
|
||||
types.forEach((type, index) => {
|
||||
const optionName = `${module.title}.${keys[index]}`;
|
||||
const moduleInConfig = config.modules?.[module.title];
|
||||
const optionName = `${module.id}.${keys[index]}`;
|
||||
const moduleInConfig = config.modules?.[module.id];
|
||||
if (type === 'object') {
|
||||
items.push(
|
||||
<MultiSelect
|
||||
@@ -46,7 +46,7 @@ function getItems(module: IModule) {
|
||||
...config,
|
||||
modules: {
|
||||
...config.modules,
|
||||
[module.title]: {
|
||||
[module.id]: {
|
||||
...moduleInConfig,
|
||||
options: {
|
||||
...moduleInConfig?.options,
|
||||
@@ -71,12 +71,12 @@ function getItems(module: IModule) {
|
||||
...config,
|
||||
modules: {
|
||||
...config.modules,
|
||||
[module.title]: {
|
||||
...config.modules[module.title],
|
||||
[module.id]: {
|
||||
...config.modules[module.id],
|
||||
options: {
|
||||
...config.modules[module.title].options,
|
||||
...config.modules[module.id].options,
|
||||
[keys[index]]: {
|
||||
...config.modules[module.title].options?.[keys[index]],
|
||||
...config.modules[module.id].options?.[keys[index]],
|
||||
value: (e.target as any)[0].value,
|
||||
},
|
||||
},
|
||||
@@ -99,7 +99,7 @@ function getItems(module: IModule) {
|
||||
onChange={(e) => {}}
|
||||
/>
|
||||
|
||||
<Button type="submit">Save</Button>
|
||||
<Button type="submit">{t('actions.save')}</Button>
|
||||
</Group>
|
||||
</form>
|
||||
);
|
||||
@@ -120,12 +120,12 @@ function getItems(module: IModule) {
|
||||
...config,
|
||||
modules: {
|
||||
...config.modules,
|
||||
[module.title]: {
|
||||
...config.modules[module.title],
|
||||
[module.id]: {
|
||||
...config.modules[module.id],
|
||||
options: {
|
||||
...config.modules[module.title].options,
|
||||
...config.modules[module.id].options,
|
||||
[keys[index]]: {
|
||||
...config.modules[module.title].options?.[keys[index]],
|
||||
...config.modules[module.id].options?.[keys[index]],
|
||||
value: e.currentTarget.checked,
|
||||
},
|
||||
},
|
||||
@@ -148,7 +148,7 @@ export function ModuleWrapper(props: any) {
|
||||
const { config, setConfig } = useConfig();
|
||||
const enabledModules = config.modules ?? {};
|
||||
// Remove 'Module' from enabled modules titles
|
||||
const isShown = enabledModules[module.title]?.enabled ?? false;
|
||||
const isShown = enabledModules[module.id]?.enabled ?? false;
|
||||
//TODO: fix the hover problem
|
||||
const [hovering, setHovering] = useState(false);
|
||||
const { t } = useTranslation('modules');
|
||||
@@ -160,7 +160,7 @@ export function ModuleWrapper(props: any) {
|
||||
return (
|
||||
<Card
|
||||
{...props}
|
||||
key={module.title}
|
||||
key={module.id}
|
||||
hidden={!isShown}
|
||||
withBorder
|
||||
radius="lg"
|
||||
@@ -195,7 +195,7 @@ export function ModuleMenu(props: any) {
|
||||
<>
|
||||
{module.options && (
|
||||
<Menu
|
||||
key={module.title}
|
||||
key={module.id}
|
||||
withinPortal
|
||||
width="lg"
|
||||
shadow="xl"
|
||||
|
||||
@@ -6,7 +6,7 @@ export const OverseerrModule: IModule = {
|
||||
title: 'Overseerr',
|
||||
icon: IconEyeglass,
|
||||
component: OverseerrMediaDisplay,
|
||||
translationNamespace: 'modules/overseerr-module',
|
||||
id: 'overseerr',
|
||||
};
|
||||
|
||||
export interface OverseerSearchProps {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useColorTheme } from '../../tools/color';
|
||||
import { MovieResult } from './Movie.d';
|
||||
import { MediaType, Result } from './SearchResult.d';
|
||||
import { TvShowResult, TvShowResultSeason } from './TvShow.d';
|
||||
|
||||
interface RequestModalProps {
|
||||
base: Result;
|
||||
opened: boolean;
|
||||
@@ -57,7 +58,7 @@ export function MovieRequestModal({
|
||||
setOpened: (opened: boolean) => void;
|
||||
}) {
|
||||
const { secondaryColor } = useColorTheme();
|
||||
const { t } = useTranslation('modules/overseerr-module');
|
||||
const { t } = useTranslation('modules/overseerr');
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@@ -114,7 +115,7 @@ export function TvRequestModal({
|
||||
}) {
|
||||
const [selection, setSelection] = useState<TvShowResultSeason[]>(result.seasons);
|
||||
const { classes, cx } = useStyles();
|
||||
const { t } = useTranslation('modules/overseerr-module');
|
||||
const { t } = useTranslation('modules/overseerr');
|
||||
|
||||
const toggleRow = (container: TvShowResultSeason) =>
|
||||
setSelection((current: TvShowResultSeason[]) =>
|
||||
|
||||
@@ -11,7 +11,7 @@ export const PingModule: IModule = {
|
||||
title: 'Ping Services',
|
||||
icon: Plug,
|
||||
component: PingComponent,
|
||||
translationNamespace: 'modules/ping-module',
|
||||
id: 'ping',
|
||||
};
|
||||
|
||||
export default function PingComponent(props: any) {
|
||||
@@ -21,9 +21,9 @@ export default function PingComponent(props: any) {
|
||||
const { url }: { url: string } = props;
|
||||
const [isOnline, setOnline] = useState<State>('loading');
|
||||
const [response, setResponse] = useState(500);
|
||||
const exists = config.modules?.[PingModule.title]?.enabled ?? false;
|
||||
const exists = config.modules?.[PingModule.id]?.enabled ?? false;
|
||||
|
||||
const { t } = useTranslation('modules/ping-module');
|
||||
const { t } = useTranslation('modules/ping');
|
||||
|
||||
function statusCheck(response: AxiosResponse) {
|
||||
const { status }: { status: string[] } = props;
|
||||
@@ -54,7 +54,7 @@ export default function PingComponent(props: any) {
|
||||
.catch((error) => {
|
||||
statusCheck(error.response);
|
||||
});
|
||||
}, [config.modules?.[PingModule.title]?.enabled]);
|
||||
}, [config.modules?.[PingModule.id]?.enabled]);
|
||||
if (!exists) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -30,15 +30,15 @@ export const SearchModule: IModule = {
|
||||
title: 'Search',
|
||||
icon: Search,
|
||||
component: SearchBar,
|
||||
translationNamespace: 'modules/search-module',
|
||||
id: 'search',
|
||||
};
|
||||
|
||||
export default function SearchBar(props: any) {
|
||||
const { classes, cx } = useStyles();
|
||||
// Config
|
||||
const { config } = useConfig();
|
||||
const isModuleEnabled = config.modules?.[SearchModule.title]?.enabled ?? false;
|
||||
const isOverseerrEnabled = config.modules?.[OverseerrModule.title]?.enabled ?? false;
|
||||
const isModuleEnabled = config.modules?.[SearchModule.id]?.enabled ?? false;
|
||||
const isOverseerrEnabled = config.modules?.[OverseerrModule.id]?.enabled ?? false;
|
||||
const OverseerrService = config.services.find(
|
||||
(service) => service.type === 'Overseerr' || service.type === 'Jellyseerr'
|
||||
);
|
||||
@@ -60,7 +60,7 @@ export default function SearchBar(props: any) {
|
||||
},
|
||||
});
|
||||
const [debounced, cancel] = useDebouncedValue(form.values.query, 250);
|
||||
const { t } = useTranslation('modules/search-module');
|
||||
const { t } = useTranslation('modules/search');
|
||||
|
||||
useEffect(() => {
|
||||
if (OverseerrService === undefined && isOverseerrEnabled) {
|
||||
|
||||
@@ -32,7 +32,7 @@ export const WeatherModule: IModule = {
|
||||
value: 'Paris',
|
||||
},
|
||||
},
|
||||
translationNamespace: 'modules/weather-module',
|
||||
id: 'weather',
|
||||
};
|
||||
|
||||
// 0 Clear sky
|
||||
@@ -49,7 +49,7 @@ export const WeatherModule: IModule = {
|
||||
// 95 *Thunderstorm: Slight or moderate
|
||||
// 96, 99 *Thunderstorm with slight and heavy hail
|
||||
export function WeatherIcon(props: any) {
|
||||
const { t } = useTranslation('modules/weather-module');
|
||||
const { t } = useTranslation('modules/weather');
|
||||
|
||||
const { code } = props;
|
||||
let data: { icon: any; name: string };
|
||||
@@ -146,9 +146,9 @@ export default function WeatherComponent(props: any) {
|
||||
const { config } = useConfig();
|
||||
const [weather, setWeather] = useState({} as WeatherResponse);
|
||||
const cityInput: string =
|
||||
(config?.modules?.[WeatherModule.title]?.options?.location?.value as string) ?? 'Paris';
|
||||
(config?.modules?.[WeatherModule.id]?.options?.location?.value as string) ?? 'Paris';
|
||||
const isFahrenheit: boolean =
|
||||
(config?.modules?.[WeatherModule.title]?.options?.freedomunit?.value as boolean) ?? false;
|
||||
(config?.modules?.[WeatherModule.id]?.options?.freedomunit?.value as boolean) ?? false;
|
||||
|
||||
useEffect(() => {
|
||||
axios
|
||||
|
||||
@@ -10,6 +10,8 @@ import {
|
||||
} from '@mantine/core';
|
||||
import { NextLink } from '@mantine/next';
|
||||
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
||||
|
||||
const useStyles = createStyles((theme) => ({
|
||||
root: {
|
||||
paddingTop: 80,
|
||||
@@ -92,3 +94,12 @@ export default function Custom404() {
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export async function getStaticProps({ locale }: { locale: string }) {
|
||||
return {
|
||||
props: {
|
||||
...(await serverSideTranslations(locale, ['404'])),
|
||||
// Will be passed to the page component as props
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,18 +17,19 @@ export async function getServerSideProps({
|
||||
res,
|
||||
locale,
|
||||
}: GetServerSidePropsContext): Promise<{ props: { config: Config } }> {
|
||||
let cookie = getCookie('config-name', { req, res });
|
||||
if (!cookie) {
|
||||
let configName = getCookie('config-name', { req, res });
|
||||
const configLocale = getCookie('config-locale', { req, res });
|
||||
if (!configName) {
|
||||
setCookie('config-name', 'default', {
|
||||
req,
|
||||
res,
|
||||
maxAge: 60 * 60 * 24 * 30,
|
||||
sameSite: 'strict',
|
||||
});
|
||||
cookie = 'default';
|
||||
configName = 'default';
|
||||
}
|
||||
|
||||
const translations = await serverSideTranslations(locale as string, [
|
||||
const translations = await serverSideTranslations((configLocale ?? locale) as string, [
|
||||
'common',
|
||||
'layout/app-shelf',
|
||||
'layout/add-service-app-shelf',
|
||||
@@ -46,19 +47,19 @@ export async function getServerSideProps({
|
||||
'settings/customization/app-width',
|
||||
'settings/customization/opacity-selector',
|
||||
'modules/common',
|
||||
'modules/date-module',
|
||||
'modules/calendar-module',
|
||||
'modules/total-downloads-module',
|
||||
'modules/search-module',
|
||||
'modules/downloads-module',
|
||||
'modules/weather-module',
|
||||
'modules/ping-module',
|
||||
'modules/docker-module',
|
||||
'modules/dashdot-module',
|
||||
'modules/overseerr-module',
|
||||
'modules/common-media-cards-module',
|
||||
'modules/date',
|
||||
'modules/calendar',
|
||||
'modules/dlspeed',
|
||||
'modules/search',
|
||||
'modules/torrents-status',
|
||||
'modules/weather',
|
||||
'modules/ping',
|
||||
'modules/docker',
|
||||
'modules/dashdot',
|
||||
'modules/overseerr',
|
||||
'modules/common-media-cards',
|
||||
]);
|
||||
return getConfig(cookie as string, translations);
|
||||
return getConfig(configName as string, translations);
|
||||
}
|
||||
|
||||
export default function HomePage(props: any) {
|
||||
|
||||
Reference in New Issue
Block a user