From 674f3027922ada5549e780dfeda5c6d4f0c6bf77 Mon Sep 17 00:00:00 2001 From: Arnei Date: Tue, 12 Dec 2023 10:04:28 +0100 Subject: [PATCH 1/9] Add upload subtitle button Adds an "Upload" button next to the "Download" button in the subtitle edit view. The button opens a file dialog where you can select a vtt file. The contents of the selected file will then replace the current subtitle cues. Tags (optional metadata from Opencast that specifiy e.g. the language of the subtitle) remain unaffected by uploading. --- src/i18n/locales/en-US.json | 6 ++ src/main/SubtitleEditor.tsx | 130 ++++++++++++++++++++++++++++++------ 2 files changed, 114 insertions(+), 22 deletions(-) diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index b77a3d038..c2aef7e34 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -251,6 +251,12 @@ "backButton-tooltip": "Return to subtitle selection", "downloadButton-title": "Download", "downloadButton-tooltip": "Download subtitle as vtt file", + "uploadButton-title": "Upload", + "uploadButton-tooltip": "Upload subtitle as vtt file", + "uploadButton-warning": "Caution! Uploading will overwrite the current subtitle. This cannot be undone. Are you sure?", + "uploadButton-error": "Upload failed.", + "uploadButton-error-filetype": "Wrong file type.", + "uploadButton-error-parse": "Could not parse subtitle file. Please ensure that the file contains valid WebVTT.", "editTitle": "Subtitle Editor - {{title}}", "editTitle-loading": "Loading", "generic": "Generic", diff --git a/src/main/SubtitleEditor.tsx b/src/main/SubtitleEditor.tsx index 8f5f08b74..d4a726f38 100644 --- a/src/main/SubtitleEditor.tsx +++ b/src/main/SubtitleEditor.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from "react"; import { css } from "@emotion/react"; -import { basicButtonStyle, flexGapReplacementStyle } from "../cssStyles"; -import { LuChevronLeft, LuDownload} from "react-icons/lu"; +import { basicButtonStyle, errorBoxStyle, flexGapReplacementStyle } from "../cssStyles"; +import { LuChevronLeft, LuDownload, LuUpload} from "react-icons/lu"; import { selectSubtitlesFromOpencastById, } from '../redux/videoSlice' @@ -16,7 +16,7 @@ import { import SubtitleVideoArea from "./SubtitleVideoArea"; import SubtitleTimeline from "./SubtitleTimeline"; import { useTranslation } from "react-i18next"; -import { useTheme } from "../themes"; +import { Theme, useTheme } from "../themes"; import { parseSubtitle, serializeSubtitle } from "../util/utilityFunctions"; import { ThemedTooltip } from "./Tooltip"; import { titleStyle, titleStyleBold } from "../cssStyles"; @@ -82,6 +82,12 @@ const SubtitleEditor : React.FC = () => { width: '100%', }) + const topRightButtons = css({ + display: 'flex', + flexDirection: 'row', + ...(flexGapReplacementStyle(10, false)), + }) + const subAreaStyle = css({ display: 'flex', flexDirection: 'row', @@ -109,7 +115,10 @@ const SubtitleEditor : React.FC = () => {
{t("subtitles.editTitle", {title: getTitle()})}
- +
+ + +
@@ -128,6 +137,15 @@ const SubtitleEditor : React.FC = () => { ); } +const subtitleButtonStyle = (theme: Theme) => css({ + fontSize: '16px', + height: '10px', + padding: '16px', + justifyContent: 'space-around', + boxShadow: `${theme.boxShadow}`, + background: `${theme.element_bg}`, +}) + const DownloadButton: React.FC = () => { const subtitle = useSelector(selectSelectedSubtitleById); @@ -147,18 +165,10 @@ const DownloadButton: React.FC = () => { const { t } = useTranslation(); const theme = useTheme(); - const style = css({ - fontSize: '16px', - height: '10px', - padding: '16px', - justifyContent: 'space-around', - boxShadow: `${theme.boxShadow}`, - background: `${theme.element_bg}`, - }); return ( -
downloadSubtitles()} > @@ -169,6 +179,90 @@ const DownloadButton: React.FC = () => { ); } +const UploadButton: React.FC = () => { + + const { t } = useTranslation(); + const theme = useTheme(); + const dispatch = useDispatch() + + const [errorState, setErrorState] = useState(false); + const [errorMessage, setErrorMessage] = useState(""); + const subtitle = useSelector(selectSelectedSubtitleById) + const selectedId = useSelector(selectSelectedSubtitleId) + // Upload Ref + const inputRef = React.useRef(null); + + const uploadSubtitles = () => { + // open file input box on click of other element + const ref = inputRef.current + if (ref !== null) { + if (confirm(t("subtitles.uploadButton-warning"))) { + ref.click(); + } + } + } + + // Save uploaded file in redux + const uploadCallback = (event: React.ChangeEvent) => { + const fileObj = event.target.files && event.target.files[0]; + if (!fileObj) { + return; + } + + // Check if image + if (fileObj.type.split('/')[0] !== 'text') { + setErrorState(true) + setErrorMessage(t("subtitles.uploadButton-error-filetype")) + return + } + + const reader = new FileReader(); + reader.onload = e => { + // the result image data + if (e.target && e.target.result) { + try { + const text = e.target.result.toString() + const subtitleParsed = parseSubtitle(text) + dispatch(setSubtitle({identifier: selectedId, subtitles: {cues: subtitleParsed, tags: subtitle.tags}})) + setErrorState(false) + } catch (e) { + console.error(e) + setErrorState(true) + setErrorMessage(t("subtitles.uploadButton-error-parse")) + } + } + } + reader.readAsText(fileObj) + }; + + return ( + <> + +
uploadSubtitles()} + > + + {t("subtitles.uploadButton-title")} +
+
+
+ {t("subtitles.uploadButton-error")}
+ {errorMessage ? t("various.error-details-text", {errorMessage: errorMessage}) : t("various.error-text")}
+
+ {/* Hidden input field for upload */} + uploadCallback(event)} + aria-hidden="true" + /> + + ); +} + /** * Takes you to a different page @@ -179,17 +273,9 @@ export const BackButton : React.FC = () => { const theme = useTheme() const dispatch = useDispatch(); - const backButtonStyle = css({ - height: '10px', - padding: '16px', - boxShadow: `${theme.boxShadow}`, - background: `${theme.element_bg}`, - justifyContent: 'space-around' - }) - return ( -
dispatch(setIsDisplayEditView(false))} From d512243eb2ada01d7d6e31e63aa23a4385687ba6 Mon Sep 17 00:00:00 2001 From: Arnei Date: Mon, 8 Apr 2024 10:56:02 +0200 Subject: [PATCH 2/9] Throw error trying to parse empty subtitle file An empty file is not valid WebVTT, but our parser will not recognize this as an error. So we just check for the empty string ourselves. --- src/util/utilityFunctions.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/util/utilityFunctions.ts b/src/util/utilityFunctions.ts index 7b39a2f56..cf25a6ba9 100644 --- a/src/util/utilityFunctions.ts +++ b/src/util/utilityFunctions.ts @@ -129,6 +129,10 @@ export function parseSubtitle(subtitle: string): SubtitleCue[] { // - Pros: Parses styles, can also parse SRT, actively maintained // - Cons: Uses node streaming library, can"t polyfill without ejecting CreateReactApp // TODO: Parse caption + if (subtitle === "") { + throw new Error("File is empty"); + } + const parser = new WebVTTParser(); const tree = parser.parse(subtitle, "metadata"); if (tree.errors.length !== 0) { From 59526c96a602cc53bab9c9eec4df5afa03231079 Mon Sep 17 00:00:00 2001 From: Arnei Date: Thu, 16 May 2024 14:50:08 +0200 Subject: [PATCH 3/9] Allow empty string as uploaded subtitles Empty string was getting filtered out due to being falsy. Fixes that. --- src/main/SubtitleEditor.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/SubtitleEditor.tsx b/src/main/SubtitleEditor.tsx index 5a35473a9..e0dbb965e 100644 --- a/src/main/SubtitleEditor.tsx +++ b/src/main/SubtitleEditor.tsx @@ -213,7 +213,7 @@ const UploadButton: React.FC = () => { return; } - // Check if image + // Check if not text if (fileObj.type.split("/")[0] !== "text") { setErrorState(true); setErrorMessage(t("subtitles.uploadButton-error-filetype")); @@ -222,8 +222,7 @@ const UploadButton: React.FC = () => { const reader = new FileReader(); reader.onload = e => { - // the result image data - if (e.target && e.target.result) { + if (e.target && (e.target.result || e.target.result === "")) { try { const text = e.target.result.toString(); const subtitleParsed = parseSubtitle(text); From fbcabd4e3c5ba038f4e01631d5f509656084757d Mon Sep 17 00:00:00 2001 From: Arnei Date: Fri, 24 May 2024 13:57:37 +0200 Subject: [PATCH 4/9] Add confirmation modal to Upload subtitle Fixes an issue with the upload subtitle button, where the automatic browser dialog used by the button would "time out", failing to open up the subsequent file dialog. This replaces it with a confirmation modal from appkit. WARNING: Requires https://github.com/opencast/appkit/pull/5 to be merged and released! --- src/i18n/locales/en-US.json | 10 +++++++++- src/main/SubtitleEditor.tsx | 37 ++++++++++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index a7fd95a47..e538eef53 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -254,7 +254,8 @@ "downloadButton-tooltip": "Download subtitle as vtt file", "uploadButton-title": "Upload", "uploadButton-tooltip": "Upload subtitle as vtt file", - "uploadButton-warning": "Caution! Uploading will overwrite the current subtitle. This cannot be undone. Are you sure?", + "uploadButton-warning-header": "Caution!", + "uploadButton-warning": "Uploading will overwrite the current subtitle. This cannot be undone. Are you sure?", "uploadButton-error": "Upload failed.", "uploadButton-error-filetype": "Wrong file type.", "uploadButton-error-parse": "Could not parse subtitle file. Please ensure that the file contains valid WebVTT.", @@ -312,5 +313,12 @@ "language": { "language": "Language" + }, + + "modal": { + "areYouSure": "Are you sure?", + "cancel": "Cancel", + "close": "Close", + "confirm": "Confirm" } } diff --git a/src/main/SubtitleEditor.tsx b/src/main/SubtitleEditor.tsx index e0dbb965e..48f230b8a 100644 --- a/src/main/SubtitleEditor.tsx +++ b/src/main/SubtitleEditor.tsx @@ -21,6 +21,7 @@ import { parseSubtitle, serializeSubtitle } from "../util/utilityFunctions"; import { ThemedTooltip } from "./Tooltip"; import { titleStyle, titleStyleBold } from "../cssStyles"; import { generateButtonTitle } from "./SubtitleSelect"; +import { ConfirmationModal, ConfirmationModalHandle } from "@opencast/appkit"; /** * Displays an editor view for a selected subtitle file @@ -189,23 +190,28 @@ const UploadButton: React.FC = () => { const theme = useTheme(); const dispatch = useAppDispatch(); + const [isFileUploadTriggered, setisFileUploadTriggered] = useState(false); const [errorState, setErrorState] = useState(false); const [errorMessage, setErrorMessage] = useState(""); const subtitle = useAppSelector(selectSelectedSubtitleById); const selectedId = useAppSelector(selectSelectedSubtitleId); // Upload Ref const inputRef = React.useRef(null); + // Modal Ref + const modalRef = React.useRef(null); - const uploadSubtitles = () => { - // open file input box on click of other element - const ref = inputRef.current; - if (ref !== null) { - if (confirm(t("subtitles.uploadButton-warning"))) { - ref.click(); - } - } + const triggerFileUpload = () => { + modalRef.current?.done(); + setisFileUploadTriggered(true); }; + useEffect(() => { + if (isFileUploadTriggered) { + inputRef.current?.click(); + setisFileUploadTriggered(false); + } + }, [isFileUploadTriggered]); + // Save uploaded file in redux const uploadCallback = (event: React.ChangeEvent) => { const fileObj = event.target.files && event.target.files[0]; @@ -243,7 +249,7 @@ const UploadButton: React.FC = () => {
uploadSubtitles()} + onClick={() => modalRef.current?.open()} > {t("subtitles.uploadButton-title")} @@ -262,6 +268,19 @@ const UploadButton: React.FC = () => { onChange={event => uploadCallback(event)} aria-hidden="true" /> + + {t("subtitles.uploadButton-warning")} + ); }; From 27df630a6041565cc4425c30f8aaa4a0107c9dfb Mon Sep 17 00:00:00 2001 From: Arnei Date: Wed, 29 May 2024 14:48:54 +0200 Subject: [PATCH 5/9] Fix parameter names --- src/main/SubtitleEditor.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/SubtitleEditor.tsx b/src/main/SubtitleEditor.tsx index 48f230b8a..e313583d5 100644 --- a/src/main/SubtitleEditor.tsx +++ b/src/main/SubtitleEditor.tsx @@ -274,9 +274,9 @@ const UploadButton: React.FC = () => { onSubmit={triggerFileUpload} ref={modalRef} text={{ - generalActionCancel: t("modal.cancel"), - generalActionClose: t("modal.close"), - manageAreYouSure: t("modal.areYouSure"), + cancel: t("modal.cancel"), + close: t("modal.close"), + areYouSure: t("modal.areYouSure"), }} > {t("subtitles.uploadButton-warning")} From b83f3d9ce1964917db3a9e95582f168cf4215571 Mon Sep 17 00:00:00 2001 From: Arnei Date: Wed, 29 May 2024 16:58:34 +0200 Subject: [PATCH 6/9] Switch error box for modal in subtitle upload Instead of trying to awkwardly fit an error box into our layout, instead inform the user via a modal if anything failed during the subtitle upload. --- src/main/SubtitleEditor.tsx | 44 +++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/main/SubtitleEditor.tsx b/src/main/SubtitleEditor.tsx index e313583d5..7bc960785 100644 --- a/src/main/SubtitleEditor.tsx +++ b/src/main/SubtitleEditor.tsx @@ -21,7 +21,7 @@ import { parseSubtitle, serializeSubtitle } from "../util/utilityFunctions"; import { ThemedTooltip } from "./Tooltip"; import { titleStyle, titleStyleBold } from "../cssStyles"; import { generateButtonTitle } from "./SubtitleSelect"; -import { ConfirmationModal, ConfirmationModalHandle } from "@opencast/appkit"; +import { ConfirmationModal, ConfirmationModalHandle, Modal, ModalHandle, boxError } from "@opencast/appkit"; /** * Displays an editor view for a selected subtitle file @@ -36,6 +36,8 @@ const SubtitleEditor: React.FC = () => { const selectedId = useAppSelector(selectSelectedSubtitleId); const captionTrack = useAppSelector(state => selectSubtitlesFromOpencastById(state, selectedId)); const theme = useTheme(); + const modalRef = React.useRef(null); + const [uploadErrorMessage, setUploadErrorMessage] = useState(undefined); // Prepare subtitle in redux useEffect(() => { @@ -62,6 +64,17 @@ const SubtitleEditor: React.FC = () => { } }, [dispatch, captionTrack, subtitle, selectedId]); + // Display error modal + useEffect(() => { + if (modalRef.current && uploadErrorMessage) { + modalRef.current?.open(); + } + if (modalRef.current && modalRef.current.close && !uploadErrorMessage) { + setUploadErrorMessage(undefined); + modalRef.current.close(); + } + }, [uploadErrorMessage]); + const getTitle = () => { if (subtitle) { return generateButtonTitle(subtitle.tags, t); @@ -85,6 +98,8 @@ const SubtitleEditor: React.FC = () => { justifyContent: "space-between", alignItems: "center", width: "100%", + ...(flexGapReplacementStyle(10, false)), + padding: "15px", }); const topRightButtons = css({ @@ -106,7 +121,6 @@ const SubtitleEditor: React.FC = () => { borderBottom: `${theme.menuBorder}`, }); - const render = () => { if (getError !== undefined) { return ( @@ -117,12 +131,19 @@ const SubtitleEditor: React.FC = () => { <>
-
+
{t("subtitles.editTitle", { title: getTitle() })}
- + + + {uploadErrorMessage} +
@@ -184,15 +205,17 @@ const DownloadButton: React.FC = () => { ); }; -const UploadButton: React.FC = () => { +const UploadButton: React.FC<{ + setErrorMessage: React.Dispatch>, +}> = ({ + setErrorMessage, +}) => { const { t } = useTranslation(); const theme = useTheme(); const dispatch = useAppDispatch(); const [isFileUploadTriggered, setisFileUploadTriggered] = useState(false); - const [errorState, setErrorState] = useState(false); - const [errorMessage, setErrorMessage] = useState(""); const subtitle = useAppSelector(selectSelectedSubtitleById); const selectedId = useAppSelector(selectSelectedSubtitleId); // Upload Ref @@ -221,7 +244,6 @@ const UploadButton: React.FC = () => { // Check if not text if (fileObj.type.split("/")[0] !== "text") { - setErrorState(true); setErrorMessage(t("subtitles.uploadButton-error-filetype")); return; } @@ -233,10 +255,8 @@ const UploadButton: React.FC = () => { const text = e.target.result.toString(); const subtitleParsed = parseSubtitle(text); dispatch(setSubtitle({ identifier: selectedId, subtitles: { cues: subtitleParsed, tags: subtitle.tags } })); - setErrorState(false); } catch (e) { console.error(e); - setErrorState(true); setErrorMessage(t("subtitles.uploadButton-error-parse")); } } @@ -255,10 +275,6 @@ const UploadButton: React.FC = () => { {t("subtitles.uploadButton-title")}
-
- {t("subtitles.uploadButton-error")}
- {errorMessage ? t("various.error-details-text", { errorMessage: errorMessage }) : t("various.error-text")}
-
{/* Hidden input field for upload */} Date: Thu, 30 May 2024 13:39:52 +0200 Subject: [PATCH 7/9] Remove unused imports --- src/main/SubtitleEditor.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/SubtitleEditor.tsx b/src/main/SubtitleEditor.tsx index 7bc960785..b88c2e769 100644 --- a/src/main/SubtitleEditor.tsx +++ b/src/main/SubtitleEditor.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from "react"; import { css } from "@emotion/react"; -import { basicButtonStyle, errorBoxStyle, flexGapReplacementStyle } from "../cssStyles"; +import { basicButtonStyle, flexGapReplacementStyle } from "../cssStyles"; import { LuChevronLeft, LuDownload, LuUpload } from "react-icons/lu"; import { selectSubtitlesFromOpencastById, @@ -21,7 +21,7 @@ import { parseSubtitle, serializeSubtitle } from "../util/utilityFunctions"; import { ThemedTooltip } from "./Tooltip"; import { titleStyle, titleStyleBold } from "../cssStyles"; import { generateButtonTitle } from "./SubtitleSelect"; -import { ConfirmationModal, ConfirmationModalHandle, Modal, ModalHandle, boxError } from "@opencast/appkit"; +import { ConfirmationModal, ConfirmationModalHandle, Modal, ModalHandle } from "@opencast/appkit"; /** * Displays an editor view for a selected subtitle file From ebb95ec9f2e9d895fa6322f4267d7f3809d1e5fb Mon Sep 17 00:00:00 2001 From: Arnei Date: Thu, 6 Jun 2024 08:26:54 +0200 Subject: [PATCH 8/9] Add new appkit release This has the modals we need for the subtitle upload --- package-lock.json | 41 +++++++++++++++++++++++++++++++++-------- package.json | 2 +- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 97c780da9..304322c23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@fontsource-variable/roboto-flex": "^5.0.3", "@iarna/toml": "^2.2.5", "@mui/material": "^5.15.2", - "@opencast/appkit": "^0.2.4", + "@opencast/appkit": "^0.3.0", "@reduxjs/toolkit": "^2.0.1", "@testing-library/jest-dom": "^6.1.6", "@types/iarna__toml": "^2.0.5", @@ -708,9 +708,9 @@ "license": "MIT" }, "node_modules/@emotion/react": { - "version": "11.11.3", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.3.tgz", - "integrity": "sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA==", + "version": "11.11.4", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", + "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.11.0", @@ -2774,12 +2774,13 @@ } }, "node_modules/@opencast/appkit": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@opencast/appkit/-/appkit-0.2.4.tgz", - "integrity": "sha512-EHByrN6o8elbQIOI4XB1vqxA5IxStLGgoX8nfOQ3EXWHbx0n/ZNeZ/DrOTTmxgTNfRxvjZR7sbjIlbSIyL5SKw==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@opencast/appkit/-/appkit-0.3.0.tgz", + "integrity": "sha512-w9jZBKpzJokT0HNjtO3rxx94Qimt8W6WmjDkg61rj5ETHv3Im794jyZLf/LRA3dsN+GfhE0dW3QuvIzXE/b2pw==", "peerDependencies": { - "@emotion/react": "^11.11.1", + "@emotion/react": "^11.11.4", "@floating-ui/react": "^0.24.3", + "focus-trap-react": "^10.2.3", "react": "^18.2.0", "react-icons": "^4.9.0", "react-merge-refs": "^2.0.2" @@ -5412,6 +5413,30 @@ "dev": true, "license": "ISC" }, + "node_modules/focus-trap": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.5.4.tgz", + "integrity": "sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==", + "peer": true, + "dependencies": { + "tabbable": "^6.2.0" + } + }, + "node_modules/focus-trap-react": { + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/focus-trap-react/-/focus-trap-react-10.2.3.tgz", + "integrity": "sha512-YXBpFu/hIeSu6NnmV2xlXzOYxuWkoOtar9jzgp3lOmjWLWY59C/b8DtDHEAV4SPU07Nd/t+nS/SBNGkhUBFmEw==", + "peer": true, + "dependencies": { + "focus-trap": "^7.5.4", + "tabbable": "^6.2.0" + }, + "peerDependencies": { + "prop-types": "^15.8.1", + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + } + }, "node_modules/for-each": { "version": "0.3.3", "dev": true, diff --git a/package.json b/package.json index 6b86797b1..dfc4cd03e 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "@fontsource-variable/roboto-flex": "^5.0.3", "@iarna/toml": "^2.2.5", "@mui/material": "^5.15.2", - "@opencast/appkit": "^0.2.4", + "@opencast/appkit": "^0.3.0", "@reduxjs/toolkit": "^2.0.1", "@testing-library/jest-dom": "^6.1.6", "@types/iarna__toml": "^2.0.5", From f2a47b31efe3138c47f286cef8c65fa96818e6c5 Mon Sep 17 00:00:00 2001 From: Arnei Date: Mon, 10 Jun 2024 08:52:37 +0200 Subject: [PATCH 9/9] Add "uploading" to create subtitle button For users wondering where they can upload their subtitle files, this hopefully guides them to creating one if a subtitle for their language does not yet exist. --- src/i18n/locales/en-US.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 6de394d29..b775856ac 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -247,7 +247,7 @@ "subtitles": { "selectSubtitleButton-tooltip": "Edit subtitles for {{title}}", "selectSubtitleButton-tooltip-aria": "Select {{title}} for subtitle editing", - "createSubtitleButton-tooltip": "Opens a dialog for creating new subtitles", + "createSubtitleButton-tooltip": "Opens a dialog for creating/uploading new subtitles", "createSubtitleButton-clicked-tooltip-aria": "Contains a dialog for creating new subtitles", "createSubtitleButton-createButton": "Create", "createSubtitleButton-createButton-tooltip": "Start a new subtitle file with the chosen title.",