refactor(lang): use global strings where appropriate and remove unused strings (#1265)

pull/1271/head
TheCatLady 3 years ago committed by GitHub
parent 544c2d9442
commit e393b53b29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -27,14 +27,10 @@ import Transition from '../Transition';
const messages = defineMessages({ const messages = defineMessages({
overviewunavailable: 'Overview unavailable.', overviewunavailable: 'Overview unavailable.',
overview: 'Overview', overview: 'Overview',
movies: 'Movies',
numberofmovies: '{count} Movies', numberofmovies: '{count} Movies',
requesting: 'Requesting…',
request: 'Request',
requestcollection: 'Request Collection', requestcollection: 'Request Collection',
requestswillbecreated: requestswillbecreated:
'The following titles will have requests created for them:', 'The following titles will have requests created for them:',
request4k: 'Request 4K',
requestcollection4k: 'Request Collection in 4K', requestcollection4k: 'Request Collection in 4K',
requestswillbecreated4k: requestswillbecreated4k:
'The following titles will have 4K requests created for them:', 'The following titles will have 4K requests created for them:',
@ -242,8 +238,10 @@ const CollectionDetails: React.FC<CollectionDetailsProps> = ({
onOk={() => requestBundle()} onOk={() => requestBundle()}
okText={ okText={
isRequesting isRequesting
? intl.formatMessage(messages.requesting) ? intl.formatMessage(globalMessages.requesting)
: intl.formatMessage(is4k ? messages.request4k : messages.request) : intl.formatMessage(
is4k ? globalMessages.request4k : globalMessages.request
)
} }
okDisabled={isRequesting} okDisabled={isRequesting}
okButtonType="primary" okButtonType="primary"
@ -431,7 +429,7 @@ const CollectionDetails: React.FC<CollectionDetailsProps> = ({
</div> </div>
<div className="slider-header"> <div className="slider-header">
<div className="slider-title"> <div className="slider-title">
<span>{intl.formatMessage(messages.movies)}</span> <span>{intl.formatMessage(globalMessages.movies)}</span>
</div> </div>
</div> </div>
<Slider <Slider

@ -1,17 +1,14 @@
import React from 'react'; import React from 'react';
import { useIntl } from 'react-intl';
import { import {
TvResult,
MovieResult, MovieResult,
PersonResult, PersonResult,
TvResult,
} from '../../../../server/models/Search'; } from '../../../../server/models/Search';
import TitleCard from '../../TitleCard';
import useVerticalScroll from '../../../hooks/useVerticalScroll'; import useVerticalScroll from '../../../hooks/useVerticalScroll';
import globalMessages from '../../../i18n/globalMessages';
import PersonCard from '../../PersonCard'; import PersonCard from '../../PersonCard';
import { defineMessages, useIntl } from 'react-intl'; import TitleCard from '../../TitleCard';
const messages = defineMessages({
noresults: 'No results.',
});
interface ListViewProps { interface ListViewProps {
items?: (TvResult | MovieResult | PersonResult)[]; items?: (TvResult | MovieResult | PersonResult)[];
@ -34,7 +31,7 @@ const ListView: React.FC<ListViewProps> = ({
<> <>
{isEmpty && ( {isEmpty && (
<div className="w-full mt-64 text-2xl text-center text-gray-400"> <div className="w-full mt-64 text-2xl text-center text-gray-400">
{intl.formatMessage(messages.noresults)} {intl.formatMessage(globalMessages.noresults)}
</div> </div>
)} )}
<ul className="cards-vertical"> <ul className="cards-vertical">

@ -36,7 +36,6 @@ import StatusBadge from '../StatusBadge';
const messages = defineMessages({ const messages = defineMessages({
releasedate: 'Release Date', releasedate: 'Release Date',
status: 'Status',
revenue: 'Revenue', revenue: 'Revenue',
budget: 'Budget', budget: 'Budget',
watchtrailer: 'Watch Trailer', watchtrailer: 'Watch Trailer',
@ -55,8 +54,6 @@ const messages = defineMessages({
'* This will irreversibly remove all data for this movie, including any requests. If this item exists in your Plex library, the media information will be recreated during the next scan.', '* This will irreversibly remove all data for this movie, including any requests. If this item exists in your Plex library, the media information will be recreated during the next scan.',
studio: '{studioCount, plural, one {Studio} other {Studios}}', studio: '{studioCount, plural, one {Studio} other {Studios}}',
viewfullcrew: 'View Full Crew', viewfullcrew: 'View Full Crew',
view: 'View',
areyousure: 'Are you sure?',
openradarr: 'Open Movie in Radarr', openradarr: 'Open Movie in Radarr',
openradarr4k: 'Open Movie in 4K Radarr', openradarr4k: 'Open Movie in 4K Radarr',
downloadstatus: 'Download Status', downloadstatus: 'Download Status',
@ -382,7 +379,7 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
<div className="mt-8"> <div className="mt-8">
<ConfirmButton <ConfirmButton
onClick={() => deleteMedia()} onClick={() => deleteMedia()}
confirmText={intl.formatMessage(messages.areyousure)} confirmText={intl.formatMessage(globalMessages.areyousure)}
className="w-full" className="w-full"
> >
{intl.formatMessage(messages.manageModalClearMedia)} {intl.formatMessage(messages.manageModalClearMedia)}
@ -557,7 +554,7 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
<div className="relative z-10 flex items-center justify-between p-4 text-gray-200 transition duration-300 h-14 group-hover:text-white"> <div className="relative z-10 flex items-center justify-between p-4 text-gray-200 transition duration-300 h-14 group-hover:text-white">
<div>{data.collection.name}</div> <div>{data.collection.name}</div>
<Button buttonSize="sm"> <Button buttonSize="sm">
{intl.formatMessage(messages.view)} {intl.formatMessage(globalMessages.view)}
</Button> </Button>
</div> </div>
</div> </div>
@ -605,7 +602,7 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
</div> </div>
)} )}
<div className="media-fact"> <div className="media-fact">
<span>{intl.formatMessage(messages.status)}</span> <span>{intl.formatMessage(globalMessages.status)}</span>
<span className="media-fact-value">{data.status}</span> <span className="media-fact-value">{data.status}</span>
</div> </div>
{data.releaseDate && ( {data.releaseDate && (

@ -1,10 +1,10 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import PlexOAuth from '../../utils/plex';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
import globalMessages from '../../i18n/globalMessages';
import PlexOAuth from '../../utils/plex';
const messages = defineMessages({ const messages = defineMessages({
signinwithplex: 'Sign In', signinwithplex: 'Sign In',
loading: 'Loading…',
signingin: 'Signing in…', signingin: 'Signing in…',
}); });
@ -49,7 +49,7 @@ const PlexLoginButton: React.FC<PlexLoginButtonProps> = ({
className="plex-button" className="plex-button"
> >
{loading {loading
? intl.formatMessage(messages.loading) ? intl.formatMessage(globalMessages.loading)
: isProcessing : isProcessing
? intl.formatMessage(messages.signingin) ? intl.formatMessage(messages.signingin)
: intl.formatMessage(messages.signinwithplex)} : intl.formatMessage(messages.signinwithplex)}

@ -2,8 +2,8 @@ import React, { useEffect, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
const messages = defineMessages({ const messages = defineMessages({
movieRequestLimit: '{quotaLimit} movies per {quotaDays} days', movieRequestLimit: '{quotaLimit} movie(s) per {quotaDays} day(s)',
tvRequestLimit: '{quotaLimit} seasons per {quotaDays} days', tvRequestLimit: '{quotaLimit} season(s) per {quotaDays} day(s)',
unlimited: 'Unlimited', unlimited: 'Unlimited',
}); });

@ -9,14 +9,13 @@ import Media from '../../../server/entity/Media';
import { MediaRequest } from '../../../server/entity/MediaRequest'; import { MediaRequest } from '../../../server/entity/MediaRequest';
import useSettings from '../../hooks/useSettings'; import useSettings from '../../hooks/useSettings';
import { Permission, useUser } from '../../hooks/useUser'; import { Permission, useUser } from '../../hooks/useUser';
import globalMessages from '../../i18n/globalMessages';
import ButtonWithDropdown from '../Common/ButtonWithDropdown'; import ButtonWithDropdown from '../Common/ButtonWithDropdown';
import RequestModal from '../RequestModal'; import RequestModal from '../RequestModal';
const messages = defineMessages({ const messages = defineMessages({
viewrequest: 'View Request', viewrequest: 'View Request',
viewrequest4k: 'View 4K Request', viewrequest4k: 'View 4K Request',
request: 'Request',
request4k: 'Request 4K',
requestmore: 'Request More', requestmore: 'Request More',
requestmore4k: 'Request More 4K', requestmore4k: 'Request More 4K',
approverequest: 'Approve Request', approverequest: 'Approve Request',
@ -114,7 +113,7 @@ const RequestButton: React.FC<RequestButtonProps> = ({
) { ) {
buttons.push({ buttons.push({
id: 'request', id: 'request',
text: intl.formatMessage(messages.request), text: intl.formatMessage(globalMessages.request),
action: () => { action: () => {
setShowRequestModal(true); setShowRequestModal(true);
}, },
@ -180,7 +179,7 @@ const RequestButton: React.FC<RequestButtonProps> = ({
) { ) {
buttons.push({ buttons.push({
id: 'request4k', id: 'request4k',
text: intl.formatMessage(messages.request4k), text: intl.formatMessage(globalMessages.request4k),
action: () => { action: () => {
setShowRequest4kModal(true); setShowRequest4kModal(true);
}, },

@ -1,29 +1,27 @@
import axios from 'axios';
import Link from 'next/link';
import React, { useContext, useEffect } from 'react'; import React, { useContext, useEffect } from 'react';
import { useInView } from 'react-intersection-observer'; import { useInView } from 'react-intersection-observer';
import type { MediaRequest } from '../../../server/entity/MediaRequest'; import { defineMessages, useIntl } from 'react-intl';
import type { TvDetails } from '../../../server/models/Tv';
import type { MovieDetails } from '../../../server/models/Movie';
import useSWR from 'swr'; import useSWR from 'swr';
import { LanguageContext } from '../../context/LanguageContext';
import { import {
MediaRequestStatus, MediaRequestStatus,
MediaStatus, MediaStatus,
} from '../../../server/constants/media'; } from '../../../server/constants/media';
import type { MediaRequest } from '../../../server/entity/MediaRequest';
import type { MovieDetails } from '../../../server/models/Movie';
import type { TvDetails } from '../../../server/models/Tv';
import { LanguageContext } from '../../context/LanguageContext';
import { Permission, useUser } from '../../hooks/useUser';
import globalMessages from '../../i18n/globalMessages';
import { withProperties } from '../../utils/typeHelpers';
import Badge from '../Common/Badge'; import Badge from '../Common/Badge';
import { useUser, Permission } from '../../hooks/useUser';
import axios from 'axios';
import Button from '../Common/Button'; import Button from '../Common/Button';
import { withProperties } from '../../utils/typeHelpers';
import Link from 'next/link';
import { defineMessages, useIntl } from 'react-intl';
import globalMessages from '../../i18n/globalMessages';
import StatusBadge from '../StatusBadge';
import CachedImage from '../Common/CachedImage'; import CachedImage from '../Common/CachedImage';
import StatusBadge from '../StatusBadge';
const messages = defineMessages({ const messages = defineMessages({
status: 'Status',
seasons: '{seasonCount, plural, one {Season} other {Seasons}}', seasons: '{seasonCount, plural, one {Season} other {Seasons}}',
all: 'All',
}); });
const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => { const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {
@ -156,7 +154,7 @@ const RequestCard: React.FC<RequestCardProps> = ({ request, onTitleData }) => {
{title.seasons.filter((season) => season.seasonNumber !== 0) {title.seasons.filter((season) => season.seasonNumber !== 0)
.length === request.seasons.length ? ( .length === request.seasons.length ? (
<span className="mr-2 uppercase"> <span className="mr-2 uppercase">
<Badge>{intl.formatMessage(messages.all)}</Badge> <Badge>{intl.formatMessage(globalMessages.all)}</Badge>
</span> </span>
) : ( ) : (
<div className="overflow-x-scroll hide-scrollbar"> <div className="overflow-x-scroll hide-scrollbar">
@ -171,7 +169,7 @@ const RequestCard: React.FC<RequestCardProps> = ({ request, onTitleData }) => {
)} )}
<div className="flex items-center mt-2 text-sm sm:mt-1"> <div className="flex items-center mt-2 text-sm sm:mt-1">
<span className="hidden mr-2 font-medium sm:block"> <span className="hidden mr-2 font-medium sm:block">
{intl.formatMessage(messages.status)} {intl.formatMessage(globalMessages.status)}
</span> </span>
{requestData.media[requestData.is4k ? 'status4k' : 'status'] === {requestData.media[requestData.is4k ? 'status4k' : 'status'] ===
MediaStatus.UNKNOWN || MediaStatus.UNKNOWN ||

@ -1,34 +1,30 @@
import axios from 'axios';
import Link from 'next/link';
import React, { useContext, useState } from 'react'; import React, { useContext, useState } from 'react';
import { useInView } from 'react-intersection-observer'; import { useInView } from 'react-intersection-observer';
import type { MediaRequest } from '../../../../server/entity/MediaRequest'; import { defineMessages, FormattedRelativeTime, useIntl } from 'react-intl';
import { useIntl, FormattedRelativeTime, defineMessages } from 'react-intl'; import { useToasts } from 'react-toast-notifications';
import { useUser, Permission } from '../../../hooks/useUser';
import { LanguageContext } from '../../../context/LanguageContext';
import type { MovieDetails } from '../../../../server/models/Movie';
import type { TvDetails } from '../../../../server/models/Tv';
import useSWR from 'swr'; import useSWR from 'swr';
import Badge from '../../Common/Badge';
import StatusBadge from '../../StatusBadge';
import { import {
MediaRequestStatus, MediaRequestStatus,
MediaStatus, MediaStatus,
} from '../../../../server/constants/media'; } from '../../../../server/constants/media';
import Button from '../../Common/Button'; import type { MediaRequest } from '../../../../server/entity/MediaRequest';
import axios from 'axios'; import type { MovieDetails } from '../../../../server/models/Movie';
import type { TvDetails } from '../../../../server/models/Tv';
import { LanguageContext } from '../../../context/LanguageContext';
import { Permission, useUser } from '../../../hooks/useUser';
import globalMessages from '../../../i18n/globalMessages'; import globalMessages from '../../../i18n/globalMessages';
import Link from 'next/link'; import Badge from '../../Common/Badge';
import { useToasts } from 'react-toast-notifications'; import Button from '../../Common/Button';
import RequestModal from '../../RequestModal';
import ConfirmButton from '../../Common/ConfirmButton';
import CachedImage from '../../Common/CachedImage'; import CachedImage from '../../Common/CachedImage';
import ConfirmButton from '../../Common/ConfirmButton';
import RequestModal from '../../RequestModal';
import StatusBadge from '../../StatusBadge';
const messages = defineMessages({ const messages = defineMessages({
seasons: '{seasonCount, plural, one {Season} other {Seasons}}', seasons: '{seasonCount, plural, one {Season} other {Seasons}}',
all: 'All',
notavailable: 'N/A',
failedretry: 'Something went wrong while retrying the request.', failedretry: 'Something went wrong while retrying the request.',
areyousure: 'Are you sure?',
status: 'Status',
requested: 'Requested', requested: 'Requested',
modified: 'Modified', modified: 'Modified',
modifieduserdate: '{date} by {user}', modifieduserdate: '{date} by {user}',
@ -218,7 +214,7 @@ const RequestItem: React.FC<RequestItemProps> = ({
{title.seasons.filter((season) => season.seasonNumber !== 0) {title.seasons.filter((season) => season.seasonNumber !== 0)
.length === request.seasons.length ? ( .length === request.seasons.length ? (
<span className="mr-2 uppercase"> <span className="mr-2 uppercase">
<Badge>{intl.formatMessage(messages.all)}</Badge> <Badge>{intl.formatMessage(globalMessages.all)}</Badge>
</span> </span>
) : ( ) : (
<div className="flex overflow-x-scroll hide-scrollbar flex-nowrap"> <div className="flex overflow-x-scroll hide-scrollbar flex-nowrap">
@ -236,7 +232,7 @@ const RequestItem: React.FC<RequestItemProps> = ({
<div className="z-10 flex flex-col justify-center w-full pr-4 mt-4 ml-4 text-sm sm:ml-2 sm:mt-0 xl:flex-1 xl:pr-0"> <div className="z-10 flex flex-col justify-center w-full pr-4 mt-4 ml-4 text-sm sm:ml-2 sm:mt-0 xl:flex-1 xl:pr-0">
<div className="card-field"> <div className="card-field">
<span className="card-field-name"> <span className="card-field-name">
{intl.formatMessage(messages.status)} {intl.formatMessage(globalMessages.status)}
</span> </span>
{requestData.media[requestData.is4k ? 'status4k' : 'status'] === {requestData.media[requestData.is4k ? 'status4k' : 'status'] ===
MediaStatus.UNKNOWN || MediaStatus.UNKNOWN ||
@ -349,7 +345,7 @@ const RequestItem: React.FC<RequestItemProps> = ({
hasPermission(Permission.MANAGE_REQUESTS) && ( hasPermission(Permission.MANAGE_REQUESTS) && (
<ConfirmButton <ConfirmButton
onClick={() => deleteRequest()} onClick={() => deleteRequest()}
confirmText={intl.formatMessage(messages.areyousure)} confirmText={intl.formatMessage(globalMessages.areyousure)}
className="w-full" className="w-full"
> >
<svg <svg

@ -1,27 +1,17 @@
import { useRouter } from 'next/router';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import useSWR from 'swr'; import useSWR from 'swr';
import type { RequestResultsResponse } from '../../../server/interfaces/api/requestInterfaces'; import type { RequestResultsResponse } from '../../../server/interfaces/api/requestInterfaces';
import LoadingSpinner from '../Common/LoadingSpinner'; import globalMessages from '../../i18n/globalMessages';
import RequestItem from './RequestItem';
import Header from '../Common/Header';
import Button from '../Common/Button'; import Button from '../Common/Button';
import { defineMessages, useIntl } from 'react-intl'; import Header from '../Common/Header';
import LoadingSpinner from '../Common/LoadingSpinner';
import PageTitle from '../Common/PageTitle'; import PageTitle from '../Common/PageTitle';
import { useRouter } from 'next/router'; import RequestItem from './RequestItem';
const messages = defineMessages({ const messages = defineMessages({
requests: 'Requests', requests: 'Requests',
showingresults:
'Showing <strong>{from}</strong> to <strong>{to}</strong> of <strong>{total}</strong> results',
resultsperpage: 'Display {pageSize} results per page',
next: 'Next',
previous: 'Previous',
filterAll: 'All',
filterPending: 'Pending',
filterApproved: 'Approved',
filterAvailable: 'Available',
filterProcessing: 'Processing',
noresults: 'No results.',
showallrequests: 'Show All Requests', showallrequests: 'Show All Requests',
sortAdded: 'Request Date', sortAdded: 'Request Date',
sortModified: 'Last Modified', sortModified: 'Last Modified',
@ -114,19 +104,19 @@ const RequestList: React.FC = () => {
className="rounded-r-only" className="rounded-r-only"
> >
<option value="all"> <option value="all">
{intl.formatMessage(messages.filterAll)} {intl.formatMessage(globalMessages.all)}
</option> </option>
<option value="pending"> <option value="pending">
{intl.formatMessage(messages.filterPending)} {intl.formatMessage(globalMessages.pending)}
</option> </option>
<option value="approved"> <option value="approved">
{intl.formatMessage(messages.filterApproved)} {intl.formatMessage(globalMessages.approved)}
</option> </option>
<option value="processing"> <option value="processing">
{intl.formatMessage(messages.filterProcessing)} {intl.formatMessage(globalMessages.processing)}
</option> </option>
<option value="available"> <option value="available">
{intl.formatMessage(messages.filterAvailable)} {intl.formatMessage(globalMessages.available)}
</option> </option>
</select> </select>
</div> </div>
@ -175,7 +165,7 @@ const RequestList: React.FC = () => {
{data.results.length === 0 && ( {data.results.length === 0 && (
<div className="flex flex-col items-center justify-center w-full py-24 text-white"> <div className="flex flex-col items-center justify-center w-full py-24 text-white">
<span className="text-2xl text-gray-400"> <span className="text-2xl text-gray-400">
{intl.formatMessage(messages.noresults)} {intl.formatMessage(globalMessages.noresults)}
</span> </span>
{currentFilter !== 'all' && ( {currentFilter !== 'all' && (
<div className="mt-4"> <div className="mt-4">
@ -197,7 +187,7 @@ const RequestList: React.FC = () => {
<div className="hidden lg:flex lg:flex-1"> <div className="hidden lg:flex lg:flex-1">
<p className="text-sm"> <p className="text-sm">
{data.results.length > 0 && {data.results.length > 0 &&
intl.formatMessage(messages.showingresults, { intl.formatMessage(globalMessages.showingresults, {
from: pageIndex * currentPageSize + 1, from: pageIndex * currentPageSize + 1,
to: to:
data.results.length < currentPageSize data.results.length < currentPageSize
@ -212,7 +202,7 @@ const RequestList: React.FC = () => {
</div> </div>
<div className="flex justify-center sm:flex-1 sm:justify-start lg:justify-center"> <div className="flex justify-center sm:flex-1 sm:justify-start lg:justify-center">
<span className="items-center -mt-3 text-sm truncate sm:mt-0"> <span className="items-center -mt-3 text-sm truncate sm:mt-0">
{intl.formatMessage(messages.resultsperpage, { {intl.formatMessage(globalMessages.resultsperpage, {
pageSize: ( pageSize: (
<select <select
id="pageSize" id="pageSize"
@ -247,7 +237,7 @@ const RequestList: React.FC = () => {
.then(() => window.scrollTo(0, 0)) .then(() => window.scrollTo(0, 0))
} }
> >
{intl.formatMessage(messages.previous)} {intl.formatMessage(globalMessages.previous)}
</Button> </Button>
<Button <Button
disabled={!hasNextPage} disabled={!hasNextPage}
@ -259,7 +249,7 @@ const RequestList: React.FC = () => {
.then(() => window.scrollTo(0, 0)) .then(() => window.scrollTo(0, 0))
} }
> >
{intl.formatMessage(messages.next)} {intl.formatMessage(globalMessages.next)}
</Button> </Button>
</div> </div>
</nav> </nav>

@ -1,16 +1,17 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { Listbox, Transition } from '@headlessui/react';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import useSWR from 'swr'; import useSWR from 'swr';
import { SmallLoadingSpinner } from '../../Common/LoadingSpinner';
import type { import type {
ServiceCommonServer, ServiceCommonServer,
ServiceCommonServerWithDetails, ServiceCommonServerWithDetails,
} from '../../../../server/interfaces/api/serviceInterfaces'; } from '../../../../server/interfaces/api/serviceInterfaces';
import { defineMessages, useIntl } from 'react-intl';
import { formatBytes } from '../../../utils/numberHelpers';
import { Listbox, Transition } from '@headlessui/react';
import { Permission, User, useUser } from '../../../hooks/useUser';
import type { UserResultsResponse } from '../../../../server/interfaces/api/userInterfaces'; import type { UserResultsResponse } from '../../../../server/interfaces/api/userInterfaces';
import { Permission, User, useUser } from '../../../hooks/useUser';
import globalMessages from '../../../i18n/globalMessages';
import { formatBytes } from '../../../utils/numberHelpers';
import { SmallLoadingSpinner } from '../../Common/LoadingSpinner';
const messages = defineMessages({ const messages = defineMessages({
advancedoptions: 'Advanced Options', advancedoptions: 'Advanced Options',
@ -22,7 +23,6 @@ const messages = defineMessages({
folder: '{path} ({space})', folder: '{path} ({space})',
requestas: 'Request As', requestas: 'Request As',
languageprofile: 'Language Profile', languageprofile: 'Language Profile',
loading: 'Loading…',
}); });
export type RequestOverrides = { export type RequestOverrides = {
@ -307,7 +307,7 @@ const AdvancedRequester: React.FC<AdvancedRequesterProps> = ({
> >
{(isValidating || !serverData) && ( {(isValidating || !serverData) && (
<option value=""> <option value="">
{intl.formatMessage(messages.loading)} {intl.formatMessage(globalMessages.loading)}
</option> </option>
)} )}
{!isValidating && {!isValidating &&
@ -351,7 +351,7 @@ const AdvancedRequester: React.FC<AdvancedRequesterProps> = ({
> >
{(isValidating || !serverData) && ( {(isValidating || !serverData) && (
<option value=""> <option value="">
{intl.formatMessage(messages.loading)} {intl.formatMessage(globalMessages.loading)}
</option> </option>
)} )}
{!isValidating && {!isValidating &&
@ -405,7 +405,7 @@ const AdvancedRequester: React.FC<AdvancedRequesterProps> = ({
> >
{(isValidating || !serverData) && ( {(isValidating || !serverData) && (
<option value=""> <option value="">
{intl.formatMessage(messages.loading)} {intl.formatMessage(globalMessages.loading)}
</option> </option>
)} )}
{!isValidating && {!isValidating &&

@ -20,25 +20,18 @@ import AdvancedRequester, { RequestOverrides } from './AdvancedRequester';
import QuotaDisplay from './QuotaDisplay'; import QuotaDisplay from './QuotaDisplay';
const messages = defineMessages({ const messages = defineMessages({
requestadmin: 'Your request will be approved automatically.', requestadmin: 'This request will be approved automatically.',
cancelrequest:
'This will remove your request. Are you sure you want to continue?',
requestSuccess: '<strong>{title}</strong> requested successfully!', requestSuccess: '<strong>{title}</strong> requested successfully!',
requestCancel: 'Request for <strong>{title}</strong> canceled.', requestCancel: 'Request for <strong>{title}</strong> canceled.',
requesttitle: 'Request {title}', requesttitle: 'Request {title}',
request4ktitle: 'Request {title} in 4K', request4ktitle: 'Request {title} in 4K',
close: 'Close',
cancel: 'Cancel Request', cancel: 'Cancel Request',
cancelling: 'Canceling…',
pendingrequest: 'Pending Request for {title}', pendingrequest: 'Pending Request for {title}',
pending4krequest: 'Pending Request for {title} in 4K', pending4krequest: 'Pending Request for {title} in 4K',
requesting: 'Requesting…',
request: 'Request',
request4k: 'Request 4K',
requestfrom: 'There is currently a pending request from {username}.', requestfrom: 'There is currently a pending request from {username}.',
request4kfrom: 'There is currently a pending 4K request from {username}.', request4kfrom: 'There is currently a pending 4K request from {username}.',
errorediting: 'Something went wrong while editing the request.', errorediting: 'Something went wrong while editing the request.',
requestedited: 'Request edited.', requestedited: 'Request for <strong>{title}</strong> edited successfully!',
requesterror: 'Something went wrong while submitting the request.', requesterror: 'Something went wrong while submitting the request.',
}); });
@ -182,10 +175,20 @@ const MovieRequestModal: React.FC<RequestModalProps> = ({
userId: requestOverrides?.user?.id, userId: requestOverrides?.user?.id,
}); });
addToast(<span>{intl.formatMessage(messages.requestedited)}</span>, { addToast(
appearance: 'success', <span>
autoDismiss: true, {intl.formatMessage(messages.requestedited, {
}); title: data?.title,
strong: function strong(msg) {
return <strong>{msg}</strong>;
},
})}
</span>,
{
appearance: 'success',
autoDismiss: true,
}
);
if (onComplete) { if (onComplete) {
onComplete(MediaStatus.PENDING); onComplete(MediaStatus.PENDING);
@ -225,11 +228,11 @@ const MovieRequestModal: React.FC<RequestModalProps> = ({
secondaryDisabled={isUpdating} secondaryDisabled={isUpdating}
secondaryText={ secondaryText={
isUpdating isUpdating
? intl.formatMessage(messages.cancelling) ? intl.formatMessage(globalMessages.canceling)
: intl.formatMessage(messages.cancel) : intl.formatMessage(messages.cancel)
} }
secondaryButtonType="danger" secondaryButtonType="danger"
cancelText={intl.formatMessage(messages.close)} cancelText={intl.formatMessage(globalMessages.close)}
iconSvg={<DownloadIcon className="w-6 h-6" />} iconSvg={<DownloadIcon className="w-6 h-6" />}
> >
{intl.formatMessage( {intl.formatMessage(
@ -286,8 +289,10 @@ const MovieRequestModal: React.FC<RequestModalProps> = ({
)} )}
okText={ okText={
isUpdating isUpdating
? intl.formatMessage(messages.requesting) ? intl.formatMessage(globalMessages.requesting)
: intl.formatMessage(is4k ? messages.request4k : messages.request) : intl.formatMessage(
is4k ? globalMessages.request4k : globalMessages.request
)
} }
okButtonType={'primary'} okButtonType={'primary'}
iconSvg={<DownloadIcon className="w-6 h-6" />} iconSvg={<DownloadIcon className="w-6 h-6" />}

@ -6,7 +6,7 @@ import ProgressCircle from '../../Common/ProgressCircle';
const messages = defineMessages({ const messages = defineMessages({
requestsremaining: requestsremaining:
'{remaining, plural, =0 {No} other {<strong>#</strong>}} {type} {remaining, plural, one {requests} other {requests}} remaining', '{remaining, plural, =0 {No} other {<strong>#</strong>}} {type} {remaining, plural, one {request} other {requests}} remaining',
movielimit: '{limit, plural, one {movie} other {movies}}', movielimit: '{limit, plural, one {movie} other {movies}}',
seasonlimit: '{limit, plural, one {season} other {seasons}}', seasonlimit: '{limit, plural, one {season} other {seasons}}',
allowedRequests: allowedRequests:
@ -22,6 +22,8 @@ const messages = defineMessages({
notenoughseasonrequests: 'Not enough season requests remaining', notenoughseasonrequests: 'Not enough season requests remaining',
requiredquota: requiredquota:
'You need to have at least <strong>{seasons}</strong> {seasons, plural, one {season request} other {season requests}} remaining in order to submit a request for this series.', 'You need to have at least <strong>{seasons}</strong> {seasons, plural, one {season request} other {season requests}} remaining in order to submit a request for this series.',
requiredquotaUser:
'This user needs to have at least <strong>{seasons}</strong> {seasons, plural, one {season request} other {season requests}} remaining in order to submit a request for this series.',
}); });
interface QuotaDisplayProps { interface QuotaDisplayProps {
@ -120,12 +122,17 @@ const QuotaDisplay: React.FC<QuotaDisplayProps> = ({
<div className="mt-4"> <div className="mt-4">
{overLimit !== undefined && ( {overLimit !== undefined && (
<div className="mb-2"> <div className="mb-2">
{intl.formatMessage(messages.requiredquota, { {intl.formatMessage(
seasons: overLimit, userOverride
strong: function strong(msg) { ? messages.requiredquota
return <span className="font-bold">{msg}</span>; : messages.requiredquotaUser,
}, {
})} seasons: overLimit,
strong: function strong(msg) {
return <span className="font-bold">{msg}</span>;
},
}
)}
</div> </div>
)} )}
<div> <div>

@ -2,12 +2,12 @@ import React from 'react';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
import useSWR from 'swr'; import useSWR from 'swr';
import { SonarrSeries } from '../../../../server/api/sonarr'; import { SonarrSeries } from '../../../../server/api/sonarr';
import globalMessages from '../../../i18n/globalMessages';
import Alert from '../../Common/Alert'; import Alert from '../../Common/Alert';
import { SmallLoadingSpinner } from '../../Common/LoadingSpinner'; import { SmallLoadingSpinner } from '../../Common/LoadingSpinner';
import Modal from '../../Common/Modal'; import Modal from '../../Common/Modal';
const messages = defineMessages({ const messages = defineMessages({
next: 'Next',
notvdbid: 'Manual Match Required', notvdbid: 'Manual Match Required',
notvdbiddescription: notvdbiddescription:
"We couldn't automatically match your request. Please select the correct match from the list below.", "We couldn't automatically match your request. Please select the correct match from the list below.",
@ -49,7 +49,7 @@ const SearchByNameModal: React.FC<SearchByNameModalProps> = ({
onCancel={onCancel} onCancel={onCancel}
onOk={closeModal} onOk={closeModal}
title={modalTitle} title={modalTitle}
okText={intl.formatMessage(messages.next)} okText={intl.formatMessage(globalMessages.next)}
okDisabled={!tvdbId} okDisabled={!tvdbId}
okButtonType="primary" okButtonType="primary"
iconSvg={ iconSvg={

@ -24,13 +24,10 @@ import QuotaDisplay from './QuotaDisplay';
import SearchByNameModal from './SearchByNameModal'; import SearchByNameModal from './SearchByNameModal';
const messages = defineMessages({ const messages = defineMessages({
requestadmin: 'Your request will be approved automatically.', requestadmin: 'This request will be approved automatically.',
cancelrequest:
'This will remove your request. Are you sure you want to continue?',
requestSuccess: '<strong>{title}</strong> requested successfully!', requestSuccess: '<strong>{title}</strong> requested successfully!',
requesttitle: 'Request {title}', requesttitle: 'Request {title}',
request4ktitle: 'Request {title} in 4K', request4ktitle: 'Request {title} in 4K',
requesting: 'Requesting…',
requestseasons: requestseasons:
'Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}', 'Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}',
requestall: 'Request All Seasons', requestall: 'Request All Seasons',
@ -38,16 +35,13 @@ const messages = defineMessages({
selectseason: 'Select Season(s)', selectseason: 'Select Season(s)',
season: 'Season', season: 'Season',
numberofepisodes: '# of Episodes', numberofepisodes: '# of Episodes',
status: 'Status',
seasonnumber: 'Season {number}', seasonnumber: 'Season {number}',
extras: 'Extras', extras: 'Extras',
notrequested: 'Not Requested',
errorediting: 'Something went wrong while editing the request.', errorediting: 'Something went wrong while editing the request.',
requestedited: 'Request edited.', requestedited: 'Request for <strong>{title}</strong> edited successfully!',
requestcancelled: 'Request canceled.', requestcancelled: 'Request for <strong>{title}</strong> canceled.',
autoapproval: 'Automatic Approval', autoapproval: 'Automatic Approval',
requesterror: 'Something went wrong while submitting the request.', requesterror: 'Something went wrong while submitting the request.',
backbutton: 'Back',
}); });
interface RequestModalProps extends React.HTMLAttributes<HTMLDivElement> { interface RequestModalProps extends React.HTMLAttributes<HTMLDivElement> {
@ -122,8 +116,18 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
addToast( addToast(
<span> <span>
{selectedSeasons.length > 0 {selectedSeasons.length > 0
? intl.formatMessage(messages.requestedited) ? intl.formatMessage(messages.requestedited, {
: intl.formatMessage(messages.requestcancelled)} title: data?.name,
strong: function strong(msg) {
return <strong>{msg}</strong>;
},
})
: intl.formatMessage(messages.requestcancelled, {
title: data?.name,
strong: function strong(msg) {
return <strong>{msg}</strong>;
},
})}
</span>, </span>,
{ {
appearance: 'success', appearance: 'success',
@ -390,7 +394,7 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
} }
cancelText={ cancelText={
tvdbId tvdbId
? intl.formatMessage(messages.backbutton) ? intl.formatMessage(globalMessages.back)
: intl.formatMessage(globalMessages.cancel) : intl.formatMessage(globalMessages.cancel)
} }
iconSvg={ iconSvg={
@ -507,7 +511,7 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
{intl.formatMessage(messages.numberofepisodes)} {intl.formatMessage(messages.numberofepisodes)}
</th> </th>
<th className="px-2 py-3 text-xs font-medium leading-4 tracking-wider text-left text-gray-200 uppercase bg-gray-500 md:px-6"> <th className="px-2 py-3 text-xs font-medium leading-4 tracking-wider text-left text-gray-200 uppercase bg-gray-500 md:px-6">
{intl.formatMessage(messages.status)} {intl.formatMessage(globalMessages.status)}
</th> </th>
</tr> </tr>
</thead> </thead>
@ -601,7 +605,9 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
<td className="py-4 pr-2 text-sm leading-5 text-gray-200 md:px-6 whitespace-nowrap"> <td className="py-4 pr-2 text-sm leading-5 text-gray-200 md:px-6 whitespace-nowrap">
{!seasonRequest && !mediaSeason && ( {!seasonRequest && !mediaSeason && (
<Badge> <Badge>
{intl.formatMessage(messages.notrequested)} {intl.formatMessage(
globalMessages.notrequested
)}
</Badge> </Badge>
)} )}
{!mediaSeason && {!mediaSeason &&

@ -1,17 +1,16 @@
import React from 'react'; import axios from 'axios';
import { Field, Form, Formik } from 'formik'; import { Field, Form, Formik } from 'formik';
import useSWR from 'swr'; import React from 'react';
import LoadingSpinner from '../../Common/LoadingSpinner';
import Button from '../../Common/Button';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
import axios from 'axios';
import * as Yup from 'yup';
import { useToasts } from 'react-toast-notifications'; import { useToasts } from 'react-toast-notifications';
import useSWR from 'swr';
import * as Yup from 'yup';
import globalMessages from '../../../i18n/globalMessages';
import Button from '../../Common/Button';
import LoadingSpinner from '../../Common/LoadingSpinner';
import NotificationTypeSelector from '../../NotificationTypeSelector'; import NotificationTypeSelector from '../../NotificationTypeSelector';
const messages = defineMessages({ const messages = defineMessages({
save: 'Save Changes',
saving: 'Saving…',
agentenabled: 'Enable Agent', agentenabled: 'Enable Agent',
botUsername: 'Bot Username', botUsername: 'Bot Username',
botAvatarUrl: 'Bot Avatar URL', botAvatarUrl: 'Bot Avatar URL',
@ -20,7 +19,6 @@ const messages = defineMessages({
discordsettingssaved: 'Discord notification settings saved successfully!', discordsettingssaved: 'Discord notification settings saved successfully!',
discordsettingsfailed: 'Discord notification settings failed to save.', discordsettingsfailed: 'Discord notification settings failed to save.',
testsent: 'Test notification sent!', testsent: 'Test notification sent!',
test: 'Test',
notificationtypes: 'Notification Types', notificationtypes: 'Notification Types',
validationUrl: 'You must provide a valid URL', validationUrl: 'You must provide a valid URL',
}); });
@ -197,7 +195,7 @@ const NotificationsDiscord: React.FC = () => {
testSettings(); testSettings();
}} }}
> >
{intl.formatMessage(messages.test)} {intl.formatMessage(globalMessages.test)}
</Button> </Button>
</span> </span>
<span className="inline-flex ml-3 rounded-md shadow-sm"> <span className="inline-flex ml-3 rounded-md shadow-sm">
@ -207,8 +205,8 @@ const NotificationsDiscord: React.FC = () => {
disabled={isSubmitting || !isValid} disabled={isSubmitting || !isValid}
> >
{isSubmitting {isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: intl.formatMessage(messages.save)} : intl.formatMessage(globalMessages.save)}
</Button> </Button>
</span> </span>
</div> </div>

@ -13,8 +13,6 @@ import LoadingSpinner from '../../Common/LoadingSpinner';
import NotificationTypeSelector from '../../NotificationTypeSelector'; import NotificationTypeSelector from '../../NotificationTypeSelector';
const messages = defineMessages({ const messages = defineMessages({
save: 'Save Changes',
saving: 'Saving…',
validationSmtpHostRequired: 'You must provide a hostname or IP address', validationSmtpHostRequired: 'You must provide a hostname or IP address',
validationSmtpPortRequired: 'You must provide a valid port number', validationSmtpPortRequired: 'You must provide a valid port number',
agentenabled: 'Enable Agent', agentenabled: 'Enable Agent',
@ -26,7 +24,6 @@ const messages = defineMessages({
authPass: 'SMTP Password', authPass: 'SMTP Password',
emailsettingssaved: 'Email notification settings saved successfully!', emailsettingssaved: 'Email notification settings saved successfully!',
emailsettingsfailed: 'Email notification settings failed to save.', emailsettingsfailed: 'Email notification settings failed to save.',
test: 'Test',
testsent: 'Test notification sent!', testsent: 'Test notification sent!',
allowselfsigned: 'Allow Self-Signed Certificates', allowselfsigned: 'Allow Self-Signed Certificates',
ssldisabletip: ssldisabletip:
@ -407,7 +404,7 @@ const NotificationsEmail: React.FC = () => {
testSettings(); testSettings();
}} }}
> >
{intl.formatMessage(messages.test)} {intl.formatMessage(globalMessages.test)}
</Button> </Button>
</span> </span>
<span className="inline-flex ml-3 rounded-md shadow-sm"> <span className="inline-flex ml-3 rounded-md shadow-sm">
@ -417,8 +414,8 @@ const NotificationsEmail: React.FC = () => {
disabled={isSubmitting || !isValid} disabled={isSubmitting || !isValid}
> >
{isSubmitting {isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: intl.formatMessage(messages.save)} : intl.formatMessage(globalMessages.save)}
</Button> </Button>
</span> </span>
</div> </div>

@ -1,18 +1,17 @@
import React from 'react'; import axios from 'axios';
import { Field, Form, Formik } from 'formik'; import { Field, Form, Formik } from 'formik';
import useSWR from 'swr'; import React from 'react';
import LoadingSpinner from '../../../Common/LoadingSpinner';
import Button from '../../../Common/Button';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
import axios from 'axios';
import * as Yup from 'yup';
import { useToasts } from 'react-toast-notifications'; import { useToasts } from 'react-toast-notifications';
import useSWR from 'swr';
import * as Yup from 'yup';
import globalMessages from '../../../../i18n/globalMessages';
import Alert from '../../../Common/Alert'; import Alert from '../../../Common/Alert';
import Button from '../../../Common/Button';
import LoadingSpinner from '../../../Common/LoadingSpinner';
import NotificationTypeSelector from '../../../NotificationTypeSelector'; import NotificationTypeSelector from '../../../NotificationTypeSelector';
const messages = defineMessages({ const messages = defineMessages({
save: 'Save Changes',
saving: 'Saving…',
agentEnabled: 'Enable Agent', agentEnabled: 'Enable Agent',
accessToken: 'Access Token', accessToken: 'Access Token',
validationAccessTokenRequired: 'You must provide an access token', validationAccessTokenRequired: 'You must provide an access token',
@ -20,7 +19,6 @@ const messages = defineMessages({
'Pushbullet notification settings saved successfully!', 'Pushbullet notification settings saved successfully!',
pushbulletSettingsFailed: 'Pushbullet notification settings failed to save.', pushbulletSettingsFailed: 'Pushbullet notification settings failed to save.',
testSent: 'Test notification sent!', testSent: 'Test notification sent!',
test: 'Test',
settingUpPushbullet: 'Setting Up Pushbullet Notifications', settingUpPushbullet: 'Setting Up Pushbullet Notifications',
settingUpPushbulletDescription: settingUpPushbulletDescription:
'To configure Pushbullet notifications, you will need to <CreateAccessTokenLink>create an access token</CreateAccessTokenLink> and enter it below.', 'To configure Pushbullet notifications, you will need to <CreateAccessTokenLink>create an access token</CreateAccessTokenLink> and enter it below.',
@ -174,7 +172,7 @@ const NotificationsPushbullet: React.FC = () => {
testSettings(); testSettings();
}} }}
> >
{intl.formatMessage(messages.test)} {intl.formatMessage(globalMessages.test)}
</Button> </Button>
</span> </span>
<span className="inline-flex ml-3 rounded-md shadow-sm"> <span className="inline-flex ml-3 rounded-md shadow-sm">
@ -184,8 +182,8 @@ const NotificationsPushbullet: React.FC = () => {
disabled={isSubmitting || !isValid} disabled={isSubmitting || !isValid}
> >
{isSubmitting {isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: intl.formatMessage(messages.save)} : intl.formatMessage(globalMessages.save)}
</Button> </Button>
</span> </span>
</div> </div>

@ -5,14 +5,13 @@ import { defineMessages, useIntl } from 'react-intl';
import { useToasts } from 'react-toast-notifications'; import { useToasts } from 'react-toast-notifications';
import useSWR from 'swr'; import useSWR from 'swr';
import * as Yup from 'yup'; import * as Yup from 'yup';
import globalMessages from '../../../../i18n/globalMessages';
import Alert from '../../../Common/Alert'; import Alert from '../../../Common/Alert';
import Button from '../../../Common/Button'; import Button from '../../../Common/Button';
import LoadingSpinner from '../../../Common/LoadingSpinner'; import LoadingSpinner from '../../../Common/LoadingSpinner';
import NotificationTypeSelector from '../../../NotificationTypeSelector'; import NotificationTypeSelector from '../../../NotificationTypeSelector';
const messages = defineMessages({ const messages = defineMessages({
save: 'Save Changes',
saving: 'Saving…',
agentenabled: 'Enable Agent', agentenabled: 'Enable Agent',
accessToken: 'Application/API Token', accessToken: 'Application/API Token',
userToken: 'User Key', userToken: 'User Key',
@ -21,7 +20,6 @@ const messages = defineMessages({
pushoversettingssaved: 'Pushover notification settings saved successfully!', pushoversettingssaved: 'Pushover notification settings saved successfully!',
pushoversettingsfailed: 'Pushover notification settings failed to save.', pushoversettingsfailed: 'Pushover notification settings failed to save.',
testsent: 'Test notification sent!', testsent: 'Test notification sent!',
test: 'Test',
settinguppushover: 'Setting Up Pushover Notifications', settinguppushover: 'Setting Up Pushover Notifications',
settinguppushoverDescription: settinguppushoverDescription:
'To configure Pushover notifications, you will need to <RegisterApplicationLink>register an application</RegisterApplicationLink> and enter the API token below. (You can use one of our <IconLink>official icons on GitHub</IconLink>.) You will also need your user key.', 'To configure Pushover notifications, you will need to <RegisterApplicationLink>register an application</RegisterApplicationLink> and enter the API token below. (You can use one of our <IconLink>official icons on GitHub</IconLink>.) You will also need your user key.',
@ -218,7 +216,7 @@ const NotificationsPushover: React.FC = () => {
testSettings(); testSettings();
}} }}
> >
{intl.formatMessage(messages.test)} {intl.formatMessage(globalMessages.test)}
</Button> </Button>
</span> </span>
<span className="inline-flex ml-3 rounded-md shadow-sm"> <span className="inline-flex ml-3 rounded-md shadow-sm">
@ -228,8 +226,8 @@ const NotificationsPushover: React.FC = () => {
disabled={isSubmitting || !isValid} disabled={isSubmitting || !isValid}
> >
{isSubmitting {isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: intl.formatMessage(messages.save)} : intl.formatMessage(globalMessages.save)}
</Button> </Button>
</span> </span>
</div> </div>

@ -1,24 +1,22 @@
import React from 'react'; import axios from 'axios';
import { Field, Form, Formik } from 'formik'; import { Field, Form, Formik } from 'formik';
import useSWR from 'swr'; import React from 'react';
import LoadingSpinner from '../../../Common/LoadingSpinner';
import Button from '../../../Common/Button';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
import axios from 'axios';
import * as Yup from 'yup';
import { useToasts } from 'react-toast-notifications'; import { useToasts } from 'react-toast-notifications';
import useSWR from 'swr';
import * as Yup from 'yup';
import globalMessages from '../../../../i18n/globalMessages';
import Alert from '../../../Common/Alert'; import Alert from '../../../Common/Alert';
import Button from '../../../Common/Button';
import LoadingSpinner from '../../../Common/LoadingSpinner';
import NotificationTypeSelector from '../../../NotificationTypeSelector'; import NotificationTypeSelector from '../../../NotificationTypeSelector';
const messages = defineMessages({ const messages = defineMessages({
save: 'Save Changes',
saving: 'Saving…',
agentenabled: 'Enable Agent', agentenabled: 'Enable Agent',
webhookUrl: 'Webhook URL', webhookUrl: 'Webhook URL',
slacksettingssaved: 'Slack notification settings saved successfully!', slacksettingssaved: 'Slack notification settings saved successfully!',
slacksettingsfailed: 'Slack notification settings failed to save.', slacksettingsfailed: 'Slack notification settings failed to save.',
testsent: 'Test notification sent!', testsent: 'Test notification sent!',
test: 'Test',
settingupslack: 'Setting Up Slack Notifications', settingupslack: 'Setting Up Slack Notifications',
settingupslackDescription: settingupslackDescription:
'To configure Slack notifications, you will need to create an <WebhookLink>Incoming Webhook</WebhookLink> integration and enter the webhook URL below.', 'To configure Slack notifications, you will need to create an <WebhookLink>Incoming Webhook</WebhookLink> integration and enter the webhook URL below.',
@ -172,7 +170,7 @@ const NotificationsSlack: React.FC = () => {
testSettings(); testSettings();
}} }}
> >
{intl.formatMessage(messages.test)} {intl.formatMessage(globalMessages.test)}
</Button> </Button>
</span> </span>
<span className="inline-flex ml-3 rounded-md shadow-sm"> <span className="inline-flex ml-3 rounded-md shadow-sm">
@ -182,8 +180,8 @@ const NotificationsSlack: React.FC = () => {
disabled={isSubmitting || !isValid} disabled={isSubmitting || !isValid}
> >
{isSubmitting {isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: intl.formatMessage(messages.save)} : intl.formatMessage(globalMessages.save)}
</Button> </Button>
</span> </span>
</div> </div>

@ -5,14 +5,13 @@ import { defineMessages, useIntl } from 'react-intl';
import { useToasts } from 'react-toast-notifications'; import { useToasts } from 'react-toast-notifications';
import useSWR from 'swr'; import useSWR from 'swr';
import * as Yup from 'yup'; import * as Yup from 'yup';
import globalMessages from '../../../i18n/globalMessages';
import Alert from '../../Common/Alert'; import Alert from '../../Common/Alert';
import Button from '../../Common/Button'; import Button from '../../Common/Button';
import LoadingSpinner from '../../Common/LoadingSpinner'; import LoadingSpinner from '../../Common/LoadingSpinner';
import NotificationTypeSelector from '../../NotificationTypeSelector'; import NotificationTypeSelector from '../../NotificationTypeSelector';
const messages = defineMessages({ const messages = defineMessages({
save: 'Save Changes',
saving: 'Saving…',
agentenabled: 'Enable Agent', agentenabled: 'Enable Agent',
botUsername: 'Bot Username', botUsername: 'Bot Username',
botAPI: 'Bot Authentication Token', botAPI: 'Bot Authentication Token',
@ -22,7 +21,6 @@ const messages = defineMessages({
telegramsettingssaved: 'Telegram notification settings saved successfully!', telegramsettingssaved: 'Telegram notification settings saved successfully!',
telegramsettingsfailed: 'Telegram notification settings failed to save.', telegramsettingsfailed: 'Telegram notification settings failed to save.',
testsent: 'Test notification sent!', testsent: 'Test notification sent!',
test: 'Test',
settinguptelegram: 'Setting Up Telegram Notifications', settinguptelegram: 'Setting Up Telegram Notifications',
settinguptelegramDescription: settinguptelegramDescription:
'To configure Telegram notifications, you will need to <CreateBotLink>create a bot</CreateBotLink> and get the bot API key. Additionally, you will need the chat ID for the chat to which you would like to send notifications. You can find this by adding <GetIdBotLink>@get_id_bot</GetIdBotLink> to the chat and issuing the <code>/my_id</code> command.', 'To configure Telegram notifications, you will need to <CreateBotLink>create a bot</CreateBotLink> and get the bot API key. Additionally, you will need the chat ID for the chat to which you would like to send notifications. You can find this by adding <GetIdBotLink>@get_id_bot</GetIdBotLink> to the chat and issuing the <code>/my_id</code> command.',
@ -260,7 +258,7 @@ const NotificationsTelegram: React.FC = () => {
testSettings(); testSettings();
}} }}
> >
{intl.formatMessage(messages.test)} {intl.formatMessage(globalMessages.test)}
</Button> </Button>
</span> </span>
<span className="inline-flex ml-3 rounded-md shadow-sm"> <span className="inline-flex ml-3 rounded-md shadow-sm">
@ -270,8 +268,8 @@ const NotificationsTelegram: React.FC = () => {
disabled={isSubmitting || !isValid} disabled={isSubmitting || !isValid}
> >
{isSubmitting {isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: intl.formatMessage(messages.save)} : intl.formatMessage(globalMessages.save)}
</Button> </Button>
</span> </span>
</div> </div>

@ -1,13 +1,14 @@
import React from 'react'; import axios from 'axios';
import { Field, Form, Formik } from 'formik'; import { Field, Form, Formik } from 'formik';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import useSWR from 'swr'; import React from 'react';
import LoadingSpinner from '../../../Common/LoadingSpinner';
import Button from '../../../Common/Button';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
import axios from 'axios';
import * as Yup from 'yup';
import { useToasts } from 'react-toast-notifications'; import { useToasts } from 'react-toast-notifications';
import useSWR from 'swr';
import * as Yup from 'yup';
import globalMessages from '../../../../i18n/globalMessages';
import Button from '../../../Common/Button';
import LoadingSpinner from '../../../Common/LoadingSpinner';
import NotificationTypeSelector from '../../../NotificationTypeSelector'; import NotificationTypeSelector from '../../../NotificationTypeSelector';
const JSONEditor = dynamic(() => import('../../../JSONEditor'), { ssr: false }); const JSONEditor = dynamic(() => import('../../../JSONEditor'), { ssr: false });
@ -35,8 +36,6 @@ const defaultPayload = {
}; };
const messages = defineMessages({ const messages = defineMessages({
save: 'Save Changes',
saving: 'Saving…',
agentenabled: 'Enable Agent', agentenabled: 'Enable Agent',
webhookUrl: 'Webhook URL', webhookUrl: 'Webhook URL',
authheader: 'Authorization Header', authheader: 'Authorization Header',
@ -44,7 +43,6 @@ const messages = defineMessages({
webhooksettingssaved: 'Webhook notification settings saved successfully!', webhooksettingssaved: 'Webhook notification settings saved successfully!',
webhooksettingsfailed: 'Webhook notification settings failed to save.', webhooksettingsfailed: 'Webhook notification settings failed to save.',
testsent: 'Test notification sent!', testsent: 'Test notification sent!',
test: 'Test',
notificationtypes: 'Notification Types', notificationtypes: 'Notification Types',
resetPayload: 'Reset to Default', resetPayload: 'Reset to Default',
resetPayloadSuccess: 'JSON payload reset successfully!', resetPayloadSuccess: 'JSON payload reset successfully!',
@ -295,7 +293,7 @@ const NotificationsWebhook: React.FC = () => {
testSettings(); testSettings();
}} }}
> >
{intl.formatMessage(messages.test)} {intl.formatMessage(globalMessages.test)}
</Button> </Button>
</span> </span>
<span className="inline-flex ml-3 rounded-md shadow-sm"> <span className="inline-flex ml-3 rounded-md shadow-sm">
@ -305,8 +303,8 @@ const NotificationsWebhook: React.FC = () => {
disabled={isSubmitting || !isValid} disabled={isSubmitting || !isValid}
> >
{isSubmitting {isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: intl.formatMessage(messages.save)} : intl.formatMessage(globalMessages.save)}
</Button> </Button>
</span> </span>
</div> </div>

@ -5,6 +5,7 @@ import { defineMessages, useIntl } from 'react-intl';
import { useToasts } from 'react-toast-notifications'; import { useToasts } from 'react-toast-notifications';
import * as Yup from 'yup'; import * as Yup from 'yup';
import type { RadarrSettings } from '../../../../server/lib/settings'; import type { RadarrSettings } from '../../../../server/lib/settings';
import globalMessages from '../../../i18n/globalMessages';
import Modal from '../../Common/Modal'; import Modal from '../../Common/Modal';
import Transition from '../../Transition'; import Transition from '../../Transition';
@ -21,11 +22,7 @@ const messages = defineMessages({
'You must select a minimum availability', 'You must select a minimum availability',
toastRadarrTestSuccess: 'Radarr connection established successfully!', toastRadarrTestSuccess: 'Radarr connection established successfully!',
toastRadarrTestFailure: 'Failed to connect to Radarr.', toastRadarrTestFailure: 'Failed to connect to Radarr.',
saving: 'Saving…',
save: 'Save Changes',
add: 'Add Server', add: 'Add Server',
test: 'Test',
testing: 'Testing…',
defaultserver: 'Default Server', defaultserver: 'Default Server',
servername: 'Server Name', servername: 'Server Name',
servernamePlaceholder: 'A Radarr Server', servernamePlaceholder: 'A Radarr Server',
@ -294,16 +291,16 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
okButtonType="primary" okButtonType="primary"
okText={ okText={
isSubmitting isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: radarr : radarr
? intl.formatMessage(messages.save) ? intl.formatMessage(globalMessages.save)
: intl.formatMessage(messages.add) : intl.formatMessage(messages.add)
} }
secondaryButtonType="warning" secondaryButtonType="warning"
secondaryText={ secondaryText={
isTesting isTesting
? intl.formatMessage(messages.testing) ? intl.formatMessage(globalMessages.testing)
: intl.formatMessage(messages.test) : intl.formatMessage(globalMessages.test)
} }
onSecondary={() => { onSecondary={() => {
if (values.apiKey && values.hostname && values.port) { if (values.apiKey && values.hostname && values.port) {

@ -30,13 +30,7 @@ const messages = defineMessages({
filterInfo: 'Info', filterInfo: 'Info',
filterWarn: 'Warning', filterWarn: 'Warning',
filterError: 'Error', filterError: 'Error',
noresults: 'No results.',
showall: 'Show All Logs', showall: 'Show All Logs',
showingresults:
'Showing <strong>{from}</strong> to <strong>{to}</strong> of <strong>{total}</strong> results',
resultsperpage: 'Display {pageSize} results per page',
next: 'Next',
previous: 'Previous',
pauseLogs: 'Pause', pauseLogs: 'Pause',
resumeLogs: 'Resume', resumeLogs: 'Resume',
viewDetails: 'View Details', viewDetails: 'View Details',
@ -393,7 +387,7 @@ const SettingsLogs: React.FC = () => {
<Table.TD colSpan={4} noPadding> <Table.TD colSpan={4} noPadding>
<div className="flex flex-col items-center justify-center w-screen p-6 lg:w-full"> <div className="flex flex-col items-center justify-center w-screen p-6 lg:w-full">
<span className="text-base"> <span className="text-base">
{intl.formatMessage(messages.noresults)} {intl.formatMessage(globalMessages.noresults)}
</span> </span>
{currentFilter !== 'debug' && ( {currentFilter !== 'debug' && (
<div className="mt-4"> <div className="mt-4">
@ -419,7 +413,7 @@ const SettingsLogs: React.FC = () => {
<div className="hidden lg:flex lg:flex-1"> <div className="hidden lg:flex lg:flex-1">
<p className="text-sm"> <p className="text-sm">
{data.results.length > 0 && {data.results.length > 0 &&
intl.formatMessage(messages.showingresults, { intl.formatMessage(globalMessages.showingresults, {
from: pageIndex * currentPageSize + 1, from: pageIndex * currentPageSize + 1,
to: to:
data.results.length < currentPageSize data.results.length < currentPageSize
@ -435,7 +429,7 @@ const SettingsLogs: React.FC = () => {
</div> </div>
<div className="flex justify-center sm:flex-1 sm:justify-start lg:justify-center"> <div className="flex justify-center sm:flex-1 sm:justify-start lg:justify-center">
<span className="items-center -mt-3 text-sm sm:-ml-4 lg:ml-0 sm:mt-0"> <span className="items-center -mt-3 text-sm sm:-ml-4 lg:ml-0 sm:mt-0">
{intl.formatMessage(messages.resultsperpage, { {intl.formatMessage(globalMessages.resultsperpage, {
pageSize: ( pageSize: (
<select <select
id="pageSize" id="pageSize"
@ -473,7 +467,7 @@ const SettingsLogs: React.FC = () => {
.then(() => window.scrollTo(0, 0)) .then(() => window.scrollTo(0, 0))
} }
> >
{intl.formatMessage(messages.previous)} {intl.formatMessage(globalMessages.previous)}
</Button> </Button>
<Button <Button
disabled={!hasNextPage} disabled={!hasNextPage}
@ -489,7 +483,7 @@ const SettingsLogs: React.FC = () => {
.then(() => window.scrollTo(0, 0)) .then(() => window.scrollTo(0, 0))
} }
> >
{intl.formatMessage(messages.next)} {intl.formatMessage(globalMessages.next)}
</Button> </Button>
</div> </div>
</nav> </nav>

@ -20,8 +20,6 @@ const messages = defineMessages({
generalsettings: 'General Settings', generalsettings: 'General Settings',
generalsettingsDescription: generalsettingsDescription:
'Configure global and default settings for Overseerr.', 'Configure global and default settings for Overseerr.',
save: 'Save Changes',
saving: 'Saving…',
apikey: 'API Key', apikey: 'API Key',
applicationTitle: 'Application Title', applicationTitle: 'Application Title',
applicationurl: 'Application URL', applicationurl: 'Application URL',
@ -423,8 +421,8 @@ const SettingsMain: React.FC = () => {
disabled={isSubmitting} disabled={isSubmitting}
> >
{isSubmitting {isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: intl.formatMessage(messages.save)} : intl.formatMessage(globalMessages.save)}
</Button> </Button>
</span> </span>
</div> </div>

@ -1,27 +1,25 @@
import axios from 'axios';
import { Field, Form, Formik } from 'formik';
import Link from 'next/link'; import Link from 'next/link';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
import { useToasts } from 'react-toast-notifications';
import useSWR from 'swr';
import Bolt from '../../assets/bolt.svg';
import DiscordLogo from '../../assets/extlogos/discord.svg'; import DiscordLogo from '../../assets/extlogos/discord.svg';
import SlackLogo from '../../assets/extlogos/slack.svg';
import TelegramLogo from '../../assets/extlogos/telegram.svg';
import PushbulletLogo from '../../assets/extlogos/pushbullet.svg'; import PushbulletLogo from '../../assets/extlogos/pushbullet.svg';
import PushoverLogo from '../../assets/extlogos/pushover.svg'; import PushoverLogo from '../../assets/extlogos/pushover.svg';
import Bolt from '../../assets/bolt.svg'; import SlackLogo from '../../assets/extlogos/slack.svg';
import { Field, Form, Formik } from 'formik'; import TelegramLogo from '../../assets/extlogos/telegram.svg';
import useSWR from 'swr'; import globalMessages from '../../i18n/globalMessages';
import Error from '../../pages/_error'; import Error from '../../pages/_error';
import LoadingSpinner from '../Common/LoadingSpinner';
import axios from 'axios';
import { useToasts } from 'react-toast-notifications';
import Button from '../Common/Button'; import Button from '../Common/Button';
import LoadingSpinner from '../Common/LoadingSpinner';
import PageTitle from '../Common/PageTitle'; import PageTitle from '../Common/PageTitle';
import globalMessages from '../../i18n/globalMessages';
const messages = defineMessages({ const messages = defineMessages({
notifications: 'Notifications', notifications: 'Notifications',
save: 'Save Changes',
saving: 'Saving…',
notificationsettings: 'Notification Settings', notificationsettings: 'Notification Settings',
notificationsettingsDescription: notificationsettingsDescription:
'Configure global notification settings. The options below will apply to all notification agents.', 'Configure global notification settings. The options below will apply to all notification agents.',
@ -248,8 +246,8 @@ const SettingsNotifications: React.FC = ({ children }) => {
disabled={isSubmitting} disabled={isSubmitting}
> >
{isSubmitting {isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: intl.formatMessage(messages.save)} : intl.formatMessage(globalMessages.save)}
</Button> </Button>
</span> </span>
</div> </div>

@ -45,8 +45,6 @@ const messages = defineMessages({
port: 'Port', port: 'Port',
enablessl: 'Enable SSL', enablessl: 'Enable SSL',
timeout: 'Timeout', timeout: 'Timeout',
save: 'Save Changes',
saving: 'Saving…',
plexlibraries: 'Plex Libraries', plexlibraries: 'Plex Libraries',
plexlibrariesDescription: plexlibrariesDescription:
'The libraries Overseerr scans for titles. Set up and save your Plex connection settings, then click the button below if no libraries are listed.', 'The libraries Overseerr scans for titles. Set up and save your Plex connection settings, then click the button below if no libraries are listed.',
@ -538,8 +536,8 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
disabled={isSubmitting} disabled={isSubmitting}
> >
{isSubmitting {isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: intl.formatMessage(messages.save)} : intl.formatMessage(globalMessages.save)}
</Button> </Button>
</span> </span>
</div> </div>

@ -1,21 +1,21 @@
import axios from 'axios';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
import Badge from '../Common/Badge';
import Button from '../Common/Button';
import useSWR from 'swr'; import useSWR from 'swr';
import type { import type {
RadarrSettings, RadarrSettings,
SonarrSettings, SonarrSettings,
} from '../../../server/lib/settings'; } from '../../../server/lib/settings';
import globalMessages from '../../i18n/globalMessages';
import Alert from '../Common/Alert';
import Badge from '../Common/Badge';
import Button from '../Common/Button';
import LoadingSpinner from '../Common/LoadingSpinner'; import LoadingSpinner from '../Common/LoadingSpinner';
import RadarrModal from './RadarrModal';
import Modal from '../Common/Modal'; import Modal from '../Common/Modal';
import PageTitle from '../Common/PageTitle';
import Transition from '../Transition'; import Transition from '../Transition';
import axios from 'axios'; import RadarrModal from './RadarrModal';
import SonarrModal from './SonarrModal'; import SonarrModal from './SonarrModal';
import Alert from '../Common/Alert';
import PageTitle from '../Common/PageTitle';
import globalMessages from '../../i18n/globalMessages';
const messages = defineMessages({ const messages = defineMessages({
services: 'Services', services: 'Services',
@ -26,8 +26,6 @@ const messages = defineMessages({
sonarrSettingsDescription: sonarrSettingsDescription:
'Configure your Sonarr connection below. You can have multiple Sonarr configurations, but only two can be active as defaults at any time (one for standard HD and one for 4K). Administrators can override the server which is used for new requests.', 'Configure your Sonarr connection below. You can have multiple Sonarr configurations, but only two can be active as defaults at any time (one for standard HD and one for 4K). Administrators can override the server which is used for new requests.',
deleteserverconfirm: 'Are you sure you want to delete this server?', deleteserverconfirm: 'Are you sure you want to delete this server?',
edit: 'Edit',
delete: 'Delete',
ssl: 'SSL', ssl: 'SSL',
default: 'Default', default: 'Default',
default4k: 'Default 4K', default4k: 'Default 4K',
@ -139,7 +137,9 @@ const ServerInstance: React.FC<ServerInstanceProps> = ({
> >
<path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" /> <path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" />
</svg> </svg>
<span className="ml-3">{intl.formatMessage(messages.edit)}</span> <span className="ml-3">
{intl.formatMessage(globalMessages.edit)}
</span>
</button> </button>
</div> </div>
<div className="flex flex-1 w-0 -ml-px"> <div className="flex flex-1 w-0 -ml-px">
@ -160,7 +160,7 @@ const ServerInstance: React.FC<ServerInstanceProps> = ({
/> />
</svg> </svg>
<span className="ml-3"> <span className="ml-3">
{intl.formatMessage(messages.delete)} {intl.formatMessage(globalMessages.delete)}
</span> </span>
</button> </button>
</div> </div>

@ -16,15 +16,11 @@ const messages = defineMessages({
users: 'Users', users: 'Users',
userSettings: 'User Settings', userSettings: 'User Settings',
userSettingsDescription: 'Configure global and default user settings.', userSettingsDescription: 'Configure global and default user settings.',
save: 'Save Changes',
saving: 'Saving…',
toastSettingsSuccess: 'User settings saved successfully!', toastSettingsSuccess: 'User settings saved successfully!',
toastSettingsFailure: 'Something went wrong while saving settings.', toastSettingsFailure: 'Something went wrong while saving settings.',
localLogin: 'Enable Local Sign-In', localLogin: 'Enable Local Sign-In',
movieRequestLimitLabel: 'Global Movie Request Limit', movieRequestLimitLabel: 'Global Movie Request Limit',
movieRequestLimit: '{quotaLimit} movies per {quotaDays} days',
tvRequestLimitLabel: 'Global Series Request Limit', tvRequestLimitLabel: 'Global Series Request Limit',
tvRequestLimit: '{quotaLimit} seasons per {quotaDays} days',
defaultPermissions: 'Default Permissions', defaultPermissions: 'Default Permissions',
}); });
@ -173,8 +169,8 @@ const SettingsUsers: React.FC = () => {
disabled={isSubmitting} disabled={isSubmitting}
> >
{isSubmitting {isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: intl.formatMessage(messages.save)} : intl.formatMessage(globalMessages.save)}
</Button> </Button>
</span> </span>
</div> </div>

@ -1,12 +1,13 @@
import React, { useState, useEffect, useCallback, useRef } from 'react';
import Transition from '../../Transition';
import Modal from '../../Common/Modal';
import { Formik, Field } from 'formik';
import type { SonarrSettings } from '../../../../server/lib/settings';
import * as Yup from 'yup';
import axios from 'axios'; import axios from 'axios';
import { Field, Formik } from 'formik';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { useToasts } from 'react-toast-notifications'; import { useToasts } from 'react-toast-notifications';
import { useIntl, defineMessages } from 'react-intl'; import * as Yup from 'yup';
import type { SonarrSettings } from '../../../../server/lib/settings';
import globalMessages from '../../../i18n/globalMessages';
import Modal from '../../Common/Modal';
import Transition from '../../Transition';
const messages = defineMessages({ const messages = defineMessages({
createsonarr: 'Add New Sonarr Server', createsonarr: 'Add New Sonarr Server',
@ -20,11 +21,7 @@ const messages = defineMessages({
validationLanguageProfileRequired: 'You must select a language profile', validationLanguageProfileRequired: 'You must select a language profile',
toastSonarrTestSuccess: 'Sonarr connection established successfully!', toastSonarrTestSuccess: 'Sonarr connection established successfully!',
toastSonarrTestFailure: 'Failed to connect to Sonarr.', toastSonarrTestFailure: 'Failed to connect to Sonarr.',
saving: 'Saving…',
save: 'Save Changes',
add: 'Add Server', add: 'Add Server',
test: 'Test',
testing: 'Testing…',
defaultserver: 'Default Server', defaultserver: 'Default Server',
servername: 'Server Name', servername: 'Server Name',
servernamePlaceholder: 'A Sonarr Server', servernamePlaceholder: 'A Sonarr Server',
@ -322,16 +319,16 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
okButtonType="primary" okButtonType="primary"
okText={ okText={
isSubmitting isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: sonarr : sonarr
? intl.formatMessage(messages.save) ? intl.formatMessage(globalMessages.save)
: intl.formatMessage(messages.add) : intl.formatMessage(messages.add)
} }
secondaryButtonType="warning" secondaryButtonType="warning"
secondaryText={ secondaryText={
isTesting isTesting
? intl.formatMessage(messages.testing) ? intl.formatMessage(globalMessages.testing)
: intl.formatMessage(messages.test) : intl.formatMessage(globalMessages.test)
} }
onSecondary={() => { onSecondary={() => {
if (values.apiKey && values.hostname && values.port) { if (values.apiKey && values.hostname && values.port) {

@ -1,18 +1,15 @@
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import React, { import React, {
ReactNode,
useCallback, useCallback,
useEffect, useEffect,
useRef, useRef,
useState, useState,
ReactNode,
} from 'react'; } from 'react';
import { useIntl } from 'react-intl';
import { useSpring } from 'react-spring'; import { useSpring } from 'react-spring';
import globalMessages from '../../i18n/globalMessages';
import TitleCard from '../TitleCard'; import TitleCard from '../TitleCard';
import { defineMessages, useIntl } from 'react-intl';
const messages = defineMessages({
noresults: 'No results.',
});
interface SliderProps { interface SliderProps {
sliderKey: string; sliderKey: string;
@ -233,7 +230,7 @@ const Slider: React.FC<SliderProps> = ({
<div className="mt-16 mb-16 text-center text-white"> <div className="mt-16 mb-16 text-center text-white">
{emptyMessage {emptyMessage
? emptyMessage ? emptyMessage
: intl.formatMessage(messages.noresults)} : intl.formatMessage(globalMessages.noresults)}
</div> </div>
)} )}
</div> </div>

@ -1,22 +1,17 @@
import React, { useState, useCallback, useEffect } from 'react';
import type { MediaType } from '../../../server/models/Search';
import { withProperties } from '../../utils/typeHelpers';
import Transition from '../Transition';
import Placeholder from './Placeholder';
import Link from 'next/link'; import Link from 'next/link';
import React, { useCallback, useEffect, useState } from 'react';
import { useIntl } from 'react-intl';
import { MediaStatus } from '../../../server/constants/media'; import { MediaStatus } from '../../../server/constants/media';
import RequestModal from '../RequestModal'; import type { MediaType } from '../../../server/models/Search';
import { defineMessages, useIntl } from 'react-intl'; import Spinner from '../../assets/spinner.svg';
import { useIsTouch } from '../../hooks/useIsTouch'; import { useIsTouch } from '../../hooks/useIsTouch';
import { Permission, useUser } from '../../hooks/useUser';
import globalMessages from '../../i18n/globalMessages'; import globalMessages from '../../i18n/globalMessages';
import Spinner from '../../assets/spinner.svg'; import { withProperties } from '../../utils/typeHelpers';
import { useUser, Permission } from '../../hooks/useUser';
import CachedImage from '../Common/CachedImage'; import CachedImage from '../Common/CachedImage';
import RequestModal from '../RequestModal';
const messages = defineMessages({ import Transition from '../Transition';
movie: 'Movie', import Placeholder from './Placeholder';
tvshow: 'Series',
});
interface TitleCardProps { interface TitleCardProps {
id: number; id: number;
@ -125,8 +120,8 @@ const TitleCard: React.FC<TitleCardProps> = ({
> >
<div className="flex items-center h-4 px-2 py-2 text-xs font-normal tracking-wider text-center text-white uppercase sm:h-5"> <div className="flex items-center h-4 px-2 py-2 text-xs font-normal tracking-wider text-center text-white uppercase sm:h-5">
{mediaType === 'movie' {mediaType === 'movie'
? intl.formatMessage(messages.movie) ? intl.formatMessage(globalMessages.movie)
: intl.formatMessage(messages.tvshow)} : intl.formatMessage(globalMessages.tvshow)}
</div> </div>
</div> </div>
<div className="z-40 pointer-events-none"> <div className="z-40 pointer-events-none">

@ -40,7 +40,6 @@ import StatusBadge from '../StatusBadge';
const messages = defineMessages({ const messages = defineMessages({
firstAirDate: 'First Air Date', firstAirDate: 'First Air Date',
nextAirDate: 'Next Air Date', nextAirDate: 'Next Air Date',
status: 'Status',
originallanguage: 'Original Language', originallanguage: 'Original Language',
overview: 'Overview', overview: 'Overview',
cast: 'Cast', cast: 'Cast',
@ -58,7 +57,6 @@ const messages = defineMessages({
anime: 'Anime', anime: 'Anime',
network: '{networkCount, plural, one {Network} other {Networks}}', network: '{networkCount, plural, one {Network} other {Networks}}',
viewfullcrew: 'View Full Crew', viewfullcrew: 'View Full Crew',
areyousure: 'Are you sure?',
opensonarr: 'Open Series in Sonarr', opensonarr: 'Open Series in Sonarr',
opensonarr4k: 'Open Series in 4K Sonarr', opensonarr4k: 'Open Series in 4K Sonarr',
downloadstatus: 'Download Status', downloadstatus: 'Download Status',
@ -420,7 +418,7 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
<div className="mt-8"> <div className="mt-8">
<ConfirmButton <ConfirmButton
onClick={() => deleteMedia()} onClick={() => deleteMedia()}
confirmText={intl.formatMessage(messages.areyousure)} confirmText={intl.formatMessage(globalMessages.areyousure)}
className="w-full" className="w-full"
> >
{intl.formatMessage(messages.manageModalClearMedia)} {intl.formatMessage(messages.manageModalClearMedia)}
@ -628,7 +626,7 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
</div> </div>
)} )}
<div className="media-fact"> <div className="media-fact">
<span>{intl.formatMessage(messages.status)}</span> <span>{intl.formatMessage(globalMessages.status)}</span>
<span className="media-fact-value">{data.status}</span> <span className="media-fact-value">{data.status}</span>
</div> </div>
{data.firstAirDate && ( {data.firstAirDate && (

@ -1,10 +1,11 @@
import axios from 'axios';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import PermissionEdit from '../PermissionEdit';
import Modal from '../Common/Modal';
import { User, useUser } from '../../hooks/useUser';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
import axios from 'axios';
import { useToasts } from 'react-toast-notifications'; import { useToasts } from 'react-toast-notifications';
import { User, useUser } from '../../hooks/useUser';
import globalMessages from '../../i18n/globalMessages';
import Modal from '../Common/Modal';
import PermissionEdit from '../PermissionEdit';
interface BulkEditProps { interface BulkEditProps {
selectedUserIds: number[]; selectedUserIds: number[];
@ -16,8 +17,6 @@ interface BulkEditProps {
const messages = defineMessages({ const messages = defineMessages({
userssaved: 'User permissions saved successfully!', userssaved: 'User permissions saved successfully!',
save: 'Save Changes',
saving: 'Saving…',
userfail: 'Something went wrong while saving user permissions.', userfail: 'Something went wrong while saving user permissions.',
edituser: 'Edit User Permissions', edituser: 'Edit User Permissions',
}); });
@ -89,7 +88,7 @@ const BulkEditModal: React.FC<BulkEditProps> = ({
updateUsers(); updateUsers();
}} }}
okDisabled={isSaving} okDisabled={isSaving}
okText={intl.formatMessage(messages.save)} okText={intl.formatMessage(globalMessages.save)}
onCancel={onCancel} onCancel={onCancel}
> >
<div className="mb-6"> <div className="mb-6">

@ -37,9 +37,7 @@ const messages = defineMessages({
role: 'Role', role: 'Role',
created: 'Created', created: 'Created',
lastupdated: 'Last Updated', lastupdated: 'Last Updated',
edit: 'Edit',
bulkedit: 'Bulk Edit', bulkedit: 'Bulk Edit',
delete: 'Delete',
owner: 'Owner', owner: 'Owner',
admin: 'Admin', admin: 'Admin',
plexuser: 'Plex User', plexuser: 'Plex User',
@ -68,11 +66,6 @@ const messages = defineMessages({
sortUpdated: 'Last Updated', sortUpdated: 'Last Updated',
sortDisplayName: 'Display Name', sortDisplayName: 'Display Name',
sortRequests: 'Request Count', sortRequests: 'Request Count',
next: 'Next',
previous: 'Previous',
showingresults:
'Showing <strong>{from}</strong> to <strong>{to}</strong> of <strong>{total}</strong> results',
resultsperpage: 'Display {pageSize} results per page',
}); });
type Sort = 'created' | 'updated' | 'requests' | 'displayname'; type Sort = 'created' | 'updated' | 'requests' | 'displayname';
@ -602,7 +595,7 @@ const UserList: React.FC = () => {
) )
} }
> >
{intl.formatMessage(messages.edit)} {intl.formatMessage(globalMessages.edit)}
</Button> </Button>
<Button <Button
buttonType="danger" buttonType="danger"
@ -613,7 +606,7 @@ const UserList: React.FC = () => {
} }
onClick={() => setDeleteModal({ isOpen: true, user })} onClick={() => setDeleteModal({ isOpen: true, user })}
> >
{intl.formatMessage(messages.delete)} {intl.formatMessage(globalMessages.delete)}
</Button> </Button>
</Table.TD> </Table.TD>
</tr> </tr>
@ -627,7 +620,7 @@ const UserList: React.FC = () => {
<div className="hidden lg:flex lg:flex-1"> <div className="hidden lg:flex lg:flex-1">
<p className="text-sm"> <p className="text-sm">
{data.results.length > 0 && {data.results.length > 0 &&
intl.formatMessage(messages.showingresults, { intl.formatMessage(globalMessages.showingresults, {
from: pageIndex * currentPageSize + 1, from: pageIndex * currentPageSize + 1,
to: to:
data.results.length < currentPageSize data.results.length < currentPageSize
@ -642,7 +635,7 @@ const UserList: React.FC = () => {
</div> </div>
<div className="flex justify-center sm:flex-1 sm:justify-start lg:justify-center"> <div className="flex justify-center sm:flex-1 sm:justify-start lg:justify-center">
<span className="items-center -mt-3 text-sm sm:-ml-4 lg:ml-0 sm:mt-0"> <span className="items-center -mt-3 text-sm sm:-ml-4 lg:ml-0 sm:mt-0">
{intl.formatMessage(messages.resultsperpage, { {intl.formatMessage(globalMessages.resultsperpage, {
pageSize: ( pageSize: (
<select <select
id="pageSize" id="pageSize"
@ -681,7 +674,7 @@ const UserList: React.FC = () => {
.then(() => window.scrollTo(0, 0)) .then(() => window.scrollTo(0, 0))
} }
> >
{intl.formatMessage(messages.previous)} {intl.formatMessage(globalMessages.previous)}
</Button> </Button>
<Button <Button
disabled={!hasNextPage} disabled={!hasNextPage}
@ -697,7 +690,7 @@ const UserList: React.FC = () => {
.then(() => window.scrollTo(0, 0)) .then(() => window.scrollTo(0, 0))
} }
> >
{intl.formatMessage(messages.next)} {intl.formatMessage(globalMessages.next)}
</Button> </Button>
</div> </div>
</nav> </nav>

@ -22,8 +22,6 @@ const messages = defineMessages({
general: 'General', general: 'General',
generalsettings: 'General Settings', generalsettings: 'General Settings',
displayName: 'Display Name', displayName: 'Display Name',
save: 'Save Changes',
saving: 'Saving…',
accounttype: 'Account Type', accounttype: 'Account Type',
plexuser: 'Plex User', plexuser: 'Plex User',
localuser: 'Local User', localuser: 'Local User',
@ -362,8 +360,8 @@ const UserGeneralSettings: React.FC = () => {
disabled={isSubmitting} disabled={isSubmitting}
> >
{isSubmitting {isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: intl.formatMessage(messages.save)} : intl.formatMessage(globalMessages.save)}
</Button> </Button>
</span> </span>
</div> </div>

@ -31,8 +31,6 @@ const messages = defineMessages({
sendSilently: 'Send Telegram Messages Silently', sendSilently: 'Send Telegram Messages Silently',
sendSilentlyDescription: 'Send notifications with no sound', sendSilentlyDescription: 'Send notifications with no sound',
validationTelegramChatId: 'You must provide a valid Telegram chat ID', validationTelegramChatId: 'You must provide a valid Telegram chat ID',
save: 'Save Changes',
saving: 'Saving…',
plexuser: 'Plex User', plexuser: 'Plex User',
localuser: 'Local User', localuser: 'Local User',
toastSettingsSuccess: 'Notification settings saved successfully!', toastSettingsSuccess: 'Notification settings saved successfully!',
@ -283,8 +281,8 @@ const UserNotificationSettings: React.FC = () => {
disabled={isSubmitting} disabled={isSubmitting}
> >
{isSubmitting {isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: intl.formatMessage(messages.save)} : intl.formatMessage(globalMessages.save)}
</Button> </Button>
</span> </span>
</div> </div>

@ -20,8 +20,6 @@ const messages = defineMessages({
currentpassword: 'Current Password', currentpassword: 'Current Password',
newpassword: 'New Password', newpassword: 'New Password',
confirmpassword: 'Confirm Password', confirmpassword: 'Confirm Password',
save: 'Save Changes',
saving: 'Saving…',
toastSettingsSuccess: 'Password saved successfully!', toastSettingsSuccess: 'Password saved successfully!',
toastSettingsFailure: 'Something went wrong while saving the password.', toastSettingsFailure: 'Something went wrong while saving the password.',
toastSettingsFailureVerifyCurrent: toastSettingsFailureVerifyCurrent:
@ -37,7 +35,6 @@ const messages = defineMessages({
'This user account currently does not have a password specifically for {applicationTitle}. Configure a password below to enable this account to sign in as a "local user."', 'This user account currently does not have a password specifically for {applicationTitle}. Configure a password below to enable this account to sign in as a "local user."',
nopasswordsetDescriptionOwnAccount: nopasswordsetDescriptionOwnAccount:
'Your account currently does not have a password specifically for {applicationTitle}. Configure a password below to enable sign in as a "local user" using your email address.', 'Your account currently does not have a password specifically for {applicationTitle}. Configure a password below to enable sign in as a "local user" using your email address.',
nopermission: 'Unauthorized',
nopermissionDescription: nopermissionDescription:
"You do not have permission to modify this user's password.", "You do not have permission to modify this user's password.",
}); });
@ -90,7 +87,10 @@ const UserPasswordChange: React.FC = () => {
<div className="mb-6"> <div className="mb-6">
<h3 className="heading">{intl.formatMessage(messages.password)}</h3> <h3 className="heading">{intl.formatMessage(messages.password)}</h3>
</div> </div>
<Alert title={intl.formatMessage(messages.nopermission)} type="error"> <Alert
title={intl.formatMessage(globalMessages.unauthorized)}
type="error"
>
{intl.formatMessage(messages.nopermissionDescription)} {intl.formatMessage(messages.nopermissionDescription)}
</Alert> </Alert>
</> </>
@ -224,8 +224,8 @@ const UserPasswordChange: React.FC = () => {
disabled={isSubmitting} disabled={isSubmitting}
> >
{isSubmitting {isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: intl.formatMessage(messages.save)} : intl.formatMessage(globalMessages.save)}
</Button> </Button>
</span> </span>
</div> </div>

@ -6,24 +6,21 @@ import { defineMessages, useIntl } from 'react-intl';
import { useToasts } from 'react-toast-notifications'; import { useToasts } from 'react-toast-notifications';
import useSWR from 'swr'; import useSWR from 'swr';
import { useUser } from '../../../../hooks/useUser'; import { useUser } from '../../../../hooks/useUser';
import globalMessages from '../../../../i18n/globalMessages';
import Error from '../../../../pages/_error'; import Error from '../../../../pages/_error';
import Alert from '../../../Common/Alert';
import Button from '../../../Common/Button'; import Button from '../../../Common/Button';
import LoadingSpinner from '../../../Common/LoadingSpinner'; import LoadingSpinner from '../../../Common/LoadingSpinner';
import PermissionEdit from '../../../PermissionEdit';
import Alert from '../../../Common/Alert';
import PageTitle from '../../../Common/PageTitle'; import PageTitle from '../../../Common/PageTitle';
import globalMessages from '../../../../i18n/globalMessages'; import PermissionEdit from '../../../PermissionEdit';
const messages = defineMessages({ const messages = defineMessages({
displayName: 'Display Name', displayName: 'Display Name',
save: 'Save Changes',
saving: 'Saving…',
plexuser: 'Plex User', plexuser: 'Plex User',
localuser: 'Local User', localuser: 'Local User',
toastSettingsSuccess: 'Permissions saved successfully!', toastSettingsSuccess: 'Permissions saved successfully!',
toastSettingsFailure: 'Something went wrong while saving settings.', toastSettingsFailure: 'Something went wrong while saving settings.',
permissions: 'Permissions', permissions: 'Permissions',
unauthorized: 'Unauthorized',
unauthorizedDescription: 'You cannot modify your own permissions.', unauthorizedDescription: 'You cannot modify your own permissions.',
}); });
@ -53,7 +50,10 @@ const UserPermissions: React.FC = () => {
{intl.formatMessage(messages.permissions)} {intl.formatMessage(messages.permissions)}
</h3> </h3>
</div> </div>
<Alert title={intl.formatMessage(messages.unauthorized)} type="error"> <Alert
title={intl.formatMessage(globalMessages.unauthorized)}
type="error"
>
{intl.formatMessage(messages.unauthorizedDescription)} {intl.formatMessage(messages.unauthorizedDescription)}
</Alert> </Alert>
</> </>
@ -120,8 +120,8 @@ const UserPermissions: React.FC = () => {
disabled={isSubmitting} disabled={isSubmitting}
> >
{isSubmitting {isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(globalMessages.saving)
: intl.formatMessage(messages.save)} : intl.formatMessage(globalMessages.save)}
</Button> </Button>
</span> </span>
</div> </div>

@ -17,7 +17,6 @@ const messages = defineMessages({
menuChangePass: 'Password', menuChangePass: 'Password',
menuNotifications: 'Notifications', menuNotifications: 'Notifications',
menuPermissions: 'Permissions', menuPermissions: 'Permissions',
unauthorized: 'Unauthorized',
unauthorizedDescription: unauthorizedDescription:
"You do not have permission to modify this user's settings.", "You do not have permission to modify this user's settings.",
}); });
@ -123,7 +122,10 @@ const UserSettings: React.FC = ({ children }) => {
/> />
<ProfileHeader user={user} isSettingsPage /> <ProfileHeader user={user} isSettingsPage />
<div className="mt-6"> <div className="mt-6">
<Alert title={intl.formatMessage(messages.unauthorized)} type="error"> <Alert
title={intl.formatMessage(globalMessages.unauthorized)}
type="error"
>
{intl.formatMessage(messages.unauthorizedDescription)} {intl.formatMessage(messages.unauthorizedDescription)}
</Alert> </Alert>
</div> </div>

@ -5,28 +5,50 @@ const globalMessages = defineMessages({
partiallyavailable: 'Partially Available', partiallyavailable: 'Partially Available',
processing: 'Processing', processing: 'Processing',
unavailable: 'Unavailable', unavailable: 'Unavailable',
notrequested: 'Not Requested',
requested: 'Requested', requested: 'Requested',
requesting: 'Requesting…',
request: 'Request', request: 'Request',
request4k: 'Request 4K',
failed: 'Failed', failed: 'Failed',
pending: 'Pending', pending: 'Pending',
declined: 'Declined', declined: 'Declined',
approved: 'Approved', approved: 'Approved',
movie: 'Movie',
movies: 'Movies', movies: 'Movies',
tvshow: 'Series',
tvshows: 'Series', tvshows: 'Series',
cancel: 'Cancel', cancel: 'Cancel',
canceling: 'Canceling…',
approve: 'Approve', approve: 'Approve',
decline: 'Decline', decline: 'Decline',
delete: 'Delete', delete: 'Delete',
retry: 'Retry', retry: 'Retry',
view: 'View',
deleting: 'Deleting…', deleting: 'Deleting…',
test: 'Test',
testing: 'Testing…',
save: 'Save Changes',
saving: 'Saving…',
close: 'Close', close: 'Close',
edit: 'Edit', edit: 'Edit',
areyousure: 'Are you sure?',
back: 'Back',
next: 'Next',
previous: 'Previous',
status: 'Status',
all: 'All',
experimental: 'Experimental', experimental: 'Experimental',
advanced: 'Advanced', advanced: 'Advanced',
loading: 'Loading…', loading: 'Loading…',
settings: 'Settings', settings: 'Settings',
usersettings: 'User Settings', usersettings: 'User Settings',
unauthorized: 'Unauthorized',
delimitedlist: '{a}, {b}', delimitedlist: '{a}, {b}',
showingresults:
'Showing <strong>{from}</strong> to <strong>{to}</strong> of <strong>{total}</strong> results',
resultsperpage: 'Display {pageSize} results per page',
noresults: 'No results.',
}); });
export default globalMessages; export default globalMessages;

@ -1,19 +1,14 @@
{ {
"components.AppDataWarning.dockerVolumeMissing": "Docker Volume Mount Missing", "components.AppDataWarning.dockerVolumeMissing": "Docker Volume Mount Missing",
"components.AppDataWarning.dockerVolumeMissingDescription": "The <code>{appDataPath}</code> volume mount was not configured properly. All data will be cleared when the container is stopped or restarted.", "components.AppDataWarning.dockerVolumeMissingDescription": "The <code>{appDataPath}</code> volume mount was not configured properly. All data will be cleared when the container is stopped or restarted.",
"components.CollectionDetails.movies": "Movies",
"components.CollectionDetails.numberofmovies": "{count} Movies", "components.CollectionDetails.numberofmovies": "{count} Movies",
"components.CollectionDetails.overview": "Overview", "components.CollectionDetails.overview": "Overview",
"components.CollectionDetails.overviewunavailable": "Overview unavailable.", "components.CollectionDetails.overviewunavailable": "Overview unavailable.",
"components.CollectionDetails.request": "Request",
"components.CollectionDetails.request4k": "Request 4K",
"components.CollectionDetails.requestSuccess": "<strong>{title}</strong> requested successfully!", "components.CollectionDetails.requestSuccess": "<strong>{title}</strong> requested successfully!",
"components.CollectionDetails.requestcollection": "Request Collection", "components.CollectionDetails.requestcollection": "Request Collection",
"components.CollectionDetails.requestcollection4k": "Request Collection in 4K", "components.CollectionDetails.requestcollection4k": "Request Collection in 4K",
"components.CollectionDetails.requesting": "Requesting…",
"components.CollectionDetails.requestswillbecreated": "The following titles will have requests created for them:", "components.CollectionDetails.requestswillbecreated": "The following titles will have requests created for them:",
"components.CollectionDetails.requestswillbecreated4k": "The following titles will have 4K requests created for them:", "components.CollectionDetails.requestswillbecreated4k": "The following titles will have 4K requests created for them:",
"components.Common.ListView.noresults": "No results.",
"components.Discover.DiscoverMovieGenre.genreMovies": "{genre} Movies", "components.Discover.DiscoverMovieGenre.genreMovies": "{genre} Movies",
"components.Discover.DiscoverMovieLanguage.languageMovies": "{language} Movies", "components.Discover.DiscoverMovieLanguage.languageMovies": "{language} Movies",
"components.Discover.DiscoverNetwork.networkSeries": "{network} Series", "components.Discover.DiscoverNetwork.networkSeries": "{network} Series",
@ -62,7 +57,6 @@
"components.MediaSlider.ShowMoreCard.seemore": "See More", "components.MediaSlider.ShowMoreCard.seemore": "See More",
"components.MovieDetails.MovieCast.fullcast": "Full Cast", "components.MovieDetails.MovieCast.fullcast": "Full Cast",
"components.MovieDetails.MovieCrew.fullcrew": "Full Crew", "components.MovieDetails.MovieCrew.fullcrew": "Full Crew",
"components.MovieDetails.areyousure": "Are you sure?",
"components.MovieDetails.budget": "Budget", "components.MovieDetails.budget": "Budget",
"components.MovieDetails.cast": "Cast", "components.MovieDetails.cast": "Cast",
"components.MovieDetails.downloadstatus": "Download Status", "components.MovieDetails.downloadstatus": "Download Status",
@ -85,9 +79,7 @@
"components.MovieDetails.revenue": "Revenue", "components.MovieDetails.revenue": "Revenue",
"components.MovieDetails.runtime": "{minutes} minutes", "components.MovieDetails.runtime": "{minutes} minutes",
"components.MovieDetails.similar": "Similar Titles", "components.MovieDetails.similar": "Similar Titles",
"components.MovieDetails.status": "Status",
"components.MovieDetails.studio": "{studioCount, plural, one {Studio} other {Studios}}", "components.MovieDetails.studio": "{studioCount, plural, one {Studio} other {Studios}}",
"components.MovieDetails.view": "View",
"components.MovieDetails.viewfullcrew": "View Full Crew", "components.MovieDetails.viewfullcrew": "View Full Crew",
"components.MovieDetails.watchtrailer": "Watch Trailer", "components.MovieDetails.watchtrailer": "Watch Trailer",
"components.NotificationTypeSelector.mediaAutoApproved": "Media Automatically Approved", "components.NotificationTypeSelector.mediaAutoApproved": "Media Automatically Approved",
@ -142,11 +134,10 @@
"components.PersonDetails.birthdate": "Born {birthdate}", "components.PersonDetails.birthdate": "Born {birthdate}",
"components.PersonDetails.crewmember": "Crew", "components.PersonDetails.crewmember": "Crew",
"components.PersonDetails.lifespan": "{birthdate} {deathdate}", "components.PersonDetails.lifespan": "{birthdate} {deathdate}",
"components.PlexLoginButton.loading": "Loading…",
"components.PlexLoginButton.signingin": "Signing in…", "components.PlexLoginButton.signingin": "Signing in…",
"components.PlexLoginButton.signinwithplex": "Sign In", "components.PlexLoginButton.signinwithplex": "Sign In",
"components.QuotaSelector.movieRequestLimit": "{quotaLimit} movies per {quotaDays} days", "components.QuotaSelector.movieRequestLimit": "{quotaLimit} movie(s) per {quotaDays} day(s)",
"components.QuotaSelector.tvRequestLimit": "{quotaLimit} seasons per {quotaDays} days", "components.QuotaSelector.tvRequestLimit": "{quotaLimit} season(s) per {quotaDays} day(s)",
"components.QuotaSelector.unlimited": "Unlimited", "components.QuotaSelector.unlimited": "Unlimited",
"components.RegionSelector.regionDefault": "All Regions", "components.RegionSelector.regionDefault": "All Regions",
"components.RegionSelector.regionServerDefault": "Default ({region})", "components.RegionSelector.regionServerDefault": "Default ({region})",
@ -163,36 +154,18 @@
"components.RequestButton.declinerequest": "Decline Request", "components.RequestButton.declinerequest": "Decline Request",
"components.RequestButton.declinerequest4k": "Decline 4K Request", "components.RequestButton.declinerequest4k": "Decline 4K Request",
"components.RequestButton.declinerequests": "Decline {requestCount} {requestCount, plural, one {Request} other {Requests}}", "components.RequestButton.declinerequests": "Decline {requestCount} {requestCount, plural, one {Request} other {Requests}}",
"components.RequestButton.request": "Request",
"components.RequestButton.request4k": "Request 4K",
"components.RequestButton.requestmore": "Request More", "components.RequestButton.requestmore": "Request More",
"components.RequestButton.requestmore4k": "Request More 4K", "components.RequestButton.requestmore4k": "Request More 4K",
"components.RequestButton.viewrequest": "View Request", "components.RequestButton.viewrequest": "View Request",
"components.RequestButton.viewrequest4k": "View 4K Request", "components.RequestButton.viewrequest4k": "View 4K Request",
"components.RequestCard.all": "All",
"components.RequestCard.seasons": "{seasonCount, plural, one {Season} other {Seasons}}", "components.RequestCard.seasons": "{seasonCount, plural, one {Season} other {Seasons}}",
"components.RequestCard.status": "Status",
"components.RequestList.RequestItem.all": "All",
"components.RequestList.RequestItem.areyousure": "Are you sure?",
"components.RequestList.RequestItem.failedretry": "Something went wrong while retrying the request.", "components.RequestList.RequestItem.failedretry": "Something went wrong while retrying the request.",
"components.RequestList.RequestItem.modified": "Modified", "components.RequestList.RequestItem.modified": "Modified",
"components.RequestList.RequestItem.modifieduserdate": "{date} by {user}", "components.RequestList.RequestItem.modifieduserdate": "{date} by {user}",
"components.RequestList.RequestItem.notavailable": "N/A",
"components.RequestList.RequestItem.requested": "Requested", "components.RequestList.RequestItem.requested": "Requested",
"components.RequestList.RequestItem.seasons": "{seasonCount, plural, one {Season} other {Seasons}}", "components.RequestList.RequestItem.seasons": "{seasonCount, plural, one {Season} other {Seasons}}",
"components.RequestList.RequestItem.status": "Status",
"components.RequestList.filterAll": "All",
"components.RequestList.filterApproved": "Approved",
"components.RequestList.filterAvailable": "Available",
"components.RequestList.filterPending": "Pending",
"components.RequestList.filterProcessing": "Processing",
"components.RequestList.next": "Next",
"components.RequestList.noresults": "No results.",
"components.RequestList.previous": "Previous",
"components.RequestList.requests": "Requests", "components.RequestList.requests": "Requests",
"components.RequestList.resultsperpage": "Display {pageSize} results per page",
"components.RequestList.showallrequests": "Show All Requests", "components.RequestList.showallrequests": "Show All Requests",
"components.RequestList.showingresults": "Showing <strong>{from}</strong> to <strong>{to}</strong> of <strong>{total}</strong> results",
"components.RequestList.sortAdded": "Request Date", "components.RequestList.sortAdded": "Request Date",
"components.RequestList.sortModified": "Last Modified", "components.RequestList.sortModified": "Last Modified",
"components.RequestModal.AdvancedRequester.advancedoptions": "Advanced Options", "components.RequestModal.AdvancedRequester.advancedoptions": "Advanced Options",
@ -201,7 +174,6 @@
"components.RequestModal.AdvancedRequester.destinationserver": "Destination Server", "components.RequestModal.AdvancedRequester.destinationserver": "Destination Server",
"components.RequestModal.AdvancedRequester.folder": "{path} ({space})", "components.RequestModal.AdvancedRequester.folder": "{path} ({space})",
"components.RequestModal.AdvancedRequester.languageprofile": "Language Profile", "components.RequestModal.AdvancedRequester.languageprofile": "Language Profile",
"components.RequestModal.AdvancedRequester.loading": "Loading…",
"components.RequestModal.AdvancedRequester.qualityprofile": "Quality Profile", "components.RequestModal.AdvancedRequester.qualityprofile": "Quality Profile",
"components.RequestModal.AdvancedRequester.requestas": "Request As", "components.RequestModal.AdvancedRequester.requestas": "Request As",
"components.RequestModal.AdvancedRequester.rootfolder": "Root Folder", "components.RequestModal.AdvancedRequester.rootfolder": "Root Folder",
@ -212,46 +184,37 @@
"components.RequestModal.QuotaDisplay.notenoughseasonrequests": "Not enough season requests remaining", "components.RequestModal.QuotaDisplay.notenoughseasonrequests": "Not enough season requests remaining",
"components.RequestModal.QuotaDisplay.quotaLink": "You can view a summary of your request limits on your <ProfileLink>profile page</ProfileLink>.", "components.RequestModal.QuotaDisplay.quotaLink": "You can view a summary of your request limits on your <ProfileLink>profile page</ProfileLink>.",
"components.RequestModal.QuotaDisplay.quotaLinkUser": "You can view a summary of this user's request limits on their <ProfileLink>profile page</ProfileLink>.", "components.RequestModal.QuotaDisplay.quotaLinkUser": "You can view a summary of this user's request limits on their <ProfileLink>profile page</ProfileLink>.",
"components.RequestModal.QuotaDisplay.requestsremaining": "{remaining, plural, =0 {No} other {<strong>#</strong>}} {type} {remaining, plural, one {requests} other {requests}} remaining", "components.RequestModal.QuotaDisplay.requestsremaining": "{remaining, plural, =0 {No} other {<strong>#</strong>}} {type} {remaining, plural, one {request} other {requests}} remaining",
"components.RequestModal.QuotaDisplay.requiredquota": "You need to have at least <strong>{seasons}</strong> {seasons, plural, one {season request} other {season requests}} remaining in order to submit a request for this series.", "components.RequestModal.QuotaDisplay.requiredquota": "You need to have at least <strong>{seasons}</strong> {seasons, plural, one {season request} other {season requests}} remaining in order to submit a request for this series.",
"components.RequestModal.QuotaDisplay.requiredquotaUser": "This user needs to have at least <strong>{seasons}</strong> {seasons, plural, one {season request} other {season requests}} remaining in order to submit a request for this series.",
"components.RequestModal.QuotaDisplay.season": "season", "components.RequestModal.QuotaDisplay.season": "season",
"components.RequestModal.QuotaDisplay.seasonlimit": "{limit, plural, one {season} other {seasons}}", "components.RequestModal.QuotaDisplay.seasonlimit": "{limit, plural, one {season} other {seasons}}",
"components.RequestModal.SearchByNameModal.next": "Next",
"components.RequestModal.SearchByNameModal.nosummary": "No summary for this title was found.", "components.RequestModal.SearchByNameModal.nosummary": "No summary for this title was found.",
"components.RequestModal.SearchByNameModal.notvdbid": "Manual Match Required", "components.RequestModal.SearchByNameModal.notvdbid": "Manual Match Required",
"components.RequestModal.SearchByNameModal.notvdbiddescription": "We couldn't automatically match your request. Please select the correct match from the list below.", "components.RequestModal.SearchByNameModal.notvdbiddescription": "We couldn't automatically match your request. Please select the correct match from the list below.",
"components.RequestModal.alreadyrequested": "Already Requested", "components.RequestModal.alreadyrequested": "Already Requested",
"components.RequestModal.autoapproval": "Automatic Approval", "components.RequestModal.autoapproval": "Automatic Approval",
"components.RequestModal.backbutton": "Back",
"components.RequestModal.cancel": "Cancel Request", "components.RequestModal.cancel": "Cancel Request",
"components.RequestModal.cancelling": "Canceling…",
"components.RequestModal.cancelrequest": "This will remove your request. Are you sure you want to continue?",
"components.RequestModal.close": "Close",
"components.RequestModal.errorediting": "Something went wrong while editing the request.", "components.RequestModal.errorediting": "Something went wrong while editing the request.",
"components.RequestModal.extras": "Extras", "components.RequestModal.extras": "Extras",
"components.RequestModal.notrequested": "Not Requested",
"components.RequestModal.numberofepisodes": "# of Episodes", "components.RequestModal.numberofepisodes": "# of Episodes",
"components.RequestModal.pending4krequest": "Pending Request for {title} in 4K", "components.RequestModal.pending4krequest": "Pending Request for {title} in 4K",
"components.RequestModal.pendingrequest": "Pending Request for {title}", "components.RequestModal.pendingrequest": "Pending Request for {title}",
"components.RequestModal.request": "Request",
"components.RequestModal.request4k": "Request 4K",
"components.RequestModal.request4kfrom": "There is currently a pending 4K request from {username}.", "components.RequestModal.request4kfrom": "There is currently a pending 4K request from {username}.",
"components.RequestModal.request4ktitle": "Request {title} in 4K", "components.RequestModal.request4ktitle": "Request {title} in 4K",
"components.RequestModal.requestCancel": "Request for <strong>{title}</strong> canceled.", "components.RequestModal.requestCancel": "Request for <strong>{title}</strong> canceled.",
"components.RequestModal.requestSuccess": "<strong>{title}</strong> requested successfully!", "components.RequestModal.requestSuccess": "<strong>{title}</strong> requested successfully!",
"components.RequestModal.requestadmin": "Your request will be approved automatically.", "components.RequestModal.requestadmin": "This request will be approved automatically.",
"components.RequestModal.requestall": "Request All Seasons", "components.RequestModal.requestall": "Request All Seasons",
"components.RequestModal.requestcancelled": "Request canceled.", "components.RequestModal.requestcancelled": "Request for <strong>{title}</strong> canceled.",
"components.RequestModal.requestedited": "Request edited.", "components.RequestModal.requestedited": "Request for <strong>{title}</strong> edited successfully!",
"components.RequestModal.requesterror": "Something went wrong while submitting the request.", "components.RequestModal.requesterror": "Something went wrong while submitting the request.",
"components.RequestModal.requestfrom": "There is currently a pending request from {username}.", "components.RequestModal.requestfrom": "There is currently a pending request from {username}.",
"components.RequestModal.requesting": "Requesting…",
"components.RequestModal.requestseasons": "Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}", "components.RequestModal.requestseasons": "Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}",
"components.RequestModal.requesttitle": "Request {title}", "components.RequestModal.requesttitle": "Request {title}",
"components.RequestModal.season": "Season", "components.RequestModal.season": "Season",
"components.RequestModal.seasonnumber": "Season {number}", "components.RequestModal.seasonnumber": "Season {number}",
"components.RequestModal.selectseason": "Select Season(s)", "components.RequestModal.selectseason": "Select Season(s)",
"components.RequestModal.status": "Status",
"components.ResetPassword.confirmpassword": "Confirm Password", "components.ResetPassword.confirmpassword": "Confirm Password",
"components.ResetPassword.email": "Email Address", "components.ResetPassword.email": "Email Address",
"components.ResetPassword.emailresetlink": "Email a Recovery Link", "components.ResetPassword.emailresetlink": "Email a Recovery Link",
@ -272,11 +235,8 @@
"components.Settings.Notifications.NotificationsPushbullet.notificationTypes": "Notification Types", "components.Settings.Notifications.NotificationsPushbullet.notificationTypes": "Notification Types",
"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed": "Pushbullet notification settings failed to save.", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsFailed": "Pushbullet notification settings failed to save.",
"components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved": "Pushbullet notification settings saved successfully!", "components.Settings.Notifications.NotificationsPushbullet.pushbulletSettingsSaved": "Pushbullet notification settings saved successfully!",
"components.Settings.Notifications.NotificationsPushbullet.save": "Save Changes",
"components.Settings.Notifications.NotificationsPushbullet.saving": "Saving…",
"components.Settings.Notifications.NotificationsPushbullet.settingUpPushbullet": "Setting Up Pushbullet Notifications", "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbullet": "Setting Up Pushbullet Notifications",
"components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "To configure Pushbullet notifications, you will need to <CreateAccessTokenLink>create an access token</CreateAccessTokenLink> and enter it below.", "components.Settings.Notifications.NotificationsPushbullet.settingUpPushbulletDescription": "To configure Pushbullet notifications, you will need to <CreateAccessTokenLink>create an access token</CreateAccessTokenLink> and enter it below.",
"components.Settings.Notifications.NotificationsPushbullet.test": "Test",
"components.Settings.Notifications.NotificationsPushbullet.testSent": "Test notification sent!", "components.Settings.Notifications.NotificationsPushbullet.testSent": "Test notification sent!",
"components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired": "You must provide an access token", "components.Settings.Notifications.NotificationsPushbullet.validationAccessTokenRequired": "You must provide an access token",
"components.Settings.Notifications.NotificationsPushover.accessToken": "Application/API Token", "components.Settings.Notifications.NotificationsPushover.accessToken": "Application/API Token",
@ -284,24 +244,18 @@
"components.Settings.Notifications.NotificationsPushover.notificationtypes": "Notification Types", "components.Settings.Notifications.NotificationsPushover.notificationtypes": "Notification Types",
"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "Pushover notification settings failed to save.", "components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "Pushover notification settings failed to save.",
"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved": "Pushover notification settings saved successfully!", "components.Settings.Notifications.NotificationsPushover.pushoversettingssaved": "Pushover notification settings saved successfully!",
"components.Settings.Notifications.NotificationsPushover.save": "Save Changes",
"components.Settings.Notifications.NotificationsPushover.saving": "Saving…",
"components.Settings.Notifications.NotificationsPushover.settinguppushover": "Setting Up Pushover Notifications", "components.Settings.Notifications.NotificationsPushover.settinguppushover": "Setting Up Pushover Notifications",
"components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "To configure Pushover notifications, you will need to <RegisterApplicationLink>register an application</RegisterApplicationLink> and enter the API token below. (You can use one of our <IconLink>official icons on GitHub</IconLink>.) You will also need your user key.", "components.Settings.Notifications.NotificationsPushover.settinguppushoverDescription": "To configure Pushover notifications, you will need to <RegisterApplicationLink>register an application</RegisterApplicationLink> and enter the API token below. (You can use one of our <IconLink>official icons on GitHub</IconLink>.) You will also need your user key.",
"components.Settings.Notifications.NotificationsPushover.test": "Test",
"components.Settings.Notifications.NotificationsPushover.testsent": "Test notification sent!", "components.Settings.Notifications.NotificationsPushover.testsent": "Test notification sent!",
"components.Settings.Notifications.NotificationsPushover.userToken": "User Key", "components.Settings.Notifications.NotificationsPushover.userToken": "User Key",
"components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired": "You must provide a valid application token", "components.Settings.Notifications.NotificationsPushover.validationAccessTokenRequired": "You must provide a valid application token",
"components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired": "You must provide a valid user key", "components.Settings.Notifications.NotificationsPushover.validationUserTokenRequired": "You must provide a valid user key",
"components.Settings.Notifications.NotificationsSlack.agentenabled": "Enable Agent", "components.Settings.Notifications.NotificationsSlack.agentenabled": "Enable Agent",
"components.Settings.Notifications.NotificationsSlack.notificationtypes": "Notification Types", "components.Settings.Notifications.NotificationsSlack.notificationtypes": "Notification Types",
"components.Settings.Notifications.NotificationsSlack.save": "Save Changes",
"components.Settings.Notifications.NotificationsSlack.saving": "Saving…",
"components.Settings.Notifications.NotificationsSlack.settingupslack": "Setting Up Slack Notifications", "components.Settings.Notifications.NotificationsSlack.settingupslack": "Setting Up Slack Notifications",
"components.Settings.Notifications.NotificationsSlack.settingupslackDescription": "To configure Slack notifications, you will need to create an <WebhookLink>Incoming Webhook</WebhookLink> integration and enter the webhook URL below.", "components.Settings.Notifications.NotificationsSlack.settingupslackDescription": "To configure Slack notifications, you will need to create an <WebhookLink>Incoming Webhook</WebhookLink> integration and enter the webhook URL below.",
"components.Settings.Notifications.NotificationsSlack.slacksettingsfailed": "Slack notification settings failed to save.", "components.Settings.Notifications.NotificationsSlack.slacksettingsfailed": "Slack notification settings failed to save.",
"components.Settings.Notifications.NotificationsSlack.slacksettingssaved": "Slack notification settings saved successfully!", "components.Settings.Notifications.NotificationsSlack.slacksettingssaved": "Slack notification settings saved successfully!",
"components.Settings.Notifications.NotificationsSlack.test": "Test",
"components.Settings.Notifications.NotificationsSlack.testsent": "Test notification sent!", "components.Settings.Notifications.NotificationsSlack.testsent": "Test notification sent!",
"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl": "You must provide a valid URL", "components.Settings.Notifications.NotificationsSlack.validationWebhookUrl": "You must provide a valid URL",
"components.Settings.Notifications.NotificationsSlack.webhookUrl": "Webhook URL", "components.Settings.Notifications.NotificationsSlack.webhookUrl": "Webhook URL",
@ -311,10 +265,7 @@
"components.Settings.Notifications.NotificationsWebhook.notificationtypes": "Notification Types", "components.Settings.Notifications.NotificationsWebhook.notificationtypes": "Notification Types",
"components.Settings.Notifications.NotificationsWebhook.resetPayload": "Reset to Default", "components.Settings.Notifications.NotificationsWebhook.resetPayload": "Reset to Default",
"components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess": "JSON payload reset successfully!", "components.Settings.Notifications.NotificationsWebhook.resetPayloadSuccess": "JSON payload reset successfully!",
"components.Settings.Notifications.NotificationsWebhook.save": "Save Changes",
"components.Settings.Notifications.NotificationsWebhook.saving": "Saving…",
"components.Settings.Notifications.NotificationsWebhook.templatevariablehelp": "Template Variable Help", "components.Settings.Notifications.NotificationsWebhook.templatevariablehelp": "Template Variable Help",
"components.Settings.Notifications.NotificationsWebhook.test": "Test",
"components.Settings.Notifications.NotificationsWebhook.testsent": "Test notification sent!", "components.Settings.Notifications.NotificationsWebhook.testsent": "Test notification sent!",
"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired": "You must provide a valid JSON payload", "components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired": "You must provide a valid JSON payload",
"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl": "You must provide a valid URL", "components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl": "You must provide a valid URL",
@ -343,8 +294,6 @@
"components.Settings.Notifications.pgpPasswordTip": "Sign encrypted email messages (PGP private key is also required)", "components.Settings.Notifications.pgpPasswordTip": "Sign encrypted email messages (PGP private key is also required)",
"components.Settings.Notifications.pgpPrivateKey": "<PgpLink>PGP</PgpLink> Private Key", "components.Settings.Notifications.pgpPrivateKey": "<PgpLink>PGP</PgpLink> Private Key",
"components.Settings.Notifications.pgpPrivateKeyTip": "Sign encrypted email messages (PGP password is also required)", "components.Settings.Notifications.pgpPrivateKeyTip": "Sign encrypted email messages (PGP password is also required)",
"components.Settings.Notifications.save": "Save Changes",
"components.Settings.Notifications.saving": "Saving…",
"components.Settings.Notifications.sendSilently": "Send Silently", "components.Settings.Notifications.sendSilently": "Send Silently",
"components.Settings.Notifications.sendSilentlyTip": "Send notifications with no sound", "components.Settings.Notifications.sendSilentlyTip": "Send notifications with no sound",
"components.Settings.Notifications.senderName": "Sender Name", "components.Settings.Notifications.senderName": "Sender Name",
@ -355,7 +304,6 @@
"components.Settings.Notifications.ssldisabletip": "SSL should be disabled on standard TLS connections (port 587)", "components.Settings.Notifications.ssldisabletip": "SSL should be disabled on standard TLS connections (port 587)",
"components.Settings.Notifications.telegramsettingsfailed": "Telegram notification settings failed to save.", "components.Settings.Notifications.telegramsettingsfailed": "Telegram notification settings failed to save.",
"components.Settings.Notifications.telegramsettingssaved": "Telegram notification settings saved successfully!", "components.Settings.Notifications.telegramsettingssaved": "Telegram notification settings saved successfully!",
"components.Settings.Notifications.test": "Test",
"components.Settings.Notifications.testsent": "Test notification sent!", "components.Settings.Notifications.testsent": "Test notification sent!",
"components.Settings.Notifications.validationBotAPIRequired": "You must provide a bot authentication token", "components.Settings.Notifications.validationBotAPIRequired": "You must provide a bot authentication token",
"components.Settings.Notifications.validationChatIdRequired": "You must provide a valid chat ID", "components.Settings.Notifications.validationChatIdRequired": "You must provide a valid chat ID",
@ -383,8 +331,6 @@
"components.Settings.RadarrModal.preventSearch": "Disable Auto-Search", "components.Settings.RadarrModal.preventSearch": "Disable Auto-Search",
"components.Settings.RadarrModal.qualityprofile": "Quality Profile", "components.Settings.RadarrModal.qualityprofile": "Quality Profile",
"components.Settings.RadarrModal.rootfolder": "Root Folder", "components.Settings.RadarrModal.rootfolder": "Root Folder",
"components.Settings.RadarrModal.save": "Save Changes",
"components.Settings.RadarrModal.saving": "Saving…",
"components.Settings.RadarrModal.selectMinimumAvailability": "Select minimum availability", "components.Settings.RadarrModal.selectMinimumAvailability": "Select minimum availability",
"components.Settings.RadarrModal.selectQualityProfile": "Select quality profile", "components.Settings.RadarrModal.selectQualityProfile": "Select quality profile",
"components.Settings.RadarrModal.selectRootFolder": "Select root folder", "components.Settings.RadarrModal.selectRootFolder": "Select root folder",
@ -393,10 +339,8 @@
"components.Settings.RadarrModal.servernamePlaceholder": "A Radarr Server", "components.Settings.RadarrModal.servernamePlaceholder": "A Radarr Server",
"components.Settings.RadarrModal.ssl": "Enable SSL", "components.Settings.RadarrModal.ssl": "Enable SSL",
"components.Settings.RadarrModal.syncEnabled": "Enable Scan", "components.Settings.RadarrModal.syncEnabled": "Enable Scan",
"components.Settings.RadarrModal.test": "Test",
"components.Settings.RadarrModal.testFirstQualityProfiles": "Test connection to load quality profiles", "components.Settings.RadarrModal.testFirstQualityProfiles": "Test connection to load quality profiles",
"components.Settings.RadarrModal.testFirstRootFolders": "Test connection to load root folders", "components.Settings.RadarrModal.testFirstRootFolders": "Test connection to load root folders",
"components.Settings.RadarrModal.testing": "Testing…",
"components.Settings.RadarrModal.toastRadarrTestFailure": "Failed to connect to Radarr.", "components.Settings.RadarrModal.toastRadarrTestFailure": "Failed to connect to Radarr.",
"components.Settings.RadarrModal.toastRadarrTestSuccess": "Radarr connection established successfully!", "components.Settings.RadarrModal.toastRadarrTestSuccess": "Radarr connection established successfully!",
"components.Settings.RadarrModal.validationApiKeyRequired": "You must provide an API key", "components.Settings.RadarrModal.validationApiKeyRequired": "You must provide an API key",
@ -473,25 +417,16 @@
"components.Settings.SettingsLogs.logs": "Logs", "components.Settings.SettingsLogs.logs": "Logs",
"components.Settings.SettingsLogs.logsDescription": "You can also view these logs directly via <code>stdout</code>, or in <code>{configDir}/logs/overseerr.log</code>.", "components.Settings.SettingsLogs.logsDescription": "You can also view these logs directly via <code>stdout</code>, or in <code>{configDir}/logs/overseerr.log</code>.",
"components.Settings.SettingsLogs.message": "Message", "components.Settings.SettingsLogs.message": "Message",
"components.Settings.SettingsLogs.next": "Next",
"components.Settings.SettingsLogs.noresults": "No results.",
"components.Settings.SettingsLogs.pauseLogs": "Pause", "components.Settings.SettingsLogs.pauseLogs": "Pause",
"components.Settings.SettingsLogs.previous": "Previous",
"components.Settings.SettingsLogs.resultsperpage": "Display {pageSize} results per page",
"components.Settings.SettingsLogs.resumeLogs": "Resume", "components.Settings.SettingsLogs.resumeLogs": "Resume",
"components.Settings.SettingsLogs.showall": "Show All Logs", "components.Settings.SettingsLogs.showall": "Show All Logs",
"components.Settings.SettingsLogs.showingresults": "Showing <strong>{from}</strong> to <strong>{to}</strong> of <strong>{total}</strong> results",
"components.Settings.SettingsLogs.time": "Timestamp", "components.Settings.SettingsLogs.time": "Timestamp",
"components.Settings.SettingsLogs.viewDetails": "View Details", "components.Settings.SettingsLogs.viewDetails": "View Details",
"components.Settings.SettingsUsers.defaultPermissions": "Default Permissions", "components.Settings.SettingsUsers.defaultPermissions": "Default Permissions",
"components.Settings.SettingsUsers.localLogin": "Enable Local Sign-In", "components.Settings.SettingsUsers.localLogin": "Enable Local Sign-In",
"components.Settings.SettingsUsers.movieRequestLimit": "{quotaLimit} movies per {quotaDays} days",
"components.Settings.SettingsUsers.movieRequestLimitLabel": "Global Movie Request Limit", "components.Settings.SettingsUsers.movieRequestLimitLabel": "Global Movie Request Limit",
"components.Settings.SettingsUsers.save": "Save Changes",
"components.Settings.SettingsUsers.saving": "Saving…",
"components.Settings.SettingsUsers.toastSettingsFailure": "Something went wrong while saving settings.", "components.Settings.SettingsUsers.toastSettingsFailure": "Something went wrong while saving settings.",
"components.Settings.SettingsUsers.toastSettingsSuccess": "User settings saved successfully!", "components.Settings.SettingsUsers.toastSettingsSuccess": "User settings saved successfully!",
"components.Settings.SettingsUsers.tvRequestLimit": "{quotaLimit} seasons per {quotaDays} days",
"components.Settings.SettingsUsers.tvRequestLimitLabel": "Global Series Request Limit", "components.Settings.SettingsUsers.tvRequestLimitLabel": "Global Series Request Limit",
"components.Settings.SettingsUsers.userSettings": "User Settings", "components.Settings.SettingsUsers.userSettings": "User Settings",
"components.Settings.SettingsUsers.userSettingsDescription": "Configure global and default user settings.", "components.Settings.SettingsUsers.userSettingsDescription": "Configure global and default user settings.",
@ -518,8 +453,6 @@
"components.Settings.SonarrModal.preventSearch": "Disable Auto-Search", "components.Settings.SonarrModal.preventSearch": "Disable Auto-Search",
"components.Settings.SonarrModal.qualityprofile": "Quality Profile", "components.Settings.SonarrModal.qualityprofile": "Quality Profile",
"components.Settings.SonarrModal.rootfolder": "Root Folder", "components.Settings.SonarrModal.rootfolder": "Root Folder",
"components.Settings.SonarrModal.save": "Save Changes",
"components.Settings.SonarrModal.saving": "Saving…",
"components.Settings.SonarrModal.seasonfolders": "Season Folders", "components.Settings.SonarrModal.seasonfolders": "Season Folders",
"components.Settings.SonarrModal.selectLanguageProfile": "Select language profile", "components.Settings.SonarrModal.selectLanguageProfile": "Select language profile",
"components.Settings.SonarrModal.selectQualityProfile": "Select quality profile", "components.Settings.SonarrModal.selectQualityProfile": "Select quality profile",
@ -529,11 +462,9 @@
"components.Settings.SonarrModal.servernamePlaceholder": "A Sonarr Server", "components.Settings.SonarrModal.servernamePlaceholder": "A Sonarr Server",
"components.Settings.SonarrModal.ssl": "Enable SSL", "components.Settings.SonarrModal.ssl": "Enable SSL",
"components.Settings.SonarrModal.syncEnabled": "Enable Scan", "components.Settings.SonarrModal.syncEnabled": "Enable Scan",
"components.Settings.SonarrModal.test": "Test",
"components.Settings.SonarrModal.testFirstLanguageProfiles": "Test connection to load language profiles", "components.Settings.SonarrModal.testFirstLanguageProfiles": "Test connection to load language profiles",
"components.Settings.SonarrModal.testFirstQualityProfiles": "Test connection to load quality profiles", "components.Settings.SonarrModal.testFirstQualityProfiles": "Test connection to load quality profiles",
"components.Settings.SonarrModal.testFirstRootFolders": "Test connection to load root folders", "components.Settings.SonarrModal.testFirstRootFolders": "Test connection to load root folders",
"components.Settings.SonarrModal.testing": "Testing…",
"components.Settings.SonarrModal.toastSonarrTestFailure": "Failed to connect to Sonarr.", "components.Settings.SonarrModal.toastSonarrTestFailure": "Failed to connect to Sonarr.",
"components.Settings.SonarrModal.toastSonarrTestSuccess": "Sonarr connection established successfully!", "components.Settings.SonarrModal.toastSonarrTestSuccess": "Sonarr connection established successfully!",
"components.Settings.SonarrModal.validationApiKeyRequired": "You must provide an API key", "components.Settings.SonarrModal.validationApiKeyRequired": "You must provide an API key",
@ -564,9 +495,7 @@
"components.Settings.currentlibrary": "Current Library: {name}", "components.Settings.currentlibrary": "Current Library: {name}",
"components.Settings.default": "Default", "components.Settings.default": "Default",
"components.Settings.default4k": "Default 4K", "components.Settings.default4k": "Default 4K",
"components.Settings.delete": "Delete",
"components.Settings.deleteserverconfirm": "Are you sure you want to delete this server?", "components.Settings.deleteserverconfirm": "Are you sure you want to delete this server?",
"components.Settings.edit": "Edit",
"components.Settings.email": "Email", "components.Settings.email": "Email",
"components.Settings.enablenotifications": "Enable Notifications", "components.Settings.enablenotifications": "Enable Notifications",
"components.Settings.enablessl": "Enable SSL", "components.Settings.enablessl": "Enable SSL",
@ -610,8 +539,6 @@
"components.Settings.radarrsettings": "Radarr Settings", "components.Settings.radarrsettings": "Radarr Settings",
"components.Settings.region": "Discover Region", "components.Settings.region": "Discover Region",
"components.Settings.regionTip": "Filter content by regional availability", "components.Settings.regionTip": "Filter content by regional availability",
"components.Settings.save": "Save Changes",
"components.Settings.saving": "Saving…",
"components.Settings.scan": "Sync Libraries", "components.Settings.scan": "Sync Libraries",
"components.Settings.scanning": "Syncing…", "components.Settings.scanning": "Syncing…",
"components.Settings.serverConnected": "connected", "components.Settings.serverConnected": "connected",
@ -662,18 +589,14 @@
"components.Setup.signinMessage": "Get started by signing in with your Plex account", "components.Setup.signinMessage": "Get started by signing in with your Plex account",
"components.Setup.tip": "Tip", "components.Setup.tip": "Tip",
"components.Setup.welcome": "Welcome to Overseerr", "components.Setup.welcome": "Welcome to Overseerr",
"components.Slider.noresults": "No results.",
"components.StatusBadge.status4k": "4K {status}", "components.StatusBadge.status4k": "4K {status}",
"components.StatusChacker.newversionDescription": "Overseerr has been updated! Please click the button below to reload the page.", "components.StatusChacker.newversionDescription": "Overseerr has been updated! Please click the button below to reload the page.",
"components.StatusChacker.newversionavailable": "Application Update", "components.StatusChacker.newversionavailable": "Application Update",
"components.StatusChacker.reloadOverseerr": "Reload", "components.StatusChacker.reloadOverseerr": "Reload",
"components.TitleCard.movie": "Movie",
"components.TitleCard.tvshow": "Series",
"components.TvDetails.TvCast.fullseriescast": "Full Series Cast", "components.TvDetails.TvCast.fullseriescast": "Full Series Cast",
"components.TvDetails.TvCrew.fullseriescrew": "Full Series Crew", "components.TvDetails.TvCrew.fullseriescrew": "Full Series Crew",
"components.TvDetails.allseasonsmarkedavailable": "* All seasons will be marked as available.", "components.TvDetails.allseasonsmarkedavailable": "* All seasons will be marked as available.",
"components.TvDetails.anime": "Anime", "components.TvDetails.anime": "Anime",
"components.TvDetails.areyousure": "Are you sure?",
"components.TvDetails.cast": "Cast", "components.TvDetails.cast": "Cast",
"components.TvDetails.downloadstatus": "Download Status", "components.TvDetails.downloadstatus": "Download Status",
"components.TvDetails.episodeRuntime": "Episode Runtime", "components.TvDetails.episodeRuntime": "Episode Runtime",
@ -699,7 +622,6 @@
"components.TvDetails.seasons": "{seasonCount, plural, one {# Season} other {# Seasons}}", "components.TvDetails.seasons": "{seasonCount, plural, one {# Season} other {# Seasons}}",
"components.TvDetails.showtype": "Series Type", "components.TvDetails.showtype": "Series Type",
"components.TvDetails.similar": "Similar Series", "components.TvDetails.similar": "Similar Series",
"components.TvDetails.status": "Status",
"components.TvDetails.viewfullcrew": "View Full Crew", "components.TvDetails.viewfullcrew": "View Full Crew",
"components.TvDetails.watchtrailer": "Watch Trailer", "components.TvDetails.watchtrailer": "Watch Trailer",
"components.UserList.accounttype": "Account Type", "components.UserList.accounttype": "Account Type",
@ -711,10 +633,8 @@
"components.UserList.createlocaluser": "Create Local User", "components.UserList.createlocaluser": "Create Local User",
"components.UserList.createuser": "Create User", "components.UserList.createuser": "Create User",
"components.UserList.creating": "Creating…", "components.UserList.creating": "Creating…",
"components.UserList.delete": "Delete",
"components.UserList.deleteconfirm": "Are you sure you want to delete this user? All existing request data from this user will be removed.", "components.UserList.deleteconfirm": "Are you sure you want to delete this user? All existing request data from this user will be removed.",
"components.UserList.deleteuser": "Delete User", "components.UserList.deleteuser": "Delete User",
"components.UserList.edit": "Edit",
"components.UserList.edituser": "Edit User Permissions", "components.UserList.edituser": "Edit User Permissions",
"components.UserList.email": "Email Address", "components.UserList.email": "Email Address",
"components.UserList.importedfromplex": "{userCount, plural, one {# new user} other {# new users}} imported from Plex successfully!", "components.UserList.importedfromplex": "{userCount, plural, one {# new user} other {# new users}} imported from Plex successfully!",
@ -722,19 +642,13 @@
"components.UserList.importfromplexerror": "Something went wrong while importing users from Plex.", "components.UserList.importfromplexerror": "Something went wrong while importing users from Plex.",
"components.UserList.lastupdated": "Last Updated", "components.UserList.lastupdated": "Last Updated",
"components.UserList.localuser": "Local User", "components.UserList.localuser": "Local User",
"components.UserList.next": "Next",
"components.UserList.nouserstoimport": "No new users to import from Plex.", "components.UserList.nouserstoimport": "No new users to import from Plex.",
"components.UserList.owner": "Owner", "components.UserList.owner": "Owner",
"components.UserList.password": "Password", "components.UserList.password": "Password",
"components.UserList.passwordinfo": "Password Information", "components.UserList.passwordinfo": "Password Information",
"components.UserList.passwordinfodescription": "Email notifications need to be configured and enabled in order to automatically generate passwords.", "components.UserList.passwordinfodescription": "Email notifications need to be configured and enabled in order to automatically generate passwords.",
"components.UserList.plexuser": "Plex User", "components.UserList.plexuser": "Plex User",
"components.UserList.previous": "Previous",
"components.UserList.resultsperpage": "Display {pageSize} results per page",
"components.UserList.role": "Role", "components.UserList.role": "Role",
"components.UserList.save": "Save Changes",
"components.UserList.saving": "Saving…",
"components.UserList.showingresults": "Showing <strong>{from}</strong> to <strong>{to}</strong> of <strong>{total}</strong> results",
"components.UserList.sortCreated": "Creation Date", "components.UserList.sortCreated": "Creation Date",
"components.UserList.sortDisplayName": "Display Name", "components.UserList.sortDisplayName": "Display Name",
"components.UserList.sortRequests": "Request Count", "components.UserList.sortRequests": "Request Count",
@ -772,8 +686,6 @@
"components.UserProfile.UserSettings.UserGeneralSettings.region": "Discover Region", "components.UserProfile.UserSettings.UserGeneralSettings.region": "Discover Region",
"components.UserProfile.UserSettings.UserGeneralSettings.regionTip": "Filter content by regional availability", "components.UserProfile.UserSettings.UserGeneralSettings.regionTip": "Filter content by regional availability",
"components.UserProfile.UserSettings.UserGeneralSettings.role": "Role", "components.UserProfile.UserSettings.UserGeneralSettings.role": "Role",
"components.UserProfile.UserSettings.UserGeneralSettings.save": "Save Changes",
"components.UserProfile.UserSettings.UserGeneralSettings.saving": "Saving…",
"components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit": "Series Request Limit", "components.UserProfile.UserSettings.UserGeneralSettings.seriesrequestlimit": "Series Request Limit",
"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure": "Something went wrong while saving settings.", "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsFailure": "Something went wrong while saving settings.",
"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess": "Settings saved successfully!", "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess": "Settings saved successfully!",
@ -787,8 +699,6 @@
"components.UserProfile.UserSettings.UserNotificationSettings.pgpKey": "<PgpLink>PGP</PgpLink> Public Key", "components.UserProfile.UserSettings.UserNotificationSettings.pgpKey": "<PgpLink>PGP</PgpLink> Public Key",
"components.UserProfile.UserSettings.UserNotificationSettings.pgpKeyTip": "Encrypt email messages", "components.UserProfile.UserSettings.UserNotificationSettings.pgpKeyTip": "Encrypt email messages",
"components.UserProfile.UserSettings.UserNotificationSettings.plexuser": "Plex User", "components.UserProfile.UserSettings.UserNotificationSettings.plexuser": "Plex User",
"components.UserProfile.UserSettings.UserNotificationSettings.save": "Save Changes",
"components.UserProfile.UserSettings.UserNotificationSettings.saving": "Saving…",
"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Send Telegram Messages Silently", "components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Send Telegram Messages Silently",
"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription": "Send notifications with no sound", "components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription": "Send notifications with no sound",
"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "Telegram Chat ID", "components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "Telegram Chat ID",
@ -804,11 +714,8 @@
"components.UserProfile.UserSettings.UserPasswordChange.nopasswordset": "No Password Set", "components.UserProfile.UserSettings.UserPasswordChange.nopasswordset": "No Password Set",
"components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescription": "This user account currently does not have a password specifically for {applicationTitle}. Configure a password below to enable this account to sign in as a \"local user.\"", "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescription": "This user account currently does not have a password specifically for {applicationTitle}. Configure a password below to enable this account to sign in as a \"local user.\"",
"components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescriptionOwnAccount": "Your account currently does not have a password specifically for {applicationTitle}. Configure a password below to enable sign in as a \"local user\" using your email address.", "components.UserProfile.UserSettings.UserPasswordChange.nopasswordsetDescriptionOwnAccount": "Your account currently does not have a password specifically for {applicationTitle}. Configure a password below to enable sign in as a \"local user\" using your email address.",
"components.UserProfile.UserSettings.UserPasswordChange.nopermission": "Unauthorized",
"components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription": "You do not have permission to modify this user's password.", "components.UserProfile.UserSettings.UserPasswordChange.nopermissionDescription": "You do not have permission to modify this user's password.",
"components.UserProfile.UserSettings.UserPasswordChange.password": "Password", "components.UserProfile.UserSettings.UserPasswordChange.password": "Password",
"components.UserProfile.UserSettings.UserPasswordChange.save": "Save Changes",
"components.UserProfile.UserSettings.UserPasswordChange.saving": "Saving…",
"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure": "Something went wrong while saving the password.", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure": "Something went wrong while saving the password.",
"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent": "Something went wrong while saving the password. Was your current password entered correctly?", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent": "Something went wrong while saving the password. Was your current password entered correctly?",
"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess": "Password saved successfully!", "components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess": "Password saved successfully!",
@ -821,17 +728,13 @@
"components.UserProfile.UserSettings.UserPermissions.localuser": "Local User", "components.UserProfile.UserSettings.UserPermissions.localuser": "Local User",
"components.UserProfile.UserSettings.UserPermissions.permissions": "Permissions", "components.UserProfile.UserSettings.UserPermissions.permissions": "Permissions",
"components.UserProfile.UserSettings.UserPermissions.plexuser": "Plex User", "components.UserProfile.UserSettings.UserPermissions.plexuser": "Plex User",
"components.UserProfile.UserSettings.UserPermissions.save": "Save Changes",
"components.UserProfile.UserSettings.UserPermissions.saving": "Saving…",
"components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure": "Something went wrong while saving settings.", "components.UserProfile.UserSettings.UserPermissions.toastSettingsFailure": "Something went wrong while saving settings.",
"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess": "Permissions saved successfully!", "components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess": "Permissions saved successfully!",
"components.UserProfile.UserSettings.UserPermissions.unauthorized": "Unauthorized",
"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription": "You cannot modify your own permissions.", "components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription": "You cannot modify your own permissions.",
"components.UserProfile.UserSettings.menuChangePass": "Password", "components.UserProfile.UserSettings.menuChangePass": "Password",
"components.UserProfile.UserSettings.menuGeneralSettings": "General", "components.UserProfile.UserSettings.menuGeneralSettings": "General",
"components.UserProfile.UserSettings.menuNotifications": "Notifications", "components.UserProfile.UserSettings.menuNotifications": "Notifications",
"components.UserProfile.UserSettings.menuPermissions": "Permissions", "components.UserProfile.UserSettings.menuPermissions": "Permissions",
"components.UserProfile.UserSettings.unauthorized": "Unauthorized",
"components.UserProfile.UserSettings.unauthorizedDescription": "You do not have permission to modify this user's settings.", "components.UserProfile.UserSettings.unauthorizedDescription": "You do not have permission to modify this user's settings.",
"components.UserProfile.limit": "{remaining} of {limit}", "components.UserProfile.limit": "{remaining} of {limit}",
"components.UserProfile.movierequests": "Movie Requests", "components.UserProfile.movierequests": "Movie Requests",
@ -843,10 +746,14 @@
"components.UserProfile.totalrequests": "Total Requests", "components.UserProfile.totalrequests": "Total Requests",
"components.UserProfile.unlimited": "Unlimited", "components.UserProfile.unlimited": "Unlimited",
"i18n.advanced": "Advanced", "i18n.advanced": "Advanced",
"i18n.all": "All",
"i18n.approve": "Approve", "i18n.approve": "Approve",
"i18n.approved": "Approved", "i18n.approved": "Approved",
"i18n.areyousure": "Are you sure?",
"i18n.available": "Available", "i18n.available": "Available",
"i18n.back": "Back",
"i18n.cancel": "Cancel", "i18n.cancel": "Cancel",
"i18n.canceling": "Canceling…",
"i18n.close": "Close", "i18n.close": "Close",
"i18n.decline": "Decline", "i18n.decline": "Decline",
"i18n.declined": "Declined", "i18n.declined": "Declined",
@ -857,17 +764,34 @@
"i18n.experimental": "Experimental", "i18n.experimental": "Experimental",
"i18n.failed": "Failed", "i18n.failed": "Failed",
"i18n.loading": "Loading…", "i18n.loading": "Loading…",
"i18n.movie": "Movie",
"i18n.movies": "Movies", "i18n.movies": "Movies",
"i18n.next": "Next",
"i18n.noresults": "No results.",
"i18n.notrequested": "Not Requested",
"i18n.partiallyavailable": "Partially Available", "i18n.partiallyavailable": "Partially Available",
"i18n.pending": "Pending", "i18n.pending": "Pending",
"i18n.previous": "Previous",
"i18n.processing": "Processing", "i18n.processing": "Processing",
"i18n.request": "Request", "i18n.request": "Request",
"i18n.request4k": "Request 4K",
"i18n.requested": "Requested", "i18n.requested": "Requested",
"i18n.requesting": "Requesting…",
"i18n.resultsperpage": "Display {pageSize} results per page",
"i18n.retry": "Retry", "i18n.retry": "Retry",
"i18n.save": "Save Changes",
"i18n.saving": "Saving…",
"i18n.settings": "Settings", "i18n.settings": "Settings",
"i18n.showingresults": "Showing <strong>{from}</strong> to <strong>{to}</strong> of <strong>{total}</strong> results",
"i18n.status": "Status",
"i18n.test": "Test",
"i18n.testing": "Testing…",
"i18n.tvshow": "Series",
"i18n.tvshows": "Series", "i18n.tvshows": "Series",
"i18n.unauthorized": "Unauthorized",
"i18n.unavailable": "Unavailable", "i18n.unavailable": "Unavailable",
"i18n.usersettings": "User Settings", "i18n.usersettings": "User Settings",
"i18n.view": "View",
"pages.errormessagewithcode": "{statusCode} - {error}", "pages.errormessagewithcode": "{statusCode} - {error}",
"pages.internalservererror": "Internal Server Error", "pages.internalservererror": "Internal Server Error",
"pages.oops": "Oops", "pages.oops": "Oops",

Loading…
Cancel
Save