mirror of
https://github.com/zoriya/flood.git
synced 2025-12-05 23:06:20 +00:00
client: migrate to lingui.js
This commit is contained in:
2
.github/workflows/check.yml
vendored
2
.github/workflows/check.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node: [15]
|
||||
check: [check-compiled-i18n, check-source-formatting, check-types, lint]
|
||||
check: [check-source-formatting, check-types, lint]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
51
.linguirc
Normal file
51
.linguirc
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"locales": [
|
||||
"af",
|
||||
"ar",
|
||||
"ca",
|
||||
"cs",
|
||||
"da",
|
||||
"de",
|
||||
"el",
|
||||
"en",
|
||||
"es",
|
||||
"fi",
|
||||
"fr",
|
||||
"he",
|
||||
"hu",
|
||||
"it",
|
||||
"ja",
|
||||
"ko",
|
||||
"nl",
|
||||
"no",
|
||||
"pl",
|
||||
"pt",
|
||||
"ro",
|
||||
"ru",
|
||||
"sr",
|
||||
"sv",
|
||||
"tr",
|
||||
"uk",
|
||||
"vi",
|
||||
"zh-Hans",
|
||||
"zh-Hant"
|
||||
],
|
||||
"sourceLocale": "en",
|
||||
"fallbackLocales": {
|
||||
"zh-Hans": "zh-Hant",
|
||||
"zh-Hant": "zh-Hans",
|
||||
"default": "en"
|
||||
},
|
||||
"catalogs": [
|
||||
{
|
||||
"path": "client/src/javascript/i18n/strings/{locale}",
|
||||
"include": [
|
||||
"<rootDir>/client/src/javascript"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
],
|
||||
"format": "minimal"
|
||||
}
|
||||
@@ -111,7 +111,6 @@ module.exports = {
|
||||
resolve: {
|
||||
extensions: ['.cjs', '.mjs', '.js', '.jsx', '.ts', '.tsx', '.json'],
|
||||
alias: {
|
||||
'react-intl': 'react-intl/react-intl-no-parser.umd.min.js',
|
||||
'@client': path.resolve('./client/src/javascript'),
|
||||
'@shared': path.resolve('./shared'),
|
||||
},
|
||||
|
||||
@@ -11,7 +11,6 @@ import AppWrapper from './components/AppWrapper';
|
||||
import LoadingOverlay from './components/general/LoadingOverlay';
|
||||
import AsyncIntlProvider from './i18n/languages';
|
||||
import ConfigStore from './stores/ConfigStore';
|
||||
import SettingStore from './stores/SettingStore';
|
||||
import UIStore from './stores/UIStore';
|
||||
import history from './util/history';
|
||||
|
||||
@@ -76,7 +75,7 @@ const FloodApp: FC = observer(() => {
|
||||
|
||||
return (
|
||||
<Suspense fallback={<LoadingOverlay />}>
|
||||
<AsyncIntlProvider language={SettingStore.floodSettings.language}>
|
||||
<AsyncIntlProvider>
|
||||
<Router history={history}>
|
||||
<QueryParamProvider ReactRouterRoute={Route}>
|
||||
<AppWrapper className={ConfigStore.preferDark ? 'dark' : undefined}>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {FC} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import classnames from 'classnames';
|
||||
import {observer} from 'mobx-react';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import AlertStore from '@client/stores/AlertStore';
|
||||
import {CircleCheckmark, CircleExclamation} from '@client/ui/icons';
|
||||
@@ -32,7 +32,7 @@ const Alert: FC<AlertProps> = observer((props: AlertProps) => {
|
||||
<li className={alertClasses}>
|
||||
{icon}
|
||||
<span className="alert__content">
|
||||
<FormattedMessage
|
||||
<Trans
|
||||
id={id}
|
||||
values={{
|
||||
count,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useRef, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import {Button, Form, FormError, FormRow, Panel, PanelContent, PanelHeader, PanelFooter, Textbox} from '@client/ui';
|
||||
import AuthActions from '@client/actions/AuthActions';
|
||||
@@ -20,7 +20,7 @@ interface AuthFormProps {
|
||||
}
|
||||
|
||||
const AuthForm: FC<AuthFormProps> = ({mode}: AuthFormProps) => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const formRef = useRef<Form>(null);
|
||||
const clientConnectionSettingsRef = useRef<ClientConnectionSettings | null>(null);
|
||||
const [errorMessage, setErrorMessage] = useState<string | {id: string} | undefined>(undefined);
|
||||
@@ -102,30 +102,16 @@ const AuthForm: FC<AuthFormProps> = ({mode}: AuthFormProps) => {
|
||||
}}
|
||||
ref={formRef}>
|
||||
<PanelHeader>
|
||||
<h1>
|
||||
{isLoginMode
|
||||
? intl.formatMessage({
|
||||
id: 'auth.login',
|
||||
})
|
||||
: intl.formatMessage({
|
||||
id: 'auth.create.an.account',
|
||||
})}
|
||||
</h1>
|
||||
<h1>{isLoginMode ? i18n._('auth.login') : i18n._('auth.create.an.account')}</h1>
|
||||
</PanelHeader>
|
||||
<PanelContent>
|
||||
<p className="copy--lead">
|
||||
{isLoginMode
|
||||
? intl.formatMessage({
|
||||
id: 'auth.login.intro',
|
||||
})
|
||||
: intl.formatMessage({
|
||||
id: 'auth.create.an.account.intro',
|
||||
})}
|
||||
{isLoginMode ? i18n._('auth.login.intro') : i18n._('auth.create.an.account.intro')}
|
||||
</p>
|
||||
{errorMessage != null ? (
|
||||
<FormRow>
|
||||
<FormError isLoading={isSubmitting}>
|
||||
{typeof errorMessage === 'string' ? errorMessage : intl.formatMessage(errorMessage)}
|
||||
{typeof errorMessage === 'string' ? errorMessage : i18n._(errorMessage)}
|
||||
</FormError>
|
||||
</FormRow>
|
||||
) : null}
|
||||
@@ -159,18 +145,10 @@ const AuthForm: FC<AuthFormProps> = ({mode}: AuthFormProps) => {
|
||||
formRef.current.resetForm();
|
||||
}
|
||||
}}>
|
||||
{intl.formatMessage({
|
||||
id: 'auth.input.clear',
|
||||
})}
|
||||
{i18n._('auth.input.clear')}
|
||||
</Button>
|
||||
<Button isLoading={isSubmitting} type="submit">
|
||||
{isLoginMode
|
||||
? intl.formatMessage({
|
||||
id: 'auth.log.in',
|
||||
})
|
||||
: intl.formatMessage({
|
||||
id: 'auth.create.account',
|
||||
})}
|
||||
{isLoginMode ? i18n._('auth.log.in') : i18n._('auth.create.account')}
|
||||
</Button>
|
||||
</FormRow>
|
||||
</PanelFooter>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {FC, ReactText, useRef, useState} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import {
|
||||
Button,
|
||||
@@ -74,14 +74,14 @@ const ClientConnectionInterruption: FC = observer(() => {
|
||||
}}>
|
||||
<PanelHeader>
|
||||
<h1>
|
||||
<FormattedMessage id="connection-interruption.heading" />
|
||||
<Trans id="connection-interruption.heading" />
|
||||
</h1>
|
||||
</PanelHeader>
|
||||
<PanelContent>
|
||||
{error && (
|
||||
<FormRow>
|
||||
<FormError>
|
||||
<FormattedMessage id={error} />
|
||||
<Trans id={error} />
|
||||
</FormError>
|
||||
</FormRow>
|
||||
)}
|
||||
@@ -89,16 +89,16 @@ const ClientConnectionInterruption: FC = observer(() => {
|
||||
<FormRow>
|
||||
<Select id="action" onSelect={setSelection} defaultID="retry">
|
||||
<SelectItem key="retry" id="retry">
|
||||
<FormattedMessage id="connection-interruption.action.selection.retry" />
|
||||
<Trans id="connection-interruption.action.selection.retry" />
|
||||
</SelectItem>
|
||||
<SelectItem key="config" id="config">
|
||||
<FormattedMessage id="connection-interruption.action.selection.config" />
|
||||
<Trans id="connection-interruption.action.selection.config" />
|
||||
</SelectItem>
|
||||
</Select>
|
||||
</FormRow>
|
||||
) : (
|
||||
<p className="copy--lead">
|
||||
<FormattedMessage id="connection-interruption.not.admin" />
|
||||
<Trans id="connection-interruption.not.admin" />
|
||||
</p>
|
||||
)}
|
||||
{selection === 'config' && (
|
||||
@@ -113,12 +113,12 @@ const ClientConnectionInterruption: FC = observer(() => {
|
||||
<FormRow justify="end">
|
||||
{selection === 'retry' && (
|
||||
<Button type="submit" isLoading={isSubmitting}>
|
||||
<FormattedMessage id="button.retry" />
|
||||
<Trans id="button.retry" />
|
||||
</Button>
|
||||
)}
|
||||
{selection === 'config' && (
|
||||
<Button type="submit" isLoading={isSubmitting}>
|
||||
<FormattedMessage id="button.save" />
|
||||
<Trans id="button.save" />
|
||||
</Button>
|
||||
)}
|
||||
</FormRow>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import classnames from 'classnames';
|
||||
import {FC} from 'react';
|
||||
import {observer} from 'mobx-react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
import {useKeyPressEvent} from 'react-use';
|
||||
|
||||
import {ContextMenu} from '@client/ui';
|
||||
@@ -22,7 +22,7 @@ const ContextMenuMountPoint: FC<ContextMenuMountPointProps> = observer(({id}: Co
|
||||
y: 0,
|
||||
};
|
||||
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
useKeyPressEvent('Escape', () => UIActions.dismissContextMenu(id));
|
||||
|
||||
@@ -51,7 +51,7 @@ const ContextMenuMountPoint: FC<ContextMenuMountPointProps> = observer(({id}: Co
|
||||
className={classnames('menu__item__label--primary', {
|
||||
'has-action': item.labelAction,
|
||||
})}>
|
||||
<span className="menu__item__label">{intl.formatMessage({id: item.label})}</span>
|
||||
<span className="menu__item__label">{i18n._(item.label)}</span>
|
||||
{item.labelAction ? (
|
||||
<span className="menu__item__label__action">
|
||||
<item.labelAction />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, ReactNode} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
const secondsToDuration = (
|
||||
cumSeconds: number,
|
||||
@@ -59,19 +59,19 @@ const Duration: FC<DurationProps> = (props: DurationProps) => {
|
||||
const duration = value === -1 ? -1 : secondsToDuration(value);
|
||||
|
||||
if (duration === -1) {
|
||||
content = <FormattedMessage id="unit.time.infinity" />;
|
||||
content = <Trans id="unit.time.infinity" />;
|
||||
} else if (duration.years != null && duration.years > 0) {
|
||||
content = [
|
||||
<span className="duration--segment" key="years">
|
||||
{duration.years}
|
||||
<em className="unit">
|
||||
<FormattedMessage id="unit.time.year" />
|
||||
<Trans id="unit.time.year" />
|
||||
</em>
|
||||
</span>,
|
||||
<span className="duration--segment" key="weeks">
|
||||
{duration.weeks}
|
||||
<em className="unit">
|
||||
<FormattedMessage id="unit.time.week" />
|
||||
<Trans id="unit.time.week" />
|
||||
</em>
|
||||
</span>,
|
||||
];
|
||||
@@ -80,13 +80,13 @@ const Duration: FC<DurationProps> = (props: DurationProps) => {
|
||||
<span className="duration--segment" key="weeks">
|
||||
{duration.weeks}
|
||||
<em className="unit">
|
||||
<FormattedMessage id="unit.time.week" />
|
||||
<Trans id="unit.time.week" />
|
||||
</em>
|
||||
</span>,
|
||||
<span className="duration--segment" key="days">
|
||||
{duration.days}
|
||||
<em className="unit">
|
||||
<FormattedMessage id="unit.time.day" />
|
||||
<Trans id="unit.time.day" />
|
||||
</em>
|
||||
</span>,
|
||||
];
|
||||
@@ -95,13 +95,13 @@ const Duration: FC<DurationProps> = (props: DurationProps) => {
|
||||
<span className="duration--segment" key="days">
|
||||
{duration.days}
|
||||
<em className="unit">
|
||||
<FormattedMessage id="unit.time.day" />
|
||||
<Trans id="unit.time.day" />
|
||||
</em>
|
||||
</span>,
|
||||
<span className="duration--segment" key="hours">
|
||||
{duration.hours}
|
||||
<em className="unit">
|
||||
<FormattedMessage id="unit.time.hour" />
|
||||
<Trans id="unit.time.hour" />
|
||||
</em>
|
||||
</span>,
|
||||
];
|
||||
@@ -110,13 +110,13 @@ const Duration: FC<DurationProps> = (props: DurationProps) => {
|
||||
<span className="duration--segment" key="hours">
|
||||
{duration.hours}
|
||||
<em className="unit">
|
||||
<FormattedMessage id="unit.time.hour" />
|
||||
<Trans id="unit.time.hour" />
|
||||
</em>
|
||||
</span>,
|
||||
<span className="duration--segment" key="minutes">
|
||||
{duration.minutes}
|
||||
<em className="unit">
|
||||
<FormattedMessage id="unit.time.minute" />
|
||||
<Trans id="unit.time.minute" />
|
||||
</em>
|
||||
</span>,
|
||||
];
|
||||
@@ -125,13 +125,13 @@ const Duration: FC<DurationProps> = (props: DurationProps) => {
|
||||
<span className="duration--segment" key="minutes">
|
||||
{duration.minutes}
|
||||
<em className="unit">
|
||||
<FormattedMessage id="unit.time.minute" />
|
||||
<Trans id="unit.time.minute" />
|
||||
</em>
|
||||
</span>,
|
||||
<span className="duration--segment" key="seconds">
|
||||
{duration.seconds}
|
||||
<em className="unit">
|
||||
<FormattedMessage id="unit.time.second" />
|
||||
<Trans id="unit.time.second" />
|
||||
</em>
|
||||
</span>,
|
||||
];
|
||||
@@ -140,7 +140,7 @@ const Duration: FC<DurationProps> = (props: DurationProps) => {
|
||||
<span className="duration--segment">
|
||||
{duration.seconds}
|
||||
<em className="unit">
|
||||
<FormattedMessage id="unit.time.second" />
|
||||
<Trans id="unit.time.second" />
|
||||
</em>
|
||||
</span>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import classnames from 'classnames';
|
||||
import {FC} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import {CheckmarkThick} from '@client/ui/icons';
|
||||
|
||||
@@ -13,7 +13,7 @@ const ICONS = {
|
||||
};
|
||||
|
||||
const LoadingDependencyList: FC<{dependencies: Dependencies}> = ({dependencies}: {dependencies: Dependencies}) => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
return (
|
||||
<ul className="dependency-list">
|
||||
@@ -28,7 +28,7 @@ const LoadingDependencyList: FC<{dependencies: Dependencies}> = ({dependencies}:
|
||||
<li className={classes} key={id}>
|
||||
{satisfied != null ? <span className="dependency-list__dependency__icon">{statusIcon}</span> : null}
|
||||
<span className="dependency-list__dependency__message">
|
||||
{typeof message === 'string' ? message : intl.formatMessage(message)}
|
||||
{typeof message === 'string' ? message : i18n._(message)}
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, ReactNode, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import PriorityLevels from '../../constants/PriorityLevels';
|
||||
|
||||
@@ -24,7 +24,7 @@ const PriorityMeter: FC<PriorityMeterProps> = ({
|
||||
changePriorityFuncRef,
|
||||
onChange,
|
||||
}: PriorityMeterProps) => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const [priorityLevel, setPriorityLevel] = useState<number>(level);
|
||||
|
||||
const changePriority = () => {
|
||||
@@ -54,24 +54,16 @@ const PriorityMeter: FC<PriorityMeterProps> = ({
|
||||
let priorityLevelElement: ReactNode;
|
||||
switch (priorityLevels[priorityLevel as keyof typeof priorityLevels]) {
|
||||
case 'DONT_DOWNLOAD':
|
||||
priorityLevelElement = intl.formatMessage({
|
||||
id: 'priority.dont.download',
|
||||
});
|
||||
priorityLevelElement = i18n._('priority.dont.download');
|
||||
break;
|
||||
case 'HIGH':
|
||||
priorityLevelElement = intl.formatMessage({
|
||||
id: 'priority.high',
|
||||
});
|
||||
priorityLevelElement = i18n._('priority.high');
|
||||
break;
|
||||
case 'LOW':
|
||||
priorityLevelElement = intl.formatMessage({
|
||||
id: 'priority.low',
|
||||
});
|
||||
priorityLevelElement = i18n._('priority.low');
|
||||
break;
|
||||
default:
|
||||
priorityLevelElement = intl.formatMessage({
|
||||
id: 'priority.normal',
|
||||
});
|
||||
priorityLevelElement = i18n._('priority.normal');
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
import {FC} from 'react';
|
||||
import {FormattedNumber, useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import {compute, getTranslationString} from '../../util/size';
|
||||
|
||||
const renderNumber = (computedNumber: ReturnType<typeof compute>) => {
|
||||
if (Number.isNaN(computedNumber.value)) {
|
||||
return '—';
|
||||
}
|
||||
|
||||
return <FormattedNumber value={computedNumber.value} />;
|
||||
};
|
||||
|
||||
interface SizeProps {
|
||||
value: number;
|
||||
precision?: number;
|
||||
@@ -20,26 +12,19 @@ interface SizeProps {
|
||||
|
||||
const Size: FC<SizeProps> = ({value, isSpeed, className, precision}: SizeProps) => {
|
||||
const computed = compute(value, precision);
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
let translatedUnit = intl.formatMessage({
|
||||
id: getTranslationString(computed.unit),
|
||||
});
|
||||
let translatedUnit = i18n._(getTranslationString(computed.unit));
|
||||
|
||||
if (isSpeed) {
|
||||
translatedUnit = intl.formatMessage(
|
||||
{
|
||||
id: 'unit.speed',
|
||||
},
|
||||
{
|
||||
baseUnit: translatedUnit,
|
||||
},
|
||||
);
|
||||
translatedUnit = i18n._('unit.speed', {
|
||||
baseUnit: translatedUnit,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<span className={className}>
|
||||
{renderNumber(computed)}
|
||||
{Number.isNaN(computed.value) ? '—' : i18n.number(computed.value)}
|
||||
<em className="unit">{translatedUnit}</em>
|
||||
</span>
|
||||
);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import {FC} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import {compute, getTranslationString} from '../../util/size';
|
||||
import TransferDataStore from '../../stores/TransferDataStore';
|
||||
|
||||
const WindowTitle: FC = observer(() => {
|
||||
const {transferSummary: summary} = TransferDataStore;
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
let title = 'Flood';
|
||||
|
||||
@@ -15,25 +15,15 @@ const WindowTitle: FC = observer(() => {
|
||||
const down = compute(summary.downRate);
|
||||
const up = compute(summary.upRate);
|
||||
|
||||
const formattedDownSpeed = intl.formatNumber(down.value);
|
||||
const formattedUpSpeed = intl.formatNumber(up.value);
|
||||
const formattedDownSpeed = i18n.number(down.value);
|
||||
const formattedUpSpeed = i18n.number(up.value);
|
||||
|
||||
const translatedDownUnit = intl.formatMessage(
|
||||
{
|
||||
id: 'unit.speed',
|
||||
},
|
||||
{
|
||||
baseUnit: intl.formatMessage({id: getTranslationString(down.unit)}),
|
||||
},
|
||||
);
|
||||
const translatedUpUnit = intl.formatMessage(
|
||||
{
|
||||
id: 'unit.speed',
|
||||
},
|
||||
{
|
||||
baseUnit: intl.formatMessage({id: getTranslationString(up.unit)}),
|
||||
},
|
||||
);
|
||||
const translatedDownUnit = i18n._('unit.speed', {
|
||||
baseUnit: i18n._(getTranslationString(down.unit)),
|
||||
});
|
||||
const translatedUpUnit = i18n._('unit.speed', {
|
||||
baseUnit: i18n._(getTranslationString(up.unit)),
|
||||
});
|
||||
|
||||
title = `↓ ${formattedDownSpeed} ${translatedDownUnit} ↑ ${formattedUpSpeed} ${translatedUpUnit} - Flood`;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, ReactNode, useEffect, useState} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {FormRow, Select, SelectItem} from '@client/ui';
|
||||
|
||||
@@ -20,7 +20,7 @@ interface ClientConnectionSettingsFormProps {
|
||||
const ClientConnectionSettingsForm: FC<ClientConnectionSettingsFormProps> = ({
|
||||
onSettingsChange,
|
||||
}: ClientConnectionSettingsFormProps) => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const [selectedClient, setSelectedClient] = useState<ClientConnectionSettings['client']>(DEFAULT_SELECTION);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -47,16 +47,14 @@ const ClientConnectionSettingsForm: FC<ClientConnectionSettingsFormProps> = ({
|
||||
<FormRow>
|
||||
<Select
|
||||
id="client"
|
||||
label={intl.formatMessage({
|
||||
id: 'connection.settings.client.select',
|
||||
})}
|
||||
label={i18n._('connection.settings.client.select')}
|
||||
onSelect={(newSelectedClient) => {
|
||||
setSelectedClient(newSelectedClient as ClientConnectionSettings['client']);
|
||||
}}
|
||||
defaultID={DEFAULT_SELECTION}>
|
||||
{SUPPORTED_CLIENTS.map((client) => (
|
||||
<SelectItem key={client} id={client}>
|
||||
<FormattedMessage id={`connection.settings.${client.toLowerCase()}`} />
|
||||
<Trans id={`connection.settings.${client.toLowerCase()}`} />
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useState} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {FormGroup, FormRow, Textbox} from '@client/ui';
|
||||
|
||||
@@ -12,7 +12,7 @@ export interface QBittorrentConnectionSettingsProps {
|
||||
const QBittorrentConnectionSettingsForm: FC<QBittorrentConnectionSettingsProps> = ({
|
||||
onSettingsChange,
|
||||
}: QBittorrentConnectionSettingsProps) => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const [settings, setSettings] = useState<QBittorrentConnectionSettings>({
|
||||
client: 'qBittorrent',
|
||||
type: 'web',
|
||||
@@ -44,29 +44,23 @@ const QBittorrentConnectionSettingsForm: FC<QBittorrentConnectionSettingsProps>
|
||||
<Textbox
|
||||
onChange={(e) => handleFormChange('url', e.target.value)}
|
||||
id="url"
|
||||
label={<FormattedMessage id="connection.settings.qbittorrent.url" />}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'connection.settings.qbittorrent.url.input.placeholder',
|
||||
})}
|
||||
label={<Trans id="connection.settings.qbittorrent.url" />}
|
||||
placeholder={i18n._('connection.settings.qbittorrent.url.input.placeholder')}
|
||||
/>
|
||||
</FormRow>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
onChange={(e) => handleFormChange('username', e.target.value)}
|
||||
id="qbt-username"
|
||||
label={<FormattedMessage id="connection.settings.qbittorrent.username" />}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'connection.settings.qbittorrent.username.input.placeholder',
|
||||
})}
|
||||
label={<Trans id="connection.settings.qbittorrent.username" />}
|
||||
placeholder={i18n._('connection.settings.qbittorrent.username.input.placeholder')}
|
||||
autoComplete="off"
|
||||
/>
|
||||
<Textbox
|
||||
onChange={(e) => handleFormChange('password', e.target.value)}
|
||||
id="qbt-password"
|
||||
label={<FormattedMessage id="connection.settings.qbittorrent.password" />}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'connection.settings.qbittorrent.password.input.placeholder',
|
||||
})}
|
||||
label={<Trans id="connection.settings.qbittorrent.password" />}
|
||||
placeholder={i18n._('connection.settings.qbittorrent.password.input.placeholder')}
|
||||
autoComplete="off"
|
||||
type="password"
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useState} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {FormError, FormGroup, FormRow, FormRowGroup, Radio, Textbox} from '@client/ui';
|
||||
|
||||
@@ -12,7 +12,7 @@ export interface RTorrentConnectionSettingsProps {
|
||||
const RTorrentConnectionSettingsForm: FC<RTorrentConnectionSettingsProps> = ({
|
||||
onSettingsChange,
|
||||
}: RTorrentConnectionSettingsProps) => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const [type, setType] = useState<'tcp' | 'socket'>('socket');
|
||||
const [settings, setSettings] = useState<RTorrentConnectionSettings | null>(null);
|
||||
|
||||
@@ -47,10 +47,7 @@ const RTorrentConnectionSettingsForm: FC<RTorrentConnectionSettingsProps> = ({
|
||||
<FormRow>
|
||||
<FormGroup>
|
||||
<FormRow>
|
||||
<FormGroup
|
||||
label={intl.formatMessage({
|
||||
id: 'connection.settings.rtorrent.type',
|
||||
})}>
|
||||
<FormGroup label={i18n._('connection.settings.rtorrent.type')}>
|
||||
<FormRow>
|
||||
<Radio
|
||||
onClick={() => {
|
||||
@@ -60,7 +57,7 @@ const RTorrentConnectionSettingsForm: FC<RTorrentConnectionSettingsProps> = ({
|
||||
id="socket"
|
||||
grow={false}
|
||||
defaultChecked={type === 'socket'}>
|
||||
<FormattedMessage id="connection.settings.rtorrent.type.socket" />
|
||||
<Trans id="connection.settings.rtorrent.type.socket" />
|
||||
</Radio>
|
||||
<Radio
|
||||
onClick={() => {
|
||||
@@ -70,7 +67,7 @@ const RTorrentConnectionSettingsForm: FC<RTorrentConnectionSettingsProps> = ({
|
||||
id="tcp"
|
||||
grow={false}
|
||||
defaultChecked={type === 'tcp'}>
|
||||
<FormattedMessage id="connection.settings.rtorrent.type.tcp" />
|
||||
<Trans id="connection.settings.rtorrent.type.tcp" />
|
||||
</Radio>
|
||||
</FormRow>
|
||||
</FormGroup>
|
||||
@@ -78,28 +75,20 @@ const RTorrentConnectionSettingsForm: FC<RTorrentConnectionSettingsProps> = ({
|
||||
{type === 'tcp' ? (
|
||||
<FormRowGroup>
|
||||
<FormRow>
|
||||
<FormError>
|
||||
{intl.formatMessage({
|
||||
id: 'connection.settings.rtorrent.type.tcp.warning',
|
||||
})}
|
||||
</FormError>
|
||||
<FormError>{i18n._('connection.settings.rtorrent.type.tcp.warning')}</FormError>
|
||||
</FormRow>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
onChange={(e) => handleFormChange('host', e.target.value)}
|
||||
id="host"
|
||||
label={<FormattedMessage id="connection.settings.rtorrent.host" />}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'connection.settings.rtorrent.host.input.placeholder',
|
||||
})}
|
||||
label={<Trans id="connection.settings.rtorrent.host" />}
|
||||
placeholder={i18n._('connection.settings.rtorrent.host.input.placeholder')}
|
||||
/>
|
||||
<Textbox
|
||||
onChange={(e) => handleFormChange('port', Number(e.target.value))}
|
||||
id="port"
|
||||
label={<FormattedMessage id="connection.settings.rtorrent.port" />}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'connection.settings.rtorrent.port.input.placeholder',
|
||||
})}
|
||||
label={<Trans id="connection.settings.rtorrent.port" />}
|
||||
placeholder={i18n._('connection.settings.rtorrent.port.input.placeholder')}
|
||||
/>
|
||||
</FormRow>
|
||||
</FormRowGroup>
|
||||
@@ -108,10 +97,8 @@ const RTorrentConnectionSettingsForm: FC<RTorrentConnectionSettingsProps> = ({
|
||||
<Textbox
|
||||
onChange={(e) => handleFormChange('socket', e.target.value)}
|
||||
id="socket"
|
||||
label={<FormattedMessage id="connection.settings.rtorrent.socket" />}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'connection.settings.rtorrent.socket.input.placeholder',
|
||||
})}
|
||||
label={<Trans id="connection.settings.rtorrent.socket" />}
|
||||
placeholder={i18n._('connection.settings.rtorrent.socket.input.placeholder')}
|
||||
/>
|
||||
</FormRow>
|
||||
)}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useState} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {FormGroup, FormRow, Textbox} from '@client/ui';
|
||||
|
||||
@@ -12,7 +12,7 @@ export interface TransmissionConnectionSettingsProps {
|
||||
const TransmissionConnectionSettingsForm: FC<TransmissionConnectionSettingsProps> = ({
|
||||
onSettingsChange,
|
||||
}: TransmissionConnectionSettingsProps) => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const [settings, setSettings] = useState<TransmissionConnectionSettings>({
|
||||
client: 'Transmission',
|
||||
type: 'rpc',
|
||||
@@ -44,29 +44,23 @@ const TransmissionConnectionSettingsForm: FC<TransmissionConnectionSettingsProps
|
||||
<Textbox
|
||||
onChange={(e) => handleFormChange('url', e.target.value)}
|
||||
id="url"
|
||||
label={<FormattedMessage id="connection.settings.transmission.url" />}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'connection.settings.transmission.url.input.placeholder',
|
||||
})}
|
||||
label={<Trans id="connection.settings.transmission.url" />}
|
||||
placeholder={i18n._('connection.settings.transmission.url.input.placeholder')}
|
||||
/>
|
||||
</FormRow>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
onChange={(e) => handleFormChange('username', e.target.value)}
|
||||
id="transmission-username"
|
||||
label={<FormattedMessage id="connection.settings.transmission.username" />}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'connection.settings.transmission.username.input.placeholder',
|
||||
})}
|
||||
label={<Trans id="connection.settings.transmission.username" />}
|
||||
placeholder={i18n._('connection.settings.transmission.username.input.placeholder')}
|
||||
autoComplete="off"
|
||||
/>
|
||||
<Textbox
|
||||
onChange={(e) => handleFormChange('password', e.target.value)}
|
||||
id="transmission-password"
|
||||
label={<FormattedMessage id="connection.settings.transmission.password" />}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'connection.settings.transmission.password.input.placeholder',
|
||||
})}
|
||||
label={<Trans id="connection.settings.transmission.password" />}
|
||||
placeholder={i18n._('connection.settings.transmission.password.input.placeholder')}
|
||||
autoComplete="off"
|
||||
type="password"
|
||||
/>
|
||||
|
||||
@@ -1,28 +1,15 @@
|
||||
import {defineMessages, WrappedComponentProps} from 'react-intl';
|
||||
import {PureComponent, ReactNodeArray} from 'react';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import {Arrow, File, FolderClosedSolid} from '@client/ui/icons';
|
||||
import FloodActions from '@client/actions/FloodActions';
|
||||
|
||||
const MESSAGES = defineMessages({
|
||||
EACCES: {
|
||||
id: 'filesystem.error.eacces',
|
||||
},
|
||||
ENOENT: {
|
||||
id: 'filesystem.error.enoent',
|
||||
},
|
||||
emptyDirectory: {
|
||||
id: 'filesystem.empty.directory',
|
||||
},
|
||||
fetching: {
|
||||
id: 'filesystem.fetching',
|
||||
},
|
||||
unknownError: {
|
||||
id: 'filesystem.error.unknown',
|
||||
},
|
||||
});
|
||||
const MESSAGES = {
|
||||
EACCES: 'filesystem.error.eacces',
|
||||
ENOENT: 'filesystem.error.enoent',
|
||||
};
|
||||
|
||||
interface FilesystemBrowserProps extends WrappedComponentProps {
|
||||
interface FilesystemBrowserProps {
|
||||
selectable?: 'files' | 'directories';
|
||||
directory: string;
|
||||
onItemSelection?: (newDestination: string, isDirectory?: boolean) => void;
|
||||
@@ -108,7 +95,7 @@ class FilesystemBrowser extends PureComponent<FilesystemBrowserProps, Filesystem
|
||||
};
|
||||
|
||||
render() {
|
||||
const {intl, selectable} = this.props;
|
||||
const {selectable} = this.props;
|
||||
const {directories, errorResponse, files} = this.state;
|
||||
let errorMessage = null;
|
||||
let listItems = null;
|
||||
@@ -119,7 +106,9 @@ class FilesystemBrowser extends PureComponent<FilesystemBrowserProps, Filesystem
|
||||
shouldShowDirectoryList = false;
|
||||
errorMessage = (
|
||||
<div className="filesystem__directory-list__item filesystem__directory-list__item--message">
|
||||
<em>{intl.formatMessage(MESSAGES.fetching)}</em>
|
||||
<em>
|
||||
<Trans id="filesystem.fetching" />
|
||||
</em>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -127,11 +116,11 @@ class FilesystemBrowser extends PureComponent<FilesystemBrowserProps, Filesystem
|
||||
if (errorResponse && errorResponse.data && errorResponse.data.code) {
|
||||
shouldShowDirectoryList = false;
|
||||
|
||||
const messageConfig = MESSAGES[errorResponse.data.code as keyof typeof MESSAGES] || MESSAGES.unknownError;
|
||||
|
||||
errorMessage = (
|
||||
<div className="filesystem__directory-list__item filesystem__directory-list__item--message">
|
||||
<em>{intl.formatMessage(messageConfig)}</em>
|
||||
<em>
|
||||
<Trans id={MESSAGES[errorResponse.data.code as keyof typeof MESSAGES] || 'filesystem.error.unknown'} />
|
||||
</em>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -141,9 +130,7 @@ class FilesystemBrowser extends PureComponent<FilesystemBrowserProps, Filesystem
|
||||
className="filesystem__directory-list__item filesystem__directory-list__item--parent"
|
||||
onClick={this.handleParentDirectoryClick}>
|
||||
<Arrow />
|
||||
{intl.formatMessage({
|
||||
id: 'filesystem.parent.directory',
|
||||
})}
|
||||
<Trans id="filesystem.parent.directory" />
|
||||
</li>
|
||||
);
|
||||
|
||||
@@ -188,7 +175,9 @@ class FilesystemBrowser extends PureComponent<FilesystemBrowserProps, Filesystem
|
||||
if ((!listItems || listItems.length === 0) && !errorMessage) {
|
||||
errorMessage = (
|
||||
<div className="filesystem__directory-list__item filesystem__directory-list__item--message">
|
||||
<em>{intl.formatMessage(MESSAGES.emptyDirectory)}</em>
|
||||
<em>
|
||||
<Trans id="filesystem.empty.directory" />
|
||||
</em>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Dropzone from 'react-dropzone';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {FC, useEffect, useState} from 'react';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import {Close, File, Files} from '@client/ui/icons';
|
||||
import {FormRowItem} from '@client/ui';
|
||||
@@ -21,7 +21,7 @@ const FileDropzone: FC<FileDropzoneProps> = ({onFilesChanged}: FileDropzoneProps
|
||||
return (
|
||||
<FormRowItem>
|
||||
<label className="form__element__label">
|
||||
<FormattedMessage id="torrents.add.torrents.label" />
|
||||
<Trans id="torrents.add.torrents.label" />
|
||||
</label>
|
||||
{files.length > 0 ? (
|
||||
<ul
|
||||
@@ -76,9 +76,9 @@ const FileDropzone: FC<FileDropzoneProps> = ({onFilesChanged}: FileDropzoneProps
|
||||
<div className="dropzone__icon">
|
||||
<Files />
|
||||
</div>
|
||||
<FormattedMessage id="torrents.add.tab.file.drop" />{' '}
|
||||
<Trans id="torrents.add.tab.file.drop" />{' '}
|
||||
<span className="dropzone__browse-button">
|
||||
<FormattedMessage id="torrents.add.tab.file.browse" />
|
||||
<Trans id="torrents.add.tab.file.browse" />
|
||||
</span>
|
||||
.
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import debounce from 'lodash/debounce';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {forwardRef, MutableRefObject, ReactNode, useEffect, useRef, useState} from 'react';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
import {useEnsuredForwardedRef} from 'react-use';
|
||||
|
||||
import {Checkbox, ContextMenu, FormElementAddon, FormRow, FormRowGroup, Portal, Textbox} from '@client/ui';
|
||||
@@ -45,7 +45,7 @@ const FilesystemBrowserTextbox = forwardRef<HTMLInputElement, FilesystemBrowserT
|
||||
const formRowRef = useRef<HTMLDivElement>(null);
|
||||
const textboxRef = useEnsuredForwardedRef(ref as MutableRefObject<HTMLInputElement>);
|
||||
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
useEffect(() => {
|
||||
const closeDirectoryList = (): void => {
|
||||
@@ -71,14 +71,14 @@ const FilesystemBrowserTextbox = forwardRef<HTMLInputElement, FilesystemBrowserT
|
||||
if (showBasePathToggle) {
|
||||
toggles.push(
|
||||
<Checkbox grow={false} id="isBasePath" key="isBasePath">
|
||||
<FormattedMessage id="torrents.destination.base_path" />
|
||||
<Trans id="torrents.destination.base_path" />
|
||||
</Checkbox>,
|
||||
);
|
||||
}
|
||||
if (showCompletedToggle) {
|
||||
toggles.push(
|
||||
<Checkbox grow={false} id="isCompleted" key="isCompleted">
|
||||
<FormattedMessage id="torrents.destination.completed" />
|
||||
<Trans id="torrents.destination.completed" />
|
||||
</Checkbox>,
|
||||
);
|
||||
}
|
||||
@@ -86,7 +86,7 @@ const FilesystemBrowserTextbox = forwardRef<HTMLInputElement, FilesystemBrowserT
|
||||
// TODO: this is getting bloated. toggles can be moved to their own elements...
|
||||
toggles.push(
|
||||
<Checkbox grow={false} id="isSequential" key="isSequential">
|
||||
<FormattedMessage id="torrents.destination.sequential" />
|
||||
<Trans id="torrents.destination.sequential" />
|
||||
</Checkbox>,
|
||||
);
|
||||
}
|
||||
@@ -118,9 +118,7 @@ const FilesystemBrowserTextbox = forwardRef<HTMLInputElement, FilesystemBrowserT
|
||||
{leading: true},
|
||||
)}
|
||||
onClick={(event) => event.nativeEvent.stopImmediatePropagation()}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'torrents.add.destination.placeholder',
|
||||
})}
|
||||
placeholder={i18n._('torrents.add.destination.placeholder')}
|
||||
ref={textboxRef}>
|
||||
<FormElementAddon
|
||||
onClick={() => {
|
||||
@@ -140,7 +138,6 @@ const FilesystemBrowserTextbox = forwardRef<HTMLInputElement, FilesystemBrowserT
|
||||
triggerRef={textboxRef}>
|
||||
<FilesystemBrowser
|
||||
directory={destination}
|
||||
intl={intl}
|
||||
selectable={selectable}
|
||||
onItemSelection={(newDestination: string, isDirectory = true) => {
|
||||
if (textboxRef.current != null) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import classnames from 'classnames';
|
||||
import {FC, ReactNode, ReactNodeArray, useEffect, useRef, useState} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import sort from 'fast-sort';
|
||||
import {Trans} from '@lingui/react';
|
||||
import {useKeyPressEvent} from 'react-use';
|
||||
|
||||
import {ContextMenu, FormElementAddon, FormRowItem, Portal, SelectItem, Textbox} from '@client/ui';
|
||||
@@ -130,7 +130,7 @@ const TagSelect: FC<TagSelectProps> = ({defaultValue, placeholder, id, label, on
|
||||
setSelectedTags([...selectedTags.filter((key) => key !== ''), tag]);
|
||||
}
|
||||
}}>
|
||||
{tag === 'untagged' ? <FormattedMessage id="filter.untagged" /> : tag}
|
||||
{tag === 'untagged' ? <Trans id="filter.untagged" /> : tag}
|
||||
</SelectItem>,
|
||||
);
|
||||
return accumulator;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import ModalActions from '../ModalActions';
|
||||
import SettingStore from '../../../stores/SettingStore';
|
||||
@@ -13,33 +13,27 @@ const AddTorrentsActions: FC<AddTorrentsActionsProps> = ({
|
||||
isAddingTorrents,
|
||||
onAddTorrentsClick,
|
||||
}: AddTorrentsActionsProps) => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
return (
|
||||
<ModalActions
|
||||
actions={[
|
||||
{
|
||||
checked: Boolean(SettingStore.floodSettings.startTorrentsOnLoad),
|
||||
clickHandler: null,
|
||||
content: intl.formatMessage({
|
||||
id: 'torrents.add.start.label',
|
||||
}),
|
||||
content: i18n._('torrents.add.start.label'),
|
||||
id: 'start',
|
||||
triggerDismiss: false,
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
clickHandler: null,
|
||||
content: intl.formatMessage({
|
||||
id: 'button.cancel',
|
||||
}),
|
||||
content: i18n._('button.cancel'),
|
||||
triggerDismiss: true,
|
||||
type: 'tertiary',
|
||||
},
|
||||
{
|
||||
clickHandler: onAddTorrentsClick,
|
||||
content: intl.formatMessage({
|
||||
id: 'torrents.add.button.add',
|
||||
}),
|
||||
content: i18n._('torrents.add.button.add'),
|
||||
isLoading: isAddingTorrents,
|
||||
submit: true,
|
||||
triggerDismiss: false,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useRef, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import {Checkbox, Form, FormRow, Textbox} from '@client/ui';
|
||||
import {saveAddTorrentsUserPreferences} from '@client/util/userPreferences';
|
||||
@@ -25,74 +25,49 @@ type AddTorrentsByCreationFormData = {
|
||||
|
||||
const AddTorrentsByCreation: FC = () => {
|
||||
const formRef = useRef<Form>(null);
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const [isCreatingTorrents, setIsCreatingTorrents] = useState<boolean>(false);
|
||||
|
||||
return (
|
||||
<Form className="inverse" ref={formRef}>
|
||||
<FilesystemBrowserTextbox
|
||||
id="sourcePath"
|
||||
label={intl.formatMessage({
|
||||
id: 'torrents.create.source.path.label',
|
||||
})}
|
||||
/>
|
||||
<FilesystemBrowserTextbox id="sourcePath" label={i18n._('torrents.create.source.path.label')} />
|
||||
<TextboxRepeater
|
||||
id="trackers"
|
||||
label={intl.formatMessage({
|
||||
id: 'torrents.create.trackers.label',
|
||||
})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'torrents.create.tracker.input.placeholder',
|
||||
})}
|
||||
label={i18n._('torrents.create.trackers.label')}
|
||||
placeholder={i18n._('torrents.create.tracker.input.placeholder')}
|
||||
defaultValues={[{id: 0, value: ''}]}
|
||||
/>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
id="name"
|
||||
label={intl.formatMessage({
|
||||
id: 'torrents.create.base.name.label',
|
||||
})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'torrents.create.base.name.input.placeholder',
|
||||
})}
|
||||
label={i18n._('torrents.create.base.name.label')}
|
||||
placeholder={i18n._('torrents.create.base.name.input.placeholder')}
|
||||
/>
|
||||
</FormRow>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
id="comment"
|
||||
label={intl.formatMessage({
|
||||
id: 'torrents.create.comment.label',
|
||||
})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'torrents.create.comment.input.placeholder',
|
||||
})}
|
||||
label={i18n._('torrents.create.comment.label')}
|
||||
placeholder={i18n._('torrents.create.comment.input.placeholder')}
|
||||
/>
|
||||
</FormRow>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
id="infoSource"
|
||||
label={intl.formatMessage({
|
||||
id: 'torrents.create.info.source.label',
|
||||
})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'torrents.create.info.source.input.placeholder',
|
||||
})}
|
||||
label={i18n._('torrents.create.info.source.label')}
|
||||
placeholder={i18n._('torrents.create.info.source.input.placeholder')}
|
||||
/>
|
||||
</FormRow>
|
||||
<FormRow>
|
||||
<Checkbox grow={false} id="isPrivate">
|
||||
{intl.formatMessage({id: 'torrents.create.is.private.label'})}
|
||||
{i18n._('torrents.create.is.private.label')}
|
||||
</Checkbox>
|
||||
</FormRow>
|
||||
<FormRow>
|
||||
<TagSelect
|
||||
id="tags"
|
||||
label={intl.formatMessage({
|
||||
id: 'torrents.add.tags',
|
||||
})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'torrents.create.tags.input.placeholder',
|
||||
})}
|
||||
label={i18n._('torrents.add.tags')}
|
||||
placeholder={i18n._('torrents.create.tags.input.placeholder')}
|
||||
/>
|
||||
</FormRow>
|
||||
<AddTorrentsActions
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useRef, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import {Form, FormRow} from '@client/ui';
|
||||
import {saveAddTorrentsUserPreferences} from '@client/util/userPreferences';
|
||||
@@ -29,7 +29,7 @@ const AddTorrentsByFile: FC = () => {
|
||||
const textboxRef = useRef<HTMLInputElement>(null);
|
||||
const [isAddingTorrents, setIsAddingTorrents] = useState<boolean>(false);
|
||||
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
return (
|
||||
<Form className="inverse" ref={formRef}>
|
||||
@@ -42,9 +42,7 @@ const AddTorrentsByFile: FC = () => {
|
||||
</FormRow>
|
||||
<FormRow>
|
||||
<TagSelect
|
||||
label={intl.formatMessage({
|
||||
id: 'torrents.add.tags',
|
||||
})}
|
||||
label={i18n._('torrents.add.tags')}
|
||||
id="tags"
|
||||
onTagSelected={(tags) => {
|
||||
if (textboxRef.current != null) {
|
||||
@@ -59,9 +57,7 @@ const AddTorrentsByFile: FC = () => {
|
||||
</FormRow>
|
||||
<FilesystemBrowserTextbox
|
||||
id="destination"
|
||||
label={intl.formatMessage({
|
||||
id: 'torrents.add.destination.label',
|
||||
})}
|
||||
label={i18n._('torrents.add.destination.label')}
|
||||
ref={textboxRef}
|
||||
selectable="directories"
|
||||
showBasePathToggle
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useRef, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import ConfigStore from '@client/stores/ConfigStore';
|
||||
import {Form, FormRow} from '@client/ui';
|
||||
@@ -31,7 +31,7 @@ const AddTorrentsByURL: FC = () => {
|
||||
const textboxRef = useRef<HTMLInputElement>(null);
|
||||
const [isAddingTorrents, setIsAddingTorrents] = useState<boolean>(false);
|
||||
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
return (
|
||||
<Form className="inverse" ref={formRef}>
|
||||
@@ -39,9 +39,7 @@ const AddTorrentsByURL: FC = () => {
|
||||
id="urls"
|
||||
label={
|
||||
<div>
|
||||
{intl.formatMessage({
|
||||
id: 'torrents.add.torrents.label',
|
||||
})}
|
||||
{i18n._('torrents.add.torrents.label')}
|
||||
{typeof navigator.registerProtocolHandler === 'function' && (
|
||||
<em
|
||||
style={{cursor: 'pointer', fontSize: '0.8em', float: 'right'}}
|
||||
@@ -54,35 +52,25 @@ const AddTorrentsByURL: FC = () => {
|
||||
);
|
||||
}
|
||||
}}>
|
||||
{intl.formatMessage({
|
||||
id: 'torrents.add.tab.url.register.magnet.handler',
|
||||
})}
|
||||
{i18n._('torrents.add.tab.url.register.magnet.handler')}
|
||||
</em>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'torrents.add.tab.url.input.placeholder',
|
||||
})}
|
||||
placeholder={i18n._('torrents.add.tab.url.input.placeholder')}
|
||||
defaultValues={
|
||||
(UIStore.activeModal?.id === 'add-torrents' && UIStore.activeModal?.initialURLs) || [{id: 0, value: ''}]
|
||||
}
|
||||
/>
|
||||
<TextboxRepeater
|
||||
id="cookies"
|
||||
label={intl.formatMessage({
|
||||
id: 'torrents.add.cookies.label',
|
||||
})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'torrents.add.cookies.input.placeholder',
|
||||
})}
|
||||
label={i18n._('torrents.add.cookies.label')}
|
||||
placeholder={i18n._('torrents.add.cookies.input.placeholder')}
|
||||
/>
|
||||
<FormRow>
|
||||
<TagSelect
|
||||
id="tags"
|
||||
label={intl.formatMessage({
|
||||
id: 'torrents.add.tags',
|
||||
})}
|
||||
label={i18n._('torrents.add.tags')}
|
||||
onTagSelected={(tags) => {
|
||||
if (textboxRef.current != null) {
|
||||
const suggestedPath = SettingStore.floodSettings.torrentDestinations?.[tags[0]];
|
||||
@@ -96,9 +84,7 @@ const AddTorrentsByURL: FC = () => {
|
||||
</FormRow>
|
||||
<FilesystemBrowserTextbox
|
||||
id="destination"
|
||||
label={intl.formatMessage({
|
||||
id: 'torrents.add.destination.label',
|
||||
})}
|
||||
label={i18n._('torrents.add.destination.label')}
|
||||
ref={textboxRef}
|
||||
selectable="directories"
|
||||
showBasePathToggle
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import AddTorrentsByCreation from './AddTorrentsByCreation';
|
||||
import AddTorrentsByFile from './AddTorrentsByFile';
|
||||
@@ -9,26 +9,20 @@ import SettingStore from '../../../stores/SettingStore';
|
||||
import UIStore from '../../../stores/UIStore';
|
||||
|
||||
const AddTorrentsModal: FC = () => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
const tabs = {
|
||||
'by-url': {
|
||||
content: AddTorrentsByURL,
|
||||
label: intl.formatMessage({
|
||||
id: 'torrents.add.tab.url.title',
|
||||
}),
|
||||
label: i18n._('torrents.add.tab.url.title'),
|
||||
},
|
||||
'by-file': {
|
||||
content: AddTorrentsByFile,
|
||||
label: intl.formatMessage({
|
||||
id: 'torrents.add.tab.file.title',
|
||||
}),
|
||||
label: i18n._('torrents.add.tab.file.title'),
|
||||
},
|
||||
'by-creation': {
|
||||
content: AddTorrentsByCreation,
|
||||
label: intl.formatMessage({
|
||||
id: 'torrents.add.tab.create.title',
|
||||
}),
|
||||
label: i18n._('torrents.add.tab.create.title'),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -41,15 +35,7 @@ const AddTorrentsModal: FC = () => {
|
||||
initialTabId = SettingStore.floodSettings.UITorrentsAddTab ?? initialTabId;
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
heading={intl.formatMessage({
|
||||
id: 'torrents.add.heading',
|
||||
})}
|
||||
tabs={tabs}
|
||||
initialTabId={initialTabId}
|
||||
/>
|
||||
);
|
||||
return <Modal heading={i18n._('torrents.add.heading')} tabs={tabs} initialTabId={initialTabId} />;
|
||||
};
|
||||
|
||||
export default AddTorrentsModal;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {
|
||||
Button,
|
||||
@@ -34,30 +34,22 @@ const DownloadRuleForm: FC<DownloadRuleFormProps> = ({
|
||||
onCancel,
|
||||
}: DownloadRuleFormProps) => {
|
||||
const {feeds} = FeedStore;
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
return (
|
||||
<FormRowGroup>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
id="label"
|
||||
label={intl.formatMessage({
|
||||
id: 'feeds.label',
|
||||
})}
|
||||
defaultValue={rule.label}
|
||||
/>
|
||||
<Textbox id="label" label={i18n._('feeds.label')} defaultValue={rule.label} />
|
||||
<Select
|
||||
disabled={!feeds.length}
|
||||
id="feedID"
|
||||
label={intl.formatMessage({
|
||||
id: 'feeds.applicable.feed',
|
||||
})}
|
||||
label={i18n._('feeds.applicable.feed')}
|
||||
defaultID={rule.feedIDs?.[0]}>
|
||||
{feeds.length === 0
|
||||
? [
|
||||
<SelectItem key="empty" id="placeholder" isPlaceholder>
|
||||
<em>
|
||||
<FormattedMessage id="feeds.no.feeds.available" />
|
||||
<Trans id="feeds.no.feeds.available" />
|
||||
</em>
|
||||
</SelectItem>,
|
||||
]
|
||||
@@ -71,7 +63,7 @@ const DownloadRuleForm: FC<DownloadRuleFormProps> = ({
|
||||
[
|
||||
<SelectItem key="select-feed" id="placeholder" isPlaceholder>
|
||||
<em>
|
||||
<FormattedMessage id="feeds.select.feed" />
|
||||
<Trans id="feeds.select.feed" />
|
||||
</em>
|
||||
</SelectItem>,
|
||||
],
|
||||
@@ -81,23 +73,15 @@ const DownloadRuleForm: FC<DownloadRuleFormProps> = ({
|
||||
<FormRow>
|
||||
<Textbox
|
||||
id="match"
|
||||
label={intl.formatMessage({
|
||||
id: 'feeds.match.pattern',
|
||||
})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'feeds.regEx',
|
||||
})}
|
||||
label={i18n._('feeds.match.pattern')}
|
||||
placeholder={i18n._('feeds.regEx')}
|
||||
defaultValue={rule.match}
|
||||
width="three-eighths"
|
||||
/>
|
||||
<Textbox
|
||||
id="exclude"
|
||||
label={intl.formatMessage({
|
||||
id: 'feeds.exclude.pattern',
|
||||
})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'feeds.regEx',
|
||||
})}
|
||||
label={i18n._('feeds.exclude.pattern')}
|
||||
placeholder={i18n._('feeds.regEx')}
|
||||
defaultValue={rule.exclude}
|
||||
width="three-eighths"
|
||||
/>
|
||||
@@ -106,12 +90,8 @@ const DownloadRuleForm: FC<DownloadRuleFormProps> = ({
|
||||
<Textbox
|
||||
addonPlacement="after"
|
||||
id="check"
|
||||
label={intl.formatMessage({
|
||||
id: 'feeds.test.match',
|
||||
})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'feeds.check',
|
||||
})}>
|
||||
label={i18n._('feeds.test.match')}
|
||||
placeholder={i18n._('feeds.check')}>
|
||||
{isPatternMatched && (
|
||||
<FormElementAddon>
|
||||
<CheckmarkThick />
|
||||
@@ -123,9 +103,7 @@ const DownloadRuleForm: FC<DownloadRuleFormProps> = ({
|
||||
<FormRowItem>
|
||||
<FilesystemBrowserTextbox
|
||||
id="destination"
|
||||
label={intl.formatMessage({
|
||||
id: 'feeds.torrent.destination',
|
||||
})}
|
||||
label={i18n._('feeds.torrent.destination')}
|
||||
selectable="directories"
|
||||
suggested={rule.destination}
|
||||
showBasePathToggle
|
||||
@@ -133,25 +111,21 @@ const DownloadRuleForm: FC<DownloadRuleFormProps> = ({
|
||||
</FormRowItem>
|
||||
<TagSelect
|
||||
id="tags"
|
||||
label={intl.formatMessage({
|
||||
id: 'feeds.apply.tags',
|
||||
})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'feeds.tags',
|
||||
})}
|
||||
label={i18n._('feeds.apply.tags')}
|
||||
placeholder={i18n._('feeds.tags')}
|
||||
defaultValue={rule.tags}
|
||||
/>
|
||||
</FormRow>
|
||||
<FormRow>
|
||||
<br />
|
||||
<Checkbox id="startOnLoad" defaultChecked={rule.startOnLoad} matchTextboxHeight>
|
||||
<FormattedMessage id="feeds.start.on.load" />
|
||||
<Trans id="feeds.start.on.load" />
|
||||
</Checkbox>
|
||||
<Button onClick={onCancel}>
|
||||
<FormattedMessage id="button.cancel" />
|
||||
<Trans id="button.cancel" />
|
||||
</Button>
|
||||
<Button type="submit" isLoading={isSubmitting}>
|
||||
<FormattedMessage id="button.save.feed" />
|
||||
<Trans id="button.save.feed" />
|
||||
</Button>
|
||||
</FormRow>
|
||||
</FormRowGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {FC} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import {Close, Edit} from '@client/ui/icons';
|
||||
|
||||
@@ -22,7 +22,7 @@ const DownloadRuleList: FC<DownloadRuleListProps> = observer(
|
||||
return (
|
||||
<ul className="interactive-list">
|
||||
<li className="interactive-list__item">
|
||||
<FormattedMessage id="feeds.no.rules.defined" />
|
||||
<Trans id="feeds.no.rules.defined" />
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
@@ -40,7 +40,7 @@ const DownloadRuleList: FC<DownloadRuleListProps> = observer(
|
||||
<li
|
||||
className="interactive-list__detail-list__item
|
||||
interactive-list__detail interactive-list__detail--tertiary">
|
||||
<FormattedMessage id="feeds.exclude" />
|
||||
<Trans id="feeds.exclude" />
|
||||
{': '}
|
||||
{rule.exclude}
|
||||
</li>
|
||||
@@ -56,7 +56,7 @@ const DownloadRuleList: FC<DownloadRuleListProps> = observer(
|
||||
|
||||
tags = (
|
||||
<li className="interactive-list__detail-list__item interactive-list__detail interactive-list__detail--tertiary">
|
||||
<FormattedMessage id="feeds.tags" />
|
||||
<Trans id="feeds.tags" />
|
||||
{': '}
|
||||
{tagNodes}
|
||||
</li>
|
||||
@@ -76,7 +76,7 @@ const DownloadRuleList: FC<DownloadRuleListProps> = observer(
|
||||
className="interactive-list__detail-list__item
|
||||
interactive-list__detail-list__item--overflow
|
||||
interactive-list__detail interactive-list__detail--secondary">
|
||||
<FormattedMessage id="feeds.match.count" values={{count: matchedCount}} />
|
||||
<Trans id="feeds.match.count" values={{count: matchedCount}} />
|
||||
</li>
|
||||
{rule === currentRule && (
|
||||
<li
|
||||
@@ -95,7 +95,7 @@ const DownloadRuleList: FC<DownloadRuleListProps> = observer(
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}>
|
||||
<FormattedMessage id="feeds.match" />
|
||||
<Trans id="feeds.match" />
|
||||
{': '}
|
||||
{rule.match}
|
||||
</li>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, ReactNodeArray, useRef, useState} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {Button, Form, FormError, FormRow, FormRowItem} from '@client/ui';
|
||||
import FeedActions from '@client/actions/FeedActions';
|
||||
@@ -71,7 +71,7 @@ interface RuleFormData {
|
||||
|
||||
const DownloadRulesTab: FC = () => {
|
||||
const formRef = useRef<Form>(null);
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
const [currentRule, setCurrentRule] = useState<Rule | null>(null);
|
||||
const [errors, setErrors] = useState<Record<string, string | undefined>>({});
|
||||
@@ -161,13 +161,13 @@ const DownloadRulesTab: FC = () => {
|
||||
}}
|
||||
ref={formRef}>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="feeds.existing.rules" />
|
||||
<Trans id="feeds.existing.rules" />
|
||||
</ModalFormSectionHeader>
|
||||
{Object.keys(errors).reduce((memo: ReactNodeArray, key) => {
|
||||
if (errors[key as ValidatedField] != null) {
|
||||
memo.push(
|
||||
<FormRow key={`error-${key}`}>
|
||||
<FormError>{intl.formatMessage({id: errors?.[key as ValidatedField]})}</FormError>
|
||||
<FormError>{i18n._(errors?.[key as ValidatedField] as string)}</FormError>
|
||||
</FormRow>,
|
||||
);
|
||||
}
|
||||
@@ -212,7 +212,7 @@ const DownloadRulesTab: FC = () => {
|
||||
onClick={() => {
|
||||
setIsEditing(true);
|
||||
}}>
|
||||
<FormattedMessage id="button.new" />
|
||||
<Trans id="button.new" />
|
||||
</Button>
|
||||
</FormRow>
|
||||
)}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {Button, FormRow, FormRowGroup, Select, SelectItem, Textbox} from '@client/ui';
|
||||
|
||||
@@ -20,7 +20,7 @@ const FeedForm: FC<FeedFormProps> = ({
|
||||
isSubmitting,
|
||||
onCancel,
|
||||
}: FeedFormProps) => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const feedInterval = currentFeed?.interval ?? defaultFeed.interval;
|
||||
|
||||
let defaultIntervalTextValue = feedInterval;
|
||||
@@ -40,29 +40,21 @@ const FeedForm: FC<FeedFormProps> = ({
|
||||
<FormRow>
|
||||
<Textbox
|
||||
id="label"
|
||||
label={intl.formatMessage({
|
||||
id: 'feeds.label',
|
||||
})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'feeds.label',
|
||||
})}
|
||||
label={i18n._('feeds.label')}
|
||||
placeholder={i18n._('feeds.label')}
|
||||
defaultValue={currentFeed?.label ?? defaultFeed.label}
|
||||
/>
|
||||
<Textbox
|
||||
id="interval"
|
||||
label={intl.formatMessage({
|
||||
id: 'feeds.select.interval',
|
||||
})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'feeds.interval',
|
||||
})}
|
||||
label={i18n._('feeds.select.interval')}
|
||||
placeholder={i18n._('feeds.interval')}
|
||||
defaultValue={defaultIntervalTextValue}
|
||||
width="one-eighth"
|
||||
/>
|
||||
<Select labelOffset defaultID={defaultIntervalMultiplier} id="intervalMultiplier" width="one-eighth">
|
||||
{intervalMultipliers.map((interval) => (
|
||||
<SelectItem key={interval.value} id={interval.value}>
|
||||
{intl.formatMessage({id: interval.message})}
|
||||
{i18n._(interval.message)}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
@@ -70,17 +62,15 @@ const FeedForm: FC<FeedFormProps> = ({
|
||||
<FormRow>
|
||||
<Textbox
|
||||
id="url"
|
||||
label={intl.formatMessage({
|
||||
id: 'feeds.url',
|
||||
})}
|
||||
placeholder={intl.formatMessage({id: 'feeds.url'})}
|
||||
label={i18n._('feeds.url')}
|
||||
placeholder={i18n._('feeds.url')}
|
||||
defaultValue={currentFeed?.url ?? defaultFeed?.url}
|
||||
/>
|
||||
<Button labelOffset onClick={onCancel}>
|
||||
<FormattedMessage id="button.cancel" />
|
||||
<Trans id="button.cancel" />
|
||||
</Button>
|
||||
<Button labelOffset type="submit" isLoading={isSubmitting}>
|
||||
<FormattedMessage id="button.save.feed" />
|
||||
<Trans id="button.save.feed" />
|
||||
</Button>
|
||||
</FormRow>
|
||||
</FormRowGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {FC, ReactNodeArray} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import {Checkbox, FormRow} from '@client/ui';
|
||||
|
||||
@@ -42,7 +42,7 @@ const FeedItems: FC<FeedItemsProps> = observer(({selectedFeedID}: FeedItemsProps
|
||||
<ul className="interactive-list">
|
||||
<li className="interactive-list__item">
|
||||
<div className="interactive-list__label">
|
||||
<FormattedMessage id="feeds.no.items.matching" />
|
||||
<Trans id="feeds.no.items.matching" />
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {FC, useRef, useState} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {Button, Form, FormRow, Select, SelectItem, Textbox} from '@client/ui';
|
||||
import FeedActions from '@client/actions/FeedActions';
|
||||
@@ -11,7 +11,7 @@ import FeedItems from './FeedItems';
|
||||
import ModalFormSectionHeader from '../ModalFormSectionHeader';
|
||||
|
||||
const FeedItemsForm: FC = observer(() => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const manualAddingFormRef = useRef<Form>(null);
|
||||
const [selectedFeedID, setSelectedFeedID] = useState<string | null>(null);
|
||||
|
||||
@@ -55,22 +55,20 @@ const FeedItemsForm: FC = observer(() => {
|
||||
}}
|
||||
ref={manualAddingFormRef}>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="feeds.browse.feeds" />
|
||||
<Trans id="feeds.browse.feeds" />
|
||||
</ModalFormSectionHeader>
|
||||
<FormRow>
|
||||
<Select
|
||||
disabled={!feeds.length}
|
||||
grow={false}
|
||||
id="feedID"
|
||||
label={intl.formatMessage({
|
||||
id: 'feeds.select.feed',
|
||||
})}
|
||||
label={i18n._('feeds.select.feed')}
|
||||
width="three-eighths">
|
||||
{!feeds.length
|
||||
? [
|
||||
<SelectItem key="empty" id="placeholder" isPlaceholder>
|
||||
<em>
|
||||
<FormattedMessage id="feeds.no.feeds.available" />
|
||||
<Trans id="feeds.no.feeds.available" />
|
||||
</em>
|
||||
</SelectItem>,
|
||||
]
|
||||
@@ -89,26 +87,18 @@ const FeedItemsForm: FC = observer(() => {
|
||||
[
|
||||
<SelectItem key="select-feed" id="placeholder" isPlaceholder>
|
||||
<em>
|
||||
<FormattedMessage id="feeds.select.feed" />
|
||||
<Trans id="feeds.select.feed" />
|
||||
</em>
|
||||
</SelectItem>,
|
||||
],
|
||||
)}
|
||||
</Select>
|
||||
{selectedFeedID && (
|
||||
<Textbox
|
||||
id="search"
|
||||
label={intl.formatMessage({
|
||||
id: 'feeds.search.term',
|
||||
})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'feeds.search',
|
||||
})}
|
||||
/>
|
||||
<Textbox id="search" label={i18n._('feeds.search.term')} placeholder={i18n._('feeds.search')} />
|
||||
)}
|
||||
{selectedFeedID && (
|
||||
<Button key="button" type="submit" labelOffset>
|
||||
<FormattedMessage id="button.download" />
|
||||
<Trans id="button.download" />
|
||||
</Button>
|
||||
)}
|
||||
</FormRow>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {FC} from 'react';
|
||||
import {observer} from 'mobx-react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {Close, Edit} from '@client/ui/icons';
|
||||
|
||||
@@ -18,13 +18,13 @@ interface FeedListProps {
|
||||
const FeedList: FC<FeedListProps> = observer(
|
||||
({currentFeed, intervalMultipliers, onSelect, onRemove}: FeedListProps) => {
|
||||
const {feeds} = FeedStore;
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
if (feeds.length === 0) {
|
||||
return (
|
||||
<ul className="interactive-list">
|
||||
<li className="interactive-list__item">
|
||||
<FormattedMessage id="feeds.no.feeds.defined" />
|
||||
<Trans id="feeds.no.feeds.defined" />
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
@@ -60,7 +60,7 @@ const FeedList: FC<FeedListProps> = observer(
|
||||
className="interactive-list__detail-list__item
|
||||
interactive-list__detail-list__item--overflow
|
||||
interactive-list__detail interactive-list__detail--secondary">
|
||||
<FormattedMessage id="feeds.match.count" values={{count: matchedCount}} />
|
||||
<Trans id="feeds.match.count" values={{count: matchedCount}} />
|
||||
</li>
|
||||
{feed === currentFeed && (
|
||||
<li
|
||||
@@ -74,7 +74,7 @@ const FeedList: FC<FeedListProps> = observer(
|
||||
<li
|
||||
className="interactive-list__detail-list__item
|
||||
interactive-list__detail interactive-list__detail--tertiary">
|
||||
{`${intervalText} ${intl.formatMessage({id: intervalMultiplierMessage})}`}
|
||||
{`${intervalText} ${i18n._(intervalMultiplierMessage)}`}
|
||||
</li>
|
||||
<li
|
||||
className="interactive-list__detail-list__item
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useEffect} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import DownloadRulesTab from './DownloadRulesTab';
|
||||
import FeedActions from '../../../actions/FeedActions';
|
||||
@@ -7,7 +7,7 @@ import FeedsTab from './FeedsTab';
|
||||
import Modal from '../Modal';
|
||||
|
||||
const FeedsModal: FC = () => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
useEffect(() => {
|
||||
FeedActions.fetchFeedMonitors();
|
||||
@@ -16,28 +16,15 @@ const FeedsModal: FC = () => {
|
||||
const tabs = {
|
||||
feeds: {
|
||||
content: FeedsTab,
|
||||
label: intl.formatMessage({
|
||||
id: 'feeds.tabs.feeds',
|
||||
}),
|
||||
label: i18n._('feeds.tabs.feeds'),
|
||||
},
|
||||
downloadRules: {
|
||||
content: DownloadRulesTab,
|
||||
label: intl.formatMessage({
|
||||
id: 'feeds.tabs.download.rules',
|
||||
}),
|
||||
label: i18n._('feeds.tabs.download.rules'),
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
heading={intl.formatMessage({
|
||||
id: 'feeds.tabs.heading',
|
||||
})}
|
||||
orientation="horizontal"
|
||||
size="large"
|
||||
tabs={tabs}
|
||||
/>
|
||||
);
|
||||
return <Modal heading={i18n._('feeds.tabs.heading')} orientation="horizontal" size="large" tabs={tabs} />;
|
||||
};
|
||||
|
||||
export default FeedsModal;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, ReactNodeArray, useRef, useState} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {Button, Form, FormError, FormRow, FormRowItem} from '@client/ui';
|
||||
import FeedActions from '@client/actions/FeedActions';
|
||||
@@ -63,7 +63,7 @@ const defaultFeed: AddFeedOptions = {
|
||||
|
||||
const FeedsTab: FC = () => {
|
||||
const formRef = useRef<Form>(null);
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const [currentFeed, setCurrentFeed] = useState<Feed | null>(null);
|
||||
const [errors, setErrors] = useState<Record<string, string | undefined>>({});
|
||||
const [isEditing, setIsEditing] = useState<boolean>(false);
|
||||
@@ -134,13 +134,13 @@ const FeedsTab: FC = () => {
|
||||
}}
|
||||
ref={formRef}>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="feeds.existing.feeds" />
|
||||
<Trans id="feeds.existing.feeds" />
|
||||
</ModalFormSectionHeader>
|
||||
{Object.keys(errors).reduce((memo: ReactNodeArray, key) => {
|
||||
if (errors[key as ValidatedField] != null) {
|
||||
memo.push(
|
||||
<FormRow key={`error-${key}`}>
|
||||
<FormError>{intl.formatMessage({id: errors?.[key as ValidatedField]})}</FormError>
|
||||
<FormError>{i18n._(errors?.[key as ValidatedField] as string)}</FormError>
|
||||
</FormRow>,
|
||||
);
|
||||
}
|
||||
@@ -192,7 +192,7 @@ const FeedsTab: FC = () => {
|
||||
onClick={() => {
|
||||
setIsEditing(true);
|
||||
}}>
|
||||
<FormattedMessage id="button.new" />
|
||||
<Trans id="button.new" />
|
||||
</Button>
|
||||
</FormRow>
|
||||
)}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useEffect, useRef, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import {CheckmarkThick, Clipboard} from '@client/ui/icons';
|
||||
import {Form, FormElementAddon, FormError, FormRow, Textbox} from '@client/ui';
|
||||
@@ -25,7 +25,7 @@ const generateMagnet = (hash: string, trackers?: Array<string>): string => {
|
||||
const GenerateMagnetModal: FC = () => {
|
||||
const magnetTextboxRef = useRef<HTMLInputElement>(null);
|
||||
const magnetTrackersTextboxRef = useRef<HTMLInputElement>(null);
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
const [isMagnetCopied, setIsMagnetCopied] = useState<boolean>(false);
|
||||
const [isMagnetTrackersCopied, setIsMagnetTrackersCopied] = useState<boolean>(false);
|
||||
@@ -55,15 +55,13 @@ const GenerateMagnetModal: FC = () => {
|
||||
|
||||
return (
|
||||
<Modal
|
||||
heading={intl.formatMessage({
|
||||
id: 'torrents.generate.magnet.heading',
|
||||
})}
|
||||
heading={i18n._('torrents.generate.magnet.heading')}
|
||||
content={
|
||||
<div className="modal__content inverse">
|
||||
<Form>
|
||||
{TorrentStore.torrents[TorrentStore.selectedTorrents[0]]?.isPrivate ? (
|
||||
<FormRow>
|
||||
<FormError>{intl.formatMessage({id: 'torrents.generate.magnet.private.torrent'})}</FormError>
|
||||
<FormError>{i18n._('torrents.generate.magnet.private.torrent')}</FormError>
|
||||
</FormRow>
|
||||
) : null}
|
||||
<FormRow>
|
||||
@@ -71,7 +69,7 @@ const GenerateMagnetModal: FC = () => {
|
||||
id="magnet"
|
||||
ref={magnetTextboxRef}
|
||||
addonPlacement="after"
|
||||
label={intl.formatMessage({id: 'torrents.generate.magnet.magnet'})}
|
||||
label={i18n._('torrents.generate.magnet.magnet')}
|
||||
defaultValue={magnetLink}
|
||||
readOnly>
|
||||
<FormElementAddon
|
||||
@@ -94,10 +92,8 @@ const GenerateMagnetModal: FC = () => {
|
||||
{trackerState.isLoadingTrackers ? (
|
||||
<Textbox
|
||||
id="loading"
|
||||
label={intl.formatMessage({id: 'torrents.generate.magnet.magnet.with.trackers'})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'torrents.generate.magnet.loading.trackers',
|
||||
})}
|
||||
label={i18n._('torrents.generate.magnet.magnet.with.trackers')}
|
||||
placeholder={i18n._('torrents.generate.magnet.loading.trackers')}
|
||||
disabled
|
||||
/>
|
||||
) : (
|
||||
@@ -105,7 +101,7 @@ const GenerateMagnetModal: FC = () => {
|
||||
id="magnet-trackers"
|
||||
ref={magnetTrackersTextboxRef}
|
||||
addonPlacement="after"
|
||||
label={intl.formatMessage({id: 'torrents.generate.magnet.magnet.with.trackers'})}
|
||||
label={i18n._('torrents.generate.magnet.magnet.with.trackers')}
|
||||
defaultValue={trackerState.magnetTrackersLink}
|
||||
readOnly>
|
||||
<FormElementAddon
|
||||
@@ -131,9 +127,7 @@ const GenerateMagnetModal: FC = () => {
|
||||
actions={[
|
||||
{
|
||||
clickHandler: null,
|
||||
content: intl.formatMessage({
|
||||
id: 'button.close',
|
||||
}),
|
||||
content: i18n._('button.close'),
|
||||
triggerDismiss: true,
|
||||
type: 'tertiary',
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import {Form} from '@client/ui';
|
||||
import TorrentActions from '@client/actions/TorrentActions';
|
||||
@@ -31,14 +31,12 @@ const getSuggestedPath = (sources: Array<string>): string | undefined => {
|
||||
};
|
||||
|
||||
const MoveTorrents: FC = () => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const [isSettingDownloadPath, setIsSettingDownloadPath] = useState<boolean>(false);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
heading={intl.formatMessage({
|
||||
id: 'torrents.move.heading',
|
||||
})}
|
||||
heading={i18n._('torrents.move.heading')}
|
||||
content={
|
||||
<div className="modal__content">
|
||||
<Form
|
||||
@@ -71,31 +69,23 @@ const MoveTorrents: FC = () => {
|
||||
actions={[
|
||||
{
|
||||
checked: true,
|
||||
content: intl.formatMessage({
|
||||
id: 'torrents.move.data.label',
|
||||
}),
|
||||
content: i18n._('torrents.move.data.label'),
|
||||
id: 'moveFiles',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
checked: false,
|
||||
content: intl.formatMessage({
|
||||
id: 'torrents.move.check_hash.label',
|
||||
}),
|
||||
content: i18n._('torrents.move.check_hash.label'),
|
||||
id: 'isCheckHash',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
content: intl.formatMessage({
|
||||
id: 'button.cancel',
|
||||
}),
|
||||
content: i18n._('button.cancel'),
|
||||
triggerDismiss: true,
|
||||
type: 'tertiary',
|
||||
},
|
||||
{
|
||||
content: intl.formatMessage({
|
||||
id: 'torrents.move.button.set.location',
|
||||
}),
|
||||
content: i18n._('torrents.move.button.set.location'),
|
||||
isLoading: isSettingDownloadPath,
|
||||
submit: true,
|
||||
type: 'primary',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useState} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {Form, FormRow} from '@client/ui';
|
||||
import {saveDeleteTorrentsUserPreferences} from '@client/util/userPreferences';
|
||||
@@ -12,21 +12,19 @@ import Modal from '../Modal';
|
||||
import ModalActions from '../ModalActions';
|
||||
|
||||
const RemoveTorrentsModal: FC = () => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const [isRemoving, setIsRemoving] = useState<boolean>(false);
|
||||
const {selectedTorrents} = TorrentStore;
|
||||
|
||||
if (selectedTorrents.length === 0) {
|
||||
return (
|
||||
<Modal
|
||||
heading={intl.formatMessage({
|
||||
id: 'torrents.remove',
|
||||
})}
|
||||
heading={i18n._('torrents.remove')}
|
||||
content={
|
||||
<div className="modal__content inverse">
|
||||
<Form>
|
||||
<FormRow>
|
||||
<FormattedMessage id="torrents.remove.error.no.torrents.selected" />
|
||||
<Trans id="torrents.remove.error.no.torrents.selected" />
|
||||
</FormRow>
|
||||
</Form>
|
||||
</div>
|
||||
@@ -34,9 +32,7 @@ const RemoveTorrentsModal: FC = () => {
|
||||
actions={[
|
||||
{
|
||||
clickHandler: null,
|
||||
content: intl.formatMessage({
|
||||
id: 'button.ok',
|
||||
}),
|
||||
content: i18n._('button.ok'),
|
||||
triggerDismiss: true,
|
||||
type: 'primary',
|
||||
},
|
||||
@@ -47,9 +43,7 @@ const RemoveTorrentsModal: FC = () => {
|
||||
|
||||
return (
|
||||
<Modal
|
||||
heading={intl.formatMessage({
|
||||
id: 'torrents.remove',
|
||||
})}
|
||||
heading={i18n._('torrents.remove')}
|
||||
content={
|
||||
<div className="modal__content">
|
||||
<Form
|
||||
@@ -69,29 +63,23 @@ const RemoveTorrentsModal: FC = () => {
|
||||
});
|
||||
}}>
|
||||
<FormRow>
|
||||
<FormattedMessage id="torrents.remove.are.you.sure" values={{count: selectedTorrents.length}} />
|
||||
<Trans id="torrents.remove.are.you.sure" values={{count: selectedTorrents.length}} />
|
||||
</FormRow>
|
||||
<ModalActions
|
||||
actions={[
|
||||
{
|
||||
checked: SettingStore.floodSettings.deleteTorrentData,
|
||||
content: intl.formatMessage({
|
||||
id: 'torrents.remove.delete.data',
|
||||
}),
|
||||
content: i18n._('torrents.remove.delete.data'),
|
||||
id: 'deleteData',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
content: intl.formatMessage({
|
||||
id: 'button.no',
|
||||
}),
|
||||
content: i18n._('button.no'),
|
||||
triggerDismiss: true,
|
||||
type: 'tertiary',
|
||||
},
|
||||
{
|
||||
content: intl.formatMessage({
|
||||
id: 'button.yes',
|
||||
}),
|
||||
content: i18n._('button.yes'),
|
||||
isLoading: isRemoving,
|
||||
submit: true,
|
||||
type: 'primary',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useRef, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import {Form, FormRow} from '@client/ui';
|
||||
import TorrentActions from '@client/actions/TorrentActions';
|
||||
@@ -10,14 +10,12 @@ import TagSelect from '../../general/form-elements/TagSelect';
|
||||
|
||||
const SetTagsModal: FC = () => {
|
||||
const formRef = useRef<Form>(null);
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const [isSettingTags, setIsSettingTags] = useState<boolean>(false);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
heading={intl.formatMessage({
|
||||
id: 'torrents.set.tags.heading',
|
||||
})}
|
||||
heading={i18n._('torrents.set.tags.heading')}
|
||||
content={
|
||||
<div className="modal__content inverse">
|
||||
<Form ref={formRef}>
|
||||
@@ -27,9 +25,7 @@ const SetTagsModal: FC = () => {
|
||||
.map((hash: string) => TorrentStore.torrents[hash].tags)[0]
|
||||
.slice()}
|
||||
id="tags"
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'torrents.set.tags.enter.tags',
|
||||
})}
|
||||
placeholder={i18n._('torrents.set.tags.enter.tags')}
|
||||
/>
|
||||
</FormRow>
|
||||
</Form>
|
||||
@@ -37,17 +33,13 @@ const SetTagsModal: FC = () => {
|
||||
}
|
||||
actions={[
|
||||
{
|
||||
content: intl.formatMessage({
|
||||
id: 'button.cancel',
|
||||
}),
|
||||
content: i18n._('button.cancel'),
|
||||
clickHandler: null,
|
||||
triggerDismiss: true,
|
||||
type: 'tertiary',
|
||||
},
|
||||
{
|
||||
content: intl.formatMessage({
|
||||
id: 'torrents.set.tags.button.set',
|
||||
}),
|
||||
content: i18n._('torrents.set.tags.button.set'),
|
||||
clickHandler: () => {
|
||||
if (formRef.current == null) {
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useEffect, useRef, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import {Form, FormRow, Textbox} from '@client/ui';
|
||||
import TorrentActions from '@client/actions/TorrentActions';
|
||||
@@ -13,7 +13,7 @@ import TextboxRepeater, {getTextArray} from '../../general/form-elements/Textbox
|
||||
|
||||
const SetTrackersModal: FC = () => {
|
||||
const formRef = useRef<Form>(null);
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const [isSettingTrackers, setIsSettingTrackers] = useState<boolean>(false);
|
||||
const [trackerState, setTrackerState] = useState<{
|
||||
isLoadingTrackers: boolean;
|
||||
@@ -38,28 +38,18 @@ const SetTrackersModal: FC = () => {
|
||||
|
||||
return (
|
||||
<Modal
|
||||
heading={intl.formatMessage({
|
||||
id: 'torrents.set.trackers.heading',
|
||||
})}
|
||||
heading={i18n._('torrents.set.trackers.heading')}
|
||||
content={
|
||||
<div className="modal__content inverse">
|
||||
<Form ref={formRef}>
|
||||
{trackerState.isLoadingTrackers ? (
|
||||
<FormRow>
|
||||
<Textbox
|
||||
id="loading"
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'torrents.set.trackers.loading.trackers',
|
||||
})}
|
||||
disabled
|
||||
/>
|
||||
<Textbox id="loading" placeholder={i18n._('torrents.set.trackers.loading.trackers')} disabled />
|
||||
</FormRow>
|
||||
) : (
|
||||
<TextboxRepeater
|
||||
id="trackers"
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'torrents.set.trackers.enter.tracker',
|
||||
})}
|
||||
placeholder={i18n._('torrents.set.trackers.enter.tracker')}
|
||||
defaultValues={
|
||||
trackerState.trackerURLs.length === 0
|
||||
? undefined
|
||||
@@ -76,9 +66,7 @@ const SetTrackersModal: FC = () => {
|
||||
actions={[
|
||||
{
|
||||
clickHandler: null,
|
||||
content: intl.formatMessage({
|
||||
id: 'button.cancel',
|
||||
}),
|
||||
content: i18n._('button.cancel'),
|
||||
triggerDismiss: true,
|
||||
type: 'tertiary',
|
||||
},
|
||||
@@ -101,9 +89,7 @@ const SetTrackersModal: FC = () => {
|
||||
UIStore.dismissModal();
|
||||
});
|
||||
},
|
||||
content: intl.formatMessage({
|
||||
id: 'torrents.set.trackers.button.set',
|
||||
}),
|
||||
content: i18n._('torrents.set.trackers.button.set'),
|
||||
isLoading: isSettingTrackers || trackerState.isLoadingTrackers,
|
||||
triggerDismiss: false,
|
||||
type: 'primary',
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import classnames from 'classnames';
|
||||
import {CSSTransition, TransitionGroup} from 'react-transition-group';
|
||||
import {FC, useEffect, useRef, useState} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {Button, Checkbox, Form, FormError, FormRowItem, FormRow, LoadingRing, Textbox} from '@client/ui';
|
||||
import {Close} from '@client/ui/icons';
|
||||
@@ -29,7 +29,7 @@ const AuthTab: FC = observer(() => {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [isUserListFetched, setIsUserListFetched] = useState<boolean>(false);
|
||||
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
useEffect(() => {
|
||||
if (AuthStore.currentUser.isAdmin) {
|
||||
@@ -43,11 +43,11 @@ const AuthTab: FC = observer(() => {
|
||||
return (
|
||||
<Form>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="auth.user.accounts" />
|
||||
<Trans id="auth.user.accounts" />
|
||||
</ModalFormSectionHeader>
|
||||
<FormRow>
|
||||
<FormError>
|
||||
<FormattedMessage id="auth.message.not.admin" />
|
||||
<Trans id="auth.message.not.admin" />
|
||||
</FormError>
|
||||
</FormRow>
|
||||
</Form>
|
||||
@@ -106,7 +106,7 @@ const AuthTab: FC = observer(() => {
|
||||
}}
|
||||
ref={formRef}>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="auth.user.accounts" />
|
||||
<Trans id="auth.user.accounts" />
|
||||
</ModalFormSectionHeader>
|
||||
<FormRow>
|
||||
<FormRowItem>
|
||||
@@ -139,7 +139,7 @@ const AuthTab: FC = observer(() => {
|
||||
} else {
|
||||
badge = (
|
||||
<span className="interactive-list__label__tag tag">
|
||||
<FormattedMessage id="auth.current.user" />
|
||||
<Trans id="auth.current.user" />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -162,32 +162,28 @@ const AuthTab: FC = observer(() => {
|
||||
</FormRowItem>
|
||||
</FormRow>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="auth.add.user" />
|
||||
<Trans id="auth.add.user" />
|
||||
</ModalFormSectionHeader>
|
||||
{error && (
|
||||
<FormRow>
|
||||
<FormError>{intl.formatMessage({id: error})}</FormError>
|
||||
<FormError>{i18n._(error)}</FormError>
|
||||
</FormRow>
|
||||
)}
|
||||
<FormRow>
|
||||
<Textbox
|
||||
id="username"
|
||||
label={<FormattedMessage id="auth.username" />}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'auth.username',
|
||||
})}
|
||||
label={<Trans id="auth.username" />}
|
||||
placeholder={i18n._('auth.username')}
|
||||
autoComplete="username"
|
||||
/>
|
||||
<Textbox
|
||||
id="password"
|
||||
label={<FormattedMessage id="auth.password" />}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'auth.password',
|
||||
})}
|
||||
label={<Trans id="auth.password" />}
|
||||
placeholder={i18n._('auth.password')}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
<Checkbox grow={false} id="isAdmin" labelOffset matchTextboxHeight>
|
||||
<FormattedMessage id="auth.admin" />
|
||||
<Trans id="auth.admin" />
|
||||
</Checkbox>
|
||||
</FormRow>
|
||||
<ClientConnectionSettingsForm
|
||||
@@ -198,7 +194,7 @@ const AuthTab: FC = observer(() => {
|
||||
<p />
|
||||
<FormRow justify="end">
|
||||
<Button isLoading={isSubmitting} priority="primary" type="submit">
|
||||
<FormattedMessage id="button.add" />
|
||||
<Trans id="button.add" />
|
||||
</Button>
|
||||
</FormRow>
|
||||
</Form>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {FC, FormEvent, useState} from 'react';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import {Form, FormRow, Textbox} from '@client/ui';
|
||||
import SettingStore from '@client/stores/SettingStore';
|
||||
@@ -62,7 +62,7 @@ const BandwidthTab: FC<BandwidthTabProps> = ({onSettingsChange, onClientSettings
|
||||
onClientSettingsChange(newChangedClientSettings);
|
||||
}}>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="settings.bandwidth.transferrate.heading" />
|
||||
<Trans id="settings.bandwidth.transferrate.heading" />
|
||||
</ModalFormSectionHeader>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
@@ -71,7 +71,7 @@ const BandwidthTab: FC<BandwidthTabProps> = ({onSettingsChange, onClientSettings
|
||||
? processSpeedsForDisplay(SettingStore.floodSettings.speedLimits.download)
|
||||
: 0
|
||||
}
|
||||
label={<FormattedMessage id="settings.bandwidth.transferrate.dropdown.preset.download.label" />}
|
||||
label={<Trans id="settings.bandwidth.transferrate.dropdown.preset.download.label" />}
|
||||
id="dropdownPresetDownload"
|
||||
/>
|
||||
</FormRow>
|
||||
@@ -82,46 +82,46 @@ const BandwidthTab: FC<BandwidthTabProps> = ({onSettingsChange, onClientSettings
|
||||
? processSpeedsForDisplay(SettingStore.floodSettings.speedLimits.upload)
|
||||
: 0
|
||||
}
|
||||
label={<FormattedMessage id="settings.bandwidth.transferrate.dropdown.preset.upload.label" />}
|
||||
label={<Trans id="settings.bandwidth.transferrate.dropdown.preset.upload.label" />}
|
||||
id="dropdownPresetUpload"
|
||||
/>
|
||||
</FormRow>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'throttleGlobalDownSpeed')}
|
||||
label={<FormattedMessage id="settings.bandwidth.transferrate.global.throttle.download" />}
|
||||
label={<Trans id="settings.bandwidth.transferrate.global.throttle.download" />}
|
||||
id="throttleGlobalDownSpeed"
|
||||
/>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'throttleGlobalUpSpeed')}
|
||||
label={<FormattedMessage id="settings.bandwidth.transferrate.global.throttle.upload" />}
|
||||
label={<Trans id="settings.bandwidth.transferrate.global.throttle.upload" />}
|
||||
id="throttleGlobalUpSpeed"
|
||||
/>
|
||||
</FormRow>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="settings.bandwidth.slots.heading" />
|
||||
<Trans id="settings.bandwidth.slots.heading" />
|
||||
</ModalFormSectionHeader>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'throttleMaxUploads')}
|
||||
label={<FormattedMessage id="settings.bandwidth.slots.upload.label" />}
|
||||
label={<Trans id="settings.bandwidth.slots.upload.label" />}
|
||||
id="throttleMaxUploads"
|
||||
/>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'throttleMaxUploadsGlobal')}
|
||||
label={<FormattedMessage id="settings.bandwidth.slots.upload.global.label" />}
|
||||
label={<Trans id="settings.bandwidth.slots.upload.global.label" />}
|
||||
id="throttleMaxUploadsGlobal"
|
||||
/>
|
||||
</FormRow>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'throttleMaxDownloads')}
|
||||
label={<FormattedMessage id="settings.bandwidth.slots.download.label" />}
|
||||
label={<Trans id="settings.bandwidth.slots.download.label" />}
|
||||
id="throttleMaxDownloads"
|
||||
/>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'throttleMaxDownloadsGlobal')}
|
||||
label={<FormattedMessage id="settings.bandwidth.slots.download.global.label" />}
|
||||
label={<Trans id="settings.bandwidth.slots.download.global.label" />}
|
||||
id="throttleMaxDownloadsGlobal"
|
||||
/>
|
||||
</FormRow>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useState} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import {Checkbox, Form, FormRow, Textbox} from '@client/ui';
|
||||
|
||||
@@ -27,13 +27,13 @@ const ConnectivityTab: FC<ConnectivityTabProps> = ({onClientSettingsChange}: Con
|
||||
onClientSettingsChange(newChangedClientSettings);
|
||||
}}>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="settings.connectivity.incoming.heading" />
|
||||
<Trans id="settings.connectivity.incoming.heading" />
|
||||
</ModalFormSectionHeader>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'networkPortRange')}
|
||||
id="networkPortRange"
|
||||
label={<FormattedMessage id="settings.connectivity.port.range.label" />}
|
||||
label={<Trans id="settings.connectivity.port.range.label" />}
|
||||
width="one-quarter"
|
||||
/>
|
||||
<Checkbox
|
||||
@@ -42,7 +42,7 @@ const ConnectivityTab: FC<ConnectivityTabProps> = ({onClientSettingsChange}: Con
|
||||
id="networkPortRandom"
|
||||
labelOffset
|
||||
matchTextboxHeight>
|
||||
<FormattedMessage id="settings.connectivity.port.randomize.label" />
|
||||
<Trans id="settings.connectivity.port.randomize.label" />
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
defaultChecked={getChangedClientSetting(changedClientSettings, 'networkPortOpen')}
|
||||
@@ -50,29 +50,29 @@ const ConnectivityTab: FC<ConnectivityTabProps> = ({onClientSettingsChange}: Con
|
||||
id="networkPortOpen"
|
||||
labelOffset
|
||||
matchTextboxHeight>
|
||||
<FormattedMessage id="settings.connectivity.port.open.label" />
|
||||
<Trans id="settings.connectivity.port.open.label" />
|
||||
</Checkbox>
|
||||
</FormRow>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'networkLocalAddress')}
|
||||
id="networkLocalAddress"
|
||||
label={<FormattedMessage id="settings.connectivity.ip.hostname.label" />}
|
||||
label={<Trans id="settings.connectivity.ip.hostname.label" />}
|
||||
/>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'networkHttpMaxOpen')}
|
||||
id="networkHttpMaxOpen"
|
||||
label={<FormattedMessage id="settings.connectivity.max.http.connections" />}
|
||||
label={<Trans id="settings.connectivity.max.http.connections" />}
|
||||
/>
|
||||
</FormRow>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="settings.connectivity.dpd.heading" />
|
||||
<Trans id="settings.connectivity.dpd.heading" />
|
||||
</ModalFormSectionHeader>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'dhtPort')}
|
||||
id="dhtPort"
|
||||
label={<FormattedMessage id="settings.connectivity.dht.port.label" />}
|
||||
label={<Trans id="settings.connectivity.dht.port.label" />}
|
||||
width="one-quarter"
|
||||
/>
|
||||
<Checkbox
|
||||
@@ -81,7 +81,7 @@ const ConnectivityTab: FC<ConnectivityTabProps> = ({onClientSettingsChange}: Con
|
||||
id="dht"
|
||||
labelOffset
|
||||
matchTextboxHeight>
|
||||
<FormattedMessage id="settings.connectivity.dht.label" />
|
||||
<Trans id="settings.connectivity.dht.label" />
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
defaultChecked={getChangedClientSetting(changedClientSettings, 'protocolPex')}
|
||||
@@ -89,41 +89,41 @@ const ConnectivityTab: FC<ConnectivityTabProps> = ({onClientSettingsChange}: Con
|
||||
id="protocolPex"
|
||||
labelOffset
|
||||
matchTextboxHeight>
|
||||
<FormattedMessage id="settings.connectivity.peer.exchange.label" />
|
||||
<Trans id="settings.connectivity.peer.exchange.label" />
|
||||
</Checkbox>
|
||||
</FormRow>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="settings.connectivity.peers.heading" />
|
||||
<Trans id="settings.connectivity.peers.heading" />
|
||||
</ModalFormSectionHeader>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'throttleMinPeersNormal')}
|
||||
id="throttleMinPeersNormal"
|
||||
label={<FormattedMessage id="settings.connectivity.peers.min.label" />}
|
||||
label={<Trans id="settings.connectivity.peers.min.label" />}
|
||||
/>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'throttleMaxPeersNormal')}
|
||||
id="throttleMaxPeersNormal"
|
||||
label={<FormattedMessage id="settings.connectivity.peers.max.label" />}
|
||||
label={<Trans id="settings.connectivity.peers.max.label" />}
|
||||
/>
|
||||
</FormRow>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'throttleMinPeersSeed')}
|
||||
id="throttleMinPeersSeed"
|
||||
label={<FormattedMessage id="settings.connectivity.peers.seeding.min.label" />}
|
||||
label={<Trans id="settings.connectivity.peers.seeding.min.label" />}
|
||||
/>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'throttleMaxPeersSeed')}
|
||||
id="throttleMaxPeersSeed"
|
||||
label={<FormattedMessage id="settings.connectivity.peers.seeding.max.label" />}
|
||||
label={<Trans id="settings.connectivity.peers.seeding.max.label" />}
|
||||
/>
|
||||
</FormRow>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'trackersNumWant')}
|
||||
id="trackersNumWant"
|
||||
label={<FormattedMessage id="settings.connectivity.peers.desired.label" />}
|
||||
label={<Trans id="settings.connectivity.peers.desired.label" />}
|
||||
width="one-half"
|
||||
/>
|
||||
</FormRow>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import {Form, FormRow} from '@client/ui';
|
||||
|
||||
@@ -15,7 +15,7 @@ interface DiskUsageTabProps {
|
||||
const DiskUsageTab: FC<DiskUsageTabProps> = (props: DiskUsageTabProps) => (
|
||||
<Form>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="settings.diskusage.mount.points" />
|
||||
<Trans id="settings.diskusage.mount.points" />
|
||||
</ModalFormSectionHeader>
|
||||
<FormRow>
|
||||
<MountPointsList onSettingsChange={props.onSettingsChange} />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useState} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import {Checkbox, Form, FormRow, Textbox} from '@client/ui';
|
||||
|
||||
@@ -27,20 +27,20 @@ const ResourcesTab: FC<ResourcesTabProps> = ({onClientSettingsChange}: Resources
|
||||
onClientSettingsChange(newChangedClientSettings);
|
||||
}}>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="settings.resources.disk.heading" />
|
||||
<Trans id="settings.resources.disk.heading" />
|
||||
</ModalFormSectionHeader>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'directoryDefault')}
|
||||
id="directoryDefault"
|
||||
label={<FormattedMessage id="settings.resources.disk.download.location.label" />}
|
||||
label={<Trans id="settings.resources.disk.download.location.label" />}
|
||||
/>
|
||||
</FormRow>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
defaultValue={getChangedClientSetting(changedClientSettings, 'networkMaxOpenFiles')}
|
||||
id="networkMaxOpenFiles"
|
||||
label={<FormattedMessage id="settings.resources.max.open.files" />}
|
||||
label={<Trans id="settings.resources.max.open.files" />}
|
||||
width="one-half"
|
||||
/>
|
||||
<Checkbox
|
||||
@@ -49,11 +49,11 @@ const ResourcesTab: FC<ResourcesTabProps> = ({onClientSettingsChange}: Resources
|
||||
id="piecesHashOnCompletion"
|
||||
labelOffset
|
||||
matchTextboxHeight>
|
||||
<FormattedMessage id="settings.resources.disk.check.hash.label" />
|
||||
<Trans id="settings.resources.disk.check.hash.label" />
|
||||
</Checkbox>
|
||||
</FormRow>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="settings.resources.memory.heading" />
|
||||
<Trans id="settings.resources.memory.heading" />
|
||||
</ModalFormSectionHeader>
|
||||
<FormRow>
|
||||
<Textbox
|
||||
@@ -61,7 +61,7 @@ const ResourcesTab: FC<ResourcesTabProps> = ({onClientSettingsChange}: Resources
|
||||
id="piecesMemoryMax"
|
||||
label={
|
||||
<div>
|
||||
<FormattedMessage id="settings.resources.memory.max.label" /> <em className="unit">(MB)</em>
|
||||
<Trans id="settings.resources.memory.max.label" /> <em className="unit">(MB)</em>
|
||||
</div>
|
||||
}
|
||||
width="one-half"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
import {useMedia} from 'react-use';
|
||||
|
||||
import type {ClientSettings} from '@shared/types/ClientSettings';
|
||||
@@ -19,7 +19,7 @@ import UITab from './UITab';
|
||||
import UIStore from '../../../stores/UIStore';
|
||||
|
||||
const SettingsModal: FC = () => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const isSmallScreen = useMedia('(max-width: 720px)');
|
||||
|
||||
const [changedClientSettings, setChangedClientSettings] = useState<Partial<ClientSettings>>({});
|
||||
@@ -47,61 +47,47 @@ const SettingsModal: FC = () => {
|
||||
onClientSettingsChange: handleClientSettingsChange,
|
||||
onSettingsChange: handleFloodSettingsChange,
|
||||
},
|
||||
label: intl.formatMessage({
|
||||
id: 'settings.tabs.bandwidth',
|
||||
}),
|
||||
label: i18n._('settings.tabs.bandwidth'),
|
||||
},
|
||||
connectivity: {
|
||||
content: ConnectivityTab,
|
||||
props: {
|
||||
onClientSettingsChange: handleClientSettingsChange,
|
||||
},
|
||||
label: intl.formatMessage({
|
||||
id: 'settings.tabs.connectivity',
|
||||
}),
|
||||
label: i18n._('settings.tabs.connectivity'),
|
||||
},
|
||||
resources: {
|
||||
content: ResourcesTab,
|
||||
props: {
|
||||
onClientSettingsChange: handleClientSettingsChange,
|
||||
},
|
||||
label: intl.formatMessage({
|
||||
id: 'settings.tabs.resources',
|
||||
}),
|
||||
label: i18n._('settings.tabs.resources'),
|
||||
},
|
||||
...(ConfigStore.authMethod !== 'none'
|
||||
? {
|
||||
authentication: {
|
||||
content: AuthTab,
|
||||
label: intl.formatMessage({
|
||||
id: 'settings.tabs.authentication',
|
||||
}),
|
||||
label: i18n._('settings.tabs.authentication'),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
ui: {
|
||||
content: UITab,
|
||||
label: intl.formatMessage({
|
||||
id: 'settings.tabs.userinterface',
|
||||
}),
|
||||
label: i18n._('settings.tabs.userinterface'),
|
||||
props: {
|
||||
onSettingsChange: handleFloodSettingsChange,
|
||||
},
|
||||
},
|
||||
diskusage: {
|
||||
content: DiskUsageTab,
|
||||
label: intl.formatMessage({
|
||||
id: 'settings.tabs.diskusage',
|
||||
}),
|
||||
label: i18n._('settings.tabs.diskusage'),
|
||||
props: {
|
||||
onSettingsChange: handleFloodSettingsChange,
|
||||
},
|
||||
},
|
||||
about: {
|
||||
content: AboutTab,
|
||||
label: intl.formatMessage({
|
||||
id: 'settings.tabs.about',
|
||||
}),
|
||||
label: i18n._('settings.tabs.about'),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -110,9 +96,7 @@ const SettingsModal: FC = () => {
|
||||
actions={[
|
||||
{
|
||||
clickHandler: null,
|
||||
content: intl.formatMessage({
|
||||
id: 'button.cancel',
|
||||
}),
|
||||
content: i18n._('button.cancel'),
|
||||
triggerDismiss: true,
|
||||
type: 'tertiary',
|
||||
},
|
||||
@@ -132,17 +116,13 @@ const SettingsModal: FC = () => {
|
||||
});
|
||||
},
|
||||
isLoading: isSavingSettings,
|
||||
content: intl.formatMessage({
|
||||
id: 'button.save',
|
||||
}),
|
||||
content: i18n._('button.save'),
|
||||
triggerDismiss: false,
|
||||
type: 'primary',
|
||||
},
|
||||
]}
|
||||
size="large"
|
||||
heading={intl.formatMessage({
|
||||
id: 'settings.tabs.heading',
|
||||
})}
|
||||
heading={i18n._('settings.tabs.heading')}
|
||||
orientation={isSmallScreen ? 'horizontal' : 'vertical'}
|
||||
tabs={tabs}
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {FC, useState} from 'react';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {Form, FormRow, Select, SelectItem, Radio} from '@client/ui';
|
||||
import Languages from '@client/constants/Languages';
|
||||
@@ -18,7 +18,7 @@ interface UITabProps {
|
||||
}
|
||||
|
||||
const UITab: FC<UITabProps> = ({onSettingsChange}: UITabProps) => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const [torrentListViewSize, setTorrentListViewSize] = useState(SettingStore.floodSettings.torrentListViewSize);
|
||||
const [selectedLanguage, setSelectedLanguage] = useState(SettingStore.floodSettings.language);
|
||||
const [UITagSelectorMode, setUITagSelectorMode] = useState(SettingStore.floodSettings.UITagSelectorMode);
|
||||
@@ -46,55 +46,53 @@ const UITab: FC<UITabProps> = ({onSettingsChange}: UITabProps) => {
|
||||
}
|
||||
}}>
|
||||
<ModalFormSectionHeader key="locale-header">
|
||||
<FormattedMessage id="settings.ui.language" />
|
||||
<Trans id="settings.ui.language" />
|
||||
</ModalFormSectionHeader>
|
||||
<FormRow key="locale-selection">
|
||||
<Select defaultID={selectedLanguage} id="language">
|
||||
{Object.keys(Languages).map((languageID) => (
|
||||
<SelectItem key={languageID} id={languageID}>
|
||||
{Languages[languageID as 'auto'].id != null
|
||||
? intl.formatMessage({
|
||||
id: Languages[languageID as 'auto'].id,
|
||||
})
|
||||
? i18n._(Languages[languageID as 'auto'].id)
|
||||
: Languages[languageID as Language]}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormRow>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="settings.ui.tag.selector.mode" />
|
||||
<Trans id="settings.ui.tag.selector.mode" />
|
||||
</ModalFormSectionHeader>
|
||||
<FormRow>
|
||||
<Radio defaultChecked={UITagSelectorMode === 'single'} groupID="ui-tag-selector-mode" id="single" width="auto">
|
||||
<FormattedMessage id="settings.ui.tag.selector.mode.single" />
|
||||
<Trans id="settings.ui.tag.selector.mode.single" />
|
||||
</Radio>
|
||||
<Radio defaultChecked={UITagSelectorMode === 'multi'} groupID="ui-tag-selector-mode" id="multi" width="auto">
|
||||
<FormattedMessage id="settings.ui.tag.selector.mode.multi" />
|
||||
<Trans id="settings.ui.tag.selector.mode.multi" />
|
||||
</Radio>
|
||||
</FormRow>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="settings.ui.torrent.list" />
|
||||
<Trans id="settings.ui.torrent.list" />
|
||||
</ModalFormSectionHeader>
|
||||
<FormRow>
|
||||
<Radio defaultChecked={torrentListViewSize === 'expanded'} groupID="ui-torrent-size" id="expanded" width="auto">
|
||||
<FormattedMessage id="settings.ui.torrent.size.expanded" />
|
||||
<Trans id="settings.ui.torrent.size.expanded" />
|
||||
</Radio>
|
||||
<Radio
|
||||
defaultChecked={torrentListViewSize === 'condensed'}
|
||||
groupID="ui-torrent-size"
|
||||
id="condensed"
|
||||
width="auto">
|
||||
<FormattedMessage id="settings.ui.torrent.size.condensed" />
|
||||
<Trans id="settings.ui.torrent.size.condensed" />
|
||||
</Radio>
|
||||
</FormRow>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="settings.ui.displayed.details" />
|
||||
<Trans id="settings.ui.displayed.details" />
|
||||
</ModalFormSectionHeader>
|
||||
<FormRow>
|
||||
<TorrentListColumnsList torrentListViewSize={torrentListViewSize} onSettingsChange={onSettingsChange} />
|
||||
</FormRow>
|
||||
<ModalFormSectionHeader>
|
||||
<FormattedMessage id="settings.ui.displayed.context.menu.items" />
|
||||
<Trans id="settings.ui.displayed.context.menu.items" />
|
||||
</ModalFormSectionHeader>
|
||||
<FormRow>
|
||||
<TorrentContextMenuActionsList onSettingsChange={onSettingsChange} />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Component} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import {Checkbox} from '@client/ui';
|
||||
import DiskUsageStore from '@client/stores/DiskUsageStore';
|
||||
@@ -88,7 +88,7 @@ class MountPointsList extends Component<MountPointsListProps, MountPointsListSta
|
||||
<Checkbox
|
||||
defaultChecked={visible}
|
||||
onClick={(event) => this.handleCheckboxValueChange(id, (event.target as HTMLInputElement).checked)}>
|
||||
<FormattedMessage id="settings.diskusage.show" />
|
||||
<Trans id="settings.diskusage.show" />
|
||||
</Checkbox>
|
||||
</span>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Component} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import {Checkbox} from '@client/ui';
|
||||
import SettingStore from '@client/stores/SettingStore';
|
||||
@@ -76,7 +76,7 @@ class TorrentContextMenuActionsList extends Component<
|
||||
<Checkbox
|
||||
defaultChecked={visible}
|
||||
onClick={(event) => this.handleCheckboxValueChange(id, (event.target as HTMLInputElement).checked)}>
|
||||
<FormattedMessage id="settings.ui.torrent.context.menu.items.show" />
|
||||
<Trans id="settings.ui.torrent.context.menu.items.show" />
|
||||
</Checkbox>
|
||||
</span>
|
||||
);
|
||||
@@ -85,7 +85,7 @@ class TorrentContextMenuActionsList extends Component<
|
||||
const content = (
|
||||
<div className="sortable-list__content sortable-list__content__wrapper">
|
||||
<span className="sortable-list__content sortable-list__content--primary">
|
||||
<FormattedMessage id={TorrentContextMenuActions[id].id} />
|
||||
<Trans id={TorrentContextMenuActions[id]} />
|
||||
</span>
|
||||
{checkbox}
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Component, ReactNode} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import {Checkbox} from '@client/ui';
|
||||
import {Error} from '@client/ui/icons';
|
||||
@@ -95,7 +95,7 @@ class TorrentListColumnsList extends Component<TorrentListColumnsListProps, Torr
|
||||
<Checkbox
|
||||
defaultChecked={visible}
|
||||
onClick={(event) => this.handleCheckboxValueChange(id, (event.target as HTMLInputElement).checked)}>
|
||||
<FormattedMessage id="settings.ui.torrent.details.enabled" />
|
||||
<Trans id="settings.ui.torrent.details.enabled" />
|
||||
</Checkbox>
|
||||
</span>
|
||||
);
|
||||
@@ -106,7 +106,7 @@ class TorrentListColumnsList extends Component<TorrentListColumnsListProps, Torr
|
||||
this.props.torrentListViewSize === 'expanded' &&
|
||||
index < this.state.torrentListColumns.length - 1
|
||||
) {
|
||||
const tooltipContent = <FormattedMessage id="settings.ui.torrent.details.tags.placement" />;
|
||||
const tooltipContent = <Trans id="settings.ui.torrent.details.tags.placement" />;
|
||||
|
||||
warning = (
|
||||
<Tooltip
|
||||
@@ -128,7 +128,7 @@ class TorrentListColumnsList extends Component<TorrentListColumnsListProps, Torr
|
||||
<div className="sortable-list__content sortable-list__content__wrapper">
|
||||
{warning}
|
||||
<span className="sortable-list__content sortable-list__content--primary">
|
||||
<FormattedMessage id={TorrentListColumns[id].id} />
|
||||
<Trans id={TorrentListColumns[id]} />
|
||||
</span>
|
||||
{checkbox}
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import classnames from 'classnames';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import {FC, useEffect, useState} from 'react';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {Button, Checkbox, Form, FormRow, FormRowItem, Select, SelectItem} from '@client/ui';
|
||||
import ConfigStore from '@client/stores/ConfigStore';
|
||||
@@ -19,7 +19,7 @@ const TorrentContents: FC = observer(() => {
|
||||
const [contents, setContents] = useState<TorrentContent[]>([]);
|
||||
const [itemsTree, setItemsTree] = useState<TorrentContentSelectionTree>({});
|
||||
const [selectedIndices, setSelectedIndices] = useState<number[]>([]);
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
useEffect(() => {
|
||||
if (UIStore.activeModal?.id === 'torrent-details') {
|
||||
@@ -85,7 +85,7 @@ const TorrentContents: FC = observer(() => {
|
||||
directoryHeadingIconContent = <Disk />;
|
||||
fileDetailContent = (
|
||||
<div className="directory-tree__node directory-tree__node--file">
|
||||
<FormattedMessage id="torrents.details.files.loading" />
|
||||
<Trans id="torrents.details.files.loading" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -128,7 +128,7 @@ const TorrentContents: FC = observer(() => {
|
||||
<div className="directory-tree__selection-toolbar">
|
||||
<FormRow align="center">
|
||||
<FormRowItem width="one-quarter" grow={false} shrink={false}>
|
||||
<FormattedMessage
|
||||
<Trans
|
||||
id="torrents.details.selected.files"
|
||||
values={{
|
||||
count: selectedIndices.length,
|
||||
@@ -154,7 +154,7 @@ const TorrentContents: FC = observer(() => {
|
||||
}}
|
||||
grow={false}
|
||||
shrink={false}>
|
||||
<FormattedMessage
|
||||
<Trans
|
||||
id="torrents.details.files.download.file"
|
||||
values={{
|
||||
count: selectedIndices.length,
|
||||
@@ -163,23 +163,11 @@ const TorrentContents: FC = observer(() => {
|
||||
</Button>
|
||||
<Select id="file-priority" persistentPlaceholder shrink={false} defaultID="">
|
||||
<SelectItem id={-1} isPlaceholder>
|
||||
<FormattedMessage id="torrents.details.selected.files.set.priority" />
|
||||
</SelectItem>
|
||||
<SelectItem id={0}>
|
||||
{intl.formatMessage({
|
||||
id: 'priority.dont.download',
|
||||
})}
|
||||
</SelectItem>
|
||||
<SelectItem id={1}>
|
||||
{intl.formatMessage({
|
||||
id: 'priority.normal',
|
||||
})}
|
||||
</SelectItem>
|
||||
<SelectItem id={2}>
|
||||
{intl.formatMessage({
|
||||
id: 'priority.high',
|
||||
})}
|
||||
<Trans id="torrents.details.selected.files.set.priority" />
|
||||
</SelectItem>
|
||||
<SelectItem id={0}>{i18n._('priority.dont.download')}</SelectItem>
|
||||
<SelectItem id={1}>{i18n._('priority.normal')}</SelectItem>
|
||||
<SelectItem id={2}>{i18n._('priority.high')}</SelectItem>
|
||||
</Select>
|
||||
</FormRow>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
import {useMedia} from 'react-use';
|
||||
|
||||
import Modal from '../Modal';
|
||||
@@ -11,40 +11,30 @@ import TorrentPeers from './TorrentPeers';
|
||||
import TorrentTrackers from './TorrentTrackers';
|
||||
|
||||
const TorrentDetailsModal: FC = () => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const isSmallScreen = useMedia('(max-width: 720px)');
|
||||
|
||||
const tabs = {
|
||||
'torrent-details': {
|
||||
content: TorrentGeneralInfo,
|
||||
label: intl.formatMessage({
|
||||
id: 'torrents.details.details',
|
||||
}),
|
||||
label: i18n._('torrents.details.details'),
|
||||
},
|
||||
'torrent-contents': {
|
||||
content: TorrentContents,
|
||||
label: intl.formatMessage({
|
||||
id: 'torrents.details.files',
|
||||
}),
|
||||
label: i18n._('torrents.details.files'),
|
||||
modalContentClasses: 'modal__content--nested-scroll',
|
||||
},
|
||||
'torrent-peers': {
|
||||
content: TorrentPeers,
|
||||
label: intl.formatMessage({
|
||||
id: 'torrents.details.peers',
|
||||
}),
|
||||
label: i18n._('torrents.details.peers'),
|
||||
},
|
||||
'torrent-trackers': {
|
||||
content: TorrentTrackers,
|
||||
label: intl.formatMessage({
|
||||
id: 'torrents.details.trackers',
|
||||
}),
|
||||
label: i18n._('torrents.details.trackers'),
|
||||
},
|
||||
'torrent-mediainfo': {
|
||||
content: TorrentMediainfo,
|
||||
label: intl.formatMessage({
|
||||
id: 'torrents.details.mediainfo',
|
||||
}),
|
||||
label: i18n._('torrents.details.mediainfo'),
|
||||
modalContentClasses: 'modal__content--nested-scroll',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {FC} from 'react';
|
||||
import {FormattedMessage, FormattedNumber, useIntl} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import type {TorrentProperties} from '@shared/types/Torrent';
|
||||
|
||||
@@ -16,7 +16,7 @@ const getTags = (tags: TorrentProperties['tags']) =>
|
||||
));
|
||||
|
||||
const TorrentGeneralInfo: FC = observer(() => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
if (UIStore.activeModal?.id !== 'torrent-details') {
|
||||
return null;
|
||||
@@ -39,7 +39,7 @@ const TorrentGeneralInfo: FC = observer(() => {
|
||||
|
||||
const VALUE_NOT_AVAILABLE = (
|
||||
<span className="not-available">
|
||||
<FormattedMessage id="torrents.details.general.none" />
|
||||
<Trans id="torrents.details.general.none" />
|
||||
</span>
|
||||
);
|
||||
|
||||
@@ -49,32 +49,34 @@ const TorrentGeneralInfo: FC = observer(() => {
|
||||
<tbody>
|
||||
<tr className="torrent-details__table__heading">
|
||||
<td className="torrent-details__table__heading--tertiary" colSpan={2}>
|
||||
<FormattedMessage id="torrents.details.general.heading.general" />
|
||||
<Trans id="torrents.details.general.heading.general" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="torrent-details__detail torrent-details__detail--dateAdded">
|
||||
<td className="torrent-details__detail__label">
|
||||
<FormattedMessage id="torrents.details.general.date.added" />
|
||||
<Trans id="torrents.details.general.date.added" />
|
||||
</td>
|
||||
<td className="torrent-details__detail__value">
|
||||
{dateAdded
|
||||
? `${intl.formatDate(dateAdded, {
|
||||
? `${i18n.date(dateAdded, {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: '2-digit',
|
||||
})} ${intl.formatTime(dateAdded)}`
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
})}`
|
||||
: VALUE_NOT_AVAILABLE}
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="torrent-details__detail torrent-details__detail--location">
|
||||
<td className="torrent-details__detail__label">
|
||||
<FormattedMessage id="torrents.details.general.location" />
|
||||
<Trans id="torrents.details.general.location" />
|
||||
</td>
|
||||
<td className="torrent-details__detail__value">{torrent.directory}</td>
|
||||
</tr>
|
||||
<tr className="torrent-details__detail torrent-details__detail--tags">
|
||||
<td className="torrent-details__detail__label">
|
||||
<FormattedMessage id="torrents.details.general.tags" />
|
||||
<Trans id="torrents.details.general.tags" />
|
||||
</td>
|
||||
<td className="torrent-details__detail__value">
|
||||
{torrent.tags.length ? getTags(torrent.tags) : VALUE_NOT_AVAILABLE}
|
||||
@@ -82,76 +84,78 @@ const TorrentGeneralInfo: FC = observer(() => {
|
||||
</tr>
|
||||
<tr className="torrent-details__table__heading">
|
||||
<td className="torrent-details__table__heading--tertiary" colSpan={2}>
|
||||
<FormattedMessage id="torrents.details.general.heading.transfer" />
|
||||
<Trans id="torrents.details.general.heading.transfer" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="torrent-details__detail torrent-details__detail--downloaded">
|
||||
<td className="torrent-details__detail__label">
|
||||
<FormattedMessage id="torrents.details.general.downloaded" />
|
||||
<Trans id="torrents.details.general.downloaded" />
|
||||
</td>
|
||||
<td className="torrent-details__detail__value">
|
||||
<FormattedNumber value={torrent.percentComplete} />
|
||||
{i18n.number(torrent.percentComplete)}
|
||||
<em className="unit">%</em>
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="torrent-details__detail torrent-details__detail--peers">
|
||||
<td className="torrent-details__detail__label">
|
||||
<FormattedMessage id="torrents.details.general.peers" />
|
||||
<Trans id="torrents.details.general.peers" />
|
||||
</td>
|
||||
<td className="torrent-details__detail__value">
|
||||
<FormattedMessage
|
||||
<Trans
|
||||
id="torrents.details.general.connected"
|
||||
values={{
|
||||
connectedCount: torrent.peersConnected,
|
||||
connected: <FormattedNumber value={torrent.peersConnected} />,
|
||||
total: <FormattedNumber value={torrent.peersTotal} />,
|
||||
connected: i18n.number(torrent.peersConnected),
|
||||
total: i18n.number(torrent.peersTotal),
|
||||
}}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="torrent-details__detail torrent-details__detail--seeds">
|
||||
<td className="torrent-details__detail__label">
|
||||
<FormattedMessage id="torrents.details.general.seeds" />
|
||||
<Trans id="torrents.details.general.seeds" />
|
||||
</td>
|
||||
<td className="torrent-details__detail__value">
|
||||
<FormattedMessage
|
||||
<Trans
|
||||
id="torrents.details.general.connected"
|
||||
values={{
|
||||
connectedCount: torrent.seedsConnected,
|
||||
connected: <FormattedNumber value={torrent.seedsConnected} />,
|
||||
total: <FormattedNumber value={torrent.seedsTotal} />,
|
||||
connected: i18n.number(torrent.seedsConnected),
|
||||
total: i18n.number(torrent.seedsTotal),
|
||||
}}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="torrent-details__table__heading">
|
||||
<td className="torrent-details__table__heading--tertiary" colSpan={2}>
|
||||
<FormattedMessage id="torrents.details.general.heading.torrent" />
|
||||
<Trans id="torrents.details.general.heading.torrent" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="torrent-details__detail torrent-details__detail--created">
|
||||
<td className="torrent-details__detail__label">
|
||||
<FormattedMessage id="torrents.details.general.date.created" />
|
||||
<Trans id="torrents.details.general.date.created" />
|
||||
</td>
|
||||
<td className="torrent-details__detail__value">
|
||||
{creation
|
||||
? `${intl.formatDate(creation, {
|
||||
? `${i18n.date(creation, {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: '2-digit',
|
||||
})} ${intl.formatTime(creation)}`
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
})}`
|
||||
: VALUE_NOT_AVAILABLE}
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="torrent-details__detail torrent-details__detail--hash">
|
||||
<td className="torrent-details__detail__label">
|
||||
<FormattedMessage id="torrents.details.general.hash" />
|
||||
<Trans id="torrents.details.general.hash" />
|
||||
</td>
|
||||
<td className="torrent-details__detail__value">{torrent.hash}</td>
|
||||
</tr>
|
||||
<tr className="torrent-details__detail torrent-details__detail--size">
|
||||
<td className="torrent-details__detail__label">
|
||||
<FormattedMessage id="torrents.details.general.size" />
|
||||
<Trans id="torrents.details.general.size" />
|
||||
</td>
|
||||
<td className="torrent-details__detail__value">
|
||||
<Size value={torrent.sizeBytes} />
|
||||
@@ -159,26 +163,22 @@ const TorrentGeneralInfo: FC = observer(() => {
|
||||
</tr>
|
||||
<tr className="torrent-details__detail torrent-details__detail--type">
|
||||
<td className="torrent-details__detail__label">
|
||||
<FormattedMessage id="torrents.details.general.type" />
|
||||
<Trans id="torrents.details.general.type" />
|
||||
</td>
|
||||
<td className="torrent-details__detail__value">
|
||||
{torrent.isPrivate
|
||||
? intl.formatMessage({
|
||||
id: 'torrents.details.general.type.private',
|
||||
})
|
||||
: intl.formatMessage({
|
||||
id: 'torrents.details.general.type.public',
|
||||
})}
|
||||
? i18n._('torrents.details.general.type.private')
|
||||
: i18n._('torrents.details.general.type.public')}
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="torrent-details__table__heading">
|
||||
<td className="torrent-details__table__heading--tertiary" colSpan={2}>
|
||||
<FormattedMessage id="torrents.details.general.heading.tracker" />
|
||||
<Trans id="torrents.details.general.heading.tracker" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="torrent-details__detail torrent-details__detail--tracker-message">
|
||||
<td className="torrent-details__detail__label">
|
||||
<FormattedMessage id="torrents.details.general.tracker.message" />
|
||||
<Trans id="torrents.details.general.tracker.message" />
|
||||
</td>
|
||||
<td className="torrent-details__detail__value">
|
||||
{torrent.message ? torrent.message : VALUE_NOT_AVAILABLE}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import classnames from 'classnames';
|
||||
import {FC, useEffect, useState} from 'react';
|
||||
import {FormattedMessage, FormattedNumber} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {Clock, DownloadThick, Ratio, Start, Stop, UploadThick} from '@client/ui/icons';
|
||||
import TorrentActions from '@client/actions/TorrentActions';
|
||||
@@ -16,6 +16,7 @@ import ProgressBar from '../../general/ProgressBar';
|
||||
import Size from '../../general/Size';
|
||||
|
||||
const TorrentHeading: FC = observer(() => {
|
||||
const {i18n} = useLingui();
|
||||
const torrent =
|
||||
UIStore.activeModal?.id === 'torrent-details' ? TorrentStore.torrents[UIStore.activeModal.hash] : undefined;
|
||||
const [torrentStatus, setTorrentStatus] = useState<'start' | 'stop'>('stop');
|
||||
@@ -61,7 +62,7 @@ const TorrentHeading: FC = observer(() => {
|
||||
</li>
|
||||
<li className="torrent-details__sub-heading__tertiary">
|
||||
<Ratio />
|
||||
<FormattedNumber value={torrent.ratio} />
|
||||
{i18n.number(torrent.ratio)}
|
||||
</li>
|
||||
<li className="torrent-details__sub-heading__tertiary">
|
||||
<Clock />
|
||||
@@ -95,7 +96,7 @@ const TorrentHeading: FC = observer(() => {
|
||||
});
|
||||
}}>
|
||||
<Start />
|
||||
<FormattedMessage id="torrents.details.actions.start" />
|
||||
<Trans id="torrents.details.actions.start" />
|
||||
</li>
|
||||
<li
|
||||
className={classnames('torrent-details__sub-heading__tertiary', 'torrent-details__action', {
|
||||
@@ -109,7 +110,7 @@ const TorrentHeading: FC = observer(() => {
|
||||
});
|
||||
}}>
|
||||
<Stop />
|
||||
<FormattedMessage id="torrents.details.actions.stop" />
|
||||
<Trans id="torrents.details.actions.stop" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import axios, {CancelTokenSource} from 'axios';
|
||||
import {FC, useEffect, useRef, useState} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {Button} from '@client/ui';
|
||||
import {Checkmark, Clipboard} from '@client/ui/icons';
|
||||
@@ -10,7 +10,7 @@ import UIStore from '@client/stores/UIStore';
|
||||
import Tooltip from '../../general/Tooltip';
|
||||
|
||||
const TorrentMediainfo: FC = () => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const cancelToken = useRef<CancelTokenSource>(axios.CancelToken.source());
|
||||
const clipboardRef = useRef<HTMLInputElement>(null);
|
||||
const [mediainfo, setMediainfo] = useState<string | null>(null);
|
||||
@@ -53,14 +53,12 @@ const TorrentMediainfo: FC = () => {
|
||||
<div className="mediainfo__toolbar">
|
||||
<div className="mediainfo__toolbar__item">
|
||||
<span className="torrent-details__table__heading--tertiary">
|
||||
<FormattedMessage id={headingMessageId} />
|
||||
<Trans id={headingMessageId} />
|
||||
</span>
|
||||
</div>
|
||||
{mediainfo && (
|
||||
<Tooltip
|
||||
content={intl.formatMessage({
|
||||
id: isCopiedToClipboard ? 'general.clipboard.copied' : 'general.clipboard.copy',
|
||||
})}
|
||||
content={i18n._(isCopiedToClipboard ? 'general.clipboard.copied' : 'general.clipboard.copy')}
|
||||
wrapperClassName="tooltip__wrapper mediainfo__toolbar__item">
|
||||
<Button
|
||||
priority="tertiary"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, Suspense, useEffect, useState} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {Trans} from '@lingui/react';
|
||||
import {useInterval} from 'react-use';
|
||||
|
||||
import {CheckmarkThick, CountryFlag, Lock, Spinner} from '@client/ui/icons';
|
||||
@@ -37,7 +37,7 @@ const TorrentPeers: FC = () => {
|
||||
<thead className="torrent-details__table__heading">
|
||||
<tr>
|
||||
<th className="torrent-details__table__heading--primary">
|
||||
<FormattedMessage id="torrents.details.peers" />
|
||||
<Trans id="torrents.details.peers" />
|
||||
<Badge>{peers.length}</Badge>
|
||||
</th>
|
||||
<th className="torrent-details__table__heading--secondary">DL</th>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC, useEffect, useState} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import type {TorrentTracker} from '@shared/types/TorrentTracker';
|
||||
|
||||
@@ -36,11 +36,11 @@ const TorrentTrackers: FC = () => {
|
||||
<thead className="torrent-details__table__heading">
|
||||
<tr>
|
||||
<th className="torrent-details__table__heading--primary">
|
||||
<FormattedMessage id="torrents.details.trackers" />
|
||||
<Trans id="torrents.details.trackers" />
|
||||
<Badge>{trackerCount}</Badge>
|
||||
</th>
|
||||
<th className="torrent-details__table__heading--secondary">
|
||||
<FormattedMessage id="torrents.details.trackers.type" />
|
||||
<Trans id="torrents.details.trackers.type" />
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {FC, ReactNode, ReactNodeArray} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import type {Disk} from '@shared/types/DiskUsage';
|
||||
|
||||
@@ -46,9 +46,9 @@ const DiskUsage: FC = observer(() => {
|
||||
<Tooltip
|
||||
content={
|
||||
<ul className="diskusage__details-list">
|
||||
<DiskUsageTooltipItem value={d.used} label={<FormattedMessage id="status.diskusage.used" />} />
|
||||
<DiskUsageTooltipItem value={d.avail} label={<FormattedMessage id="status.diskusage.free" />} />
|
||||
<DiskUsageTooltipItem value={d.size} label={<FormattedMessage id="status.diskusage.total" />} />
|
||||
<DiskUsageTooltipItem value={d.used} label={<Trans id="status.diskusage.used" />} />
|
||||
<DiskUsageTooltipItem value={d.avail} label={<Trans id="status.diskusage.free" />} />
|
||||
<DiskUsageTooltipItem value={d.size} label={<Trans id="status.diskusage.total" />} />
|
||||
</ul>
|
||||
}
|
||||
position="top"
|
||||
@@ -69,7 +69,7 @@ const DiskUsage: FC = observer(() => {
|
||||
return (
|
||||
<ul className="sidebar-filter sidebar__item">
|
||||
<li className="sidebar-filter__item sidebar-filter__item--heading">
|
||||
<FormattedMessage id="status.diskusage.title" />
|
||||
<Trans id="status.diskusage.title" />
|
||||
</li>
|
||||
{diskNodes}
|
||||
</ul>
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
import {defineMessages, useIntl} from 'react-intl';
|
||||
import {FC, useRef} from 'react';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import {Feed} from '@client/ui/icons';
|
||||
import UIActions from '@client/actions/UIActions';
|
||||
|
||||
import Tooltip from '../general/Tooltip';
|
||||
|
||||
const MESSAGES = defineMessages({
|
||||
feeds: {
|
||||
id: 'sidebar.button.feeds',
|
||||
},
|
||||
});
|
||||
|
||||
const FeedsButton: FC = () => {
|
||||
const intl = useIntl();
|
||||
const label = intl.formatMessage(MESSAGES.feeds);
|
||||
const {i18n} = useLingui();
|
||||
const tooltipRef = useRef<Tooltip>(null);
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content={label}
|
||||
content={i18n._('sidebar.button.feeds')}
|
||||
onClick={() => {
|
||||
if (tooltipRef.current != null) {
|
||||
tooltipRef.current.dismissTooltip();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import AuthActions from '@client/actions/AuthActions';
|
||||
import ConfigStore from '@client/stores/ConfigStore';
|
||||
@@ -8,7 +8,7 @@ import {Logout} from '@client/ui/icons';
|
||||
import Tooltip from '../general/Tooltip';
|
||||
|
||||
const LogoutButton: FC = () => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
if (ConfigStore.authMethod === 'none') {
|
||||
return null;
|
||||
@@ -16,9 +16,7 @@ const LogoutButton: FC = () => {
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content={intl.formatMessage({
|
||||
id: 'sidebar.button.log.out',
|
||||
})}
|
||||
content={i18n._('sidebar.button.log.out')}
|
||||
onClick={() =>
|
||||
AuthActions.logout().then(() => {
|
||||
window.location.reload();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import classnames from 'classnames';
|
||||
import {defineMessages, useIntl} from 'react-intl';
|
||||
import {FC, useEffect, useRef, useState} from 'react';
|
||||
import {observer} from 'mobx-react';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import FloodActions from '@client/actions/FloodActions';
|
||||
import {ChevronLeft, ChevronRight, LoadingIndicatorDots, Notification as NotificationIcon} from '@client/ui/icons';
|
||||
@@ -20,27 +20,6 @@ const fetchNotifications = (paginationStart: number) =>
|
||||
start: paginationStart,
|
||||
});
|
||||
|
||||
const MESSAGES = defineMessages({
|
||||
'notification.torrent.finished.heading': {
|
||||
id: 'notification.torrent.finished.heading',
|
||||
},
|
||||
'notification.torrent.finished.body': {
|
||||
id: 'notification.torrent.finished.body',
|
||||
},
|
||||
'notification.torrent.errored.heading': {
|
||||
id: 'notification.torrent.errored.heading',
|
||||
},
|
||||
'notification.torrent.errored.body': {
|
||||
id: 'notification.torrent.errored.body',
|
||||
},
|
||||
'notification.feed.torrent.added.heading': {
|
||||
id: 'notification.feed.torrent.added.heading',
|
||||
},
|
||||
'notification.feed.torrent.added.body': {
|
||||
id: 'notification.feed.torrent.added.body',
|
||||
},
|
||||
});
|
||||
|
||||
interface NotificationTopToolbarProps {
|
||||
paginationStart: number;
|
||||
notificationTotal: number;
|
||||
@@ -50,7 +29,7 @@ const NotificationTopToolbar: FC<NotificationTopToolbarProps> = ({
|
||||
paginationStart,
|
||||
notificationTotal,
|
||||
}: NotificationTopToolbarProps) => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
if (notificationTotal > NOTIFICATIONS_PER_PAGE) {
|
||||
let countStart = paginationStart + 1;
|
||||
@@ -67,19 +46,13 @@ const NotificationTopToolbar: FC<NotificationTopToolbarProps> = ({
|
||||
return (
|
||||
<div className="toolbar toolbar--dark toolbar--top tooltip__toolbar tooltip__content--padding-surrogate">
|
||||
<span className="toolbar__item toolbar__item--label">
|
||||
{`${intl.formatMessage({
|
||||
id: 'notification.showing',
|
||||
})} `}
|
||||
{`${i18n._('notification.showing')} `}
|
||||
<strong>
|
||||
{countStart}
|
||||
{` ${intl.formatMessage({
|
||||
id: 'general.to',
|
||||
})} `}
|
||||
{` ${i18n._('general.to')} `}
|
||||
{countEnd}
|
||||
</strong>
|
||||
{` ${intl.formatMessage({
|
||||
id: 'general.of',
|
||||
})} `}
|
||||
{` ${i18n._('general.of')} `}
|
||||
<strong>{notificationTotal}</strong>
|
||||
</span>
|
||||
</div>
|
||||
@@ -95,35 +68,24 @@ interface NotificationItemProps {
|
||||
}
|
||||
|
||||
const NotificationItem: FC<NotificationItemProps> = ({index, notification}: NotificationItemProps) => {
|
||||
const intl = useIntl();
|
||||
const date = intl.formatDate(notification.ts, {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: '2-digit',
|
||||
});
|
||||
const time = intl.formatTime(notification.ts);
|
||||
const {i18n} = useLingui();
|
||||
|
||||
return (
|
||||
<li className="notifications__list__item" key={index}>
|
||||
<div className="notification__heading">
|
||||
<span className="notification__category">
|
||||
{intl.formatMessage(
|
||||
MESSAGES[`${notification.id}.heading` as keyof typeof MESSAGES] || {id: 'general.error.unknown'},
|
||||
)}
|
||||
</span>
|
||||
<span className="notification__category">{i18n._(`${notification.id}.heading`)}</span>
|
||||
{' — '}
|
||||
<span className="notification__timestamp">{`${date} ${intl.formatMessage({
|
||||
id: 'general.at',
|
||||
})} ${time}`}</span>
|
||||
</div>
|
||||
<div className="notification__message">
|
||||
{intl.formatMessage(
|
||||
MESSAGES[`${notification.id}.body` as keyof typeof MESSAGES] || {
|
||||
id: 'general.error.unknown',
|
||||
},
|
||||
notification.data,
|
||||
)}
|
||||
<span className="notification__timestamp">
|
||||
{i18n.date(new Date(notification.ts), {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: '2-digit',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
<div className="notification__message">{i18n._(`${notification.id}.body`, notification.data)}</div>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
@@ -143,7 +105,7 @@ const NotificationBottomToolbar: FC<NotificationBottomToolbarProps> = ({
|
||||
onClearClick,
|
||||
onNextClick,
|
||||
}: NotificationBottomToolbarProps) => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
if (notificationTotal > 0) {
|
||||
const newerButtonClass = classnames('toolbar__item toolbar__item--button', 'tooltip__content--padding-surrogate', {
|
||||
@@ -178,9 +140,7 @@ const NotificationBottomToolbar: FC<NotificationBottomToolbarProps> = ({
|
||||
className="toolbar__item toolbar__item--button
|
||||
tooltip__content--padding-surrogate"
|
||||
onClick={onClearClick}>
|
||||
{intl.formatMessage({
|
||||
id: 'notification.clear.all',
|
||||
})}
|
||||
{i18n._('notification.clear.all')}
|
||||
</li>
|
||||
<li className={olderButtonClass} onClick={onNextClick}>
|
||||
{`${olderFrom} - ${olderTo}`}
|
||||
@@ -194,7 +154,7 @@ const NotificationBottomToolbar: FC<NotificationBottomToolbarProps> = ({
|
||||
};
|
||||
|
||||
const NotificationsButton: FC = observer(() => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
const tooltipRef = useRef<Tooltip>(null);
|
||||
const notificationsListRef = useRef<HTMLUListElement>(null);
|
||||
@@ -264,9 +224,7 @@ const NotificationsButton: FC = observer(() => {
|
||||
</div>
|
||||
) : (
|
||||
<div className="notifications tooltip__content--padding-surrogate" style={{textAlign: 'center'}}>
|
||||
{intl.formatMessage({
|
||||
id: 'notification.no.notification',
|
||||
})}
|
||||
{i18n._('notification.no.notification')}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import classnames from 'classnames';
|
||||
import {FC, useEffect, useRef} from 'react';
|
||||
import {observer} from 'mobx-react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import {Close, Search} from '@client/ui/icons';
|
||||
import TorrentFilterStore from '@client/stores/TorrentFilterStore';
|
||||
import UIActions from '@client/actions/UIActions';
|
||||
|
||||
const SearchBox: FC = observer(() => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const {searchFilter} = TorrentFilterStore.filters;
|
||||
@@ -48,9 +48,7 @@ const SearchBox: FC = observer(() => {
|
||||
className="textbox"
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'sidebar.search.placeholder',
|
||||
})}
|
||||
placeholder={i18n._('sidebar.search.placeholder')}
|
||||
onChange={(event) => {
|
||||
UIActions.setTorrentsSearchFilter(event.target.value);
|
||||
}}
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
import {defineMessages, useIntl} from 'react-intl';
|
||||
import {FC, useRef} from 'react';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import {Settings} from '@client/ui/icons';
|
||||
import UIActions from '@client/actions/UIActions';
|
||||
|
||||
import Tooltip from '../general/Tooltip';
|
||||
|
||||
const MESSAGES = defineMessages({
|
||||
settings: {
|
||||
id: 'sidebar.button.settings',
|
||||
},
|
||||
});
|
||||
|
||||
const SettingsButton: FC = () => {
|
||||
const intl = useIntl();
|
||||
const label = intl.formatMessage(MESSAGES.settings);
|
||||
const {i18n} = useLingui();
|
||||
const tooltipRef = useRef<Tooltip>(null);
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content={label}
|
||||
content={i18n._('sidebar.button.settings')}
|
||||
onClick={() => {
|
||||
if (tooltipRef.current != null) {
|
||||
tooltipRef.current.dismissTooltip();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import classnames from 'classnames';
|
||||
import {FC} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import Badge from '../general/Badge';
|
||||
|
||||
@@ -15,7 +15,7 @@ interface SidebarFilterProps {
|
||||
|
||||
const SidebarFilter: FC<SidebarFilterProps> = (props: SidebarFilterProps) => {
|
||||
const {isActive, count, slug, icon, handleClick} = props;
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
const classNames = classnames('sidebar-filter__item', {
|
||||
'is-active': isActive,
|
||||
@@ -23,16 +23,12 @@ const SidebarFilter: FC<SidebarFilterProps> = (props: SidebarFilterProps) => {
|
||||
let {name} = props;
|
||||
|
||||
if (name === '') {
|
||||
name = intl.formatMessage({
|
||||
id: 'filter.all',
|
||||
});
|
||||
name = i18n._('filter.all');
|
||||
} else if (name === 'untagged') {
|
||||
if (count === 0) {
|
||||
return null;
|
||||
}
|
||||
name = intl.formatMessage({
|
||||
id: 'filter.untagged',
|
||||
});
|
||||
name = i18n._('filter.untagged');
|
||||
}
|
||||
|
||||
if (slug === 'checking' || slug === 'error') {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import {FC, useRef} from 'react';
|
||||
import {FormattedMessage, IntlShape, useIntl} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import sortedIndex from 'lodash/sortedIndex';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import type {I18n} from '@lingui/core';
|
||||
|
||||
import ClientActions from '@client/actions/ClientActions';
|
||||
import {Limits} from '@client/ui/icons';
|
||||
@@ -16,16 +18,16 @@ import Tooltip from '../general/Tooltip';
|
||||
import type {DropdownItem} from '../general/form-elements/Dropdown';
|
||||
|
||||
const HumanReadableSpeed: FC<{bytes: number}> = ({bytes}: {bytes: number}) =>
|
||||
bytes === 0 ? <FormattedMessage id="speed.unlimited" /> : <Size value={bytes} isSpeed precision={1} />;
|
||||
bytes === 0 ? <Trans id="speed.unlimited" /> : <Size value={bytes} isSpeed precision={1} />;
|
||||
|
||||
const getSpeedList = ({
|
||||
intl,
|
||||
i18n,
|
||||
direction,
|
||||
speedLimits,
|
||||
throttleGlobalDownSpeed,
|
||||
throttleGlobalUpSpeed,
|
||||
}: {
|
||||
intl: IntlShape;
|
||||
i18n: I18n;
|
||||
direction: TransferDirection;
|
||||
speedLimits: {
|
||||
download: Array<number>;
|
||||
@@ -37,8 +39,8 @@ const getSpeedList = ({
|
||||
const heading = {
|
||||
className: `dropdown__label dropdown__label--${direction}`,
|
||||
...(direction === 'download'
|
||||
? {displayName: intl.formatMessage({id: 'sidebar.speedlimits.download'})}
|
||||
: {displayName: intl.formatMessage({id: 'sidebar.speedlimits.upload'})}),
|
||||
? {displayName: i18n._('sidebar.speedlimits.download')}
|
||||
: {displayName: i18n._('sidebar.speedlimits.upload')}),
|
||||
selectable: false,
|
||||
value: null,
|
||||
};
|
||||
@@ -92,12 +94,12 @@ const getSpeedList = ({
|
||||
};
|
||||
|
||||
const SpeedLimitDropdown: FC = observer(() => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const tooltipRef = useRef<Tooltip>(null);
|
||||
|
||||
const label = intl.formatMessage({id: 'sidebar.button.speedlimits'});
|
||||
const label = i18n._('sidebar.button.speedlimits');
|
||||
const speedListOptions = {
|
||||
intl,
|
||||
i18n,
|
||||
speedLimits: SettingStore.floodSettings.speedLimits,
|
||||
throttleGlobalDownSpeed: SettingStore.clientSettings?.throttleGlobalDownSpeed ?? 0,
|
||||
throttleGlobalUpSpeed: SettingStore.clientSettings?.throttleGlobalUpSpeed ?? 0,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {FC} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import {Active, All, Completed, DownloadSmall, Error, Inactive, Stop, Spinner, UploadSmall} from '@client/ui/icons';
|
||||
import TorrentFilterStore from '@client/stores/TorrentFilterStore';
|
||||
@@ -11,7 +11,7 @@ import type {TorrentStatus} from '@shared/constants/torrentStatusMap';
|
||||
import SidebarFilter from './SidebarFilter';
|
||||
|
||||
const StatusFilters: FC = observer(() => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
const filters: Array<{
|
||||
label: string;
|
||||
@@ -19,65 +19,47 @@ const StatusFilters: FC = observer(() => {
|
||||
icon: JSX.Element;
|
||||
}> = [
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
id: 'filter.all',
|
||||
}),
|
||||
label: i18n._('filter.all'),
|
||||
slug: '',
|
||||
icon: <All />,
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
id: 'filter.status.downloading',
|
||||
}),
|
||||
label: i18n._('filter.status.downloading'),
|
||||
slug: 'downloading',
|
||||
icon: <DownloadSmall />,
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
id: 'filter.status.seeding',
|
||||
}),
|
||||
label: i18n._('filter.status.seeding'),
|
||||
slug: 'seeding',
|
||||
icon: <UploadSmall />,
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
id: 'filter.status.checking',
|
||||
}),
|
||||
label: i18n._('filter.status.checking'),
|
||||
slug: 'checking',
|
||||
icon: <Spinner />,
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
id: 'filter.status.completed',
|
||||
}),
|
||||
label: i18n._('filter.status.completed'),
|
||||
slug: 'complete',
|
||||
icon: <Completed />,
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
id: 'filter.status.stopped',
|
||||
}),
|
||||
label: i18n._('filter.status.stopped'),
|
||||
slug: 'stopped',
|
||||
icon: <Stop />,
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
id: 'filter.status.active',
|
||||
}),
|
||||
label: i18n._('filter.status.active'),
|
||||
slug: 'active',
|
||||
icon: <Active />,
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
id: 'filter.status.inactive',
|
||||
}),
|
||||
label: i18n._('filter.status.inactive'),
|
||||
slug: 'inactive',
|
||||
icon: <Inactive />,
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
id: 'filter.status.error',
|
||||
}),
|
||||
label: i18n._('filter.status.error'),
|
||||
slug: 'error',
|
||||
icon: <Error />,
|
||||
},
|
||||
@@ -98,7 +80,7 @@ const StatusFilters: FC = observer(() => {
|
||||
return (
|
||||
<ul className="sidebar-filter sidebar__item">
|
||||
<li className="sidebar-filter__item sidebar-filter__item--heading">
|
||||
<FormattedMessage id="filter.status.title" />
|
||||
<Trans id="filter.status.title" />
|
||||
</li>
|
||||
{filterElements}
|
||||
</ul>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {FC} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import SidebarFilter from './SidebarFilter';
|
||||
import TorrentFilterStore from '../../stores/TorrentFilterStore';
|
||||
@@ -39,7 +39,7 @@ const TagFilters: FC = observer(() => {
|
||||
return (
|
||||
<ul className="sidebar-filter sidebar__item">
|
||||
<li className="sidebar-filter__item sidebar-filter__item--heading">
|
||||
<FormattedMessage id="filter.tag.title" />
|
||||
<Trans id="filter.tag.title" />
|
||||
</li>
|
||||
{filterElements}
|
||||
</ul>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import ConfigStore from '@client/stores/ConfigStore';
|
||||
import {ThemeSwitch} from '@client/ui/icons';
|
||||
@@ -7,13 +7,11 @@ import {ThemeSwitch} from '@client/ui/icons';
|
||||
import Tooltip from '../general/Tooltip';
|
||||
|
||||
const ThemeSwitchButton: FC = () => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content={intl.formatMessage({
|
||||
id: ConfigStore.preferDark ? 'sidebar.button.theme.light' : 'sidebar.button.theme.dark',
|
||||
})}
|
||||
content={i18n._(ConfigStore.preferDark ? 'sidebar.button.theme.light' : 'sidebar.button.theme.dark')}
|
||||
onClick={() => ConfigStore.setUserPreferDark(!ConfigStore.preferDark)}
|
||||
position="bottom"
|
||||
wrapperClassName="sidebar__action sidebar__icon-button
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {FC} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import SidebarFilter from './SidebarFilter';
|
||||
import TorrentFilterStore from '../../stores/TorrentFilterStore';
|
||||
@@ -38,7 +38,7 @@ const TrackerFilters: FC = observer(() => {
|
||||
return (
|
||||
<ul className="sidebar-filter sidebar__item">
|
||||
<li className="sidebar-filter__item sidebar-filter__item--heading">
|
||||
<FormattedMessage id="filter.tracker.title" />
|
||||
<Trans id="filter.tracker.title" />
|
||||
</li>
|
||||
{filterElements}
|
||||
</ul>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import classnames from 'classnames';
|
||||
import {defineMessages, useIntl} from 'react-intl';
|
||||
import {FC} from 'react';
|
||||
import {observer} from 'mobx-react';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import ClientStatusStore from '@client/stores/ClientStatusStore';
|
||||
import {Download, InfinityIcon, Upload} from '@client/ui/icons';
|
||||
@@ -15,12 +15,6 @@ import Size from '../general/Size';
|
||||
|
||||
import type {TransferRateGraphInspectorPoint} from './TransferRateGraph';
|
||||
|
||||
const messages = defineMessages({
|
||||
ago: {
|
||||
id: 'general.ago',
|
||||
},
|
||||
});
|
||||
|
||||
const icons = {
|
||||
download: <Download />,
|
||||
infinity: <InfinityIcon />,
|
||||
@@ -32,7 +26,7 @@ interface TransferRateDetailsProps {
|
||||
}
|
||||
|
||||
const TransferRateDetails: FC<TransferRateDetailsProps> = observer(({inspectorPoint}: TransferRateDetailsProps) => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
const getCurrentTransferRate = (direction: TransferDirection, options: {showHoverDuration?: boolean} = {}) => {
|
||||
const {throttleGlobalDownSpeed = 0, throttleGlobalUpSpeed = 0} = SettingStore.clientSettings || {};
|
||||
@@ -73,7 +67,7 @@ const TransferRateDetails: FC<TransferRateDetailsProps> = observer(({inspectorPo
|
||||
timestamp = (
|
||||
<div className={timestampClasses}>
|
||||
<Duration
|
||||
suffix={intl.formatMessage(messages.ago)}
|
||||
suffix={i18n._('general.ago')}
|
||||
value={Math.trunc((Date.now() - inspectorPoint.nearestTimestamp) / 1000)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import classnames from 'classnames';
|
||||
import {FC} from 'react';
|
||||
import {observer} from 'mobx-react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import {Add, Menu, Remove, Start, Stop} from '@client/ui/icons';
|
||||
import SettingActions from '@client/actions/SettingActions';
|
||||
@@ -14,7 +14,7 @@ import Action from './Action';
|
||||
import SortDropdown from './SortDropdown';
|
||||
|
||||
const ActionBar: FC = observer(() => {
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
const {sortTorrents: sortBy, torrentListViewSize} = SettingStore.floodSettings;
|
||||
|
||||
const classes = classnames('action-bar', {
|
||||
@@ -49,9 +49,7 @@ const ActionBar: FC = observer(() => {
|
||||
<div className="actions action-bar__item action-bar__item--torrent-operations">
|
||||
<div className="action-bar__group">
|
||||
<Action
|
||||
label={intl.formatMessage({
|
||||
id: 'actionbar.button.start.torrent',
|
||||
})}
|
||||
label={i18n._('actionbar.button.start.torrent')}
|
||||
slug="start-torrent"
|
||||
icon={<Start />}
|
||||
clickHandler={() =>
|
||||
@@ -61,9 +59,7 @@ const ActionBar: FC = observer(() => {
|
||||
}
|
||||
/>
|
||||
<Action
|
||||
label={intl.formatMessage({
|
||||
id: 'actionbar.button.stop.torrent',
|
||||
})}
|
||||
label={i18n._('actionbar.button.stop.torrent')}
|
||||
slug="stop-torrent"
|
||||
icon={<Stop />}
|
||||
clickHandler={() =>
|
||||
@@ -75,17 +71,13 @@ const ActionBar: FC = observer(() => {
|
||||
</div>
|
||||
<div className="action-bar__group action-bar__group--has-divider">
|
||||
<Action
|
||||
label={intl.formatMessage({
|
||||
id: 'actionbar.button.add.torrent',
|
||||
})}
|
||||
label={i18n._('actionbar.button.add.torrent')}
|
||||
slug="add-torrent"
|
||||
icon={<Add />}
|
||||
clickHandler={() => UIActions.displayModal({id: 'add-torrents'})}
|
||||
/>
|
||||
<Action
|
||||
label={intl.formatMessage({
|
||||
id: 'actionbar.button.remove.torrent',
|
||||
})}
|
||||
label={i18n._('actionbar.button.remove.torrent')}
|
||||
slug="remove-torrent"
|
||||
icon={<Remove />}
|
||||
clickHandler={() =>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {FC} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
|
||||
import type {FloodSettings} from '@shared/types/FloodSettings';
|
||||
|
||||
@@ -29,7 +29,7 @@ interface SortDropdownProps {
|
||||
|
||||
const SortDropdown: FC<SortDropdownProps> = (props: SortDropdownProps) => {
|
||||
const {direction, selectedProperty, onSortChange} = props;
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
if (selectedProperty == null) {
|
||||
return null;
|
||||
@@ -38,10 +38,10 @@ const SortDropdown: FC<SortDropdownProps> = (props: SortDropdownProps) => {
|
||||
const header = (
|
||||
<button className="dropdown__button" type="button">
|
||||
<label className="dropdown__label">
|
||||
<FormattedMessage id="torrents.sort.title" />
|
||||
<Trans id="torrents.sort.title" />
|
||||
</label>
|
||||
<span className="dropdown__value">
|
||||
<FormattedMessage id={TorrentListColumns[selectedProperty]?.id || TorrentListColumns.dateAdded.id} />
|
||||
<Trans id={TorrentListColumns[selectedProperty]} />
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
@@ -56,7 +56,7 @@ const SortDropdown: FC<SortDropdownProps> = (props: SortDropdownProps) => {
|
||||
return {
|
||||
displayName: (
|
||||
<div className="sort-dropdown__item">
|
||||
{intl.formatMessage(TorrentListColumns[sortProp])}
|
||||
{i18n._(TorrentListColumns[sortProp])}
|
||||
{directionIndicator}
|
||||
</div>
|
||||
),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import classnames from 'classnames';
|
||||
import {forwardRef, MutableRefObject, ReactNodeArray, useRef, useState} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import {Trans, useLingui} from '@lingui/react';
|
||||
import {useEnsuredForwardedRef} from 'react-use';
|
||||
|
||||
import TorrentListColumns, {TorrentListColumn} from '../../constants/TorrentListColumns';
|
||||
@@ -28,7 +28,7 @@ const TableHeading = observer(
|
||||
const tableHeading = useEnsuredForwardedRef<HTMLDivElement>(ref as MutableRefObject<HTMLDivElement>);
|
||||
const resizeLine = useRef<HTMLDivElement>(null);
|
||||
|
||||
const intl = useIntl();
|
||||
const {i18n} = useLingui();
|
||||
|
||||
const handlePointerMove = (event: PointerEvent) => {
|
||||
let widthDelta = 0;
|
||||
@@ -79,7 +79,7 @@ const TableHeading = observer(
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
const labelID = TorrentListColumns[id]?.id;
|
||||
const labelID = TorrentListColumns[id];
|
||||
if (labelID == null) {
|
||||
return accumulator;
|
||||
}
|
||||
@@ -121,12 +121,8 @@ const TableHeading = observer(
|
||||
|
||||
accumulator.push(
|
||||
<div className={classes} key={id} onClick={() => onCellClick(id)} style={{width: `${width}px`}}>
|
||||
<span
|
||||
className="table__heading__label"
|
||||
title={intl.formatMessage({
|
||||
id: labelID,
|
||||
})}>
|
||||
<FormattedMessage id={labelID} />
|
||||
<span className="table__heading__label" title={i18n._(labelID)}>
|
||||
<Trans id={labelID} />
|
||||
</span>
|
||||
{handle}
|
||||
</div>,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {FC, ReactNode, useEffect, useRef} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {observer} from 'mobx-react';
|
||||
import {reaction} from 'mobx';
|
||||
import {Trans} from '@lingui/react';
|
||||
|
||||
import type {FixedSizeList} from 'react-window';
|
||||
|
||||
@@ -54,7 +54,7 @@ const TorrentList: FC = observer(() => {
|
||||
content = (
|
||||
<div className="torrents__alert__wrapper">
|
||||
<div className="torrents__alert">
|
||||
<FormattedMessage id="torrents.list.cannot.connect" />
|
||||
<Trans id="torrents.list.cannot.connect" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -62,7 +62,7 @@ const TorrentList: FC = observer(() => {
|
||||
content = (
|
||||
<div className="torrents__alert__wrapper">
|
||||
<div className="torrents__alert">
|
||||
<FormattedMessage id="torrents.list.no.torrents" />
|
||||
<Trans id="torrents.list.no.torrents" />
|
||||
</div>
|
||||
{TorrentFilterStore.isFilterActive && (
|
||||
<div className="torrents__alert__action">
|
||||
@@ -71,7 +71,7 @@ const TorrentList: FC = observer(() => {
|
||||
TorrentFilterStore.clearAllFilters();
|
||||
}}
|
||||
priority="tertiary">
|
||||
<FormattedMessage id="torrents.list.clear.filters" />
|
||||
<Trans id="torrents.list.clear.filters" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
@@ -148,7 +148,7 @@ const TorrentList: FC = observer(() => {
|
||||
<div className="dropzone__icon">
|
||||
<Files />
|
||||
</div>
|
||||
<FormattedMessage id="torrents.list.drop" />
|
||||
<Trans id="torrents.list.drop" />
|
||||
</div>
|
||||
</div>
|
||||
</TorrentListDropzone>
|
||||
|
||||
@@ -39,7 +39,7 @@ const getContextMenuItems = (torrent: TorrentProperties): Array<ContextMenuItem>
|
||||
{
|
||||
type: 'action',
|
||||
action: 'start',
|
||||
label: TorrentContextMenuActions.start.id,
|
||||
label: TorrentContextMenuActions.start,
|
||||
clickHandler: () => {
|
||||
TorrentActions.startTorrents({
|
||||
hashes: TorrentStore.selectedTorrents,
|
||||
@@ -49,7 +49,7 @@ const getContextMenuItems = (torrent: TorrentProperties): Array<ContextMenuItem>
|
||||
{
|
||||
type: 'action',
|
||||
action: 'stop',
|
||||
label: TorrentContextMenuActions.stop.id,
|
||||
label: TorrentContextMenuActions.stop,
|
||||
clickHandler: () => {
|
||||
TorrentActions.stopTorrents({
|
||||
hashes: TorrentStore.selectedTorrents,
|
||||
@@ -59,7 +59,7 @@ const getContextMenuItems = (torrent: TorrentProperties): Array<ContextMenuItem>
|
||||
{
|
||||
type: 'action',
|
||||
action: 'remove',
|
||||
label: TorrentContextMenuActions.remove.id,
|
||||
label: TorrentContextMenuActions.remove,
|
||||
clickHandler: () => {
|
||||
UIActions.displayModal({id: 'remove-torrents'});
|
||||
},
|
||||
@@ -67,7 +67,7 @@ const getContextMenuItems = (torrent: TorrentProperties): Array<ContextMenuItem>
|
||||
{
|
||||
type: 'action',
|
||||
action: 'checkHash',
|
||||
label: TorrentContextMenuActions.checkHash.id,
|
||||
label: TorrentContextMenuActions.checkHash,
|
||||
clickHandler: () => {
|
||||
TorrentActions.checkHash({
|
||||
hashes: TorrentStore.selectedTorrents,
|
||||
@@ -80,7 +80,7 @@ const getContextMenuItems = (torrent: TorrentProperties): Array<ContextMenuItem>
|
||||
{
|
||||
type: 'action',
|
||||
action: 'setTaxonomy',
|
||||
label: TorrentContextMenuActions.setTaxonomy.id,
|
||||
label: TorrentContextMenuActions.setTaxonomy,
|
||||
clickHandler: () => {
|
||||
UIActions.displayModal({id: 'set-taxonomy'});
|
||||
},
|
||||
@@ -88,7 +88,7 @@ const getContextMenuItems = (torrent: TorrentProperties): Array<ContextMenuItem>
|
||||
{
|
||||
type: 'action',
|
||||
action: 'move',
|
||||
label: TorrentContextMenuActions.move.id,
|
||||
label: TorrentContextMenuActions.move,
|
||||
clickHandler: () => {
|
||||
UIActions.displayModal({id: 'move-torrents'});
|
||||
},
|
||||
@@ -96,7 +96,7 @@ const getContextMenuItems = (torrent: TorrentProperties): Array<ContextMenuItem>
|
||||
{
|
||||
type: 'action',
|
||||
action: 'setTrackers',
|
||||
label: TorrentContextMenuActions.setTrackers.id,
|
||||
label: TorrentContextMenuActions.setTrackers,
|
||||
clickHandler: () => {
|
||||
UIActions.displayModal({id: 'set-trackers'});
|
||||
},
|
||||
@@ -107,7 +107,7 @@ const getContextMenuItems = (torrent: TorrentProperties): Array<ContextMenuItem>
|
||||
{
|
||||
type: 'action',
|
||||
action: 'torrentDetails',
|
||||
label: TorrentContextMenuActions.torrentDetails.id,
|
||||
label: TorrentContextMenuActions.torrentDetails,
|
||||
clickHandler: () => {
|
||||
UIActions.displayModal({
|
||||
id: 'torrent-details',
|
||||
@@ -118,7 +118,7 @@ const getContextMenuItems = (torrent: TorrentProperties): Array<ContextMenuItem>
|
||||
{
|
||||
type: 'action',
|
||||
action: 'downloadContents',
|
||||
label: TorrentContextMenuActions.downloadContents.id,
|
||||
label: TorrentContextMenuActions.downloadContents,
|
||||
clickHandler: (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -136,7 +136,7 @@ const getContextMenuItems = (torrent: TorrentProperties): Array<ContextMenuItem>
|
||||
{
|
||||
type: 'action',
|
||||
action: 'downloadMetainfo',
|
||||
label: TorrentContextMenuActions.downloadMetainfo.id,
|
||||
label: TorrentContextMenuActions.downloadMetainfo,
|
||||
clickHandler: (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -154,7 +154,7 @@ const getContextMenuItems = (torrent: TorrentProperties): Array<ContextMenuItem>
|
||||
{
|
||||
type: 'action',
|
||||
action: 'generateMagnet',
|
||||
label: TorrentContextMenuActions.generateMagnet.id,
|
||||
label: TorrentContextMenuActions.generateMagnet,
|
||||
clickHandler: () => {
|
||||
UIActions.displayModal({id: 'generate-magnet'});
|
||||
},
|
||||
@@ -162,7 +162,7 @@ const getContextMenuItems = (torrent: TorrentProperties): Array<ContextMenuItem>
|
||||
{
|
||||
type: 'action',
|
||||
action: 'setInitialSeeding',
|
||||
label: TorrentContextMenuActions.setInitialSeeding.id,
|
||||
label: TorrentContextMenuActions.setInitialSeeding,
|
||||
clickHandler: () => {
|
||||
const {selectedTorrents} = TorrentStore;
|
||||
TorrentActions.setInitialSeeding({
|
||||
@@ -176,7 +176,7 @@ const getContextMenuItems = (torrent: TorrentProperties): Array<ContextMenuItem>
|
||||
{
|
||||
type: 'action',
|
||||
action: 'setSequential',
|
||||
label: TorrentContextMenuActions.setSequential.id,
|
||||
label: TorrentContextMenuActions.setSequential,
|
||||
clickHandler: () => {
|
||||
const {selectedTorrents} = TorrentStore;
|
||||
TorrentActions.setSequential({
|
||||
@@ -190,7 +190,7 @@ const getContextMenuItems = (torrent: TorrentProperties): Array<ContextMenuItem>
|
||||
{
|
||||
type: 'action',
|
||||
action: 'setPriority',
|
||||
label: TorrentContextMenuActions.setPriority.id,
|
||||
label: TorrentContextMenuActions.setPriority,
|
||||
clickHandler: () => {
|
||||
if (changePriorityFuncRef.current != null) {
|
||||
TorrentActions.setPriority({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {FormattedNumber} from 'react-intl';
|
||||
import {forwardRef} from 'react';
|
||||
import {observer} from 'mobx-react';
|
||||
import {useLingui} from '@lingui/react';
|
||||
|
||||
import ProgressBar from '../general/ProgressBar';
|
||||
import SettingStore from '../../stores/SettingStore';
|
||||
@@ -35,6 +35,7 @@ const TorrentListRowExpanded = observer(
|
||||
}: TorrentListRowExpandedProps,
|
||||
ref,
|
||||
) => {
|
||||
const {i18n} = useLingui();
|
||||
const columns = SettingStore.floodSettings.torrentListColumns;
|
||||
|
||||
const primarySection: React.ReactNodeArray = [
|
||||
@@ -57,7 +58,7 @@ const TorrentListRowExpanded = observer(
|
||||
column="percentComplete"
|
||||
content={(torrent) => (
|
||||
<span>
|
||||
<FormattedNumber value={torrent.percentComplete} maximumFractionDigits={1} />
|
||||
{i18n.number(torrent.percentComplete, {maximumFractionDigits: 1})}
|
||||
<em className="unit">%</em>
|
||||
—
|
||||
<Size value={torrent.downTotal} />
|
||||
|
||||
@@ -1,46 +1,18 @@
|
||||
const TorrentContextMenuActions = {
|
||||
start: {
|
||||
id: 'torrents.list.context.start',
|
||||
},
|
||||
stop: {
|
||||
id: 'torrents.list.context.stop',
|
||||
},
|
||||
remove: {
|
||||
id: 'torrents.list.context.remove',
|
||||
},
|
||||
checkHash: {
|
||||
id: 'torrents.list.context.check.hash',
|
||||
},
|
||||
setTaxonomy: {
|
||||
id: 'torrents.list.context.set.tags',
|
||||
},
|
||||
move: {
|
||||
id: 'torrents.list.context.move',
|
||||
},
|
||||
setTrackers: {
|
||||
id: 'torrents.list.context.set.trackers',
|
||||
},
|
||||
torrentDetails: {
|
||||
id: 'torrents.list.context.details',
|
||||
},
|
||||
downloadContents: {
|
||||
id: 'torrents.list.context.download.contents',
|
||||
},
|
||||
downloadMetainfo: {
|
||||
id: 'torrents.list.context.download.metainfo',
|
||||
},
|
||||
generateMagnet: {
|
||||
id: 'torrents.list.context.generate.magnet',
|
||||
},
|
||||
setInitialSeeding: {
|
||||
id: 'torrents.list.context.initial.seeding',
|
||||
},
|
||||
setSequential: {
|
||||
id: 'torrents.list.context.sequential',
|
||||
},
|
||||
setPriority: {
|
||||
id: 'torrents.list.context.priority',
|
||||
},
|
||||
start: 'torrents.list.context.start',
|
||||
stop: 'torrents.list.context.stop',
|
||||
remove: 'torrents.list.context.remove',
|
||||
checkHash: 'torrents.list.context.check.hash',
|
||||
setTaxonomy: 'torrents.list.context.set.tags',
|
||||
move: 'torrents.list.context.move',
|
||||
setTrackers: 'torrents.list.context.set.trackers',
|
||||
torrentDetails: 'torrents.list.context.details',
|
||||
downloadContents: 'torrents.list.context.download.contents',
|
||||
downloadMetainfo: 'torrents.list.context.download.metainfo',
|
||||
generateMagnet: 'torrents.list.context.generate.magnet',
|
||||
setInitialSeeding: 'torrents.list.context.initial.seeding',
|
||||
setSequential: 'torrents.list.context.sequential',
|
||||
setPriority: 'torrents.list.context.priority',
|
||||
} as const;
|
||||
|
||||
export default TorrentContextMenuActions;
|
||||
|
||||
@@ -1,61 +1,23 @@
|
||||
const TorrentListColumns = {
|
||||
dateAdded: {
|
||||
id: 'torrents.properties.date.added',
|
||||
},
|
||||
downRate: {
|
||||
id: 'torrents.properties.download.speed',
|
||||
},
|
||||
downTotal: {
|
||||
id: 'torrents.properties.download.total',
|
||||
},
|
||||
eta: {
|
||||
id: 'torrents.properties.eta',
|
||||
},
|
||||
name: {
|
||||
id: 'torrents.properties.name',
|
||||
},
|
||||
peers: {
|
||||
id: 'torrents.properties.peers',
|
||||
},
|
||||
percentComplete: {
|
||||
id: 'torrents.properties.percentage',
|
||||
},
|
||||
ratio: {
|
||||
id: 'torrents.properties.ratio',
|
||||
},
|
||||
seeds: {
|
||||
id: 'torrents.properties.seeds',
|
||||
},
|
||||
sizeBytes: {
|
||||
id: 'torrents.properties.size',
|
||||
},
|
||||
tags: {
|
||||
id: 'torrents.properties.tags',
|
||||
},
|
||||
upRate: {
|
||||
id: 'torrents.properties.upload.speed',
|
||||
},
|
||||
upTotal: {
|
||||
id: 'torrents.properties.upload.total',
|
||||
},
|
||||
dateCreated: {
|
||||
id: 'torrents.properties.creation.date',
|
||||
},
|
||||
directory: {
|
||||
id: 'torrents.properties.directory',
|
||||
},
|
||||
hash: {
|
||||
id: 'torrents.properties.hash',
|
||||
},
|
||||
isPrivate: {
|
||||
id: 'torrents.properties.is.private',
|
||||
},
|
||||
message: {
|
||||
id: 'torrents.properties.tracker.message',
|
||||
},
|
||||
trackerURIs: {
|
||||
id: 'torrents.properties.trackers',
|
||||
},
|
||||
dateAdded: 'torrents.properties.date.added',
|
||||
downRate: 'torrents.properties.download.speed',
|
||||
downTotal: 'torrents.properties.download.total',
|
||||
eta: 'torrents.properties.eta',
|
||||
name: 'torrents.properties.name',
|
||||
peers: 'torrents.properties.peers',
|
||||
percentComplete: 'torrents.properties.percentage',
|
||||
ratio: 'torrents.properties.ratio',
|
||||
seeds: 'torrents.properties.seeds',
|
||||
sizeBytes: 'torrents.properties.size',
|
||||
tags: 'torrents.properties.tags',
|
||||
upRate: 'torrents.properties.upload.speed',
|
||||
upTotal: 'torrents.properties.upload.total',
|
||||
dateCreated: 'torrents.properties.creation.date',
|
||||
directory: 'torrents.properties.directory',
|
||||
hash: 'torrents.properties.hash',
|
||||
isPrivate: 'torrents.properties.is.private',
|
||||
message: 'torrents.properties.tracker.message',
|
||||
trackerURIs: 'torrents.properties.trackers',
|
||||
} as const;
|
||||
|
||||
export default TorrentListColumns;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user