mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
fix(lang): UI string edits, round 2 (#1202)
This commit is contained in:
@@ -36,7 +36,7 @@ const messages = defineMessages({
|
|||||||
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:',
|
||||||
requestSuccess: '<strong>{title}</strong> successfully requested!',
|
requestSuccess: '<strong>{title}</strong> requested successfully!',
|
||||||
});
|
});
|
||||||
|
|
||||||
interface CollectionDetailsProps {
|
interface CollectionDetailsProps {
|
||||||
|
@@ -5,7 +5,7 @@ import {
|
|||||||
LanguageContext,
|
LanguageContext,
|
||||||
AvailableLocales,
|
AvailableLocales,
|
||||||
} from '../../../context/LanguageContext';
|
} from '../../../context/LanguageContext';
|
||||||
import { FormattedMessage, defineMessages } from 'react-intl';
|
import { useIntl, defineMessages } from 'react-intl';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
changelanguage: 'Change Language',
|
changelanguage: 'Change Language',
|
||||||
@@ -80,6 +80,7 @@ const availableLanguages: AvailableLanguageObject = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const LanguagePicker: React.FC = () => {
|
const LanguagePicker: React.FC = () => {
|
||||||
|
const intl = useIntl();
|
||||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||||
const { locale, setLocale } = useContext(LanguageContext);
|
const { locale, setLocale } = useContext(LanguageContext);
|
||||||
const [isDropdownOpen, setDropdownOpen] = useState(false);
|
const [isDropdownOpen, setDropdownOpen] = useState(false);
|
||||||
@@ -128,7 +129,7 @@ const LanguagePicker: React.FC = () => {
|
|||||||
htmlFor="language"
|
htmlFor="language"
|
||||||
className="block pb-2 text-sm font-medium leading-5 text-gray-300"
|
className="block pb-2 text-sm font-medium leading-5 text-gray-300"
|
||||||
>
|
>
|
||||||
<FormattedMessage {...messages.changelanguage} />
|
{intl.formatMessage(messages.changelanguage)}
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
id="language"
|
id="language"
|
||||||
|
@@ -2,7 +2,7 @@ import React, { ReactNode, useRef } from 'react';
|
|||||||
import Transition from '../../Transition';
|
import Transition from '../../Transition';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { defineMessages, FormattedMessage } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import { useUser, Permission } from '../../../hooks/useUser';
|
import { useUser, Permission } from '../../../hooks/useUser';
|
||||||
import useClickOutside from '../../../hooks/useClickOutside';
|
import useClickOutside from '../../../hooks/useClickOutside';
|
||||||
|
|
||||||
@@ -119,6 +119,7 @@ const SidebarLinks: SidebarLinkProps[] = [
|
|||||||
const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
|
const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
|
||||||
const navRef = useRef<HTMLDivElement>(null);
|
const navRef = useRef<HTMLDivElement>(null);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const intl = useIntl();
|
||||||
const { hasPermission } = useUser();
|
const { hasPermission } = useUser();
|
||||||
useClickOutside(navRef, () => setClosed());
|
useClickOutside(navRef, () => setClosed());
|
||||||
return (
|
return (
|
||||||
@@ -212,9 +213,9 @@ const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
|
|||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
{sidebarLink.svgIcon}
|
{sidebarLink.svgIcon}
|
||||||
<FormattedMessage
|
{intl.formatMessage(
|
||||||
{...messages[sidebarLink.messagesKey]}
|
messages[sidebarLink.messagesKey]
|
||||||
/>
|
)}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
@@ -266,9 +267,7 @@ const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
|
|||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
{sidebarLink.svgIcon}
|
{sidebarLink.svgIcon}
|
||||||
<FormattedMessage
|
{intl.formatMessage(messages[sidebarLink.messagesKey])}
|
||||||
{...messages[sidebarLink.messagesKey]}
|
|
||||||
/>
|
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
@@ -4,12 +4,12 @@ import UserDropdown from './UserDropdown';
|
|||||||
import Sidebar from './Sidebar';
|
import Sidebar from './Sidebar';
|
||||||
import LanguagePicker from './LanguagePicker';
|
import LanguagePicker from './LanguagePicker';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { defineMessages, FormattedMessage } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import { Permission, useUser } from '../../hooks/useUser';
|
import { Permission, useUser } from '../../hooks/useUser';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
alphawarning:
|
alphawarning:
|
||||||
'This is ALPHA software. Features may be broken and/or unstable. Please report issues on GitHub!',
|
'This is ALPHA software. Features may be broken and/or unstable. Please report any issues on GitHub!',
|
||||||
});
|
});
|
||||||
|
|
||||||
const Layout: React.FC = ({ children }) => {
|
const Layout: React.FC = ({ children }) => {
|
||||||
@@ -17,6 +17,7 @@ const Layout: React.FC = ({ children }) => {
|
|||||||
const [isScrolled, setIsScrolled] = useState(false);
|
const [isScrolled, setIsScrolled] = useState(false);
|
||||||
const { hasPermission } = useUser();
|
const { hasPermission } = useUser();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const updateScrolled = () => {
|
const updateScrolled = () => {
|
||||||
@@ -101,7 +102,7 @@ const Layout: React.FC = ({ children }) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex-1 ml-3 md:flex md:justify-between">
|
<div className="flex-1 ml-3 md:flex md:justify-between">
|
||||||
<p className="text-sm leading-5 text-white">
|
<p className="text-sm leading-5 text-white">
|
||||||
<FormattedMessage {...messages.alphawarning} />
|
{intl.formatMessage(messages.alphawarning)}
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-3 text-sm leading-5 md:mt-0 md:ml-6">
|
<p className="mt-3 text-sm leading-5 md:mt-0 md:ml-6">
|
||||||
<a
|
<a
|
||||||
|
@@ -4,7 +4,7 @@ import { useUser } from '../../hooks/useUser';
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useRouter } from 'next/dist/client/router';
|
import { useRouter } from 'next/dist/client/router';
|
||||||
import ImageFader from '../Common/ImageFader';
|
import ImageFader from '../Common/ImageFader';
|
||||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import Transition from '../Transition';
|
import Transition from '../Transition';
|
||||||
import LanguagePicker from '../Layout/LanguagePicker';
|
import LanguagePicker from '../Layout/LanguagePicker';
|
||||||
import LocalLogin from './LocalLogin';
|
import LocalLogin from './LocalLogin';
|
||||||
@@ -77,9 +77,9 @@ const Login: React.FC = () => {
|
|||||||
<LanguagePicker />
|
<LanguagePicker />
|
||||||
</div>
|
</div>
|
||||||
<div className="relative z-40 px-4 sm:mx-auto sm:w-full sm:max-w-md">
|
<div className="relative z-40 px-4 sm:mx-auto sm:w-full sm:max-w-md">
|
||||||
<img src="/logo.png" className="w-auto mx-auto max-h-32" alt="Logo" />
|
<img src="/logo.png" className="max-w-full" alt="Logo" />
|
||||||
<h2 className="mt-2 text-3xl font-extrabold leading-9 text-center text-gray-100">
|
<h2 className="mt-2 text-3xl font-extrabold leading-9 text-center text-gray-100">
|
||||||
<FormattedMessage {...messages.signinheader} />
|
{intl.formatMessage(messages.signinheader)}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative z-50 mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
<div className="relative z-50 mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
||||||
|
@@ -6,21 +6,21 @@ import { useRouter } from 'next/router';
|
|||||||
import Header from '../Common/Header';
|
import Header from '../Common/Header';
|
||||||
import type { MovieDetails } from '../../../server/models/Movie';
|
import type { MovieDetails } from '../../../server/models/Movie';
|
||||||
import { LanguageContext } from '../../context/LanguageContext';
|
import { LanguageContext } from '../../context/LanguageContext';
|
||||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import PageTitle from '../Common/PageTitle';
|
import PageTitle from '../Common/PageTitle';
|
||||||
import useDiscover from '../../hooks/useDiscover';
|
import useDiscover from '../../hooks/useDiscover';
|
||||||
import Error from '../../pages/_error';
|
import Error from '../../pages/_error';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
recommendations: 'Recommendations',
|
recommendations: 'Recommendations',
|
||||||
recommendationssubtext: 'If you liked {title}, you might also like…',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const MovieRecommendations: React.FC = () => {
|
const MovieRecommendations: React.FC = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { locale } = useContext(LanguageContext);
|
const { locale } = useContext(LanguageContext);
|
||||||
const { data: movieData, error: movieError } = useSWR<MovieDetails>(
|
const { data: movieData } = useSWR<MovieDetails>(
|
||||||
`/api/v1/movie/${router.query.movieId}?language=${locale}`
|
`/api/v1/movie/${router.query.movieId}?language=${locale}`
|
||||||
);
|
);
|
||||||
const {
|
const {
|
||||||
@@ -47,14 +47,12 @@ const MovieRecommendations: React.FC = () => {
|
|||||||
<div className="mt-1 mb-5">
|
<div className="mt-1 mb-5">
|
||||||
<Header
|
<Header
|
||||||
subtext={
|
subtext={
|
||||||
movieData && !movieError
|
<Link href={`/movie/${movieData?.id}`}>
|
||||||
? intl.formatMessage(messages.recommendationssubtext, {
|
<a className="hover:underline">{movieData?.title}</a>
|
||||||
title: movieData.title,
|
</Link>
|
||||||
})
|
|
||||||
: ''
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<FormattedMessage {...messages.recommendations} />
|
{intl.formatMessage(messages.recommendations)}
|
||||||
</Header>
|
</Header>
|
||||||
</div>
|
</div>
|
||||||
<ListView
|
<ListView
|
||||||
|
@@ -6,21 +6,21 @@ import { useRouter } from 'next/router';
|
|||||||
import Header from '../Common/Header';
|
import Header from '../Common/Header';
|
||||||
import { LanguageContext } from '../../context/LanguageContext';
|
import { LanguageContext } from '../../context/LanguageContext';
|
||||||
import type { MovieDetails } from '../../../server/models/Movie';
|
import type { MovieDetails } from '../../../server/models/Movie';
|
||||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import PageTitle from '../Common/PageTitle';
|
import PageTitle from '../Common/PageTitle';
|
||||||
import useDiscover from '../../hooks/useDiscover';
|
import useDiscover from '../../hooks/useDiscover';
|
||||||
import Error from '../../pages/_error';
|
import Error from '../../pages/_error';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
similar: 'Similar Titles',
|
similar: 'Similar Titles',
|
||||||
similarsubtext: 'Other movies similar to {title}',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const MovieSimilar: React.FC = () => {
|
const MovieSimilar: React.FC = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { locale } = useContext(LanguageContext);
|
const { locale } = useContext(LanguageContext);
|
||||||
const { data: movieData, error: movieError } = useSWR<MovieDetails>(
|
const { data: movieData } = useSWR<MovieDetails>(
|
||||||
`/api/v1/movie/${router.query.movieId}?language=${locale}`
|
`/api/v1/movie/${router.query.movieId}?language=${locale}`
|
||||||
);
|
);
|
||||||
const {
|
const {
|
||||||
@@ -45,14 +45,12 @@ const MovieSimilar: React.FC = () => {
|
|||||||
<div className="mt-1 mb-5">
|
<div className="mt-1 mb-5">
|
||||||
<Header
|
<Header
|
||||||
subtext={
|
subtext={
|
||||||
movieData && !movieError
|
<Link href={`/movie/${movieData?.id}`}>
|
||||||
? intl.formatMessage(messages.similarsubtext, {
|
<a className="hover:underline">{movieData?.title}</a>
|
||||||
title: movieData.title,
|
</Link>
|
||||||
})
|
|
||||||
: undefined
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<FormattedMessage {...messages.similar} />
|
{intl.formatMessage(messages.similar)}
|
||||||
</Header>
|
</Header>
|
||||||
</div>
|
</div>
|
||||||
<ListView
|
<ListView
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useContext, useMemo } from 'react';
|
import React, { useState, useContext, useMemo } from 'react';
|
||||||
import { defineMessages, FormattedNumber, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import type { MovieDetails as MovieDetailsType } from '../../../server/models/Movie';
|
import type { MovieDetails as MovieDetailsType } from '../../../server/models/Movie';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
@@ -595,11 +595,10 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
|||||||
<div className="media-fact">
|
<div className="media-fact">
|
||||||
<span>{intl.formatMessage(messages.revenue)}</span>
|
<span>{intl.formatMessage(messages.revenue)}</span>
|
||||||
<span className="media-fact-value">
|
<span className="media-fact-value">
|
||||||
<FormattedNumber
|
{intl.formatNumber(data.revenue, {
|
||||||
currency="USD"
|
currency: 'USD',
|
||||||
style="currency"
|
style: 'currency',
|
||||||
value={data.revenue}
|
})}
|
||||||
/>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -607,11 +606,10 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
|||||||
<div className="media-fact">
|
<div className="media-fact">
|
||||||
<span>{intl.formatMessage(messages.budget)}</span>
|
<span>{intl.formatMessage(messages.budget)}</span>
|
||||||
<span className="media-fact-value">
|
<span className="media-fact-value">
|
||||||
<FormattedNumber
|
{intl.formatNumber(data.budget, {
|
||||||
currency="USD"
|
currency: 'USD',
|
||||||
style="currency"
|
style: 'currency',
|
||||||
value={data.budget}
|
})}
|
||||||
/>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@@ -18,11 +18,10 @@ import AdvancedRequester, { RequestOverrides } from './AdvancedRequester';
|
|||||||
import globalMessages from '../../i18n/globalMessages';
|
import globalMessages from '../../i18n/globalMessages';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
requestadmin:
|
requestadmin: 'Your request will be immediately approved.',
|
||||||
'Your request will be immediately approved. Do you wish to continue?',
|
|
||||||
cancelrequest:
|
cancelrequest:
|
||||||
'This will remove your request. Are you sure you want to continue?',
|
'This will remove your request. Are you sure you want to continue?',
|
||||||
requestSuccess: '<strong>{title}</strong> successfully requested!',
|
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',
|
||||||
|
@@ -10,7 +10,8 @@ const messages = defineMessages({
|
|||||||
next: 'Next',
|
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.",
|
||||||
nosummary: 'No summary for this title was found.',
|
nosummary: 'No summary for this title was found.',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -25,7 +25,7 @@ const messages = defineMessages({
|
|||||||
requestadmin: 'Your request will be immediately approved.',
|
requestadmin: 'Your request will be immediately approved.',
|
||||||
cancelrequest:
|
cancelrequest:
|
||||||
'This will remove your request. Are you sure you want to continue?',
|
'This will remove your request. Are you sure you want to continue?',
|
||||||
requestSuccess: '<strong>{title}</strong> successfully requested!',
|
requestSuccess: '<strong>{title}</strong> requested successfully!',
|
||||||
requesttitle: 'Request {title}',
|
requesttitle: 'Request {title}',
|
||||||
request4ktitle: 'Request {title} in 4K',
|
request4ktitle: 'Request {title} in 4K',
|
||||||
requesting: 'Requesting…',
|
requesting: 'Requesting…',
|
||||||
@@ -45,7 +45,6 @@ const messages = defineMessages({
|
|||||||
requestcancelled: 'Request canceled.',
|
requestcancelled: 'Request canceled.',
|
||||||
autoapproval: 'Automatic Approval',
|
autoapproval: 'Automatic Approval',
|
||||||
requesterror: 'Something went wrong while submitting the request.',
|
requesterror: 'Something went wrong while submitting the request.',
|
||||||
next: 'Next',
|
|
||||||
backbutton: 'Back',
|
backbutton: 'Back',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -7,13 +7,15 @@ import { Field, Form, Formik } from 'formik';
|
|||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import PageTitle from '../Common/PageTitle';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
forgotpassword: 'Forgot Your Password?',
|
passwordreset: 'Password Reset',
|
||||||
emailresetlink: 'Email Me a Recovery Link',
|
resetpassword: 'Reset your password',
|
||||||
|
emailresetlink: 'Email a Recovery Link',
|
||||||
email: 'Email',
|
email: 'Email',
|
||||||
validationemailrequired: 'You must provide a valid email address',
|
validationemailrequired: 'You must provide a valid email address',
|
||||||
gobacklogin: 'Go Back to Sign-In Page',
|
gobacklogin: 'Return to Sign-In Page',
|
||||||
requestresetlinksuccessmessage:
|
requestresetlinksuccessmessage:
|
||||||
'A password reset link will be sent to the provided email address if it is associated with a valid user.',
|
'A password reset link will be sent to the provided email address if it is associated with a valid user.',
|
||||||
});
|
});
|
||||||
@@ -30,6 +32,7 @@ const ResetPassword: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative flex flex-col min-h-screen bg-gray-900 py-14">
|
<div className="relative flex flex-col min-h-screen bg-gray-900 py-14">
|
||||||
|
<PageTitle title={intl.formatMessage(messages.passwordreset)} />
|
||||||
<ImageFader
|
<ImageFader
|
||||||
backgroundImages={[
|
backgroundImages={[
|
||||||
'/images/rotate1.jpg',
|
'/images/rotate1.jpg',
|
||||||
@@ -44,13 +47,9 @@ const ResetPassword: React.FC = () => {
|
|||||||
<LanguagePicker />
|
<LanguagePicker />
|
||||||
</div>
|
</div>
|
||||||
<div className="relative z-40 px-4 sm:mx-auto sm:w-full sm:max-w-md">
|
<div className="relative z-40 px-4 sm:mx-auto sm:w-full sm:max-w-md">
|
||||||
<img
|
<img src="/logo.png" className="max-w-full" alt="Logo" />
|
||||||
src="/logo.png"
|
|
||||||
className="w-auto mx-auto max-h-32"
|
|
||||||
alt="Overseerr Logo"
|
|
||||||
/>
|
|
||||||
<h2 className="mt-2 text-3xl font-extrabold leading-9 text-center text-gray-100">
|
<h2 className="mt-2 text-3xl font-extrabold leading-9 text-center text-gray-100">
|
||||||
{intl.formatMessage(messages.forgotpassword)}
|
{intl.formatMessage(messages.resetpassword)}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative z-50 mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
<div className="relative z-50 mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
||||||
|
@@ -10,16 +10,16 @@ import { useRouter } from 'next/router';
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
resetpassword: 'Reset Password',
|
passwordreset: 'Password Reset',
|
||||||
|
resetpassword: 'Reset your password',
|
||||||
password: 'Password',
|
password: 'Password',
|
||||||
confirmpassword: 'Confirm Password',
|
confirmpassword: 'Confirm Password',
|
||||||
validationpasswordrequired: 'You must provide a password',
|
validationpasswordrequired: 'You must provide a password',
|
||||||
validationpasswordmatch: 'Password must match',
|
validationpasswordmatch: 'Passwords must match',
|
||||||
validationpasswordminchars:
|
validationpasswordminchars:
|
||||||
'Password is too short; should be a minimum of 8 characters',
|
'Password is too short; should be a minimum of 8 characters',
|
||||||
gobacklogin: 'Go Back to Sign-In Page',
|
gobacklogin: 'Return to Sign-In Page',
|
||||||
resetpasswordsuccessmessage:
|
resetpasswordsuccessmessage: 'Password reset successfully!',
|
||||||
'If the link is valid and is connected to a user then the password has been reset.',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const ResetPassword: React.FC = () => {
|
const ResetPassword: React.FC = () => {
|
||||||
@@ -60,11 +60,7 @@ const ResetPassword: React.FC = () => {
|
|||||||
<LanguagePicker />
|
<LanguagePicker />
|
||||||
</div>
|
</div>
|
||||||
<div className="relative z-40 px-4 sm:mx-auto sm:w-full sm:max-w-md">
|
<div className="relative z-40 px-4 sm:mx-auto sm:w-full sm:max-w-md">
|
||||||
<img
|
<img src="/logo.png" className="max-w-full" alt="Logo" />
|
||||||
src="/logo.png"
|
|
||||||
className="w-auto mx-auto max-h-32"
|
|
||||||
alt="Overseerr Logo"
|
|
||||||
/>
|
|
||||||
<h2 className="mt-2 text-3xl font-extrabold leading-9 text-center text-gray-100">
|
<h2 className="mt-2 text-3xl font-extrabold leading-9 text-center text-gray-100">
|
||||||
{intl.formatMessage(messages.resetpassword)}
|
{intl.formatMessage(messages.resetpassword)}
|
||||||
</h2>
|
</h2>
|
||||||
|
@@ -15,8 +15,8 @@ import globalMessages from '../../../i18n/globalMessages';
|
|||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
save: 'Save Changes',
|
save: 'Save Changes',
|
||||||
saving: 'Saving…',
|
saving: 'Saving…',
|
||||||
validationSmtpHostRequired: 'You must provide an SMTP host',
|
validationSmtpHostRequired: 'You must provide a hostname or IP address',
|
||||||
validationSmtpPortRequired: 'You must provide an SMTP port',
|
validationSmtpPortRequired: 'You must provide a valid port number',
|
||||||
agentenabled: 'Enable Agent',
|
agentenabled: 'Enable Agent',
|
||||||
emailsender: 'Sender Address',
|
emailsender: 'Sender Address',
|
||||||
smtpHost: 'SMTP Host',
|
smtpHost: 'SMTP Host',
|
||||||
@@ -80,9 +80,9 @@ const NotificationsEmail: React.FC = () => {
|
|||||||
/^(([a-z]|\d|_|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*)?([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])$/i,
|
/^(([a-z]|\d|_|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*)?([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])$/i,
|
||||||
intl.formatMessage(messages.validationSmtpHostRequired)
|
intl.formatMessage(messages.validationSmtpHostRequired)
|
||||||
),
|
),
|
||||||
smtpPort: Yup.number().required(
|
smtpPort: Yup.number()
|
||||||
intl.formatMessage(messages.validationSmtpPortRequired)
|
.typeError(intl.formatMessage(messages.validationSmtpPortRequired))
|
||||||
),
|
.required(intl.formatMessage(messages.validationSmtpPortRequired)),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!data && !error) {
|
if (!data && !error) {
|
||||||
|
@@ -12,13 +12,13 @@ const messages = defineMessages({
|
|||||||
createradarr: 'Add New Radarr Server',
|
createradarr: 'Add New Radarr Server',
|
||||||
editradarr: 'Edit Radarr Server',
|
editradarr: 'Edit Radarr Server',
|
||||||
validationNameRequired: 'You must provide a server name',
|
validationNameRequired: 'You must provide a server name',
|
||||||
validationHostnameRequired: 'You must provide a hostname/IP',
|
validationHostnameRequired: 'You must provide a hostname or IP address',
|
||||||
validationPortRequired: 'You must provide a port',
|
validationPortRequired: 'You must provide a valid port number',
|
||||||
validationApiKeyRequired: 'You must provide an API key',
|
validationApiKeyRequired: 'You must provide an API key',
|
||||||
validationRootFolderRequired: 'You must select a root folder',
|
validationRootFolderRequired: 'You must select a root folder',
|
||||||
validationProfileRequired: 'You must select a profile',
|
validationProfileRequired: 'You must select a profile',
|
||||||
validationMinimumAvailabilityRequired: 'You must select minimum availability',
|
validationMinimumAvailabilityRequired: 'You must select minimum availability',
|
||||||
toastRadarrTestSuccess: 'Radarr connection established!',
|
toastRadarrTestSuccess: 'Radarr connection established successfully!',
|
||||||
toastRadarrTestFailure: 'Failed to connect to Radarr.',
|
toastRadarrTestFailure: 'Failed to connect to Radarr.',
|
||||||
saving: 'Saving…',
|
saving: 'Saving…',
|
||||||
save: 'Save Changes',
|
save: 'Save Changes',
|
||||||
@@ -28,7 +28,7 @@ const messages = defineMessages({
|
|||||||
defaultserver: 'Default Server',
|
defaultserver: 'Default Server',
|
||||||
servername: 'Server Name',
|
servername: 'Server Name',
|
||||||
servernamePlaceholder: 'A Radarr Server',
|
servernamePlaceholder: 'A Radarr Server',
|
||||||
hostname: 'Hostname',
|
hostname: 'Hostname or IP Address',
|
||||||
port: 'Port',
|
port: 'Port',
|
||||||
ssl: 'SSL',
|
ssl: 'SSL',
|
||||||
apiKey: 'API Key',
|
apiKey: 'API Key',
|
||||||
@@ -98,9 +98,9 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
|||||||
/^(([a-z]|\d|_|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*)?([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])$/i,
|
/^(([a-z]|\d|_|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*)?([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])$/i,
|
||||||
intl.formatMessage(messages.validationHostnameRequired)
|
intl.formatMessage(messages.validationHostnameRequired)
|
||||||
),
|
),
|
||||||
port: Yup.number().required(
|
port: Yup.number()
|
||||||
intl.formatMessage(messages.validationPortRequired)
|
.typeError(intl.formatMessage(messages.validationPortRequired))
|
||||||
),
|
.required(intl.formatMessage(messages.validationPortRequired)),
|
||||||
apiKey: Yup.string().required(
|
apiKey: Yup.string().required(
|
||||||
intl.formatMessage(messages.validationApiKeyRequired)
|
intl.formatMessage(messages.validationApiKeyRequired)
|
||||||
),
|
),
|
||||||
|
@@ -18,9 +18,10 @@ const messages = defineMessages({
|
|||||||
latestversion: 'Latest',
|
latestversion: 'Latest',
|
||||||
currentversion: 'Current Version',
|
currentversion: 'Current Version',
|
||||||
viewchangelog: 'View Changelog',
|
viewchangelog: 'View Changelog',
|
||||||
runningDevelop: 'You are running a develop version of Overseerr!',
|
runningDevelop: 'Development Version',
|
||||||
runningDevelopMessage:
|
runningDevelopMessage:
|
||||||
'The changes in your version will not be available below. Please see the <GithubLink>GitHub repository</GithubLink> for latest updates.',
|
'The latest changes to the <code>develop</code> branch of Overseerr are not shown below.\
|
||||||
|
Please see the commit history for this branch on <GithubLink>GitHub</GithubLink> for details.',
|
||||||
});
|
});
|
||||||
|
|
||||||
const REPO_RELEASE_API =
|
const REPO_RELEASE_API =
|
||||||
@@ -161,6 +162,9 @@ const Releases: React.FC<ReleasesProps> = ({ currentVersion }) => {
|
|||||||
{currentVersion.startsWith('develop-') && (
|
{currentVersion.startsWith('develop-') && (
|
||||||
<Alert title={intl.formatMessage(messages.runningDevelop)}>
|
<Alert title={intl.formatMessage(messages.runningDevelop)}>
|
||||||
{intl.formatMessage(messages.runningDevelopMessage, {
|
{intl.formatMessage(messages.runningDevelopMessage, {
|
||||||
|
code: function code(msg) {
|
||||||
|
return <code className="bg-opacity-50">{msg}</code>;
|
||||||
|
},
|
||||||
GithubLink: function GithubLink(msg) {
|
GithubLink: function GithubLink(msg) {
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
|
@@ -4,19 +4,21 @@ import Error from '../../../pages/_error';
|
|||||||
import List from '../../Common/List';
|
import List from '../../Common/List';
|
||||||
import LoadingSpinner from '../../Common/LoadingSpinner';
|
import LoadingSpinner from '../../Common/LoadingSpinner';
|
||||||
import { SettingsAboutResponse } from '../../../../server/interfaces/api/settingsInterfaces';
|
import { SettingsAboutResponse } from '../../../../server/interfaces/api/settingsInterfaces';
|
||||||
import { defineMessages, FormattedNumber, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import Releases from './Releases';
|
import Releases from './Releases';
|
||||||
import Badge from '../../Common/Badge';
|
import Badge from '../../Common/Badge';
|
||||||
|
import PageTitle from '../../Common/PageTitle';
|
||||||
|
import globalMessages from '../../../i18n/globalMessages';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
about: 'About',
|
||||||
overseerrinformation: 'Overseerr Information',
|
overseerrinformation: 'Overseerr Information',
|
||||||
version: 'Version',
|
version: 'Version',
|
||||||
totalmedia: 'Total Media',
|
totalmedia: 'Total Media',
|
||||||
totalrequests: 'Total Requests',
|
totalrequests: 'Total Requests',
|
||||||
gettingsupport: 'Getting Support',
|
gettingsupport: 'Getting Support',
|
||||||
githubdiscussions: 'GitHub Discussions',
|
githubdiscussions: 'GitHub Discussions',
|
||||||
clickheretojoindiscord: 'Click here to join our Discord server.',
|
timezone: 'Time Zone',
|
||||||
timezone: 'Timezone',
|
|
||||||
supportoverseerr: 'Support Overseerr',
|
supportoverseerr: 'Support Overseerr',
|
||||||
helppaycoffee: 'Help Pay for Coffee',
|
helppaycoffee: 'Help Pay for Coffee',
|
||||||
documentation: 'Documentation',
|
documentation: 'Documentation',
|
||||||
@@ -39,20 +41,26 @@ const SettingsAbout: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<PageTitle
|
||||||
|
title={[
|
||||||
|
intl.formatMessage(messages.about),
|
||||||
|
intl.formatMessage(globalMessages.settings),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<div className="section">
|
<div className="section">
|
||||||
<List title={intl.formatMessage(messages.overseerrinformation)}>
|
<List title={intl.formatMessage(messages.overseerrinformation)}>
|
||||||
<List.Item title={intl.formatMessage(messages.version)}>
|
<List.Item title={intl.formatMessage(messages.version)}>
|
||||||
{data.version}
|
<code>{data.version}</code>
|
||||||
</List.Item>
|
</List.Item>
|
||||||
<List.Item title={intl.formatMessage(messages.totalmedia)}>
|
<List.Item title={intl.formatMessage(messages.totalmedia)}>
|
||||||
<FormattedNumber value={data.totalMediaItems} />
|
{intl.formatNumber(data.totalMediaItems)}
|
||||||
</List.Item>
|
</List.Item>
|
||||||
<List.Item title={intl.formatMessage(messages.totalrequests)}>
|
<List.Item title={intl.formatMessage(messages.totalrequests)}>
|
||||||
<FormattedNumber value={data.totalRequests} />
|
{intl.formatNumber(data.totalRequests)}
|
||||||
</List.Item>
|
</List.Item>
|
||||||
{data.tz && (
|
{data.tz && (
|
||||||
<List.Item title={intl.formatMessage(messages.timezone)}>
|
<List.Item title={intl.formatMessage(messages.timezone)}>
|
||||||
{data.tz}
|
<code>{data.tz}</code>
|
||||||
</List.Item>
|
</List.Item>
|
||||||
)}
|
)}
|
||||||
</List>
|
</List>
|
||||||
@@ -86,7 +94,7 @@ const SettingsAbout: React.FC = () => {
|
|||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className="text-indigo-500 hover:underline"
|
className="text-indigo-500 hover:underline"
|
||||||
>
|
>
|
||||||
{intl.formatMessage(messages.clickheretojoindiscord)}
|
https://discord.gg/PkCWJSeCk7
|
||||||
</a>
|
</a>
|
||||||
</List.Item>
|
</List.Item>
|
||||||
</List>
|
</List>
|
||||||
|
@@ -15,8 +15,11 @@ import { useToasts } from 'react-toast-notifications';
|
|||||||
import Badge from '../../Common/Badge';
|
import Badge from '../../Common/Badge';
|
||||||
import { CacheItem } from '../../../../server/interfaces/api/settingsInterfaces';
|
import { CacheItem } from '../../../../server/interfaces/api/settingsInterfaces';
|
||||||
import { formatBytes } from '../../../utils/numberHelpers';
|
import { formatBytes } from '../../../utils/numberHelpers';
|
||||||
|
import PageTitle from '../../Common/PageTitle';
|
||||||
|
import globalMessages from '../../../i18n/globalMessages';
|
||||||
|
|
||||||
const messages: { [messageName: string]: MessageDescriptor } = defineMessages({
|
const messages: { [messageName: string]: MessageDescriptor } = defineMessages({
|
||||||
|
jobsandcache: 'Jobs & Cache',
|
||||||
jobs: 'Jobs',
|
jobs: 'Jobs',
|
||||||
jobsDescription:
|
jobsDescription:
|
||||||
'Overseerr performs certain maintenance tasks as regularly-scheduled jobs,\
|
'Overseerr performs certain maintenance tasks as regularly-scheduled jobs,\
|
||||||
@@ -118,6 +121,12 @@ const SettingsJobs: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<PageTitle
|
||||||
|
title={[
|
||||||
|
intl.formatMessage(messages.jobsandcache),
|
||||||
|
intl.formatMessage(globalMessages.settings),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h3 className="heading">{intl.formatMessage(messages.jobs)}</h3>
|
<h3 className="heading">{intl.formatMessage(messages.jobs)}</h3>
|
||||||
<p className="description">
|
<p className="description">
|
||||||
|
@@ -3,10 +3,10 @@ import Link from 'next/link';
|
|||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { defineMessages, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import PageTitle from '../Common/PageTitle';
|
import PageTitle from '../Common/PageTitle';
|
||||||
|
import globalMessages from '../../i18n/globalMessages';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
settings: 'Settings',
|
menuGeneralSettings: 'General',
|
||||||
menuGeneralSettings: 'General Settings',
|
|
||||||
menuUsers: 'Users',
|
menuUsers: 'Users',
|
||||||
menuPlexSettings: 'Plex',
|
menuPlexSettings: 'Plex',
|
||||||
menuServices: 'Services',
|
menuServices: 'Services',
|
||||||
@@ -99,7 +99,7 @@ const SettingsLayout: React.FC = ({ children }) => {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageTitle title={intl.formatMessage(messages.settings)} />
|
<PageTitle title={intl.formatMessage(globalMessages.settings)} />
|
||||||
<div className="mt-6">
|
<div className="mt-6">
|
||||||
<div className="sm:hidden">
|
<div className="sm:hidden">
|
||||||
<select
|
<select
|
||||||
|
@@ -9,7 +9,9 @@ import Error from '../../../pages/_error';
|
|||||||
import Badge from '../../Common/Badge';
|
import Badge from '../../Common/Badge';
|
||||||
import Button from '../../Common/Button';
|
import Button from '../../Common/Button';
|
||||||
import LoadingSpinner from '../../Common/LoadingSpinner';
|
import LoadingSpinner from '../../Common/LoadingSpinner';
|
||||||
|
import PageTitle from '../../Common/PageTitle';
|
||||||
import Table from '../../Common/Table';
|
import Table from '../../Common/Table';
|
||||||
|
import globalMessages from '../../../i18n/globalMessages';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
logs: 'Logs',
|
logs: 'Logs',
|
||||||
@@ -93,6 +95,12 @@ const SettingsLogs: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<PageTitle
|
||||||
|
title={[
|
||||||
|
intl.formatMessage(messages.logs),
|
||||||
|
intl.formatMessage(globalMessages.settings),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<h3 className="heading">{intl.formatMessage(messages.logs)}</h3>
|
<h3 className="heading">{intl.formatMessage(messages.logs)}</h3>
|
||||||
<p className="description">
|
<p className="description">
|
||||||
|
@@ -13,8 +13,10 @@ import Badge from '../Common/Badge';
|
|||||||
import globalMessages from '../../i18n/globalMessages';
|
import globalMessages from '../../i18n/globalMessages';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import RegionSelector from '../RegionSelector';
|
import RegionSelector from '../RegionSelector';
|
||||||
|
import PageTitle from '../Common/PageTitle';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
general: 'General',
|
||||||
generalsettings: 'General Settings',
|
generalsettings: 'General Settings',
|
||||||
generalsettingsDescription:
|
generalsettingsDescription:
|
||||||
'Configure global and default settings for Overseerr.',
|
'Configure global and default settings for Overseerr.',
|
||||||
@@ -24,21 +26,19 @@ const messages = defineMessages({
|
|||||||
applicationTitle: 'Application Title',
|
applicationTitle: 'Application Title',
|
||||||
applicationurl: 'Application URL',
|
applicationurl: 'Application URL',
|
||||||
region: 'Discover Region',
|
region: 'Discover Region',
|
||||||
regionTip:
|
regionTip: 'Filter content by regional availability',
|
||||||
'Filter content by region (only applies to the "Popular" and "Upcoming" categories)',
|
|
||||||
originallanguage: 'Discover Language',
|
originallanguage: 'Discover Language',
|
||||||
originallanguageTip:
|
originallanguageTip: 'Filter content by original language',
|
||||||
'Filter content by original language (only applies to the "Popular" and "Upcoming" categories)',
|
toastApiKeySuccess: 'New API key generated successfully!',
|
||||||
toastApiKeySuccess: 'New API key generated!',
|
|
||||||
toastApiKeyFailure: 'Something went wrong while generating a new API key.',
|
toastApiKeyFailure: 'Something went wrong while generating a new API key.',
|
||||||
toastSettingsSuccess: 'Settings successfully saved!',
|
toastSettingsSuccess: 'Settings saved successfully!',
|
||||||
toastSettingsFailure: 'Something went wrong while saving settings.',
|
toastSettingsFailure: 'Something went wrong while saving settings.',
|
||||||
hideAvailable: 'Hide Available Media',
|
hideAvailable: 'Hide Available Media',
|
||||||
csrfProtection: 'Enable CSRF Protection',
|
csrfProtection: 'Enable CSRF Protection',
|
||||||
csrfProtectionTip:
|
csrfProtectionTip:
|
||||||
'Sets external API access to read-only (requires HTTPS and Overseerr must be reloaded for changes to take effect)',
|
'Sets external API access to read-only (requires HTTPS, and Overseerr must be reloaded for changes to take effect)',
|
||||||
csrfProtectionHoverTip:
|
csrfProtectionHoverTip:
|
||||||
'Do NOT enable this unless you understand what you are doing!',
|
'Do NOT enable this setting unless you understand what you are doing!',
|
||||||
trustProxy: 'Enable Proxy Support',
|
trustProxy: 'Enable Proxy Support',
|
||||||
trustProxyTip:
|
trustProxyTip:
|
||||||
'Allows Overseerr to correctly register client IP addresses behind a proxy (Overseerr must be reloaded for changes to take effect)',
|
'Allows Overseerr to correctly register client IP addresses behind a proxy (Overseerr must be reloaded for changes to take effect)',
|
||||||
@@ -46,7 +46,7 @@ const messages = defineMessages({
|
|||||||
validationApplicationUrl: 'You must provide a valid URL',
|
validationApplicationUrl: 'You must provide a valid URL',
|
||||||
validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',
|
validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',
|
||||||
originalLanguageDefault: 'All Languages',
|
originalLanguageDefault: 'All Languages',
|
||||||
partialRequestsEnabled: 'Enable Partial Series Requests',
|
partialRequestsEnabled: 'Allow Partial Series Requests',
|
||||||
});
|
});
|
||||||
|
|
||||||
const SettingsMain: React.FC = () => {
|
const SettingsMain: React.FC = () => {
|
||||||
@@ -119,6 +119,12 @@ const SettingsMain: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<PageTitle
|
||||||
|
title={[
|
||||||
|
intl.formatMessage(messages.general),
|
||||||
|
intl.formatMessage(globalMessages.settings),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h3 className="heading">
|
<h3 className="heading">
|
||||||
{intl.formatMessage(messages.generalsettings)}
|
{intl.formatMessage(messages.generalsettings)}
|
||||||
|
@@ -15,8 +15,11 @@ import LoadingSpinner from '../Common/LoadingSpinner';
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useToasts } from 'react-toast-notifications';
|
import { useToasts } from 'react-toast-notifications';
|
||||||
import Button from '../Common/Button';
|
import Button from '../Common/Button';
|
||||||
|
import PageTitle from '../Common/PageTitle';
|
||||||
|
import globalMessages from '../../i18n/globalMessages';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
notifications: 'Notifications',
|
||||||
save: 'Save Changes',
|
save: 'Save Changes',
|
||||||
saving: 'Saving…',
|
saving: 'Saving…',
|
||||||
notificationsettings: 'Notification Settings',
|
notificationsettings: 'Notification Settings',
|
||||||
@@ -174,6 +177,12 @@ const SettingsNotifications: React.FC = ({ children }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<PageTitle
|
||||||
|
title={[
|
||||||
|
intl.formatMessage(messages.notifications),
|
||||||
|
intl.formatMessage(globalMessages.settings),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h3 className="heading">
|
<h3 className="heading">
|
||||||
{intl.formatMessage(messages.notificationsettings)}
|
{intl.formatMessage(messages.notificationsettings)}
|
||||||
|
@@ -9,12 +9,15 @@ import Button from '../Common/Button';
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import LibraryItem from './LibraryItem';
|
import LibraryItem from './LibraryItem';
|
||||||
import Badge from '../Common/Badge';
|
import Badge from '../Common/Badge';
|
||||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import Alert from '../Common/Alert';
|
import Alert from '../Common/Alert';
|
||||||
import Spinner from '../../assets/spinner.svg';
|
import Spinner from '../../assets/spinner.svg';
|
||||||
|
import PageTitle from '../Common/PageTitle';
|
||||||
|
import globalMessages from '../../i18n/globalMessages';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
plex: 'Plex',
|
||||||
plexsettings: 'Plex Settings',
|
plexsettings: 'Plex Settings',
|
||||||
plexsettingsDescription:
|
plexsettingsDescription:
|
||||||
'Configure the settings for your Plex server. Overseerr scans your Plex libraries to see what content is available.',
|
'Configure the settings for your Plex server. Overseerr scans your Plex libraries to see what content is available.',
|
||||||
@@ -30,17 +33,17 @@ const messages = defineMessages({
|
|||||||
serverpresetRefreshing: 'Retrieving servers…',
|
serverpresetRefreshing: 'Retrieving servers…',
|
||||||
serverpresetLoad: 'Press the button to load available servers',
|
serverpresetLoad: 'Press the button to load available servers',
|
||||||
toastPlexRefresh: 'Retrieving server list from Plex',
|
toastPlexRefresh: 'Retrieving server list from Plex',
|
||||||
toastPlexRefreshSuccess: 'Retrieved server list from Plex',
|
toastPlexRefreshSuccess: 'Plex server list retrieved successfully!',
|
||||||
toastPlexRefreshFailure: 'Unable to retrieve server list from Plex',
|
toastPlexRefreshFailure: 'Failed to retrieve Plex server list.',
|
||||||
toastPlexConnecting: 'Attempting to connect to Plex server',
|
toastPlexConnecting: 'Attempting to connect to Plex…',
|
||||||
toastPlexConnectingSuccess: 'Connected to Plex server',
|
toastPlexConnectingSuccess: 'Plex connection established successfully!',
|
||||||
toastPlexConnectingFailure: 'Unable to connect to Plex server',
|
toastPlexConnectingFailure: 'Failed to connect to Plex.',
|
||||||
settingUpPlex: 'Setting Up Plex',
|
settingUpPlex: 'Setting Up Plex',
|
||||||
settingUpPlexDescription:
|
settingUpPlexDescription:
|
||||||
'To set up Plex, you can either enter your details manually \
|
'To set up Plex, you can either enter your details manually \
|
||||||
or select a server retrieved from <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>.\
|
or select a server retrieved from <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>.\
|
||||||
Press the button to the right of the dropdown to check connectivity and retrieve available servers.',
|
Press the button to the right of the dropdown to check connectivity and retrieve available servers.',
|
||||||
hostname: 'Hostname/IP',
|
hostname: 'Hostname or IP Address',
|
||||||
port: 'Port',
|
port: 'Port',
|
||||||
ssl: 'SSL',
|
ssl: 'SSL',
|
||||||
timeout: 'Timeout',
|
timeout: 'Timeout',
|
||||||
@@ -59,8 +62,8 @@ const messages = defineMessages({
|
|||||||
librariesRemaining: 'Libraries Remaining: {count}',
|
librariesRemaining: 'Libraries Remaining: {count}',
|
||||||
startscan: 'Start Scan',
|
startscan: 'Start Scan',
|
||||||
cancelscan: 'Cancel Scan',
|
cancelscan: 'Cancel Scan',
|
||||||
validationHostnameRequired: 'You must provide a hostname/IP',
|
validationHostnameRequired: 'You must provide a hostname or IP address',
|
||||||
validationPortRequired: 'You must provide a port',
|
validationPortRequired: 'You must provide a valid port number',
|
||||||
});
|
});
|
||||||
|
|
||||||
interface Library {
|
interface Library {
|
||||||
@@ -120,9 +123,9 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
|||||||
/^(([a-z]|\d|_|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*)?([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])$/i,
|
/^(([a-z]|\d|_|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*)?([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])$/i,
|
||||||
intl.formatMessage(messages.validationHostnameRequired)
|
intl.formatMessage(messages.validationHostnameRequired)
|
||||||
),
|
),
|
||||||
port: Yup.number().required(
|
port: Yup.number()
|
||||||
intl.formatMessage(messages.validationPortRequired)
|
.typeError(intl.formatMessage(messages.validationPortRequired))
|
||||||
),
|
.required(intl.formatMessage(messages.validationPortRequired)),
|
||||||
});
|
});
|
||||||
|
|
||||||
const activeLibraries =
|
const activeLibraries =
|
||||||
@@ -259,12 +262,16 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<PageTitle
|
||||||
|
title={[
|
||||||
|
intl.formatMessage(messages.plex),
|
||||||
|
intl.formatMessage(globalMessages.settings),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h3 className="heading">
|
<h3 className="heading">{intl.formatMessage(messages.plexsettings)}</h3>
|
||||||
<FormattedMessage {...messages.plexsettings} />
|
|
||||||
</h3>
|
|
||||||
<p className="description">
|
<p className="description">
|
||||||
<FormattedMessage {...messages.plexsettingsDescription} />
|
{intl.formatMessage(messages.plexsettingsDescription)}
|
||||||
</p>
|
</p>
|
||||||
<div className="section">
|
<div className="section">
|
||||||
<Alert title={intl.formatMessage(messages.settingUpPlex)} type="info">
|
<Alert title={intl.formatMessage(messages.settingUpPlex)} type="info">
|
||||||
@@ -350,11 +357,9 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
|||||||
<div className="form-row">
|
<div className="form-row">
|
||||||
<label htmlFor="name" className="text-label">
|
<label htmlFor="name" className="text-label">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<span>
|
<span>{intl.formatMessage(messages.servername)}</span>
|
||||||
<FormattedMessage {...messages.servername} />
|
|
||||||
</span>
|
|
||||||
<span className="text-gray-500">
|
<span className="text-gray-500">
|
||||||
<FormattedMessage {...messages.servernameTip} />
|
{intl.formatMessage(messages.servernameTip)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
@@ -376,7 +381,7 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="form-row">
|
<div className="form-row">
|
||||||
<label htmlFor="preset" className="text-label">
|
<label htmlFor="preset" className="text-label">
|
||||||
<FormattedMessage {...messages.serverpreset} />
|
{intl.formatMessage(messages.serverpreset)}
|
||||||
</label>
|
</label>
|
||||||
<div className="form-input">
|
<div className="form-input">
|
||||||
<div className="form-input-field input-group">
|
<div className="form-input-field input-group">
|
||||||
@@ -460,7 +465,7 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="form-row">
|
<div className="form-row">
|
||||||
<label htmlFor="hostname" className="text-label">
|
<label htmlFor="hostname" className="text-label">
|
||||||
<FormattedMessage {...messages.hostname} />
|
{intl.formatMessage(messages.hostname)}
|
||||||
</label>
|
</label>
|
||||||
<div className="form-input">
|
<div className="form-input">
|
||||||
<div className="form-input-field">
|
<div className="form-input-field">
|
||||||
@@ -482,7 +487,7 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="form-row">
|
<div className="form-row">
|
||||||
<label htmlFor="port" className="text-label">
|
<label htmlFor="port" className="text-label">
|
||||||
<FormattedMessage {...messages.port} />
|
{intl.formatMessage(messages.port)}
|
||||||
</label>
|
</label>
|
||||||
<div className="form-input">
|
<div className="form-input">
|
||||||
<Field
|
<Field
|
||||||
@@ -545,10 +550,10 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
|||||||
</Formik>
|
</Formik>
|
||||||
<div className="mt-10 mb-6">
|
<div className="mt-10 mb-6">
|
||||||
<h3 className="heading">
|
<h3 className="heading">
|
||||||
<FormattedMessage {...messages.plexlibraries} />
|
{intl.formatMessage(messages.plexlibraries)}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="description">
|
<p className="description">
|
||||||
<FormattedMessage {...messages.plexlibrariesDescription} />
|
{intl.formatMessage(messages.plexlibrariesDescription)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="section">
|
<div className="section">
|
||||||
@@ -581,11 +586,9 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-10 mb-6">
|
<div className="mt-10 mb-6">
|
||||||
<h3 className="heading">
|
<h3 className="heading">{intl.formatMessage(messages.manualscan)}</h3>
|
||||||
<FormattedMessage {...messages.manualscan} />
|
|
||||||
</h3>
|
|
||||||
<p className="description">
|
<p className="description">
|
||||||
<FormattedMessage {...messages.manualscanDescription} />
|
{intl.formatMessage(messages.manualscanDescription)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="section">
|
<div className="section">
|
||||||
@@ -615,28 +618,24 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
|||||||
{dataSync.currentLibrary && (
|
{dataSync.currentLibrary && (
|
||||||
<div className="flex items-center mb-2 mr-0 sm:mb-0 sm:mr-2">
|
<div className="flex items-center mb-2 mr-0 sm:mb-0 sm:mr-2">
|
||||||
<Badge>
|
<Badge>
|
||||||
<FormattedMessage
|
{intl.formatMessage(messages.currentlibrary, {
|
||||||
{...messages.currentlibrary}
|
name: dataSync.currentLibrary.name,
|
||||||
values={{ name: dataSync.currentLibrary.name }}
|
})}
|
||||||
/>
|
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<Badge badgeType="warning">
|
<Badge badgeType="warning">
|
||||||
<FormattedMessage
|
{intl.formatMessage(messages.librariesRemaining, {
|
||||||
{...messages.librariesRemaining}
|
count: dataSync.currentLibrary
|
||||||
values={{
|
? dataSync.libraries.slice(
|
||||||
count: dataSync.currentLibrary
|
dataSync.libraries.findIndex(
|
||||||
? dataSync.libraries.slice(
|
(library) =>
|
||||||
dataSync.libraries.findIndex(
|
library.id === dataSync.currentLibrary?.id
|
||||||
(library) =>
|
) + 1
|
||||||
library.id === dataSync.currentLibrary?.id
|
).length
|
||||||
) + 1
|
: 0,
|
||||||
).length
|
})}
|
||||||
: 0,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@@ -658,7 +657,7 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
|||||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<FormattedMessage {...messages.startscan} />
|
{intl.formatMessage(messages.startscan)}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -678,7 +677,7 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
|||||||
d="M6 18L18 6M6 6l12 12"
|
d="M6 18L18 6M6 6l12 12"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<FormattedMessage {...messages.cancelscan} />
|
{intl.formatMessage(messages.cancelscan)}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@@ -14,8 +14,11 @@ import Transition from '../Transition';
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import SonarrModal from './SonarrModal';
|
import SonarrModal from './SonarrModal';
|
||||||
import Alert from '../Common/Alert';
|
import Alert from '../Common/Alert';
|
||||||
|
import PageTitle from '../Common/PageTitle';
|
||||||
|
import globalMessages from '../../i18n/globalMessages';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
services: 'Services',
|
||||||
radarrsettings: 'Radarr Settings',
|
radarrsettings: 'Radarr Settings',
|
||||||
radarrSettingsDescription:
|
radarrSettingsDescription:
|
||||||
'Configure your Radarr connection below. You can have multiple Radarr 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 Radarr connection below. You can have multiple Radarr 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.',
|
||||||
@@ -214,6 +217,12 @@ const SettingsServices: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<PageTitle
|
||||||
|
title={[
|
||||||
|
intl.formatMessage(messages.services),
|
||||||
|
intl.formatMessage(globalMessages.settings),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h3 className="heading">
|
<h3 className="heading">
|
||||||
{intl.formatMessage(messages.radarrsettings)}
|
{intl.formatMessage(messages.radarrsettings)}
|
||||||
|
@@ -8,13 +8,16 @@ import Button from '../../Common/Button';
|
|||||||
import { defineMessages, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import { useToasts } from 'react-toast-notifications';
|
import { useToasts } from 'react-toast-notifications';
|
||||||
import PermissionEdit from '../../PermissionEdit';
|
import PermissionEdit from '../../PermissionEdit';
|
||||||
|
import PageTitle from '../../Common/PageTitle';
|
||||||
|
import globalMessages from '../../../i18n/globalMessages';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
userSettings: 'Users',
|
users: 'Users',
|
||||||
|
userSettings: 'User Settings',
|
||||||
userSettingsDescription: 'Configure global and default user settings.',
|
userSettingsDescription: 'Configure global and default user settings.',
|
||||||
save: 'Save Changes',
|
save: 'Save Changes',
|
||||||
saving: 'Saving…',
|
saving: 'Saving…',
|
||||||
toastSettingsSuccess: 'Settings successfully saved!',
|
toastSettingsSuccess: 'User settings saved successfully!',
|
||||||
toastSettingsFailure: 'Something went wrong while saving settings.',
|
toastSettingsFailure: 'Something went wrong while saving settings.',
|
||||||
localLogin: 'Enable Local User Sign-In',
|
localLogin: 'Enable Local User Sign-In',
|
||||||
defaultPermissions: 'Default User Permissions',
|
defaultPermissions: 'Default User Permissions',
|
||||||
@@ -33,6 +36,12 @@ const SettingsUsers: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<PageTitle
|
||||||
|
title={[
|
||||||
|
intl.formatMessage(messages.users),
|
||||||
|
intl.formatMessage(globalMessages.settings),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h3 className="heading">{intl.formatMessage(messages.userSettings)}</h3>
|
<h3 className="heading">{intl.formatMessage(messages.userSettings)}</h3>
|
||||||
<p className="description">
|
<p className="description">
|
||||||
|
@@ -12,13 +12,13 @@ const messages = defineMessages({
|
|||||||
createsonarr: 'Add New Sonarr Server',
|
createsonarr: 'Add New Sonarr Server',
|
||||||
editsonarr: 'Edit Sonarr Server',
|
editsonarr: 'Edit Sonarr Server',
|
||||||
validationNameRequired: 'You must provide a server name',
|
validationNameRequired: 'You must provide a server name',
|
||||||
validationHostnameRequired: 'You must provide a hostname/IP',
|
validationHostnameRequired: 'You must provide a hostname or IP address',
|
||||||
validationPortRequired: 'You must provide a port',
|
validationPortRequired: 'You must provide a valid port number',
|
||||||
validationApiKeyRequired: 'You must provide an API key',
|
validationApiKeyRequired: 'You must provide an API key',
|
||||||
validationRootFolderRequired: 'You must select a root folder',
|
validationRootFolderRequired: 'You must select a root folder',
|
||||||
validationProfileRequired: 'You must select a quality profile',
|
validationProfileRequired: 'You must select a quality profile',
|
||||||
validationLanguageProfileRequired: 'You must select a language profile',
|
validationLanguageProfileRequired: 'You must select a language profile',
|
||||||
toastSonarrTestSuccess: 'Sonarr connection established!',
|
toastSonarrTestSuccess: 'Sonarr connection established successfully!',
|
||||||
toastSonarrTestFailure: 'Failed to connect to Sonarr.',
|
toastSonarrTestFailure: 'Failed to connect to Sonarr.',
|
||||||
saving: 'Saving…',
|
saving: 'Saving…',
|
||||||
save: 'Save Changes',
|
save: 'Save Changes',
|
||||||
@@ -28,7 +28,7 @@ const messages = defineMessages({
|
|||||||
defaultserver: 'Default Server',
|
defaultserver: 'Default Server',
|
||||||
servername: 'Server Name',
|
servername: 'Server Name',
|
||||||
servernamePlaceholder: 'A Sonarr Server',
|
servernamePlaceholder: 'A Sonarr Server',
|
||||||
hostname: 'Hostname',
|
hostname: 'Hostname or IP Address',
|
||||||
port: 'Port',
|
port: 'Port',
|
||||||
ssl: 'SSL',
|
ssl: 'SSL',
|
||||||
apiKey: 'API Key',
|
apiKey: 'API Key',
|
||||||
@@ -109,9 +109,9 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
|||||||
/^(([a-z]|\d|_|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*)?([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])$/i,
|
/^(([a-z]|\d|_|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*)?([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])$/i,
|
||||||
intl.formatMessage(messages.validationHostnameRequired)
|
intl.formatMessage(messages.validationHostnameRequired)
|
||||||
),
|
),
|
||||||
port: Yup.number().required(
|
port: Yup.number()
|
||||||
intl.formatMessage(messages.validationPortRequired)
|
.typeError(intl.formatMessage(messages.validationPortRequired))
|
||||||
),
|
.required(intl.formatMessage(messages.validationPortRequired)),
|
||||||
apiKey: Yup.string().required(
|
apiKey: Yup.string().required(
|
||||||
intl.formatMessage(messages.validationApiKeyRequired)
|
intl.formatMessage(messages.validationApiKeyRequired)
|
||||||
),
|
),
|
||||||
|
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
|
|||||||
import { useUser } from '../../hooks/useUser';
|
import { useUser } from '../../hooks/useUser';
|
||||||
import PlexLoginButton from '../PlexLoginButton';
|
import PlexLoginButton from '../PlexLoginButton';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { defineMessages, FormattedMessage } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
welcome: 'Welcome to Overseerr',
|
welcome: 'Welcome to Overseerr',
|
||||||
@@ -14,6 +14,7 @@ interface LoginWithPlexProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const LoginWithPlex: React.FC<LoginWithPlexProps> = ({ onComplete }) => {
|
const LoginWithPlex: React.FC<LoginWithPlexProps> = ({ onComplete }) => {
|
||||||
|
const intl = useIntl();
|
||||||
const [authToken, setAuthToken] = useState<string | undefined>(undefined);
|
const [authToken, setAuthToken] = useState<string | undefined>(undefined);
|
||||||
const { user, revalidate } = useUser();
|
const { user, revalidate } = useUser();
|
||||||
|
|
||||||
@@ -45,10 +46,10 @@ const LoginWithPlex: React.FC<LoginWithPlexProps> = ({ onComplete }) => {
|
|||||||
return (
|
return (
|
||||||
<form>
|
<form>
|
||||||
<div className="flex justify-center mb-2 text-xl font-bold">
|
<div className="flex justify-center mb-2 text-xl font-bold">
|
||||||
<FormattedMessage {...messages.welcome} />
|
{intl.formatMessage(messages.welcome)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-center pb-6 mb-2 text-sm">
|
<div className="flex justify-center pb-6 mb-2 text-sm">
|
||||||
<FormattedMessage {...messages.signinMessage} />
|
{intl.formatMessage(messages.signinMessage)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-center">
|
<div className="flex items-center justify-center">
|
||||||
<PlexLoginButton onAuthToken={(authToken) => setAuthToken(authToken)} />
|
<PlexLoginButton onAuthToken={(authToken) => setAuthToken(authToken)} />
|
||||||
|
@@ -7,7 +7,7 @@ import SettingsServices from '../Settings/SettingsServices';
|
|||||||
import LoginWithPlex from './LoginWithPlex';
|
import LoginWithPlex from './LoginWithPlex';
|
||||||
import SetupSteps from './SetupSteps';
|
import SetupSteps from './SetupSteps';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import Badge from '../Common/Badge';
|
import Badge from '../Common/Badge';
|
||||||
import LanguagePicker from '../Layout/LanguagePicker';
|
import LanguagePicker from '../Layout/LanguagePicker';
|
||||||
import PageTitle from '../Common/PageTitle';
|
import PageTitle from '../Common/PageTitle';
|
||||||
@@ -63,11 +63,7 @@ const Setup: React.FC = () => {
|
|||||||
<LanguagePicker />
|
<LanguagePicker />
|
||||||
</div>
|
</div>
|
||||||
<div className="relative z-40 px-4 sm:mx-auto sm:w-full sm:max-w-4xl">
|
<div className="relative z-40 px-4 sm:mx-auto sm:w-full sm:max-w-4xl">
|
||||||
<img
|
<img src="/logo.png" className="max-w-full sm:max-w-md" alt="Logo" />
|
||||||
src="/logo.png"
|
|
||||||
className="w-auto mx-auto mb-10 max-h-32"
|
|
||||||
alt="Logo"
|
|
||||||
/>
|
|
||||||
<AppDataWarning />
|
<AppDataWarning />
|
||||||
<nav className="relative z-50">
|
<nav className="relative z-50">
|
||||||
<ul
|
<ul
|
||||||
@@ -115,7 +111,7 @@ const Setup: React.FC = () => {
|
|||||||
disabled={!plexSettingsComplete}
|
disabled={!plexSettingsComplete}
|
||||||
onClick={() => setCurrentStep(3)}
|
onClick={() => setCurrentStep(3)}
|
||||||
>
|
>
|
||||||
<FormattedMessage {...messages.continue} />
|
{intl.formatMessage(messages.continue)}
|
||||||
</Button>
|
</Button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -133,11 +129,9 @@ const Setup: React.FC = () => {
|
|||||||
onClick={() => finishSetup()}
|
onClick={() => finishSetup()}
|
||||||
disabled={isUpdating}
|
disabled={isUpdating}
|
||||||
>
|
>
|
||||||
{isUpdating ? (
|
{isUpdating
|
||||||
<FormattedMessage {...messages.finishing} />
|
? intl.formatMessage(messages.finishing)
|
||||||
) : (
|
: intl.formatMessage(messages.finish)}
|
||||||
<FormattedMessage {...messages.finish} />
|
|
||||||
)}
|
|
||||||
</Button>
|
</Button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -8,7 +8,7 @@ import React, {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import { useSpring } from 'react-spring';
|
import { useSpring } from 'react-spring';
|
||||||
import TitleCard from '../TitleCard';
|
import TitleCard from '../TitleCard';
|
||||||
import { defineMessages, FormattedMessage } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
noresults: 'No results.',
|
noresults: 'No results.',
|
||||||
@@ -36,6 +36,7 @@ const Slider: React.FC<SliderProps> = ({
|
|||||||
emptyMessage,
|
emptyMessage,
|
||||||
placeholder = <TitleCard.Placeholder />,
|
placeholder = <TitleCard.Placeholder />,
|
||||||
}) => {
|
}) => {
|
||||||
|
const intl = useIntl();
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const [scrollPos, setScrollPos] = useState({ isStart: true, isEnd: false });
|
const [scrollPos, setScrollPos] = useState({ isStart: true, isEnd: false });
|
||||||
|
|
||||||
@@ -230,11 +231,9 @@ const Slider: React.FC<SliderProps> = ({
|
|||||||
))}
|
))}
|
||||||
{isEmpty && (
|
{isEmpty && (
|
||||||
<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)}
|
||||||
<FormattedMessage {...messages.noresults} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@@ -5,10 +5,10 @@ import Modal from '../Common/Modal';
|
|||||||
import Transition from '../Transition';
|
import Transition from '../Transition';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
newversionavailable: 'New Version Available',
|
newversionavailable: 'Application Update',
|
||||||
newversionDescription:
|
newversionDescription:
|
||||||
'An update is now available. Click the button below to reload the application.',
|
'Overseerr has been updated! Please click the button below to reload the page.',
|
||||||
reloadOverseerr: 'Reload Overseerr',
|
reloadOverseerr: 'Reload',
|
||||||
});
|
});
|
||||||
|
|
||||||
const StatusChecker: React.FC = () => {
|
const StatusChecker: React.FC = () => {
|
||||||
|
@@ -5,22 +5,22 @@ import ListView from '../Common/ListView';
|
|||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { LanguageContext } from '../../context/LanguageContext';
|
import { LanguageContext } from '../../context/LanguageContext';
|
||||||
import Header from '../Common/Header';
|
import Header from '../Common/Header';
|
||||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import { TvDetails } from '../../../server/models/Tv';
|
import { TvDetails } from '../../../server/models/Tv';
|
||||||
import PageTitle from '../Common/PageTitle';
|
import PageTitle from '../Common/PageTitle';
|
||||||
import Error from '../../pages/_error';
|
import Error from '../../pages/_error';
|
||||||
import useDiscover from '../../hooks/useDiscover';
|
import useDiscover from '../../hooks/useDiscover';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
recommendations: 'Recommendations',
|
recommendations: 'Recommendations',
|
||||||
recommendationssubtext: 'If you liked {title}, you might also like…',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const TvRecommendations: React.FC = () => {
|
const TvRecommendations: React.FC = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { locale } = useContext(LanguageContext);
|
const { locale } = useContext(LanguageContext);
|
||||||
const { data: tvData, error: tvError } = useSWR<TvDetails>(
|
const { data: tvData } = useSWR<TvDetails>(
|
||||||
`/api/v1/tv/${router.query.tvId}?language=${locale}`
|
`/api/v1/tv/${router.query.tvId}?language=${locale}`
|
||||||
);
|
);
|
||||||
const {
|
const {
|
||||||
@@ -45,14 +45,12 @@ const TvRecommendations: React.FC = () => {
|
|||||||
<div className="mt-1 mb-5">
|
<div className="mt-1 mb-5">
|
||||||
<Header
|
<Header
|
||||||
subtext={
|
subtext={
|
||||||
tvData && !tvError
|
<Link href={`/tv/${tvData?.id}`}>
|
||||||
? intl.formatMessage(messages.recommendationssubtext, {
|
<a className="hover:underline">{tvData?.name}</a>
|
||||||
title: tvData.name,
|
</Link>
|
||||||
})
|
|
||||||
: ''
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<FormattedMessage {...messages.recommendations} />
|
{intl.formatMessage(messages.recommendations)}
|
||||||
</Header>
|
</Header>
|
||||||
</div>
|
</div>
|
||||||
<ListView
|
<ListView
|
||||||
|
@@ -4,23 +4,23 @@ import type { TvResult } from '../../../server/models/Search';
|
|||||||
import ListView from '../Common/ListView';
|
import ListView from '../Common/ListView';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { LanguageContext } from '../../context/LanguageContext';
|
import { LanguageContext } from '../../context/LanguageContext';
|
||||||
import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
|
import { useIntl, defineMessages } from 'react-intl';
|
||||||
import type { TvDetails } from '../../../server/models/Tv';
|
import type { TvDetails } from '../../../server/models/Tv';
|
||||||
import Header from '../Common/Header';
|
import Header from '../Common/Header';
|
||||||
import PageTitle from '../Common/PageTitle';
|
import PageTitle from '../Common/PageTitle';
|
||||||
import useDiscover from '../../hooks/useDiscover';
|
import useDiscover from '../../hooks/useDiscover';
|
||||||
import Error from '../../pages/_error';
|
import Error from '../../pages/_error';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
similar: 'Similar Series',
|
similar: 'Similar Series',
|
||||||
similarsubtext: 'Other series similar to {title}',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const TvSimilar: React.FC = () => {
|
const TvSimilar: React.FC = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { locale } = useContext(LanguageContext);
|
const { locale } = useContext(LanguageContext);
|
||||||
const { data: tvData, error: tvError } = useSWR<TvDetails>(
|
const { data: tvData } = useSWR<TvDetails>(
|
||||||
`/api/v1/tv/${router.query.tvId}?language=${locale}`
|
`/api/v1/tv/${router.query.tvId}?language=${locale}`
|
||||||
);
|
);
|
||||||
const {
|
const {
|
||||||
@@ -43,14 +43,12 @@ const TvSimilar: React.FC = () => {
|
|||||||
<div className="mt-1 mb-5">
|
<div className="mt-1 mb-5">
|
||||||
<Header
|
<Header
|
||||||
subtext={
|
subtext={
|
||||||
tvData && !tvError
|
<Link href={`/tv/${tvData?.id}`}>
|
||||||
? intl.formatMessage(messages.similarsubtext, {
|
<a className="hover:underline">{tvData?.name}</a>
|
||||||
title: tvData.name,
|
</Link>
|
||||||
})
|
|
||||||
: undefined
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<FormattedMessage {...messages.similar} />
|
{intl.formatMessage(messages.similar)}
|
||||||
</Header>
|
</Header>
|
||||||
</div>
|
</div>
|
||||||
<ListView
|
<ListView
|
||||||
|
@@ -15,10 +15,10 @@ interface BulkEditProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
userssaved: 'Users saved',
|
userssaved: 'User permissions saved successfully!',
|
||||||
save: 'Save Changes',
|
save: 'Save Changes',
|
||||||
saving: 'Saving…',
|
saving: 'Saving…',
|
||||||
userfail: 'Something went wrong while saving the user.',
|
userfail: 'Something went wrong while saving user permissions.',
|
||||||
edituser: 'Edit User Permissions',
|
edituser: 'Edit User Permissions',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -13,8 +13,11 @@ import Badge from '../../../Common/Badge';
|
|||||||
import Button from '../../../Common/Button';
|
import Button from '../../../Common/Button';
|
||||||
import LoadingSpinner from '../../../Common/LoadingSpinner';
|
import LoadingSpinner from '../../../Common/LoadingSpinner';
|
||||||
import RegionSelector from '../../../RegionSelector';
|
import RegionSelector from '../../../RegionSelector';
|
||||||
|
import globalMessages from '../../../../i18n/globalMessages';
|
||||||
|
import PageTitle from '../../../Common/PageTitle';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
general: 'General',
|
||||||
generalsettings: 'General Settings',
|
generalsettings: 'General Settings',
|
||||||
displayName: 'Display Name',
|
displayName: 'Display Name',
|
||||||
save: 'Save Changes',
|
save: 'Save Changes',
|
||||||
@@ -26,14 +29,12 @@ const messages = defineMessages({
|
|||||||
owner: 'Owner',
|
owner: 'Owner',
|
||||||
admin: 'Admin',
|
admin: 'Admin',
|
||||||
user: 'User',
|
user: 'User',
|
||||||
toastSettingsSuccess: 'Settings successfully saved!',
|
toastSettingsSuccess: 'Settings saved successfully!',
|
||||||
toastSettingsFailure: 'Something went wrong while saving settings.',
|
toastSettingsFailure: 'Something went wrong while saving settings.',
|
||||||
region: 'Discover Region',
|
region: 'Discover Region',
|
||||||
regionTip:
|
regionTip: 'Filter content by regional availability',
|
||||||
'Filter content by region (only applies to the "Popular" and "Upcoming" categories)',
|
|
||||||
originallanguage: 'Discover Language',
|
originallanguage: 'Discover Language',
|
||||||
originallanguageTip:
|
originallanguageTip: 'Filter content by original language',
|
||||||
'Filter content by original language (only applies to the "Popular" and "Upcoming" categories)',
|
|
||||||
originalLanguageDefault: 'All Languages',
|
originalLanguageDefault: 'All Languages',
|
||||||
languageServerDefault: 'Default ({language})',
|
languageServerDefault: 'Default ({language})',
|
||||||
});
|
});
|
||||||
@@ -94,6 +95,12 @@ const UserGeneralSettings: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<PageTitle
|
||||||
|
title={[
|
||||||
|
intl.formatMessage(messages.general),
|
||||||
|
intl.formatMessage(globalMessages.usersettings),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h3 className="heading">
|
<h3 className="heading">
|
||||||
{intl.formatMessage(messages.generalsettings)}
|
{intl.formatMessage(messages.generalsettings)}
|
||||||
|
@@ -14,8 +14,10 @@ import * as Yup from 'yup';
|
|||||||
import Badge from '../../../Common/Badge';
|
import Badge from '../../../Common/Badge';
|
||||||
import globalMessages from '../../../../i18n/globalMessages';
|
import globalMessages from '../../../../i18n/globalMessages';
|
||||||
import { PgpLink } from '../../../Settings/Notifications/NotificationsEmail';
|
import { PgpLink } from '../../../Settings/Notifications/NotificationsEmail';
|
||||||
|
import PageTitle from '../../../Common/PageTitle';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
notifications: 'Notifications',
|
||||||
notificationsettings: 'Notification Settings',
|
notificationsettings: 'Notification Settings',
|
||||||
enableNotifications: 'Enable Notifications',
|
enableNotifications: 'Enable Notifications',
|
||||||
discordId: 'Discord User ID',
|
discordId: 'Discord User ID',
|
||||||
@@ -33,7 +35,7 @@ const messages = defineMessages({
|
|||||||
saving: 'Saving…',
|
saving: 'Saving…',
|
||||||
plexuser: 'Plex User',
|
plexuser: 'Plex User',
|
||||||
localuser: 'Local User',
|
localuser: 'Local User',
|
||||||
toastSettingsSuccess: 'Settings successfully saved!',
|
toastSettingsSuccess: 'Notification settings saved successfully!',
|
||||||
toastSettingsFailure: 'Something went wrong while saving settings.',
|
toastSettingsFailure: 'Something went wrong while saving settings.',
|
||||||
pgpKey: '<PgpLink>PGP</PgpLink> Public Key',
|
pgpKey: '<PgpLink>PGP</PgpLink> Public Key',
|
||||||
pgpKeyTip: 'Encrypt email messages',
|
pgpKeyTip: 'Encrypt email messages',
|
||||||
@@ -70,6 +72,13 @@ const UserNotificationSettings: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<PageTitle
|
||||||
|
title={[
|
||||||
|
intl.formatMessage(messages.notifications),
|
||||||
|
intl.formatMessage(globalMessages.usersettings),
|
||||||
|
user?.displayName,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h3 className="heading">
|
<h3 className="heading">
|
||||||
{intl.formatMessage(messages.notificationsettings)}
|
{intl.formatMessage(messages.notificationsettings)}
|
||||||
|
@@ -12,6 +12,8 @@ import Button from '../../../Common/Button';
|
|||||||
import LoadingSpinner from '../../../Common/LoadingSpinner';
|
import LoadingSpinner from '../../../Common/LoadingSpinner';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import useSettings from '../../../../hooks/useSettings';
|
import useSettings from '../../../../hooks/useSettings';
|
||||||
|
import PageTitle from '../../../Common/PageTitle';
|
||||||
|
import globalMessages from '../../../../i18n/globalMessages';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
password: 'Password',
|
password: 'Password',
|
||||||
@@ -20,19 +22,23 @@ const messages = defineMessages({
|
|||||||
confirmpassword: 'Confirm Password',
|
confirmpassword: 'Confirm Password',
|
||||||
save: 'Save Changes',
|
save: 'Save Changes',
|
||||||
saving: 'Saving…',
|
saving: 'Saving…',
|
||||||
toastSettingsSuccess: 'Password changed!',
|
toastSettingsSuccess: 'Password saved successfully!',
|
||||||
toastSettingsFailure:
|
toastSettingsFailure: 'Something went wrong while saving the password.',
|
||||||
'Something went wrong while changing the password. Is your current password correct?',
|
toastSettingsFailureVerifyCurrent:
|
||||||
|
'Something went wrong while saving the password. Was your current password entered correctly?',
|
||||||
validationCurrentPassword: 'You must provide your current password',
|
validationCurrentPassword: 'You must provide your current password',
|
||||||
validationNewPassword: 'You must provide a new password',
|
validationNewPassword: 'You must provide a new password',
|
||||||
validationNewPasswordLength:
|
validationNewPasswordLength:
|
||||||
'Password is too short; should be a minimum of 8 characters',
|
'Password is too short; should be a minimum of 8 characters',
|
||||||
validationConfirmPassword: 'You must confirm your new password',
|
validationConfirmPassword: 'You must confirm the new password',
|
||||||
validationConfirmPasswordSame: 'Password must match',
|
validationConfirmPasswordSame: 'Passwords must match',
|
||||||
nopasswordset: 'No Password Set',
|
nopasswordset: 'No Password Set',
|
||||||
nopasswordsetDescription:
|
nopasswordsetDescription:
|
||||||
'This user account currently does not have a password specifically for {applicationTitle}.\
|
'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."',
|
Configure a password below to enable this account to sign in as a "local user."',
|
||||||
|
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.',
|
||||||
nopermission: 'Unauthorized',
|
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.",
|
||||||
@@ -95,6 +101,13 @@ const UserPasswordChange: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<PageTitle
|
||||||
|
title={[
|
||||||
|
intl.formatMessage(messages.password),
|
||||||
|
intl.formatMessage(globalMessages.usersettings),
|
||||||
|
user?.displayName,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<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>
|
||||||
@@ -119,10 +132,17 @@ const UserPasswordChange: React.FC = () => {
|
|||||||
appearance: 'success',
|
appearance: 'success',
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
addToast(intl.formatMessage(messages.toastSettingsFailure), {
|
addToast(
|
||||||
autoDismiss: true,
|
intl.formatMessage(
|
||||||
appearance: 'error',
|
data.hasPassword && user?.id === currentUser?.id
|
||||||
});
|
? messages.toastSettingsFailureVerifyCurrent
|
||||||
|
: messages.toastSettingsFailure
|
||||||
|
),
|
||||||
|
{
|
||||||
|
autoDismiss: true,
|
||||||
|
appearance: 'error',
|
||||||
|
}
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
revalidate();
|
revalidate();
|
||||||
resetForm();
|
resetForm();
|
||||||
@@ -137,9 +157,15 @@ const UserPasswordChange: React.FC = () => {
|
|||||||
type="warning"
|
type="warning"
|
||||||
title={intl.formatMessage(messages.nopasswordset)}
|
title={intl.formatMessage(messages.nopasswordset)}
|
||||||
>
|
>
|
||||||
{intl.formatMessage(messages.nopasswordsetDescription, {
|
{intl.formatMessage(
|
||||||
applicationTitle: settings.currentSettings.applicationTitle,
|
user?.id === currentUser?.id
|
||||||
})}
|
? messages.nopasswordsetDescriptionOwnAccount
|
||||||
|
: messages.nopasswordsetDescription,
|
||||||
|
{
|
||||||
|
applicationTitle:
|
||||||
|
settings.currentSettings.applicationTitle,
|
||||||
|
}
|
||||||
|
)}
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
{data.hasPassword && user?.id === currentUser?.id && (
|
{data.hasPassword && user?.id === currentUser?.id && (
|
||||||
|
@@ -11,6 +11,8 @@ import Button from '../../../Common/Button';
|
|||||||
import LoadingSpinner from '../../../Common/LoadingSpinner';
|
import LoadingSpinner from '../../../Common/LoadingSpinner';
|
||||||
import PermissionEdit from '../../../PermissionEdit';
|
import PermissionEdit from '../../../PermissionEdit';
|
||||||
import Alert from '../../../Common/Alert';
|
import Alert from '../../../Common/Alert';
|
||||||
|
import PageTitle from '../../../Common/PageTitle';
|
||||||
|
import globalMessages from '../../../../i18n/globalMessages';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
displayName: 'Display Name',
|
displayName: 'Display Name',
|
||||||
@@ -18,7 +20,7 @@ const messages = defineMessages({
|
|||||||
saving: 'Saving…',
|
saving: 'Saving…',
|
||||||
plexuser: 'Plex User',
|
plexuser: 'Plex User',
|
||||||
localuser: 'Local User',
|
localuser: 'Local User',
|
||||||
toastSettingsSuccess: 'Settings successfully saved!',
|
toastSettingsSuccess: 'Permissions saved successfully!',
|
||||||
toastSettingsFailure: 'Something went wrong while saving settings.',
|
toastSettingsFailure: 'Something went wrong while saving settings.',
|
||||||
permissions: 'Permissions',
|
permissions: 'Permissions',
|
||||||
unauthorized: 'Unauthorized',
|
unauthorized: 'Unauthorized',
|
||||||
@@ -60,6 +62,13 @@ const UserPermissions: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<PageTitle
|
||||||
|
title={[
|
||||||
|
intl.formatMessage(messages.permissions),
|
||||||
|
intl.formatMessage(globalMessages.usersettings),
|
||||||
|
user?.displayName,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h3 className="heading">{intl.formatMessage(messages.permissions)}</h3>
|
<h3 className="heading">{intl.formatMessage(messages.permissions)}</h3>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -10,10 +10,10 @@ import PageTitle from '../../Common/PageTitle';
|
|||||||
import ProfileHeader from '../ProfileHeader';
|
import ProfileHeader from '../ProfileHeader';
|
||||||
import useSettings from '../../../hooks/useSettings';
|
import useSettings from '../../../hooks/useSettings';
|
||||||
import Alert from '../../Common/Alert';
|
import Alert from '../../Common/Alert';
|
||||||
|
import globalMessages from '../../../i18n/globalMessages';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
settings: 'User Settings',
|
menuGeneralSettings: 'General',
|
||||||
menuGeneralSettings: 'General Settings',
|
|
||||||
menuChangePass: 'Password',
|
menuChangePass: 'Password',
|
||||||
menuNotifications: 'Notifications',
|
menuNotifications: 'Notifications',
|
||||||
menuPermissions: 'Permissions',
|
menuPermissions: 'Permissions',
|
||||||
@@ -115,7 +115,12 @@ const UserSettings: React.FC = ({ children }) => {
|
|||||||
if (currentUser?.id !== 1 && user.id === 1) {
|
if (currentUser?.id !== 1 && user.id === 1) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageTitle title={intl.formatMessage(messages.settings)} />
|
<PageTitle
|
||||||
|
title={[
|
||||||
|
intl.formatMessage(globalMessages.usersettings),
|
||||||
|
user.displayName,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<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(messages.unauthorized)} type="error">
|
||||||
@@ -136,7 +141,12 @@ const UserSettings: React.FC = ({ children }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageTitle title={intl.formatMessage(messages.settings)} />
|
<PageTitle
|
||||||
|
title={[
|
||||||
|
intl.formatMessage(globalMessages.usersettings),
|
||||||
|
user.displayName,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<ProfileHeader user={user} isSettingsPage />
|
<ProfileHeader user={user} isSettingsPage />
|
||||||
<div className="mt-6">
|
<div className="mt-6">
|
||||||
<div className="sm:hidden">
|
<div className="sm:hidden">
|
||||||
|
@@ -24,6 +24,8 @@ const globalMessages = defineMessages({
|
|||||||
experimental: 'Experimental',
|
experimental: 'Experimental',
|
||||||
advanced: 'Advanced',
|
advanced: 'Advanced',
|
||||||
loading: 'Loading…',
|
loading: 'Loading…',
|
||||||
|
settings: 'Settings',
|
||||||
|
usersettings: 'User Settings',
|
||||||
});
|
});
|
||||||
|
|
||||||
export default globalMessages;
|
export default globalMessages;
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
"components.CollectionDetails.overviewunavailable": "Overview unavailable.",
|
"components.CollectionDetails.overviewunavailable": "Overview unavailable.",
|
||||||
"components.CollectionDetails.request": "Request",
|
"components.CollectionDetails.request": "Request",
|
||||||
"components.CollectionDetails.request4k": "Request 4K",
|
"components.CollectionDetails.request4k": "Request 4K",
|
||||||
"components.CollectionDetails.requestSuccess": "<strong>{title}</strong> successfully requested!",
|
"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.requesting": "Requesting…",
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
"components.Layout.UserDropdown.myprofile": "Profile",
|
"components.Layout.UserDropdown.myprofile": "Profile",
|
||||||
"components.Layout.UserDropdown.settings": "Settings",
|
"components.Layout.UserDropdown.settings": "Settings",
|
||||||
"components.Layout.UserDropdown.signout": "Sign Out",
|
"components.Layout.UserDropdown.signout": "Sign Out",
|
||||||
"components.Layout.alphawarning": "This is ALPHA software. Features may be broken and/or unstable. Please report issues on GitHub!",
|
"components.Layout.alphawarning": "This is ALPHA software. Features may be broken and/or unstable. Please report any issues on GitHub!",
|
||||||
"components.Login.email": "Email Address",
|
"components.Login.email": "Email Address",
|
||||||
"components.Login.forgotpassword": "Forgot Password?",
|
"components.Login.forgotpassword": "Forgot Password?",
|
||||||
"components.Login.loginerror": "Something went wrong while trying to sign in.",
|
"components.Login.loginerror": "Something went wrong while trying to sign in.",
|
||||||
@@ -86,12 +86,10 @@
|
|||||||
"components.MovieDetails.play4konplex": "Play 4K on Plex",
|
"components.MovieDetails.play4konplex": "Play 4K on Plex",
|
||||||
"components.MovieDetails.playonplex": "Play on Plex",
|
"components.MovieDetails.playonplex": "Play on Plex",
|
||||||
"components.MovieDetails.recommendations": "Recommendations",
|
"components.MovieDetails.recommendations": "Recommendations",
|
||||||
"components.MovieDetails.recommendationssubtext": "If you liked {title}, you might also like…",
|
|
||||||
"components.MovieDetails.releasedate": "Release Date",
|
"components.MovieDetails.releasedate": "Release Date",
|
||||||
"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.similarsubtext": "Other movies similar to {title}",
|
|
||||||
"components.MovieDetails.status": "Status",
|
"components.MovieDetails.status": "Status",
|
||||||
"components.MovieDetails.studio": "{studioCount, plural, one {Studio} other {Studios}}",
|
"components.MovieDetails.studio": "{studioCount, plural, one {Studio} other {Studios}}",
|
||||||
"components.MovieDetails.unavailable": "Unavailable",
|
"components.MovieDetails.unavailable": "Unavailable",
|
||||||
@@ -212,7 +210,7 @@
|
|||||||
"components.RequestModal.SearchByNameModal.next": "Next",
|
"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.backbutton": "Back",
|
||||||
@@ -222,7 +220,6 @@
|
|||||||
"components.RequestModal.close": "Close",
|
"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.next": "Next",
|
|
||||||
"components.RequestModal.notrequested": "Not Requested",
|
"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",
|
||||||
@@ -238,7 +235,7 @@
|
|||||||
"components.RequestModal.requestcancelled": "Request canceled.",
|
"components.RequestModal.requestcancelled": "Request canceled.",
|
||||||
"components.RequestModal.requestedited": "Request edited.",
|
"components.RequestModal.requestedited": "Request edited.",
|
||||||
"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.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}",
|
||||||
@@ -248,15 +245,15 @@
|
|||||||
"components.RequestModal.status": "Status",
|
"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 Me a Recovery Link",
|
"components.ResetPassword.emailresetlink": "Email a Recovery Link",
|
||||||
"components.ResetPassword.forgotpassword": "Reset your password",
|
"components.ResetPassword.gobacklogin": "Return to Sign-In Page",
|
||||||
"components.ResetPassword.gobacklogin": "Go Back to Sign-In Page",
|
|
||||||
"components.ResetPassword.password": "Password",
|
"components.ResetPassword.password": "Password",
|
||||||
|
"components.ResetPassword.passwordreset": "Password Reset",
|
||||||
"components.ResetPassword.requestresetlinksuccessmessage": "A password reset link will be sent to the provided email address if it is associated with a valid user.",
|
"components.ResetPassword.requestresetlinksuccessmessage": "A password reset link will be sent to the provided email address if it is associated with a valid user.",
|
||||||
"components.ResetPassword.resetpassword": "Reset your password",
|
"components.ResetPassword.resetpassword": "Reset your password",
|
||||||
"components.ResetPassword.resetpasswordsuccessmessage": "Password successfully reset, if the link was valid and associated with an existing user.",
|
"components.ResetPassword.resetpasswordsuccessmessage": "Password reset successfully!",
|
||||||
"components.ResetPassword.validationemailrequired": "You must provide a valid email address",
|
"components.ResetPassword.validationemailrequired": "You must provide a valid email address",
|
||||||
"components.ResetPassword.validationpasswordmatch": "Password must match",
|
"components.ResetPassword.validationpasswordmatch": "Passwords must match",
|
||||||
"components.ResetPassword.validationpasswordminchars": "Password is too short; should be a minimum of 8 characters",
|
"components.ResetPassword.validationpasswordminchars": "Password is too short; should be a minimum of 8 characters",
|
||||||
"components.ResetPassword.validationpasswordrequired": "You must provide a password",
|
"components.ResetPassword.validationpasswordrequired": "You must provide a password",
|
||||||
"components.Search.search": "Search",
|
"components.Search.search": "Search",
|
||||||
@@ -354,8 +351,8 @@
|
|||||||
"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",
|
||||||
"components.Settings.Notifications.validationEmail": "You must provide a valid email address",
|
"components.Settings.Notifications.validationEmail": "You must provide a valid email address",
|
||||||
"components.Settings.Notifications.validationSmtpHostRequired": "You must provide an SMTP host",
|
"components.Settings.Notifications.validationSmtpHostRequired": "You must provide a hostname or IP address",
|
||||||
"components.Settings.Notifications.validationSmtpPortRequired": "You must provide an SMTP port",
|
"components.Settings.Notifications.validationSmtpPortRequired": "You must provide a valid port number",
|
||||||
"components.Settings.Notifications.validationUrl": "You must provide a valid URL",
|
"components.Settings.Notifications.validationUrl": "You must provide a valid URL",
|
||||||
"components.Settings.Notifications.webhookUrl": "Webhook URL",
|
"components.Settings.Notifications.webhookUrl": "Webhook URL",
|
||||||
"components.Settings.Notifications.webhookUrlPlaceholder": "Server Settings → Integrations → Webhooks",
|
"components.Settings.Notifications.webhookUrlPlaceholder": "Server Settings → Integrations → Webhooks",
|
||||||
@@ -369,7 +366,7 @@
|
|||||||
"components.Settings.RadarrModal.editradarr": "Edit Radarr Server",
|
"components.Settings.RadarrModal.editradarr": "Edit Radarr Server",
|
||||||
"components.Settings.RadarrModal.externalUrl": "External URL",
|
"components.Settings.RadarrModal.externalUrl": "External URL",
|
||||||
"components.Settings.RadarrModal.externalUrlPlaceholder": "External URL pointing to your Radarr server",
|
"components.Settings.RadarrModal.externalUrlPlaceholder": "External URL pointing to your Radarr server",
|
||||||
"components.Settings.RadarrModal.hostname": "Hostname",
|
"components.Settings.RadarrModal.hostname": "Hostname or IP Address",
|
||||||
"components.Settings.RadarrModal.loadingprofiles": "Loading quality profiles…",
|
"components.Settings.RadarrModal.loadingprofiles": "Loading quality profiles…",
|
||||||
"components.Settings.RadarrModal.loadingrootfolders": "Loading root folders…",
|
"components.Settings.RadarrModal.loadingrootfolders": "Loading root folders…",
|
||||||
"components.Settings.RadarrModal.minimumAvailability": "Minimum Availability",
|
"components.Settings.RadarrModal.minimumAvailability": "Minimum Availability",
|
||||||
@@ -392,28 +389,28 @@
|
|||||||
"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.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!",
|
"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",
|
||||||
"components.Settings.RadarrModal.validationApplicationUrl": "You must provide a valid URL",
|
"components.Settings.RadarrModal.validationApplicationUrl": "You must provide a valid URL",
|
||||||
"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash",
|
"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash",
|
||||||
"components.Settings.RadarrModal.validationBaseUrlLeadingSlash": "Base URL must have a leading slash",
|
"components.Settings.RadarrModal.validationBaseUrlLeadingSlash": "Base URL must have a leading slash",
|
||||||
"components.Settings.RadarrModal.validationBaseUrlTrailingSlash": "Base URL must not end in a trailing slash",
|
"components.Settings.RadarrModal.validationBaseUrlTrailingSlash": "Base URL must not end in a trailing slash",
|
||||||
"components.Settings.RadarrModal.validationHostnameRequired": "You must provide a hostname/IP",
|
"components.Settings.RadarrModal.validationHostnameRequired": "You must provide a hostname or IP address",
|
||||||
"components.Settings.RadarrModal.validationMinimumAvailabilityRequired": "You must select a minimum availability",
|
"components.Settings.RadarrModal.validationMinimumAvailabilityRequired": "You must select a minimum availability",
|
||||||
"components.Settings.RadarrModal.validationNameRequired": "You must provide a server name",
|
"components.Settings.RadarrModal.validationNameRequired": "You must provide a server name",
|
||||||
"components.Settings.RadarrModal.validationPortRequired": "You must provide a port",
|
"components.Settings.RadarrModal.validationPortRequired": "You must provide a valid port number",
|
||||||
"components.Settings.RadarrModal.validationProfileRequired": "You must select a quality profile",
|
"components.Settings.RadarrModal.validationProfileRequired": "You must select a quality profile",
|
||||||
"components.Settings.RadarrModal.validationRootFolderRequired": "You must select a root folder",
|
"components.Settings.RadarrModal.validationRootFolderRequired": "You must select a root folder",
|
||||||
"components.Settings.SettingsAbout.Releases.currentversion": "Current Version",
|
"components.Settings.SettingsAbout.Releases.currentversion": "Current Version",
|
||||||
"components.Settings.SettingsAbout.Releases.latestversion": "Latest",
|
"components.Settings.SettingsAbout.Releases.latestversion": "Latest",
|
||||||
"components.Settings.SettingsAbout.Releases.releasedataMissing": "Release data unavailable. Is GitHub down?",
|
"components.Settings.SettingsAbout.Releases.releasedataMissing": "Release data unavailable. Is GitHub down?",
|
||||||
"components.Settings.SettingsAbout.Releases.releases": "Releases",
|
"components.Settings.SettingsAbout.Releases.releases": "Releases",
|
||||||
"components.Settings.SettingsAbout.Releases.runningDevelop": "You are running a develop version of Overseerr!",
|
"components.Settings.SettingsAbout.Releases.runningDevelop": "Development Version",
|
||||||
"components.Settings.SettingsAbout.Releases.runningDevelopMessage": "The changes in your version will not be available below. Please see the <GithubLink>GitHub repository</GithubLink> for latest updates.",
|
"components.Settings.SettingsAbout.Releases.runningDevelopMessage": "The latest changes to the <code>develop</code> branch of Overseerr are not shown below. Please see the commit history for this branch on <GithubLink>GitHub</GithubLink> for details.",
|
||||||
"components.Settings.SettingsAbout.Releases.versionChangelog": "Version Changelog",
|
"components.Settings.SettingsAbout.Releases.versionChangelog": "Version Changelog",
|
||||||
"components.Settings.SettingsAbout.Releases.viewchangelog": "View Changelog",
|
"components.Settings.SettingsAbout.Releases.viewchangelog": "View Changelog",
|
||||||
"components.Settings.SettingsAbout.Releases.viewongithub": "View on GitHub",
|
"components.Settings.SettingsAbout.Releases.viewongithub": "View on GitHub",
|
||||||
"components.Settings.SettingsAbout.clickheretojoindiscord": "Click here to join our Discord server!",
|
"components.Settings.SettingsAbout.about": "About",
|
||||||
"components.Settings.SettingsAbout.documentation": "Documentation",
|
"components.Settings.SettingsAbout.documentation": "Documentation",
|
||||||
"components.Settings.SettingsAbout.gettingsupport": "Getting Support",
|
"components.Settings.SettingsAbout.gettingsupport": "Getting Support",
|
||||||
"components.Settings.SettingsAbout.githubdiscussions": "GitHub Discussions",
|
"components.Settings.SettingsAbout.githubdiscussions": "GitHub Discussions",
|
||||||
@@ -421,7 +418,7 @@
|
|||||||
"components.Settings.SettingsAbout.overseerrinformation": "Overseerr Information",
|
"components.Settings.SettingsAbout.overseerrinformation": "Overseerr Information",
|
||||||
"components.Settings.SettingsAbout.preferredmethod": "Preferred",
|
"components.Settings.SettingsAbout.preferredmethod": "Preferred",
|
||||||
"components.Settings.SettingsAbout.supportoverseerr": "Support Overseerr",
|
"components.Settings.SettingsAbout.supportoverseerr": "Support Overseerr",
|
||||||
"components.Settings.SettingsAbout.timezone": "Timezone",
|
"components.Settings.SettingsAbout.timezone": "Time Zone",
|
||||||
"components.Settings.SettingsAbout.totalmedia": "Total Media",
|
"components.Settings.SettingsAbout.totalmedia": "Total Media",
|
||||||
"components.Settings.SettingsAbout.totalrequests": "Total Requests",
|
"components.Settings.SettingsAbout.totalrequests": "Total Requests",
|
||||||
"components.Settings.SettingsAbout.version": "Version",
|
"components.Settings.SettingsAbout.version": "Version",
|
||||||
@@ -443,6 +440,7 @@
|
|||||||
"components.Settings.SettingsJobsCache.jobname": "Job Name",
|
"components.Settings.SettingsJobsCache.jobname": "Job Name",
|
||||||
"components.Settings.SettingsJobsCache.jobs": "Jobs",
|
"components.Settings.SettingsJobsCache.jobs": "Jobs",
|
||||||
"components.Settings.SettingsJobsCache.jobsDescription": "Overseerr performs certain maintenance tasks as regularly-scheduled jobs, but they can also be manually triggered below. Manually running a job will not alter its schedule.",
|
"components.Settings.SettingsJobsCache.jobsDescription": "Overseerr performs certain maintenance tasks as regularly-scheduled jobs, but they can also be manually triggered below. Manually running a job will not alter its schedule.",
|
||||||
|
"components.Settings.SettingsJobsCache.jobsandcache": "Jobs & Cache",
|
||||||
"components.Settings.SettingsJobsCache.jobstarted": "{jobname} started.",
|
"components.Settings.SettingsJobsCache.jobstarted": "{jobname} started.",
|
||||||
"components.Settings.SettingsJobsCache.jobtype": "Type",
|
"components.Settings.SettingsJobsCache.jobtype": "Type",
|
||||||
"components.Settings.SettingsJobsCache.nextexecution": "Next Execution",
|
"components.Settings.SettingsJobsCache.nextexecution": "Next Execution",
|
||||||
@@ -476,9 +474,10 @@
|
|||||||
"components.Settings.SettingsUsers.save": "Save Changes",
|
"components.Settings.SettingsUsers.save": "Save Changes",
|
||||||
"components.Settings.SettingsUsers.saving": "Saving…",
|
"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": "Settings successfully saved!",
|
"components.Settings.SettingsUsers.toastSettingsSuccess": "User settings saved successfully!",
|
||||||
"components.Settings.SettingsUsers.userSettings": "Users",
|
"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.",
|
||||||
|
"components.Settings.SettingsUsers.users": "Users",
|
||||||
"components.Settings.SonarrModal.add": "Add Server",
|
"components.Settings.SonarrModal.add": "Add Server",
|
||||||
"components.Settings.SonarrModal.animelanguageprofile": "Anime Language Profile",
|
"components.Settings.SonarrModal.animelanguageprofile": "Anime Language Profile",
|
||||||
"components.Settings.SonarrModal.animequalityprofile": "Anime Quality Profile",
|
"components.Settings.SonarrModal.animequalityprofile": "Anime Quality Profile",
|
||||||
@@ -492,7 +491,7 @@
|
|||||||
"components.Settings.SonarrModal.editsonarr": "Edit Sonarr Server",
|
"components.Settings.SonarrModal.editsonarr": "Edit Sonarr Server",
|
||||||
"components.Settings.SonarrModal.externalUrl": "External URL",
|
"components.Settings.SonarrModal.externalUrl": "External URL",
|
||||||
"components.Settings.SonarrModal.externalUrlPlaceholder": "External URL pointing to your Sonarr server",
|
"components.Settings.SonarrModal.externalUrlPlaceholder": "External URL pointing to your Sonarr server",
|
||||||
"components.Settings.SonarrModal.hostname": "Hostname",
|
"components.Settings.SonarrModal.hostname": "Hostname or IP Address",
|
||||||
"components.Settings.SonarrModal.languageprofile": "Language Profile",
|
"components.Settings.SonarrModal.languageprofile": "Language Profile",
|
||||||
"components.Settings.SonarrModal.loadinglanguageprofiles": "Loading language profiles…",
|
"components.Settings.SonarrModal.loadinglanguageprofiles": "Loading language profiles…",
|
||||||
"components.Settings.SonarrModal.loadingprofiles": "Loading quality profiles…",
|
"components.Settings.SonarrModal.loadingprofiles": "Loading quality profiles…",
|
||||||
@@ -518,16 +517,16 @@
|
|||||||
"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.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!",
|
"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",
|
||||||
"components.Settings.SonarrModal.validationApplicationUrl": "You must provide a valid URL",
|
"components.Settings.SonarrModal.validationApplicationUrl": "You must provide a valid URL",
|
||||||
"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash",
|
"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash",
|
||||||
"components.Settings.SonarrModal.validationBaseUrlLeadingSlash": "Base URL must have a leading slash",
|
"components.Settings.SonarrModal.validationBaseUrlLeadingSlash": "Base URL must have a leading slash",
|
||||||
"components.Settings.SonarrModal.validationBaseUrlTrailingSlash": "Base URL must not end in a trailing slash",
|
"components.Settings.SonarrModal.validationBaseUrlTrailingSlash": "Base URL must not end in a trailing slash",
|
||||||
"components.Settings.SonarrModal.validationHostnameRequired": "You must provide a hostname/IP",
|
"components.Settings.SonarrModal.validationHostnameRequired": "You must provide a hostname or IP address",
|
||||||
"components.Settings.SonarrModal.validationLanguageProfileRequired": "You must select a language profile",
|
"components.Settings.SonarrModal.validationLanguageProfileRequired": "You must select a language profile",
|
||||||
"components.Settings.SonarrModal.validationNameRequired": "You must provide a server name",
|
"components.Settings.SonarrModal.validationNameRequired": "You must provide a server name",
|
||||||
"components.Settings.SonarrModal.validationPortRequired": "You must provide a port",
|
"components.Settings.SonarrModal.validationPortRequired": "You must provide a valid port number",
|
||||||
"components.Settings.SonarrModal.validationProfileRequired": "You must select a quality profile",
|
"components.Settings.SonarrModal.validationProfileRequired": "You must select a quality profile",
|
||||||
"components.Settings.SonarrModal.validationRootFolderRequired": "You must select a root folder",
|
"components.Settings.SonarrModal.validationRootFolderRequired": "You must select a root folder",
|
||||||
"components.Settings.activeProfile": "Active Profile",
|
"components.Settings.activeProfile": "Active Profile",
|
||||||
@@ -540,8 +539,8 @@
|
|||||||
"components.Settings.cancelscan": "Cancel Scan",
|
"components.Settings.cancelscan": "Cancel Scan",
|
||||||
"components.Settings.copied": "Copied API key to clipboard.",
|
"components.Settings.copied": "Copied API key to clipboard.",
|
||||||
"components.Settings.csrfProtection": "Enable CSRF Protection",
|
"components.Settings.csrfProtection": "Enable CSRF Protection",
|
||||||
"components.Settings.csrfProtectionHoverTip": "Do NOT enable this unless you understand what you are doing!",
|
"components.Settings.csrfProtectionHoverTip": "Do NOT enable this setting unless you understand what you are doing!",
|
||||||
"components.Settings.csrfProtectionTip": "Sets external API access to read-only (requires HTTPS and Overseerr must be reloaded for changes to take effect)",
|
"components.Settings.csrfProtectionTip": "Sets external API access to read-only (requires HTTPS, and Overseerr must be reloaded for changes to take effect)",
|
||||||
"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",
|
||||||
@@ -550,15 +549,16 @@
|
|||||||
"components.Settings.edit": "Edit",
|
"components.Settings.edit": "Edit",
|
||||||
"components.Settings.email": "Email",
|
"components.Settings.email": "Email",
|
||||||
"components.Settings.enablenotifications": "Enable Notifications",
|
"components.Settings.enablenotifications": "Enable Notifications",
|
||||||
|
"components.Settings.general": "General",
|
||||||
"components.Settings.generalsettings": "General Settings",
|
"components.Settings.generalsettings": "General Settings",
|
||||||
"components.Settings.generalsettingsDescription": "Configure global and default settings for Overseerr.",
|
"components.Settings.generalsettingsDescription": "Configure global and default settings for Overseerr.",
|
||||||
"components.Settings.hideAvailable": "Hide Available Media",
|
"components.Settings.hideAvailable": "Hide Available Media",
|
||||||
"components.Settings.hostname": "Hostname/IP",
|
"components.Settings.hostname": "Hostname or IP Address",
|
||||||
"components.Settings.librariesRemaining": "Libraries Remaining: {count}",
|
"components.Settings.librariesRemaining": "Libraries Remaining: {count}",
|
||||||
"components.Settings.manualscan": "Manual Library Scan",
|
"components.Settings.manualscan": "Manual Library Scan",
|
||||||
"components.Settings.manualscanDescription": "Normally, this will only be run once every 24 hours. Overseerr will check your Plex server's recently added more aggressively. If this is your first time configuring Plex, a one-time full manual library scan is recommended!",
|
"components.Settings.manualscanDescription": "Normally, this will only be run once every 24 hours. Overseerr will check your Plex server's recently added more aggressively. If this is your first time configuring Plex, a one-time full manual library scan is recommended!",
|
||||||
"components.Settings.menuAbout": "About",
|
"components.Settings.menuAbout": "About",
|
||||||
"components.Settings.menuGeneralSettings": "General Settings",
|
"components.Settings.menuGeneralSettings": "General",
|
||||||
"components.Settings.menuJobs": "Jobs & Cache",
|
"components.Settings.menuJobs": "Jobs & Cache",
|
||||||
"components.Settings.menuLogs": "Logs",
|
"components.Settings.menuLogs": "Logs",
|
||||||
"components.Settings.menuNotifications": "Notifications",
|
"components.Settings.menuNotifications": "Notifications",
|
||||||
@@ -569,6 +569,7 @@
|
|||||||
"components.Settings.nodefaultdescription": "At least one server must be marked as default before any requests will make it to your services.",
|
"components.Settings.nodefaultdescription": "At least one server must be marked as default before any requests will make it to your services.",
|
||||||
"components.Settings.notificationAgentSettingsDescription": "Choose the types of notifications to send, and which notification agents to use.",
|
"components.Settings.notificationAgentSettingsDescription": "Choose the types of notifications to send, and which notification agents to use.",
|
||||||
"components.Settings.notificationAgentsSettings": "Notification Agents",
|
"components.Settings.notificationAgentsSettings": "Notification Agents",
|
||||||
|
"components.Settings.notifications": "Notifications",
|
||||||
"components.Settings.notificationsettings": "Notification Settings",
|
"components.Settings.notificationsettings": "Notification Settings",
|
||||||
"components.Settings.notificationsettingsDescription": "Configure global notification settings. The options below will apply to all notification agents.",
|
"components.Settings.notificationsettingsDescription": "Configure global notification settings. The options below will apply to all notification agents.",
|
||||||
"components.Settings.notificationsettingsfailed": "Notification settings failed to save.",
|
"components.Settings.notificationsettingsfailed": "Notification settings failed to save.",
|
||||||
@@ -576,8 +577,9 @@
|
|||||||
"components.Settings.notrunning": "Not Running",
|
"components.Settings.notrunning": "Not Running",
|
||||||
"components.Settings.originalLanguageDefault": "All Languages",
|
"components.Settings.originalLanguageDefault": "All Languages",
|
||||||
"components.Settings.originallanguage": "Discover Language",
|
"components.Settings.originallanguage": "Discover Language",
|
||||||
"components.Settings.originallanguageTip": "Filter content by original language (only applies to the \"Popular\" and \"Upcoming\" categories)",
|
"components.Settings.originallanguageTip": "Filter content by original language",
|
||||||
"components.Settings.partialRequestsEnabled": "Enable Partial Series Requests",
|
"components.Settings.partialRequestsEnabled": "Allow Partial Series Requests",
|
||||||
|
"components.Settings.plex": "Plex",
|
||||||
"components.Settings.plexlibraries": "Plex Libraries",
|
"components.Settings.plexlibraries": "Plex Libraries",
|
||||||
"components.Settings.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.",
|
"components.Settings.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.",
|
||||||
"components.Settings.plexsettings": "Plex Settings",
|
"components.Settings.plexsettings": "Plex Settings",
|
||||||
@@ -586,7 +588,7 @@
|
|||||||
"components.Settings.radarrSettingsDescription": "Configure your Radarr connection below. You can have multiple Radarr 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.",
|
"components.Settings.radarrSettingsDescription": "Configure your Radarr connection below. You can have multiple Radarr 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.",
|
||||||
"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 region (only applies to the \"Popular\" and \"Upcoming\" categories)",
|
"components.Settings.regionTip": "Filter content by regional availability",
|
||||||
"components.Settings.save": "Save Changes",
|
"components.Settings.save": "Save Changes",
|
||||||
"components.Settings.saving": "Saving…",
|
"components.Settings.saving": "Saving…",
|
||||||
"components.Settings.scan": "Scan Plex Libraries",
|
"components.Settings.scan": "Scan Plex Libraries",
|
||||||
@@ -602,31 +604,31 @@
|
|||||||
"components.Settings.serverpresetManualMessage": "Manual configuration",
|
"components.Settings.serverpresetManualMessage": "Manual configuration",
|
||||||
"components.Settings.serverpresetPlaceholder": "Plex Server",
|
"components.Settings.serverpresetPlaceholder": "Plex Server",
|
||||||
"components.Settings.serverpresetRefreshing": "Retrieving servers…",
|
"components.Settings.serverpresetRefreshing": "Retrieving servers…",
|
||||||
|
"components.Settings.services": "Services",
|
||||||
"components.Settings.settingUpPlex": "Setting Up Plex",
|
"components.Settings.settingUpPlex": "Setting Up Plex",
|
||||||
"components.Settings.settingUpPlexDescription": "To set up Plex, you can either enter your details manually or select a server retrieved from <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Press the button to the right of the dropdown to check connectivity and retrieve available servers.",
|
"components.Settings.settingUpPlexDescription": "To set up Plex, you can either enter your details manually or select a server retrieved from <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Press the button to the right of the dropdown to check connectivity and retrieve available servers.",
|
||||||
"components.Settings.settings": "Settings",
|
|
||||||
"components.Settings.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.",
|
"components.Settings.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.",
|
||||||
"components.Settings.sonarrsettings": "Sonarr Settings",
|
"components.Settings.sonarrsettings": "Sonarr Settings",
|
||||||
"components.Settings.ssl": "SSL",
|
"components.Settings.ssl": "SSL",
|
||||||
"components.Settings.startscan": "Start Scan",
|
"components.Settings.startscan": "Start Scan",
|
||||||
"components.Settings.timeout": "Timeout",
|
"components.Settings.timeout": "Timeout",
|
||||||
"components.Settings.toastApiKeyFailure": "Something went wrong while generating a new API key.",
|
"components.Settings.toastApiKeyFailure": "Something went wrong while generating a new API key.",
|
||||||
"components.Settings.toastApiKeySuccess": "New API key generated!",
|
"components.Settings.toastApiKeySuccess": "New API key generated successfully!",
|
||||||
"components.Settings.toastPlexConnecting": "Attempting to connect to Plex…",
|
"components.Settings.toastPlexConnecting": "Attempting to connect to Plex…",
|
||||||
"components.Settings.toastPlexConnectingFailure": "Unable to connect to Plex!",
|
"components.Settings.toastPlexConnectingFailure": "Failed to connect to Plex.",
|
||||||
"components.Settings.toastPlexConnectingSuccess": "Connected to Plex server.",
|
"components.Settings.toastPlexConnectingSuccess": "Plex connection established successfully!",
|
||||||
"components.Settings.toastPlexRefresh": "Retrieving server list from Plex…",
|
"components.Settings.toastPlexRefresh": "Retrieving server list from Plex…",
|
||||||
"components.Settings.toastPlexRefreshFailure": "Unable to retrieve Plex server list!",
|
"components.Settings.toastPlexRefreshFailure": "Failed to retrieve Plex server list.",
|
||||||
"components.Settings.toastPlexRefreshSuccess": "Retrieved Plex server list.",
|
"components.Settings.toastPlexRefreshSuccess": "Plex server list retrieved successfully!",
|
||||||
"components.Settings.toastSettingsFailure": "Something went wrong while saving settings.",
|
"components.Settings.toastSettingsFailure": "Something went wrong while saving settings.",
|
||||||
"components.Settings.toastSettingsSuccess": "Settings successfully saved!",
|
"components.Settings.toastSettingsSuccess": "Settings saved successfully!",
|
||||||
"components.Settings.trustProxy": "Enable Proxy Support",
|
"components.Settings.trustProxy": "Enable Proxy Support",
|
||||||
"components.Settings.trustProxyTip": "Allows Overseerr to correctly register client IP addresses behind a proxy (Overseerr must be reloaded for changes to take effect)",
|
"components.Settings.trustProxyTip": "Allows Overseerr to correctly register client IP addresses behind a proxy (Overseerr must be reloaded for changes to take effect)",
|
||||||
"components.Settings.validationApplicationTitle": "You must provide an application title",
|
"components.Settings.validationApplicationTitle": "You must provide an application title",
|
||||||
"components.Settings.validationApplicationUrl": "You must provide a valid URL",
|
"components.Settings.validationApplicationUrl": "You must provide a valid URL",
|
||||||
"components.Settings.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash",
|
"components.Settings.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash",
|
||||||
"components.Settings.validationHostnameRequired": "You must provide a hostname/IP",
|
"components.Settings.validationHostnameRequired": "You must provide a hostname or IP address",
|
||||||
"components.Settings.validationPortRequired": "You must provide a port",
|
"components.Settings.validationPortRequired": "You must provide a valid port number",
|
||||||
"components.Settings.webhook": "Webhook",
|
"components.Settings.webhook": "Webhook",
|
||||||
"components.Setup.configureplex": "Configure Plex",
|
"components.Setup.configureplex": "Configure Plex",
|
||||||
"components.Setup.configureservices": "Configure Services",
|
"components.Setup.configureservices": "Configure Services",
|
||||||
@@ -641,9 +643,9 @@
|
|||||||
"components.Setup.welcome": "Welcome to Overseerr",
|
"components.Setup.welcome": "Welcome to Overseerr",
|
||||||
"components.Slider.noresults": "No results.",
|
"components.Slider.noresults": "No results.",
|
||||||
"components.StatusBadge.status4k": "4K {status}",
|
"components.StatusBadge.status4k": "4K {status}",
|
||||||
"components.StatusChacker.newversionDescription": "An update is now available. Click the button below to reload the application.",
|
"components.StatusChacker.newversionDescription": "Overseerr has been updated! Please click the button below to reload the page.",
|
||||||
"components.StatusChacker.newversionavailable": "New Version Available",
|
"components.StatusChacker.newversionavailable": "Application Update",
|
||||||
"components.StatusChacker.reloadOverseerr": "Reload Overseerr",
|
"components.StatusChacker.reloadOverseerr": "Reload",
|
||||||
"components.TitleCard.movie": "Movie",
|
"components.TitleCard.movie": "Movie",
|
||||||
"components.TitleCard.tvshow": "Series",
|
"components.TitleCard.tvshow": "Series",
|
||||||
"components.TvDetails.TvCast.fullseriescast": "Full Series Cast",
|
"components.TvDetails.TvCast.fullseriescast": "Full Series Cast",
|
||||||
@@ -678,11 +680,9 @@
|
|||||||
"components.TvDetails.play4konplex": "Play 4K on Plex",
|
"components.TvDetails.play4konplex": "Play 4K on Plex",
|
||||||
"components.TvDetails.playonplex": "Play on Plex",
|
"components.TvDetails.playonplex": "Play on Plex",
|
||||||
"components.TvDetails.recommendations": "Recommendations",
|
"components.TvDetails.recommendations": "Recommendations",
|
||||||
"components.TvDetails.recommendationssubtext": "If you liked {title}, you might also like…",
|
|
||||||
"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.similarsubtext": "Other series similar to {title}",
|
|
||||||
"components.TvDetails.status": "Status",
|
"components.TvDetails.status": "Status",
|
||||||
"components.TvDetails.unavailable": "Unavailable",
|
"components.TvDetails.unavailable": "Unavailable",
|
||||||
"components.TvDetails.userrating": "User Rating",
|
"components.TvDetails.userrating": "User Rating",
|
||||||
@@ -730,10 +730,10 @@
|
|||||||
"components.UserList.usercreatedsuccess": "User created successfully!",
|
"components.UserList.usercreatedsuccess": "User created successfully!",
|
||||||
"components.UserList.userdeleted": "User deleted.",
|
"components.UserList.userdeleted": "User deleted.",
|
||||||
"components.UserList.userdeleteerror": "Something went wrong while deleting the user.",
|
"components.UserList.userdeleteerror": "Something went wrong while deleting the user.",
|
||||||
"components.UserList.userfail": "Something went wrong while saving the user.",
|
"components.UserList.userfail": "Something went wrong while saving user permissions.",
|
||||||
"components.UserList.userlist": "User List",
|
"components.UserList.userlist": "User List",
|
||||||
"components.UserList.users": "Users",
|
"components.UserList.users": "Users",
|
||||||
"components.UserList.userssaved": "Users saved!",
|
"components.UserList.userssaved": "User permissions saved successfully!",
|
||||||
"components.UserList.validationEmail": "You must provide a valid email address",
|
"components.UserList.validationEmail": "You must provide a valid email address",
|
||||||
"components.UserList.validationpasswordminchars": "Password is too short; should be a minimum of 8 characters",
|
"components.UserList.validationpasswordminchars": "Password is too short; should be a minimum of 8 characters",
|
||||||
"components.UserProfile.ProfileHeader.joindate": "Joined {joindate}",
|
"components.UserProfile.ProfileHeader.joindate": "Joined {joindate}",
|
||||||
@@ -744,26 +744,28 @@
|
|||||||
"components.UserProfile.UserSettings.UserGeneralSettings.accounttype": "Account Type",
|
"components.UserProfile.UserSettings.UserGeneralSettings.accounttype": "Account Type",
|
||||||
"components.UserProfile.UserSettings.UserGeneralSettings.admin": "Admin",
|
"components.UserProfile.UserSettings.UserGeneralSettings.admin": "Admin",
|
||||||
"components.UserProfile.UserSettings.UserGeneralSettings.displayName": "Display Name",
|
"components.UserProfile.UserSettings.UserGeneralSettings.displayName": "Display Name",
|
||||||
|
"components.UserProfile.UserSettings.UserGeneralSettings.general": "General",
|
||||||
"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings": "General Settings",
|
"components.UserProfile.UserSettings.UserGeneralSettings.generalsettings": "General Settings",
|
||||||
"components.UserProfile.UserSettings.UserGeneralSettings.languageServerDefault": "Default ({language})",
|
"components.UserProfile.UserSettings.UserGeneralSettings.languageServerDefault": "Default ({language})",
|
||||||
"components.UserProfile.UserSettings.UserGeneralSettings.localuser": "Local User",
|
"components.UserProfile.UserSettings.UserGeneralSettings.localuser": "Local User",
|
||||||
"components.UserProfile.UserSettings.UserGeneralSettings.originalLanguageDefault": "All Languages",
|
"components.UserProfile.UserSettings.UserGeneralSettings.originalLanguageDefault": "All Languages",
|
||||||
"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage": "Discover Language",
|
"components.UserProfile.UserSettings.UserGeneralSettings.originallanguage": "Discover Language",
|
||||||
"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip": "Filter content by original language (only applies to the \"Popular\" and \"Upcoming\" categories)",
|
"components.UserProfile.UserSettings.UserGeneralSettings.originallanguageTip": "Filter content by original language",
|
||||||
"components.UserProfile.UserSettings.UserGeneralSettings.owner": "Owner",
|
"components.UserProfile.UserSettings.UserGeneralSettings.owner": "Owner",
|
||||||
"components.UserProfile.UserSettings.UserGeneralSettings.plexuser": "Plex User",
|
"components.UserProfile.UserSettings.UserGeneralSettings.plexuser": "Plex User",
|
||||||
"components.UserProfile.UserSettings.UserGeneralSettings.region": "Discover Region",
|
"components.UserProfile.UserSettings.UserGeneralSettings.region": "Discover Region",
|
||||||
"components.UserProfile.UserSettings.UserGeneralSettings.regionTip": "Filter content by region (only applies to the \"Popular\" and \"Upcoming\" categories)",
|
"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.save": "Save Changes",
|
||||||
"components.UserProfile.UserSettings.UserGeneralSettings.saving": "Saving…",
|
"components.UserProfile.UserSettings.UserGeneralSettings.saving": "Saving…",
|
||||||
"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 successfully saved!",
|
"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess": "Settings saved successfully!",
|
||||||
"components.UserProfile.UserSettings.UserGeneralSettings.user": "User",
|
"components.UserProfile.UserSettings.UserGeneralSettings.user": "User",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.discordId": "Discord ID",
|
"components.UserProfile.UserSettings.UserNotificationSettings.discordId": "Discord ID",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "The <FindDiscordIdLink>ID number</FindDiscordIdLink> for your Discord user account",
|
"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "The <FindDiscordIdLink>ID number</FindDiscordIdLink> for your Discord user account",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.enableNotifications": "Enable Notifications",
|
"components.UserProfile.UserSettings.UserNotificationSettings.enableNotifications": "Enable Notifications",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.localuser": "Local User",
|
"components.UserProfile.UserSettings.UserNotificationSettings.localuser": "Local User",
|
||||||
|
"components.UserProfile.UserSettings.UserNotificationSettings.notifications": "Notifications",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings": "Notification Settings",
|
"components.UserProfile.UserSettings.UserNotificationSettings.notificationsettings": "Notification Settings",
|
||||||
"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",
|
||||||
@@ -776,7 +778,7 @@
|
|||||||
"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTip": "Add <GetIdBotLink>@get_id_bot</GetIdBotLink> to the chat",
|
"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTip": "Add <GetIdBotLink>@get_id_bot</GetIdBotLink> to the chat",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "<TelegramBotLink>Start a chat</TelegramBotLink>, add <GetIdBotLink>@get_id_bot</GetIdBotLink>, and issue the <code>/my_id</code> command",
|
"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "<TelegramBotLink>Start a chat</TelegramBotLink>, add <GetIdBotLink>@get_id_bot</GetIdBotLink>, and issue the <code>/my_id</code> command",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsFailure": "Something went wrong while saving settings.",
|
"components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsFailure": "Something went wrong while saving settings.",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsSuccess": "Settings successfully saved!",
|
"components.UserProfile.UserSettings.UserNotificationSettings.toastSettingsSuccess": "Notification settings saved successfully!",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "You must provide a valid Discord user ID",
|
"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "You must provide a valid Discord user ID",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "You must provide a valid Telegram chat ID",
|
"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "You must provide a valid Telegram chat ID",
|
||||||
"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword": "Confirm Password",
|
"components.UserProfile.UserSettings.UserPasswordChange.confirmpassword": "Confirm Password",
|
||||||
@@ -784,15 +786,17 @@
|
|||||||
"components.UserProfile.UserSettings.UserPasswordChange.newpassword": "New Password",
|
"components.UserProfile.UserSettings.UserPasswordChange.newpassword": "New Password",
|
||||||
"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.nopermission": "Unauthorized",
|
"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.save": "Save Changes",
|
||||||
"components.UserProfile.UserSettings.UserPasswordChange.saving": "Saving…",
|
"components.UserProfile.UserSettings.UserPasswordChange.saving": "Saving…",
|
||||||
"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure": "Something went wrong while changing the password. Is your current password correct?",
|
"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailure": "Something went wrong while saving the password.",
|
||||||
"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess": "Password changed!",
|
"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsFailureVerifyCurrent": "Something went wrong while saving the password. Was your current password entered correctly?",
|
||||||
"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword": "You must confirm your new password",
|
"components.UserProfile.UserSettings.UserPasswordChange.toastSettingsSuccess": "Password saved successfully!",
|
||||||
"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame": "Password must match",
|
"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPassword": "You must confirm the new password",
|
||||||
|
"components.UserProfile.UserSettings.UserPasswordChange.validationConfirmPasswordSame": "Passwords must match",
|
||||||
"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword": "You must provide your current password",
|
"components.UserProfile.UserSettings.UserPasswordChange.validationCurrentPassword": "You must provide your current password",
|
||||||
"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword": "You must provide a new password",
|
"components.UserProfile.UserSettings.UserPasswordChange.validationNewPassword": "You must provide a new password",
|
||||||
"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength": "Password is too short; should be a minimum of 8 characters",
|
"components.UserProfile.UserSettings.UserPasswordChange.validationNewPasswordLength": "Password is too short; should be a minimum of 8 characters",
|
||||||
@@ -803,14 +807,13 @@
|
|||||||
"components.UserProfile.UserSettings.UserPermissions.save": "Save Changes",
|
"components.UserProfile.UserSettings.UserPermissions.save": "Save Changes",
|
||||||
"components.UserProfile.UserSettings.UserPermissions.saving": "Saving…",
|
"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": "Settings successfully saved!",
|
"components.UserProfile.UserSettings.UserPermissions.toastSettingsSuccess": "Permissions saved successfully!",
|
||||||
"components.UserProfile.UserSettings.UserPermissions.unauthorized": "Unauthorized",
|
"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 Settings",
|
"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.settings": "User Settings",
|
|
||||||
"components.UserProfile.UserSettings.unauthorized": "Unauthorized",
|
"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.norequests": "No Requests",
|
"components.UserProfile.norequests": "No Requests",
|
||||||
@@ -836,12 +839,15 @@
|
|||||||
"i18n.request": "Request",
|
"i18n.request": "Request",
|
||||||
"i18n.requested": "Requested",
|
"i18n.requested": "Requested",
|
||||||
"i18n.retry": "Retry",
|
"i18n.retry": "Retry",
|
||||||
|
"i18n.settings": "Settings",
|
||||||
"i18n.tvshows": "Series",
|
"i18n.tvshows": "Series",
|
||||||
"i18n.unavailable": "Unavailable",
|
"i18n.unavailable": "Unavailable",
|
||||||
"pages.internalServerError": "{statusCode} - Internal server error",
|
"i18n.usersettings": "User Settings",
|
||||||
|
"pages.errormessagewithcode": "404 - {error}",
|
||||||
|
"pages.internalservererror": "Internal Server Error",
|
||||||
"pages.oops": "Oops",
|
"pages.oops": "Oops",
|
||||||
"pages.pageNotFound": "404 - Page Not Found",
|
"pages.pagenotfound": "Page Not Found",
|
||||||
"pages.returnHome": "Return Home",
|
"pages.returnHome": "Return Home",
|
||||||
"pages.serviceUnavailable": "{statusCode} - Service unavailable",
|
"pages.serviceunavailable": "Service Unavailable",
|
||||||
"pages.somethingWentWrong": "{statusCode} - Something went wrong"
|
"pages.somethingwentwrong": "Something Went Wrong"
|
||||||
}
|
}
|
||||||
|
@@ -1,21 +1,28 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { defineMessages, FormattedMessage } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
import PageTitle from '../components/Common/PageTitle';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
pageNotFound: '404 - Page Not Found',
|
errormessagewithcode: '404 - {error}',
|
||||||
|
pagenotfound: 'Page Not Found',
|
||||||
returnHome: 'Return Home',
|
returnHome: 'Return Home',
|
||||||
});
|
});
|
||||||
|
|
||||||
const Custom404: React.FC = () => {
|
const Custom404: React.FC = () => {
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="error-message">
|
<div className="error-message">
|
||||||
|
<PageTitle title={intl.formatMessage(messages.pagenotfound)} />
|
||||||
<div className="text-4xl">
|
<div className="text-4xl">
|
||||||
<FormattedMessage {...messages.pageNotFound} />
|
{intl.formatMessage(messages.errormessagewithcode, {
|
||||||
|
error: intl.formatMessage(messages.pagenotfound),
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
<Link href="/">
|
<Link href="/">
|
||||||
<a className="flex">
|
<a className="flex">
|
||||||
<FormattedMessage {...messages.returnHome} />
|
{intl.formatMessage(messages.returnHome)}
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6 ml-2"
|
className="w-6 h-6 ml-2"
|
||||||
fill="none"
|
fill="none"
|
||||||
|
@@ -2,16 +2,18 @@ import React from 'react';
|
|||||||
import type { NextPage } from 'next';
|
import type { NextPage } from 'next';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import type { Undefinable } from '../utils/typeHelpers';
|
import type { Undefinable } from '../utils/typeHelpers';
|
||||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
import PageTitle from '../components/Common/PageTitle';
|
||||||
|
|
||||||
interface ErrorProps {
|
interface ErrorProps {
|
||||||
statusCode?: number;
|
statusCode?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
internalServerError: '{statusCode} - Internal server error',
|
errormessagewithcode: '{statusCode} - {error}',
|
||||||
serviceUnavailable: '{statusCode} - Service unavailable',
|
internalservererror: 'Internal Server Error',
|
||||||
somethingWentWrong: '{statusCode} - Something went wrong',
|
serviceunavailable: 'Service Unavailable',
|
||||||
|
somethingwentwrong: 'Something Went Wrong',
|
||||||
oops: 'Oops',
|
oops: 'Oops',
|
||||||
returnHome: 'Return Home',
|
returnHome: 'Return Home',
|
||||||
});
|
});
|
||||||
@@ -22,25 +24,29 @@ const Error: NextPage<ErrorProps> = ({ statusCode }) => {
|
|||||||
const getErrorMessage = (statusCode?: number) => {
|
const getErrorMessage = (statusCode?: number) => {
|
||||||
switch (statusCode) {
|
switch (statusCode) {
|
||||||
case 500:
|
case 500:
|
||||||
return intl.formatMessage(messages.internalServerError, {
|
return intl.formatMessage(messages.internalservererror);
|
||||||
statusCode: 500,
|
|
||||||
});
|
|
||||||
case 503:
|
case 503:
|
||||||
return intl.formatMessage(messages.serviceUnavailable, {
|
return intl.formatMessage(messages.serviceunavailable);
|
||||||
statusCode: 503,
|
|
||||||
});
|
|
||||||
default:
|
default:
|
||||||
return intl.formatMessage(messages.somethingWentWrong, {
|
return statusCode
|
||||||
statusCode: statusCode ?? intl.formatMessage(messages.oops),
|
? intl.formatMessage(messages.somethingwentwrong)
|
||||||
});
|
: intl.formatMessage(messages.oops);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className="error-message">
|
<div className="error-message">
|
||||||
<div className="text-4xl">{getErrorMessage(statusCode)}</div>
|
<PageTitle title={getErrorMessage(statusCode)} />
|
||||||
|
<div className="text-4xl">
|
||||||
|
{statusCode
|
||||||
|
? intl.formatMessage(messages.errormessagewithcode, {
|
||||||
|
statusCode: statusCode,
|
||||||
|
message: getErrorMessage(statusCode),
|
||||||
|
})
|
||||||
|
: getErrorMessage(statusCode)}
|
||||||
|
</div>
|
||||||
<Link href="/">
|
<Link href="/">
|
||||||
<a className="flex">
|
<a className="flex">
|
||||||
<FormattedMessage {...messages.returnHome} />
|
{intl.formatMessage(messages.returnHome)}
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6 ml-2"
|
className="w-6 h-6 ml-2"
|
||||||
fill="none"
|
fill="none"
|
||||||
|
Reference in New Issue
Block a user