mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-12 16:35:49 +01:00
🚧 wip extract to translations file
This commit is contained in:
@@ -23,16 +23,16 @@ import {
|
||||
} from '../common';
|
||||
import { serviceItem } from '../../tools/types';
|
||||
import { useColorTheme } from '../../tools/color';
|
||||
import { t } from 'i18next';
|
||||
|
||||
export const CalendarModule: IModule = {
|
||||
title: 'Calendar',
|
||||
description:
|
||||
'A calendar module for displaying upcoming releases. It interacts with the Sonarr and Radarr API.',
|
||||
title: t('modules.calendar.title'),
|
||||
description: t('modules.calendar.description'),
|
||||
icon: CalendarIcon,
|
||||
component: CalendarComponent,
|
||||
options: {
|
||||
sundaystart: {
|
||||
name: 'Start the week on Sunday',
|
||||
name: t('modules.calendar.options.sundayStart'),
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Badge, Button, Group, Image, Stack, Text, Title } from '@mantine/core';
|
||||
import { IconDownload, IconExternalLink, IconPlayerPlay } from '@tabler/icons';
|
||||
import { t } from 'i18next';
|
||||
import { useState } from 'react';
|
||||
import { useColorTheme } from '../../tools/color';
|
||||
import { useConfig } from '../../tools/state';
|
||||
@@ -209,7 +210,7 @@ export function MediaDisplay({ media }: { media: IMedia }) {
|
||||
size="sm"
|
||||
rightIcon={<IconPlayerPlay size={15} />}
|
||||
>
|
||||
Play
|
||||
{t('modules.common.mediaCard.buttons.play')}
|
||||
</Button>
|
||||
)}
|
||||
{media.imdbId && (
|
||||
@@ -249,7 +250,7 @@ export function MediaDisplay({ media }: { media: IMedia }) {
|
||||
size="sm"
|
||||
rightIcon={<IconDownload size={15} />}
|
||||
>
|
||||
Request
|
||||
{t('modules.common.mediaCard.buttons.request')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createStyles, Stack, Title, useMantineColorScheme, useMantineTheme } from '@mantine/core';
|
||||
import { IconCalendar as CalendarIcon } from '@tabler/icons';
|
||||
import axios from 'axios';
|
||||
import { t } from 'i18next';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useConfig } from '../../tools/state';
|
||||
import { serviceItem } from '../../tools/types';
|
||||
@@ -143,30 +144,30 @@ export function DashdotComponent() {
|
||||
|
||||
const graphs = [
|
||||
{
|
||||
name: 'CPU',
|
||||
name: t('modules.dashDot.card.graphs.cpu.title'),
|
||||
enabled: cpuEnabled,
|
||||
params: {
|
||||
multiView: dashConfig?.cpuMultiView?.value ?? false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Storage',
|
||||
name: t('modules.dashDot.card.graphs.cpu.title'),
|
||||
enabled: storageEnabled && !isCompact,
|
||||
params: {
|
||||
multiView: dashConfig?.storageMultiView?.value ?? false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'RAM',
|
||||
name: t('modules.dashDot.card.graphs.memory.title'),
|
||||
enabled: ramEnabled,
|
||||
},
|
||||
{
|
||||
name: 'Network',
|
||||
name: t('modules.dashDot.card.graphs.network.title'),
|
||||
enabled: networkEnabled,
|
||||
spanTwo: true,
|
||||
},
|
||||
{
|
||||
name: 'GPU',
|
||||
name: t('modules.dashDot.card.graphs.gpu.title'),
|
||||
enabled: gpuEnabled,
|
||||
spanTwo: true,
|
||||
},
|
||||
@@ -175,27 +176,26 @@ export function DashdotComponent() {
|
||||
if (dashdotUrl === '') {
|
||||
return (
|
||||
<div>
|
||||
<h2 className={classes.heading}>Dash.</h2>
|
||||
<p>
|
||||
No dash. service found. Please add one to your Homarr dashboard or set a dashdot URL in
|
||||
the module options
|
||||
</p>
|
||||
<h2 className={classes.heading}>{t('modules.dashDot.card.title')}</h2>
|
||||
<p>{t('modules.dashDot.card.errors.noService')}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 className={classes.heading}>Dash.</h2>
|
||||
<h2 className={classes.heading}>{t('modules.dashDot.card.title')}</h2>
|
||||
|
||||
{!info ? (
|
||||
<p>Cannot acquire information from dash. - are you running the latest version?</p>
|
||||
<p>{t('modules.dashDot.card.errors.noInformation')}</p>
|
||||
) : (
|
||||
<div className={classes.graphsContainer}>
|
||||
<div className={classes.table}>
|
||||
{storageEnabled && isCompact && (
|
||||
<div className={classes.tableRow}>
|
||||
<p className={classes.tableLabel}>Storage:</p>
|
||||
<p className={classes.tableLabel}>
|
||||
{t('modules.dashDot.card.graphs.storage.label')}
|
||||
</p>
|
||||
<p className={classes.tableValue}>
|
||||
{((100 * totalUsed) / (totalSize || 1)).toFixed(1)}%{'\n'}
|
||||
{bytePrettyPrint(totalUsed)} / {bytePrettyPrint(totalSize)}
|
||||
@@ -204,10 +204,15 @@ export function DashdotComponent() {
|
||||
)}
|
||||
{networkEnabled && (
|
||||
<div className={classes.tableRow}>
|
||||
<p className={classes.tableLabel}>Network:</p>
|
||||
<p className={classes.tableLabel}>
|
||||
{t('modules.dashDot.card.graphs.network.label')}
|
||||
</p>
|
||||
<p className={classes.tableValue}>
|
||||
{bpsPrettyPrint(info?.network?.speedUp)} Up{'\n'}
|
||||
{bpsPrettyPrint(info?.network?.speedDown)} Down
|
||||
{bpsPrettyPrint(info?.network?.speedUp)}{' '}
|
||||
{t('modules.dashDot.card.graphs.network.metrics.upload')}
|
||||
{'\n'}
|
||||
{bpsPrettyPrint(info?.network?.speedDown)}
|
||||
{t('modules.dashDot.card.graphs.network.metrics.download')}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -4,6 +4,8 @@ import { useEffect, useState } from 'react';
|
||||
import Docker from 'dockerode';
|
||||
import { IconBrandDocker, IconX } from '@tabler/icons';
|
||||
import { showNotification } from '@mantine/notifications';
|
||||
import { t } from 'i18next';
|
||||
|
||||
import ContainerActionBar from './ContainerActionBar';
|
||||
import DockerTable from './DockerTable';
|
||||
import { useConfig } from '../../tools/state';
|
||||
@@ -42,10 +44,10 @@ export default function DockerMenuButton(props: any) {
|
||||
// Send an Error notification
|
||||
showNotification({
|
||||
autoClose: 1500,
|
||||
title: <Text>Docker integration failed</Text>,
|
||||
title: <Text>{t('layout.header.docker.errors.integrationFailed.title')}</Text>,
|
||||
color: 'red',
|
||||
icon: <IconX />,
|
||||
message: 'Did you forget to mount the docker socket ?',
|
||||
message: t('layout.header.docker.errors.integrationFailed.message'),
|
||||
})
|
||||
);
|
||||
}, 300);
|
||||
@@ -67,7 +69,7 @@ export default function DockerMenuButton(props: any) {
|
||||
>
|
||||
<DockerTable containers={containers} selection={selection} setSelection={setSelection} />
|
||||
</Drawer>
|
||||
<Tooltip label="Docker">
|
||||
<Tooltip label={t('layout.header.docker.actionIcon.tooltip')}>
|
||||
<ActionIcon
|
||||
variant="default"
|
||||
radius="md"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Table, Checkbox, Group, Badge, createStyles, ScrollArea, TextInput } from '@mantine/core';
|
||||
import { IconSearch } from '@tabler/icons';
|
||||
import { t } from 'i18next';
|
||||
|
||||
import Dockerode from 'dockerode';
|
||||
import { useEffect, useState } from 'react';
|
||||
import ContainerState from './ContainerState';
|
||||
@@ -80,7 +82,9 @@ export default function DockerTable({
|
||||
</Badge>
|
||||
))}
|
||||
{element.Ports.length > 3 && (
|
||||
<Badge variant="filled">{element.Ports.length - 3} more</Badge>
|
||||
<Badge variant="filled">
|
||||
{t('modules.docker.table.body.portCollapse', { ports: element.Ports.length - 3 })}
|
||||
</Badge>
|
||||
)}
|
||||
</Group>
|
||||
</td>
|
||||
@@ -94,7 +98,7 @@ export default function DockerTable({
|
||||
return (
|
||||
<ScrollArea style={{ height: '80vh' }}>
|
||||
<TextInput
|
||||
placeholder="Search by container or image name"
|
||||
placeholder={t('modules.docker.search.placeholder')}
|
||||
mt="md"
|
||||
icon={<IconSearch size={14} />}
|
||||
value={search}
|
||||
@@ -111,10 +115,10 @@ export default function DockerTable({
|
||||
transitionDuration={0}
|
||||
/>
|
||||
</th>
|
||||
<th>Name</th>
|
||||
<th>Image</th>
|
||||
<th>Ports</th>
|
||||
<th>State</th>
|
||||
<th>{t('modules.docker.table.header.name')}</th>
|
||||
<th>{t('modules.docker.table.header.image')}</th>
|
||||
<th>{t('modules.docker.table.header.ports')}</th>
|
||||
<th>{t('modules.docker.table.header.state')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>{rows}</tbody>
|
||||
|
||||
@@ -20,6 +20,7 @@ import { useConfig } from '../../tools/state';
|
||||
import { AddItemShelfButton } from '../../components/AppShelf/AddAppShelfItem';
|
||||
import { useSetSafeInterval } from '../../tools/hooks/useSetSafeInterval';
|
||||
import { humanFileSize } from '../../tools/humanFileSize';
|
||||
import { t } from 'i18next';
|
||||
|
||||
export const DownloadsModule: IModule = {
|
||||
title: 'Torrent',
|
||||
@@ -105,12 +106,12 @@ export default function DownloadComponent() {
|
||||
const DEVICE_WIDTH = 576;
|
||||
const ths = (
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Size</th>
|
||||
{width > 576 ? <th>Down</th> : ''}
|
||||
{width > 576 ? <th>Up</th> : ''}
|
||||
<th>ETA</th>
|
||||
<th>Progress</th>
|
||||
<th>{t('modules.downloads.card.table.header.name')}</th>
|
||||
<th>{t('modules.downloads.card.table.header.size')}</th>
|
||||
{width > 576 ? <th>{t('modules.downloads.card.table.header.download')}</th> : ''}
|
||||
{width > 576 ? <th>{t('modules.downloads.card.table.header.upload')}</th> : ''}
|
||||
<th>{t('modules.downloads.card.table.header.estimatedTimeOfArrival')}</th>
|
||||
<th>{t('modules.downloads.card.table.header.progress')}</th>
|
||||
</tr>
|
||||
);
|
||||
// Convert Seconds to readable format.
|
||||
@@ -195,7 +196,7 @@ export default function DownloadComponent() {
|
||||
</Table>
|
||||
) : (
|
||||
<Center style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Title order={3}>No torrents found</Title>
|
||||
<Title order={3}>{t('modules.downloads.card.table.body.nothingFound')}</Title>
|
||||
</Center>
|
||||
)}
|
||||
</ScrollArea>
|
||||
|
||||
@@ -3,12 +3,13 @@ import { showNotification, updateNotification } from '@mantine/notifications';
|
||||
import { IconAlertCircle, IconCheck, IconDownload } from '@tabler/icons';
|
||||
import axios from 'axios';
|
||||
import Consola from 'consola';
|
||||
import { t } from 'i18next';
|
||||
|
||||
import { useState } from 'react';
|
||||
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;
|
||||
@@ -67,23 +68,23 @@ export function MovieRequestModal({
|
||||
title={
|
||||
<Group>
|
||||
<IconDownload />
|
||||
Ask for {result.title}
|
||||
{t('modules.overseerr.popup.item.buttons.askFor', { title: result.title })}
|
||||
</Group>
|
||||
}
|
||||
>
|
||||
<Stack>
|
||||
<Alert
|
||||
icon={<IconAlertCircle size={16} />}
|
||||
title="Using API key"
|
||||
title={t('modules.overseerr.popup.item.alerts.automaticApproval.title')}
|
||||
color={secondaryColor}
|
||||
radius="md"
|
||||
variant="filled"
|
||||
>
|
||||
This request will be automatically approved
|
||||
{t('modules.overseerr.popup.item.alerts.automaticApproval.text')}
|
||||
</Alert>
|
||||
<Group>
|
||||
<Button variant="outline" color="gray" onClick={() => setOpened(false)}>
|
||||
Cancel
|
||||
{t('modules.overseerr.popup.item.buttons.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
@@ -91,7 +92,7 @@ export function MovieRequestModal({
|
||||
askForMedia(MediaType.Movie, result.id, result.title, []);
|
||||
}}
|
||||
>
|
||||
Request
|
||||
{t('modules.overseerr.popup.item.buttons.request')}
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
@@ -148,22 +149,24 @@ export function TvRequestModal({
|
||||
title={
|
||||
<Group>
|
||||
<IconDownload />
|
||||
Ask for {result.name ?? result.originalName ?? 'a TV show'}
|
||||
{t('modules.overseerr.popup.item.buttons.askFor', {
|
||||
title: result.name ?? result.originalName ?? 'a TV show',
|
||||
})}
|
||||
</Group>
|
||||
}
|
||||
>
|
||||
<Stack>
|
||||
<Alert
|
||||
icon={<IconAlertCircle size={16} />}
|
||||
title="Using API key"
|
||||
title={t('modules.overseerr.popup.item.alerts.automaticApproval.title')}
|
||||
color={secondaryColor}
|
||||
radius="md"
|
||||
variant="filled"
|
||||
>
|
||||
This request will be automatically approved
|
||||
{t('modules.overseerr.popup.item.alerts.automaticApproval.text')}
|
||||
</Alert>
|
||||
<Table captionSide="bottom" highlightOnHover>
|
||||
<caption>Tick the seasons that you want to be downloaded</caption>
|
||||
<caption>{t('modules.overseerr.popup.seasonSelector.caption')}</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
@@ -174,15 +177,15 @@ export function TvRequestModal({
|
||||
transitionDuration={0}
|
||||
/>
|
||||
</th>
|
||||
<th>Season</th>
|
||||
<th>Number of episodes</th>
|
||||
<th>{t('modules.overseerr.popup.seasonSelector.table.header.season')}</th>
|
||||
<th>{t('modules.overseerr.popup.seasonSelector.table.header.numberOfEpisodes')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>{rows}</tbody>
|
||||
</Table>
|
||||
<Group>
|
||||
<Button variant="outline" color="gray" onClick={() => setOpened(false)}>
|
||||
Cancel
|
||||
{t('modules.overseerr.popup.item.buttons.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
@@ -196,7 +199,7 @@ export function TvRequestModal({
|
||||
);
|
||||
}}
|
||||
>
|
||||
Request
|
||||
{t('modules.overseerr.popup.item.buttons.request')}
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useEffect, useState } from 'react';
|
||||
import { IconPlug as Plug } from '@tabler/icons';
|
||||
import { useConfig } from '../../tools/state';
|
||||
import { IModule } from '../ModuleTypes';
|
||||
import { t } from 'i18next';
|
||||
|
||||
export const PingModule: IModule = {
|
||||
title: 'Ping Services',
|
||||
@@ -68,10 +69,10 @@ export default function PingComponent(props: any) {
|
||||
radius="lg"
|
||||
label={
|
||||
isOnline === 'loading'
|
||||
? 'Loading...'
|
||||
? t('modules.ping.states.loading')
|
||||
: isOnline === 'online'
|
||||
? `Online - ${response}`
|
||||
: `Offline - ${response}`
|
||||
? t('modules.ping.states.online', { response })
|
||||
: t('modules.ping.states.offline', { response })
|
||||
}
|
||||
>
|
||||
<Indicator
|
||||
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
IconDownload as Download,
|
||||
IconMovie,
|
||||
} from '@tabler/icons';
|
||||
import { t } from 'i18next';
|
||||
|
||||
import axios from 'axios';
|
||||
import { showNotification } from '@mantine/notifications';
|
||||
import { useConfig } from '../../tools/state';
|
||||
@@ -175,7 +177,7 @@ export default function SearchBar(props: any) {
|
||||
radius="md"
|
||||
size="md"
|
||||
styles={{ rightSection: { pointerEvents: 'none' } }}
|
||||
placeholder="Search the web..."
|
||||
placeholder={t('layout.header.search.input.placeholder')}
|
||||
{...props}
|
||||
{...form.getInputProps('query')}
|
||||
/>
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
import { useConfig } from '../../tools/state';
|
||||
import { IModule } from '../ModuleTypes';
|
||||
import { WeatherResponse } from './WeatherInterface';
|
||||
import { t } from 'i18next';
|
||||
|
||||
export const WeatherModule: IModule = {
|
||||
title: 'Weather',
|
||||
@@ -52,75 +53,81 @@ export function WeatherIcon(props: any) {
|
||||
let data: { icon: any; name: string };
|
||||
switch (code) {
|
||||
case 0: {
|
||||
data = { icon: Sun, name: 'Clear' };
|
||||
data = { icon: Sun, name: t('modules.weather.card.weatherDescriptions.clear') };
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
case 2:
|
||||
case 3: {
|
||||
data = { icon: Cloud, name: 'Mainly clear' };
|
||||
data = { icon: Cloud, name: t('modules.weather.card.weatherDescriptions.mainlyClear') };
|
||||
break;
|
||||
}
|
||||
case 45:
|
||||
case 48: {
|
||||
data = { icon: CloudFog, name: 'Fog' };
|
||||
data = { icon: CloudFog, name: t('modules.weather.card.weatherDescriptions.fog') };
|
||||
break;
|
||||
}
|
||||
case 51:
|
||||
case 53:
|
||||
case 55: {
|
||||
data = { icon: Cloud, name: 'Drizzle' };
|
||||
data = { icon: Cloud, name: t('modules.weather.card.weatherDescriptions.drizzle') };
|
||||
break;
|
||||
}
|
||||
case 56:
|
||||
case 57: {
|
||||
data = { icon: Snowflake, name: 'Freezing drizzle' };
|
||||
data = {
|
||||
icon: Snowflake,
|
||||
name: t('modules.weather.card.weatherDescriptions.freezingDrizzle'),
|
||||
};
|
||||
break;
|
||||
}
|
||||
case 61:
|
||||
case 63:
|
||||
case 65: {
|
||||
data = { icon: CloudRain, name: 'Rain' };
|
||||
data = { icon: CloudRain, name: t('modules.weather.card.weatherDescriptions.rain') };
|
||||
break;
|
||||
}
|
||||
case 66:
|
||||
case 67: {
|
||||
data = { icon: CloudRain, name: 'Freezing rain' };
|
||||
data = { icon: CloudRain, name: t('modules.weather.card.weatherDescriptions.freezingRain') };
|
||||
break;
|
||||
}
|
||||
case 71:
|
||||
case 73:
|
||||
case 75: {
|
||||
data = { icon: CloudSnow, name: 'Snow fall' };
|
||||
data = { icon: CloudSnow, name: t('modules.weather.card.weatherDescriptions.snowFall') };
|
||||
break;
|
||||
}
|
||||
case 77: {
|
||||
data = { icon: CloudSnow, name: 'Snow grains' };
|
||||
data = { icon: CloudSnow, name: t('modules.weather.card.weatherDescriptions.snowGrains') };
|
||||
break;
|
||||
}
|
||||
case 80:
|
||||
case 81:
|
||||
case 82: {
|
||||
data = { icon: CloudRain, name: 'Rain showers' };
|
||||
data = { icon: CloudRain, name: t('modules.weather.card.weatherDescriptions.rainShowers') };
|
||||
|
||||
break;
|
||||
}
|
||||
case 85:
|
||||
case 86: {
|
||||
data = { icon: CloudSnow, name: 'Snow showers' };
|
||||
data = { icon: CloudSnow, name: t('modules.weather.card.weatherDescriptions.snowShowers') };
|
||||
break;
|
||||
}
|
||||
case 95: {
|
||||
data = { icon: CloudStorm, name: 'Thunderstorm' };
|
||||
data = { icon: CloudStorm, name: t('modules.weather.card.weatherDescriptions.thunderstorm') };
|
||||
break;
|
||||
}
|
||||
case 96:
|
||||
case 99: {
|
||||
data = { icon: CloudStorm, name: 'Thunderstorm with hail' };
|
||||
data = {
|
||||
icon: CloudStorm,
|
||||
name: t('modules.weather.card.weatherDescriptions.thunderstormWithHail'),
|
||||
};
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
data = { icon: QuestionMark, name: 'Unknown' };
|
||||
data = { icon: QuestionMark, name: t('modules.weather.card.weatherDescriptions.unknown') };
|
||||
}
|
||||
}
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user