Compare commits

...

84 Commits

Author SHA1 Message Date
Mehak Nasir
6a65826fd5 fix: group at subsection field added in redux state 2023-01-05 14:31:44 +05:00
Jesper Hodge
ad47bfacd4 docs: add fix for m1 macs to readme (#421) 2023-01-03 16:32:54 -05:00
Jenkins
9e9bac997b chore(i18n): update translations 2022-12-25 16:32:50 -05:00
connorhaugh
014fbeac71 feat: release select type page (#418) 2022-12-23 09:22:14 -05:00
connorhaugh
0b214faeca feat: add problem editor to FLCC (#417) 2022-12-20 16:14:43 -05:00
Zachary Hancock
abff65a11a fix: LTI providers should not be shown unless enabled (#416) 2022-12-19 10:46:04 -05:00
Adolfo R. Brandes
2f6eed237a fix: Editors should support runtime configuration
Fetching settings directly via `process.env` circumvents the runtime
configuration mechanism.  Change the editor page to use `getConfig()`
instead.
2022-12-13 23:55:36 +00:00
Kristin Aoki
7253c9bba3 feat: upgrade lib-content-components 1.69.1 (#411) 2022-12-13 09:27:22 -05:00
Jenkins
a84d3c09e8 chore(i18n): update translations 2022-12-11 16:27:30 -05:00
Raymond Zhou
f5e1f1cf6b feat: FLCC v1.68.0 (#407) 2022-12-09 11:37:31 -05:00
ayesha waris
8096a389da style: confirmation modal added for in-context discussion toggle (#404)
* style: confirmation modal added for in-context discussion toggle

* refactor: removed duplicate message id

* refactor: function moved to on line direct call
2022-12-09 18:40:21 +05:00
kenclary
1a21850fc4 feat: upgrade lib-content-components to 1.66.3. (#405) 2022-12-07 11:58:26 -05:00
Kristin Aoki
efae5ecd4b feat: upgrade ib-content-components to 1.66.0 (#403) 2022-12-05 16:59:49 -05:00
Jenkins
1e043325d6 chore(i18n): update translations 2022-12-04 16:32:30 -05:00
Raymond Zhou
0bfce5594d feat: update paragon to v20.21.0 (#399) 2022-12-02 11:12:25 -05:00
connorhaugh
dbe2787785 feat: update flcc to 1.63.1 (#400) 2022-12-02 10:47:53 -05:00
connorhaugh
20e98319af feat: remove default background color for editors (#398) 2022-12-02 10:23:07 -05:00
Abdullah Waheed
2063049747 feat: added new translations in Makefile and updated all the translations 2022-11-30 13:30:22 +00:00
edX requirements bot
a7def9ce25 fix: -t flag added in pull translation command (#393) 2022-11-30 16:44:21 +05:00
Kristin Aoki
2418207149 feat: bump lib-content-componets to 1.61.0 (#397) 2022-11-29 16:34:42 -05:00
Kristin Aoki
5da5967e97 feat: update lib-content-componets to 1.60.1 (#395) 2022-11-29 15:10:40 -05:00
Jenkins
45b2bf5b13 chore(i18n): update translations 2022-11-27 16:32:27 -05:00
ayesha waris
7527f6c764 Style: Toggle remains Disabled and Link to instructor dashboard show on Disabled Cohorts (#375)
* style: on disabled cohorts toggle remains disabled and link to instructor dashboard shows

* fix: test cases fixed

Co-authored-by: Mehak Nasir <mehaknasir94@gmail.com>
2022-11-21 14:41:40 +05:00
Ghassan Maslamani
bdfa1fdeb3 fix: force studio url to reload if changed
This chagne make it possible if this module was loaded **then**
  the configuration for studio url is changed, then it will pick
  the last value.

  More context overhangio/tutor-mfe/issues/86
2022-11-18 13:49:16 +00:00
Raymond Zhou
79f58cc8d0 feat: update to flcc 1.60 (#392) 2022-11-17 12:25:03 -05:00
Adolfo R. Brandes
437d0a37a9 docs: Document current feature-set of this MFE
This updates the README to include brief documentation on the purpose of
this MFE, the main features it provides, as well as their configuration
and external requirements.
2022-11-17 14:13:23 +00:00
Saad Yousaf
0e24a0767b fix: show Zoom settings when pii sharing is enabled and make launch email optional (#387)
Co-authored-by: Mehak Nasir <mehaknasir94@gmail.com>
2022-11-16 13:14:16 +05:00
connorhaugh
91abf56977 feat: upgrade flcc to 1.58.0 (#390) 2022-11-15 13:31:15 -05:00
Kristin Aoki
f0734d86db feat: upgrade frontend-lib-components to 1.57.0 (#388) 2022-11-15 09:27:46 -05:00
Ahtisham Shahid
3581d633c1 Revert "fix: show Zoom settings when pii sharing is enabled and make launch email optional (#380)" (#386)
This reverts commit b8895bef33.
2022-11-11 21:25:41 +05:00
Saad Yousaf
b8895bef33 fix: show Zoom settings when pii sharing is enabled and make launch email optional (#380)
Co-authored-by: Mehak Nasir <mehaknasir94@gmail.com>
2022-11-11 18:08:26 +05:00
Kristin Aoki
89d0d12559 feat: bump upgrade of flcc to 1.56.1 (#385) 2022-11-10 09:35:09 -05:00
Abderraouf Mehdi Bouhali
34fe291268 fix(rtl): mirror legacy page card arrow 2022-11-07 16:03:36 +00:00
Jenkins
4b1e292e1c chore(i18n): update translations 2022-11-06 16:32:32 -05:00
Kristin Aoki
90eb6fd0c3 feat: upgrade frontend-lib-content-components to 1.55.0 (#379) 2022-11-03 19:05:20 -04:00
Kristin Aoki
50da8a0f0b feat: upgrade flcc to 1.52.0 and paragon to 20.18.0 (#377) 2022-11-02 11:26:46 -04:00
Awais Ansari
7dcd328f2e fix: add . to helper message 2022-11-01 17:39:01 +05:00
Awais Ansari
e2d66cc605 fix: update helper text for bigBlueButton free plan 2022-11-01 17:39:01 +05:00
kenclary
f5fc721b3b feat: update lib-content-components to 1.51.2. TNL-10183. (#371) 2022-10-27 14:46:37 -04:00
Kristin Aoki
c4bbb6fa70 feat: update frontend-lib-content-components to 1.51.1 2022-10-25 11:10:20 -04:00
Muhammad Adeel Tajamul
748aee2cff fix: added bbb learn more env variable (#365)
Co-authored-by: adeel.tajamul <adeel.tajamul@arbisoft.com>
2022-10-20 17:31:14 +05:00
Kristin Aoki
31473d3f49 feat: update lib-content-components to 1.49.0 2022-10-19 15:30:18 -04:00
Kristin Aoki
4de727791a feat: update frontend-lib-content-components to 1.48.0 and upgrades paragon to 20.13.0 2022-10-17 15:34:09 -04:00
Zachary Hancock
d1d04d5585 feat: configure lti providers on exam settings modal (#363) 2022-10-13 09:22:36 -04:00
Raymond Zhou
6f41a14012 feat: update FLCC (#362) 2022-10-12 16:02:05 -04:00
Zachary Hancock
f54dc17788 feat: configure lti exam providers (#356)
Allows setting a course exam provider to integrations managed by edx-exams. This option is gated by the CourseWaffleFlag course_apps.exams_ida in edx-platform.
2022-10-11 11:54:33 -04:00
Jenkins
7954baf6bd chore(i18n): update translations 2022-10-09 17:32:24 -04:00
connorhaugh
1ff270f6e6 feat: update FLCC (#359) 2022-10-07 10:35:38 -04:00
Kristin Aoki
4ec612dd67 feat: upgrade lib-content-components to 1.41.0 (#352) 2022-10-07 09:15:06 -04:00
Jenkins
a7b0b46e37 chore(i18n): update translations 2022-10-02 17:33:09 -04:00
connorhaugh
ce66be7678 feat: add schedule to renovate jobs
this will make patch/minor upgrade renovate jobs be run daily.
2022-09-28 12:46:25 -04:00
SaadYousaf
3567b36ece fix: handle null blackout dates 2022-09-26 13:25:15 +05:00
Ahtisham Shahid
9db3ded793 fix: changed client secret input type to password (#351)
* fix: changed client secret input type to password

* fix: made secret not required field
2022-09-21 14:44:13 +05:00
Sarina Canelake
4755ae4d67 Fix github url strings (org edx -> openedx) (#348)
* fix: fix github url strings (org edx -> openedx)

* fix: update path to .github workflows to read from openedx org
2022-09-12 14:37:49 -04:00
Jenkins
022502c2a3 chore(i18n): update translations 2022-09-11 17:25:40 -04:00
Kristin Aoki
8a69e51526 feat: upgrade content components 1.39.0 2022-09-08 14:21:31 -04:00
Arunmozhi
38f9f689c9 Simplify in-context discussion toggles [BD-38] (#339)
* refactor: remove unit level visibility toggle

* refactor: remove the in-context discussion settings toggle

* refactor: rename graded units label of in-context discussion setting
2022-09-07 16:41:48 +05:00
connorhaugh
7922ceb711 feat: upgrade flcc minor version (#347) 2022-09-06 15:27:59 -04:00
Mehak Nasir
b142befdc1 fix: dont show free tier in options if no free tier available
fix: free_tier not sent in zoom configs and lti config removed from free_tier

fix: bbb all use cases fixed
2022-09-06 17:05:57 +05:00
Kristin Aoki
ca6848693a feat: update lib-content-components to 1.38.0 2022-08-31 16:43:15 -04:00
Kristin Aoki
ce7fd1593f feat: upgrade lib-content-components to 1.37.0 2022-08-31 16:16:09 -04:00
Kristin Aoki
21c7250672 feat: update lib-content-components to 1.35.0 2022-08-29 10:53:58 -04:00
Muhammad Abdullah Waheed
8dfac206c5 refactor: updated renovate config to auto update minor and patch versions of edx dependencies (#335) 2022-08-24 16:51:39 -04:00
Kristin Aoki
2965508ad1 feat: update lib-content-components to 1.34.0 2022-08-24 14:48:39 -04:00
Mehak Nasir
4bd251d849 fix: fix crash issue on accessing undefined keys (#337) 2022-08-24 16:31:52 +05:00
connorhaugh
325f8727c8 feat: update to flcc 1.33 (#336)
* feat: update to flcc 1.33

* fix: use better npm version
2022-08-23 14:27:01 -04:00
Kristin Aoki
2f212919bd feat: update lib-content-components to 1.31.0 2022-08-18 10:15:34 -04:00
Kristin Aoki
f88411adee feat: update lib-content-components to 1.30.0 2022-08-15 12:48:24 -04:00
Kristin Aoki
f1830dd63e feat: update lib-content-components to 1.29.0 2022-08-12 11:32:23 -04:00
Kristin Aoki
5f73e4277f feat: update lib-content-components to 1.28.0 2022-08-10 11:24:26 -04:00
Kristin Aoki
9fce8ab363 feat: update lib-content-components to 1.27.0 2022-08-08 16:50:49 -04:00
Kristin Aoki
6bc682565c feat: update lib-content-components to 1.26.0 2022-08-08 13:21:11 -04:00
edx-semantic-release
0faba86890 chore(i18n): update translations 2022-08-07 17:31:33 -04:00
Raymond Zhou
154c4ba629 feat: update paragon to 20.6.1 (#326) 2022-08-04 12:35:23 -04:00
Raymond Zhou
e0e3347cda feat: update frontend-platform (#325) 2022-08-02 21:23:38 -04:00
Raymond Zhou
c94a94c08e feat: update lib-content-components to 1.25.1 (#324) 2022-08-02 16:25:13 -04:00
Maman Khan
fcb9e91aa2 Moving code coverage from codecov package to CI (#311)
* fix: removed depreciated package codecov

* fix: syncing package and package-lock
2022-07-28 16:31:41 +05:00
Matt Hughes
21c36a45fa Fixing translations job in this repo (#321)
* chore(i18n): update translations

* fix: upgrade frontend-lib-content-component version

* build: update js dependency lockfile

Co-authored-by: edx-semantic-release <edx-semantic-release@edx.org>
Co-authored-by: Alie Langston <alangsto@wellesley.edu>
2022-07-13 08:34:58 -04:00
alangsto
26a7974cd1 fix: upgrade frontend-lib-content-components version (#320) 2022-07-12 11:14:05 -04:00
Mehak Nasir
d6997b8b4f feat: bbb screens integrated in live (#316)
* feat: bbb screens integrated in live

test: test cases added for bbb screens

fix: field populate issue resolved

fix: added link for read more about plans

fix: launch email is only visible in case of zoom

* fix: free plan message improved

* chore: frontend lib content version update

* chore: frontend lib dependency updated
2022-07-07 19:39:42 +05:00
Raymond Zhou
1bd884c7ca Feat dependency updates (#314) 2022-06-28 16:19:25 -04:00
Raymond Zhou
e8dd28b490 feat: frontend-lib-content-components v1.22 (#313) 2022-06-28 14:50:42 -04:00
Raymond Zhou
9898a00c70 feat: update frontend-lib-content-components (#310) 2022-06-10 10:59:57 -04:00
connorhaugh
6fa312f7b4 feat: upgrade FLCC version (#309)
Co-authored-by: rayzhou-bit <rzhou@2u.com>
2022-06-09 16:08:04 -04:00
65 changed files with 17140 additions and 25686 deletions

2
.env
View File

@@ -5,6 +5,7 @@ CREDENTIALS_BASE_URL=''
CSRF_TOKEN_API_PATH=''
DISCOVERY_API_BASE_URL=''
ECOMMERCE_BASE_URL=''
EXAMS_BASE_URL=''
FAVICON_URL=''
LANGUAGE_PREFERENCE_COOKIE_NAME=''
LMS_BASE_URL=''
@@ -26,3 +27,4 @@ USER_INFO_COOKIE_NAME=''
ENABLE_PROGRESS_GRAPH_SETTINGS=false
ENABLE_TEAM_TYPE_SETTING=false
ENABLE_NEW_EDITOR_PAGES=true
BBB_LEARN_MORE_URL=''

View File

@@ -4,6 +4,7 @@ BASE_URL='localhost:2001'
CREDENTIALS_BASE_URL='http://localhost:18150'
CSRF_TOKEN_API_PATH='/csrf/api/v1/token'
DISCOVERY_API_BASE_URL=
EXAMS_BASE_URL=
ECOMMERCE_BASE_URL='http://localhost:18130'
FAVICON_URL='https://edx-cdn.org/v3/default/favicon.ico'
LANGUAGE_PREFERENCE_COOKIE_NAME='openedx-language-preference'
@@ -28,3 +29,4 @@ USER_INFO_COOKIE_NAME='edx-user-info'
ENABLE_PROGRESS_GRAPH_SETTINGS=false
ENABLE_TEAM_TYPE_SETTING=false
ENABLE_NEW_EDITOR_PAGES=true
BBB_LEARN_MORE_URL=''

View File

@@ -4,6 +4,7 @@ CREDENTIALS_BASE_URL='http://localhost:18150'
CSRF_TOKEN_API_PATH='/csrf/api/v1/token'
DISCOVERY_API_BASE_URL='http://localhost:18381'
ECOMMERCE_BASE_URL='http://localhost:18130'
EXAMS_BASE_URL=
FAVICON_URL='https://edx-cdn.org/v3/default/favicon.ico'
LANGUAGE_PREFERENCE_COOKIE_NAME='openedx-language-preference'
LMS_BASE_URL='http://localhost:18000'
@@ -27,3 +28,4 @@ USER_INFO_COOKIE_NAME='edx-user-info'
ENABLE_PROGRESS_GRAPH_SETTINGS=false
ENABLE_TEAM_TYPE_SETTING=false
ENABLE_NEW_EDITOR_PAGES=true
BBB_LEARN_MORE_URL=''

View File

@@ -7,6 +7,7 @@ module.exports = createConfig('eslint',
controlComponents: ['Input'],
}],
'template-curly-spacing': 'off',
'react-hooks/exhaustive-deps': 'off',
indent: 'off',
},
});

View File

@@ -7,4 +7,4 @@ on:
jobs:
commitlint:
uses: edx/.github/.github/workflows/commitlint.yml@master
uses: openedx/.github/.github/workflows/commitlint.yml@master

View File

@@ -10,4 +10,4 @@ on:
jobs:
version-check:
uses: edx/.github/.github/workflows/lockfileversion-check.yml@master
uses: openedx/.github/.github/workflows/lockfileversion-check.yml@master

View File

@@ -19,6 +19,6 @@ jobs:
node-version: ${{ matrix.node }}
- run: make validate.ci
- name: Upload coverage
uses: codecov/codecov-action@v2
uses: codecov/codecov-action@v3
with:
fail_ci_if_error: true

4
Makefile Executable file → Normal file
View File

@@ -1,6 +1,6 @@
transifex_resource = frontend-app-course-authoring
export TRANSIFEX_RESOURCE = ${transifex_resource}
transifex_langs = "ar,fr,es_419,zh_CN"
transifex_langs = "ar,fr,es_419,zh_CN,pt,it,de,uk,ru,hi,fr_CA"
transifex_utils = ./node_modules/.bin/transifex-utils.js
i18n = ./src/i18n
@@ -47,7 +47,7 @@ push_translations:
# Pulls translations from Transifex.
pull_translations:
tx pull -f --mode reviewed --languages=$(transifex_langs)
tx pull -t -f --mode reviewed --languages=$(transifex_langs)
# This target is used by Travis.
validate-no-uncommitted-package-lock-changes:

View File

@@ -1,21 +1,162 @@
|Build Status| |Codecov| |license|
#############################
frontend-app-course-authoring
=============================
#############################
Please tag `@edx/teaching-and-learning <https://github.com/orgs/edx/teams/teaching-and-learning>`_ on any PRs or issues. Thanks.
Prerequisite
************
Introduction
************
This is the Course Authoring micro-frontend, currently under development by `2U <https://2u.com>`_.
Its purpose is to provide both a framework and UI for new or replacement React-based authoring features outside ``edx-platform``. You can find the current set described below.
********
Features
********
Feature: Pages and Resources Studio Tab
=======================================
Enables a "Pages & Resources" menu item in Studio, under the "Content" menu.
Requirements
------------
The following are external requirements for this feature to function correctly:
* ``edx-platform`` Django settings:
* ``COURSE_AUTHORING_MICROFRONTEND_URL``: must be set in the CMS environment and point to this MFE's deployment URL.
* ``edx-platform`` Waffle flags:
* ``discussions.pages_and_resources_mfe``: must be enabled for the set of users meant to access this feature.
* `frontend-app-learning <https://github.com/openedx/frontend-app-learning>`_: This MFE expects it to be the LMS frontend.
* `frontend-app-discussions <https://github.com/openedx/frontend-app-discussions/>`_: This is what the "Discussions" configuration provided by this feature actually configures. Without it, discussion settings are ignored.
Configuration
-------------
In additional to the standard settings, the following local configuration items are required:
* ``LEARNING_BASE_URL``: points to Learning MFE; necessary so that the `View Live` button works
* ``ENABLE_PROGRESS_GRAPH_SETTINGS``: allow enabling or disabling the learner progress graph course-wide
Feature Description
-------------------
Clicking on the "Pages & Resources" menu item takes the user to the course's ``pages-and-resources`` standalone page in this MFE. (In a devstack, for instance: http://localhost:2001/course/course-v1:edX+DemoX+Demo_Course/pages-and-resources.)
UX-wise, **Pages & Resources** is meant to look like a Studio tab, so reproduces Studio's header.
For a particular course, this page allows one to:
* Configure the new Discussions MFE (making this a requirement for it). This includes:
* Enabling/disabling the feature entirely
* Picking a different discussion provider, while showing a comparison matrix between them:
* edX
* Ed Discussion
* InScribe
* Piazza
* Yellowdig
* Allowing to configure the selected provider
* Enable/Disable learner progress
* Enable/Disable learner notes
* Enable/Disable the learner wiki
* Enable/Disable the LMS calculator
* Go to the textbook management page in Studio (in a devstack: http://localhost:18010/textbooks/course-v1:edX+DemoX+Demo_Course)
* Go to the custom page management page in Studio(in a devstack http://localhost:18010/tabs/course-v1:edX+DemoX+Demo_Course)
Feature: New React XBlock Editors
=================================
This allows an operator to enable the use of new React editors for the HTML, Video, and Problem XBlocks, all of which are provided here.
Requirements
------------
* ``edx-platform`` Django settings:
* ``COURSE_AUTHORING_MICROFRONTEND_URL``: must be set in the CMS environment and point to this MFE's deployment URL.
* ``edx-platform`` Waffle flags:
* ``new_core_editors.use_new_text_editor``: must be enabled for the new HTML Xblock editor to be used in Studio
* ``new_core_editors.use_new_video_editor``: must be enabled for the new Video Xblock editor to be used in Studio
* ``new_core_editors.use_new_problem_editor``: must be enabled for the new Problem Xblock editor to be used in Studio
Configuration
-------------
In additional to the standard settings, the following local configuration item is required:
* ``ENABLE_NEW_EDITOR_PAGES``: must be enabled in order to actually present the new XBlock editors
Feature Description
-------------------
When a corresponding waffle flag is set, upon editing a block in Studio, the view is rendered by this MFE instead of by the XBlock's authoring view. The user remains in Studio.
.. note::
The new editors themselves are currently implemented in a repository outside ``openedx``: `frontend-lib-content-components <https://github.com/edx/frontend-lib-content-components/>`_, a dependency of this MFE. This repository is slated to be moved to the ``openedx`` org, however.
Feature: New Proctoring Exams View
==================================
Requirements
------------
* ``edx-platform`` Django settings:
* ``COURSE_AUTHORING_MICROFRONTEND_URL``: must be set in the CMS environment and point to this MFE's deployment URL.
* ``ZENDESK_*``: necessary if automatic ZenDesk ticket creation is desired
* ``edx-platform`` Feature flags:
* ``ENABLE_EXAM_SETTINGS_HTML_VIEW``: this feature flag must be enabled for the link to the settings view to be shown
* `edx-exams <https://github.com/edx/edx-exams>`_: for this feature to work, the ``edx-exams`` IDA must be deployed and its API accessible by the browser
Configuration
-------------
In additional to the standard settings, the following local configuration item is required:
* ``EXAMS_BASE_URL``: URL to the ``edx-exams`` deployment
Feature Description
-------------------
In Studio, a new item ("Proctored Exam Settings") is added to "Other Course Settings" in the course's "Certificates" settings page. When clicked, this takes the author to the corresponding page in the Course Authoring MFE, where one can:
* Enable proctored exams for the course
* Allow opting out of proctored exams
* Select a proctoring provider
* Enable automatic creation of Zendesk tickets for "suspicious" proctored exam attempts
**********
Developing
**********
`Devstack <https://edx.readthedocs.io/projects/edx-installing-configuring-and-running/en/latest/installation/index.html>`_. If you start Devstack with ``make dev.up.studio`` that should give you everything you need as a companion to this frontend.
Installation and Startup
------------------------
========================
1. Clone the repo:
``git clone https://github.com/edx/frontend-app-course-authoring.git``
``git clone https://github.com/openedx/frontend-app-course-authoring.git``
2. Install npm dependencies:
@@ -32,8 +173,21 @@ If your devstack includes the default Demo course, you can visit the following U
- `Proctored Exam Settings <http://localhost:2001/course/course-v1:edX+DemoX+Demo_Course/proctored-exam-settings>`_
- `Pages and Resources <http://localhost:2001/course/course-v1:edX+DemoX+Demo_Course/pages-and-resources>`_ (work in progress)
Troubleshooting
========================
* ``npm ERR! gyp ERR! build error`` while running npm install on Macs with M1 processors: Probably due to a compatibility issue of node-canvas with M1.
Run ``brew install pkg-config pixman cairo pango libpng jpeg giflib librsvg`` before ``npm install`` to get the correct versions of the dependencies.
If there is still an error, look for "no package [...] found" in the error message and install missing package via brew.
(https://github.com/Automattic/node-canvas/issues/1733)
*********
Deploying
*********
Production Build
----------------
================
The production build is created with ``npm run build``.

View File

@@ -2,4 +2,4 @@
React App i18n HOWTO
####################
This document has moved to the frontend-platform repo: https://github.com/edx/frontend-platform/blob/master/docs/how_tos/i18n.rst
This document has moved to the frontend-platform repo: https://github.com/openedx/frontend-platform/blob/master/docs/how_tos/i18n.rst

37266
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
"description": "Frontend application template",
"repository": {
"type": "git",
"url": "git+https://github.com/edx/frontend-app-course-authoring.git"
"url": "git+https://github.com/openedx/frontend-app-course-authoring.git"
},
"browserslist": [
"extends @edx/browserslist-config"
@@ -25,20 +25,20 @@
},
"author": "edX",
"license": "AGPL-3.0",
"homepage": "https://github.com/edx/frontend-app-course-authoring#readme",
"homepage": "https://github.com/openedx/frontend-app-course-authoring#readme",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/edx/frontend-app-course-authoring/issues"
"url": "https://github.com/openedx/frontend-app-course-authoring/issues"
},
"dependencies": {
"@edx/frontend-build": "8.0.4",
"@edx/brand": "npm:@edx/brand-openedx@1.1.0",
"@edx/frontend-component-footer": "10.1.6",
"@edx/frontend-lib-content-components": "1.20.0",
"@edx/frontend-platform": "1.15.5",
"@edx/paragon": "19.9.0",
"@edx/frontend-build": "^11.0.0",
"@edx/frontend-component-footer": "11.1.1",
"@edx/frontend-lib-content-components": "^1.72.0",
"@edx/frontend-platform": "2.5.1",
"@edx/paragon": "^20.21.0",
"@fortawesome/fontawesome-svg-core": "1.2.28",
"@fortawesome/free-brands-svg-icons": "5.11.2",
"@fortawesome/free-regular-svg-icons": "5.11.2",
@@ -66,19 +66,17 @@
},
"devDependencies": {
"@edx/browserslist-config": "1.0.0",
"@edx/frontend-build": "8.0.4",
"@edx/frontend-build": "^11.0.0",
"@edx/reactifex": "^1.0.3",
"enzyme": "3.11.0",
"enzyme-adapter-react-16": "1.15.6",
"enzyme-to-json": "^3.6.2",
"@testing-library/jest-dom": "5.14.1",
"@testing-library/jest-dom": "5.16.4",
"@testing-library/react": "12.1.1",
"@testing-library/user-event": "^13.2.1",
"axios-mock-adapter": "1.20.0",
"codecov": "3.8.3",
"enzyme": "3.11.0",
"enzyme-adapter-react-16": "1.15.6",
"enzyme-to-json": "^3.6.2",
"glob": "7.1.6",
"husky": "3.1.0",
"jest": "24.9.0",
"react-test-renderer": "16.9.0",
"reactifex": "1.1.1"
}

View File

@@ -1,9 +1,19 @@
{
"extends": [
"config:base"
"config:base",
"schedule:daily",
":rebaseStalePrs",
":semanticCommits"
],
"patch": {
"automerge": true
},
"rebaseStalePrs": true
"rebaseStalePrs": true,
"packageRules": [
{
"matchPackagePatterns": ["@edx"],
"matchUpdateTypes": ["minor", "patch"],
"automerge": true
}
]
}

View File

@@ -28,6 +28,7 @@ export default function CourseAuthoringPage({ courseId, children }) {
const courseTitle = courseDetail ? courseDetail.name : courseId;
const courseAppsApiStatus = useSelector(getCourseAppsApiStatus);
const inProgress = useSelector(getLoadingStatus) === RequestStatus.IN_PROGRESS;
const { pathname } = useLocation();
if (courseAppsApiStatus === RequestStatus.DENIED) {
return (
<PermissionDeniedAlert />
@@ -49,9 +50,8 @@ export default function CourseAuthoringPage({ courseId, children }) {
</div>
);
const { pathname } = useLocation();
return (
<div className="bg-light-200">
<div className={pathname.includes('/editor/') ? '' : 'bg-light-200'}>
{/* While V2 Editors are tempoarily served from thier own pages
using url pattern containing /editor/,
we shouldn't have the header and footer on these pages.

View File

@@ -0,0 +1,34 @@
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { getConfig } from '@edx/frontend-platform';
class ExamsApiService {
static isAvailable() {
return !!this.getExamsBaseUrl();
}
static getExamsBaseUrl() {
return getConfig().EXAMS_BASE_URL;
}
static getExamConfigurationUrl(courseId) {
return `${ExamsApiService.getExamsBaseUrl()}/api/v1/configs/course_id/${courseId}`;
}
static getAvailableProviders() {
const apiClient = getAuthenticatedHttpClient();
const providersUrl = `${ExamsApiService.getExamsBaseUrl()}/api/v1/providers`;
return apiClient.get(providersUrl);
}
static getCourseExamConfiguration(courseId) {
const apiClient = getAuthenticatedHttpClient();
return apiClient.get(this.getExamConfigurationUrl(courseId));
}
static saveCourseExamConfiguration(courseId, dataToSave) {
const apiClient = getAuthenticatedHttpClient();
return apiClient.patch(this.getExamConfigurationUrl(courseId), dataToSave);
}
}
export default ExamsApiService;

View File

@@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { useParams } from 'react-router';
import { EditorPage } from '@edx/frontend-lib-content-components';
import { getConfig } from '@edx/frontend-platform';
const EditorContainer = ({
courseId,
@@ -13,8 +14,8 @@ const EditorContainer = ({
courseId={courseId}
blockType={blockType}
blockId={blockId}
studioEndpointUrl={process.env.STUDIO_BASE_URL}
lmsEndpointUrl={process.env.LMS_BASE_URL}
studioEndpointUrl={getConfig().STUDIO_BASE_URL}
lmsEndpointUrl={getConfig().LMS_BASE_URL}
/>
</div>
);

View File

@@ -2,11 +2,11 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Button, Card } from '@edx/paragon';
const DeletePopup = ({
const ConfirmationPopup = ({
label,
bodyText,
onDelete,
deleteLabel,
onConfirm,
confirmLabel,
onCancel,
cancelLabel,
}) => (
@@ -22,21 +22,21 @@ const DeletePopup = ({
<Button variant="tertiary" onClick={onCancel}>
{cancelLabel}
</Button>
<Button variant="outline-brand" className="ml-2" onClick={onDelete}>
{deleteLabel}
<Button variant="outline-brand" className="ml-2" onClick={onConfirm}>
{confirmLabel}
</Button>
</Card.Footer>
</Card.Body>
</Card>
);
DeletePopup.propTypes = {
ConfirmationPopup.propTypes = {
label: PropTypes.string.isRequired,
bodyText: PropTypes.string.isRequired,
onDelete: PropTypes.func.isRequired,
onConfirm: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
deleteLabel: PropTypes.string.isRequired,
confirmLabel: PropTypes.string.isRequired,
cancelLabel: PropTypes.string.isRequired,
};
export default DeletePopup;
export default ConfirmationPopup;

View File

@@ -13,6 +13,7 @@ export default function FormSwitchGroup({
onChange,
onBlur,
checked,
disabled,
}) {
const helpTextId = `${id}HelpText`;
@@ -36,6 +37,7 @@ export default function FormSwitchGroup({
onChange={onChange}
onBlur={onBlur}
checked={checked}
disabled={disabled}
/>
</div>
<Form.Text
@@ -57,9 +59,11 @@ FormSwitchGroup.propTypes = {
onChange: PropTypes.func.isRequired,
onBlur: PropTypes.func,
checked: PropTypes.bool.isRequired,
disabled: PropTypes.bool,
};
FormSwitchGroup.defaultProps = {
className: null,
onBlur: null,
name: null,
disabled: false,
};

View File

@@ -1,31 +1,27 @@
import arMessages from './messages/ar.json';
import caMessages from './messages/ca.json';
// no need to import en messages-- they are in the defaultMessage field
import es419Messages from './messages/es_419.json';
import frMessages from './messages/fr.json';
import es419Messages from './messages/es_419.json';
import zhcnMessages from './messages/zh_CN.json';
import heMessages from './messages/he.json';
import idMessages from './messages/id.json';
import kokrMessages from './messages/ko_kr.json';
import plMessages from './messages/pl.json';
import ptbrMessages from './messages/pt_br.json';
import ruMessages from './messages/ru.json';
import thMessages from './messages/th.json';
import ptMessages from './messages/pt.json';
import itMessages from './messages/it.json';
import ukMessages from './messages/uk.json';
import deMessages from './messages/de.json';
import ruMessages from './messages/ru.json';
import hiMessages from './messages/hi.json';
import frCAMessages from './messages/fr_CA.json';
// no need to import en messages-- they are in the defaultMessage field
const messages = {
ar: arMessages,
'es-419': es419Messages,
fr: frMessages,
'zh-cn': zhcnMessages,
ca: caMessages,
he: heMessages,
id: idMessages,
'ko-kr': kokrMessages,
pl: plMessages,
'pt-br': ptbrMessages,
pt: ptMessages,
it: itMessages,
de: deMessages,
hi: hiMessages,
'fr-ca': frCAMessages,
ru: ruMessages,
th: thMessages,
uk: ukMessages,
};

View File

@@ -1,52 +1,57 @@
{
"authoring.alert.error.connection": "We encountered a technical error when loading this page. This might be a temporary issue, so please try again in a few minutes. If the problem persists, please go to the {supportLink} for help.",
"authoring.loading": "Loading...",
"authoring.alert.error.permission": "You are not authorized to view this page. If you feel you should have access, please reach out to your course team admin to be given access.",
"authoring.alert.save.error.connection": "We encountered a technical error when applying changes. This might be a temporary issue, so please try again in a few minutes. If the problem persists, please go to the {supportLink} for help.",
"authoring.alert.support.text": "Support Page",
"course-authoring.pages-resources.app-settings-modal.button.cancel": "Cancel",
"course-authoring.pages-resources.app-settings-modal.button.save": "Save",
"course-authoring.pages-resources.app-settings-modal.button.saving": "Saving",
"course-authoring.pages-resources.app-settings-modal.button.saved": "Saved",
"course-authoring.pages-resources.app-settings-modal.button.retry": "Retry",
"course-authoring.pages-resources.app-settings-modal.badge.enabled": "Enabled",
"course-authoring.pages-resources.app-settings-modal.badge.disabled": "Disabled",
"course-authoring.pages-resources.app-settings-modal.save-error.title": "We couldn't apply your changes.",
"course-authoring.pages-resources.app-settings-modal.save-error.message": "Please check your entries and try again.",
"course-authoring.pages-resources.calculator.heading": "Configure calculator",
"course-authoring.pages-resources.calculator.enable-calculator.label": "Calculator",
"course-authoring.pages-resources.calculator.enable-calculator.help": "The calculator supports numbers, operators, constants,\n functions, and other mathematical concepts. When enabled, an icon to\n access the calculator appears on all pages in the body of your course.",
"course-authoring.pages-resources.calculator.enable-calculator.link": "Learn more about the calculator",
"authoring.discussions.documentationPage": "Visit the {name} documentation page",
"authoring.discussions.formInstructions": "Complete the fields below to set up your discussion tool.",
"authoring.discussions.consumerKey": "Consumer Key",
"authoring.discussions.consumerKey.required": "Consumer key is a required field",
"authoring.discussions.consumerSecret": "Consumer Secret",
"authoring.discussions.consumerSecret.required": "Consumer secret is a required field",
"authoring.discussions.launchUrl": "Launch URL",
"authoring.discussions.launchUrl.required": "Launch URL is a required field",
"authoring.discussions.stuffOnlyConfigInfo": "To enable {providerName} for your course, please contact their support team at {supportEmail} to learn more about pricing and usage.",
"authoring.discussions.stuffOnlyConfigGuide": "To fully configure {providerName} will also require sharing usernames and emails for learners and course team. Please contact your edX project coordinator to enable PII sharing for this course.",
"authoring.discussions.piiSharing": "Optionally share a user's username and/or email with the LTI provider:",
"authoring.discussions.piiShareUsername": "Share username",
"authoring.discussions.piiShareEmail": "Share email",
"authoring.discussions.appDocInstructions.contact": "Contact: {link}",
"authoring.discussions.appDocInstructions.documentationLink": "General documentation",
"authoring.discussions.appDocInstructions.accessibilityDocumentationLink": "Accessibility documentation",
"authoring.discussions.appDocInstructions.configurationLink": "Configuration documentation",
"authoring.discussions.appDocInstructions.learnMoreLink": "Learn more about {providerName}",
"authoring.discussions.appDocInstructions.linkTextHeading": "External help and documentation",
"authoring.alert.error.connection": "واجهنا خطأ تقنيًا أثناء تحميل هذه الصفحة. قد تكون هذه مشكلة عارضة، لذا يرجى المحاولة مجددًا خلال بضع دقائق. إن استمرت المشكلة فيرجى الذهاب إلى {support_link} للحصول على المساعدة.",
"authoring.loading": "التحميل جارٍ...",
"authoring.alert.error.permission": "لست مخوّلا بمشاهدة هذه الصفحة. إن كنت ترى أن لديك حقًا في ذلك، فيرجى التواصل مع مدير فريق مساقك ليمنحك حق الوصول.",
"authoring.alert.save.error.connection": "واجهنا خطأ تقنيًا أثناء تطبيق التغييرات. قد تكون هذه مشكلة عارضة، لذا يرجى المحاولة مجددًا خلال بضع دقائق. إن استمرت المشكلة فيرجى الذهاب إلى {support_link} للحصول على المساعدة.",
"authoring.alert.support.text": "صفحة الدعم",
"course-authoring.pages-resources.app-settings-modal.button.cancel": "إلغاء",
"course-authoring.pages-resources.app-settings-modal.button.save": "حفظ",
"course-authoring.pages-resources.app-settings-modal.button.saving": "الحفظ جارٍ",
"course-authoring.pages-resources.app-settings-modal.button.saved": "تم الحفظ",
"course-authoring.pages-resources.app-settings-modal.button.retry": "إعادة المحاولة",
"course-authoring.pages-resources.app-settings-modal.badge.enabled": "مفعّل",
"course-authoring.pages-resources.app-settings-modal.badge.disabled": "معطل",
"course-authoring.pages-resources.app-settings-modal.save-error.title": "لم نتمكن من تطبيق تغييراتك.",
"course-authoring.pages-resources.app-settings-modal.save-error.message": "رجاءً تحقق من مدخلاتك و حاول مجددًا.",
"course-authoring.pages-resources.calculator.heading": "تهيئة الآلة الحاسبة",
"course-authoring.pages-resources.calculator.enable-calculator.label": "الآلة الحاسبة",
"course-authoring.pages-resources.calculator.enable-calculator.help": "تقبل الحاسبة الأرقام، العمليات، الثوابت، الدوال، و مفاهيم رياضية أخرى. عند تمكينها، ستظهر أيقونة للوصول إلى الآلة الحاسبة في كل صفحة من متن مساقك.",
"course-authoring.pages-resources.calculator.enable-calculator.link": "معرفة المزيد عن الآلة الحاسبة",
"authoring.discussions.documentationPage": "زيارة صفجة وثائق {name}.",
"authoring.discussions.formInstructions": "أكمل الحقول أدناه لتثبيت أداة المناقشة.",
"authoring.discussions.consumerKey": "مفتاح المستهلك (Consumer Key)",
"authoring.discussions.consumerKey.required": "حقل مفتاح المستهلك مطلوب",
"authoring.discussions.consumerSecret": "سر المستهلك (Consumer Secret)",
"authoring.discussions.consumerSecret.required": "حقل سر المستهلك مطلوب",
"authoring.discussions.launchUrl": "عنوان التشغيل (Launch URL)",
"authoring.discussions.launchUrl.required": "حقل تفعيل عنوان التشغيل مطلوب",
"authoring.discussions.stuffOnlyConfigInfo": "لتفعيل {providerName} لمساقك، يرجى الاتصال بفريق الدعم الخاص بهم {supportEmail} لمعرفة المزيد حول الأسعار و الاستخدام.",
"authoring.discussions.stuffOnlyConfigGuide": "إتمام تهيئة {providerName} يتطلب كذلك مشاركة أسماء المستخدمين و عناوين البريد الإلكتروني الخاصة بالمتعلمي و بفريق المساق. يرجى الاتصال بمنسق مشروعك على edX لتفعيل مشاركة معلومات التعريف الشخصية لهذا المساق.",
"authoring.discussions.piiSharing": "شارك اختياريًا اسم المستخدم و / أو بريده الالكتروني مع مزود LTI.",
"authoring.discussions.piiShareUsername": "مشاركة اسم المستخدم",
"authoring.discussions.piiShareEmail": "مشاركة البريد الإلكتروني",
"authoring.discussions.appDocInstructions.contact": "اتصل بـ: {link}",
"authoring.discussions.appDocInstructions.documentationLink": "الوثائق العامة",
"authoring.discussions.appDocInstructions.accessibilityDocumentationLink": "وثائق قابلية الوصول",
"authoring.discussions.appDocInstructions.configurationLink": "وثائق التهيئة",
"authoring.discussions.appDocInstructions.learnMoreLink": "معرفة المزيد عن {providerName}",
"authoring.discussions.appDocInstructions.linkTextHeading": "مساعدة و وثائق خارجية",
"authoring.discussions.appDocInstructions.linkText": "{link}",
"authoring.discussions.configurationChangeConsequences": "Students will lose access to any active or previous discussion posts for your course.",
"authoring.discussions.configure.app": "Configure {name}",
"authoring.discussions.configure": "Configure discussions",
"authoring.discussions.ok": "OK",
"authoring.discussions.cancel": "Cancel",
"authoring.discussions.confirmConfigurationChange": "Are you sure you want to change the discussion settings?",
"authoring.discussions.backButton": "Back",
"authoring.discussions.saveButton": "Save",
"authoring.discussions.savingButton": "Saving",
"authoring.discussions.savedButton": "Saved",
"authoring.discussions.configurationChangeConsequences": "سيفقد الطلبة امكانية الوصول لأي منشورات مناقشة حالية أو سابقة في مساقك.",
"authoring.discussions.configure.app": "تهيئة {name}",
"authoring.discussions.configure": "تهيئة المناقشات",
"authoring.discussions.ok": "حسناً",
"authoring.discussions.cancel": "إلغاء",
"authoring.discussions.confirm": "تأكيد",
"authoring.discussions.confirmConfigurationChange": "أمتأكد أنك تريد تغيير إعدادات المناقشة؟",
"authoring.discussions.confirmEnableDiscussionsLabel": "هل تريد تفعيل المناقشات على الوحدات في الأقسام الفرعية المنقّطة؟",
"authoring.discussions.cancelEnableDiscussionsLabel": "هل تريد تعطيل المناقشات على الوحدات في الأقسام الفرعية المنقّطة؟",
"authoring.discussions.confirmEnableDiscussions": "سيؤدي تفعيل هذا الخيار إلى تمكين المناقشة تلقائيًا على جميع وحدات الأقسام الفرعية المنقطّة باستثناء الامتحانات الموقوتة.",
"authoring.discussions.cancelEnableDiscussions": "سيؤدي تعطيل هذا الخيار إلى تعطيل المناقشة تلقائيًا في جميع وحدات الأقسام الفرعية المنقّطة. سيتم إدراج مواضيع المناقشة التي تحتوي رسالة واحدة على الأقل ضمن \"المواضيع المؤرشفة\" تحت تبويب المواضيع على صفحة المناقشات.",
"authoring.discussions.backButton": "رجوع",
"authoring.discussions.saveButton": "حفظ",
"authoring.discussions.savingButton": "الحفظ جارٍ",
"authoring.discussions.savedButton": "تم الحفظ",
"authoring.discussions.appConfigForm.appName-piazza": "Piazza",
"authoring.discussions.appConfigForm.appName-yellowdig": "Yellowdig",
"authoring.discussions.appConfigForm.appName-inscribe": "InScribe",
@@ -54,290 +59,294 @@
"authoring.discussions.appConfigForm.appName-ed-discuss": "Ed Discussion",
"authoring.discussions.appConfigForm.appName-legacy": "edX",
"authoring.discussions.appConfigForm.appName-openedx": "edX",
"authoring.discussions.builtIn.divisionByGroup": "Cohorts",
"authoring.discussions.builtIn.divideByCohorts.label": "Divide discussions by cohorts",
"authoring.discussions.builtIn.divideByCohorts.help": "Learners will only be able to view and respond to discussions posted by members of their cohort.",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.label": "Divide course-wide discussion topics",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.help": "Choose which of your general course-wide discussion topics you would like to divide.",
"authoring.discussions.builtIn.divideGeneralTopic.label": "General",
"authoring.discussions.builtIn.divideQuestionsForTAsTopic.label": "Questions for the TAs",
"authoring.discussions.builtIn.visibilityInContext": "Visibility of in-context discussions",
"authoring.discussions.builtIn.inContextDiscussion.label": "In-context discussion",
"authoring.discussions.builtIn.inContextDiscussion.help": "Learners will be able to view or hide a discussion side panel to engage with discussion on the course unit page.",
"authoring.discussions.builtIn.gradedUnitPages.label": "Graded unit pages",
"authoring.discussions.builtIn.gradedUnitPages.help": "Allow learners to engage with discussion on all graded unit pages except timed exams.",
"authoring.discussions.builtIn.groupInContextSubsection.label": "Group in context discussion at the subsection level",
"authoring.discussions.builtIn.groupInContextSubsection.help": "Learners will be able to view any post in the sub-section no matter which unit page they are viewing. While this is not recommended, if your course has short learning sequences or low enrollment grouping may increase engagement.",
"authoring.discussions.builtIn.allowUnitLevelVisibility.label": "Allow visibility configuration for each course unit",
"authoring.discussions.builtIn.allowUnitLevelVisibility.help": "With this advanced setting enabled you will be able to override the global visibility setting and turn discussions on or off for each unit from the course outline view..",
"authoring.discussions.builtIn.anonymousPosting": "Anonymous posting",
"authoring.discussions.builtIn.allowAnonymous.label": "Allow anonymous discussion posts",
"authoring.discussions.builtIn.allowAnonymous.help": "If enabled, learners can create posts that are anonymous to all users.",
"authoring.discussions.builtIn.allowAnonymousPeers.label": "Allow anonymous discussion posts to peers",
"authoring.discussions.builtIn.allowAnonymousPeers.help": "Learners will be able to post anonymously to other peers but all posts will be visible to course staff.",
"authoring.discussions.builtIn.reportedContentEmailNotifications": "Notifications",
"authoring.discussions.builtIn.reportedContentEmailNotifications.label": "Email notifications for reported content",
"authoring.discussions.builtIn.reportedContentEmailNotifications.help": "Discussion Admins, Moderators, Community TAs and Group Community TAs (only for their own cohort) will receive an email notification when content is reported.",
"authoring.discussions.discussionTopics": "Discussion topics",
"authoring.discussions.discussionTopics.label": "General discussion topics",
"authoring.discussions.discussionTopics.help": "Discussions can include general topics not contained to the course structure. All courses have a general topic by default.",
"authoring.discussions.discussionTopic.required": "Topic name is a required field",
"authoring.discussions.discussionTopic.alreadyExistError": "It looks like this name is already in use",
"authoring.discussions.addTopicButton": "Add topic",
"authoring.discussions.deleteButton": "Delete",
"authoring.discussions.cancelButton": "Cancel",
"authoring.discussions.discussionTopicDeletion.help": "edX recommends that you do not delete discussion topics once your course is running.",
"authoring.discussions.discussionTopicDeletion.label": "Delete this topic?",
"authoring.discussions.builtIn.renameGeneralTopic.label": "Rename general topic",
"authoring.discussions.generalTopicHelp.help": "This is the default discussion topic for your course.",
"authoring.discussions.builtIn.configureAdditionalTopic.label": "Configure topic",
"authoring.discussions.addTopicHelpText": "Choose a unique name for your topic",
"authoring.discussions.blackoutDates": "Discussion blackout dates",
"authoring.discussions.builtIn.blackoutDates.label": "Blackout dates",
"authoring.discussions.builtIn.blackoutDates.help": "If added, learners will not be able to post in discussions between these dates.",
"authoring.discussions.addBlackoutDatesButton": "Add blackout date range",
"authoring.discussions.builtIn.configureBlackoutDates.label": "Configure blackout date range",
"authoring.discussions.blackoutStartDate.help": "Enter a start date, e.g. 12/10/2023",
"authoring.discussions.blackoutEndDate.help": "Enter an end date, e.g. 12/17/2023",
"authoring.discussions.blackoutStartTime.help": "Enter a start time, e.g. 09:00 AM",
"authoring.discussions.blackoutEndTime.help": "Enter an end time, e.g. 05:00 PM",
"authoring.discussions.activeBlackoutDatesDeletion.help": "These blackout dates are currently active. If deleted, learners will be able to post in discussions during these dates. Are you sure you want to proceed?",
"authoring.discussions.blackoutDatesDeletion.help": "If deleted, learners will be able to post in discussions during these dates.",
"authoring.discussions.completeBlackoutDatesDeletion.help": "Are you sure you want to delete these blackout dates?",
"authoring.discussions.activeBlackoutDatesDeletion.label": "Delete active blackout dates?",
"authoring.discussions.blackoutDatesDeletion.label": "Delete blackout dates?",
"authoring.blackoutDates.delete": "Delete Blackout Dates",
"authoring.discussions.builtIn.divisionByGroup": "الأفواج",
"authoring.discussions.builtIn.divideByCohorts.label": "تقسيم المناقشات حسب الأفواج",
"authoring.discussions.builtIn.divideByCohorts.help": "سيستطيع المتعلمون القراءة و الرد على المناقشات التي ينشرها أعضاء فوجهم فقط.",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.label": "تقسيم مناقشات المساق العامة",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.help": "اختر من بين مواضيع المناقشة العامة على مستوى مساقك، أي المواضيع تريد أن تقسّم.",
"authoring.discussions.builtIn.divideGeneralTopic.label": "عام",
"authoring.discussions.builtIn.divideQuestionsForTAsTopic.label": "أسئلة للأساتذة المساعدين",
"authoring.discussions.builtIn.cohortsEnabled.label": "لضبط هذه الإعدادات، قم بتفعيل الأفواج على ",
"authoring.discussions.builtIn.instructorDashboard.label": "لوحة معلومات الأستاذ",
"authoring.discussions.builtIn.visibilityInContext": "رؤية المناقشات ذات السياق.",
"authoring.discussions.builtIn.gradedUnitPages.label": "تفعيل المناقشات على الوحدات المتواجدة في أقسام فرعية منقّطة",
"authoring.discussions.builtIn.gradedUnitPages.help": "السماح للطلاب بالتفاعل مع المناقشات على جميع صفحات الوحدات باستثناء الامتحانات الموقوتة.",
"authoring.discussions.builtIn.groupInContextSubsection.label": "تجميع المناقشات ذات السياق على مستوى الأقسام الفرعية.",
"authoring.discussions.builtIn.groupInContextSubsection.help": "سيستطيع المتعلمون عرض أي منشور في القسم الفرعي بغض النظر عن صفحة الوحدة التي يشاهدونها. رغم أن هذا غير مستحسن، فإنه قد يزيد من المشاركة إن كان مساقك يحتوي على سلاسل تعلبمية قصيرة أو يتضمن أفواجًا صغيرة من المسجلين.",
"authoring.discussions.builtIn.anonymousPosting": "النشر كمجهول",
"authoring.discussions.builtIn.allowAnonymous.label": "السماح بمنشورات المناقشة مجهولة الكاتب",
"authoring.discussions.builtIn.allowAnonymous.help": "عند التفعيل، سيستطيع الطلاب إنشاء منشورات تبدو لجميع المستخدمين مجهولة الكاتب.",
"authoring.discussions.builtIn.allowAnonymousPeers.label": "السماح للأقران بنشر مناقشات مجهولة الكاتب.",
"authoring.discussions.builtIn.allowAnonymousPeers.help": "سيستطيع المتعلمون النشر دون الكشف عن هويتهم لأقرانهم، لكن جميع المنشورات ستكون مرئية لطاقم المساق.",
"authoring.discussions.builtIn.reportedContentEmailNotifications": "الإشعارات",
"authoring.discussions.builtIn.reportedContentEmailNotifications.label": "بريد إلكتروني للإشعار بالمحتوى المبلغ عنه",
"authoring.discussions.builtIn.reportedContentEmailNotifications.help": "سيتلقى مدراء المناقشة، المشرفون، أساتذة المجتمع المساعدون، و أساتذة الفوج المساعدون (فقط في أفواجهم) بريدًا إلكترونيا عند التبليغ عن محتوى.",
"authoring.discussions.discussionTopics": "مواضيع المناقشة",
"authoring.discussions.discussionTopics.label": "مواضيع المناقشة العامة",
"authoring.discussions.discussionTopics.help": "قد تحتوى المناقشات مواضيع عامة ليست ضمن هيكل المساق. لدى جميع المساقات موضوع عام بشكل افتراضي.",
"authoring.discussions.discussionTopic.required": "حقل اسم الموضوع مطلوب",
"authoring.discussions.discussionTopic.alreadyExistError": "يبدو أن هذا الاسم مستخدم من قبل",
"authoring.discussions.addTopicButton": "إضافة موضوع",
"authoring.discussions.deleteButton": "حذف",
"authoring.discussions.cancelButton": "إلغاء",
"authoring.discussions.discussionTopicDeletion.help": "ننصح في edX بعدم حذف مواضيع المناقشة بعد إنطلاق مساقك.",
"authoring.discussions.discussionTopicDeletion.label": "هل تريد حذف هذا الموضوع؟",
"authoring.discussions.builtIn.renameGeneralTopic.label": "تعديل اسم الموضوع العام",
"authoring.discussions.generalTopicHelp.help": "هذا هو موضوع المناقشة الافتراضي لمساقك.",
"authoring.discussions.builtIn.configureAdditionalTopic.label": "تهيئة الموضوع",
"authoring.discussions.addTopicHelpText": "اختر اسما فريدًا لموضوعك",
"authoring.discussions.blackoutDates": "مواعيد تعطيل المناقشة",
"authoring.discussions.builtIn.blackoutDates.label": "مواعيد التعطيل",
"authoring.discussions.builtIn.blackoutDates.help": "عند الإضافة لن يستطيع المتعلمون النشر في المناقشات بين هذه التواريخ.",
"authoring.discussions.addBlackoutDatesButton": "إضافة نطاق زمني للتعطيل",
"authoring.discussions.builtIn.configureBlackoutDates.label": "تهيئة النطاق الزمني للتعطيل",
"authoring.discussions.blackoutStartDate.help": "أدخل تاريخ بدء، مثلا 12/10/2023",
"authoring.discussions.blackoutEndDate.help": "أدخل تاريخ انتهاء، مثلا 12/17/2023",
"authoring.discussions.blackoutStartTime.help": "أدخل وقت البدء، مثلا 09:00 صباحًا",
"authoring.discussions.blackoutEndTime.help": "أدخل وقت الانتهاء، مثلا 05:00 مساءً",
"authoring.discussions.activeBlackoutDatesDeletion.help": "مواعيد التعطيل هذه مفعّلة حاليا. إن تم حذفها، فسيستطيع المتعلمون النشر في المناقشات خلال هذه التواريخ. هل انت متأكد أنك تريد المواصلة؟",
"authoring.discussions.blackoutDatesDeletion.help": "عند الحذف سيستطيع المتعلمون النشر في المناقشات خلال هذه التواريخ.",
"authoring.discussions.completeBlackoutDatesDeletion.help": "هل أنت متأكد أنك تريد حذف تواريخ التعطيل هذه؟",
"authoring.discussions.activeBlackoutDatesDeletion.label": "هل تريد حذف تواريخ التعطيل المفعّلة؟",
"authoring.discussions.blackoutDatesDeletion.label": "هل تريد حذف تواريخ التعطيل؟",
"authoring.blackoutDates.delete": "حذف تواريخ التعطيل",
"authoring.blackoutDates.status": "{status}",
"authoring.blackoutDates.startDate.required": "Start date is a required field",
"authoring.blackoutDates.endDate.required": "End date is a required field",
"authoring.blackoutDates.startDate.inPast": "Start date cannot be after end date",
"authoring.blackoutDates.endDate.inPast": "End date cannot be before start date",
"authoring.blackoutDates.startTime.inPast": "Start time cannot be after end time",
"authoring.blackoutDates.endTime.inPast": "End time cannot be before start time",
"authoring.blackoutDates.startTime.inValidFormat": "Enter a valid start time",
"authoring.blackoutDates.endTime.inValidFormat": "Enter a valid end time",
"authoring.blackoutDates.startDate.inValidFormat": "Enter a valid start Date",
"authoring.blackoutDates.endDate.inValidFormat": "Enter a valid end date",
"authoring.topics.delete": "Delete Topic",
"authoring.topics.expand": "Expand",
"authoring.topics.collapse": "Collapse",
"authoring.blackoutDates.start.date": "Start date",
"authoring.blackoutDates.start.time": "Start time (optional) ({zone})",
"authoring.blackoutDates.end.date": "End date",
"authoring.blackoutDates.end.time": "End time (optional) ({zone})",
"authoring.discussions.heading": "Select a discussion tool for this course",
"authoring.discussions.supportedFeatures": "Supported features",
"authoring.discussions.supportedFeatureList-mobile-show": "Show supported features",
"authoring.discussions.supportedFeatureList-mobile-hide": "Hide supported features",
"authoring.discussions.noApps": "There are no discussions providers available for your course.",
"authoring.discussions.nextButton": "Next",
"authoring.discussions.appFullSupport": "Full support",
"authoring.discussions.appBasicSupport": "Basic support",
"authoring.discussions.selectApp": "Select {appName}",
"authoring.blackoutDates.startDate.required": "حقل تاريخ البدء مطلوب",
"authoring.blackoutDates.endDate.required": "حقل تاريخ الانتهاء مطلوب",
"authoring.blackoutDates.startDate.inPast": "لا يمكن لتاريخ البدء أن يأتي بعد تاريخ الانتهاء",
"authoring.blackoutDates.endDate.inPast": "لا يمكن لتاريخ الانتهاء أن يسبق تاريخ البدء",
"authoring.blackoutDates.startTime.inPast": "لا يمكن لوقت البدء أن يأتي بعد وقت الانتهاء",
"authoring.blackoutDates.endTime.inPast": "لا يمكن لوقت الانتهاء أن يسبق وقت البدء",
"authoring.blackoutDates.startTime.inValidFormat": "أدخل وقت بدء صالحًا",
"authoring.blackoutDates.endTime.inValidFormat": "أدخل وقت انتهاء صالحًا",
"authoring.blackoutDates.startDate.inValidFormat": "أدخل تاريخ بدء صالحًا",
"authoring.blackoutDates.endDate.inValidFormat": "أدخل تاريخ انتهاء صالحًا",
"authoring.topics.delete": "حذف الموضوع",
"authoring.topics.expand": "توسيع",
"authoring.topics.collapse": "طي",
"authoring.blackoutDates.start.date": "تاريخ البدء",
"authoring.blackoutDates.start.time": "وقت البدء (اختياري) ({zone})",
"authoring.blackoutDates.end.date": "تاريخ الانتهاء",
"authoring.blackoutDates.end.time": "وقت الانتهاء (اختياري) ({zone})",
"authoring.discussions.heading": "حدد أداة مناقشة لهذا المساق.",
"authoring.discussions.supportedFeatures": "الميزات المدعومة",
"authoring.discussions.supportedFeatureList-mobile-show": "إظهار الميزات المدعومة",
"authoring.discussions.supportedFeatureList-mobile-hide": "إخفاء الميزات المدعومة",
"authoring.discussions.noApps": "لا يوجد أي مزود مناقشات متوفّر لمساقك.",
"authoring.discussions.nextButton": "التالي",
"authoring.discussions.appFullSupport": "دعم كامل",
"authoring.discussions.appBasicSupport": "دعم قاعدي",
"authoring.discussions.selectApp": "اختيار {اسم تطبيق}",
"authoring.discussions.appList.appName-legacy": "edX",
"authoring.discussions.appList.appDescription-legacy": "Start conversations with other learners, ask questions, and interact with other learners in the course.",
"authoring.discussions.appList.appDescription-legacy": "ابدأ مناقشات مع متعلمين آخرين، اطرح أسئلة، و تفاعل مع المتعلمين في المساق.",
"authoring.discussions.appList.appName-openedx": "edX",
"authoring.discussions.appList.appDescription-openedx": "Start conversations with other learners, ask questions, and interact with other learners in the course.",
"authoring.discussions.appList.appDescription-openedx": "ابدأ مناقشات مع متعلمين آخرين، اطرح أسئلة، و تفاعل مع المتعلمين في المساق.",
"authoring.discussions.appList.appName-piazza": "Piazza",
"authoring.discussions.appList.appDescription-piazza": "Piazza is designed to connect students, TAs, and professors so every student can get the help they need when they need it.",
"authoring.discussions.appList.appDescription-yellowdig": "Yellowdig offers educators a gameful learning digital solution to improve student engagement by building learning communities for any course modality.",
"authoring.discussions.appList.appDescription-inscribe": "InScribe leverages the power of community + artificial intelligence to connect individuals to the answers, resources, and people they need to succeed.",
"authoring.discussions.appList.appDescription-discourse": "Discourse is modern forum software for your community. Use it as a mailing list, discussion forum, long-form chat room, and more!",
"authoring.discussions.appList.appDescription-ed-discus": "Ed Discussion helps scale class communication in a beautiful and intuitive interface. Questions reach and benefit the whole class. Less emails, more time saved.",
"authoring.discussions.featureName-discussion-page": "Discussion page",
"authoring.discussions.featureName-embedded-course-sections": "Embedded course sections",
"authoring.discussions.featureName-advanced-in-context-discussion": "Advanced in context discussion",
"authoring.discussions.featureName-anonymous-posting": "Anonymous posting",
"authoring.discussions.featureName-automatic-learner-enrollment": "Automatic learner enrollment",
"authoring.discussions.featureName-blackout-discussion-dates": "Blackout discussion dates",
"authoring.discussions.featureName-community-ta-support": "Community TA support",
"authoring.discussions.featureName-course-cohort-support": "Course cohort support",
"authoring.discussions.featureName-direct-messages-from-instructors": "Direct messages from instructors",
"authoring.discussions.featureName-discussion-content-prompts": "Discussion content prompts",
"authoring.discussions.featureName-email-notifications": "Email notifications",
"authoring.discussions.featureName-graded-discussions": "Graded discussions",
"authoring.discussions.featureName-in-platform-notifications": "In-platform notifications",
"authoring.discussions.featureName-internationalization-support": "Internationalization support",
"authoring.discussions.featureName-lti-advanced-sharing-mode": "LTI advanced sharing",
"authoring.discussions.featureName-basic-configuration": "Basic configuration",
"authoring.discussions.featureName-primary-discussion-app-experience": "Primary discussion app experience",
"authoring.discussions.featureName-question-&-discussion-support": "Question & discussion support",
"authoring.discussions.featureName-report/flag-content-to-moderators": "Report content to moderators",
"authoring.discussions.featureName-research-data-events": "Research data events",
"authoring.discussions.featureName-simplified-in-context-discussion": "Simplified in-context discussion",
"authoring.discussions.featureName-user-mentions": "User mentions",
"authoring.discussions.featureName-wcag-2.1": "WCAG 2.1 support",
"authoring.discussions.wcag-2.0-support": "WCAG 2.0 support",
"authoring.discussions.basic-support": "Basic support",
"authoring.discussions.partial-support": "Partial support",
"authoring.discussions.full-support": "Full support",
"authoring.discussions.common-support": "Commonly requested",
"authoring.discussions.settings": "Settings",
"authoring.discussions.applyButton": "Apply",
"authoring.discussions.applyingButton": "Applying",
"authoring.discussions.appliedButton": "Applied",
"authoring.discussions.noProviderSwitchAfterCourseStarted": "Discussion provider can't be changed after course has started, please reach out to partner support.",
"authoring.discussions.providerSelection": "Provider selection",
"authoring.discussions.Incomplete": "Incomplete",
"course-authoring.pages-resources.notes.heading": "Configure notes",
"course-authoring.pages-resources.notes.enable-notes.label": "Notes",
"course-authoring.pages-resources.notes.enable-notes.help": "Learners can access their notes either in the body of the\n course of on a notes page. On the notes page, a learner can see all the\n notes made during the course. The page also contains links to the location\n of the notes in the course body.",
"course-authoring.pages-resources.notes.enable-notes.link": "Learn more about notes",
"authoring.pagesAndResources.live.enableLive.heading": "Configure Live",
"authoring.pagesAndResources.live.enableLive.label": "Live",
"authoring.pagesAndResources.live.enableLive.help": "Schedule meetings and conduct live course sessions with learners.",
"authoring.pagesAndResources.live.enableLive.link": "Learn more about live",
"authoring.live.selectProvider": "Select a video conferencing tool",
"authoring.live.formInstructions": "Complete the fields below to set up your video conferencing tool.",
"authoring.live.consumerKey": "Consumer Key",
"authoring.live.consumerKey.required": "Consumer key is a required field",
"authoring.live.consumerSecret": "Consumer Secret",
"authoring.live.consumerSecret.required": "Consumer secret is a required field",
"authoring.live.launchUrl": "Launch URL",
"authoring.live.launchUrl.required": "Launch URL is a required field",
"authoring.live.launchEmail": "Launch Email",
"authoring.live.launchEmail.required": "Launch Email is a required field",
"authoring.live.provider.helpText": "This configuration will require sharing username and emails of learners and the course team with {providerName}.",
"authoring.live.requestPiiSharingEnable": "This configuration will require sharing usernames and emails of learners and the course team with {provider}. To access the LTI configuration for {provider}, please request your edX project coordinator to get PII sharing enabled for this course.",
"authoring.live.appDocInstructions.documentationLink": "General documentation",
"authoring.live.appDocInstructions.accessibilityDocumentationLink": "Accessibility documentation",
"authoring.live.appDocInstructions.configurationLink": "Configuration documentation",
"authoring.live.appDocInstructions.learnMoreLink": "Learn more about {providerName}",
"authoring.live.appDocInstructions.linkTextHeading": "External help and documentation",
"authoring.discussions.appList.appDescription-piazza": "Piazza مصمم لربط الطلبة، الأساتذة، و الأساتذة المساعدين بما يمكن كل طالب من الحصول على المساعدة التي يحتاجها في حينها.",
"authoring.discussions.appList.appDescription-yellowdig": "Yellowdig يقدم للمعلمين حلاً رقميًا تعليميًا ممتعًا لتحسين مشاركة الطلاب من خلال بناء مجتمعات متعلمين لأي نمط مساق. ",
"authoring.discussions.appList.appDescription-inscribe": " InScribe يستفيد من قوة المجتمع + الذكاء الاصطناعي لربط الأفراد بالإجابات و الموارد و الأشخاص الذين يحتاجونهم لينجحوا.",
"authoring.discussions.appList.appDescription-discourse": "Discourse برنامج منتدى حديث لمجتمعك. استخدمه كقائمة بريدية، كمنتدى مناقشة، كغرفة دردشة طويلة، و أكثر من ذلك!",
"authoring.discussions.appList.appDescription-ed-discus": "يساعد Ed Discussion على توسيع نطاق التواصل في الفصل في واجهة جميلة وبديهية. الأسئلة تبلغ و تفيد الفصل بأكمله. قلل من رسائل البريد الإلكتروني و اربح مزيدًا من الوقت.",
"authoring.discussions.featureName-discussion-page": "صفحة المناقشة",
"authoring.discussions.featureName-embedded-course-sections": "أقسام فرعية للمساق",
"authoring.discussions.featureName-advanced-in-context-discussion": "متقدم في المناقشات ذات السياق",
"authoring.discussions.featureName-anonymous-posting": "النشر كمجهول",
"authoring.discussions.featureName-automatic-learner-enrollment": "تسجيل المتعلمين تلقائيا",
"authoring.discussions.featureName-blackout-discussion-dates": "مواعيد تعطيل المناقشة",
"authoring.discussions.featureName-community-ta-support": "دعم الأساتذة المساعدين من المجتمع",
"authoring.discussions.featureName-course-cohort-support": "دعم أفواج المساق",
"authoring.discussions.featureName-direct-messages-from-instructors": "الرسائل المباشرة من الأساتذة",
"authoring.discussions.featureName-discussion-content-prompts": "إرشادات عن محتوى المناقشة",
"authoring.discussions.featureName-email-notifications": "إشعارات البريد الإلكتروني",
"authoring.discussions.featureName-graded-discussions": "المناقشات المنقّطة",
"authoring.discussions.featureName-in-platform-notifications": "الإشعارات داخل المنصة",
"authoring.discussions.featureName-internationalization-support": "دعم التدويل",
"authoring.discussions.featureName-lti-advanced-sharing-mode": "مشاركة LTI متقدمة",
"authoring.discussions.featureName-basic-configuration": "التهيئة القاعدية",
"authoring.discussions.featureName-primary-discussion-app-experience": "التجربة الأساسية لتطبيق المناقشة",
"authoring.discussions.featureName-question-&-discussion-support": "دعم الأسئلة و المناقشات",
"authoring.discussions.featureName-report/flag-content-to-moderators": "تبليغ المشرفين عن المحتوى",
"authoring.discussions.featureName-research-data-events": "أحداث بيانات البحث",
"authoring.discussions.featureName-simplified-in-context-discussion": "مناقشات ذات سياق مبسطة",
"authoring.discussions.featureName-user-mentions": "الإشارة للمستخدمين",
"authoring.discussions.featureName-wcag-2.1": "دعم WCAG 2.1",
"authoring.discussions.wcag-2.0-support": "دعم WCAG 2.0",
"authoring.discussions.basic-support": "دعم القاعدي",
"authoring.discussions.partial-support": "دعم جزئي",
"authoring.discussions.full-support": "دعم كامل",
"authoring.discussions.common-support": "مطلوبة بكثرة",
"authoring.discussions.settings": "الإعدادات",
"authoring.discussions.applyButton": "تقديم طلب",
"authoring.discussions.applyingButton": "تقديم الطلب جارٍ",
"authoring.discussions.appliedButton": "تم تقديم الطلب",
"authoring.discussions.noProviderSwitchAfterCourseStarted": "لا يمكن تغيير مزود المناقشة بعد انطلاق المساق، يرجى التواصل مع دعم الشركاء.",
"authoring.discussions.providerSelection": "اختيار المزود",
"authoring.discussions.Incomplete": "غير مكتملة",
"course-authoring.pages-resources.notes.heading": "تهيئة الملاحظات",
"course-authoring.pages-resources.notes.enable-notes.label": "الملاحظات",
"course-authoring.pages-resources.notes.enable-notes.help": "يمكن للمتعلمين الوصول إلى ملاحظاتهم إما في متن المساق أو في صفحة الملاحظات. يمكن للمتعلم رؤية جميع الملاحظات التي دونت خلال هذا المساق في صفحة الملاحظات. تحتوي الصفحة كذلك على روابط لمواضع الملاحظات في متن المساق.",
"course-authoring.pages-resources.notes.enable-notes.link": "معرفة المزيد عن الملاحظات",
"authoring.live.bbb.selectPlan.label": "خدد خطة",
"authoring.pagesAndResources.live.enableLive.heading": "تهيئة البث المباشر",
"authoring.pagesAndResources.live.enableLive.label": "البث المباشر",
"authoring.pagesAndResources.live.enableLive.help": "قم بجدولة اجتماعات و نظّم جلسات تدريس مباشرة مع الطلبة.",
"authoring.pagesAndResources.live.enableLive.link": "معرفة المزيد عن البث المباشر",
"authoring.live.selectProvider": "حدد أداة مؤتمرات الفيديو",
"authoring.live.formInstructions": "أكمل الحقول أدناه لتثبيت أداة مؤتمرات الفيديو الخاصة بك.",
"authoring.live.consumerKey": "مفتاح المستهلك (Consumer Key)",
"authoring.live.consumerKey.required": "حقل مفتاح المستهلك مطلوب",
"authoring.live.consumerSecret": "سر المستهلك (Consumer Secret)",
"authoring.live.consumerSecret.required": "حقل سر المستهلك مطلوب",
"authoring.live.launchUrl": "عنوان التشغيل (Launch URL)",
"authoring.live.launchUrl.required": "حقل عنوان التشغيل مطلوب",
"authoring.live.launchEmail": "عنوان بريد التشغيل الإلكتروني (Launch Email)",
"authoring.live.launchEmail.required": "حقل عنوان بريد التشغيل الإلكتروني مطلوب",
"authoring.live.provider.helpText": "تتطلب هذه التهيئة مشاركة {providerName} أسماء المستخدمين و عناوين البريد الإلكتروني الخاصة بالمتعلمين و فريق المساق.",
"authoring.live.requestPiiSharingEnable": "تتطلب هذه التهيئة مشاركة {provider} أسماء المستخدمين و عناوين البريد الإلكتروني الخاصة بالمتعلمين و فريق المساق. للوصول إلى تهيئة LTI الخاصة بـ{provider}، يرجى الاتصال بمنسق مشروعك على edX لتفعيل مشاركة معلومات التعريف الشخصية لهذا المساق.",
"authoring.live.appDocInstructions.documentationLink": "الوثائق العامة",
"authoring.live.appDocInstructions.accessibilityDocumentationLink": "وثائق قابلية الوصول",
"authoring.live.appDocInstructions.configurationLink": "وثائق التهيئة",
"authoring.live.appDocInstructions.learnMoreLink": "معرفة المزيد عن {providerName}",
"authoring.live.appDocInstructions.linkTextHeading": "مساعدة و وثائق خارجية",
"authoring.live.appDocInstructions.linkText": "{link}",
"authoring.live.appName-yellowdig": "Zoom",
"authoring.live.appName-googleMeet": "Google Meet",
"authoring.live.appName-microsoftTeams": "Microsoft Teams",
"course-authoring.pages-resources.heading": "الصفحات والموارد",
"course-authoring.pages-resources.resources.settings.button": "settings",
"course-authoring.pages-resources.viewLive.button": "View live",
"course-authoring.badge.enabled": "Enabled",
"authoring.proctoring.no": "No",
"authoring.proctoring.yes": "Yes",
"authoring.proctoring.support.text": "Support Page",
"authoring.proctoring.enableproctoredexams.label": "Proctored exams",
"authoring.proctoring.enableproctoredexams.help": "Enable and configure proctored exams in your course.",
"authoring.proctoring.enabled": "Enabled",
"authoring.proctoring.learn.more": "Learn more about proctoring",
"authoring.proctoring.provider.label": "Proctoring provider",
"authoring.proctoring.provider.help": "Select the proctoring provider you want to use for this course run.",
"authoring.proctoring.provider.help.aftercoursestart": "Proctoring provider cannot be modified after course start date.",
"authoring.proctoring.escalationemail.label": "Proctortrack escalation email",
"authoring.proctoring.escalationemail.help": "Provide an email address to be contacted by the support team for escalations (e.g. appeals, delayed reviews).",
"authoring.proctoring.escalationemail.error.blank": "The Proctortrack Escalation Email field cannot be empty if proctortrack is the selected provider.",
"authoring.proctoring.escalationemail.error.invalid": "The Proctortrack Escalation Email field is in the wrong format and is not valid.",
"authoring.proctoring.allowoptout.label": "Allow learners to opt out of proctoring on proctored exams",
"authoring.proctoring.createzendesk.label": "Create Zendesk tickets for suspicious attempts",
"authoring.proctoring.error.single": "There is 1 error in this form.",
"authoring.proctoring.escalationemail.error.multiple": "There are {numOfErrors} errors in this form.",
"authoring.proctoring.save": "Save",
"authoring.proctoring.saving": "Saving...",
"authoring.proctoring.cancel": "Cancel",
"authoring.proctoring.studio.link.text": "Go back to your course in Studio",
"authoring.proctoring.alert.success": "\n Proctored exam settings saved successfully. {studioCourseRunURL}.\n ",
"authoring.examsettings.alert.error": "\n We encountered a technical error while trying to save proctored exam settings.\n This might be a temporary issue, so please try again in a few minutes.\n If the problem persists,\n please go to the {support_link} for help.\n ",
"course-authoring.pages-resources.progress.heading": "Configure progress",
"course-authoring.pages-resources.progress.enable-progress.label": "Progress",
"course-authoring.pages-resources.progress.enable-progress.help": "As students work through graded assignments, scores\n will appear under the progress tab. The progress tab contains a chart of\n all graded assignments in the course, with a list of all assignments and\n scores below.",
"course-authoring.pages-resources.progress.enable-progress.link": "Learn more about progress",
"course-authoring.pages-resources.progress.enable-graph.label": "Enable progress graph",
"course-authoring.pages-resources.progress.enable-graph.help": "If enabled, students can view the progress graph",
"authoring.pagesAndResources.teams.heading": "Configure teams",
"authoring.pagesAndResources.teams.enableTeams.label": "Teams",
"authoring.pagesAndResources.teams.enableTeams.help": "Allow learners to work together on specific projects or activities.",
"authoring.pagesAndResources.teams.enableTeams.link": "Learn more about teams",
"authoring.pagesAndResources.teams.teamSize.heading": "Team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSize": "Max team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeHelp": "The maximum number of learners that can join a team",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeEmpty": "Enter max team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeInvalid": "Max team size must be a positive number larger than zero.",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeTooHigh": "Max team size cannot be greater than {max}",
"authoring.pagesAndResources.teams.groups.heading": "Groups",
"authoring.pagesAndResources.teams.groups.help": "Groups are spaces where learners can create or join teams.",
"authoring.pagesAndResources.teams.configureGroup.heading": "Configure group",
"authoring.pagesAndResources.teams.group.name.label": "Name",
"authoring.pagesAndResources.teams.group.name.help": "Choose a unique name for this group",
"authoring.pagesAndResources.teams.group.name.error.empty": "Enter a unique name for this group",
"authoring.pagesAndResources.teams.group.name.error.exists": "It looks like this name is already in use",
"authoring.pagesAndResources.teams.group.description.label": "Description",
"authoring.pagesAndResources.teams.group.description.help": "Enter details about this group",
"authoring.pagesAndResources.teams.group.description.error": "Enter a description for this group",
"authoring.pagesAndResources.teams.group.type.label": "Type",
"authoring.pagesAndResources.teams.group.type.help": "Control who can see, create and join teams",
"authoring.pagesAndResources.teams.group.types.open": "Open",
"authoring.pagesAndResources.teams.group.types.open.description": "Learners can create, join, leave, and see other teams",
"authoring.pagesAndResources.teams.group.types.public_managed": "Public managed",
"authoring.pagesAndResources.teams.group.types.public_managed.description": "Only course staff can control teams and memberships. Learners can see other teams.",
"authoring.pagesAndResources.teams.group.types.private_managed": "Private managed",
"authoring.pagesAndResources.teams.group.types.private_managed.description": "Only course staff can control teams, memberships, and see other teams",
"authoring.pagesAndResources.teams.group.maxSize.label": "Max team size (optional)",
"authoring.pagesAndResources.teams.group.maxSize.help": "Override the global max team size",
"authoring.pagesAndResources.teams.addGroup.button": "Add group",
"authoring.pagesAndResources.teams.group.delete": "Delete",
"authoring.pagesAndResources.teams.group.expand": "Expand group editor",
"authoring.pagesAndResources.teams.group.collapse": "Close group editor",
"authoring.pagesAndResources.teams.deleteGroup.initiateDelete": "Delete",
"authoring.pagesAndResources.teams.deleteGroup.cancel-delete.button": "Cancel",
"authoring.pagesAndResources.teams.deleteGroup.heading": "Delete this group?",
"authoring.pagesAndResources.teams.deleteGroup.body": "edX recommends that you do not delete groups once your course is running.\n Your group will no longer be visible in the LMS and learners will not be able to leave teams associated with it.\n Please delete learners from teams before deleting the associated group.",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.title": "No groups found",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.message": "Add one or more groups to enable teams.",
"course-authoring.pages-resources.wiki.heading": "Configure wiki",
"course-authoring.pages-resources.wiki.enable-wiki.label": "Wiki",
"course-authoring.pages-resources.wiki.enable-wiki.help": "The course wiki can be set up based on the needs of your\n course. Common uses might include sharing answers to course FAQs, sharing\n editable course information, or providing access to learner-created\n resources.",
"course-authoring.pages-resources.wiki.enable-wiki.link": "Learn more about the wiki",
"course-authoring.pages-resources.wiki.enable-public-wiki.label": "Enable public wiki access",
"course-authoring.pages-resources.wiki.enable-public-wiki.help": "If enabled, edX users can view the course wiki even when\n they're not enrolled in the course.",
"authoring.examsettings.enableproctoredexams.help": "إذا تم تحديده ، يتم تفعيل الامتحانات المراقبة في مساقك.",
"authoring.live.appName-bigBlueButton": "BigBlueButton",
"authoring.live.requestPiiSharingEnableForBbb": "تتطلب هذه التهيئة مشاركة {provider} أسماء المستخدمين الخاصة بالمتعلمين و فريق المساق.",
"authoring.live.piiSharingEnableHelpText": "لتفعيل هذه الميزة، يرجى الاتصال بفريق دعم edX لتفعيل مشاركة معلومات التعريف الشخصية لهذا المساق.",
"authoring.live.freePlanMessage": "الخطة المجانية مهيئة سلفًا، ولا حاجة ﻷي تهيئة إضافية. باختيار الخطة المجانية ، فإنك توافق على بنود Blindside Networks الواردة في",
"authoring.live.privacyPolicy": "سياسة خصوصيتها.",
"course-authoring.pages-resources.heading": "الصفحات و الموارد",
"course-authoring.pages-resources.resources.settings.button": "الإعدادات",
"course-authoring.pages-resources.viewLive.button": "مشاهدة النسخة الحية",
"course-authoring.badge.enabled": "مفعّل",
"authoring.proctoring.no": "لا",
"authoring.proctoring.yes": "نعم",
"authoring.proctoring.support.text": "صفحة الدعم",
"authoring.proctoring.enableproctoredexams.label": "الامتحانات المراقبة",
"authoring.proctoring.enableproctoredexams.help": "قم بتفعيل و تهيئة الامتحانات المراقبة في مساقك.",
"authoring.proctoring.enabled": "مفعّل",
"authoring.proctoring.learn.more": "معرفة المزيد عن المراقبة",
"authoring.proctoring.provider.label": "مزود المراقبة",
"authoring.proctoring.provider.help": "حدد مزود المراقبة الذي تريد استخدامه لهذا المساق.",
"authoring.proctoring.provider.help.aftercoursestart": "لا يمكن تعديل مزود المراقبة بعد تاريخ بدء المساق.",
"authoring.proctoring.escalationemail.label": "عنوان بريد التصعيد الإلكتروني لـ Proctortrack",
"authoring.proctoring.escalationemail.help": "أدخل عنوان بريد إلكتروني لتلقي رسائل التصعيد (مثلا طلبات الاستئناف، المراجعات المتأخرة، و غيرها) من فريق الدعم.",
"authoring.proctoring.escalationemail.error.blank": "حقل عنوان بريد التصعيد الإلكتروني لـ Proctortrack لا يمكن أن يكون فارغًا إن كان Proctortrack هو المزود المختار.",
"authoring.proctoring.escalationemail.error.invalid": "حقل بريد التصعيد الإلكتروني لـ Proctortrack صيغته خاطئة و هو غير صالح.",
"authoring.proctoring.allowoptout.label": "السماح للمتعلمين بعدم الخضوع للمراقبة في الامتحانات المراقَبة",
"authoring.proctoring.createzendesk.label": "إنشاء تذاكر Zendesk للمحاولات المشبوهة",
"authoring.proctoring.error.single": "يوجد خطأ واحد في هذه الاستمارة.",
"authoring.proctoring.escalationemail.error.multiple": "{numOfErrors, plural,\n zero {لا يوجد خطأ}\n one {يوجد خطأ واحد}\n two {يوجد خطآن}\n few {توجد # أخطا}\n many {يوجد # خطأً}\n other {يوجد # خطإٍ}\n} في هذا النموذج.",
"authoring.proctoring.save": "حفظ",
"authoring.proctoring.saving": "الحفظ جارٍ...",
"authoring.proctoring.cancel": "إلغاء",
"authoring.proctoring.studio.link.text": "الرجوع إلى مساقك في الاستوديو",
"authoring.proctoring.alert.success": "تم حفظ إعدادات الامتحانات المراقبة بنجاح. {studioCourseRunURL}.",
"authoring.examsettings.alert.error": "واجهنا خطأ تقنيًا أثناء محاولة حفظ إعدادات الامتحان المراقب. قد تكون هذه مشكلة عارضة، لذا يرجى المحاولة مجددًا خلال بضع دقائق. إن استمرت المشكلة فيرجى الذهاب إلى {support_link} للحصول على المساعدة.",
"course-authoring.pages-resources.progress.heading": "تهيئة التقدم",
"course-authoring.pages-resources.progress.enable-progress.label": "التقدم",
"course-authoring.pages-resources.progress.enable-progress.help": "بينما يعمل الطلاب على واجباتهم المنقّطة، ستظهر الدرجات تحت تبويت التقدم. يحتوي تبويب التقدّم مخططًا لجميع الواجبات المنقّطة في المساق، مع قائمة بجميع الواجبات و الدرجات أدناه.",
"course-authoring.pages-resources.progress.enable-progress.link": "معرفة المزيد عن التقدم",
"course-authoring.pages-resources.progress.enable-graph.label": "تفعيل مخطط التقدم البياني",
"course-authoring.pages-resources.progress.enable-graph.help": "عند التفعيل، سيستطيع الطلاب رؤية مخطط التقدم البياني",
"authoring.pagesAndResources.teams.heading": "تهيئة الفِرق",
"authoring.pagesAndResources.teams.enableTeams.label": "الفِرق",
"authoring.pagesAndResources.teams.enableTeams.help": "تتيح للمتعلمين العمل معًا على مشاريع أو أنشطة محددة.",
"authoring.pagesAndResources.teams.enableTeams.link": "معرفة المزيد عن الفِرق",
"authoring.pagesAndResources.teams.teamSize.heading": "حجم الفريق",
"authoring.pagesAndResources.teams.teamSize.maxTeamSize": "الحجم الأقصى للفريق",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeHelp": "العدد الأقصى من المتعلمين القادرين على الانضمام لفريق ما.",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeEmpty": "أدخل أقصى حجم للفريق",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeInvalid": "يجب أن يكون الحجم الأقصى للفريق عددًا موجبًا أكبر من الصفر.",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeTooHigh": "لا يمكن للحجم الأقصى للفريق أن يفوق {max}",
"authoring.pagesAndResources.teams.groups.heading": "المجموعات",
"authoring.pagesAndResources.teams.groups.help": "المجموعات فضاءات يمكن للمتعلمين فيها إنشاء فرق أو الانضمام إليها.",
"authoring.pagesAndResources.teams.configureGroup.heading": "تهيئة المجموعة",
"authoring.pagesAndResources.teams.group.name.label": "الاسم",
"authoring.pagesAndResources.teams.group.name.help": "اختر اسمًا فريدًا لهذه المجموعة",
"authoring.pagesAndResources.teams.group.name.error.empty": "أدخل اسمًا فريدًا لهذه المجموعة",
"authoring.pagesAndResources.teams.group.name.error.exists": "يبدو أن هذا الاسم مستخدم من قبل",
"authoring.pagesAndResources.teams.group.description.label": "الوصف",
"authoring.pagesAndResources.teams.group.description.help": "أدخل تفاصيل عن هذه المجموعة",
"authoring.pagesAndResources.teams.group.description.error": "أدخل وصفا لهذه المجموعة",
"authoring.pagesAndResources.teams.group.type.label": "النوع",
"authoring.pagesAndResources.teams.group.type.help": "تحكم في من يستطيع رؤية و إنشاء الفرق و الانضمام إليها.",
"authoring.pagesAndResources.teams.group.types.open": "مفتوحة",
"authoring.pagesAndResources.teams.group.types.open.description": "يستطيع المتعلمون إنشاء فرق، الانضمام للفرق و مغادرتها، و أيضا مشاهدة الفرق الأخرى",
"authoring.pagesAndResources.teams.group.types.public_managed": "عامة خاضعة للإدارة",
"authoring.pagesAndResources.teams.group.types.public_managed.description": "وحده طاقم المساق مخول بالتحكم في الفرق و العضويات. يمكن للمتعلمين رؤية الفرق الأخرى.",
"authoring.pagesAndResources.teams.group.types.private_managed": "خاصة خاضعة للإدارة",
"authoring.pagesAndResources.teams.group.types.private_managed.description": "وحده طاقم المساق مخول بالتحكم في الفرق و العضويات و كذا رؤية الفرق الأخرى.",
"authoring.pagesAndResources.teams.group.maxSize.label": "الحجم الأقصى للفريق (اختياري)",
"authoring.pagesAndResources.teams.group.maxSize.help": "تجاوز الحجم الأقصى العام للفريق",
"authoring.pagesAndResources.teams.addGroup.button": "إضافة مجموعة",
"authoring.pagesAndResources.teams.group.delete": "حذف",
"authoring.pagesAndResources.teams.group.expand": "توسيع محرر المجموعة",
"authoring.pagesAndResources.teams.group.collapse": "إغلاق محرر المجموعة",
"authoring.pagesAndResources.teams.deleteGroup.initiateDelete": "حذف",
"authoring.pagesAndResources.teams.deleteGroup.cancel-delete.button": "إلغاء",
"authoring.pagesAndResources.teams.deleteGroup.heading": "هل تريد حذف هذه المجموعة؟",
"authoring.pagesAndResources.teams.deleteGroup.body": "ننصح في edX بعدم حذف المجموعات بعد انطلاق مساقك. حينها لن تكون مجموعتك مرئية في LMS و لن يستطيع المتعلمون مغادرة الفرق المرتبطة بها. يرجى حذف المتعلمين من الفرق قبل حذف المجموعة المرتبطة بها.",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.title": "لا توجد مجموعات",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.message": "أضف مجموعة واحدة أو أكثر لتمكين الفرق.",
"course-authoring.pages-resources.wiki.heading": "تهيئة الويكي",
"course-authoring.pages-resources.wiki.enable-wiki.label": "الويكي",
"course-authoring.pages-resources.wiki.enable-wiki.help": "يمكن تهيئة الويكي بناءً على احتياجات المساق. من بين الاستخدامات الشائعة: مشاركة اجوبة الأسئلة الشائعة في المساق، مشاركة معلومات المساق القابلة للتعديل، و إتاحة الوصول إلى الموارد التي ينشئها المتعلمون.",
"course-authoring.pages-resources.wiki.enable-wiki.link": "معرفة المزيد عن الويكي",
"course-authoring.pages-resources.wiki.enable-public-wiki.label": "تفعيل الوصول العام",
"course-authoring.pages-resources.wiki.enable-public-wiki.help": "إن تم التفعيل، فسيستطيع مستخدمو edX عرض ويكي المساق حتى وإن كانوا غير مسجلين في المساق.",
"authoring.examsettings.enableproctoredexams.help": "في حال التأشير، يتم تفعيل الامتحانات المراقبة في مساقك.",
"authoring.examsettings.allowoptout.label": "السماح بالخروج من الامتحانات المُراقبة",
"authoring.examsettings.allowoptout.help": "\n If this value is \"Yes\", learners can choose to take proctored exams without proctoring.\n If this value is \"No\", all learners must take the exam with proctoring.\n ",
"authoring.examsettings.allowoptout.help": "\nإن كانت هذه القيمة \"نعم\"، فيمكن للمتعلمبن أن يختاروا اجتياز الامتحان المراقب من غير مراقبة.\nإن كانت هذه القيمة \"لا\"، فسيكون عن جميع المتعلمين اجتياز الامتحان بالمراقبة.",
"authoring.examsettings.provider.label": "موفر المراقبة",
"authoring.examsettings.escalationemail.label": "البريد الإلكتروني لتصعيد مسار المراقبة",
"authoring.examsettings.escalationemail.help": "\n Required if \"proctortrack\" is selected as your proctoring provider. Enter an email address to be\n contacted by the support team whenever there are escalations (e.g. appeals, delayed reviews, etc.).\n ",
"authoring.examsettings.escalationemail.help": "\nمطلوب إن تم تحديد \"Proctortrack\" كمزود المراقبة الخاص بك. أدخل عنوان بريد إلكتروني كي يتصل بك فريق الدعم حينما يكون هنالك تصعيد (مثلا: طلبات الاستئناف و المراجعات المتأخرة، و غيرها) من فريق الدعم.",
"authoring.examsettings.createzendesk.label": "أنشئ تذاكر Zendesk لمحاولات الاختبار المشبوهة",
"authoring.examsettings.createzendesk.help": "إذا كانت هذه القيمة \"نعم\"، فسيتم إنشاء تذكرة Zendesk لمحاولات الاختبار المراقبة المشتبه فيها.",
"authoring.examsettings.submit": "إرسال",
"authoring.examsettings.alert.success": "\nتم حفظ إعدادات الاختبار Proctored بنجاح.\nيمكنك العودة إلى مقرّرك التعليمي في الاستوديو {studioCourseRunURL}",
"authoring.examsettings.alert.success": "\nتم حفظ إعدادات الاختبار Proctored بنجاح.\nيمكنك الرجوع إلى مساقك في الاستوديو {studioCourseRunURL}.",
"authoring.examsettings.allowoptout.no": "لا",
"authoring.examsettings.allowoptout.yes": "نعم",
"authoring.examsettings.createzendesk.no": "لا",
"authoring.examsettings.createzendesk.yes": "نعم",
"authoring.examsettings.support.text": "Support Page",
"authoring.examsettings.support.text": "صفحة الدعم",
"authoring.examsettings.escalationemail.enableproctoredexams.label": "تفعيل الامتحانات المراقَبة",
"authoring.examsettings.escalationemail.error.blank": "لا يمكن أن يكون حقل البريد الإلكتروني الخاص بتصعيد ProctorTrack فارغًا إذا كانمسار المراقبة هو المزود المحدد.",
"authoring.examsettings.escalationemail.error.invalid": "إن حقل البريد الإلكتروني للتصعيد في مسار المراقبة بتنسيق غير صحيح وغير صالح.",
"authoring.examsettings.error.single": "يوجد خطأ واحد في هذا النموذج.",
"authoring.examsettings.escalationemail.error.multiple": "يوجد {numOfErrors} خطأ في هذا النموذج.",
"authoring.examsettings.provider.help": "حدد مزود المراقبة الذي تريد استخدامه لتشغيل هذا المساق.",
"authoring.examsettings.escalationemail.error.multiple": "{numOfErrors, plural,\nzero {لا يوجد خطأ}\none {يوجد خطأ واحد}\ntwo {يوجد خطآن}\nfew {توجد # أخطا}\nmany {يوجد # خطأً}\nother {يوجد # خطإٍ}\n} في هذا النموذج.",
"authoring.examsettings.provider.help": "حدد مزود المراقبة الذي تريد استخدامه لطبعة المساق هذه.",
"authoring.examsettings.provider.help.aftercoursestart": "لا يمكن تعديل مزود المعالجة بعد تاريخ بدء المساق.",
"header.links.content": "المحتوى",
"header.links.settings": "إعدادات الحساب",
"header.links.settings": "الإعدادات",
"header.links.content.tools": "الأدوات",
"header.links.outline": "المخطّط الكلّي",
"header.links.outline": "المخطط الكلّي",
"header.links.updates": "التحديثات",
"header.links.pages": "Pages & Resources",
"header.links.filesAndUploads": "الملفات والتحميل ",
"header.links.pages": "الصفحات و الموارد",
"header.links.filesAndUploads": "الملفات و التحميل ",
"header.links.textbooks": "الكتب",
"header.links.videoUploads": "تحميلات الفيديو",
"header.links.scheduleAndDetails": "وضع جدول لوحدة",
"header.links.grading": "التقييم",
"header.links.videoUploads": "الفيديوهات المرفوعة",
"header.links.scheduleAndDetails": "المواعيد و التفاصيل",
"header.links.grading": "التنقيط",
"header.links.courseTeam": "فريق المساق",
"header.links.groupConfigurations": "إعدادات المجموعة",
"header.links.proctoredExamSettings": "إعدادات الامتحان المراقب",
"header.links.groupConfigurations": "تهيئة المجموعات",
"header.links.proctoredExamSettings": "إعدادات الامتحانات المراقبة",
"header.links.advancedSettings": "الإعدادات المتقدمة",
"header.links.certificates": "الشهادات",
"header.links.publisher": "ناشر",
"header.links.import": "استيراد",
"header.links.export": "تصدير",
"header.links.checklists": "قوائم المراجعة",
"header.user.menu.studio": "صفحة استوديو الرئيسية",
"header.user.menu.maintenance": "صيانة",
"header.user.menu.logout": "خروج",
"header.links.publisher": "الناشر",
"header.links.import": "الاستيراد",
"header.links.export": "التصدير",
"header.links.checklists": "قوائم التدقيق",
"header.user.menu.studio": "صفحة الاستوديو الرئيسية",
"header.user.menu.maintenance": "الصيانة",
"header.user.menu.logout": "تسجيل الخروج",
"header.label.account.menu": "قائمة الحساب",
"header.label.account.menu.for": "قائمة الحساب للمستخدم {username}",
"header.label.main.nav": "الرئيسية",
"header.label.main.menu": "القائمة الرئيسية",
"header.label.main.header": "الرئيسية",
"header.label.secondary.nav": "ثانوي",
"header.label.courseOutline": "العودة إلى مخطط المساق في استوديو"
"header.label.secondary.nav": "الثانوية",
"header.label.courseOutline": "الرجوع إلى مخطط المساق الكلّي في الاستوديو"
}

View File

@@ -1 +0,0 @@
{}

352
src/i18n/messages/de.json Normal file
View File

@@ -0,0 +1,352 @@
{
"authoring.alert.error.connection": "We encountered a technical error when loading this page. This might be a temporary issue, so please try again in a few minutes. If the problem persists, please go to the {supportLink} for help.",
"authoring.loading": "Loading...",
"authoring.alert.error.permission": "You are not authorized to view this page. If you feel you should have access, please reach out to your course team admin to be given access.",
"authoring.alert.save.error.connection": "We encountered a technical error when applying changes. This might be a temporary issue, so please try again in a few minutes. If the problem persists, please go to the {supportLink} for help.",
"authoring.alert.support.text": "Support Page",
"course-authoring.pages-resources.app-settings-modal.button.cancel": "Cancel",
"course-authoring.pages-resources.app-settings-modal.button.save": "Save",
"course-authoring.pages-resources.app-settings-modal.button.saving": "Saving",
"course-authoring.pages-resources.app-settings-modal.button.saved": "Saved",
"course-authoring.pages-resources.app-settings-modal.button.retry": "Retry",
"course-authoring.pages-resources.app-settings-modal.badge.enabled": "Enabled",
"course-authoring.pages-resources.app-settings-modal.badge.disabled": "Disabled",
"course-authoring.pages-resources.app-settings-modal.save-error.title": "We couldn't apply your changes.",
"course-authoring.pages-resources.app-settings-modal.save-error.message": "Please check your entries and try again.",
"course-authoring.pages-resources.calculator.heading": "Configure calculator",
"course-authoring.pages-resources.calculator.enable-calculator.label": "Calculator",
"course-authoring.pages-resources.calculator.enable-calculator.help": "The calculator supports numbers, operators, constants,\n functions, and other mathematical concepts. When enabled, an icon to\n access the calculator appears on all pages in the body of your course.",
"course-authoring.pages-resources.calculator.enable-calculator.link": "Learn more about the calculator",
"authoring.discussions.documentationPage": "Visit the {name} documentation page",
"authoring.discussions.formInstructions": "Complete the fields below to set up your discussion tool.",
"authoring.discussions.consumerKey": "Consumer Key",
"authoring.discussions.consumerKey.required": "Consumer key is a required field",
"authoring.discussions.consumerSecret": "Consumer Secret",
"authoring.discussions.consumerSecret.required": "Consumer secret is a required field",
"authoring.discussions.launchUrl": "Launch URL",
"authoring.discussions.launchUrl.required": "Launch URL is a required field",
"authoring.discussions.stuffOnlyConfigInfo": "To enable {providerName} for your course, please contact their support team at {supportEmail} to learn more about pricing and usage.",
"authoring.discussions.stuffOnlyConfigGuide": "To fully configure {providerName} will also require sharing usernames and emails for learners and course team. Please contact your edX project coordinator to enable PII sharing for this course.",
"authoring.discussions.piiSharing": "Optionally share a user's username and/or email with the LTI provider:",
"authoring.discussions.piiShareUsername": "Share username",
"authoring.discussions.piiShareEmail": "Share email",
"authoring.discussions.appDocInstructions.contact": "Contact: {link}",
"authoring.discussions.appDocInstructions.documentationLink": "General documentation",
"authoring.discussions.appDocInstructions.accessibilityDocumentationLink": "Accessibility documentation",
"authoring.discussions.appDocInstructions.configurationLink": "Configuration documentation",
"authoring.discussions.appDocInstructions.learnMoreLink": "Learn more about {providerName}",
"authoring.discussions.appDocInstructions.linkTextHeading": "External help and documentation",
"authoring.discussions.appDocInstructions.linkText": "{link}",
"authoring.discussions.configurationChangeConsequences": "Students will lose access to any active or previous discussion posts for your course.",
"authoring.discussions.configure.app": "Configure {name}",
"authoring.discussions.configure": "Configure discussions",
"authoring.discussions.ok": "OK",
"authoring.discussions.cancel": "Cancel",
"authoring.discussions.confirm": "Confirm",
"authoring.discussions.confirmConfigurationChange": "Are you sure you want to change the discussion settings?",
"authoring.discussions.confirmEnableDiscussionsLabel": "Enable discussions on units in graded subsections?",
"authoring.discussions.cancelEnableDiscussionsLabel": "Disable discussions on units in graded subsections?",
"authoring.discussions.confirmEnableDiscussions": "Enabling this toggle will automatically enable discussion on all units in graded subsections, that are not timed exams.",
"authoring.discussions.cancelEnableDiscussions": "Disabling this toggle will automatically disable discussion on all units in graded subsections. Discussion topics containing at least 1 thread will be listed and accessible under “Archived” in Topics tab on the Discussions page.",
"authoring.discussions.backButton": "Back",
"authoring.discussions.saveButton": "Save",
"authoring.discussions.savingButton": "Saving",
"authoring.discussions.savedButton": "Saved",
"authoring.discussions.appConfigForm.appName-piazza": "Piazza",
"authoring.discussions.appConfigForm.appName-yellowdig": "Yellowdig",
"authoring.discussions.appConfigForm.appName-inscribe": "InScribe",
"authoring.discussions.appConfigForm.appName-discourse": "Discourse",
"authoring.discussions.appConfigForm.appName-ed-discuss": "Ed Discussion",
"authoring.discussions.appConfigForm.appName-legacy": "edX",
"authoring.discussions.appConfigForm.appName-openedx": "edX",
"authoring.discussions.builtIn.divisionByGroup": "Cohorts",
"authoring.discussions.builtIn.divideByCohorts.label": "Divide discussions by cohorts",
"authoring.discussions.builtIn.divideByCohorts.help": "Learners will only be able to view and respond to discussions posted by members of their cohort.",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.label": "Divide course-wide discussion topics",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.help": "Choose which of your general course-wide discussion topics you would like to divide.",
"authoring.discussions.builtIn.divideGeneralTopic.label": "General",
"authoring.discussions.builtIn.divideQuestionsForTAsTopic.label": "Questions for the TAs",
"authoring.discussions.builtIn.cohortsEnabled.label": "To adjust these settings, enable cohorts on the ",
"authoring.discussions.builtIn.instructorDashboard.label": "instructor dashboard",
"authoring.discussions.builtIn.visibilityInContext": "Visibility of in-context discussions",
"authoring.discussions.builtIn.gradedUnitPages.label": "Enable discussions on units in graded subsections",
"authoring.discussions.builtIn.gradedUnitPages.help": "Allow learners to engage with discussion on all graded unit pages except timed exams.",
"authoring.discussions.builtIn.groupInContextSubsection.label": "Group in context discussion at the subsection level",
"authoring.discussions.builtIn.groupInContextSubsection.help": "Learners will be able to view any post in the sub-section no matter which unit page they are viewing. While this is not recommended, if your course has short learning sequences or low enrollment grouping may increase engagement.",
"authoring.discussions.builtIn.anonymousPosting": "Anonymous posting",
"authoring.discussions.builtIn.allowAnonymous.label": "Allow anonymous discussion posts",
"authoring.discussions.builtIn.allowAnonymous.help": "If enabled, learners can create posts that are anonymous to all users.",
"authoring.discussions.builtIn.allowAnonymousPeers.label": "Allow anonymous discussion posts to peers",
"authoring.discussions.builtIn.allowAnonymousPeers.help": "Learners will be able to post anonymously to other peers but all posts will be visible to course staff.",
"authoring.discussions.builtIn.reportedContentEmailNotifications": "Notifications",
"authoring.discussions.builtIn.reportedContentEmailNotifications.label": "Email notifications for reported content",
"authoring.discussions.builtIn.reportedContentEmailNotifications.help": "Discussion Admins, Moderators, Community TAs and Group Community TAs (only for their own cohort) will receive an email notification when content is reported.",
"authoring.discussions.discussionTopics": "Discussion topics",
"authoring.discussions.discussionTopics.label": "General discussion topics",
"authoring.discussions.discussionTopics.help": "Discussions can include general topics not contained to the course structure. All courses have a general topic by default.",
"authoring.discussions.discussionTopic.required": "Topic name is a required field",
"authoring.discussions.discussionTopic.alreadyExistError": "It looks like this name is already in use",
"authoring.discussions.addTopicButton": "Add topic",
"authoring.discussions.deleteButton": "Delete",
"authoring.discussions.cancelButton": "Cancel",
"authoring.discussions.discussionTopicDeletion.help": "edX recommends that you do not delete discussion topics once your course is running.",
"authoring.discussions.discussionTopicDeletion.label": "Delete this topic?",
"authoring.discussions.builtIn.renameGeneralTopic.label": "Rename general topic",
"authoring.discussions.generalTopicHelp.help": "This is the default discussion topic for your course.",
"authoring.discussions.builtIn.configureAdditionalTopic.label": "Configure topic",
"authoring.discussions.addTopicHelpText": "Choose a unique name for your topic",
"authoring.discussions.blackoutDates": "Discussion blackout dates",
"authoring.discussions.builtIn.blackoutDates.label": "Blackout dates",
"authoring.discussions.builtIn.blackoutDates.help": "If added, learners will not be able to post in discussions between these dates.",
"authoring.discussions.addBlackoutDatesButton": "Add blackout date range",
"authoring.discussions.builtIn.configureBlackoutDates.label": "Configure blackout date range",
"authoring.discussions.blackoutStartDate.help": "Enter a start date, e.g. 12/10/2023",
"authoring.discussions.blackoutEndDate.help": "Enter an end date, e.g. 12/17/2023",
"authoring.discussions.blackoutStartTime.help": "Enter a start time, e.g. 09:00 AM",
"authoring.discussions.blackoutEndTime.help": "Enter an end time, e.g. 05:00 PM",
"authoring.discussions.activeBlackoutDatesDeletion.help": "These blackout dates are currently active. If deleted, learners will be able to post in discussions during these dates. Are you sure you want to proceed?",
"authoring.discussions.blackoutDatesDeletion.help": "If deleted, learners will be able to post in discussions during these dates.",
"authoring.discussions.completeBlackoutDatesDeletion.help": "Are you sure you want to delete these blackout dates?",
"authoring.discussions.activeBlackoutDatesDeletion.label": "Delete active blackout dates?",
"authoring.discussions.blackoutDatesDeletion.label": "Delete blackout dates?",
"authoring.blackoutDates.delete": "Delete Blackout Dates",
"authoring.blackoutDates.status": "{status}",
"authoring.blackoutDates.startDate.required": "Start date is a required field",
"authoring.blackoutDates.endDate.required": "End date is a required field",
"authoring.blackoutDates.startDate.inPast": "Start date cannot be after end date",
"authoring.blackoutDates.endDate.inPast": "End date cannot be before start date",
"authoring.blackoutDates.startTime.inPast": "Start time cannot be after end time",
"authoring.blackoutDates.endTime.inPast": "End time cannot be before start time",
"authoring.blackoutDates.startTime.inValidFormat": "Enter a valid start time",
"authoring.blackoutDates.endTime.inValidFormat": "Enter a valid end time",
"authoring.blackoutDates.startDate.inValidFormat": "Enter a valid start Date",
"authoring.blackoutDates.endDate.inValidFormat": "Enter a valid end date",
"authoring.topics.delete": "Delete Topic",
"authoring.topics.expand": "Expand",
"authoring.topics.collapse": "Collapse",
"authoring.blackoutDates.start.date": "Start date",
"authoring.blackoutDates.start.time": "Start time (optional) ({zone})",
"authoring.blackoutDates.end.date": "End date",
"authoring.blackoutDates.end.time": "End time (optional) ({zone})",
"authoring.discussions.heading": "Select a discussion tool for this course",
"authoring.discussions.supportedFeatures": "Supported features",
"authoring.discussions.supportedFeatureList-mobile-show": "Show supported features",
"authoring.discussions.supportedFeatureList-mobile-hide": "Hide supported features",
"authoring.discussions.noApps": "There are no discussions providers available for your course.",
"authoring.discussions.nextButton": "Next",
"authoring.discussions.appFullSupport": "Full support",
"authoring.discussions.appBasicSupport": "Basic support",
"authoring.discussions.selectApp": "Select {appName}",
"authoring.discussions.appList.appName-legacy": "edX",
"authoring.discussions.appList.appDescription-legacy": "Start conversations with other learners, ask questions, and interact with other learners in the course.",
"authoring.discussions.appList.appName-openedx": "edX",
"authoring.discussions.appList.appDescription-openedx": "Start conversations with other learners, ask questions, and interact with other learners in the course.",
"authoring.discussions.appList.appName-piazza": "Piazza",
"authoring.discussions.appList.appDescription-piazza": "Piazza is designed to connect students, TAs, and professors so every student can get the help they need when they need it.",
"authoring.discussions.appList.appDescription-yellowdig": "Yellowdig offers educators a gameful learning digital solution to improve student engagement by building learning communities for any course modality.",
"authoring.discussions.appList.appDescription-inscribe": "InScribe leverages the power of community + artificial intelligence to connect individuals to the answers, resources, and people they need to succeed.",
"authoring.discussions.appList.appDescription-discourse": "Discourse is modern forum software for your community. Use it as a mailing list, discussion forum, long-form chat room, and more!",
"authoring.discussions.appList.appDescription-ed-discus": "Ed Discussion helps scale class communication in a beautiful and intuitive interface. Questions reach and benefit the whole class. Less emails, more time saved.",
"authoring.discussions.featureName-discussion-page": "Discussion page",
"authoring.discussions.featureName-embedded-course-sections": "Embedded course sections",
"authoring.discussions.featureName-advanced-in-context-discussion": "Advanced in context discussion",
"authoring.discussions.featureName-anonymous-posting": "Anonymous posting",
"authoring.discussions.featureName-automatic-learner-enrollment": "Automatic learner enrollment",
"authoring.discussions.featureName-blackout-discussion-dates": "Blackout discussion dates",
"authoring.discussions.featureName-community-ta-support": "Community TA support",
"authoring.discussions.featureName-course-cohort-support": "Course cohort support",
"authoring.discussions.featureName-direct-messages-from-instructors": "Direct messages from instructors",
"authoring.discussions.featureName-discussion-content-prompts": "Discussion content prompts",
"authoring.discussions.featureName-email-notifications": "Email notifications",
"authoring.discussions.featureName-graded-discussions": "Graded discussions",
"authoring.discussions.featureName-in-platform-notifications": "In-platform notifications",
"authoring.discussions.featureName-internationalization-support": "Internationalization support",
"authoring.discussions.featureName-lti-advanced-sharing-mode": "LTI advanced sharing",
"authoring.discussions.featureName-basic-configuration": "Basic configuration",
"authoring.discussions.featureName-primary-discussion-app-experience": "Primary discussion app experience",
"authoring.discussions.featureName-question-&-discussion-support": "Question & discussion support",
"authoring.discussions.featureName-report/flag-content-to-moderators": "Report content to moderators",
"authoring.discussions.featureName-research-data-events": "Research data events",
"authoring.discussions.featureName-simplified-in-context-discussion": "Simplified in-context discussion",
"authoring.discussions.featureName-user-mentions": "User mentions",
"authoring.discussions.featureName-wcag-2.1": "WCAG 2.1 support",
"authoring.discussions.wcag-2.0-support": "WCAG 2.0 support",
"authoring.discussions.basic-support": "Basic support",
"authoring.discussions.partial-support": "Partial support",
"authoring.discussions.full-support": "Full support",
"authoring.discussions.common-support": "Commonly requested",
"authoring.discussions.settings": "Settings",
"authoring.discussions.applyButton": "Apply",
"authoring.discussions.applyingButton": "Applying",
"authoring.discussions.appliedButton": "Applied",
"authoring.discussions.noProviderSwitchAfterCourseStarted": "Discussion provider can't be changed after course has started, please reach out to partner support.",
"authoring.discussions.providerSelection": "Provider selection",
"authoring.discussions.Incomplete": "Incomplete",
"course-authoring.pages-resources.notes.heading": "Configure notes",
"course-authoring.pages-resources.notes.enable-notes.label": "Notes",
"course-authoring.pages-resources.notes.enable-notes.help": "Learners can access their notes either in the body of the\n course of on a notes page. On the notes page, a learner can see all the\n notes made during the course. The page also contains links to the location\n of the notes in the course body.",
"course-authoring.pages-resources.notes.enable-notes.link": "Learn more about notes",
"authoring.live.bbb.selectPlan.label": "Select a plan",
"authoring.pagesAndResources.live.enableLive.heading": "Configure Live",
"authoring.pagesAndResources.live.enableLive.label": "Live",
"authoring.pagesAndResources.live.enableLive.help": "Schedule meetings and conduct live course sessions with learners.",
"authoring.pagesAndResources.live.enableLive.link": "Learn more about live",
"authoring.live.selectProvider": "Select a video conferencing tool",
"authoring.live.formInstructions": "Complete the fields below to set up your video conferencing tool.",
"authoring.live.consumerKey": "Consumer Key",
"authoring.live.consumerKey.required": "Consumer key is a required field",
"authoring.live.consumerSecret": "Consumer Secret",
"authoring.live.consumerSecret.required": "Consumer secret is a required field",
"authoring.live.launchUrl": "Launch URL",
"authoring.live.launchUrl.required": "Launch URL is a required field",
"authoring.live.launchEmail": "Launch Email",
"authoring.live.launchEmail.required": "Launch Email is a required field",
"authoring.live.provider.helpText": "This configuration will require sharing username and emails of learners and the course team with {providerName}.",
"authoring.live.requestPiiSharingEnable": "This configuration will require sharing usernames and emails of learners and the course team with {provider}. To access the LTI configuration for {provider}, please request your edX project coordinator to get PII sharing enabled for this course.",
"authoring.live.appDocInstructions.documentationLink": "General documentation",
"authoring.live.appDocInstructions.accessibilityDocumentationLink": "Accessibility documentation",
"authoring.live.appDocInstructions.configurationLink": "Configuration documentation",
"authoring.live.appDocInstructions.learnMoreLink": "Learn more about {providerName}",
"authoring.live.appDocInstructions.linkTextHeading": "External help and documentation",
"authoring.live.appDocInstructions.linkText": "{link}",
"authoring.live.appName-yellowdig": "Zoom",
"authoring.live.appName-googleMeet": "Google Meet",
"authoring.live.appName-microsoftTeams": "Microsoft Teams",
"authoring.live.appName-bigBlueButton": "BigBlueButton",
"authoring.live.requestPiiSharingEnableForBbb": "This configuration will require sharing usernames of learners and the course team with {provider}.",
"authoring.live.piiSharingEnableHelpText": "To enable this feature, contact your edX support team to enable PII sharing for this course.",
"authoring.live.freePlanMessage": "The free plan is pre-configured, and no additional configurations are required. By selecting the free plan, you are agreeing to Blindside Networks",
"authoring.live.privacyPolicy": "Privacy Policy.",
"course-authoring.pages-resources.heading": "Pages & Resources",
"course-authoring.pages-resources.resources.settings.button": "settings",
"course-authoring.pages-resources.viewLive.button": "View live",
"course-authoring.badge.enabled": "Enabled",
"authoring.proctoring.no": "No",
"authoring.proctoring.yes": "Yes",
"authoring.proctoring.support.text": "Support Page",
"authoring.proctoring.enableproctoredexams.label": "Proctored exams",
"authoring.proctoring.enableproctoredexams.help": "Enable and configure proctored exams in your course.",
"authoring.proctoring.enabled": "Enabled",
"authoring.proctoring.learn.more": "Learn more about proctoring",
"authoring.proctoring.provider.label": "Proctoring provider",
"authoring.proctoring.provider.help": "Select the proctoring provider you want to use for this course run.",
"authoring.proctoring.provider.help.aftercoursestart": "Proctoring provider cannot be modified after course start date.",
"authoring.proctoring.escalationemail.label": "Proctortrack escalation email",
"authoring.proctoring.escalationemail.help": "Provide an email address to be contacted by the support team for escalations (e.g. appeals, delayed reviews).",
"authoring.proctoring.escalationemail.error.blank": "The Proctortrack Escalation Email field cannot be empty if proctortrack is the selected provider.",
"authoring.proctoring.escalationemail.error.invalid": "The Proctortrack Escalation Email field is in the wrong format and is not valid.",
"authoring.proctoring.allowoptout.label": "Allow learners to opt out of proctoring on proctored exams",
"authoring.proctoring.createzendesk.label": "Create Zendesk tickets for suspicious attempts",
"authoring.proctoring.error.single": "There is 1 error in this form.",
"authoring.proctoring.escalationemail.error.multiple": "There are {numOfErrors} errors in this form.",
"authoring.proctoring.save": "Save",
"authoring.proctoring.saving": "Saving...",
"authoring.proctoring.cancel": "Cancel",
"authoring.proctoring.studio.link.text": "Go back to your course in Studio",
"authoring.proctoring.alert.success": "\n Proctored exam settings saved successfully. {studioCourseRunURL}.\n ",
"authoring.examsettings.alert.error": "\n We encountered a technical error while trying to save proctored exam settings.\n This might be a temporary issue, so please try again in a few minutes.\n If the problem persists,\n please go to the {support_link} for help.\n ",
"course-authoring.pages-resources.progress.heading": "Configure progress",
"course-authoring.pages-resources.progress.enable-progress.label": "Progress",
"course-authoring.pages-resources.progress.enable-progress.help": "As students work through graded assignments, scores\n will appear under the progress tab. The progress tab contains a chart of\n all graded assignments in the course, with a list of all assignments and\n scores below.",
"course-authoring.pages-resources.progress.enable-progress.link": "Learn more about progress",
"course-authoring.pages-resources.progress.enable-graph.label": "Enable progress graph",
"course-authoring.pages-resources.progress.enable-graph.help": "If enabled, students can view the progress graph",
"authoring.pagesAndResources.teams.heading": "Configure teams",
"authoring.pagesAndResources.teams.enableTeams.label": "Teams",
"authoring.pagesAndResources.teams.enableTeams.help": "Allow learners to work together on specific projects or activities.",
"authoring.pagesAndResources.teams.enableTeams.link": "Learn more about teams",
"authoring.pagesAndResources.teams.teamSize.heading": "Team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSize": "Max team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeHelp": "The maximum number of learners that can join a team",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeEmpty": "Enter max team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeInvalid": "Max team size must be a positive number larger than zero.",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeTooHigh": "Max team size cannot be greater than {max}",
"authoring.pagesAndResources.teams.groups.heading": "Groups",
"authoring.pagesAndResources.teams.groups.help": "Groups are spaces where learners can create or join teams.",
"authoring.pagesAndResources.teams.configureGroup.heading": "Configure group",
"authoring.pagesAndResources.teams.group.name.label": "Name",
"authoring.pagesAndResources.teams.group.name.help": "Choose a unique name for this group",
"authoring.pagesAndResources.teams.group.name.error.empty": "Enter a unique name for this group",
"authoring.pagesAndResources.teams.group.name.error.exists": "It looks like this name is already in use",
"authoring.pagesAndResources.teams.group.description.label": "Description",
"authoring.pagesAndResources.teams.group.description.help": "Enter details about this group",
"authoring.pagesAndResources.teams.group.description.error": "Enter a description for this group",
"authoring.pagesAndResources.teams.group.type.label": "Type",
"authoring.pagesAndResources.teams.group.type.help": "Control who can see, create and join teams",
"authoring.pagesAndResources.teams.group.types.open": "Open",
"authoring.pagesAndResources.teams.group.types.open.description": "Learners can create, join, leave, and see other teams",
"authoring.pagesAndResources.teams.group.types.public_managed": "Public managed",
"authoring.pagesAndResources.teams.group.types.public_managed.description": "Only course staff can control teams and memberships. Learners can see other teams.",
"authoring.pagesAndResources.teams.group.types.private_managed": "Private managed",
"authoring.pagesAndResources.teams.group.types.private_managed.description": "Only course staff can control teams, memberships, and see other teams",
"authoring.pagesAndResources.teams.group.maxSize.label": "Max team size (optional)",
"authoring.pagesAndResources.teams.group.maxSize.help": "Override the global max team size",
"authoring.pagesAndResources.teams.addGroup.button": "Add group",
"authoring.pagesAndResources.teams.group.delete": "Delete",
"authoring.pagesAndResources.teams.group.expand": "Expand group editor",
"authoring.pagesAndResources.teams.group.collapse": "Close group editor",
"authoring.pagesAndResources.teams.deleteGroup.initiateDelete": "Delete",
"authoring.pagesAndResources.teams.deleteGroup.cancel-delete.button": "Cancel",
"authoring.pagesAndResources.teams.deleteGroup.heading": "Delete this group?",
"authoring.pagesAndResources.teams.deleteGroup.body": "edX recommends that you do not delete groups once your course is running.\n Your group will no longer be visible in the LMS and learners will not be able to leave teams associated with it.\n Please delete learners from teams before deleting the associated group.",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.title": "No groups found",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.message": "Add one or more groups to enable teams.",
"course-authoring.pages-resources.wiki.heading": "Configure wiki",
"course-authoring.pages-resources.wiki.enable-wiki.label": "Wiki",
"course-authoring.pages-resources.wiki.enable-wiki.help": "The course wiki can be set up based on the needs of your\n course. Common uses might include sharing answers to course FAQs, sharing\n editable course information, or providing access to learner-created\n resources.",
"course-authoring.pages-resources.wiki.enable-wiki.link": "Learn more about the wiki",
"course-authoring.pages-resources.wiki.enable-public-wiki.label": "Enable public wiki access",
"course-authoring.pages-resources.wiki.enable-public-wiki.help": "If enabled, edX users can view the course wiki even when\n they're not enrolled in the course.",
"authoring.examsettings.enableproctoredexams.help": "If checked, proctored exams are enabled in your course.",
"authoring.examsettings.allowoptout.label": "Allow Opting Out of Proctored Exams",
"authoring.examsettings.allowoptout.help": "\n If this value is \"Yes\", learners can choose to take proctored exams without proctoring.\n If this value is \"No\", all learners must take the exam with proctoring.\n ",
"authoring.examsettings.provider.label": "Proctoring Provider",
"authoring.examsettings.escalationemail.label": "Proctortrack Escalation Email",
"authoring.examsettings.escalationemail.help": "\n Required if \"proctortrack\" is selected as your proctoring provider. Enter an email address to be\n contacted by the support team whenever there are escalations (e.g. appeals, delayed reviews, etc.).\n ",
"authoring.examsettings.createzendesk.label": "Create Zendesk Tickets for Suspicious Proctored Exam Attempts",
"authoring.examsettings.createzendesk.help": "If this value is \"Yes\", a Zendesk ticket will be created for suspicious proctored exam attempts.",
"authoring.examsettings.submit": "Submit",
"authoring.examsettings.alert.success": "\n Proctored exam settings saved successfully.\n You can go back to your course in Studio {studioCourseRunURL}.\n ",
"authoring.examsettings.allowoptout.no": "No",
"authoring.examsettings.allowoptout.yes": "Yes",
"authoring.examsettings.createzendesk.no": "No",
"authoring.examsettings.createzendesk.yes": "Yes",
"authoring.examsettings.support.text": "Support Page",
"authoring.examsettings.escalationemail.enableproctoredexams.label": "Enable Proctored Exams",
"authoring.examsettings.escalationemail.error.blank": "The Proctortrack Escalation Email field cannot be empty if proctortrack is the selected provider.",
"authoring.examsettings.escalationemail.error.invalid": "The Proctortrack Escalation Email field is in the wrong format and is not valid.",
"authoring.examsettings.error.single": "There is 1 error in this form.",
"authoring.examsettings.escalationemail.error.multiple": "There are {numOfErrors} errors in this form.",
"authoring.examsettings.provider.help": "Select the proctoring provider you want to use for this course run.",
"authoring.examsettings.provider.help.aftercoursestart": "Proctoring provider cannot be modified after course start date.",
"header.links.content": "Content",
"header.links.settings": "Settings",
"header.links.content.tools": "Tools",
"header.links.outline": "Outline",
"header.links.updates": "Updates",
"header.links.pages": "Pages & Resources",
"header.links.filesAndUploads": "Files & Uploads",
"header.links.textbooks": "Textbooks",
"header.links.videoUploads": "Video Uploads",
"header.links.scheduleAndDetails": "Schedule & Details",
"header.links.grading": "Grading",
"header.links.courseTeam": "Course Team",
"header.links.groupConfigurations": "Group Configurations",
"header.links.proctoredExamSettings": "Proctored Exam Settings",
"header.links.advancedSettings": "Advanced Settings",
"header.links.certificates": "Certificates",
"header.links.publisher": "Publisher",
"header.links.import": "Import",
"header.links.export": "Export",
"header.links.checklists": "Checklists",
"header.user.menu.studio": "Studio Home",
"header.user.menu.maintenance": "Maintenance",
"header.user.menu.logout": "Logout",
"header.label.account.menu": "Account Menu",
"header.label.account.menu.for": "Account menu for {username}",
"header.label.main.nav": "Main",
"header.label.main.menu": "Main Menu",
"header.label.main.header": "Main",
"header.label.secondary.nav": "Secondary",
"header.label.courseOutline": "Back to course outline in Studio"
}

View File

@@ -42,7 +42,12 @@
"authoring.discussions.configure": "Configura discusiones",
"authoring.discussions.ok": "OK",
"authoring.discussions.cancel": "Cancelar",
"authoring.discussions.confirm": "Confirm",
"authoring.discussions.confirmConfigurationChange": "¿Estas seguro que deseas cambiar la configuración de las discusiones? ",
"authoring.discussions.confirmEnableDiscussionsLabel": "Enable discussions on units in graded subsections?",
"authoring.discussions.cancelEnableDiscussionsLabel": "Disable discussions on units in graded subsections?",
"authoring.discussions.confirmEnableDiscussions": "Enabling this toggle will automatically enable discussion on all units in graded subsections, that are not timed exams.",
"authoring.discussions.cancelEnableDiscussions": "Disabling this toggle will automatically disable discussion on all units in graded subsections. Discussion topics containing at least 1 thread will be listed and accessible under “Archived” in Topics tab on the Discussions page.",
"authoring.discussions.backButton": "Volver atrás",
"authoring.discussions.saveButton": "Guardar",
"authoring.discussions.savingButton": "Guardando",
@@ -61,15 +66,13 @@
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.help": "Escoge cuales de los temas de tus discusiones de todo el cursos te gustaría dividir.",
"authoring.discussions.builtIn.divideGeneralTopic.label": "General",
"authoring.discussions.builtIn.divideQuestionsForTAsTopic.label": "Preguntas para las herramientas asistidas",
"authoring.discussions.builtIn.cohortsEnabled.label": "To adjust these settings, enable cohorts on the ",
"authoring.discussions.builtIn.instructorDashboard.label": "instructor dashboard",
"authoring.discussions.builtIn.visibilityInContext": "visualización de las discusioness en contexto",
"authoring.discussions.builtIn.inContextDiscussion.label": "discusiones en contexto",
"authoring.discussions.builtIn.inContextDiscussion.help": "Los estudiantes podrán ver u ocultar el panel de discusiones para participar en la discusión de la unidad de página del curso.",
"authoring.discussions.builtIn.gradedUnitPages.label": "Unidades de página calificadas",
"authoring.discussions.builtIn.gradedUnitPages.label": "Habilitar discusiones en unidades de subsecciones calificables",
"authoring.discussions.builtIn.gradedUnitPages.help": "Permítele a los estudiantes participar con discusiones en todas las unidades de página calificables con excepción de los exámenes cronometrados.",
"authoring.discussions.builtIn.groupInContextSubsection.label": "Grupo en la discusión de contexto en el nivel de subseción",
"authoring.discussions.builtIn.groupInContextSubsection.help": "Los estudiantes podrán ver cualquier publicación en la sub-sección sin importar en que unidad de página se encuentren visualizando. Mientras esto no sea recomendado, si tu curso cuenta con pocas secuencias de aprendizaje o bajo número de inscripciones, hacer grupos puede incrementar la participación.",
"authoring.discussions.builtIn.allowUnitLevelVisibility.label": "Permite la visibilidad de la configuración para cada unidad de curso",
"authoring.discussions.builtIn.allowUnitLevelVisibility.help": "Con esta configuración avanzada habilitada podrás anular la visibilidad global de la configuración y encender o apagar las discusiones para cada unidad desde la vista de esquema de curso.",
"authoring.discussions.builtIn.anonymousPosting": "Publicación anonima",
"authoring.discussions.builtIn.allowAnonymous.label": "Habilita publicaciones anonimas en las discusiones",
"authoring.discussions.builtIn.allowAnonymous.help": "Si es permitido, los estudiantes puedrán crear publicaciones anonimas para todos los usuarios.",
@@ -183,22 +186,23 @@
"course-authoring.pages-resources.notes.enable-notes.label": "Notas",
"course-authoring.pages-resources.notes.enable-notes.help": "Los estudiantes pueden acceder a las notas ya sea en el cuerpo del \n curso en una página de notas. En la página de notas, el estudiante puede ver todas las\n notas realizadas durante el curso. La página también contiene enlaces a la ubicación\n de las notas en el cuerpo del curso.",
"course-authoring.pages-resources.notes.enable-notes.link": "Aprende más acerca de las notas",
"authoring.live.bbb.selectPlan.label": "Seleccione un plan",
"authoring.pagesAndResources.live.enableLive.heading": "Configurar en vivo",
"authoring.pagesAndResources.live.enableLive.label": "Live",
"authoring.pagesAndResources.live.enableLive.label": "En vivo",
"authoring.pagesAndResources.live.enableLive.help": "Programe reuniones y realice sesiones de cursos en vivo con los alumnos.",
"authoring.pagesAndResources.live.enableLive.link": "Learn more about live",
"authoring.pagesAndResources.live.enableLive.link": "Más información sobre el vivo",
"authoring.live.selectProvider": "Seleccione una herramienta de videoconferencia",
"authoring.live.formInstructions": "Complete los campos a continuación para configurar su herramienta de videoconferencia.",
"authoring.live.consumerKey": "Consumidor Clave",
"authoring.live.consumerKey.required": "Consumidor clave es requerido en este campo",
"authoring.live.consumerSecret": "Consumer Secret",
"authoring.live.consumerSecret": "Consumidor Secreto",
"authoring.live.consumerSecret.required": "Consumidor secreto es requerido en este campo",
"authoring.live.launchUrl": "Lanzamiento URL",
"authoring.live.launchUrl.required": "Lanzamiento URL es requerida para este campo",
"authoring.live.launchEmail": "Correo electrónico de lanzamiento",
"authoring.live.launchEmail.required": "El correo electrónico de lanzamiento es un campo obligatorio",
"authoring.live.provider.helpText": "This configuration will require sharing username and emails of learners and the course team with {providerName}.",
"authoring.live.requestPiiSharingEnable": "This configuration will require sharing usernames and emails of learners and the course team with {provider}. To access the LTI configuration for {provider}, please request your edX project coordinator to get PII sharing enabled for this course.",
"authoring.live.provider.helpText": "Esta configuración requerirá compartir el nombre de usuario y los correos electrónicos de los alumnos, además del equipo del curso con {providerName}.",
"authoring.live.requestPiiSharingEnable": "Esta configuración requerirá compartir los nombres de usuario y los correos electrónicos de los alumnos, además del equipo del curso con {provider}. Para acceder a la configuración de LTI para {provider}, solicite a su coordinador de proyectos de edX que habilite el uso compartido de PII para este curso.",
"authoring.live.appDocInstructions.documentationLink": "Documentación general ",
"authoring.live.appDocInstructions.accessibilityDocumentationLink": "Documentación de accesibilidad ",
"authoring.live.appDocInstructions.configurationLink": "Documentación de configuración",
@@ -208,6 +212,11 @@
"authoring.live.appName-yellowdig": "Zoom",
"authoring.live.appName-googleMeet": "Reunión de Google",
"authoring.live.appName-microsoftTeams": "Equipos de Microsoft",
"authoring.live.appName-bigBlueButton": "GranBotónAzul",
"authoring.live.requestPiiSharingEnableForBbb": "Esta configuración requerirá compartir los nombres de usuario de los alumnos y el equipo del curso con {provider}.",
"authoring.live.piiSharingEnableHelpText": "Para habilitar esta función, comuníquese con el equipo de soporte de edX para habilitar el uso compartido de PII para este curso.",
"authoring.live.freePlanMessage": "The free plan is pre-configured, and no additional configurations are required. By selecting the free plan, you are agreeing to Blindside Networks",
"authoring.live.privacyPolicy": "Privacy Policy.",
"course-authoring.pages-resources.heading": "Páginas & Recursos",
"course-authoring.pages-resources.resources.settings.button": "configuraciones",
"course-authoring.pages-resources.viewLive.button": "Ver en vivo",

View File

@@ -42,7 +42,12 @@
"authoring.discussions.configure": "Configurez les discussions",
"authoring.discussions.ok": "OK",
"authoring.discussions.cancel": "Annuler",
"authoring.discussions.confirm": "Confirm",
"authoring.discussions.confirmConfigurationChange": "Voulez-vous vraiment modifier les paramètres de discussion ?",
"authoring.discussions.confirmEnableDiscussionsLabel": "Enable discussions on units in graded subsections?",
"authoring.discussions.cancelEnableDiscussionsLabel": "Disable discussions on units in graded subsections?",
"authoring.discussions.confirmEnableDiscussions": "Enabling this toggle will automatically enable discussion on all units in graded subsections, that are not timed exams.",
"authoring.discussions.cancelEnableDiscussions": "Disabling this toggle will automatically disable discussion on all units in graded subsections. Discussion topics containing at least 1 thread will be listed and accessible under “Archived” in Topics tab on the Discussions page.",
"authoring.discussions.backButton": "Retour",
"authoring.discussions.saveButton": "Enregistrer",
"authoring.discussions.savingButton": "Enregistrement",
@@ -61,15 +66,13 @@
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.help": "Choisissez lequel des sujets de discussion à l'échelle du cours vous souhaitez diviser.",
"authoring.discussions.builtIn.divideGeneralTopic.label": "Général",
"authoring.discussions.builtIn.divideQuestionsForTAsTopic.label": "Questions pour les assistants d'enseignement",
"authoring.discussions.builtIn.cohortsEnabled.label": "To adjust these settings, enable cohorts on the ",
"authoring.discussions.builtIn.instructorDashboard.label": "instructor dashboard",
"authoring.discussions.builtIn.visibilityInContext": "Visibilité des discussions en contexte",
"authoring.discussions.builtIn.inContextDiscussion.label": "Discussion en contexte",
"authoring.discussions.builtIn.inContextDiscussion.help": "Les apprenants pourront afficher ou masquer un panneau latéral de discussion pour participer à la discussion sur la page de l'unité de cours.",
"authoring.discussions.builtIn.gradedUnitPages.label": "Pages d'unités notées",
"authoring.discussions.builtIn.gradedUnitPages.label": "Enable discussions on units in graded subsections",
"authoring.discussions.builtIn.gradedUnitPages.help": "Permettez aux apprenants de participer à la discussion sur toutes les pages d'unités notées, à l'exception des examens chronométrés.",
"authoring.discussions.builtIn.groupInContextSubsection.label": "Discussion de groupe en contexte au niveau des sous-sections",
"authoring.discussions.builtIn.groupInContextSubsection.help": "Les apprenants pourront voir n'importe quel article de la sous-section, quelle que soit la page d'unité qu'ils consultent. Bien que cela ne soit pas recommandé, si votre cours comporte de courtes séquences d'apprentissage ou un faible regroupement d'inscription cela peut augmenter l'engagement.",
"authoring.discussions.builtIn.allowUnitLevelVisibility.label": "Autoriser la configuration de la visibilité pour chaque unité de cours",
"authoring.discussions.builtIn.allowUnitLevelVisibility.help": "Avec ce paramètre avancé activé, vous pourrez remplacer le paramètre de visibilité globale et activer ou désactiver les discussions pour chaque unité à partir de la vue d'ensemble du cours.",
"authoring.discussions.builtIn.anonymousPosting": "Publication anonyme",
"authoring.discussions.builtIn.allowAnonymous.label": "Autoriser les posts de discussion anonymes",
"authoring.discussions.builtIn.allowAnonymous.help": "Si activé, les apprenants pourront créer des publications qui resteront anonymes à tous les utilisateurs.",
@@ -183,6 +186,7 @@
"course-authoring.pages-resources.notes.enable-notes.label": "Notes",
"course-authoring.pages-resources.notes.enable-notes.help": "Les apprenants peuvent accéder à leurs notes à partir du\n corps du cours ou une page de notes. Sur la page de notes, un apprenant peut voir toutes les\n notes conçues durant le cours. La page contient également les liens vers la location\n des notes dans le corps du cours.",
"course-authoring.pages-resources.notes.enable-notes.link": "Apprenez en plus sur notes",
"authoring.live.bbb.selectPlan.label": "Select a plan",
"authoring.pagesAndResources.live.enableLive.heading": "Configurer en direct",
"authoring.pagesAndResources.live.enableLive.label": "Live",
"authoring.pagesAndResources.live.enableLive.help": "Planifiez des réunions et organisez des sessions de cours en direct avec les apprenants.",
@@ -208,6 +212,11 @@
"authoring.live.appName-yellowdig": "Zoom",
"authoring.live.appName-googleMeet": "Google Meet",
"authoring.live.appName-microsoftTeams": "Microsoft Teams",
"authoring.live.appName-bigBlueButton": "BigBlueButton",
"authoring.live.requestPiiSharingEnableForBbb": "This configuration will require sharing usernames of learners and the course team with {provider}.",
"authoring.live.piiSharingEnableHelpText": "To enable this feature, contact your edX support team to enable PII sharing for this course.",
"authoring.live.freePlanMessage": "The free plan is pre-configured, and no additional configurations are required. By selecting the free plan, you are agreeing to Blindside Networks",
"authoring.live.privacyPolicy": "Privacy Policy.",
"course-authoring.pages-resources.heading": "Pages et ressources",
"course-authoring.pages-resources.resources.settings.button": "paramètres",
"course-authoring.pages-resources.viewLive.button": "Aperçu temps réel",

View File

@@ -0,0 +1,352 @@
{
"authoring.alert.error.connection": "Nous avons rencontré une erreur technique lors du chargement de cette page. Cela peut être un problème temporaire, veuillez donc réessayer dans quelques minutes. Si le problème persiste, accédez à {support_link} pour obtenir de l'aide.",
"authoring.loading": "Chargement...",
"authoring.alert.error.permission": "Vous n'êtes pas autorisé à afficher cette page. Si vous croyez que vous devriez avoir accès à cette page, veuillez contacter l'équipe administrative du cours pour obtenir la permission.",
"authoring.alert.save.error.connection": "Nous avons rencontré une erreur technique lors de l'application des modifications. Cela peut être un problème temporaire, veuillez donc réessayer dans quelques minutes. Si le problème persiste, accédez à {support_link} pour obtenir de l'aide.",
"authoring.alert.support.text": "Page de support",
"course-authoring.pages-resources.app-settings-modal.button.cancel": "Annuler",
"course-authoring.pages-resources.app-settings-modal.button.save": "Sauvegarder",
"course-authoring.pages-resources.app-settings-modal.button.saving": "Sauvegarde en cours",
"course-authoring.pages-resources.app-settings-modal.button.saved": "Sauvegardé",
"course-authoring.pages-resources.app-settings-modal.button.retry": "Réessayez",
"course-authoring.pages-resources.app-settings-modal.badge.enabled": "Activé",
"course-authoring.pages-resources.app-settings-modal.badge.disabled": "Désactivé",
"course-authoring.pages-resources.app-settings-modal.save-error.title": "Nous n'avons pas pu appliquer vos changements.",
"course-authoring.pages-resources.app-settings-modal.save-error.message": "Veuillez vérifier vos entrées et réessayer.",
"course-authoring.pages-resources.calculator.heading": "Configurer la calculatrice",
"course-authoring.pages-resources.calculator.enable-calculator.label": "Calculatrice",
"course-authoring.pages-resources.calculator.enable-calculator.help": "La calculatrice prend en charge les nombres, les opérateurs, les constantes,\n fonctions et autres concepts mathématiques. Lorsqu'elle est activée, une icône pour\n accéder à la calculatrice apparaît sur toutes les pages du corps de votre cours.",
"course-authoring.pages-resources.calculator.enable-calculator.link": "En savoir plus sur la calculatrice",
"authoring.discussions.documentationPage": "Visitez la page de documentation de {name}",
"authoring.discussions.formInstructions": "Complétez les champs ci-dessous pour configurer votre outil de discussion.",
"authoring.discussions.consumerKey": "Clé du consommateur",
"authoring.discussions.consumerKey.required": "La clé du consommateur est un champ obligatoire",
"authoring.discussions.consumerSecret": "Secret du consommateur",
"authoring.discussions.consumerSecret.required": "Le secret du consommateur est un champ obligatoire",
"authoring.discussions.launchUrl": "URL de lancement",
"authoring.discussions.launchUrl.required": "L'URL de lancement est un champ obligatoire",
"authoring.discussions.stuffOnlyConfigInfo": "Pour activer {providerName} pour votre cours, veuillez contacter leur équipe d'assistance à {supportEmail} pour en savoir plus sur les prix et l'utilisation.",
"authoring.discussions.stuffOnlyConfigGuide": "Pour configurer entièrement {providerName}, il faudra également partager les noms d'utilisateur et les courriels pour les apprenants et l'équipe du cours. Veuillez contacter votre coordinateur de projet edX pour activer le partage de PII pour ce cours.",
"authoring.discussions.piiSharing": "Partagez en option le nom d'utilisateur et/ou l'adresse courriel d'un utilisateur avec le fournisseur LTI :",
"authoring.discussions.piiShareUsername": "Partager le nom d'utilisateur",
"authoring.discussions.piiShareEmail": "Partager l'adresse courriel",
"authoring.discussions.appDocInstructions.contact": "Contact : {link}",
"authoring.discussions.appDocInstructions.documentationLink": "Documentation générale",
"authoring.discussions.appDocInstructions.accessibilityDocumentationLink": "Documentation daccessibilité",
"authoring.discussions.appDocInstructions.configurationLink": "Documentation de configuration",
"authoring.discussions.appDocInstructions.learnMoreLink": "Apprenez-en plus sur {providerName}",
"authoring.discussions.appDocInstructions.linkTextHeading": "Aide externe et documentation",
"authoring.discussions.appDocInstructions.linkText": "{link}",
"authoring.discussions.configurationChangeConsequences": "Les étudiants perdront l'accès à tous les messages de discussion actifs ou précédents pour votre cours.",
"authoring.discussions.configure.app": "Configurer {name}",
"authoring.discussions.configure": "Configurez les discussions",
"authoring.discussions.ok": "OK",
"authoring.discussions.cancel": "Annuler",
"authoring.discussions.confirm": "Confirmer",
"authoring.discussions.confirmConfigurationChange": "Voulez-vous vraiment modifier les paramètres de discussion ?",
"authoring.discussions.confirmEnableDiscussionsLabel": "Activer les discussions sur les unités dans les sous-sections notées ?",
"authoring.discussions.cancelEnableDiscussionsLabel": "Désactiver les discussions sur les unités dans les sous-sections notées ?",
"authoring.discussions.confirmEnableDiscussions": "L'activation de cette bascule activera automatiquement la discussion sur toutes les unités dans les sous-sections notées, qui ne sont pas des examens chronométrés.",
"authoring.discussions.cancelEnableDiscussions": "La désactivation de cette bascule désactivera automatiquement la discussion sur toutes les unités dans les sous-sections notées. Les sujets de discussion contenant au moins 1 fil de discussion seront répertoriés et accessibles sous \"Archivés\" dans l'onglet Sujets de la page Discussions.",
"authoring.discussions.backButton": "Retour",
"authoring.discussions.saveButton": "Sauvegarder",
"authoring.discussions.savingButton": "Sauvegarde en cours",
"authoring.discussions.savedButton": "Sauvegardé",
"authoring.discussions.appConfigForm.appName-piazza": "Piazza",
"authoring.discussions.appConfigForm.appName-yellowdig": "Yellowdig",
"authoring.discussions.appConfigForm.appName-inscribe": "InScribe",
"authoring.discussions.appConfigForm.appName-discourse": "Discourse",
"authoring.discussions.appConfigForm.appName-ed-discuss": "Ed Discussion",
"authoring.discussions.appConfigForm.appName-legacy": "edX",
"authoring.discussions.appConfigForm.appName-openedx": "edX",
"authoring.discussions.builtIn.divisionByGroup": "Cohortes",
"authoring.discussions.builtIn.divideByCohorts.label": "Divisez les discussions par cohortes",
"authoring.discussions.builtIn.divideByCohorts.help": "Les apprenants ne pourront voir et répondre qu'aux discussions publiées par les membres de leur cohorte.",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.label": "Divisez les sujets de discussion à l'échelle du cours",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.help": "Choisissez lequel des sujets de discussion à l'échelle du cours vous souhaitez diviser.",
"authoring.discussions.builtIn.divideGeneralTopic.label": "Général",
"authoring.discussions.builtIn.divideQuestionsForTAsTopic.label": "Questions pour les assistants d'enseignement",
"authoring.discussions.builtIn.cohortsEnabled.label": "Pour ajuster ces paramètres, activez les cohortes sur le",
"authoring.discussions.builtIn.instructorDashboard.label": "tableau de bord de l'instructeur",
"authoring.discussions.builtIn.visibilityInContext": "Visibilité des discussions en contexte",
"authoring.discussions.builtIn.gradedUnitPages.label": "Activer les discussions sur les unités dans les sous-sections notées",
"authoring.discussions.builtIn.gradedUnitPages.help": "Permettez aux apprenants de participer à la discussion sur toutes les pages d'unités notées, à l'exception des examens chronométrés.",
"authoring.discussions.builtIn.groupInContextSubsection.label": "Discussion de groupe en contexte au niveau des sous-sections",
"authoring.discussions.builtIn.groupInContextSubsection.help": "Les apprenants pourront voir n'importe quel article de la sous-section, quelle que soit la page d'unité qu'ils consultent. Bien que cela ne soit pas recommandé, si votre cours comporte de courtes séquences d'apprentissage ou un faible regroupement d'inscription cela peut augmenter l'engagement.",
"authoring.discussions.builtIn.anonymousPosting": "Publication anonyme",
"authoring.discussions.builtIn.allowAnonymous.label": "Autoriser les posts de discussion anonymes",
"authoring.discussions.builtIn.allowAnonymous.help": "Si activé, les apprenants pourront créer des publications qui resteront anonymes à tous les utilisateurs.",
"authoring.discussions.builtIn.allowAnonymousPeers.label": "Autorisez les posts de discussion anonymes aux pairs",
"authoring.discussions.builtIn.allowAnonymousPeers.help": "Les apprenants seront capables de poster de manière anonymes aux autres pairs mais tous les posts seront visibles par l'équipe du cours.",
"authoring.discussions.builtIn.reportedContentEmailNotifications": "Notifications",
"authoring.discussions.builtIn.reportedContentEmailNotifications.label": "Notifications par courriel pour le contenu signalé",
"authoring.discussions.builtIn.reportedContentEmailNotifications.help": "Les administrateurs de discussion, les modérateurs, les assistants de communauté et les assistants de communauté de groupe (uniquement pour leur propre cohorte) recevront une notification par courriel lorsque du contenu est signalé.",
"authoring.discussions.discussionTopics": "Sujets de discussions",
"authoring.discussions.discussionTopics.label": "Sujets de discussion généraux",
"authoring.discussions.discussionTopics.help": "Les discussions peuvent inclure des sujets généraux non contenus dans la structure du cours. Tous les cours ont un sujet général par défaut.",
"authoring.discussions.discussionTopic.required": "Le nom du sujet est un champ obligatoire",
"authoring.discussions.discussionTopic.alreadyExistError": "Il semble que ce nom soit déjà utilisé",
"authoring.discussions.addTopicButton": "Ajoutez un sujet",
"authoring.discussions.deleteButton": "Supprimer",
"authoring.discussions.cancelButton": "Annuler",
"authoring.discussions.discussionTopicDeletion.help": "EDUlib vous recommande de ne pas supprimer les sujets de discussion une fois que votre cours est en cours.",
"authoring.discussions.discussionTopicDeletion.label": "Supprimer ce sujet ?",
"authoring.discussions.builtIn.renameGeneralTopic.label": "Renommez le sujet général",
"authoring.discussions.generalTopicHelp.help": "Ceci est le sujet de discussion par défaut pour votre cours.",
"authoring.discussions.builtIn.configureAdditionalTopic.label": "Configurez le sujet",
"authoring.discussions.addTopicHelpText": "Choisissez un nom unique pour votre sujet",
"authoring.discussions.blackoutDates": "Dates d'interdiction des discussions",
"authoring.discussions.builtIn.blackoutDates.label": "Dates d'interdiction",
"authoring.discussions.builtIn.blackoutDates.help": "S'ils sont ajoutés, les apprenants ne pourront pas participer aux discussions entre ces dates.",
"authoring.discussions.addBlackoutDatesButton": "Ajouter une plage de dates d'interdiction",
"authoring.discussions.builtIn.configureBlackoutDates.label": "Configurer la plage de dates d'interdiction",
"authoring.discussions.blackoutStartDate.help": "Entrez une date de début, par exemple le 12/10/2023.",
"authoring.discussions.blackoutEndDate.help": "Entrez une date de fin, par exemple le 17/12/2023.",
"authoring.discussions.blackoutStartTime.help": "Entrez une heure de début, par exemple 09h00",
"authoring.discussions.blackoutEndTime.help": "Entrez une heure de fin, par exemple 17h00",
"authoring.discussions.activeBlackoutDatesDeletion.help": "Ces dates d'interdiction sont actuellement actives. Si elles sont supprimées, les apprenants pourront publier dans les discussions pendant ces dates. Êtes-vous sûr de vouloir continuer ?",
"authoring.discussions.blackoutDatesDeletion.help": "Si supprimé, les apprenants pourront participer aux discussions pendant ces dates.",
"authoring.discussions.completeBlackoutDatesDeletion.help": "Êtes-vous sûr de vouloir supprimer ces dates d'interdiction ?",
"authoring.discussions.activeBlackoutDatesDeletion.label": "Supprimer les dates d'interdiction actives ?",
"authoring.discussions.blackoutDatesDeletion.label": "Supprimer les dates d'interdiction ?",
"authoring.blackoutDates.delete": "Supprimer les dates d'interdiction",
"authoring.blackoutDates.status": "{status}",
"authoring.blackoutDates.startDate.required": "La date de début est un champ obligatoire",
"authoring.blackoutDates.endDate.required": "La date de fin est un champ obligatoire",
"authoring.blackoutDates.startDate.inPast": "La date de début ne peut pas être après la date de fin",
"authoring.blackoutDates.endDate.inPast": "La date de fin ne peut pas être avant la date de début",
"authoring.blackoutDates.startTime.inPast": "L'heure de début ne peut pas être après l'heure de fin",
"authoring.blackoutDates.endTime.inPast": "L'heure de fin ne peut pas être avant l'heure de début",
"authoring.blackoutDates.startTime.inValidFormat": "Entrer un temps de départ valide",
"authoring.blackoutDates.endTime.inValidFormat": "Entrer un temps de fin valide",
"authoring.blackoutDates.startDate.inValidFormat": "Entrer une date valide de départ",
"authoring.blackoutDates.endDate.inValidFormat": "Entrer une date valide de fin",
"authoring.topics.delete": "Supprimer le sujet",
"authoring.topics.expand": "Développer",
"authoring.topics.collapse": "Replier",
"authoring.blackoutDates.start.date": "Date de début",
"authoring.blackoutDates.start.time": "Heure de début (facultatif) ({zone})",
"authoring.blackoutDates.end.date": "Date de fin",
"authoring.blackoutDates.end.time": "Heure de fin (facultatif) ({zone})",
"authoring.discussions.heading": "Sélectionnez un outil de discussion pour ce cours",
"authoring.discussions.supportedFeatures": "Fonctionnalités prises en charge",
"authoring.discussions.supportedFeatureList-mobile-show": "Afficher les fonctionnalités prises en charge",
"authoring.discussions.supportedFeatureList-mobile-hide": "Masquer les fonctionnalités prises en charge",
"authoring.discussions.noApps": "Aucun fournisseur de discussion n'est disponible pour votre cours.",
"authoring.discussions.nextButton": "Suivant",
"authoring.discussions.appFullSupport": "Support complet",
"authoring.discussions.appBasicSupport": "Support de base",
"authoring.discussions.selectApp": "Choisissez {appName}",
"authoring.discussions.appList.appName-legacy": "edX",
"authoring.discussions.appList.appDescription-legacy": "Démarrez des conversations avec d'autres apprenants, posez des questions et interagissez avec d'autres apprenants du cours.",
"authoring.discussions.appList.appName-openedx": "edX",
"authoring.discussions.appList.appDescription-openedx": "Entamez des conversations avec d'autres apprenants, posez des questions et interagissez avec d'autres apprenants du cours.",
"authoring.discussions.appList.appName-piazza": "Piazza",
"authoring.discussions.appList.appDescription-piazza": "Piazza est conçu pour connecter les étudiants, les assistants enseignants et les professeurs afin que chaque étudiant puisse obtenir l'aide dont il a besoin quand il en a besoin.",
"authoring.discussions.appList.appDescription-yellowdig": "Yellowdig offre aux éducateurs une solution d'enseignement ludique pour augmenter l'engagement des étudiants en construisant des communautés d'apprentissage pour toutes les modalités de cours.",
"authoring.discussions.appList.appDescription-inscribe": "InScribe exploite le pouvoir des communauté + l'intelligence artificielle pour connecter les individus aux réponses, aux ressources et aux personnes qu'ils ont besoin pour exceller.",
"authoring.discussions.appList.appDescription-discourse": "Discourse est un programme de forum moderne pour votre communauté. Utilisez le en tant que liste de courriel, forum de discussion, salle de conversation et bien plus!",
"authoring.discussions.appList.appDescription-ed-discus": "Ed Discussion aide les communications en classe avec une belle interface intuitive. Les questions rejoignent et bénéficient toute la classe. Moins de courriel, plus de temps épargnés.",
"authoring.discussions.featureName-discussion-page": "Page de discussion",
"authoring.discussions.featureName-embedded-course-sections": "Sections de cours intégrées",
"authoring.discussions.featureName-advanced-in-context-discussion": "Discussion avancée en contexte",
"authoring.discussions.featureName-anonymous-posting": "Publication anonyme",
"authoring.discussions.featureName-automatic-learner-enrollment": "Inscription automatique de l'apprenant",
"authoring.discussions.featureName-blackout-discussion-dates": "Dates de discussions interdites",
"authoring.discussions.featureName-community-ta-support": "Support des assistants d'enseignement de la communauté",
"authoring.discussions.featureName-course-cohort-support": "Support des cohortes de cours",
"authoring.discussions.featureName-direct-messages-from-instructors": "Messages directs des instructeurs",
"authoring.discussions.featureName-discussion-content-prompts": "Instructions pour le contenu de discussion",
"authoring.discussions.featureName-email-notifications": "Notifications par courriel",
"authoring.discussions.featureName-graded-discussions": "Discussions notées",
"authoring.discussions.featureName-in-platform-notifications": "Notifications sur la plateforme",
"authoring.discussions.featureName-internationalization-support": "Support pour l'Internationalisation",
"authoring.discussions.featureName-lti-advanced-sharing-mode": "Partage avancé LTI",
"authoring.discussions.featureName-basic-configuration": "Configuration de base",
"authoring.discussions.featureName-primary-discussion-app-experience": "Application de discussion primaire",
"authoring.discussions.featureName-question-&-discussion-support": "Support aux Questions et Discussions",
"authoring.discussions.featureName-report/flag-content-to-moderators": "Signaler du contenu aux modérateurs",
"authoring.discussions.featureName-research-data-events": "Recherche de données d'évènements",
"authoring.discussions.featureName-simplified-in-context-discussion": "Simplifié dans le contexte de la discussion",
"authoring.discussions.featureName-user-mentions": "Mentions utilisatrices",
"authoring.discussions.featureName-wcag-2.1": "Support WCAG 2.1",
"authoring.discussions.wcag-2.0-support": "Support WCAG 2.0",
"authoring.discussions.basic-support": "Support de base",
"authoring.discussions.partial-support": "Support partiel",
"authoring.discussions.full-support": "Support complet",
"authoring.discussions.common-support": "Demande fréquente",
"authoring.discussions.settings": "Paramètres",
"authoring.discussions.applyButton": "Appliquer",
"authoring.discussions.applyingButton": "Appliquer",
"authoring.discussions.appliedButton": "Appliqué",
"authoring.discussions.noProviderSwitchAfterCourseStarted": "Le fournisseur de discussion ne peut pas être modifié une fois le cours commencé, veuillez contacter l'assistance partenaire.",
"authoring.discussions.providerSelection": "Sélection des fournisseurs",
"authoring.discussions.Incomplete": "Incomplet",
"course-authoring.pages-resources.notes.heading": "Configurer les notes",
"course-authoring.pages-resources.notes.enable-notes.label": "Notes",
"course-authoring.pages-resources.notes.enable-notes.help": "Les apprenants peuvent accéder à leurs notes à partir du\n corps du cours ou une page de notes. Sur la page de notes, un apprenant peut voir toutes les\n notes conçues durant le cours. La page contient également les liens vers la location\n des notes dans le corps du cours.",
"course-authoring.pages-resources.notes.enable-notes.link": "Apprenez en plus sur notes",
"authoring.live.bbb.selectPlan.label": "Sélectionnez un forfait",
"authoring.pagesAndResources.live.enableLive.heading": "Configurer en direct",
"authoring.pagesAndResources.live.enableLive.label": "En direct",
"authoring.pagesAndResources.live.enableLive.help": "Planifiez des réunions et organisez des sessions de cours en direct avec les apprenants.",
"authoring.pagesAndResources.live.enableLive.link": "En savoir plus sur le direct",
"authoring.live.selectProvider": "Sélectionnez un outil de visioconférence",
"authoring.live.formInstructions": "Complétez les champs ci-dessous pour paramétrer votre outil de visioconférence.",
"authoring.live.consumerKey": "La clé du consommateur",
"authoring.live.consumerKey.required": "La clé du consommateur est un champ obligatoire",
"authoring.live.consumerSecret": "Secret du consommateur",
"authoring.live.consumerSecret.required": "Le secret du consommateur est un champ obligatoire",
"authoring.live.launchUrl": "URL de lancement",
"authoring.live.launchUrl.required": "L'URL de lancement est un champ obligatoire",
"authoring.live.launchEmail": "Lancer l&#39;e-mail",
"authoring.live.launchEmail.required": "L&#39;e-mail de lancement est un champ obligatoire",
"authoring.live.provider.helpText": "Cette configuration nécessitera le partage du nom d'utilisateur et des courriels des apprenants et de l'équipe du cours avec {providerName}.",
"authoring.live.requestPiiSharingEnable": "Cette configuration nécessitera le partage des noms d'utilisateur et des courriels des apprenants et de l'équipe du cours avec {provider}. Pour accéder à la configuration LTI pour {provider}, veuillez demander à votre coordinateur de projet edX d'activer le partage des PII pour ce cours.",
"authoring.live.appDocInstructions.documentationLink": "Documentation générale",
"authoring.live.appDocInstructions.accessibilityDocumentationLink": "Documentation daccessibilité",
"authoring.live.appDocInstructions.configurationLink": "Documentation de configuration",
"authoring.live.appDocInstructions.learnMoreLink": "Apprenez-en plus sur {providerName}",
"authoring.live.appDocInstructions.linkTextHeading": "Aide externe et documentation",
"authoring.live.appDocInstructions.linkText": "{link}",
"authoring.live.appName-yellowdig": "Zoom",
"authoring.live.appName-googleMeet": "Google Meet",
"authoring.live.appName-microsoftTeams": "Équipes Microsoft",
"authoring.live.appName-bigBlueButton": "BigBlueButton",
"authoring.live.requestPiiSharingEnableForBbb": "Cette configuration nécessitera le partage des noms d'utilisateur des apprenants et de l'équipe du cours avec {provider}.",
"authoring.live.piiSharingEnableHelpText": "Pour activer cette fonctionnalité, contactez votre équipe d'assistance edX afin d'activer le partage des PII pour ce cours.",
"authoring.live.freePlanMessage": "Le forfait gratuit est préconfiguré et aucune configuration supplémentaire n'est requise. En sélectionnant le forfait gratuit, vous acceptez Blindside Networks",
"authoring.live.privacyPolicy": "Politique de confidentialité.",
"course-authoring.pages-resources.heading": "Pages et ressources",
"course-authoring.pages-resources.resources.settings.button": "paramètres",
"course-authoring.pages-resources.viewLive.button": "Aperçu temps réel",
"course-authoring.badge.enabled": "Activé",
"authoring.proctoring.no": "Non",
"authoring.proctoring.yes": "Oui",
"authoring.proctoring.support.text": "Page de support",
"authoring.proctoring.enableproctoredexams.label": "Examens surveillés",
"authoring.proctoring.enableproctoredexams.help": "Activez et configurez les examens surveillés dans votre cours.",
"authoring.proctoring.enabled": "Activé",
"authoring.proctoring.learn.more": "En savoir plus sur la surveillance",
"authoring.proctoring.provider.label": "Fournisseur de service de surveillance",
"authoring.proctoring.provider.help": "Sélectionnez le fournisseur de surveillance que vous souhaitez utiliser pour cette session de cours.",
"authoring.proctoring.provider.help.aftercoursestart": "Le fournisseur de surveillance ne peut pas être modifié après la date de début du cours.",
"authoring.proctoring.escalationemail.label": "Courriel d'escalade Proctortrack",
"authoring.proctoring.escalationemail.help": "Fournissez une adresse courriel à contacter par l'équipe de support pour les escalades (par exemple, appels, avis retardés).",
"authoring.proctoring.escalationemail.error.blank": "Le champ courriel Proctortrack Escalation ne peut pas être vide si Proctortrack est le fournisseur sélectionné.",
"authoring.proctoring.escalationemail.error.invalid": "Le champ du courriel d'escalade Proctortrack n'est pas au bon format et n'est pas valide.",
"authoring.proctoring.allowoptout.label": "Permettre aux apprenants de se retirer de la surveillance des examens surveillés",
"authoring.proctoring.createzendesk.label": "Créer les tickets Zendesk pour les tentatives suspectes",
"authoring.proctoring.error.single": "Il y a 1 erreur dans ce formulaire.",
"authoring.proctoring.escalationemail.error.multiple": "Il y a {numOfErrors} erreurs dans ce formulaire.",
"authoring.proctoring.save": "Sauvegarder",
"authoring.proctoring.saving": "Sauvegarde...",
"authoring.proctoring.cancel": "Annuler",
"authoring.proctoring.studio.link.text": "Retournez à votre cours dans Studio",
"authoring.proctoring.alert.success": "\n Les paramètres de l'examen surveillé ont bien été enregistrés. {studioCourseRunURL}.\n ",
"authoring.examsettings.alert.error": "\n Nous avons rencontré une erreur technique en tentant de sauvegarder les paramètres de l'examen surveillé.\n Ceci est probablement un problème temporaire, veuillez réessayer dans quelques minutes. \n Si le problème persiste,\n veuillez aller sur {support_link} pour de l'aide.\n ",
"course-authoring.pages-resources.progress.heading": "Configurer la progression",
"course-authoring.pages-resources.progress.enable-progress.label": "Progression",
"course-authoring.pages-resources.progress.enable-progress.help": "Au fur et à mesure que les élèves effectuent des devoirs notés, les notes\n apparaîtront sous l'onglet de progression. L'onglet de progression contient un graphique de\n tous les devoirs notés dans le cours, avec une liste de tous les devoirs et\n les notes ci-dessous.",
"course-authoring.pages-resources.progress.enable-progress.link": "Apprenez en plus sur la progression",
"course-authoring.pages-resources.progress.enable-graph.label": "Activer le graphique de progression",
"course-authoring.pages-resources.progress.enable-graph.help": "Si activé, les étudiants peuvent consulter le graphique de progression",
"authoring.pagesAndResources.teams.heading": "Configurer les équipes",
"authoring.pagesAndResources.teams.enableTeams.label": "Équipes",
"authoring.pagesAndResources.teams.enableTeams.help": "Permettre aux apprenant de travailler ensemble sur des projets ou activités spécifiques.",
"authoring.pagesAndResources.teams.enableTeams.link": "Apprenez en plus à propos des équipes",
"authoring.pagesAndResources.teams.teamSize.heading": "Taille de l'équipe",
"authoring.pagesAndResources.teams.teamSize.maxTeamSize": "Taille maximale de l'équipe",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeHelp": "Le nombre maximum d'apprenants qui peuvent rejoindre une équipe",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeEmpty": "Entrez la taille maximale de l'équipe",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeInvalid": "La taille maximale de l'équipe doit être un nombre positif supérieur à zéro.",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeTooHigh": "Taille maximale des équipes ne peut pas être plus que {max}",
"authoring.pagesAndResources.teams.groups.heading": "Groupes",
"authoring.pagesAndResources.teams.groups.help": "Les groupes sont des espaces où les apprenant peuvent rejoindre ou créer des équipes.",
"authoring.pagesAndResources.teams.configureGroup.heading": "Configurer un groupe",
"authoring.pagesAndResources.teams.group.name.label": "Nom",
"authoring.pagesAndResources.teams.group.name.help": "Choisissez un nom unique pour ce groupe",
"authoring.pagesAndResources.teams.group.name.error.empty": "Entrer un nom unique pour ce groupe",
"authoring.pagesAndResources.teams.group.name.error.exists": "Il semble que ce nom soit déjà utilisé",
"authoring.pagesAndResources.teams.group.description.label": "Description",
"authoring.pagesAndResources.teams.group.description.help": "Entrez les détails de ce groupe",
"authoring.pagesAndResources.teams.group.description.error": "Entrer une description pour ce groupe",
"authoring.pagesAndResources.teams.group.type.label": "Type",
"authoring.pagesAndResources.teams.group.type.help": "Contrôlez qui peut voir, créer et rejoindre des équipes",
"authoring.pagesAndResources.teams.group.types.open": "Ouvert",
"authoring.pagesAndResources.teams.group.types.open.description": "Les apprenants peuvent créer, rejoindre, quitter et voir d'autres équipes.",
"authoring.pagesAndResources.teams.group.types.public_managed": "Géré par le public",
"authoring.pagesAndResources.teams.group.types.public_managed.description": "Seul le personnel du cours peut contrôler les équipes et les adhésions. Les apprenants peuvent voir les autres équipes.",
"authoring.pagesAndResources.teams.group.types.private_managed": "Gestion privée",
"authoring.pagesAndResources.teams.group.types.private_managed.description": "Seul le personnel du cours peut contrôler les équipes, les adhésions et voir les autres équipes.",
"authoring.pagesAndResources.teams.group.maxSize.label": "Taille maximale de l'équipe (optionelle)",
"authoring.pagesAndResources.teams.group.maxSize.help": "Outrepasser la taille maximale globale des équipes",
"authoring.pagesAndResources.teams.addGroup.button": "Ajouter un groupe",
"authoring.pagesAndResources.teams.group.delete": "Supprimer",
"authoring.pagesAndResources.teams.group.expand": "Développer l'éditeur de groupe",
"authoring.pagesAndResources.teams.group.collapse": "Fermer l'éditeur du groupe",
"authoring.pagesAndResources.teams.deleteGroup.initiateDelete": "Supprimer",
"authoring.pagesAndResources.teams.deleteGroup.cancel-delete.button": "Annuler",
"authoring.pagesAndResources.teams.deleteGroup.heading": "Supprimer ce groupe ?",
"authoring.pagesAndResources.teams.deleteGroup.body": "edX recommande de ne pas supprimer les groupes une fois que le cours a commencé.\nVos groupes ne seront plus visibles dans le LMS et les apprenants ne seront plus en mesure de quitter les équipes associées aux groupes supprimés.\nVeuillez retirer les apprenants des équipes avant de supprimer le groupe associé.",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.title": "Aucun groupe trouvé",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.message": "Ajouter un ou plusieurs groupes pour permettre les équipes.",
"course-authoring.pages-resources.wiki.heading": "Configurer le wiki",
"course-authoring.pages-resources.wiki.enable-wiki.label": "Wiki",
"course-authoring.pages-resources.wiki.enable-wiki.help": "Le wiki du cours peut être configuré en fonction des besoins de votre\ncours. Les utilisations courantes peuvent inclure le partage de réponses aux FAQ du cours, le partage\n d'informations de cours modifiables ou donner accès à des informations créées par\n les apprenants.",
"course-authoring.pages-resources.wiki.enable-wiki.link": "Apprenez en plus sur le wiki",
"course-authoring.pages-resources.wiki.enable-public-wiki.label": "Activer l'accès public au wiki",
"course-authoring.pages-resources.wiki.enable-public-wiki.help": "Si activé, les utilisateurs edX peuvent afficher le wiki du cours même lorsqu'ils\n ne sont pas inscrits au cours.",
"authoring.examsettings.enableproctoredexams.help": "Si coché, les examens surveillés seront permis dans votre cours.",
"authoring.examsettings.allowoptout.label": "Autoriser l'exclusion des examens surveillés",
"authoring.examsettings.allowoptout.help": "\n Si cette valeur est «Oui», les apprenants peuvent choisir de passer des examens surveillés sans surveillance.\n Si cette valeur est \"Non\", tous les apprenants doivent passer l'examen avec surveillance.\n ",
"authoring.examsettings.provider.label": "Fournisseur de service de surveillance",
"authoring.examsettings.escalationemail.label": "Courriel d'escalade Proctortrack",
"authoring.examsettings.escalationemail.help": "\n Requis si «proctortrack» est choisi comme votre fournisseur de surveillance. Entrez une adresse de courriel à\n contacter par l'équipe de support lorsqu'il y a des escalades (ex. appels, revues en retard, etc.).\n ",
"authoring.examsettings.createzendesk.label": "Créer des billets ZenDesk pour les tentatives d'examen surveillé suspectes",
"authoring.examsettings.createzendesk.help": "Si cette valeur est «Oui», un billet ZenDesk sera créé pour les tentatives d'examen surveillé suspectes.",
"authoring.examsettings.submit": "Soumettre",
"authoring.examsettings.alert.success": "\n Paramètres d'examen sauvegardés avec succès.\n Vous pouvez retourner dans le Studio du cours {studioCourseRunURL}.\n ",
"authoring.examsettings.allowoptout.no": "Non",
"authoring.examsettings.allowoptout.yes": "Oui",
"authoring.examsettings.createzendesk.no": "Non",
"authoring.examsettings.createzendesk.yes": "Oui",
"authoring.examsettings.support.text": "Page de support",
"authoring.examsettings.escalationemail.enableproctoredexams.label": "Activer les examens surveillés",
"authoring.examsettings.escalationemail.error.blank": "Le champ courriel Proctortrack Escalation ne peut pas être vide si Proctortrack est le fournisseur sélectionné.",
"authoring.examsettings.escalationemail.error.invalid": "Le champ du courriel d'escalade Proctortrack n'est pas au bon format et n'est pas valide.",
"authoring.examsettings.error.single": "Il y a 1 erreur dans ce formulaire.",
"authoring.examsettings.escalationemail.error.multiple": "Il y a {numOfErrors} erreurs dans ce formulaire.",
"authoring.examsettings.provider.help": "Sélectionnez le fournisseur d'examen surveillé que vous souhaitez utiliser pour cette session de cours.",
"authoring.examsettings.provider.help.aftercoursestart": "Le fournisseur de surveillance ne peut pas être modifié après la date de début du cours.",
"header.links.content": "Contenu",
"header.links.settings": "Paramètres",
"header.links.content.tools": "Outils",
"header.links.outline": "Plan du Cours",
"header.links.updates": "Annonces",
"header.links.pages": "Pages et ressources",
"header.links.filesAndUploads": "Fichiers & téléversements",
"header.links.textbooks": "Manuels",
"header.links.videoUploads": "Téléversements des vidéos",
"header.links.scheduleAndDetails": "Dates & Détails",
"header.links.grading": "Évaluation",
"header.links.courseTeam": "Équipe pédagogique",
"header.links.groupConfigurations": "Configuration des groupes",
"header.links.proctoredExamSettings": "Paramètres d'examen surveillé",
"header.links.advancedSettings": "Paramètres avancés",
"header.links.certificates": "Attestations",
"header.links.publisher": "Éditeur",
"header.links.import": "Importer",
"header.links.export": "Exporter",
"header.links.checklists": "Listes de contrôle",
"header.user.menu.studio": "Accueil Studio",
"header.user.menu.maintenance": "Entretien",
"header.user.menu.logout": "Déconnexion",
"header.label.account.menu": "Menu de compte",
"header.label.account.menu.for": "Menu de compte pour {username}",
"header.label.main.nav": "Principal",
"header.label.main.menu": "Menu principal",
"header.label.main.header": "Principal",
"header.label.secondary.nav": "Secondaire",
"header.label.courseOutline": "Retour au plan de cours dans Studio"
}

View File

@@ -1 +0,0 @@
{}

352
src/i18n/messages/hi.json Normal file
View File

@@ -0,0 +1,352 @@
{
"authoring.alert.error.connection": "We encountered a technical error when loading this page. This might be a temporary issue, so please try again in a few minutes. If the problem persists, please go to the {supportLink} for help.",
"authoring.loading": "Loading...",
"authoring.alert.error.permission": "You are not authorized to view this page. If you feel you should have access, please reach out to your course team admin to be given access.",
"authoring.alert.save.error.connection": "We encountered a technical error when applying changes. This might be a temporary issue, so please try again in a few minutes. If the problem persists, please go to the {supportLink} for help.",
"authoring.alert.support.text": "Support Page",
"course-authoring.pages-resources.app-settings-modal.button.cancel": "Cancel",
"course-authoring.pages-resources.app-settings-modal.button.save": "Save",
"course-authoring.pages-resources.app-settings-modal.button.saving": "Saving",
"course-authoring.pages-resources.app-settings-modal.button.saved": "Saved",
"course-authoring.pages-resources.app-settings-modal.button.retry": "Retry",
"course-authoring.pages-resources.app-settings-modal.badge.enabled": "Enabled",
"course-authoring.pages-resources.app-settings-modal.badge.disabled": "Disabled",
"course-authoring.pages-resources.app-settings-modal.save-error.title": "We couldn't apply your changes.",
"course-authoring.pages-resources.app-settings-modal.save-error.message": "Please check your entries and try again.",
"course-authoring.pages-resources.calculator.heading": "Configure calculator",
"course-authoring.pages-resources.calculator.enable-calculator.label": "Calculator",
"course-authoring.pages-resources.calculator.enable-calculator.help": "The calculator supports numbers, operators, constants,\n functions, and other mathematical concepts. When enabled, an icon to\n access the calculator appears on all pages in the body of your course.",
"course-authoring.pages-resources.calculator.enable-calculator.link": "Learn more about the calculator",
"authoring.discussions.documentationPage": "Visit the {name} documentation page",
"authoring.discussions.formInstructions": "Complete the fields below to set up your discussion tool.",
"authoring.discussions.consumerKey": "Consumer Key",
"authoring.discussions.consumerKey.required": "Consumer key is a required field",
"authoring.discussions.consumerSecret": "Consumer Secret",
"authoring.discussions.consumerSecret.required": "Consumer secret is a required field",
"authoring.discussions.launchUrl": "Launch URL",
"authoring.discussions.launchUrl.required": "Launch URL is a required field",
"authoring.discussions.stuffOnlyConfigInfo": "To enable {providerName} for your course, please contact their support team at {supportEmail} to learn more about pricing and usage.",
"authoring.discussions.stuffOnlyConfigGuide": "To fully configure {providerName} will also require sharing usernames and emails for learners and course team. Please contact your edX project coordinator to enable PII sharing for this course.",
"authoring.discussions.piiSharing": "Optionally share a user's username and/or email with the LTI provider:",
"authoring.discussions.piiShareUsername": "Share username",
"authoring.discussions.piiShareEmail": "Share email",
"authoring.discussions.appDocInstructions.contact": "Contact: {link}",
"authoring.discussions.appDocInstructions.documentationLink": "General documentation",
"authoring.discussions.appDocInstructions.accessibilityDocumentationLink": "Accessibility documentation",
"authoring.discussions.appDocInstructions.configurationLink": "Configuration documentation",
"authoring.discussions.appDocInstructions.learnMoreLink": "Learn more about {providerName}",
"authoring.discussions.appDocInstructions.linkTextHeading": "External help and documentation",
"authoring.discussions.appDocInstructions.linkText": "{link}",
"authoring.discussions.configurationChangeConsequences": "Students will lose access to any active or previous discussion posts for your course.",
"authoring.discussions.configure.app": "Configure {name}",
"authoring.discussions.configure": "Configure discussions",
"authoring.discussions.ok": "OK",
"authoring.discussions.cancel": "Cancel",
"authoring.discussions.confirm": "Confirm",
"authoring.discussions.confirmConfigurationChange": "Are you sure you want to change the discussion settings?",
"authoring.discussions.confirmEnableDiscussionsLabel": "Enable discussions on units in graded subsections?",
"authoring.discussions.cancelEnableDiscussionsLabel": "Disable discussions on units in graded subsections?",
"authoring.discussions.confirmEnableDiscussions": "Enabling this toggle will automatically enable discussion on all units in graded subsections, that are not timed exams.",
"authoring.discussions.cancelEnableDiscussions": "Disabling this toggle will automatically disable discussion on all units in graded subsections. Discussion topics containing at least 1 thread will be listed and accessible under “Archived” in Topics tab on the Discussions page.",
"authoring.discussions.backButton": "Back",
"authoring.discussions.saveButton": "Save",
"authoring.discussions.savingButton": "Saving",
"authoring.discussions.savedButton": "Saved",
"authoring.discussions.appConfigForm.appName-piazza": "Piazza",
"authoring.discussions.appConfigForm.appName-yellowdig": "Yellowdig",
"authoring.discussions.appConfigForm.appName-inscribe": "InScribe",
"authoring.discussions.appConfigForm.appName-discourse": "Discourse",
"authoring.discussions.appConfigForm.appName-ed-discuss": "Ed Discussion",
"authoring.discussions.appConfigForm.appName-legacy": "edX",
"authoring.discussions.appConfigForm.appName-openedx": "edX",
"authoring.discussions.builtIn.divisionByGroup": "Cohorts",
"authoring.discussions.builtIn.divideByCohorts.label": "Divide discussions by cohorts",
"authoring.discussions.builtIn.divideByCohorts.help": "Learners will only be able to view and respond to discussions posted by members of their cohort.",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.label": "Divide course-wide discussion topics",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.help": "Choose which of your general course-wide discussion topics you would like to divide.",
"authoring.discussions.builtIn.divideGeneralTopic.label": "General",
"authoring.discussions.builtIn.divideQuestionsForTAsTopic.label": "Questions for the TAs",
"authoring.discussions.builtIn.cohortsEnabled.label": "To adjust these settings, enable cohorts on the ",
"authoring.discussions.builtIn.instructorDashboard.label": "instructor dashboard",
"authoring.discussions.builtIn.visibilityInContext": "Visibility of in-context discussions",
"authoring.discussions.builtIn.gradedUnitPages.label": "Enable discussions on units in graded subsections",
"authoring.discussions.builtIn.gradedUnitPages.help": "Allow learners to engage with discussion on all graded unit pages except timed exams.",
"authoring.discussions.builtIn.groupInContextSubsection.label": "Group in context discussion at the subsection level",
"authoring.discussions.builtIn.groupInContextSubsection.help": "Learners will be able to view any post in the sub-section no matter which unit page they are viewing. While this is not recommended, if your course has short learning sequences or low enrollment grouping may increase engagement.",
"authoring.discussions.builtIn.anonymousPosting": "Anonymous posting",
"authoring.discussions.builtIn.allowAnonymous.label": "Allow anonymous discussion posts",
"authoring.discussions.builtIn.allowAnonymous.help": "If enabled, learners can create posts that are anonymous to all users.",
"authoring.discussions.builtIn.allowAnonymousPeers.label": "Allow anonymous discussion posts to peers",
"authoring.discussions.builtIn.allowAnonymousPeers.help": "Learners will be able to post anonymously to other peers but all posts will be visible to course staff.",
"authoring.discussions.builtIn.reportedContentEmailNotifications": "Notifications",
"authoring.discussions.builtIn.reportedContentEmailNotifications.label": "Email notifications for reported content",
"authoring.discussions.builtIn.reportedContentEmailNotifications.help": "Discussion Admins, Moderators, Community TAs and Group Community TAs (only for their own cohort) will receive an email notification when content is reported.",
"authoring.discussions.discussionTopics": "Discussion topics",
"authoring.discussions.discussionTopics.label": "General discussion topics",
"authoring.discussions.discussionTopics.help": "Discussions can include general topics not contained to the course structure. All courses have a general topic by default.",
"authoring.discussions.discussionTopic.required": "Topic name is a required field",
"authoring.discussions.discussionTopic.alreadyExistError": "It looks like this name is already in use",
"authoring.discussions.addTopicButton": "Add topic",
"authoring.discussions.deleteButton": "Delete",
"authoring.discussions.cancelButton": "Cancel",
"authoring.discussions.discussionTopicDeletion.help": "edX recommends that you do not delete discussion topics once your course is running.",
"authoring.discussions.discussionTopicDeletion.label": "Delete this topic?",
"authoring.discussions.builtIn.renameGeneralTopic.label": "Rename general topic",
"authoring.discussions.generalTopicHelp.help": "This is the default discussion topic for your course.",
"authoring.discussions.builtIn.configureAdditionalTopic.label": "Configure topic",
"authoring.discussions.addTopicHelpText": "Choose a unique name for your topic",
"authoring.discussions.blackoutDates": "Discussion blackout dates",
"authoring.discussions.builtIn.blackoutDates.label": "Blackout dates",
"authoring.discussions.builtIn.blackoutDates.help": "If added, learners will not be able to post in discussions between these dates.",
"authoring.discussions.addBlackoutDatesButton": "Add blackout date range",
"authoring.discussions.builtIn.configureBlackoutDates.label": "Configure blackout date range",
"authoring.discussions.blackoutStartDate.help": "Enter a start date, e.g. 12/10/2023",
"authoring.discussions.blackoutEndDate.help": "Enter an end date, e.g. 12/17/2023",
"authoring.discussions.blackoutStartTime.help": "Enter a start time, e.g. 09:00 AM",
"authoring.discussions.blackoutEndTime.help": "Enter an end time, e.g. 05:00 PM",
"authoring.discussions.activeBlackoutDatesDeletion.help": "These blackout dates are currently active. If deleted, learners will be able to post in discussions during these dates. Are you sure you want to proceed?",
"authoring.discussions.blackoutDatesDeletion.help": "If deleted, learners will be able to post in discussions during these dates.",
"authoring.discussions.completeBlackoutDatesDeletion.help": "Are you sure you want to delete these blackout dates?",
"authoring.discussions.activeBlackoutDatesDeletion.label": "Delete active blackout dates?",
"authoring.discussions.blackoutDatesDeletion.label": "Delete blackout dates?",
"authoring.blackoutDates.delete": "Delete Blackout Dates",
"authoring.blackoutDates.status": "{status}",
"authoring.blackoutDates.startDate.required": "Start date is a required field",
"authoring.blackoutDates.endDate.required": "End date is a required field",
"authoring.blackoutDates.startDate.inPast": "Start date cannot be after end date",
"authoring.blackoutDates.endDate.inPast": "End date cannot be before start date",
"authoring.blackoutDates.startTime.inPast": "Start time cannot be after end time",
"authoring.blackoutDates.endTime.inPast": "End time cannot be before start time",
"authoring.blackoutDates.startTime.inValidFormat": "Enter a valid start time",
"authoring.blackoutDates.endTime.inValidFormat": "Enter a valid end time",
"authoring.blackoutDates.startDate.inValidFormat": "Enter a valid start Date",
"authoring.blackoutDates.endDate.inValidFormat": "Enter a valid end date",
"authoring.topics.delete": "Delete Topic",
"authoring.topics.expand": "Expand",
"authoring.topics.collapse": "Collapse",
"authoring.blackoutDates.start.date": "Start date",
"authoring.blackoutDates.start.time": "Start time (optional) ({zone})",
"authoring.blackoutDates.end.date": "End date",
"authoring.blackoutDates.end.time": "End time (optional) ({zone})",
"authoring.discussions.heading": "Select a discussion tool for this course",
"authoring.discussions.supportedFeatures": "Supported features",
"authoring.discussions.supportedFeatureList-mobile-show": "Show supported features",
"authoring.discussions.supportedFeatureList-mobile-hide": "Hide supported features",
"authoring.discussions.noApps": "There are no discussions providers available for your course.",
"authoring.discussions.nextButton": "Next",
"authoring.discussions.appFullSupport": "Full support",
"authoring.discussions.appBasicSupport": "Basic support",
"authoring.discussions.selectApp": "Select {appName}",
"authoring.discussions.appList.appName-legacy": "edX",
"authoring.discussions.appList.appDescription-legacy": "Start conversations with other learners, ask questions, and interact with other learners in the course.",
"authoring.discussions.appList.appName-openedx": "edX",
"authoring.discussions.appList.appDescription-openedx": "Start conversations with other learners, ask questions, and interact with other learners in the course.",
"authoring.discussions.appList.appName-piazza": "Piazza",
"authoring.discussions.appList.appDescription-piazza": "Piazza is designed to connect students, TAs, and professors so every student can get the help they need when they need it.",
"authoring.discussions.appList.appDescription-yellowdig": "Yellowdig offers educators a gameful learning digital solution to improve student engagement by building learning communities for any course modality.",
"authoring.discussions.appList.appDescription-inscribe": "InScribe leverages the power of community + artificial intelligence to connect individuals to the answers, resources, and people they need to succeed.",
"authoring.discussions.appList.appDescription-discourse": "Discourse is modern forum software for your community. Use it as a mailing list, discussion forum, long-form chat room, and more!",
"authoring.discussions.appList.appDescription-ed-discus": "Ed Discussion helps scale class communication in a beautiful and intuitive interface. Questions reach and benefit the whole class. Less emails, more time saved.",
"authoring.discussions.featureName-discussion-page": "Discussion page",
"authoring.discussions.featureName-embedded-course-sections": "Embedded course sections",
"authoring.discussions.featureName-advanced-in-context-discussion": "Advanced in context discussion",
"authoring.discussions.featureName-anonymous-posting": "Anonymous posting",
"authoring.discussions.featureName-automatic-learner-enrollment": "Automatic learner enrollment",
"authoring.discussions.featureName-blackout-discussion-dates": "Blackout discussion dates",
"authoring.discussions.featureName-community-ta-support": "Community TA support",
"authoring.discussions.featureName-course-cohort-support": "Course cohort support",
"authoring.discussions.featureName-direct-messages-from-instructors": "Direct messages from instructors",
"authoring.discussions.featureName-discussion-content-prompts": "Discussion content prompts",
"authoring.discussions.featureName-email-notifications": "Email notifications",
"authoring.discussions.featureName-graded-discussions": "Graded discussions",
"authoring.discussions.featureName-in-platform-notifications": "In-platform notifications",
"authoring.discussions.featureName-internationalization-support": "Internationalization support",
"authoring.discussions.featureName-lti-advanced-sharing-mode": "LTI advanced sharing",
"authoring.discussions.featureName-basic-configuration": "Basic configuration",
"authoring.discussions.featureName-primary-discussion-app-experience": "Primary discussion app experience",
"authoring.discussions.featureName-question-&-discussion-support": "Question & discussion support",
"authoring.discussions.featureName-report/flag-content-to-moderators": "Report content to moderators",
"authoring.discussions.featureName-research-data-events": "Research data events",
"authoring.discussions.featureName-simplified-in-context-discussion": "Simplified in-context discussion",
"authoring.discussions.featureName-user-mentions": "User mentions",
"authoring.discussions.featureName-wcag-2.1": "WCAG 2.1 support",
"authoring.discussions.wcag-2.0-support": "WCAG 2.0 support",
"authoring.discussions.basic-support": "Basic support",
"authoring.discussions.partial-support": "Partial support",
"authoring.discussions.full-support": "Full support",
"authoring.discussions.common-support": "Commonly requested",
"authoring.discussions.settings": "Settings",
"authoring.discussions.applyButton": "Apply",
"authoring.discussions.applyingButton": "Applying",
"authoring.discussions.appliedButton": "Applied",
"authoring.discussions.noProviderSwitchAfterCourseStarted": "Discussion provider can't be changed after course has started, please reach out to partner support.",
"authoring.discussions.providerSelection": "Provider selection",
"authoring.discussions.Incomplete": "Incomplete",
"course-authoring.pages-resources.notes.heading": "Configure notes",
"course-authoring.pages-resources.notes.enable-notes.label": "Notes",
"course-authoring.pages-resources.notes.enable-notes.help": "Learners can access their notes either in the body of the\n course of on a notes page. On the notes page, a learner can see all the\n notes made during the course. The page also contains links to the location\n of the notes in the course body.",
"course-authoring.pages-resources.notes.enable-notes.link": "Learn more about notes",
"authoring.live.bbb.selectPlan.label": "Select a plan",
"authoring.pagesAndResources.live.enableLive.heading": "Configure Live",
"authoring.pagesAndResources.live.enableLive.label": "Live",
"authoring.pagesAndResources.live.enableLive.help": "Schedule meetings and conduct live course sessions with learners.",
"authoring.pagesAndResources.live.enableLive.link": "Learn more about live",
"authoring.live.selectProvider": "Select a video conferencing tool",
"authoring.live.formInstructions": "Complete the fields below to set up your video conferencing tool.",
"authoring.live.consumerKey": "Consumer Key",
"authoring.live.consumerKey.required": "Consumer key is a required field",
"authoring.live.consumerSecret": "Consumer Secret",
"authoring.live.consumerSecret.required": "Consumer secret is a required field",
"authoring.live.launchUrl": "Launch URL",
"authoring.live.launchUrl.required": "Launch URL is a required field",
"authoring.live.launchEmail": "Launch Email",
"authoring.live.launchEmail.required": "Launch Email is a required field",
"authoring.live.provider.helpText": "This configuration will require sharing username and emails of learners and the course team with {providerName}.",
"authoring.live.requestPiiSharingEnable": "This configuration will require sharing usernames and emails of learners and the course team with {provider}. To access the LTI configuration for {provider}, please request your edX project coordinator to get PII sharing enabled for this course.",
"authoring.live.appDocInstructions.documentationLink": "General documentation",
"authoring.live.appDocInstructions.accessibilityDocumentationLink": "Accessibility documentation",
"authoring.live.appDocInstructions.configurationLink": "Configuration documentation",
"authoring.live.appDocInstructions.learnMoreLink": "Learn more about {providerName}",
"authoring.live.appDocInstructions.linkTextHeading": "External help and documentation",
"authoring.live.appDocInstructions.linkText": "{link}",
"authoring.live.appName-yellowdig": "Zoom",
"authoring.live.appName-googleMeet": "Google Meet",
"authoring.live.appName-microsoftTeams": "Microsoft Teams",
"authoring.live.appName-bigBlueButton": "BigBlueButton",
"authoring.live.requestPiiSharingEnableForBbb": "This configuration will require sharing usernames of learners and the course team with {provider}.",
"authoring.live.piiSharingEnableHelpText": "To enable this feature, contact your edX support team to enable PII sharing for this course.",
"authoring.live.freePlanMessage": "The free plan is pre-configured, and no additional configurations are required. By selecting the free plan, you are agreeing to Blindside Networks",
"authoring.live.privacyPolicy": "Privacy Policy.",
"course-authoring.pages-resources.heading": "Pages & Resources",
"course-authoring.pages-resources.resources.settings.button": "settings",
"course-authoring.pages-resources.viewLive.button": "View live",
"course-authoring.badge.enabled": "Enabled",
"authoring.proctoring.no": "No",
"authoring.proctoring.yes": "Yes",
"authoring.proctoring.support.text": "Support Page",
"authoring.proctoring.enableproctoredexams.label": "Proctored exams",
"authoring.proctoring.enableproctoredexams.help": "Enable and configure proctored exams in your course.",
"authoring.proctoring.enabled": "Enabled",
"authoring.proctoring.learn.more": "Learn more about proctoring",
"authoring.proctoring.provider.label": "Proctoring provider",
"authoring.proctoring.provider.help": "Select the proctoring provider you want to use for this course run.",
"authoring.proctoring.provider.help.aftercoursestart": "Proctoring provider cannot be modified after course start date.",
"authoring.proctoring.escalationemail.label": "Proctortrack escalation email",
"authoring.proctoring.escalationemail.help": "Provide an email address to be contacted by the support team for escalations (e.g. appeals, delayed reviews).",
"authoring.proctoring.escalationemail.error.blank": "The Proctortrack Escalation Email field cannot be empty if proctortrack is the selected provider.",
"authoring.proctoring.escalationemail.error.invalid": "The Proctortrack Escalation Email field is in the wrong format and is not valid.",
"authoring.proctoring.allowoptout.label": "Allow learners to opt out of proctoring on proctored exams",
"authoring.proctoring.createzendesk.label": "Create Zendesk tickets for suspicious attempts",
"authoring.proctoring.error.single": "There is 1 error in this form.",
"authoring.proctoring.escalationemail.error.multiple": "There are {numOfErrors} errors in this form.",
"authoring.proctoring.save": "Save",
"authoring.proctoring.saving": "Saving...",
"authoring.proctoring.cancel": "Cancel",
"authoring.proctoring.studio.link.text": "Go back to your course in Studio",
"authoring.proctoring.alert.success": "\n Proctored exam settings saved successfully. {studioCourseRunURL}.\n ",
"authoring.examsettings.alert.error": "\n We encountered a technical error while trying to save proctored exam settings.\n This might be a temporary issue, so please try again in a few minutes.\n If the problem persists,\n please go to the {support_link} for help.\n ",
"course-authoring.pages-resources.progress.heading": "Configure progress",
"course-authoring.pages-resources.progress.enable-progress.label": "Progress",
"course-authoring.pages-resources.progress.enable-progress.help": "As students work through graded assignments, scores\n will appear under the progress tab. The progress tab contains a chart of\n all graded assignments in the course, with a list of all assignments and\n scores below.",
"course-authoring.pages-resources.progress.enable-progress.link": "Learn more about progress",
"course-authoring.pages-resources.progress.enable-graph.label": "Enable progress graph",
"course-authoring.pages-resources.progress.enable-graph.help": "If enabled, students can view the progress graph",
"authoring.pagesAndResources.teams.heading": "Configure teams",
"authoring.pagesAndResources.teams.enableTeams.label": "Teams",
"authoring.pagesAndResources.teams.enableTeams.help": "Allow learners to work together on specific projects or activities.",
"authoring.pagesAndResources.teams.enableTeams.link": "Learn more about teams",
"authoring.pagesAndResources.teams.teamSize.heading": "Team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSize": "Max team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeHelp": "The maximum number of learners that can join a team",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeEmpty": "Enter max team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeInvalid": "Max team size must be a positive number larger than zero.",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeTooHigh": "Max team size cannot be greater than {max}",
"authoring.pagesAndResources.teams.groups.heading": "Groups",
"authoring.pagesAndResources.teams.groups.help": "Groups are spaces where learners can create or join teams.",
"authoring.pagesAndResources.teams.configureGroup.heading": "Configure group",
"authoring.pagesAndResources.teams.group.name.label": "Name",
"authoring.pagesAndResources.teams.group.name.help": "Choose a unique name for this group",
"authoring.pagesAndResources.teams.group.name.error.empty": "Enter a unique name for this group",
"authoring.pagesAndResources.teams.group.name.error.exists": "It looks like this name is already in use",
"authoring.pagesAndResources.teams.group.description.label": "Description",
"authoring.pagesAndResources.teams.group.description.help": "Enter details about this group",
"authoring.pagesAndResources.teams.group.description.error": "Enter a description for this group",
"authoring.pagesAndResources.teams.group.type.label": "Type",
"authoring.pagesAndResources.teams.group.type.help": "Control who can see, create and join teams",
"authoring.pagesAndResources.teams.group.types.open": "Open",
"authoring.pagesAndResources.teams.group.types.open.description": "Learners can create, join, leave, and see other teams",
"authoring.pagesAndResources.teams.group.types.public_managed": "Public managed",
"authoring.pagesAndResources.teams.group.types.public_managed.description": "Only course staff can control teams and memberships. Learners can see other teams.",
"authoring.pagesAndResources.teams.group.types.private_managed": "Private managed",
"authoring.pagesAndResources.teams.group.types.private_managed.description": "Only course staff can control teams, memberships, and see other teams",
"authoring.pagesAndResources.teams.group.maxSize.label": "Max team size (optional)",
"authoring.pagesAndResources.teams.group.maxSize.help": "Override the global max team size",
"authoring.pagesAndResources.teams.addGroup.button": "Add group",
"authoring.pagesAndResources.teams.group.delete": "Delete",
"authoring.pagesAndResources.teams.group.expand": "Expand group editor",
"authoring.pagesAndResources.teams.group.collapse": "Close group editor",
"authoring.pagesAndResources.teams.deleteGroup.initiateDelete": "Delete",
"authoring.pagesAndResources.teams.deleteGroup.cancel-delete.button": "Cancel",
"authoring.pagesAndResources.teams.deleteGroup.heading": "Delete this group?",
"authoring.pagesAndResources.teams.deleteGroup.body": "edX recommends that you do not delete groups once your course is running.\n Your group will no longer be visible in the LMS and learners will not be able to leave teams associated with it.\n Please delete learners from teams before deleting the associated group.",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.title": "No groups found",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.message": "Add one or more groups to enable teams.",
"course-authoring.pages-resources.wiki.heading": "Configure wiki",
"course-authoring.pages-resources.wiki.enable-wiki.label": "Wiki",
"course-authoring.pages-resources.wiki.enable-wiki.help": "The course wiki can be set up based on the needs of your\n course. Common uses might include sharing answers to course FAQs, sharing\n editable course information, or providing access to learner-created\n resources.",
"course-authoring.pages-resources.wiki.enable-wiki.link": "Learn more about the wiki",
"course-authoring.pages-resources.wiki.enable-public-wiki.label": "Enable public wiki access",
"course-authoring.pages-resources.wiki.enable-public-wiki.help": "If enabled, edX users can view the course wiki even when\n they're not enrolled in the course.",
"authoring.examsettings.enableproctoredexams.help": "If checked, proctored exams are enabled in your course.",
"authoring.examsettings.allowoptout.label": "Allow Opting Out of Proctored Exams",
"authoring.examsettings.allowoptout.help": "\n If this value is \"Yes\", learners can choose to take proctored exams without proctoring.\n If this value is \"No\", all learners must take the exam with proctoring.\n ",
"authoring.examsettings.provider.label": "Proctoring Provider",
"authoring.examsettings.escalationemail.label": "Proctortrack Escalation Email",
"authoring.examsettings.escalationemail.help": "\n Required if \"proctortrack\" is selected as your proctoring provider. Enter an email address to be\n contacted by the support team whenever there are escalations (e.g. appeals, delayed reviews, etc.).\n ",
"authoring.examsettings.createzendesk.label": "Create Zendesk Tickets for Suspicious Proctored Exam Attempts",
"authoring.examsettings.createzendesk.help": "If this value is \"Yes\", a Zendesk ticket will be created for suspicious proctored exam attempts.",
"authoring.examsettings.submit": "Submit",
"authoring.examsettings.alert.success": "\n Proctored exam settings saved successfully.\n You can go back to your course in Studio {studioCourseRunURL}.\n ",
"authoring.examsettings.allowoptout.no": "No",
"authoring.examsettings.allowoptout.yes": "Yes",
"authoring.examsettings.createzendesk.no": "No",
"authoring.examsettings.createzendesk.yes": "Yes",
"authoring.examsettings.support.text": "Support Page",
"authoring.examsettings.escalationemail.enableproctoredexams.label": "Enable Proctored Exams",
"authoring.examsettings.escalationemail.error.blank": "The Proctortrack Escalation Email field cannot be empty if proctortrack is the selected provider.",
"authoring.examsettings.escalationemail.error.invalid": "The Proctortrack Escalation Email field is in the wrong format and is not valid.",
"authoring.examsettings.error.single": "There is 1 error in this form.",
"authoring.examsettings.escalationemail.error.multiple": "There are {numOfErrors} errors in this form.",
"authoring.examsettings.provider.help": "Select the proctoring provider you want to use for this course run.",
"authoring.examsettings.provider.help.aftercoursestart": "Proctoring provider cannot be modified after course start date.",
"header.links.content": "Content",
"header.links.settings": "Settings",
"header.links.content.tools": "Tools",
"header.links.outline": "Outline",
"header.links.updates": "Updates",
"header.links.pages": "Pages & Resources",
"header.links.filesAndUploads": "Files & Uploads",
"header.links.textbooks": "Textbooks",
"header.links.videoUploads": "Video Uploads",
"header.links.scheduleAndDetails": "Schedule & Details",
"header.links.grading": "Grading",
"header.links.courseTeam": "Course Team",
"header.links.groupConfigurations": "Group Configurations",
"header.links.proctoredExamSettings": "Proctored Exam Settings",
"header.links.advancedSettings": "Advanced Settings",
"header.links.certificates": "Certificates",
"header.links.publisher": "Publisher",
"header.links.import": "Import",
"header.links.export": "Export",
"header.links.checklists": "Checklists",
"header.user.menu.studio": "Studio Home",
"header.user.menu.maintenance": "Maintenance",
"header.user.menu.logout": "Logout",
"header.label.account.menu": "Account Menu",
"header.label.account.menu.for": "Account menu for {username}",
"header.label.main.nav": "Main",
"header.label.main.menu": "Main Menu",
"header.label.main.header": "Main",
"header.label.secondary.nav": "Secondary",
"header.label.courseOutline": "Back to course outline in Studio"
}

View File

@@ -1 +0,0 @@
{}

352
src/i18n/messages/it.json Normal file
View File

@@ -0,0 +1,352 @@
{
"authoring.alert.error.connection": "We encountered a technical error when loading this page. This might be a temporary issue, so please try again in a few minutes. If the problem persists, please go to the {supportLink} for help.",
"authoring.loading": "Loading...",
"authoring.alert.error.permission": "You are not authorized to view this page. If you feel you should have access, please reach out to your course team admin to be given access.",
"authoring.alert.save.error.connection": "We encountered a technical error when applying changes. This might be a temporary issue, so please try again in a few minutes. If the problem persists, please go to the {supportLink} for help.",
"authoring.alert.support.text": "Support Page",
"course-authoring.pages-resources.app-settings-modal.button.cancel": "Cancel",
"course-authoring.pages-resources.app-settings-modal.button.save": "Save",
"course-authoring.pages-resources.app-settings-modal.button.saving": "Saving",
"course-authoring.pages-resources.app-settings-modal.button.saved": "Saved",
"course-authoring.pages-resources.app-settings-modal.button.retry": "Retry",
"course-authoring.pages-resources.app-settings-modal.badge.enabled": "Enabled",
"course-authoring.pages-resources.app-settings-modal.badge.disabled": "Disabled",
"course-authoring.pages-resources.app-settings-modal.save-error.title": "We couldn't apply your changes.",
"course-authoring.pages-resources.app-settings-modal.save-error.message": "Please check your entries and try again.",
"course-authoring.pages-resources.calculator.heading": "Configure calculator",
"course-authoring.pages-resources.calculator.enable-calculator.label": "Calculator",
"course-authoring.pages-resources.calculator.enable-calculator.help": "The calculator supports numbers, operators, constants,\n functions, and other mathematical concepts. When enabled, an icon to\n access the calculator appears on all pages in the body of your course.",
"course-authoring.pages-resources.calculator.enable-calculator.link": "Learn more about the calculator",
"authoring.discussions.documentationPage": "Visit the {name} documentation page",
"authoring.discussions.formInstructions": "Complete the fields below to set up your discussion tool.",
"authoring.discussions.consumerKey": "Consumer Key",
"authoring.discussions.consumerKey.required": "Consumer key is a required field",
"authoring.discussions.consumerSecret": "Consumer Secret",
"authoring.discussions.consumerSecret.required": "Consumer secret is a required field",
"authoring.discussions.launchUrl": "Launch URL",
"authoring.discussions.launchUrl.required": "Launch URL is a required field",
"authoring.discussions.stuffOnlyConfigInfo": "To enable {providerName} for your course, please contact their support team at {supportEmail} to learn more about pricing and usage.",
"authoring.discussions.stuffOnlyConfigGuide": "To fully configure {providerName} will also require sharing usernames and emails for learners and course team. Please contact your edX project coordinator to enable PII sharing for this course.",
"authoring.discussions.piiSharing": "Optionally share a user's username and/or email with the LTI provider:",
"authoring.discussions.piiShareUsername": "Share username",
"authoring.discussions.piiShareEmail": "Share email",
"authoring.discussions.appDocInstructions.contact": "Contact: {link}",
"authoring.discussions.appDocInstructions.documentationLink": "General documentation",
"authoring.discussions.appDocInstructions.accessibilityDocumentationLink": "Accessibility documentation",
"authoring.discussions.appDocInstructions.configurationLink": "Configuration documentation",
"authoring.discussions.appDocInstructions.learnMoreLink": "Learn more about {providerName}",
"authoring.discussions.appDocInstructions.linkTextHeading": "External help and documentation",
"authoring.discussions.appDocInstructions.linkText": "{link}",
"authoring.discussions.configurationChangeConsequences": "Students will lose access to any active or previous discussion posts for your course.",
"authoring.discussions.configure.app": "Configure {name}",
"authoring.discussions.configure": "Configure discussions",
"authoring.discussions.ok": "OK",
"authoring.discussions.cancel": "Cancel",
"authoring.discussions.confirm": "Confirm",
"authoring.discussions.confirmConfigurationChange": "Are you sure you want to change the discussion settings?",
"authoring.discussions.confirmEnableDiscussionsLabel": "Enable discussions on units in graded subsections?",
"authoring.discussions.cancelEnableDiscussionsLabel": "Disable discussions on units in graded subsections?",
"authoring.discussions.confirmEnableDiscussions": "Enabling this toggle will automatically enable discussion on all units in graded subsections, that are not timed exams.",
"authoring.discussions.cancelEnableDiscussions": "Disabling this toggle will automatically disable discussion on all units in graded subsections. Discussion topics containing at least 1 thread will be listed and accessible under “Archived” in Topics tab on the Discussions page.",
"authoring.discussions.backButton": "Back",
"authoring.discussions.saveButton": "Save",
"authoring.discussions.savingButton": "Saving",
"authoring.discussions.savedButton": "Saved",
"authoring.discussions.appConfigForm.appName-piazza": "Piazza",
"authoring.discussions.appConfigForm.appName-yellowdig": "Yellowdig",
"authoring.discussions.appConfigForm.appName-inscribe": "InScribe",
"authoring.discussions.appConfigForm.appName-discourse": "Discourse",
"authoring.discussions.appConfigForm.appName-ed-discuss": "Ed Discussion",
"authoring.discussions.appConfigForm.appName-legacy": "edX",
"authoring.discussions.appConfigForm.appName-openedx": "edX",
"authoring.discussions.builtIn.divisionByGroup": "Cohorts",
"authoring.discussions.builtIn.divideByCohorts.label": "Divide discussions by cohorts",
"authoring.discussions.builtIn.divideByCohorts.help": "Learners will only be able to view and respond to discussions posted by members of their cohort.",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.label": "Divide course-wide discussion topics",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.help": "Choose which of your general course-wide discussion topics you would like to divide.",
"authoring.discussions.builtIn.divideGeneralTopic.label": "General",
"authoring.discussions.builtIn.divideQuestionsForTAsTopic.label": "Questions for the TAs",
"authoring.discussions.builtIn.cohortsEnabled.label": "To adjust these settings, enable cohorts on the ",
"authoring.discussions.builtIn.instructorDashboard.label": "instructor dashboard",
"authoring.discussions.builtIn.visibilityInContext": "Visibility of in-context discussions",
"authoring.discussions.builtIn.gradedUnitPages.label": "Enable discussions on units in graded subsections",
"authoring.discussions.builtIn.gradedUnitPages.help": "Allow learners to engage with discussion on all graded unit pages except timed exams.",
"authoring.discussions.builtIn.groupInContextSubsection.label": "Group in context discussion at the subsection level",
"authoring.discussions.builtIn.groupInContextSubsection.help": "Learners will be able to view any post in the sub-section no matter which unit page they are viewing. While this is not recommended, if your course has short learning sequences or low enrollment grouping may increase engagement.",
"authoring.discussions.builtIn.anonymousPosting": "Anonymous posting",
"authoring.discussions.builtIn.allowAnonymous.label": "Allow anonymous discussion posts",
"authoring.discussions.builtIn.allowAnonymous.help": "If enabled, learners can create posts that are anonymous to all users.",
"authoring.discussions.builtIn.allowAnonymousPeers.label": "Allow anonymous discussion posts to peers",
"authoring.discussions.builtIn.allowAnonymousPeers.help": "Learners will be able to post anonymously to other peers but all posts will be visible to course staff.",
"authoring.discussions.builtIn.reportedContentEmailNotifications": "Notifications",
"authoring.discussions.builtIn.reportedContentEmailNotifications.label": "Email notifications for reported content",
"authoring.discussions.builtIn.reportedContentEmailNotifications.help": "Discussion Admins, Moderators, Community TAs and Group Community TAs (only for their own cohort) will receive an email notification when content is reported.",
"authoring.discussions.discussionTopics": "Discussion topics",
"authoring.discussions.discussionTopics.label": "General discussion topics",
"authoring.discussions.discussionTopics.help": "Discussions can include general topics not contained to the course structure. All courses have a general topic by default.",
"authoring.discussions.discussionTopic.required": "Topic name is a required field",
"authoring.discussions.discussionTopic.alreadyExistError": "It looks like this name is already in use",
"authoring.discussions.addTopicButton": "Add topic",
"authoring.discussions.deleteButton": "Delete",
"authoring.discussions.cancelButton": "Cancel",
"authoring.discussions.discussionTopicDeletion.help": "edX recommends that you do not delete discussion topics once your course is running.",
"authoring.discussions.discussionTopicDeletion.label": "Delete this topic?",
"authoring.discussions.builtIn.renameGeneralTopic.label": "Rename general topic",
"authoring.discussions.generalTopicHelp.help": "This is the default discussion topic for your course.",
"authoring.discussions.builtIn.configureAdditionalTopic.label": "Configure topic",
"authoring.discussions.addTopicHelpText": "Choose a unique name for your topic",
"authoring.discussions.blackoutDates": "Discussion blackout dates",
"authoring.discussions.builtIn.blackoutDates.label": "Blackout dates",
"authoring.discussions.builtIn.blackoutDates.help": "If added, learners will not be able to post in discussions between these dates.",
"authoring.discussions.addBlackoutDatesButton": "Add blackout date range",
"authoring.discussions.builtIn.configureBlackoutDates.label": "Configure blackout date range",
"authoring.discussions.blackoutStartDate.help": "Enter a start date, e.g. 12/10/2023",
"authoring.discussions.blackoutEndDate.help": "Enter an end date, e.g. 12/17/2023",
"authoring.discussions.blackoutStartTime.help": "Enter a start time, e.g. 09:00 AM",
"authoring.discussions.blackoutEndTime.help": "Enter an end time, e.g. 05:00 PM",
"authoring.discussions.activeBlackoutDatesDeletion.help": "These blackout dates are currently active. If deleted, learners will be able to post in discussions during these dates. Are you sure you want to proceed?",
"authoring.discussions.blackoutDatesDeletion.help": "If deleted, learners will be able to post in discussions during these dates.",
"authoring.discussions.completeBlackoutDatesDeletion.help": "Are you sure you want to delete these blackout dates?",
"authoring.discussions.activeBlackoutDatesDeletion.label": "Delete active blackout dates?",
"authoring.discussions.blackoutDatesDeletion.label": "Delete blackout dates?",
"authoring.blackoutDates.delete": "Delete Blackout Dates",
"authoring.blackoutDates.status": "{status}",
"authoring.blackoutDates.startDate.required": "Start date is a required field",
"authoring.blackoutDates.endDate.required": "End date is a required field",
"authoring.blackoutDates.startDate.inPast": "Start date cannot be after end date",
"authoring.blackoutDates.endDate.inPast": "End date cannot be before start date",
"authoring.blackoutDates.startTime.inPast": "Start time cannot be after end time",
"authoring.blackoutDates.endTime.inPast": "End time cannot be before start time",
"authoring.blackoutDates.startTime.inValidFormat": "Enter a valid start time",
"authoring.blackoutDates.endTime.inValidFormat": "Enter a valid end time",
"authoring.blackoutDates.startDate.inValidFormat": "Enter a valid start Date",
"authoring.blackoutDates.endDate.inValidFormat": "Enter a valid end date",
"authoring.topics.delete": "Delete Topic",
"authoring.topics.expand": "Expand",
"authoring.topics.collapse": "Collapse",
"authoring.blackoutDates.start.date": "Start date",
"authoring.blackoutDates.start.time": "Start time (optional) ({zone})",
"authoring.blackoutDates.end.date": "End date",
"authoring.blackoutDates.end.time": "End time (optional) ({zone})",
"authoring.discussions.heading": "Select a discussion tool for this course",
"authoring.discussions.supportedFeatures": "Supported features",
"authoring.discussions.supportedFeatureList-mobile-show": "Show supported features",
"authoring.discussions.supportedFeatureList-mobile-hide": "Hide supported features",
"authoring.discussions.noApps": "There are no discussions providers available for your course.",
"authoring.discussions.nextButton": "Next",
"authoring.discussions.appFullSupport": "Full support",
"authoring.discussions.appBasicSupport": "Basic support",
"authoring.discussions.selectApp": "Select {appName}",
"authoring.discussions.appList.appName-legacy": "edX",
"authoring.discussions.appList.appDescription-legacy": "Start conversations with other learners, ask questions, and interact with other learners in the course.",
"authoring.discussions.appList.appName-openedx": "edX",
"authoring.discussions.appList.appDescription-openedx": "Start conversations with other learners, ask questions, and interact with other learners in the course.",
"authoring.discussions.appList.appName-piazza": "Piazza",
"authoring.discussions.appList.appDescription-piazza": "Piazza is designed to connect students, TAs, and professors so every student can get the help they need when they need it.",
"authoring.discussions.appList.appDescription-yellowdig": "Yellowdig offers educators a gameful learning digital solution to improve student engagement by building learning communities for any course modality.",
"authoring.discussions.appList.appDescription-inscribe": "InScribe leverages the power of community + artificial intelligence to connect individuals to the answers, resources, and people they need to succeed.",
"authoring.discussions.appList.appDescription-discourse": "Discourse is modern forum software for your community. Use it as a mailing list, discussion forum, long-form chat room, and more!",
"authoring.discussions.appList.appDescription-ed-discus": "Ed Discussion helps scale class communication in a beautiful and intuitive interface. Questions reach and benefit the whole class. Less emails, more time saved.",
"authoring.discussions.featureName-discussion-page": "Discussion page",
"authoring.discussions.featureName-embedded-course-sections": "Embedded course sections",
"authoring.discussions.featureName-advanced-in-context-discussion": "Advanced in context discussion",
"authoring.discussions.featureName-anonymous-posting": "Anonymous posting",
"authoring.discussions.featureName-automatic-learner-enrollment": "Automatic learner enrollment",
"authoring.discussions.featureName-blackout-discussion-dates": "Blackout discussion dates",
"authoring.discussions.featureName-community-ta-support": "Community TA support",
"authoring.discussions.featureName-course-cohort-support": "Course cohort support",
"authoring.discussions.featureName-direct-messages-from-instructors": "Direct messages from instructors",
"authoring.discussions.featureName-discussion-content-prompts": "Discussion content prompts",
"authoring.discussions.featureName-email-notifications": "Email notifications",
"authoring.discussions.featureName-graded-discussions": "Graded discussions",
"authoring.discussions.featureName-in-platform-notifications": "In-platform notifications",
"authoring.discussions.featureName-internationalization-support": "Internationalization support",
"authoring.discussions.featureName-lti-advanced-sharing-mode": "LTI advanced sharing",
"authoring.discussions.featureName-basic-configuration": "Basic configuration",
"authoring.discussions.featureName-primary-discussion-app-experience": "Primary discussion app experience",
"authoring.discussions.featureName-question-&-discussion-support": "Question & discussion support",
"authoring.discussions.featureName-report/flag-content-to-moderators": "Report content to moderators",
"authoring.discussions.featureName-research-data-events": "Research data events",
"authoring.discussions.featureName-simplified-in-context-discussion": "Simplified in-context discussion",
"authoring.discussions.featureName-user-mentions": "User mentions",
"authoring.discussions.featureName-wcag-2.1": "WCAG 2.1 support",
"authoring.discussions.wcag-2.0-support": "WCAG 2.0 support",
"authoring.discussions.basic-support": "Basic support",
"authoring.discussions.partial-support": "Partial support",
"authoring.discussions.full-support": "Full support",
"authoring.discussions.common-support": "Commonly requested",
"authoring.discussions.settings": "Settings",
"authoring.discussions.applyButton": "Apply",
"authoring.discussions.applyingButton": "Applying",
"authoring.discussions.appliedButton": "Applied",
"authoring.discussions.noProviderSwitchAfterCourseStarted": "Discussion provider can't be changed after course has started, please reach out to partner support.",
"authoring.discussions.providerSelection": "Provider selection",
"authoring.discussions.Incomplete": "Incomplete",
"course-authoring.pages-resources.notes.heading": "Configure notes",
"course-authoring.pages-resources.notes.enable-notes.label": "Notes",
"course-authoring.pages-resources.notes.enable-notes.help": "Learners can access their notes either in the body of the\n course of on a notes page. On the notes page, a learner can see all the\n notes made during the course. The page also contains links to the location\n of the notes in the course body.",
"course-authoring.pages-resources.notes.enable-notes.link": "Learn more about notes",
"authoring.live.bbb.selectPlan.label": "Select a plan",
"authoring.pagesAndResources.live.enableLive.heading": "Configure Live",
"authoring.pagesAndResources.live.enableLive.label": "Live",
"authoring.pagesAndResources.live.enableLive.help": "Schedule meetings and conduct live course sessions with learners.",
"authoring.pagesAndResources.live.enableLive.link": "Learn more about live",
"authoring.live.selectProvider": "Select a video conferencing tool",
"authoring.live.formInstructions": "Complete the fields below to set up your video conferencing tool.",
"authoring.live.consumerKey": "Consumer Key",
"authoring.live.consumerKey.required": "Consumer key is a required field",
"authoring.live.consumerSecret": "Consumer Secret",
"authoring.live.consumerSecret.required": "Consumer secret is a required field",
"authoring.live.launchUrl": "Launch URL",
"authoring.live.launchUrl.required": "Launch URL is a required field",
"authoring.live.launchEmail": "Launch Email",
"authoring.live.launchEmail.required": "Launch Email is a required field",
"authoring.live.provider.helpText": "This configuration will require sharing username and emails of learners and the course team with {providerName}.",
"authoring.live.requestPiiSharingEnable": "This configuration will require sharing usernames and emails of learners and the course team with {provider}. To access the LTI configuration for {provider}, please request your edX project coordinator to get PII sharing enabled for this course.",
"authoring.live.appDocInstructions.documentationLink": "General documentation",
"authoring.live.appDocInstructions.accessibilityDocumentationLink": "Accessibility documentation",
"authoring.live.appDocInstructions.configurationLink": "Configuration documentation",
"authoring.live.appDocInstructions.learnMoreLink": "Learn more about {providerName}",
"authoring.live.appDocInstructions.linkTextHeading": "External help and documentation",
"authoring.live.appDocInstructions.linkText": "{link}",
"authoring.live.appName-yellowdig": "Zoom",
"authoring.live.appName-googleMeet": "Google Meet",
"authoring.live.appName-microsoftTeams": "Microsoft Teams",
"authoring.live.appName-bigBlueButton": "BigBlueButton",
"authoring.live.requestPiiSharingEnableForBbb": "This configuration will require sharing usernames of learners and the course team with {provider}.",
"authoring.live.piiSharingEnableHelpText": "To enable this feature, contact your edX support team to enable PII sharing for this course.",
"authoring.live.freePlanMessage": "The free plan is pre-configured, and no additional configurations are required. By selecting the free plan, you are agreeing to Blindside Networks",
"authoring.live.privacyPolicy": "Privacy Policy.",
"course-authoring.pages-resources.heading": "Pages & Resources",
"course-authoring.pages-resources.resources.settings.button": "settings",
"course-authoring.pages-resources.viewLive.button": "View live",
"course-authoring.badge.enabled": "Enabled",
"authoring.proctoring.no": "No",
"authoring.proctoring.yes": "Yes",
"authoring.proctoring.support.text": "Support Page",
"authoring.proctoring.enableproctoredexams.label": "Proctored exams",
"authoring.proctoring.enableproctoredexams.help": "Enable and configure proctored exams in your course.",
"authoring.proctoring.enabled": "Enabled",
"authoring.proctoring.learn.more": "Learn more about proctoring",
"authoring.proctoring.provider.label": "Proctoring provider",
"authoring.proctoring.provider.help": "Select the proctoring provider you want to use for this course run.",
"authoring.proctoring.provider.help.aftercoursestart": "Proctoring provider cannot be modified after course start date.",
"authoring.proctoring.escalationemail.label": "Proctortrack escalation email",
"authoring.proctoring.escalationemail.help": "Provide an email address to be contacted by the support team for escalations (e.g. appeals, delayed reviews).",
"authoring.proctoring.escalationemail.error.blank": "The Proctortrack Escalation Email field cannot be empty if proctortrack is the selected provider.",
"authoring.proctoring.escalationemail.error.invalid": "The Proctortrack Escalation Email field is in the wrong format and is not valid.",
"authoring.proctoring.allowoptout.label": "Allow learners to opt out of proctoring on proctored exams",
"authoring.proctoring.createzendesk.label": "Create Zendesk tickets for suspicious attempts",
"authoring.proctoring.error.single": "There is 1 error in this form.",
"authoring.proctoring.escalationemail.error.multiple": "There are {numOfErrors} errors in this form.",
"authoring.proctoring.save": "Save",
"authoring.proctoring.saving": "Saving...",
"authoring.proctoring.cancel": "Cancel",
"authoring.proctoring.studio.link.text": "Go back to your course in Studio",
"authoring.proctoring.alert.success": "\n Proctored exam settings saved successfully. {studioCourseRunURL}.\n ",
"authoring.examsettings.alert.error": "\n We encountered a technical error while trying to save proctored exam settings.\n This might be a temporary issue, so please try again in a few minutes.\n If the problem persists,\n please go to the {support_link} for help.\n ",
"course-authoring.pages-resources.progress.heading": "Configure progress",
"course-authoring.pages-resources.progress.enable-progress.label": "Progress",
"course-authoring.pages-resources.progress.enable-progress.help": "As students work through graded assignments, scores\n will appear under the progress tab. The progress tab contains a chart of\n all graded assignments in the course, with a list of all assignments and\n scores below.",
"course-authoring.pages-resources.progress.enable-progress.link": "Learn more about progress",
"course-authoring.pages-resources.progress.enable-graph.label": "Enable progress graph",
"course-authoring.pages-resources.progress.enable-graph.help": "If enabled, students can view the progress graph",
"authoring.pagesAndResources.teams.heading": "Configure teams",
"authoring.pagesAndResources.teams.enableTeams.label": "Teams",
"authoring.pagesAndResources.teams.enableTeams.help": "Allow learners to work together on specific projects or activities.",
"authoring.pagesAndResources.teams.enableTeams.link": "Learn more about teams",
"authoring.pagesAndResources.teams.teamSize.heading": "Team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSize": "Max team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeHelp": "The maximum number of learners that can join a team",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeEmpty": "Enter max team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeInvalid": "Max team size must be a positive number larger than zero.",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeTooHigh": "Max team size cannot be greater than {max}",
"authoring.pagesAndResources.teams.groups.heading": "Groups",
"authoring.pagesAndResources.teams.groups.help": "Groups are spaces where learners can create or join teams.",
"authoring.pagesAndResources.teams.configureGroup.heading": "Configure group",
"authoring.pagesAndResources.teams.group.name.label": "Name",
"authoring.pagesAndResources.teams.group.name.help": "Choose a unique name for this group",
"authoring.pagesAndResources.teams.group.name.error.empty": "Enter a unique name for this group",
"authoring.pagesAndResources.teams.group.name.error.exists": "It looks like this name is already in use",
"authoring.pagesAndResources.teams.group.description.label": "Description",
"authoring.pagesAndResources.teams.group.description.help": "Enter details about this group",
"authoring.pagesAndResources.teams.group.description.error": "Enter a description for this group",
"authoring.pagesAndResources.teams.group.type.label": "Type",
"authoring.pagesAndResources.teams.group.type.help": "Control who can see, create and join teams",
"authoring.pagesAndResources.teams.group.types.open": "Open",
"authoring.pagesAndResources.teams.group.types.open.description": "Learners can create, join, leave, and see other teams",
"authoring.pagesAndResources.teams.group.types.public_managed": "Public managed",
"authoring.pagesAndResources.teams.group.types.public_managed.description": "Only course staff can control teams and memberships. Learners can see other teams.",
"authoring.pagesAndResources.teams.group.types.private_managed": "Private managed",
"authoring.pagesAndResources.teams.group.types.private_managed.description": "Only course staff can control teams, memberships, and see other teams",
"authoring.pagesAndResources.teams.group.maxSize.label": "Max team size (optional)",
"authoring.pagesAndResources.teams.group.maxSize.help": "Override the global max team size",
"authoring.pagesAndResources.teams.addGroup.button": "Add group",
"authoring.pagesAndResources.teams.group.delete": "Delete",
"authoring.pagesAndResources.teams.group.expand": "Expand group editor",
"authoring.pagesAndResources.teams.group.collapse": "Close group editor",
"authoring.pagesAndResources.teams.deleteGroup.initiateDelete": "Delete",
"authoring.pagesAndResources.teams.deleteGroup.cancel-delete.button": "Cancel",
"authoring.pagesAndResources.teams.deleteGroup.heading": "Delete this group?",
"authoring.pagesAndResources.teams.deleteGroup.body": "edX recommends that you do not delete groups once your course is running.\n Your group will no longer be visible in the LMS and learners will not be able to leave teams associated with it.\n Please delete learners from teams before deleting the associated group.",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.title": "No groups found",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.message": "Add one or more groups to enable teams.",
"course-authoring.pages-resources.wiki.heading": "Configure wiki",
"course-authoring.pages-resources.wiki.enable-wiki.label": "Wiki",
"course-authoring.pages-resources.wiki.enable-wiki.help": "The course wiki can be set up based on the needs of your\n course. Common uses might include sharing answers to course FAQs, sharing\n editable course information, or providing access to learner-created\n resources.",
"course-authoring.pages-resources.wiki.enable-wiki.link": "Learn more about the wiki",
"course-authoring.pages-resources.wiki.enable-public-wiki.label": "Enable public wiki access",
"course-authoring.pages-resources.wiki.enable-public-wiki.help": "If enabled, edX users can view the course wiki even when\n they're not enrolled in the course.",
"authoring.examsettings.enableproctoredexams.help": "If checked, proctored exams are enabled in your course.",
"authoring.examsettings.allowoptout.label": "Allow Opting Out of Proctored Exams",
"authoring.examsettings.allowoptout.help": "\n If this value is \"Yes\", learners can choose to take proctored exams without proctoring.\n If this value is \"No\", all learners must take the exam with proctoring.\n ",
"authoring.examsettings.provider.label": "Proctoring Provider",
"authoring.examsettings.escalationemail.label": "Proctortrack Escalation Email",
"authoring.examsettings.escalationemail.help": "\n Required if \"proctortrack\" is selected as your proctoring provider. Enter an email address to be\n contacted by the support team whenever there are escalations (e.g. appeals, delayed reviews, etc.).\n ",
"authoring.examsettings.createzendesk.label": "Create Zendesk Tickets for Suspicious Proctored Exam Attempts",
"authoring.examsettings.createzendesk.help": "If this value is \"Yes\", a Zendesk ticket will be created for suspicious proctored exam attempts.",
"authoring.examsettings.submit": "Submit",
"authoring.examsettings.alert.success": "\n Proctored exam settings saved successfully.\n You can go back to your course in Studio {studioCourseRunURL}.\n ",
"authoring.examsettings.allowoptout.no": "No",
"authoring.examsettings.allowoptout.yes": "Yes",
"authoring.examsettings.createzendesk.no": "No",
"authoring.examsettings.createzendesk.yes": "Yes",
"authoring.examsettings.support.text": "Support Page",
"authoring.examsettings.escalationemail.enableproctoredexams.label": "Enable Proctored Exams",
"authoring.examsettings.escalationemail.error.blank": "The Proctortrack Escalation Email field cannot be empty if proctortrack is the selected provider.",
"authoring.examsettings.escalationemail.error.invalid": "The Proctortrack Escalation Email field is in the wrong format and is not valid.",
"authoring.examsettings.error.single": "There is 1 error in this form.",
"authoring.examsettings.escalationemail.error.multiple": "There are {numOfErrors} errors in this form.",
"authoring.examsettings.provider.help": "Select the proctoring provider you want to use for this course run.",
"authoring.examsettings.provider.help.aftercoursestart": "Proctoring provider cannot be modified after course start date.",
"header.links.content": "Content",
"header.links.settings": "Settings",
"header.links.content.tools": "Tools",
"header.links.outline": "Outline",
"header.links.updates": "Updates",
"header.links.pages": "Pages & Resources",
"header.links.filesAndUploads": "Files & Uploads",
"header.links.textbooks": "Textbooks",
"header.links.videoUploads": "Video Uploads",
"header.links.scheduleAndDetails": "Schedule & Details",
"header.links.grading": "Grading",
"header.links.courseTeam": "Course Team",
"header.links.groupConfigurations": "Group Configurations",
"header.links.proctoredExamSettings": "Proctored Exam Settings",
"header.links.advancedSettings": "Advanced Settings",
"header.links.certificates": "Certificates",
"header.links.publisher": "Publisher",
"header.links.import": "Import",
"header.links.export": "Export",
"header.links.checklists": "Checklists",
"header.user.menu.studio": "Studio Home",
"header.user.menu.maintenance": "Maintenance",
"header.user.menu.logout": "Logout",
"header.label.account.menu": "Account Menu",
"header.label.account.menu.for": "Account menu for {username}",
"header.label.main.nav": "Main",
"header.label.main.menu": "Main Menu",
"header.label.main.header": "Main",
"header.label.secondary.nav": "Secondary",
"header.label.courseOutline": "Back to course outline in Studio"
}

View File

@@ -1 +0,0 @@
{}

View File

@@ -1 +0,0 @@
{}

352
src/i18n/messages/pt.json Normal file
View File

@@ -0,0 +1,352 @@
{
"authoring.alert.error.connection": "We encountered a technical error when loading this page. This might be a temporary issue, so please try again in a few minutes. If the problem persists, please go to the {supportLink} for help.",
"authoring.loading": "Loading...",
"authoring.alert.error.permission": "You are not authorized to view this page. If you feel you should have access, please reach out to your course team admin to be given access.",
"authoring.alert.save.error.connection": "We encountered a technical error when applying changes. This might be a temporary issue, so please try again in a few minutes. If the problem persists, please go to the {supportLink} for help.",
"authoring.alert.support.text": "Support Page",
"course-authoring.pages-resources.app-settings-modal.button.cancel": "Cancel",
"course-authoring.pages-resources.app-settings-modal.button.save": "Save",
"course-authoring.pages-resources.app-settings-modal.button.saving": "Saving",
"course-authoring.pages-resources.app-settings-modal.button.saved": "Saved",
"course-authoring.pages-resources.app-settings-modal.button.retry": "Retry",
"course-authoring.pages-resources.app-settings-modal.badge.enabled": "Enabled",
"course-authoring.pages-resources.app-settings-modal.badge.disabled": "Disabled",
"course-authoring.pages-resources.app-settings-modal.save-error.title": "We couldn't apply your changes.",
"course-authoring.pages-resources.app-settings-modal.save-error.message": "Please check your entries and try again.",
"course-authoring.pages-resources.calculator.heading": "Configure calculator",
"course-authoring.pages-resources.calculator.enable-calculator.label": "Calculator",
"course-authoring.pages-resources.calculator.enable-calculator.help": "The calculator supports numbers, operators, constants,\n functions, and other mathematical concepts. When enabled, an icon to\n access the calculator appears on all pages in the body of your course.",
"course-authoring.pages-resources.calculator.enable-calculator.link": "Learn more about the calculator",
"authoring.discussions.documentationPage": "Visit the {name} documentation page",
"authoring.discussions.formInstructions": "Complete the fields below to set up your discussion tool.",
"authoring.discussions.consumerKey": "Consumer Key",
"authoring.discussions.consumerKey.required": "Consumer key is a required field",
"authoring.discussions.consumerSecret": "Consumer Secret",
"authoring.discussions.consumerSecret.required": "Consumer secret is a required field",
"authoring.discussions.launchUrl": "Launch URL",
"authoring.discussions.launchUrl.required": "Launch URL is a required field",
"authoring.discussions.stuffOnlyConfigInfo": "To enable {providerName} for your course, please contact their support team at {supportEmail} to learn more about pricing and usage.",
"authoring.discussions.stuffOnlyConfigGuide": "To fully configure {providerName} will also require sharing usernames and emails for learners and course team. Please contact your edX project coordinator to enable PII sharing for this course.",
"authoring.discussions.piiSharing": "Optionally share a user's username and/or email with the LTI provider:",
"authoring.discussions.piiShareUsername": "Share username",
"authoring.discussions.piiShareEmail": "Share email",
"authoring.discussions.appDocInstructions.contact": "Contact: {link}",
"authoring.discussions.appDocInstructions.documentationLink": "General documentation",
"authoring.discussions.appDocInstructions.accessibilityDocumentationLink": "Accessibility documentation",
"authoring.discussions.appDocInstructions.configurationLink": "Configuration documentation",
"authoring.discussions.appDocInstructions.learnMoreLink": "Learn more about {providerName}",
"authoring.discussions.appDocInstructions.linkTextHeading": "External help and documentation",
"authoring.discussions.appDocInstructions.linkText": "{link}",
"authoring.discussions.configurationChangeConsequences": "Students will lose access to any active or previous discussion posts for your course.",
"authoring.discussions.configure.app": "Configure {name}",
"authoring.discussions.configure": "Configure discussions",
"authoring.discussions.ok": "OK",
"authoring.discussions.cancel": "Cancel",
"authoring.discussions.confirm": "Confirm",
"authoring.discussions.confirmConfigurationChange": "Are you sure you want to change the discussion settings?",
"authoring.discussions.confirmEnableDiscussionsLabel": "Enable discussions on units in graded subsections?",
"authoring.discussions.cancelEnableDiscussionsLabel": "Disable discussions on units in graded subsections?",
"authoring.discussions.confirmEnableDiscussions": "Enabling this toggle will automatically enable discussion on all units in graded subsections, that are not timed exams.",
"authoring.discussions.cancelEnableDiscussions": "Disabling this toggle will automatically disable discussion on all units in graded subsections. Discussion topics containing at least 1 thread will be listed and accessible under “Archived” in Topics tab on the Discussions page.",
"authoring.discussions.backButton": "Back",
"authoring.discussions.saveButton": "Save",
"authoring.discussions.savingButton": "Saving",
"authoring.discussions.savedButton": "Saved",
"authoring.discussions.appConfigForm.appName-piazza": "Piazza",
"authoring.discussions.appConfigForm.appName-yellowdig": "Yellowdig",
"authoring.discussions.appConfigForm.appName-inscribe": "InScribe",
"authoring.discussions.appConfigForm.appName-discourse": "Discourse",
"authoring.discussions.appConfigForm.appName-ed-discuss": "Ed Discussion",
"authoring.discussions.appConfigForm.appName-legacy": "edX",
"authoring.discussions.appConfigForm.appName-openedx": "edX",
"authoring.discussions.builtIn.divisionByGroup": "Cohorts",
"authoring.discussions.builtIn.divideByCohorts.label": "Divide discussions by cohorts",
"authoring.discussions.builtIn.divideByCohorts.help": "Learners will only be able to view and respond to discussions posted by members of their cohort.",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.label": "Divide course-wide discussion topics",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.help": "Choose which of your general course-wide discussion topics you would like to divide.",
"authoring.discussions.builtIn.divideGeneralTopic.label": "General",
"authoring.discussions.builtIn.divideQuestionsForTAsTopic.label": "Questions for the TAs",
"authoring.discussions.builtIn.cohortsEnabled.label": "To adjust these settings, enable cohorts on the ",
"authoring.discussions.builtIn.instructorDashboard.label": "instructor dashboard",
"authoring.discussions.builtIn.visibilityInContext": "Visibility of in-context discussions",
"authoring.discussions.builtIn.gradedUnitPages.label": "Enable discussions on units in graded subsections",
"authoring.discussions.builtIn.gradedUnitPages.help": "Allow learners to engage with discussion on all graded unit pages except timed exams.",
"authoring.discussions.builtIn.groupInContextSubsection.label": "Group in context discussion at the subsection level",
"authoring.discussions.builtIn.groupInContextSubsection.help": "Learners will be able to view any post in the sub-section no matter which unit page they are viewing. While this is not recommended, if your course has short learning sequences or low enrollment grouping may increase engagement.",
"authoring.discussions.builtIn.anonymousPosting": "Anonymous posting",
"authoring.discussions.builtIn.allowAnonymous.label": "Allow anonymous discussion posts",
"authoring.discussions.builtIn.allowAnonymous.help": "If enabled, learners can create posts that are anonymous to all users.",
"authoring.discussions.builtIn.allowAnonymousPeers.label": "Allow anonymous discussion posts to peers",
"authoring.discussions.builtIn.allowAnonymousPeers.help": "Learners will be able to post anonymously to other peers but all posts will be visible to course staff.",
"authoring.discussions.builtIn.reportedContentEmailNotifications": "Notifications",
"authoring.discussions.builtIn.reportedContentEmailNotifications.label": "Email notifications for reported content",
"authoring.discussions.builtIn.reportedContentEmailNotifications.help": "Discussion Admins, Moderators, Community TAs and Group Community TAs (only for their own cohort) will receive an email notification when content is reported.",
"authoring.discussions.discussionTopics": "Discussion topics",
"authoring.discussions.discussionTopics.label": "General discussion topics",
"authoring.discussions.discussionTopics.help": "Discussions can include general topics not contained to the course structure. All courses have a general topic by default.",
"authoring.discussions.discussionTopic.required": "Topic name is a required field",
"authoring.discussions.discussionTopic.alreadyExistError": "It looks like this name is already in use",
"authoring.discussions.addTopicButton": "Add topic",
"authoring.discussions.deleteButton": "Delete",
"authoring.discussions.cancelButton": "Cancel",
"authoring.discussions.discussionTopicDeletion.help": "edX recommends that you do not delete discussion topics once your course is running.",
"authoring.discussions.discussionTopicDeletion.label": "Delete this topic?",
"authoring.discussions.builtIn.renameGeneralTopic.label": "Rename general topic",
"authoring.discussions.generalTopicHelp.help": "This is the default discussion topic for your course.",
"authoring.discussions.builtIn.configureAdditionalTopic.label": "Configure topic",
"authoring.discussions.addTopicHelpText": "Choose a unique name for your topic",
"authoring.discussions.blackoutDates": "Discussion blackout dates",
"authoring.discussions.builtIn.blackoutDates.label": "Blackout dates",
"authoring.discussions.builtIn.blackoutDates.help": "If added, learners will not be able to post in discussions between these dates.",
"authoring.discussions.addBlackoutDatesButton": "Add blackout date range",
"authoring.discussions.builtIn.configureBlackoutDates.label": "Configure blackout date range",
"authoring.discussions.blackoutStartDate.help": "Enter a start date, e.g. 12/10/2023",
"authoring.discussions.blackoutEndDate.help": "Enter an end date, e.g. 12/17/2023",
"authoring.discussions.blackoutStartTime.help": "Enter a start time, e.g. 09:00 AM",
"authoring.discussions.blackoutEndTime.help": "Enter an end time, e.g. 05:00 PM",
"authoring.discussions.activeBlackoutDatesDeletion.help": "These blackout dates are currently active. If deleted, learners will be able to post in discussions during these dates. Are you sure you want to proceed?",
"authoring.discussions.blackoutDatesDeletion.help": "If deleted, learners will be able to post in discussions during these dates.",
"authoring.discussions.completeBlackoutDatesDeletion.help": "Are you sure you want to delete these blackout dates?",
"authoring.discussions.activeBlackoutDatesDeletion.label": "Delete active blackout dates?",
"authoring.discussions.blackoutDatesDeletion.label": "Delete blackout dates?",
"authoring.blackoutDates.delete": "Delete Blackout Dates",
"authoring.blackoutDates.status": "{status}",
"authoring.blackoutDates.startDate.required": "Start date is a required field",
"authoring.blackoutDates.endDate.required": "End date is a required field",
"authoring.blackoutDates.startDate.inPast": "Start date cannot be after end date",
"authoring.blackoutDates.endDate.inPast": "End date cannot be before start date",
"authoring.blackoutDates.startTime.inPast": "Start time cannot be after end time",
"authoring.blackoutDates.endTime.inPast": "End time cannot be before start time",
"authoring.blackoutDates.startTime.inValidFormat": "Enter a valid start time",
"authoring.blackoutDates.endTime.inValidFormat": "Enter a valid end time",
"authoring.blackoutDates.startDate.inValidFormat": "Enter a valid start Date",
"authoring.blackoutDates.endDate.inValidFormat": "Enter a valid end date",
"authoring.topics.delete": "Delete Topic",
"authoring.topics.expand": "Expand",
"authoring.topics.collapse": "Collapse",
"authoring.blackoutDates.start.date": "Start date",
"authoring.blackoutDates.start.time": "Start time (optional) ({zone})",
"authoring.blackoutDates.end.date": "End date",
"authoring.blackoutDates.end.time": "End time (optional) ({zone})",
"authoring.discussions.heading": "Select a discussion tool for this course",
"authoring.discussions.supportedFeatures": "Supported features",
"authoring.discussions.supportedFeatureList-mobile-show": "Show supported features",
"authoring.discussions.supportedFeatureList-mobile-hide": "Hide supported features",
"authoring.discussions.noApps": "There are no discussions providers available for your course.",
"authoring.discussions.nextButton": "Next",
"authoring.discussions.appFullSupport": "Full support",
"authoring.discussions.appBasicSupport": "Basic support",
"authoring.discussions.selectApp": "Select {appName}",
"authoring.discussions.appList.appName-legacy": "edX",
"authoring.discussions.appList.appDescription-legacy": "Start conversations with other learners, ask questions, and interact with other learners in the course.",
"authoring.discussions.appList.appName-openedx": "edX",
"authoring.discussions.appList.appDescription-openedx": "Start conversations with other learners, ask questions, and interact with other learners in the course.",
"authoring.discussions.appList.appName-piazza": "Piazza",
"authoring.discussions.appList.appDescription-piazza": "Piazza is designed to connect students, TAs, and professors so every student can get the help they need when they need it.",
"authoring.discussions.appList.appDescription-yellowdig": "Yellowdig offers educators a gameful learning digital solution to improve student engagement by building learning communities for any course modality.",
"authoring.discussions.appList.appDescription-inscribe": "InScribe leverages the power of community + artificial intelligence to connect individuals to the answers, resources, and people they need to succeed.",
"authoring.discussions.appList.appDescription-discourse": "Discourse is modern forum software for your community. Use it as a mailing list, discussion forum, long-form chat room, and more!",
"authoring.discussions.appList.appDescription-ed-discus": "Ed Discussion helps scale class communication in a beautiful and intuitive interface. Questions reach and benefit the whole class. Less emails, more time saved.",
"authoring.discussions.featureName-discussion-page": "Discussion page",
"authoring.discussions.featureName-embedded-course-sections": "Embedded course sections",
"authoring.discussions.featureName-advanced-in-context-discussion": "Advanced in context discussion",
"authoring.discussions.featureName-anonymous-posting": "Anonymous posting",
"authoring.discussions.featureName-automatic-learner-enrollment": "Automatic learner enrollment",
"authoring.discussions.featureName-blackout-discussion-dates": "Blackout discussion dates",
"authoring.discussions.featureName-community-ta-support": "Community TA support",
"authoring.discussions.featureName-course-cohort-support": "Course cohort support",
"authoring.discussions.featureName-direct-messages-from-instructors": "Direct messages from instructors",
"authoring.discussions.featureName-discussion-content-prompts": "Discussion content prompts",
"authoring.discussions.featureName-email-notifications": "Email notifications",
"authoring.discussions.featureName-graded-discussions": "Graded discussions",
"authoring.discussions.featureName-in-platform-notifications": "In-platform notifications",
"authoring.discussions.featureName-internationalization-support": "Internationalization support",
"authoring.discussions.featureName-lti-advanced-sharing-mode": "LTI advanced sharing",
"authoring.discussions.featureName-basic-configuration": "Basic configuration",
"authoring.discussions.featureName-primary-discussion-app-experience": "Primary discussion app experience",
"authoring.discussions.featureName-question-&-discussion-support": "Question & discussion support",
"authoring.discussions.featureName-report/flag-content-to-moderators": "Report content to moderators",
"authoring.discussions.featureName-research-data-events": "Research data events",
"authoring.discussions.featureName-simplified-in-context-discussion": "Simplified in-context discussion",
"authoring.discussions.featureName-user-mentions": "User mentions",
"authoring.discussions.featureName-wcag-2.1": "WCAG 2.1 support",
"authoring.discussions.wcag-2.0-support": "WCAG 2.0 support",
"authoring.discussions.basic-support": "Basic support",
"authoring.discussions.partial-support": "Partial support",
"authoring.discussions.full-support": "Full support",
"authoring.discussions.common-support": "Commonly requested",
"authoring.discussions.settings": "Settings",
"authoring.discussions.applyButton": "Apply",
"authoring.discussions.applyingButton": "Applying",
"authoring.discussions.appliedButton": "Applied",
"authoring.discussions.noProviderSwitchAfterCourseStarted": "Discussion provider can't be changed after course has started, please reach out to partner support.",
"authoring.discussions.providerSelection": "Provider selection",
"authoring.discussions.Incomplete": "Incomplete",
"course-authoring.pages-resources.notes.heading": "Configure notes",
"course-authoring.pages-resources.notes.enable-notes.label": "Notes",
"course-authoring.pages-resources.notes.enable-notes.help": "Learners can access their notes either in the body of the\n course of on a notes page. On the notes page, a learner can see all the\n notes made during the course. The page also contains links to the location\n of the notes in the course body.",
"course-authoring.pages-resources.notes.enable-notes.link": "Learn more about notes",
"authoring.live.bbb.selectPlan.label": "Select a plan",
"authoring.pagesAndResources.live.enableLive.heading": "Configure Live",
"authoring.pagesAndResources.live.enableLive.label": "Live",
"authoring.pagesAndResources.live.enableLive.help": "Schedule meetings and conduct live course sessions with learners.",
"authoring.pagesAndResources.live.enableLive.link": "Learn more about live",
"authoring.live.selectProvider": "Select a video conferencing tool",
"authoring.live.formInstructions": "Complete the fields below to set up your video conferencing tool.",
"authoring.live.consumerKey": "Consumer Key",
"authoring.live.consumerKey.required": "Consumer key is a required field",
"authoring.live.consumerSecret": "Consumer Secret",
"authoring.live.consumerSecret.required": "Consumer secret is a required field",
"authoring.live.launchUrl": "Launch URL",
"authoring.live.launchUrl.required": "Launch URL is a required field",
"authoring.live.launchEmail": "Launch Email",
"authoring.live.launchEmail.required": "Launch Email is a required field",
"authoring.live.provider.helpText": "This configuration will require sharing username and emails of learners and the course team with {providerName}.",
"authoring.live.requestPiiSharingEnable": "This configuration will require sharing usernames and emails of learners and the course team with {provider}. To access the LTI configuration for {provider}, please request your edX project coordinator to get PII sharing enabled for this course.",
"authoring.live.appDocInstructions.documentationLink": "General documentation",
"authoring.live.appDocInstructions.accessibilityDocumentationLink": "Accessibility documentation",
"authoring.live.appDocInstructions.configurationLink": "Configuration documentation",
"authoring.live.appDocInstructions.learnMoreLink": "Learn more about {providerName}",
"authoring.live.appDocInstructions.linkTextHeading": "External help and documentation",
"authoring.live.appDocInstructions.linkText": "{link}",
"authoring.live.appName-yellowdig": "Zoom",
"authoring.live.appName-googleMeet": "Google Meet",
"authoring.live.appName-microsoftTeams": "Microsoft Teams",
"authoring.live.appName-bigBlueButton": "BigBlueButton",
"authoring.live.requestPiiSharingEnableForBbb": "This configuration will require sharing usernames of learners and the course team with {provider}.",
"authoring.live.piiSharingEnableHelpText": "To enable this feature, contact your edX support team to enable PII sharing for this course.",
"authoring.live.freePlanMessage": "The free plan is pre-configured, and no additional configurations are required. By selecting the free plan, you are agreeing to Blindside Networks",
"authoring.live.privacyPolicy": "Privacy Policy.",
"course-authoring.pages-resources.heading": "Pages & Resources",
"course-authoring.pages-resources.resources.settings.button": "settings",
"course-authoring.pages-resources.viewLive.button": "View live",
"course-authoring.badge.enabled": "Enabled",
"authoring.proctoring.no": "No",
"authoring.proctoring.yes": "Yes",
"authoring.proctoring.support.text": "Support Page",
"authoring.proctoring.enableproctoredexams.label": "Proctored exams",
"authoring.proctoring.enableproctoredexams.help": "Enable and configure proctored exams in your course.",
"authoring.proctoring.enabled": "Enabled",
"authoring.proctoring.learn.more": "Learn more about proctoring",
"authoring.proctoring.provider.label": "Proctoring provider",
"authoring.proctoring.provider.help": "Select the proctoring provider you want to use for this course run.",
"authoring.proctoring.provider.help.aftercoursestart": "Proctoring provider cannot be modified after course start date.",
"authoring.proctoring.escalationemail.label": "Proctortrack escalation email",
"authoring.proctoring.escalationemail.help": "Provide an email address to be contacted by the support team for escalations (e.g. appeals, delayed reviews).",
"authoring.proctoring.escalationemail.error.blank": "The Proctortrack Escalation Email field cannot be empty if proctortrack is the selected provider.",
"authoring.proctoring.escalationemail.error.invalid": "The Proctortrack Escalation Email field is in the wrong format and is not valid.",
"authoring.proctoring.allowoptout.label": "Allow learners to opt out of proctoring on proctored exams",
"authoring.proctoring.createzendesk.label": "Create Zendesk tickets for suspicious attempts",
"authoring.proctoring.error.single": "There is 1 error in this form.",
"authoring.proctoring.escalationemail.error.multiple": "There are {numOfErrors} errors in this form.",
"authoring.proctoring.save": "Save",
"authoring.proctoring.saving": "Saving...",
"authoring.proctoring.cancel": "Cancel",
"authoring.proctoring.studio.link.text": "Go back to your course in Studio",
"authoring.proctoring.alert.success": "\n Proctored exam settings saved successfully. {studioCourseRunURL}.\n ",
"authoring.examsettings.alert.error": "\n We encountered a technical error while trying to save proctored exam settings.\n This might be a temporary issue, so please try again in a few minutes.\n If the problem persists,\n please go to the {support_link} for help.\n ",
"course-authoring.pages-resources.progress.heading": "Configure progress",
"course-authoring.pages-resources.progress.enable-progress.label": "Progress",
"course-authoring.pages-resources.progress.enable-progress.help": "As students work through graded assignments, scores\n will appear under the progress tab. The progress tab contains a chart of\n all graded assignments in the course, with a list of all assignments and\n scores below.",
"course-authoring.pages-resources.progress.enable-progress.link": "Learn more about progress",
"course-authoring.pages-resources.progress.enable-graph.label": "Enable progress graph",
"course-authoring.pages-resources.progress.enable-graph.help": "If enabled, students can view the progress graph",
"authoring.pagesAndResources.teams.heading": "Configure teams",
"authoring.pagesAndResources.teams.enableTeams.label": "Teams",
"authoring.pagesAndResources.teams.enableTeams.help": "Allow learners to work together on specific projects or activities.",
"authoring.pagesAndResources.teams.enableTeams.link": "Learn more about teams",
"authoring.pagesAndResources.teams.teamSize.heading": "Team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSize": "Max team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeHelp": "The maximum number of learners that can join a team",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeEmpty": "Enter max team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeInvalid": "Max team size must be a positive number larger than zero.",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeTooHigh": "Max team size cannot be greater than {max}",
"authoring.pagesAndResources.teams.groups.heading": "Groups",
"authoring.pagesAndResources.teams.groups.help": "Groups are spaces where learners can create or join teams.",
"authoring.pagesAndResources.teams.configureGroup.heading": "Configure group",
"authoring.pagesAndResources.teams.group.name.label": "Name",
"authoring.pagesAndResources.teams.group.name.help": "Choose a unique name for this group",
"authoring.pagesAndResources.teams.group.name.error.empty": "Enter a unique name for this group",
"authoring.pagesAndResources.teams.group.name.error.exists": "It looks like this name is already in use",
"authoring.pagesAndResources.teams.group.description.label": "Description",
"authoring.pagesAndResources.teams.group.description.help": "Enter details about this group",
"authoring.pagesAndResources.teams.group.description.error": "Enter a description for this group",
"authoring.pagesAndResources.teams.group.type.label": "Type",
"authoring.pagesAndResources.teams.group.type.help": "Control who can see, create and join teams",
"authoring.pagesAndResources.teams.group.types.open": "Open",
"authoring.pagesAndResources.teams.group.types.open.description": "Learners can create, join, leave, and see other teams",
"authoring.pagesAndResources.teams.group.types.public_managed": "Public managed",
"authoring.pagesAndResources.teams.group.types.public_managed.description": "Only course staff can control teams and memberships. Learners can see other teams.",
"authoring.pagesAndResources.teams.group.types.private_managed": "Private managed",
"authoring.pagesAndResources.teams.group.types.private_managed.description": "Only course staff can control teams, memberships, and see other teams",
"authoring.pagesAndResources.teams.group.maxSize.label": "Max team size (optional)",
"authoring.pagesAndResources.teams.group.maxSize.help": "Override the global max team size",
"authoring.pagesAndResources.teams.addGroup.button": "Add group",
"authoring.pagesAndResources.teams.group.delete": "Delete",
"authoring.pagesAndResources.teams.group.expand": "Expand group editor",
"authoring.pagesAndResources.teams.group.collapse": "Close group editor",
"authoring.pagesAndResources.teams.deleteGroup.initiateDelete": "Delete",
"authoring.pagesAndResources.teams.deleteGroup.cancel-delete.button": "Cancel",
"authoring.pagesAndResources.teams.deleteGroup.heading": "Delete this group?",
"authoring.pagesAndResources.teams.deleteGroup.body": "edX recommends that you do not delete groups once your course is running.\n Your group will no longer be visible in the LMS and learners will not be able to leave teams associated with it.\n Please delete learners from teams before deleting the associated group.",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.title": "No groups found",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.message": "Add one or more groups to enable teams.",
"course-authoring.pages-resources.wiki.heading": "Configure wiki",
"course-authoring.pages-resources.wiki.enable-wiki.label": "Wiki",
"course-authoring.pages-resources.wiki.enable-wiki.help": "The course wiki can be set up based on the needs of your\n course. Common uses might include sharing answers to course FAQs, sharing\n editable course information, or providing access to learner-created\n resources.",
"course-authoring.pages-resources.wiki.enable-wiki.link": "Learn more about the wiki",
"course-authoring.pages-resources.wiki.enable-public-wiki.label": "Enable public wiki access",
"course-authoring.pages-resources.wiki.enable-public-wiki.help": "If enabled, edX users can view the course wiki even when\n they're not enrolled in the course.",
"authoring.examsettings.enableproctoredexams.help": "If checked, proctored exams are enabled in your course.",
"authoring.examsettings.allowoptout.label": "Allow Opting Out of Proctored Exams",
"authoring.examsettings.allowoptout.help": "\n If this value is \"Yes\", learners can choose to take proctored exams without proctoring.\n If this value is \"No\", all learners must take the exam with proctoring.\n ",
"authoring.examsettings.provider.label": "Proctoring Provider",
"authoring.examsettings.escalationemail.label": "Proctortrack Escalation Email",
"authoring.examsettings.escalationemail.help": "\n Required if \"proctortrack\" is selected as your proctoring provider. Enter an email address to be\n contacted by the support team whenever there are escalations (e.g. appeals, delayed reviews, etc.).\n ",
"authoring.examsettings.createzendesk.label": "Create Zendesk Tickets for Suspicious Proctored Exam Attempts",
"authoring.examsettings.createzendesk.help": "If this value is \"Yes\", a Zendesk ticket will be created for suspicious proctored exam attempts.",
"authoring.examsettings.submit": "Submit",
"authoring.examsettings.alert.success": "\n Proctored exam settings saved successfully.\n You can go back to your course in Studio {studioCourseRunURL}.\n ",
"authoring.examsettings.allowoptout.no": "No",
"authoring.examsettings.allowoptout.yes": "Yes",
"authoring.examsettings.createzendesk.no": "No",
"authoring.examsettings.createzendesk.yes": "Yes",
"authoring.examsettings.support.text": "Support Page",
"authoring.examsettings.escalationemail.enableproctoredexams.label": "Enable Proctored Exams",
"authoring.examsettings.escalationemail.error.blank": "The Proctortrack Escalation Email field cannot be empty if proctortrack is the selected provider.",
"authoring.examsettings.escalationemail.error.invalid": "The Proctortrack Escalation Email field is in the wrong format and is not valid.",
"authoring.examsettings.error.single": "There is 1 error in this form.",
"authoring.examsettings.escalationemail.error.multiple": "There are {numOfErrors} errors in this form.",
"authoring.examsettings.provider.help": "Select the proctoring provider you want to use for this course run.",
"authoring.examsettings.provider.help.aftercoursestart": "Proctoring provider cannot be modified after course start date.",
"header.links.content": "Content",
"header.links.settings": "Settings",
"header.links.content.tools": "Tools",
"header.links.outline": "Outline",
"header.links.updates": "Updates",
"header.links.pages": "Pages & Resources",
"header.links.filesAndUploads": "Files & Uploads",
"header.links.textbooks": "Textbooks",
"header.links.videoUploads": "Video Uploads",
"header.links.scheduleAndDetails": "Schedule & Details",
"header.links.grading": "Grading",
"header.links.courseTeam": "Course Team",
"header.links.groupConfigurations": "Group Configurations",
"header.links.proctoredExamSettings": "Proctored Exam Settings",
"header.links.advancedSettings": "Advanced Settings",
"header.links.certificates": "Certificates",
"header.links.publisher": "Publisher",
"header.links.import": "Import",
"header.links.export": "Export",
"header.links.checklists": "Checklists",
"header.user.menu.studio": "Studio Home",
"header.user.menu.maintenance": "Maintenance",
"header.user.menu.logout": "Logout",
"header.label.account.menu": "Account Menu",
"header.label.account.menu.for": "Account menu for {username}",
"header.label.main.nav": "Main",
"header.label.main.menu": "Main Menu",
"header.label.main.header": "Main",
"header.label.secondary.nav": "Secondary",
"header.label.courseOutline": "Back to course outline in Studio"
}

View File

@@ -1 +0,0 @@
{}

View File

@@ -1 +1,352 @@
{}
{
"authoring.alert.error.connection": "We encountered a technical error when loading this page. This might be a temporary issue, so please try again in a few minutes. If the problem persists, please go to the {supportLink} for help.",
"authoring.loading": "Loading...",
"authoring.alert.error.permission": "You are not authorized to view this page. If you feel you should have access, please reach out to your course team admin to be given access.",
"authoring.alert.save.error.connection": "We encountered a technical error when applying changes. This might be a temporary issue, so please try again in a few minutes. If the problem persists, please go to the {supportLink} for help.",
"authoring.alert.support.text": "Support Page",
"course-authoring.pages-resources.app-settings-modal.button.cancel": "Cancel",
"course-authoring.pages-resources.app-settings-modal.button.save": "Save",
"course-authoring.pages-resources.app-settings-modal.button.saving": "Saving",
"course-authoring.pages-resources.app-settings-modal.button.saved": "Saved",
"course-authoring.pages-resources.app-settings-modal.button.retry": "Retry",
"course-authoring.pages-resources.app-settings-modal.badge.enabled": "Enabled",
"course-authoring.pages-resources.app-settings-modal.badge.disabled": "Disabled",
"course-authoring.pages-resources.app-settings-modal.save-error.title": "We couldn't apply your changes.",
"course-authoring.pages-resources.app-settings-modal.save-error.message": "Please check your entries and try again.",
"course-authoring.pages-resources.calculator.heading": "Configure calculator",
"course-authoring.pages-resources.calculator.enable-calculator.label": "Calculator",
"course-authoring.pages-resources.calculator.enable-calculator.help": "The calculator supports numbers, operators, constants,\n functions, and other mathematical concepts. When enabled, an icon to\n access the calculator appears on all pages in the body of your course.",
"course-authoring.pages-resources.calculator.enable-calculator.link": "Learn more about the calculator",
"authoring.discussions.documentationPage": "Visit the {name} documentation page",
"authoring.discussions.formInstructions": "Complete the fields below to set up your discussion tool.",
"authoring.discussions.consumerKey": "Consumer Key",
"authoring.discussions.consumerKey.required": "Consumer key is a required field",
"authoring.discussions.consumerSecret": "Consumer Secret",
"authoring.discussions.consumerSecret.required": "Consumer secret is a required field",
"authoring.discussions.launchUrl": "Launch URL",
"authoring.discussions.launchUrl.required": "Launch URL is a required field",
"authoring.discussions.stuffOnlyConfigInfo": "To enable {providerName} for your course, please contact their support team at {supportEmail} to learn more about pricing and usage.",
"authoring.discussions.stuffOnlyConfigGuide": "To fully configure {providerName} will also require sharing usernames and emails for learners and course team. Please contact your edX project coordinator to enable PII sharing for this course.",
"authoring.discussions.piiSharing": "Optionally share a user's username and/or email with the LTI provider:",
"authoring.discussions.piiShareUsername": "Share username",
"authoring.discussions.piiShareEmail": "Share email",
"authoring.discussions.appDocInstructions.contact": "Contact: {link}",
"authoring.discussions.appDocInstructions.documentationLink": "General documentation",
"authoring.discussions.appDocInstructions.accessibilityDocumentationLink": "Accessibility documentation",
"authoring.discussions.appDocInstructions.configurationLink": "Configuration documentation",
"authoring.discussions.appDocInstructions.learnMoreLink": "Learn more about {providerName}",
"authoring.discussions.appDocInstructions.linkTextHeading": "External help and documentation",
"authoring.discussions.appDocInstructions.linkText": "{link}",
"authoring.discussions.configurationChangeConsequences": "Students will lose access to any active or previous discussion posts for your course.",
"authoring.discussions.configure.app": "Configure {name}",
"authoring.discussions.configure": "Configure discussions",
"authoring.discussions.ok": "OK",
"authoring.discussions.cancel": "Cancel",
"authoring.discussions.confirm": "Confirm",
"authoring.discussions.confirmConfigurationChange": "Are you sure you want to change the discussion settings?",
"authoring.discussions.confirmEnableDiscussionsLabel": "Enable discussions on units in graded subsections?",
"authoring.discussions.cancelEnableDiscussionsLabel": "Disable discussions on units in graded subsections?",
"authoring.discussions.confirmEnableDiscussions": "Enabling this toggle will automatically enable discussion on all units in graded subsections, that are not timed exams.",
"authoring.discussions.cancelEnableDiscussions": "Disabling this toggle will automatically disable discussion on all units in graded subsections. Discussion topics containing at least 1 thread will be listed and accessible under “Archived” in Topics tab on the Discussions page.",
"authoring.discussions.backButton": "Back",
"authoring.discussions.saveButton": "Save",
"authoring.discussions.savingButton": "Saving",
"authoring.discussions.savedButton": "Saved",
"authoring.discussions.appConfigForm.appName-piazza": "Piazza",
"authoring.discussions.appConfigForm.appName-yellowdig": "Yellowdig",
"authoring.discussions.appConfigForm.appName-inscribe": "InScribe",
"authoring.discussions.appConfigForm.appName-discourse": "Discourse",
"authoring.discussions.appConfigForm.appName-ed-discuss": "Ed Discussion",
"authoring.discussions.appConfigForm.appName-legacy": "edX",
"authoring.discussions.appConfigForm.appName-openedx": "edX",
"authoring.discussions.builtIn.divisionByGroup": "Cohorts",
"authoring.discussions.builtIn.divideByCohorts.label": "Divide discussions by cohorts",
"authoring.discussions.builtIn.divideByCohorts.help": "Learners will only be able to view and respond to discussions posted by members of their cohort.",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.label": "Divide course-wide discussion topics",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.help": "Choose which of your general course-wide discussion topics you would like to divide.",
"authoring.discussions.builtIn.divideGeneralTopic.label": "General",
"authoring.discussions.builtIn.divideQuestionsForTAsTopic.label": "Questions for the TAs",
"authoring.discussions.builtIn.cohortsEnabled.label": "To adjust these settings, enable cohorts on the ",
"authoring.discussions.builtIn.instructorDashboard.label": "instructor dashboard",
"authoring.discussions.builtIn.visibilityInContext": "Visibility of in-context discussions",
"authoring.discussions.builtIn.gradedUnitPages.label": "Enable discussions on units in graded subsections",
"authoring.discussions.builtIn.gradedUnitPages.help": "Allow learners to engage with discussion on all graded unit pages except timed exams.",
"authoring.discussions.builtIn.groupInContextSubsection.label": "Group in context discussion at the subsection level",
"authoring.discussions.builtIn.groupInContextSubsection.help": "Learners will be able to view any post in the sub-section no matter which unit page they are viewing. While this is not recommended, if your course has short learning sequences or low enrollment grouping may increase engagement.",
"authoring.discussions.builtIn.anonymousPosting": "Anonymous posting",
"authoring.discussions.builtIn.allowAnonymous.label": "Allow anonymous discussion posts",
"authoring.discussions.builtIn.allowAnonymous.help": "If enabled, learners can create posts that are anonymous to all users.",
"authoring.discussions.builtIn.allowAnonymousPeers.label": "Allow anonymous discussion posts to peers",
"authoring.discussions.builtIn.allowAnonymousPeers.help": "Learners will be able to post anonymously to other peers but all posts will be visible to course staff.",
"authoring.discussions.builtIn.reportedContentEmailNotifications": "Notifications",
"authoring.discussions.builtIn.reportedContentEmailNotifications.label": "Email notifications for reported content",
"authoring.discussions.builtIn.reportedContentEmailNotifications.help": "Discussion Admins, Moderators, Community TAs and Group Community TAs (only for their own cohort) will receive an email notification when content is reported.",
"authoring.discussions.discussionTopics": "Discussion topics",
"authoring.discussions.discussionTopics.label": "General discussion topics",
"authoring.discussions.discussionTopics.help": "Discussions can include general topics not contained to the course structure. All courses have a general topic by default.",
"authoring.discussions.discussionTopic.required": "Topic name is a required field",
"authoring.discussions.discussionTopic.alreadyExistError": "It looks like this name is already in use",
"authoring.discussions.addTopicButton": "Add topic",
"authoring.discussions.deleteButton": "Delete",
"authoring.discussions.cancelButton": "Cancel",
"authoring.discussions.discussionTopicDeletion.help": "edX recommends that you do not delete discussion topics once your course is running.",
"authoring.discussions.discussionTopicDeletion.label": "Delete this topic?",
"authoring.discussions.builtIn.renameGeneralTopic.label": "Rename general topic",
"authoring.discussions.generalTopicHelp.help": "This is the default discussion topic for your course.",
"authoring.discussions.builtIn.configureAdditionalTopic.label": "Configure topic",
"authoring.discussions.addTopicHelpText": "Choose a unique name for your topic",
"authoring.discussions.blackoutDates": "Discussion blackout dates",
"authoring.discussions.builtIn.blackoutDates.label": "Blackout dates",
"authoring.discussions.builtIn.blackoutDates.help": "If added, learners will not be able to post in discussions between these dates.",
"authoring.discussions.addBlackoutDatesButton": "Add blackout date range",
"authoring.discussions.builtIn.configureBlackoutDates.label": "Configure blackout date range",
"authoring.discussions.blackoutStartDate.help": "Enter a start date, e.g. 12/10/2023",
"authoring.discussions.blackoutEndDate.help": "Enter an end date, e.g. 12/17/2023",
"authoring.discussions.blackoutStartTime.help": "Enter a start time, e.g. 09:00 AM",
"authoring.discussions.blackoutEndTime.help": "Enter an end time, e.g. 05:00 PM",
"authoring.discussions.activeBlackoutDatesDeletion.help": "These blackout dates are currently active. If deleted, learners will be able to post in discussions during these dates. Are you sure you want to proceed?",
"authoring.discussions.blackoutDatesDeletion.help": "If deleted, learners will be able to post in discussions during these dates.",
"authoring.discussions.completeBlackoutDatesDeletion.help": "Are you sure you want to delete these blackout dates?",
"authoring.discussions.activeBlackoutDatesDeletion.label": "Delete active blackout dates?",
"authoring.discussions.blackoutDatesDeletion.label": "Delete blackout dates?",
"authoring.blackoutDates.delete": "Delete Blackout Dates",
"authoring.blackoutDates.status": "{status}",
"authoring.blackoutDates.startDate.required": "Start date is a required field",
"authoring.blackoutDates.endDate.required": "End date is a required field",
"authoring.blackoutDates.startDate.inPast": "Start date cannot be after end date",
"authoring.blackoutDates.endDate.inPast": "End date cannot be before start date",
"authoring.blackoutDates.startTime.inPast": "Start time cannot be after end time",
"authoring.blackoutDates.endTime.inPast": "End time cannot be before start time",
"authoring.blackoutDates.startTime.inValidFormat": "Enter a valid start time",
"authoring.blackoutDates.endTime.inValidFormat": "Enter a valid end time",
"authoring.blackoutDates.startDate.inValidFormat": "Enter a valid start Date",
"authoring.blackoutDates.endDate.inValidFormat": "Enter a valid end date",
"authoring.topics.delete": "Delete Topic",
"authoring.topics.expand": "Expand",
"authoring.topics.collapse": "Collapse",
"authoring.blackoutDates.start.date": "Start date",
"authoring.blackoutDates.start.time": "Start time (optional) ({zone})",
"authoring.blackoutDates.end.date": "End date",
"authoring.blackoutDates.end.time": "End time (optional) ({zone})",
"authoring.discussions.heading": "Select a discussion tool for this course",
"authoring.discussions.supportedFeatures": "Supported features",
"authoring.discussions.supportedFeatureList-mobile-show": "Show supported features",
"authoring.discussions.supportedFeatureList-mobile-hide": "Hide supported features",
"authoring.discussions.noApps": "There are no discussions providers available for your course.",
"authoring.discussions.nextButton": "Next",
"authoring.discussions.appFullSupport": "Full support",
"authoring.discussions.appBasicSupport": "Basic support",
"authoring.discussions.selectApp": "Select {appName}",
"authoring.discussions.appList.appName-legacy": "edX",
"authoring.discussions.appList.appDescription-legacy": "Start conversations with other learners, ask questions, and interact with other learners in the course.",
"authoring.discussions.appList.appName-openedx": "edX",
"authoring.discussions.appList.appDescription-openedx": "Start conversations with other learners, ask questions, and interact with other learners in the course.",
"authoring.discussions.appList.appName-piazza": "Piazza",
"authoring.discussions.appList.appDescription-piazza": "Piazza is designed to connect students, TAs, and professors so every student can get the help they need when they need it.",
"authoring.discussions.appList.appDescription-yellowdig": "Yellowdig offers educators a gameful learning digital solution to improve student engagement by building learning communities for any course modality.",
"authoring.discussions.appList.appDescription-inscribe": "InScribe leverages the power of community + artificial intelligence to connect individuals to the answers, resources, and people they need to succeed.",
"authoring.discussions.appList.appDescription-discourse": "Discourse is modern forum software for your community. Use it as a mailing list, discussion forum, long-form chat room, and more!",
"authoring.discussions.appList.appDescription-ed-discus": "Ed Discussion helps scale class communication in a beautiful and intuitive interface. Questions reach and benefit the whole class. Less emails, more time saved.",
"authoring.discussions.featureName-discussion-page": "Discussion page",
"authoring.discussions.featureName-embedded-course-sections": "Embedded course sections",
"authoring.discussions.featureName-advanced-in-context-discussion": "Advanced in context discussion",
"authoring.discussions.featureName-anonymous-posting": "Anonymous posting",
"authoring.discussions.featureName-automatic-learner-enrollment": "Automatic learner enrollment",
"authoring.discussions.featureName-blackout-discussion-dates": "Blackout discussion dates",
"authoring.discussions.featureName-community-ta-support": "Community TA support",
"authoring.discussions.featureName-course-cohort-support": "Course cohort support",
"authoring.discussions.featureName-direct-messages-from-instructors": "Direct messages from instructors",
"authoring.discussions.featureName-discussion-content-prompts": "Discussion content prompts",
"authoring.discussions.featureName-email-notifications": "Email notifications",
"authoring.discussions.featureName-graded-discussions": "Graded discussions",
"authoring.discussions.featureName-in-platform-notifications": "In-platform notifications",
"authoring.discussions.featureName-internationalization-support": "Internationalization support",
"authoring.discussions.featureName-lti-advanced-sharing-mode": "LTI advanced sharing",
"authoring.discussions.featureName-basic-configuration": "Basic configuration",
"authoring.discussions.featureName-primary-discussion-app-experience": "Primary discussion app experience",
"authoring.discussions.featureName-question-&-discussion-support": "Question & discussion support",
"authoring.discussions.featureName-report/flag-content-to-moderators": "Report content to moderators",
"authoring.discussions.featureName-research-data-events": "Research data events",
"authoring.discussions.featureName-simplified-in-context-discussion": "Simplified in-context discussion",
"authoring.discussions.featureName-user-mentions": "User mentions",
"authoring.discussions.featureName-wcag-2.1": "WCAG 2.1 support",
"authoring.discussions.wcag-2.0-support": "WCAG 2.0 support",
"authoring.discussions.basic-support": "Basic support",
"authoring.discussions.partial-support": "Partial support",
"authoring.discussions.full-support": "Full support",
"authoring.discussions.common-support": "Commonly requested",
"authoring.discussions.settings": "Settings",
"authoring.discussions.applyButton": "Apply",
"authoring.discussions.applyingButton": "Applying",
"authoring.discussions.appliedButton": "Applied",
"authoring.discussions.noProviderSwitchAfterCourseStarted": "Discussion provider can't be changed after course has started, please reach out to partner support.",
"authoring.discussions.providerSelection": "Provider selection",
"authoring.discussions.Incomplete": "Incomplete",
"course-authoring.pages-resources.notes.heading": "Configure notes",
"course-authoring.pages-resources.notes.enable-notes.label": "Notes",
"course-authoring.pages-resources.notes.enable-notes.help": "Learners can access their notes either in the body of the\n course of on a notes page. On the notes page, a learner can see all the\n notes made during the course. The page also contains links to the location\n of the notes in the course body.",
"course-authoring.pages-resources.notes.enable-notes.link": "Learn more about notes",
"authoring.live.bbb.selectPlan.label": "Select a plan",
"authoring.pagesAndResources.live.enableLive.heading": "Configure Live",
"authoring.pagesAndResources.live.enableLive.label": "Live",
"authoring.pagesAndResources.live.enableLive.help": "Schedule meetings and conduct live course sessions with learners.",
"authoring.pagesAndResources.live.enableLive.link": "Learn more about live",
"authoring.live.selectProvider": "Select a video conferencing tool",
"authoring.live.formInstructions": "Complete the fields below to set up your video conferencing tool.",
"authoring.live.consumerKey": "Consumer Key",
"authoring.live.consumerKey.required": "Consumer key is a required field",
"authoring.live.consumerSecret": "Consumer Secret",
"authoring.live.consumerSecret.required": "Consumer secret is a required field",
"authoring.live.launchUrl": "Launch URL",
"authoring.live.launchUrl.required": "Launch URL is a required field",
"authoring.live.launchEmail": "Launch Email",
"authoring.live.launchEmail.required": "Launch Email is a required field",
"authoring.live.provider.helpText": "This configuration will require sharing username and emails of learners and the course team with {providerName}.",
"authoring.live.requestPiiSharingEnable": "This configuration will require sharing usernames and emails of learners and the course team with {provider}. To access the LTI configuration for {provider}, please request your edX project coordinator to get PII sharing enabled for this course.",
"authoring.live.appDocInstructions.documentationLink": "General documentation",
"authoring.live.appDocInstructions.accessibilityDocumentationLink": "Accessibility documentation",
"authoring.live.appDocInstructions.configurationLink": "Configuration documentation",
"authoring.live.appDocInstructions.learnMoreLink": "Learn more about {providerName}",
"authoring.live.appDocInstructions.linkTextHeading": "External help and documentation",
"authoring.live.appDocInstructions.linkText": "{link}",
"authoring.live.appName-yellowdig": "Zoom",
"authoring.live.appName-googleMeet": "Google Meet",
"authoring.live.appName-microsoftTeams": "Microsoft Teams",
"authoring.live.appName-bigBlueButton": "BigBlueButton",
"authoring.live.requestPiiSharingEnableForBbb": "This configuration will require sharing usernames of learners and the course team with {provider}.",
"authoring.live.piiSharingEnableHelpText": "To enable this feature, contact your edX support team to enable PII sharing for this course.",
"authoring.live.freePlanMessage": "The free plan is pre-configured, and no additional configurations are required. By selecting the free plan, you are agreeing to Blindside Networks",
"authoring.live.privacyPolicy": "Privacy Policy.",
"course-authoring.pages-resources.heading": "Pages & Resources",
"course-authoring.pages-resources.resources.settings.button": "settings",
"course-authoring.pages-resources.viewLive.button": "View live",
"course-authoring.badge.enabled": "Enabled",
"authoring.proctoring.no": "No",
"authoring.proctoring.yes": "Yes",
"authoring.proctoring.support.text": "Support Page",
"authoring.proctoring.enableproctoredexams.label": "Proctored exams",
"authoring.proctoring.enableproctoredexams.help": "Enable and configure proctored exams in your course.",
"authoring.proctoring.enabled": "Enabled",
"authoring.proctoring.learn.more": "Learn more about proctoring",
"authoring.proctoring.provider.label": "Proctoring provider",
"authoring.proctoring.provider.help": "Select the proctoring provider you want to use for this course run.",
"authoring.proctoring.provider.help.aftercoursestart": "Proctoring provider cannot be modified after course start date.",
"authoring.proctoring.escalationemail.label": "Proctortrack escalation email",
"authoring.proctoring.escalationemail.help": "Provide an email address to be contacted by the support team for escalations (e.g. appeals, delayed reviews).",
"authoring.proctoring.escalationemail.error.blank": "The Proctortrack Escalation Email field cannot be empty if proctortrack is the selected provider.",
"authoring.proctoring.escalationemail.error.invalid": "The Proctortrack Escalation Email field is in the wrong format and is not valid.",
"authoring.proctoring.allowoptout.label": "Allow learners to opt out of proctoring on proctored exams",
"authoring.proctoring.createzendesk.label": "Create Zendesk tickets for suspicious attempts",
"authoring.proctoring.error.single": "There is 1 error in this form.",
"authoring.proctoring.escalationemail.error.multiple": "There are {numOfErrors} errors in this form.",
"authoring.proctoring.save": "Save",
"authoring.proctoring.saving": "Saving...",
"authoring.proctoring.cancel": "Cancel",
"authoring.proctoring.studio.link.text": "Go back to your course in Studio",
"authoring.proctoring.alert.success": "\n Proctored exam settings saved successfully. {studioCourseRunURL}.\n ",
"authoring.examsettings.alert.error": "\n We encountered a technical error while trying to save proctored exam settings.\n This might be a temporary issue, so please try again in a few minutes.\n If the problem persists,\n please go to the {support_link} for help.\n ",
"course-authoring.pages-resources.progress.heading": "Configure progress",
"course-authoring.pages-resources.progress.enable-progress.label": "Progress",
"course-authoring.pages-resources.progress.enable-progress.help": "As students work through graded assignments, scores\n will appear under the progress tab. The progress tab contains a chart of\n all graded assignments in the course, with a list of all assignments and\n scores below.",
"course-authoring.pages-resources.progress.enable-progress.link": "Learn more about progress",
"course-authoring.pages-resources.progress.enable-graph.label": "Enable progress graph",
"course-authoring.pages-resources.progress.enable-graph.help": "If enabled, students can view the progress graph",
"authoring.pagesAndResources.teams.heading": "Configure teams",
"authoring.pagesAndResources.teams.enableTeams.label": "Teams",
"authoring.pagesAndResources.teams.enableTeams.help": "Allow learners to work together on specific projects or activities.",
"authoring.pagesAndResources.teams.enableTeams.link": "Learn more about teams",
"authoring.pagesAndResources.teams.teamSize.heading": "Team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSize": "Max team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeHelp": "The maximum number of learners that can join a team",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeEmpty": "Enter max team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeInvalid": "Max team size must be a positive number larger than zero.",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeTooHigh": "Max team size cannot be greater than {max}",
"authoring.pagesAndResources.teams.groups.heading": "Groups",
"authoring.pagesAndResources.teams.groups.help": "Groups are spaces where learners can create or join teams.",
"authoring.pagesAndResources.teams.configureGroup.heading": "Configure group",
"authoring.pagesAndResources.teams.group.name.label": "Name",
"authoring.pagesAndResources.teams.group.name.help": "Choose a unique name for this group",
"authoring.pagesAndResources.teams.group.name.error.empty": "Enter a unique name for this group",
"authoring.pagesAndResources.teams.group.name.error.exists": "It looks like this name is already in use",
"authoring.pagesAndResources.teams.group.description.label": "Description",
"authoring.pagesAndResources.teams.group.description.help": "Enter details about this group",
"authoring.pagesAndResources.teams.group.description.error": "Enter a description for this group",
"authoring.pagesAndResources.teams.group.type.label": "Type",
"authoring.pagesAndResources.teams.group.type.help": "Control who can see, create and join teams",
"authoring.pagesAndResources.teams.group.types.open": "Open",
"authoring.pagesAndResources.teams.group.types.open.description": "Learners can create, join, leave, and see other teams",
"authoring.pagesAndResources.teams.group.types.public_managed": "Public managed",
"authoring.pagesAndResources.teams.group.types.public_managed.description": "Only course staff can control teams and memberships. Learners can see other teams.",
"authoring.pagesAndResources.teams.group.types.private_managed": "Private managed",
"authoring.pagesAndResources.teams.group.types.private_managed.description": "Only course staff can control teams, memberships, and see other teams",
"authoring.pagesAndResources.teams.group.maxSize.label": "Max team size (optional)",
"authoring.pagesAndResources.teams.group.maxSize.help": "Override the global max team size",
"authoring.pagesAndResources.teams.addGroup.button": "Add group",
"authoring.pagesAndResources.teams.group.delete": "Delete",
"authoring.pagesAndResources.teams.group.expand": "Expand group editor",
"authoring.pagesAndResources.teams.group.collapse": "Close group editor",
"authoring.pagesAndResources.teams.deleteGroup.initiateDelete": "Delete",
"authoring.pagesAndResources.teams.deleteGroup.cancel-delete.button": "Cancel",
"authoring.pagesAndResources.teams.deleteGroup.heading": "Delete this group?",
"authoring.pagesAndResources.teams.deleteGroup.body": "edX recommends that you do not delete groups once your course is running.\n Your group will no longer be visible in the LMS and learners will not be able to leave teams associated with it.\n Please delete learners from teams before deleting the associated group.",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.title": "No groups found",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.message": "Add one or more groups to enable teams.",
"course-authoring.pages-resources.wiki.heading": "Configure wiki",
"course-authoring.pages-resources.wiki.enable-wiki.label": "Wiki",
"course-authoring.pages-resources.wiki.enable-wiki.help": "The course wiki can be set up based on the needs of your\n course. Common uses might include sharing answers to course FAQs, sharing\n editable course information, or providing access to learner-created\n resources.",
"course-authoring.pages-resources.wiki.enable-wiki.link": "Learn more about the wiki",
"course-authoring.pages-resources.wiki.enable-public-wiki.label": "Enable public wiki access",
"course-authoring.pages-resources.wiki.enable-public-wiki.help": "If enabled, edX users can view the course wiki even when\n they're not enrolled in the course.",
"authoring.examsettings.enableproctoredexams.help": "If checked, proctored exams are enabled in your course.",
"authoring.examsettings.allowoptout.label": "Allow Opting Out of Proctored Exams",
"authoring.examsettings.allowoptout.help": "\n If this value is \"Yes\", learners can choose to take proctored exams without proctoring.\n If this value is \"No\", all learners must take the exam with proctoring.\n ",
"authoring.examsettings.provider.label": "Proctoring Provider",
"authoring.examsettings.escalationemail.label": "Proctortrack Escalation Email",
"authoring.examsettings.escalationemail.help": "\n Required if \"proctortrack\" is selected as your proctoring provider. Enter an email address to be\n contacted by the support team whenever there are escalations (e.g. appeals, delayed reviews, etc.).\n ",
"authoring.examsettings.createzendesk.label": "Create Zendesk Tickets for Suspicious Proctored Exam Attempts",
"authoring.examsettings.createzendesk.help": "If this value is \"Yes\", a Zendesk ticket will be created for suspicious proctored exam attempts.",
"authoring.examsettings.submit": "Submit",
"authoring.examsettings.alert.success": "\n Proctored exam settings saved successfully.\n You can go back to your course in Studio {studioCourseRunURL}.\n ",
"authoring.examsettings.allowoptout.no": "No",
"authoring.examsettings.allowoptout.yes": "Yes",
"authoring.examsettings.createzendesk.no": "No",
"authoring.examsettings.createzendesk.yes": "Yes",
"authoring.examsettings.support.text": "Support Page",
"authoring.examsettings.escalationemail.enableproctoredexams.label": "Enable Proctored Exams",
"authoring.examsettings.escalationemail.error.blank": "The Proctortrack Escalation Email field cannot be empty if proctortrack is the selected provider.",
"authoring.examsettings.escalationemail.error.invalid": "The Proctortrack Escalation Email field is in the wrong format and is not valid.",
"authoring.examsettings.error.single": "There is 1 error in this form.",
"authoring.examsettings.escalationemail.error.multiple": "There are {numOfErrors} errors in this form.",
"authoring.examsettings.provider.help": "Select the proctoring provider you want to use for this course run.",
"authoring.examsettings.provider.help.aftercoursestart": "Proctoring provider cannot be modified after course start date.",
"header.links.content": "Content",
"header.links.settings": "Settings",
"header.links.content.tools": "Tools",
"header.links.outline": "Outline",
"header.links.updates": "Updates",
"header.links.pages": "Pages & Resources",
"header.links.filesAndUploads": "Files & Uploads",
"header.links.textbooks": "Textbooks",
"header.links.videoUploads": "Video Uploads",
"header.links.scheduleAndDetails": "Schedule & Details",
"header.links.grading": "Grading",
"header.links.courseTeam": "Course Team",
"header.links.groupConfigurations": "Group Configurations",
"header.links.proctoredExamSettings": "Proctored Exam Settings",
"header.links.advancedSettings": "Advanced Settings",
"header.links.certificates": "Certificates",
"header.links.publisher": "Publisher",
"header.links.import": "Import",
"header.links.export": "Export",
"header.links.checklists": "Checklists",
"header.user.menu.studio": "Studio Home",
"header.user.menu.maintenance": "Maintenance",
"header.user.menu.logout": "Logout",
"header.label.account.menu": "Account Menu",
"header.label.account.menu.for": "Account menu for {username}",
"header.label.main.nav": "Main",
"header.label.main.menu": "Main Menu",
"header.label.main.header": "Main",
"header.label.secondary.nav": "Secondary",
"header.label.courseOutline": "Back to course outline in Studio"
}

View File

@@ -1 +0,0 @@
{}

View File

@@ -1 +1,352 @@
{}
{
"authoring.alert.error.connection": "We encountered a technical error when loading this page. This might be a temporary issue, so please try again in a few minutes. If the problem persists, please go to the {supportLink} for help.",
"authoring.loading": "Loading...",
"authoring.alert.error.permission": "You are not authorized to view this page. If you feel you should have access, please reach out to your course team admin to be given access.",
"authoring.alert.save.error.connection": "We encountered a technical error when applying changes. This might be a temporary issue, so please try again in a few minutes. If the problem persists, please go to the {supportLink} for help.",
"authoring.alert.support.text": "Support Page",
"course-authoring.pages-resources.app-settings-modal.button.cancel": "Cancel",
"course-authoring.pages-resources.app-settings-modal.button.save": "Save",
"course-authoring.pages-resources.app-settings-modal.button.saving": "Saving",
"course-authoring.pages-resources.app-settings-modal.button.saved": "Saved",
"course-authoring.pages-resources.app-settings-modal.button.retry": "Retry",
"course-authoring.pages-resources.app-settings-modal.badge.enabled": "Enabled",
"course-authoring.pages-resources.app-settings-modal.badge.disabled": "Disabled",
"course-authoring.pages-resources.app-settings-modal.save-error.title": "We couldn't apply your changes.",
"course-authoring.pages-resources.app-settings-modal.save-error.message": "Please check your entries and try again.",
"course-authoring.pages-resources.calculator.heading": "Configure calculator",
"course-authoring.pages-resources.calculator.enable-calculator.label": "Calculator",
"course-authoring.pages-resources.calculator.enable-calculator.help": "The calculator supports numbers, operators, constants,\n functions, and other mathematical concepts. When enabled, an icon to\n access the calculator appears on all pages in the body of your course.",
"course-authoring.pages-resources.calculator.enable-calculator.link": "Learn more about the calculator",
"authoring.discussions.documentationPage": "Visit the {name} documentation page",
"authoring.discussions.formInstructions": "Complete the fields below to set up your discussion tool.",
"authoring.discussions.consumerKey": "Consumer Key",
"authoring.discussions.consumerKey.required": "Consumer key is a required field",
"authoring.discussions.consumerSecret": "Consumer Secret",
"authoring.discussions.consumerSecret.required": "Consumer secret is a required field",
"authoring.discussions.launchUrl": "Launch URL",
"authoring.discussions.launchUrl.required": "Launch URL is a required field",
"authoring.discussions.stuffOnlyConfigInfo": "To enable {providerName} for your course, please contact their support team at {supportEmail} to learn more about pricing and usage.",
"authoring.discussions.stuffOnlyConfigGuide": "To fully configure {providerName} will also require sharing usernames and emails for learners and course team. Please contact your edX project coordinator to enable PII sharing for this course.",
"authoring.discussions.piiSharing": "Optionally share a user's username and/or email with the LTI provider:",
"authoring.discussions.piiShareUsername": "Share username",
"authoring.discussions.piiShareEmail": "Share email",
"authoring.discussions.appDocInstructions.contact": "Contact: {link}",
"authoring.discussions.appDocInstructions.documentationLink": "General documentation",
"authoring.discussions.appDocInstructions.accessibilityDocumentationLink": "Accessibility documentation",
"authoring.discussions.appDocInstructions.configurationLink": "Configuration documentation",
"authoring.discussions.appDocInstructions.learnMoreLink": "Learn more about {providerName}",
"authoring.discussions.appDocInstructions.linkTextHeading": "External help and documentation",
"authoring.discussions.appDocInstructions.linkText": "{link}",
"authoring.discussions.configurationChangeConsequences": "Students will lose access to any active or previous discussion posts for your course.",
"authoring.discussions.configure.app": "Configure {name}",
"authoring.discussions.configure": "Configure discussions",
"authoring.discussions.ok": "OK",
"authoring.discussions.cancel": "Cancel",
"authoring.discussions.confirm": "Confirm",
"authoring.discussions.confirmConfigurationChange": "Are you sure you want to change the discussion settings?",
"authoring.discussions.confirmEnableDiscussionsLabel": "Enable discussions on units in graded subsections?",
"authoring.discussions.cancelEnableDiscussionsLabel": "Disable discussions on units in graded subsections?",
"authoring.discussions.confirmEnableDiscussions": "Enabling this toggle will automatically enable discussion on all units in graded subsections, that are not timed exams.",
"authoring.discussions.cancelEnableDiscussions": "Disabling this toggle will automatically disable discussion on all units in graded subsections. Discussion topics containing at least 1 thread will be listed and accessible under “Archived” in Topics tab on the Discussions page.",
"authoring.discussions.backButton": "Back",
"authoring.discussions.saveButton": "Save",
"authoring.discussions.savingButton": "Saving",
"authoring.discussions.savedButton": "Saved",
"authoring.discussions.appConfigForm.appName-piazza": "Piazza",
"authoring.discussions.appConfigForm.appName-yellowdig": "Yellowdig",
"authoring.discussions.appConfigForm.appName-inscribe": "InScribe",
"authoring.discussions.appConfigForm.appName-discourse": "Discourse",
"authoring.discussions.appConfigForm.appName-ed-discuss": "Ed Discussion",
"authoring.discussions.appConfigForm.appName-legacy": "edX",
"authoring.discussions.appConfigForm.appName-openedx": "edX",
"authoring.discussions.builtIn.divisionByGroup": "Cohorts",
"authoring.discussions.builtIn.divideByCohorts.label": "Divide discussions by cohorts",
"authoring.discussions.builtIn.divideByCohorts.help": "Learners will only be able to view and respond to discussions posted by members of their cohort.",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.label": "Divide course-wide discussion topics",
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.help": "Choose which of your general course-wide discussion topics you would like to divide.",
"authoring.discussions.builtIn.divideGeneralTopic.label": "General",
"authoring.discussions.builtIn.divideQuestionsForTAsTopic.label": "Questions for the TAs",
"authoring.discussions.builtIn.cohortsEnabled.label": "To adjust these settings, enable cohorts on the ",
"authoring.discussions.builtIn.instructorDashboard.label": "instructor dashboard",
"authoring.discussions.builtIn.visibilityInContext": "Visibility of in-context discussions",
"authoring.discussions.builtIn.gradedUnitPages.label": "Enable discussions on units in graded subsections",
"authoring.discussions.builtIn.gradedUnitPages.help": "Allow learners to engage with discussion on all graded unit pages except timed exams.",
"authoring.discussions.builtIn.groupInContextSubsection.label": "Group in context discussion at the subsection level",
"authoring.discussions.builtIn.groupInContextSubsection.help": "Learners will be able to view any post in the sub-section no matter which unit page they are viewing. While this is not recommended, if your course has short learning sequences or low enrollment grouping may increase engagement.",
"authoring.discussions.builtIn.anonymousPosting": "Anonymous posting",
"authoring.discussions.builtIn.allowAnonymous.label": "Allow anonymous discussion posts",
"authoring.discussions.builtIn.allowAnonymous.help": "If enabled, learners can create posts that are anonymous to all users.",
"authoring.discussions.builtIn.allowAnonymousPeers.label": "Allow anonymous discussion posts to peers",
"authoring.discussions.builtIn.allowAnonymousPeers.help": "Learners will be able to post anonymously to other peers but all posts will be visible to course staff.",
"authoring.discussions.builtIn.reportedContentEmailNotifications": "Notifications",
"authoring.discussions.builtIn.reportedContentEmailNotifications.label": "Email notifications for reported content",
"authoring.discussions.builtIn.reportedContentEmailNotifications.help": "Discussion Admins, Moderators, Community TAs and Group Community TAs (only for their own cohort) will receive an email notification when content is reported.",
"authoring.discussions.discussionTopics": "Discussion topics",
"authoring.discussions.discussionTopics.label": "General discussion topics",
"authoring.discussions.discussionTopics.help": "Discussions can include general topics not contained to the course structure. All courses have a general topic by default.",
"authoring.discussions.discussionTopic.required": "Topic name is a required field",
"authoring.discussions.discussionTopic.alreadyExistError": "It looks like this name is already in use",
"authoring.discussions.addTopicButton": "Add topic",
"authoring.discussions.deleteButton": "Delete",
"authoring.discussions.cancelButton": "Cancel",
"authoring.discussions.discussionTopicDeletion.help": "edX recommends that you do not delete discussion topics once your course is running.",
"authoring.discussions.discussionTopicDeletion.label": "Delete this topic?",
"authoring.discussions.builtIn.renameGeneralTopic.label": "Rename general topic",
"authoring.discussions.generalTopicHelp.help": "This is the default discussion topic for your course.",
"authoring.discussions.builtIn.configureAdditionalTopic.label": "Configure topic",
"authoring.discussions.addTopicHelpText": "Choose a unique name for your topic",
"authoring.discussions.blackoutDates": "Discussion blackout dates",
"authoring.discussions.builtIn.blackoutDates.label": "Blackout dates",
"authoring.discussions.builtIn.blackoutDates.help": "If added, learners will not be able to post in discussions between these dates.",
"authoring.discussions.addBlackoutDatesButton": "Add blackout date range",
"authoring.discussions.builtIn.configureBlackoutDates.label": "Configure blackout date range",
"authoring.discussions.blackoutStartDate.help": "Enter a start date, e.g. 12/10/2023",
"authoring.discussions.blackoutEndDate.help": "Enter an end date, e.g. 12/17/2023",
"authoring.discussions.blackoutStartTime.help": "Enter a start time, e.g. 09:00 AM",
"authoring.discussions.blackoutEndTime.help": "Enter an end time, e.g. 05:00 PM",
"authoring.discussions.activeBlackoutDatesDeletion.help": "These blackout dates are currently active. If deleted, learners will be able to post in discussions during these dates. Are you sure you want to proceed?",
"authoring.discussions.blackoutDatesDeletion.help": "If deleted, learners will be able to post in discussions during these dates.",
"authoring.discussions.completeBlackoutDatesDeletion.help": "Are you sure you want to delete these blackout dates?",
"authoring.discussions.activeBlackoutDatesDeletion.label": "Delete active blackout dates?",
"authoring.discussions.blackoutDatesDeletion.label": "Delete blackout dates?",
"authoring.blackoutDates.delete": "Delete Blackout Dates",
"authoring.blackoutDates.status": "{status}",
"authoring.blackoutDates.startDate.required": "Start date is a required field",
"authoring.blackoutDates.endDate.required": "End date is a required field",
"authoring.blackoutDates.startDate.inPast": "Start date cannot be after end date",
"authoring.blackoutDates.endDate.inPast": "End date cannot be before start date",
"authoring.blackoutDates.startTime.inPast": "Start time cannot be after end time",
"authoring.blackoutDates.endTime.inPast": "End time cannot be before start time",
"authoring.blackoutDates.startTime.inValidFormat": "Enter a valid start time",
"authoring.blackoutDates.endTime.inValidFormat": "Enter a valid end time",
"authoring.blackoutDates.startDate.inValidFormat": "Enter a valid start Date",
"authoring.blackoutDates.endDate.inValidFormat": "Enter a valid end date",
"authoring.topics.delete": "Delete Topic",
"authoring.topics.expand": "Expand",
"authoring.topics.collapse": "Collapse",
"authoring.blackoutDates.start.date": "Start date",
"authoring.blackoutDates.start.time": "Start time (optional) ({zone})",
"authoring.blackoutDates.end.date": "End date",
"authoring.blackoutDates.end.time": "End time (optional) ({zone})",
"authoring.discussions.heading": "Select a discussion tool for this course",
"authoring.discussions.supportedFeatures": "Supported features",
"authoring.discussions.supportedFeatureList-mobile-show": "Show supported features",
"authoring.discussions.supportedFeatureList-mobile-hide": "Hide supported features",
"authoring.discussions.noApps": "There are no discussions providers available for your course.",
"authoring.discussions.nextButton": "Next",
"authoring.discussions.appFullSupport": "Full support",
"authoring.discussions.appBasicSupport": "Basic support",
"authoring.discussions.selectApp": "Select {appName}",
"authoring.discussions.appList.appName-legacy": "edX",
"authoring.discussions.appList.appDescription-legacy": "Start conversations with other learners, ask questions, and interact with other learners in the course.",
"authoring.discussions.appList.appName-openedx": "edX",
"authoring.discussions.appList.appDescription-openedx": "Start conversations with other learners, ask questions, and interact with other learners in the course.",
"authoring.discussions.appList.appName-piazza": "Piazza",
"authoring.discussions.appList.appDescription-piazza": "Piazza is designed to connect students, TAs, and professors so every student can get the help they need when they need it.",
"authoring.discussions.appList.appDescription-yellowdig": "Yellowdig offers educators a gameful learning digital solution to improve student engagement by building learning communities for any course modality.",
"authoring.discussions.appList.appDescription-inscribe": "InScribe leverages the power of community + artificial intelligence to connect individuals to the answers, resources, and people they need to succeed.",
"authoring.discussions.appList.appDescription-discourse": "Discourse is modern forum software for your community. Use it as a mailing list, discussion forum, long-form chat room, and more!",
"authoring.discussions.appList.appDescription-ed-discus": "Ed Discussion helps scale class communication in a beautiful and intuitive interface. Questions reach and benefit the whole class. Less emails, more time saved.",
"authoring.discussions.featureName-discussion-page": "Discussion page",
"authoring.discussions.featureName-embedded-course-sections": "Embedded course sections",
"authoring.discussions.featureName-advanced-in-context-discussion": "Advanced in context discussion",
"authoring.discussions.featureName-anonymous-posting": "Anonymous posting",
"authoring.discussions.featureName-automatic-learner-enrollment": "Automatic learner enrollment",
"authoring.discussions.featureName-blackout-discussion-dates": "Blackout discussion dates",
"authoring.discussions.featureName-community-ta-support": "Community TA support",
"authoring.discussions.featureName-course-cohort-support": "Course cohort support",
"authoring.discussions.featureName-direct-messages-from-instructors": "Direct messages from instructors",
"authoring.discussions.featureName-discussion-content-prompts": "Discussion content prompts",
"authoring.discussions.featureName-email-notifications": "Email notifications",
"authoring.discussions.featureName-graded-discussions": "Graded discussions",
"authoring.discussions.featureName-in-platform-notifications": "In-platform notifications",
"authoring.discussions.featureName-internationalization-support": "Internationalization support",
"authoring.discussions.featureName-lti-advanced-sharing-mode": "LTI advanced sharing",
"authoring.discussions.featureName-basic-configuration": "Basic configuration",
"authoring.discussions.featureName-primary-discussion-app-experience": "Primary discussion app experience",
"authoring.discussions.featureName-question-&-discussion-support": "Question & discussion support",
"authoring.discussions.featureName-report/flag-content-to-moderators": "Report content to moderators",
"authoring.discussions.featureName-research-data-events": "Research data events",
"authoring.discussions.featureName-simplified-in-context-discussion": "Simplified in-context discussion",
"authoring.discussions.featureName-user-mentions": "User mentions",
"authoring.discussions.featureName-wcag-2.1": "WCAG 2.1 support",
"authoring.discussions.wcag-2.0-support": "WCAG 2.0 support",
"authoring.discussions.basic-support": "Basic support",
"authoring.discussions.partial-support": "Partial support",
"authoring.discussions.full-support": "Full support",
"authoring.discussions.common-support": "Commonly requested",
"authoring.discussions.settings": "Settings",
"authoring.discussions.applyButton": "Apply",
"authoring.discussions.applyingButton": "Applying",
"authoring.discussions.appliedButton": "Applied",
"authoring.discussions.noProviderSwitchAfterCourseStarted": "Discussion provider can't be changed after course has started, please reach out to partner support.",
"authoring.discussions.providerSelection": "Provider selection",
"authoring.discussions.Incomplete": "Incomplete",
"course-authoring.pages-resources.notes.heading": "Configure notes",
"course-authoring.pages-resources.notes.enable-notes.label": "Notes",
"course-authoring.pages-resources.notes.enable-notes.help": "Learners can access their notes either in the body of the\n course of on a notes page. On the notes page, a learner can see all the\n notes made during the course. The page also contains links to the location\n of the notes in the course body.",
"course-authoring.pages-resources.notes.enable-notes.link": "Learn more about notes",
"authoring.live.bbb.selectPlan.label": "Select a plan",
"authoring.pagesAndResources.live.enableLive.heading": "Configure Live",
"authoring.pagesAndResources.live.enableLive.label": "Live",
"authoring.pagesAndResources.live.enableLive.help": "Schedule meetings and conduct live course sessions with learners.",
"authoring.pagesAndResources.live.enableLive.link": "Learn more about live",
"authoring.live.selectProvider": "Select a video conferencing tool",
"authoring.live.formInstructions": "Complete the fields below to set up your video conferencing tool.",
"authoring.live.consumerKey": "Consumer Key",
"authoring.live.consumerKey.required": "Consumer key is a required field",
"authoring.live.consumerSecret": "Consumer Secret",
"authoring.live.consumerSecret.required": "Consumer secret is a required field",
"authoring.live.launchUrl": "Launch URL",
"authoring.live.launchUrl.required": "Launch URL is a required field",
"authoring.live.launchEmail": "Launch Email",
"authoring.live.launchEmail.required": "Launch Email is a required field",
"authoring.live.provider.helpText": "This configuration will require sharing username and emails of learners and the course team with {providerName}.",
"authoring.live.requestPiiSharingEnable": "This configuration will require sharing usernames and emails of learners and the course team with {provider}. To access the LTI configuration for {provider}, please request your edX project coordinator to get PII sharing enabled for this course.",
"authoring.live.appDocInstructions.documentationLink": "General documentation",
"authoring.live.appDocInstructions.accessibilityDocumentationLink": "Accessibility documentation",
"authoring.live.appDocInstructions.configurationLink": "Configuration documentation",
"authoring.live.appDocInstructions.learnMoreLink": "Learn more about {providerName}",
"authoring.live.appDocInstructions.linkTextHeading": "External help and documentation",
"authoring.live.appDocInstructions.linkText": "{link}",
"authoring.live.appName-yellowdig": "Zoom",
"authoring.live.appName-googleMeet": "Google Meet",
"authoring.live.appName-microsoftTeams": "Microsoft Teams",
"authoring.live.appName-bigBlueButton": "BigBlueButton",
"authoring.live.requestPiiSharingEnableForBbb": "This configuration will require sharing usernames of learners and the course team with {provider}.",
"authoring.live.piiSharingEnableHelpText": "To enable this feature, contact your edX support team to enable PII sharing for this course.",
"authoring.live.freePlanMessage": "The free plan is pre-configured, and no additional configurations are required. By selecting the free plan, you are agreeing to Blindside Networks",
"authoring.live.privacyPolicy": "Privacy Policy.",
"course-authoring.pages-resources.heading": "Pages & Resources",
"course-authoring.pages-resources.resources.settings.button": "settings",
"course-authoring.pages-resources.viewLive.button": "View live",
"course-authoring.badge.enabled": "Enabled",
"authoring.proctoring.no": "No",
"authoring.proctoring.yes": "Yes",
"authoring.proctoring.support.text": "Support Page",
"authoring.proctoring.enableproctoredexams.label": "Proctored exams",
"authoring.proctoring.enableproctoredexams.help": "Enable and configure proctored exams in your course.",
"authoring.proctoring.enabled": "Enabled",
"authoring.proctoring.learn.more": "Learn more about proctoring",
"authoring.proctoring.provider.label": "Proctoring provider",
"authoring.proctoring.provider.help": "Select the proctoring provider you want to use for this course run.",
"authoring.proctoring.provider.help.aftercoursestart": "Proctoring provider cannot be modified after course start date.",
"authoring.proctoring.escalationemail.label": "Proctortrack escalation email",
"authoring.proctoring.escalationemail.help": "Provide an email address to be contacted by the support team for escalations (e.g. appeals, delayed reviews).",
"authoring.proctoring.escalationemail.error.blank": "The Proctortrack Escalation Email field cannot be empty if proctortrack is the selected provider.",
"authoring.proctoring.escalationemail.error.invalid": "The Proctortrack Escalation Email field is in the wrong format and is not valid.",
"authoring.proctoring.allowoptout.label": "Allow learners to opt out of proctoring on proctored exams",
"authoring.proctoring.createzendesk.label": "Create Zendesk tickets for suspicious attempts",
"authoring.proctoring.error.single": "There is 1 error in this form.",
"authoring.proctoring.escalationemail.error.multiple": "There are {numOfErrors} errors in this form.",
"authoring.proctoring.save": "Save",
"authoring.proctoring.saving": "Saving...",
"authoring.proctoring.cancel": "Cancel",
"authoring.proctoring.studio.link.text": "Go back to your course in Studio",
"authoring.proctoring.alert.success": "\n Proctored exam settings saved successfully. {studioCourseRunURL}.\n ",
"authoring.examsettings.alert.error": "\n We encountered a technical error while trying to save proctored exam settings.\n This might be a temporary issue, so please try again in a few minutes.\n If the problem persists,\n please go to the {support_link} for help.\n ",
"course-authoring.pages-resources.progress.heading": "Configure progress",
"course-authoring.pages-resources.progress.enable-progress.label": "Progress",
"course-authoring.pages-resources.progress.enable-progress.help": "As students work through graded assignments, scores\n will appear under the progress tab. The progress tab contains a chart of\n all graded assignments in the course, with a list of all assignments and\n scores below.",
"course-authoring.pages-resources.progress.enable-progress.link": "Learn more about progress",
"course-authoring.pages-resources.progress.enable-graph.label": "Enable progress graph",
"course-authoring.pages-resources.progress.enable-graph.help": "If enabled, students can view the progress graph",
"authoring.pagesAndResources.teams.heading": "Configure teams",
"authoring.pagesAndResources.teams.enableTeams.label": "Teams",
"authoring.pagesAndResources.teams.enableTeams.help": "Allow learners to work together on specific projects or activities.",
"authoring.pagesAndResources.teams.enableTeams.link": "Learn more about teams",
"authoring.pagesAndResources.teams.teamSize.heading": "Team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSize": "Max team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeHelp": "The maximum number of learners that can join a team",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeEmpty": "Enter max team size",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeInvalid": "Max team size must be a positive number larger than zero.",
"authoring.pagesAndResources.teams.teamSize.maxTeamSizeTooHigh": "Max team size cannot be greater than {max}",
"authoring.pagesAndResources.teams.groups.heading": "Groups",
"authoring.pagesAndResources.teams.groups.help": "Groups are spaces where learners can create or join teams.",
"authoring.pagesAndResources.teams.configureGroup.heading": "Configure group",
"authoring.pagesAndResources.teams.group.name.label": "Name",
"authoring.pagesAndResources.teams.group.name.help": "Choose a unique name for this group",
"authoring.pagesAndResources.teams.group.name.error.empty": "Enter a unique name for this group",
"authoring.pagesAndResources.teams.group.name.error.exists": "It looks like this name is already in use",
"authoring.pagesAndResources.teams.group.description.label": "Description",
"authoring.pagesAndResources.teams.group.description.help": "Enter details about this group",
"authoring.pagesAndResources.teams.group.description.error": "Enter a description for this group",
"authoring.pagesAndResources.teams.group.type.label": "Type",
"authoring.pagesAndResources.teams.group.type.help": "Control who can see, create and join teams",
"authoring.pagesAndResources.teams.group.types.open": "Open",
"authoring.pagesAndResources.teams.group.types.open.description": "Learners can create, join, leave, and see other teams",
"authoring.pagesAndResources.teams.group.types.public_managed": "Public managed",
"authoring.pagesAndResources.teams.group.types.public_managed.description": "Only course staff can control teams and memberships. Learners can see other teams.",
"authoring.pagesAndResources.teams.group.types.private_managed": "Private managed",
"authoring.pagesAndResources.teams.group.types.private_managed.description": "Only course staff can control teams, memberships, and see other teams",
"authoring.pagesAndResources.teams.group.maxSize.label": "Max team size (optional)",
"authoring.pagesAndResources.teams.group.maxSize.help": "Override the global max team size",
"authoring.pagesAndResources.teams.addGroup.button": "Add group",
"authoring.pagesAndResources.teams.group.delete": "Delete",
"authoring.pagesAndResources.teams.group.expand": "Expand group editor",
"authoring.pagesAndResources.teams.group.collapse": "Close group editor",
"authoring.pagesAndResources.teams.deleteGroup.initiateDelete": "Delete",
"authoring.pagesAndResources.teams.deleteGroup.cancel-delete.button": "Cancel",
"authoring.pagesAndResources.teams.deleteGroup.heading": "Delete this group?",
"authoring.pagesAndResources.teams.deleteGroup.body": "edX recommends that you do not delete groups once your course is running.\n Your group will no longer be visible in the LMS and learners will not be able to leave teams associated with it.\n Please delete learners from teams before deleting the associated group.",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.title": "No groups found",
"authoring.pagesAndResources.teams.enableGroups.error.noGroupsFound.message": "Add one or more groups to enable teams.",
"course-authoring.pages-resources.wiki.heading": "Configure wiki",
"course-authoring.pages-resources.wiki.enable-wiki.label": "Wiki",
"course-authoring.pages-resources.wiki.enable-wiki.help": "The course wiki can be set up based on the needs of your\n course. Common uses might include sharing answers to course FAQs, sharing\n editable course information, or providing access to learner-created\n resources.",
"course-authoring.pages-resources.wiki.enable-wiki.link": "Learn more about the wiki",
"course-authoring.pages-resources.wiki.enable-public-wiki.label": "Enable public wiki access",
"course-authoring.pages-resources.wiki.enable-public-wiki.help": "If enabled, edX users can view the course wiki even when\n they're not enrolled in the course.",
"authoring.examsettings.enableproctoredexams.help": "If checked, proctored exams are enabled in your course.",
"authoring.examsettings.allowoptout.label": "Allow Opting Out of Proctored Exams",
"authoring.examsettings.allowoptout.help": "\n If this value is \"Yes\", learners can choose to take proctored exams without proctoring.\n If this value is \"No\", all learners must take the exam with proctoring.\n ",
"authoring.examsettings.provider.label": "Proctoring Provider",
"authoring.examsettings.escalationemail.label": "Proctortrack Escalation Email",
"authoring.examsettings.escalationemail.help": "\n Required if \"proctortrack\" is selected as your proctoring provider. Enter an email address to be\n contacted by the support team whenever there are escalations (e.g. appeals, delayed reviews, etc.).\n ",
"authoring.examsettings.createzendesk.label": "Create Zendesk Tickets for Suspicious Proctored Exam Attempts",
"authoring.examsettings.createzendesk.help": "If this value is \"Yes\", a Zendesk ticket will be created for suspicious proctored exam attempts.",
"authoring.examsettings.submit": "Submit",
"authoring.examsettings.alert.success": "\n Proctored exam settings saved successfully.\n You can go back to your course in Studio {studioCourseRunURL}.\n ",
"authoring.examsettings.allowoptout.no": "No",
"authoring.examsettings.allowoptout.yes": "Yes",
"authoring.examsettings.createzendesk.no": "No",
"authoring.examsettings.createzendesk.yes": "Yes",
"authoring.examsettings.support.text": "Support Page",
"authoring.examsettings.escalationemail.enableproctoredexams.label": "Enable Proctored Exams",
"authoring.examsettings.escalationemail.error.blank": "The Proctortrack Escalation Email field cannot be empty if proctortrack is the selected provider.",
"authoring.examsettings.escalationemail.error.invalid": "The Proctortrack Escalation Email field is in the wrong format and is not valid.",
"authoring.examsettings.error.single": "There is 1 error in this form.",
"authoring.examsettings.escalationemail.error.multiple": "There are {numOfErrors} errors in this form.",
"authoring.examsettings.provider.help": "Select the proctoring provider you want to use for this course run.",
"authoring.examsettings.provider.help.aftercoursestart": "Proctoring provider cannot be modified after course start date.",
"header.links.content": "Content",
"header.links.settings": "Settings",
"header.links.content.tools": "Tools",
"header.links.outline": "Outline",
"header.links.updates": "Updates",
"header.links.pages": "Pages & Resources",
"header.links.filesAndUploads": "Files & Uploads",
"header.links.textbooks": "Textbooks",
"header.links.videoUploads": "Video Uploads",
"header.links.scheduleAndDetails": "Schedule & Details",
"header.links.grading": "Grading",
"header.links.courseTeam": "Course Team",
"header.links.groupConfigurations": "Group Configurations",
"header.links.proctoredExamSettings": "Proctored Exam Settings",
"header.links.advancedSettings": "Advanced Settings",
"header.links.certificates": "Certificates",
"header.links.publisher": "Publisher",
"header.links.import": "Import",
"header.links.export": "Export",
"header.links.checklists": "Checklists",
"header.user.menu.studio": "Studio Home",
"header.user.menu.maintenance": "Maintenance",
"header.user.menu.logout": "Logout",
"header.label.account.menu": "Account Menu",
"header.label.account.menu.for": "Account menu for {username}",
"header.label.main.nav": "Main",
"header.label.main.menu": "Main Menu",
"header.label.main.header": "Main",
"header.label.secondary.nav": "Secondary",
"header.label.courseOutline": "Back to course outline in Studio"
}

View File

@@ -42,7 +42,12 @@
"authoring.discussions.configure": "Configure discussions",
"authoring.discussions.ok": "OK",
"authoring.discussions.cancel": "Cancel",
"authoring.discussions.confirm": "Confirm",
"authoring.discussions.confirmConfigurationChange": "Are you sure you want to change the discussion settings?",
"authoring.discussions.confirmEnableDiscussionsLabel": "Enable discussions on units in graded subsections?",
"authoring.discussions.cancelEnableDiscussionsLabel": "Disable discussions on units in graded subsections?",
"authoring.discussions.confirmEnableDiscussions": "Enabling this toggle will automatically enable discussion on all units in graded subsections, that are not timed exams.",
"authoring.discussions.cancelEnableDiscussions": "Disabling this toggle will automatically disable discussion on all units in graded subsections. Discussion topics containing at least 1 thread will be listed and accessible under “Archived” in Topics tab on the Discussions page.",
"authoring.discussions.backButton": "Back",
"authoring.discussions.saveButton": "Save",
"authoring.discussions.savingButton": "Saving",
@@ -61,15 +66,13 @@
"authoring.discussions.builtIn.divideCourseTopicsByCohorts.help": "Choose which of your general course-wide discussion topics you would like to divide.",
"authoring.discussions.builtIn.divideGeneralTopic.label": "General",
"authoring.discussions.builtIn.divideQuestionsForTAsTopic.label": "Questions for the TAs",
"authoring.discussions.builtIn.cohortsEnabled.label": "To adjust these settings, enable cohorts on the ",
"authoring.discussions.builtIn.instructorDashboard.label": "instructor dashboard",
"authoring.discussions.builtIn.visibilityInContext": "Visibility of in-context discussions",
"authoring.discussions.builtIn.inContextDiscussion.label": "In-context discussion",
"authoring.discussions.builtIn.inContextDiscussion.help": "Learners will be able to view or hide a discussion side panel to engage with discussion on the course unit page.",
"authoring.discussions.builtIn.gradedUnitPages.label": "Graded unit pages",
"authoring.discussions.builtIn.gradedUnitPages.label": "Enable discussions on units in graded subsections",
"authoring.discussions.builtIn.gradedUnitPages.help": "Allow learners to engage with discussion on all graded unit pages except timed exams.",
"authoring.discussions.builtIn.groupInContextSubsection.label": "Group in context discussion at the subsection level",
"authoring.discussions.builtIn.groupInContextSubsection.help": "Learners will be able to view any post in the sub-section no matter which unit page they are viewing. While this is not recommended, if your course has short learning sequences or low enrollment grouping may increase engagement.",
"authoring.discussions.builtIn.allowUnitLevelVisibility.label": "Allow visibility configuration for each course unit",
"authoring.discussions.builtIn.allowUnitLevelVisibility.help": "With this advanced setting enabled you will be able to override the global visibility setting and turn discussions on or off for each unit from the course outline view..",
"authoring.discussions.builtIn.anonymousPosting": "Anonymous posting",
"authoring.discussions.builtIn.allowAnonymous.label": "Allow anonymous discussion posts",
"authoring.discussions.builtIn.allowAnonymous.help": "If enabled, learners can create posts that are anonymous to all users.",
@@ -183,6 +186,7 @@
"course-authoring.pages-resources.notes.enable-notes.label": "Notes",
"course-authoring.pages-resources.notes.enable-notes.help": "Learners can access their notes either in the body of the\n course of on a notes page. On the notes page, a learner can see all the\n notes made during the course. The page also contains links to the location\n of the notes in the course body.",
"course-authoring.pages-resources.notes.enable-notes.link": "Learn more about notes",
"authoring.live.bbb.selectPlan.label": "Select a plan",
"authoring.pagesAndResources.live.enableLive.heading": "Configure Live",
"authoring.pagesAndResources.live.enableLive.label": "Live",
"authoring.pagesAndResources.live.enableLive.help": "Schedule meetings and conduct live course sessions with learners.",
@@ -208,6 +212,11 @@
"authoring.live.appName-yellowdig": "Zoom",
"authoring.live.appName-googleMeet": "Google Meet",
"authoring.live.appName-microsoftTeams": "Microsoft Teams",
"authoring.live.appName-bigBlueButton": "BigBlueButton",
"authoring.live.requestPiiSharingEnableForBbb": "This configuration will require sharing usernames of learners and the course team with {provider}.",
"authoring.live.piiSharingEnableHelpText": "To enable this feature, contact your edX support team to enable PII sharing for this course.",
"authoring.live.freePlanMessage": "The free plan is pre-configured, and no additional configurations are required. By selecting the free plan, you are agreeing to Blindside Networks",
"authoring.live.privacyPolicy": "Privacy Policy.",
"course-authoring.pages-resources.heading": "Pages & Resources",
"course-authoring.pages-resources.resources.settings.button": "settings",
"course-authoring.pages-resources.viewLive.button": "View live",

View File

@@ -47,9 +47,11 @@ initialize({
SUPPORT_URL: process.env.SUPPORT_URL || null,
SUPPORT_EMAIL: process.env.SUPPORT_EMAIL || null,
LEARNING_BASE_URL: process.env.LEARNING_BASE_URL,
EXAMS_BASE_URL: process.env.EXAMS_BASE_URL || null,
CALCULATOR_HELP_URL: process.env.CALCULATOR_HELP_URL || null,
ENABLE_PROGRESS_GRAPH_SETTINGS: process.env.ENABLE_PROGRESS_GRAPH_SETTINGS || 'false',
ENABLE_TEAM_TYPE_SETTING: process.env.ENABLE_TEAM_TYPE_SETTING === 'true',
BBB_LEARN_MORE_URL: process.env.BBB_LEARN_MORE_URL || '',
}, 'CourseAuthoringConfig');
},
},

View File

@@ -8,10 +8,9 @@ ensureConfig([
'STUDIO_BASE_URL',
], 'Course Apps API service');
const apiBaseUrl = getConfig().STUDIO_BASE_URL;
const courseAppsApiUrl = `${apiBaseUrl}/api/course_apps/v1/apps`;
const courseAdvancedSettingsApiUrl = `${apiBaseUrl}/api/contentstore/v0/advanced_settings`;
const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL;
const getCourseAppsApiUrl = () => `${getApiBaseUrl()}/api/course_apps/v1/apps`;
const getCourseAdvancedSettingsApiUrl = () => `${getApiBaseUrl()}/api/contentstore/v0/advanced_settings`;
/**
* Fetches the course apps installed for provided course
@@ -20,7 +19,7 @@ const courseAdvancedSettingsApiUrl = `${apiBaseUrl}/api/contentstore/v0/advanced
*/
export async function getCourseApps(courseId) {
const { data } = await getAuthenticatedHttpClient()
.get(`${courseAppsApiUrl}/${courseId}`);
.get(`${getCourseAppsApiUrl()}/${courseId}`);
return camelCaseObject(data);
}
@@ -33,7 +32,7 @@ export async function getCourseApps(courseId) {
export async function updateCourseApp(courseId, appId, state) {
await getAuthenticatedHttpClient()
.patch(
`${courseAppsApiUrl}/${courseId}`,
`${getCourseAppsApiUrl()}/${courseId}`,
{
id: appId,
enabled: state,
@@ -49,7 +48,7 @@ export async function updateCourseApp(courseId, appId, state) {
*/
export async function getCourseAdvancedSettings(courseId, settings) {
const { data } = await getAuthenticatedHttpClient()
.get(`${courseAdvancedSettingsApiUrl}/${courseId}`, { filter_fields: settings.map(snakeCase).join(',') });
.get(`${getCourseAdvancedSettingsApiUrl()}/${courseId}`, { filter_fields: settings.map(snakeCase).join(',') });
return camelCaseObject(data);
}
@@ -62,6 +61,6 @@ export async function getCourseAdvancedSettings(courseId, settings) {
*/
export async function updateCourseAdvancedSettings(courseId, setting, value) {
const { data } = await getAuthenticatedHttpClient()
.patch(`${courseAdvancedSettingsApiUrl}/${courseId}`, { [snakeCase(setting)]: { value } });
.patch(`${getCourseAdvancedSettingsApiUrl()}/${courseId}`, { [snakeCase(setting)]: { value } });
return camelCaseObject(data);
}

View File

@@ -25,19 +25,19 @@ function OpenedXConfigForm({
onSubmit, formRef, intl, legacy,
}) {
const {
selectedAppId, enableInContext, enableGradedUnits, unitLevelVisibility, discussionTopicIds, divideDiscussionIds,
selectedAppId, enableGradedUnits, discussionTopicIds, divideDiscussionIds,
} = useSelector(state => state.discussions);
const appConfigObj = useModel('appConfigs', selectedAppId);
const discussionTopicsModel = useModels('discussionTopics', discussionTopicIds);
const legacyAppConfig = {
...(appConfigObj || {}),
divideDiscussionIds,
enableInContext,
enableInContext: true,
enableGradedUnits,
unitLevelVisibility,
unitLevelVisibility: true,
allowAnonymousPostsPeers: appConfigObj?.allowAnonymousPostsPeers || false,
reportedContentEmailNotifications: appConfigObj?.reportedContentEmailNotifications || false,
enableReportedContentEmailNotifications: appConfigObj?.enableReportedContentEmailNotifications || false,
enableReportedContentEmailNotifications: Boolean(appConfigObj?.enableReportedContentEmailNotifications) || false,
blackoutDates: appConfigObj?.blackoutDates || [],
discussionTopics: discussionTopicsModel || [],
divideByCohorts: appConfigObj?.divideByCohorts || false,
@@ -48,10 +48,8 @@ function OpenedXConfigForm({
const [validDiscussionTopics, setValidDiscussionTopics] = useState(discussionTopicsModel);
// These fields are only used for the new provider and aren't supported for legacy.
const additionalFields = legacy ? {} : {
enableInContext: Yup.bool().default(true),
enabledGradedUnits: Yup.bool().default(false),
groupAtSubsection: Yup.bool().default(false),
unitLevelVisibility: Yup.bool().default(false),
};
const validationSchema = Yup.object().shape({
blackoutDates: Yup.array(

View File

@@ -41,15 +41,16 @@ const defaultAppConfig = (divideDiscussionIds = []) => ({
],
divideDiscussionIds,
enableGradedUnits: undefined,
enableInContext: undefined,
enableInContext: true,
groupAtSubsection: false,
unitLevelVisibility: undefined,
unitLevelVisibility: true,
allowAnonymousPosts: false,
allowAnonymousPostsPeers: false,
reportedContentEmailNotifications: false,
enableReportedContentEmailNotifications: false,
allowDivisionByUnit: false,
blackoutDates: [],
cohortsEnabled: false,
});
describe('OpenedXConfigForm', () => {
let axiosMock;
@@ -109,7 +110,6 @@ describe('OpenedXConfigForm', () => {
expect(queryByText(container, messages.visibilityInContext.defaultMessage)).toBeInTheDocument();
expect(queryByText(container, messages.gradedUnitPagesLabel.defaultMessage)).toBeInTheDocument();
expect(queryByText(container, messages.groupInContextSubsectionLabel.defaultMessage)).toBeInTheDocument();
expect(queryByText(container, messages.allowUnitLevelVisibilityLabel.defaultMessage)).toBeInTheDocument();
});
test('calls onSubmit when the formRef is submitted', async () => {
@@ -139,17 +139,20 @@ describe('OpenedXConfigForm', () => {
await mockStore({
...legacyApiResponse,
plugin_configuration: {
...legacyApiResponse.plugin_configuration,
...legacyApiResponse.plugin_configuration,
reported_content_email_notifications_flag: true,
divided_course_wide_discussions: [],
available_division_schemes: [],
},
});
createComponent();
const { divideDiscussionIds } = defaultAppConfig(['13f106c6-6735-4e84-b097-0456cff55960', 'course']);
// DivisionByGroupFields
expect(container.querySelector('#alert')).toBeInTheDocument();
expect(container.querySelector('#divideByCohorts')).toBeInTheDocument();
expect(container.querySelector('#divideByCohorts')).not.toBeChecked();
expect(container.querySelector('#divideByCohorts')).toBeDisabled();
expect(container.querySelector('#divideCourseTopicsByCohorts')).not.toBeInTheDocument();
divideDiscussionIds.forEach(id => expect(
@@ -180,6 +183,7 @@ describe('OpenedXConfigForm', () => {
reported_content_email_notifications_flag: true,
always_divide_inline_discussions: true,
divided_course_wide_discussions: [],
available_division_schemes: ['cohorts'],
},
});
createComponent();
@@ -187,14 +191,10 @@ describe('OpenedXConfigForm', () => {
// DivisionByGroupFields
expect(container.querySelector('#divideByCohorts')).toBeInTheDocument();
expect(container.querySelector('#divideByCohorts')).toBeChecked();
expect(container.querySelector('#divideByCohorts')).not.toBeChecked();
expect(
container.querySelector('#divideCourseTopicsByCohorts'),
).toBeInTheDocument();
expect(
container.querySelector('#divideCourseTopicsByCohorts'),
).not.toBeChecked();
).not.toBeInTheDocument();
divideDiscussionIds.forEach(id => expect(
container.querySelector(`#checkbox-${id}`),
).not.toBeInTheDocument());
@@ -230,13 +230,10 @@ describe('OpenedXConfigForm', () => {
// DivisionByGroupFields
expect(container.querySelector('#divideByCohorts')).toBeInTheDocument();
expect(container.querySelector('#divideByCohorts')).toBeChecked();
expect(container.querySelector('#divideCourseTopicsByCohorts')).toBeInTheDocument();
expect(container.querySelector('#divideCourseTopicsByCohorts')).toBeChecked();
expect(container.querySelector('#divideByCohorts')).not.toBeChecked();
expect(container.querySelector('#divideCourseTopicsByCohorts')).not.toBeInTheDocument();
divideDiscussionIds.forEach(id => {
expect(container.querySelector(`#checkbox-${id}`)).toBeInTheDocument();
expect(container.querySelector(`#checkbox-${id}`)).toBeChecked();
expect(container.querySelector(`#checkbox-${id}`)).not.toBeInTheDocument();
});
});

View File

@@ -1,8 +1,12 @@
import React, { useEffect, useContext } from 'react';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Form, TransitionReplace } from '@edx/paragon';
import {
Form, TransitionReplace, Hyperlink, Alert,
} from '@edx/paragon';
import { AppContext } from '@edx/frontend-platform/react';
import { FieldArray, useFormikContext } from 'formik';
import _ from 'lodash';
import { useParams } from 'react-router-dom';
import FormSwitchGroup from '../../../../../generic/FormSwitchGroup';
import messages from '../../messages';
import AppConfigFormDivider from './AppConfigFormDivider';
@@ -21,8 +25,13 @@ const DivisionByGroupFields = ({ intl }) => {
discussionTopics,
divideByCohorts,
divideCourseTopicsByCohorts,
cohortsEnabled,
} = appConfig;
const { courseId } = useParams();
const { config } = useContext(AppContext);
const learningCourseURL = `${config.LMS_BASE_URL}/courses/${courseId}/instructor`;
useEffect(() => {
if (divideByCohorts) {
if (!divideCourseTopicsByCohorts && _.size(discussionTopics) !== _.size(divideDiscussionIds)) {
@@ -56,20 +65,30 @@ const DivisionByGroupFields = ({ intl }) => {
return (
<>
<h5 className="text-gray-500 mb-2 mt-4">
<h5 className="text-gray-500 mb-4 mt-4">
{intl.formatMessage(messages.divisionByGroup)}
</h5>
{!cohortsEnabled
&& (
<Alert className="bg-light-200 font-weight-normal h5" id="alert">
{intl.formatMessage(messages.cohortsEnabled)}
<Hyperlink destination={learningCourseURL} target="_blank">
{intl.formatMessage(messages.instructorDashboard)}
</Hyperlink>
</Alert>
)}
<FormSwitchGroup
onChange={handleChange}
className="mt-2"
onBlur={handleBlur}
id="divideByCohorts"
checked={divideByCohorts}
checked={cohortsEnabled === false ? cohortsEnabled : divideByCohorts}
label={intl.formatMessage(messages.divideByCohortsLabel)}
helpText={intl.formatMessage(messages.divideByCohortsHelp)}
disabled={!cohortsEnabled}
/>
<TransitionReplace>
{divideByCohorts ? (
{(divideByCohorts && cohortsEnabled) ? (
<React.Fragment key="open">
<AppConfigFormDivider />
<FormSwitchGroup

View File

@@ -1,10 +1,11 @@
import React from 'react';
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { TransitionReplace } from '@edx/paragon';
import { useFormikContext } from 'formik';
import FormSwitchGroup from '../../../../../generic/FormSwitchGroup';
import messages from '../../messages';
import AppConfigFormDivider from './AppConfigFormDivider';
import ConfirmationPopup from '../../../../../generic/ConfirmationPopup';
function InContextDiscussionFields({
onBlur,
@@ -12,54 +13,54 @@ function InContextDiscussionFields({
intl,
values,
}) {
const {
setFieldValue,
} = useFormikContext();
const [showPopup, setShowPopup] = useState(false);
const handleConfirmation = () => {
setFieldValue('enableGradedUnits', !values.enableGradedUnits);
setShowPopup(false);
};
return (
<>
<h5 className="text-gray-500 mt-4">{intl.formatMessage(messages.visibilityInContext)}</h5>
{showPopup
? (
<ConfirmationPopup
label={values.enableGradedUnits
? intl.formatMessage(messages.cancelEnableDiscussionsLabel)
: intl.formatMessage(messages.confirmEnableDiscussionsLabel)}
bodyText={values.enableGradedUnits
? intl.formatMessage(messages.cancelEnableDiscussions)
: intl.formatMessage(messages.confirmEnableDiscussions)}
onConfirm={handleConfirmation}
confirmLabel={intl.formatMessage(messages.confirm)}
onCancel={() => setShowPopup(false)}
cancelLabel={intl.formatMessage(messages.cancelButton)}
/>
)
: (
<FormSwitchGroup
onChange={() => setShowPopup(true)}
onBlur={onBlur}
id="enableGradedUnits"
checked={values.enableGradedUnits}
label={intl.formatMessage(messages.gradedUnitPagesLabel)}
helpText={intl.formatMessage(messages.gradedUnitPagesHelp)}
/>
)}
<AppConfigFormDivider />
<FormSwitchGroup
onChange={onChange}
onBlur={onBlur}
id="enableInContext"
checked={values.enableInContext}
label={intl.formatMessage(messages.inContextDiscussionLabel)}
helpText={intl.formatMessage(messages.inContextDiscussionHelp)}
id="groupAtSubsection"
checked={values.groupAtSubsection}
label={intl.formatMessage(messages.groupInContextSubsectionLabel)}
helpText={intl.formatMessage(messages.groupInContextSubsectionHelp)}
/>
<TransitionReplace>
{values.enableInContext ? (
<React.Fragment key="open">
<AppConfigFormDivider />
<FormSwitchGroup
onChange={onChange}
onBlur={onBlur}
className="ml-4"
id="enableGradedUnits"
checked={values.enableGradedUnits}
label={intl.formatMessage(messages.gradedUnitPagesLabel)}
helpText={intl.formatMessage(messages.gradedUnitPagesHelp)}
/>
<AppConfigFormDivider />
<FormSwitchGroup
onChange={onChange}
onBlur={onBlur}
className="ml-4"
id="groupAtSubsection"
checked={values.groupAtSubsection}
label={intl.formatMessage(messages.groupInContextSubsectionLabel)}
helpText={intl.formatMessage(messages.groupInContextSubsectionHelp)}
/>
<AppConfigFormDivider />
<FormSwitchGroup
onChange={onChange}
onBlur={onBlur}
className="ml-4"
id="unitLevelVisibility"
checked={values.unitLevelVisibility}
label={intl.formatMessage(messages.allowUnitLevelVisibilityLabel)}
helpText={intl.formatMessage(messages.allowUnitLevelVisibilityHelp)}
/>
</React.Fragment>
) : <React.Fragment key="closed" />}
</TransitionReplace>
</>
);
}
@@ -69,10 +70,8 @@ InContextDiscussionFields.propTypes = {
onChange: PropTypes.func.isRequired,
intl: intlShape.isRequired,
values: PropTypes.shape({
enableInContext: PropTypes.bool,
enableGradedUnits: PropTypes.bool,
groupAtSubsection: PropTypes.bool,
unitLevelVisibility: PropTypes.bool,
}).isRequired,
};

View File

@@ -14,7 +14,7 @@ import {
badgeVariant,
} from '../../../../data/constants';
import CollapsableEditor from '../../../../../../generic/CollapsableEditor';
import DeletePopup from '../../../../../../generic/DeletePopup';
import ConfirmationPopup from '../../../../../../generic/ConfirmationPopup';
import CollapseCardHeading from './CollapseCardHeading';
const BlackoutDatesItem = ({
@@ -51,13 +51,13 @@ const BlackoutDatesItem = ({
if (showDeletePopup) {
return (
<DeletePopup
<ConfirmationPopup
label={blackoutDate.status === constants.ACTIVE
? intl.formatMessage(messages.activeBlackoutDatesDeletionLabel)
: intl.formatMessage(messages.blackoutDatesDeletionLabel)}
bodyText={intl.formatMessage(deleteHelperText[blackoutDate.status])}
onDelete={onDelete}
deleteLabel={intl.formatMessage(messages.deleteButton)}
onConfirm={onDelete}
confirmLabel={intl.formatMessage(messages.deleteButton)}
onCancel={() => setShowDeletePopup(false)}
cancelLabel={intl.formatMessage(messages.cancelButton)}
/>

View File

@@ -28,11 +28,36 @@ const messages = defineMessages({
defaultMessage: 'Cancel',
description: 'Button allowing the user to return to discussion provider configurations.',
},
confirm: {
id: 'authoring.discussions.confirm',
defaultMessage: 'Confirm',
description: 'Button allowing the user to confirm Confirmation.',
},
confirmConfigurationChange: {
id: 'authoring.discussions.confirmConfigurationChange',
defaultMessage: 'Are you sure you want to change the discussion settings?',
description: 'Asks the user whether he/she really wants to change settings.',
},
confirmEnableDiscussionsLabel: {
id: 'authoring.discussions.confirmEnableDiscussionsLabel',
defaultMessage: 'Enable discussions on units in graded subsections?',
description: 'Asks the user whether he/she really wants to enable discussions on units in graded subsections.',
},
cancelEnableDiscussionsLabel: {
id: 'authoring.discussions.cancelEnableDiscussionsLabel',
defaultMessage: 'Disable discussions on units in graded subsections?',
description: 'Asks the user whether he/she really wants to disable discussions on units in graded subsections.',
},
confirmEnableDiscussions: {
id: 'authoring.discussions.confirmEnableDiscussions',
defaultMessage: 'Enabling this toggle will automatically enable discussion on all units in graded subsections, that are not timed exams.',
description: 'Asks the user whether he/she really wants to enable discussions on units in graded subsections.',
},
cancelEnableDiscussions: {
id: 'authoring.discussions.cancelEnableDiscussions',
defaultMessage: 'Disabling this toggle will automatically disable discussion on all units in graded subsections. Discussion topics containing at least 1 thread will be listed and accessible under “Archived” in Topics tab on the Discussions page.',
description: 'Asks the user whether he/she really wants to disable discussions on units in graded subsections.',
},
backButton: {
id: 'authoring.discussions.backButton',
defaultMessage: 'Back',
@@ -124,23 +149,24 @@ const messages = defineMessages({
defaultMessage: 'Questions for the TAs',
description: 'Label for a checkbox allowing a user to divide the Questions for the TAs (TA stands for "teaching assistant") course wide topic by cohorts.',
},
cohortsEnabled: {
id: 'authoring.discussions.builtIn.cohortsEnabled.label',
defaultMessage: 'To adjust these settings, enable cohorts on the ',
description: 'Label text informing the user to enable cohort',
},
instructorDashboard: {
id: 'authoring.discussions.builtIn.instructorDashboard.label',
defaultMessage: 'instructor dashboard',
description: 'Label text for instructor dashboard',
},
// In-context discussion fields
visibilityInContext: {
id: 'authoring.discussions.builtIn.visibilityInContext',
defaultMessage: 'Visibility of in-context discussions',
},
inContextDiscussionLabel: {
id: 'authoring.discussions.builtIn.inContextDiscussion.label',
defaultMessage: 'In-context discussion',
},
inContextDiscussionHelp: {
id: 'authoring.discussions.builtIn.inContextDiscussion.help',
defaultMessage: 'Learners will be able to view or hide a discussion side panel to engage with discussion on the course unit page.',
},
gradedUnitPagesLabel: {
id: 'authoring.discussions.builtIn.gradedUnitPages.label',
defaultMessage: 'Graded unit pages',
defaultMessage: 'Enable discussions on units in graded subsections',
},
gradedUnitPagesHelp: {
id: 'authoring.discussions.builtIn.gradedUnitPages.help',
@@ -154,14 +180,6 @@ const messages = defineMessages({
id: 'authoring.discussions.builtIn.groupInContextSubsection.help',
defaultMessage: 'Learners will be able to view any post in the sub-section no matter which unit page they are viewing. While this is not recommended, if your course has short learning sequences or low enrollment grouping may increase engagement.',
},
allowUnitLevelVisibilityLabel: {
id: 'authoring.discussions.builtIn.allowUnitLevelVisibility.label',
defaultMessage: 'Allow visibility configuration for each course unit',
},
allowUnitLevelVisibilityHelp: {
id: 'authoring.discussions.builtIn.allowUnitLevelVisibility.help',
defaultMessage: 'With this advanced setting enabled you will be able to override the global visibility setting and turn discussions on or off for each unit from the course outline view..',
},
// Anonymous posting fields
anonymousPosting: {

View File

@@ -32,7 +32,7 @@ function normalizeLtiConfig(data) {
}
export function normalizeBlackoutDates(data) {
if (!data.length) {
if (!data || Object.keys(data).length < 1) {
return [];
}
@@ -56,6 +56,7 @@ function normalizePluginConfig(data) {
if (!data || Object.keys(data).length < 1) {
return {};
}
const enableDivideByCohorts = data.always_divide_inline_discussions && data.division_scheme === 'cohort';
const enableDivideCourseTopicsByCohorts = enableDivideByCohorts && data.divided_course_wide_discussions.length > 0;
return {
@@ -69,6 +70,8 @@ function normalizePluginConfig(data) {
allowDivisionByUnit: false,
divideByCohorts: enableDivideByCohorts,
divideCourseTopicsByCohorts: enableDivideCourseTopicsByCohorts,
cohortsEnabled: data.available_division_schemes?.includes('cohort') || false,
groupAtSubsection: data.group_at_subsection,
};
}

View File

@@ -252,6 +252,7 @@ describe('Data layer integration tests', () => {
alwaysDivideInlineDiscussions: false,
allowDivisionByUnit: false,
divideCourseTopicsByCohorts: false,
cohortsEnabled: false,
});
});
});
@@ -455,6 +456,7 @@ describe('Data layer integration tests', () => {
allowDivisionsByUnit: true,
alwaysDivideInlineDiscussions: true,
divideCourseTopicsByCohorts: true,
divisionScheme: DivisionSchemes.COHORT,
divideDiscussionIds,
discussionTopics: [
{ name: 'Edx', id: '13f106c6-6735-4e84-b097-0456cff55960' },
@@ -463,7 +465,6 @@ describe('Data layer integration tests', () => {
},
pagesAndResourcesPath,
), store.dispatch);
expect(window.location.pathname).toEqual(pagesAndResourcesPath);
expect(store.getState().discussions).toEqual(
expect.objectContaining({
@@ -490,6 +491,7 @@ describe('Data layer integration tests', () => {
// happens, but NOT what we want to have happen!
divideByCohorts: true,
divisionScheme: DivisionSchemes.COHORT,
cohortsEnabled: false,
allowDivisionByUnit: false,
divideCourseTopicsByCohorts: true,
});

View File

@@ -0,0 +1,129 @@
import React, { useEffect, useState } from 'react';
import { getConfig } from '@edx/frontend-platform';
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Form, Hyperlink } from '@edx/paragon';
import PropTypes from 'prop-types';
import messages from './messages';
import { providerNames, bbbPlanTypes } from './constants';
import AppConfigFormDivider from '../discussions/app-config-form/apps/shared/AppConfigFormDivider';
import LiveCommonFields from './LiveCommonFields';
import { useModel } from '../../generic/model-store';
function BbbSettings({
intl,
values,
setFieldValue,
}) {
const [bbbPlan, setBbbPlan] = useState(values.tierType);
useEffect(() => {
setBbbPlan(values.tierType);
}, [values.tierType]);
const app = useModel('liveApps', 'big_blue_button');
const isPiiDisabled = !values.piiSharingEnable;
function getBbbPlanOptions() {
const options = ['Select', bbbPlanTypes.commercial];
if (app.hasFreeTier) { options.push(bbbPlanTypes.free); }
return options.map(option => (
<option
key={option}
value={option}
data-testid={option}
>
{option}
</option>
));
}
const handlePlanChange = (e) => {
setBbbPlan(e.target.value);
setFieldValue('tierType', e.target.value);
};
return (
<>
{isPiiDisabled ? (
<p data-testid="request-pii-sharing">
{intl.formatMessage(messages.requestPiiSharingEnableForBbb, { provider: providerNames[values.provider] })}
</p>
) : (
<p data-testid="helper-text">
{intl.formatMessage(messages.providerHelperText, { providerName: providerNames[values.provider] })}
</p>
)}
<Form.Group controlId="bbs-settings" data-testid="plansDropDown">
<Form.Label as="planSelector" className="h6">
<FormattedMessage
id="authoring.live.bbb.selectPlan.label"
defaultMessage="Select a plan"
description="Label for bbb plan selection"
/>
</Form.Label>
<Form.Control
as="select"
name="tierType"
value={bbbPlan}
onChange={handlePlanChange}
disabled={isPiiDisabled}
>
{getBbbPlanOptions()}
</Form.Control>
</Form.Group>
<Hyperlink
destination={getConfig().BBB_LEARN_MORE_URL}
target="_blank"
rel="noopener noreferrer"
showLaunchIcon
className="text-primary-500 pt-2"
>
{ intl.formatMessage(messages.learnMore, { providerName: 'plans' }) }
</Hyperlink>
<>
<AppConfigFormDivider thick marginAdj={{ default: 0, sm: 2 }} />
{isPiiDisabled ? (
<p data-testid="help-request-pii-sharing">
{intl.formatMessage(messages.piiSharingEnableHelpTextBbb)}
</p>
) : (
<>
{bbbPlan === bbbPlanTypes.commercial && <LiveCommonFields values={values} />}
{bbbPlan === bbbPlanTypes.free && (
<span data-testid="free-plan-message">
{intl.formatMessage(messages.freePlanMessage)}
<Hyperlink
destination="https://bigbluebutton.org/privacy-policy/"
target="_blank"
rel="noopener noreferrer"
showLaunchIcon
className="text-gray-700 ml-1"
>
{intl.formatMessage(messages.privacyPolicy)}
</Hyperlink>
</span>
)}
</>
)}
</>
</>
);
}
BbbSettings.propTypes = {
intl: intlShape.isRequired,
values: PropTypes.shape({
consumerKey: PropTypes.string,
consumerSecret: PropTypes.string,
launchUrl: PropTypes.string,
launchEmail: PropTypes.string,
provider: PropTypes.string,
piiSharingEmail: PropTypes.bool,
piiSharingUsername: PropTypes.bool,
piiSharingEnable: PropTypes.bool,
tierType: PropTypes.string,
}).isRequired,
setFieldValue: PropTypes.func.isRequired,
};
export default injectIntl(BbbSettings);

View File

@@ -0,0 +1,134 @@
import {
render,
queryByTestId,
getByRole,
getAllByRole,
waitForElementToBeRemoved,
} from '@testing-library/react';
import { Switch } from 'react-router-dom';
import { initializeMockApp, history } from '@edx/frontend-platform';
import MockAdapter from 'axios-mock-adapter';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { AppProvider, PageRoute } from '@edx/frontend-platform/react';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import userEvent from '@testing-library/user-event';
import initializeStore from '../../store';
import { executeThunk } from '../../utils';
import LiveSettings from './Settings';
import {
generateLiveConfigurationApiResponse,
courseId,
initialState,
configurationProviders,
} from './factories/mockApiResponses';
import { fetchLiveConfiguration, fetchLiveProviders } from './data/thunks';
import { providerConfigurationApiUrl, providersApiUrl } from './data/api';
import messages from './messages';
import PagesAndResourcesProvider from '../PagesAndResourcesProvider';
let axiosMock;
let container;
let store;
const liveSettingsUrl = `/course/${courseId}/pages-and-resources/live/settings`;
const renderComponent = () => {
const wrapper = render(
<IntlProvider locale="en">
<AppProvider store={store}>
<PagesAndResourcesProvider courseId={courseId}>
<Switch>
<PageRoute path={liveSettingsUrl}>
<LiveSettings onClose={() => {}} />
</PageRoute>
</Switch>
</PagesAndResourcesProvider>
</AppProvider>
</IntlProvider>,
);
container = wrapper.container;
};
const mockStore = async ({
usernameSharing = false,
emailSharing = false,
enabled = true,
piiSharingAllowed = true,
isFreeTier = false,
}) => {
const fetchProviderConfigUrl = `${providersApiUrl}/${courseId}/`;
const fetchLiveConfigUrl = `${providerConfigurationApiUrl}/${courseId}/`;
axiosMock.onGet(fetchProviderConfigUrl).reply(200, configurationProviders(emailSharing, usernameSharing, 'big_blue_button', isFreeTier));
axiosMock.onGet(fetchLiveConfigUrl).reply(200, generateLiveConfigurationApiResponse(enabled, piiSharingAllowed, 'bigBlueButton', isFreeTier));
await executeThunk(fetchLiveProviders(courseId), store.dispatch);
await executeThunk(fetchLiveConfiguration(courseId), store.dispatch);
};
describe('BBB Settings', () => {
beforeEach(async () => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: false,
roles: [],
},
});
store = initializeStore(initialState);
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
history.push(liveSettingsUrl);
});
test('Plan dropdown to be visible and enabled in UI', async () => {
await mockStore({ emailSharing: true });
renderComponent();
const spinner = getByRole(container, 'status');
await waitForElementToBeRemoved(spinner);
expect(queryByTestId(container, 'plansDropDown')).toBeInTheDocument();
expect(container.querySelector('select[name="tierType"]')).not.toBeDisabled();
});
test.each([[true, 3], [false, 2]])('Plan dropdown should display correct number of options', async (isFreeTier, noOfOptions) => {
await mockStore({ emailSharing: true, isFreeTier });
renderComponent();
const spinner = getByRole(container, 'status');
await waitForElementToBeRemoved(spinner);
const dropDown = queryByTestId(container, 'plansDropDown');
expect(getAllByRole(dropDown, 'option').length).toBe(noOfOptions);
});
test('Connect to support and PII sharing message is visible and plans selection is disabled, When pii sharing is disabled, ',
async () => {
await mockStore({ piiSharingAllowed: false });
renderComponent();
const spinner = getByRole(container, 'status');
await waitForElementToBeRemoved(spinner);
const requestPiiText = queryByTestId(container, 'request-pii-sharing');
const helpRequestPiiText = queryByTestId(container, 'help-request-pii-sharing');
expect(requestPiiText).toHaveTextContent(
messages.requestPiiSharingEnableForBbb.defaultMessage.replaceAll('{provider}', 'BigBlueButton'),
);
expect(helpRequestPiiText).toHaveTextContent(messages.piiSharingEnableHelpTextBbb.defaultMessage);
expect(container.querySelector('select[name="tierType"]')).toBeDisabled();
});
test('free plans message is visible when free plan is selected', async () => {
await mockStore({ emailSharing: true, isFreeTier: true });
renderComponent();
const spinner = getByRole(container, 'status');
await waitForElementToBeRemoved(spinner);
const dropDown = container.querySelector('select[name="tierType"]');
userEvent.selectOptions(
dropDown,
getByRole(dropDown, 'option', { name: 'Free' }),
);
expect(queryByTestId(container, 'free-plan-message')).toBeInTheDocument();
expect(queryByTestId(container, 'free-plan-message')).toHaveTextContent(messages.freePlanMessage.defaultMessage);
});
});

View File

@@ -0,0 +1,49 @@
import React from 'react';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import PropTypes from 'prop-types';
import messages from './messages';
import FormikControl from '../../generic/FormikControl';
function LiveCommonFields({
intl,
values,
}) {
return (
<>
<p className="pb-2">{intl.formatMessage(messages.formInstructions)}</p>
<FormikControl
name="consumerKey"
value={values.consumerKey}
floatingLabel={intl.formatMessage(messages.consumerKey)}
className="pb-1"
type="input"
/>
<FormikControl
name="consumerSecret"
value={values.consumerSecret}
floatingLabel={intl.formatMessage(messages.consumerSecret)}
className="pb-1"
type="password"
/>
<FormikControl
name="launchUrl"
value={values.launchUrl}
floatingLabel={intl.formatMessage(messages.launchUrl)}
className="pb-1"
type="input"
/>
</>
);
}
LiveCommonFields.propTypes = {
intl: intlShape.isRequired,
values: PropTypes.shape({
consumerKey: PropTypes.string,
consumerSecret: PropTypes.string,
launchUrl: PropTypes.string,
launchEmail: PropTypes.string,
}).isRequired,
};
export default injectIntl(LiveCommonFields);

View File

@@ -5,16 +5,16 @@ import { SelectableBox, Icon } from '@edx/paragon';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import PropTypes from 'prop-types';
import * as Yup from 'yup';
import { fetchLiveData, saveLiveConfiguration, saveLiveConfigurationAsDraft } from './data/thunks';
import { selectApp } from './data/slice';
import FormikControl from '../../generic/FormikControl';
import AppSettingsModal from '../app-settings-modal/AppSettingsModal';
import { useModel } from '../../generic/model-store';
import Loading from '../../generic/Loading';
import iconsSrc from './constants';
import { iconsSrc, bbbPlanTypes } from './constants';
import { RequestStatus } from '../../data/constants';
import messages from './messages';
import ZoomSettings from './ZoomSettings';
import BBBSettings from './BBBSettings';
function LiveSettings({
intl,
@@ -38,16 +38,26 @@ function LiveSettings({
launchEmail: appConfig?.launchEmail || '',
provider: selectedAppId || 'zoom',
piiSharingEnable: piiSharingAllowed || false,
piiSharingUsername: app?.piiSharing.username || false,
piiSharingEmail: app?.piiSharing.email || false,
piiSharingUsername: app?.piiSharing?.username || false,
piiSharingEmail: app?.piiSharing?.email || false,
tierType: appConfig?.tierType || '',
};
const validationSchema = {
enabled: Yup.boolean(),
consumerKey: Yup.string().required(intl.formatMessage(messages.consumerKeyRequired)),
consumerSecret: Yup.string().required(intl.formatMessage(messages.consumerSecretRequired)),
launchUrl: Yup.string().required(intl.formatMessage(messages.launchUrlRequired)),
launchEmail: Yup.string().required(intl.formatMessage(messages.launchEmailRequired)),
consumerKey: Yup.string().when(['provider', 'tierType'], {
is: (provider, tier) => provider === 'zoom' || (provider === 'big_blue_button' && tier === bbbPlanTypes.commercial),
then: Yup.string().required(intl.formatMessage(messages.consumerKeyRequired)),
}),
consumerSecret: Yup.string().when(['provider', 'tierType'], {
is: (provider, tier) => provider === 'zoom' || (provider === 'big_blue_button' && tier === bbbPlanTypes.commercial),
then: Yup.string().notRequired(intl.formatMessage(messages.consumerSecretRequired)),
}),
launchUrl: Yup.string().when(['provider', 'tierType'], {
is: (provider, tier) => provider === 'zoom' || (provider === 'big_blue_button' && tier === bbbPlanTypes.commercial),
then: Yup.string().required(intl.formatMessage(messages.launchUrlRequired)),
}),
launchEmail: Yup.string(),
};
const handleProviderChange = (providerId, setFieldValue, values) => {
@@ -103,48 +113,13 @@ function LiveSettings({
</SelectableBox>
))}
</SelectableBox.Set>
{(!values.piiSharingEnable && (values.piiSharingEmail || values.piiSharingUsername)) ? (
<p data-testid="request-pii-sharing">
{intl.formatMessage(messages.requestPiiSharingEnable, { provider: values.provider })}
</p>
) : (
<>
{(values.piiSharingEmail || values.piiSharingUsername)
&& (
<p data-testid="helper-text">
{intl.formatMessage(messages.providerHelperText, { providerName: values.provider })}
</p>
)}
<p className="pb-2">{intl.formatMessage(messages.formInstructions)}</p>
<FormikControl
name="consumerKey"
value={values.consumerKey}
floatingLabel={intl.formatMessage(messages.consumerKey)}
className="pb-1"
type="input"
{values.provider === 'zoom' ? <ZoomSettings values={values} />
: (
<BBBSettings
values={values}
setFieldValue={setFieldValue}
/>
<FormikControl
name="consumerSecret"
value={values.consumerSecret}
floatingLabel={intl.formatMessage(messages.consumerSecret)}
className="pb-1"
type="input"
/>
<FormikControl
name="launchUrl"
value={values.launchUrl}
floatingLabel={intl.formatMessage(messages.launchUrl)}
className="pb-1"
type="input"
/>
<FormikControl
name="launchEmail"
value={values.launchEmail}
floatingLabel={intl.formatMessage(messages.launchEmail)}
type="input"
/>
</>
)}
)}
</>
)}
</>

View File

@@ -87,15 +87,12 @@ describe('LiveSettings', () => {
test('Live Configuration modal is visible', async () => {
renderComponent();
expect(queryByRole(container, 'dialog')).toBeVisible();
});
test('Displays "Configure Live" heading', async () => {
renderComponent();
const headingElement = queryByTestId(container, 'modal-title');
expect(headingElement).toHaveTextContent(messages.heading.defaultMessage);
});
@@ -140,76 +137,9 @@ describe('LiveSettings', () => {
expect(providers.childElementCount).toBe(2);
expect(providers).toHaveTextContent('Zoom');
expect(providers).toHaveTextContent('BigBlueButton');
expect(helperText).toHaveTextContent(
messages.providerHelperText.defaultMessage.replace('{providerName}', 'zoom'),
);
});
test('LTI fields are visible when pii sharing is enabled and email or username sharing required', async () => {
await mockStore({ emailSharing: true });
renderComponent();
const spinner = getByRole(container, 'status');
await waitForElementToBeRemoved(spinner);
const consumerKey = container.querySelector('input[name="consumerKey"]').parentElement;
const consumerSecret = container.querySelector('input[name="consumerSecret"]').parentElement;
const launchUrl = container.querySelector('input[name="launchUrl"]').parentElement;
const launchEmail = container.querySelector('input[name="launchEmail"]').parentElement;
expect(consumerKey.firstChild).toBeVisible();
expect(consumerKey.lastChild).toHaveTextContent(messages.consumerKey.defaultMessage);
expect(consumerSecret.firstChild).toBeVisible();
expect(consumerSecret.lastChild).toHaveTextContent(messages.consumerSecret.defaultMessage);
expect(launchUrl.firstChild).toBeVisible();
expect(launchUrl.lastChild).toHaveTextContent(messages.launchUrl.defaultMessage);
expect(launchEmail.firstChild).toBeVisible();
expect(launchEmail.lastChild).toHaveTextContent(messages.launchEmail.defaultMessage);
});
test(
'Only connect to support message is visible when pii sharing is disabled and email or username sharing is required',
async () => {
await mockStore({ emailSharing: true, piiSharingAllowed: false });
renderComponent();
const spinner = getByRole(container, 'status');
await waitForElementToBeRemoved(spinner);
const requestPiiText = queryByTestId(container, 'request-pii-sharing');
const consumerKey = container.querySelector('input[name="consumerKey"]');
const consumerSecret = container.querySelector('input[name="consumerSecret"]');
const launchUrl = container.querySelector('input[name="launchUrl"]');
const launchEmail = container.querySelector('input[name="launchEmail"]');
expect(requestPiiText).toHaveTextContent(
messages.requestPiiSharingEnable.defaultMessage.replaceAll('{provider}', 'zoom'),
);
expect(consumerKey).not.toBeInTheDocument();
expect(consumerSecret).not.toBeInTheDocument();
expect(launchUrl).not.toBeInTheDocument();
expect(launchEmail).not.toBeInTheDocument();
},
);
test('Provider Configuration should be displayed correctly', async () => {
const apiDefaultResponse = generateLiveConfigurationApiResponse(true, true);
await mockStore({ emailSharing: false, piiSharingAllowed: false });
renderComponent();
const spinner = getByRole(container, 'status');
await waitForElementToBeRemoved(spinner);
const consumerKey = container.querySelector('input[name="consumerKey"]');
const consumerSecret = container.querySelector('input[name="consumerSecret"]');
const launchUrl = container.querySelector('input[name="launchUrl"]');
const launchEmail = container.querySelector('input[name="launchEmail"]');
expect(consumerKey.value).toBe(apiDefaultResponse.lti_configuration.lti_1p1_client_key);
expect(consumerSecret.value).toBe(apiDefaultResponse.lti_configuration.lti_1p1_client_secret);
expect(launchUrl.value).toBe(apiDefaultResponse.lti_configuration.lti_1p1_launch_url);
expect(launchEmail.value).toBe(
apiDefaultResponse.lti_configuration.lti_config.additional_parameters.custom_instructor_email,
messages.providerHelperText.defaultMessage.replace('{providerName}', 'Zoom'),
);
});

View File

@@ -0,0 +1,54 @@
import React from 'react';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import PropTypes from 'prop-types';
import messages from './messages';
import { providerNames } from './constants';
import LiveCommonFields from './LiveCommonFields';
import FormikControl from '../../generic/FormikControl';
function ZoomSettings({
intl,
values,
}) {
return (
<>
{!values.piiSharingEnable ? (
<p data-testid="request-pii-sharing">
{intl.formatMessage(messages.requestPiiSharingEnable, { provider: providerNames[values.provider] })}
</p>
) : (
<>
{(values.piiSharingEmail || values.piiSharingUsername)
&& (
<p data-testid="helper-text">
{intl.formatMessage(messages.providerHelperText, { providerName: providerNames[values.provider] })}
</p>
)}
<LiveCommonFields values={values} />
<FormikControl
name="launchEmail"
value={values.launchEmail}
floatingLabel={intl.formatMessage(messages.launchEmail)}
type="input"
/>
</>
)}
</>
);
}
ZoomSettings.propTypes = {
intl: intlShape.isRequired,
values: PropTypes.shape({
consumerKey: PropTypes.string,
consumerSecret: PropTypes.string,
launchUrl: PropTypes.string,
launchEmail: PropTypes.string,
provider: PropTypes.string,
piiSharingEmail: PropTypes.bool,
piiSharingUsername: PropTypes.bool,
piiSharingEnable: PropTypes.bool,
}).isRequired,
};
export default injectIntl(ZoomSettings);

View File

@@ -0,0 +1,150 @@
import {
render,
queryByTestId,
getByRole,
waitForElementToBeRemoved,
} from '@testing-library/react';
import { Switch } from 'react-router-dom';
import { initializeMockApp, history } from '@edx/frontend-platform';
import MockAdapter from 'axios-mock-adapter';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { AppProvider, PageRoute } from '@edx/frontend-platform/react';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import initializeStore from '../../store';
import { executeThunk } from '../../utils';
import LiveSettings from './Settings';
import {
generateLiveConfigurationApiResponse,
courseId,
initialState,
configurationProviders,
} from './factories/mockApiResponses';
import { fetchLiveConfiguration, fetchLiveProviders } from './data/thunks';
import { providerConfigurationApiUrl, providersApiUrl } from './data/api';
import messages from './messages';
import PagesAndResourcesProvider from '../PagesAndResourcesProvider';
let axiosMock;
let container;
let store;
const liveSettingsUrl = `/course/${courseId}/pages-and-resources/live/settings`;
const renderComponent = () => {
const wrapper = render(
<IntlProvider locale="en">
<AppProvider store={store}>
<PagesAndResourcesProvider courseId={courseId}>
<Switch>
<PageRoute path={liveSettingsUrl}>
<LiveSettings onClose={() => {}} />
</PageRoute>
</Switch>
</PagesAndResourcesProvider>
</AppProvider>
</IntlProvider>,
);
container = wrapper.container;
};
const mockStore = async ({
usernameSharing = false,
emailSharing = false,
enabled = true,
piiSharingAllowed = true,
}) => {
const fetchProviderConfigUrl = `${providersApiUrl}/${courseId}/`;
const fetchLiveConfigUrl = `${providerConfigurationApiUrl}/${courseId}/`;
axiosMock.onGet(fetchProviderConfigUrl).reply(200, configurationProviders(emailSharing, usernameSharing));
axiosMock.onGet(fetchLiveConfigUrl).reply(200, generateLiveConfigurationApiResponse(enabled, piiSharingAllowed));
await executeThunk(fetchLiveProviders(courseId), store.dispatch);
await executeThunk(fetchLiveConfiguration(courseId), store.dispatch);
};
describe('Zoom Settings', () => {
beforeEach(async () => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: false,
roles: [],
},
});
store = initializeStore(initialState);
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
history.push(liveSettingsUrl);
});
test('LTI fields are visible when pii sharing is enabled', async () => {
await mockStore({ piiSharingAllowed: true });
renderComponent();
const spinner = getByRole(container, 'status');
await waitForElementToBeRemoved(spinner);
const consumerKey = container.querySelector('input[name="consumerKey"]').parentElement;
const consumerSecret = container.querySelector('input[name="consumerSecret"]').parentElement;
const launchUrl = container.querySelector('input[name="launchUrl"]').parentElement;
const launchEmail = container.querySelector('input[name="launchEmail"]').parentElement;
expect(consumerKey.firstChild).toBeVisible();
expect(consumerKey.lastChild).toHaveTextContent(messages.consumerKey.defaultMessage);
expect(consumerSecret.firstChild).toBeVisible();
expect(consumerSecret.lastChild).toHaveTextContent(messages.consumerSecret.defaultMessage);
expect(launchUrl.firstChild).toBeVisible();
expect(launchUrl.lastChild).toHaveTextContent(messages.launchUrl.defaultMessage);
expect(launchEmail.firstChild).toBeVisible();
expect(launchEmail.lastChild).toHaveTextContent(messages.launchEmail.defaultMessage);
});
test(
'Only connect to support message is visible when pii sharing is disabled',
async () => {
await mockStore({ piiSharingAllowed: false });
renderComponent();
const spinner = getByRole(container, 'status');
await waitForElementToBeRemoved(spinner);
const requestPiiText = queryByTestId(container, 'request-pii-sharing');
const consumerKey = container.querySelector('input[name="consumerKey"]');
const consumerSecret = container.querySelector('input[name="consumerSecret"]');
const launchUrl = container.querySelector('input[name="launchUrl"]');
const launchEmail = container.querySelector('input[name="launchEmail"]');
expect(requestPiiText).toHaveTextContent(
messages.requestPiiSharingEnable.defaultMessage.replaceAll('{provider}', 'Zoom'),
);
expect(consumerKey).not.toBeInTheDocument();
expect(consumerSecret).not.toBeInTheDocument();
expect(launchUrl).not.toBeInTheDocument();
expect(launchEmail).not.toBeInTheDocument();
},
);
test('Provider Configuration should be displayed correctly', async () => {
const apiDefaultResponse = generateLiveConfigurationApiResponse(true, true);
await mockStore({ piiSharingAllowed: true });
renderComponent();
const spinner = getByRole(container, 'status');
await waitForElementToBeRemoved(spinner);
const consumerKey = container.querySelector('input[name="consumerKey"]');
const consumerSecret = container.querySelector('input[name="consumerSecret"]');
const launchUrl = container.querySelector('input[name="launchUrl"]');
const launchEmail = container.querySelector('input[name="launchEmail"]');
expect(consumerKey.value).toBe(apiDefaultResponse.lti_configuration.lti_1p1_client_key);
expect(consumerSecret.value).toBe(apiDefaultResponse.lti_configuration.lti_1p1_client_secret);
expect(launchUrl.value).toBe(apiDefaultResponse.lti_configuration.lti_1p1_launch_url);
expect(launchEmail.value).toBe(
apiDefaultResponse.lti_configuration.lti_config.additional_parameters.custom_instructor_email,
);
});
});

View File

@@ -1,9 +1,20 @@
import { GoogleMeet, MicrosoftTeams, Zoom } from '@edx/paragon/icons';
import {
GoogleMeet, MicrosoftTeams, Zoom, Bbb,
} from '@edx/paragon/icons';
const iconsSrc = {
export const iconsSrc = {
googleMeet: GoogleMeet,
microsoftTeams: MicrosoftTeams,
zoom: Zoom,
bigBlueButton: Bbb,
};
export { iconsSrc as default };
export const providerNames = {
zoom: 'Zoom',
big_blue_button: 'BigBlueButton',
};
export const bbbPlanTypes = {
free: 'Free',
commercial: 'Commercial/self-hosted',
};

View File

@@ -1,6 +1,7 @@
/* eslint-disable import/prefer-default-export */
import { ensureConfig, getConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { bbbPlanTypes } from '../constants';
ensureConfig([
'STUDIO_BASE_URL',
@@ -17,6 +18,7 @@ function normalizeProviders(data) {
featureIds: app.features,
name: app.name,
piiSharing: app.pii_sharing,
hasFreeTier: app.has_free_tier,
}));
return {
@@ -35,24 +37,28 @@ function normalizeLtiConfig(data) {
consumerKey: data.lti_1p1_client_key,
consumerSecret: data.lti_1p1_client_secret,
launchUrl: data.lti_1p1_launch_url,
launchEmail: data.lti_config.additional_parameters.custom_instructor_email,
launchEmail: data.lti_config?.additional_parameters?.custom_instructor_email,
tierType: data.tierType,
};
}
export function normalizeSettings(data) {
let tier;
if (data.provider_type === 'big_blue_button') {
tier = data.free_tier === true ? bbbPlanTypes.free : bbbPlanTypes.commercial;
}
return {
enabled: data.enabled,
piiSharingAllowed: data.pii_sharing_allowed,
appConfig: {
id: data.provider_type,
...normalizeLtiConfig(data.lti_configuration),
...normalizeLtiConfig({ ...data.lti_configuration, tierType: tier }),
},
};
}
export function deNormalizeSettings(data) {
const ltiConfiguration = {};
if (data.consumerKey) {
ltiConfiguration.lti_1p1_client_key = data.consumerKey;
}
@@ -62,14 +68,14 @@ export function deNormalizeSettings(data) {
if (data.launchUrl) {
ltiConfiguration.lti_1p1_launch_url = data.launchUrl;
}
if (data.launchEmail) {
ltiConfiguration.lti_config = {
additional_parameters: {
if (data?.provider === 'zoom' || data.tierType !== 'Free') {
ltiConfiguration.lti_config = {};
if (data.launchEmail) {
ltiConfiguration.lti_config.additional_parameters = {
custom_instructor_email: data.launchEmail,
},
};
};
}
}
if (Object.keys(ltiConfiguration).length > 0) {
// Only add this in if we're sending LTI fields.
// TODO: Eventually support LTI v1.3 here.
@@ -78,9 +84,10 @@ export function deNormalizeSettings(data) {
const apiData = {
enabled: data?.enabled || false,
lti_configuration: ltiConfiguration,
lti_configuration: Object.keys(ltiConfiguration).length ? ltiConfiguration : undefined,
provider_type: data?.provider || 'zoom',
pii_sharing_allowed: data?.piiSharingEnable || false,
free_tier: data?.provider === 'zoom' ? false : Boolean(data.tierType === 'Free'),
};
return apiData;
}
@@ -105,7 +112,6 @@ export async function getLiveProviders(courseId) {
export async function getLiveConfiguration(courseId) {
const { data } = await getAuthenticatedHttpClient()
.get(`${providerConfigurationApiUrl}/${courseId}/`);
return normalizeSettings(data);
}
@@ -114,6 +120,5 @@ export async function postLiveConfiguration(courseId, config) {
`${providerConfigurationApiUrl}/${courseId}/`,
deNormalizeSettings(config),
);
return normalizeSettings(data);
}

View File

@@ -36,9 +36,11 @@ export const initialState = {
export const configurationProviders = (
emailSharing,
usernameSharing,
activeProvider = 'zoom',
hasFreeTier,
) => ({
providers: {
active: 'zoom',
active: activeProvider,
available: {
zoom: {
features: [],
@@ -48,13 +50,12 @@ export const configurationProviders = (
username: usernameSharing,
},
},
googleMeet: {
big_blue_button: {
additional_parameters: [],
features: [],
name: 'Google Meet',
pii_sharing: {
email: true,
username: true,
},
has_free_tier: hasFreeTier,
name: 'Big Blue Button',
},
},
},
@@ -63,6 +64,8 @@ export const configurationProviders = (
export const generateLiveConfigurationApiResponse = (
enabled,
piiSharingAllowed,
providerType = 'zoom',
isFreeTier,
) => ({
course_key: courseId,
enabled,
@@ -78,5 +81,6 @@ export const generateLiveConfigurationApiResponse = (
},
},
pii_sharing_allowed: piiSharingAllowed,
provider_type: 'zoom',
provider_type: providerType,
free_tier: providerType === 'bigBlueButton' ? isFreeTier : undefined,
});

View File

@@ -141,6 +141,33 @@ const messages = defineMessages({
defaultMessage: 'Microsoft Teams',
description: 'The name of the Microsoft Teams app.',
},
'appName-bigBlueButton': {
id: 'authoring.live.appName-bigBlueButton',
defaultMessage: 'BigBlueButton',
description: 'The name of the Big Blue Button Teams app.',
},
requestPiiSharingEnableForBbb: {
id: 'authoring.live.requestPiiSharingEnableForBbb',
defaultMessage: 'This configuration will require sharing usernames of learners and the course team with {provider}.',
description: 'Tells the user that they require sharing usernames with the provider to use this feature',
},
piiSharingEnableHelpTextBbb: {
id: 'authoring.live.piiSharingEnableHelpText',
defaultMessage: 'To enable this feature, contact your edX support team to enable PII sharing for this course.',
description: 'Tells the user that request edx project coordinator to enable the PII sharing to access the LTI configuration for a provider.',
},
freePlanMessage: {
id: 'authoring.live.freePlanMessage',
defaultMessage: 'The free plan is pre-configured, and no additional configurations are required. By selecting the free plan, you are agreeing to Blindside Networks',
description: 'Tells user that free plans requires no additional configurations',
},
privacyPolicy: {
id: 'authoring.live.privacyPolicy',
defaultMessage: 'Privacy Policy.',
description: 'The text of privacy policy hyperlink for free plan',
},
});
export default messages;

View File

@@ -12,3 +12,11 @@
-webkit-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.3) !important;
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.3) !important;
}
[dir=rtl] {
.desktop-card, .mobile-card {
.pgn__card-header-actions .pgn__hyperlink .btn-icon {
transform: scaleX(-1)
}
}
}

View File

@@ -13,6 +13,7 @@ import {
ActionRow, Alert, Badge, Form, Hyperlink, ModalDialog, StatefulButton,
} from '@edx/paragon';
import ExamsApiService from '../../data/services/ExamsApiService';
import StudioApiService from '../../data/services/StudioApiService';
import Loading from '../../generic/Loading';
import ConnectionErrorAlert from '../../generic/ConnectionErrorAlert';
@@ -36,7 +37,9 @@ function ProctoringSettings({ intl, onClose }) {
const [loaded, setLoaded] = useState(false);
const [loadingConnectionError, setLoadingConnectionError] = useState(false);
const [loadingPermissionError, setLoadingPermissionError] = useState(false);
const [allowLtiProviders, setAllowLtiProviders] = useState(false);
const [availableProctoringProviders, setAvailableProctoringProviders] = useState([]);
const [ltiProctoringProviders, setLtiProctoringProviders] = useState([]);
const [courseStartDate, setCourseStartDate] = useState('');
const [saveSuccess, setSaveSuccess] = useState(false);
const [saveError, setSaveError] = useState(false);
@@ -85,6 +88,10 @@ function ProctoringSettings({ intl, onClose }) {
}
}
function isLtiProvider(provider) {
return ltiProctoringProviders.some(p => p.name === provider);
}
function setFocusToProctortrackEscalationEmailInput() {
if (proctoringEscalationEmailInputRef && proctoringEscalationEmailInputRef.current) {
proctoringEscalationEmailInputRef.current.focus();
@@ -92,23 +99,35 @@ function ProctoringSettings({ intl, onClose }) {
}
function postSettingsBackToServer() {
const dataToPostBack = {
const providerIsLti = isLtiProvider(formValues.proctoringProvider);
const studioDataToPostBack = {
proctored_exam_settings: {
enable_proctored_exams: formValues.enableProctoredExams,
proctoring_provider: formValues.proctoringProvider,
// lti providers are managed outside edx-platform, lti_external indicates this
proctoring_provider: providerIsLti ? 'lti_external' : formValues.proctoringProvider,
create_zendesk_tickets: formValues.createZendeskTickets,
},
};
if (isEdxStaff) {
dataToPostBack.proctored_exam_settings.allow_proctoring_opt_out = formValues.allowOptingOut;
studioDataToPostBack.proctored_exam_settings.allow_proctoring_opt_out = formValues.allowOptingOut;
}
if (formValues.proctoringProvider === 'proctortrack') {
dataToPostBack.proctored_exam_settings.proctoring_escalation_email = formValues.proctortrackEscalationEmail === '' ? null : formValues.proctortrackEscalationEmail;
studioDataToPostBack.proctored_exam_settings.proctoring_escalation_email = formValues.proctortrackEscalationEmail === '' ? null : formValues.proctortrackEscalationEmail;
}
// only save back to exam service if necessary
setSubmissionInProgress(true);
StudioApiService.saveProctoredExamSettingsData(courseId, dataToPostBack).then(() => {
const saveOperations = [StudioApiService.saveProctoredExamSettingsData(courseId, studioDataToPostBack)];
if (allowLtiProviders && ExamsApiService.isAvailable()) {
saveOperations.push(
ExamsApiService.saveCourseExamConfiguration(
courseId, { provider: providerIsLti ? formValues.proctoringProvider : null },
),
);
}
Promise.all(saveOperations)
.then(() => {
setSaveSuccess(true);
setSaveError(false);
setSubmissionInProgress(false);
@@ -178,6 +197,11 @@ function ProctoringSettings({ intl, onClose }) {
return markDisabled;
}
function getProviderDisplayLabel(provider) {
// if a display label exists for this provider return it
return ltiProctoringProviders.find(p => p.name === provider)?.verbose_name || provider;
}
function getProctoringProviderOptions(providers) {
return providers.map(provider => (
<option
@@ -186,7 +210,7 @@ function ProctoringSettings({ intl, onClose }) {
disabled={isDisabledOption(provider)}
data-testid={provider}
>
{provider}
{getProviderDisplayLabel(provider)}
</option>
));
}
@@ -344,7 +368,7 @@ function ProctoringSettings({ intl, onClose }) {
)}
{/* CREATE ZENDESK TICKETS */}
{ isEdxStaff && formValues.enableProctoredExams && (
{ isEdxStaff && formValues.enableProctoredExams && !isLtiProvider(formValues.proctoringProvider) && (
<fieldset aria-describedby="createZendeskTicketsText">
<Form.Group controlId="formCreateZendeskTickets">
<Form.Label as="legend" className="font-weight-bold">
@@ -446,23 +470,51 @@ function ProctoringSettings({ intl, onClose }) {
useEffect(
() => {
StudioApiService.getProctoredExamSettingsData(courseId)
Promise.all([
StudioApiService.getProctoredExamSettingsData(courseId),
ExamsApiService.isAvailable() ? ExamsApiService.getCourseExamConfiguration(courseId) : Promise.resolve(),
ExamsApiService.isAvailable() ? ExamsApiService.getAvailableProviders() : Promise.resolve(),
])
.then(
response => {
const proctoredExamSettings = response.data.proctored_exam_settings;
([settingsResponse, examConfigResponse, ltiProvidersResponse]) => {
const proctoredExamSettings = settingsResponse.data.proctored_exam_settings;
setLoaded(true);
setLoading(false);
setSubmissionInProgress(false);
setCourseStartDate(response.data.course_start_date);
setCourseStartDate(settingsResponse.data.course_start_date);
const isProctortrack = proctoredExamSettings.proctoring_provider === 'proctortrack';
setShowProctortrackEscalationEmail(isProctortrack);
setAvailableProctoringProviders(response.data.available_proctoring_providers);
setAvailableProctoringProviders(settingsResponse.data.available_proctoring_providers);
const proctoringEscalationEmail = proctoredExamSettings.proctoring_escalation_email;
// The list of providers returned by studio settings are the default behavior. If lti_external
// is available as an option display the list of LTI providers returned by the exam service.
// Setting 'lti_external' in studio indicates an LTI provider configured outside of edx-platform.
// This option is not directly selectable.
const proctoringProvidersStudio = settingsResponse.data.available_proctoring_providers;
const proctoringProvidersLti = ltiProvidersResponse?.data || [];
const enableLtiProviders = proctoringProvidersStudio.includes('lti_external');
setAllowLtiProviders(enableLtiProviders);
setLtiProctoringProviders(proctoringProvidersLti);
// flatten provider objects and coalesce values to just the provider key
let availableProviders = proctoringProvidersStudio.filter(value => value !== 'lti_external');
if (enableLtiProviders) {
availableProviders = proctoringProvidersLti.reduce(
(result, provider) => [...result, provider.name], availableProviders,
);
}
setAvailableProctoringProviders(availableProviders);
let selectedProvider;
if (proctoredExamSettings.proctoring_provider === 'lti_external') {
selectedProvider = examConfigResponse.data.provider;
} else {
selectedProvider = proctoredExamSettings.proctoring_provider;
}
setFormValues({
...formValues,
proctoringProvider: selectedProvider,
enableProctoredExams: proctoredExamSettings.enable_proctored_exams,
proctoringProvider: proctoredExamSettings.proctoring_provider,
allowOptingOut: proctoredExamSettings.allow_proctoring_opt_out,
createZendeskTickets: proctoredExamSettings.create_zendesk_tickets,
// The backend API may return null for the proctoringEscalationEmail value, which is the default.
@@ -473,7 +525,7 @@ function ProctoringSettings({ intl, onClose }) {
},
).catch(
error => {
if (error.response.status === 403) {
if (error.response?.status === 403) {
setLoadingPermissionError(true);
} else {
setLoadingConnectionError(true);

View File

@@ -4,12 +4,13 @@ import {
} from '@testing-library/react';
import MockAdapter from 'axios-mock-adapter';
import { initializeMockApp } from '@edx/frontend-platform';
import { initializeMockApp, mergeConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { IntlProvider, injectIntl } from '@edx/frontend-platform/i18n';
import { AppProvider } from '@edx/frontend-platform/react';
import StudioApiService from '../../data/services/StudioApiService';
import ExamsApiService from '../../data/services/ExamsApiService';
import initializeStore from '../../store';
import PagesAndResourcesProvider from '../PagesAndResourcesProvider';
import ProctoredExamSettings from './Settings';
@@ -33,7 +34,19 @@ const intlWrapper = children => (
let axiosMock;
describe('ProctoredExamSettings', () => {
beforeEach(() => {
function setupApp(isAdmin = true) {
mergeConfig({
EXAMS_BASE_URL: 'http://exams.testing.co',
}, 'CourseAuthoringConfig');
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: isAdmin,
roles: [],
},
});
store = initializeStore({
models: {
courseApps: {
@@ -41,39 +54,47 @@ describe('ProctoredExamSettings', () => {
},
},
});
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onGet(
`${ExamsApiService.getExamsBaseUrl()}/api/v1/providers`,
).reply(200, [
{
name: 'test_lti',
verbose_name: 'LTI Provider',
},
]);
axiosMock.onGet(
`${ExamsApiService.getExamsBaseUrl()}/api/v1/configs/course_id/${defaultProps.courseId}`,
).reply(200, {
provider: null,
});
axiosMock.onGet(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, {
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
proctoring_escalation_email: 'test@example.com',
create_zendesk_tickets: true,
},
available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc', 'lti_external'],
course_start_date: '2070-01-01T00:00:00Z',
});
}
afterEach(() => {
cleanup();
axiosMock.reset();
});
beforeEach(async () => {
setupApp();
});
describe('Field dependencies', () => {
beforeEach(async () => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: true,
roles: [],
},
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onGet(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, {
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
proctoring_escalation_email: 'test@example.com',
create_zendesk_tickets: true,
},
available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
course_start_date: '2070-01-01T00:00:00Z',
});
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
});
@@ -166,21 +187,23 @@ describe('ProctoredExamSettings', () => {
expect(screen.queryByTestId('createZendeskTicketsYes')).toBeNull();
expect(screen.queryByTestId('createZendeskTicketsNo')).toBeNull();
});
it('Hides unsupported fields when lti provider is selected', async () => {
await waitFor(() => {
screen.getByDisplayValue('mockproc');
});
const selectElement = screen.getByDisplayValue('mockproc');
await act(async () => {
fireEvent.change(selectElement, { target: { value: 'test_lti' } });
});
expect(screen.queryByTestId('escalationEmail')).toBeNull();
expect(screen.queryByTestId('createZendeskTicketsYes')).toBeNull();
expect(screen.queryByTestId('createZendeskTicketsNo')).toBeNull();
});
});
describe('Validation with invalid escalation email', () => {
beforeEach(async () => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: false,
roles: [],
},
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onGet(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, {
@@ -399,83 +422,131 @@ describe('ProctoredExamSettings', () => {
course_start_date: '2013-01-01T00:00:00Z',
};
function setup(data, isAdmin) {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: isAdmin,
roles: [],
},
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
function mockCourseData(data) {
axiosMock.onGet(StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId)).reply(200, data);
}
it('Disables irrelevant proctoring provider fields when user is not an administrator and it is after start date', async () => {
setup(mockGetPastCourseData, false);
const isAdmin = false;
setupApp(isAdmin);
mockCourseData(mockGetPastCourseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const providerOption = screen.getByTestId('proctortrack');
expect(providerOption.hasAttribute('disabled')).toEqual(true);
});
it('Enables all proctoring provider options if user is not an administrator and it is before start date', async () => {
setup(mockGetFutureCourseData, false);
const isAdmin = false;
setupApp(isAdmin);
mockCourseData(mockGetFutureCourseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const providerOption = screen.getByTestId('proctortrack');
expect(providerOption.hasAttribute('disabled')).toEqual(false);
});
it('Enables all proctoring provider options if user administrator and it is after start date', async () => {
setup(mockGetPastCourseData, true);
const isAdmin = true;
setupApp(isAdmin);
mockCourseData(mockGetPastCourseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const providerOption = screen.getByTestId('proctortrack');
expect(providerOption.hasAttribute('disabled')).toEqual(false);
});
it('Enables all proctoring provider options if user administrator and it is before start date', async () => {
setup(mockGetFutureCourseData, true);
const isAdmin = true;
setupApp(isAdmin);
mockCourseData(mockGetFutureCourseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const providerOption = screen.getByTestId('proctortrack');
expect(providerOption.hasAttribute('disabled')).toEqual(false);
});
it('Does not include lti_external as a selectable option', async () => {
const courseData = {
...mockGetFutureCourseData,
available_proctoring_providers: ['lti_external', 'proctortrack', 'mockproc'],
};
mockCourseData(courseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await waitFor(() => {
screen.getByDisplayValue('mockproc');
});
expect(screen.queryByTestId('lti_external')).toBeNull();
});
it('Includes lti proctoring provider options when lti_external is allowed by studio', async () => {
const courseData = {
...mockGetFutureCourseData,
available_proctoring_providers: ['lti_external', 'proctortrack', 'mockproc'],
};
mockCourseData(courseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await waitFor(() => {
screen.getByDisplayValue('mockproc');
});
const providerOption = screen.getByTestId('test_lti');
// as as admin the provider should not be disabled
expect(providerOption.hasAttribute('disabled')).toEqual(false);
});
it('Does not include lti provider options when lti_external is not available in studio', async () => {
const isAdmin = true;
setupApp(isAdmin);
mockCourseData(mockGetFutureCourseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await waitFor(() => {
screen.getByDisplayValue('mockproc');
});
const providerOption = screen.queryByTestId('test_lti');
expect(providerOption).not.toBeInTheDocument();
});
it('Does not request lti provider options if there is no exam service url configuration', async () => {
mergeConfig({
EXAMS_BASE_URL: null,
}, 'CourseAuthoringConfig');
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await waitFor(() => {
screen.getByDisplayValue('mockproc');
});
// only outgoing request should be for studio settings
expect(axiosMock.history.get.length).toBe(1);
expect(axiosMock.history.get[0].url.includes('proctored_exam_settings')).toEqual(true);
});
it('Selected LTI proctoring provider is shown on page load', async () => {
const courseData = { ...mockGetFutureCourseData };
courseData.available_proctoring_providers = ['lti_external', 'proctortrack', 'mockproc'];
courseData.proctored_exam_settings.proctoring_provider = 'lti_external';
mockCourseData(courseData);
axiosMock.onGet(
`${ExamsApiService.getExamsBaseUrl()}/api/v1/configs/course_id/${defaultProps.courseId}`,
).reply(200, {
provider: 'test_lti',
});
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await waitFor(() => {
screen.getByText('Proctoring provider');
});
// make sure test_lti is the selected provider
expect(screen.getByDisplayValue('LTI Provider')).toBeInTheDocument();
});
});
describe('Toggles field visibility based on user permissions', () => {
function setup(isAdmin) {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: isAdmin,
roles: [],
},
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onGet(StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId)).reply(200, {
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
proctoring_escalation_email: 'test@example.com',
create_zendesk_tickets: true,
},
available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
course_start_date: '2070-01-01T00:00:00Z',
});
}
it('Hides opting out and zendesk tickets for non edX staff', async () => {
setup(false);
setupApp(false);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
expect(screen.queryByTestId('allowOptingOutYes')).toBeNull();
expect(screen.queryByTestId('createZendeskTicketsYes')).toBeNull();
});
it('Shows opting out and zendesk tickets for edX staff', async () => {
setup(true);
setupApp(true);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
expect(screen.queryByTestId('allowOptingOutYes')).not.toBeNull();
expect(screen.queryByTestId('createZendeskTicketsYes')).not.toBeNull();
@@ -483,18 +554,6 @@ describe('ProctoredExamSettings', () => {
});
describe('Connection states', () => {
beforeEach(() => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: true,
roles: [],
},
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
});
it('Shows the spinner before the connection is complete', async () => {
await act(async () => {
render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />));
@@ -504,7 +563,7 @@ describe('ProctoredExamSettings', () => {
});
});
it('Show connection error message when we suffer server side error', async () => {
it('Show connection error message when we suffer studio server side error', async () => {
axiosMock.onGet(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(500);
@@ -516,6 +575,18 @@ describe('ProctoredExamSettings', () => {
);
});
it('Show connection error message when we suffer edx-exams server side error', async () => {
axiosMock.onGet(
`${ExamsApiService.getExamsBaseUrl()}/api/v1/providers`,
).reply(500);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const connectionError = screen.getByTestId('connectionErrorAlert');
expect(connectionError.textContent).toEqual(
expect.stringContaining('We encountered a technical error when loading this page.'),
);
});
it('Show permission error message when user do not have enough permission', async () => {
axiosMock.onGet(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
@@ -530,34 +601,16 @@ describe('ProctoredExamSettings', () => {
});
describe('Save settings', () => {
beforeEach(() => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: true,
roles: [],
},
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient(), { onNoMatch: 'throwException' });
axiosMock.onGet(StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId)).reply(200, {
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
proctoring_escalation_email: 'test@example.com',
create_zendesk_tickets: true,
},
available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
});
});
it('Disable button while submitting', async () => {
beforeEach(async () => {
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, 'success');
axiosMock.onPatch(
`${ExamsApiService.getExamsBaseUrl()}/api/v1/configs/course_id/${defaultProps.courseId}`,
).reply(200, 'success');
});
it('Disable button while submitting', async () => {
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
let submitButton = screen.getByTestId('submissionButton');
expect(screen.queryByTestId('saveInProgress')).toBeFalsy();
@@ -570,10 +623,6 @@ describe('ProctoredExamSettings', () => {
});
it('Makes API call successfully with proctoring_escalation_email if proctortrack', async () => {
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, 'success');
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
// Make a change to the provider to proctortrack and set the email
const selectElement = screen.getByDisplayValue('mockproc');
@@ -609,10 +658,6 @@ describe('ProctoredExamSettings', () => {
});
it('Makes API call successfully without proctoring_escalation_email if not proctortrack', async () => {
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, 'success');
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
// make sure we have not selected proctortrack as the proctoring provider
@@ -639,7 +684,112 @@ describe('ProctoredExamSettings', () => {
expect(document.activeElement).toEqual(errorAlert);
});
it('Makes API call generated error', async () => {
it('Successfully updates exam configuration and studio provider is set to "lti_external" for lti providers', async () => {
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
// Make a change to the provider to proctortrack and set the email
const selectElement = screen.getByDisplayValue('mockproc');
await act(async () => {
fireEvent.change(selectElement, { target: { value: 'test_lti' } });
});
const submitButton = screen.getByTestId('submissionButton');
await act(async () => {
fireEvent.click(submitButton);
});
// update exam service config
expect(axiosMock.history.patch.length).toBe(1);
expect(JSON.parse(axiosMock.history.patch[0].data)).toEqual({
provider: 'test_lti',
});
// update studio settings
expect(axiosMock.history.post.length).toBe(1);
expect(JSON.parse(axiosMock.history.post[0].data)).toEqual({
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'lti_external',
create_zendesk_tickets: true,
},
});
const errorAlert = screen.getByTestId('saveSuccess');
expect(errorAlert.textContent).toEqual(
expect.stringContaining('Proctored exam settings saved successfully.'),
);
expect(document.activeElement).toEqual(errorAlert);
});
it('Sets exam service provider to null if a non-lti provider is selected', async () => {
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const submitButton = screen.getByTestId('submissionButton');
await act(async () => {
fireEvent.click(submitButton);
});
// update exam service config
expect(axiosMock.history.patch.length).toBe(1);
expect(JSON.parse(axiosMock.history.patch[0].data)).toEqual({
provider: null,
});
expect(axiosMock.history.patch.length).toBe(1);
expect(axiosMock.history.post.length).toBe(1);
expect(JSON.parse(axiosMock.history.post[0].data)).toEqual({
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
create_zendesk_tickets: true,
},
});
const errorAlert = screen.getByTestId('saveSuccess');
expect(errorAlert.textContent).toEqual(
expect.stringContaining('Proctored exam settings saved successfully.'),
);
expect(document.activeElement).toEqual(errorAlert);
});
it('Does not update exam service if lti is not enabled in studio', async () => {
axiosMock.onGet(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, {
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
proctoring_escalation_email: 'test@example.com',
create_zendesk_tickets: true,
},
available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
course_start_date: '2070-01-01T00:00:00Z',
});
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const submitButton = screen.getByTestId('submissionButton');
await act(async () => {
fireEvent.click(submitButton);
});
// does not update exam service config
expect(axiosMock.history.patch.length).toBe(0);
// does update studio
expect(axiosMock.history.post.length).toBe(1);
expect(JSON.parse(axiosMock.history.post[0].data)).toEqual({
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
create_zendesk_tickets: true,
},
});
const errorAlert = screen.getByTestId('saveSuccess');
expect(errorAlert.textContent).toEqual(
expect.stringContaining('Proctored exam settings saved successfully.'),
);
expect(document.activeElement).toEqual(errorAlert);
});
it('Makes studio API call generated error', async () => {
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(500);
@@ -657,11 +807,29 @@ describe('ProctoredExamSettings', () => {
expect(document.activeElement).toEqual(errorAlert);
});
it('Makes exams API call generated error', async () => {
axiosMock.onPatch(
`${ExamsApiService.getExamsBaseUrl()}/api/v1/configs/course_id/${defaultProps.courseId}`,
).reply(500, 'error');
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const submitButton = screen.getByTestId('submissionButton');
await act(async () => {
fireEvent.click(submitButton);
});
expect(axiosMock.history.post.length).toBe(1);
const errorAlert = screen.getByTestId('saveError');
expect(errorAlert.textContent).toEqual(
expect.stringContaining('We encountered a technical error while trying to save proctored exam settings'),
);
expect(document.activeElement).toEqual(errorAlert);
});
it('Manages focus correctly after different save statuses', async () => {
// first make a call that will cause a save error
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).replyOnce(500);
).reply(500);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const submitButton = screen.getByTestId('submissionButton');
@@ -678,7 +846,7 @@ describe('ProctoredExamSettings', () => {
// now make a call that will allow for a successful save
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).replyOnce(200, 'success');
).reply(200, 'success');
await act(async () => {
fireEvent.click(submitButton);
});
@@ -693,28 +861,8 @@ describe('ProctoredExamSettings', () => {
it('Include Zendesk ticket in post request if user is not an admin', async () => {
// use non-admin user for test
initializeMockApp({
authenticatedUser: {
userId: 4,
username: 'abc1234',
administrator: false,
roles: [],
},
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient(), { onNoMatch: 'throwException' });
axiosMock.onGet(StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId)).reply(200, {
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
proctoring_escalation_email: 'test@example.com',
create_zendesk_tickets: true,
},
available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
});
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, 'success');
const isAdmin = false;
setupApp(isAdmin);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
// Make a change to the proctoring provider

View File

@@ -60,7 +60,7 @@ function TeamSettings({
onClose={onClose}
bodyClassName="bg-light-200"
// Topic is supported for backwards compatibility, the new field is team_sets:
// ref: https://github.com/edx/edx-platform/blob/15461d3b6e6c0a724a7b8ed09241d970f201e5e7/openedx/core/lib/teams_config.py#L104-L108
// ref: https://github.com/openedx/edx-platform/blob/15461d3b6e6c0a724a7b8ed09241d970f201e5e7/openedx/core/lib/teams_config.py#L104-L108
initialValues={{
maxTeamSize: teamsConfiguration?.maxTeamSize,
groups: teamsConfiguration?.teamSets || teamsConfiguration?.topics,

View File

@@ -15,6 +15,7 @@ import {
import { getConfig } from '@edx/frontend-platform';
import messages from './ProctoredExamSettings.messages';
import ExamsApiService from '../data/services/ExamsApiService';
import StudioApiService from '../data/services/StudioApiService';
import Loading from '../generic/Loading';
import ConnectionErrorAlert from '../generic/ConnectionErrorAlert';
@@ -33,8 +34,10 @@ function ProctoredExamSettings({ courseId, intl }) {
const [loadingPermissionError, setLoadingPermissionError] = useState(false);
const [enableProctoredExams, setEnableProctoredExams] = useState(true);
const [allowOptingOut, setAllowOptingOut] = useState(false);
const [allowLtiProviders, setAllowLtiProviders] = useState(false);
const [proctoringProvider, setProctoringProvider] = useState('');
const [availableProctoringProviders, setAvailableProctoringProviders] = useState([]);
const [ltiProctoringProviders, setLtiProctoringProviders] = useState([]);
const [proctortrackEscalationEmail, setProctortrackEscalationEmail] = useState('');
const [createZendeskTickets, setCreateZendeskTickets] = useState(false);
const [courseStartDate, setCourseStartDate] = useState('');
@@ -89,24 +92,41 @@ function ProctoredExamSettings({ courseId, intl }) {
}
}
function isLtiProvider(provider) {
return ltiProctoringProviders.some(p => p.name === provider);
}
function postSettingsBackToServer() {
const dataToPostBack = {
const providerIsLti = isLtiProvider(proctoringProvider);
const studioDataToPostBack = {
proctored_exam_settings: {
enable_proctored_exams: enableProctoredExams,
proctoring_provider: proctoringProvider,
// lti providers are managed outside edx-platform, lti_external indicates this
proctoring_provider: providerIsLti ? 'lti_external' : proctoringProvider,
create_zendesk_tickets: createZendeskTickets,
},
};
if (isEdxStaff) {
dataToPostBack.proctored_exam_settings.allow_proctoring_opt_out = allowOptingOut;
studioDataToPostBack.proctored_exam_settings.allow_proctoring_opt_out = allowOptingOut;
}
if (proctoringProvider === 'proctortrack') {
dataToPostBack.proctored_exam_settings.proctoring_escalation_email = proctortrackEscalationEmail === '' ? null : proctortrackEscalationEmail;
studioDataToPostBack.proctored_exam_settings.proctoring_escalation_email = proctortrackEscalationEmail === '' ? null : proctortrackEscalationEmail;
}
setSubmissionInProgress(true);
StudioApiService.saveProctoredExamSettingsData(courseId, dataToPostBack).then(() => {
// only save back to exam service if necessary
const saveOperations = [StudioApiService.saveProctoredExamSettingsData(courseId, studioDataToPostBack)];
if (allowLtiProviders && ExamsApiService.isAvailable()) {
saveOperations.push(
ExamsApiService.saveCourseExamConfiguration(
courseId, { provider: providerIsLti ? proctoringProvider : null },
),
);
}
Promise.all(saveOperations)
.then(() => {
setSaveSuccess(true);
setSaveError(false);
setSubmissionInProgress(false);
@@ -172,6 +192,11 @@ function ProctoredExamSettings({ courseId, intl }) {
return markDisabled;
}
function getProviderDisplayLabel(provider) {
// if a display label exists for this provider return it
return ltiProctoringProviders.find(p => p.name === provider)?.verbose_name || provider;
}
function getProctoringProviderOptions(providers) {
return providers.map(provider => (
<option
@@ -180,7 +205,7 @@ function ProctoredExamSettings({ courseId, intl }) {
disabled={isDisabledOption(provider)}
data-testid={provider}
>
{provider}
{getProviderDisplayLabel(provider)}
</option>
));
}
@@ -338,7 +363,7 @@ function ProctoredExamSettings({ courseId, intl }) {
</Form.Group>
)}
{/* CREATE ZENDESK TICKETS */}
{ isEdxStaff && enableProctoredExams && (
{ isEdxStaff && enableProctoredExams && !isLtiProvider(proctoringProvider) && (
<fieldset aria-describedby="createZendeskTicketsText">
<Form.Group controlId="formCreateZendeskTickets">
<Form.Label as="legend">
@@ -470,20 +495,47 @@ function ProctoredExamSettings({ courseId, intl }) {
useEffect(
() => {
dispatch(fetchExamSettingsPending(courseId));
StudioApiService.getProctoredExamSettingsData(courseId)
Promise.all([
StudioApiService.getProctoredExamSettingsData(courseId),
ExamsApiService.isAvailable() ? ExamsApiService.getCourseExamConfiguration(courseId) : Promise.resolve(),
ExamsApiService.isAvailable() ? ExamsApiService.getAvailableProviders() : Promise.resolve(),
])
.then(
response => {
const proctoredExamSettings = response.data.proctored_exam_settings;
([settingsResponse, examConfigResponse, ltiProvidersResponse]) => {
const proctoredExamSettings = settingsResponse.data.proctored_exam_settings;
setLoaded(true);
setLoading(false);
setSubmissionInProgress(false);
setCourseStartDate(response.data.course_start_date);
setCourseStartDate(settingsResponse.data.course_start_date);
setEnableProctoredExams(proctoredExamSettings.enable_proctored_exams);
setAllowOptingOut(proctoredExamSettings.allow_proctoring_opt_out);
setProctoringProvider(proctoredExamSettings.proctoring_provider);
const isProctortrack = proctoredExamSettings.proctoring_provider === 'proctortrack';
setShowProctortrackEscalationEmail(isProctortrack);
setAvailableProctoringProviders(response.data.available_proctoring_providers);
// The list of providers returned by studio settings are the default behavior. If lti_external
// is available as an option display the list of LTI providers returned by the exam service.
// Setting 'lti_external' in studio indicates an LTI provider configured outside of edx-platform.
// This option is not directly selectable.
const proctoringProvidersStudio = settingsResponse.data.available_proctoring_providers;
const proctoringProvidersLti = ltiProvidersResponse?.data || [];
const enableLtiProviders = proctoringProvidersStudio.includes('lti_external');
setAllowLtiProviders(enableLtiProviders);
setLtiProctoringProviders(proctoringProvidersLti);
// flatten provider objects and coalesce values to just the provider key
let availableProviders = proctoringProvidersStudio.filter(value => value !== 'lti_external');
if (enableLtiProviders) {
availableProviders = proctoringProvidersLti.reduce(
(result, provider) => [...result, provider.name], availableProviders,
);
}
setAvailableProctoringProviders(availableProviders);
if (proctoredExamSettings.proctoring_provider === 'lti_external') {
setProctoringProvider(examConfigResponse.data.provider);
} else {
setProctoringProvider(proctoredExamSettings.proctoring_provider);
}
// The backend API may return null for the proctoringEscalationEmail value, which is the default.
// In order to keep our email input component controlled, we use the empty string as the default
@@ -494,9 +546,10 @@ function ProctoredExamSettings({ courseId, intl }) {
setCreateZendeskTickets(proctoredExamSettings.create_zendesk_tickets);
dispatch(fetchExamSettingsSuccess(courseId));
},
).catch(
)
.catch(
error => {
if (error.response.status === 403) {
if (error.response?.status === 403) {
setLoadingPermissionError(true);
} else {
setLoadingConnectionError(true);

View File

@@ -5,11 +5,12 @@ import {
import { IntlProvider, injectIntl } from '@edx/frontend-platform/i18n';
// import * as auth from '@edx/frontend-platform/auth';
import MockAdapter from 'axios-mock-adapter';
import { initializeMockApp } from '@edx/frontend-platform';
import { initializeMockApp, mergeConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { AppProvider } from '@edx/frontend-platform/react';
import ProctoredExamSettings from './ProctoredExamSettings';
import StudioApiService from '../data/services/StudioApiService';
import ExamsApiService from '../data/services/ExamsApiService';
import initializeStore from '../store';
const defaultProps = {
@@ -30,38 +31,61 @@ const intlWrapper = children => (
);
describe('ProctoredExamSettings', () => {
function setupApp(isAdmin = true) {
mergeConfig({
EXAMS_BASE_URL: 'http://exams.testing.co',
}, 'CourseAuthoringConfig');
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: isAdmin,
roles: [],
},
});
store = initializeStore();
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onGet(
`${ExamsApiService.getExamsBaseUrl()}/api/v1/providers`,
).reply(200, [
{
name: 'test_lti',
verbose_name: 'LTI Provider',
},
]);
axiosMock.onGet(
`${ExamsApiService.getExamsBaseUrl()}/api/v1/configs/course_id/${defaultProps.courseId}`,
).reply(200, {
provider: null,
});
axiosMock.onGet(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, {
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
proctoring_escalation_email: 'test@example.com',
create_zendesk_tickets: true,
},
available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc', 'lti_external'],
course_start_date: '2070-01-01T00:00:00Z',
});
}
afterEach(() => {
cleanup();
axiosMock.reset();
});
beforeEach(async () => {
setupApp();
});
describe('Field dependencies', () => {
beforeEach(async () => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: true,
roles: [],
},
});
store = initializeStore();
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onGet(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, {
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
proctoring_escalation_email: 'test@example.com',
create_zendesk_tickets: true,
},
available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
course_start_date: '2070-01-01T00:00:00Z',
});
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
});
@@ -154,21 +178,23 @@ describe('ProctoredExamSettings', () => {
expect(screen.queryByTestId('createZendeskTicketsYes')).toBeNull();
expect(screen.queryByTestId('createZendeskTicketsNo')).toBeNull();
});
it('Hides unsupported fields when lti provider is selected', async () => {
await waitFor(() => {
screen.getByDisplayValue('mockproc');
});
const selectElement = screen.getByDisplayValue('mockproc');
await act(async () => {
fireEvent.change(selectElement, { target: { value: 'test_lti' } });
});
expect(screen.queryByTestId('escalationEmail')).toBeNull();
expect(screen.queryByTestId('createZendeskTicketsYes')).toBeNull();
expect(screen.queryByTestId('createZendeskTicketsNo')).toBeNull();
});
});
describe('Validation with invalid escalation email', () => {
beforeEach(async () => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: false,
roles: [],
},
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onGet(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, {
@@ -183,10 +209,6 @@ describe('ProctoredExamSettings', () => {
course_start_date: '2070-01-01T00:00:00Z',
});
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, {});
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
});
@@ -268,9 +290,16 @@ describe('ProctoredExamSettings', () => {
});
it('Has no error when invalid proctoring escalation email is provided with proctoring disabled', async () => {
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, 'success');
axiosMock.onPatch(
`${ExamsApiService.getExamsBaseUrl()}/api/v1/configs/course_id/${defaultProps.courseId}`,
).reply(200, 'success');
await waitFor(() => {
screen.getByDisplayValue('proctortrack');
});
const selectEscalationEmailElement = screen.getByDisplayValue('test@example.com');
await act(async () => {
fireEvent.change(selectEscalationEmailElement, { target: { value: '' } });
@@ -293,6 +322,13 @@ describe('ProctoredExamSettings', () => {
});
it('Has no error when valid proctoring escalation email is provided with proctortrack selected', async () => {
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, 'success');
axiosMock.onPatch(
`${ExamsApiService.getExamsBaseUrl()}/api/v1/configs/course_id/${defaultProps.courseId}`,
).reply(200, 'success');
await waitFor(() => {
screen.getByDisplayValue('proctortrack');
});
@@ -387,83 +423,114 @@ describe('ProctoredExamSettings', () => {
course_start_date: '2013-01-01T00:00:00Z',
};
function setup(data, isAdmin) {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: isAdmin,
roles: [],
},
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
function mockCourseData(data) {
axiosMock.onGet(StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId)).reply(200, data);
}
it('Disables irrelevant proctoring provider fields when user is not an administrator and it is after start date', async () => {
setup(mockGetPastCourseData, false);
const isAdmin = false;
setupApp(isAdmin);
mockCourseData(mockGetPastCourseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const providerOption = screen.getByTestId('proctortrack');
expect(providerOption.hasAttribute('disabled')).toEqual(true);
});
it('Enables all proctoring provider options if user is not an administrator and it is before start date', async () => {
setup(mockGetFutureCourseData, false);
const isAdmin = false;
setupApp(isAdmin);
mockCourseData(mockGetFutureCourseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const providerOption = screen.getByTestId('proctortrack');
expect(providerOption.hasAttribute('disabled')).toEqual(false);
});
it('Enables all proctoring provider options if user administrator and it is after start date', async () => {
setup(mockGetPastCourseData, true);
const isAdmin = true;
setupApp(isAdmin);
mockCourseData(mockGetPastCourseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const providerOption = screen.getByTestId('proctortrack');
expect(providerOption.hasAttribute('disabled')).toEqual(false);
});
it('Enables all proctoring provider options if user administrator and it is before start date', async () => {
setup(mockGetFutureCourseData, true);
const isAdmin = true;
setupApp(isAdmin);
mockCourseData(mockGetFutureCourseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const providerOption = screen.getByTestId('proctortrack');
expect(providerOption.hasAttribute('disabled')).toEqual(false);
});
it('Does not include lti_external as a selectable option', async () => {
const courseData = mockGetFutureCourseData;
courseData.available_proctoring_providers = ['lti_external', 'proctortrack', 'mockproc'];
mockCourseData(courseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await waitFor(() => {
screen.getByDisplayValue('mockproc');
});
expect(screen.queryByTestId('lti_external')).toBeNull();
});
it('Includes lti proctoring provider options when lti_external is allowed by studio', async () => {
const courseData = mockGetFutureCourseData;
courseData.available_proctoring_providers = ['lti_external', 'proctortrack', 'mockproc'];
mockCourseData(courseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await waitFor(() => {
screen.getByDisplayValue('mockproc');
});
const providerOption = screen.getByTestId('test_lti');
// as as admin the provider should not be disabled
expect(providerOption.hasAttribute('disabled')).toEqual(false);
});
it('Does not request lti provider options if there is no exam service url configuration', async () => {
mergeConfig({
EXAMS_BASE_URL: null,
}, 'CourseAuthoringConfig');
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await waitFor(() => {
screen.getByDisplayValue('mockproc');
});
// only outgoing request should be for studio settings
expect(axiosMock.history.get.length).toBe(1);
expect(axiosMock.history.get[0].url.includes('proctored_exam_settings')).toEqual(true);
});
it('Selected LTI proctoring provider is shown on page load', async () => {
const courseData = { ...mockGetFutureCourseData };
courseData.available_proctoring_providers = ['lti_external', 'proctortrack', 'mockproc'];
courseData.proctored_exam_settings.proctoring_provider = 'lti_external';
mockCourseData(courseData);
axiosMock.onGet(
`${ExamsApiService.getExamsBaseUrl()}/api/v1/configs/course_id/${defaultProps.courseId}`,
).reply(200, {
provider: 'test_lti',
});
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await waitFor(() => {
screen.getByText('Proctoring Provider');
});
// make sure test_lti is the selected provider
expect(screen.getByDisplayValue('LTI Provider')).toBeInTheDocument();
});
});
describe('Toggles field visibility based on user permissions', () => {
function setup(isAdmin) {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: isAdmin,
roles: [],
},
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onGet(StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId)).reply(200, {
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
proctoring_escalation_email: 'test@example.com',
create_zendesk_tickets: true,
},
available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
course_start_date: '2070-01-01T00:00:00Z',
});
}
it('Hides opting out and zendesk tickets for non edX staff', async () => {
setup(false);
setupApp(false);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
expect(screen.queryByTestId('allowOptingOutYes')).toBeNull();
expect(screen.queryByTestId('createZendeskTicketsYes')).toBeNull();
});
it('Shows opting out and zendesk tickets for edX staff', async () => {
setup(true);
setupApp(true);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
expect(screen.queryByTestId('allowOptingOutYes')).not.toBeNull();
expect(screen.queryByTestId('createZendeskTicketsYes')).not.toBeNull();
@@ -471,18 +538,6 @@ describe('ProctoredExamSettings', () => {
});
describe('Connection states', () => {
beforeEach(() => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: true,
roles: [],
},
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
});
it('Shows the spinner before the connection is complete', async () => {
await act(async () => {
render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />));
@@ -492,7 +547,7 @@ describe('ProctoredExamSettings', () => {
});
});
it('Show connection error message when we suffer server side error', async () => {
it('Show connection error message when we suffer studio server side error', async () => {
axiosMock.onGet(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(500);
@@ -504,6 +559,18 @@ describe('ProctoredExamSettings', () => {
);
});
it('Show connection error message when we suffer edx-exams server side error', async () => {
axiosMock.onGet(
`${ExamsApiService.getExamsBaseUrl()}/api/v1/providers`,
).reply(500);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const connectionError = screen.getByTestId('connectionErrorAlert');
expect(connectionError.textContent).toEqual(
expect.stringContaining('We encountered a technical error when loading this page.'),
);
});
it('Show permission error message when user do not have enough permission', async () => {
axiosMock.onGet(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
@@ -518,27 +585,13 @@ describe('ProctoredExamSettings', () => {
});
describe('Save settings', () => {
beforeEach(() => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: true,
roles: [],
},
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient(), { onNoMatch: 'throwException' });
axiosMock.onGet(StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId)).reply(200, {
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
proctoring_escalation_email: 'test@example.com',
create_zendesk_tickets: true,
},
available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
});
beforeEach(async () => {
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, 'success');
axiosMock.onPatch(
`${ExamsApiService.getExamsBaseUrl()}/api/v1/configs/course_id/${defaultProps.courseId}`,
).reply(200, 'success');
});
it('Show spinner while saving', async () => {
@@ -557,16 +610,14 @@ describe('ProctoredExamSettings', () => {
expect(submitSpinner).toBeDefined();
await waitForElementToBeRemoved(submitSpinner);
expect(axiosMock.history.get.length).toBe(1);
expect(axiosMock.history.post.length).toBe(1);
// request studio settings, exam config, and exam service providers
expect(axiosMock.history.get.length).toBe(3);
expect(axiosMock.history.post.length).toBe(1); // studio
expect(axiosMock.history.patch.length).toBe(1); // edx-exams
expect(screen.queryByTestId('saveInProgress')).toBeFalsy();
});
it('Makes API call successfully with proctoring_escalation_email if proctortrack', async () => {
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, 'success');
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
// Make a change to the provider to proctortrack and set the email
const selectElement = screen.getByDisplayValue('mockproc');
@@ -602,10 +653,6 @@ describe('ProctoredExamSettings', () => {
});
it('Makes API call successfully without proctoring_escalation_email if not proctortrack', async () => {
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, 'success');
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
// make sure we have not selected proctortrack as the proctoring provider
@@ -632,7 +679,112 @@ describe('ProctoredExamSettings', () => {
expect(document.activeElement).toEqual(errorAlert);
});
it('Makes API call generated error', async () => {
it('Successfully updates exam configuration and studio provider is set to "lti_external" for lti providers', async () => {
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
// Make a change to the provider to proctortrack and set the email
const selectElement = screen.getByDisplayValue('mockproc');
await act(async () => {
fireEvent.change(selectElement, { target: { value: 'test_lti' } });
});
const submitButton = screen.getByTestId('submissionButton');
await act(async () => {
fireEvent.click(submitButton);
});
// update exam service config
expect(axiosMock.history.patch.length).toBe(1);
expect(JSON.parse(axiosMock.history.patch[0].data)).toEqual({
provider: 'test_lti',
});
// update studio settings
expect(axiosMock.history.post.length).toBe(1);
expect(JSON.parse(axiosMock.history.post[0].data)).toEqual({
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'lti_external',
create_zendesk_tickets: true,
},
});
const errorAlert = screen.getByTestId('saveSuccess');
expect(errorAlert.textContent).toEqual(
expect.stringContaining('Proctored exam settings saved successfully.'),
);
expect(document.activeElement).toEqual(errorAlert);
});
it('Sets exam service provider to null if a non-lti provider is selected', async () => {
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const submitButton = screen.getByTestId('submissionButton');
await act(async () => {
fireEvent.click(submitButton);
});
// update exam service config
expect(axiosMock.history.patch.length).toBe(1);
expect(JSON.parse(axiosMock.history.patch[0].data)).toEqual({
provider: null,
});
expect(axiosMock.history.patch.length).toBe(1);
expect(axiosMock.history.post.length).toBe(1);
expect(JSON.parse(axiosMock.history.post[0].data)).toEqual({
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
create_zendesk_tickets: true,
},
});
const errorAlert = screen.getByTestId('saveSuccess');
expect(errorAlert.textContent).toEqual(
expect.stringContaining('Proctored exam settings saved successfully.'),
);
expect(document.activeElement).toEqual(errorAlert);
});
it('Does not update exam service if lti is not enabled in studio', async () => {
axiosMock.onGet(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, {
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
proctoring_escalation_email: 'test@example.com',
create_zendesk_tickets: true,
},
available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
course_start_date: '2070-01-01T00:00:00Z',
});
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const submitButton = screen.getByTestId('submissionButton');
await act(async () => {
fireEvent.click(submitButton);
});
// does not update exam service config
expect(axiosMock.history.patch.length).toBe(0);
// does update studio
expect(axiosMock.history.post.length).toBe(1);
expect(JSON.parse(axiosMock.history.post[0].data)).toEqual({
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
create_zendesk_tickets: true,
},
});
const errorAlert = screen.getByTestId('saveSuccess');
expect(errorAlert.textContent).toEqual(
expect.stringContaining('Proctored exam settings saved successfully.'),
);
expect(document.activeElement).toEqual(errorAlert);
});
it('Makes studio API call generated error', async () => {
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(500);
@@ -650,11 +802,29 @@ describe('ProctoredExamSettings', () => {
expect(document.activeElement).toEqual(errorAlert);
});
it('Makes exams API call generated error', async () => {
axiosMock.onPatch(
`${ExamsApiService.getExamsBaseUrl()}/api/v1/configs/course_id/${defaultProps.courseId}`,
).reply(500, 'error');
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const submitButton = screen.getByTestId('submissionButton');
await act(async () => {
fireEvent.click(submitButton);
});
expect(axiosMock.history.post.length).toBe(1);
const errorAlert = screen.getByTestId('saveError');
expect(errorAlert.textContent).toEqual(
expect.stringContaining('We encountered a technical error while trying to save proctored exam settings'),
);
expect(document.activeElement).toEqual(errorAlert);
});
it('Manages focus correctly after different save statuses', async () => {
// first make a call that will cause a save error
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).replyOnce(500);
).reply(500);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
const submitButton = screen.getByTestId('submissionButton');
@@ -671,7 +841,7 @@ describe('ProctoredExamSettings', () => {
// now make a call that will allow for a successful save
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).replyOnce(200, 'success');
).reply(200, 'success');
await act(async () => {
fireEvent.click(submitButton);
});
@@ -686,31 +856,14 @@ describe('ProctoredExamSettings', () => {
it('Include Zendesk ticket in post request if user is not an admin', async () => {
// use non-admin user for test
initializeMockApp({
authenticatedUser: {
userId: 4,
username: 'abc1234',
administrator: false,
roles: [],
},
});
axiosMock = new MockAdapter(getAuthenticatedHttpClient(), { onNoMatch: 'throwException' });
axiosMock.onGet(StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId)).reply(200, {
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
proctoring_escalation_email: 'test@example.com',
create_zendesk_tickets: true,
},
available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
});
axiosMock.onPost(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, 'success');
const isAdmin = false;
setupApp(isAdmin);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
// Make a change to the proctoring provider
await waitFor(() => {
screen.getByDisplayValue('mockproc');
});
const selectElement = screen.getByDisplayValue('mockproc');
await act(async () => {
fireEvent.change(selectElement, { target: { value: 'proctortrack' } });

View File

@@ -9,6 +9,8 @@ import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import 'babel-polyfill';
import { mergeConfig } from '@edx/frontend-platform';
Enzyme.configure({ adapter: new Adapter() });
/* need to mock window for tinymce on import, as it is JSDOM incompatible */
@@ -41,3 +43,15 @@ global.IntersectionObserver = jest.fn(function mockIntersectionObserver() {
window.getComputedStyle = jest.fn(() => ({
getPropertyValue: jest.fn(),
}));
// Ensure app-specific configs are loaded during tests since
// initialize() is not called.
mergeConfig({
SUPPORT_URL: process.env.SUPPORT_URL || null,
SUPPORT_EMAIL: process.env.SUPPORT_EMAIL || null,
LEARNING_BASE_URL: process.env.LEARNING_BASE_URL,
EXAMS_BASE_URL: process.env.EXAMS_BASE_URL || null,
CALCULATOR_HELP_URL: process.env.CALCULATOR_HELP_URL || null,
ENABLE_PROGRESS_GRAPH_SETTINGS: process.env.ENABLE_PROGRESS_GRAPH_SETTINGS || 'false',
ENABLE_TEAM_TYPE_SETTING: process.env.ENABLE_TEAM_TYPE_SETTING === 'true',
}, 'CourseAuthoringConfig');