Initial pass for translations

pull/2415/head
nitsua 3 years ago committed by Qstick
parent 93aa50b780
commit a75a19698d

@ -14,6 +14,7 @@ import TablePager from 'Components/Table/TablePager';
import { align, icons, kinds } from 'Helpers/Props'; import { align, icons, kinds } from 'Helpers/Props';
import getRemovedItems from 'Utilities/Object/getRemovedItems'; import getRemovedItems from 'Utilities/Object/getRemovedItems';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems'; import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds'; import getSelectedIds from 'Utilities/Table/getSelectedIds';
import removeOldSelectedState from 'Utilities/Table/removeOldSelectedState'; import removeOldSelectedState from 'Utilities/Table/removeOldSelectedState';
import selectAll from 'Utilities/Table/selectAll'; import selectAll from 'Utilities/Table/selectAll';
@ -120,11 +121,11 @@ class Blocklist extends Component {
const selectedIds = this.getSelectedIds(); const selectedIds = this.getSelectedIds();
return ( return (
<PageContent title="Blocklist"> <PageContent title={translate('Blocklist')}>
<PageToolbar> <PageToolbar>
<PageToolbarSection> <PageToolbarSection>
<PageToolbarButton <PageToolbarButton
label="Remove Selected" label={translate('RemoveSelected')}
iconName={icons.REMOVE} iconName={icons.REMOVE}
isDisabled={!selectedIds.length} isDisabled={!selectedIds.length}
isSpinning={isRemoving} isSpinning={isRemoving}
@ -132,7 +133,7 @@ class Blocklist extends Component {
/> />
<PageToolbarButton <PageToolbarButton
label="Clear" label={translate('Clear')}
iconName={icons.CLEAR} iconName={icons.CLEAR}
isSpinning={isClearingBlocklistExecuting} isSpinning={isClearingBlocklistExecuting}
onPress={onClearBlocklistPress} onPress={onClearBlocklistPress}
@ -145,7 +146,7 @@ class Blocklist extends Component {
columns={columns} columns={columns}
> >
<PageToolbarButton <PageToolbarButton
label="Options" label={translate('Options')}
iconName={icons.TABLE} iconName={icons.TABLE}
/> />
</TableOptionsModalWrapper> </TableOptionsModalWrapper>
@ -160,7 +161,9 @@ class Blocklist extends Component {
{ {
!isAnyFetching && !!error && !isAnyFetching && !!error &&
<div>Unable to load blocklist</div> <div>
{translate('UnableToLoadBlocklist')}
</div>
} }
{ {
@ -210,9 +213,9 @@ class Blocklist extends Component {
<ConfirmModal <ConfirmModal
isOpen={isConfirmRemoveModalOpen} isOpen={isConfirmRemoveModalOpen}
kind={kinds.DANGER} kind={kinds.DANGER}
title="Remove Selected" title={translate('RemoveSelected')}
message={'Are you sure you want to remove the selected items from the blocklist?'} message={translate('RemoveSelectedMessageText')}
confirmLabel="Remove Selected" confirmLabel={translate('RemoveSelected')}
onConfirm={this.onRemoveSelectedConfirmed} onConfirm={this.onRemoveSelectedConfirmed}
onCancel={this.onConfirmRemoveModalClose} onCancel={this.onConfirmRemoveModalClose}
/> />

@ -8,6 +8,7 @@ import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent'; import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter'; import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import translate from 'Utilities/String/translate';
class BlocklistDetailsModal extends Component { class BlocklistDetailsModal extends Component {
@ -39,19 +40,19 @@ class BlocklistDetailsModal extends Component {
<ModalBody> <ModalBody>
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
title="Name" title={translate('Name')}
data={sourceTitle} data={sourceTitle}
/> />
<DescriptionListItem <DescriptionListItem
title="Protocol" title={translate('Protocol')}
data={protocol} data={protocol}
/> />
{ {
!!message && !!message &&
<DescriptionListItem <DescriptionListItem
title="Indexer" title={translate('Indexer')}
data={indexer} data={indexer}
/> />
} }
@ -59,7 +60,7 @@ class BlocklistDetailsModal extends Component {
{ {
!!message && !!message &&
<DescriptionListItem <DescriptionListItem
title="Message" title={translate('Message')}
data={message} data={message}
/> />
} }

@ -8,6 +8,7 @@ import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell'; import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import TableRow from 'Components/Table/TableRow'; import TableRow from 'Components/Table/TableRow';
import { icons, kinds } from 'Helpers/Props'; import { icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import BlocklistDetailsModal from './BlocklistDetailsModal'; import BlocklistDetailsModal from './BlocklistDetailsModal';
import styles from './BlocklistRow.css'; import styles from './BlocklistRow.css';
@ -141,7 +142,7 @@ class BlocklistRow extends Component {
/> />
<IconButton <IconButton
title="Remove from blocklist" title={translate('RemoveFromBlocklist')}
name={icons.REMOVE} name={icons.REMOVE}
kind={kinds.DANGER} kind={kinds.DANGER}
onPress={onRemovePress} onPress={onRemovePress}

@ -9,6 +9,7 @@ import Link from 'Components/Link/Link';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import formatDateTime from 'Utilities/Date/formatDateTime'; import formatDateTime from 'Utilities/Date/formatDateTime';
import formatAge from 'Utilities/Number/formatAge'; import formatAge from 'Utilities/Number/formatAge';
import translate from 'Utilities/String/translate';
import styles from './HistoryDetails.css'; import styles from './HistoryDetails.css';
function getDetailedList(statusMessages) { function getDetailedList(statusMessages) {
@ -47,7 +48,9 @@ function formatMissing(value) {
function formatChange(oldValue, newValue) { function formatChange(oldValue, newValue) {
return ( return (
<div> {formatMissing(oldValue)} <Icon name={icons.ARROW_RIGHT_NO_CIRCLE} size={12} /> {formatMissing(newValue)} </div> <div>
{formatMissing(oldValue)} <Icon name={icons.ARROW_RIGHT_NO_CIRCLE} size={12} /> {formatMissing(newValue)}
</div>
); );
} }
@ -77,14 +80,14 @@ function HistoryDetails(props) {
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
descriptionClassName={styles.description} descriptionClassName={styles.description}
title="Name" title={translate('Name')}
data={sourceTitle} data={sourceTitle}
/> />
{ {
!!indexer && !!indexer &&
<DescriptionListItem <DescriptionListItem
title="Indexer" title={translate('Indexer')}
data={indexer} data={indexer}
/> />
} }
@ -93,7 +96,7 @@ function HistoryDetails(props) {
!!releaseGroup && !!releaseGroup &&
<DescriptionListItem <DescriptionListItem
descriptionClassName={styles.description} descriptionClassName={styles.description}
title="Release Group" title={translate('ReleaseGroup')}
data={releaseGroup} data={releaseGroup}
/> />
} }
@ -114,7 +117,7 @@ function HistoryDetails(props) {
{ {
!!downloadClient && !!downloadClient &&
<DescriptionListItem <DescriptionListItem
title="Download Client" title={translate('DownloadClient')}
data={downloadClient} data={downloadClient}
/> />
} }
@ -122,7 +125,7 @@ function HistoryDetails(props) {
{ {
!!downloadId && !!downloadId &&
<DescriptionListItem <DescriptionListItem
title="Grab ID" title={translate('GrabID')}
data={downloadId} data={downloadId}
/> />
} }
@ -130,7 +133,7 @@ function HistoryDetails(props) {
{ {
!!indexer && !!indexer &&
<DescriptionListItem <DescriptionListItem
title="Age (when grabbed)" title={translate('AgeWhenGrabbed')}
data={formatAge(age, ageHours, ageMinutes)} data={formatAge(age, ageHours, ageMinutes)}
/> />
} }
@ -138,7 +141,7 @@ function HistoryDetails(props) {
{ {
!!publishedDate && !!publishedDate &&
<DescriptionListItem <DescriptionListItem
title="Published Date" title={translate('PublishedDate')}
data={formatDateTime(publishedDate, shortDateFormat, timeFormat, { includeSeconds: true })} data={formatDateTime(publishedDate, shortDateFormat, timeFormat, { includeSeconds: true })}
/> />
} }
@ -155,14 +158,14 @@ function HistoryDetails(props) {
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
descriptionClassName={styles.description} descriptionClassName={styles.description}
title="Name" title={translate('Name')}
data={sourceTitle} data={sourceTitle}
/> />
{ {
!!message && !!message &&
<DescriptionListItem <DescriptionListItem
title="Message" title={translate('Message')}
data={message} data={message}
/> />
} }
@ -180,7 +183,7 @@ function HistoryDetails(props) {
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
descriptionClassName={styles.description} descriptionClassName={styles.description}
title="Name" title={translate('Name')}
data={sourceTitle} data={sourceTitle}
/> />
@ -188,7 +191,7 @@ function HistoryDetails(props) {
!!droppedPath && !!droppedPath &&
<DescriptionListItem <DescriptionListItem
descriptionClassName={styles.description} descriptionClassName={styles.description}
title="Source" title={translate('Source')}
data={droppedPath} data={droppedPath}
/> />
} }
@ -197,7 +200,7 @@ function HistoryDetails(props) {
!!importedPath && !!importedPath &&
<DescriptionListItem <DescriptionListItem
descriptionClassName={styles.description} descriptionClassName={styles.description}
title="Imported To" title={translate('ImportedTo')}
data={importedPath} data={importedPath}
/> />
} }
@ -229,12 +232,12 @@ function HistoryDetails(props) {
return ( return (
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
title="Name" title={translate('Name')}
data={sourceTitle} data={sourceTitle}
/> />
<DescriptionListItem <DescriptionListItem
title="Reason" title={translate('Reason')}
data={reasonMessage} data={reasonMessage}
/> />
</DescriptionList> </DescriptionList>
@ -250,12 +253,12 @@ function HistoryDetails(props) {
return ( return (
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
title="Source Path" title={translate('SourcePath')}
data={sourcePath} data={sourcePath}
/> />
<DescriptionListItem <DescriptionListItem
title="Destination Path" title={translate('DestinationPath')}
data={path} data={path}
/> />
</DescriptionList> </DescriptionList>
@ -271,7 +274,7 @@ function HistoryDetails(props) {
return ( return (
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
title="Path" title={translate('Path')}
data={sourceTitle} data={sourceTitle}
/> />
{ {
@ -286,7 +289,7 @@ function HistoryDetails(props) {
}) })
} }
<DescriptionListItem <DescriptionListItem
title="Existing tags scrubbed" title={translate('ExistingTagsScrubbed')}
data={tagsScrubbed === 'True' ? <Icon name={icons.CHECK} /> : <Icon name={icons.REMOVE} />} data={tagsScrubbed === 'True' ? <Icon name={icons.CHECK} /> : <Icon name={icons.REMOVE} />}
/> />
</DescriptionList> </DescriptionList>
@ -301,14 +304,14 @@ function HistoryDetails(props) {
return ( return (
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
title="Name" title={translate('Name')}
data={sourceTitle} data={sourceTitle}
/> />
{ {
!!statusMessages && !!statusMessages &&
<DescriptionListItem <DescriptionListItem
title="Import failures" title={translate('ImportFailures')}
data={getDetailedList(JSON.parse(statusMessages))} data={getDetailedList(JSON.parse(statusMessages))}
/> />
} }
@ -332,14 +335,14 @@ function HistoryDetails(props) {
return ( return (
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
title="Name" title={translate('Name')}
data={sourceTitle} data={sourceTitle}
/> />
{ {
!!indexer && !!indexer &&
<DescriptionListItem <DescriptionListItem
title="Indexer" title={translate('Indexer')}
data={indexer} data={indexer}
/> />
} }
@ -347,7 +350,7 @@ function HistoryDetails(props) {
{ {
!!releaseGroup && !!releaseGroup &&
<DescriptionListItem <DescriptionListItem
title="Release Group" title={translate('ReleaseGroup')}
data={releaseGroup} data={releaseGroup}
/> />
} }
@ -368,7 +371,7 @@ function HistoryDetails(props) {
{ {
!!downloadClient && !!downloadClient &&
<DescriptionListItem <DescriptionListItem
title="Download Client" title={translate('DownloadClient')}
data={downloadClient} data={downloadClient}
/> />
} }
@ -376,7 +379,7 @@ function HistoryDetails(props) {
{ {
!!downloadId && !!downloadId &&
<DescriptionListItem <DescriptionListItem
title="Grab ID" title={translate('GrabID')}
data={downloadId} data={downloadId}
/> />
} }
@ -384,7 +387,7 @@ function HistoryDetails(props) {
{ {
!!indexer && !!indexer &&
<DescriptionListItem <DescriptionListItem
title="Age (when grabbed)" title={translate('AgeWhenGrabbed')}
data={formatAge(age, ageHours, ageMinutes)} data={formatAge(age, ageHours, ageMinutes)}
/> />
} }
@ -392,7 +395,7 @@ function HistoryDetails(props) {
{ {
!!publishedDate && !!publishedDate &&
<DescriptionListItem <DescriptionListItem
title="Published Date" title={translate('PublishedDate')}
data={formatDateTime(publishedDate, shortDateFormat, timeFormat, { includeSeconds: true })} data={formatDateTime(publishedDate, shortDateFormat, timeFormat, { includeSeconds: true })}
/> />
} }
@ -409,14 +412,14 @@ function HistoryDetails(props) {
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
descriptionClassName={styles.description} descriptionClassName={styles.description}
title="Name" title={translate('Name')}
data={sourceTitle} data={sourceTitle}
/> />
{ {
!!message && !!message &&
<DescriptionListItem <DescriptionListItem
title="Message" title={translate('Message')}
data={message} data={message}
/> />
} }
@ -428,7 +431,7 @@ function HistoryDetails(props) {
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
descriptionClassName={styles.description} descriptionClassName={styles.description}
title="Name" title={translate('Name')}
data={sourceTitle} data={sourceTitle}
/> />
</DescriptionList> </DescriptionList>

@ -13,6 +13,7 @@ import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptions
import TablePager from 'Components/Table/TablePager'; import TablePager from 'Components/Table/TablePager';
import { align, icons } from 'Helpers/Props'; import { align, icons } from 'Helpers/Props';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems'; import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import translate from 'Utilities/String/translate';
import HistoryRowConnector from './HistoryRowConnector'; import HistoryRowConnector from './HistoryRowConnector';
class History extends Component { class History extends Component {
@ -66,11 +67,11 @@ class History extends Component {
const hasError = error || albumsError; const hasError = error || albumsError;
return ( return (
<PageContent title="History"> <PageContent title={translate('History')}>
<PageToolbar> <PageToolbar>
<PageToolbarSection> <PageToolbarSection>
<PageToolbarButton <PageToolbarButton
label="Refresh" label={translate('Refresh')}
iconName={icons.REFRESH} iconName={icons.REFRESH}
isSpinning={isFetching} isSpinning={isFetching}
onPress={onFirstPagePress} onPress={onFirstPagePress}
@ -83,7 +84,7 @@ class History extends Component {
columns={columns} columns={columns}
> >
<PageToolbarButton <PageToolbarButton
label="Options" label={translate('Options')}
iconName={icons.TABLE} iconName={icons.TABLE}
/> />
</TableOptionsModalWrapper> </TableOptionsModalWrapper>
@ -106,7 +107,9 @@ class History extends Component {
{ {
!isFetchingAny && hasError && !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 { align, icons } from 'Helpers/Props';
import getRemovedItems from 'Utilities/Object/getRemovedItems'; import getRemovedItems from 'Utilities/Object/getRemovedItems';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems'; import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds'; import getSelectedIds from 'Utilities/Table/getSelectedIds';
import removeOldSelectedState from 'Utilities/Table/removeOldSelectedState'; import removeOldSelectedState from 'Utilities/Table/removeOldSelectedState';
import selectAll from 'Utilities/Table/selectAll'; import selectAll from 'Utilities/Table/selectAll';
@ -168,11 +169,11 @@ class Queue extends Component {
const disableSelectedActions = selectedCount === 0; const disableSelectedActions = selectedCount === 0;
return ( return (
<PageContent title="Queue"> <PageContent title={translate('Queue')}>
<PageToolbar> <PageToolbar>
<PageToolbarSection> <PageToolbarSection>
<PageToolbarButton <PageToolbarButton
label="Refresh" label={translate('Refresh')}
iconName={icons.REFRESH} iconName={icons.REFRESH}
isSpinning={isRefreshing} isSpinning={isRefreshing}
onPress={onRefreshPress} onPress={onRefreshPress}
@ -181,7 +182,7 @@ class Queue extends Component {
<PageToolbarSeparator /> <PageToolbarSeparator />
<PageToolbarButton <PageToolbarButton
label="Grab Selected" label={translate('GrabSelected')}
iconName={icons.DOWNLOAD} iconName={icons.DOWNLOAD}
isDisabled={disableSelectedActions || !isPendingSelected} isDisabled={disableSelectedActions || !isPendingSelected}
isSpinning={isGrabbing} isSpinning={isGrabbing}
@ -189,7 +190,7 @@ class Queue extends Component {
/> />
<PageToolbarButton <PageToolbarButton
label="Remove Selected" label={translate('RemoveSelected')}
iconName={icons.REMOVE} iconName={icons.REMOVE}
isDisabled={disableSelectedActions} isDisabled={disableSelectedActions}
isSpinning={isRemoving} isSpinning={isRemoving}
@ -206,7 +207,7 @@ class Queue extends Component {
optionsComponent={QueueOptionsConnector} optionsComponent={QueueOptionsConnector}
> >
<PageToolbarButton <PageToolbarButton
label="Options" label={translate('Options')}
iconName={icons.TABLE} iconName={icons.TABLE}
/> />
</TableOptionsModalWrapper> </TableOptionsModalWrapper>

@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import Icon from 'Components/Icon'; import Icon from 'Components/Icon';
import { icons, kinds } from 'Helpers/Props'; import { icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
function QueueDetails(props) { function QueueDetails(props) {
const { const {
@ -23,7 +24,7 @@ function QueueDetails(props) {
return ( return (
<Icon <Icon
name={icons.PENDING} 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 <Icon
name={icons.DOWNLOAD} name={icons.DOWNLOAD}
kind={kinds.DANGER} kind={kinds.DANGER}
title={`Import failed: ${errorMessage}`} title={translate('ImportFailedInterp', [errorMessage])}
/> />
); );
} }
@ -47,7 +48,7 @@ function QueueDetails(props) {
<Icon <Icon
name={icons.DOWNLOADING} name={icons.DOWNLOADING}
kind={kinds.DANGER} kind={kinds.DANGER}
title={`Download failed: ${errorMessage}`} title={translate('DownloadFailedInterp', [errorMessage])}
/> />
); );
} }
@ -57,7 +58,7 @@ function QueueDetails(props) {
<Icon <Icon
name={icons.DOWNLOADING} name={icons.DOWNLOADING}
kind={kinds.DANGER} kind={kinds.DANGER}
title="Download failed: check download client for more details" title={translate('DownloadFailedCheckDownloadClientForMoreDetails')}
/> />
); );
} }
@ -67,7 +68,7 @@ function QueueDetails(props) {
<Icon <Icon
name={icons.DOWNLOADING} name={icons.DOWNLOADING}
kind={kinds.WARNING} kind={kinds.WARNING}
title="Download warning: check download client for more details" title={translate('DownloadWarningCheckDownloadClientForMoreDetails')}
/> />
); );
} }
@ -76,7 +77,7 @@ function QueueDetails(props) {
return ( return (
<Icon <Icon
name={icons.DOWNLOADING} name={icons.DOWNLOADING}
title={`Album is downloading - ${progress.toFixed(1)}% ${title}`} title={translate('AlbumIsDownloadingInterp', [progress.toFixed(1), title])}
/> />
); );
} }

@ -4,6 +4,7 @@ import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup'; import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel'; import FormLabel from 'Components/Form/FormLabel';
import { inputTypes } from 'Helpers/Props'; import { inputTypes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
class QueueOptions extends Component { class QueueOptions extends Component {
@ -54,13 +55,15 @@ class QueueOptions extends Component {
return ( return (
<Fragment> <Fragment>
<FormGroup> <FormGroup>
<FormLabel>Show Unknown Artist Items</FormLabel> <FormLabel>
{translate('ShowUnknownArtistItems')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="includeUnknownArtistItems" name="includeUnknownArtistItems"
value={includeUnknownArtistItems} value={includeUnknownArtistItems}
helpText="Show items without a artist in the queue, this could include removed artists, movies or anything else in Lidarr's category" helpText={translate('IncludeUnknownArtistItemsHelpText')}
onChange={this.onOptionChange} onChange={this.onOptionChange}
/> />
</FormGroup> </FormGroup>

@ -16,6 +16,7 @@ import Popover from 'Components/Tooltip/Popover';
import { icons, kinds, tooltipPositions } from 'Helpers/Props'; import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal'; import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
import translate from 'Utilities/String/translate';
import QueueStatusCell from './QueueStatusCell'; import QueueStatusCell from './QueueStatusCell';
import RemoveQueueItemModal from './RemoveQueueItemModal'; import RemoveQueueItemModal from './RemoveQueueItemModal';
import TimeleftCell from './TimeleftCell'; import TimeleftCell from './TimeleftCell';
@ -309,7 +310,7 @@ class QueueRow extends Component {
kind={kinds.DANGER} 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." body="This release failed parsing checks and was manually downloaded from an interactive search. Import is likely to fail."
position={tooltipPositions.LEFT} position={tooltipPositions.LEFT}
/> />
@ -334,7 +335,7 @@ class QueueRow extends Component {
} }
<SpinnerIconButton <SpinnerIconButton
title="Remove from queue" title={translate('RemoveFromQueue')}
name={icons.REMOVE} name={icons.REMOVE}
isSpinning={isRemoving} isSpinning={isRemoving}
onPress={this.onRemoveQueueItemPress} onPress={this.onRemoveQueueItemPress}

@ -4,6 +4,7 @@ import Icon from 'Components/Icon';
import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableRowCell from 'Components/Table/Cells/TableRowCell';
import Popover from 'Components/Tooltip/Popover'; import Popover from 'Components/Tooltip/Popover';
import { icons, kinds, tooltipPositions } from 'Helpers/Props'; import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './QueueStatusCell.css'; import styles from './QueueStatusCell.css';
function getDetailedPopoverBody(statusMessages) { function getDetailedPopoverBody(statusMessages) {
@ -49,7 +50,7 @@ function QueueStatusCell(props) {
// status === 'downloading' // status === 'downloading'
let iconName = icons.DOWNLOADING; let iconName = icons.DOWNLOADING;
let iconKind = kinds.DEFAULT; let iconKind = kinds.DEFAULT;
let title = 'Downloading'; let title = translate('Downloading');
if (hasWarning) { if (hasWarning) {
iconKind = kinds.WARNING; iconKind = kinds.WARNING;

@ -10,6 +10,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter'; import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds, sizes } from 'Helpers/Props'; import { inputTypes, kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
class RemoveQueueItemModal extends Component { class RemoveQueueItemModal extends Component {
@ -95,26 +96,30 @@ class RemoveQueueItemModal extends Component {
</div> </div>
<FormGroup> <FormGroup>
<FormLabel>Remove From Download Client</FormLabel> <FormLabel>
{translate('RemoveFromDownloadClient')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="remove" name="remove"
value={remove} value={remove}
helpTextWarning="Removing will remove the download and the file(s) from the download client." helpTextWarning={translate('RemoveHelpTextWarning')}
isDisabled={!canIgnore} isDisabled={!canIgnore}
onChange={this.onRemoveChange} onChange={this.onRemoveChange}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Blocklist Release</FormLabel> <FormLabel>
{translate('BlocklistRelease')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="blocklist" name="blocklist"
value={blocklist} value={blocklist}
helpText="Prevents Lidarr from automatically grabbing this release again" helpText={translate('BlocklistHelpText')}
onChange={this.onBlocklistChange} onChange={this.onBlocklistChange}
/> />
</FormGroup> </FormGroup>
@ -122,12 +127,14 @@ class RemoveQueueItemModal extends Component {
{ {
blocklist && blocklist &&
<FormGroup> <FormGroup>
<FormLabel>Skip Redownload</FormLabel> <FormLabel>
{translate('SkipRedownload')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="skipredownload" name="skipredownload"
value={skipredownload} value={skipredownload}
helpText="Prevents Lidarr from trying download an alternative release for this item" helpText={translate('SkipredownloadHelpText')}
onChange={this.onSkipReDownloadChange} onChange={this.onSkipReDownloadChange}
/> />
</FormGroup> </FormGroup>

@ -10,6 +10,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter'; import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds, sizes } from 'Helpers/Props'; import { inputTypes, kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './RemoveQueueItemsModal.css'; import styles from './RemoveQueueItemsModal.css';
class RemoveQueueItemsModal extends Component { class RemoveQueueItemsModal extends Component {
@ -96,13 +97,15 @@ class RemoveQueueItemsModal extends Component {
</div> </div>
<FormGroup> <FormGroup>
<FormLabel>Remove From Download Client</FormLabel> <FormLabel>
{translate('RemoveFromDownloadClient')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="remove" name="remove"
value={remove} value={remove}
helpTextWarning="Removing will remove the download and the file(s) from the download client." helpTextWarning={translate('RemoveHelpTextWarning')}
isDisabled={!canIgnore} isDisabled={!canIgnore}
onChange={this.onRemoveChange} onChange={this.onRemoveChange}
/> />
@ -117,7 +120,7 @@ class RemoveQueueItemsModal extends Component {
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="blocklist" name="blocklist"
value={blocklist} value={blocklist}
helpText="Prevents Lidarr from automatically grabbing these files again" helpText={translate('BlocklistHelpText')}
onChange={this.onBlocklistChange} onChange={this.onBlocklistChange}
/> />
</FormGroup> </FormGroup>
@ -125,12 +128,14 @@ class RemoveQueueItemsModal extends Component {
{ {
blocklist && blocklist &&
<FormGroup> <FormGroup>
<FormLabel>Skip Redownload</FormLabel> <FormLabel>
{translate('SkipRedownload')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="skipredownload" name="skipredownload"
value={skipredownload} value={skipredownload}
helpText="Prevents Lidarr from trying download alternative releases for the removed items" helpText={translate('SkipredownloadHelpText')}
onChange={this.onSkipReDownloadChange} onChange={this.onSkipReDownloadChange}
/> />
</FormGroup> </FormGroup>

@ -5,6 +5,7 @@ import formatTime from 'Utilities/Date/formatTime';
import formatTimeSpan from 'Utilities/Date/formatTimeSpan'; import formatTimeSpan from 'Utilities/Date/formatTimeSpan';
import getRelativeDate from 'Utilities/Date/getRelativeDate'; import getRelativeDate from 'Utilities/Date/getRelativeDate';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
import translate from 'Utilities/String/translate';
import styles from './TimeleftCell.css'; import styles from './TimeleftCell.css';
function TimeleftCell(props) { function TimeleftCell(props) {
@ -26,7 +27,7 @@ function TimeleftCell(props) {
return ( return (
<TableRowCell <TableRowCell
className={styles.timeleft} className={styles.timeleft}
title={`Delaying download until ${date} at ${time}`} title={translate('DelayingDownloadUntilInterp', [date, time])}
> >
- -
</TableRowCell> </TableRowCell>
@ -40,7 +41,7 @@ function TimeleftCell(props) {
return ( return (
<TableRowCell <TableRowCell
className={styles.timeleft} className={styles.timeleft}
title={`Retrying download ${date} at ${time}`} title={translate('RetryingDownloadInterp', [date, time])}
> >
- -
</TableRowCell> </TableRowCell>

@ -1,43 +1,44 @@
import React from 'react'; import React from 'react';
import DescriptionList from 'Components/DescriptionList/DescriptionList'; import DescriptionList from 'Components/DescriptionList/DescriptionList';
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem'; import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
import translate from 'Utilities/String/translate';
function ArtistMonitoringOptionsPopoverContent() { function ArtistMonitoringOptionsPopoverContent() {
return ( return (
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
title="All Albums" title={translate('AllAlbums')}
data="Monitor all albums except specials" data={translate('AllAlbumsData')}
/> />
<DescriptionListItem <DescriptionListItem
title="Future Albums" title={translate('FutureAlbums')}
data="Monitor albums that have not released yet" data={translate('FutureAlbumsData')}
/> />
<DescriptionListItem <DescriptionListItem
title="Missing Albums" title={translate('MissingAlbums')}
data="Monitor albums that do not have files or have not released yet" data={translate('MissingAlbumsData')}
/> />
<DescriptionListItem <DescriptionListItem
title="Existing Albums" title={translate('ExistingAlbums')}
data="Monitor albums that have files or have not released yet" data={translate('ExistingAlbumsData')}
/> />
<DescriptionListItem <DescriptionListItem
title="First Album" title={translate('FirstAlbum')}
data="Monitor the first albums. All other albums will be ignored" data={translate('FirstAlbumData')}
/> />
<DescriptionListItem <DescriptionListItem
title="Latest Album" title={translate('LatestAlbum')}
data="Monitor the latest albums and future albums" data={translate('LatestAlbumData')}
/> />
<DescriptionListItem <DescriptionListItem
title="None" title={translate('None')}
data="No albums will be monitored" data={translate('NoneData')}
/> />
</DescriptionList> </DescriptionList>
); );

@ -10,6 +10,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds } from 'Helpers/Props'; import { inputTypes, kinds } from 'Helpers/Props';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
import translate from 'Utilities/String/translate';
import styles from './DeleteAlbumModalContent.css'; import styles from './DeleteAlbumModalContent.css';
class DeleteAlbumModalContent extends Component { class DeleteAlbumModalContent extends Component {
@ -91,13 +92,15 @@ class DeleteAlbumModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Add List Exclusion</FormLabel> <FormLabel>
{translate('AddListExclusion')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="addImportListExclusion" name="addImportListExclusion"
value={addImportListExclusion} value={addImportListExclusion}
helpText="Prevent album from being added to Lidarr by Import Lists or Artist Refresh" helpText={translate('AddImportListExclusionHelpText')}
kind={kinds.DANGER} kind={kinds.DANGER}
onChange={this.onAddImportListExclusionChange} onChange={this.onAddImportListExclusionChange}
/> />
@ -106,14 +109,18 @@ class DeleteAlbumModalContent extends Component {
{ {
!addImportListExclusion && !addImportListExclusion &&
<div className={styles.deleteFilesMessage}> <div className={styles.deleteFilesMessage}>
<div>If you don't add an import list exclusion and the artist has a metadata profile other than 'None' then this album may be re-added during the next artist refresh.</div> <div>
{translate('IfYouDontAddAnImportListExclusionAndTheArtistHasAMetadataProfileOtherThanNoneThenThisAlbumMayBeReaddedDuringTheNextArtistRefresh')}
</div>
</div> </div>
} }
{ {
deleteFiles && deleteFiles &&
<div className={styles.deleteFilesMessage}> <div className={styles.deleteFilesMessage}>
<div>The album's files will be deleted.</div> <div>
{translate('TheAlbumsFilesWillBeDeleted')}
</div>
{ {
!!trackFileCount && !!trackFileCount &&

@ -27,6 +27,7 @@ import RetagPreviewModalConnector from 'Retag/RetagPreviewModalConnector';
import fonts from 'Styles/Variables/fonts'; import fonts from 'Styles/Variables/fonts';
import TrackFileEditorModal from 'TrackFile/Editor/TrackFileEditorModal'; import TrackFileEditorModal from 'TrackFile/Editor/TrackFileEditorModal';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
import translate from 'Utilities/String/translate';
import selectAll from 'Utilities/Table/selectAll'; import selectAll from 'Utilities/Table/selectAll';
import toggleSelected from 'Utilities/Table/toggleSelected'; import toggleSelected from 'Utilities/Table/toggleSelected';
import AlbumDetailsLinks from './AlbumDetailsLinks'; import AlbumDetailsLinks from './AlbumDetailsLinks';
@ -241,14 +242,14 @@ class AlbumDetails extends Component {
<PageToolbar> <PageToolbar>
<PageToolbarSection> <PageToolbarSection>
<PageToolbarButton <PageToolbarButton
label="Search Album" label={translate('SearchAlbum')}
iconName={icons.SEARCH} iconName={icons.SEARCH}
isSpinning={isSearching} isSpinning={isSearching}
onPress={onSearchPress} onPress={onSearchPress}
/> />
<PageToolbarButton <PageToolbarButton
label="Interactive Search" label={translate('InteractiveSearch')}
iconName={icons.INTERACTIVE} iconName={icons.INTERACTIVE}
onPress={this.onInteractiveSearchPress} onPress={this.onInteractiveSearchPress}
/> />
@ -256,28 +257,28 @@ class AlbumDetails extends Component {
<PageToolbarSeparator /> <PageToolbarSeparator />
<PageToolbarButton <PageToolbarButton
label="Preview Rename" label={translate('PreviewRename')}
iconName={icons.ORGANIZE} iconName={icons.ORGANIZE}
isDisabled={!hasTrackFiles} isDisabled={!hasTrackFiles}
onPress={this.onOrganizePress} onPress={this.onOrganizePress}
/> />
<PageToolbarButton <PageToolbarButton
label="Preview Retag" label={translate('PreviewRetag')}
iconName={icons.RETAG} iconName={icons.RETAG}
isDisabled={!hasTrackFiles} isDisabled={!hasTrackFiles}
onPress={this.onRetagPress} onPress={this.onRetagPress}
/> />
<PageToolbarButton <PageToolbarButton
label="Manage Tracks" label={translate('ManageTracks')}
iconName={icons.TRACK_FILE} iconName={icons.TRACK_FILE}
isDisabled={!hasTrackFiles} isDisabled={!hasTrackFiles}
onPress={this.onManageTracksPress} onPress={this.onManageTracksPress}
/> />
<PageToolbarButton <PageToolbarButton
label="History" label={translate('History')}
iconName={icons.HISTORY} iconName={icons.HISTORY}
onPress={this.onArtistHistoryPress} onPress={this.onArtistHistoryPress}
/> />
@ -285,13 +286,13 @@ class AlbumDetails extends Component {
<PageToolbarSeparator /> <PageToolbarSeparator />
<PageToolbarButton <PageToolbarButton
label="Edit" label={translate('Edit')}
iconName={icons.EDIT} iconName={icons.EDIT}
onPress={this.onEditAlbumPress} onPress={this.onEditAlbumPress}
/> />
<PageToolbarButton <PageToolbarButton
label="Delete" label={translate('Delete')}
iconName={icons.DELETE} iconName={icons.DELETE}
onPress={this.onDeleteAlbumPress} onPress={this.onDeleteAlbumPress}
/> />
@ -299,7 +300,7 @@ class AlbumDetails extends Component {
</PageToolbarSection> </PageToolbarSection>
<PageToolbarSection alignContent={align.RIGHT}> <PageToolbarSection alignContent={align.RIGHT}>
<PageToolbarButton <PageToolbarButton
label={allExpanded ? 'Collapse All' : 'Expand All'} label={allExpanded ? translate('AllExpandedCollapseAll') : translate('AllExpandedExpandAll')}
iconName={expandIcon} iconName={expandIcon}
onPress={this.onExpandAllPress} onPress={this.onExpandAllPress}
/> />
@ -349,7 +350,7 @@ class AlbumDetails extends Component {
className={styles.albumNavigationButton} className={styles.albumNavigationButton}
name={icons.ARROW_LEFT} name={icons.ARROW_LEFT}
size={30} size={30}
title={`Go to ${previousAlbum.title}`} title={translate('GoToInterp', [previousAlbum.title])}
to={`/album/${previousAlbum.foreignAlbumId}`} to={`/album/${previousAlbum.foreignAlbumId}`}
/> />
@ -357,7 +358,7 @@ class AlbumDetails extends Component {
className={styles.albumNavigationButton} className={styles.albumNavigationButton}
name={icons.ARROW_UP} name={icons.ARROW_UP}
size={30} size={30}
title={`Go to ${artist.artistName}`} title={translate('GoToInterp', [artist.artistName])}
to={`/artist/${artist.foreignArtistId}`} to={`/artist/${artist.foreignArtistId}`}
/> />
@ -365,7 +366,7 @@ class AlbumDetails extends Component {
className={styles.albumNavigationButton} className={styles.albumNavigationButton}
name={icons.ARROW_RIGHT} name={icons.ARROW_RIGHT}
size={30} size={30}
title={`Go to ${nextAlbum.title}`} title={translate('GoToInterp', [nextAlbum.title])}
to={`/album/${nextAlbum.foreignAlbumId}`} to={`/album/${nextAlbum.foreignAlbumId}`}
/> />
</div> </div>
@ -439,7 +440,7 @@ class AlbumDetails extends Component {
!!albumType && !!albumType &&
<Label <Label
className={styles.detailsLabel} className={styles.detailsLabel}
title="Type" title={translate('Type')}
size={sizes.LARGE} size={sizes.LARGE}
> >
<Icon <Icon
@ -498,12 +499,16 @@ class AlbumDetails extends Component {
{ {
!isFetching && albumsError && !isFetching && albumsError &&
<div>Loading albums failed</div> <div>
{translate('LoadingAlbumsFailed')}
</div>
} }
{ {
!isFetching && trackFilesError && !isFetching && trackFilesError &&
<div>Loading track files failed</div> <div>
{translate('LoadingTrackFilesFailed')}
</div>
} }
{ {

@ -7,6 +7,7 @@ import Link from 'Components/Link/Link';
import Table from 'Components/Table/Table'; import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody'; import TableBody from 'Components/Table/TableBody';
import { icons, kinds, sizes } from 'Helpers/Props'; import { icons, kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import TrackRowConnector from './TrackRowConnector'; import TrackRowConnector from './TrackRowConnector';
import styles from './AlbumDetailsMedium.css'; import styles from './AlbumDetailsMedium.css';
@ -120,7 +121,7 @@ class AlbumDetailsMedium extends Component {
} }
<Label <Label
title={`${totalTrackCount} tracks total. ${trackFileCount} tracks with files.`} title={translate('TotalTrackCountTracksTotalTrackFileCountTracksWithFilesInterp', [totalTrackCount, trackFileCount])}
kind={getTrackCountKind(albumMonitored, trackFileCount, trackCount)} kind={getTrackCountKind(albumMonitored, trackFileCount, trackCount)}
size={sizes.LARGE} size={sizes.LARGE}
> >
@ -137,7 +138,7 @@ class AlbumDetailsMedium extends Component {
<Icon <Icon
className={styles.expandButtonIcon} className={styles.expandButtonIcon}
name={isExpanded ? icons.COLLAPSE : icons.EXPAND} name={isExpanded ? icons.COLLAPSE : icons.EXPAND}
title={isExpanded ? 'Hide tracks' : 'Show tracks'} title={isExpanded ? translate('IsExpandedHideTracks') : translate('IsExpandedShowTracks')}
size={24} size={24}
/> />
{ {
@ -181,7 +182,7 @@ class AlbumDetailsMedium extends Component {
<IconButton <IconButton
name={icons.COLLAPSE} name={icons.COLLAPSE}
size={20} size={20}
title="Hide tracks" title={translate('HideTracks')}
onPress={this.onExpandPress} onPress={this.onExpandPress}
/> />
</div> </div>

@ -9,6 +9,7 @@ import NotFound from 'Components/NotFound';
import PageContent from 'Components/Page/PageContent'; import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody'; import PageContentBody from 'Components/Page/PageContentBody';
import { clearAlbums, fetchAlbums } from 'Store/Actions/albumActions'; import { clearAlbums, fetchAlbums } from 'Store/Actions/albumActions';
import translate from 'Utilities/String/translate';
import AlbumDetailsConnector from './AlbumDetailsConnector'; import AlbumDetailsConnector from './AlbumDetailsConnector';
function createMapStateToProps() { function createMapStateToProps() {
@ -94,7 +95,7 @@ class AlbumDetailsPageConnector extends Component {
if (!foreignAlbumId) { if (!foreignAlbumId) {
return ( return (
<NotFound <NotFound
message="Sorry, that album cannot be found." message={translate('SorryThatAlbumCannotBeFound')}
/> />
); );
} }

@ -5,6 +5,7 @@ import ConfirmModal from 'Components/Modal/ConfirmModal';
import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableRowCell from 'Components/Table/Cells/TableRowCell';
import { icons, kinds } from 'Helpers/Props'; import { icons, kinds } from 'Helpers/Props';
import FileDetailsModal from 'TrackFile/FileDetailsModal'; import FileDetailsModal from 'TrackFile/FileDetailsModal';
import translate from 'Utilities/String/translate';
import styles from './TrackActionsCell.css'; import styles from './TrackActionsCell.css';
class TrackActionsCell extends Component { class TrackActionsCell extends Component {
@ -86,9 +87,9 @@ class TrackActionsCell extends Component {
<ConfirmModal <ConfirmModal
isOpen={isConfirmDeleteModalOpen} isOpen={isConfirmDeleteModalOpen}
kind={kinds.DANGER} kind={kinds.DANGER}
title="Delete Track File" title={translate('DeleteTrackFile')}
message={`Are you sure you want to delete ${trackFilePath}?`} message={translate('DeleteTrackFileMessageText', [trackFilePath])}
confirmLabel="Delete" confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDelete} onConfirm={this.onConfirmDelete}
onCancel={this.onConfirmDeleteModalClose} onCancel={this.onConfirmDeleteModalClose}
/> />

@ -11,6 +11,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter'; import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes } from 'Helpers/Props'; import { inputTypes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
class EditAlbumModalContent extends Component { class EditAlbumModalContent extends Component {
@ -59,36 +60,42 @@ class EditAlbumModalContent extends Component {
{...otherProps} {...otherProps}
> >
<FormGroup> <FormGroup>
<FormLabel>Monitored</FormLabel> <FormLabel>
{translate('Monitored')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="monitored" name="monitored"
helpText="Lidarr will search for and download album" helpText={translate('MonitoredHelpText')}
{...monitored} {...monitored}
onChange={onInputChange} onChange={onInputChange}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Automatically Switch Release</FormLabel> <FormLabel>
{translate('AutomaticallySwitchRelease')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="anyReleaseOk" name="anyReleaseOk"
helpText="Lidarr will automatically switch to the release best matching downloaded tracks" helpText={translate('AnyReleaseOkHelpText')}
{...anyReleaseOk} {...anyReleaseOk}
onChange={onInputChange} onChange={onInputChange}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel> Release</FormLabel> <FormLabel>
{translate('Release')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.ALBUM_RELEASE_SELECT} type={inputTypes.ALBUM_RELEASE_SELECT}
name="releases" name="releases"
helpText="Change release for this album" helpText={translate('ReleasesHelpText')}
isDisabled={anyReleaseOk.value && statistics.trackFileCount > 0} isDisabled={anyReleaseOk.value && statistics.trackFileCount > 0}
albumReleases={releases} albumReleases={releases}
onChange={onInputChange} onChange={onInputChange}

@ -3,6 +3,7 @@ import React from 'react';
import Icon from 'Components/Icon'; import Icon from 'Components/Icon';
import Popover from 'Components/Tooltip/Popover'; import Popover from 'Components/Tooltip/Popover';
import { icons, kinds, tooltipPositions } from 'Helpers/Props'; import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import SceneInfo from './SceneInfo'; import SceneInfo from './SceneInfo';
import styles from './EpisodeNumber.css'; import styles from './EpisodeNumber.css';
@ -40,7 +41,7 @@ function EpisodeNumber(props) {
} }
</span> </span>
} }
title="Scene Information" title={translate('SceneInformation')}
body={ body={
<SceneInfo <SceneInfo
sceneSeasonNumber={sceneSeasonNumber} sceneSeasonNumber={sceneSeasonNumber}
@ -70,7 +71,7 @@ function EpisodeNumber(props) {
className={styles.warning} className={styles.warning}
name={icons.WARNING} name={icons.WARNING}
kind={kinds.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} className={styles.warning}
name={icons.WARNING} name={icons.WARNING}
kind={kinds.WARNING} kind={kinds.WARNING}
title="Episode does not have an absolute episode number" title={translate('EpisodeDoesNotHaveAnAbsoluteEpisodeNumber')}
/> />
} }
</span> </span>

@ -5,6 +5,7 @@ import Icon from 'Components/Icon';
import ProgressBar from 'Components/ProgressBar'; import ProgressBar from 'Components/ProgressBar';
import { icons, kinds, sizes } from 'Helpers/Props'; import { icons, kinds, sizes } from 'Helpers/Props';
import isBefore from 'Utilities/Date/isBefore'; import isBefore from 'Utilities/Date/isBefore';
import translate from 'Utilities/String/translate';
import TrackQuality from './TrackQuality'; import TrackQuality from './TrackQuality';
import styles from './EpisodeStatus.css'; import styles from './EpisodeStatus.css';
@ -35,7 +36,7 @@ function EpisodeStatus(props) {
{...queueItem} {...queueItem}
progressBar={ progressBar={
<ProgressBar <ProgressBar
title={`Album is downloading - ${progress.toFixed(1)}% ${queueItem.title}`} title={translate('AlbumIsDownloadingInterp', [progress.toFixed(1), queueItem.title])}
progress={progress} progress={progress}
kind={kinds.PURPLE} kind={kinds.PURPLE}
size={sizes.MEDIUM} size={sizes.MEDIUM}
@ -51,7 +52,7 @@ function EpisodeStatus(props) {
<div className={styles.center}> <div className={styles.center}>
<Icon <Icon
name={icons.DOWNLOADING} name={icons.DOWNLOADING}
title="Album is downloading" title={translate('AlbumIsDownloading')}
/> />
</div> </div>
); );
@ -67,7 +68,7 @@ function EpisodeStatus(props) {
quality={quality} quality={quality}
size={trackFile.size} size={trackFile.size}
isCutoffNotMet={isCutoffNotMet} isCutoffNotMet={isCutoffNotMet}
title="Track Downloaded" title={translate('TrackDownloaded')}
/> />
</div> </div>
); );
@ -78,7 +79,7 @@ function EpisodeStatus(props) {
<div className={styles.center}> <div className={styles.center}>
<Icon <Icon
name={icons.TBA} name={icons.TBA}
title="TBA" title={translate('TBA')}
/> />
</div> </div>
); );
@ -89,7 +90,7 @@ function EpisodeStatus(props) {
<div className={styles.center}> <div className={styles.center}>
<Icon <Icon
name={icons.UNMONITORED} name={icons.UNMONITORED}
title="Album is not monitored" title={translate('AlbumIsNotMonitored')}
/> />
</div> </div>
); );
@ -100,7 +101,7 @@ function EpisodeStatus(props) {
<div className={styles.center}> <div className={styles.center}>
<Icon <Icon
name={icons.MISSING} name={icons.MISSING}
title="Track missing from disk" title={translate('TrackMissingFromDisk')}
/> />
</div> </div>
); );
@ -110,7 +111,7 @@ function EpisodeStatus(props) {
<div className={styles.center}> <div className={styles.center}>
<Icon <Icon
name={icons.NOT_AIRED} name={icons.NOT_AIRED}
title="Album has not aired" title={translate('AlbumHasNotAired')}
/> />
</div> </div>
); );

@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import DescriptionList from 'Components/DescriptionList/DescriptionList'; import DescriptionList from 'Components/DescriptionList/DescriptionList';
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem'; import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
import translate from 'Utilities/String/translate';
import styles from './SceneInfo.css'; import styles from './SceneInfo.css';
function SceneInfo(props) { function SceneInfo(props) {
@ -20,7 +21,7 @@ function SceneInfo(props) {
<DescriptionListItem <DescriptionListItem
titleClassName={styles.title} titleClassName={styles.title}
descriptionClassName={styles.description} descriptionClassName={styles.description}
title="Season" title={translate('Season')}
data={sceneSeasonNumber} data={sceneSeasonNumber}
/> />
} }
@ -30,7 +31,7 @@ function SceneInfo(props) {
<DescriptionListItem <DescriptionListItem
titleClassName={styles.title} titleClassName={styles.title}
descriptionClassName={styles.description} descriptionClassName={styles.description}
title="Episode" title={translate('Episode')}
data={sceneEpisodeNumber} data={sceneEpisodeNumber}
/> />
} }
@ -40,7 +41,7 @@ function SceneInfo(props) {
<DescriptionListItem <DescriptionListItem
titleClassName={styles.title} titleClassName={styles.title}
descriptionClassName={styles.description} descriptionClassName={styles.description}
title="Absolute" title={translate('Absolute')}
data={sceneAbsoluteEpisodeNumber} data={sceneAbsoluteEpisodeNumber}
/> />
} }
@ -50,7 +51,7 @@ function SceneInfo(props) {
<DescriptionListItem <DescriptionListItem
titleClassName={styles.title} titleClassName={styles.title}
descriptionClassName={styles.description} descriptionClassName={styles.description}
title={alternateTitles.length === 1 ? 'Title' : 'Titles'} title={alternateTitles.length === 1 ? translate('AlternateTitleslength1Title') : translate('AlternateTitleslength1Titles')}
data={ data={
<div> <div>
{ {

@ -15,6 +15,7 @@ import VirtualTableRow from 'Components/Table/VirtualTableRow';
import { align, sortDirections } from 'Helpers/Props'; import { align, sortDirections } from 'Helpers/Props';
import getIndexOfFirstCharacter from 'Utilities/Array/getIndexOfFirstCharacter'; import getIndexOfFirstCharacter from 'Utilities/Array/getIndexOfFirstCharacter';
import getErrorMessage from 'Utilities/Object/getErrorMessage'; import getErrorMessage from 'Utilities/Object/getErrorMessage';
import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds'; import getSelectedIds from 'Utilities/Table/getSelectedIds';
import selectAll from 'Utilities/Table/selectAll'; import selectAll from 'Utilities/Table/selectAll';
import toggleSelected from 'Utilities/Table/toggleSelected'; import toggleSelected from 'Utilities/Table/toggleSelected';
@ -330,7 +331,7 @@ class AlbumStudio extends Component {
} = this.state; } = this.state;
return ( return (
<PageContent title="Album Studio"> <PageContent title={translate('AlbumStudio')}>
<PageToolbar> <PageToolbar>
<PageToolbarSection /> <PageToolbarSection />
<PageToolbarSection alignContent={align.RIGHT}> <PageToolbarSection alignContent={align.RIGHT}>

@ -2,6 +2,7 @@ import classNames from 'classnames';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React, { Component } from 'react'; import React, { Component } from 'react';
import MonitorToggleButton from 'Components/MonitorToggleButton'; import MonitorToggleButton from 'Components/MonitorToggleButton';
import translate from 'Utilities/String/translate';
import styles from './AlbumStudioAlbum.css'; import styles from './AlbumStudioAlbum.css';
class AlbumStudioAlbum extends Component { class AlbumStudioAlbum extends Component {
@ -67,7 +68,7 @@ class AlbumStudioAlbum extends Component {
percentOfTracks < 100 && monitored && styles.missingWanted, percentOfTracks < 100 && monitored && styles.missingWanted,
percentOfTracks === 100 && styles.allTracks percentOfTracks === 100 && styles.allTracks
)} )}
title={`${trackFileCount}/${totalTrackCount} tracks downloaded`} title={translate('TrackFileCounttotalTrackCountTracksDownloadedInterp', [trackFileCount, totalTrackCount])}
> >
{ {
totalTrackCount === 0 ? '0/0' : `${trackFileCount}/${totalTrackCount}` totalTrackCount === 0 ? '0/0' : `${trackFileCount}/${totalTrackCount}`

@ -8,6 +8,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { kinds } from 'Helpers/Props'; import { kinds } from 'Helpers/Props';
import UpdateChanges from 'System/Updates/UpdateChanges'; import UpdateChanges from 'System/Updates/UpdateChanges';
import translate from 'Utilities/String/translate';
import styles from './AppUpdatedModalContent.css'; import styles from './AppUpdatedModalContent.css';
function AppUpdatedModalContent(props) { function AppUpdatedModalContent(props) {
@ -49,12 +50,12 @@ function AppUpdatedModalContent(props) {
</div> </div>
<UpdateChanges <UpdateChanges
title="New" title={translate('New')}
changes={update.changes.new} changes={update.changes.new}
/> />
<UpdateChanges <UpdateChanges
title="Fixed" title={translate('Fixed')}
changes={update.changes.fixed} changes={update.changes.fixed}
/> />
</div> </div>

@ -11,6 +11,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { icons, inputTypes, kinds } from 'Helpers/Props'; import { icons, inputTypes, kinds } from 'Helpers/Props';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
import translate from 'Utilities/String/translate';
import styles from './DeleteArtistModalContent.css'; import styles from './DeleteArtistModalContent.css';
class DeleteArtistModalContent extends Component { class DeleteArtistModalContent extends Component {
@ -67,7 +68,7 @@ class DeleteArtistModalContent extends Component {
const addImportListExclusion = this.state.addImportListExclusion; const addImportListExclusion = this.state.addImportListExclusion;
let deleteFilesLabel = `Delete ${trackFileCount} Track Files`; let deleteFilesLabel = `Delete ${trackFileCount} Track Files`;
let deleteFilesHelpText = 'Delete the track files and artist folder'; let deleteFilesHelpText = translate('DeleteFilesHelpText');
if (trackFileCount === 0) { if (trackFileCount === 0) {
deleteFilesLabel = 'Delete Artist Folder'; deleteFilesLabel = 'Delete Artist Folder';
@ -106,13 +107,15 @@ class DeleteArtistModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Add List Exclusion</FormLabel> <FormLabel>
{translate('AddListExclusion')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="addImportListExclusion" name="addImportListExclusion"
value={addImportListExclusion} value={addImportListExclusion}
helpText="Prevent artist from being added to Lidarr by Import lists" helpText={translate('AddImportListExclusionHelpText')}
kind={kinds.DANGER} kind={kinds.DANGER}
onChange={this.onAddImportListExclusionChange} onChange={this.onAddImportListExclusionChange}
/> />
@ -121,7 +124,9 @@ class DeleteArtistModalContent extends Component {
{ {
deleteFiles && deleteFiles &&
<div className={styles.deleteFilesMessage}> <div className={styles.deleteFilesMessage}>
<div>The artist folder <strong>{path}</strong> and all of its content will be deleted.</div> <div>
{translate('TheArtistFolderStrongpathstrongAndAllOfItsContentWillBeDeleted')}
</div>
{ {
!!trackFileCount && !!trackFileCount &&

@ -10,6 +10,7 @@ import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRow from 'Components/Table/TableRow'; import TableRow from 'Components/Table/TableRow';
import { kinds, sizes } from 'Helpers/Props'; import { kinds, sizes } from 'Helpers/Props';
import formatTimeSpan from 'Utilities/Date/formatTimeSpan'; import formatTimeSpan from 'Utilities/Date/formatTimeSpan';
import translate from 'Utilities/String/translate';
import styles from './AlbumRow.css'; import styles from './AlbumRow.css';
function getTrackCountKind(monitored, trackFileCount, trackCount) { function getTrackCountKind(monitored, trackFileCount, trackCount) {
@ -202,7 +203,7 @@ class AlbumRow extends Component {
className={styles.status} className={styles.status}
> >
<Label <Label
title={`${totalTrackCount} tracks total. ${trackFileCount} tracks with files.`} title={translate('TotalTrackCountTracksTotalTrackFileCountTracksWithFilesInterp', [totalTrackCount, trackFileCount])}
kind={getTrackCountKind(monitored, trackFileCount, trackCount)} kind={getTrackCountKind(monitored, trackFileCount, trackCount)}
size={sizes.MEDIUM} size={sizes.MEDIUM}
> >

@ -29,6 +29,7 @@ import QualityProfileNameConnector from 'Settings/Profiles/Quality/QualityProfil
import fonts from 'Styles/Variables/fonts'; import fonts from 'Styles/Variables/fonts';
import TrackFileEditorModal from 'TrackFile/Editor/TrackFileEditorModal'; import TrackFileEditorModal from 'TrackFile/Editor/TrackFileEditorModal';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
import translate from 'Utilities/String/translate';
import selectAll from 'Utilities/Table/selectAll'; import selectAll from 'Utilities/Table/selectAll';
import toggleSelected from 'Utilities/Table/toggleSelected'; import toggleSelected from 'Utilities/Table/toggleSelected';
import InteractiveImportModal from '../../InteractiveImport/InteractiveImportModal'; import InteractiveImportModal from '../../InteractiveImport/InteractiveImportModal';
@ -233,7 +234,7 @@ class ArtistDetails extends Component {
const continuing = status === 'continuing'; const continuing = status === 'continuing';
const endedString = artistType === 'Person' ? 'Deceased' : 'Ended'; const endedString = artistType === 'Person' ? 'Deceased' : 'Ended';
let trackFilesCountMessage = 'No track files'; let trackFilesCountMessage = translate('TrackFilesCountMessage');
if (trackFileCount === 1) { if (trackFileCount === 1) {
trackFilesCountMessage = '1 track file'; trackFilesCountMessage = '1 track file';
@ -254,64 +255,64 @@ class ArtistDetails extends Component {
<PageToolbar> <PageToolbar>
<PageToolbarSection> <PageToolbarSection>
<PageToolbarButton <PageToolbarButton
label="Refresh & Scan" label={translate('RefreshScan')}
iconName={icons.REFRESH} iconName={icons.REFRESH}
spinningName={icons.REFRESH} spinningName={icons.REFRESH}
title="Refresh information and scan disk" title={translate('RefreshInformationAndScanDisk')}
isSpinning={isRefreshing} isSpinning={isRefreshing}
onPress={onRefreshPress} onPress={onRefreshPress}
/> />
<PageToolbarButton <PageToolbarButton
label="Search Monitored" label={translate('SearchMonitored')}
iconName={icons.SEARCH} iconName={icons.SEARCH}
isDisabled={!monitored || !hasMonitoredAlbums || !hasAlbums} isDisabled={!monitored || !hasMonitoredAlbums || !hasAlbums}
isSpinning={isSearching} isSpinning={isSearching}
title={hasMonitoredAlbums ? undefined : 'No monitored albums for this artist'} title={hasMonitoredAlbums ? undefined : translate('HasMonitoredAlbumsNoMonitoredAlbumsForThisArtist')}
onPress={onSearchPress} onPress={onSearchPress}
/> />
<PageToolbarButton <PageToolbarButton
label="Interactive Search" label={translate('InteractiveSearch')}
iconName={icons.INTERACTIVE} iconName={icons.INTERACTIVE}
isDisabled={!monitored || !hasMonitoredAlbums || !hasAlbums} isDisabled={!monitored || !hasMonitoredAlbums || !hasAlbums}
isSpinning={isSearching} isSpinning={isSearching}
title={hasMonitoredAlbums ? undefined : 'No monitored albums for this artist'} title={hasMonitoredAlbums ? undefined : translate('HasMonitoredAlbumsNoMonitoredAlbumsForThisArtist')}
onPress={this.onInteractiveSearchPress} onPress={this.onInteractiveSearchPress}
/> />
<PageToolbarSeparator /> <PageToolbarSeparator />
<PageToolbarButton <PageToolbarButton
label="Preview Rename" label={translate('PreviewRename')}
iconName={icons.ORGANIZE} iconName={icons.ORGANIZE}
isDisabled={!hasTrackFiles} isDisabled={!hasTrackFiles}
onPress={this.onOrganizePress} onPress={this.onOrganizePress}
/> />
<PageToolbarButton <PageToolbarButton
label="Preview Retag" label={translate('PreviewRetag')}
iconName={icons.RETAG} iconName={icons.RETAG}
isDisabled={!hasTrackFiles} isDisabled={!hasTrackFiles}
onPress={this.onRetagPress} onPress={this.onRetagPress}
/> />
<PageToolbarButton <PageToolbarButton
label="Manage Tracks" label={translate('ManageTracks')}
iconName={icons.TRACK_FILE} iconName={icons.TRACK_FILE}
isDisabled={!hasTrackFiles} isDisabled={!hasTrackFiles}
onPress={this.onManageTracksPress} onPress={this.onManageTracksPress}
/> />
<PageToolbarButton <PageToolbarButton
label="History" label={translate('History')}
iconName={icons.HISTORY} iconName={icons.HISTORY}
isDisabled={!hasAlbums} isDisabled={!hasAlbums}
onPress={this.onArtistHistoryPress} onPress={this.onArtistHistoryPress}
/> />
<PageToolbarButton <PageToolbarButton
label="Manual Import" label={translate('ManualImport')}
iconName={icons.INTERACTIVE} iconName={icons.INTERACTIVE}
onPress={this.onInteractiveImportPress} onPress={this.onInteractiveImportPress}
/> />
@ -319,13 +320,13 @@ class ArtistDetails extends Component {
<PageToolbarSeparator /> <PageToolbarSeparator />
<PageToolbarButton <PageToolbarButton
label="Edit" label={translate('Edit')}
iconName={icons.EDIT} iconName={icons.EDIT}
onPress={this.onEditArtistPress} onPress={this.onEditArtistPress}
/> />
<PageToolbarButton <PageToolbarButton
label="Delete" label={translate('Delete')}
iconName={icons.DELETE} iconName={icons.DELETE}
onPress={this.onDeleteArtistPress} onPress={this.onDeleteArtistPress}
/> />
@ -333,7 +334,7 @@ class ArtistDetails extends Component {
<PageToolbarSection alignContent={align.RIGHT}> <PageToolbarSection alignContent={align.RIGHT}>
<PageToolbarButton <PageToolbarButton
label={allExpanded ? 'Collapse All' : 'Expand All'} label={allExpanded ? translate('AllExpandedCollapseAll') : translate('AllExpandedExpandAll')}
iconName={expandIcon} iconName={expandIcon}
onPress={this.onExpandAllPress} onPress={this.onExpandAllPress}
/> />
@ -386,7 +387,7 @@ class ArtistDetails extends Component {
size={20} size={20}
/> />
} }
title="Alternate Titles" title={translate('AlternateTitles')}
body={<ArtistAlternateTitles alternateTitles={alternateTitles} />} body={<ArtistAlternateTitles alternateTitles={alternateTitles} />}
position={tooltipPositions.BOTTOM} position={tooltipPositions.BOTTOM}
/> />
@ -399,7 +400,7 @@ class ArtistDetails extends Component {
className={styles.artistNavigationButton} className={styles.artistNavigationButton}
name={icons.ARROW_LEFT} name={icons.ARROW_LEFT}
size={30} size={30}
title={`Go to ${previousArtist.artistName}`} title={translate('GoToInterp', [previousArtist.artistName])}
to={`/artist/${previousArtist.foreignArtistId}`} to={`/artist/${previousArtist.foreignArtistId}`}
/> />
@ -407,7 +408,7 @@ class ArtistDetails extends Component {
className={styles.artistNavigationButton} className={styles.artistNavigationButton}
name={icons.ARROW_UP} name={icons.ARROW_UP}
size={30} size={30}
title={'Go to artist listing'} title={translate('GoToArtistListing')}
to={{ to={{
pathname: '/', pathname: '/',
state: { restoreScrollPosition: true } state: { restoreScrollPosition: true }
@ -418,7 +419,7 @@ class ArtistDetails extends Component {
className={styles.artistNavigationButton} className={styles.artistNavigationButton}
name={icons.ARROW_RIGHT} name={icons.ARROW_RIGHT}
size={30} size={30}
title={`Go to ${nextArtist.artistName}`} title={translate('GoToInterp', [nextArtist.artistName])}
to={`/artist/${nextArtist.foreignArtistId}`} to={`/artist/${nextArtist.foreignArtistId}`}
/> />
</div> </div>
@ -467,7 +468,7 @@ class ArtistDetails extends Component {
<Label <Label
className={styles.detailsLabel} className={styles.detailsLabel}
title="Quality Profile" title={translate('QualityProfile')}
size={sizes.LARGE} size={sizes.LARGE}
> >
<Icon <Icon
@ -500,7 +501,7 @@ class ArtistDetails extends Component {
<Label <Label
className={styles.detailsLabel} className={styles.detailsLabel}
title={continuing ? 'More albums are expected' : 'No additional albums are expected'} title={continuing ? translate('ContinuingMoreAlbumsAreExpected') : translate('ContinuingNoAdditionalAlbumsAreExpected')}
size={sizes.LARGE} size={sizes.LARGE}
> >
<Icon <Icon
@ -582,12 +583,16 @@ class ArtistDetails extends Component {
{ {
!isFetching && albumsError && !isFetching && albumsError &&
<div>Loading albums failed</div> <div>
{translate('LoadingAlbumsFailed')}
</div>
} }
{ {
!isFetching && trackFilesError && !isFetching && trackFilesError &&
<div>Loading track files failed</div> <div>
{translate('LoadingTrackFilesFailed')}
</div>
} }
{ {

@ -9,6 +9,7 @@ import NotFound from 'Components/NotFound';
import PageContent from 'Components/Page/PageContent'; import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody'; import PageContentBody from 'Components/Page/PageContentBody';
import getErrorMessage from 'Utilities/Object/getErrorMessage'; import getErrorMessage from 'Utilities/Object/getErrorMessage';
import translate from 'Utilities/String/translate';
import ArtistDetailsConnector from './ArtistDetailsConnector'; import ArtistDetailsConnector from './ArtistDetailsConnector';
import styles from './ArtistDetails.css'; import styles from './ArtistDetails.css';
@ -92,7 +93,7 @@ class ArtistDetailsPageConnector extends Component {
if (!foreignArtistId) { if (!foreignArtistId) {
return ( return (
<NotFound <NotFound
message="Sorry, that artist cannot be found." message={translate('SorryThatArtistCannotBeFound')}
/> />
); );
} }

@ -9,6 +9,7 @@ import TableBody from 'Components/Table/TableBody';
import { icons, sortDirections } from 'Helpers/Props'; import { icons, sortDirections } from 'Helpers/Props';
import OrganizePreviewModalConnector from 'Organize/OrganizePreviewModalConnector'; import OrganizePreviewModalConnector from 'Organize/OrganizePreviewModalConnector';
import TrackFileEditorModal from 'TrackFile/Editor/TrackFileEditorModal'; import TrackFileEditorModal from 'TrackFile/Editor/TrackFileEditorModal';
import translate from 'Utilities/String/translate';
import getToggledRange from 'Utilities/Table/getToggledRange'; import getToggledRange from 'Utilities/Table/getToggledRange';
import AlbumRowConnector from './AlbumRowConnector'; import AlbumRowConnector from './AlbumRowConnector';
import styles from './ArtistDetailsSeason.css'; import styles from './ArtistDetailsSeason.css';
@ -159,7 +160,7 @@ class ArtistDetailsSeason extends Component {
<Icon <Icon
className={styles.expandButtonIcon} className={styles.expandButtonIcon}
name={isExpanded ? icons.COLLAPSE : icons.EXPAND} name={isExpanded ? icons.COLLAPSE : icons.EXPAND}
title={isExpanded ? 'Hide albums' : 'Show albums'} title={isExpanded ? translate('IsExpandedHideAlbums') : translate('IsExpandedShowAlbums')}
size={24} size={24}
/> />
@ -209,7 +210,7 @@ class ArtistDetailsSeason extends Component {
iconClassName={styles.collapseButtonIcon} iconClassName={styles.collapseButtonIcon}
name={icons.COLLAPSE} name={icons.COLLAPSE}
size={20} size={20}
title="Hide albums" title={translate('HideAlbums')}
onPress={this.onExpandPress} onPress={this.onExpandPress}
/> />
</div> </div>

@ -15,6 +15,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import Popover from 'Components/Tooltip/Popover'; import Popover from 'Components/Tooltip/Popover';
import { icons, inputTypes, kinds, tooltipPositions } from 'Helpers/Props'; import { icons, inputTypes, kinds, tooltipPositions } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './EditArtistModalContent.css'; import styles from './EditArtistModalContent.css';
class EditArtistModalContent extends Component { class EditArtistModalContent extends Component {
@ -87,19 +88,23 @@ class EditArtistModalContent extends Component {
<ModalBody> <ModalBody>
<Form {...otherProps}> <Form {...otherProps}>
<FormGroup> <FormGroup>
<FormLabel>Monitored</FormLabel> <FormLabel>
{translate('Monitored')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="monitored" name="monitored"
helpText="Download monitored albums from this artist" helpText={translate('MonitoredHelpText')}
{...monitored} {...monitored}
onChange={onInputChange} onChange={onInputChange}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Quality Profile</FormLabel> <FormLabel>
{translate('QualityProfile')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.QUALITY_PROFILE_SELECT} type={inputTypes.QUALITY_PROFILE_SELECT}
@ -122,7 +127,7 @@ class EditArtistModalContent extends Component {
name={icons.INFO} name={icons.INFO}
/> />
} }
title="Metadata Profile" title={translate('MetadataProfile')}
body={<ArtistMetadataProfilePopoverContent />} body={<ArtistMetadataProfilePopoverContent />}
position={tooltipPositions.RIGHT} position={tooltipPositions.RIGHT}
/> />
@ -132,7 +137,7 @@ class EditArtistModalContent extends Component {
<FormInputGroup <FormInputGroup
type={inputTypes.METADATA_PROFILE_SELECT} type={inputTypes.METADATA_PROFILE_SELECT}
name="metadataProfileId" name="metadataProfileId"
helpText="Changes will take place on next artist refresh" helpText={translate('MetadataProfileIdHelpText')}
includeNone={true} includeNone={true}
{...metadataProfileId} {...metadataProfileId}
onChange={onInputChange} onChange={onInputChange}
@ -141,7 +146,9 @@ class EditArtistModalContent extends Component {
} }
<FormGroup> <FormGroup>
<FormLabel>Path</FormLabel> <FormLabel>
{translate('Path')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.PATH} type={inputTypes.PATH}
@ -152,7 +159,9 @@ class EditArtistModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Tags</FormLabel> <FormLabel>
{translate('Tags')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TAG} type={inputTypes.TAG}

@ -14,6 +14,7 @@ import TableBody from 'Components/Table/TableBody';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper'; import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import { align, icons, sortDirections } from 'Helpers/Props'; import { align, icons, sortDirections } from 'Helpers/Props';
import getErrorMessage from 'Utilities/Object/getErrorMessage'; import getErrorMessage from 'Utilities/Object/getErrorMessage';
import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds'; import getSelectedIds from 'Utilities/Table/getSelectedIds';
import selectAll from 'Utilities/Table/selectAll'; import selectAll from 'Utilities/Table/selectAll';
import toggleSelected from 'Utilities/Table/toggleSelected'; import toggleSelected from 'Utilities/Table/toggleSelected';
@ -143,7 +144,7 @@ class ArtistEditor extends Component {
const selectedArtistIds = this.getSelectedIds(); const selectedArtistIds = this.getSelectedIds();
return ( return (
<PageContent title="Artist Editor"> <PageContent title={translate('ArtistEditor')}>
<PageToolbar> <PageToolbar>
<PageToolbarSection /> <PageToolbarSection />
<PageToolbarSection alignContent={align.RIGHT}> <PageToolbarSection alignContent={align.RIGHT}>
@ -152,7 +153,7 @@ class ArtistEditor extends Component {
onTableOptionChange={onTableOptionChange} onTableOptionChange={onTableOptionChange}
> >
<PageToolbarButton <PageToolbarButton
label="Options" label={translate('Options')}
iconName={icons.TABLE} iconName={icons.TABLE}
/> />
</TableOptionsModalWrapper> </TableOptionsModalWrapper>

@ -8,6 +8,7 @@ import SelectInput from 'Components/Form/SelectInput';
import SpinnerButton from 'Components/Link/SpinnerButton'; import SpinnerButton from 'Components/Link/SpinnerButton';
import PageContentFooter from 'Components/Page/PageContentFooter'; import PageContentFooter from 'Components/Page/PageContentFooter';
import { kinds } from 'Helpers/Props'; import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import ArtistEditorFooterLabel from './ArtistEditorFooterLabel'; import ArtistEditorFooterLabel from './ArtistEditorFooterLabel';
import DeleteArtistModal from './Delete/DeleteArtistModal'; import DeleteArtistModal from './Delete/DeleteArtistModal';
import TagsModal from './Tags/TagsModal'; import TagsModal from './Tags/TagsModal';
@ -165,7 +166,7 @@ class ArtistEditorFooter extends Component {
<PageContentFooter> <PageContentFooter>
<div className={styles.inputContainer}> <div className={styles.inputContainer}>
<ArtistEditorFooterLabel <ArtistEditorFooterLabel
label="Monitor Artist" label={translate('MonitorArtist')}
isSaving={isSaving && monitored !== NO_CHANGE} isSaving={isSaving && monitored !== NO_CHANGE}
/> />
@ -196,7 +197,7 @@ class ArtistEditorFooter extends Component {
className={styles.inputContainer} className={styles.inputContainer}
> >
<ArtistEditorFooterLabel <ArtistEditorFooterLabel
label="Quality Profile" label={translate('QualityProfile')}
isSaving={isSaving && qualityProfileId !== NO_CHANGE} isSaving={isSaving && qualityProfileId !== NO_CHANGE}
/> />
@ -218,7 +219,7 @@ class ArtistEditorFooter extends Component {
className={styles.inputContainer} className={styles.inputContainer}
> >
<ArtistEditorFooterLabel <ArtistEditorFooterLabel
label="Metadata Profile" label={translate('MetadataProfile')}
isSaving={isSaving && metadataProfileId !== NO_CHANGE} isSaving={isSaving && metadataProfileId !== NO_CHANGE}
/> />
@ -240,7 +241,7 @@ class ArtistEditorFooter extends Component {
className={styles.inputContainer} className={styles.inputContainer}
> >
<ArtistEditorFooterLabel <ArtistEditorFooterLabel
label="Root Folder" label={translate('RootFolder')}
isSaving={isSaving && rootFolderPath !== NO_CHANGE} isSaving={isSaving && rootFolderPath !== NO_CHANGE}
/> />
@ -263,7 +264,7 @@ class ArtistEditorFooter extends Component {
<div className={styles.buttonContainer}> <div className={styles.buttonContainer}>
<div className={styles.buttonContainerContent}> <div className={styles.buttonContainerContent}>
<ArtistEditorFooterLabel <ArtistEditorFooterLabel
label={`${selectedCount} Artist(s) Selected`} label={translate('SelectedCountArtistsSelectedInterp', [selectedCount])}
isSaving={false} isSaving={false}
/> />

@ -12,6 +12,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter'; import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds, sizes } from 'Helpers/Props'; import { inputTypes, kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './TagsModalContent.css'; import styles from './TagsModalContent.css';
class TagsModalContent extends Component { class TagsModalContent extends Component {
@ -74,7 +75,9 @@ class TagsModalContent extends Component {
<ModalBody> <ModalBody>
<Form> <Form>
<FormGroup> <FormGroup>
<FormLabel>Tags</FormLabel> <FormLabel>
{translate('Tags')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TAG} type={inputTypes.TAG}
@ -85,7 +88,9 @@ class TagsModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Apply Tags</FormLabel> <FormLabel>
{translate('ApplyTags')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.SELECT} type={inputTypes.SELECT}
@ -93,17 +98,19 @@ class TagsModalContent extends Component {
value={applyTags} value={applyTags}
values={applyTagsOptions} values={applyTagsOptions}
helpTexts={[ helpTexts={[
'How to apply tags to the selected artist', translate('ApplyTagsHelpTexts1'),
'Add: Add the tags the existing list of tags', translate('ApplyTagsHelpTexts2'),
'Remove: Remove the entered tags', translate('ApplyTagsHelpTexts3'),
'Replace: Replace the tags with the entered tags (enter no tags to clear all tags)' translate('ApplyTagsHelpTexts4')
]} ]}
onChange={this.onInputChange} onChange={this.onInputChange}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Result</FormLabel> <FormLabel>
{translate('Result')}
</FormLabel>
<div className={styles.result}> <div className={styles.result}>
{ {
@ -120,7 +127,7 @@ class TagsModalContent extends Component {
return ( return (
<Label <Label
key={tag.id} key={tag.id}
title={removeTag ? 'Removing tag' : 'Existing tag'} title={removeTag ? translate('RemoveTagRemovingTag') : translate('RemoveTagExistingTag')}
kind={removeTag ? kinds.INVERSE : kinds.INFO} kind={removeTag ? kinds.INVERSE : kinds.INFO}
size={sizes.LARGE} size={sizes.LARGE}
> >
@ -146,7 +153,7 @@ class TagsModalContent extends Component {
return ( return (
<Label <Label
key={tag.id} key={tag.id}
title={'Adding tag'} title={translate('AddingTag')}
kind={kinds.SUCCESS} kind={kinds.SUCCESS}
size={sizes.LARGE} size={sizes.LARGE}
> >

@ -8,6 +8,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import Table from 'Components/Table/Table'; import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody'; import TableBody from 'Components/Table/TableBody';
import translate from 'Utilities/String/translate';
import ArtistHistoryRowConnector from './ArtistHistoryRowConnector'; import ArtistHistoryRowConnector from './ArtistHistoryRowConnector';
const columns = [ const columns = [
@ -80,12 +81,16 @@ class ArtistHistoryModalContent extends Component {
{ {
!isFetching && !!error && !isFetching && !!error &&
<div>Unable to load history.</div> <div>
{translate('UnableToLoadHistory')}
</div>
} }
{ {
isPopulated && !hasItems && !error && isPopulated && !hasItems && !error &&
<div>No history.</div> <div>
{translate('NoHistory')}
</div>
} }
{ {

@ -11,6 +11,7 @@ import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRow from 'Components/Table/TableRow'; import TableRow from 'Components/Table/TableRow';
import Popover from 'Components/Tooltip/Popover'; import Popover from 'Components/Tooltip/Popover';
import { icons, kinds, tooltipPositions } from 'Helpers/Props'; import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './ArtistHistoryRow.css'; import styles from './ArtistHistoryRow.css';
function getTitle(eventType) { function getTitle(eventType) {
@ -132,7 +133,7 @@ class ArtistHistoryRow extends Component {
{ {
eventType === 'grabbed' && eventType === 'grabbed' &&
<IconButton <IconButton
title="Mark as failed" title={translate('MarkAsFailed')}
name={icons.REMOVE} name={icons.REMOVE}
onPress={this.onMarkAsFailedPress} onPress={this.onMarkAsFailedPress}
/> />
@ -142,9 +143,9 @@ class ArtistHistoryRow extends Component {
<ConfirmModal <ConfirmModal
isOpen={isMarkAsFailedModalOpen} isOpen={isMarkAsFailedModalOpen}
kind={kinds.DANGER} kind={kinds.DANGER}
title="Mark as Failed" title={translate('MarkAsFailed')}
message={`Are you sure you want to mark '${sourceTitle}' as failed?`} message={translate('MarkAsFailedMessageText', [sourceTitle])}
confirmLabel="Mark as Failed" confirmLabel={translate('MarkAsFailed')}
onConfirm={this.onConfirmMarkAsFailed} onConfirm={this.onConfirmMarkAsFailed}
onCancel={this.onMarkAsFailedModalClose} onCancel={this.onMarkAsFailedModalClose}
/> />

@ -14,6 +14,7 @@ import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptions
import { align, icons, sortDirections } from 'Helpers/Props'; import { align, icons, sortDirections } from 'Helpers/Props';
import getErrorMessage from 'Utilities/Object/getErrorMessage'; import getErrorMessage from 'Utilities/Object/getErrorMessage';
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder'; import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
import translate from 'Utilities/String/translate';
import ArtistIndexFooterConnector from './ArtistIndexFooterConnector'; import ArtistIndexFooterConnector from './ArtistIndexFooterConnector';
import ArtistIndexBannersConnector from './Banners/ArtistIndexBannersConnector'; import ArtistIndexBannersConnector from './Banners/ArtistIndexBannersConnector';
import ArtistIndexBannerOptionsModal from './Banners/Options/ArtistIndexBannerOptionsModal'; import ArtistIndexBannerOptionsModal from './Banners/Options/ArtistIndexBannerOptionsModal';
@ -213,7 +214,7 @@ class ArtistIndex extends Component {
<PageToolbar> <PageToolbar>
<PageToolbarSection> <PageToolbarSection>
<PageToolbarButton <PageToolbarButton
label="Update all" label={translate('UpdateAll')}
iconName={icons.REFRESH} iconName={icons.REFRESH}
spinningName={icons.REFRESH} spinningName={icons.REFRESH}
isSpinning={isRefreshingArtist} isSpinning={isRefreshingArtist}
@ -221,7 +222,7 @@ class ArtistIndex extends Component {
/> />
<PageToolbarButton <PageToolbarButton
label="RSS Sync" label={translate('RSSSync')}
iconName={icons.RSS} iconName={icons.RSS}
isSpinning={isRssSyncExecuting} isSpinning={isRssSyncExecuting}
isDisabled={hasNoArtist} isDisabled={hasNoArtist}
@ -242,7 +243,7 @@ class ArtistIndex extends Component {
optionsComponent={ArtistIndexTableOptionsConnector} optionsComponent={ArtistIndexTableOptionsConnector}
> >
<PageToolbarButton <PageToolbarButton
label="Options" label={translate('Options')}
iconName={icons.TABLE} iconName={icons.TABLE}
/> />
</TableOptionsModalWrapper> : </TableOptionsModalWrapper> :
@ -252,7 +253,7 @@ class ArtistIndex extends Component {
{ {
view === 'posters' ? view === 'posters' ?
<PageToolbarButton <PageToolbarButton
label="Options" label={translate('Options')}
iconName={icons.POSTER} iconName={icons.POSTER}
isDisabled={hasNoArtist} isDisabled={hasNoArtist}
onPress={this.onPosterOptionsPress} onPress={this.onPosterOptionsPress}
@ -263,7 +264,7 @@ class ArtistIndex extends Component {
{ {
view === 'banners' ? view === 'banners' ?
<PageToolbarButton <PageToolbarButton
label="Options" label={translate('Options')}
iconName={icons.POSTER} iconName={icons.POSTER}
isDisabled={hasNoArtist} isDisabled={hasNoArtist}
onPress={this.onBannerOptionsPress} onPress={this.onBannerOptionsPress}
@ -274,7 +275,7 @@ class ArtistIndex extends Component {
{ {
view === 'overview' ? view === 'overview' ?
<PageToolbarButton <PageToolbarButton
label="Options" label={translate('Options')}
iconName={icons.OVERVIEW} iconName={icons.OVERVIEW}
isDisabled={hasNoArtist} isDisabled={hasNoArtist}
onPress={this.onOverviewOptionsPress} onPress={this.onOverviewOptionsPress}

@ -5,6 +5,7 @@ import { ColorImpairedConsumer } from 'App/ColorImpairedContext';
import DescriptionList from 'Components/DescriptionList/DescriptionList'; import DescriptionList from 'Components/DescriptionList/DescriptionList';
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem'; import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
import translate from 'Utilities/String/translate';
import styles from './ArtistIndexFooter.css'; import styles from './ArtistIndexFooter.css';
class ArtistIndexFooter extends PureComponent { class ArtistIndexFooter extends PureComponent {
@ -60,7 +61,9 @@ class ArtistIndexFooter extends PureComponent {
enableColorImpairedMode && 'colorImpaired' enableColorImpairedMode && 'colorImpaired'
)} )}
/> />
<div>Continuing (All tracks downloaded)</div> <div>
{translate('ContinuingAllTracksDownloaded')}
</div>
</div> </div>
<div className={styles.legendItem}> <div className={styles.legendItem}>
@ -70,7 +73,9 @@ class ArtistIndexFooter extends PureComponent {
enableColorImpairedMode && 'colorImpaired' enableColorImpairedMode && 'colorImpaired'
)} )}
/> />
<div>Ended (All tracks downloaded)</div> <div>
{translate('EndedAllTracksDownloaded')}
</div>
</div> </div>
<div className={styles.legendItem}> <div className={styles.legendItem}>
@ -80,7 +85,9 @@ class ArtistIndexFooter extends PureComponent {
enableColorImpairedMode && 'colorImpaired' enableColorImpairedMode && 'colorImpaired'
)} )}
/> />
<div>Missing Tracks (Artist monitored)</div> <div>
{translate('MissingTracksArtistMonitored')}
</div>
</div> </div>
<div className={styles.legendItem}> <div className={styles.legendItem}>
@ -90,55 +97,57 @@ class ArtistIndexFooter extends PureComponent {
enableColorImpairedMode && 'colorImpaired' enableColorImpairedMode && 'colorImpaired'
)} )}
/> />
<div>Missing Tracks (Artist not monitored)</div> <div>
{translate('MissingTracksArtistNotMonitored')}
</div>
</div> </div>
</div> </div>
<div className={styles.statistics}> <div className={styles.statistics}>
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
title="Artist" title={translate('Artist')}
data={count} data={count}
/> />
<DescriptionListItem <DescriptionListItem
title="Ended" title={translate('Ended')}
data={ended} data={ended}
/> />
<DescriptionListItem <DescriptionListItem
title="Continuing" title={translate('Continuing')}
data={continuing} data={continuing}
/> />
</DescriptionList> </DescriptionList>
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
title="Monitored" title={translate('Monitored')}
data={monitored} data={monitored}
/> />
<DescriptionListItem <DescriptionListItem
title="Unmonitored" title={translate('Unmonitored')}
data={count - monitored} data={count - monitored}
/> />
</DescriptionList> </DescriptionList>
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
title="Tracks" title={translate('Tracks')}
data={tracks} data={tracks}
/> />
<DescriptionListItem <DescriptionListItem
title="Files" title={translate('Files')}
data={trackFiles} data={trackFiles}
/> />
</DescriptionList> </DescriptionList>
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
title="Total File Size" title={translate('TotalFileSize')}
data={formatBytes(totalFileSize)} data={formatBytes(totalFileSize)}
/> />
</DescriptionList> </DescriptionList>

@ -10,6 +10,7 @@ import Link from 'Components/Link/Link';
import SpinnerIconButton from 'Components/Link/SpinnerIconButton'; import SpinnerIconButton from 'Components/Link/SpinnerIconButton';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import getRelativeDate from 'Utilities/Date/getRelativeDate'; import getRelativeDate from 'Utilities/Date/getRelativeDate';
import translate from 'Utilities/String/translate';
import ArtistIndexBannerInfo from './ArtistIndexBannerInfo'; import ArtistIndexBannerInfo from './ArtistIndexBannerInfo';
import styles from './ArtistIndexBanner.css'; import styles from './ArtistIndexBanner.css';
@ -108,7 +109,7 @@ class ArtistIndexBanner extends Component {
<SpinnerIconButton <SpinnerIconButton
className={styles.action} className={styles.action}
name={icons.REFRESH} name={icons.REFRESH}
title="Refresh Artist" title={translate('RefreshArtist')}
isSpinning={isRefreshingArtist} isSpinning={isRefreshingArtist}
onPress={onRefreshArtistPress} onPress={onRefreshArtistPress}
/> />
@ -118,7 +119,7 @@ class ArtistIndexBanner extends Component {
<SpinnerIconButton <SpinnerIconButton
className={styles.action} className={styles.action}
name={icons.SEARCH} name={icons.SEARCH}
title="Search for monitored albums" title={translate('SearchForMonitoredAlbums')}
isSpinning={isSearchingArtist} isSpinning={isSearchingArtist}
onPress={onSearchPress} onPress={onSearchPress}
/> />
@ -127,7 +128,7 @@ class ArtistIndexBanner extends Component {
<IconButton <IconButton
className={styles.action} className={styles.action}
name={icons.EDIT} name={icons.EDIT}
title="Edit Artist" title={translate('EditArtist')}
onPress={this.onEditArtistPress} onPress={this.onEditArtistPress}
/> />
</Label> </Label>
@ -136,7 +137,7 @@ class ArtistIndexBanner extends Component {
status === 'ended' && status === 'ended' &&
<div <div
className={styles.ended} 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 ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes } from 'Helpers/Props'; import { inputTypes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
const bannerSizeOptions = [ const bannerSizeOptions = [
{ key: 'small', value: 'Small' }, { key: 'small', value: 'Small' },
@ -114,7 +115,9 @@ class ArtistIndexBannerOptionsModalContent extends Component {
<ModalBody> <ModalBody>
<Form> <Form>
<FormGroup> <FormGroup>
<FormLabel> Size</FormLabel> <FormLabel>
{translate('Size')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.SELECT} type={inputTypes.SELECT}
@ -126,61 +129,71 @@ class ArtistIndexBannerOptionsModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Detailed Progress Bar</FormLabel> <FormLabel>
{translate('DetailedProgressBar')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="detailedProgressBar" name="detailedProgressBar"
value={detailedProgressBar} value={detailedProgressBar}
helpText="Show text on progess bar" helpText={translate('DetailedProgressBarHelpText')}
onChange={this.onChangeBannerOption} onChange={this.onChangeBannerOption}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Show Name</FormLabel> <FormLabel>
{translate('ShowName')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="showTitle" name="showTitle"
value={showTitle} value={showTitle}
helpText="Show artist name under banner" helpText={translate('ShowTitleHelpText')}
onChange={this.onChangeBannerOption} onChange={this.onChangeBannerOption}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Show Monitored</FormLabel> <FormLabel>
{translate('ShowMonitored')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="showMonitored" name="showMonitored"
value={showMonitored} value={showMonitored}
helpText="Show monitored status under banner" helpText={translate('ShowMonitoredHelpText')}
onChange={this.onChangeBannerOption} onChange={this.onChangeBannerOption}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Show Quality Profile</FormLabel> <FormLabel>
{translate('ShowQualityProfile')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="showQualityProfile" name="showQualityProfile"
value={showQualityProfile} value={showQualityProfile}
helpText="Show quality profile under banner" helpText={translate('ShowQualityProfileHelpText')}
onChange={this.onChangeBannerOption} onChange={this.onChangeBannerOption}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Show Search</FormLabel> <FormLabel>
{translate('ShowSearch')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="showSearchAction" name="showSearchAction"
value={showSearchAction} value={showSearchAction}
helpText="Show search button on hover" helpText={translate('ShowSearchActionHelpText')}
onChange={this.onChangeBannerOption} onChange={this.onChangeBannerOption}
/> />
</FormGroup> </FormGroup>

@ -11,6 +11,7 @@ import SpinnerIconButton from 'Components/Link/SpinnerIconButton';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import dimensions from 'Styles/Variables/dimensions'; import dimensions from 'Styles/Variables/dimensions';
import fonts from 'Styles/Variables/fonts'; import fonts from 'Styles/Variables/fonts';
import translate from 'Utilities/String/translate';
import ArtistIndexOverviewInfo from './ArtistIndexOverviewInfo'; import ArtistIndexOverviewInfo from './ArtistIndexOverviewInfo';
import styles from './ArtistIndexOverview.css'; import styles from './ArtistIndexOverview.css';
@ -129,7 +130,7 @@ class ArtistIndexOverview extends Component {
status === 'ended' && status === 'ended' &&
<div <div
className={styles.ended} className={styles.ended}
title="Ended" title={translate('Ended')}
/> />
} }
@ -172,7 +173,7 @@ class ArtistIndexOverview extends Component {
<div className={styles.actions}> <div className={styles.actions}>
<SpinnerIconButton <SpinnerIconButton
name={icons.REFRESH} name={icons.REFRESH}
title="Refresh Artist" title={translate('RefreshArtist')}
isSpinning={isRefreshingArtist} isSpinning={isRefreshingArtist}
onPress={onRefreshArtistPress} onPress={onRefreshArtistPress}
/> />
@ -182,7 +183,7 @@ class ArtistIndexOverview extends Component {
<SpinnerIconButton <SpinnerIconButton
className={styles.action} className={styles.action}
name={icons.SEARCH} name={icons.SEARCH}
title="Search for monitored albums" title={translate('SearchForMonitoredAlbums')}
isSpinning={isSearchingArtist} isSpinning={isSearchingArtist}
onPress={onSearchPress} onPress={onSearchPress}
/> />
@ -190,7 +191,7 @@ class ArtistIndexOverview extends Component {
<IconButton <IconButton
name={icons.EDIT} name={icons.EDIT}
title="Edit Artist" title={translate('EditArtist')}
onPress={this.onEditArtistPress} onPress={this.onEditArtistPress}
/> />
</div> </div>

@ -11,6 +11,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter'; import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes } from 'Helpers/Props'; import { inputTypes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
const posterSizeOptions = [ const posterSizeOptions = [
{ key: 'small', value: 'Small' }, { key: 'small', value: 'Small' },
@ -142,7 +143,9 @@ class ArtistIndexOverviewOptionsModalContent extends Component {
<ModalBody> <ModalBody>
<Form> <Form>
<FormGroup> <FormGroup>
<FormLabel>Poster Size</FormLabel> <FormLabel>
{translate('PosterSize')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.SELECT} type={inputTypes.SELECT}
@ -154,19 +157,23 @@ class ArtistIndexOverviewOptionsModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Detailed Progress Bar</FormLabel> <FormLabel>
{translate('DetailedProgressBar')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="detailedProgressBar" name="detailedProgressBar"
value={detailedProgressBar} value={detailedProgressBar}
helpText="Show text on progess bar" helpText={translate('DetailedProgressBarHelpText')}
onChange={this.onChangeOverviewOption} onChange={this.onChangeOverviewOption}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Show Monitored</FormLabel> <FormLabel>
{translate('ShowMonitored')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
@ -178,7 +185,9 @@ class ArtistIndexOverviewOptionsModalContent extends Component {
<FormGroup> <FormGroup>
<FormLabel>Show Quality Profile</FormLabel> <FormLabel>
{translate('ShowQualityProfile')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
@ -189,7 +198,9 @@ class ArtistIndexOverviewOptionsModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Show Last Album</FormLabel> <FormLabel>
{translate('ShowLastAlbum')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
@ -200,7 +211,9 @@ class ArtistIndexOverviewOptionsModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Show Date Added</FormLabel> <FormLabel>
{translate('ShowDateAdded')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
@ -211,7 +224,9 @@ class ArtistIndexOverviewOptionsModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Show Album Count</FormLabel> <FormLabel>
{translate('ShowAlbumCount')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
@ -222,7 +237,9 @@ class ArtistIndexOverviewOptionsModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Show Path</FormLabel> <FormLabel>
{translate('ShowPath')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
@ -233,7 +250,9 @@ class ArtistIndexOverviewOptionsModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Show Size on Disk</FormLabel> <FormLabel>
{translate('ShowSizeOnDisk')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
@ -244,13 +263,15 @@ class ArtistIndexOverviewOptionsModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Show Search</FormLabel> <FormLabel>
{translate('ShowSearch')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="showSearchAction" name="showSearchAction"
value={showSearchAction} value={showSearchAction}
helpText="Show search button" helpText={translate('ShowSearchActionHelpText')}
onChange={this.onChangeOverviewOption} onChange={this.onChangeOverviewOption}
/> />
</FormGroup> </FormGroup>

@ -10,6 +10,7 @@ import Link from 'Components/Link/Link';
import SpinnerIconButton from 'Components/Link/SpinnerIconButton'; import SpinnerIconButton from 'Components/Link/SpinnerIconButton';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import getRelativeDate from 'Utilities/Date/getRelativeDate'; import getRelativeDate from 'Utilities/Date/getRelativeDate';
import translate from 'Utilities/String/translate';
import ArtistIndexPosterInfo from './ArtistIndexPosterInfo'; import ArtistIndexPosterInfo from './ArtistIndexPosterInfo';
import styles from './ArtistIndexPoster.css'; import styles from './ArtistIndexPoster.css';
@ -122,7 +123,7 @@ class ArtistIndexPoster extends Component {
<SpinnerIconButton <SpinnerIconButton
className={styles.action} className={styles.action}
name={icons.REFRESH} name={icons.REFRESH}
title="Refresh Artist" title={translate('RefreshArtist')}
isSpinning={isRefreshingArtist} isSpinning={isRefreshingArtist}
onPress={onRefreshArtistPress} onPress={onRefreshArtistPress}
/> />
@ -132,7 +133,7 @@ class ArtistIndexPoster extends Component {
<SpinnerIconButton <SpinnerIconButton
className={styles.action} className={styles.action}
name={icons.SEARCH} name={icons.SEARCH}
title="Search for monitored albums" title={translate('SearchForMonitoredAlbums')}
isSpinning={isSearchingArtist} isSpinning={isSearchingArtist}
onPress={onSearchPress} onPress={onSearchPress}
/> />
@ -141,7 +142,7 @@ class ArtistIndexPoster extends Component {
<IconButton <IconButton
className={styles.action} className={styles.action}
name={icons.EDIT} name={icons.EDIT}
title="Edit Artist" title={translate('EditArtist')}
onPress={this.onEditArtistPress} onPress={this.onEditArtistPress}
/> />
</Label> </Label>
@ -150,7 +151,7 @@ class ArtistIndexPoster extends Component {
status === 'ended' && status === 'ended' &&
<div <div
className={styles.ended} 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 ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes } from 'Helpers/Props'; import { inputTypes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
const posterSizeOptions = [ const posterSizeOptions = [
{ key: 'small', value: 'Small' }, { key: 'small', value: 'Small' },
@ -114,7 +115,9 @@ class ArtistIndexPosterOptionsModalContent extends Component {
<ModalBody> <ModalBody>
<Form> <Form>
<FormGroup> <FormGroup>
<FormLabel>Poster Size</FormLabel> <FormLabel>
{translate('PosterSize')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.SELECT} type={inputTypes.SELECT}
@ -126,61 +129,71 @@ class ArtistIndexPosterOptionsModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Detailed Progress Bar</FormLabel> <FormLabel>
{translate('DetailedProgressBar')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="detailedProgressBar" name="detailedProgressBar"
value={detailedProgressBar} value={detailedProgressBar}
helpText="Show text on progess bar" helpText={translate('DetailedProgressBarHelpText')}
onChange={this.onChangePosterOption} onChange={this.onChangePosterOption}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Show Name</FormLabel> <FormLabel>
{translate('ShowName')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="showTitle" name="showTitle"
value={showTitle} value={showTitle}
helpText="Show artist name under poster" helpText={translate('ShowTitleHelpText')}
onChange={this.onChangePosterOption} onChange={this.onChangePosterOption}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Show Monitored</FormLabel> <FormLabel>
{translate('ShowMonitored')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="showMonitored" name="showMonitored"
value={showMonitored} value={showMonitored}
helpText="Show monitored status under poster" helpText={translate('ShowMonitoredHelpText')}
onChange={this.onChangePosterOption} onChange={this.onChangePosterOption}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Show Quality Profile</FormLabel> <FormLabel>
{translate('ShowQualityProfile')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="showQualityProfile" name="showQualityProfile"
value={showQualityProfile} value={showQualityProfile}
helpText="Show quality profile under poster" helpText={translate('ShowQualityProfileHelpText')}
onChange={this.onChangePosterOption} onChange={this.onChangePosterOption}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Show Search</FormLabel> <FormLabel>
{translate('ShowSearch')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="showSearchAction" name="showSearchAction"
value={showSearchAction} value={showSearchAction}
helpText="Show search button on hover" helpText={translate('ShowSearchActionHelpText')}
onChange={this.onChangePosterOption} onChange={this.onChangePosterOption}
/> />
</FormGroup> </FormGroup>

@ -3,6 +3,7 @@ import React from 'react';
import ProgressBar from 'Components/ProgressBar'; import ProgressBar from 'Components/ProgressBar';
import { sizes } from 'Helpers/Props'; import { sizes } from 'Helpers/Props';
import getProgressBarKind from 'Utilities/Artist/getProgressBarKind'; import getProgressBarKind from 'Utilities/Artist/getProgressBarKind';
import translate from 'Utilities/String/translate';
import styles from './ArtistIndexProgressBar.css'; import styles from './ArtistIndexProgressBar.css';
function ArtistIndexProgressBar(props) { function ArtistIndexProgressBar(props) {
@ -28,7 +29,7 @@ function ArtistIndexProgressBar(props) {
size={detailedProgressBar ? sizes.MEDIUM : sizes.SMALL} size={detailedProgressBar ? sizes.MEDIUM : sizes.SMALL}
showText={detailedProgressBar} showText={detailedProgressBar}
text={text} text={text}
title={`${trackFileCount} / ${trackCount} (Total: ${totalTrackCount})`} title={translate('TrackFileCountTrackCountTotalTotalTrackCountInterp', [trackFileCount, trackCount, totalTrackCount])}
width={posterWidth} width={posterWidth}
/> />
); );

@ -6,6 +6,7 @@ import IconButton from 'Components/Link/IconButton';
import SpinnerIconButton from 'Components/Link/SpinnerIconButton'; import SpinnerIconButton from 'Components/Link/SpinnerIconButton';
import VirtualTableRowCell from 'Components/Table/Cells/VirtualTableRowCell'; import VirtualTableRowCell from 'Components/Table/Cells/VirtualTableRowCell';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
class ArtistIndexActionsCell extends Component { class ArtistIndexActionsCell extends Component {
@ -65,14 +66,14 @@ class ArtistIndexActionsCell extends Component {
> >
<SpinnerIconButton <SpinnerIconButton
name={icons.REFRESH} name={icons.REFRESH}
title="Refresh Artist" title={translate('RefreshArtist')}
isSpinning={isRefreshingArtist} isSpinning={isRefreshingArtist}
onPress={onRefreshArtistPress} onPress={onRefreshArtistPress}
/> />
<IconButton <IconButton
name={icons.EDIT} name={icons.EDIT}
title="Edit Artist" title={translate('EditArtist')}
onPress={this.onEditArtistPress} onPress={this.onEditArtistPress}
/> />

@ -17,6 +17,7 @@ import TagListConnector from 'Components/TagListConnector';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import getProgressBarKind from 'Utilities/Artist/getProgressBarKind'; import getProgressBarKind from 'Utilities/Artist/getProgressBarKind';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
import translate from 'Utilities/String/translate';
import ArtistStatusCell from './ArtistStatusCell'; import ArtistStatusCell from './ArtistStatusCell';
import hasGrowableColumns from './hasGrowableColumns'; import hasGrowableColumns from './hasGrowableColumns';
import styles from './ArtistIndexRow.css'; import styles from './ArtistIndexRow.css';
@ -307,7 +308,7 @@ class ArtistIndexRow extends Component {
kind={getProgressBarKind(status, monitored, progress)} kind={getProgressBarKind(status, monitored, progress)}
showText={true} showText={true}
text={`${trackFileCount} / ${trackCount}`} text={`${trackFileCount} / ${trackCount}`}
title={`${trackFileCount} / ${trackCount} (Total: ${totalTrackCount})`} title={translate('TrackFileCountTrackCountTotalTotalTrackCountInterp', [trackFileCount, trackCount, totalTrackCount])}
width={125} width={125}
/> />
</VirtualTableRowCell> </VirtualTableRowCell>
@ -396,7 +397,7 @@ class ArtistIndexRow extends Component {
> >
<SpinnerIconButton <SpinnerIconButton
name={icons.REFRESH} name={icons.REFRESH}
title="Refresh Artist" title={translate('RefreshArtist')}
isSpinning={isRefreshingArtist} isSpinning={isRefreshingArtist}
onPress={onRefreshArtistPress} onPress={onRefreshArtistPress}
/> />
@ -406,7 +407,7 @@ class ArtistIndexRow extends Component {
<SpinnerIconButton <SpinnerIconButton
className={styles.action} className={styles.action}
name={icons.SEARCH} name={icons.SEARCH}
title="Search for monitored albums" title={translate('SearchForMonitoredAlbums')}
isSpinning={isSearchingArtist} isSpinning={isSearchingArtist}
onPress={onSearchPress} onPress={onSearchPress}
/> />
@ -414,7 +415,7 @@ class ArtistIndexRow extends Component {
<IconButton <IconButton
name={icons.EDIT} name={icons.EDIT}
title="Edit Artist" title={translate('EditArtist')}
onPress={this.onEditArtistPress} onPress={this.onEditArtistPress}
/> />
</VirtualTableRowCell> </VirtualTableRowCell>

@ -4,6 +4,7 @@ import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup'; import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel'; import FormLabel from 'Components/Form/FormLabel';
import { inputTypes } from 'Helpers/Props'; import { inputTypes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
class ArtistIndexTableOptions extends Component { class ArtistIndexTableOptions extends Component {
@ -64,25 +65,29 @@ class ArtistIndexTableOptions extends Component {
return ( return (
<Fragment> <Fragment>
<FormGroup> <FormGroup>
<FormLabel>Show Banners</FormLabel> <FormLabel>
{translate('ShowBanners')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="showBanners" name="showBanners"
value={showBanners} value={showBanners}
helpText="Show banners instead of names" helpText={translate('ShowBannersHelpText')}
onChange={this.onTableOptionChange} onChange={this.onTableOptionChange}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Show Search</FormLabel> <FormLabel>
{translate('ShowSearch')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="showSearchAction" name="showSearchAction"
value={showSearchAction} value={showSearchAction}
helpText="Show search button on hover" helpText={translate('ShowSearchActionHelpText')}
onChange={this.onTableOptionChange} onChange={this.onTableOptionChange}
/> />
</FormGroup> </FormGroup>

@ -4,6 +4,7 @@ import Icon from 'Components/Icon';
import MonitorToggleButton from 'Components/MonitorToggleButton'; import MonitorToggleButton from 'Components/MonitorToggleButton';
import VirtualTableRowCell from 'Components/Table/Cells/TableRowCell'; import VirtualTableRowCell from 'Components/Table/Cells/TableRowCell';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './ArtistStatusCell.css'; import styles from './ArtistStatusCell.css';
function ArtistStatusCell(props) { function ArtistStatusCell(props) {
@ -36,7 +37,7 @@ function ArtistStatusCell(props) {
<Icon <Icon
className={styles.statusIcon} className={styles.statusIcon}
name={status === 'ended' ? icons.ARTIST_ENDED : icons.ARTIST_CONTINUING} name={status === 'ended' ? icons.ARTIST_ENDED : icons.ARTIST_CONTINUING}
title={status === 'ended' ? endedString : 'Continuing'} title={status === 'ended' ? endedString : translate('StatusEndedContinuing')}
/> />
</Component> </Component>
); );

@ -8,6 +8,7 @@ import Icon from 'Components/Icon';
import Link from 'Components/Link/Link'; import Link from 'Components/Link/Link';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import formatTime from 'Utilities/Date/formatTime'; import formatTime from 'Utilities/Date/formatTime';
import translate from 'Utilities/String/translate';
import styles from './AgendaEvent.css'; import styles from './AgendaEvent.css';
class AgendaEvent extends Component { class AgendaEvent extends Component {
@ -110,7 +111,7 @@ class AgendaEvent extends Component {
!queueItem && grabbed && !queueItem && grabbed &&
<Icon <Icon
name={icons.DOWNLOADING} name={icons.DOWNLOADING}
title="Album is downloading" title={translate('AlbumIsDownloading')}
/> />
} }
</Link> </Link>

@ -1,6 +1,7 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React, { Component } from 'react'; import React, { Component } from 'react';
import LoadingIndicator from 'Components/Loading/LoadingIndicator'; import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import translate from 'Utilities/String/translate';
import AgendaConnector from './Agenda/AgendaConnector'; import AgendaConnector from './Agenda/AgendaConnector';
import * as calendarViews from './calendarViews'; import * as calendarViews from './calendarViews';
import CalendarDaysConnector from './Day/CalendarDaysConnector'; import CalendarDaysConnector from './Day/CalendarDaysConnector';
@ -30,7 +31,9 @@ class Calendar extends Component {
{ {
!isFetching && !!error && !isFetching && !!error &&
<div>Unable to load the calendar</div> <div>
{translate('UnableToLoadTheCalendar')}
</div>
} }
{ {

@ -12,6 +12,7 @@ import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator'; import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import { align, icons } from 'Helpers/Props'; import { align, icons } from 'Helpers/Props';
import getErrorMessage from 'Utilities/Object/getErrorMessage'; import getErrorMessage from 'Utilities/Object/getErrorMessage';
import translate from 'Utilities/String/translate';
import CalendarConnector from './CalendarConnector'; import CalendarConnector from './CalendarConnector';
import CalendarLinkModal from './iCal/CalendarLinkModal'; import CalendarLinkModal from './iCal/CalendarLinkModal';
import LegendConnector from './Legend/LegendConnector'; import LegendConnector from './Legend/LegendConnector';
@ -97,11 +98,11 @@ class CalendarPage extends Component {
const isMeasured = this.state.width > 0; const isMeasured = this.state.width > 0;
return ( return (
<PageContent title="Calendar"> <PageContent title={translate('Calendar')}>
<PageToolbar> <PageToolbar>
<PageToolbarSection> <PageToolbarSection>
<PageToolbarButton <PageToolbarButton
label="iCal Link" label={translate('ICalLink')}
iconName={icons.CALENDAR} iconName={icons.CALENDAR}
onPress={this.onGetCalendarLinkPress} onPress={this.onGetCalendarLinkPress}
/> />
@ -109,14 +110,14 @@ class CalendarPage extends Component {
<PageToolbarSeparator /> <PageToolbarSeparator />
<PageToolbarButton <PageToolbarButton
label="RSS Sync" label={translate('RSSSync')}
iconName={icons.RSS} iconName={icons.RSS}
isSpinning={isRssSyncExecuting} isSpinning={isRssSyncExecuting}
onPress={onRssSyncPress} onPress={onRssSyncPress}
/> />
<PageToolbarButton <PageToolbarButton
label="Search for Missing" label={translate('SearchForMissing')}
iconName={icons.SEARCH} iconName={icons.SEARCH}
isDisabled={!missingAlbumIds.length} isDisabled={!missingAlbumIds.length}
isSpinning={isSearchingForMissing} isSpinning={isSearchingForMissing}
@ -126,7 +127,7 @@ class CalendarPage extends Component {
<PageToolbarSection alignContent={align.RIGHT}> <PageToolbarSection alignContent={align.RIGHT}>
<PageToolbarButton <PageToolbarButton
label="Options" label={translate('Options')}
iconName={icons.POSTER} iconName={icons.POSTER}
onPress={this.onOptionsPress} onPress={this.onOptionsPress}
/> />

@ -6,6 +6,7 @@ import getStatusStyle from 'Calendar/getStatusStyle';
import Icon from 'Components/Icon'; import Icon from 'Components/Icon';
import Link from 'Components/Link/Link'; import Link from 'Components/Link/Link';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import CalendarEventQueueDetails from './CalendarEventQueueDetails'; import CalendarEventQueueDetails from './CalendarEventQueueDetails';
import styles from './CalendarEvent.css'; import styles from './CalendarEvent.css';
@ -97,7 +98,7 @@ class CalendarEvent extends Component {
<Icon <Icon
className={styles.statusIcon} className={styles.statusIcon}
name={icons.DOWNLOADING} name={icons.DOWNLOADING}
title="Album is downloading" title={translate('AlbumIsDownloading')}
/> />
} }
</div> </div>

@ -3,6 +3,7 @@ import React from 'react';
import QueueDetails from 'Activity/Queue/QueueDetails'; import QueueDetails from 'Activity/Queue/QueueDetails';
import CircularProgressBar from 'Components/CircularProgressBar'; import CircularProgressBar from 'Components/CircularProgressBar';
import colors from 'Styles/Variables/colors'; import colors from 'Styles/Variables/colors';
import translate from 'Utilities/String/translate';
function CalendarEventQueueDetails(props) { function CalendarEventQueueDetails(props) {
const { const {
@ -25,7 +26,7 @@ function CalendarEventQueueDetails(props) {
status={status} status={status}
errorMessage={errorMessage} errorMessage={errorMessage}
progressBar={ progressBar={
<div title={`Album is downloading - ${progress.toFixed(1)}% ${title}`}> <div title={translate('AlbumIsDownloadingInterp', [progress.toFixed(1), title])}>
<CircularProgressBar <CircularProgressBar
progress={progress} progress={progress}
size={20} size={20}

@ -12,6 +12,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes } from 'Helpers/Props'; import { inputTypes } from 'Helpers/Props';
import { firstDayOfWeekOptions, timeFormatOptions, weekColumnOptions } from 'Settings/UI/UISettings'; import { firstDayOfWeekOptions, timeFormatOptions, weekColumnOptions } from 'Settings/UI/UISettings';
import translate from 'Utilities/String/translate';
class CalendarOptionsModalContent extends Component { class CalendarOptionsModalContent extends Component {
@ -110,38 +111,44 @@ class CalendarOptionsModalContent extends Component {
</ModalHeader> </ModalHeader>
<ModalBody> <ModalBody>
<FieldSet legend="Local"> <FieldSet legend={translate('Local')}>
<Form> <Form>
<FormGroup> <FormGroup>
<FormLabel>Collapse Multiple Albums</FormLabel> <FormLabel>
{translate('CollapseMultipleAlbums')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="collapseMultipleAlbums" name="collapseMultipleAlbums"
value={collapseMultipleAlbums} value={collapseMultipleAlbums}
helpText="Collapse multiple albums releasing on the same day" helpText={translate('CollapseMultipleAlbumsHelpText')}
onChange={this.onOptionInputChange} onChange={this.onOptionInputChange}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Icon for Cutoff Unmet</FormLabel> <FormLabel>
{translate('IconForCutoffUnmet')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="showCutoffUnmetIcon" name="showCutoffUnmetIcon"
value={showCutoffUnmetIcon} value={showCutoffUnmetIcon}
helpText="Show icon for files when the cutoff hasn't been met" helpText={translate('ShowCutoffUnmetIconHelpText')}
onChange={this.onOptionInputChange} onChange={this.onOptionInputChange}
/> />
</FormGroup> </FormGroup>
</Form> </Form>
</FieldSet> </FieldSet>
<FieldSet legend="Global"> <FieldSet legend={translate('Global')}>
<Form> <Form>
<FormGroup> <FormGroup>
<FormLabel>First Day of Week</FormLabel> <FormLabel>
{translate('FirstDayOfWeek')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.SELECT} type={inputTypes.SELECT}
@ -153,7 +160,9 @@ class CalendarOptionsModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Week Column Header</FormLabel> <FormLabel>
{translate('WeekColumnHeader')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.SELECT} type={inputTypes.SELECT}
@ -161,12 +170,14 @@ class CalendarOptionsModalContent extends Component {
values={weekColumnOptions} values={weekColumnOptions}
value={calendarWeekColumnHeader} value={calendarWeekColumnHeader}
onChange={this.onGlobalInputChange} onChange={this.onGlobalInputChange}
helpText="Shown above each column when week is the active view" helpText={translate('ShownAboveEachColumnWhenWeekIsTheActiveView')}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Time Format</FormLabel> <FormLabel>
{translate('TimeFormat')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.SELECT} type={inputTypes.SELECT}
@ -176,13 +187,15 @@ class CalendarOptionsModalContent extends Component {
onChange={this.onGlobalInputChange} onChange={this.onGlobalInputChange}
/> />
</FormGroup><FormGroup> </FormGroup><FormGroup>
<FormLabel>Enable Color-Impaired Mode</FormLabel> <FormLabel>
{translate('EnableColorImpairedMode')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="enableColorImpairedMode" name="enableColorImpairedMode"
value={enableColorImpairedMode} value={enableColorImpairedMode}
helpText="Altered style to allow color-impaired users to better distinguish color coded information" helpText={translate('EnableColorImpairedModeHelpText')}
onChange={this.onGlobalInputChange} onChange={this.onGlobalInputChange}
/> />
</FormGroup> </FormGroup>

@ -13,6 +13,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter'; import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { icons, inputTypes, kinds, sizes } from 'Helpers/Props'; import { icons, inputTypes, kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
function getUrls(state) { function getUrls(state) {
const { const {
@ -113,49 +114,57 @@ class CalendarLinkModalContent extends Component {
<ModalBody> <ModalBody>
<Form> <Form>
<FormGroup> <FormGroup>
<FormLabel>Include Unmonitored</FormLabel> <FormLabel>
{translate('IncludeUnmonitored')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="unmonitored" name="unmonitored"
value={unmonitored} value={unmonitored}
helpText="Include unmonitored albums in the iCal feed" helpText={translate('UnmonitoredHelpText')}
onChange={this.onInputChange} onChange={this.onInputChange}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Past Days</FormLabel> <FormLabel>
{translate('PastDays')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.NUMBER} type={inputTypes.NUMBER}
name="pastDays" name="pastDays"
value={pastDays} value={pastDays}
helpText="Days for iCal feed to look into the past" helpText={translate('PastDaysHelpText')}
onChange={this.onInputChange} onChange={this.onInputChange}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Future Days</FormLabel> <FormLabel>
{translate('FutureDays')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.NUMBER} type={inputTypes.NUMBER}
name="futureDays" name="futureDays"
value={futureDays} value={futureDays}
helpText="Days for iCal feed to look into the future" helpText={translate('FutureDaysHelpText')}
onChange={this.onInputChange} onChange={this.onInputChange}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Tags</FormLabel> <FormLabel>
{translate('Tags')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TAG} type={inputTypes.TAG}
name="tags" name="tags"
value={tags} value={tags}
helpText="Feed will only contain artists with at least one matching tag" helpText={translate('TagsHelpText')}
onChange={this.onInputChange} onChange={this.onInputChange}
/> />
</FormGroup> </FormGroup>
@ -163,14 +172,16 @@ class CalendarLinkModalContent extends Component {
<FormGroup <FormGroup
size={sizes.LARGE} size={sizes.LARGE}
> >
<FormLabel>iCal Feed</FormLabel> <FormLabel>
{translate('ICalFeed')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="iCalHttpUrl" name="iCalHttpUrl"
value={iCalHttpUrl} value={iCalHttpUrl}
readOnly={true} readOnly={true}
helpText="Copy this URL to your client(s) or click to subscribe if your browser supports webcal" helpText={translate('ICalHttpUrlHelpText')}
buttons={[ buttons={[
<ClipboardButton <ClipboardButton
key="copy" key="copy"

@ -14,6 +14,7 @@ import Scroller from 'Components/Scroller/Scroller';
import Table from 'Components/Table/Table'; import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody'; import TableBody from 'Components/Table/TableBody';
import { kinds, scrollDirections } from 'Helpers/Props'; import { kinds, scrollDirections } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import FileBrowserRow from './FileBrowserRow'; import FileBrowserRow from './FileBrowserRow';
import styles from './FileBrowserModalContent.css'; import styles from './FileBrowserModalContent.css';
@ -134,7 +135,7 @@ class FileBrowserModalContent extends Component {
<PathInput <PathInput
className={styles.pathInput} className={styles.pathInput}
placeholder="Start typing or select a path below" placeholder={translate('StartTypingOrSelectAPathBelow')}
hasFileBrowser={false} hasFileBrowser={false}
{...otherProps} {...otherProps}
value={this.state.currentPath} value={this.state.currentPath}
@ -148,7 +149,9 @@ class FileBrowserModalContent extends Component {
> >
{ {
!!error && !!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 IconButton from 'Components/Link/IconButton';
import SpinnerIconButton from 'Components/Link/SpinnerIconButton'; import SpinnerIconButton from 'Components/Link/SpinnerIconButton';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './CustomFilter.css'; import styles from './CustomFilter.css';
class CustomFilter extends Component { class CustomFilter extends Component {
@ -89,7 +90,7 @@ class CustomFilter extends Component {
/> />
<SpinnerIconButton <SpinnerIconButton
title="Remove filter" title={translate('RemoveFilter')}
name={icons.REMOVE} name={icons.REMOVE}
isSpinning={this.state.isDeleting} isSpinning={this.state.isDeleting}
onPress={this.onRemovePress} onPress={this.onRemovePress}

@ -176,7 +176,7 @@ function FormInputGroup(props) {
<Icon <Icon
name={icons.UNSAVED_SETTING} name={icons.UNSAVED_SETTING}
className={styles.pendingChangesIcon} className={styles.pendingChangesIcon}
title="Change has not been saved yet" title={translate('ChangeHasNotBeenSavedYet')}
/> />
} }
</div> */} </div> */}

@ -1,11 +1,12 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import PageContent from 'Components/Page/PageContent'; import PageContent from 'Components/Page/PageContent';
import translate from 'Utilities/String/translate';
import styles from './NotFound.css'; import styles from './NotFound.css';
function NotFound({ message }) { function NotFound({ message }) {
return ( return (
<PageContent title="MIA"> <PageContent title={translate('MIA')}>
<div className={styles.container}> <div className={styles.container}>
<div className={styles.message}> <div className={styles.message}>
{message} {message}

@ -15,6 +15,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter'; import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes } from 'Helpers/Props'; import { inputTypes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import TableOptionsColumn from './TableOptionsColumn'; import TableOptionsColumn from './TableOptionsColumn';
import TableOptionsColumnDragPreview from './TableOptionsColumnDragPreview'; import TableOptionsColumnDragPreview from './TableOptionsColumnDragPreview';
import TableOptionsColumnDragSource from './TableOptionsColumnDragSource'; import TableOptionsColumnDragSource from './TableOptionsColumnDragSource';
@ -144,13 +145,15 @@ class TableOptionsModal extends Component {
{ {
hasPageSize ? hasPageSize ?
<FormGroup> <FormGroup>
<FormLabel>Page Size</FormLabel> <FormLabel>
{translate('PageSize')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.NUMBER} type={inputTypes.NUMBER}
name="pageSize" name="pageSize"
value={pageSize || 0} value={pageSize || 0}
helpText="Number of items to show on each page" helpText={translate('PageSizeHelpText')}
errors={pageSizeError ? [{ message: pageSizeError }] : undefined} errors={pageSizeError ? [{ message: pageSizeError }] : undefined}
onChange={this.onPageSizeChange} onChange={this.onPageSizeChange}
/> />
@ -168,7 +171,9 @@ class TableOptionsModal extends Component {
{ {
canModifyColumns ? canModifyColumns ?
<FormGroup> <FormGroup>
<FormLabel>Columns</FormLabel> <FormLabel>
{translate('Columns')}
</FormLabel>
<div> <div>
<FormInputHelpText <FormInputHelpText

@ -11,6 +11,7 @@ import Scroller from 'Components/Scroller/Scroller';
import Table from 'Components/Table/Table'; import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody'; import TableBody from 'Components/Table/TableBody';
import { scrollDirections } from 'Helpers/Props'; import { scrollDirections } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import SelectAlbumRow from './SelectAlbumRow'; import SelectAlbumRow from './SelectAlbumRow';
import styles from './SelectAlbumModalContent.css'; import styles from './SelectAlbumModalContent.css';
@ -87,7 +88,7 @@ class SelectAlbumModalContent extends Component {
} }
<TextInput <TextInput
className={styles.filterInput} className={styles.filterInput}
placeholder="Filter album" placeholder={translate('FilterPlaceHolder')}
name="filter" name="filter"
value={filter} value={filter}
autoFocus={true} autoFocus={true}

@ -5,6 +5,7 @@ import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellCo
import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRow from 'Components/Table/TableRow'; import TableRow from 'Components/Table/TableRow';
import { kinds, sizes } from 'Helpers/Props'; import { kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './SelectAlbumRow.css'; import styles from './SelectAlbumRow.css';
function getTrackCountKind(monitored, trackFileCount, trackCount) { function getTrackCountKind(monitored, trackFileCount, trackCount) {
@ -97,7 +98,7 @@ class SelectAlbumRow extends Component {
key={name} key={name}
> >
<Label <Label
title={`${totalTrackCount} tracks total. ${trackFileCount} tracks with files.`} title={translate('TotalTrackCountTracksTotalTrackFileCountTracksWithFilesInterp', [totalTrackCount, trackFileCount])}
kind={getTrackCountKind(monitored, trackFileCount, trackCount)} kind={getTrackCountKind(monitored, trackFileCount, trackCount)}
size={sizes.MEDIUM} size={sizes.MEDIUM}
> >

@ -8,6 +8,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import Scroller from 'Components/Scroller/Scroller'; import Scroller from 'Components/Scroller/Scroller';
import { scrollDirections } from 'Helpers/Props'; import { scrollDirections } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import SelectArtistRow from './SelectArtistRow'; import SelectArtistRow from './SelectArtistRow';
import styles from './SelectArtistModalContent.css'; import styles from './SelectArtistModalContent.css';
@ -55,7 +56,7 @@ class SelectArtistModalContent extends Component {
> >
<TextInput <TextInput
className={styles.filterInput} className={styles.filterInput}
placeholder="Filter artist" placeholder={translate('FilterPlaceHolder')}
name="filter" name="filter"
value={filter} value={filter}
autoFocus={true} autoFocus={true}

@ -5,6 +5,7 @@ import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellCo
import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRowButton from 'Components/Table/TableRowButton'; import TableRowButton from 'Components/Table/TableRowButton';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './RecentFolderRow.css'; import styles from './RecentFolderRow.css';
class RecentFolderRow extends Component { class RecentFolderRow extends Component {
@ -44,7 +45,7 @@ class RecentFolderRow extends Component {
<TableRowCell className={styles.actions}> <TableRowCell className={styles.actions}>
<IconButton <IconButton
title="Remove" title={translate('Remove')}
name={icons.REMOVE} name={icons.REMOVE}
onPress={this.onRemovePress} onPress={this.onRemovePress}
/> />

@ -16,6 +16,7 @@ import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
import SelectTrackModal from 'InteractiveImport/Track/SelectTrackModal'; import SelectTrackModal from 'InteractiveImport/Track/SelectTrackModal';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems'; import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import translate from 'Utilities/String/translate';
import InteractiveImportRowCellPlaceholder from './InteractiveImportRowCellPlaceholder'; import InteractiveImportRowCellPlaceholder from './InteractiveImportRowCellPlaceholder';
import styles from './InteractiveImportRow.css'; import styles from './InteractiveImportRow.css';
@ -197,7 +198,7 @@ class InteractiveImportRow extends Component {
const pathCell = additionalFile ? ( const pathCell = additionalFile ? (
<Tooltip <Tooltip
anchor={pathCellContents} anchor={pathCellContents}
tooltip='This file is already in your library for a release you are currently importing' tooltip={translate('AnchorTooltip')}
position={tooltipPositions.TOP} position={tooltipPositions.TOP}
/> />
) : pathCellContents; ) : pathCellContents;
@ -221,7 +222,7 @@ class InteractiveImportRow extends Component {
<TableRowCellButton <TableRowCellButton
isDisabled={!allowArtistChange} isDisabled={!allowArtistChange}
title={allowArtistChange ? 'Click to change artist' : undefined} title={allowArtistChange ? translate('AllowArtistChangeClickToChangeArtist') : undefined}
onPress={this.onSelectArtistPress} onPress={this.onSelectArtistPress}
> >
{ {
@ -231,7 +232,7 @@ class InteractiveImportRow extends Component {
<TableRowCellButton <TableRowCellButton
isDisabled={!artist} isDisabled={!artist}
title={artist ? 'Click to change album' : undefined} title={artist ? translate('ArtistClickToChangeAlbum') : undefined}
onPress={this.onSelectAlbumPress} onPress={this.onSelectAlbumPress}
> >
{ {
@ -241,7 +242,7 @@ class InteractiveImportRow extends Component {
<TableRowCellButton <TableRowCellButton
isDisabled={!artist || !album} isDisabled={!artist || !album}
title={artist && album ? 'Click to change track' : undefined} title={artist && album ? translate('ArtistAlbumClickToChangeTrack') : undefined}
onPress={this.onSelectTrackPress} onPress={this.onSelectTrackPress}
> >
{ {
@ -254,7 +255,7 @@ class InteractiveImportRow extends Component {
<TableRowCellButton <TableRowCellButton
className={styles.quality} className={styles.quality}
title="Click to change quality" title={translate('ClickToChangeQuality')}
onPress={this.onSelectQualityPress} onPress={this.onSelectQualityPress}
> >
{ {
@ -285,7 +286,7 @@ class InteractiveImportRow extends Component {
kind={kinds.DANGER} kind={kinds.DANGER}
/> />
} }
title="Release Rejected" title={translate('ReleaseRejected')}
body={ body={
<ul> <ul>
{ {

@ -11,6 +11,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter'; import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds } from 'Helpers/Props'; import { inputTypes, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
class SelectQualityModalContent extends Component { class SelectQualityModalContent extends Component {
@ -91,14 +92,18 @@ class SelectQualityModalContent extends Component {
{ {
!isFetching && !!error && !isFetching && !!error &&
<div>Unable to load qualities</div> <div>
{translate('UnableToLoadQualities')}
</div>
} }
{ {
isPopulated && !error && isPopulated && !error &&
<Form> <Form>
<FormGroup> <FormGroup>
<FormLabel>Quality</FormLabel> <FormLabel>
{translate('Quality')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.SELECT} type={inputTypes.SELECT}
@ -110,7 +115,9 @@ class SelectQualityModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Proper</FormLabel> <FormLabel>
{translate('Proper')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
@ -121,7 +128,9 @@ class SelectQualityModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Real</FormLabel> <FormLabel>
{translate('Real')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}

@ -6,6 +6,7 @@ import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import TableRowButton from 'Components/Table/TableRowButton'; import TableRowButton from 'Components/Table/TableRowButton';
import Popover from 'Components/Tooltip/Popover'; import Popover from 'Components/Tooltip/Popover';
import { icons, kinds, tooltipPositions } from 'Helpers/Props'; import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
class SelectTrackRow extends Component { class SelectTrackRow extends Component {
@ -96,7 +97,7 @@ class SelectTrackRow extends Component {
kind={iconKind} kind={iconKind}
/> />
} }
title={'Track status'} title={translate('TrackStatus')}
body={iconTip} body={iconTip}
position={tooltipPositions.LEFT} position={tooltipPositions.LEFT}
/> />

@ -13,6 +13,7 @@ import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import formatDateTime from 'Utilities/Date/formatDateTime'; import formatDateTime from 'Utilities/Date/formatDateTime';
import formatAge from 'Utilities/Number/formatAge'; import formatAge from 'Utilities/Number/formatAge';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
import translate from 'Utilities/String/translate';
import Peers from './Peers'; import Peers from './Peers';
import styles from './InteractiveSearchRow.css'; import styles from './InteractiveSearchRow.css';
@ -179,7 +180,7 @@ class InteractiveSearchRow extends Component {
kind={kinds.DANGER} kind={kinds.DANGER}
/> />
} }
title="Release Rejected" title={translate('ReleaseRejected')}
body={ body={
<ul> <ul>
{ {
@ -213,9 +214,9 @@ class InteractiveSearchRow extends Component {
<ConfirmModal <ConfirmModal
isOpen={this.state.isConfirmGrabModalOpen} isOpen={this.state.isConfirmGrabModalOpen}
kind={kinds.WARNING} kind={kinds.WARNING}
title="Grab Release" title={translate('GrabRelease')}
message={`Lidarr was unable to determine which artist and album this release was for. Lidarr may be unable to automatically import this release. Do you want to grab '${title}'?`} message={translate('GrabReleaseMessageText', [title])}
confirmLabel="Grab" confirmLabel={translate('Grab')}
onConfirm={this.onGrabConfirm} onConfirm={this.onGrabConfirm}
onCancel={this.onGrabCancel} onCancel={this.onGrabCancel}
/> />

@ -9,6 +9,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter'; import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { kinds } from 'Helpers/Props'; import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds'; import getSelectedIds from 'Utilities/Table/getSelectedIds';
import selectAll from 'Utilities/Table/selectAll'; import selectAll from 'Utilities/Table/selectAll';
import toggleSelected from 'Utilities/Table/toggleSelected'; import toggleSelected from 'Utilities/Table/toggleSelected';
@ -100,12 +101,16 @@ class OrganizePreviewModalContent extends Component {
{ {
!isFetching && error && !isFetching && error &&
<div>Error loading previews</div> <div>
{translate('ErrorLoadingPreviews')}
</div>
} }
{ {
!isFetching && isPopulated && !items.length && !isFetching && isPopulated && !items.length &&
<div>Success! My work is done, no files to rename.</div> <div>
{translate('SuccessMyWorkIsDoneNoFilesToRename')}
</div>
} }
{ {

@ -9,6 +9,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter'; import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { kinds } from 'Helpers/Props'; import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds'; import getSelectedIds from 'Utilities/Table/getSelectedIds';
import selectAll from 'Utilities/Table/selectAll'; import selectAll from 'Utilities/Table/selectAll';
import toggleSelected from 'Utilities/Table/toggleSelected'; import toggleSelected from 'Utilities/Table/toggleSelected';
@ -99,12 +100,16 @@ class RetagPreviewModalContent extends Component {
{ {
!isFetching && error && !isFetching && error &&
<div>Error loading previews</div> <div>
{translate('ErrorLoadingPreviews')}
</div>
} }
{ {
!isFetching && ((isPopulated && !items.length)) && !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 PageContentBody from 'Components/Page/PageContentBody';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import getErrorMessage from 'Utilities/Object/getErrorMessage'; import getErrorMessage from 'Utilities/Object/getErrorMessage';
import translate from 'Utilities/String/translate';
import AddNewAlbumSearchResultConnector from './Album/AddNewAlbumSearchResultConnector'; import AddNewAlbumSearchResultConnector from './Album/AddNewAlbumSearchResultConnector';
import AddNewArtistSearchResultConnector from './Artist/AddNewArtistSearchResultConnector'; import AddNewArtistSearchResultConnector from './Artist/AddNewArtistSearchResultConnector';
import styles from './AddNewItem.css'; import styles from './AddNewItem.css';
@ -87,7 +88,7 @@ class AddNewItem extends Component {
const isFetching = this.state.isFetching; const isFetching = this.state.isFetching;
return ( return (
<PageContent title="Add New Item"> <PageContent title={translate('AddNewItem')}>
<PageContentBody> <PageContentBody>
<div className={styles.searchContainer}> <div className={styles.searchContainer}>
<div className={styles.searchIconContainer}> <div className={styles.searchIconContainer}>
@ -101,7 +102,7 @@ class AddNewItem extends Component {
className={styles.searchInput} className={styles.searchInput}
name="searchBox" name="searchBox"
value={term} value={term}
placeholder="eg. Breaking Benjamin, lidarr:854a1807-025b-42a8-ba8c-2a39717f1d25" placeholder={translate('SearchBoxPlaceHolder')}
autoFocus={true} autoFocus={true}
onChange={this.onSearchInputChange} onChange={this.onSearchInputChange}
/> />

@ -10,6 +10,7 @@ import Link from 'Components/Link/Link';
import { icons, sizes } from 'Helpers/Props'; import { icons, sizes } from 'Helpers/Props';
import dimensions from 'Styles/Variables/dimensions'; import dimensions from 'Styles/Variables/dimensions';
import fonts from 'Styles/Variables/fonts'; import fonts from 'Styles/Variables/fonts';
import translate from 'Utilities/String/translate';
import AddNewAlbumModal from './AddNewAlbumModal'; import AddNewAlbumModal from './AddNewAlbumModal';
import styles from './AddNewAlbumSearchResult.css'; import styles from './AddNewAlbumSearchResult.css';
@ -130,7 +131,7 @@ class AddNewAlbumSearchResult extends Component {
className={styles.alreadyExistsIcon} className={styles.alreadyExistsIcon}
name={icons.CHECK_CIRCLE} name={icons.CHECK_CIRCLE}
size={36} size={36}
title="Already in your library" title={translate('AlreadyInYourLibrary')}
/> : /> :
null null
} }

@ -9,6 +9,7 @@ import Link from 'Components/Link/Link';
import { icons, kinds, sizes } from 'Helpers/Props'; import { icons, kinds, sizes } from 'Helpers/Props';
import dimensions from 'Styles/Variables/dimensions'; import dimensions from 'Styles/Variables/dimensions';
import fonts from 'Styles/Variables/fonts'; import fonts from 'Styles/Variables/fonts';
import translate from 'Utilities/String/translate';
import AddNewArtistModal from './AddNewArtistModal'; import AddNewArtistModal from './AddNewArtistModal';
import styles from './AddNewArtistSearchResult.css'; import styles from './AddNewArtistSearchResult.css';
@ -137,7 +138,7 @@ class AddNewArtistSearchResult extends Component {
className={styles.alreadyExistsIcon} className={styles.alreadyExistsIcon}
name={icons.CHECK_CIRCLE} name={icons.CHECK_CIRCLE}
size={36} size={36}
title="Already in your library" title={translate('AlreadyInYourLibrary')}
/> : /> :
null null
} }

@ -9,6 +9,7 @@ import FormLabel from 'Components/Form/FormLabel';
import Icon from 'Components/Icon'; import Icon from 'Components/Icon';
import Popover from 'Components/Tooltip/Popover'; import Popover from 'Components/Tooltip/Popover';
import { icons, inputTypes, tooltipPositions } from 'Helpers/Props'; import { icons, inputTypes, tooltipPositions } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './AddArtistOptionsForm.css'; import styles from './AddArtistOptionsForm.css';
class AddArtistOptionsForm extends Component { class AddArtistOptionsForm extends Component {
@ -43,7 +44,9 @@ class AddArtistOptionsForm extends Component {
return ( return (
<Form {...otherProps}> <Form {...otherProps}>
<FormGroup> <FormGroup>
<FormLabel>Root Folder</FormLabel> <FormLabel>
{translate('RootFolder')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.ROOT_FOLDER_SELECT} type={inputTypes.ROOT_FOLDER_SELECT}
@ -64,7 +67,7 @@ class AddArtistOptionsForm extends Component {
name={icons.INFO} name={icons.INFO}
/> />
} }
title="Monitoring Options" title={translate('MonitoringOptions')}
body={<ArtistMonitoringOptionsPopoverContent />} body={<ArtistMonitoringOptionsPopoverContent />}
position={tooltipPositions.RIGHT} position={tooltipPositions.RIGHT}
/> />
@ -79,7 +82,9 @@ class AddArtistOptionsForm extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Quality Profile</FormLabel> <FormLabel>
{translate('QualityProfile')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.QUALITY_PROFILE_SELECT} type={inputTypes.QUALITY_PROFILE_SELECT}
@ -102,7 +107,7 @@ class AddArtistOptionsForm extends Component {
name={icons.INFO} name={icons.INFO}
/> />
} }
title="Metadata Profile" title={translate('MetadataProfile')}
body={<ArtistMetadataProfilePopoverContent />} body={<ArtistMetadataProfilePopoverContent />}
position={tooltipPositions.RIGHT} position={tooltipPositions.RIGHT}
/> />
@ -119,7 +124,9 @@ class AddArtistOptionsForm extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Tags</FormLabel> <FormLabel>
{translate('Tags')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TAG} type={inputTypes.TAG}

@ -4,6 +4,7 @@ import React from 'react';
import Icon from 'Components/Icon'; import Icon from 'Components/Icon';
import Link from 'Components/Link/Link'; import Link from 'Components/Link/Link';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './AdvancedSettingsButton.css'; import styles from './AdvancedSettingsButton.css';
function AdvancedSettingsButton(props) { function AdvancedSettingsButton(props) {
@ -15,7 +16,7 @@ function AdvancedSettingsButton(props) {
return ( return (
<Link <Link
className={styles.button} className={styles.button}
title={advancedSettings ? 'Shown, click to hide' : 'Hidden, click to show'} title={advancedSettings ? translate('AdvancedSettingsShownClickToHide') : translate('AdvancedSettingsHiddenClickToShow')}
onPress={onAdvancedSettingsPress} onPress={onAdvancedSettingsPress}
> >
<Icon <Icon

@ -6,6 +6,7 @@ import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator'; import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector'; import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import translate from 'Utilities/String/translate';
import DownloadClientsConnector from './DownloadClients/DownloadClientsConnector'; import DownloadClientsConnector from './DownloadClients/DownloadClientsConnector';
import DownloadClientOptionsConnector from './Options/DownloadClientOptionsConnector'; import DownloadClientOptionsConnector from './Options/DownloadClientOptionsConnector';
import RemotePathMappingsConnector from './RemotePathMappings/RemotePathMappingsConnector'; import RemotePathMappingsConnector from './RemotePathMappings/RemotePathMappingsConnector';
@ -58,7 +59,7 @@ class DownloadClientSettings extends Component {
} = this.state; } = this.state;
return ( return (
<PageContent title="Download Client Settings"> <PageContent title={translate('DownloadClientSettings')}>
<SettingsToolbarConnector <SettingsToolbarConnector
isSaving={isSaving} isSaving={isSaving}
hasPendingChanges={hasPendingChanges} hasPendingChanges={hasPendingChanges}
@ -67,7 +68,7 @@ class DownloadClientSettings extends Component {
<PageToolbarSeparator /> <PageToolbarSeparator />
<PageToolbarButton <PageToolbarButton
label="Test All Clients" label={translate('TestAllClients')}
iconName={icons.TEST} iconName={icons.TEST}
isSpinning={isTestingAll} isSpinning={isTestingAll}
onPress={dispatchTestAllDownloadClients} onPress={dispatchTestAllDownloadClients}

@ -9,6 +9,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter'; import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { kinds } from 'Helpers/Props'; import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import AddDownloadClientItem from './AddDownloadClientItem'; import AddDownloadClientItem from './AddDownloadClientItem';
import styles from './AddDownloadClientModalContent.css'; import styles from './AddDownloadClientModalContent.css';
@ -42,7 +43,9 @@ class AddDownloadClientModalContent extends Component {
{ {
!isSchemaFetching && !!schemaError && !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> <div>
<Alert kind={kinds.INFO}> <Alert kind={kinds.INFO}>
<div>Lidarr supports any downloadClient that uses the Newznab standard, as well as other downloadClients listed below.</div> <div>
<div>For more information on the individual downloadClients, click on the info buttons.</div> {translate('LidarrSupportsAnyDownloadClientThatUsesTheNewznabStandardAsWellAsOtherDownloadClientsListedBelow')}
</div>
<div>
{translate('ForMoreInformationOnTheIndividualDownloadClientsClickOnTheInfoButtons')}
</div>
</Alert> </Alert>
<FieldSet legend="Usenet"> <FieldSet legend={translate('Usenet')}>
<div className={styles.downloadClients}> <div className={styles.downloadClients}>
{ {
usenetDownloadClients.map((downloadClient) => { usenetDownloadClients.map((downloadClient) => {
@ -71,7 +78,7 @@ class AddDownloadClientModalContent extends Component {
</div> </div>
</FieldSet> </FieldSet>
<FieldSet legend="Torrents"> <FieldSet legend={translate('Torrents')}>
<div className={styles.downloadClients}> <div className={styles.downloadClients}>
{ {
torrentDownloadClients.map((downloadClient) => { torrentDownloadClients.map((downloadClient) => {

@ -4,6 +4,7 @@ import Card from 'Components/Card';
import Label from 'Components/Label'; import Label from 'Components/Label';
import ConfirmModal from 'Components/Modal/ConfirmModal'; import ConfirmModal from 'Components/Modal/ConfirmModal';
import { kinds } from 'Helpers/Props'; import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import EditDownloadClientModalConnector from './EditDownloadClientModalConnector'; import EditDownloadClientModalConnector from './EditDownloadClientModalConnector';
import styles from './DownloadClient.css'; import styles from './DownloadClient.css';
@ -103,9 +104,9 @@ class DownloadClient extends Component {
<ConfirmModal <ConfirmModal
isOpen={this.state.isDeleteDownloadClientModalOpen} isOpen={this.state.isDeleteDownloadClientModalOpen}
kind={kinds.DANGER} kind={kinds.DANGER}
title="Delete Download Client" title={translate('DeleteDownloadClient')}
message={`Are you sure you want to delete the download client '${name}'?`} message={translate('DeleteDownloadClientMessageText', [name])}
confirmLabel="Delete" confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteDownloadClient} onConfirm={this.onConfirmDeleteDownloadClient}
onCancel={this.onDeleteDownloadClientModalClose} onCancel={this.onDeleteDownloadClientModalClose}
/> />

@ -5,6 +5,7 @@ import FieldSet from 'Components/FieldSet';
import Icon from 'Components/Icon'; import Icon from 'Components/Icon';
import PageSectionContent from 'Components/Page/PageSectionContent'; import PageSectionContent from 'Components/Page/PageSectionContent';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import AddDownloadClientModal from './AddDownloadClientModal'; import AddDownloadClientModal from './AddDownloadClientModal';
import DownloadClient from './DownloadClient'; import DownloadClient from './DownloadClient';
import EditDownloadClientModalConnector from './EditDownloadClientModalConnector'; import EditDownloadClientModalConnector from './EditDownloadClientModalConnector';
@ -58,9 +59,9 @@ class DownloadClients extends Component {
} = this.state; } = this.state;
return ( return (
<FieldSet legend="Download Clients"> <FieldSet legend={translate('DownloadClients')}>
<PageSectionContent <PageSectionContent
errorMessage="Unable to load download clients" errorMessage={translate('UnableToLoadDownloadClients')}
{...otherProps} {...otherProps}
> >
<div className={styles.downloadClients}> <div className={styles.downloadClients}>

@ -14,6 +14,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter'; import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds } from 'Helpers/Props'; import { inputTypes, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './EditDownloadClientModalContent.css'; import styles from './EditDownloadClientModalContent.css';
class EditDownloadClientModalContent extends Component { class EditDownloadClientModalContent extends Component {
@ -63,7 +64,9 @@ class EditDownloadClientModalContent extends Component {
{ {
!isFetching && !!error && !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> <FormGroup>
<FormLabel>Name</FormLabel> <FormLabel>
{translate('Name')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
@ -91,7 +96,9 @@ class EditDownloadClientModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Enable</FormLabel> <FormLabel>
{translate('Enable')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
@ -120,12 +127,14 @@ class EditDownloadClientModalContent extends Component {
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
> >
<FormLabel>Client Priority</FormLabel> <FormLabel>
{translate('ClientPriority')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.NUMBER} type={inputTypes.NUMBER}
name="priority" name="priority"
helpText="Prioritize multiple Download Clients. Round-Robin is used for clients with the same priority." helpText={translate('PriorityHelpText')}
min={1} min={1}
max={50} max={50}
{...priority} {...priority}

@ -7,6 +7,7 @@ import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel'; import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator'; import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { inputTypes, sizes } from 'Helpers/Props'; import { inputTypes, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
function DownloadClientOptions(props) { function DownloadClientOptions(props) {
const { const {
@ -27,21 +28,25 @@ function DownloadClientOptions(props) {
{ {
!isFetching && error && !isFetching && error &&
<div>Unable to load download client options</div> <div>
{translate('UnableToLoadDownloadClientOptions')}
</div>
} }
{ {
hasSettings && !isFetching && !error && hasSettings && !isFetching && !error &&
<div> <div>
<FieldSet legend="Completed Download Handling"> <FieldSet legend={translate('CompletedDownloadHandling')}>
<Form> <Form>
<FormGroup size={sizes.MEDIUM}> <FormGroup size={sizes.MEDIUM}>
<FormLabel>Enable</FormLabel> <FormLabel>
{translate('Enable')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="enableCompletedDownloadHandling" name="enableCompletedDownloadHandling"
helpText="Automatically import completed downloads from download client" helpText={translate('EnableCompletedDownloadHandlingHelpText')}
onChange={onInputChange} onChange={onInputChange}
{...settings.enableCompletedDownloadHandling} {...settings.enableCompletedDownloadHandling}
/> />
@ -52,12 +57,14 @@ function DownloadClientOptions(props) {
isAdvanced={true} isAdvanced={true}
size={sizes.MEDIUM} size={sizes.MEDIUM}
> >
<FormLabel>Remove</FormLabel> <FormLabel>
{translate('Remove')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="removeCompletedDownloads" name="removeCompletedDownloads"
helpText="Remove imported downloads from download client history" helpText={translate('RemoveCompletedDownloadsHelpText')}
onChange={onInputChange} onChange={onInputChange}
{...settings.removeCompletedDownloads} {...settings.removeCompletedDownloads}
/> />
@ -66,16 +73,18 @@ function DownloadClientOptions(props) {
</FieldSet> </FieldSet>
<FieldSet <FieldSet
legend="Failed Download Handling" legend={translate('FailedDownloadHandling')}
> >
<Form> <Form>
<FormGroup size={sizes.MEDIUM}> <FormGroup size={sizes.MEDIUM}>
<FormLabel>Redownload</FormLabel> <FormLabel>
{translate('Redownload')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="autoRedownloadFailed" name="autoRedownloadFailed"
helpText="Automatically search for and attempt to download a different release" helpText={translate('AutoRedownloadFailedHelpText')}
onChange={onInputChange} onChange={onInputChange}
{...settings.autoRedownloadFailed} {...settings.autoRedownloadFailed}
/> />
@ -86,12 +95,14 @@ function DownloadClientOptions(props) {
isAdvanced={true} isAdvanced={true}
size={sizes.MEDIUM} size={sizes.MEDIUM}
> >
<FormLabel>Remove</FormLabel> <FormLabel>
{translate('Remove')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="removeFailedDownloads" name="removeFailedDownloads"
helpText="Remove failed downloads from download client history" helpText={translate('RemoveFailedDownloadsHelpText')}
onChange={onInputChange} onChange={onInputChange}
{...settings.removeFailedDownloads} {...settings.removeFailedDownloads}
/> />

@ -13,6 +13,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds } from 'Helpers/Props'; import { inputTypes, kinds } from 'Helpers/Props';
import { stringSettingShape } from 'Helpers/Props/Shapes/settingShape'; import { stringSettingShape } from 'Helpers/Props/Shapes/settingShape';
import translate from 'Utilities/String/translate';
import styles from './EditRemotePathMappingModalContent.css'; import styles from './EditRemotePathMappingModalContent.css';
function EditRemotePathMappingModalContent(props) { function EditRemotePathMappingModalContent(props) {
@ -51,19 +52,23 @@ function EditRemotePathMappingModalContent(props) {
{ {
!isFetching && !!error && !isFetching && !!error &&
<div>Unable to add a new remote path mapping, please try again.</div> <div>
{translate('UnableToAddANewRemotePathMappingPleaseTryAgain')}
</div>
} }
{ {
!isFetching && !error && !isFetching && !error &&
<Form {...otherProps}> <Form {...otherProps}>
<FormGroup> <FormGroup>
<FormLabel>Host</FormLabel> <FormLabel>
{translate('Host')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.SELECT} type={inputTypes.SELECT}
name="host" name="host"
helpText="The same host you specified for the remote Download Client" helpText={translate('HostHelpText')}
{...host} {...host}
values={downloadClientHosts} values={downloadClientHosts}
onChange={onInputChange} onChange={onInputChange}
@ -71,24 +76,28 @@ function EditRemotePathMappingModalContent(props) {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Remote Path</FormLabel> <FormLabel>
{translate('RemotePath')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="remotePath" name="remotePath"
helpText="Root path to the directory that the Download Client accesses" helpText={translate('RemotePathHelpText')}
{...remotePath} {...remotePath}
onChange={onInputChange} onChange={onInputChange}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Local Path</FormLabel> <FormLabel>
{translate('LocalPath')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.PATH} type={inputTypes.PATH}
name="localPath" name="localPath"
helpText="Path that Lidarr should use to access the remote path locally" helpText={translate('LocalPathHelpText')}
{...localPath} {...localPath}
onChange={onInputChange} onChange={onInputChange}
/> />

@ -5,6 +5,7 @@ import Icon from 'Components/Icon';
import Link from 'Components/Link/Link'; import Link from 'Components/Link/Link';
import ConfirmModal from 'Components/Modal/ConfirmModal'; import ConfirmModal from 'Components/Modal/ConfirmModal';
import { icons, kinds } from 'Helpers/Props'; import { icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import EditRemotePathMappingModalConnector from './EditRemotePathMappingModalConnector'; import EditRemotePathMappingModalConnector from './EditRemotePathMappingModalConnector';
import styles from './RemotePathMapping.css'; import styles from './RemotePathMapping.css';
@ -87,9 +88,9 @@ class RemotePathMapping extends Component {
<ConfirmModal <ConfirmModal
isOpen={this.state.isDeleteRemotePathMappingModalOpen} isOpen={this.state.isDeleteRemotePathMappingModalOpen}
kind={kinds.DANGER} kind={kinds.DANGER}
title="Delete Delay Profile" title={translate('DeleteDelayProfile')}
message="Are you sure you want to delete this remote path mapping?" message={translate('DeleteDelayProfileMessageText')}
confirmLabel="Delete" confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteRemotePathMapping} onConfirm={this.onConfirmDeleteRemotePathMapping}
onCancel={this.onDeleteRemotePathMappingModalClose} onCancel={this.onDeleteRemotePathMappingModalClose}
/> />

@ -5,6 +5,7 @@ import Icon from 'Components/Icon';
import Link from 'Components/Link/Link'; import Link from 'Components/Link/Link';
import PageSectionContent from 'Components/Page/PageSectionContent'; import PageSectionContent from 'Components/Page/PageSectionContent';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import EditRemotePathMappingModalConnector from './EditRemotePathMappingModalConnector'; import EditRemotePathMappingModalConnector from './EditRemotePathMappingModalConnector';
import RemotePathMapping from './RemotePathMapping'; import RemotePathMapping from './RemotePathMapping';
import styles from './RemotePathMappings.css'; import styles from './RemotePathMappings.css';
@ -44,9 +45,9 @@ class RemotePathMappings extends Component {
} = this.props; } = this.props;
return ( return (
<FieldSet legend="Remote Path Mappings"> <FieldSet legend={translate('RemotePathMappings')}>
<PageSectionContent <PageSectionContent
errorMessage="Unable to load Remote Path Mappings" errorMessage={translate('UnableToLoadRemotePathMappings')}
{...otherProps} {...otherProps}
> >
<div className={styles.remotePathMappingsHeader}> <div className={styles.remotePathMappingsHeader}>

@ -5,6 +5,7 @@ import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup'; import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel'; import FormLabel from 'Components/Form/FormLabel';
import { inputTypes, sizes } from 'Helpers/Props'; import { inputTypes, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
function AnalyticSettings(props) { function AnalyticSettings(props) {
const { const {
@ -17,15 +18,17 @@ function AnalyticSettings(props) {
} = settings; } = settings;
return ( return (
<FieldSet legend="Analytics"> <FieldSet legend={translate('Analytics')}>
<FormGroup size={sizes.MEDIUM}> <FormGroup size={sizes.MEDIUM}>
<FormLabel>Send Anonymous Usage Data</FormLabel> <FormLabel>
{translate('SendAnonymousUsageData')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="analyticsEnabled" name="analyticsEnabled"
helpText="Send anonymous usage and error information to Lidarr's servers. This includes information on your browser, which Lidarr WebUI pages you use, error reporting as well as OS and runtime version. We will use this information to prioritize features and bug fixes." helpText={translate('AnalyticsEnabledHelpText')}
helpTextWarning="Requires restart to take effect" helpTextWarning={translate('AnalyticsEnabledHelpTextWarning')}
onChange={onInputChange} onChange={onInputChange}
{...analyticsEnabled} {...analyticsEnabled}
/> />

@ -5,6 +5,7 @@ import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup'; import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel'; import FormLabel from 'Components/Form/FormLabel';
import { inputTypes } from 'Helpers/Props'; import { inputTypes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
function BackupSettings(props) { function BackupSettings(props) {
const { const {
@ -24,17 +25,19 @@ function BackupSettings(props) {
} }
return ( return (
<FieldSet legend="Backups"> <FieldSet legend={translate('Backups')}>
<FormGroup <FormGroup
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
> >
<FormLabel>Folder</FormLabel> <FormLabel>
{translate('Folder')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.PATH} type={inputTypes.PATH}
name="backupFolder" name="backupFolder"
helpText="Relative paths will be under Lidarr's AppData directory" helpText={translate('BackupFolderHelpText')}
onChange={onInputChange} onChange={onInputChange}
{...backupFolder} {...backupFolder}
/> />
@ -44,13 +47,15 @@ function BackupSettings(props) {
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
> >
<FormLabel>Interval</FormLabel> <FormLabel>
{translate('Interval')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.NUMBER} type={inputTypes.NUMBER}
name="backupInterval" name="backupInterval"
unit="days" unit="days"
helpText="Interval to backup the Lidarr DB and settings" helpText={translate('BackupIntervalHelpText')}
onChange={onInputChange} onChange={onInputChange}
{...backupInterval} {...backupInterval}
/> />
@ -60,13 +65,15 @@ function BackupSettings(props) {
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
> >
<FormLabel>Retention</FormLabel> <FormLabel>
{translate('Retention')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.NUMBER} type={inputTypes.NUMBER}
name="backupRetention" name="backupRetention"
unit="days" unit="days"
helpText="Automatic backups older than the retention period will be cleaned up automatically" helpText={translate('BackupRetentionHelpText')}
onChange={onInputChange} onChange={onInputChange}
{...backupRetention} {...backupRetention}
/> />

@ -8,6 +8,7 @@ import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody'; import PageContentBody from 'Components/Page/PageContentBody';
import { kinds } from 'Helpers/Props'; import { kinds } from 'Helpers/Props';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector'; import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import translate from 'Utilities/String/translate';
import AnalyticSettings from './AnalyticSettings'; import AnalyticSettings from './AnalyticSettings';
import BackupSettings from './BackupSettings'; import BackupSettings from './BackupSettings';
import HostSettings from './HostSettings'; import HostSettings from './HostSettings';
@ -110,7 +111,7 @@ class GeneralSettings extends Component {
} = this.props; } = this.props;
return ( return (
<PageContent title="General Settings"> <PageContent title={translate('GeneralSettings')}>
<SettingsToolbarConnector <SettingsToolbarConnector
{...otherProps} {...otherProps}
/> />
@ -123,7 +124,9 @@ class GeneralSettings extends Component {
{ {
!isFetching && error && !isFetching && error &&
<div>Unable to load General settings</div> <div>
{translate('UnableToLoadGeneralSettings')}
</div>
} }
{ {
@ -183,12 +186,12 @@ class GeneralSettings extends Component {
<ConfirmModal <ConfirmModal
isOpen={this.state.isRestartRequiredModalOpen} isOpen={this.state.isRestartRequiredModalOpen}
kind={kinds.DANGER} kind={kinds.DANGER}
title="Restart Lidarr" title={translate('RestartLidarr')}
message={ message={
`Lidarr requires a restart to apply changes, do you want to restart now? ${isWindowsService ? 'Depending which user is running the Lidarr service you may need to restart Lidarr as admin once before the service will start automatically.' : ''}` `Lidarr requires a restart to apply changes, do you want to restart now? ${isWindowsService ? 'Depending which user is running the Lidarr service you may need to restart Lidarr as admin once before the service will start automatically.' : ''}`
} }
cancelLabel="I'll restart later" cancelLabel={translate('IllRestartLater')}
confirmLabel="Restart Now" confirmLabel={translate('RestartNow')}
onConfirm={this.onConfirmRestart} onConfirm={this.onConfirmRestart}
onCancel={this.onCloseRestartRequiredModalOpen} onCancel={this.onCloseRestartRequiredModalOpen}
/> />

@ -5,6 +5,7 @@ import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup'; import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel'; import FormLabel from 'Components/Form/FormLabel';
import { inputTypes, sizes } from 'Helpers/Props'; import { inputTypes, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
function HostSettings(props) { function HostSettings(props) {
const { const {
@ -27,25 +28,29 @@ function HostSettings(props) {
} = settings; } = settings;
return ( return (
<FieldSet legend="Host"> <FieldSet legend={translate('Host')}>
<FormGroup <FormGroup
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
> >
<FormLabel>Bind Address</FormLabel> <FormLabel>
{translate('BindAddress')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="bindAddress" name="bindAddress"
helpText="Valid IP4 address or '*' for all interfaces" helpText={translate('BindAddressHelpText')}
helpTextWarning="Requires restart to take effect" helpTextWarning={translate('BindAddressHelpTextWarning')}
onChange={onInputChange} onChange={onInputChange}
{...bindAddress} {...bindAddress}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Port Number</FormLabel> <FormLabel>
{translate('PortNumber')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.NUMBER} type={inputTypes.NUMBER}
@ -53,20 +58,22 @@ function HostSettings(props) {
min={1} min={1}
max={65535} max={65535}
autocomplete="off" autocomplete="off"
helpTextWarning="Requires restart to take effect" helpTextWarning={translate('RequiresRestartToTakeEffect')}
onChange={onInputChange} onChange={onInputChange}
{...port} {...port}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>URL Base</FormLabel> <FormLabel>
{translate('URLBase')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="urlBase" name="urlBase"
helpText="For reverse proxy support, default is empty" helpText={translate('UrlBaseHelpText')}
helpTextWarning="Requires restart to take effect" helpTextWarning={translate('UrlBaseHelpTextWarning')}
onChange={onInputChange} onChange={onInputChange}
{...urlBase} {...urlBase}
/> />
@ -77,12 +84,14 @@ function HostSettings(props) {
isAdvanced={true} isAdvanced={true}
size={sizes.MEDIUM} size={sizes.MEDIUM}
> >
<FormLabel>Enable SSL</FormLabel> <FormLabel>
{translate('EnableSSL')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="enableSsl" name="enableSsl"
helpText=" Requires restart running as administrator to take effect" helpText={translate('EnableSslHelpText')}
onChange={onInputChange} onChange={onInputChange}
{...enableSsl} {...enableSsl}
/> />
@ -94,14 +103,16 @@ function HostSettings(props) {
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
> >
<FormLabel>SSL Port</FormLabel> <FormLabel>
{translate('SSLPort')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.NUMBER} type={inputTypes.NUMBER}
name="sslPort" name="sslPort"
min={1} min={1}
max={65535} max={65535}
helpTextWarning="Requires restart to take effect" helpTextWarning={translate('SslPortHelpTextWarning')}
onChange={onInputChange} onChange={onInputChange}
{...sslPort} {...sslPort}
/> />
@ -115,13 +126,15 @@ function HostSettings(props) {
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
> >
<FormLabel>SSL Cert Path</FormLabel> <FormLabel>
{translate('SSLCertPath')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="sslCertPath" name="sslCertPath"
helpText="Path to pfx file" helpText={translate('SslCertPathHelpText')}
helpTextWarning="Requires restart to take effect" helpTextWarning={translate('SslCertPathHelpTextWarning')}
onChange={onInputChange} onChange={onInputChange}
{...sslCertPath} {...sslCertPath}
/> />
@ -135,13 +148,15 @@ function HostSettings(props) {
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
> >
<FormLabel>SSL Cert Password</FormLabel> <FormLabel>
{translate('SSLCertPassword')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.PASSWORD} type={inputTypes.PASSWORD}
name="sslCertPassword" name="sslCertPassword"
helpText="Password for pfx file" helpText={translate('SslCertPasswordHelpText')}
helpTextWarning="Requires restart to take effect" helpTextWarning={translate('SslCertPasswordHelpTextWarning')}
onChange={onInputChange} onChange={onInputChange}
{...sslCertPassword} {...sslCertPassword}
/> />
@ -152,12 +167,14 @@ function HostSettings(props) {
{ {
isWindows && mode !== 'service' && isWindows && mode !== 'service' &&
<FormGroup size={sizes.MEDIUM}> <FormGroup size={sizes.MEDIUM}>
<FormLabel>Open browser on start</FormLabel> <FormLabel>
{translate('OpenBrowserOnStart')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="launchBrowser" name="launchBrowser"
helpText=" Open a web browser and navigate to Lidarr homepage on app start." helpText={translate('LaunchBrowserHelpText')}
onChange={onInputChange} onChange={onInputChange}
{...launchBrowser} {...launchBrowser}
/> />

@ -5,6 +5,7 @@ import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup'; import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel'; import FormLabel from 'Components/Form/FormLabel';
import { inputTypes } from 'Helpers/Props'; import { inputTypes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
const logLevelOptions = [ const logLevelOptions = [
{ key: 'info', value: 'Info' }, { key: 'info', value: 'Info' },
@ -23,15 +24,17 @@ function LoggingSettings(props) {
} = settings; } = settings;
return ( return (
<FieldSet legend="Logging"> <FieldSet legend={translate('Logging')}>
<FormGroup> <FormGroup>
<FormLabel>Log Level</FormLabel> <FormLabel>
{translate('LogLevel')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.SELECT} type={inputTypes.SELECT}
name="logLevel" name="logLevel"
values={logLevelOptions} values={logLevelOptions}
helpTextWarning={logLevel.value === 'trace' ? 'Trace logging should only be enabled temporarily' : undefined} helpTextWarning={logLevel.value === 'trace' ? translate('LogLevelvalueTraceTraceLoggingShouldOnlyBeEnabledTemporarily') : undefined}
onChange={onInputChange} onChange={onInputChange}
{...logLevel} {...logLevel}
/> />

@ -5,6 +5,7 @@ import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup'; import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel'; import FormLabel from 'Components/Form/FormLabel';
import { inputTypes, sizes } from 'Helpers/Props'; import { inputTypes, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
function ProxySettings(props) { function ProxySettings(props) {
const { const {
@ -30,9 +31,11 @@ function ProxySettings(props) {
]; ];
return ( return (
<FieldSet legend="Proxy"> <FieldSet legend={translate('Proxy')}>
<FormGroup size={sizes.MEDIUM}> <FormGroup size={sizes.MEDIUM}>
<FormLabel>Use Proxy</FormLabel> <FormLabel>
{translate('UseProxy')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
@ -46,7 +49,9 @@ function ProxySettings(props) {
proxyEnabled.value && proxyEnabled.value &&
<div> <div>
<FormGroup> <FormGroup>
<FormLabel>Proxy Type</FormLabel> <FormLabel>
{translate('ProxyType')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.SELECT} type={inputTypes.SELECT}
@ -58,7 +63,9 @@ function ProxySettings(props) {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Hostname</FormLabel> <FormLabel>
{translate('Hostname')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
@ -69,7 +76,9 @@ function ProxySettings(props) {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Port</FormLabel> <FormLabel>
{translate('Port')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.NUMBER} type={inputTypes.NUMBER}
@ -82,43 +91,51 @@ function ProxySettings(props) {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Username</FormLabel> <FormLabel>
{translate('Username')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="proxyUsername" 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} onChange={onInputChange}
{...proxyUsername} {...proxyUsername}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Password</FormLabel> <FormLabel>
{translate('Password')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.PASSWORD} type={inputTypes.PASSWORD}
name="proxyPassword" 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} onChange={onInputChange}
{...proxyPassword} {...proxyPassword}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Ignored Addresses</FormLabel> <FormLabel>
{translate('IgnoredAddresses')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="proxyBypassFilter" name="proxyBypassFilter"
helpText="Use ',' as a separator, and '*.' as a wildcard for subdomains" helpText={translate('ProxyBypassFilterHelpText')}
onChange={onInputChange} onChange={onInputChange}
{...proxyBypassFilter} {...proxyBypassFilter}
/> />
</FormGroup> </FormGroup>
<FormGroup size={sizes.MEDIUM}> <FormGroup size={sizes.MEDIUM}>
<FormLabel>Bypass Proxy for Local Addresses</FormLabel> <FormLabel>
{translate('BypassProxyForLocalAddresses')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}

@ -9,6 +9,7 @@ import Icon from 'Components/Icon';
import ClipboardButton from 'Components/Link/ClipboardButton'; import ClipboardButton from 'Components/Link/ClipboardButton';
import ConfirmModal from 'Components/Modal/ConfirmModal'; import ConfirmModal from 'Components/Modal/ConfirmModal';
import { icons, inputTypes, kinds } from 'Helpers/Props'; import { icons, inputTypes, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
const authenticationMethodOptions = [ const authenticationMethodOptions = [
{ key: 'none', value: 'None' }, { key: 'none', value: 'None' },
@ -76,15 +77,17 @@ class SecuritySettings extends Component {
const authenticationEnabled = authenticationMethod && authenticationMethod.value !== 'none'; const authenticationEnabled = authenticationMethod && authenticationMethod.value !== 'none';
return ( return (
<FieldSet legend="Security"> <FieldSet legend={translate('Security')}>
<FormGroup> <FormGroup>
<FormLabel>Authentication</FormLabel> <FormLabel>
{translate('Authentication')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.SELECT} type={inputTypes.SELECT}
name="authenticationMethod" name="authenticationMethod"
values={authenticationMethodOptions} values={authenticationMethodOptions}
helpText="Require Username and Password to access Lidarr" helpText={translate('AuthenticationMethodHelpText')}
onChange={onInputChange} onChange={onInputChange}
{...authenticationMethod} {...authenticationMethod}
/> />
@ -93,7 +96,9 @@ class SecuritySettings extends Component {
{ {
authenticationEnabled && authenticationEnabled &&
<FormGroup> <FormGroup>
<FormLabel>Username</FormLabel> <FormLabel>
{translate('Username')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
@ -107,7 +112,9 @@ class SecuritySettings extends Component {
{ {
authenticationEnabled && authenticationEnabled &&
<FormGroup> <FormGroup>
<FormLabel>Password</FormLabel> <FormLabel>
{translate('Password')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.PASSWORD} type={inputTypes.PASSWORD}
@ -119,13 +126,15 @@ class SecuritySettings extends Component {
} }
<FormGroup> <FormGroup>
<FormLabel>API Key</FormLabel> <FormLabel>
{translate('APIKey')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="apiKey" name="apiKey"
readOnly={true} readOnly={true}
helpTextWarning="Requires restart to take effect" helpTextWarning={translate('ApiKeyHelpTextWarning')}
buttons={[ buttons={[
<ClipboardButton <ClipboardButton
key="copy" key="copy"
@ -151,13 +160,15 @@ class SecuritySettings extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Certificate Validation</FormLabel> <FormLabel>
{translate('CertificateValidation')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.SELECT} type={inputTypes.SELECT}
name="certificateValidation" name="certificateValidation"
values={certificateValidationOptions} values={certificateValidationOptions}
helpText="Change how strict HTTPS certification validation is" helpText={translate('CertificateValidationHelpText')}
onChange={onInputChange} onChange={onInputChange}
{...certificateValidation} {...certificateValidation}
/> />
@ -166,9 +177,9 @@ class SecuritySettings extends Component {
<ConfirmModal <ConfirmModal
isOpen={this.state.isConfirmApiKeyResetModalOpen} isOpen={this.state.isConfirmApiKeyResetModalOpen}
kind={kinds.DANGER} kind={kinds.DANGER}
title="Reset API Key" title={translate('ResetAPIKey')}
message="Are you sure you want to reset your API Key?" message={translate('ResetAPIKeyMessageText')}
confirmLabel="Reset" confirmLabel={translate('Reset')}
onConfirm={this.onConfirmResetApiKey} onConfirm={this.onConfirmResetApiKey}
onCancel={this.onCloseResetApiKeyModal} onCancel={this.onCloseResetApiKeyModal}
/> />

@ -6,6 +6,7 @@ import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel'; import FormLabel from 'Components/Form/FormLabel';
import { inputTypes, sizes } from 'Helpers/Props'; import { inputTypes, sizes } from 'Helpers/Props';
import titleCase from 'Utilities/String/titleCase'; import titleCase from 'Utilities/String/titleCase';
import translate from 'Utilities/String/translate';
function UpdateSettings(props) { function UpdateSettings(props) {
const { const {
@ -45,24 +46,28 @@ function UpdateSettings(props) {
if (isDocker) { if (isDocker) {
return ( return (
<FieldSet legend="Updates"> <FieldSet legend={translate('Updates')}>
<div>Updating is disabled inside a docker container. Update the container image instead.</div> <div>
{translate('UpdatingIsDisabledInsideADockerContainerUpdateTheContainerImageInstead')}
</div>
</FieldSet> </FieldSet>
); );
} }
return ( return (
<FieldSet legend="Updates"> <FieldSet legend={translate('Updates')}>
<FormGroup <FormGroup
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
> >
<FormLabel>Branch</FormLabel> <FormLabel>
{translate('Branch')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="branch" name="branch"
helpText={usingExternalUpdateMechanism ? 'Branch used by external update mechanism' : 'Branch to use to update Lidarr'} helpText={usingExternalUpdateMechanism ? translate('UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism') : translate('UsingExternalUpdateMechanismBranchToUseToUpdateLidarr')}
helpLink="https://wiki.servarr.com/lidarr/faq#how-do-i-update-lidarr" helpLink="https://wiki.servarr.com/lidarr/faq#how-do-i-update-lidarr"
{...branch} {...branch}
onChange={onInputChange} onChange={onInputChange}
@ -78,12 +83,14 @@ function UpdateSettings(props) {
isAdvanced={true} isAdvanced={true}
size={sizes.MEDIUM} size={sizes.MEDIUM}
> >
<FormLabel>Automatic</FormLabel> <FormLabel>
{translate('Automatic')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="updateAutomatically" name="updateAutomatically"
helpText="Automatically download and install updates. You will still be able to install from System: Updates" helpText={translate('UpdateAutomaticallyHelpText')}
onChange={onInputChange} onChange={onInputChange}
{...updateAutomatically} {...updateAutomatically}
/> />
@ -93,13 +100,15 @@ function UpdateSettings(props) {
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
> >
<FormLabel>Mechanism</FormLabel> <FormLabel>
{translate('Mechanism')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.SELECT} type={inputTypes.SELECT}
name="updateMechanism" name="updateMechanism"
values={updateOptions} values={updateOptions}
helpText="Use Lidarr's built-in updater or a script" helpText={translate('UpdateMechanismHelpText')}
helpLink="https://wiki.servarr.com/lidarr/faq#how-do-i-update-lidarr" helpLink="https://wiki.servarr.com/lidarr/faq#how-do-i-update-lidarr"
onChange={onInputChange} onChange={onInputChange}
{...updateMechanism} {...updateMechanism}
@ -112,12 +121,14 @@ function UpdateSettings(props) {
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
> >
<FormLabel>Script Path</FormLabel> <FormLabel>
{translate('ScriptPath')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="updateScriptPath" 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} onChange={onInputChange}
{...updateScriptPath} {...updateScriptPath}
/> />

@ -13,6 +13,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds } from 'Helpers/Props'; import { inputTypes, kinds } from 'Helpers/Props';
import { stringSettingShape } from 'Helpers/Props/Shapes/settingShape'; import { stringSettingShape } from 'Helpers/Props/Shapes/settingShape';
import translate from 'Utilities/String/translate';
import styles from './EditImportListExclusionModalContent.css'; import styles from './EditImportListExclusionModalContent.css';
function EditImportListExclusionModalContent(props) { function EditImportListExclusionModalContent(props) {
@ -49,7 +50,9 @@ function EditImportListExclusionModalContent(props) {
{ {
!isFetching && !!error && !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} {...otherProps}
> >
<FormGroup> <FormGroup>
<FormLabel>Entity Name</FormLabel> <FormLabel>
{translate('EntityName')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="artistName" name="artistName"
helpText="The name of the artist/album to exclude (can be anything meaningful)" helpText={translate('ArtistNameHelpText')}
{...artistName} {...artistName}
onChange={onInputChange} onChange={onInputChange}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Musicbrainz Id</FormLabel> <FormLabel>
{translate('MusicbrainzId')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="foreignId" name="foreignId"
helpText="The Musicbrainz Id of the artist/album to exclude" helpText={translate('ForeignIdHelpText')}
{...foreignId} {...foreignId}
onChange={onInputChange} onChange={onInputChange}
/> />

@ -5,6 +5,7 @@ import Icon from 'Components/Icon';
import Link from 'Components/Link/Link'; import Link from 'Components/Link/Link';
import ConfirmModal from 'Components/Modal/ConfirmModal'; import ConfirmModal from 'Components/Modal/ConfirmModal';
import { icons, kinds } from 'Helpers/Props'; import { icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import EditImportListExclusionModalConnector from './EditImportListExclusionModalConnector'; import EditImportListExclusionModalConnector from './EditImportListExclusionModalConnector';
import styles from './ImportListExclusion.css'; import styles from './ImportListExclusion.css';
@ -85,9 +86,9 @@ class ImportListExclusion extends Component {
<ConfirmModal <ConfirmModal
isOpen={this.state.isDeleteImportListExclusionModalOpen} isOpen={this.state.isDeleteImportListExclusionModalOpen}
kind={kinds.DANGER} kind={kinds.DANGER}
title="Delete Import List Exclusion" title={translate('DeleteImportListExclusion')}
message="Are you sure you want to delete this import list exclusion?" message={translate('DeleteImportListExclusionMessageText')}
confirmLabel="Delete" confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteImportListExclusion} onConfirm={this.onConfirmDeleteImportListExclusion}
onCancel={this.onDeleteImportListExclusionModalClose} onCancel={this.onDeleteImportListExclusionModalClose}
/> />

@ -5,6 +5,7 @@ import Icon from 'Components/Icon';
import Link from 'Components/Link/Link'; import Link from 'Components/Link/Link';
import PageSectionContent from 'Components/Page/PageSectionContent'; import PageSectionContent from 'Components/Page/PageSectionContent';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import EditImportListExclusionModalConnector from './EditImportListExclusionModalConnector'; import EditImportListExclusionModalConnector from './EditImportListExclusionModalConnector';
import ImportListExclusion from './ImportListExclusion'; import ImportListExclusion from './ImportListExclusion';
import styles from './ImportListExclusions.css'; import styles from './ImportListExclusions.css';
@ -44,9 +45,9 @@ class ImportListExclusions extends Component {
} = this.props; } = this.props;
return ( return (
<FieldSet legend="Import List Exclusions"> <FieldSet legend={translate('ImportListExclusions')}>
<PageSectionContent <PageSectionContent
errorMessage="Unable to load Import List Exclusions" errorMessage={translate('UnableToLoadImportListExclusions')}
{...otherProps} {...otherProps}
> >
<div className={styles.importListExclusionsHeader}> <div className={styles.importListExclusionsHeader}>

@ -6,6 +6,7 @@ import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator'; import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector'; import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import translate from 'Utilities/String/translate';
import ImportListsExclusionsConnector from './ImportListExclusions/ImportListExclusionsConnector'; import ImportListsExclusionsConnector from './ImportListExclusions/ImportListExclusionsConnector';
import ImportListsConnector from './ImportLists/ImportListsConnector'; import ImportListsConnector from './ImportLists/ImportListsConnector';
@ -54,7 +55,7 @@ class ImportListSettings extends Component {
} = this.state; } = this.state;
return ( return (
<PageContent title="Import List Settings"> <PageContent title={translate('ImportListSettings')}>
<SettingsToolbarConnector <SettingsToolbarConnector
isSaving={isSaving} isSaving={isSaving}
hasPendingChanges={hasPendingChanges} hasPendingChanges={hasPendingChanges}
@ -63,7 +64,7 @@ class ImportListSettings extends Component {
<PageToolbarSeparator /> <PageToolbarSeparator />
<PageToolbarButton <PageToolbarButton
label="Test All Lists" label={translate('TestAllLists')}
iconName={icons.TEST} iconName={icons.TEST}
isSpinning={isTestingAll} isSpinning={isTestingAll}
onPress={dispatchTestAllImportLists} onPress={dispatchTestAllImportLists}

@ -10,6 +10,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import { kinds } from 'Helpers/Props'; import { kinds } from 'Helpers/Props';
import titleCase from 'Utilities/String/titleCase'; import titleCase from 'Utilities/String/titleCase';
import translate from 'Utilities/String/translate';
import AddImportListItem from './AddImportListItem'; import AddImportListItem from './AddImportListItem';
import styles from './AddImportListModalContent.css'; import styles from './AddImportListModalContent.css';
@ -42,7 +43,9 @@ class AddImportListModalContent extends Component {
{ {
!isSchemaFetching && !!schemaError && !isSchemaFetching && !!schemaError &&
<div>Unable to add a new list, please try again.</div> <div>
{translate('UnableToAddANewListPleaseTryAgain')}
</div>
} }
{ {
@ -50,8 +53,12 @@ class AddImportListModalContent extends Component {
<div> <div>
<Alert kind={kinds.INFO}> <Alert kind={kinds.INFO}>
<div>Lidarr supports multiple lists for importing Albums and Artists into the database.</div> <div>
<div>For more information on the individual lists, click on the info buttons.</div> {translate('LidarrSupportsMultipleListsForImportingAlbumsAndArtistsIntoTheDatabase')}
</div>
<div>
{translate('ForMoreInformationOnTheIndividualListsClickOnTheInfoButtons')}
</div>
</Alert> </Alert>
{ {
Object.keys(listGroups).map((key) => { Object.keys(listGroups).map((key) => {

@ -18,23 +18,24 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader'; import ModalHeader from 'Components/Modal/ModalHeader';
import Popover from 'Components/Tooltip/Popover'; import Popover from 'Components/Tooltip/Popover';
import { icons, inputTypes, kinds, tooltipPositions } from 'Helpers/Props'; import { icons, inputTypes, kinds, tooltipPositions } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './EditImportListModalContent.css'; import styles from './EditImportListModalContent.css';
function ImportListMonitoringOptionsPopoverContent() { function ImportListMonitoringOptionsPopoverContent() {
return ( return (
<DescriptionList> <DescriptionList>
<DescriptionListItem <DescriptionListItem
title="None" title={translate('None')}
data="Do not monitor artists or albums" data="Do not monitor artists or albums"
/> />
<DescriptionListItem <DescriptionListItem
title="Specific Album" title={translate('SpecificAlbum')}
data="Monitor artists but only monitor albums explicitly included in the list" data="Monitor artists but only monitor albums explicitly included in the list"
/> />
<DescriptionListItem <DescriptionListItem
title="All Artist Albums" title={translate('AllArtistAlbums')}
data="Monitor artists and all albums for each artist included on the import list" data="Monitor artists and all albums for each artist included on the import list"
/> />
</DescriptionList> </DescriptionList>
@ -94,7 +95,9 @@ function EditImportListModalContent(props) {
{ {
!isFetching && !!error && !isFetching && !!error &&
<div>Unable to add a new list, please try again.</div> <div>
{translate('UnableToAddANewListPleaseTryAgain')}
</div>
} }
{ {
@ -110,7 +113,9 @@ function EditImportListModalContent(props) {
</Alert> </Alert>
} }
<FormGroup> <FormGroup>
<FormLabel>Name</FormLabel> <FormLabel>
{translate('Name')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
@ -121,12 +126,14 @@ function EditImportListModalContent(props) {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Enable Automatic Add</FormLabel> <FormLabel>
{translate('EnableAutomaticAdd')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="enableAutomaticAdd" name="enableAutomaticAdd"
helpText={'Add artist/albums to Lidarr when syncs are performed via the UI or by Lidarr'} helpText={translate('EnableAutomaticAddHelpText')}
{...enableAutomaticAdd} {...enableAutomaticAdd}
onChange={onInputChange} onChange={onInputChange}
/> />
@ -143,7 +150,7 @@ function EditImportListModalContent(props) {
name={icons.INFO} name={icons.INFO}
/> />
} }
title="Monitoring Options" title={translate('MonitoringOptions')}
body={<ImportListMonitoringOptionsPopoverContent />} body={<ImportListMonitoringOptionsPopoverContent />}
position={tooltipPositions.RIGHT} position={tooltipPositions.RIGHT}
/> />
@ -153,43 +160,49 @@ function EditImportListModalContent(props) {
type={inputTypes.SELECT} type={inputTypes.SELECT}
name="shouldMonitor" name="shouldMonitor"
values={monitorOptions} values={monitorOptions}
helpText={'Monitor artists and albums added from this list'} helpText={translate('ShouldMonitorHelpText')}
{...shouldMonitor} {...shouldMonitor}
onChange={onInputChange} onChange={onInputChange}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Root Folder</FormLabel> <FormLabel>
{translate('RootFolder')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.ROOT_FOLDER_SELECT} type={inputTypes.ROOT_FOLDER_SELECT}
name="rootFolderPath" name="rootFolderPath"
helpText={'Root Folder list items will be added to'} helpText={translate('RootFolderPathHelpText')}
{...rootFolderPath} {...rootFolderPath}
onChange={onInputChange} onChange={onInputChange}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Quality Profile</FormLabel> <FormLabel>
{translate('QualityProfile')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.QUALITY_PROFILE_SELECT} type={inputTypes.QUALITY_PROFILE_SELECT}
name="qualityProfileId" name="qualityProfileId"
helpText={'Quality Profile list items should be added with'} helpText={translate('QualityProfileIdHelpText')}
{...qualityProfileId} {...qualityProfileId}
onChange={onInputChange} onChange={onInputChange}
/> />
</FormGroup> </FormGroup>
<FormGroup className={showMetadataProfile ? undefined : styles.hideMetadataProfile}> <FormGroup className={showMetadataProfile ? undefined : styles.hideMetadataProfile}>
<FormLabel>Metadata Profile</FormLabel> <FormLabel>
{translate('MetadataProfile')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.METADATA_PROFILE_SELECT} type={inputTypes.METADATA_PROFILE_SELECT}
name="metadataProfileId" name="metadataProfileId"
helpText={'Metadata Profile list items should be added with'} helpText={translate('MetadataProfileIdHelpText')}
{...metadataProfileId} {...metadataProfileId}
includeNone={true} includeNone={true}
onChange={onInputChange} onChange={onInputChange}
@ -197,12 +210,14 @@ function EditImportListModalContent(props) {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Lidarr Tags</FormLabel> <FormLabel>
{translate('LidarrTags')}
</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TAG} type={inputTypes.TAG}
name="tags" name="tags"
helpText="Add artists from this list with these tags" helpText={translate('TagsHelpText')}
{...tags} {...tags}
onChange={onInputChange} onChange={onInputChange}
/> />

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save