fix: various additional i18n issues

* fix: adding messages for i18n issues related to aria labels

* fix: replacing ternary operator

* refactor: injecting intl object to prevent extra modifications on license details component

* test: fixing failing snapshot test

* chore: best descriptions to aria label and removing aria label not needed

* test: snapshot update and fixing ut

* chore: best descriptions to aria labels
This commit is contained in:
jacobo-dominguez-wgu
2025-05-13 14:14:14 -06:00
committed by GitHub
parent 4ebc1590e7
commit 88aa4c1524
15 changed files with 118 additions and 61 deletions

View File

@@ -120,7 +120,7 @@ const CardHeader = ({
value={titleValue}
name="displayName"
onChange={(e) => setTitleValue(e.target.value)}
aria-label="edit field"
aria-label={intl.formatMessage(messages.editFieldAriaLabel)}
onBlur={() => onEditSubmit(titleValue)}
onKeyDown={(e) => {
if (e.key === 'Enter') {

View File

@@ -1,6 +1,10 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
editFieldAriaLabel: {
id: 'course-authoring.course-outline.card.edit-field.aria-label',
defaultMessage: 'Edit field',
},
expandTooltip: {
id: 'course-authoring.course-outline.card.expandTooltip',
defaultMessage: 'Collapse/Expand this card',

View File

@@ -130,7 +130,7 @@ const AnswerOption = ({
</Collapsible.Body>
</div>
<div className="d-flex flex-row flex-nowrap">
<Collapsible.Trigger aria-label="Toggle feedback" className="btn-icon btn-icon-primary btn-icon-md align-items-center">
<Collapsible.Trigger aria-label={intl.formatMessage(messages.feedbackToggleIconAriaLabel)} className="btn-icon btn-icon-primary btn-icon-md align-items-center">
<Icon
src={FeedbackOutline}
alt={intl.formatMessage(messages.feedbackToggleIconAltText)}

View File

@@ -26,6 +26,11 @@ const messages = defineMessages({
defaultMessage: 'Feedback message',
description: 'Placeholder text for feedback text',
},
feedbackToggleIconAriaLabel: {
id: 'authoring.answerwidget.feedback.icon.aria-label',
defaultMessage: 'Toggle feedback',
description: 'Accessible (screen reader) label for "Toggle Feedback" icon',
},
feedbackToggleIconAltText: {
id: 'authoring.answerwidget.feedback.icon.alt',
defaultMessage: 'Toggle feedback',

View File

@@ -30,17 +30,17 @@ const LicenseDetails = ({
// redux
updateField,
}) => (
level !== LicenseLevel.course && details && license !== 'select' ? (
level !== LicenseLevel.course && details && license !== 'select' && (
<div className="x-small border-primary-100 border-bottom m-0 pr-1">
<Form.Group className="pb-2">
<div className="mb-3">
<FormattedMessage {...messages.detailsSubsectionTitle} />
</div>
{license === LicenseTypes.allRightsReserved ? (
{license === LicenseTypes.allRightsReserved && (
<div className="mt-2">
<FormattedMessage {...messages.allRightsReservedSectionMessage} />
</div>
) : null}
)}
{license === LicenseTypes.creativeCommons
? (
<Stack gap={4}>
@@ -55,7 +55,6 @@ const LicenseDetails = ({
<CheckboxControl
disabled
checked
aria-label="Checkbox"
/>
</ActionRow>
</Form.Group>
@@ -80,7 +79,6 @@ const LicenseDetails = ({
noncommercial: e.target.checked,
},
})}
aria-label="Checkbox"
/>
</ActionRow>
</Form.Group>
@@ -106,7 +104,6 @@ const LicenseDetails = ({
shareAlike: e.target.checked ? false : details.shareAlike,
},
})}
aria-label="Checkbox"
/>
</ActionRow>
</Form.Group>
@@ -132,7 +129,6 @@ const LicenseDetails = ({
noDerivatives: e.target.checked ? false : details.noDerivatives,
},
})}
aria-label="Checkbox"
/>
</ActionRow>
</Form.Group>
@@ -144,7 +140,7 @@ const LicenseDetails = ({
) : null}
</Form.Group>
</div>
) : null
)
);
LicenseDetails.propTypes = {

View File

@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`LicenseDetails snapshots snapshots: renders as expected with default props 1`] = `null`;
exports[`LicenseDetails snapshots snapshots: renders as expected with default props 1`] = `false`;
exports[`LicenseDetails snapshots snapshots: renders as expected with level set to block and license set to Creative Commons 1`] = `
<div
@@ -40,7 +40,6 @@ exports[`LicenseDetails snapshots snapshots: renders as expected with level set
</Form.Label>
<ActionRow.Spacer />
<CheckboxControl
aria-label="Checkbox"
checked={true}
disabled={true}
/>
@@ -71,7 +70,6 @@ exports[`LicenseDetails snapshots snapshots: renders as expected with level set
</Form.Label>
<ActionRow.Spacer />
<CheckboxControl
aria-label="Checkbox"
disabled={false}
onChange={[Function]}
/>
@@ -102,7 +100,6 @@ exports[`LicenseDetails snapshots snapshots: renders as expected with level set
</Form.Label>
<ActionRow.Spacer />
<CheckboxControl
aria-label="Checkbox"
disabled={false}
onChange={[Function]}
/>
@@ -131,7 +128,6 @@ exports[`LicenseDetails snapshots snapshots: renders as expected with level set
</Form.Label>
<ActionRow.Spacer />
<CheckboxControl
aria-label="Checkbox"
disabled={false}
onChange={[Function]}
/>
@@ -179,7 +175,7 @@ exports[`LicenseDetails snapshots snapshots: renders as expected with level set
</div>
`;
exports[`LicenseDetails snapshots snapshots: renders as expected with level set to block and license set to select 1`] = `null`;
exports[`LicenseDetails snapshots snapshots: renders as expected with level set to block and license set to select 1`] = `false`;
exports[`LicenseDetails snapshots snapshots: renders as expected with level set to library 1`] = `
<div

View File

@@ -205,7 +205,7 @@ describe('FilesAndUploads', () => {
await mockStore(RequestStatus.SUCCESSFUL);
axiosMock.onGet(`${getAssetsUrl(courseId)}?display_name=download.png&page_size=1`).reply(200, { assets: [] });
axiosMock.onPost(getAssetsUrl(courseId)).reply(200, generateNewAssetApiResponse());
const addFilesButton = screen.getByLabelText('file-input');
const addFilesButton = screen.getByLabelText(messages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFilesButton, file);
await executeThunk(validateAssetFiles(courseId, [file]), store.dispatch);
await waitFor(() => {
@@ -221,7 +221,7 @@ describe('FilesAndUploads', () => {
axiosMock.onGet(
`${getAssetsUrl(courseId)}?display_name=mOckID6&page_size=1`,
).reply(200, { assets: [{ display_name: 'mOckID6' }] });
const addFilesButton = screen.getByLabelText('file-input');
const addFilesButton = screen.getByLabelText(messages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFilesButton, file);
await executeThunk(validateAssetFiles(courseId, [file]), store.dispatch);
expect(screen.getByText(filesPageMessages.overwriteConfirmMessage.defaultMessage)).toBeVisible();
@@ -242,7 +242,7 @@ describe('FilesAndUploads', () => {
};
axiosMock.onPost(getAssetsUrl(courseId)).reply(200, responseData);
const addFilesButton = screen.getByLabelText('file-input');
const addFilesButton = screen.getByLabelText(messages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFilesButton, file);
await executeThunk(validateAssetFiles(courseId, [file]), store.dispatch);
@@ -266,7 +266,7 @@ describe('FilesAndUploads', () => {
axiosMock.onGet(
`${getAssetsUrl(courseId)}?display_name=mOckID6&page_size=1`,
).reply(200, { assets: [{ display_name: 'mOckID6' }] });
const addFilesButton = screen.getByLabelText('file-input');
const addFilesButton = screen.getByLabelText(messages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFilesButton, file);
await executeThunk(validateAssetFiles(courseId, [file]), store.dispatch);
@@ -558,7 +558,7 @@ describe('FilesAndUploads', () => {
await mockStore(RequestStatus.SUCCESSFUL);
axiosMock.onGet(`${getAssetsUrl(courseId)}?display_name=download.png&page_size=1`).reply(200, { assets: [] });
axiosMock.onPost(getAssetsUrl(courseId)).reply(413, { error: errorMessage });
const addFilesButton = screen.getByLabelText('file-input');
const addFilesButton = screen.getByLabelText(messages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFilesButton, file);
await waitFor(() => {
const addStatus = store.getState().assets.addingStatus;
@@ -571,7 +571,7 @@ describe('FilesAndUploads', () => {
it('404 validation should show error', async () => {
await mockStore(RequestStatus.SUCCESSFUL);
axiosMock.onGet(`${getAssetsUrl(courseId)}?display_name=download.png&page_size=1`).reply(404);
const addFilesButton = screen.getByLabelText('file-input');
const addFilesButton = screen.getByLabelText(messages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFilesButton, file);
await executeThunk(addAssetFile(courseId, file, 1), store.dispatch);
const addStatus = store.getState().assets.addingStatus;
@@ -584,7 +584,7 @@ describe('FilesAndUploads', () => {
await mockStore(RequestStatus.SUCCESSFUL);
axiosMock.onGet(`${getAssetsUrl(courseId)}?display_name=download.png&page_size=1`).reply(200, { assets: [] });
axiosMock.onPost(getAssetsUrl(courseId)).reply(404);
const addFilesButton = screen.getByLabelText('file-input');
const addFilesButton = screen.getByLabelText(messages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFilesButton, file);
await executeThunk(addAssetFile(courseId, file, 1), store.dispatch);
const addStatus = store.getState().assets.addingStatus;

View File

@@ -1,6 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useIntl } from '@edx/frontend-platform/i18n';
import { getSupportedFormats } from '../videos-page/data/utils';
import messages from './messages';
export const useFileInput = ({
onAddFile,
@@ -23,17 +25,20 @@ export const useFileInput = ({
};
};
const FileInput = ({ fileInput: hook, supportedFileFormats, allowMultiple }) => (
<input
accept={getSupportedFormats(supportedFileFormats)}
aria-label="file-input"
className="upload d-none"
onChange={hook.addFile}
ref={hook.ref}
type="file"
multiple={allowMultiple}
/>
);
const FileInput = ({ fileInput: hook, supportedFileFormats, allowMultiple }) => {
const intl = useIntl();
return (
<input
accept={getSupportedFormats(supportedFileFormats)}
aria-label={intl.formatMessage(messages.fileInputAriaLabel)}
className="upload d-none"
onChange={hook.addFile}
ref={hook.ref}
type="file"
multiple={allowMultiple}
/>
);
};
FileInput.propTypes = {
fileInput: PropTypes.shape({

View File

@@ -209,6 +209,11 @@ const messages = defineMessages({
defaultMessage: 'Upload error',
description: 'Title for upload error alert',
},
fileInputAriaLabel: {
id: 'course-authoring.files-and-uploads.fileInput.ariaLabel',
defaultMessage: 'Upload a file',
description: 'Accessible (screen reader) label for file input',
},
});
export default messages;

View File

@@ -91,7 +91,7 @@ const SortAndFilterModal = ({
className="text-center"
value="displayName,asc"
type="radio"
aria-label="name descending radio"
aria-label={intl.formatMessage(messages.sortByNameAscendingAriaLabel)}
>
<FormattedMessage {...messages.sortByNameAscending} />
</SelectableBox>
@@ -99,7 +99,7 @@ const SortAndFilterModal = ({
className="text-center"
value="dateAdded,desc"
type="radio"
aria-label="date added descending radio"
aria-label={intl.formatMessage(messages.sortByNewestAriaLabel)}
>
<FormattedMessage {...messages.sortByNewest} />
</SelectableBox>
@@ -107,7 +107,7 @@ const SortAndFilterModal = ({
className="text-center"
value="fileSize,desc"
type="radio"
aria-label="file size descending radio"
aria-label={intl.formatMessage(messages.sortBySizeDescendingAriaLabel)}
>
<FormattedMessage {...messages.sortBySizeDescending} />
</SelectableBox>
@@ -115,7 +115,7 @@ const SortAndFilterModal = ({
className="text-center"
value="displayName,desc"
type="radio"
aria-label="name ascending radio"
aria-label={intl.formatMessage(messages.sortByNameDescendingAriaLabel)}
>
<FormattedMessage {...messages.sortByNameDescending} />
</SelectableBox>
@@ -123,7 +123,7 @@ const SortAndFilterModal = ({
className="text-center"
value="dateAdded,asc"
type="radio"
aria-label="date added ascending radio"
aria-label={intl.formatMessage(messages.sortByOldestAriaLabel)}
>
<FormattedMessage {...messages.sortByOldest} />
</SelectableBox>
@@ -131,7 +131,7 @@ const SortAndFilterModal = ({
className="text-center"
value="fileSize,asc"
type="radio"
aria-label="file size ascending radio"
aria-label={intl.formatMessage(messages.sortBySizeAscendingAriaLabel)}
>
<FormattedMessage {...messages.sortBySizeAscending} />
</SelectableBox>

View File

@@ -22,31 +22,61 @@ const messages = defineMessages({
defaultMessage: 'Cancel',
},
sortByNameAscending: {
id: 'course-authoring..files-and-videos.sort-and-filter.modal.sortByNameAscendingButton.label',
id: 'course-authoring.files-and-videos.sort-and-filter.modal.sortByNameAscendingButton.label',
defaultMessage: 'Name (A-Z)',
},
sortByNameAscendingAriaLabel: {
id: 'course-authoring.files-and-videos.sort-and-filter.modal.sortByNameAscendingButton.aria-label',
defaultMessage: 'name descending radio',
description: 'Accessible (screen reader) label for "name descending" filter',
},
sortByNewest: {
id: 'course-authoring..files-and-videos.sort-and-filter.modal.sortByNewestButton.label',
id: 'course-authoring.files-and-videos.sort-and-filter.modal.sortByNewestButton.label',
defaultMessage: 'Newest',
},
sortByNewestAriaLabel: {
id: 'course-authoring.files-and-videos.sort-and-filter.modal.sortByNewestButton.label-label',
defaultMessage: 'date added descending radio',
description: 'Accessible (screen reader) label for "date added descending" filter',
},
sortBySizeDescending: {
id: 'course-authoring..files-and-videos.sort-and-filter.modal.sortBySizeDescendingButton.label',
id: 'course-authoring.files-and-videos.sort-and-filter.modal.sortBySizeDescendingButton.label',
defaultMessage: 'File size (High to low)',
},
sortBySizeDescendingAriaLabel: {
id: 'course-authoring.files-and-videos.sort-and-filter.modal.sortBySizeDescendingButton.aria-label',
defaultMessage: 'file size descending radio',
description: 'Accessible (screen reader) label for "file size descending" filter',
},
sortByNameDescending: {
id: 'course-authoring..files-and-videos.sort-and-filter.modal.sortByNameDescendingButton.label',
id: 'course-authoring.files-and-videos.sort-and-filter.modal.sortByNameDescendingButton.label',
defaultMessage: 'Name (Z-A)',
},
sortByNameDescendingAriaLabel: {
id: 'course-authoring.files-and-videos.sort-and-filter.modal.sortByNameDescendingButton.aria-label',
defaultMessage: 'name ascending radio',
description: 'Accessible (screen reader) label for "name ascending" filter',
},
sortByOldest: {
id: 'course-authoring..files-and-videos.sort-and-filter.modal.sortByOldestButton.label',
id: 'course-authoring.files-and-videos.sort-and-filter.modal.sortByOldestButton.label',
defaultMessage: 'Oldest',
},
sortByOldestAriaLabel: {
id: 'course-authoring.files-and-videos.sort-and-filter.modal.sortByOldestButton.aria-label',
defaultMessage: 'date added ascending radio',
description: 'Accessible (screen reader) label for "date added ascending" filter',
},
sortBySizeAscending: {
id: 'course-authoring..files-and-videos.sort-and-filter.modal.sortBySizeAscendingButton.label',
id: 'course-authoring.files-and-videos.sort-and-filter.modal.sortBySizeAscendingButton.label',
defaultMessage: 'File size (Low to high)',
},
sortBySizeAscendingAriaLabel: {
id: 'course-authoring.files-and-videos.sort-and-filter.modal.sortBySizeAscendingButton.aria-label',
defaultMessage: 'file size ascending radio',
description: 'Accessible (screen reader) label for "file size ascending" filter',
},
applySortButton: {
id: 'course-authoring..files-and-videos.sort-and-filter.modal.applyySortButton.label',
id: 'course-authoring.files-and-videos.sort-and-filter.modal.applyySortButton.label',
defaultMessage: 'Apply',
},
});

View File

@@ -244,7 +244,7 @@ describe('Videos page', () => {
axiosUnauthenticateMock.onPut('http://testing.org').reply(200);
axiosMock.onGet(getCourseVideosApiUrl(courseId)).reply(200, generateAddVideoApiResponse());
const addFilesButton = screen.getAllByLabelText('file-input')[3];
const addFilesButton = screen.getAllByLabelText(messages.fileInputAriaLabel.defaultMessage)[3];
await act(async () => {
userEvent.upload(addFilesButton, file);
});
@@ -263,7 +263,7 @@ describe('Videos page', () => {
const setFailedSpy = jest.spyOn(api, 'sendVideoUploadStatus').mockImplementation(() => {});
uploadSpy.mockResolvedValue(new Promise(() => {}));
const addFilesButton = screen.getAllByLabelText('file-input')[3];
const addFilesButton = screen.getAllByLabelText(messages.fileInputAriaLabel.defaultMessage)[3];
await act(async () => {
userEvent.upload(addFilesButton, file);
});
@@ -294,7 +294,7 @@ describe('Videos page', () => {
const setFailedSpy = jest.spyOn(api, 'sendVideoUploadStatus').mockImplementation(() => {});
uploadSpy.mockResolvedValue(new Promise(() => {}));
const addFilesButton = screen.getAllByLabelText('file-input')[3];
const addFilesButton = screen.getAllByLabelText(messages.fileInputAriaLabel.defaultMessage)[3];
await act(async () => {
userEvent.upload(addFilesButton, file);
});
@@ -610,7 +610,7 @@ describe('Videos page', () => {
axiosMock.onPost(getCourseVideosApiUrl(courseId)).reply(413, { error: errorMessage });
axiosMock.onGet(getCourseVideosApiUrl(courseId)).reply(200, generateAddVideoApiResponse());
const addFilesButton = screen.getAllByLabelText('file-input')[3];
const addFilesButton = screen.getAllByLabelText(messages.fileInputAriaLabel.defaultMessage)[3];
await act(async () => {
userEvent.upload(addFilesButton, file);
});
@@ -627,7 +627,7 @@ describe('Videos page', () => {
axiosMock.onPost(getCourseVideosApiUrl(courseId)).reply(404);
axiosMock.onGet(getCourseVideosApiUrl(courseId)).reply(200, generateAddVideoApiResponse());
const addFilesButton = screen.getAllByLabelText('file-input')[3];
const addFilesButton = screen.getAllByLabelText(messages.fileInputAriaLabel.defaultMessage)[3];
await act(async () => {
userEvent.upload(addFilesButton, file);
});
@@ -658,7 +658,7 @@ describe('Videos page', () => {
axiosMock.onPost(getCourseVideosApiUrl(courseId)).reply(204, generateNewVideoApiResponse());
axiosUnauthenticateMock.onPut('http://testing.org').reply(404);
axiosMock.onGet(getCourseVideosApiUrl(courseId)).reply(200, generateAddVideoApiResponse());
const addFilesButton = screen.getAllByLabelText('file-input')[3];
const addFilesButton = screen.getAllByLabelText(messages.fileInputAriaLabel.defaultMessage)[3];
await act(async () => {
userEvent.upload(addFilesButton, file);
});

View File

@@ -27,6 +27,7 @@ import {
import { getApiBaseUrl } from '../data/api';
import messages from './messages';
import genericMessages from '../../generic/messages';
import transcriptRowMessages from './transcript-item/messages';
import VideosPageProvider from '../VideosPageProvider';
import { deleteVideoTranscript } from '../data/thunks';
@@ -116,7 +117,7 @@ describe('TranscriptTab', () => {
it('should upload new transcript', async () => {
axiosMock.onPost(`${getApiBaseUrl()}/transcript_upload/`).reply(204);
await act(async () => {
const addFileInput = screen.getByLabelText('file-input');
const addFileInput = screen.getByLabelText(genericMessages.fileInputAriaLabel.defaultMessage);
expect(addFileInput).toBeInTheDocument();
userEvent.upload(addFileInput, file);
@@ -129,7 +130,7 @@ describe('TranscriptTab', () => {
it('should show default error message', async () => {
axiosMock.onPost(`${getApiBaseUrl()}/transcript_upload/`).reply(404);
await act(async () => {
const addFileInput = screen.getByLabelText('file-input');
const addFileInput = screen.getByLabelText(genericMessages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFileInput, file);
});
const addStatus = store.getState().videos.transcriptStatus;
@@ -142,7 +143,7 @@ describe('TranscriptTab', () => {
it('should show api provided error message', async () => {
axiosMock.onPost(`${getApiBaseUrl()}/transcript_upload/`).reply(404, { error: 'api error' });
await act(async () => {
const addFileInput = screen.getByLabelText('file-input');
const addFileInput = screen.getByLabelText(genericMessages.fileInputAriaLabel.defaultMessage);
userEvent.upload(addFileInput, file);
});
const addStatus = store.getState().videos.transcriptStatus;
@@ -299,7 +300,7 @@ describe('TranscriptTab', () => {
axiosMock.onPost(`${getApiBaseUrl()}/transcript_upload/`).reply(204);
await act(async () => {
const addFileInput = screen.getAllByLabelText('file-input')[0];
const addFileInput = screen.getAllByLabelText(genericMessages.fileInputAriaLabel.defaultMessage)[0];
userEvent.upload(addFileInput, file);
});
const addStatus = store.getState().videos.transcriptStatus;
@@ -315,7 +316,7 @@ describe('TranscriptTab', () => {
axiosMock.onPost(`${getApiBaseUrl()}/transcript_upload/`).reply(404);
await act(async () => {
const addFileInput = screen.getAllByLabelText('file-input')[0];
const addFileInput = screen.getAllByLabelText(genericMessages.fileInputAriaLabel.defaultMessage)[0];
userEvent.upload(addFileInput, file);
});

View File

@@ -119,14 +119,14 @@ const OrderTranscriptForm = ({
>
<SelectableBox
value="order"
aria-label="none radio"
aria-label={intl.formatMessage(messages.noneAriaLabel)}
className="text-center"
>
<FormattedMessage {...messages.noneLabel} />
</SelectableBox>
<SelectableBox
value="Cielo24"
aria-label="Cielo24 radio"
aria-label={intl.formatMessage(messages.cieloAriaLabel)}
className="text-center"
disabled={!validCieloTranscriptionPlan && cieloHasCredentials}
>
@@ -134,7 +134,7 @@ const OrderTranscriptForm = ({
</SelectableBox>
<SelectableBox
value="3PlayMedia"
aria-label="3PlayMedia radio"
aria-label={intl.formatMessage(messages.threePlayMediaAriaLabel)}
className="text-center"
disabled={!validThreePlayTranscriptionPlan && threePlayHasCredentials}
>

View File

@@ -28,16 +28,31 @@ const messages = defineMessages({
defaultMessage: 'None',
description: 'Label for order transcript None option',
},
noneAriaLabel: {
id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.none.aria-label',
defaultMessage: 'none radio',
description: 'Accessible (screen reader) label for order transcript None option',
},
cieloLabel: {
id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.cielo24.label',
defaultMessage: 'Cielo24',
description: 'Label for order transcript Cieol24 option',
},
cieloAriaLabel: {
id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.cielo24.aria-label',
defaultMessage: 'Cielo24 radio',
description: 'Accessible (screen reader) label for order transcript Cieol24 option',
},
threePlayMediaLabel: {
id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.3PlayMedia.label',
defaultMessage: '3Play Media',
description: 'Label for order transcript 3Play Media option',
},
threePlayMediaAriaLabel: {
id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.3PlayMedia.aria-label',
defaultMessage: '3PlayMedia radio',
description: 'Accessible (screen reader) label for order transcript 3Play Media option',
},
updateSettingsLabel: {
id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.updateSettings.label',
defaultMessage: 'Update settings',