Add translations to frontend/InteractiveImport

This commit is contained in:
Stevie Robinson 2023-08-14 01:28:16 +02:00 committed by GitHub
parent 16d95ea6bf
commit 060b66aa39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 161 additions and 63 deletions

View File

@ -71,7 +71,7 @@ interface SelectEpisodeModalContentProps {
isAnime: boolean;
sortKey?: string;
sortDirection?: string;
modalTitle?: string;
modalTitle: string;
onEpisodesSelect(selectedEpisodes: SelectedEpisode[]): unknown;
onModalClose(): unknown;
}
@ -103,7 +103,7 @@ function SelectEpisodeModalContent(props: SelectEpisodeModalContentProps) {
const dispatch = useDispatch();
const filterEpisodeNumber = parseInt(filter);
const errorMessage = getErrorMessage(error, 'Unable to load episodes');
const errorMessage = getErrorMessage(error, translate('EpisodesLoadError'));
const selectedCount = selectedIds.length;
const selectedEpisodesCount = getSelectedIds(selectedState).length;
const selectionIsValid =
@ -197,13 +197,15 @@ function SelectEpisodeModalContent(props: SelectEpisodeModalContentProps) {
if (!details) {
details =
selectedCount > 1
? `${selectedCount} selected files`
: `${selectedCount} selected file`;
? translate('CountSelectedFiles', { selectedCount })
: translate('CountSelectedFile', { selectedCount });
}
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>{modalTitle} - Select Episode(s)</ModalHeader>
<ModalHeader>
{translate('SelectEpisodesModalTitle', { modalTitle })}
</ModalHeader>
<ModalBody
className={styles.modalBody}
@ -211,7 +213,7 @@ function SelectEpisodeModalContent(props: SelectEpisodeModalContentProps) {
>
<TextInput
className={styles.filterInput}
placeholder="Filter episodes by title or number"
placeholder={translate('FilterEpisodesPlaceholder')}
name="filter"
value={filter}
autoFocus={true}
@ -256,7 +258,7 @@ function SelectEpisodeModalContent(props: SelectEpisodeModalContentProps) {
) : null}
{isPopulated && !items.length
? 'No episodes were found for the selected season'
? translate('NoEpisodesFoundForSelectedSeason')
: null}
</Scroller>
</ModalBody>
@ -265,14 +267,14 @@ function SelectEpisodeModalContent(props: SelectEpisodeModalContentProps) {
<div className={styles.details}>{details}</div>
<div className={styles.buttons}>
<Button onPress={onModalClose}>Cancel</Button>
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
<Button
kind={kinds.SUCCESS}
isDisabled={!selectionIsValid}
onPress={onEpisodesSelectWrapper}
>
Select Episodes
{translate('SelectEpisodes')}
</Button>
</div>
</ModalFooter>

View File

@ -100,7 +100,7 @@ function InteractiveImportSelectFolderModalContent(
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{modalTitle} - {translate('SelectFolder')}
{translate('SelectFolderModalTitle', { modalTitle })}
</ModalHeader>
<ModalBody>

View File

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

View File

@ -147,9 +147,19 @@ const COLUMNS = [
];
const importModeOptions = [
{ key: 'chooseImportMode', value: 'Choose Import Mode', disabled: true },
{ key: 'move', value: 'Move Files' },
{ key: 'copy', value: 'Hardlink/Copy Files' },
{
key: 'chooseImportMode',
value: () => translate('ChooseImportMode'),
disabled: true,
},
{
key: 'move',
value: () => translate('MoveFiles'),
},
{
key: 'copy',
value: () => translate('HardlinkCopyFiles'),
},
];
function isSameEpisodeFile(
@ -260,12 +270,31 @@ function InteractiveImportModalContent(
useState<string | null>(null);
const [selectState, setSelectState] = useSelectState();
const [bulkSelectOptions, setBulkSelectOptions] = useState([
{ key: 'select', value: 'Select...', disabled: true },
{ key: 'season', value: 'Select Season' },
{ key: 'episode', value: 'Select Episode(s)' },
{ key: 'quality', value: 'Select Quality' },
{ key: 'releaseGroup', value: 'Select Release Group' },
{ key: 'language', value: 'Select Language' },
{
key: 'select',
value: translate('SelectDropdown'),
disabled: true,
},
{
key: 'season',
value: translate('SelectSeason'),
},
{
key: 'episode',
value: translate('SelectEpisodes'),
},
{
key: 'quality',
value: translate('SelectQuality'),
},
{
key: 'releaseGroup',
value: translate('SelectReleaseGroup'),
},
{
key: 'language',
value: translate('SelectLanguage'),
},
]);
const { allSelected, allUnselected, selectedState } = selectState;
const previousIsDeleting = usePrevious(isDeleting);
@ -296,7 +325,7 @@ function InteractiveImportModalContent(
newBulkSelectOptions.splice(1, 0, {
key: 'series',
value: 'Select Series',
value: translate('SelectSeries'),
});
setBulkSelectOptions(newBulkSelectOptions);
@ -410,7 +439,9 @@ function InteractiveImportModalContent(
const files: InteractiveImportCommandOptions[] = [];
if (finalImportMode === 'chooseImportMode') {
setInteractiveImportErrorMessage('An import mode must be selected');
setInteractiveImportErrorMessage(
translate('InteractiveImportNoImportMode')
);
return;
}
@ -431,35 +462,35 @@ function InteractiveImportModalContent(
if (!series) {
setInteractiveImportErrorMessage(
'Series must be chosen for each selected file'
translate('InteractiveImportNoSeries')
);
return;
}
if (isNaN(seasonNumber)) {
setInteractiveImportErrorMessage(
'Season must be chosen for each selected file'
translate('InteractiveImportNoSeason')
);
return;
}
if (!episodes || !episodes.length) {
setInteractiveImportErrorMessage(
'One or more episodes must be chosen for each selected file'
translate('InteractiveImportNoEpisode')
);
return;
}
if (!quality) {
setInteractiveImportErrorMessage(
'Quality must be chosen for each selected file'
translate('InteractiveImportNoQuality')
);
return;
}
if (!languages) {
setInteractiveImportErrorMessage(
'Language(s) must be chosen for each selected file'
translate('InteractiveImportNoLanguage')
);
return;
}
@ -699,7 +730,7 @@ function InteractiveImportModalContent(
const errorMessage = getErrorMessage(
error,
'Unable to load manual import items'
translate('InteractiveImportLoadError')
);
return (
@ -716,7 +747,9 @@ function InteractiveImportModalContent(
<Icon name={icons.FILTER} size={22} />
<div className={styles.filterText}>
{filterExistingFiles ? 'Unmapped Files Only' : 'All Files'}
{filterExistingFiles
? translate('UnmappedFilesOnly')
: translate('AllFiles')}
</div>
</MenuButton>
@ -726,7 +759,7 @@ function InteractiveImportModalContent(
isSelected={!filterExistingFiles}
onPress={onFilterExistingFilesChange}
>
All Files
{translate('AllFiles')}
</SelectedMenuItem>
<SelectedMenuItem
@ -734,7 +767,7 @@ function InteractiveImportModalContent(
isSelected={filterExistingFiles}
onPress={onFilterExistingFilesChange}
>
Unmapped Files Only
{translate('UnmappedFilesOnly')}
</SelectedMenuItem>
</MenuContent>
</Menu>
@ -777,7 +810,7 @@ function InteractiveImportModalContent(
) : null}
{isPopulated && !items.length && !isFetching
? 'No video files were found in the selected folder'
? translate('InteractiveImportNoFilesFound')
: null}
</ModalBody>
@ -793,7 +826,7 @@ function InteractiveImportModalContent(
}
onPress={onDeleteSelectedPress}
>
Delete
{translate('Delete')}
</SpinnerButton>
) : null}
@ -831,7 +864,7 @@ function InteractiveImportModalContent(
isDisabled={!selectedIds.length || !!invalidRowsSelected.length}
onPress={onImportSelectedPress}
>
Import
{translate('Import')}
</Button>
</div>
</ModalFooter>
@ -891,9 +924,9 @@ function InteractiveImportModalContent(
<ConfirmModal
isOpen={isConfirmDeleteModalOpen}
kind={kinds.DANGER}
title="Delete Selected Episode Files"
message={'Are you sure you want to delete the selected episode files?'}
confirmLabel="Delete"
title={translate('DeleteSelectedEpisodeFiles')}
message={translate('DeleteSelectedEpisodeFilesHelpText')}
confirmLabel={translate('Delete')}
onConfirm={onConfirmDelete}
onCancel={onConfirmDeleteModalClose}
/>

View File

@ -348,7 +348,9 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
{isSeriesColumnVisible ? (
<TableRowCellButton
isDisabled={!allowSeriesChange}
title={allowSeriesChange ? 'Click to change series' : undefined}
title={
allowSeriesChange ? translate('ClickToChangeSeries') : undefined
}
onPress={onSelectSeriesPress}
>
{showSeriesPlaceholder ? (
@ -361,7 +363,7 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
<TableRowCellButton
isDisabled={!series}
title={series ? 'Click to change season' : undefined}
title={series ? translate('ClickToChangeSeason') : undefined}
onPress={onSelectSeasonPress}
>
{showSeasonNumberPlaceholder ? (
@ -379,7 +381,7 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
isDisabled={!series || requiresSeasonNumber}
title={
series && !requiresSeasonNumber
? 'Click to change episode'
? translate('ClickToChangeEpisode')
: undefined
}
onPress={onSelectEpisodePress}
@ -392,7 +394,7 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
</TableRowCellButton>
<TableRowCellButton
title="Click to change release group"
title={translate('ClickToChangeReleaseGroup')}
onPress={onSelectReleaseGroupPress}
>
{showReleaseGroupPlaceholder ? (
@ -404,7 +406,7 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
<TableRowCellButton
className={styles.quality}
title="Click to change quality"
title={translate('ClickToChangeQuality')}
onPress={onSelectQualityPress}
>
{showQualityPlaceholder && <InteractiveImportRowCellPlaceholder />}
@ -416,7 +418,7 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
<TableRowCellButton
className={styles.languages}
title="Click to change language"
title={translate('ClickToChangeLanguage')}
onPress={onSelectLanguagePress}
>
{showLanguagePlaceholder && <InteractiveImportRowCellPlaceholder />}
@ -450,7 +452,7 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
{rejections.length ? (
<Popover
anchor={<Icon name={icons.DANGER} kind={kinds.DANGER} />}
title="Release Rejected"
title={translate('ReleaseRejected')}
body={
<ul>
{rejections.map((rejection, index) => {

View File

@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useState } from 'react';
import Modal from 'Components/Modal/Modal';
import usePrevious from 'Helpers/Hooks/usePrevious';
import { sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import InteractiveImportSelectFolderModalContent from './Folder/InteractiveImportSelectFolderModalContent';
import InteractiveImportModalContent from './Interactive/InteractiveImportModalContent';
@ -18,7 +19,7 @@ function InteractiveImportModal(props: InteractiveImportModalProps) {
isOpen,
folder,
downloadId,
modalTitle = 'Manual Import',
modalTitle = translate('ManualImport'),
onModalClose,
...otherProps
} = props;

View File

@ -16,6 +16,7 @@ import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import Language from 'Language/Language';
import createLanguagesSelector from 'Store/Selectors/createLanguagesSelector';
import translate from 'Utilities/String/translate';
import styles from './SelectLanguageModalContent.css';
interface SelectLanguageModalContentProps {
@ -78,13 +79,15 @@ function SelectLanguageModalContent(props: SelectLanguageModalContentProps) {
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>{modalTitle} - Select Language</ModalHeader>
<ModalHeader>
{translate('SelectLanguageModalTitle', { modalTitle })}
</ModalHeader>
<ModalBody>
{isFetching ? <LoadingIndicator /> : null}
{!isFetching && error ? (
<Alert kind={kinds.DANGER}>Unable to load Languages</Alert>
<Alert kind={kinds.DANGER}>{translate('LanguagesLoadError')}</Alert>
) : null}
{isPopulated && !error ? (
@ -111,10 +114,10 @@ function SelectLanguageModalContent(props: SelectLanguageModalContentProps) {
</ModalBody>
<ModalFooter>
<Button onPress={onModalClose}>Cancel</Button>
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
<Button kind={kinds.SUCCESS} onPress={onLanguagesSelectWrapper}>
Select Languages
{translate('SelectLanguages')}
</Button>
</ModalFooter>
</ModalContent>

View File

@ -19,6 +19,7 @@ import Quality, { QualityModel } from 'Quality/Quality';
import { fetchQualityProfileSchema } from 'Store/Actions/settingsActions';
import { CheckInputChanged } from 'typings/inputs';
import getQualities from 'Utilities/Quality/getQualities';
import translate from 'Utilities/String/translate';
interface QualitySchemaState {
isFetching: boolean;
@ -128,13 +129,13 @@ function SelectQualityModalContent(props: SelectQualityModalContentProps) {
{isFetching && <LoadingIndicator />}
{!isFetching && error ? (
<Alert kind={kinds.DANGER}>Unable to load qualities</Alert>
<Alert kind={kinds.DANGER}>{translate('QualitiesLoadError')}</Alert>
) : null}
{isPopulated && !error ? (
<Form>
<FormGroup>
<FormLabel>Quality</FormLabel>
<FormLabel>{translate('Quality')}</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
@ -146,7 +147,7 @@ function SelectQualityModalContent(props: SelectQualityModalContentProps) {
</FormGroup>
<FormGroup>
<FormLabel>Proper</FormLabel>
<FormLabel>{translate('Proper')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
@ -157,7 +158,7 @@ function SelectQualityModalContent(props: SelectQualityModalContentProps) {
</FormGroup>
<FormGroup>
<FormLabel>Real</FormLabel>
<FormLabel>{translate('Real')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
@ -174,7 +175,7 @@ function SelectQualityModalContent(props: SelectQualityModalContentProps) {
<Button onPress={onModalClose}>Cancel</Button>
<Button kind={kinds.SUCCESS} onPress={onQualitySelectWrapper}>
Select Quality
{translate('SelectQuality')}
</Button>
</ModalFooter>
</ModalContent>

View File

@ -9,6 +9,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds, scrollDirections } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './SelectReleaseGroupModalContent.css';
interface SelectReleaseGroupModalContentProps {
@ -37,7 +38,9 @@ function SelectReleaseGroupModalContent(
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>{modalTitle} - Set Release Group</ModalHeader>
<ModalHeader>
{translate('SetReleaseGroupModalTitle', { modalTitle })}
</ModalHeader>
<ModalBody
className={styles.modalBody}
@ -45,7 +48,7 @@ function SelectReleaseGroupModalContent(
>
<Form>
<FormGroup>
<FormLabel>Release Group</FormLabel>
<FormLabel>{translate('ReleaseGroup')}</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
@ -59,10 +62,10 @@ function SelectReleaseGroupModalContent(
</ModalBody>
<ModalFooter>
<Button onPress={onModalClose}>Cancel</Button>
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
<Button kind={kinds.SUCCESS} onPress={onReleaseGroupSelectWrapper}>
Set Release Group
{translate('SetReleaseGroup')}
</Button>
</ModalFooter>
</ModalContent>

View File

@ -7,6 +7,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { Season } from 'Series/Series';
import { createSeriesSelectorForHook } from 'Store/Selectors/createSeriesSelector';
import translate from 'Utilities/String/translate';
import SelectSeasonRow from './SelectSeasonRow';
interface SelectSeasonModalContentProps {
@ -25,7 +26,9 @@ function SelectSeasonModalContent(props: SelectSeasonModalContentProps) {
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>{modalTitle} - Select Season</ModalHeader>
<ModalHeader>
{translate('SelectSeasonModalTitle', { modalTitle })}
</ModalHeader>
<ModalBody>
{seasons.map((item) => {
@ -40,7 +43,7 @@ function SelectSeasonModalContent(props: SelectSeasonModalContentProps) {
</ModalBody>
<ModalFooter>
<Button onPress={onModalClose}>Cancel</Button>
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
</ModalFooter>
</ModalContent>
);

View File

@ -1,5 +1,6 @@
import React, { useCallback } from 'react';
import Link from 'Components/Link/Link';
import translate from 'Utilities/String/translate';
import styles from './SelectSeasonRow.css';
interface SelectSeasonRowProps {
@ -20,7 +21,9 @@ function SelectSeasonRow(props: SelectSeasonRowProps) {
component="div"
onPress={onSeasonSelectWrapper}
>
{seasonNumber === 0 ? 'Specials' : `Season ${seasonNumber}`}
{seasonNumber === 0
? translate('Specials')
: translate('SeasonNumberToken', { seasonNumber })}
</Link>
);
}

View File

@ -10,6 +10,7 @@ import Scroller from 'Components/Scroller/Scroller';
import { scrollDirections } from 'Helpers/Props';
import Series from 'Series/Series';
import createAllSeriesSelector from 'Store/Selectors/createAllSeriesSelector';
import translate from 'Utilities/String/translate';
import SelectSeriesRow from './SelectSeriesRow';
import styles from './SelectSeriesModalContent.css';
@ -61,7 +62,7 @@ function SelectSeriesModalContent(props: SelectSeriesModalContentProps) {
>
<TextInput
className={styles.filterInput}
placeholder="Filter series"
placeholder={translate('FilterSeriesPlaceholder')}
name="filter"
value={filter}
autoFocus={true}
@ -83,7 +84,7 @@ function SelectSeriesModalContent(props: SelectSeriesModalContentProps) {
</ModalBody>
<ModalFooter>
<Button onPress={onModalClose}>Cancel</Button>
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
</ModalFooter>
</ModalContent>
);

View File

@ -61,6 +61,7 @@
"AirsTimeOn": "{time} on {networkLabel}",
"AirsTomorrowOn": "Tomorrow at {time} on {networkLabel}",
"All": "All",
"AllFiles": "All Files",
"AllResultsAreHiddenByTheAppliedFilter": "All results are hidden by the applied filter",
"AllSeriesInRootFolderHaveBeenImported": "All series in {path} have been imported",
"AllTitles": "All Titles",
@ -166,10 +167,17 @@
"ChmodFolderHelpText": "Octal, applied during import/rename to media folders and files (without execute bits)",
"ChmodFolderHelpTextWarning": "This only works if the user running sonarr is the owner of the file. It's better to ensure the download client sets the permissions properly.",
"ChooseAnotherFolder": "Choose another folder",
"ChooseImportMode": "Choose Import Mode",
"ChownGroup": "chown Group",
"ChownGroupHelpText": "Group name or gid. Use gid for remote file systems.",
"ChownGroupHelpTextWarning": "This only works if the user running sonarr is the owner of the file. It's better to ensure the download client uses the same group as sonarr.",
"Clear": "Clear",
"ClickToChangeEpisode": "Click to change episode",
"ClickToChangeLanguage": "Click to change language",
"ClickToChangeQuality": "Click to change quality",
"ClickToChangeReleaseGroup": "Click to change release group",
"ClickToChangeSeason": "Click to change season",
"ClickToChangeSeries": "Click to change series",
"ClientPriority": "Client Priority",
"Clone": "Clone",
"CloneAutoTag": "Clone Auto Tag",
@ -205,6 +213,8 @@
"CountImportListsSelected": "{count} import list(s) selected",
"CountIndexersSelected": "{count} indexer(s) selected",
"CountSeasons": "{count} Seasons",
"CountSelectedFile": "{selectedCount} selected file",
"CountSelectedFiles": "{selectedCount} selected files",
"CreateEmptySeriesFolders": "Create Empty Series Folders",
"CreateEmptySeriesFoldersHelpText": "Create missing series folders during disk scan",
"CreateGroup": "Create Group",
@ -277,6 +287,8 @@
"DeleteRootFolderMessageText": "Are you sure you want to delete the root folder '{path}'?",
"DeleteSelectedDownloadClients": "Delete Download Client(s)",
"DeleteSelectedDownloadClientsMessageText": "Are you sure you want to delete {count} selected download client(s)?",
"DeleteSelectedEpisodeFiles": "Delete Selected Episode Files",
"DeleteSelectedEpisodeFilesHelpText": "Are you sure you want to delete the selected episode files?",
"DeleteSelectedImportLists": "Delete Import List(s)",
"DeleteSelectedImportListsMessageText": "Are you sure you want to delete {count} selected import list(s)?",
"DeleteSelectedIndexers": "Delete Indexer(s)",
@ -401,6 +413,7 @@
"EpisodeTitleRequired": "Episode Title Required",
"EpisodeTitleRequiredHelpText": "Prevent importing for up to 48 hours if the episode title is in the naming format and the episode title is TBA",
"Episodes": "Episodes",
"EpisodesLoadError": "Unable to load episodes",
"Error": "Error",
"ErrorLoadingContent": "There was an error loading this content",
"ErrorLoadingContents": "Error loading contents",
@ -445,6 +458,7 @@
"FilterDoesNotEndWith": "does not end with",
"FilterDoesNotStartWith": "does not start with",
"FilterEndsWith": "ends with",
"FilterEpisodesPlaceholder": "Filter episodes by title or number",
"FilterEqual": "equal",
"FilterGreaterThan": "greater than",
"FilterGreaterThanOrEqual": "greater than or equal",
@ -459,6 +473,7 @@
"FilterNotEqual": "not equal",
"FilterNotInLast": "not in the last",
"FilterNotInNext": "not in the next",
"FilterSeriesPlaceholder": "Filter series",
"FilterStartsWith": "starts with",
"FinaleTooltip": "Series or season finale",
"FirstDayOfWeek": "First Day of Week",
@ -484,6 +499,7 @@
"Grabbed": "Grabbed",
"GrabbedHistoryTooltip": "Episode grabbed from {indexer} and sent to {downloadClient}",
"Group": "Group",
"HardlinkCopyFiles": "Hardlink/Copy Files",
"HasMissingSeason": "Has Missing Season",
"Health": "Health",
"Here": "here",
@ -577,6 +593,14 @@
"InstanceName": "Instance Name",
"InstanceNameHelpText": "Instance name in tab and for Syslog app name",
"InteractiveImport": "Interactive Import",
"InteractiveImportLoadError": "Unable to load manual import items",
"InteractiveImportNoEpisode": "One or more episodes must be chosen for each selected file",
"InteractiveImportNoFilesFound": "No video files were found in the selected folder",
"InteractiveImportNoImportMode": "An import mode must be selected",
"InteractiveImportNoLanguage": "Language(s) must be chosen for each selected file",
"InteractiveImportNoQuality": "Quality must be chosen for each selected file",
"InteractiveImportNoSeason": "Season must be chosen for each selected file",
"InteractiveImportNoSeries": "Series must be chosen for each selected file",
"InteractiveSearch": "Interactive Search",
"Interval": "Interval",
"InvalidFormat": "Invalid Format",
@ -629,6 +653,7 @@
"ManageIndexers": "Manage Indexers",
"ManageLists": "Manage Lists",
"Manual": "Manual",
"ManualImport": "Manual Import",
"ManualImportItemsLoadError": "Unable to load manual import items",
"MappedNetworkDrivesWindowsService": "Mapped network drives are not available when running as a Windows Service, see the [FAQ](https://wiki.servarr.com/sonarr/faq#why-cant-sonarr-see-my-files-on-a-remote-server) for more information.",
"MarkAsFailed": "Mark as Failed",
@ -701,6 +726,7 @@
"MoreInfo": "More Info",
"MountHealthCheckMessage": "Mount containing a series path is mounted read-only: ",
"MoveAutomatically": "Move Automatically",
"MoveFiles": "Move Files",
"MultiEpisode": "Multi Episode",
"MultiEpisodeInvalidFormat": "Multi Episode: Invalid Format",
"MultiEpisodeStyle": "Multi Episode Style",
@ -730,6 +756,7 @@
"NoDownloadClientsFound": "No download clients found",
"NoEpisodeHistory": "No episode history",
"NoEpisodeOverview": "No episode overview",
"NoEpisodesFoundForSelectedSeason": "No episodes were found for the selected season",
"NoEventsFound": "No events found",
"NoHistoryBlocklist": "No history blocklist",
"NoHistoryFound": "No history found",
@ -877,6 +904,7 @@
"ReleaseProfileTagHelpText": "Release profiles will apply to series with at least one matching tag. Leave blank to apply to all series",
"ReleaseProfiles": "Release Profiles",
"ReleaseProfilesLoadError": "Unable to load Release Profiles",
"ReleaseRejected": "Release Rejected",
"ReleaseTitle": "Release Title",
"Reload": "Reload",
"RemotePath": "Remote Path",
@ -1007,13 +1035,26 @@
"SeasonFolder": "Season Folder",
"SeasonFolderFormat": "Season Folder Format",
"SeasonNumber": "Season Number",
"SeasonNumberToken": "Season {seasonNumber}",
"SeasonPack": "Season Pack",
"SeasonPremiere": "Season Premiere",
"SeasonPremieresOnly": "Season Premieres Only",
"Seasons": "Seasons",
"Security": "Security",
"Seeders": "Seeders",
"SelectDropdown": "Select...",
"SelectEpisodes": "Select Episode(s)",
"SelectEpisodesModalTitle": "{modalTitle} - Select Episode(s)",
"SelectFolder": "Select Folder",
"SelectFolderModalTitle": "{modalTitle} - Select Folder",
"SelectLanguage": "Select Language",
"SelectLanguageModalTitle": "{modalTitle} - Select Language",
"SelectLanguages": "Select Languages",
"SelectQuality": "Select Quality",
"SelectReleaseGroup": "Select Release Group",
"SelectSeason": "Select Season",
"SelectSeasonModalTitle": "{modalTitle} - Select Season",
"SelectSeries": "Select Series",
"SendAnonymousUsageData": "Send Anonymous Usage Data",
"Series": "Series",
"SeriesAndEpisodeInformationIsProvidedByTheTVDB": "Series and episode information is provided by TheTVDB.com. [Please consider supporting them](https://www.thetvdb.com/subscribe).",
@ -1034,6 +1075,8 @@
"SetPermissions": "Set Permissions",
"SetPermissionsLinuxHelpText": "Should chmod be run when files are imported/renamed?",
"SetPermissionsLinuxHelpTextWarning": "If you're unsure what these settings do, do not alter them.",
"SetReleaseGroup": "Set Release Group",
"SetReleaseGroupModalTitle": "{modalTitle} - Set Release Group",
"SetTags": "Set Tags",
"Settings": "Settings",
"ShortDateFormat": "Short Date Format",
@ -1069,6 +1112,7 @@
"Space": "Space",
"Special": "Special",
"SpecialEpisode": "Special Episode",
"Specials": "Specials",
"SpecialsFolderFormat": "Specials Folder Format",
"SslCertPassword": "SSL Cert Password",
"SslCertPasswordHelpText": "Password for pfx file",
@ -1168,6 +1212,7 @@
"Unknown": "Unknown",
"UnknownEventTooltip": "Unknown event",
"Unlimited": "Unlimited",
"UnmappedFilesOnly": "Unmapped Files Only",
"UnmappedFolders": "Unmapped Folders",
"UnmonitorDeletedEpisodes": "Unmonitor Deleted Episodes",
"UnmonitorDeletedEpisodesHelpText": "Episodes deleted from disk are automatically unmonitored in Sonarr",