feat(frontend): added more localized strings

This commit is contained in:
sct
2020-11-27 06:59:22 +00:00
parent 45d6a1e1c0
commit 659a601877
25 changed files with 646 additions and 268 deletions

View File

@@ -1,8 +1,14 @@
import React, { useEffect } from 'react';
import useClipboard from 'react-use-clipboard';
import { useToasts } from 'react-toast-notifications';
import { defineMessages, useIntl } from 'react-intl';
const messages = defineMessages({
copied: 'Copied API key to clipboard',
});
const CopyButton: React.FC<{ textToCopy: string }> = ({ textToCopy }) => {
const intl = useIntl();
const [isCopied, setCopied] = useClipboard(textToCopy, {
successDuration: 1000,
});
@@ -10,12 +16,12 @@ const CopyButton: React.FC<{ textToCopy: string }> = ({ textToCopy }) => {
useEffect(() => {
if (isCopied) {
addToast('Copied API key to clipboard', {
addToast(intl.formatMessage(messages.copied), {
appearance: 'info',
autoDismiss: true,
});
}
}, [isCopied, addToast]);
}, [isCopied, addToast, intl]);
return (
<button

View File

@@ -10,6 +10,10 @@ import * as Yup from 'yup';
const messages = defineMessages({
save: 'Save Changes',
saving: 'Saving...',
agentenabled: 'Agent Enabled',
webhookUrl: 'Webhook URL',
validationWebhookUrlRequired: 'You must provide a webhook URL',
webhookUrlPlaceholder: 'Server Settings -> Integrations -> Webhooks',
});
const NotificationsDiscord: React.FC = () => {
@@ -19,7 +23,9 @@ const NotificationsDiscord: React.FC = () => {
);
const NotificationsDiscordSchema = Yup.object().shape({
webhookUrl: Yup.string().required('You must provide a webhook URL'),
webhookUrl: Yup.string().required(
intl.formatMessage(messages.validationWebhookUrlRequired)
),
});
if (!data && !error) {
@@ -58,7 +64,7 @@ const NotificationsDiscord: React.FC = () => {
htmlFor="isDefault"
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
>
Agent Enabled
{intl.formatMessage(messages.agentenabled)}
</label>
<div className="mt-1 sm:mt-0 sm:col-span-2">
<Field
@@ -74,7 +80,7 @@ const NotificationsDiscord: React.FC = () => {
htmlFor="name"
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
>
Webhook URL
{intl.formatMessage(messages.webhookUrl)}
</label>
<div className="mt-1 sm:mt-0 sm:col-span-2">
<div className="max-w-lg flex rounded-md shadow-sm">
@@ -82,7 +88,9 @@ const NotificationsDiscord: React.FC = () => {
id="webhookUrl"
name="webhookUrl"
type="text"
placeholder="Server Settings -> Integrations -> Webhooks"
placeholder={intl.formatMessage(
messages.webhookUrlPlaceholder
)}
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
/>
</div>

View File

@@ -10,6 +10,16 @@ import * as Yup from 'yup';
const messages = defineMessages({
save: 'Save Changes',
saving: 'Saving...',
validationFromRequired: 'You must provide an email sender address',
validationSmtpHostRequired: 'You must provide an SMTP host',
validationSmtpPortRequired: 'You must provide an SMTP port',
agentenabled: 'Agent Enabled',
emailsender: 'Email Sender Address',
smtpHost: 'SMTP Host',
smtpPort: 'SMTP Port',
enableSsl: 'Enable SSL',
authUser: 'Auth User',
authPass: 'Auth Pass',
});
const NotificationsEmail: React.FC = () => {
@@ -20,10 +30,14 @@ const NotificationsEmail: React.FC = () => {
const NotificationsDiscordSchema = Yup.object().shape({
emailFrom: Yup.string().required(
'You must provide an email sender address'
intl.formatMessage(messages.validationFromRequired)
),
smtpHost: Yup.string().required(
intl.formatMessage(messages.validationSmtpHostRequired)
),
smtpPort: Yup.number().required(
intl.formatMessage(messages.validationSmtpPortRequired)
),
smtpHost: Yup.string().required('You must provide an SMTP host'),
smtpPort: Yup.number().required('You must provide an SMTP port'),
});
if (!data && !error) {
@@ -88,7 +102,7 @@ const NotificationsEmail: React.FC = () => {
htmlFor="name"
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
>
Email Sender Address
{intl.formatMessage(messages.emailsender)}
</label>
<div className="mt-1 sm:mt-0 sm:col-span-2">
<div className="max-w-lg flex rounded-md shadow-sm">
@@ -110,7 +124,7 @@ const NotificationsEmail: React.FC = () => {
htmlFor="name"
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
>
SMTP Host
{intl.formatMessage(messages.smtpHost)}
</label>
<div className="mt-1 sm:mt-0 sm:col-span-2">
<div className="max-w-lg flex rounded-md shadow-sm">
@@ -132,7 +146,7 @@ const NotificationsEmail: React.FC = () => {
htmlFor="name"
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
>
SMTP Port
{intl.formatMessage(messages.smtpPort)}
</label>
<div className="mt-1 sm:mt-0 sm:col-span-2">
<div className="max-w-lg flex rounded-md shadow-sm">
@@ -154,7 +168,7 @@ const NotificationsEmail: React.FC = () => {
htmlFor="isDefault"
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
>
Enable SSL
{intl.formatMessage(messages.enableSsl)}
</label>
<div className="mt-1 sm:mt-0 sm:col-span-2">
<Field
@@ -170,7 +184,7 @@ const NotificationsEmail: React.FC = () => {
htmlFor="name"
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
>
Auth User
{intl.formatMessage(messages.authUser)}
</label>
<div className="mt-1 sm:mt-0 sm:col-span-2">
<div className="max-w-lg flex rounded-md shadow-sm">
@@ -178,7 +192,6 @@ const NotificationsEmail: React.FC = () => {
id="authUser"
name="authUser"
type="text"
placeholder="localhost"
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
/>
</div>
@@ -189,7 +202,7 @@ const NotificationsEmail: React.FC = () => {
htmlFor="name"
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
>
Auth Pass
{intl.formatMessage(messages.authPass)}
</label>
<div className="mt-1 sm:mt-0 sm:col-span-2">
<div className="max-w-lg flex rounded-md shadow-sm">
@@ -197,7 +210,6 @@ const NotificationsEmail: React.FC = () => {
id="authPass"
name="authPass"
type="password"
placeholder="localhost"
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
/>
</div>

View File

@@ -1,13 +1,17 @@
import React from 'react';
import useSWR from 'swr';
import LoadingSpinner from '../Common/LoadingSpinner';
import Badge from '../Common/Badge';
import { FormattedDate, FormattedRelativeTime } from 'react-intl';
import { FormattedRelativeTime, defineMessages, useIntl } from 'react-intl';
import Button from '../Common/Button';
import { hasPermission } from '../../../server/lib/permissions';
import { Permission } from '../../hooks/useUser';
const messages = defineMessages({
jobname: 'Job Name',
nextexecution: 'Next Execution',
runnow: 'Run Now',
});
const SettingsJobs: React.FC = () => {
const intl = useIntl();
const { data, error } = useSWR<{ name: string; nextExecutionTime: string }[]>(
'/api/v1/settings/jobs'
);
@@ -25,10 +29,10 @@ const SettingsJobs: React.FC = () => {
<thead>
<tr>
<th className="px-6 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
Job Name
{intl.formatMessage(messages.jobname)}
</th>
<th className="px-6 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
Next Execution
{intl.formatMessage(messages.nextexecution)}
</th>
<th className="px-6 py-3 bg-gray-500"></th>
</tr>
@@ -54,7 +58,9 @@ const SettingsJobs: React.FC = () => {
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-right text-sm leading-5 font-medium">
<Button buttonType="primary">Run Now</Button>
<Button buttonType="primary">
{intl.formatMessage(messages.runnow)}
</Button>
</td>
</tr>
))}

View File

@@ -1,6 +1,17 @@
import React from 'react';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { defineMessages, useIntl } from 'react-intl';
const messages = defineMessages({
menuGeneralSettings: 'General Settings',
menuPlexSettings: 'Plex',
menuServices: 'Services',
menuNotifications: 'Notifications',
menuLogs: 'Logs',
menuJobs: 'Jobs',
menuAbout: 'About',
});
interface SettingsRoute {
text: string;
@@ -8,46 +19,48 @@ interface SettingsRoute {
regex: RegExp;
}
const settingsRoutes: SettingsRoute[] = [
{
text: 'General Settings',
route: '/settings/main',
regex: /^\/settings(\/main)?$/,
},
{
text: 'Plex',
route: '/settings/plex',
regex: /^\/settings\/plex/,
},
{
text: 'Services',
route: '/settings/services',
regex: /^\/settings\/services/,
},
{
text: 'Notifications',
route: '/settings/notifications/email',
regex: /^\/settings\/notifications/,
},
{
text: 'Logs',
route: '/settings/logs',
regex: /^\/settings\/logs/,
},
{
text: 'Jobs',
route: '/settings/jobs',
regex: /^\/settings\/jobs/,
},
{
text: 'About',
route: '/settings/about',
regex: /^\/settings\/about/,
},
];
const SettingsLayout: React.FC = ({ children }) => {
const router = useRouter();
const intl = useIntl();
const settingsRoutes: SettingsRoute[] = [
{
text: intl.formatMessage(messages.menuGeneralSettings),
route: '/settings/main',
regex: /^\/settings(\/main)?$/,
},
{
text: intl.formatMessage(messages.menuPlexSettings),
route: '/settings/plex',
regex: /^\/settings\/plex/,
},
{
text: intl.formatMessage(messages.menuServices),
route: '/settings/services',
regex: /^\/settings\/services/,
},
{
text: intl.formatMessage(messages.menuNotifications),
route: '/settings/notifications/email',
regex: /^\/settings\/notifications/,
},
{
text: intl.formatMessage(messages.menuLogs),
route: '/settings/logs',
regex: /^\/settings\/logs/,
},
{
text: intl.formatMessage(messages.menuJobs),
route: '/settings/jobs',
regex: /^\/settings\/jobs/,
},
{
text: intl.formatMessage(messages.menuAbout),
route: '/settings/about',
regex: /^\/settings\/about/,
},
];
const activeLinkColor =
'border-indigo-600 text-indigo-500 focus:outline-none focus:text-indigo-500 focus:border-indigo-500';

View File

@@ -9,8 +9,13 @@ import Button from '../Common/Button';
import { defineMessages, useIntl } from 'react-intl';
const messages = defineMessages({
generalsettings: 'General Settings',
generalsettingsDescription:
'These are settings related to general Overseerr configuration.',
save: 'Save Changes',
saving: 'Saving...',
apikey: 'API Key',
applicationurl: 'Application URL',
});
const SettingsMain: React.FC = () => {
@@ -27,10 +32,10 @@ const SettingsMain: React.FC = () => {
<>
<div>
<h3 className="text-lg leading-6 font-medium text-gray-200">
General Settings
{intl.formatMessage(messages.generalsettings)}
</h3>
<p className="mt-1 max-w-2xl text-sm leading-5 text-gray-500">
These are settings related to general Overseerr configuration.
{intl.formatMessage(messages.generalsettingsDescription)}
</p>
</div>
<div className="mt-6 sm:mt-5">
@@ -59,7 +64,7 @@ const SettingsMain: React.FC = () => {
htmlFor="username"
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
>
API Key
{intl.formatMessage(messages.apikey)}
</label>
<div className="mt-1 sm:mt-0 sm:col-span-2">
<div className="max-w-lg flex rounded-md shadow-sm">
@@ -93,7 +98,7 @@ const SettingsMain: React.FC = () => {
htmlFor="name"
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
>
Application URL
{intl.formatMessage(messages.applicationurl)}
</label>
<div className="mt-1 sm:mt-0 sm:col-span-2">
<div className="max-w-lg flex rounded-md shadow-sm">

View File

@@ -1,6 +1,13 @@
import Link from 'next/link';
import { useRouter } from 'next/router';
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
const messages = defineMessages({
notificationsettings: 'Notification Settings',
notificationsettingsDescription:
'Here you can pick and choose what types of notifications to send and through what types of services.',
});
interface SettingsRoute {
text: string;
@@ -23,6 +30,7 @@ const settingsRoutes: SettingsRoute[] = [
const SettingsNotifications: React.FC = ({ children }) => {
const router = useRouter();
const intl = useIntl();
const activeLinkColor = 'bg-gray-700';
@@ -55,11 +63,10 @@ const SettingsNotifications: React.FC = ({ children }) => {
<>
<div className="mb-6">
<h3 className="text-lg leading-6 font-medium text-gray-200">
Notification Settings
{intl.formatMessage(messages.notificationsettings)}
</h3>
<p className="mt-1 max-w-2xl text-sm leading-5 text-gray-500">
Here you can pick and choose what types of notifications to send and
through what types of services.
{intl.formatMessage(messages.notificationsettingsDescription)}
</p>
</div>
<div>