🚧 wip migrate to next-i18n

This commit is contained in:
Manuel Ruwe
2022-08-22 09:50:54 +02:00
parent ac4dc23e08
commit 6d0a31f79e
61 changed files with 817 additions and 753 deletions

View File

@@ -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: t('modules.calendar.title'),
description: t('modules.calendar.description'),
title: 'Calendar',
description:
'A calendar module for displaying upcoming releases. It interacts with the Sonarr and Radarr API.',
icon: CalendarIcon,
component: CalendarComponent,
options: {
sundaystart: {
name: t('modules.calendar.options.sundayStart'),
name: 'Start the week on Sunday',
value: false,
},
},

View File

@@ -1,6 +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 { useTranslation } from 'next-i18next';
import { useState } from 'react';
import { useColorTheme } from '../../tools/color';
import { useConfig } from '../../tools/state';
@@ -160,6 +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');
return (
<Group mr="xs" align="stretch" noWrap style={{ maxHeight: 200 }}>
@@ -210,7 +211,7 @@ export function MediaDisplay({ media }: { media: IMedia }) {
size="sm"
rightIcon={<IconPlayerPlay size={15} />}
>
{t('modules.common.mediaCard.buttons.play')}
{t('buttons.play')}
</Button>
)}
{media.imdbId && (
@@ -250,7 +251,7 @@ export function MediaDisplay({ media }: { media: IMedia }) {
size="sm"
rightIcon={<IconDownload size={15} />}
>
{t('modules.common.mediaCard.buttons.request')}
{t('buttons.request')}
</Button>
</>
)}

View File

@@ -1,7 +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 { useTranslation } from 'next-i18next';
import { useEffect, useState } from 'react';
import { useConfig } from '../../tools/state';
import { serviceItem } from '../../tools/types';
@@ -142,32 +142,34 @@ 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 graphs = [
{
name: t('modules.dashDot.card.graphs.cpu.title'),
name: t('card.graphs.cpu.title'),
enabled: cpuEnabled,
params: {
multiView: dashConfig?.cpuMultiView?.value ?? false,
},
},
{
name: t('modules.dashDot.card.graphs.cpu.title'),
name: t('card.graphs.cpu.title'),
enabled: storageEnabled && !isCompact,
params: {
multiView: dashConfig?.storageMultiView?.value ?? false,
},
},
{
name: t('modules.dashDot.card.graphs.memory.title'),
name: t('card.graphs.memory.title'),
enabled: ramEnabled,
},
{
name: t('modules.dashDot.card.graphs.network.title'),
name: t('card.graphs.network.title'),
enabled: networkEnabled,
spanTwo: true,
},
{
name: t('modules.dashDot.card.graphs.gpu.title'),
name: t('card.graphs.gpu.title'),
enabled: gpuEnabled,
spanTwo: true,
},
@@ -176,26 +178,24 @@ export function DashdotComponent() {
if (dashdotUrl === '') {
return (
<div>
<h2 className={classes.heading}>{t('modules.dashDot.card.title')}</h2>
<p>{t('modules.dashDot.card.errors.noService')}</p>
<h2 className={classes.heading}>{t('card.title')}</h2>
<p>{t('card.errors.noService')}</p>
</div>
);
}
return (
<div>
<h2 className={classes.heading}>{t('modules.dashDot.card.title')}</h2>
<h2 className={classes.heading}>{t('card.title')}</h2>
{!info ? (
<p>{t('modules.dashDot.card.errors.noInformation')}</p>
<p>{t('card.errors.noInformation')}</p>
) : (
<div className={classes.graphsContainer}>
<div className={classes.table}>
{storageEnabled && isCompact && (
<div className={classes.tableRow}>
<p className={classes.tableLabel}>
{t('modules.dashDot.card.graphs.storage.label')}
</p>
<p className={classes.tableLabel}>{t('card.graphs.storage.label')}</p>
<p className={classes.tableValue}>
{((100 * totalUsed) / (totalSize || 1)).toFixed(1)}%{'\n'}
{bytePrettyPrint(totalUsed)} / {bytePrettyPrint(totalSize)}
@@ -204,15 +204,12 @@ export function DashdotComponent() {
)}
{networkEnabled && (
<div className={classes.tableRow}>
<p className={classes.tableLabel}>
{t('modules.dashDot.card.graphs.network.label')}
</p>
<p className={classes.tableLabel}>{t('card.graphs.network.label')}</p>
<p className={classes.tableValue}>
{bpsPrettyPrint(info?.network?.speedUp)}{' '}
{t('modules.dashDot.card.graphs.network.metrics.upload')}
{bpsPrettyPrint(info?.network?.speedUp)} {t('card.graphs.network.metrics.upload')}
{'\n'}
{bpsPrettyPrint(info?.network?.speedDown)}
{t('modules.dashDot.card.graphs.network.metrics.download')}
{t('card.graphs.network.metrics.download')}
</p>
</div>
)}

View File

@@ -11,9 +11,10 @@ import {
} from '@tabler/icons';
import axios from 'axios';
import Dockerode from 'dockerode';
import { useState } from 'react';
import { useTranslation } from 'next-i18next';
import { tryMatchService } from '../../tools/addToHomarr';
import { AddAppShelfItemForm } from '../../components/AppShelf/AddAppShelfItem';
import { useState } from 'react';
function sendDockerCommand(
action: string,
@@ -21,6 +22,8 @@ function sendDockerCommand(
containerName: string,
reload: () => void
) {
const { t } = useTranslation('modules/docker-module');
showNotification({
id: containerId,
loading: true,
@@ -34,8 +37,8 @@ function sendDockerCommand(
.then((res) => {
updateNotification({
id: containerId,
title: `Container ${containerName} ${action}ed`,
message: `Your container was successfully ${action}ed`,
title: t('messages.successfullyExecuted.message', { containerName, action }),
message: t('messages.successfullyExecuted.message', { action }),
icon: <IconCheck />,
autoClose: 2000,
});
@@ -44,7 +47,7 @@ function sendDockerCommand(
updateNotification({
id: containerId,
color: 'red',
title: 'There was an error',
title: t('errors.unknownError.title'),
message: err.response.data.reason,
autoClose: 2000,
});
@@ -61,6 +64,8 @@ export interface ContainerActionBarProps {
export default function ContainerActionBar({ selected, reload }: ContainerActionBarProps) {
const [opened, setOpened] = useState<boolean>(false);
const { t } = useTranslation('modules/docker-module');
return (
<Group>
<Modal
@@ -68,12 +73,12 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction
radius="md"
opened={opened}
onClose={() => setOpened(false)}
title="Add service"
title={t('actionBar.addService.title')}
>
<AddAppShelfItemForm
setOpened={setOpened}
{...tryMatchService(selected.at(0))}
message="Add service to homarr"
message={t('actionBar.addService.message')}
/>
</Modal>
<Button
@@ -89,7 +94,7 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction
color="orange"
radius="md"
>
Restart
{t('actionBar.restart.title')}
</Button>
<Button
leftIcon={<IconPlayerStop />}
@@ -104,7 +109,7 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction
color="red"
radius="md"
>
Stop
{t('actionBar.stop.title')}
</Button>
<Button
leftIcon={<IconPlayerPlay />}
@@ -119,10 +124,10 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction
color="green"
radius="md"
>
Start
{t('actionBar.start.title')}
</Button>
<Button leftIcon={<IconRefresh />} onClick={() => reload()} variant="light" radius="md">
Refresh data
{t('actionBar.refreshData.title')}
</Button>
<Button
leftIcon={<IconPlus />}
@@ -133,7 +138,7 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction
if (selected.length !== 1) {
showNotification({
autoClose: 5000,
title: <Title order={5}>Please only add one service at a time!</Title>,
title: <Title order={5}>{t('errors.oneServiceAtATime')}</Title>,
color: 'red',
message: undefined,
});
@@ -142,7 +147,7 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction
}
}}
>
Add to Homarr
{t('actionBar.addToHomarr.title')}
</Button>
<Button
leftIcon={<IconTrash />}
@@ -157,7 +162,7 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction
)
}
>
Remove
{t('actionBar.remove.title')}
</Button>
</Group>
);

View File

@@ -1,4 +1,5 @@
import { Badge, BadgeVariant, MantineSize } from '@mantine/core';
import { useTranslation } from 'next-i18next';
import Dockerode from 'dockerode';
export interface ContainerStateProps {
@@ -7,6 +8,9 @@ export interface ContainerStateProps {
export default function ContainerState(props: ContainerStateProps) {
const { state } = props;
const { t } = useTranslation('modules/docker-module');
const options: {
size: MantineSize;
radius: MantineSize;
@@ -20,28 +24,28 @@ export default function ContainerState(props: ContainerStateProps) {
case 'running': {
return (
<Badge color="green" {...options}>
Running
{t('table.states.running')}
</Badge>
);
}
case 'created': {
return (
<Badge color="cyan" {...options}>
Created
{t('table.states.created')}
</Badge>
);
}
case 'exited': {
return (
<Badge color="red" {...options}>
Stopped
{t('table.states.stopped')}
</Badge>
);
}
default: {
return (
<Badge color="purple" {...options}>
Unknown
{t('table.states.unknown')}
</Badge>
);
}

View File

@@ -1,10 +1,10 @@
import { ActionIcon, Drawer, Group, LoadingOverlay, Text, Tooltip } from '@mantine/core';
import { ActionIcon, Drawer, Text, Tooltip } from '@mantine/core';
import axios from 'axios';
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 { useTranslation } from 'next-i18next';
import ContainerActionBar from './ContainerActionBar';
import DockerTable from './DockerTable';
@@ -25,6 +25,8 @@ export default function DockerMenuButton(props: any) {
const { config } = useConfig();
const moduleEnabled = config.modules?.[DockerModule.title]?.enabled ?? false;
const { t } = useTranslation('modules/docker-module');
useEffect(() => {
reload();
}, [config.modules]);
@@ -44,10 +46,10 @@ export default function DockerMenuButton(props: any) {
// Send an Error notification
showNotification({
autoClose: 1500,
title: <Text>{t('layout.header.docker.errors.integrationFailed.title')}</Text>,
title: <Text>{t('errors.integrationFailed.title')}</Text>,
color: 'red',
icon: <IconX />,
message: t('layout.header.docker.errors.integrationFailed.message'),
message: t('errors.integrationFailed.message'),
})
);
}, 300);
@@ -69,7 +71,7 @@ export default function DockerMenuButton(props: any) {
>
<DockerTable containers={containers} selection={selection} setSelection={setSelection} />
</Drawer>
<Tooltip label={t('layout.header.docker.actionIcon.tooltip')}>
<Tooltip label={t('actionIcon.tooltip')}>
<ActionIcon
variant="default"
radius="md"

View File

@@ -1,6 +1,6 @@
import { Table, Checkbox, Group, Badge, createStyles, ScrollArea, TextInput } from '@mantine/core';
import { IconSearch } from '@tabler/icons';
import { t } from 'i18next';
import { useTranslation } from 'next-i18next';
import Dockerode from 'dockerode';
import { useEffect, useState } from 'react';
@@ -28,6 +28,8 @@ export default function DockerTable({
const { classes, cx } = useStyles();
const [search, setSearch] = useState('');
const { t } = useTranslation('modules/docker-module');
useEffect(() => {
setContainers(containers);
}, [containers]);
@@ -83,7 +85,7 @@ export default function DockerTable({
))}
{element.Ports.length > 3 && (
<Badge variant="filled">
{t('modules.docker.table.body.portCollapse', { ports: element.Ports.length - 3 })}
{t('table.body.portCollapse', { ports: element.Ports.length - 3 })}
</Badge>
)}
</Group>
@@ -98,7 +100,7 @@ export default function DockerTable({
return (
<ScrollArea style={{ height: '80vh' }}>
<TextInput
placeholder={t('modules.docker.search.placeholder')}
placeholder={t('search.placeholder')}
mt="md"
icon={<IconSearch size={14} />}
value={search}
@@ -115,10 +117,10 @@ export default function DockerTable({
transitionDuration={0}
/>
</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>
<th>{t('table.header.name')}</th>
<th>{t('table.header.image')}</th>
<th>{t('table.header.ports')}</th>
<th>{t('table.header.state')}</th>
</tr>
</thead>
<tbody>{rows}</tbody>

View File

@@ -20,7 +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';
import { useTranslation } from 'next-i18next';
export const DownloadsModule: IModule = {
title: 'Torrent',
@@ -50,6 +50,9 @@ export default function DownloadComponent() {
const [torrents, setTorrents] = useState<NormalizedTorrent[]>([]);
const setSafeInterval = useSetSafeInterval();
const [isLoading, setIsLoading] = useState(true);
const { t } = useTranslation('modules/downloads-module');
useEffect(() => {
setIsLoading(true);
if (downloadServices.length === 0) return;
@@ -106,12 +109,12 @@ export default function DownloadComponent() {
const DEVICE_WIDTH = 576;
const ths = (
<tr>
<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>
<th>{t('card.table.header.name')}</th>
<th>{t('card.table.header.size')}</th>
{width > 576 ? <th>{t('card.table.header.download')}</th> : ''}
{width > 576 ? <th>{t('card.table.header.upload')}</th> : ''}
<th>{t('card.table.header.estimatedTimeOfArrival')}</th>
<th>{t('card.table.header.progress')}</th>
</tr>
);
// Convert Seconds to readable format.
@@ -196,7 +199,7 @@ export default function DownloadComponent() {
</Table>
) : (
<Center style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<Title order={3}>{t('modules.downloads.card.table.body.nothingFound')}</Title>
<Title order={3}>{t('card.table.body.nothingFound')}</Title>
</Center>
)}
</ScrollArea>

View File

@@ -3,7 +3,7 @@ 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 { useTranslation } from 'next-i18next';
import { useState } from 'react';
import { useColorTheme } from '../../tools/color';
@@ -28,6 +28,7 @@ const useStyles = createStyles((theme) => ({
export function RequestModal({ base, opened, setOpened }: RequestModalProps) {
const [result, setResult] = useState<MovieResult | TvShowResult>();
const { secondaryColor } = useColorTheme();
function getResults(base: Result) {
axios.get(`/api/modules/overseerr/${base.id}?type=${base.mediaType}`).then((res) => {
setResult(res.data);
@@ -56,6 +57,8 @@ export function MovieRequestModal({
setOpened: (opened: boolean) => void;
}) {
const { secondaryColor } = useColorTheme();
const { t } = useTranslation('modules/overseerr-module');
return (
<Modal
onClose={() => setOpened(false)}
@@ -68,23 +71,23 @@ export function MovieRequestModal({
title={
<Group>
<IconDownload />
{t('modules.overseerr.popup.item.buttons.askFor', { title: result.title })}
{t('popup.item.buttons.askFor', { title: result.title })}
</Group>
}
>
<Stack>
<Alert
icon={<IconAlertCircle size={16} />}
title={t('modules.overseerr.popup.item.alerts.automaticApproval.title')}
title={t('popup.item.alerts.automaticApproval.title')}
color={secondaryColor}
radius="md"
variant="filled"
>
{t('modules.overseerr.popup.item.alerts.automaticApproval.text')}
{t('popup.item.alerts.automaticApproval.text')}
</Alert>
<Group>
<Button variant="outline" color="gray" onClick={() => setOpened(false)}>
{t('modules.overseerr.popup.item.buttons.cancel')}
{t('popup.item.buttons.cancel')}
</Button>
<Button
variant="outline"
@@ -92,7 +95,7 @@ export function MovieRequestModal({
askForMedia(MediaType.Movie, result.id, result.title, []);
}}
>
{t('modules.overseerr.popup.item.buttons.request')}
{t('popup.item.buttons.request')}
</Button>
</Group>
</Stack>
@@ -111,6 +114,7 @@ export function TvRequestModal({
}) {
const [selection, setSelection] = useState<TvShowResultSeason[]>(result.seasons);
const { classes, cx } = useStyles();
const { t } = useTranslation('modules/overseerr-module');
const toggleRow = (container: TvShowResultSeason) =>
setSelection((current: TvShowResultSeason[]) =>
@@ -149,7 +153,7 @@ export function TvRequestModal({
title={
<Group>
<IconDownload />
{t('modules.overseerr.popup.item.buttons.askFor', {
{t('popup.item.buttons.askFor', {
title: result.name ?? result.originalName ?? 'a TV show',
})}
</Group>
@@ -158,15 +162,15 @@ export function TvRequestModal({
<Stack>
<Alert
icon={<IconAlertCircle size={16} />}
title={t('modules.overseerr.popup.item.alerts.automaticApproval.title')}
title={t('popup.item.alerts.automaticApproval.title')}
color={secondaryColor}
radius="md"
variant="filled"
>
{t('modules.overseerr.popup.item.alerts.automaticApproval.text')}
{t('popup.item.alerts.automaticApproval.text')}
</Alert>
<Table captionSide="bottom" highlightOnHover>
<caption>{t('modules.overseerr.popup.seasonSelector.caption')}</caption>
<caption>{t('popup.seasonSelector.caption')}</caption>
<thead>
<tr>
<th>
@@ -177,15 +181,15 @@ export function TvRequestModal({
transitionDuration={0}
/>
</th>
<th>{t('modules.overseerr.popup.seasonSelector.table.header.season')}</th>
<th>{t('modules.overseerr.popup.seasonSelector.table.header.numberOfEpisodes')}</th>
<th>{t('popup.seasonSelector.table.header.season')}</th>
<th>{t('popup.seasonSelector.table.header.numberOfEpisodes')}</th>
</tr>
</thead>
<tbody>{rows}</tbody>
</Table>
<Group>
<Button variant="outline" color="gray" onClick={() => setOpened(false)}>
{t('modules.overseerr.popup.item.buttons.cancel')}
{t('popup.item.buttons.cancel')}
</Button>
<Button
variant="outline"
@@ -199,7 +203,7 @@ export function TvRequestModal({
);
}}
>
{t('modules.overseerr.popup.item.buttons.request')}
{t('popup.item.buttons.request')}
</Button>
</Group>
</Stack>

View File

@@ -5,7 +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';
import { useTranslation } from 'next-i18next';
export const PingModule: IModule = {
title: 'Ping Services',
@@ -23,6 +23,8 @@ export default function PingComponent(props: any) {
const [response, setResponse] = useState(500);
const exists = config.modules?.[PingModule.title]?.enabled ?? false;
const { t } = useTranslation('modules/ping-module');
function statusCheck(response: AxiosResponse) {
const { status }: { status: string[] } = props;
//Default Status
@@ -69,10 +71,10 @@ export default function PingComponent(props: any) {
radius="lg"
label={
isOnline === 'loading'
? t('modules.ping.states.loading')
? t('states.loading')
: isOnline === 'online'
? t('modules.ping.states.online', { response })
: t('modules.ping.states.offline', { response })
? t('states.online', { response })
: t('states.offline', { response })
}
>
<Indicator

View File

@@ -8,8 +8,7 @@ import {
IconDownload as Download,
IconMovie,
} from '@tabler/icons';
import { t } from 'i18next';
import { useTranslation } from 'next-i18next';
import axios from 'axios';
import { showNotification } from '@mantine/notifications';
import { useConfig } from '../../tools/state';
@@ -61,6 +60,7 @@ export default function SearchBar(props: any) {
},
});
const [debounced, cancel] = useDebouncedValue(form.values.query, 250);
const { t } = useTranslation('modules/search-module');
useEffect(() => {
if (OverseerrService === undefined && isOverseerrEnabled) {
@@ -177,7 +177,7 @@ export default function SearchBar(props: any) {
radius="md"
size="md"
styles={{ rightSection: { pointerEvents: 'none' } }}
placeholder={t('layout.header.search.input.placeholder')}
placeholder={t('input.placeholder')}
{...props}
{...form.getInputProps('query')}
/>

View File

@@ -13,10 +13,10 @@ import {
IconSnowflake as Snowflake,
IconSun as Sun,
} from '@tabler/icons';
import { useTranslation } from 'next-i18next';
import { useConfig } from '../../tools/state';
import { IModule } from '../ModuleTypes';
import { WeatherResponse } from './WeatherInterface';
import { t } from 'i18next';
export const WeatherModule: IModule = {
title: 'Weather',
@@ -49,85 +49,87 @@ 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 { code } = props;
let data: { icon: any; name: string };
switch (code) {
case 0: {
data = { icon: Sun, name: t('modules.weather.card.weatherDescriptions.clear') };
data = { icon: Sun, name: t('card.weatherDescriptions.clear') };
break;
}
case 1:
case 2:
case 3: {
data = { icon: Cloud, name: t('modules.weather.card.weatherDescriptions.mainlyClear') };
data = { icon: Cloud, name: t('card.weatherDescriptions.mainlyClear') };
break;
}
case 45:
case 48: {
data = { icon: CloudFog, name: t('modules.weather.card.weatherDescriptions.fog') };
data = { icon: CloudFog, name: t('card.weatherDescriptions.fog') };
break;
}
case 51:
case 53:
case 55: {
data = { icon: Cloud, name: t('modules.weather.card.weatherDescriptions.drizzle') };
data = { icon: Cloud, name: t('card.weatherDescriptions.drizzle') };
break;
}
case 56:
case 57: {
data = {
icon: Snowflake,
name: t('modules.weather.card.weatherDescriptions.freezingDrizzle'),
name: t('card.weatherDescriptions.freezingDrizzle'),
};
break;
}
case 61:
case 63:
case 65: {
data = { icon: CloudRain, name: t('modules.weather.card.weatherDescriptions.rain') };
data = { icon: CloudRain, name: t('card.weatherDescriptions.rain') };
break;
}
case 66:
case 67: {
data = { icon: CloudRain, name: t('modules.weather.card.weatherDescriptions.freezingRain') };
data = { icon: CloudRain, name: t('card.weatherDescriptions.freezingRain') };
break;
}
case 71:
case 73:
case 75: {
data = { icon: CloudSnow, name: t('modules.weather.card.weatherDescriptions.snowFall') };
data = { icon: CloudSnow, name: t('card.weatherDescriptions.snowFall') };
break;
}
case 77: {
data = { icon: CloudSnow, name: t('modules.weather.card.weatherDescriptions.snowGrains') };
data = { icon: CloudSnow, name: t('card.weatherDescriptions.snowGrains') };
break;
}
case 80:
case 81:
case 82: {
data = { icon: CloudRain, name: t('modules.weather.card.weatherDescriptions.rainShowers') };
data = { icon: CloudRain, name: t('card.weatherDescriptions.rainShowers') };
break;
}
case 85:
case 86: {
data = { icon: CloudSnow, name: t('modules.weather.card.weatherDescriptions.snowShowers') };
data = { icon: CloudSnow, name: t('card.weatherDescriptions.snowShowers') };
break;
}
case 95: {
data = { icon: CloudStorm, name: t('modules.weather.card.weatherDescriptions.thunderstorm') };
data = { icon: CloudStorm, name: t('card.weatherDescriptions.thunderstorm') };
break;
}
case 96:
case 99: {
data = {
icon: CloudStorm,
name: t('modules.weather.card.weatherDescriptions.thunderstormWithHail'),
name: t('card.weatherDescriptions.thunderstormWithHail'),
};
break;
}
default: {
data = { icon: QuestionMark, name: t('modules.weather.card.weatherDescriptions.unknown') };
data = { icon: QuestionMark, name: t('card.weatherDescriptions.unknown') };
}
}
return (