mirror of
https://github.com/Readarr/Readarr
synced 2026-01-02 05:37:45 +01:00
Localization framework
This commit is contained in:
parent
144134446d
commit
d87bf5ae63
196 changed files with 3074 additions and 924 deletions
|
|
@ -14,6 +14,7 @@ import TablePager from 'Components/Table/TablePager';
|
|||
import { align, icons, kinds } from 'Helpers/Props';
|
||||
import getRemovedItems from 'Utilities/Object/getRemovedItems';
|
||||
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||
import removeOldSelectedState from 'Utilities/Table/removeOldSelectedState';
|
||||
import selectAll from 'Utilities/Table/selectAll';
|
||||
|
|
@ -120,11 +121,11 @@ class Blacklist extends Component {
|
|||
const selectedIds = this.getSelectedIds();
|
||||
|
||||
return (
|
||||
<PageContent title="Blacklist">
|
||||
<PageContent title={translate('Blacklist')}>
|
||||
<PageToolbar>
|
||||
<PageToolbarSection>
|
||||
<PageToolbarButton
|
||||
label="Remove Selected"
|
||||
label={translate('RemoveSelected')}
|
||||
iconName={icons.REMOVE}
|
||||
isDisabled={!selectedIds.length}
|
||||
isSpinning={isRemoving}
|
||||
|
|
@ -132,7 +133,7 @@ class Blacklist extends Component {
|
|||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label="Clear"
|
||||
label={translate('Clear')}
|
||||
iconName={icons.CLEAR}
|
||||
isSpinning={isClearingBlacklistExecuting}
|
||||
onPress={onClearBlacklistPress}
|
||||
|
|
@ -145,7 +146,7 @@ class Blacklist extends Component {
|
|||
columns={columns}
|
||||
>
|
||||
<PageToolbarButton
|
||||
label="Options"
|
||||
label={translate('Options')}
|
||||
iconName={icons.TABLE}
|
||||
/>
|
||||
</TableOptionsModalWrapper>
|
||||
|
|
@ -160,7 +161,9 @@ class Blacklist extends Component {
|
|||
|
||||
{
|
||||
!isAnyFetching && !!error &&
|
||||
<div>Unable to load blacklist</div>
|
||||
<div>
|
||||
{translate('UnableToLoadBlacklist')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -210,9 +213,9 @@ class Blacklist extends Component {
|
|||
<ConfirmModal
|
||||
isOpen={isConfirmRemoveModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title="Remove Selected"
|
||||
message={'Are you sure you want to remove the selected items from the blacklist?'}
|
||||
confirmLabel="Remove Selected"
|
||||
title={translate('RemoveSelected')}
|
||||
message={translate('RemoveSelectedMessageText')}
|
||||
confirmLabel={translate('RemoveSelected')}
|
||||
onConfirm={this.onRemoveSelectedConfirmed}
|
||||
onCancel={this.onConfirmRemoveModalClose}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import ModalBody from 'Components/Modal/ModalBody';
|
|||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
class BlacklistDetailsModal extends Component {
|
||||
|
||||
|
|
@ -39,19 +40,19 @@ class BlacklistDetailsModal extends Component {
|
|||
<ModalBody>
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title="Name"
|
||||
title={translate('Name')}
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title="Protocol"
|
||||
title={translate('Protocol')}
|
||||
data={protocol}
|
||||
/>
|
||||
|
||||
{
|
||||
!!message &&
|
||||
<DescriptionListItem
|
||||
title="Indexer"
|
||||
title={translate('Indexer')}
|
||||
data={indexer}
|
||||
/>
|
||||
}
|
||||
|
|
@ -59,7 +60,7 @@ class BlacklistDetailsModal extends Component {
|
|||
{
|
||||
!!message &&
|
||||
<DescriptionListItem
|
||||
title="Message"
|
||||
title={translate('Message')}
|
||||
data={message}
|
||||
/>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
|||
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import BlacklistDetailsModal from './BlacklistDetailsModal';
|
||||
import styles from './BlacklistRow.css';
|
||||
|
||||
|
|
@ -141,7 +142,7 @@ class BlacklistRow extends Component {
|
|||
/>
|
||||
|
||||
<IconButton
|
||||
title="Remove from blacklist"
|
||||
title={translate('RemoveFromBlacklist')}
|
||||
name={icons.REMOVE}
|
||||
kind={kinds.DANGER}
|
||||
onPress={onRemovePress}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import Link from 'Components/Link/Link';
|
|||
import { icons } from 'Helpers/Props';
|
||||
import formatDateTime from 'Utilities/Date/formatDateTime';
|
||||
import formatAge from 'Utilities/Number/formatAge';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './HistoryDetails.css';
|
||||
|
||||
function getDetailedList(statusMessages) {
|
||||
|
|
@ -77,14 +78,14 @@ function HistoryDetails(props) {
|
|||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title="Name"
|
||||
title={translate('Name')}
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
{
|
||||
!!indexer &&
|
||||
<DescriptionListItem
|
||||
title="Indexer"
|
||||
title={translate('Indexer')}
|
||||
data={indexer}
|
||||
/>
|
||||
}
|
||||
|
|
@ -93,7 +94,7 @@ function HistoryDetails(props) {
|
|||
!!releaseGroup &&
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title="Release Group"
|
||||
title={translate('ReleaseGroup')}
|
||||
data={releaseGroup}
|
||||
/>
|
||||
}
|
||||
|
|
@ -114,7 +115,7 @@ function HistoryDetails(props) {
|
|||
{
|
||||
!!downloadClient &&
|
||||
<DescriptionListItem
|
||||
title="Download Client"
|
||||
title={translate('DownloadClient')}
|
||||
data={downloadClient}
|
||||
/>
|
||||
}
|
||||
|
|
@ -122,7 +123,7 @@ function HistoryDetails(props) {
|
|||
{
|
||||
!!downloadId &&
|
||||
<DescriptionListItem
|
||||
title="Grab ID"
|
||||
title={translate('GrabID')}
|
||||
data={downloadId}
|
||||
/>
|
||||
}
|
||||
|
|
@ -130,7 +131,7 @@ function HistoryDetails(props) {
|
|||
{
|
||||
!!indexer &&
|
||||
<DescriptionListItem
|
||||
title="Age (when grabbed)"
|
||||
title={translate('AgeWhenGrabbed')}
|
||||
data={formatAge(age, ageHours, ageMinutes)}
|
||||
/>
|
||||
}
|
||||
|
|
@ -138,7 +139,7 @@ function HistoryDetails(props) {
|
|||
{
|
||||
!!publishedDate &&
|
||||
<DescriptionListItem
|
||||
title="Published Date"
|
||||
title={translate('PublishedDate')}
|
||||
data={formatDateTime(publishedDate, shortDateFormat, timeFormat, { includeSeconds: true })}
|
||||
/>
|
||||
}
|
||||
|
|
@ -155,14 +156,14 @@ function HistoryDetails(props) {
|
|||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title="Name"
|
||||
title={translate('Name')}
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
{
|
||||
!!message &&
|
||||
<DescriptionListItem
|
||||
title="Message"
|
||||
title={translate('Message')}
|
||||
data={message}
|
||||
/>
|
||||
}
|
||||
|
|
@ -180,7 +181,7 @@ function HistoryDetails(props) {
|
|||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title="Name"
|
||||
title={translate('Name')}
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
|
|
@ -188,7 +189,7 @@ function HistoryDetails(props) {
|
|||
!!droppedPath &&
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title="Source"
|
||||
title={translate('Source')}
|
||||
data={droppedPath}
|
||||
/>
|
||||
}
|
||||
|
|
@ -197,7 +198,7 @@ function HistoryDetails(props) {
|
|||
!!importedPath &&
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title="Imported To"
|
||||
title={translate('ImportedTo')}
|
||||
data={importedPath}
|
||||
/>
|
||||
}
|
||||
|
|
@ -229,12 +230,12 @@ function HistoryDetails(props) {
|
|||
return (
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title="Name"
|
||||
title={translate('Name')}
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title="Reason"
|
||||
title={translate('Reason')}
|
||||
data={reasonMessage}
|
||||
/>
|
||||
</DescriptionList>
|
||||
|
|
@ -250,12 +251,12 @@ function HistoryDetails(props) {
|
|||
return (
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title="Source Path"
|
||||
title={translate('SourcePath')}
|
||||
data={sourcePath}
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title="Destination Path"
|
||||
title={translate('DestinationPath')}
|
||||
data={path}
|
||||
/>
|
||||
</DescriptionList>
|
||||
|
|
@ -271,7 +272,7 @@ function HistoryDetails(props) {
|
|||
return (
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title="Path"
|
||||
title={translate('Path')}
|
||||
data={sourceTitle}
|
||||
/>
|
||||
{
|
||||
|
|
@ -286,7 +287,7 @@ function HistoryDetails(props) {
|
|||
})
|
||||
}
|
||||
<DescriptionListItem
|
||||
title="Existing tags scrubbed"
|
||||
title={translate('ExistingTagsScrubbed')}
|
||||
data={tagsScrubbed === 'True' ? <Icon name={icons.CHECK} /> : <Icon name={icons.REMOVE} />}
|
||||
/>
|
||||
</DescriptionList>
|
||||
|
|
@ -301,14 +302,14 @@ function HistoryDetails(props) {
|
|||
return (
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title="Name"
|
||||
title={translate('Name')}
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
{
|
||||
!!statusMessages &&
|
||||
<DescriptionListItem
|
||||
title="Import failures"
|
||||
title={translate('ImportFailures')}
|
||||
data={getDetailedList(JSON.parse(statusMessages))}
|
||||
/>
|
||||
}
|
||||
|
|
@ -332,14 +333,14 @@ function HistoryDetails(props) {
|
|||
return (
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title="Name"
|
||||
title={translate('Name')}
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
{
|
||||
!!indexer &&
|
||||
<DescriptionListItem
|
||||
title="Indexer"
|
||||
title={translate('Indexer')}
|
||||
data={indexer}
|
||||
/>
|
||||
}
|
||||
|
|
@ -347,7 +348,7 @@ function HistoryDetails(props) {
|
|||
{
|
||||
!!releaseGroup &&
|
||||
<DescriptionListItem
|
||||
title="Release Group"
|
||||
title={translate('ReleaseGroup')}
|
||||
data={releaseGroup}
|
||||
/>
|
||||
}
|
||||
|
|
@ -368,7 +369,7 @@ function HistoryDetails(props) {
|
|||
{
|
||||
!!downloadClient &&
|
||||
<DescriptionListItem
|
||||
title="Download Client"
|
||||
title={translate('DownloadClient')}
|
||||
data={downloadClient}
|
||||
/>
|
||||
}
|
||||
|
|
@ -376,7 +377,7 @@ function HistoryDetails(props) {
|
|||
{
|
||||
!!downloadId &&
|
||||
<DescriptionListItem
|
||||
title="Grab ID"
|
||||
title={translate('GrabID')}
|
||||
data={downloadId}
|
||||
/>
|
||||
}
|
||||
|
|
@ -384,7 +385,7 @@ function HistoryDetails(props) {
|
|||
{
|
||||
!!indexer &&
|
||||
<DescriptionListItem
|
||||
title="Age (when grabbed)"
|
||||
title={translate('AgeWhenGrabbed')}
|
||||
data={formatAge(age, ageHours, ageMinutes)}
|
||||
/>
|
||||
}
|
||||
|
|
@ -392,7 +393,7 @@ function HistoryDetails(props) {
|
|||
{
|
||||
!!publishedDate &&
|
||||
<DescriptionListItem
|
||||
title="Published Date"
|
||||
title={translate('PublishedDate')}
|
||||
data={formatDateTime(publishedDate, shortDateFormat, timeFormat, { includeSeconds: true })}
|
||||
/>
|
||||
}
|
||||
|
|
@ -409,14 +410,14 @@ function HistoryDetails(props) {
|
|||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title="Name"
|
||||
title={translate('Name')}
|
||||
data={sourceTitle}
|
||||
/>
|
||||
|
||||
{
|
||||
!!message &&
|
||||
<DescriptionListItem
|
||||
title="Message"
|
||||
title={translate('Message')}
|
||||
data={message}
|
||||
/>
|
||||
}
|
||||
|
|
@ -428,7 +429,7 @@ function HistoryDetails(props) {
|
|||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
descriptionClassName={styles.description}
|
||||
title="Name"
|
||||
title={translate('Name')}
|
||||
data={sourceTitle}
|
||||
/>
|
||||
</DescriptionList>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptions
|
|||
import TablePager from 'Components/Table/TablePager';
|
||||
import { align, icons } from 'Helpers/Props';
|
||||
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import HistoryRowConnector from './HistoryRowConnector';
|
||||
|
||||
class History extends Component {
|
||||
|
|
@ -66,11 +67,11 @@ class History extends Component {
|
|||
const hasError = error || booksError;
|
||||
|
||||
return (
|
||||
<PageContent title="History">
|
||||
<PageContent title={translate('History')}>
|
||||
<PageToolbar>
|
||||
<PageToolbarSection>
|
||||
<PageToolbarButton
|
||||
label="Refresh"
|
||||
label={translate('Refresh')}
|
||||
iconName={icons.REFRESH}
|
||||
isSpinning={isFetching}
|
||||
onPress={onFirstPagePress}
|
||||
|
|
@ -83,7 +84,7 @@ class History extends Component {
|
|||
columns={columns}
|
||||
>
|
||||
<PageToolbarButton
|
||||
label="Options"
|
||||
label={translate('Options')}
|
||||
iconName={icons.TABLE}
|
||||
/>
|
||||
</TableOptionsModalWrapper>
|
||||
|
|
@ -106,7 +107,9 @@ class History extends Component {
|
|||
|
||||
{
|
||||
!isFetchingAny && hasError &&
|
||||
<div>Unable to load history</div>
|
||||
<div>
|
||||
{translate('UnableToLoadHistory')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import TablePager from 'Components/Table/TablePager';
|
|||
import { align, icons } from 'Helpers/Props';
|
||||
import getRemovedItems from 'Utilities/Object/getRemovedItems';
|
||||
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||
import removeOldSelectedState from 'Utilities/Table/removeOldSelectedState';
|
||||
import selectAll from 'Utilities/Table/selectAll';
|
||||
|
|
@ -150,11 +151,11 @@ class Queue extends Component {
|
|||
const disableSelectedActions = selectedCount === 0;
|
||||
|
||||
return (
|
||||
<PageContent title="Queue">
|
||||
<PageContent title={translate('Queue')}>
|
||||
<PageToolbar>
|
||||
<PageToolbarSection>
|
||||
<PageToolbarButton
|
||||
label="Refresh"
|
||||
label={translate('Refresh')}
|
||||
iconName={icons.REFRESH}
|
||||
isSpinning={isRefreshing}
|
||||
onPress={onRefreshPress}
|
||||
|
|
@ -163,7 +164,7 @@ class Queue extends Component {
|
|||
<PageToolbarSeparator />
|
||||
|
||||
<PageToolbarButton
|
||||
label="Grab Selected"
|
||||
label={translate('GrabSelected')}
|
||||
iconName={icons.DOWNLOAD}
|
||||
isDisabled={disableSelectedActions || !isPendingSelected}
|
||||
isSpinning={isGrabbing}
|
||||
|
|
@ -171,7 +172,7 @@ class Queue extends Component {
|
|||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label="Remove Selected"
|
||||
label={translate('RemoveSelected')}
|
||||
iconName={icons.REMOVE}
|
||||
isDisabled={disableSelectedActions}
|
||||
isSpinning={isRemoving}
|
||||
|
|
@ -188,7 +189,7 @@ class Queue extends Component {
|
|||
optionsComponent={QueueOptionsConnector}
|
||||
>
|
||||
<PageToolbarButton
|
||||
label="Options"
|
||||
label={translate('Options')}
|
||||
iconName={icons.TABLE}
|
||||
/>
|
||||
</TableOptionsModalWrapper>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
|||
import React from 'react';
|
||||
import Icon from 'Components/Icon';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
function QueueDetails(props) {
|
||||
const {
|
||||
|
|
@ -23,7 +24,7 @@ function QueueDetails(props) {
|
|||
return (
|
||||
<Icon
|
||||
name={icons.PENDING}
|
||||
title={`Release will be processed ${moment(estimatedCompletionTime).fromNow()}`}
|
||||
title={translate('ReleaseWillBeProcessedInterp', [moment(estimatedCompletionTime).fromNow()])}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -34,7 +35,7 @@ function QueueDetails(props) {
|
|||
<Icon
|
||||
name={icons.DOWNLOAD}
|
||||
kind={kinds.DANGER}
|
||||
title={`Import failed: ${errorMessage}`}
|
||||
title={translate('ImportFailedInterp', [errorMessage])}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -47,7 +48,7 @@ function QueueDetails(props) {
|
|||
<Icon
|
||||
name={icons.DOWNLOADING}
|
||||
kind={kinds.DANGER}
|
||||
title={`Download failed: ${errorMessage}`}
|
||||
title={translate('DownloadFailedInterp', [errorMessage])}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -57,7 +58,7 @@ function QueueDetails(props) {
|
|||
<Icon
|
||||
name={icons.DOWNLOADING}
|
||||
kind={kinds.DANGER}
|
||||
title="Download failed: check download client for more details"
|
||||
title={translate('DownloadFailedCheckDownloadClientForMoreDetails')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -67,7 +68,7 @@ function QueueDetails(props) {
|
|||
<Icon
|
||||
name={icons.DOWNLOADING}
|
||||
kind={kinds.WARNING}
|
||||
title="Download warning: check download client for more details"
|
||||
title={translate('DownloadWarningCheckDownloadClientForMoreDetails')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -76,7 +77,7 @@ function QueueDetails(props) {
|
|||
return (
|
||||
<Icon
|
||||
name={icons.DOWNLOADING}
|
||||
title={`Book is downloading - ${progress.toFixed(1)}% ${title}`}
|
||||
title={translate('BookIsDownloadingInterp', [progress.toFixed(1), title])}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import FormGroup from 'Components/Form/FormGroup';
|
|||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import { inputTypes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
class QueueOptions extends Component {
|
||||
|
||||
|
|
@ -54,13 +55,15 @@ class QueueOptions extends Component {
|
|||
return (
|
||||
<Fragment>
|
||||
<FormGroup>
|
||||
<FormLabel>Show Unknown Author Items</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowUnknownAuthorItems')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="includeUnknownAuthorItems"
|
||||
value={includeUnknownAuthorItems}
|
||||
helpText="Show items without a author in the queue, this could include removed authors, movies or anything else in Readarr's category"
|
||||
helpText={translate('IncludeUnknownAuthorItemsHelpText')}
|
||||
onChange={this.onOptionChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import TableRow from 'Components/Table/TableRow';
|
|||
import Popover from 'Components/Tooltip/Popover';
|
||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import QueueStatusCell from './QueueStatusCell';
|
||||
import RemoveQueueItemModal from './RemoveQueueItemModal';
|
||||
import TimeleftCell from './TimeleftCell';
|
||||
|
|
@ -285,7 +286,7 @@ class QueueRow extends Component {
|
|||
kind={kinds.DANGER}
|
||||
/>
|
||||
}
|
||||
title="Manual Download"
|
||||
title={translate('ManualDownload')}
|
||||
body="This release failed parsing checks and was manually downloaded from an interactive search. Import is likely to fail."
|
||||
position={tooltipPositions.LEFT}
|
||||
/>
|
||||
|
|
@ -310,7 +311,7 @@ class QueueRow extends Component {
|
|||
}
|
||||
|
||||
<SpinnerIconButton
|
||||
title="Remove from queue"
|
||||
title={translate('RemoveFromQueue')}
|
||||
name={icons.REMOVE}
|
||||
isSpinning={isRemoving}
|
||||
onPress={this.onRemoveQueueItemPress}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import Icon from 'Components/Icon';
|
|||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './QueueStatusCell.css';
|
||||
|
||||
function getDetailedPopoverBody(statusMessages) {
|
||||
|
|
@ -49,7 +50,7 @@ function QueueStatusCell(props) {
|
|||
// status === 'downloading'
|
||||
let iconName = icons.DOWNLOADING;
|
||||
let iconKind = kinds.DEFAULT;
|
||||
let title = 'Downloading';
|
||||
let title = translate('Title');
|
||||
|
||||
if (hasWarning) {
|
||||
iconKind = kinds.WARNING;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes, kinds, sizes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
class RemoveQueueItemModal extends Component {
|
||||
|
||||
|
|
@ -95,26 +96,30 @@ class RemoveQueueItemModal extends Component {
|
|||
</div>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Remove From Download Client</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('RemoveFromDownloadClient')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="remove"
|
||||
value={remove}
|
||||
helpTextWarning="Removing will remove the download and the file(s) from the download client."
|
||||
helpTextWarning={translate('RemoveHelpTextWarning')}
|
||||
isDisabled={!canIgnore}
|
||||
onChange={this.onRemoveChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Blacklist Release</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('BlacklistRelease')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="blacklist"
|
||||
value={blacklist}
|
||||
helpText="Prevents Readarr from automatically grabbing this release again"
|
||||
helpText={translate('BlacklistHelpText')}
|
||||
onChange={this.onBlacklistChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
@ -122,12 +127,14 @@ class RemoveQueueItemModal extends Component {
|
|||
{
|
||||
blacklist &&
|
||||
<FormGroup>
|
||||
<FormLabel>Skip Redownload</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('SkipRedownload')}
|
||||
</FormLabel>
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="skipredownload"
|
||||
value={skipredownload}
|
||||
helpText="Prevents Readarr from trying download an alternative release for this item"
|
||||
helpText={translate('SkipredownloadHelpText')}
|
||||
onChange={this.onSkipReDownloadChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes, kinds, sizes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './RemoveQueueItemsModal.css';
|
||||
|
||||
class RemoveQueueItemsModal extends Component {
|
||||
|
|
@ -96,13 +97,15 @@ class RemoveQueueItemsModal extends Component {
|
|||
</div>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Remove From Download Client</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('RemoveFromDownloadClient')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="remove"
|
||||
value={remove}
|
||||
helpTextWarning="Removing will remove the download and the file(s) from the download client."
|
||||
helpTextWarning={translate('RemoveHelpTextWarning')}
|
||||
isDisabled={!canIgnore}
|
||||
onChange={this.onRemoveChange}
|
||||
/>
|
||||
|
|
@ -117,7 +120,7 @@ class RemoveQueueItemsModal extends Component {
|
|||
type={inputTypes.CHECK}
|
||||
name="blacklist"
|
||||
value={blacklist}
|
||||
helpText="Prevents Readarr from automatically grabbing these files again"
|
||||
helpText={translate('BlacklistHelpText')}
|
||||
onChange={this.onBlacklistChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
@ -125,12 +128,14 @@ class RemoveQueueItemsModal extends Component {
|
|||
{
|
||||
blacklist &&
|
||||
<FormGroup>
|
||||
<FormLabel>Skip Redownload</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('SkipRedownload')}
|
||||
</FormLabel>
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="skipredownload"
|
||||
value={skipredownload}
|
||||
helpText="Prevents Readarr from trying download alternative releases for the removed items"
|
||||
helpText={translate('SkipredownloadHelpText')}
|
||||
onChange={this.onSkipReDownloadChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import formatTime from 'Utilities/Date/formatTime';
|
|||
import formatTimeSpan from 'Utilities/Date/formatTimeSpan';
|
||||
import getRelativeDate from 'Utilities/Date/getRelativeDate';
|
||||
import formatBytes from 'Utilities/Number/formatBytes';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './TimeleftCell.css';
|
||||
|
||||
function TimeleftCell(props) {
|
||||
|
|
@ -26,7 +27,7 @@ function TimeleftCell(props) {
|
|||
return (
|
||||
<TableRowCell
|
||||
className={styles.timeleft}
|
||||
title={`Delaying download until ${date} at ${time}`}
|
||||
title={translate('DelayingDownloadUntilInterp', [date, time])}
|
||||
>
|
||||
-
|
||||
</TableRowCell>
|
||||
|
|
@ -40,7 +41,7 @@ function TimeleftCell(props) {
|
|||
return (
|
||||
<TableRowCell
|
||||
className={styles.timeleft}
|
||||
title={`Retrying download ${date} at ${time}`}
|
||||
title={translate('RetryingDownloadInterp', [date, time])}
|
||||
>
|
||||
-
|
||||
</TableRowCell>
|
||||
|
|
|
|||
|
|
@ -1,42 +1,43 @@
|
|||
import React from 'react';
|
||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
function AuthorMonitoringOptionsPopoverContent() {
|
||||
return (
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title="All Books"
|
||||
title={translate('AllBooks')}
|
||||
data="Monitor all books"
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title="Future Books"
|
||||
title={translate('FutureBooks')}
|
||||
data="Monitor books that have not released yet"
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title="Missing Books"
|
||||
title={translate('MissingBooks')}
|
||||
data="Monitor books that do not have files or have not released yet"
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title="Existing Books"
|
||||
title={translate('ExistingBooks')}
|
||||
data="Monitor books that have files or have not released yet"
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title="First Book"
|
||||
title={translate('FirstBook')}
|
||||
data="Monitor the first book. All other books will be ignored"
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title="Latest Book"
|
||||
title={translate('LatestBook')}
|
||||
data="Monitor the latest book and future books"
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title="None"
|
||||
title={translate('None')}
|
||||
data="No books will be monitored"
|
||||
/>
|
||||
</DescriptionList>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
|
|||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import UpdateChanges from 'System/Updates/UpdateChanges';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './AppUpdatedModalContent.css';
|
||||
|
||||
function AppUpdatedModalContent(props) {
|
||||
|
|
@ -49,12 +50,12 @@ function AppUpdatedModalContent(props) {
|
|||
</div>
|
||||
|
||||
<UpdateChanges
|
||||
title="New"
|
||||
title={translate('New')}
|
||||
changes={update.changes.new}
|
||||
/>
|
||||
|
||||
<UpdateChanges
|
||||
title="Fixed"
|
||||
title={translate('Fixed')}
|
||||
changes={update.changes.fixed}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
|
|||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { icons, inputTypes, kinds } from 'Helpers/Props';
|
||||
import formatBytes from 'Utilities/Number/formatBytes';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './DeleteAuthorModalContent.css';
|
||||
|
||||
class DeleteAuthorModalContent extends Component {
|
||||
|
|
@ -67,7 +68,7 @@ class DeleteAuthorModalContent extends Component {
|
|||
const addImportListExclusion = this.state.addImportListExclusion;
|
||||
|
||||
let deleteFilesLabel = `Delete ${bookFileCount} Book Files`;
|
||||
let deleteFilesHelpText = 'Delete the book files and author folder';
|
||||
let deleteFilesHelpText = translate('DeleteFilesHelpText');
|
||||
|
||||
if (bookFileCount === 0) {
|
||||
deleteFilesLabel = 'Delete Author Folder';
|
||||
|
|
@ -106,13 +107,15 @@ class DeleteAuthorModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Add List Exclusion</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('AddListExclusion')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="addImportListExclusion"
|
||||
value={addImportListExclusion}
|
||||
helpText="Prevent author from being added to Readarr by Import lists"
|
||||
helpText={translate('AddImportListExclusionHelpText')}
|
||||
kind={kinds.DANGER}
|
||||
onChange={this.onAddImportListExclusionChange}
|
||||
/>
|
||||
|
|
@ -121,7 +124,9 @@ class DeleteAuthorModalContent extends Component {
|
|||
{
|
||||
deleteFiles &&
|
||||
<div className={styles.deleteFilesMessage}>
|
||||
<div>The author folder <strong>{path}</strong> and all of its content will be deleted.</div>
|
||||
<div>
|
||||
{translate('TheAuthorFolderStrongpathstrongAndAllOfItsContentWillBeDeleted')}
|
||||
</div>
|
||||
|
||||
{
|
||||
!!bookFileCount &&
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import InteractiveSearchFilterMenuConnector from 'InteractiveSearch/InteractiveS
|
|||
import InteractiveSearchTable from 'InteractiveSearch/InteractiveSearchTable';
|
||||
import OrganizePreviewModalConnector from 'Organize/OrganizePreviewModalConnector';
|
||||
import RetagPreviewModalConnector from 'Retag/RetagPreviewModalConnector';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import selectAll from 'Utilities/Table/selectAll';
|
||||
import toggleSelected from 'Utilities/Table/toggleSelected';
|
||||
import InteractiveImportModal from '../../InteractiveImport/InteractiveImportModal';
|
||||
|
|
@ -181,41 +182,41 @@ class AuthorDetails extends Component {
|
|||
<PageToolbar>
|
||||
<PageToolbarSection>
|
||||
<PageToolbarButton
|
||||
label="Refresh & Scan"
|
||||
label={translate('RefreshScan')}
|
||||
iconName={icons.REFRESH}
|
||||
spinningName={icons.REFRESH}
|
||||
title="Refresh information and scan disk"
|
||||
title={translate('RefreshInformationAndScanDisk')}
|
||||
isSpinning={isRefreshing}
|
||||
onPress={onRefreshPress}
|
||||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label="Search Monitored"
|
||||
label={translate('SearchMonitored')}
|
||||
iconName={icons.SEARCH}
|
||||
isDisabled={!monitored || !hasMonitoredBooks || !hasBooks}
|
||||
isSpinning={isSearching}
|
||||
title={hasMonitoredBooks ? undefined : 'No monitored books for this author'}
|
||||
title={hasMonitoredBooks ? undefined : translate('HasMonitoredBooksNoMonitoredBooksForThisAuthor')}
|
||||
onPress={onSearchPress}
|
||||
/>
|
||||
|
||||
<PageToolbarSeparator />
|
||||
|
||||
<PageToolbarButton
|
||||
label="Preview Rename"
|
||||
label={translate('PreviewRename')}
|
||||
iconName={icons.ORGANIZE}
|
||||
isDisabled={!hasBookFiles}
|
||||
onPress={this.onOrganizePress}
|
||||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label="Preview Retag"
|
||||
label={translate('PreviewRetag')}
|
||||
iconName={icons.RETAG}
|
||||
isDisabled={!hasBookFiles}
|
||||
onPress={this.onRetagPress}
|
||||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label="Manual Import"
|
||||
label={translate('ManualImport')}
|
||||
iconName={icons.INTERACTIVE}
|
||||
onPress={this.onInteractiveImportPress}
|
||||
/>
|
||||
|
|
@ -223,13 +224,13 @@ class AuthorDetails extends Component {
|
|||
<PageToolbarSeparator />
|
||||
|
||||
<PageToolbarButton
|
||||
label="Edit"
|
||||
label={translate('Edit')}
|
||||
iconName={icons.EDIT}
|
||||
onPress={this.onEditAuthorPress}
|
||||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label="Delete"
|
||||
label={translate('Delete')}
|
||||
iconName={icons.DELETE}
|
||||
onPress={this.onDeleteAuthorPress}
|
||||
/>
|
||||
|
|
@ -237,7 +238,7 @@ class AuthorDetails extends Component {
|
|||
|
||||
<PageToolbarSection alignContent={align.RIGHT}>
|
||||
<PageToolbarButton
|
||||
label={allExpanded ? 'Collapse All' : 'Expand All'}
|
||||
label={allExpanded ? translate('AllExpandedCollapseAll') : translate('AllExpandedExpandAll')}
|
||||
iconName={expandIcon}
|
||||
onPress={this.onExpandAllPress}
|
||||
/>
|
||||
|
|
@ -258,7 +259,7 @@ class AuthorDetails extends Component {
|
|||
className={styles.authorNavigationButton}
|
||||
name={icons.ARROW_LEFT}
|
||||
size={30}
|
||||
title={`Go to ${previousAuthor.authorName}`}
|
||||
title={translate('GoToInterp', [previousAuthor.authorName])}
|
||||
to={`/author/${previousAuthor.titleSlug}`}
|
||||
/>
|
||||
|
||||
|
|
@ -266,7 +267,7 @@ class AuthorDetails extends Component {
|
|||
className={styles.authorUpButton}
|
||||
name={icons.ARROW_UP}
|
||||
size={30}
|
||||
title={'Go to author listing'}
|
||||
title={translate('GoToAuthorListing')}
|
||||
to={'/'}
|
||||
/>
|
||||
|
||||
|
|
@ -274,7 +275,7 @@ class AuthorDetails extends Component {
|
|||
className={styles.authorNavigationButton}
|
||||
name={icons.ARROW_RIGHT}
|
||||
size={30}
|
||||
title={`Go to ${nextAuthor.authorName}`}
|
||||
title={translate('GoToInterp', [nextAuthor.authorName])}
|
||||
to={`/author/${nextAuthor.titleSlug}`}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -288,12 +289,16 @@ class AuthorDetails extends Component {
|
|||
|
||||
{
|
||||
!isFetching && booksError &&
|
||||
<div>Loading books failed</div>
|
||||
<div>
|
||||
{translate('LoadingBooksFailed')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && bookFilesError &&
|
||||
<div>Loading book files failed</div>
|
||||
<div>
|
||||
{translate('LoadingBookFilesFailed')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import QualityProfileNameConnector from 'Settings/Profiles/Quality/QualityProfil
|
|||
import fonts from 'Styles/Variables/fonts';
|
||||
import formatBytes from 'Utilities/Number/formatBytes';
|
||||
import stripHtml from 'Utilities/String/stripHtml';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AuthorAlternateTitles from './AuthorAlternateTitles';
|
||||
import AuthorDetailsLinks from './AuthorDetailsLinks';
|
||||
import AuthorTagsConnector from './AuthorTagsConnector';
|
||||
|
|
@ -95,7 +96,7 @@ class AuthorDetailsHeader extends Component {
|
|||
|
||||
const continuing = status === 'continuing';
|
||||
|
||||
let bookFilesCountMessage = 'No book files';
|
||||
let bookFilesCountMessage = translate('BookFilesCountMessage');
|
||||
|
||||
if (bookFileCount === 1) {
|
||||
bookFilesCountMessage = '1 book file';
|
||||
|
|
@ -152,7 +153,7 @@ class AuthorDetailsHeader extends Component {
|
|||
size={20}
|
||||
/>
|
||||
}
|
||||
title="Alternate Titles"
|
||||
title={translate('AlternateTitles')}
|
||||
body={<AuthorAlternateTitles alternateTitles={alternateTitles} />}
|
||||
position={tooltipPositions.BOTTOM}
|
||||
/>
|
||||
|
|
@ -204,7 +205,7 @@ class AuthorDetailsHeader extends Component {
|
|||
|
||||
<Label
|
||||
className={styles.detailsLabel}
|
||||
title="Quality Profile"
|
||||
title={translate('QualityProfile')}
|
||||
size={sizes.LARGE}
|
||||
>
|
||||
<Icon
|
||||
|
|
@ -237,7 +238,7 @@ class AuthorDetailsHeader extends Component {
|
|||
|
||||
<Label
|
||||
className={styles.detailsLabel}
|
||||
title={continuing ? 'More books are expected' : 'No additional books are expected'}
|
||||
title={continuing ? translate('ContinuingMoreBooksAreExpected') : translate('ContinuingNoAdditionalBooksAreExpected')}
|
||||
size={sizes.LARGE}
|
||||
>
|
||||
<Icon
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import NotFound from 'Components/NotFound';
|
|||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AuthorDetailsConnector from './AuthorDetailsConnector';
|
||||
import styles from './AuthorDetails.css';
|
||||
|
||||
|
|
@ -92,7 +93,7 @@ class AuthorDetailsPageConnector extends Component {
|
|||
if (!titleSlug) {
|
||||
return (
|
||||
<NotFound
|
||||
message="Sorry, that author cannot be found."
|
||||
message={translate('SorryThatAuthorCannotBeFound')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import MonitorToggleButton from 'Components/MonitorToggleButton';
|
|||
import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import { icons, sortDirections } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import getToggledRange from 'Utilities/Table/getToggledRange';
|
||||
import BookRowConnector from './BookRowConnector';
|
||||
import styles from './AuthorDetailsSeries.css';
|
||||
|
|
@ -152,7 +153,7 @@ class AuthorDetailsSeries extends Component {
|
|||
<Icon
|
||||
className={styles.expandButtonIcon}
|
||||
name={isExpanded ? icons.COLLAPSE : icons.EXPAND}
|
||||
title={isExpanded ? 'Hide books' : 'Show books'}
|
||||
title={isExpanded ? translate('IsExpandedHideBooks') : translate('IsExpandedShowBooks')}
|
||||
size={24}
|
||||
/>
|
||||
|
||||
|
|
@ -198,7 +199,7 @@ class AuthorDetailsSeries extends Component {
|
|||
iconClassName={styles.collapseButtonIcon}
|
||||
name={icons.COLLAPSE}
|
||||
size={20}
|
||||
title="Hide books"
|
||||
title={translate('HideBooks')}
|
||||
onPress={this.onExpandPress}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellCo
|
|||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import { kinds, sizes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './BookRow.css';
|
||||
|
||||
function getBookCountKind(monitored, bookFileCount, bookCount) {
|
||||
|
|
@ -196,7 +197,7 @@ class BookRow extends Component {
|
|||
className={styles.status}
|
||||
>
|
||||
<Label
|
||||
title={`${totalBookCount} books total. ${bookFileCount} books with files.`}
|
||||
title={translate('TotalBookCountBooksTotalBookFileCountBooksWithFilesInterp', [totalBookCount, bookFileCount])}
|
||||
kind={getBookCountKind(monitored, bookFileCount, bookCount)}
|
||||
size={sizes.MEDIUM}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
|
|||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import { icons, inputTypes, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './EditAuthorModalContent.css';
|
||||
|
||||
class EditAuthorModalContent extends Component {
|
||||
|
|
@ -87,19 +88,23 @@ class EditAuthorModalContent extends Component {
|
|||
<ModalBody>
|
||||
<Form {...otherProps}>
|
||||
<FormGroup>
|
||||
<FormLabel>Monitored</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Monitored')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="monitored"
|
||||
helpText="Download monitored books from this author"
|
||||
helpText={translate('MonitoredHelpText')}
|
||||
{...monitored}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Quality Profile</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('QualityProfile')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.QUALITY_PROFILE_SELECT}
|
||||
|
|
@ -122,7 +127,7 @@ class EditAuthorModalContent extends Component {
|
|||
name={icons.INFO}
|
||||
/>
|
||||
}
|
||||
title="Metadata Profile"
|
||||
title={translate('MetadataProfile')}
|
||||
body={<AuthorMetadataProfilePopoverContent />}
|
||||
position={tooltipPositions.RIGHT}
|
||||
/>
|
||||
|
|
@ -132,7 +137,7 @@ class EditAuthorModalContent extends Component {
|
|||
<FormInputGroup
|
||||
type={inputTypes.METADATA_PROFILE_SELECT}
|
||||
name="metadataProfileId"
|
||||
helpText="Changes will take place on next author refresh"
|
||||
helpText={translate('MetadataProfileIdHelpText')}
|
||||
includeNone={true}
|
||||
{...metadataProfileId}
|
||||
onChange={onInputChange}
|
||||
|
|
@ -141,7 +146,9 @@ class EditAuthorModalContent extends Component {
|
|||
}
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Path</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Path')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.PATH}
|
||||
|
|
@ -152,7 +159,9 @@ class EditAuthorModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Tags</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Tags')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TAG}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import TableBody from 'Components/Table/TableBody';
|
|||
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
||||
import { align, icons, sortDirections } from 'Helpers/Props';
|
||||
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||
import selectAll from 'Utilities/Table/selectAll';
|
||||
import toggleSelected from 'Utilities/Table/toggleSelected';
|
||||
|
|
@ -143,7 +144,7 @@ class AuthorEditor extends Component {
|
|||
const selectedAuthorIds = this.getSelectedIds();
|
||||
|
||||
return (
|
||||
<PageContent title="Author Editor">
|
||||
<PageContent title={translate('AuthorEditor')}>
|
||||
<PageToolbar>
|
||||
<PageToolbarSection />
|
||||
<PageToolbarSection alignContent={align.RIGHT}>
|
||||
|
|
@ -152,7 +153,7 @@ class AuthorEditor extends Component {
|
|||
onTableOptionChange={onTableOptionChange}
|
||||
>
|
||||
<PageToolbarButton
|
||||
label="Options"
|
||||
label={translate('Options')}
|
||||
iconName={icons.TABLE}
|
||||
/>
|
||||
</TableOptionsModalWrapper>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import SelectInput from 'Components/Form/SelectInput';
|
|||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||
import PageContentFooter from 'Components/Page/PageContentFooter';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AuthorEditorFooterLabel from './AuthorEditorFooterLabel';
|
||||
import DeleteAuthorModal from './Delete/DeleteAuthorModal';
|
||||
import TagsModal from './Tags/TagsModal';
|
||||
|
|
@ -165,7 +166,7 @@ class AuthorEditorFooter extends Component {
|
|||
<PageContentFooter>
|
||||
<div className={styles.inputContainer}>
|
||||
<AuthorEditorFooterLabel
|
||||
label="Monitor Author"
|
||||
label={translate('MonitorAuthor')}
|
||||
isSaving={isSaving && monitored !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
|
|
@ -196,7 +197,7 @@ class AuthorEditorFooter extends Component {
|
|||
className={styles.inputContainer}
|
||||
>
|
||||
<AuthorEditorFooterLabel
|
||||
label="Quality Profile"
|
||||
label={translate('QualityProfile')}
|
||||
isSaving={isSaving && qualityProfileId !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
|
|
@ -218,7 +219,7 @@ class AuthorEditorFooter extends Component {
|
|||
className={styles.inputContainer}
|
||||
>
|
||||
<AuthorEditorFooterLabel
|
||||
label="Metadata Profile"
|
||||
label={translate('MetadataProfile')}
|
||||
isSaving={isSaving && metadataProfileId !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
|
|
@ -240,7 +241,7 @@ class AuthorEditorFooter extends Component {
|
|||
className={styles.inputContainer}
|
||||
>
|
||||
<AuthorEditorFooterLabel
|
||||
label="Root Folder"
|
||||
label={translate('RootFolder')}
|
||||
isSaving={isSaving && rootFolderPath !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
|
|
@ -263,7 +264,7 @@ class AuthorEditorFooter extends Component {
|
|||
<div className={styles.buttonContainer}>
|
||||
<div className={styles.buttonContainerContent}>
|
||||
<AuthorEditorFooterLabel
|
||||
label={`${selectedCount} Author(s) Selected`}
|
||||
label={translate('SelectedCountAuthorsSelectedInterp', [selectedCount])}
|
||||
isSaving={false}
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes, kinds, sizes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './TagsModalContent.css';
|
||||
|
||||
class TagsModalContent extends Component {
|
||||
|
|
@ -74,7 +75,9 @@ class TagsModalContent extends Component {
|
|||
<ModalBody>
|
||||
<Form>
|
||||
<FormGroup>
|
||||
<FormLabel>Tags</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Tags')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TAG}
|
||||
|
|
@ -85,7 +88,9 @@ class TagsModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Apply Tags</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ApplyTags')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
|
|
@ -93,17 +98,19 @@ class TagsModalContent extends Component {
|
|||
value={applyTags}
|
||||
values={applyTagsOptions}
|
||||
helpTexts={[
|
||||
'How to apply tags to the selected author',
|
||||
'Add: Add the tags the existing list of tags',
|
||||
'Remove: Remove the entered tags',
|
||||
'Replace: Replace the tags with the entered tags (enter no tags to clear all tags)'
|
||||
translate('ApplyTagsHelpTexts1'),
|
||||
translate('ApplyTagsHelpTexts2'),
|
||||
translate('ApplyTagsHelpTexts3'),
|
||||
translate('ApplyTagsHelpTexts4')
|
||||
]}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Result</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Result')}
|
||||
</FormLabel>
|
||||
|
||||
<div className={styles.result}>
|
||||
{
|
||||
|
|
@ -120,7 +127,7 @@ class TagsModalContent extends Component {
|
|||
return (
|
||||
<Label
|
||||
key={tag.id}
|
||||
title={removeTag ? 'Removing tag' : 'Existing tag'}
|
||||
title={removeTag ? translate('RemoveTagRemovingTag') : translate('RemoveTagExistingTag')}
|
||||
kind={removeTag ? kinds.INVERSE : kinds.INFO}
|
||||
size={sizes.LARGE}
|
||||
>
|
||||
|
|
@ -146,7 +153,7 @@ class TagsModalContent extends Component {
|
|||
return (
|
||||
<Label
|
||||
key={tag.id}
|
||||
title={'Adding tag'}
|
||||
title={translate('AddingTag')}
|
||||
kind={kinds.SUCCESS}
|
||||
size={sizes.LARGE}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
|||
import TableRow from 'Components/Table/TableRow';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './AuthorHistoryRow.css';
|
||||
|
||||
function getTitle(eventType) {
|
||||
|
|
@ -132,7 +133,7 @@ class AuthorHistoryRow extends Component {
|
|||
{
|
||||
eventType === 'grabbed' &&
|
||||
<IconButton
|
||||
title="Mark as failed"
|
||||
title={translate('MarkAsFailed')}
|
||||
name={icons.REMOVE}
|
||||
onPress={this.onMarkAsFailedPress}
|
||||
/>
|
||||
|
|
@ -142,9 +143,9 @@ class AuthorHistoryRow extends Component {
|
|||
<ConfirmModal
|
||||
isOpen={isMarkAsFailedModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title="Mark as Failed"
|
||||
message={`Are you sure you want to mark '${sourceTitle}' as failed?`}
|
||||
confirmLabel="Mark as Failed"
|
||||
title={translate('MarkAsFailed')}
|
||||
message={translate('MarkAsFailedMessageText', [sourceTitle])}
|
||||
confirmLabel={translate('MarkAsFailed')}
|
||||
onConfirm={this.onConfirmMarkAsFailed}
|
||||
onCancel={this.onMarkAsFailedModalClose}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import React, { Component } from 'react';
|
|||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AuthorHistoryRowConnector from './AuthorHistoryRowConnector';
|
||||
|
||||
const columns = [
|
||||
|
|
@ -69,12 +70,16 @@ class AuthorHistoryTableContent extends Component {
|
|||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>Unable to load history.</div>
|
||||
<div>
|
||||
{translate('UnableToLoadHistory')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
isPopulated && !hasItems && !error &&
|
||||
<div>No history.</div>
|
||||
<div>
|
||||
{translate('NoHistory')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptions
|
|||
import { align, icons, sortDirections } from 'Helpers/Props';
|
||||
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AuthorIndexFooterConnector from './AuthorIndexFooterConnector';
|
||||
import AuthorIndexBannersConnector from './Banners/AuthorIndexBannersConnector';
|
||||
import AuthorIndexBannerOptionsModal from './Banners/Options/AuthorIndexBannerOptionsModal';
|
||||
|
|
@ -213,7 +214,7 @@ class AuthorIndex extends Component {
|
|||
<PageToolbar>
|
||||
<PageToolbarSection>
|
||||
<PageToolbarButton
|
||||
label="Update all"
|
||||
label={translate('UpdateAll')}
|
||||
iconName={icons.REFRESH}
|
||||
spinningName={icons.REFRESH}
|
||||
isSpinning={isRefreshingAuthor}
|
||||
|
|
@ -221,7 +222,7 @@ class AuthorIndex extends Component {
|
|||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label="RSS Sync"
|
||||
label={translate('RSSSync')}
|
||||
iconName={icons.RSS}
|
||||
isSpinning={isRssSyncExecuting}
|
||||
isDisabled={hasNoAuthor}
|
||||
|
|
@ -242,7 +243,7 @@ class AuthorIndex extends Component {
|
|||
optionsComponent={AuthorIndexTableOptionsConnector}
|
||||
>
|
||||
<PageToolbarButton
|
||||
label="Options"
|
||||
label={translate('Options')}
|
||||
iconName={icons.TABLE}
|
||||
/>
|
||||
</TableOptionsModalWrapper> :
|
||||
|
|
@ -252,7 +253,7 @@ class AuthorIndex extends Component {
|
|||
{
|
||||
view === 'posters' ?
|
||||
<PageToolbarButton
|
||||
label="Options"
|
||||
label={translate('Options')}
|
||||
iconName={icons.POSTER}
|
||||
isDisabled={hasNoAuthor}
|
||||
onPress={this.onPosterOptionsPress}
|
||||
|
|
@ -263,7 +264,7 @@ class AuthorIndex extends Component {
|
|||
{
|
||||
view === 'banners' ?
|
||||
<PageToolbarButton
|
||||
label="Options"
|
||||
label={translate('Options')}
|
||||
iconName={icons.POSTER}
|
||||
isDisabled={hasNoAuthor}
|
||||
onPress={this.onBannerOptionsPress}
|
||||
|
|
@ -274,7 +275,7 @@ class AuthorIndex extends Component {
|
|||
{
|
||||
view === 'overview' ?
|
||||
<PageToolbarButton
|
||||
label="Options"
|
||||
label={translate('Options')}
|
||||
iconName={icons.OVERVIEW}
|
||||
isDisabled={hasNoAuthor}
|
||||
onPress={this.onOverviewOptionsPress}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { ColorImpairedConsumer } from 'App/ColorImpairedContext';
|
|||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||
import formatBytes from 'Utilities/Number/formatBytes';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './AuthorIndexFooter.css';
|
||||
|
||||
class AuthorIndexFooter extends PureComponent {
|
||||
|
|
@ -60,7 +61,9 @@ class AuthorIndexFooter extends PureComponent {
|
|||
enableColorImpairedMode && 'colorImpaired'
|
||||
)}
|
||||
/>
|
||||
<div>Continuing (All books downloaded)</div>
|
||||
<div>
|
||||
{translate('ContinuingAllBooksDownloaded')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.legendItem}>
|
||||
|
|
@ -70,7 +73,9 @@ class AuthorIndexFooter extends PureComponent {
|
|||
enableColorImpairedMode && 'colorImpaired'
|
||||
)}
|
||||
/>
|
||||
<div>Ended (All books downloaded)</div>
|
||||
<div>
|
||||
{translate('EndedAllBooksDownloaded')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.legendItem}>
|
||||
|
|
@ -80,7 +85,9 @@ class AuthorIndexFooter extends PureComponent {
|
|||
enableColorImpairedMode && 'colorImpaired'
|
||||
)}
|
||||
/>
|
||||
<div>Missing Books (Author monitored)</div>
|
||||
<div>
|
||||
{translate('MissingBooksAuthorMonitored')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.legendItem}>
|
||||
|
|
@ -90,55 +97,57 @@ class AuthorIndexFooter extends PureComponent {
|
|||
enableColorImpairedMode && 'colorImpaired'
|
||||
)}
|
||||
/>
|
||||
<div>Missing Books (Author not monitored)</div>
|
||||
<div>
|
||||
{translate('MissingBooksAuthorNotMonitored')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.statistics}>
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title="Authors"
|
||||
title={translate('Authors')}
|
||||
data={count}
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title="Ended"
|
||||
title={translate('Ended')}
|
||||
data={ended}
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title="Continuing"
|
||||
title={translate('Continuing')}
|
||||
data={continuing}
|
||||
/>
|
||||
</DescriptionList>
|
||||
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title="Monitored"
|
||||
title={translate('Monitored')}
|
||||
data={monitored}
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title="Unmonitored"
|
||||
title={translate('Unmonitored')}
|
||||
data={count - monitored}
|
||||
/>
|
||||
</DescriptionList>
|
||||
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title="Books"
|
||||
title={translate('Books')}
|
||||
data={books}
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
title="Files"
|
||||
title={translate('Files')}
|
||||
data={bookFiles}
|
||||
/>
|
||||
</DescriptionList>
|
||||
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
title="Total File Size"
|
||||
title={translate('TotalFileSize')}
|
||||
data={formatBytes(totalFileSize)}
|
||||
/>
|
||||
</DescriptionList>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import Link from 'Components/Link/Link';
|
|||
import SpinnerIconButton from 'Components/Link/SpinnerIconButton';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import getRelativeDate from 'Utilities/Date/getRelativeDate';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AuthorIndexBannerInfo from './AuthorIndexBannerInfo';
|
||||
import styles from './AuthorIndexBanner.css';
|
||||
|
||||
|
|
@ -107,7 +108,7 @@ class AuthorIndexBanner extends Component {
|
|||
<SpinnerIconButton
|
||||
className={styles.action}
|
||||
name={icons.REFRESH}
|
||||
title="Refresh Author"
|
||||
title={translate('RefreshAuthor')}
|
||||
isSpinning={isRefreshingAuthor}
|
||||
onPress={onRefreshAuthorPress}
|
||||
/>
|
||||
|
|
@ -117,7 +118,7 @@ class AuthorIndexBanner extends Component {
|
|||
<SpinnerIconButton
|
||||
className={styles.action}
|
||||
name={icons.SEARCH}
|
||||
title="Search for monitored books"
|
||||
title={translate('SearchForMonitoredBooks')}
|
||||
isSpinning={isSearchingAuthor}
|
||||
onPress={onSearchPress}
|
||||
/>
|
||||
|
|
@ -126,7 +127,7 @@ class AuthorIndexBanner extends Component {
|
|||
<IconButton
|
||||
className={styles.action}
|
||||
name={icons.EDIT}
|
||||
title="Edit Author"
|
||||
title={translate('EditAuthor')}
|
||||
onPress={this.onEditAuthorPress}
|
||||
/>
|
||||
</Label>
|
||||
|
|
@ -135,7 +136,7 @@ class AuthorIndexBanner extends Component {
|
|||
status === 'ended' &&
|
||||
<div
|
||||
className={styles.ended}
|
||||
title="Ended"
|
||||
title={translate('Ended')}
|
||||
/>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
const bannerSizeOptions = [
|
||||
{ key: 'small', value: 'Small' },
|
||||
|
|
@ -114,7 +115,9 @@ class AuthorIndexBannerOptionsModalContent extends Component {
|
|||
<ModalBody>
|
||||
<Form>
|
||||
<FormGroup>
|
||||
<FormLabel> Size</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Size')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
|
|
@ -126,61 +129,71 @@ class AuthorIndexBannerOptionsModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Detailed Progress Bar</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('DetailedProgressBar')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="detailedProgressBar"
|
||||
value={detailedProgressBar}
|
||||
helpText="Show text on progess bar"
|
||||
helpText={translate('DetailedProgressBarHelpText')}
|
||||
onChange={this.onChangeBannerOption}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Show Name</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowName')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="showTitle"
|
||||
value={showTitle}
|
||||
helpText="Show author name under banner"
|
||||
helpText={translate('ShowTitleHelpText')}
|
||||
onChange={this.onChangeBannerOption}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Show Monitored</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowMonitored')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="showMonitored"
|
||||
value={showMonitored}
|
||||
helpText="Show monitored status under banner"
|
||||
helpText={translate('ShowMonitoredHelpText')}
|
||||
onChange={this.onChangeBannerOption}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Show Quality Profile</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowQualityProfile')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="showQualityProfile"
|
||||
value={showQualityProfile}
|
||||
helpText="Show quality profile under banner"
|
||||
helpText={translate('ShowQualityProfileHelpText')}
|
||||
onChange={this.onChangeBannerOption}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Show Search</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowSearch')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="showSearchAction"
|
||||
value={showSearchAction}
|
||||
helpText="Show search button on hover"
|
||||
helpText={translate('ShowSearchActionHelpText')}
|
||||
onChange={this.onChangeBannerOption}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { icons } from 'Helpers/Props';
|
|||
import dimensions from 'Styles/Variables/dimensions';
|
||||
import fonts from 'Styles/Variables/fonts';
|
||||
import stripHtml from 'Utilities/String/stripHtml';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AuthorIndexOverviewInfo from './AuthorIndexOverviewInfo';
|
||||
import styles from './AuthorIndexOverview.css';
|
||||
|
||||
|
|
@ -130,7 +131,7 @@ class AuthorIndexOverview extends Component {
|
|||
status === 'ended' &&
|
||||
<div
|
||||
className={styles.ended}
|
||||
title="Ended"
|
||||
title={translate('Ended')}
|
||||
/>
|
||||
}
|
||||
|
||||
|
|
@ -173,7 +174,7 @@ class AuthorIndexOverview extends Component {
|
|||
<div className={styles.actions}>
|
||||
<SpinnerIconButton
|
||||
name={icons.REFRESH}
|
||||
title="Refresh Author"
|
||||
title={translate('RefreshAuthor')}
|
||||
isSpinning={isRefreshingAuthor}
|
||||
onPress={onRefreshAuthorPress}
|
||||
/>
|
||||
|
|
@ -183,7 +184,7 @@ class AuthorIndexOverview extends Component {
|
|||
<SpinnerIconButton
|
||||
className={styles.action}
|
||||
name={icons.SEARCH}
|
||||
title="Search for monitored books"
|
||||
title={translate('SearchForMonitoredBooks')}
|
||||
isSpinning={isSearchingAuthor}
|
||||
onPress={onSearchPress}
|
||||
/>
|
||||
|
|
@ -191,7 +192,7 @@ class AuthorIndexOverview extends Component {
|
|||
|
||||
<IconButton
|
||||
name={icons.EDIT}
|
||||
title="Edit Author"
|
||||
title={translate('EditAuthor')}
|
||||
onPress={this.onEditAuthorPress}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
const posterSizeOptions = [
|
||||
{ key: 'small', value: 'Small' },
|
||||
|
|
@ -142,7 +143,9 @@ class AuthorIndexOverviewOptionsModalContent extends Component {
|
|||
<ModalBody>
|
||||
<Form>
|
||||
<FormGroup>
|
||||
<FormLabel>Poster Size</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('PosterSize')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
|
|
@ -154,19 +157,23 @@ class AuthorIndexOverviewOptionsModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Detailed Progress Bar</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('DetailedProgressBar')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="detailedProgressBar"
|
||||
value={detailedProgressBar}
|
||||
helpText="Show text on progess bar"
|
||||
helpText={translate('DetailedProgressBarHelpText')}
|
||||
onChange={this.onChangeOverviewOption}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Show Monitored</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowMonitored')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
|
|
@ -178,7 +185,9 @@ class AuthorIndexOverviewOptionsModalContent extends Component {
|
|||
|
||||
<FormGroup>
|
||||
|
||||
<FormLabel>Show Quality Profile</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowQualityProfile')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
|
|
@ -189,7 +198,9 @@ class AuthorIndexOverviewOptionsModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Show Last Book</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowLastBook')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
|
|
@ -200,7 +211,9 @@ class AuthorIndexOverviewOptionsModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Show Date Added</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowDateAdded')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
|
|
@ -211,7 +224,9 @@ class AuthorIndexOverviewOptionsModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Show Book Count</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowBookCount')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
|
|
@ -222,7 +237,9 @@ class AuthorIndexOverviewOptionsModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Show Path</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowPath')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
|
|
@ -233,7 +250,9 @@ class AuthorIndexOverviewOptionsModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Show Size on Disk</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowSizeOnDisk')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
|
|
@ -244,13 +263,15 @@ class AuthorIndexOverviewOptionsModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Show Search</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowSearch')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="showSearchAction"
|
||||
value={showSearchAction}
|
||||
helpText="Show search button"
|
||||
helpText={translate('ShowSearchActionHelpText')}
|
||||
onChange={this.onChangeOverviewOption}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import Link from 'Components/Link/Link';
|
|||
import SpinnerIconButton from 'Components/Link/SpinnerIconButton';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import getRelativeDate from 'Utilities/Date/getRelativeDate';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AuthorIndexPosterInfo from './AuthorIndexPosterInfo';
|
||||
import styles from './AuthorIndexPoster.css';
|
||||
|
||||
|
|
@ -122,7 +123,7 @@ class AuthorIndexPoster extends Component {
|
|||
<SpinnerIconButton
|
||||
className={styles.action}
|
||||
name={icons.REFRESH}
|
||||
title="Refresh Author"
|
||||
title={translate('RefreshAuthor')}
|
||||
isSpinning={isRefreshingAuthor}
|
||||
onPress={onRefreshAuthorPress}
|
||||
/>
|
||||
|
|
@ -132,7 +133,7 @@ class AuthorIndexPoster extends Component {
|
|||
<SpinnerIconButton
|
||||
className={styles.action}
|
||||
name={icons.SEARCH}
|
||||
title="Search for monitored books"
|
||||
title={translate('SearchForMonitoredBooks')}
|
||||
isSpinning={isSearchingAuthor}
|
||||
onPress={onSearchPress}
|
||||
/>
|
||||
|
|
@ -141,7 +142,7 @@ class AuthorIndexPoster extends Component {
|
|||
<IconButton
|
||||
className={styles.action}
|
||||
name={icons.EDIT}
|
||||
title="Edit Author"
|
||||
title={translate('EditAuthor')}
|
||||
onPress={this.onEditAuthorPress}
|
||||
/>
|
||||
</Label>
|
||||
|
|
@ -150,7 +151,7 @@ class AuthorIndexPoster extends Component {
|
|||
status === 'ended' &&
|
||||
<div
|
||||
className={styles.ended}
|
||||
title="Ended"
|
||||
title={translate('Ended')}
|
||||
/>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
const posterSizeOptions = [
|
||||
{ key: 'small', value: 'Small' },
|
||||
|
|
@ -114,7 +115,9 @@ class AuthorIndexPosterOptionsModalContent extends Component {
|
|||
<ModalBody>
|
||||
<Form>
|
||||
<FormGroup>
|
||||
<FormLabel>Poster Size</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('PosterSize')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
|
|
@ -126,61 +129,71 @@ class AuthorIndexPosterOptionsModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Detailed Progress Bar</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('DetailedProgressBar')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="detailedProgressBar"
|
||||
value={detailedProgressBar}
|
||||
helpText="Show text on progess bar"
|
||||
helpText={translate('DetailedProgressBarHelpText')}
|
||||
onChange={this.onChangePosterOption}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Show Name</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowName')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="showTitle"
|
||||
value={showTitle}
|
||||
helpText="Show author name under poster"
|
||||
helpText={translate('ShowTitleHelpText')}
|
||||
onChange={this.onChangePosterOption}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Show Monitored</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowMonitored')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="showMonitored"
|
||||
value={showMonitored}
|
||||
helpText="Show monitored status under poster"
|
||||
helpText={translate('ShowMonitoredHelpText')}
|
||||
onChange={this.onChangePosterOption}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Show Quality Profile</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowQualityProfile')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="showQualityProfile"
|
||||
value={showQualityProfile}
|
||||
helpText="Show quality profile under poster"
|
||||
helpText={translate('ShowQualityProfileHelpText')}
|
||||
onChange={this.onChangePosterOption}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Show Search</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowSearch')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="showSearchAction"
|
||||
value={showSearchAction}
|
||||
helpText="Show search button on hover"
|
||||
helpText={translate('ShowSearchActionHelpText')}
|
||||
onChange={this.onChangePosterOption}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import React from 'react';
|
|||
import ProgressBar from 'Components/ProgressBar';
|
||||
import { sizes } from 'Helpers/Props';
|
||||
import getProgressBarKind from 'Utilities/Author/getProgressBarKind';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './AuthorIndexProgressBar.css';
|
||||
|
||||
function AuthorIndexProgressBar(props) {
|
||||
|
|
@ -28,7 +29,7 @@ function AuthorIndexProgressBar(props) {
|
|||
size={detailedProgressBar ? sizes.MEDIUM : sizes.SMALL}
|
||||
showText={detailedProgressBar}
|
||||
text={text}
|
||||
title={`${bookFileCount} / ${bookCount} (Total: ${totalBookCount})`}
|
||||
title={translate('BookFileCountBookCountTotalTotalBookCountInterp', [bookFileCount, bookCount, totalBookCount])}
|
||||
width={posterWidth}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import IconButton from 'Components/Link/IconButton';
|
|||
import SpinnerIconButton from 'Components/Link/SpinnerIconButton';
|
||||
import VirtualTableRowCell from 'Components/Table/Cells/VirtualTableRowCell';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
class AuthorIndexActionsCell extends Component {
|
||||
|
||||
|
|
@ -65,14 +66,14 @@ class AuthorIndexActionsCell extends Component {
|
|||
>
|
||||
<SpinnerIconButton
|
||||
name={icons.REFRESH}
|
||||
title="Refresh Author"
|
||||
title={translate('RefreshAuthor')}
|
||||
isSpinning={isRefreshingAuthor}
|
||||
onPress={onRefreshAuthorPress}
|
||||
/>
|
||||
|
||||
<IconButton
|
||||
name={icons.EDIT}
|
||||
title="Edit Author"
|
||||
title={translate('EditAuthor')}
|
||||
onPress={this.onEditAuthorPress}
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import TagListConnector from 'Components/TagListConnector';
|
|||
import { icons } from 'Helpers/Props';
|
||||
import getProgressBarKind from 'Utilities/Author/getProgressBarKind';
|
||||
import formatBytes from 'Utilities/Number/formatBytes';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AuthorStatusCell from './AuthorStatusCell';
|
||||
import hasGrowableColumns from './hasGrowableColumns';
|
||||
import styles from './AuthorIndexRow.css';
|
||||
|
|
@ -278,7 +279,7 @@ class AuthorIndexRow extends Component {
|
|||
kind={getProgressBarKind(status, monitored, progress)}
|
||||
showText={true}
|
||||
text={`${bookFileCount} / ${bookCount}`}
|
||||
title={`${bookFileCount} / ${bookCount} (Total: ${totalBookCount})`}
|
||||
title={translate('BookFileCountBookCountTotalTotalBookCountInterp', [bookFileCount, bookCount, totalBookCount])}
|
||||
width={125}
|
||||
/>
|
||||
</VirtualTableRowCell>
|
||||
|
|
@ -356,7 +357,7 @@ class AuthorIndexRow extends Component {
|
|||
>
|
||||
<SpinnerIconButton
|
||||
name={icons.REFRESH}
|
||||
title="Refresh Author"
|
||||
title={translate('RefreshAuthor')}
|
||||
isSpinning={isRefreshingAuthor}
|
||||
onPress={onRefreshAuthorPress}
|
||||
/>
|
||||
|
|
@ -366,7 +367,7 @@ class AuthorIndexRow extends Component {
|
|||
<SpinnerIconButton
|
||||
className={styles.action}
|
||||
name={icons.SEARCH}
|
||||
title="Search for monitored books"
|
||||
title={translate('SearchForMonitoredBooks')}
|
||||
isSpinning={isSearchingAuthor}
|
||||
onPress={onSearchPress}
|
||||
/>
|
||||
|
|
@ -374,7 +375,7 @@ class AuthorIndexRow extends Component {
|
|||
|
||||
<IconButton
|
||||
name={icons.EDIT}
|
||||
title="Edit Author"
|
||||
title={translate('EditAuthor')}
|
||||
onPress={this.onEditAuthorPress}
|
||||
/>
|
||||
</VirtualTableRowCell>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import FormGroup from 'Components/Form/FormGroup';
|
|||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import { inputTypes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
class AuthorIndexTableOptions extends Component {
|
||||
|
||||
|
|
@ -64,25 +65,29 @@ class AuthorIndexTableOptions extends Component {
|
|||
return (
|
||||
<Fragment>
|
||||
<FormGroup>
|
||||
<FormLabel>Show Banners</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowBanners')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="showBanners"
|
||||
value={showBanners}
|
||||
helpText="Show banners instead of names"
|
||||
helpText={translate('ShowBannersHelpText')}
|
||||
onChange={this.onTableOptionChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Show Search</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ShowSearch')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="showSearchAction"
|
||||
value={showSearchAction}
|
||||
helpText="Show search button on hover"
|
||||
helpText={translate('ShowSearchActionHelpText')}
|
||||
onChange={this.onTableOptionChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import React from 'react';
|
|||
import Icon from 'Components/Icon';
|
||||
import VirtualTableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './AuthorStatusCell.css';
|
||||
|
||||
function AuthorStatusCell(props) {
|
||||
|
|
@ -22,13 +23,13 @@ function AuthorStatusCell(props) {
|
|||
<Icon
|
||||
className={styles.statusIcon}
|
||||
name={monitored ? icons.MONITORED : icons.UNMONITORED}
|
||||
title={monitored ? 'Author is monitored' : 'Author is unmonitored'}
|
||||
title={monitored ? translate('MonitoredAuthorIsMonitored') : translate('MonitoredAuthorIsUnmonitored')}
|
||||
/>
|
||||
|
||||
<Icon
|
||||
className={styles.statusIcon}
|
||||
name={status === 'ended' ? icons.AUTHOR_ENDED : icons.AUTHOR_CONTINUING}
|
||||
title={status === 'ended' ? 'Deceased' : 'Continuing'}
|
||||
title={status === 'ended' ? translate('StatusEndedDeceased') : translate('StatusEndedContinuing')}
|
||||
/>
|
||||
</Component>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
|
|||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes, kinds } from 'Helpers/Props';
|
||||
import formatBytes from 'Utilities/Number/formatBytes';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './DeleteBookModalContent.css';
|
||||
|
||||
class DeleteBookModalContent extends Component {
|
||||
|
|
@ -91,13 +92,15 @@ class DeleteBookModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Add List Exclusion</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('AddListExclusion')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="addImportListExclusion"
|
||||
value={addImportListExclusion}
|
||||
helpText="Prevent book from being added to Readarr by Import Lists or Author Refresh"
|
||||
helpText={translate('AddImportListExclusionHelpText')}
|
||||
kind={kinds.DANGER}
|
||||
onChange={this.onAddImportListExclusionChange}
|
||||
/>
|
||||
|
|
@ -106,14 +109,18 @@ class DeleteBookModalContent extends Component {
|
|||
{
|
||||
!addImportListExclusion &&
|
||||
<div className={styles.deleteFilesMessage}>
|
||||
<div>If you don't add an import list exclusion and the author has a metadata profile other than 'None' then this book may be re-added during the next author refresh.</div>
|
||||
<div>
|
||||
{translate('IfYouDontAddAnImportListExclusionAndTheAuthorHasAMetadataProfileOtherThanNoneThenThisBookMayBeReaddedDuringTheNextAuthorRefresh')}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
deleteFiles &&
|
||||
<div className={styles.deleteFilesMessage}>
|
||||
<div>The book's files will be deleted.</div>
|
||||
<div>
|
||||
{translate('TheBooksFilesWillBeDeleted')}
|
||||
</div>
|
||||
|
||||
{
|
||||
!!bookFileCount &&
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import InteractiveSearchFilterMenuConnector from 'InteractiveSearch/InteractiveS
|
|||
import InteractiveSearchTable from 'InteractiveSearch/InteractiveSearchTable';
|
||||
import OrganizePreviewModalConnector from 'Organize/OrganizePreviewModalConnector';
|
||||
import RetagPreviewModalConnector from 'Retag/RetagPreviewModalConnector';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import BookDetailsHeaderConnector from './BookDetailsHeaderConnector';
|
||||
import styles from './BookDetails.css';
|
||||
|
||||
|
|
@ -114,16 +115,16 @@ class BookDetails extends Component {
|
|||
<PageToolbar>
|
||||
<PageToolbarSection>
|
||||
<PageToolbarButton
|
||||
label="Refresh"
|
||||
label={translate('Refresh')}
|
||||
iconName={icons.REFRESH}
|
||||
spinningName={icons.REFRESH}
|
||||
title="Refresh information"
|
||||
title={translate('RefreshInformation')}
|
||||
isSpinning={isRefreshing}
|
||||
onPress={onRefreshPress}
|
||||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label="Search Book"
|
||||
label={translate('SearchBook')}
|
||||
iconName={icons.SEARCH}
|
||||
isSpinning={isSearching}
|
||||
onPress={onSearchPress}
|
||||
|
|
@ -132,14 +133,14 @@ class BookDetails extends Component {
|
|||
<PageToolbarSeparator />
|
||||
|
||||
<PageToolbarButton
|
||||
label="Preview Rename"
|
||||
label={translate('PreviewRename')}
|
||||
iconName={icons.ORGANIZE}
|
||||
isDisabled={!hasBookFiles}
|
||||
onPress={this.onOrganizePress}
|
||||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label="Preview Retag"
|
||||
label={translate('PreviewRetag')}
|
||||
iconName={icons.RETAG}
|
||||
isDisabled={!hasBookFiles}
|
||||
onPress={this.onRetagPress}
|
||||
|
|
@ -148,13 +149,13 @@ class BookDetails extends Component {
|
|||
<PageToolbarSeparator />
|
||||
|
||||
<PageToolbarButton
|
||||
label="Edit"
|
||||
label={translate('Edit')}
|
||||
iconName={icons.EDIT}
|
||||
onPress={this.onEditBookPress}
|
||||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label="Delete"
|
||||
label={translate('Delete')}
|
||||
iconName={icons.DELETE}
|
||||
onPress={this.onDeleteBookPress}
|
||||
/>
|
||||
|
|
@ -194,7 +195,7 @@ class BookDetails extends Component {
|
|||
className={styles.bookNavigationButton}
|
||||
name={icons.ARROW_LEFT}
|
||||
size={30}
|
||||
title={`Go to ${previousBook.title}`}
|
||||
title={translate('GoToInterp', [previousBook.title])}
|
||||
to={`/book/${previousBook.titleSlug}`}
|
||||
/>
|
||||
|
||||
|
|
@ -202,7 +203,7 @@ class BookDetails extends Component {
|
|||
className={styles.bookUpButton}
|
||||
name={icons.ARROW_UP}
|
||||
size={30}
|
||||
title={`Go to ${author.authorName}`}
|
||||
title={translate('GoToInterp', [author.authorName])}
|
||||
to={`/author/${author.titleSlug}`}
|
||||
/>
|
||||
|
||||
|
|
@ -210,7 +211,7 @@ class BookDetails extends Component {
|
|||
className={styles.bookNavigationButton}
|
||||
name={icons.ARROW_RIGHT}
|
||||
size={30}
|
||||
title={`Go to ${nextBook.title}`}
|
||||
title={translate('GoToInterp', [nextBook.title])}
|
||||
to={`/book/${nextBook.titleSlug}`}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -224,7 +225,9 @@ class BookDetails extends Component {
|
|||
|
||||
{
|
||||
!isFetching && bookFilesError &&
|
||||
<div>Loading book files failed</div>
|
||||
<div>
|
||||
{translate('LoadingBookFilesFailed')}
|
||||
</div>
|
||||
}
|
||||
|
||||
<Tabs selectedIndex={this.state.tabIndex} onSelect={this.onTabSelect}>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import NotFound from 'Components/NotFound';
|
|||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import { clearBooks, fetchBooks } from 'Store/Actions/bookActions';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import BookDetailsConnector from './BookDetailsConnector';
|
||||
|
||||
function createMapStateToProps() {
|
||||
|
|
@ -94,7 +95,7 @@ class BookDetailsPageConnector extends Component {
|
|||
if (!titleSlug) {
|
||||
return (
|
||||
<NotFound
|
||||
message="Sorry, that book cannot be found."
|
||||
message={translate('SorryThatBookCannotBeFound')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
class EditBookModalContent extends Component {
|
||||
|
||||
|
|
@ -60,36 +61,42 @@ class EditBookModalContent extends Component {
|
|||
{...otherProps}
|
||||
>
|
||||
<FormGroup>
|
||||
<FormLabel>Monitored</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Monitored')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="monitored"
|
||||
helpText="Readarr will search for and download book"
|
||||
helpText={translate('MonitoredHelpText')}
|
||||
{...monitored}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Automatically Switch Edition</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('AutomaticallySwitchEdition')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="anyEditionOk"
|
||||
helpText="Readarr will automatically switch to the edition best matching downloaded files"
|
||||
helpText={translate('AnyEditionOkHelpText')}
|
||||
{...anyEditionOk}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Edition</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Edition')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.BOOK_EDITION_SELECT}
|
||||
name="editions"
|
||||
helpText="Change edition for this book"
|
||||
helpText={translate('EditionsHelpText')}
|
||||
isDisabled={anyEditionOk.value && hasFile}
|
||||
bookEditions={editions}
|
||||
onChange={onInputChange}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import React from 'react';
|
|||
import Icon from 'Components/Icon';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import SceneInfo from './SceneInfo';
|
||||
import styles from './EpisodeNumber.css';
|
||||
|
||||
|
|
@ -40,7 +41,7 @@ function EpisodeNumber(props) {
|
|||
}
|
||||
</span>
|
||||
}
|
||||
title="Scene Information"
|
||||
title={translate('SceneInformation')}
|
||||
body={
|
||||
<SceneInfo
|
||||
sceneSeasonNumber={sceneSeasonNumber}
|
||||
|
|
@ -70,7 +71,7 @@ function EpisodeNumber(props) {
|
|||
className={styles.warning}
|
||||
name={icons.WARNING}
|
||||
kind={kinds.WARNING}
|
||||
title="Scene number hasn't been verified yet"
|
||||
title={translate('SceneNumberHasntBeenVerifiedYet')}
|
||||
/>
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +81,7 @@ function EpisodeNumber(props) {
|
|||
className={styles.warning}
|
||||
name={icons.WARNING}
|
||||
kind={kinds.WARNING}
|
||||
title="Episode does not have an absolute episode number"
|
||||
title={translate('EpisodeDoesNotHaveAnAbsoluteEpisodeNumber')}
|
||||
/>
|
||||
}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import Icon from 'Components/Icon';
|
|||
import ProgressBar from 'Components/ProgressBar';
|
||||
import { icons, kinds, sizes } from 'Helpers/Props';
|
||||
import isBefore from 'Utilities/Date/isBefore';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import BookQuality from './BookQuality';
|
||||
import styles from './EpisodeStatus.css';
|
||||
|
||||
|
|
@ -35,7 +36,7 @@ function EpisodeStatus(props) {
|
|||
{...queueItem}
|
||||
progressBar={
|
||||
<ProgressBar
|
||||
title={`Book is downloading - ${progress.toFixed(1)}% ${queueItem.title}`}
|
||||
title={translate('BookIsDownloadingInterp', [progress.toFixed(1), queueItem.title])}
|
||||
progress={progress}
|
||||
kind={kinds.PURPLE}
|
||||
size={sizes.MEDIUM}
|
||||
|
|
@ -51,7 +52,7 @@ function EpisodeStatus(props) {
|
|||
<div className={styles.center}>
|
||||
<Icon
|
||||
name={icons.DOWNLOADING}
|
||||
title="Book is downloading"
|
||||
title={translate('BookIsDownloading')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -67,7 +68,7 @@ function EpisodeStatus(props) {
|
|||
quality={quality}
|
||||
size={bookFile.size}
|
||||
isCutoffNotMet={isCutoffNotMet}
|
||||
title="Book Downloaded"
|
||||
title={translate('BookDownloaded')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -78,7 +79,7 @@ function EpisodeStatus(props) {
|
|||
<div className={styles.center}>
|
||||
<Icon
|
||||
name={icons.TBA}
|
||||
title="TBA"
|
||||
title={translate('TBA')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -89,7 +90,7 @@ function EpisodeStatus(props) {
|
|||
<div className={styles.center}>
|
||||
<Icon
|
||||
name={icons.UNMONITORED}
|
||||
title="Book is not monitored"
|
||||
title={translate('BookIsNotMonitored')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -100,7 +101,7 @@ function EpisodeStatus(props) {
|
|||
<div className={styles.center}>
|
||||
<Icon
|
||||
name={icons.MISSING}
|
||||
title="Book missing from disk"
|
||||
title={translate('BookMissingFromDisk')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -110,7 +111,7 @@ function EpisodeStatus(props) {
|
|||
<div className={styles.center}>
|
||||
<Icon
|
||||
name={icons.NOT_AIRED}
|
||||
title="Book has not aired"
|
||||
title={translate('BookHasNotAired')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
|
|||
import React from 'react';
|
||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './SceneInfo.css';
|
||||
|
||||
function SceneInfo(props) {
|
||||
|
|
@ -20,7 +21,7 @@ function SceneInfo(props) {
|
|||
<DescriptionListItem
|
||||
titleClassName={styles.title}
|
||||
descriptionClassName={styles.description}
|
||||
title="Season"
|
||||
title={translate('Season')}
|
||||
data={sceneSeasonNumber}
|
||||
/>
|
||||
}
|
||||
|
|
@ -30,7 +31,7 @@ function SceneInfo(props) {
|
|||
<DescriptionListItem
|
||||
titleClassName={styles.title}
|
||||
descriptionClassName={styles.description}
|
||||
title="Episode"
|
||||
title={translate('Episode')}
|
||||
data={sceneEpisodeNumber}
|
||||
/>
|
||||
}
|
||||
|
|
@ -40,7 +41,7 @@ function SceneInfo(props) {
|
|||
<DescriptionListItem
|
||||
titleClassName={styles.title}
|
||||
descriptionClassName={styles.description}
|
||||
title="Absolute"
|
||||
title={translate('Absolute')}
|
||||
data={sceneAbsoluteEpisodeNumber}
|
||||
/>
|
||||
}
|
||||
|
|
@ -50,7 +51,7 @@ function SceneInfo(props) {
|
|||
<DescriptionListItem
|
||||
titleClassName={styles.title}
|
||||
descriptionClassName={styles.description}
|
||||
title={alternateTitles.length === 1 ? 'Title' : 'Titles'}
|
||||
title={alternateTitles.length === 1 ? translate('AlternateTitleslength1Title') : translate('AlternateTitleslength1Titles')}
|
||||
data={
|
||||
<div>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import IconButton from 'Components/Link/IconButton';
|
|||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './BookFileActionsCell.css';
|
||||
|
||||
class BookFileActionsCell extends Component {
|
||||
|
|
@ -86,9 +87,9 @@ class BookFileActionsCell extends Component {
|
|||
<ConfirmModal
|
||||
isOpen={isConfirmDeleteModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title="Delete Book File"
|
||||
message={`Are you sure you want to delete ${path}?`}
|
||||
confirmLabel="Delete"
|
||||
title={translate('DeleteBookFile')}
|
||||
message={translate('DeleteBookFileMessageText', [path])}
|
||||
confirmLabel={translate('Delete')}
|
||||
onConfirm={this.onConfirmDelete}
|
||||
onCancel={this.onConfirmDeleteModalClose}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import Table from 'Components/Table/Table';
|
|||
import TableBody from 'Components/Table/TableBody';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||
import removeOldSelectedState from 'Utilities/Table/removeOldSelectedState';
|
||||
import selectAll from 'Utilities/Table/selectAll';
|
||||
|
|
@ -218,9 +219,9 @@ class BookFileEditorTableContent extends Component {
|
|||
<ConfirmModal
|
||||
isOpen={isConfirmDeleteModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title="Delete Selected Book Files"
|
||||
message={'Are you sure you want to delete the selected book files?'}
|
||||
confirmLabel="Delete"
|
||||
title={translate('DeleteSelectedBookFiles')}
|
||||
message={translate('DeleteSelectedBookFilesMessageText')}
|
||||
confirmLabel={translate('Delete')}
|
||||
onConfirm={this.onConfirmDelete}
|
||||
onCancel={this.onConfirmDeleteModalClose}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
|
|||
import React, { Component } from 'react';
|
||||
import Icon from 'Components/Icon';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import FileDetails from './FileDetails';
|
||||
import styles from './ExpandingFileDetails.css';
|
||||
|
||||
|
|
@ -55,7 +56,7 @@ class ExpandingFileDetails extends Component {
|
|||
<Icon
|
||||
className={styles.expandButtonIcon}
|
||||
name={isExpanded ? icons.COLLAPSE : icons.EXPAND}
|
||||
title={isExpanded ? 'Hide file info' : 'Show file info'}
|
||||
title={isExpanded ? translate('IsExpandedHideFileInfo') : translate('IsExpandedShowFileInfo')}
|
||||
size={24}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import DescriptionListItemDescription from 'Components/DescriptionList/Descripti
|
|||
import DescriptionListItemTitle from 'Components/DescriptionList/DescriptionListItemTitle';
|
||||
import Link from 'Components/Link/Link';
|
||||
import stripHtml from 'Utilities/String/stripHtml';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './FileDetails.css';
|
||||
|
||||
function renderRejections(rejections) {
|
||||
|
|
@ -43,7 +44,7 @@ function FileDetails(props) {
|
|||
{
|
||||
filename &&
|
||||
<DescriptionListItem
|
||||
title="Filename"
|
||||
title={translate('Filename')}
|
||||
data={filename}
|
||||
descriptionClassName={styles.filename}
|
||||
/>
|
||||
|
|
@ -51,119 +52,119 @@ function FileDetails(props) {
|
|||
{
|
||||
audioTags.title !== undefined &&
|
||||
<DescriptionListItem
|
||||
title="Track Title"
|
||||
title={translate('TrackTitle')}
|
||||
data={audioTags.title}
|
||||
/>
|
||||
}
|
||||
{
|
||||
audioTags.trackNumbers[0] > 0 &&
|
||||
<DescriptionListItem
|
||||
title="Track Number"
|
||||
title={translate('TrackNumber')}
|
||||
data={audioTags.trackNumbers[0]}
|
||||
/>
|
||||
}
|
||||
{
|
||||
audioTags.discNumber > 0 &&
|
||||
<DescriptionListItem
|
||||
title="Disc Number"
|
||||
title={translate('DiscNumber')}
|
||||
data={audioTags.discNumber}
|
||||
/>
|
||||
}
|
||||
{
|
||||
audioTags.discCount > 0 &&
|
||||
<DescriptionListItem
|
||||
title="Disc Count"
|
||||
title={translate('DiscCount')}
|
||||
data={audioTags.discCount}
|
||||
/>
|
||||
}
|
||||
{
|
||||
audioTags.bookTitle !== undefined &&
|
||||
<DescriptionListItem
|
||||
title="Book"
|
||||
title={translate('Book')}
|
||||
data={audioTags.bookTitle}
|
||||
/>
|
||||
}
|
||||
{
|
||||
audioTags.authorTitle !== undefined &&
|
||||
<DescriptionListItem
|
||||
title="Author"
|
||||
title={translate('Author')}
|
||||
data={audioTags.authorTitle}
|
||||
/>
|
||||
}
|
||||
{
|
||||
audioTags.seriesTitle !== undefined &&
|
||||
<DescriptionListItem
|
||||
title="Series"
|
||||
title={translate('Series')}
|
||||
data={audioTags.seriesTitle}
|
||||
/>
|
||||
}
|
||||
{
|
||||
audioTags.seriesIndex !== undefined &&
|
||||
<DescriptionListItem
|
||||
title="Series Number"
|
||||
title={translate('SeriesNumber')}
|
||||
data={audioTags.seriesIndex}
|
||||
/>
|
||||
}
|
||||
{
|
||||
audioTags.country !== undefined &&
|
||||
<DescriptionListItem
|
||||
title="Country"
|
||||
title={translate('Country')}
|
||||
data={audioTags.country.name}
|
||||
/>
|
||||
}
|
||||
{
|
||||
audioTags.language !== undefined && audioTags.language !== 'UND' &&
|
||||
<DescriptionListItem
|
||||
title="Language"
|
||||
title={translate('Language')}
|
||||
data={audioTags.language}
|
||||
/>
|
||||
}
|
||||
{
|
||||
audioTags.year > 0 &&
|
||||
<DescriptionListItem
|
||||
title="Year"
|
||||
title={translate('Year')}
|
||||
data={audioTags.year}
|
||||
/>
|
||||
}
|
||||
{
|
||||
audioTags.label !== undefined &&
|
||||
<DescriptionListItem
|
||||
title="Label"
|
||||
title={translate('Label')}
|
||||
data={audioTags.label}
|
||||
/>
|
||||
}
|
||||
{
|
||||
audioTags.publisher !== undefined &&
|
||||
<DescriptionListItem
|
||||
title="Publisher"
|
||||
title={translate('Publisher')}
|
||||
data={audioTags.publisher}
|
||||
/>
|
||||
}
|
||||
{
|
||||
audioTags.catalogNumber !== undefined &&
|
||||
<DescriptionListItem
|
||||
title="Catalog Number"
|
||||
title={translate('CatalogNumber')}
|
||||
data={audioTags.catalogNumber}
|
||||
/>
|
||||
}
|
||||
{
|
||||
audioTags.disambiguation !== undefined &&
|
||||
<DescriptionListItem
|
||||
title="Overview"
|
||||
title={translate('Overview')}
|
||||
data={stripHtml(audioTags.disambiguation)}
|
||||
/>
|
||||
}
|
||||
{
|
||||
audioTags.isbn !== undefined &&
|
||||
<DescriptionListItem
|
||||
title="ISBN"
|
||||
title={translate('ISBN')}
|
||||
data={audioTags.isbn}
|
||||
/>
|
||||
}
|
||||
{
|
||||
audioTags.asin !== undefined &&
|
||||
<DescriptionListItem
|
||||
title="ASIN"
|
||||
title={translate('ASIN')}
|
||||
data={audioTags.asin}
|
||||
/>
|
||||
} {
|
||||
|
|
@ -172,7 +173,7 @@ function FileDetails(props) {
|
|||
to={`https://musicbrainz.org/author/${audioTags.authorMBId}`}
|
||||
>
|
||||
<DescriptionListItem
|
||||
title="MusicBrainz Author ID"
|
||||
title={translate('MusicBrainzAuthorID')}
|
||||
data={audioTags.authorMBId}
|
||||
/>
|
||||
</Link>
|
||||
|
|
@ -183,7 +184,7 @@ function FileDetails(props) {
|
|||
to={`https://musicbrainz.org/release-group/${audioTags.bookMBId}`}
|
||||
>
|
||||
<DescriptionListItem
|
||||
title="MusicBrainz Book ID"
|
||||
title={translate('MusicBrainzBookID')}
|
||||
data={audioTags.bookMBId}
|
||||
/>
|
||||
</Link>
|
||||
|
|
@ -194,7 +195,7 @@ function FileDetails(props) {
|
|||
to={`https://musicbrainz.org/release/${audioTags.releaseMBId}`}
|
||||
>
|
||||
<DescriptionListItem
|
||||
title="MusicBrainz Release ID"
|
||||
title={translate('MusicBrainzReleaseID')}
|
||||
data={audioTags.releaseMBId}
|
||||
/>
|
||||
</Link>
|
||||
|
|
@ -205,7 +206,7 @@ function FileDetails(props) {
|
|||
to={`https://musicbrainz.org/recording/${audioTags.recordingMBId}`}
|
||||
>
|
||||
<DescriptionListItem
|
||||
title="MusicBrainz Recording ID"
|
||||
title={translate('MusicBrainzRecordingID')}
|
||||
data={audioTags.recordingMBId}
|
||||
/>
|
||||
</Link>
|
||||
|
|
@ -216,7 +217,7 @@ function FileDetails(props) {
|
|||
to={`https://musicbrainz.org/track/${audioTags.trackMBId}`}
|
||||
>
|
||||
<DescriptionListItem
|
||||
title="MusicBrainz Track ID"
|
||||
title={translate('MusicBrainzTrackID')}
|
||||
data={audioTags.trackMBId}
|
||||
/>
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import VirtualTableRow from 'Components/Table/VirtualTableRow';
|
|||
import { align, sortDirections } from 'Helpers/Props';
|
||||
import getIndexOfFirstCharacter from 'Utilities/Array/getIndexOfFirstCharacter';
|
||||
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||
import selectAll from 'Utilities/Table/selectAll';
|
||||
import toggleSelected from 'Utilities/Table/toggleSelected';
|
||||
|
|
@ -347,7 +348,7 @@ class Bookshelf extends Component {
|
|||
} = this.state;
|
||||
|
||||
return (
|
||||
<PageContent title="Book Studio">
|
||||
<PageContent title={translate('BookStudio')}>
|
||||
<PageToolbar>
|
||||
<PageToolbarSection />
|
||||
<PageToolbarSection alignContent={align.RIGHT}>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import classNames from 'classnames';
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import MonitorToggleButton from 'Components/MonitorToggleButton';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './BookshelfBook.css';
|
||||
|
||||
class BookshelfBook extends Component {
|
||||
|
|
@ -58,7 +59,7 @@ class BookshelfBook extends Component {
|
|||
percentOfBooks < 100 && monitored && styles.missingWanted,
|
||||
percentOfBooks === 100 && styles.allBooks
|
||||
)}
|
||||
title={`${bookFileCount}/${totalBookCount} books downloaded`}
|
||||
title={translate('BookFileCounttotalBookCountBooksDownloadedInterp', [bookFileCount, totalBookCount])}
|
||||
>
|
||||
{
|
||||
totalBookCount === 0 ? '0/0' : `${bookFileCount}/${totalBookCount}`
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import MonitorToggleButton from 'Components/MonitorToggleButton';
|
|||
import VirtualTableRowCell from 'Components/Table/Cells/VirtualTableRowCell';
|
||||
import VirtualTableSelectCell from 'Components/Table/Cells/VirtualTableSelectCell';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import BookshelfBook from './BookshelfBook';
|
||||
import styles from './BookshelfRow.css';
|
||||
|
||||
|
|
@ -52,7 +53,7 @@ class BookshelfRow extends Component {
|
|||
<Icon
|
||||
className={styles.statusIcon}
|
||||
name={status === 'ended' ? icons.AUTHOR_ENDED : icons.AUTHOR_CONTINUING}
|
||||
title={status === 'ended' ? 'Ended' : 'Continuing'}
|
||||
title={status === 'ended' ? translate('StatusEndedEnded') : translate('StatusEndedContinuing')}
|
||||
/>
|
||||
</VirtualTableRowCell>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import Icon from 'Components/Icon';
|
|||
import Link from 'Components/Link/Link';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import formatTime from 'Utilities/Date/formatTime';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './AgendaEvent.css';
|
||||
|
||||
class AgendaEvent extends Component {
|
||||
|
|
@ -110,7 +111,7 @@ class AgendaEvent extends Component {
|
|||
!queueItem && grabbed &&
|
||||
<Icon
|
||||
name={icons.DOWNLOADING}
|
||||
title="Book is downloading"
|
||||
title={translate('BookIsDownloading')}
|
||||
/>
|
||||
}
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AgendaConnector from './Agenda/AgendaConnector';
|
||||
import * as calendarViews from './calendarViews';
|
||||
import CalendarDaysConnector from './Day/CalendarDaysConnector';
|
||||
|
|
@ -30,7 +31,9 @@ class Calendar extends Component {
|
|||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>Unable to load the calendar</div>
|
||||
<div>
|
||||
{translate('UnableToLoadTheCalendar')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
|||
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
||||
import { align, icons } from 'Helpers/Props';
|
||||
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import CalendarConnector from './CalendarConnector';
|
||||
import CalendarLinkModal from './iCal/CalendarLinkModal';
|
||||
import LegendConnector from './Legend/LegendConnector';
|
||||
|
|
@ -94,17 +95,17 @@ class CalendarPage extends Component {
|
|||
const isMeasured = this.state.width > 0;
|
||||
|
||||
return (
|
||||
<PageContent title="Calendar">
|
||||
<PageContent title={translate('Calendar')}>
|
||||
<PageToolbar>
|
||||
<PageToolbarSection>
|
||||
<PageToolbarButton
|
||||
label="iCal Link"
|
||||
label={translate('ICalLink')}
|
||||
iconName={icons.CALENDAR}
|
||||
onPress={this.onGetCalendarLinkPress}
|
||||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label="Search for Missing"
|
||||
label={translate('SearchForMissing')}
|
||||
iconName={icons.SEARCH}
|
||||
isDisabled={!missingBookIds.length}
|
||||
isSpinning={isSearchingForMissing}
|
||||
|
|
@ -114,7 +115,7 @@ class CalendarPage extends Component {
|
|||
|
||||
<PageToolbarSection alignContent={align.RIGHT}>
|
||||
<PageToolbarButton
|
||||
label="Options"
|
||||
label={translate('Options')}
|
||||
iconName={icons.POSTER}
|
||||
onPress={this.onOptionsPress}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import getStatusStyle from 'Calendar/getStatusStyle';
|
|||
import Icon from 'Components/Icon';
|
||||
import Link from 'Components/Link/Link';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import CalendarEventQueueDetails from './CalendarEventQueueDetails';
|
||||
import styles from './CalendarEvent.css';
|
||||
|
||||
|
|
@ -97,7 +98,7 @@ class CalendarEvent extends Component {
|
|||
<Icon
|
||||
className={styles.statusIcon}
|
||||
name={icons.DOWNLOADING}
|
||||
title="Book is downloading"
|
||||
title={translate('BookIsDownloading')}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import React from 'react';
|
|||
import QueueDetails from 'Activity/Queue/QueueDetails';
|
||||
import CircularProgressBar from 'Components/CircularProgressBar';
|
||||
import colors from 'Styles/Variables/colors';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
function CalendarEventQueueDetails(props) {
|
||||
const {
|
||||
|
|
@ -25,7 +26,7 @@ function CalendarEventQueueDetails(props) {
|
|||
status={status}
|
||||
errorMessage={errorMessage}
|
||||
progressBar={
|
||||
<div title={`Book is downloading - ${progress.toFixed(1)}% ${title}`}>
|
||||
<div title={translate('BookIsDownloadingInterp', [progress.toFixed(1), title])}>
|
||||
<CircularProgressBar
|
||||
progress={progress}
|
||||
size={20}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
|
|||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes } from 'Helpers/Props';
|
||||
import { firstDayOfWeekOptions, timeFormatOptions, weekColumnOptions } from 'Settings/UI/UISettings';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
class CalendarOptionsModalContent extends Component {
|
||||
|
||||
|
|
@ -110,38 +111,44 @@ class CalendarOptionsModalContent extends Component {
|
|||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
<FieldSet legend="Local">
|
||||
<FieldSet legend={translate('Local')}>
|
||||
<Form>
|
||||
<FormGroup>
|
||||
<FormLabel>Collapse Multiple Books</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('CollapseMultipleBooks')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="collapseMultipleBooks"
|
||||
value={collapseMultipleBooks}
|
||||
helpText="Collapse multiple books releasing on the same day"
|
||||
helpText={translate('CollapseMultipleBooksHelpText')}
|
||||
onChange={this.onOptionInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Icon for Cutoff Unmet</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('IconForCutoffUnmet')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="showCutoffUnmetIcon"
|
||||
value={showCutoffUnmetIcon}
|
||||
helpText="Show icon for files when the cutoff hasn't been met"
|
||||
helpText={translate('ShowCutoffUnmetIconHelpText')}
|
||||
onChange={this.onOptionInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
</FieldSet>
|
||||
|
||||
<FieldSet legend="Global">
|
||||
<FieldSet legend={translate('Global')}>
|
||||
<Form>
|
||||
<FormGroup>
|
||||
<FormLabel>First Day of Week</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('FirstDayOfWeek')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
|
|
@ -153,7 +160,9 @@ class CalendarOptionsModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Week Column Header</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('WeekColumnHeader')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
|
|
@ -161,12 +170,14 @@ class CalendarOptionsModalContent extends Component {
|
|||
values={weekColumnOptions}
|
||||
value={calendarWeekColumnHeader}
|
||||
onChange={this.onGlobalInputChange}
|
||||
helpText="Shown above each column when week is the active view"
|
||||
helpText={translate('ShownAboveEachColumnWhenWeekIsTheActiveView')}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Time Format</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('TimeFormat')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
|
|
@ -176,13 +187,15 @@ class CalendarOptionsModalContent extends Component {
|
|||
onChange={this.onGlobalInputChange}
|
||||
/>
|
||||
</FormGroup><FormGroup>
|
||||
<FormLabel>Enable Color-Impaired Mode</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('EnableColorImpairedMode')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="enableColorImpairedMode"
|
||||
value={enableColorImpairedMode}
|
||||
helpText="Altered style to allow color-impaired users to better distinguish color coded information"
|
||||
helpText={translate('EnableColorImpairedModeHelpText')}
|
||||
onChange={this.onGlobalInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { icons, inputTypes, kinds, sizes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
function getUrls(state) {
|
||||
const {
|
||||
|
|
@ -113,49 +114,57 @@ class CalendarLinkModalContent extends Component {
|
|||
<ModalBody>
|
||||
<Form>
|
||||
<FormGroup>
|
||||
<FormLabel>Include Unmonitored</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('IncludeUnmonitored')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="unmonitored"
|
||||
value={unmonitored}
|
||||
helpText="Include unmonitored books in the iCal feed"
|
||||
helpText={translate('UnmonitoredHelpText')}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Past Days</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('PastDays')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.NUMBER}
|
||||
name="pastDays"
|
||||
value={pastDays}
|
||||
helpText="Days for iCal feed to look into the past"
|
||||
helpText={translate('PastDaysHelpText')}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Future Days</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('FutureDays')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.NUMBER}
|
||||
name="futureDays"
|
||||
value={futureDays}
|
||||
helpText="Days for iCal feed to look into the future"
|
||||
helpText={translate('FutureDaysHelpText')}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Tags</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Tags')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TAG}
|
||||
name="tags"
|
||||
value={tags}
|
||||
helpText="Feed will only contain authors with at least one matching tag"
|
||||
helpText={translate('TagsHelpText')}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
@ -163,14 +172,16 @@ class CalendarLinkModalContent extends Component {
|
|||
<FormGroup
|
||||
size={sizes.LARGE}
|
||||
>
|
||||
<FormLabel>iCal Feed</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ICalFeed')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="iCalHttpUrl"
|
||||
value={iCalHttpUrl}
|
||||
readOnly={true}
|
||||
helpText="Copy this URL to your client(s) or click to subscribe if your browser supports webcal"
|
||||
helpText={translate('ICalHttpUrlHelpText')}
|
||||
buttons={[
|
||||
<ClipboardButton
|
||||
key="copy"
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import Scroller from 'Components/Scroller/Scroller';
|
|||
import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import { kinds, scrollDirections } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import FileBrowserRow from './FileBrowserRow';
|
||||
import styles from './FileBrowserModalContent.css';
|
||||
|
||||
|
|
@ -134,7 +135,7 @@ class FileBrowserModalContent extends Component {
|
|||
|
||||
<PathInput
|
||||
className={styles.pathInput}
|
||||
placeholder="Start typing or select a path below"
|
||||
placeholder={translate('StartTypingOrSelectAPathBelow')}
|
||||
hasFileBrowser={false}
|
||||
{...otherProps}
|
||||
value={this.state.currentPath}
|
||||
|
|
@ -148,7 +149,9 @@ class FileBrowserModalContent extends Component {
|
|||
>
|
||||
{
|
||||
!!error &&
|
||||
<div>Error loading contents</div>
|
||||
<div>
|
||||
{translate('ErrorLoadingContents')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import React, { Component } from 'react';
|
|||
import IconButton from 'Components/Link/IconButton';
|
||||
import SpinnerIconButton from 'Components/Link/SpinnerIconButton';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './CustomFilter.css';
|
||||
|
||||
class CustomFilter extends Component {
|
||||
|
|
@ -89,7 +90,7 @@ class CustomFilter extends Component {
|
|||
/>
|
||||
|
||||
<SpinnerIconButton
|
||||
title="Remove filter"
|
||||
title={translate('RemoveFilter')}
|
||||
name={icons.REMOVE}
|
||||
isSpinning={this.state.isDeleting}
|
||||
onPress={this.onRemovePress}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
|
|||
import React from 'react';
|
||||
import Link from 'Components/Link/Link';
|
||||
import { inputTypes } from 'Helpers/Props';
|
||||
// import translate from 'Utilities/String/translate';
|
||||
import AutoCompleteInput from './AutoCompleteInput';
|
||||
import BookEditionSelectInputConnector from './BookEditionSelectInputConnector';
|
||||
import BookshelfInputConnector from './BookshelfInputConnector';
|
||||
|
|
@ -172,7 +173,7 @@ function FormInputGroup(props) {
|
|||
<Icon
|
||||
name={icons.UNSAVED_SETTING}
|
||||
className={styles.pendingChangesIcon}
|
||||
title="Change has not been saved yet"
|
||||
title={translate('ChangeHasNotBeenSavedYet')}
|
||||
/>
|
||||
}
|
||||
</div> */}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './NotFound.css';
|
||||
|
||||
function NotFound({ message }) {
|
||||
return (
|
||||
<PageContent title="MIA">
|
||||
<PageContent title={translate('MIA')}>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.message}>
|
||||
{message}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { createSelector } from 'reselect';
|
|||
import { saveDimensions, setIsSidebarVisible } from 'Store/Actions/appActions';
|
||||
import { fetchAuthor } from 'Store/Actions/authorActions';
|
||||
import { fetchCustomFilters } from 'Store/Actions/customFilterActions';
|
||||
import { fetchImportLists, fetchMetadataProfiles, fetchQualityProfiles, fetchUISettings } from 'Store/Actions/settingsActions';
|
||||
import { fetchImportLists, fetchLanguages, fetchMetadataProfiles, fetchQualityProfiles, fetchUISettings } from 'Store/Actions/settingsActions';
|
||||
import { fetchStatus } from 'Store/Actions/systemActions';
|
||||
import { fetchTags } from 'Store/Actions/tagActions';
|
||||
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
||||
|
|
@ -46,6 +46,7 @@ const selectIsPopulated = createSelector(
|
|||
(state) => state.customFilters.isPopulated,
|
||||
(state) => state.tags.isPopulated,
|
||||
(state) => state.settings.ui.isPopulated,
|
||||
(state) => state.settings.languages.isPopulated,
|
||||
(state) => state.settings.qualityProfiles.isPopulated,
|
||||
(state) => state.settings.metadataProfiles.isPopulated,
|
||||
(state) => state.settings.importLists.isPopulated,
|
||||
|
|
@ -54,6 +55,7 @@ const selectIsPopulated = createSelector(
|
|||
customFiltersIsPopulated,
|
||||
tagsIsPopulated,
|
||||
uiSettingsIsPopulated,
|
||||
languagesIsPopulated,
|
||||
qualityProfilesIsPopulated,
|
||||
metadataProfilesIsPopulated,
|
||||
importListsIsPopulated,
|
||||
|
|
@ -63,6 +65,7 @@ const selectIsPopulated = createSelector(
|
|||
customFiltersIsPopulated &&
|
||||
tagsIsPopulated &&
|
||||
uiSettingsIsPopulated &&
|
||||
languagesIsPopulated &&
|
||||
qualityProfilesIsPopulated &&
|
||||
metadataProfilesIsPopulated &&
|
||||
importListsIsPopulated &&
|
||||
|
|
@ -75,6 +78,7 @@ const selectErrors = createSelector(
|
|||
(state) => state.customFilters.error,
|
||||
(state) => state.tags.error,
|
||||
(state) => state.settings.ui.error,
|
||||
(state) => state.settings.languages.error,
|
||||
(state) => state.settings.qualityProfiles.error,
|
||||
(state) => state.settings.metadataProfiles.error,
|
||||
(state) => state.settings.importLists.error,
|
||||
|
|
@ -83,6 +87,7 @@ const selectErrors = createSelector(
|
|||
customFiltersError,
|
||||
tagsError,
|
||||
uiSettingsError,
|
||||
languagesError,
|
||||
qualityProfilesError,
|
||||
metadataProfilesError,
|
||||
importListsError,
|
||||
|
|
@ -92,6 +97,7 @@ const selectErrors = createSelector(
|
|||
customFiltersError ||
|
||||
tagsError ||
|
||||
uiSettingsError ||
|
||||
languagesError ||
|
||||
qualityProfilesError ||
|
||||
metadataProfilesError ||
|
||||
importListsError ||
|
||||
|
|
@ -103,6 +109,7 @@ const selectErrors = createSelector(
|
|||
customFiltersError,
|
||||
tagsError,
|
||||
uiSettingsError,
|
||||
languagesError,
|
||||
qualityProfilesError,
|
||||
metadataProfilesError,
|
||||
importListsError,
|
||||
|
|
@ -147,6 +154,9 @@ function createMapDispatchToProps(dispatch, props) {
|
|||
dispatchFetchTags() {
|
||||
dispatch(fetchTags());
|
||||
},
|
||||
dispatchFetchLanguages() {
|
||||
dispatch(fetchLanguages());
|
||||
},
|
||||
dispatchFetchQualityProfiles() {
|
||||
dispatch(fetchQualityProfiles());
|
||||
},
|
||||
|
|
@ -189,6 +199,7 @@ class PageConnector extends Component {
|
|||
this.props.dispatchFetchAuthor();
|
||||
this.props.dispatchFetchCustomFilters();
|
||||
this.props.dispatchFetchTags();
|
||||
this.props.dispatchFetchLanguages();
|
||||
this.props.dispatchFetchQualityProfiles();
|
||||
this.props.dispatchFetchMetadataProfiles();
|
||||
this.props.dispatchFetchImportLists();
|
||||
|
|
@ -213,6 +224,7 @@ class PageConnector extends Component {
|
|||
hasError,
|
||||
dispatchFetchAuthor,
|
||||
dispatchFetchTags,
|
||||
dispatchFetchLanguages,
|
||||
dispatchFetchQualityProfiles,
|
||||
dispatchFetchMetadataProfiles,
|
||||
dispatchFetchImportLists,
|
||||
|
|
@ -252,6 +264,7 @@ PageConnector.propTypes = {
|
|||
dispatchFetchAuthor: PropTypes.func.isRequired,
|
||||
dispatchFetchCustomFilters: PropTypes.func.isRequired,
|
||||
dispatchFetchTags: PropTypes.func.isRequired,
|
||||
dispatchFetchLanguages: PropTypes.func.isRequired,
|
||||
dispatchFetchQualityProfiles: PropTypes.func.isRequired,
|
||||
dispatchFetchMetadataProfiles: PropTypes.func.isRequired,
|
||||
dispatchFetchImportLists: PropTypes.func.isRequired,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import TableOptionsColumn from './TableOptionsColumn';
|
||||
import TableOptionsColumnDragPreview from './TableOptionsColumnDragPreview';
|
||||
import TableOptionsColumnDragSource from './TableOptionsColumnDragSource';
|
||||
|
|
@ -144,13 +145,15 @@ class TableOptionsModal extends Component {
|
|||
{
|
||||
hasPageSize ?
|
||||
<FormGroup>
|
||||
<FormLabel>Page Size</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('PageSize')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.NUMBER}
|
||||
name="pageSize"
|
||||
value={pageSize || 0}
|
||||
helpText="Number of items to show on each page"
|
||||
helpText={translate('PageSizeHelpText')}
|
||||
errors={pageSizeError ? [{ message: pageSizeError }] : undefined}
|
||||
onChange={this.onPageSizeChange}
|
||||
/>
|
||||
|
|
@ -168,7 +171,9 @@ class TableOptionsModal extends Component {
|
|||
{
|
||||
canModifyColumns ?
|
||||
<FormGroup>
|
||||
<FormLabel>Columns</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Columns')}
|
||||
</FormLabel>
|
||||
|
||||
<div>
|
||||
<FormInputHelpText
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
|
|||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import Scroller from 'Components/Scroller/Scroller';
|
||||
import { scrollDirections } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import SelectAuthorRow from './SelectAuthorRow';
|
||||
import styles from './SelectAuthorModalContent.css';
|
||||
|
||||
|
|
@ -55,7 +56,7 @@ class SelectAuthorModalContent extends Component {
|
|||
>
|
||||
<TextInput
|
||||
className={styles.filterInput}
|
||||
placeholder="Filter author"
|
||||
placeholder={translate('FilterPlaceHolder')}
|
||||
name="filter"
|
||||
value={filter}
|
||||
autoFocus={true}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import Scroller from 'Components/Scroller/Scroller';
|
|||
import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import { scrollDirections } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import SelectBookRow from './SelectBookRow';
|
||||
import styles from './SelectBookModalContent.css';
|
||||
|
||||
|
|
@ -84,7 +85,7 @@ class SelectBookModalContent extends Component {
|
|||
}
|
||||
<TextInput
|
||||
className={styles.filterInput}
|
||||
placeholder="Filter book"
|
||||
placeholder={translate('FilterPlaceHolder')}
|
||||
name="filter"
|
||||
value={filter}
|
||||
autoFocus={true}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellCo
|
|||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import { kinds, sizes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './SelectBookRow.css';
|
||||
|
||||
function getBookCountKind(monitored, bookFileCount, bookCount) {
|
||||
|
|
@ -85,7 +86,7 @@ class SelectBookRow extends Component {
|
|||
key={name}
|
||||
>
|
||||
<Label
|
||||
title={`${totalBookCount} books total. ${bookFileCount} books with files.`}
|
||||
title={translate('TotalBookCountBooksTotalBookFileCountBooksWithFilesInterp', [totalBookCount, bookFileCount])}
|
||||
kind={getBookCountKind(monitored, bookFileCount, bookCount)}
|
||||
size={sizes.MEDIUM}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellCo
|
|||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableRowButton from 'Components/Table/TableRowButton';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './RecentFolderRow.css';
|
||||
|
||||
class RecentFolderRow extends Component {
|
||||
|
|
@ -44,7 +45,7 @@ class RecentFolderRow extends Component {
|
|||
|
||||
<TableRowCell className={styles.actions}>
|
||||
<IconButton
|
||||
title="Remove"
|
||||
title={translate('Remove')}
|
||||
name={icons.REMOVE}
|
||||
onPress={this.onRemovePress}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import SelectAuthorModal from 'InteractiveImport/Author/SelectAuthorModal';
|
|||
import SelectBookModal from 'InteractiveImport/Book/SelectBookModal';
|
||||
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
|
||||
import formatBytes from 'Utilities/Number/formatBytes';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import InteractiveImportRowCellPlaceholder from './InteractiveImportRowCellPlaceholder';
|
||||
import styles from './InteractiveImportRow.css';
|
||||
|
||||
|
|
@ -211,7 +212,7 @@ class InteractiveImportRow extends Component {
|
|||
|
||||
<TableRowCellButton
|
||||
isDisabled={!allowAuthorChange}
|
||||
title={allowAuthorChange ? 'Click to change author' : undefined}
|
||||
title={allowAuthorChange ? translate('AllowAuthorChangeClickToChangeAuthor') : undefined}
|
||||
onPress={this.onSelectAuthorPress}
|
||||
>
|
||||
{
|
||||
|
|
@ -221,7 +222,7 @@ class InteractiveImportRow extends Component {
|
|||
|
||||
<TableRowCellButton
|
||||
isDisabled={!author}
|
||||
title={author ? 'Click to change book' : undefined}
|
||||
title={author ? translate('AuthorClickToChangeBook') : undefined}
|
||||
onPress={this.onSelectBookPress}
|
||||
>
|
||||
{
|
||||
|
|
@ -231,7 +232,7 @@ class InteractiveImportRow extends Component {
|
|||
|
||||
<TableRowCellButton
|
||||
className={styles.quality}
|
||||
title="Click to change quality"
|
||||
title={translate('ClickToChangeQuality')}
|
||||
onPress={this.onSelectQualityPress}
|
||||
>
|
||||
{
|
||||
|
|
@ -262,7 +263,7 @@ class InteractiveImportRow extends Component {
|
|||
kind={kinds.DANGER}
|
||||
/>
|
||||
}
|
||||
title="Release Rejected"
|
||||
title={translate('ReleaseRejected')}
|
||||
body={
|
||||
<ul>
|
||||
{
|
||||
|
|
@ -284,12 +285,12 @@ class InteractiveImportRow extends Component {
|
|||
|
||||
<ConfirmModal
|
||||
isOpen={isDetailsModalOpen}
|
||||
title="File Details"
|
||||
title={translate('FileDetails')}
|
||||
message={fileDetails}
|
||||
size={sizes.LARGE}
|
||||
kind={kinds.DEFAULT}
|
||||
hideCancelButton={true}
|
||||
confirmLabel="Close"
|
||||
confirmLabel={translate('Close')}
|
||||
onConfirm={this.onDetailsModalClose}
|
||||
onCancel={this.onDetailsModalClose}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
class SelectQualityModalContent extends Component {
|
||||
|
||||
|
|
@ -91,14 +92,18 @@ class SelectQualityModalContent extends Component {
|
|||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>Unable to load qualities</div>
|
||||
<div>
|
||||
{translate('UnableToLoadQualities')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
isPopulated && !error &&
|
||||
<Form>
|
||||
<FormGroup>
|
||||
<FormLabel>Quality</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Quality')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
|
|
@ -110,7 +115,9 @@ class SelectQualityModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Proper</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Proper')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
|
|
@ -121,7 +128,9 @@ class SelectQualityModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Real</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Real')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
|||
import formatDateTime from 'Utilities/Date/formatDateTime';
|
||||
import formatAge from 'Utilities/Number/formatAge';
|
||||
import formatBytes from 'Utilities/Number/formatBytes';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import Peers from './Peers';
|
||||
import styles from './InteractiveSearchRow.css';
|
||||
|
||||
|
|
@ -179,7 +180,7 @@ class InteractiveSearchRow extends Component {
|
|||
kind={kinds.DANGER}
|
||||
/>
|
||||
}
|
||||
title="Release Rejected"
|
||||
title={translate('ReleaseRejected')}
|
||||
body={
|
||||
<ul>
|
||||
{
|
||||
|
|
@ -213,9 +214,9 @@ class InteractiveSearchRow extends Component {
|
|||
<ConfirmModal
|
||||
isOpen={this.state.isConfirmGrabModalOpen}
|
||||
kind={kinds.WARNING}
|
||||
title="Grab Release"
|
||||
message={`Readarr was unable to determine which author and book this release was for. Readarr may be unable to automatically import this release. Do you want to grab '${title}'?`}
|
||||
confirmLabel="Grab"
|
||||
title={translate('GrabRelease')}
|
||||
message={translate('GrabReleaseMessageText', [title])}
|
||||
confirmLabel={translate('Grab')}
|
||||
onConfirm={this.onGrabConfirm}
|
||||
onCancel={this.onGrabCancel}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||
import selectAll from 'Utilities/Table/selectAll';
|
||||
import toggleSelected from 'Utilities/Table/toggleSelected';
|
||||
|
|
@ -100,12 +101,16 @@ class OrganizePreviewModalContent extends Component {
|
|||
|
||||
{
|
||||
!isFetching && error &&
|
||||
<div>Error loading previews</div>
|
||||
<div>
|
||||
{translate('ErrorLoadingPreviews')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && isPopulated && !items.length &&
|
||||
<div>Success! My work is done, no files to rename.</div>
|
||||
<div>
|
||||
{translate('SuccessMyWorkIsDoneNoFilesToRename')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||
import selectAll from 'Utilities/Table/selectAll';
|
||||
import toggleSelected from 'Utilities/Table/toggleSelected';
|
||||
|
|
@ -104,12 +105,16 @@ class RetagPreviewModalContent extends Component {
|
|||
|
||||
{
|
||||
!isFetching && error &&
|
||||
<div>Error loading previews</div>
|
||||
<div>
|
||||
{translate('ErrorLoadingPreviews')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && ((isPopulated && !items.length)) &&
|
||||
<div>Success! My work is done, no files to retag.</div>
|
||||
<div>
|
||||
{translate('SuccessMyWorkIsDoneNoFilesToRetag')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import PageContent from 'Components/Page/PageContent';
|
|||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AddNewAuthorSearchResultConnector from './Author/AddNewAuthorSearchResultConnector';
|
||||
import AddNewBookSearchResultConnector from './Book/AddNewBookSearchResultConnector';
|
||||
import styles from './AddNewItem.css';
|
||||
|
|
@ -87,7 +88,7 @@ class AddNewItem extends Component {
|
|||
const isFetching = this.state.isFetching;
|
||||
|
||||
return (
|
||||
<PageContent title="Add New Item">
|
||||
<PageContent title={translate('AddNewItem')}>
|
||||
<PageContentBody>
|
||||
<div className={styles.searchContainer}>
|
||||
<div className={styles.searchIconContainer}>
|
||||
|
|
@ -101,7 +102,7 @@ class AddNewItem extends Component {
|
|||
className={styles.searchInput}
|
||||
name="searchBox"
|
||||
value={term}
|
||||
placeholder="eg. War and Peace, goodreads:656, isbn:067003469X, asin:B00JCDK5ME"
|
||||
placeholder={translate('SearchBoxPlaceHolder')}
|
||||
autoFocus={true}
|
||||
onChange={this.onSearchInputChange}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { icons, kinds, sizes } from 'Helpers/Props';
|
|||
import dimensions from 'Styles/Variables/dimensions';
|
||||
import fonts from 'Styles/Variables/fonts';
|
||||
import stripHtml from 'Utilities/String/stripHtml';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AddNewAuthorModal from './AddNewAuthorModal';
|
||||
import styles from './AddNewAuthorSearchResult.css';
|
||||
|
||||
|
|
@ -139,7 +140,7 @@ class AddNewAuthorSearchResult extends Component {
|
|||
className={styles.alreadyExistsIcon}
|
||||
name={icons.CHECK_CIRCLE}
|
||||
size={36}
|
||||
title="Already in your library"
|
||||
title={translate('AlreadyInYourLibrary')}
|
||||
/> :
|
||||
null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { icons, sizes } from 'Helpers/Props';
|
|||
import dimensions from 'Styles/Variables/dimensions';
|
||||
import fonts from 'Styles/Variables/fonts';
|
||||
import stripHtml from 'Utilities/String/stripHtml';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AddNewBookModal from './AddNewBookModal';
|
||||
import styles from './AddNewBookSearchResult.css';
|
||||
|
||||
|
|
@ -131,7 +132,7 @@ class AddNewBookSearchResult extends Component {
|
|||
className={styles.alreadyExistsIcon}
|
||||
name={icons.CHECK_CIRCLE}
|
||||
size={36}
|
||||
title="Already in your library"
|
||||
title={translate('AlreadyInYourLibrary')}
|
||||
/> :
|
||||
null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import FormLabel from 'Components/Form/FormLabel';
|
|||
import Icon from 'Components/Icon';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import { icons, inputTypes, tooltipPositions } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './AddAuthorOptionsForm.css';
|
||||
|
||||
class AddAuthorOptionsForm extends Component {
|
||||
|
|
@ -43,7 +44,9 @@ class AddAuthorOptionsForm extends Component {
|
|||
return (
|
||||
<Form {...otherProps}>
|
||||
<FormGroup>
|
||||
<FormLabel>Root Folder</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('RootFolder')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.ROOT_FOLDER_SELECT}
|
||||
|
|
@ -64,7 +67,7 @@ class AddAuthorOptionsForm extends Component {
|
|||
name={icons.INFO}
|
||||
/>
|
||||
}
|
||||
title="Monitoring Options"
|
||||
title={translate('MonitoringOptions')}
|
||||
body={<AuthorMonitoringOptionsPopoverContent />}
|
||||
position={tooltipPositions.RIGHT}
|
||||
/>
|
||||
|
|
@ -79,7 +82,9 @@ class AddAuthorOptionsForm extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Quality Profile</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('QualityProfile')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.QUALITY_PROFILE_SELECT}
|
||||
|
|
@ -102,7 +107,7 @@ class AddAuthorOptionsForm extends Component {
|
|||
name={icons.INFO}
|
||||
/>
|
||||
}
|
||||
title="Metadata Profile"
|
||||
title={translate('MetadataProfile')}
|
||||
body={<AuthorMetadataProfilePopoverContent />}
|
||||
position={tooltipPositions.RIGHT}
|
||||
/>
|
||||
|
|
@ -119,7 +124,9 @@ class AddAuthorOptionsForm extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Tags</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Tags')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TAG}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import React from 'react';
|
|||
import Icon from 'Components/Icon';
|
||||
import Link from 'Components/Link/Link';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './AdvancedSettingsButton.css';
|
||||
|
||||
function AdvancedSettingsButton(props) {
|
||||
|
|
@ -15,7 +16,7 @@ function AdvancedSettingsButton(props) {
|
|||
return (
|
||||
<Link
|
||||
className={styles.button}
|
||||
title={advancedSettings ? 'Shown, click to hide' : 'Hidden, click to show'}
|
||||
title={advancedSettings ? translate('AdvancedSettingsShownClickToHide') : translate('AdvancedSettingsHiddenClickToShow')}
|
||||
onPress={onAdvancedSettingsPress}
|
||||
>
|
||||
<Icon
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import PageContent from 'Components/Page/PageContent';
|
|||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import { inputTypes } from 'Helpers/Props';
|
||||
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
const logLevelOptions = [
|
||||
{ key: 'info', value: 'Info' },
|
||||
|
|
@ -34,7 +35,7 @@ class DevelopmentSettings extends Component {
|
|||
} = this.props;
|
||||
|
||||
return (
|
||||
<PageContent title="Development">
|
||||
<PageContent title={translate('Development')}>
|
||||
<SettingsToolbarConnector
|
||||
{...otherProps}
|
||||
onSavePress={onSavePress}
|
||||
|
|
@ -59,14 +60,16 @@ class DevelopmentSettings extends Component {
|
|||
id="developmentSettings"
|
||||
{...otherProps}
|
||||
>
|
||||
<FieldSet legend="Metadata Provider Source">
|
||||
<FieldSet legend={translate('MetadataProviderSource')}>
|
||||
<FormGroup>
|
||||
<FormLabel>Metadata Source</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('MetadataSource')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="metadataSource"
|
||||
helpText="Alternative Metadata Source (Leave blank for default)"
|
||||
helpText={translate('MetadataSourceHelpText')}
|
||||
helpLink="https://wiki.servarr.com/Readarr_Settings#Metadata"
|
||||
onChange={onInputChange}
|
||||
{...settings.metadataSource}
|
||||
|
|
@ -74,21 +77,25 @@ class DevelopmentSettings extends Component {
|
|||
</FormGroup>
|
||||
</FieldSet>
|
||||
|
||||
<FieldSet legend="Logging">
|
||||
<FieldSet legend={translate('Logging')}>
|
||||
<FormGroup>
|
||||
<FormLabel>Log Rotation</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('LogRotation')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.NUMBER}
|
||||
name="logRotate"
|
||||
helpText="Max number of log files to keep saved in logs folder"
|
||||
helpText={translate('LogRotateHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...settings.logRotate}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Console Log Level</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ConsoleLogLevel')}
|
||||
</FormLabel>
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="consoleLogLevel"
|
||||
|
|
@ -99,26 +106,30 @@ class DevelopmentSettings extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Log SQL</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('LogSQL')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="logSql"
|
||||
helpText="Log all SQL queries from Readarr"
|
||||
helpText={translate('LogSqlHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...settings.logSql}
|
||||
/>
|
||||
</FormGroup>
|
||||
</FieldSet>
|
||||
|
||||
<FieldSet legend="Analytics">
|
||||
<FieldSet legend={translate('Analytics')}>
|
||||
<FormGroup>
|
||||
<FormLabel>Filter Analytics Events</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('FilterAnalyticsEvents')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="filterSentryEvents"
|
||||
helpText="Filter known user error events from being sent as Analytics"
|
||||
helpText={translate('FilterSentryEventsHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...settings.filterSentryEvents}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
|||
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import DownloadClientsConnector from './DownloadClients/DownloadClientsConnector';
|
||||
import DownloadClientOptionsConnector from './Options/DownloadClientOptionsConnector';
|
||||
import RemotePathMappingsConnector from './RemotePathMappings/RemotePathMappingsConnector';
|
||||
|
|
@ -58,7 +59,7 @@ class DownloadClientSettings extends Component {
|
|||
} = this.state;
|
||||
|
||||
return (
|
||||
<PageContent title="Download Client Settings">
|
||||
<PageContent title={translate('DownloadClientSettings')}>
|
||||
<SettingsToolbarConnector
|
||||
isSaving={isSaving}
|
||||
hasPendingChanges={hasPendingChanges}
|
||||
|
|
@ -67,7 +68,7 @@ class DownloadClientSettings extends Component {
|
|||
<PageToolbarSeparator />
|
||||
|
||||
<PageToolbarButton
|
||||
label="Test All Clients"
|
||||
label={translate('TestAllClients')}
|
||||
iconName={icons.TEST}
|
||||
isSpinning={isTestingAll}
|
||||
onPress={dispatchTestAllDownloadClients}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AddDownloadClientItem from './AddDownloadClientItem';
|
||||
import styles from './AddDownloadClientModalContent.css';
|
||||
|
||||
|
|
@ -42,7 +43,9 @@ class AddDownloadClientModalContent extends Component {
|
|||
|
||||
{
|
||||
!isSchemaFetching && !!schemaError &&
|
||||
<div>Unable to add a new downloadClient, please try again.</div>
|
||||
<div>
|
||||
{translate('UnableToAddANewDownloadClientPleaseTryAgain')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -50,11 +53,15 @@ class AddDownloadClientModalContent extends Component {
|
|||
<div>
|
||||
|
||||
<Alert kind={kinds.INFO}>
|
||||
<div>Readarr supports any downloadClient that uses the Newznab standard, as well as other downloadClients listed below.</div>
|
||||
<div>For more information on the individual downloadClients, click on the info buttons.</div>
|
||||
<div>
|
||||
{translate('ReadarrSupportsAnyDownloadClientThatUsesTheNewznabStandardAsWellAsOtherDownloadClientsListedBelow')}
|
||||
</div>
|
||||
<div>
|
||||
{translate('ForMoreInformationOnTheIndividualDownloadClientsClickOnTheInfoButtons')}
|
||||
</div>
|
||||
</Alert>
|
||||
|
||||
<FieldSet legend="Usenet">
|
||||
<FieldSet legend={translate('Usenet')}>
|
||||
<div className={styles.downloadClients}>
|
||||
{
|
||||
usenetDownloadClients.map((downloadClient) => {
|
||||
|
|
@ -71,7 +78,7 @@ class AddDownloadClientModalContent extends Component {
|
|||
</div>
|
||||
</FieldSet>
|
||||
|
||||
<FieldSet legend="Torrents">
|
||||
<FieldSet legend={translate('Torrents')}>
|
||||
<div className={styles.downloadClients}>
|
||||
{
|
||||
torrentDownloadClients.map((downloadClient) => {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import Card from 'Components/Card';
|
|||
import Label from 'Components/Label';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import EditDownloadClientModalConnector from './EditDownloadClientModalConnector';
|
||||
import styles from './DownloadClient.css';
|
||||
|
||||
|
|
@ -103,9 +104,9 @@ class DownloadClient extends Component {
|
|||
<ConfirmModal
|
||||
isOpen={this.state.isDeleteDownloadClientModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title="Delete Download Client"
|
||||
message={`Are you sure you want to delete the download client '${name}'?`}
|
||||
confirmLabel="Delete"
|
||||
title={translate('DeleteDownloadClient')}
|
||||
message={translate('DeleteDownloadClientMessageText', [name])}
|
||||
confirmLabel={translate('Delete')}
|
||||
onConfirm={this.onConfirmDeleteDownloadClient}
|
||||
onCancel={this.onDeleteDownloadClientModalClose}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import FieldSet from 'Components/FieldSet';
|
|||
import Icon from 'Components/Icon';
|
||||
import PageSectionContent from 'Components/Page/PageSectionContent';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AddDownloadClientModal from './AddDownloadClientModal';
|
||||
import DownloadClient from './DownloadClient';
|
||||
import EditDownloadClientModalConnector from './EditDownloadClientModalConnector';
|
||||
|
|
@ -58,9 +59,9 @@ class DownloadClients extends Component {
|
|||
} = this.state;
|
||||
|
||||
return (
|
||||
<FieldSet legend="Download Clients">
|
||||
<FieldSet legend={translate('DownloadClients')}>
|
||||
<PageSectionContent
|
||||
errorMessage="Unable to load download clients"
|
||||
errorMessage={translate('UnableToLoadDownloadClients')}
|
||||
{...otherProps}
|
||||
>
|
||||
<div className={styles.downloadClients}>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './EditDownloadClientModalContent.css';
|
||||
|
||||
class EditDownloadClientModalContent extends Component {
|
||||
|
|
@ -63,7 +64,9 @@ class EditDownloadClientModalContent extends Component {
|
|||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>Unable to add a new download client, please try again.</div>
|
||||
<div>
|
||||
{translate('UnableToAddANewDownloadClientPleaseTryAgain')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -80,7 +83,9 @@ class EditDownloadClientModalContent extends Component {
|
|||
}
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Name')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
|
|
@ -91,7 +96,9 @@ class EditDownloadClientModalContent extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Enable</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Enable')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
|
|
@ -120,12 +127,14 @@ class EditDownloadClientModalContent extends Component {
|
|||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
>
|
||||
<FormLabel>Client Priority</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ClientPriority')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.NUMBER}
|
||||
name="priority"
|
||||
helpText="Prioritize multiple Download Clients. Round-Robin is used for clients with the same priority."
|
||||
helpText={translate('PriorityHelpText')}
|
||||
min={1}
|
||||
max={50}
|
||||
{...priority}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import FormInputGroup from 'Components/Form/FormInputGroup';
|
|||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import { inputTypes, sizes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
function DownloadClientOptions(props) {
|
||||
const {
|
||||
|
|
@ -27,21 +28,25 @@ function DownloadClientOptions(props) {
|
|||
|
||||
{
|
||||
!isFetching && error &&
|
||||
<div>Unable to load download client options</div>
|
||||
<div>
|
||||
{translate('UnableToLoadDownloadClientOptions')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
hasSettings && !isFetching && !error &&
|
||||
<div>
|
||||
<FieldSet legend="Completed Download Handling">
|
||||
<FieldSet legend={translate('CompletedDownloadHandling')}>
|
||||
<Form>
|
||||
<FormGroup size={sizes.MEDIUM}>
|
||||
<FormLabel>Enable</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Enable')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="enableCompletedDownloadHandling"
|
||||
helpText="Automatically import completed downloads from download client"
|
||||
helpText={translate('EnableCompletedDownloadHandlingHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...settings.enableCompletedDownloadHandling}
|
||||
/>
|
||||
|
|
@ -52,12 +57,14 @@ function DownloadClientOptions(props) {
|
|||
isAdvanced={true}
|
||||
size={sizes.MEDIUM}
|
||||
>
|
||||
<FormLabel>Remove</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Remove')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="removeCompletedDownloads"
|
||||
helpText="Remove imported downloads from download client history"
|
||||
helpText={translate('RemoveCompletedDownloadsHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...settings.removeCompletedDownloads}
|
||||
/>
|
||||
|
|
@ -66,16 +73,18 @@ function DownloadClientOptions(props) {
|
|||
</FieldSet>
|
||||
|
||||
<FieldSet
|
||||
legend="Failed Download Handling"
|
||||
legend={translate('FailedDownloadHandling')}
|
||||
>
|
||||
<Form>
|
||||
<FormGroup size={sizes.MEDIUM}>
|
||||
<FormLabel>Redownload</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Redownload')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="autoRedownloadFailed"
|
||||
helpText="Automatically search for and attempt to download a different release"
|
||||
helpText={translate('AutoRedownloadFailedHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...settings.autoRedownloadFailed}
|
||||
/>
|
||||
|
|
@ -86,12 +95,14 @@ function DownloadClientOptions(props) {
|
|||
isAdvanced={true}
|
||||
size={sizes.MEDIUM}
|
||||
>
|
||||
<FormLabel>Remove</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Remove')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="removeFailedDownloads"
|
||||
helpText="Remove failed downloads from download client history"
|
||||
helpText={translate('RemoveFailedDownloadsHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...settings.removeFailedDownloads}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
|
|||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes, kinds } from 'Helpers/Props';
|
||||
import { stringSettingShape } from 'Helpers/Props/Shapes/settingShape';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './EditRemotePathMappingModalContent.css';
|
||||
|
||||
function EditRemotePathMappingModalContent(props) {
|
||||
|
|
@ -51,19 +52,23 @@ function EditRemotePathMappingModalContent(props) {
|
|||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>Unable to add a new remote path mapping, please try again.</div>
|
||||
<div>
|
||||
{translate('UnableToAddANewRemotePathMappingPleaseTryAgain')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && !error &&
|
||||
<Form {...otherProps}>
|
||||
<FormGroup>
|
||||
<FormLabel>Host</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Host')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="host"
|
||||
helpText="The same host you specified for the remote Download Client"
|
||||
helpText={translate('HostHelpText')}
|
||||
{...host}
|
||||
values={downloadClientHosts}
|
||||
onChange={onInputChange}
|
||||
|
|
@ -71,24 +76,28 @@ function EditRemotePathMappingModalContent(props) {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Remote Path</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('RemotePath')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="remotePath"
|
||||
helpText="Root path to the directory that the Download Client accesses"
|
||||
helpText={translate('RemotePathHelpText')}
|
||||
{...remotePath}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Local Path</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('LocalPath')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.PATH}
|
||||
name="localPath"
|
||||
helpText="Path that Readarr should use to access the remote path locally"
|
||||
helpText={translate('LocalPathHelpText')}
|
||||
{...localPath}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import Icon from 'Components/Icon';
|
|||
import Link from 'Components/Link/Link';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import EditRemotePathMappingModalConnector from './EditRemotePathMappingModalConnector';
|
||||
import styles from './RemotePathMapping.css';
|
||||
|
||||
|
|
@ -87,9 +88,9 @@ class RemotePathMapping extends Component {
|
|||
<ConfirmModal
|
||||
isOpen={this.state.isDeleteRemotePathMappingModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title="Delete Delay Profile"
|
||||
message="Are you sure you want to delete this remote path mapping?"
|
||||
confirmLabel="Delete"
|
||||
title={translate('DeleteDelayProfile')}
|
||||
message={translate('DeleteDelayProfileMessageText')}
|
||||
confirmLabel={translate('Delete')}
|
||||
onConfirm={this.onConfirmDeleteRemotePathMapping}
|
||||
onCancel={this.onDeleteRemotePathMappingModalClose}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import Icon from 'Components/Icon';
|
|||
import Link from 'Components/Link/Link';
|
||||
import PageSectionContent from 'Components/Page/PageSectionContent';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import EditRemotePathMappingModalConnector from './EditRemotePathMappingModalConnector';
|
||||
import RemotePathMapping from './RemotePathMapping';
|
||||
import styles from './RemotePathMappings.css';
|
||||
|
|
@ -44,9 +45,9 @@ class RemotePathMappings extends Component {
|
|||
} = this.props;
|
||||
|
||||
return (
|
||||
<FieldSet legend="Remote Path Mappings">
|
||||
<FieldSet legend={translate('RemotePathMappings')}>
|
||||
<PageSectionContent
|
||||
errorMessage="Unable to load Remote Path Mappings"
|
||||
errorMessage={translate('UnableToLoadRemotePathMappings')}
|
||||
{...otherProps}
|
||||
>
|
||||
<div className={styles.remotePathMappingsHeader}>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import FormGroup from 'Components/Form/FormGroup';
|
|||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import { inputTypes, sizes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
function AnalyticSettings(props) {
|
||||
const {
|
||||
|
|
@ -17,15 +18,17 @@ function AnalyticSettings(props) {
|
|||
} = settings;
|
||||
|
||||
return (
|
||||
<FieldSet legend="Analytics">
|
||||
<FieldSet legend={translate('Analytics')}>
|
||||
<FormGroup size={sizes.MEDIUM}>
|
||||
<FormLabel>Send Anonymous Usage Data</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('SendAnonymousUsageData')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="analyticsEnabled"
|
||||
helpText="Send anonymous usage and error information to Readarr's servers. This includes information on your browser, which Readarr WebUI pages you use, error reporting as well as OS and runtime version. We will use this information to prioritize features and bug fixes."
|
||||
helpTextWarning="Requires restart to take effect"
|
||||
helpText={translate('AnalyticsEnabledHelpText')}
|
||||
helpTextWarning={translate('AnalyticsEnabledHelpTextWarning')}
|
||||
onChange={onInputChange}
|
||||
{...analyticsEnabled}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import FormGroup from 'Components/Form/FormGroup';
|
|||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import { inputTypes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
function BackupSettings(props) {
|
||||
const {
|
||||
|
|
@ -24,17 +25,19 @@ function BackupSettings(props) {
|
|||
}
|
||||
|
||||
return (
|
||||
<FieldSet legend="Backups">
|
||||
<FieldSet legend={translate('Backups')}>
|
||||
<FormGroup
|
||||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
>
|
||||
<FormLabel>Folder</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Folder')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.PATH}
|
||||
name="backupFolder"
|
||||
helpText="Relative paths will be under Readarr's AppData directory"
|
||||
helpText={translate('BackupFolderHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...backupFolder}
|
||||
/>
|
||||
|
|
@ -44,13 +47,15 @@ function BackupSettings(props) {
|
|||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
>
|
||||
<FormLabel>Interval</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Interval')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.NUMBER}
|
||||
name="backupInterval"
|
||||
unit="days"
|
||||
helpText="Interval to backup the Readarr DB and settings"
|
||||
helpText={translate('BackupIntervalHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...backupInterval}
|
||||
/>
|
||||
|
|
@ -60,13 +65,15 @@ function BackupSettings(props) {
|
|||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
>
|
||||
<FormLabel>Retention</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Retention')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.NUMBER}
|
||||
name="backupRetention"
|
||||
unit="days"
|
||||
helpText="Automatic backups older than the retention period will be cleaned up automatically"
|
||||
helpText={translate('BackupRetentionHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...backupRetention}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import PageContent from 'Components/Page/PageContent';
|
|||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AnalyticSettings from './AnalyticSettings';
|
||||
import BackupSettings from './BackupSettings';
|
||||
import HostSettings from './HostSettings';
|
||||
|
|
@ -110,7 +111,7 @@ class GeneralSettings extends Component {
|
|||
} = this.props;
|
||||
|
||||
return (
|
||||
<PageContent title="General Settings">
|
||||
<PageContent title={translate('GeneralSettings')}>
|
||||
<SettingsToolbarConnector
|
||||
{...otherProps}
|
||||
/>
|
||||
|
|
@ -123,7 +124,9 @@ class GeneralSettings extends Component {
|
|||
|
||||
{
|
||||
!isFetching && error &&
|
||||
<div>Unable to load General settings</div>
|
||||
<div>
|
||||
{translate('UnableToLoadGeneralSettings')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -183,12 +186,12 @@ class GeneralSettings extends Component {
|
|||
<ConfirmModal
|
||||
isOpen={this.state.isRestartRequiredModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title="Restart Readarr"
|
||||
title={translate('RestartReadarr')}
|
||||
message={
|
||||
`Readarr requires a restart to apply changes, do you want to restart now? ${isWindowsService ? 'Depending which user is running the Readarr service you may need to restart Readarr as admin once before the service will start automatically.' : ''}`
|
||||
}
|
||||
cancelLabel="I'll restart later"
|
||||
confirmLabel="Restart Now"
|
||||
cancelLabel={translate('IllRestartLater')}
|
||||
confirmLabel={translate('RestartNow')}
|
||||
onConfirm={this.onConfirmRestart}
|
||||
onCancel={this.onCloseRestartRequiredModalOpen}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import FormGroup from 'Components/Form/FormGroup';
|
|||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import { inputTypes, sizes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
function HostSettings(props) {
|
||||
const {
|
||||
|
|
@ -27,45 +28,51 @@ function HostSettings(props) {
|
|||
} = settings;
|
||||
|
||||
return (
|
||||
<FieldSet legend="Host">
|
||||
<FieldSet legend={translate('Host')}>
|
||||
<FormGroup
|
||||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
>
|
||||
<FormLabel>Bind Address</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('BindAddress')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="bindAddress"
|
||||
helpText="Valid IP4 address or '*' for all interfaces"
|
||||
helpTextWarning="Requires restart to take effect"
|
||||
helpText={translate('BindAddressHelpText')}
|
||||
helpTextWarning={translate('BindAddressHelpTextWarning')}
|
||||
onChange={onInputChange}
|
||||
{...bindAddress}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Port Number</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('PortNumber')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.NUMBER}
|
||||
name="port"
|
||||
min={1}
|
||||
max={65535}
|
||||
helpTextWarning="Requires restart to take effect"
|
||||
helpTextWarning={translate('PortHelpTextWarning')}
|
||||
onChange={onInputChange}
|
||||
{...port}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>URL Base</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('URLBase')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="urlBase"
|
||||
helpText="For reverse proxy support, default is empty"
|
||||
helpTextWarning="Requires restart to take effect"
|
||||
helpText={translate('UrlBaseHelpText')}
|
||||
helpTextWarning={translate('UrlBaseHelpTextWarning')}
|
||||
onChange={onInputChange}
|
||||
{...urlBase}
|
||||
/>
|
||||
|
|
@ -76,12 +83,14 @@ function HostSettings(props) {
|
|||
isAdvanced={true}
|
||||
size={sizes.MEDIUM}
|
||||
>
|
||||
<FormLabel>Enable SSL</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('EnableSSL')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="enableSsl"
|
||||
helpText=" Requires restart running as administrator to take effect"
|
||||
helpText={translate('EnableSslHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...enableSsl}
|
||||
/>
|
||||
|
|
@ -93,14 +102,16 @@ function HostSettings(props) {
|
|||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
>
|
||||
<FormLabel>SSL Port</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('SSLPort')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.NUMBER}
|
||||
name="sslPort"
|
||||
min={1}
|
||||
max={65535}
|
||||
helpTextWarning="Requires restart to take effect"
|
||||
helpTextWarning={translate('SslPortHelpTextWarning')}
|
||||
onChange={onInputChange}
|
||||
{...sslPort}
|
||||
/>
|
||||
|
|
@ -114,13 +125,15 @@ function HostSettings(props) {
|
|||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
>
|
||||
<FormLabel>SSL Cert Path</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('SSLCertPath')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="sslCertPath"
|
||||
helpText="Path to pfx file"
|
||||
helpTextWarning="Requires restart to take effect"
|
||||
helpText={translate('SslCertPathHelpText')}
|
||||
helpTextWarning={translate('SslCertPathHelpTextWarning')}
|
||||
onChange={onInputChange}
|
||||
{...sslCertPath}
|
||||
/>
|
||||
|
|
@ -134,13 +147,15 @@ function HostSettings(props) {
|
|||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
>
|
||||
<FormLabel>SSL Cert Password</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('SSLCertPassword')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.PASSWORD}
|
||||
name="sslCertPassword"
|
||||
helpText="Password for pfx file"
|
||||
helpTextWarning="Requires restart to take effect"
|
||||
helpText={translate('SslCertPasswordHelpText')}
|
||||
helpTextWarning={translate('SslCertPasswordHelpTextWarning')}
|
||||
onChange={onInputChange}
|
||||
{...sslCertPassword}
|
||||
/>
|
||||
|
|
@ -151,12 +166,14 @@ function HostSettings(props) {
|
|||
{
|
||||
isWindows && mode !== 'service' &&
|
||||
<FormGroup size={sizes.MEDIUM}>
|
||||
<FormLabel>Open browser on start</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('OpenBrowserOnStart')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="launchBrowser"
|
||||
helpText=" Open a web browser and navigate to Readarr homepage on app start."
|
||||
helpText={translate('LaunchBrowserHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...launchBrowser}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import FormGroup from 'Components/Form/FormGroup';
|
|||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import { inputTypes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
const logLevelOptions = [
|
||||
{ key: 'info', value: 'Info' },
|
||||
|
|
@ -23,15 +24,17 @@ function LoggingSettings(props) {
|
|||
} = settings;
|
||||
|
||||
return (
|
||||
<FieldSet legend="Logging">
|
||||
<FieldSet legend={translate('Logging')}>
|
||||
<FormGroup>
|
||||
<FormLabel>Log Level</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('LogLevel')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="logLevel"
|
||||
values={logLevelOptions}
|
||||
helpTextWarning={logLevel.value === 'trace' ? 'Trace logging should only be enabled temporarily' : undefined}
|
||||
helpTextWarning={logLevel.value === 'trace' ? translate('LogLevelvalueTraceTraceLoggingShouldOnlyBeEnabledTemporarily') : undefined}
|
||||
onChange={onInputChange}
|
||||
{...logLevel}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import FormGroup from 'Components/Form/FormGroup';
|
|||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import { inputTypes, sizes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
function ProxySettings(props) {
|
||||
const {
|
||||
|
|
@ -30,9 +31,11 @@ function ProxySettings(props) {
|
|||
];
|
||||
|
||||
return (
|
||||
<FieldSet legend="Proxy">
|
||||
<FieldSet legend={translate('Proxy')}>
|
||||
<FormGroup size={sizes.MEDIUM}>
|
||||
<FormLabel>Use Proxy</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('UseProxy')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
|
|
@ -46,7 +49,9 @@ function ProxySettings(props) {
|
|||
proxyEnabled.value &&
|
||||
<div>
|
||||
<FormGroup>
|
||||
<FormLabel>Proxy Type</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ProxyType')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
|
|
@ -58,7 +63,9 @@ function ProxySettings(props) {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Hostname</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Hostname')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
|
|
@ -69,7 +76,9 @@ function ProxySettings(props) {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Port</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Port')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.NUMBER}
|
||||
|
|
@ -82,43 +91,51 @@ function ProxySettings(props) {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Username</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Username')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="proxyUsername"
|
||||
helpText="You only need to enter a username and password if one is required. Leave them blank otherwise."
|
||||
helpText={translate('ProxyUsernameHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...proxyUsername}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Password</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Password')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.PASSWORD}
|
||||
name="proxyPassword"
|
||||
helpText="You only need to enter a username and password if one is required. Leave them blank otherwise."
|
||||
helpText={translate('ProxyPasswordHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...proxyPassword}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Ignored Addresses</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('IgnoredAddresses')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="proxyBypassFilter"
|
||||
helpText="Use ',' as a separator, and '*.' as a wildcard for subdomains"
|
||||
helpText={translate('ProxyBypassFilterHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...proxyBypassFilter}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup size={sizes.MEDIUM}>
|
||||
<FormLabel>Bypass Proxy for Local Addresses</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('BypassProxyForLocalAddresses')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import Icon from 'Components/Icon';
|
|||
import ClipboardButton from 'Components/Link/ClipboardButton';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import { icons, inputTypes, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
const authenticationMethodOptions = [
|
||||
{ key: 'none', value: 'None' },
|
||||
|
|
@ -76,15 +77,17 @@ class SecuritySettings extends Component {
|
|||
const authenticationEnabled = authenticationMethod && authenticationMethod.value !== 'none';
|
||||
|
||||
return (
|
||||
<FieldSet legend="Security">
|
||||
<FieldSet legend={translate('Security')}>
|
||||
<FormGroup>
|
||||
<FormLabel>Authentication</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Authentication')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="authenticationMethod"
|
||||
values={authenticationMethodOptions}
|
||||
helpText="Require Username and Password to access Readarr"
|
||||
helpText={translate('AuthenticationMethodHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...authenticationMethod}
|
||||
/>
|
||||
|
|
@ -93,7 +96,9 @@ class SecuritySettings extends Component {
|
|||
{
|
||||
authenticationEnabled &&
|
||||
<FormGroup>
|
||||
<FormLabel>Username</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Username')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
|
|
@ -107,7 +112,9 @@ class SecuritySettings extends Component {
|
|||
{
|
||||
authenticationEnabled &&
|
||||
<FormGroup>
|
||||
<FormLabel>Password</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Password')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.PASSWORD}
|
||||
|
|
@ -119,13 +126,15 @@ class SecuritySettings extends Component {
|
|||
}
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>API Key</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('APIKey')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="apiKey"
|
||||
readOnly={true}
|
||||
helpTextWarning="Requires restart to take effect"
|
||||
helpTextWarning={translate('ApiKeyHelpTextWarning')}
|
||||
buttons={[
|
||||
<ClipboardButton
|
||||
key="copy"
|
||||
|
|
@ -151,13 +160,15 @@ class SecuritySettings extends Component {
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Certificate Validation</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('CertificateValidation')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="certificateValidation"
|
||||
values={certificateValidationOptions}
|
||||
helpText="Change how strict HTTPS certification validation is"
|
||||
helpText={translate('CertificateValidationHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...certificateValidation}
|
||||
/>
|
||||
|
|
@ -166,9 +177,9 @@ class SecuritySettings extends Component {
|
|||
<ConfirmModal
|
||||
isOpen={this.state.isConfirmApiKeyResetModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title="Reset API Key"
|
||||
message="Are you sure you want to reset your API Key?"
|
||||
confirmLabel="Reset"
|
||||
title={translate('ResetAPIKey')}
|
||||
message={translate('ResetAPIKeyMessageText')}
|
||||
confirmLabel={translate('Reset')}
|
||||
onConfirm={this.onConfirmResetApiKey}
|
||||
onCancel={this.onCloseResetApiKeyModal}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import FormInputGroup from 'Components/Form/FormInputGroup';
|
|||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import { inputTypes, sizes } from 'Helpers/Props';
|
||||
import titleCase from 'Utilities/String/titleCase';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
function UpdateSettings(props) {
|
||||
const {
|
||||
|
|
@ -45,24 +46,28 @@ function UpdateSettings(props) {
|
|||
|
||||
if (isDocker) {
|
||||
return (
|
||||
<FieldSet legend="Updates">
|
||||
<div>Updating is disabled inside a docker container. Update the container image instead.</div>
|
||||
<FieldSet legend={translate('Updates')}>
|
||||
<div>
|
||||
{translate('UpdatingIsDisabledInsideADockerContainerUpdateTheContainerImageInstead')}
|
||||
</div>
|
||||
</FieldSet>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<FieldSet legend="Updates">
|
||||
<FieldSet legend={translate('Updates')}>
|
||||
<FormGroup
|
||||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
>
|
||||
<FormLabel>Branch</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Branch')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="branch"
|
||||
helpText={usingExternalUpdateMechanism ? 'Branch used by external update mechanism' : 'Branch to use to update Readarr'}
|
||||
helpText={usingExternalUpdateMechanism ? translate('UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism') : translate('UsingExternalUpdateMechanismBranchToUseToUpdateReadarr')}
|
||||
helpLink="https://wiki.servarr.com/Readarr_FAQ#How_do_I_update_my_Readarr"
|
||||
{...branch}
|
||||
onChange={onInputChange}
|
||||
|
|
@ -78,12 +83,14 @@ function UpdateSettings(props) {
|
|||
isAdvanced={true}
|
||||
size={sizes.MEDIUM}
|
||||
>
|
||||
<FormLabel>Automatic</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Automatic')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="updateAutomatically"
|
||||
helpText="Automatically download and install updates. You will still be able to install from System: Updates"
|
||||
helpText={translate('UpdateAutomaticallyHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...updateAutomatically}
|
||||
/>
|
||||
|
|
@ -93,13 +100,15 @@ function UpdateSettings(props) {
|
|||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
>
|
||||
<FormLabel>Mechanism</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('Mechanism')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="updateMechanism"
|
||||
values={updateOptions}
|
||||
helpText="Use Readarr's built-in updater or a script"
|
||||
helpText={translate('UpdateMechanismHelpText')}
|
||||
helpLink="https://wiki.servarr.com/Readarr_FAQ#How_do_I_update_my_Readarr"
|
||||
onChange={onInputChange}
|
||||
{...updateMechanism}
|
||||
|
|
@ -112,12 +121,14 @@ function UpdateSettings(props) {
|
|||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
>
|
||||
<FormLabel>Script Path</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('ScriptPath')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="updateScriptPath"
|
||||
helpText="Path to a custom script that takes an extracted update package and handle the remainder of the update process"
|
||||
helpText={translate('UpdateScriptPathHelpText')}
|
||||
onChange={onInputChange}
|
||||
{...updateScriptPath}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
|
|||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes, kinds } from 'Helpers/Props';
|
||||
import { stringSettingShape } from 'Helpers/Props/Shapes/settingShape';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './EditImportListExclusionModalContent.css';
|
||||
|
||||
function EditImportListExclusionModalContent(props) {
|
||||
|
|
@ -49,7 +50,9 @@ function EditImportListExclusionModalContent(props) {
|
|||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>Unable to add a new import list exclusion, please try again.</div>
|
||||
<div>
|
||||
{translate('UnableToAddANewImportListExclusionPleaseTryAgain')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -58,24 +61,28 @@ function EditImportListExclusionModalContent(props) {
|
|||
{...otherProps}
|
||||
>
|
||||
<FormGroup>
|
||||
<FormLabel>Entity Name</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('EntityName')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="authorName"
|
||||
helpText="The name of the author/book to exclude (can be anything meaningful)"
|
||||
helpText={translate('AuthorNameHelpText')}
|
||||
{...authorName}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Musicbrainz Id</FormLabel>
|
||||
<FormLabel>
|
||||
{translate('MusicbrainzId')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="foreignId"
|
||||
helpText="The Musicbrainz Id of the author/book to exclude"
|
||||
helpText={translate('ForeignIdHelpText')}
|
||||
{...foreignId}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue