Translate Updated and Connection Lost Modals in frontend

(cherry picked from commit 074aa6f4457bf83173e6ba7209c452a6e0659a35)
This commit is contained in:
Stevie Robinson
2023-08-13 23:03:52 +02:00
committed by Bogdan
parent 31261f66ad
commit 307adf053e
5 changed files with 51 additions and 18 deletions

View File

@@ -1,6 +1,7 @@
.version { .version {
margin: 0 3px; margin: 0 3px;
font-weight: bold; font-weight: bold;
font-family: var(--defaultFontFamily);
} }
.maintenance { .maintenance {

View File

@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import Button from 'Components/Link/Button'; import Button from 'Components/Link/Button';
import LoadingIndicator from 'Components/Loading/LoadingIndicator'; import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import ModalBody from 'Components/Modal/ModalBody'; import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent'; import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter'; import ModalFooter from 'Components/Modal/ModalFooter';
@@ -64,12 +65,12 @@ function AppUpdatedModalContent(props) {
return ( return (
<ModalContent onModalClose={onModalClose}> <ModalContent onModalClose={onModalClose}>
<ModalHeader> <ModalHeader>
Prowlarr Updated {translate('AppUpdated', { appName: 'Prowlarr' })}
</ModalHeader> </ModalHeader>
<ModalBody> <ModalBody>
<div> <div>
Version <span className={styles.version}>{version}</span> of Prowlarr has been installed, in order to get the latest changes you'll need to reload Prowlarr. <InlineMarkdown data={translate('AppUpdatedVersion', { appName: 'Prowlarr', version })} blockClassName={styles.version} />
</div> </div>
{ {
@@ -77,16 +78,14 @@ function AppUpdatedModalContent(props) {
<div> <div>
{ {
!update.changes && !update.changes &&
<div className={styles.maintenance}> <div className={styles.maintenance}>{translate('MaintenanceRelease')}</div>
{translate('MaintenanceRelease')}
</div>
} }
{ {
!!update.changes && !!update.changes &&
<div> <div>
<div className={styles.changes}> <div className={styles.changes}>
What's new? {translate('WhatsNew')}
</div> </div>
<UpdateChanges <UpdateChanges
@@ -113,14 +112,14 @@ function AppUpdatedModalContent(props) {
<Button <Button
onPress={onSeeChangesPress} onPress={onSeeChangesPress}
> >
Recent Changes {translate('RecentChanges')}
</Button> </Button>
<Button <Button
kind={kinds.PRIMARY} kind={kinds.PRIMARY}
onPress={onModalClose} onPress={onModalClose}
> >
Reload {translate('Reload')}
</Button> </Button>
</ModalFooter> </ModalFooter>
</ModalContent> </ModalContent>

View File

@@ -28,11 +28,11 @@ function ConnectionLostModal(props) {
<ModalBody> <ModalBody>
<div> <div>
{translate('ConnectionLostMessage')} {translate('ConnectionLostToBackend', { appName: 'Prowlarr' })}
</div> </div>
<div className={styles.automatic}> <div className={styles.automatic}>
{translate('ConnectionLostAutomaticMessage')} {translate('ConnectionLostReconnect', { appName: 'Prowlarr' })}
</div> </div>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>

View File

@@ -10,27 +10,55 @@ class InlineMarkdown extends Component {
render() { render() {
const { const {
className, className,
data data,
blockClassName
} = this.props; } = this.props;
// For now only replace links // For now only replace links or code blocks (not both)
const markdownBlocks = []; const markdownBlocks = [];
if (data) { if (data) {
const regex = RegExp(/\[(.+?)\]\((.+?)\)/g); const linkRegex = RegExp(/\[(.+?)\]\((.+?)\)/g);
let endIndex = 0; let endIndex = 0;
let match = null; let match = null;
while ((match = regex.exec(data)) !== null) {
while ((match = linkRegex.exec(data)) !== null) {
if (match.index > endIndex) { if (match.index > endIndex) {
markdownBlocks.push(data.substr(endIndex, match.index - endIndex)); markdownBlocks.push(data.substr(endIndex, match.index - endIndex));
} }
markdownBlocks.push(<Link key={match.index} to={match[2]}>{match[1]}</Link>); markdownBlocks.push(<Link key={match.index} to={match[2]}>{match[1]}</Link>);
endIndex = match.index + match[0].length; endIndex = match.index + match[0].length;
} }
if (endIndex !== data.length) { if (endIndex !== data.length && markdownBlocks.length > 0) {
markdownBlocks.push(data.substr(endIndex, data.length - endIndex)); markdownBlocks.push(data.substr(endIndex, data.length - endIndex));
} }
const codeRegex = RegExp(/(?=`)`(?!`)[^`]*(?=`)`(?!`)/g);
endIndex = 0;
match = null;
let matchedCode = false;
while ((match = codeRegex.exec(data)) !== null) {
matchedCode = true;
if (match.index > endIndex) {
markdownBlocks.push(data.substr(endIndex, match.index - endIndex));
}
markdownBlocks.push(<code key={`code-${match.index}`} className={blockClassName ?? null}>{match[0].substring(1, match[0].length - 1)}</code>);
endIndex = match.index + match[0].length;
}
if (endIndex !== data.length && markdownBlocks.length > 0 && matchedCode) {
markdownBlocks.push(data.substr(endIndex, data.length - endIndex));
}
if (markdownBlocks.length === 0) {
markdownBlocks.push(data);
}
} }
return <span className={className}>{markdownBlocks}</span>; return <span className={className}>{markdownBlocks}</span>;
@@ -39,7 +67,8 @@ class InlineMarkdown extends Component {
InlineMarkdown.propTypes = { InlineMarkdown.propTypes = {
className: PropTypes.string, className: PropTypes.string,
data: PropTypes.string data: PropTypes.string,
blockClassName: PropTypes.string
}; };
export default InlineMarkdown; export default InlineMarkdown;

View File

@@ -31,6 +31,8 @@
"AppProfileInUse": "App Profile in Use", "AppProfileInUse": "App Profile in Use",
"AppProfileSelectHelpText": "App profiles are used to control RSS, Automatic Search and Interactive Search settings on application sync", "AppProfileSelectHelpText": "App profiles are used to control RSS, Automatic Search and Interactive Search settings on application sync",
"AppSettingsSummary": "Applications and settings to configure how Prowlarr interacts with your PVR programs", "AppSettingsSummary": "Applications and settings to configure how Prowlarr interacts with your PVR programs",
"AppUpdated": "{appName} Updated",
"AppUpdatedVersion": "{appName} has been updated to version `{version}`, in order to get the latest changes you'll need to reload {appName}",
"Application": "Application", "Application": "Application",
"ApplicationLongTermStatusCheckAllClientMessage": "All applications are unavailable due to failures for more than 6 hours", "ApplicationLongTermStatusCheckAllClientMessage": "All applications are unavailable due to failures for more than 6 hours",
"ApplicationLongTermStatusCheckSingleClientMessage": "Applications unavailable due to failures for more than 6 hours: {0}", "ApplicationLongTermStatusCheckSingleClientMessage": "Applications unavailable due to failures for more than 6 hours: {0}",
@@ -103,8 +105,8 @@
"ConnectSettings": "Connect Settings", "ConnectSettings": "Connect Settings",
"ConnectSettingsSummary": "Notifications and custom scripts", "ConnectSettingsSummary": "Notifications and custom scripts",
"ConnectionLost": "Connection Lost", "ConnectionLost": "Connection Lost",
"ConnectionLostAutomaticMessage": "Prowlarr will try to connect automatically, or you can click reload below.", "ConnectionLostReconnect": "{appName} will try to connect automatically, or you can click reload below.",
"ConnectionLostMessage": "Prowlarr has lost its connection to the backend and will need to be reloaded to restore functionality.", "ConnectionLostToBackend": "{appName} has lost its connection to the backend and will need to be reloaded to restore functionality.",
"Connections": "Connections", "Connections": "Connections",
"CouldNotConnectSignalR": "Could not connect to SignalR, UI won't update", "CouldNotConnectSignalR": "Could not connect to SignalR, UI won't update",
"CountApplicationsSelected": "{count} application(s) selected", "CountApplicationsSelected": "{count} application(s) selected",
@@ -375,6 +377,7 @@
"RSSIsNotSupportedWithThisIndexer": "RSS is not supported with this indexer", "RSSIsNotSupportedWithThisIndexer": "RSS is not supported with this indexer",
"RawSearchSupported": "Raw Search Supported", "RawSearchSupported": "Raw Search Supported",
"ReadTheWikiForMoreInformation": "Read the Wiki for more information", "ReadTheWikiForMoreInformation": "Read the Wiki for more information",
"RecentChanges": "Recent Changes",
"Reddit": "Reddit", "Reddit": "Reddit",
"Redirect": "Redirect", "Redirect": "Redirect",
"RedirectHelpText": "Redirect incoming download request for indexer and pass the grab directly instead of proxying the request via Prowlarr", "RedirectHelpText": "Redirect incoming download request for indexer and pass the grab directly instead of proxying the request via Prowlarr",
@@ -552,6 +555,7 @@
"VipExpiration": "VIP Expiration", "VipExpiration": "VIP Expiration",
"Warn": "Warn", "Warn": "Warn",
"Website": "Website", "Website": "Website",
"WhatsNew": "What's New?",
"Wiki": "Wiki", "Wiki": "Wiki",
"Year": "Year", "Year": "Year",
"Yes": "Yes", "Yes": "Yes",