mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-09 15:05:48 +01:00
🌐 Replaced hardcoded text to use translation
This commit is contained in:
@@ -12,7 +12,12 @@
|
|||||||
"label": "Items"
|
"label": "Items"
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"label": "Layout"
|
"label": "Layout",
|
||||||
|
"data":{
|
||||||
|
"autoGrid": "Auto Grid",
|
||||||
|
"horizontal": "Horizontal",
|
||||||
|
"vertical": "Vertical"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -21,5 +26,21 @@
|
|||||||
"title": "Bookmark list empty",
|
"title": "Bookmark list empty",
|
||||||
"text": "Add new items to this list in the edit mode"
|
"text": "Add new items to this list in the edit mode"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"item": {
|
||||||
|
"validation": {
|
||||||
|
"length100": "Length must be between 1 and 100",
|
||||||
|
"length200": "Length must be between 1 and 200",
|
||||||
|
"length400": "Length must be between 1 and 400",
|
||||||
|
"invalidLink": "Not a valid link",
|
||||||
|
"errorMsg": "Did not save, because there were validation errors. Please adust your inputs"
|
||||||
|
},
|
||||||
|
"name": "Name",
|
||||||
|
"url": "URL",
|
||||||
|
"newTab": "Open in new tab",
|
||||||
|
"hideHostname": "Hide Hostname",
|
||||||
|
"hideIcon": "Hide Icon",
|
||||||
|
"delete": "Delete"
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,13 +11,25 @@
|
|||||||
"label": "Start the week on Sunday"
|
"label": "Start the week on Sunday"
|
||||||
},
|
},
|
||||||
"radarrReleaseType": {
|
"radarrReleaseType": {
|
||||||
"label": "Radarr release type"
|
"label": "Radarr release type",
|
||||||
|
"data":{
|
||||||
|
"inCinemas": "In Cinemas",
|
||||||
|
"physicalRelease": "Physical",
|
||||||
|
"digitalRelease": "Digital"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"hideWeekDays": {
|
"hideWeekDays": {
|
||||||
"label": "Hide week days"
|
"label": "Hide week days"
|
||||||
},
|
},
|
||||||
"fontSize": {
|
"fontSize": {
|
||||||
"label": "Font Size"
|
"label": "Font Size",
|
||||||
|
"data":{
|
||||||
|
"xs": "Extra Small",
|
||||||
|
"sm": "Small",
|
||||||
|
"md": "Medium",
|
||||||
|
"lg": "Large",
|
||||||
|
"xl": "Extra Large"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,8 @@
|
|||||||
"noUrl": {
|
"noUrl": {
|
||||||
"title": "Invalid URL",
|
"title": "Invalid URL",
|
||||||
"text": "Ensure that you've entered a valid address in the configuration of your widget"
|
"text": "Ensure that you've entered a valid address in the configuration of your widget"
|
||||||
}
|
},
|
||||||
|
"browserSupport": "Your Browser does not support iframes. Please update your browser."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,37 @@
|
|||||||
},
|
},
|
||||||
"tooltips": {
|
"tooltips": {
|
||||||
"approve": "Approve requests",
|
"approve": "Approve requests",
|
||||||
"decline": "Decline requests"
|
"decline": "Decline requests",
|
||||||
|
"approving": "Approving Request..."
|
||||||
|
},
|
||||||
|
"mutation": {
|
||||||
|
"approving": "Approving",
|
||||||
|
"declining": "Declining",
|
||||||
|
"request": "request...",
|
||||||
|
"approved": "Request was approved!",
|
||||||
|
"declined": "Request was declined!"
|
||||||
|
},
|
||||||
|
"detail": {
|
||||||
|
"label": "Stats for nerds",
|
||||||
|
"id": "ID",
|
||||||
|
"device": "Device",
|
||||||
|
"video": {
|
||||||
|
"video":"Video",
|
||||||
|
"resolution": "Resolution",
|
||||||
|
"framerate": "Framerate",
|
||||||
|
"codec": "Video Codec"
|
||||||
|
},
|
||||||
|
"audio": {
|
||||||
|
"audio": "Audio",
|
||||||
|
"channels": "Audio Channels",
|
||||||
|
"codec": "Audio Codec"
|
||||||
|
},
|
||||||
|
"transcoding": {
|
||||||
|
"transcoding": "Transcoding",
|
||||||
|
"context": "Context",
|
||||||
|
"requested": "Hardware Encoding Requested",
|
||||||
|
"source": "Source Codec",
|
||||||
|
"target": "Target Codec"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,11 @@
|
|||||||
"settings": {
|
"settings": {
|
||||||
"title": "Media requests stats",
|
"title": "Media requests stats",
|
||||||
"direction": {
|
"direction": {
|
||||||
"label": "Direction of the layout."
|
"label": "Direction of the layout.",
|
||||||
|
"data":{
|
||||||
|
"row": "Horizontal",
|
||||||
|
"column": "Vertical"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
"title": "Settings for media server widget"
|
"title": "Settings for media server widget"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"loading": "Homarr is loading streams...",
|
||||||
"card": {
|
"card": {
|
||||||
"table": {
|
"table": {
|
||||||
"header": {
|
"header": {
|
||||||
|
|||||||
@@ -12,7 +12,8 @@
|
|||||||
"label": "Refresh interval (in minutes)"
|
"label": "Refresh interval (in minutes)"
|
||||||
},
|
},
|
||||||
"dangerousAllowSanitizedItemContent": {
|
"dangerousAllowSanitizedItemContent": {
|
||||||
"label": ""
|
"label": "Allow HTML formatting (Dangerous)",
|
||||||
|
"info": "Allowing HTML formatting from outside could be dangerous.<br/>Please make sure that the feed is from a trusted source."
|
||||||
},
|
},
|
||||||
"textLinesClamp": {
|
"textLinesClamp": {
|
||||||
"label": "Text lines clamp"
|
"label": "Text lines clamp"
|
||||||
|
|||||||
@@ -63,7 +63,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"loading": {
|
"loading": {
|
||||||
"title": "Loading..."
|
"title": "Loading...",
|
||||||
|
"description": "Homarr is establishing a connection..."
|
||||||
},
|
},
|
||||||
"popover": {
|
"popover": {
|
||||||
"introductionPrefix": "Managed by",
|
"introductionPrefix": "Managed by",
|
||||||
|
|||||||
@@ -31,7 +31,8 @@
|
|||||||
"title": "Error",
|
"title": "Error",
|
||||||
"message": "An error has occurred"
|
"message": "An error has occurred"
|
||||||
},
|
},
|
||||||
"paused": "Paused"
|
"paused": "Paused",
|
||||||
|
"notImplemented": "NOT IMPLEMENTED"
|
||||||
},
|
},
|
||||||
"history": {
|
"history": {
|
||||||
"header": {
|
"header": {
|
||||||
|
|||||||
@@ -32,5 +32,6 @@
|
|||||||
"thunderstormWithHail": "Thunderstorm with hail",
|
"thunderstormWithHail": "Thunderstorm with hail",
|
||||||
"unknown": "Unknown"
|
"unknown": "Unknown"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"error": "An error occured"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,6 @@ export async function getStaticProps({ req, res, locale }: GetServerSidePropsCon
|
|||||||
const useStyles = createStyles(() => ({
|
const useStyles = createStyles(() => ({
|
||||||
image: {
|
image: {
|
||||||
margin: '0 auto',
|
margin: '0 auto',
|
||||||
display: 'blcok',
|
display: 'block',
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ const definition = defineWidget({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
itemComponent({ data, onChange, delete: deleteData }) {
|
itemComponent({ data, onChange, delete: deleteData }) {
|
||||||
|
const { t } = useTranslation('modules/bookmark');
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
initialValues: data,
|
initialValues: data,
|
||||||
validate: {
|
validate: {
|
||||||
@@ -83,15 +84,15 @@ const definition = defineWidget({
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'Length must be between 1 and 100';
|
return t('item.validation.length100');
|
||||||
},
|
},
|
||||||
href: (value) => {
|
href: (value) => {
|
||||||
if (!z.string().min(1).max(200).safeParse(value).success) {
|
if (!z.string().min(1).max(200).safeParse(value).success) {
|
||||||
return 'Length must be between 1 and 200';
|
return t('item.validation.length200');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!z.string().url().safeParse(value).success) {
|
if (!z.string().url().safeParse(value).success) {
|
||||||
return 'Not a valid link';
|
return t('item.validation.invalidLink');
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -101,7 +102,7 @@ const definition = defineWidget({
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'Length must be between 1 and 100';
|
return t('item.validation.length400');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
validateInputOnChange: true,
|
validateInputOnChange: true,
|
||||||
@@ -122,13 +123,13 @@ const definition = defineWidget({
|
|||||||
<TextInput
|
<TextInput
|
||||||
icon={<IconTypography size="1rem" />}
|
icon={<IconTypography size="1rem" />}
|
||||||
{...form.getInputProps('name')}
|
{...form.getInputProps('name')}
|
||||||
label="Name"
|
label={t('item.name')}
|
||||||
withAsterisk
|
withAsterisk
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
icon={<IconLink size="1rem" />}
|
icon={<IconLink size="1rem" />}
|
||||||
{...form.getInputProps('href')}
|
{...form.getInputProps('href')}
|
||||||
label="URL"
|
label={t('item.url')}
|
||||||
withAsterisk
|
withAsterisk
|
||||||
/>
|
/>
|
||||||
<IconSelector
|
<IconSelector
|
||||||
@@ -140,17 +141,17 @@ const definition = defineWidget({
|
|||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
{...form.getInputProps('openNewTab')}
|
{...form.getInputProps('openNewTab')}
|
||||||
label="Open in new tab"
|
label={t('item.newTab')}
|
||||||
checked={form.values.openNewTab}
|
checked={form.values.openNewTab}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
{...form.getInputProps('hideHostname')}
|
{...form.getInputProps('hideHostname')}
|
||||||
label="Hide Hostname"
|
label={t('item.hideHostname')}
|
||||||
checked={form.values.hideHostname}
|
checked={form.values.hideHostname}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
{...form.getInputProps('hideIcon')}
|
{...form.getInputProps('hideIcon')}
|
||||||
label="Hide Icon"
|
label={t('item.hideIcon')}
|
||||||
checked={form.values.hideIcon}
|
checked={form.values.hideIcon}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
@@ -159,11 +160,11 @@ const definition = defineWidget({
|
|||||||
variant="light"
|
variant="light"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
Delete
|
{t('item.delete')}
|
||||||
</Button>
|
</Button>
|
||||||
{!form.isValid() && (
|
{!form.isValid() && (
|
||||||
<Alert color="red" icon={<IconAlertTriangle size="1rem" />}>
|
<Alert color="red" icon={<IconAlertTriangle size="1rem" />}>
|
||||||
Did not save, because there were validation errors. Please adust your inputs
|
{t('item.validation.errorMsg')}
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -174,18 +175,9 @@ const definition = defineWidget({
|
|||||||
layout: {
|
layout: {
|
||||||
type: 'select',
|
type: 'select',
|
||||||
data: [
|
data: [
|
||||||
{
|
{ value: 'autoGrid', },
|
||||||
label: 'Auto Grid',
|
{ value: 'horizontal', },
|
||||||
value: 'autoGrid',
|
{ value: 'vertical', },
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Horizontal',
|
|
||||||
value: 'horizontal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Vertical',
|
|
||||||
value: 'vertical',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
defaultValue: 'autoGrid',
|
defaultValue: 'autoGrid',
|
||||||
},
|
},
|
||||||
@@ -206,10 +198,10 @@ interface BookmarkWidgetTileProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function BookmarkWidgetTile({ widget }: BookmarkWidgetTileProps) {
|
function BookmarkWidgetTile({ widget }: BookmarkWidgetTileProps) {
|
||||||
const { t } = useTranslation('modules/bookmark');
|
|
||||||
const { classes } = useStyles();
|
const { classes } = useStyles();
|
||||||
const { enabled: isEditModeEnabled } = useEditModeStore();
|
const { enabled: isEditModeEnabled } = useEditModeStore();
|
||||||
const { fn, colors, colorScheme } = useMantineTheme();
|
const { fn, colors, colorScheme } = useMantineTheme();
|
||||||
|
const { t } = useTranslation('modules/bookmark');
|
||||||
|
|
||||||
if (widget.properties.items.length === 0) {
|
if (widget.properties.items.length === 0) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -33,20 +33,20 @@ const definition = defineWidget({
|
|||||||
type: 'select',
|
type: 'select',
|
||||||
defaultValue: 'inCinemas',
|
defaultValue: 'inCinemas',
|
||||||
data: [
|
data: [
|
||||||
{ label: 'In Cinemas', value: 'inCinemas' },
|
{ value: 'inCinemas' },
|
||||||
{ label: 'Physical', value: 'physicalRelease' },
|
{ value: 'physicalRelease' },
|
||||||
{ label: 'Digital', value: 'digitalRelease' },
|
{ value: 'digitalRelease' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
fontSize: {
|
fontSize: {
|
||||||
type: 'select',
|
type: 'select',
|
||||||
defaultValue: 'xs',
|
defaultValue: 'xs',
|
||||||
data: [
|
data: [
|
||||||
{ label: 'Extra Small', value: 'xs' },
|
{ value: 'xs' },
|
||||||
{ label: 'Small', value: 'sm' },
|
{ value: 'sm' },
|
||||||
{ label: 'Medium', value: 'md' },
|
{ value: 'md' },
|
||||||
{ label: 'Large', value: 'lg' },
|
{ value: 'lg' },
|
||||||
{ label: 'Extra Large', value: 'xl' },
|
{ value: 'xl' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ function IFrameTile({ widget }: IFrameTileProps) {
|
|||||||
title="widget iframe"
|
title="widget iframe"
|
||||||
allow={allowedPermissions.join(' ')}
|
allow={allowedPermissions.join(' ')}
|
||||||
>
|
>
|
||||||
<Text>Your Browser does not support iframes. Please update your browser.</Text>
|
<Text>{t('card.errors.browserSupport')}</Text>
|
||||||
</iframe>
|
</iframe>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -58,12 +58,13 @@ const useMediaRequestDecisionMutation = () => {
|
|||||||
utils.mediaRequest.all.invalidate();
|
utils.mediaRequest.all.invalidate();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const { t } = useTranslation('modules/media-requests-list');
|
||||||
return async (variables: MediaRequestDecisionVariables) => {
|
return async (variables: MediaRequestDecisionVariables) => {
|
||||||
const action = variables.isApproved ? 'Approving' : 'Declining';
|
const action = variables.isApproved ? t('mutation.approving') : t('mutation.declining');
|
||||||
notifications.show({
|
notifications.show({
|
||||||
id: `decide-${variables.request.id}`,
|
id: `decide-${variables.request.id}`,
|
||||||
color: 'yellow',
|
color: 'yellow',
|
||||||
title: `${action} request...`,
|
title: `${action} ${t('mutation.request')}`,
|
||||||
message: undefined,
|
message: undefined,
|
||||||
loading: true,
|
loading: true,
|
||||||
});
|
});
|
||||||
@@ -75,7 +76,7 @@ const useMediaRequestDecisionMutation = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
onSuccess(_data, variables) {
|
onSuccess(_data, variables) {
|
||||||
const title = variables.isApproved ? 'Request was approved!' : 'Request was declined!';
|
const title = variables.isApproved ? t('mutation.approved') : t('mutation.declined');
|
||||||
notifications.update({
|
notifications.update({
|
||||||
id: `decide-${variables.id}`,
|
id: `decide-${variables.id}`,
|
||||||
color: 'teal',
|
color: 'teal',
|
||||||
@@ -187,7 +188,7 @@ function MediaRequestListTile({ widget }: MediaRequestListWidgetProps) {
|
|||||||
notifications.show({
|
notifications.show({
|
||||||
id: `approve ${item.id}`,
|
id: `approve ${item.id}`,
|
||||||
color: 'yellow',
|
color: 'yellow',
|
||||||
title: 'Approving request...',
|
title: t('tooltips.approving'),
|
||||||
message: undefined,
|
message: undefined,
|
||||||
loading: true,
|
loading: true,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ const definition = defineWidget({
|
|||||||
type: 'select',
|
type: 'select',
|
||||||
defaultValue: 'row' as 'row' | 'column',
|
defaultValue: 'row' as 'row' | 'column',
|
||||||
data: [
|
data: [
|
||||||
{ label: 'Horizontal', value: 'row' },
|
{ value: 'row' },
|
||||||
{ label: 'Vertical', value: 'column' },
|
{ value: 'column' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,27 +2,29 @@ import { Card, Divider, Flex, Grid, Group, Text } from '@mantine/core';
|
|||||||
import { IconDeviceMobile, IconId } from '@tabler/icons-react';
|
import { IconDeviceMobile, IconId } from '@tabler/icons-react';
|
||||||
|
|
||||||
import { GenericSessionInfo } from '../../types/api/media-server/session-info';
|
import { GenericSessionInfo } from '../../types/api/media-server/session-info';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
export const DetailCollapseable = ({ session }: { session: GenericSessionInfo }) => {
|
export const DetailCollapseable = ({ session }: { session: GenericSessionInfo }) => {
|
||||||
let details: { title: string; metrics: { name: string; value: string | undefined }[] }[] = [];
|
let details: { title: string; metrics: { name: string; value: string | undefined }[] }[] = [];
|
||||||
|
const { t } = useTranslation('modules/media-server-list');
|
||||||
|
|
||||||
if (session.currentlyPlaying) {
|
if (session.currentlyPlaying) {
|
||||||
if (session.currentlyPlaying.metadata.video) {
|
if (session.currentlyPlaying.metadata.video) {
|
||||||
details = [
|
details = [
|
||||||
...details,
|
...details,
|
||||||
{
|
{
|
||||||
title: 'Video',
|
title: t('detail.video.'),
|
||||||
metrics: [
|
metrics: [
|
||||||
{
|
{
|
||||||
name: 'Resolution',
|
name: t('detail.video.resolution'),
|
||||||
value: `${session.currentlyPlaying.metadata.video.width}x${session.currentlyPlaying.metadata.video.height}`,
|
value: `${session.currentlyPlaying.metadata.video.width}x${session.currentlyPlaying.metadata.video.height}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Framerate',
|
name: t('detail.video.framerate'),
|
||||||
value: session.currentlyPlaying.metadata.video.videoFrameRate,
|
value: session.currentlyPlaying.metadata.video.videoFrameRate,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Codec',
|
name: t('detail.video.codec'),
|
||||||
value: session.currentlyPlaying.metadata.video.videoCodec,
|
value: session.currentlyPlaying.metadata.video.videoCodec,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -39,14 +41,14 @@ export const DetailCollapseable = ({ session }: { session: GenericSessionInfo })
|
|||||||
details = [
|
details = [
|
||||||
...details,
|
...details,
|
||||||
{
|
{
|
||||||
title: 'Audio',
|
title: t('detail.audio.audio'),
|
||||||
metrics: [
|
metrics: [
|
||||||
{
|
{
|
||||||
name: 'Audio channels',
|
name: t('detail.audio.channels'),
|
||||||
value: `${session.currentlyPlaying.metadata.audio.audioChannels}`,
|
value: `${session.currentlyPlaying.metadata.audio.audioChannels}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Audio codec',
|
name: t('detail.audio.codec'),
|
||||||
value: session.currentlyPlaying.metadata.audio.audioCodec,
|
value: session.currentlyPlaying.metadata.audio.audioCodec,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -58,24 +60,24 @@ export const DetailCollapseable = ({ session }: { session: GenericSessionInfo })
|
|||||||
details = [
|
details = [
|
||||||
...details,
|
...details,
|
||||||
{
|
{
|
||||||
title: 'Transcoding',
|
title: t('detail.transcoding.transcoding'),
|
||||||
metrics: [
|
metrics: [
|
||||||
{
|
{
|
||||||
name: 'Resolution',
|
name: t('detail.video.resolution'),
|
||||||
value: `${session.currentlyPlaying.metadata.transcoding.width}x${session.currentlyPlaying.metadata.transcoding.height}`,
|
value: `${session.currentlyPlaying.metadata.transcoding.width}x${session.currentlyPlaying.metadata.transcoding.height}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Context',
|
name: t('detail.transcoding.context'),
|
||||||
value: session.currentlyPlaying.metadata.transcoding.context,
|
value: session.currentlyPlaying.metadata.transcoding.context,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Hardware encoding requested',
|
name: t('detail.transcoding.requested'),
|
||||||
value: session.currentlyPlaying.metadata.transcoding.transcodeHwRequested
|
value: session.currentlyPlaying.metadata.transcoding.transcodeHwRequested
|
||||||
? 'yes'
|
? 'yes'
|
||||||
: 'no',
|
: 'no',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Source codec',
|
name: t('detail.transcoding.source'),
|
||||||
value:
|
value:
|
||||||
session.currentlyPlaying.metadata.transcoding.sourceAudioCodec ||
|
session.currentlyPlaying.metadata.transcoding.sourceAudioCodec ||
|
||||||
session.currentlyPlaying.metadata.transcoding.sourceVideoCodec
|
session.currentlyPlaying.metadata.transcoding.sourceVideoCodec
|
||||||
@@ -83,7 +85,7 @@ export const DetailCollapseable = ({ session }: { session: GenericSessionInfo })
|
|||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Target codec',
|
name: t('detail.transcoding.target'),
|
||||||
value: `${session.currentlyPlaying.metadata.transcoding.videoCodec} ${session.currentlyPlaying.metadata.transcoding.audioCodec}`,
|
value: `${session.currentlyPlaying.metadata.transcoding.videoCodec} ${session.currentlyPlaying.metadata.transcoding.audioCodec}`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -97,19 +99,19 @@ export const DetailCollapseable = ({ session }: { session: GenericSessionInfo })
|
|||||||
<Flex justify="space-between" mb="xs">
|
<Flex justify="space-between" mb="xs">
|
||||||
<Group>
|
<Group>
|
||||||
<IconId size={16} />
|
<IconId size={16} />
|
||||||
<Text>ID</Text>
|
<Text>{t('detail.id')}</Text>
|
||||||
</Group>
|
</Group>
|
||||||
<Text>{session.id}</Text>
|
<Text>{session.id}</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex justify="space-between" mb="md">
|
<Flex justify="space-between" mb="md">
|
||||||
<Group>
|
<Group>
|
||||||
<IconDeviceMobile size={16} />
|
<IconDeviceMobile size={16} />
|
||||||
<Text>Device</Text>
|
<Text>{t('detail.device')}</Text>
|
||||||
</Group>
|
</Group>
|
||||||
<Text>{session.sessionName}</Text>
|
<Text>{session.sessionName}</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
{details.length > 0 && (
|
{details.length > 0 && (
|
||||||
<Divider label="Stats for nerds" labelPosition="center" mt="lg" mb="sm" />
|
<Divider label={t('detail.label')} labelPosition="center" mt="lg" mb="sm" />
|
||||||
)}
|
)}
|
||||||
<Grid>
|
<Grid>
|
||||||
{details.map((detail, index) => (
|
{details.map((detail, index) => (
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ interface MediaServerWidgetProps {
|
|||||||
function MediaServerTile({ widget }: MediaServerWidgetProps) {
|
function MediaServerTile({ widget }: MediaServerWidgetProps) {
|
||||||
const { t } = useTranslation('modules/media-server');
|
const { t } = useTranslation('modules/media-server');
|
||||||
const { config } = useConfigContext();
|
const { config } = useConfigContext();
|
||||||
const isEditMode = useEditModeStore((x) => x.enabled);
|
|
||||||
|
|
||||||
const { data, isError, isFetching, isInitialLoading } = useGetMediaServers({
|
const { data, isError, isFetching, isInitialLoading } = useGetMediaServers({
|
||||||
enabled: config !== undefined,
|
enabled: config !== undefined,
|
||||||
@@ -72,7 +71,7 @@ function MediaServerTile({ widget }: MediaServerWidgetProps) {
|
|||||||
<Loader />
|
<Loader />
|
||||||
<Stack align="center" spacing={0}>
|
<Stack align="center" spacing={0}>
|
||||||
<Text>{t('descriptor.name')}</Text>
|
<Text>{t('descriptor.name')}</Text>
|
||||||
<Text color="dimmed">Homarr is loading streams...</Text>
|
<Text color="dimmed">{t('descriptor.loading')}</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ const definition = defineWidget({
|
|||||||
dangerousAllowSanitizedItemContent: {
|
dangerousAllowSanitizedItemContent: {
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
|
info: true,
|
||||||
},
|
},
|
||||||
textLinesClamp: {
|
textLinesClamp: {
|
||||||
type: 'slider',
|
type: 'slider',
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
createStyles,
|
createStyles,
|
||||||
useMantineTheme,
|
useMantineTheme,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useDisclosure, useElementSize } from '@mantine/hooks';
|
import { useDisclosure } from '@mantine/hooks';
|
||||||
import {
|
import {
|
||||||
IconAffiliate,
|
IconAffiliate,
|
||||||
IconDatabase,
|
IconDatabase,
|
||||||
@@ -37,9 +37,8 @@ interface TorrentQueueItemProps {
|
|||||||
width: number;
|
width: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BitTorrrentQueueItem = ({ torrent, width, app }: TorrentQueueItemProps) => {
|
export const BitTorrentQueueItem = ({ torrent, width, app }: TorrentQueueItemProps) => {
|
||||||
const [popoverOpened, { open: openPopover, close: closePopover }] = useDisclosure(false);
|
const [popoverOpened, { open: openPopover, close: closePopover }] = useDisclosure(false);
|
||||||
const theme = useMantineTheme();
|
|
||||||
const { classes } = useStyles();
|
const { classes } = useStyles();
|
||||||
const { t } = useTranslation('modules/torrents-status');
|
const { t } = useTranslation('modules/torrents-status');
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import { AppIntegrationType } from '../../types/app';
|
|||||||
import { useGetDownloadClientsQueue } from '../download-speed/useGetNetworkSpeed';
|
import { useGetDownloadClientsQueue } from '../download-speed/useGetNetworkSpeed';
|
||||||
import { defineWidget } from '../helper';
|
import { defineWidget } from '../helper';
|
||||||
import { IWidget } from '../widgets';
|
import { IWidget } from '../widgets';
|
||||||
import { BitTorrrentQueueItem } from './TorrentQueueItem';
|
import { BitTorrentQueueItem } from './TorrentQueueItem';
|
||||||
|
|
||||||
dayjs.extend(duration);
|
dayjs.extend(duration);
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
@@ -108,7 +108,7 @@ function TorrentTile({ widget }: TorrentTileProps) {
|
|||||||
<Loader />
|
<Loader />
|
||||||
<Stack align="center" spacing={0}>
|
<Stack align="center" spacing={0}>
|
||||||
<Text>{t('card.loading.title')}</Text>
|
<Text>{t('card.loading.title')}</Text>
|
||||||
<Text color="dimmed">Homarr is establishing a connection...</Text>
|
<Text color="dimmed">{t('card.loading.description')}</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
@@ -156,7 +156,7 @@ function TorrentTile({ widget }: TorrentTileProps) {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{filteredTorrents.map((torrent, index) => (
|
{filteredTorrents.map((torrent, index) => (
|
||||||
<BitTorrrentQueueItem key={index} torrent={torrent} width={width} app={undefined} />
|
<BitTorrentQueueItem key={index} torrent={torrent} width={width} app={undefined} />
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{filteredTorrents.length !== torrents.length && (
|
{filteredTorrents.length !== torrents.length && (
|
||||||
|
|||||||
@@ -109,13 +109,13 @@ export const UsenetQueueList: FunctionComponent<UsenetQueueListProps> = ({ appId
|
|||||||
<tr key={nzb.id}>
|
<tr key={nzb.id}>
|
||||||
<td>
|
<td>
|
||||||
{nzb.state === 'paused' ? (
|
{nzb.state === 'paused' ? (
|
||||||
<Tooltip label="NOT IMPLEMENTED">
|
<Tooltip label={t('queue.notImplemented')}>
|
||||||
<ActionIcon color="gray" variant="subtle" radius="xl" size="sm">
|
<ActionIcon color="gray" variant="subtle" radius="xl" size="sm">
|
||||||
<IconPlayerPlay size="16" />
|
<IconPlayerPlay size="16" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : (
|
) : (
|
||||||
<Tooltip label="NOT IMPLEMENTED">
|
<Tooltip label={t('queue.notImplemented')}>
|
||||||
<ActionIcon color="primary" variant="subtle" radius="xl" size="sm">
|
<ActionIcon color="primary" variant="subtle" radius="xl" size="sm">
|
||||||
<IconPlayerPause size="16" />
|
<IconPlayerPause size="16" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
IconSun,
|
IconSun,
|
||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { useElementSize } from '@mantine/hooks';
|
|
||||||
|
|
||||||
interface WeatherIconProps {
|
interface WeatherIconProps {
|
||||||
code: number;
|
code: number;
|
||||||
@@ -25,8 +24,7 @@ interface WeatherIconProps {
|
|||||||
*/
|
*/
|
||||||
export const WeatherIcon = ({ code, size=50 }: WeatherIconProps) => {
|
export const WeatherIcon = ({ code, size=50 }: WeatherIconProps) => {
|
||||||
const { t } = useTranslation('modules/weather');
|
const { t } = useTranslation('modules/weather');
|
||||||
const { width, ref } = useElementSize();
|
|
||||||
|
|
||||||
const { icon: Icon, name } =
|
const { icon: Icon, name } =
|
||||||
weatherDefinitions.find((wd) => wd.codes.includes(code)) ?? unknownWeather;
|
weatherDefinitions.find((wd) => wd.codes.includes(code)) ?? unknownWeather;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import {
|
|||||||
IconArrowDownRight,
|
IconArrowDownRight,
|
||||||
IconArrowUpRight,
|
IconArrowUpRight,
|
||||||
IconCloudRain,
|
IconCloudRain,
|
||||||
IconCurrentLocation,
|
|
||||||
IconMapPin,
|
IconMapPin,
|
||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
import { api } from '~/utils/api';
|
import { api } from '~/utils/api';
|
||||||
@@ -12,6 +11,7 @@ import { api } from '~/utils/api';
|
|||||||
import { defineWidget } from '../helper';
|
import { defineWidget } from '../helper';
|
||||||
import { IWidget } from '../widgets';
|
import { IWidget } from '../widgets';
|
||||||
import { WeatherIcon } from './WeatherIcon';
|
import { WeatherIcon } from './WeatherIcon';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const definition = defineWidget({
|
const definition = defineWidget({
|
||||||
id: 'weather',
|
id: 'weather',
|
||||||
@@ -52,6 +52,7 @@ interface WeatherTileProps {
|
|||||||
function WeatherTile({ widget }: WeatherTileProps) {
|
function WeatherTile({ widget }: WeatherTileProps) {
|
||||||
const { data: weather, isLoading, isError } = api.weather.at.useQuery(widget.properties.location);
|
const { data: weather, isLoading, isError } = api.weather.at.useQuery(widget.properties.location);
|
||||||
const { width, ref } = useElementSize();
|
const { width, ref } = useElementSize();
|
||||||
|
const { t } = useTranslation('modules/weather');
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
@@ -77,7 +78,7 @@ function WeatherTile({ widget }: WeatherTileProps) {
|
|||||||
if (isError) {
|
if (isError) {
|
||||||
return (
|
return (
|
||||||
<Center>
|
<Center>
|
||||||
<Text weight={500}>An error occured</Text>
|
<Text weight={500}>{t('error')}</Text>
|
||||||
</Center>
|
</Center>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user