From 2b39da69b96482976fedcf08bae16c1ebabae372 Mon Sep 17 00:00:00 2001 From: Arunmozhi Date: Wed, 1 Sep 2021 13:47:39 +0000 Subject: [PATCH 01/63] feat: add reset option to Randomized Content Block This makes the reset button to refresh the contents of a Randomized Content Block (RCB) without reloading the full page by fetching a new set of problems in the "reset" response and replacing the DOM contents. The reset button returns the student view as a string and the client uses the HtmlUtils package to replace the contents and reinitializes the XBlock. This allows students to use the RCB as a flash card system. Co-authored-by: tinumide --- .../public/js/library_content_reset.js | 18 +++++++ .../xmodule/xmodule/library_content_module.py | 36 +++++++++++++- .../xmodule/tests/test_library_content.py | 47 ++++++++++++++++++- .../sass/course/courseware/_courseware.scss | 11 +++++ lms/templates/vert_module.html | 6 +++ 5 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 common/lib/xmodule/xmodule/assets/library_content/public/js/library_content_reset.js diff --git a/common/lib/xmodule/xmodule/assets/library_content/public/js/library_content_reset.js b/common/lib/xmodule/xmodule/assets/library_content/public/js/library_content_reset.js new file mode 100644 index 0000000000..e985d3c2a6 --- /dev/null +++ b/common/lib/xmodule/xmodule/assets/library_content/public/js/library_content_reset.js @@ -0,0 +1,18 @@ +/* JavaScript for reset option that can be done on a randomized LibraryContentBlock */ +function LibraryContentReset(runtime, element) { + $('.problem-reset-btn', element).click((e) => { + e.preventDefault(); + $.post({ + url: runtime.handlerUrl(element, 'reset_selected_children'), + success(data) { + edx.HtmlUtils.setHtml(element, edx.HtmlUtils.HTML(data)); + // Rebind the reset button for the block + XBlock.initializeBlock(element); + // Render the new set of problems (XBlocks) + $(".xblock", element).each(function(i, child) { + XBlock.initializeBlock(child); + }); + }, + }); + }); +} diff --git a/common/lib/xmodule/xmodule/library_content_module.py b/common/lib/xmodule/xmodule/library_content_module.py index e7f1fbaff2..599656e676 100644 --- a/common/lib/xmodule/xmodule/library_content_module.py +++ b/common/lib/xmodule/xmodule/library_content_module.py @@ -8,6 +8,7 @@ import logging import random from copy import copy from gettext import ngettext +from rest_framework import status import bleach from django.conf import settings @@ -21,7 +22,7 @@ from web_fragments.fragment import Fragment from webob import Response from xblock.completable import XBlockCompletionMode from xblock.core import XBlock -from xblock.fields import Integer, List, Scope, String +from xblock.fields import Integer, List, Scope, String, Boolean from capa.responsetypes import registry from xmodule.mako_module import MakoTemplateBlockBase @@ -176,6 +177,14 @@ class LibraryContentBlock( default=[], scope=Scope.user_state, ) + # This cannot be called `show_reset_button`, because children blocks inherit this as a default value. + allow_resetting_children = Boolean( + display_name=_("Show Reset Button"), + help=_("Determines whether a 'Reset Problems' button is shown, so users may reset their answers and reshuffle " + "selected items."), + scope=Scope.settings, + default=False + ) @property def source_library_key(self): @@ -346,6 +355,27 @@ class LibraryContentBlock( return self.selected + @XBlock.handler + def reset_selected_children(self, _, __): + """ + Resets the XBlock's state for a user. + + This resets the state of all `selected` children and then clears the `selected` field + so that the new blocks are randomly chosen for this user. + """ + if not self.allow_resetting_children: + return Response('"Resetting selected children" is not allowed for this XBlock', + status=status.HTTP_400_BAD_REQUEST) + + for block_type, block_id in self.selected_children(): + block = self.runtime.get_block(self.location.course_key.make_usage_key(block_type, block_id)) + if hasattr(block, 'reset_problem'): + block.reset_problem(None) + block.save() + + self.selected = [] + return Response(json.dumps(self.student_view({}).content)) + def _get_selected_child_blocks(self): """ Generator returning XBlock instances of the children selected for the @@ -383,7 +413,11 @@ class LibraryContentBlock( 'show_bookmark_button': False, 'watched_completable_blocks': set(), 'completion_delay_ms': None, + 'reset_button': self.allow_resetting_children, })) + + fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/library_content_reset.js')) + fragment.initialize_js('LibraryContentReset') return fragment def author_view(self, context): diff --git a/common/lib/xmodule/xmodule/tests/test_library_content.py b/common/lib/xmodule/xmodule/tests/test_library_content.py index 628f471e88..748a962f1d 100644 --- a/common/lib/xmodule/xmodule/tests/test_library_content.py +++ b/common/lib/xmodule/xmodule/tests/test_library_content.py @@ -3,7 +3,8 @@ Basic unit tests for LibraryContentBlock Higher-level tests are in `cms/djangoapps/contentstore/tests/test_libraries.py`. """ -from unittest.mock import Mock, patch +import ddt +from unittest.mock import MagicMock, Mock, patch from bson.objectid import ObjectId from fs.memoryfs import MemoryFS @@ -11,6 +12,7 @@ from lxml import etree from search.search_engine_base import SearchEngine from web_fragments.fragment import Fragment from xblock.runtime import Runtime as VanillaRuntime +from rest_framework import status from xmodule.library_content_module import ANY_CAPA_TYPE_VALUE, LibraryContentBlock from xmodule.library_tools import LibraryToolsService @@ -20,6 +22,7 @@ from xmodule.modulestore.tests.utils import MixedSplitTestCase from xmodule.tests import get_test_system from xmodule.validation import StudioValidationMessage from xmodule.x_module import AUTHOR_VIEW +from xmodule.capa_module import ProblemBlock from .test_course_module import DummySystem as TestImportSystem @@ -30,6 +33,7 @@ class LibraryContentTest(MixedSplitTestCase): """ Base class for tests of LibraryContentBlock (library_content_block.py) """ + def setUp(self): super().setUp() @@ -164,6 +168,7 @@ class TestLibraryContentExportImport(LibraryContentTest): self._verify_xblock_properties(imported_lc_block) +@ddt.ddt class LibraryContentBlockTestMixin: """ Basic unit tests for LibraryContentBlock @@ -378,6 +383,45 @@ class LibraryContentBlockTestMixin: assert len(selected) == count return selected + @ddt.data( + # User resets selected children with reset button on content block + (True, 8), + # User resets selected children without reset button on content block + (False, 8), + ) + @ddt.unpack + def test_reset_selected_children_capa_blocks(self, allow_resetting_children, max_count): + """ + Tests that the `reset_selected_children` method of a content block resets only + XBlocks that have a `reset_problem` attribute when `allow_resetting_children` is True + + This test block has 4 HTML XBlocks and 4 Problem XBlocks. Therefore, if we ensure + that the `reset_problem` has been called len(self.problem_types) times, then + it means that this is working correctly + """ + self.lc_block.allow_resetting_children = allow_resetting_children + self.lc_block.max_count = max_count + # Add some capa blocks + self._create_capa_problems() + self.lc_block.refresh_children() + self.lc_block = self.store.get_item(self.lc_block.location) + # Mock the student view to return an empty dict to be returned as response + self.lc_block.student_view = MagicMock() + self.lc_block.student_view.return_value.content = {} + + with patch.object(ProblemBlock, 'reset_problem', return_value={'success': True}) as reset_problem: + response = self.lc_block.reset_selected_children(None, None) + + if allow_resetting_children: + self.lc_block.student_view.assert_called_once_with({}) + assert reset_problem.call_count == len(self.problem_types) + assert response.status_code == status.HTTP_200_OK + assert response.content_type == "text/html" + assert response.body == b"{}" + else: + reset_problem.assert_not_called() + assert response.status_code == status.HTTP_400_BAD_REQUEST + @patch('xmodule.library_tools.SearchEngine.get_search_engine', Mock(return_value=None, autospec=True)) class TestLibraryContentBlockNoSearchIndex(LibraryContentBlockTestMixin, LibraryContentTest): @@ -396,6 +440,7 @@ class TestLibraryContentBlockWithSearchIndex(LibraryContentBlockTestMixin, Libra """ Tests for library container with mocked search engine response. """ + def _get_search_response(self, field_dictionary=None): """ Mocks search response as returned by search engine """ target_type = field_dictionary.get('problem_types') diff --git a/lms/static/sass/course/courseware/_courseware.scss b/lms/static/sass/course/courseware/_courseware.scss index 67a5a70405..33f8dae798 100644 --- a/lms/static/sass/course/courseware/_courseware.scss +++ b/lms/static/sass/course/courseware/_courseware.scss @@ -635,6 +635,17 @@ html.video-fullscreen { border-bottom: 1px solid #ddd; margin-bottom: ($baseline*0.75); padding: 0 0 15px; + + .problem-reset-btn-wrapper { + position: relative; + .problem-reset-btn { + &:hover, + &:focus, + &:active { + color: $primary; + } + } + } } .vert > .xblock-student_view.is-hidden, diff --git a/lms/templates/vert_module.html b/lms/templates/vert_module.html index 131bbfc8ca..0e52e3c7f4 100644 --- a/lms/templates/vert_module.html +++ b/lms/templates/vert_module.html @@ -69,6 +69,12 @@ from openedx.core.djangolib.markup import HTML % endfor +% if reset_button: +
+ +
+% endif + <%static:require_module_async module_name="js/dateutil_factory" class_name="DateUtilFactory"> DateUtilFactory.transform('.localized-datetime'); From 2fc04e65db843d0d59c12b80789f75c52436bb9f Mon Sep 17 00:00:00 2001 From: Syed Sajjad Hussain Shah Date: Wed, 25 May 2022 14:56:38 +0500 Subject: [PATCH 02/63] fix: Name field validation issue from lms [VAN-965] --- openedx/core/djangoapps/user_api/accounts/api.py | 7 ++++++- openedx/core/djangoapps/user_authn/views/register.py | 5 ++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/openedx/core/djangoapps/user_api/accounts/api.py b/openedx/core/djangoapps/user_api/accounts/api.py index 754882f2ce..8cc013cb94 100644 --- a/openedx/core/djangoapps/user_api/accounts/api.py +++ b/openedx/core/djangoapps/user_api/accounts/api.py @@ -5,6 +5,7 @@ Programmatic integration point for User API Accounts sub-application import datetime +import re from django.conf import settings from django.core.exceptions import ObjectDoesNotExist @@ -403,7 +404,11 @@ def get_name_validation_error(name): :return: Validation error message. """ - return '' if name else accounts.REQUIRED_FIELD_NAME_MSG + if name: + regex = re.findall(r'https|http?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+', name) + return _('Enter a valid name') if bool(regex) else '' + else: + return accounts.REQUIRED_FIELD_NAME_MSG def get_username_validation_error(username): diff --git a/openedx/core/djangoapps/user_authn/views/register.py b/openedx/core/djangoapps/user_authn/views/register.py index 7ba3a8920e..2f73253800 100644 --- a/openedx/core/djangoapps/user_authn/views/register.py +++ b/openedx/core/djangoapps/user_authn/views/register.py @@ -795,8 +795,11 @@ class RegistrationValidationView(APIView): def name_handler(self, request): """ Validates whether fullname is valid """ name = request.data.get('name') + validation_error = get_name_validation_error(name) + if validation_error: + return validation_error self.username_suggestions = generate_username_suggestions(name) - return get_name_validation_error(name) + return validation_error def username_handler(self, request): """ Validates whether the username is valid. """ From 7eb9a45e2db1b4ef6199d4364528f128cdbfc136 Mon Sep 17 00:00:00 2001 From: Waheed Ahmed Date: Tue, 31 May 2022 16:07:05 +0500 Subject: [PATCH 03/63] fix: cross-site scripting vulnerability on logout page The target URL on logout page is marked as safe while rendering and making the page volunerable to Cross-site scripting vulnerability. Rendered the target variable outside safe HTML so that it should be treated as text. VAN-972 --- lms/templates/logout.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lms/templates/logout.html b/lms/templates/logout.html index 48a9428c84..272d933542 100644 --- a/lms/templates/logout.html +++ b/lms/templates/logout.html @@ -10,9 +10,9 @@

{% blocktrans trimmed asvar sso_signout_msg %} - {start_anchor}Click here{end_anchor} to delete your single signed on (SSO) session. + {start_anchor}{{ tpa_logout_url }}{middle_anchor}Click here{end_anchor} to delete your single signed on (SSO) session. {% endblocktrans %} - {% interpolate_html sso_signout_msg start_anchor=''|safe end_anchor=''|safe %} + {% interpolate_html sso_signout_msg start_anchor=''|safe end_anchor=''|safe %}

{% else %} @@ -36,9 +36,9 @@

{% blocktrans trimmed asvar signout_msg1 %} - If you are not redirected within 5 seconds, {start_anchor}click here to go to the home page{end_anchor}. + If you are not redirected within 5 seconds, {start_anchor}{{ target }}{middle_anchor}click here to go to the home page{end_anchor}. {% endblocktrans %} - {% interpolate_html signout_msg1 start_anchor=''|safe end_anchor=''|safe %} + {% interpolate_html signout_msg1 start_anchor=''|safe end_anchor=''|safe %}

{% endif %} From 1172dd00e53514bf05f05e79bf8e6ba9a07b28fc Mon Sep 17 00:00:00 2001 From: Navin Karkera Date: Wed, 25 May 2022 21:41:40 +0530 Subject: [PATCH 04/63] fix: [BB-6261] warn and trim name for site configuration before saving --- .../commands/create_or_update_site_configuration.py | 12 +++++++++++- .../test_create_or_update_site_configuration.py | 13 +++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/openedx/core/djangoapps/site_configuration/management/commands/create_or_update_site_configuration.py b/openedx/core/djangoapps/site_configuration/management/commands/create_or_update_site_configuration.py index fd3f97f86a..c97944b910 100644 --- a/openedx/core/djangoapps/site_configuration/management/commands/create_or_update_site_configuration.py +++ b/openedx/core/djangoapps/site_configuration/management/commands/create_or_update_site_configuration.py @@ -70,6 +70,7 @@ class Command(BaseCommand): def handle(self, *args, **options): site_id = options.get('site_id') domain = options.get('domain') + name = domain configuration = options.get('configuration') config_file_data = options.get('config_file_data') @@ -78,9 +79,18 @@ class Command(BaseCommand): if site_id is not None: site, created = Site.objects.get_or_create(id=site_id) else: + name_max_length = Site._meta.get_field("name").max_length + if name: + if len(str(name)) > name_max_length: + LOG.warning( + f"The name {name} is too long, truncating to {name_max_length}" + " characters. Please update site name in admin." + ) + # trim name as the column has a limit of 50 characters + name = name[:name_max_length] site, created = Site.objects.get_or_create( domain=domain, - name=domain, + name=name, ) if created: LOG.info(f"Site does not exist. Created new site '{site.domain}'") diff --git a/openedx/core/djangoapps/site_configuration/management/commands/tests/test_create_or_update_site_configuration.py b/openedx/core/djangoapps/site_configuration/management/commands/tests/test_create_or_update_site_configuration.py index 5b4d3f8ae1..e572c3631f 100644 --- a/openedx/core/djangoapps/site_configuration/management/commands/tests/test_create_or_update_site_configuration.py +++ b/openedx/core/djangoapps/site_configuration/management/commands/tests/test_create_or_update_site_configuration.py @@ -107,6 +107,19 @@ class CreateOrUpdateSiteConfigurationTest(TestCase): assert not site_configuration.site_values assert not site_configuration.enabled + def test_site_created_when_domain_longer_than_50_characters(self): + """ + Verify that a SiteConfiguration instance is created with name trimmed + to 50 characters when domain is longer than 50 characters + """ + self.assert_site_configuration_does_not_exist() + + domain = "studio.newtestserverwithlongname.development.opencraft.hosting" + call_command(self.command, f"{domain}") + site = Site.objects.filter(domain=domain) + assert site.exists() + assert site[0].name == domain[:50] + def test_both_enabled_disabled_flags(self): """ Verify the error on providing both the --enabled and --disabled flags. From 02e29168b2d7bb76f7e6567ac72aa0a2978b5da2 Mon Sep 17 00:00:00 2001 From: Awais Qureshi Date: Wed, 1 Jun 2022 16:02:13 +0500 Subject: [PATCH 05/63] =?UTF-8?q?feat!:=20Removing=20sandbox=20folder=20fr?= =?UTF-8?q?om=20platform=20and=20installing=20it=20from=20p=E2=80=A6=20(#3?= =?UTF-8?q?0402)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat!: common/lib/sandbox-packages folder moved to a new library. --- .../util/tests/test_codejail_includes.py | 26 + common/lib/capa/capa/safe_exec/README.rst | 10 +- common/lib/sandbox-packages/README | 1 - common/lib/sandbox-packages/eia.py | 112 --- .../lib/sandbox-packages/loncapa/__init__.py | 3 - .../sandbox-packages/loncapa/loncapa_check.py | 41 - common/lib/sandbox-packages/setup.py | 17 - .../sandbox-packages/verifiers/__init__.py | 0 .../sandbox-packages/verifiers/draganddrop.py | 433 --------- .../verifiers/tests_draganddrop.py | 843 ------------------ pavelib/quality.py | 5 +- requirements/edx-sandbox/py38.in | 7 +- requirements/edx-sandbox/py38.txt | 5 +- requirements/edx/base.in | 1 + requirements/edx/base.txt | 5 +- requirements/edx/development.txt | 5 +- requirements/edx/local.in | 1 - requirements/edx/testing.txt | 5 +- scripts/verify-dunder-init.sh | 2 +- 19 files changed, 46 insertions(+), 1476 deletions(-) create mode 100644 common/djangoapps/util/tests/test_codejail_includes.py delete mode 100644 common/lib/sandbox-packages/README delete mode 100644 common/lib/sandbox-packages/eia.py delete mode 100644 common/lib/sandbox-packages/loncapa/__init__.py delete mode 100644 common/lib/sandbox-packages/loncapa/loncapa_check.py delete mode 100644 common/lib/sandbox-packages/setup.py delete mode 100644 common/lib/sandbox-packages/verifiers/__init__.py delete mode 100644 common/lib/sandbox-packages/verifiers/draganddrop.py delete mode 100644 common/lib/sandbox-packages/verifiers/tests_draganddrop.py diff --git a/common/djangoapps/util/tests/test_codejail_includes.py b/common/djangoapps/util/tests/test_codejail_includes.py new file mode 100644 index 0000000000..0e56240a54 --- /dev/null +++ b/common/djangoapps/util/tests/test_codejail_includes.py @@ -0,0 +1,26 @@ +""" +Tests for codejail-includes package. +""" + +import unittest + +import eia +import loncapa +from verifiers import draganddrop + + +class TestCodeJailIncludes(unittest.TestCase): + """ tests for codejail includes""" + + def test_loncapa(self): + random_integer = loncapa.lc_random(2, 60, 5) + assert random_integer <= 60 + assert random_integer >= 2 + + def test_nested_list_and_list1(self): + assert draganddrop.PositionsCompare([[1, 2], 40]) == draganddrop.PositionsCompare([1, 3]) + + def test_Eia(self): + # Test cases. All of these should return True + assert eia.iseia(100) # 100 ohm resistor is EIA + assert not eia.iseia(101) # 101 is not diff --git a/common/lib/capa/capa/safe_exec/README.rst b/common/lib/capa/capa/safe_exec/README.rst index 9a28480caf..ef12f45af6 100644 --- a/common/lib/capa/capa/safe_exec/README.rst +++ b/common/lib/capa/capa/safe_exec/README.rst @@ -15,18 +15,12 @@ CodeJail`__, with a few customized tweaks. __ https://github.com/edx/codejail/blob/master/README.rst -1. At the instruction to install packages into the sandboxed code, you'll +1. At the instruction to install packages into the sandboxed code, you'll need to install the requirements from requirements/edx-sandbox:: $ pip install -r requirements/edx-sandbox/base.txt -2. At the instruction to create the AppArmor profile, you'll need a line in - the profile for the sandbox packages. is the full path to - your edx_platform repo:: - - /common/lib/sandbox-packages/** r, - -3. You can configure resource limits in settings.py. A CODE_JAIL setting is +2. You can configure resource limits in settings.py. A CODE_JAIL setting is available, a dictionary. The "limits" key lets you adjust the limits for CPU time, real time, and memory use. Setting any of them to zero disables that limit:: diff --git a/common/lib/sandbox-packages/README b/common/lib/sandbox-packages/README deleted file mode 100644 index 706998b08e..0000000000 --- a/common/lib/sandbox-packages/README +++ /dev/null @@ -1 +0,0 @@ -This directory is in the Python path for sandboxed Python execution. diff --git a/common/lib/sandbox-packages/eia.py b/common/lib/sandbox-packages/eia.py deleted file mode 100644 index f8c2da59f1..0000000000 --- a/common/lib/sandbox-packages/eia.py +++ /dev/null @@ -1,112 +0,0 @@ -""" -Standard resistor values. - -Commonly used for verifying electronic components in circuit classes are -standard values, or conversely, for generating realistic component -values in parameterized problems. For details, see: - -http://en.wikipedia.org/wiki/Electronic_color_code -""" - - -# pylint: disable=invalid-name -# r is standard name for a resistor. We would like to use it as such. - -import math -import numbers - -E6 = [10, 15, 22, 33, 47, 68] - -E12 = [10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82] -E24 = [10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82, 11, 13, 16, 20, - 24, 30, 36, 43, 51, 62, 75, 91] - -E48 = [100, 121, 147, 178, 215, 261, 316, 383, 464, 562, 681, 825, 105, - 127, 154, 187, 226, 274, 332, 402, 487, 590, 715, 866, 110, 133, - 162, 196, 237, 287, 348, 422, 511, 619, 750, 909, 115, 140, 169, - 205, 249, 301, 365, 442, 536, 649, 787, 953] - -E96 = [100, 121, 147, 178, 215, 261, 316, 383, 464, 562, 681, 825, 102, - 124, 150, 182, 221, 267, 324, 392, 475, 576, 698, 845, 105, 127, - 154, 187, 226, 274, 332, 402, 487, 590, 715, 866, 107, 130, 158, - 191, 232, 280, 340, 412, 499, 604, 732, 887, 110, 133, 162, 196, - 237, 287, 348, 422, 511, 619, 750, 909, 113, 137, 165, 200, 243, - 294, 357, 432, 523, 634, 768, 931, 115, 140, 169, 205, 249, 301, - 365, 442, 536, 649, 787, 953, 118, 143, 174, 210, 255, 309, 374, - 453, 549, 665, 806, 976] - -E192 = [100, 121, 147, 178, 215, 261, 316, 383, 464, 562, 681, 825, 101, - 123, 149, 180, 218, 264, 320, 388, 470, 569, 690, 835, 102, 124, - 150, 182, 221, 267, 324, 392, 475, 576, 698, 845, 104, 126, 152, - 184, 223, 271, 328, 397, 481, 583, 706, 856, 105, 127, 154, 187, - 226, 274, 332, 402, 487, 590, 715, 866, 106, 129, 156, 189, 229, - 277, 336, 407, 493, 597, 723, 876, 107, 130, 158, 191, 232, 280, - 340, 412, 499, 604, 732, 887, 109, 132, 160, 193, 234, 284, 344, - 417, 505, 612, 741, 898, 110, 133, 162, 196, 237, 287, 348, 422, - 511, 619, 750, 909, 111, 135, 164, 198, 240, 291, 352, 427, 517, - 626, 759, 920, 113, 137, 165, 200, 243, 294, 357, 432, 523, 634, - 768, 931, 114, 138, 167, 203, 246, 298, 361, 437, 530, 642, 777, - 942, 115, 140, 169, 205, 249, 301, 365, 442, 536, 649, 787, 953, - 117, 142, 172, 208, 252, 305, 370, 448, 542, 657, 796, 965, 118, - 143, 174, 210, 255, 309, 374, 453, 549, 665, 806, 976, 120, 145, - 176, 213, 258, 312, 379, 459, 556, 673, 816, 988] - - -def iseia(r, valid_types=(E6, E12, E24)): - ''' - Check if a component is a valid EIA value. - - By default, check 5% component values - ''' - - # Step 1: Discount things which are not numbers - if not isinstance(r, numbers.Number) or \ - r < 0 or \ - math.isnan(r) or \ - math.isinf(r): - return False - - # Special case: 0 is an okay resistor - if r == 0: - return True - - # Step 2: Move into the range [100, 1000) - while r < 100: - r = r * 10 - while r >= 1000: - r = r / 10 - - # Step 3: Discount things which are not integers, and cast to int - if abs(r - round(r)) > 0.01: - return False - r = int(round(r)) - - # Step 4: Check if we're a valid EIA value - for type_list in valid_types: - if r in type_list: - return True - if int(r / 10.) in type_list and (r % 10) == 0: - return True - - return False - -if __name__ == '__main__': - # Test cases. All of these should return True - print(iseia(100)) # 100 ohm resistor is EIA - print(not iseia(101)) # 101 is not - print(not iseia(100.3)) # Floating point close to EIA is not EIA - print(iseia(100.001)) # But within floating point error is - print(iseia(1e5)) # We handle big numbers well - print(iseia(2200)) # We handle middle-of-the-list well - # We can handle 1% components correctly; 2.2k is EIA24, but not EIA48. - print(not iseia(2200, (E48, E96, E192))) - print(iseia(5490e2, (E48, E96, E192))) - print(iseia(2200)) - print(not iseia(5490e2)) - print(iseia(1e-5)) # We handle little numbers well - print(not iseia("Hello")) # Junk handled okay - print(not iseia(float('NaN'))) - print(not iseia(-1)) - print(not iseia(iseia)) - print(not iseia(float('Inf'))) - print(iseia(0)) # Corner case. 0 is a standard resistor value. diff --git a/common/lib/sandbox-packages/loncapa/__init__.py b/common/lib/sandbox-packages/loncapa/__init__.py deleted file mode 100644 index 3d613e04de..0000000000 --- a/common/lib/sandbox-packages/loncapa/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/python # lint-amnesty, pylint: disable=missing-module-docstring - -from .loncapa_check import * # lint-amnesty, pylint: disable=redefined-builtin diff --git a/common/lib/sandbox-packages/loncapa/loncapa_check.py b/common/lib/sandbox-packages/loncapa/loncapa_check.py deleted file mode 100644 index 80a0a51545..0000000000 --- a/common/lib/sandbox-packages/loncapa/loncapa_check.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/python # lint-amnesty, pylint: disable=missing-module-docstring -# -# File: mitx/lib/loncapa/loncapa_check.py -# -# Python functions which duplicate the standard comparison functions available to LON-CAPA problems. -# Used in translating LON-CAPA problems to i4x problem specification language. - - -import math -import random -from six.moves import range - - -def lc_random(lower, upper, stepsize): - ''' - like random.randrange but lower and upper can be non-integer - ''' - nstep = int((upper - lower) / (1.0 * stepsize)) - choices = [lower + x * stepsize for x in range(nstep)] - return random.choice(choices) - - -def lc_choose(index, *args): - ''' - return args[index] - ''' - try: - return args[int(index) - 1] - except Exception as err: # lint-amnesty, pylint: disable=broad-except, unused-variable - pass - if len(args): # lint-amnesty, pylint: disable=len-as-condition - return args[0] - raise Exception( - "loncapa_check.lc_choose error, index={index}, args={args}".format( - index=index, - args=args, - ) - ) - -deg2rad = math.pi / 180.0 -rad2deg = 180.0 / math.pi diff --git a/common/lib/sandbox-packages/setup.py b/common/lib/sandbox-packages/setup.py deleted file mode 100644 index 3a02c854bc..0000000000 --- a/common/lib/sandbox-packages/setup.py +++ /dev/null @@ -1,17 +0,0 @@ -# lint-amnesty, pylint: disable=missing-module-docstring - -from setuptools import setup - -setup( - name="sandbox-packages", - version="0.1.1", - packages=[ - "loncapa", - "verifiers", - ], - py_modules=[ - "eia", - ], - install_requires=[ - ], -) diff --git a/common/lib/sandbox-packages/verifiers/__init__.py b/common/lib/sandbox-packages/verifiers/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/common/lib/sandbox-packages/verifiers/draganddrop.py b/common/lib/sandbox-packages/verifiers/draganddrop.py deleted file mode 100644 index 9d41366c58..0000000000 --- a/common/lib/sandbox-packages/verifiers/draganddrop.py +++ /dev/null @@ -1,433 +0,0 @@ -""" Grader of drag and drop input. - -Client side behavior: user can drag and drop images from list on base image. - - - Then json returned from client is: - { - "draggable": [ - { "image1": "t1" }, - { "ant": "t2" }, - { "molecule": "t3" }, - ] -} -values are target names. - -or: - { - "draggable": [ - { "image1": "[10, 20]" }, - { "ant": "[30, 40]" }, - { "molecule": "[100, 200]" }, - ] -} -values are (x, y) coordinates of centers of dragged images. -""" - - -import json -import six -from six.moves import zip - - -def flat_user_answer(user_answer): - """ - Convert nested `user_answer` to flat format. - - {'up': {'first': {'p': 'p_l'}}} - - to - - {'up': 'p_l[p][first]'} - """ - - def parse_user_answer(answer): - key = list(answer.keys())[0] - value = list(answer.values())[0] - if isinstance(value, dict): - - # Make complex value: - # Example: - # Create like 'p_l[p][first]' from {'first': {'p': 'p_l'} - complex_value_list = [] - v_value = value - while isinstance(v_value, dict): - v_key = list(v_value.keys())[0] - v_value = list(v_value.values())[0] - complex_value_list.append(v_key) - - complex_value = '{0}'.format(v_value) - for i in reversed(complex_value_list): - complex_value = '{0}[{1}]'.format(complex_value, i) - - res = {key: complex_value} - return res - else: - return answer - - result = [] - for answer in user_answer: - parse_answer = parse_user_answer(answer) - result.append(parse_answer) - - return result - - -class PositionsCompare(list): - """ Class for comparing positions. - - Args: - list or string:: - "abc" - target - [10, 20] - list of integers - [[10, 20], 200] list of list and integer - - """ - def __eq__(self, other): - """ Compares two arguments. - - Default lists behavior is conversion of string "abc" to list - ["a", "b", "c"]. We will use that. - - If self or other is empty - returns False. - - Args: - self, other: str, unicode, list, int, float - - Returns: bool - """ - # checks if self or other is not empty list (empty lists = false) - if not self or not other: - return False - - if (isinstance(self[0], (list, int, float)) and - isinstance(other[0], (list, int, float))): - return self.coordinate_positions_compare(other) - - elif (isinstance(self[0], (six.text_type, str)) and - isinstance(other[0], (six.text_type, str))): - return ''.join(self) == ''.join(other) - else: # improper argument types: no (float / int or lists of list - #and float / int pair) or two string / unicode lists pair - return False - - def __ne__(self, other): - return not self.__eq__(other) - - def coordinate_positions_compare(self, other, r=10): - """ Checks if self is equal to other inside radius of forgiveness - (default 10 px). - - Args: - self, other: [x, y] or [[x, y], r], where r is radius of - forgiveness; - x, y, r: int - - Returns: bool. - """ - # get max radius of forgiveness - if isinstance(self[0], list): # [(x, y), r] case - r = max(self[1], r) - x1, y1 = self[0] - else: - x1, y1 = self - - if isinstance(other[0], list): # [(x, y), r] case - r = max(other[1], r) - x2, y2 = other[0] - else: - x2, y2 = other - - if (x2 - x1) ** 2 + (y2 - y1) ** 2 > r * r: - return False - - return True - - -class DragAndDrop(object): - """ Grader class for drag and drop inputtype. - """ - - def grade(self): - ''' Grader user answer. - - Checks if every draggable isplaced on proper target or on proper - coordinates within radius of forgiveness (default is 10). - - Returns: bool. - ''' - for draggable in self.excess_draggables: - if self.excess_draggables[draggable]: - return False # user answer has more draggables than correct answer - - # Number of draggables in user_groups may be differ that in - # correct_groups, that is incorrect, except special case with 'number' - for index, draggable_ids in enumerate(self.correct_groups): - # 'number' rule special case - # for reusable draggables we may get in self.user_groups - # {'1': [u'2', u'2', u'2'], '0': [u'1', u'1'], '2': [u'3']} - # if '+number' is in rule - do not remove duplicates and strip - # '+number' from rule - current_rule = list(self.correct_positions[index].keys())[0] - if 'number' in current_rule: - rule_values = self.correct_positions[index][current_rule] - # clean rule, do not do clean duplicate items - self.correct_positions[index].pop(current_rule, None) - parsed_rule = current_rule.replace('+', '').replace('number', '') - self.correct_positions[index][parsed_rule] = rule_values - else: # remove dublicates - self.user_groups[index] = list(set(self.user_groups[index])) - - if sorted(draggable_ids) != sorted(self.user_groups[index]): - return False - - # Check that in every group, for rule of that group, user positions of - # every element are equal with correct positions - for index, _ in enumerate(self.correct_groups): - rules_executed = 0 - for rule in ('exact', 'anyof', 'unordered_equal'): - # every group has only one rule - if self.correct_positions[index].get(rule, None): - rules_executed += 1 - if not self.compare_positions( - self.correct_positions[index][rule], - self.user_positions[index]['user'], flag=rule): - return False - if not rules_executed: # no correct rules for current group - # probably xml content mistake - wrong rules names - return False - - return True - - def compare_positions(self, correct, user, flag): - """ Compares two lists of positions with flag rules. Order of - correct/user arguments is matter only in 'anyof' flag. - - Rules description: - - 'exact' means 1-1 ordered relationship:: - - [el1, el2, el3] is 'exact' equal to [el5, el6, el7] when - el1 == el5, el2 == el6, el3 == el7. - Equality function is custom, see below. - - - 'anyof' means subset relationship:: - - user = [el1, el2] is 'anyof' equal to correct = [el1, el2, el3] - when - set(user) <= set(correct). - - 'anyof' is ordered relationship. It always checks if user - is subset of correct - - Equality function is custom, see below. - - Examples: - - - many draggables per position: - user ['1', '2', '2', '2'] is 'anyof' equal to ['1', '2', '3'] - - - draggables can be placed in any order: - user ['1', '2', '3', '4'] is 'anyof' equal to ['4', '2', '1', 3'] - - 'unordered_equal' is same as 'exact' but disregards on order - - Equality functions: - - Equality functon depends on type of element. They declared in - PositionsCompare class. For position like targets - ids ("t1", "t2", etc..) it is string equality function. For coordinate - positions ([1, 2] or [[1, 2], 15]) it is coordinate_positions_compare - function (see docstrings in PositionsCompare class) - - Args: - correst, user: lists of positions - - Returns: True if within rule lists are equal, otherwise False. - """ - if flag == 'exact': - if len(correct) != len(user): - return False - for el1, el2 in zip(correct, user): - if PositionsCompare(el1) != PositionsCompare(el2): - return False - - if flag == 'anyof': - for u_el in user: - for c_el in correct: - if PositionsCompare(u_el) == PositionsCompare(c_el): - break - else: - # General: the else is executed after the for, - # only if the for terminates normally (not by a break) - - # In this case, 'for' is terminated normally if every element - # from 'correct' list isn't equal to concrete element from - # 'user' list. So as we found one element from 'user' list, - # that not in 'correct' list - we return False - return False - - if flag == 'unordered_equal': - if len(correct) != len(user): - return False - temp = correct[:] - for u_el in user: - for c_el in temp: - if PositionsCompare(u_el) == PositionsCompare(c_el): - temp.remove(c_el) - break - else: - # same as upper - if we found element from 'user' list, - # that not in 'correct' list - we return False. - return False - - return True - - def __init__(self, correct_answer, user_answer): - """ Populates DragAndDrop variables from user_answer and correct_answer. - If correct_answer is dict, converts it to list. - Correct answer in dict form is simple structure for fast and simple - grading. Example of correct answer dict example:: - - correct_answer = {'name4': 't1', - 'name_with_icon': 't1', - '5': 't2', - '7': 't2'} - - It is draggable_name: dragable_position mapping. - - Advanced form converted from simple form uses 'exact' rule - for matching. - - Correct answer in list form is designed for advanced cases:: - - correct_answers = [ - { - 'draggables': ['1', '2', '3', '4', '5', '6'], - 'targets': [ - 's_left', 's_right', 's_sigma', 's_sigma_star', 'p_pi_1', 'p_pi_2'], - 'rule': 'anyof'}, - { - 'draggables': ['7', '8', '9', '10'], - 'targets': ['p_left_1', 'p_left_2', 'p_right_1', 'p_right_2'], - 'rule': 'anyof' - } - ] - - Advanced answer in list form is list of dicts, and every dict must have - 3 keys: 'draggables', 'targets' and 'rule'. 'Draggables' value is - list of draggables ids, 'targes' values are list of targets ids, 'rule' - value one of 'exact', 'anyof', 'unordered_equal', 'anyof+number', - 'unordered_equal+number' - - Advanced form uses "all dicts must match with their rule" logic. - - Same draggable cannot appears more that in one dict. - - Behavior is more widely explained in sphinx documentation. - - Args: - user_answer: json - correct_answer: dict or list - """ - - self.correct_groups = [] # Correct groups from xml. - self.correct_positions = [] # Correct positions for comparing. - self.user_groups = [] # Will be populated from user answer. - self.user_positions = [] # Will be populated from user answer. - - # Convert from dict answer format to list format. - if isinstance(correct_answer, dict): - tmp = [] - for key in sorted(correct_answer.keys()): - value = correct_answer[key] - tmp.append({ - 'draggables': [key], - 'targets': [value], - 'rule': 'exact'}) - correct_answer = tmp - - # Convert string `user_answer` to object. - user_answer = json.loads(user_answer) - - # This dictionary will hold a key for each draggable the user placed on - # the image. The value is True if that draggable is not mentioned in any - # correct_answer entries. If the draggable is mentioned in at least one - # correct_answer entry, the value is False. - # default to consider every user answer excess until proven otherwise. - self.excess_draggables = dict( - (list(users_draggable.keys())[0], True) - for users_draggable in user_answer - ) - - # Convert nested `user_answer` to flat format. - user_answer = flat_user_answer(user_answer) - - # Create identical data structures from user answer and correct answer. - for answer in correct_answer: - user_groups_data = [] - user_positions_data = [] - for draggable_dict in user_answer: - # Draggable_dict is 1-to-1 {draggable_name: position}. - draggable_name = list(draggable_dict.keys())[0] - if draggable_name in answer['draggables']: - user_groups_data.append(draggable_name) - user_positions_data.append( - draggable_dict[draggable_name] - ) - # proved that this is not excess - self.excess_draggables[draggable_name] = False - - self.correct_groups.append(answer['draggables']) - self.correct_positions.append({answer['rule']: answer['targets']}) - self.user_groups.append(user_groups_data) - self.user_positions.append({'user': user_positions_data}) - - -def grade(user_input, correct_answer): - """ Creates DragAndDrop instance from user_input and correct_answer and - calls DragAndDrop.grade for grading. - - Supports two interfaces for correct_answer: dict and list. - - Args: - user_input: json. Format:: - - { "draggables": - [{"1": [10, 10]}, {"name_with_icon": [20, 20]}]}' - - or - - {"draggables": [{"1": "t1"}, \ - {"name_with_icon": "t2"}]} - - correct_answer: dict or list. - - Dict form:: - - {'1': 't1', 'name_with_icon': 't2'} - - or - - {'1': '[10, 10]', 'name_with_icon': '[[10, 10], 20]'} - - List form:: - - correct_answer = [ - { - 'draggables': ['l3_o', 'l10_o'], - 'targets': ['t1_o', 't9_o'], - 'rule': 'anyof' - }, - { - 'draggables': ['l1_c', 'l8_c'], - 'targets': ['t5_c', 't6_c'], - 'rule': 'anyof' - } - ] - - Returns: bool - """ - return DragAndDrop(correct_answer=correct_answer, - user_answer=user_input).grade() diff --git a/common/lib/sandbox-packages/verifiers/tests_draganddrop.py b/common/lib/sandbox-packages/verifiers/tests_draganddrop.py deleted file mode 100644 index 03bea08587..0000000000 --- a/common/lib/sandbox-packages/verifiers/tests_draganddrop.py +++ /dev/null @@ -1,843 +0,0 @@ -# lint-amnesty, pylint: disable=missing-module-docstring - -import json -import unittest - -from . import draganddrop - -from .draganddrop import PositionsCompare - - -class Test_PositionsCompare(unittest.TestCase): - """ describe""" - - def test_nested_list_and_list1(self): - assert PositionsCompare([[1, 2], 40]) == PositionsCompare([1, 3]) - - def test_nested_list_and_list2(self): - assert PositionsCompare([1, 12]) != PositionsCompare([1, 1]) - - def test_list_and_list1(self): - assert PositionsCompare([[1, 2], 12]) != PositionsCompare([1, 15]) - - def test_list_and_list2(self): - assert PositionsCompare([1, 11]) == PositionsCompare([1, 1]) - - def test_numerical_list_and_string_list(self): - assert PositionsCompare([1, 2]) != PositionsCompare(['1']) - - def test_string_and_string_list1(self): - assert PositionsCompare('1') == PositionsCompare(['1']) - - def test_string_and_string_list2(self): - assert PositionsCompare('abc') == PositionsCompare('abc') - - def test_string_and_string_list3(self): - assert PositionsCompare('abd') != PositionsCompare('abe') - - def test_float_and_string(self): - assert PositionsCompare([3.5, 5.7]) != PositionsCompare(['1']) - - def test_floats_and_ints(self): - assert PositionsCompare([3.5, 4.5]) == PositionsCompare([5, 7]) - - -class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disable=missing-class-docstring - - def test_targets_are_draggable_1(self): - user_input = json.dumps([ - {'p': 'p_l'}, - {'up': {'first': {'p': 'p_l'}}} - ]) - - correct_answer = [ - { - 'draggables': ['p'], - 'targets': ['p_l', 'p_r'], - 'rule': 'anyof' - }, - { - 'draggables': ['up'], - 'targets': [ - 'p_l[p][first]' - ], - 'rule': 'anyof' - } - ] - assert draganddrop.grade(user_input, correct_answer) - - def test_targets_are_draggable_2(self): - user_input = json.dumps([ - {'p': 'p_l'}, - {'p': 'p_r'}, - {'s': 's_l'}, - {'s': 's_r'}, - {'up': {'1': {'p': 'p_l'}}}, - {'up': {'3': {'p': 'p_l'}}}, - {'up': {'1': {'p': 'p_r'}}}, - {'up': {'3': {'p': 'p_r'}}}, - {'up_and_down': {'1': {'s': 's_l'}}}, - {'up_and_down': {'1': {'s': 's_r'}}} - ]) - - correct_answer = [ - { - 'draggables': ['p'], - 'targets': ['p_l', 'p_r'], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['s'], - 'targets': ['s_l', 's_r'], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['up_and_down'], - 'targets': ['s_l[s][1]', 's_r[s][1]'], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['up'], - 'targets': [ - 'p_l[p][1]', - 'p_l[p][3]', - 'p_r[p][1]', - 'p_r[p][3]', - ], - 'rule': 'unordered_equal' - } - ] - assert draganddrop.grade(user_input, correct_answer) - - def test_targets_are_draggable_2_manual_parsing(self): - user_input = json.dumps([ - {'up': 'p_l[p][1]'}, - {'p': 'p_l'}, - {'up': 'p_l[p][3]'}, - {'up': 'p_r[p][1]'}, - {'p': 'p_r'}, - {'up': 'p_r[p][3]'}, - {'up_and_down': 's_l[s][1]'}, - {'s': 's_l'}, - {'up_and_down': 's_r[s][1]'}, - {'s': 's_r'} - ]) - - correct_answer = [ - { - 'draggables': ['p'], - 'targets': ['p_l', 'p_r'], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['s'], - 'targets': ['s_l', 's_r'], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['up_and_down'], - 'targets': ['s_l[s][1]', 's_r[s][1]'], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['up'], - 'targets': [ - 'p_l[p][1]', - 'p_l[p][3]', - 'p_r[p][1]', - 'p_r[p][3]', - ], - 'rule': 'unordered_equal' - } - ] - assert draganddrop.grade(user_input, correct_answer) - - def test_targets_are_draggable_3_nested(self): - user_input = json.dumps([ - {'molecule': 'left_side_tagret'}, - {'molecule': 'right_side_tagret'}, - {'p': {'p_target': {'molecule': 'left_side_tagret'}}}, - {'p': {'p_target': {'molecule': 'right_side_tagret'}}}, - {'s': {'s_target': {'molecule': 'left_side_tagret'}}}, - {'s': {'s_target': {'molecule': 'right_side_tagret'}}}, - {'up': {'1': {'p': {'p_target': {'molecule': 'left_side_tagret'}}}}}, - {'up': {'3': {'p': {'p_target': {'molecule': 'left_side_tagret'}}}}}, - {'up': {'1': {'p': {'p_target': {'molecule': 'right_side_tagret'}}}}}, - {'up': {'3': {'p': {'p_target': {'molecule': 'right_side_tagret'}}}}}, - {'up_and_down': {'1': {'s': {'s_target': {'molecule': 'left_side_tagret'}}}}}, - {'up_and_down': {'1': {'s': {'s_target': {'molecule': 'right_side_tagret'}}}}} - ]) - - correct_answer = [ - { - 'draggables': ['molecule'], - 'targets': ['left_side_tagret', 'right_side_tagret'], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['p'], - 'targets': [ - 'left_side_tagret[molecule][p_target]', - 'right_side_tagret[molecule][p_target]', - ], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['s'], - 'targets': [ - 'left_side_tagret[molecule][s_target]', - 'right_side_tagret[molecule][s_target]', - ], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['up_and_down'], - 'targets': [ - 'left_side_tagret[molecule][s_target][s][1]', - 'right_side_tagret[molecule][s_target][s][1]', - ], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['up'], - 'targets': [ - 'left_side_tagret[molecule][p_target][p][1]', - 'left_side_tagret[molecule][p_target][p][3]', - 'right_side_tagret[molecule][p_target][p][1]', - 'right_side_tagret[molecule][p_target][p][3]', - ], - 'rule': 'unordered_equal' - } - ] - assert draganddrop.grade(user_input, correct_answer) - - def test_targets_are_draggable_4_real_example(self): - user_input = json.dumps([ - {'single_draggable': 's_l'}, - {'single_draggable': 's_r'}, - {'single_draggable': 'p_sigma'}, - {'single_draggable': 'p_sigma*'}, - {'single_draggable': 's_sigma'}, - {'single_draggable': 's_sigma*'}, - {'double_draggable': 'p_pi*'}, - {'double_draggable': 'p_pi'}, - {'triple_draggable': 'p_l'}, - {'triple_draggable': 'p_r'}, - {'up': {'1': {'triple_draggable': 'p_l'}}}, - {'up': {'2': {'triple_draggable': 'p_l'}}}, - {'up': {'2': {'triple_draggable': 'p_r'}}}, - {'up': {'3': {'triple_draggable': 'p_r'}}}, - {'up_and_down': {'1': {'single_draggable': 's_l'}}}, - {'up_and_down': {'1': {'single_draggable': 's_r'}}}, - {'up_and_down': {'1': {'single_draggable': 's_sigma'}}}, - {'up_and_down': {'1': {'single_draggable': 's_sigma*'}}}, - {'up_and_down': {'1': {'double_draggable': 'p_pi'}}}, - {'up_and_down': {'2': {'double_draggable': 'p_pi'}}} - ]) - - # 10 targets: - # s_l, s_r, p_l, p_r, s_sigma, s_sigma*, p_pi, p_sigma, p_pi*, p_sigma* - # - # 3 draggable objects, which have targets (internal target ids - 1, 2, 3): - # single_draggable, double_draggable, triple_draggable - # - # 2 draggable objects: - # up, up_and_down - correct_answer = [ - { - 'draggables': ['triple_draggable'], - 'targets': ['p_l', 'p_r'], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['double_draggable'], - 'targets': ['p_pi', 'p_pi*'], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['single_draggable'], - 'targets': ['s_l', 's_r', 's_sigma', 's_sigma*', 'p_sigma', 'p_sigma*'], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['up'], - 'targets': [ - 'p_l[triple_draggable][1]', - 'p_l[triple_draggable][2]', - 'p_r[triple_draggable][2]', - 'p_r[triple_draggable][3]', - ], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['up_and_down'], - 'targets': [ - 's_l[single_draggable][1]', - 's_r[single_draggable][1]', - 's_sigma[single_draggable][1]', - 's_sigma*[single_draggable][1]', - 'p_pi[double_draggable][1]', - 'p_pi[double_draggable][2]', - ], - 'rule': 'unordered_equal' - }, - - ] - assert draganddrop.grade(user_input, correct_answer) - - def test_targets_true(self): - user_input = '[{"1": "t1"}, \ - {"name_with_icon": "t2"}]' - correct_answer = {'1': 't1', 'name_with_icon': 't2'} - assert draganddrop.grade(user_input, correct_answer) - - def test_expect_no_actions_wrong(self): - user_input = '[{"1": "t1"}, \ - {"name_with_icon": "t2"}]' - correct_answer = [] - assert not draganddrop.grade(user_input, correct_answer) - - def test_expect_no_actions_right(self): - user_input = '[]' - correct_answer = [] - assert draganddrop.grade(user_input, correct_answer) - - def test_targets_false(self): - user_input = '[{"1": "t1"}, \ - {"name_with_icon": "t2"}]' - correct_answer = {'1': 't3', 'name_with_icon': 't2'} - assert not draganddrop.grade(user_input, correct_answer) - - def test_multiple_images_per_target_true(self): - user_input = '[{"1": "t1"}, {"name_with_icon": "t2"}, \ - {"2": "t1"}]' - correct_answer = {'1': 't1', 'name_with_icon': 't2', '2': 't1'} - assert draganddrop.grade(user_input, correct_answer) - - def test_multiple_images_per_target_false(self): - user_input = '[{"1": "t1"}, {"name_with_icon": "t2"}, \ - {"2": "t1"}]' - correct_answer = {'1': 't2', 'name_with_icon': 't2', '2': 't1'} - assert not draganddrop.grade(user_input, correct_answer) - - def test_targets_and_positions(self): - user_input = '[{"1": [10,10]}, \ - {"name_with_icon": [[10,10],4]}]' - correct_answer = {'1': [10, 10], 'name_with_icon': [[10, 10], 4]} - assert draganddrop.grade(user_input, correct_answer) - - def test_position_and_targets(self): - user_input = '[{"1": "t1"}, {"name_with_icon": "t2"}]' - correct_answer = {'1': 't1', 'name_with_icon': 't2'} - assert draganddrop.grade(user_input, correct_answer) - - def test_positions_exact(self): - user_input = '[{"1": [10, 10]}, {"name_with_icon": [20, 20]}]' - correct_answer = {'1': [10, 10], 'name_with_icon': [20, 20]} - assert draganddrop.grade(user_input, correct_answer) - - def test_positions_false(self): - user_input = '[{"1": [10, 10]}, {"name_with_icon": [20, 20]}]' - correct_answer = {'1': [25, 25], 'name_with_icon': [20, 20]} - assert not draganddrop.grade(user_input, correct_answer) - - def test_positions_true_in_radius(self): - user_input = '[{"1": [10, 10]}, {"name_with_icon": [20, 20]}]' - correct_answer = {'1': [14, 14], 'name_with_icon': [20, 20]} - assert draganddrop.grade(user_input, correct_answer) - - def test_positions_true_in_manual_radius(self): - user_input = '[{"1": [10, 10]}, {"name_with_icon": [20, 20]}]' - correct_answer = {'1': [[40, 10], 30], 'name_with_icon': [20, 20]} - assert draganddrop.grade(user_input, correct_answer) - - def test_positions_false_in_manual_radius(self): - user_input = '[{"1": [10, 10]}, {"name_with_icon": [20, 20]}]' - correct_answer = {'1': [[40, 10], 29], 'name_with_icon': [20, 20]} - assert not draganddrop.grade(user_input, correct_answer) - - def test_correct_answer_not_has_key_from_user_answer(self): - user_input = '[{"1": "t1"}, {"name_with_icon": "t2"}]' - correct_answer = {'3': 't3', 'name_with_icon': 't2'} - assert not draganddrop.grade(user_input, correct_answer) - - def test_anywhere(self): - """Draggables can be places anywhere on base image. - Place grass in the middle of the image and ant in the - right upper corner.""" - user_input = '[{"ant":[610.5,57.449951171875]},\ - {"grass":[322.5,199.449951171875]}]' - - correct_answer = {'grass': [[300, 200], 200], 'ant': [[500, 0], 200]} - assert draganddrop.grade(user_input, correct_answer) - - def test_lcao_correct(self): - """Describe carbon molecule in LCAO-MO""" - user_input = '[{"1":"s_left"}, \ - {"5":"s_right"},{"4":"s_sigma"},{"6":"s_sigma_star"},{"7":"p_left_1"}, \ - {"8":"p_left_2"},{"10":"p_right_1"},{"9":"p_right_2"}, \ - {"2":"p_pi_1"},{"3":"p_pi_2"},{"11":"s_sigma_name"}, \ - {"13":"s_sigma_star_name"},{"15":"p_pi_name"},{"16":"p_pi_star_name"}, \ - {"12":"p_sigma_name"},{"14":"p_sigma_star_name"}]' - - correct_answer = [{ - 'draggables': ['1', '2', '3', '4', '5', '6'], - 'targets': [ - 's_left', 's_right', 's_sigma', 's_sigma_star', 'p_pi_1', 'p_pi_2' - ], - 'rule': 'anyof' - }, { - 'draggables': ['7', '8', '9', '10'], - 'targets': ['p_left_1', 'p_left_2', 'p_right_1', 'p_right_2'], - 'rule': 'anyof' - }, { - 'draggables': ['11', '12'], - 'targets': ['s_sigma_name', 'p_sigma_name'], - 'rule': 'anyof' - }, { - 'draggables': ['13', '14'], - 'targets': ['s_sigma_star_name', 'p_sigma_star_name'], - 'rule': 'anyof' - }, { - 'draggables': ['15'], - 'targets': ['p_pi_name'], - 'rule': 'anyof' - }, { - 'draggables': ['16'], - 'targets': ['p_pi_star_name'], - 'rule': 'anyof' - }] - - assert draganddrop.grade(user_input, correct_answer) - - def test_lcao_extra_element_incorrect(self): - """Describe carbon molecule in LCAO-MO""" - user_input = '[{"1":"s_left"}, \ - {"5":"s_right"},{"4":"s_sigma"},{"6":"s_sigma_star"},{"7":"p_left_1"}, \ - {"8":"p_left_2"},{"17":"p_left_3"},{"10":"p_right_1"},{"9":"p_right_2"}, \ - {"2":"p_pi_1"},{"3":"p_pi_2"},{"11":"s_sigma_name"}, \ - {"13":"s_sigma_star_name"},{"15":"p_pi_name"},{"16":"p_pi_star_name"}, \ - {"12":"p_sigma_name"},{"14":"p_sigma_star_name"}]' - - correct_answer = [{ - 'draggables': ['1', '2', '3', '4', '5', '6'], - 'targets': [ - 's_left', 's_right', 's_sigma', 's_sigma_star', 'p_pi_1', 'p_pi_2' - ], - 'rule': 'anyof' - }, { - 'draggables': ['7', '8', '9', '10'], - 'targets': ['p_left_1', 'p_left_2', 'p_right_1', 'p_right_2'], - 'rule': 'anyof' - }, { - 'draggables': ['11', '12'], - 'targets': ['s_sigma_name', 'p_sigma_name'], - 'rule': 'anyof' - }, { - 'draggables': ['13', '14'], - 'targets': ['s_sigma_star_name', 'p_sigma_star_name'], - 'rule': 'anyof' - }, { - 'draggables': ['15'], - 'targets': ['p_pi_name'], - 'rule': 'anyof' - }, { - 'draggables': ['16'], - 'targets': ['p_pi_star_name'], - 'rule': 'anyof' - }] - - assert not draganddrop.grade(user_input, correct_answer) - - def test_reuse_draggable_no_mupliples(self): - """Test reusable draggables (no mupltiple draggables per target)""" - user_input = '[{"1":"target1"}, \ - {"2":"target2"},{"1":"target3"},{"2":"target4"},{"2":"target5"}, \ - {"3":"target6"}]' - correct_answer = [ - { - 'draggables': ['1'], - 'targets': ['target1', 'target3'], - 'rule': 'anyof' - }, - { - 'draggables': ['2'], - 'targets': ['target2', 'target4', 'target5'], - 'rule': 'anyof' - }, - { - 'draggables': ['3'], - 'targets': ['target6'], - 'rule': 'anyof' - } - ] - assert draganddrop.grade(user_input, correct_answer) - - def test_reuse_draggable_with_mupliples(self): - """Test reusable draggables with mupltiple draggables per target""" - user_input = '[{"1":"target1"}, \ - {"2":"target2"},{"1":"target1"},{"2":"target4"},{"2":"target4"}, \ - {"3":"target6"}]' - correct_answer = [ - { - 'draggables': ['1'], - 'targets': ['target1', 'target3'], - 'rule': 'anyof' - }, - { - 'draggables': ['2'], - 'targets': ['target2', 'target4'], - 'rule': 'anyof' - }, - { - 'draggables': ['3'], - 'targets': ['target6'], - 'rule': 'anyof' - } - ] - assert draganddrop.grade(user_input, correct_answer) - - def test_reuse_many_draggable_with_mupliples(self): - """Test reusable draggables with mupltiple draggables per target""" - user_input = '[{"1":"target1"}, \ - {"2":"target2"},{"1":"target1"},{"2":"target4"},{"2":"target4"}, \ - {"3":"target6"}, {"4": "target3"}, {"5": "target4"}, \ - {"5": "target5"}, {"6": "target2"}]' - correct_answer = [ - { - 'draggables': ['1', '4'], - 'targets': ['target1', 'target3'], - 'rule': 'anyof' - }, - { - 'draggables': ['2', '6'], - 'targets': ['target2', 'target4'], - 'rule': 'anyof' - }, - { - 'draggables': ['5'], - 'targets': ['target4', 'target5'], - 'rule': 'anyof' - }, - { - 'draggables': ['3'], - 'targets': ['target6'], - 'rule': 'anyof' - } - ] - assert draganddrop.grade(user_input, correct_answer) - - def test_reuse_many_draggable_with_mupliples_wrong(self): - """Test reusable draggables with mupltiple draggables per target""" - user_input = '[{"1":"target1"}, \ - {"2":"target2"},{"1":"target1"}, \ - {"2":"target3"}, \ - {"2":"target4"}, \ - {"3":"target6"}, {"4": "target3"}, {"5": "target4"}, \ - {"5": "target5"}, {"6": "target2"}]' - correct_answer = [ - { - 'draggables': ['1', '4'], - 'targets': ['target1', 'target3'], - 'rule': 'anyof' - }, - { - 'draggables': ['2', '6'], - 'targets': ['target2', 'target4'], - 'rule': 'anyof' - }, - { - 'draggables': ['5'], - 'targets': ['target4', 'target5'], - 'rule': 'anyof' - }, - { - 'draggables': ['3'], - 'targets': ['target6'], - 'rule': 'anyof' - }] - assert not draganddrop.grade(user_input, correct_answer) - - def test_label_10_targets_with_a_b_c_false(self): - """Test reusable draggables (no mupltiple draggables per target)""" - user_input = '[{"a":"target1"}, \ - {"b":"target2"},{"c":"target3"},{"a":"target4"},{"b":"target5"}, \ - {"c":"target6"}, {"a":"target7"},{"b":"target8"},{"c":"target9"}, \ - {"a":"target1"}]' - correct_answer = [ - { - 'draggables': ['a'], - 'targets': ['target1', 'target4', 'target7', 'target10'], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['b'], - 'targets': ['target2', 'target5', 'target8'], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['c'], - 'targets': ['target3', 'target6', 'target9'], - 'rule': 'unordered_equal' - } - ] - assert not draganddrop.grade(user_input, correct_answer) - - def test_label_10_targets_with_a_b_c_(self): - """Test reusable draggables (no mupltiple draggables per target)""" - user_input = '[{"a":"target1"}, \ - {"b":"target2"},{"c":"target3"},{"a":"target4"},{"b":"target5"}, \ - {"c":"target6"}, {"a":"target7"},{"b":"target8"},{"c":"target9"}, \ - {"a":"target10"}]' - correct_answer = [ - { - 'draggables': ['a'], - 'targets': ['target1', 'target4', 'target7', 'target10'], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['b'], - 'targets': ['target2', 'target5', 'target8'], - 'rule': 'unordered_equal' - }, - { - 'draggables': ['c'], - 'targets': ['target3', 'target6', 'target9'], - 'rule': 'unordered_equal' - } - ] - assert draganddrop.grade(user_input, correct_answer) - - def test_label_10_targets_with_a_b_c_multiple(self): - """Test reusable draggables (mupltiple draggables per target)""" - user_input = '[{"a":"target1"}, \ - {"b":"target2"},{"c":"target3"},{"b":"target5"}, \ - {"c":"target6"}, {"a":"target7"},{"b":"target8"},{"c":"target9"}, \ - {"a":"target1"}]' - correct_answer = [ - { - 'draggables': ['a', 'a', 'a'], - 'targets': ['target1', 'target4', 'target7', 'target10'], - 'rule': 'anyof+number' - }, - { - 'draggables': ['b', 'b', 'b'], - 'targets': ['target2', 'target5', 'target8'], - 'rule': 'anyof+number' - }, - { - 'draggables': ['c', 'c', 'c'], - 'targets': ['target3', 'target6', 'target9'], - 'rule': 'anyof+number' - } - ] - assert draganddrop.grade(user_input, correct_answer) - - def test_label_10_targets_with_a_b_c_multiple_false(self): - """Test reusable draggables (mupltiple draggables per target)""" - user_input = '[{"a":"target1"}, \ - {"b":"target2"},{"c":"target3"},{"a":"target4"},{"b":"target5"}, \ - {"c":"target6"}, {"a":"target7"},{"b":"target8"},{"c":"target9"}, \ - {"a":"target1"}]' - correct_answer = [ - { - 'draggables': ['a', 'a', 'a'], - 'targets': ['target1', 'target4', 'target7', 'target10'], - 'rule': 'anyof+number' - }, - { - 'draggables': ['b', 'b', 'b'], - 'targets': ['target2', 'target5', 'target8'], - 'rule': 'anyof+number' - }, - { - 'draggables': ['c', 'c', 'c'], - 'targets': ['target3', 'target6', 'target9'], - 'rule': 'anyof+number' - } - ] - assert not draganddrop.grade(user_input, correct_answer) - - def test_label_10_targets_with_a_b_c_reused(self): - """Test a b c in 10 labels reused""" - user_input = '[{"a":"target1"}, \ - {"b":"target2"},{"c":"target3"},{"b":"target5"}, \ - {"c":"target6"}, {"b":"target8"},{"c":"target9"}, \ - {"a":"target10"}]' - correct_answer = [ - { - 'draggables': ['a', 'a'], - 'targets': ['target1', 'target10'], - 'rule': 'unordered_equal+number' - }, - { - 'draggables': ['b', 'b', 'b'], - 'targets': ['target2', 'target5', 'target8'], - 'rule': 'unordered_equal+number' - }, - { - 'draggables': ['c', 'c', 'c'], - 'targets': ['target3', 'target6', 'target9'], - 'rule': 'unordered_equal+number' - } - ] - assert draganddrop.grade(user_input, correct_answer) - - def test_label_10_targets_with_a_b_c_reused_false(self): - """Test a b c in 10 labels reused false""" - user_input = '[{"a":"target1"}, \ - {"b":"target2"},{"c":"target3"},{"b":"target5"}, {"a":"target8"},\ - {"c":"target6"}, {"b":"target8"},{"c":"target9"}, \ - {"a":"target10"}]' - correct_answer = [ - { - 'draggables': ['a', 'a'], - 'targets': ['target1', 'target10'], - 'rule': 'unordered_equal+number' - }, - { - 'draggables': ['b', 'b', 'b'], - 'targets': ['target2', 'target5', 'target8'], - 'rule': 'unordered_equal+number' - }, - { - 'draggables': ['c', 'c', 'c'], - 'targets': ['target3', 'target6', 'target9'], - 'rule': 'unordered_equal+number' - } - ] - assert not draganddrop.grade(user_input, correct_answer) - - def test_mixed_reuse_and_not_reuse(self): - """Test reusable draggables """ - user_input = '[{"a":"target1"}, \ - {"b":"target2"},{"c":"target3"}, {"a":"target4"},\ - {"a":"target5"}]' - correct_answer = [ - { - 'draggables': ['a', 'b'], - 'targets': ['target1', 'target2', 'target4', 'target5'], - 'rule': 'anyof' - }, - { - 'draggables': ['c'], - 'targets': ['target3'], - 'rule': 'exact' - } - ] - assert draganddrop.grade(user_input, correct_answer) - - def test_mixed_reuse_and_not_reuse_number(self): - """Test reusable draggables with number """ - user_input = '[{"a":"target1"}, \ - {"b":"target2"},{"c":"target3"}, {"a":"target4"}]' - correct_answer = [ - { - 'draggables': ['a', 'a', 'b'], - 'targets': ['target1', 'target2', 'target4'], - 'rule': 'anyof+number' - }, - { - 'draggables': ['c'], - 'targets': ['target3'], - 'rule': 'exact' - } - ] - assert draganddrop.grade(user_input, correct_answer) - - def test_mixed_reuse_and_not_reuse_number_false(self): - """Test reusable draggables with numbers, but wrong""" - user_input = '[{"a":"target1"}, \ - {"b":"target2"},{"c":"target3"}, {"a":"target4"}, {"a":"target10"}]' - correct_answer = [ - { - 'draggables': ['a', 'a', 'b'], - 'targets': ['target1', 'target2', 'target4', 'target10'], - 'rule': 'anyof_number' - }, - { - 'draggables': ['c'], - 'targets': ['target3'], - 'rule': 'exact' - } - ] - assert not draganddrop.grade(user_input, correct_answer) - - def test_alternative_correct_answer(self): - user_input = '[{"name_with_icon":"t1"},\ - {"name_with_icon":"t1"},{"name_with_icon":"t1"},{"name4":"t1"}, \ - {"name4":"t1"}]' - correct_answer = [ - {'draggables': ['name4'], 'targets': ['t1', 't1'], 'rule': 'exact'}, - {'draggables': ['name_with_icon'], 'targets': ['t1', 't1', 't1'], - 'rule': 'exact'} - ] - assert draganddrop.grade(user_input, correct_answer) - - -class Test_DragAndDrop_Populate(unittest.TestCase): # lint-amnesty, pylint: disable=missing-class-docstring - - def test_1(self): - correct_answer = {'1': [[40, 10], 29], 'name_with_icon': [20, 20]} - user_input = '[{"1": [10, 10]}, {"name_with_icon": [20, 20]}]' - dnd = draganddrop.DragAndDrop(correct_answer, user_input) - - correct_groups = [['1'], ['name_with_icon']] - correct_positions = [{'exact': [[[40, 10], 29]]}, {'exact': [[20, 20]]}] - user_groups = [['1'], ['name_with_icon']] - user_positions = [{'user': [[10, 10]]}, {'user': [[20, 20]]}] - - assert correct_groups == dnd.correct_groups - assert correct_positions == dnd.correct_positions - assert user_groups == dnd.user_groups - assert user_positions == dnd.user_positions - - -class Test_DraAndDrop_Compare_Positions(unittest.TestCase): # lint-amnesty, pylint: disable=missing-class-docstring - - def test_1(self): - dnd = draganddrop.DragAndDrop({'1': 't1'}, '[{"1": "t1"}]') - assert dnd.compare_positions(correct=[[1, 1], [2, 3]], user=[[2, 3], [1, 1]], flag='anyof') - - def test_2a(self): - dnd = draganddrop.DragAndDrop({'1': 't1'}, '[{"1": "t1"}]') - assert dnd.compare_positions(correct=[[1, 1], [2, 3]], user=[[2, 3], [1, 1]], flag='exact') - - def test_2b(self): - dnd = draganddrop.DragAndDrop({'1': 't1'}, '[{"1": "t1"}]') - assert not dnd.compare_positions(correct=[[1, 1], [2, 3]], user=[[2, 13], [1, 1]], flag='exact') - - def test_3(self): - dnd = draganddrop.DragAndDrop({'1': 't1'}, '[{"1": "t1"}]') - assert not dnd.compare_positions(correct=['a', 'b'], user=['a', 'b', 'c'], flag='anyof') - - def test_4(self): - dnd = draganddrop.DragAndDrop({'1': 't1'}, '[{"1": "t1"}]') - assert dnd.compare_positions(correct=['a', 'b', 'c'], user=['a', 'b'], flag='anyof') - - def test_5(self): - dnd = draganddrop.DragAndDrop({'1': 't1'}, '[{"1": "t1"}]') - assert not dnd.compare_positions(correct=['a', 'b', 'c'], user=['a', 'c', 'b'], flag='exact') - - def test_6(self): - dnd = draganddrop.DragAndDrop({'1': 't1'}, '[{"1": "t1"}]') - assert dnd.compare_positions(correct=['a', 'b', 'c'], user=['a', 'c', 'b'], flag='anyof') - - def test_7(self): - dnd = draganddrop.DragAndDrop({'1': 't1'}, '[{"1": "t1"}]') - assert not dnd.compare_positions(correct=['a', 'b', 'b'], user=['a', 'c', 'b'], flag='anyof') - - -def suite(): # lint-amnesty, pylint: disable=missing-function-docstring - - testcases = [Test_PositionsCompare, - Test_DragAndDrop_Populate, - Test_DragAndDrop_Grade, - Test_DraAndDrop_Compare_Positions] - suites = [] - for testcase in testcases: - suites.append(unittest.TestLoader().loadTestsFromTestCase(testcase)) - return unittest.TestSuite(suites) - -if __name__ == "__main__": - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/pavelib/quality.py b/pavelib/quality.py index 1a2d83a4fa..9f233c8a70 100644 --- a/pavelib/quality.py +++ b/pavelib/quality.py @@ -71,10 +71,7 @@ def top_python_dirs(dirname): dirs = os.listdir(subdir) top_dirs.extend(d for d in dirs if os.path.isdir(os.path.join(subdir, d))) - # sandbox-packages module causes F0001: module-not-found error when running pylint - # this will exclude sandbox-packages module from pylint execution - # TODO: upgrade the functionality to run pylint tests on sandbox-packages module too. - modules_to_remove = ['sandbox-packages', '__pycache__'] + modules_to_remove = ['__pycache__'] for module in modules_to_remove: if module in top_dirs: top_dirs.remove(module) diff --git a/requirements/edx-sandbox/py38.in b/requirements/edx-sandbox/py38.in index 9d90dcba97..115c8d98f4 100644 --- a/requirements/edx-sandbox/py38.in +++ b/requirements/edx-sandbox/py38.in @@ -11,12 +11,11 @@ pyparsing # Python Parsing module random2 # Implementation of random module that works identically under Python 2 and 3 scipy # Math, science, and engineering library sympy # Symbolic math library +codejail-includes # CodeJail manages execution of untrusted code in secure sandboxes. # numpy>=1.17.0 caused failures in importing numpy in code-jail environment. # The issue will be investigated and fixed in https://openedx.atlassian.net/browse/BOM-2841. numpy>=1.16.0,<1.17.0 -# Install these packages from the edx-platform working tree -# NOTE: if you change code in these packages, you MUST change the version -# number in its setup.py or the code WILL NOT be installed during deploy. --e common/lib/sandbox-packages + + diff --git a/requirements/edx-sandbox/py38.txt b/requirements/edx-sandbox/py38.txt index 8fde6fc3ff..8e164568f4 100644 --- a/requirements/edx-sandbox/py38.txt +++ b/requirements/edx-sandbox/py38.txt @@ -4,8 +4,6 @@ # # make upgrade # -common/lib/sandbox-packages - # via -r requirements/edx-sandbox/py38.in cffi==1.15.0 # via cryptography chem==1.2.0 @@ -14,6 +12,8 @@ click==8.1.3 # via # -c requirements/edx-sandbox/../constraints.txt # nltk +codejail-includes==1.0.0 + # via -r requirements/edx-sandbox/py38.in cryptography==37.0.2 # via -r requirements/edx-sandbox/py38.in cycler==0.11.0 @@ -82,6 +82,7 @@ scipy==1.7.3 six==1.16.0 # via # chem + # codejail-includes # python-dateutil sympy==1.10.1 # via diff --git a/requirements/edx/base.in b/requirements/edx/base.in index 1c88257651..703fc0ee97 100644 --- a/requirements/edx/base.in +++ b/requirements/edx/base.in @@ -36,6 +36,7 @@ botocore==1.8.17 # via boto3, s3transfer bridgekeeper # Used for determining permissions for courseware. celery # Asynchronous task execution library chem # A helper library for chemistry calculations +codejail-includes # CodeJail manages execution of untrusted code in secure sandboxes. contextlib2 # We need contextlib2.ExitStack so we can stop using contextlib.nested which doesn't exist in python 3 crowdsourcehinter-xblock cryptography # Implementations of assorted cryptography algorithms diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index c86e5eb722..1dce877b6f 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -22,8 +22,6 @@ # via -r requirements/edx/local.in -e git+https://github.com/edx/RateXBlock.git@2.0.1#egg=rate-xblock # via -r requirements/edx/github.in --e common/lib/sandbox-packages - # via -r requirements/edx/local.in -e openedx/core/lib/xblock_builtin/xblock_discussion # via -r requirements/edx/local.in -e git+https://github.com/edx-solutions/xblock-google-drive.git@2d176468e33c0713c911b563f8f65f7cf232f5b6#egg=xblock-google-drive @@ -143,6 +141,8 @@ code-annotations==1.3.0 # via # edx-enterprise # edx-toggles +codejail-includes==1.0.0 + # via -r requirements/edx/base.in contextlib2==21.6.0 # via -r requirements/edx/base.in coreapi==2.3.3 @@ -962,6 +962,7 @@ six==1.16.0 # chem # click-repl # codejail + # codejail-includes # crowdsourcehinter-xblock # edx-ace # edx-auth-backends diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index d8f9de315a..e42a7f83e0 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -22,8 +22,6 @@ # via -r requirements/edx/testing.txt -e git+https://github.com/edx/RateXBlock.git@2.0.1#egg=rate-xblock # via -r requirements/edx/testing.txt --e common/lib/sandbox-packages - # via -r requirements/edx/testing.txt -e openedx/core/lib/xblock_builtin/xblock_discussion # via -r requirements/edx/testing.txt -e git+https://github.com/edx-solutions/xblock-google-drive.git@2d176468e33c0713c911b563f8f65f7cf232f5b6#egg=xblock-google-drive @@ -203,6 +201,8 @@ code-annotations==1.3.0 # edx-enterprise # edx-lint # edx-toggles +codejail-includes==1.0.0 + # via -r requirements/edx/testing.txt contextlib2==21.6.0 # via -r requirements/edx/testing.txt coreapi==2.3.3 @@ -1334,6 +1334,7 @@ six==1.16.0 # chem # click-repl # codejail + # codejail-includes # crowdsourcehinter-xblock # edx-ace # edx-auth-backends diff --git a/requirements/edx/local.in b/requirements/edx/local.in index e68bbadf11..eb0165c473 100644 --- a/requirements/edx/local.in +++ b/requirements/edx/local.in @@ -1,7 +1,6 @@ # Python libraries to install that are local to the edx-platform repo -e . -e common/lib/capa --e common/lib/sandbox-packages -e common/lib/xmodule -e openedx/core/lib/xblock_builtin/xblock_discussion diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 390da4feb0..6b3da93e4a 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -22,8 +22,6 @@ # via -r requirements/edx/base.txt -e git+https://github.com/edx/RateXBlock.git@2.0.1#egg=rate-xblock # via -r requirements/edx/base.txt --e common/lib/sandbox-packages - # via -r requirements/edx/base.txt -e openedx/core/lib/xblock_builtin/xblock_discussion # via -r requirements/edx/base.txt -e git+https://github.com/edx-solutions/xblock-google-drive.git@2d176468e33c0713c911b563f8f65f7cf232f5b6#egg=xblock-google-drive @@ -195,6 +193,8 @@ code-annotations==1.3.0 # edx-enterprise # edx-lint # edx-toggles +codejail-includes==1.0.0 + # via -r requirements/edx/base.txt contextlib2==21.6.0 # via -r requirements/edx/base.txt coreapi==2.3.3 @@ -1261,6 +1261,7 @@ six==1.16.0 # chem # click-repl # codejail + # codejail-includes # crowdsourcehinter-xblock # edx-ace # edx-auth-backends diff --git a/scripts/verify-dunder-init.sh b/scripts/verify-dunder-init.sh index c6cf3134bb..9c9fbb130a 100755 --- a/scripts/verify-dunder-init.sh +++ b/scripts/verify-dunder-init.sh @@ -38,7 +38,7 @@ exclude+='|^common/test/data/?.*$' # * common/lib/xmodule -> EXCLUDE from check. # * common/lib/xmodule/xmodule/modulestore -> INCLUDE in check. exclude+='|^common/lib$' -exclude+='|^common/lib/(capa|sandbox-packages|xmodule)$' +exclude+='|^common/lib/(capa|xmodule)$' # Docs, scripts. exclude+='|^docs/.*$' From 2e13033fbe217a692409ac4b9b47e151a0df7e2d Mon Sep 17 00:00:00 2001 From: connorhaugh <49422820+connorhaugh@users.noreply.github.com> Date: Wed, 1 Jun 2022 10:52:09 -0400 Subject: [PATCH 06/63] Revert "Feat change default title for text xblock to be 'text'" --- .../contentstore/tests/test_utils.py | 31 ------------------- cms/djangoapps/contentstore/utils.py | 11 ------- cms/djangoapps/contentstore/views/item.py | 5 +-- cms/templates/studio_xblock_wrapper.html | 4 +-- 4 files changed, 3 insertions(+), 48 deletions(-) diff --git a/cms/djangoapps/contentstore/tests/test_utils.py b/cms/djangoapps/contentstore/tests/test_utils.py index d0c76125e9..2ed40b6942 100644 --- a/cms/djangoapps/contentstore/tests/test_utils.py +++ b/cms/djangoapps/contentstore/tests/test_utils.py @@ -736,34 +736,3 @@ class ValidateCourseOlxTests(CourseTestCase): ignore=ignore, allowed_xblocks=allowed_xblocks ) - - -class DetermineLabelTestCase(TestCase): - """Tests for xblock Title quirks""" - - def validate_html_replaced_with_text(self): - """ - Tests that display names for "html" xblocks are repleaced with "Text" when the display name is otherwise unset. - """ - display_name = None - block_type = "html" - result = utils.determine_label(display_name, block_type) - self.assertEqual(result, display_name) - - def validate_set_titles_not_replaced(self): - """ - Tests that display names for "html" xblocks are not repleaced with "Text" when the display name is set. - """ - display_name = "Something" - block_type = "html" - result = utils.determine_label(display_name, block_type) - self.assertEqual(result, display_name) - - def validate_non_html_blocks_titles_not_replaced(self): - """ - Tests that display names for non-"html" xblocks are not repleaced with "Text" when the display name is set. - """ - display_name = None - block_type = "something else" - result = utils.determine_label(display_name, block_type) - self.assertEqual(result, display_name) diff --git a/cms/djangoapps/contentstore/utils.py b/cms/djangoapps/contentstore/utils.py index bb5a53fb94..1e0d3e60c6 100644 --- a/cms/djangoapps/contentstore/utils.py +++ b/cms/djangoapps/contentstore/utils.py @@ -703,17 +703,6 @@ def get_sibling_urls(subsection, unit_location): # pylint: disable=too-many-s return prev_url, next_url -def determine_label(display_name, block_type): - """ - Returns the name of the xblock to display in studio. - Please see TNL-9838. - """ - label = display_name - if block_type == 'html': - label = _("Text") - return label - - @contextmanager def translation_language(language): """Context manager to override the translation language for the scope diff --git a/cms/djangoapps/contentstore/views/item.py b/cms/djangoapps/contentstore/views/item.py index 2ef9b80d38..69c3117417 100644 --- a/cms/djangoapps/contentstore/views/item.py +++ b/cms/djangoapps/contentstore/views/item.py @@ -427,16 +427,13 @@ def xblock_view_handler(request, usage_key_string, view_name): # Note that the container view recursively adds headers into the preview fragment, # so only the "Pages" view requires that this extra wrapper be included. - display_label = xblock.display_name or xblock.scope_ids.block_type - if not xblock.display_name and xblock.scope_ids.block_type == 'html': - display_label = _("Text") if is_pages_view: fragment.content = render_to_string('component.html', { 'xblock_context': context, 'xblock': xblock, 'locator': usage_key, 'preview': fragment.content, - 'label': display_label, + 'label': xblock.display_name or xblock.scope_ids.block_type, }) else: raise Http404 diff --git a/cms/templates/studio_xblock_wrapper.html b/cms/templates/studio_xblock_wrapper.html index 5f3b5bf875..15a2d3a857 100644 --- a/cms/templates/studio_xblock_wrapper.html +++ b/cms/templates/studio_xblock_wrapper.html @@ -2,7 +2,7 @@ <%! from django.utils.translation import gettext as _ from cms.djangoapps.contentstore.views.helpers import xblock_studio_url -from cms.djangoapps.contentstore.utils import is_visible_to_specific_partition_groups, get_editor_page_base_url, determine_label +from cms.djangoapps.contentstore.utils import is_visible_to_specific_partition_groups, get_editor_page_base_url from lms.lib.utils import is_unit from openedx.core.djangolib.js_utils import ( dump_js_escaped_json, js_escaped_string @@ -17,7 +17,7 @@ xblock_url = xblock_studio_url(xblock) show_inline = xblock.has_children and not xblock_url section_class = "level-nesting" if show_inline else "level-element" collapsible_class = "is-collapsible" if xblock.has_children else "" -label = determine_label(xblock.display_name_with_default, xblock.scope_ids.block_type) +label = xblock.display_name_with_default or xblock.scope_ids.block_type messages = xblock.validate().to_json() block_is_unit = is_unit(xblock) %> From 364acbb9a3ce8fe6b8439bc73560bc9d88cded8a Mon Sep 17 00:00:00 2001 From: John Nagro Date: Wed, 1 Jun 2022 11:35:31 -0400 Subject: [PATCH 07/63] feat: release edx-enterprise 3.49.6 (#30526) ENT-5895 --- requirements/constraints.txt | 2 +- requirements/edx/base.txt | 2 +- requirements/edx/development.txt | 2 +- requirements/edx/testing.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 3af7d27891..6b2012a134 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -25,7 +25,7 @@ django-storages<1.9 # The team that owns this package will manually bump this package rather than having it pulled in automatically. # This is to allow them to better control its deployment and to do it in a process that works better # for them. -edx-enterprise==3.49.5 +edx-enterprise==3.49.6 # Newer versions need a more recent version of python-dateutil freezegun==0.3.12 diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 1dce877b6f..63769732e0 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -467,7 +467,7 @@ edx-drf-extensions==8.0.1 # edx-rbac # edx-when # edxval -edx-enterprise==3.49.5 +edx-enterprise==3.49.6 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/base.in diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index e42a7f83e0..ba460e3e37 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -580,7 +580,7 @@ edx-drf-extensions==8.0.1 # edx-rbac # edx-when # edxval -edx-enterprise==3.49.5 +edx-enterprise==3.49.6 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/testing.txt diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 6b3da93e4a..f0b9a01b2f 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -563,7 +563,7 @@ edx-drf-extensions==8.0.1 # edx-rbac # edx-when # edxval -edx-enterprise==3.49.5 +edx-enterprise==3.49.6 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt From d7ae3181b6355b700c1ba1c0983eb6a597badd0c Mon Sep 17 00:00:00 2001 From: Justin Hynes Date: Wed, 1 Jun 2022 08:40:36 -0400 Subject: [PATCH 08/63] fix: fix issue with incorrect bulk email schedules [MICROBA-1835] * The DateTime string received from the Comms MFE was already in UTC so there is no need to convert the schedule to UTC on the backend. --- lms/djangoapps/instructor/tests/test_api.py | 100 +++--------------- lms/djangoapps/instructor/views/api.py | 43 +++----- lms/djangoapps/instructor_task/api.py | 36 ------- .../instructor_task/rest_api/v1/views.py | 9 +- .../instructor_task/tests/test_api.py | 77 -------------- 5 files changed, 37 insertions(+), 228 deletions(-) diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py index 08a27a0619..92d9625f1c 100644 --- a/lms/djangoapps/instructor/tests/test_api.py +++ b/lms/djangoapps/instructor/tests/test_api.py @@ -95,7 +95,7 @@ from openedx.core.djangoapps.django_comment_common.models import FORUM_ROLE_COMM from openedx.core.djangoapps.django_comment_common.utils import seed_permissions_roles from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.djangoapps.site_configuration.tests.mixins import SiteMixin -from openedx.core.djangoapps.user_api.preferences.api import set_user_preference, delete_user_preference +from openedx.core.djangoapps.user_api.preferences.api import delete_user_preference from openedx.core.lib.teams_config import TeamsConfig from openedx.core.lib.xblock_utils import grade_histogram from openedx.features.course_experience import RELATIVE_DATES_FLAG @@ -3399,11 +3399,6 @@ class TestInstructorSendEmail(SiteMixin, SharedModuleStoreTestCase, LoginEnrollm super().tearDown() delete_user_preference(self.instructor, 'time_zone', username=self.instructor.username) - def _get_expected_schedule(self, schedule, timezone): - local_tz = dateutil.tz.gettz(timezone) - local_dt = dateutil.parser.parse(schedule).replace(tzinfo=local_tz) - return local_dt.astimezone(pytz.utc) - def test_send_email_as_logged_in_instructor(self): url = reverse('send_email', kwargs={'course_id': str(self.course.id)}) response = self.client.post(url, self.full_test_message) @@ -3491,15 +3486,13 @@ class TestInstructorSendEmail(SiteMixin, SharedModuleStoreTestCase, LoginEnrollm template_name=org_template, from_addr=org_email).count() @patch("lms.djangoapps.instructor.views.api.task_api.submit_bulk_course_email") - def test_send_email_with_schedule_and_timezone(self, mock_task_api): + def test_send_email_with_schedule(self, mock_task_api): """ Test for the new scheduling logic added to the `send_email` function. """ - schedule = "2030-05-02T14:00:00.000Z" - timezone = "America/New_York" + schedule = "2099-05-02T14:00:00.000Z" self.full_test_message['schedule'] = schedule - self.full_test_message['browser_timezone'] = timezone - expected_schedule = self._get_expected_schedule(schedule, timezone) + expected_schedule = dateutil.parser.parse(schedule).replace(tzinfo=pytz.utc) url = reverse('send_email', kwargs={'course_id': str(self.course.id)}) response = self.client.post(url, self.full_test_message) @@ -3509,95 +3502,36 @@ class TestInstructorSendEmail(SiteMixin, SharedModuleStoreTestCase, LoginEnrollm assert arg_schedule == expected_schedule @patch("lms.djangoapps.instructor.views.api.task_api.submit_bulk_course_email") - def test_send_email_with_schedule_and_no_browser_timezone(self, mock_task_api): - """ - Test that verifies we will retrieve and use the preferred time zone if possible. - """ - schedule = "2030-05-02T14:00:00.000Z" - timezone = "America/New_York" - self.full_test_message['schedule'] = schedule - self.full_test_message['browser_timezone'] = "" - expected_schedule = self._get_expected_schedule(schedule, timezone) - set_user_preference(self.instructor, 'time_zone', timezone) - - url = reverse('send_email', kwargs={'course_id': str(self.course.id)}) - response = self.client.post(url, self.full_test_message) - - assert response.status_code == 200 - _, _, _, arg_schedule = mock_task_api.call_args.args - assert arg_schedule == expected_schedule - - @patch("lms.djangoapps.instructor.views.api.task_api.submit_bulk_course_email") - def test_send_email_with_schedule_and_preferred_timezone(self, mock_task_api): - """ - Test that verifies we will use the preferred timezone over the browser timezone if possible. - """ - schedule = "2030-05-02T14:00:00.000Z" - preferred_timezone = "America/Anchorage" - self.full_test_message['schedule'] = schedule - self.full_test_message['browser_timezone'] = "America/New_York" - expected_schedule = self._get_expected_schedule(schedule, preferred_timezone) - set_user_preference(self.instructor, 'time_zone', preferred_timezone) - - url = reverse('send_email', kwargs={'course_id': str(self.course.id)}) - response = self.client.post(url, self.full_test_message) - - assert response.status_code == 200 - _, _, _, arg_schedule = mock_task_api.call_args.args - assert arg_schedule == expected_schedule - - def test_send_email_with_malformed_schedule_expect_error(self): + def test_send_email_with_malformed_schedule_expect_error(self, mock_task_api): + schedule = "Blub Glub" self.full_test_message['schedule'] = "Blub Glub" - self.full_test_message['browser_timezone'] = "America/New_York" - expected_messages = [ - "Error occurred while attempting to create a scheduled bulk email task: unknown string format", - ] + expected_message = ( + f"Error occurred creating a scheduled bulk email task. Schedule provided: '{schedule}'. Error: unknown " + "string format" + ) url = reverse('send_email', kwargs={'course_id': str(self.course.id)}) with LogCapture() as log: response = self.client.post(url, self.full_test_message) assert response.status_code == 400 - log.check_present( - (LOG_PATH, "ERROR", expected_messages[0]), - ) - - def test_send_email_with_malformed_timezone_expect_error(self): - self.full_test_message['schedule'] = "2030-05-02T14:00:00.000Z" - self.full_test_message['browser_timezone'] = "Flim/Flam" - expected_messages = [ - "Error occurred while attempting to create a scheduled bulk email task: Unable to determine the time zone " - "to use to convert the schedule to UTC", - ] - - url = reverse('send_email', kwargs={'course_id': str(self.course.id)}) - with LogCapture() as log: - response = self.client.post(url, self.full_test_message) - - assert response.status_code == 400 - log.check_present( - (LOG_PATH, "ERROR", expected_messages[0]), - ) + log.check_present((LOG_PATH, "ERROR", expected_message),) + mock_task_api.assert_not_called() def test_send_email_with_lapsed_date_expect_error(self): schedule = "2020-01-01T00:00:00.000Z" - timezone = "America/New_York" self.full_test_message['schedule'] = schedule - self.full_test_message['browser_timezone'] = timezone - expected_schedule = self._get_expected_schedule(schedule, timezone) - expected_messages = [ - "Error occurred while attempting to create a scheduled bulk email task: The requested schedule " - f"'{expected_schedule}' is in the past" - ] + expected_message = ( + f"Error occurred creating a scheduled bulk email task. Schedule provided: '{schedule}'. Error: the " + "requested schedule is in the past" + ) url = reverse('send_email', kwargs={'course_id': str(self.course.id)}) with LogCapture() as log: response = self.client.post(url, self.full_test_message) assert response.status_code == 400 - log.check_present( - (LOG_PATH, "ERROR", expected_messages[0]), - ) + log.check_present((LOG_PATH, "ERROR", expected_message),) class MockCompletionInfo: diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index 6ad7f2057c..8388fffb4f 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -14,6 +14,7 @@ import string import random import re +import dateutil import pytz import edx_api_doc_tools as apidocs from django.conf import settings @@ -89,7 +90,6 @@ from lms.djangoapps.discussion.django_comment_client.utils import ( ) from lms.djangoapps.instructor import enrollment from lms.djangoapps.instructor.access import ROLES, allow_access, list_with_level, revoke_access, update_forum_role -from lms.djangoapps.instructor_task.api import convert_schedule_to_utc_from_local from lms.djangoapps.instructor.constants import INVOICE_KEY from lms.djangoapps.instructor.enrollment import ( enroll_email, @@ -2698,7 +2698,7 @@ def send_email(request, course_id): course_overview = CourseOverview.get_from_id(course_id) if not is_bulk_email_feature_enabled(course_id): - log.warning('Email is not enabled for course %s', course_id) + log.warning(f"Email is not enabled for course {course_id}") return HttpResponseForbidden("Email is not enabled for this course.") targets = json.loads(request.POST.get("send_to")) @@ -2706,20 +2706,22 @@ def send_email(request, course_id): message = request.POST.get("message") # optional, this is a date and time in the form of an ISO8601 string schedule = request.POST.get("schedule", "") - # optional, this is the timezone captured from the author's browser when requesting a scheduled email - browser_timezone = request.POST.get("browser_timezone", "") - # If this is a scheduled bulk email request then we try to convert the requested schedule date to UTC. We do this - # before we attempt to create the email object instance in case there is an issue as we don't want to have an - # orphaned email object that will never be sent. + schedule_dt = None if schedule: try: - schedule = convert_schedule_to_utc_from_local(schedule, browser_timezone, request.user) - _determine_valid_schedule(schedule) - except ValueError as error: - error_message = f"Error occurred while attempting to create a scheduled bulk email task: {error}" - log.error(f"{error_message}") - return HttpResponseBadRequest(repr(error_message)) + # convert the schedule from a string to a datetime, then check if its a valid future date and time, dateutil + # will throw a ValueError if the schedule is no good. + schedule_dt = dateutil.parser.parse(schedule).replace(tzinfo=pytz.utc) + if schedule_dt < datetime.datetime.now(pytz.utc): + raise ValueError("the requested schedule is in the past") + except ValueError as value_error: + error_message = ( + f"Error occurred creating a scheduled bulk email task. Schedule provided: '{schedule}'. Error: " + f"{value_error}" + ) + log.error(error_message) + return HttpResponseBadRequest(error_message) # Retrieve the customized email "from address" and email template from site configuration for the course/partner. If # there is no site configuration enabled for the current site then we use system defaults for both. @@ -2742,7 +2744,7 @@ def send_email(request, course_id): return HttpResponseBadRequest(repr(err)) # Submit the task, so that the correct InstructorTask object gets created (for monitoring purposes) - task_api.submit_bulk_course_email(request, course_id, email.id, schedule) + task_api.submit_bulk_course_email(request, course_id, email.id, schedule_dt) response_payload = { 'course_id': str(course_id), @@ -3600,16 +3602,3 @@ def _get_branded_email_template(course_overview): template_name = template_name.get(course_overview.display_org_with_default) return template_name - - -def _determine_valid_schedule(schedule): - """ - Utility function that determines if the requested schedule is in the future. Raises ValueError if the schedule time - has already lapsed. - - Args: - schedule (DateTime): UTC DateTime representing the desired date and time to process a scheduled instructor task. - """ - now = datetime.datetime.now(pytz.utc) - if schedule < now: - raise ValueError(f"The requested schedule '{schedule}' is in the past") diff --git a/lms/djangoapps/instructor_task/api.py b/lms/djangoapps/instructor_task/api.py index 03c4d29b0a..bbf5bf7b28 100644 --- a/lms/djangoapps/instructor_task/api.py +++ b/lms/djangoapps/instructor_task/api.py @@ -11,7 +11,6 @@ import hashlib import logging from collections import Counter -import dateutil import pytz from celery.states import READY_STATES @@ -51,7 +50,6 @@ from lms.djangoapps.instructor_task.tasks import ( send_bulk_course_email, generate_anonymous_ids_for_course ) -from openedx.core.djangoapps.user_api.preferences.api import get_user_preference from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order log = logging.getLogger(__name__) @@ -589,37 +587,3 @@ def process_scheduled_instructor_tasks(): submit_scheduled_task(schedule) except QueueConnectionError as exc: log.error(f"Error processing scheduled task with task id '{schedule.task.id}': {exc}") - - -def convert_schedule_to_utc_from_local(schedule, browser_timezone, user): - """ - Utility function to help convert the schedule of an instructor task from the requesters local time and timezone - (taken from the request) to a UTC datetime. - - Args: - schedule (String): The desired time to execute a scheduled task, in local time, in the form of an ISO8601 - string. - timezone (String): The time zone, as captured by the user's web browser, in the form of a string. - user (User): The user requesting the action, captured from the originating web request. Used to lookup the - the time zone preference as set in the user's account settings. - - Returns: - DateTime: A datetime instance describing when to execute this schedule task converted to the UTC timezone. - """ - # look up the requesting user's timezone from their account settings - preferred_timezone = get_user_preference(user, 'time_zone', username=user.username) - # use the user's preferred timezone (if available), otherwise use the browser timezone. - timezone = preferred_timezone if preferred_timezone else browser_timezone - - # convert the schedule to UTC - log.info(f"Converting requested schedule from local time '{schedule}' with the timezone '{timezone}' to UTC") - - local_tz = dateutil.tz.gettz(timezone) - if local_tz is None: - raise ValueError( - "Unable to determine the time zone to use to convert the schedule to UTC" - ) - local_dt = dateutil.parser.parse(schedule).replace(tzinfo=local_tz) - schedule_utc = local_dt.astimezone(pytz.utc) - - return schedule_utc diff --git a/lms/djangoapps/instructor_task/rest_api/v1/views.py b/lms/djangoapps/instructor_task/rest_api/v1/views.py index 5b1664dcd1..10ebfb21b3 100644 --- a/lms/djangoapps/instructor_task/rest_api/v1/views.py +++ b/lms/djangoapps/instructor_task/rest_api/v1/views.py @@ -6,6 +6,7 @@ import json import logging import pytz +import dateutil from celery.states import REVOKED from django.db import transaction from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication @@ -14,7 +15,6 @@ from rest_framework.response import Response from rest_framework import generics, status from lms.djangoapps.bulk_email.api import update_course_email -from lms.djangoapps.instructor_task.api import convert_schedule_to_utc_from_local from lms.djangoapps.instructor_task.data import InstructorTaskTypes from lms.djangoapps.instructor_task.models import InstructorTaskSchedule, SCHEDULED from lms.djangoapps.instructor_task.rest_api.v1.exceptions import TaskUpdateException @@ -126,10 +126,9 @@ class ModifyScheduledBulkEmailInstructorTask(generics.DestroyAPIView, generics.U with transaction.atomic(): if schedule: - browser_timezone = request.data.get("browser_timezone", None) - schedule_utc = convert_schedule_to_utc_from_local(schedule, browser_timezone, request.user) - self._verify_valid_schedule(schedule_id, schedule_utc) - task_schedule.task_due = schedule_utc + schedule_dt = dateutil.parser.parse(schedule).replace(tzinfo=pytz.utc) + self._verify_valid_schedule(schedule_id, schedule_dt) + task_schedule.task_due = schedule_dt task_schedule.save() if email_data: email_id = email_data.get("id") diff --git a/lms/djangoapps/instructor_task/tests/test_api.py b/lms/djangoapps/instructor_task/tests/test_api.py index 79d2184582..4b84fbff7f 100644 --- a/lms/djangoapps/instructor_task/tests/test_api.py +++ b/lms/djangoapps/instructor_task/tests/test_api.py @@ -7,7 +7,6 @@ import json from unittest.mock import MagicMock, Mock, patch from uuid import uuid4 -import dateutil import pytest import pytz import ddt @@ -22,7 +21,6 @@ from lms.djangoapps.bulk_email.data import BulkEmailTargetChoices from lms.djangoapps.certificates.data import CertificateStatuses from lms.djangoapps.certificates.models import CertificateGenerationHistory from lms.djangoapps.instructor_task.api import ( - convert_schedule_to_utc_from_local, SpecificStudentIdMissingError, generate_anonymous_ids, generate_certificates_for_students, @@ -63,7 +61,6 @@ from lms.djangoapps.instructor_task.tests.test_base import ( InstructorTaskTestCase, TestReportMixin ) -from openedx.core.djangoapps.user_api.preferences.api import set_user_preference, delete_user_preference LOG_PATH = 'lms.djangoapps.instructor_task.api' @@ -531,77 +528,3 @@ class InstructorTaskCourseSubmitTest(TestReportMixin, InstructorTaskCourseTestCa process_scheduled_instructor_tasks() log.check_present((LOG_PATH, "ERROR", expected_messages[0]),) - - -@patch('lms.djangoapps.bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) # lint-amnesty, pylint: disable=line-too-long -class ScheduledInstructorTaskTests(TestReportMixin, InstructorTaskCourseTestCase): - """ - Tests API methods that support scheduled instructor tasks - """ - def setUp(self): - super().setUp() - self.instructor = UserFactory.create(username="instructor", email="instructor@edx.org") - - def tearDown(self): - super().tearDown() - delete_user_preference(self.instructor, 'time_zone', self.instructor.username) - - def _get_expected_schedule(self, schedule, timezone): - local_tz = dateutil.tz.gettz(timezone) - local_dt = dateutil.parser.parse(schedule).replace(tzinfo=local_tz) - return local_dt.astimezone(pytz.utc) - - def test_convert_schedule_to_utc_from_local_no_user_preference(self): - """ - A test that verifies the behavior of the `convert_schedule_to_utc_from_local` function. Verifies that we use - the browser provided timezone data if there is no preferred timezone set by the user in their account settings. - """ - schedule = "2099-05-02T14:00:00.000Z" - browser_timezone = "America/New_York" - expected_schedule = self._get_expected_schedule(schedule, browser_timezone) - - schedule_utc = convert_schedule_to_utc_from_local(schedule, browser_timezone, self.instructor) - - assert schedule_utc == expected_schedule - - def test_convert_schedule_to_utc_from_local_with_preferred_timezone(self): - """ - A test that verifies the behavior of the `convert_schedule_to_utc_from_local` function. Verifies that we use the - preferred timezone if a user has set one in their account settings. - """ - schedule = "2099-05-02T14:00:00.000Z" - preferred_timezone = "America/Anchorage" - set_user_preference(self.instructor, 'time_zone', preferred_timezone) - expected_schedule = self._get_expected_schedule(schedule, preferred_timezone) - - schedule_utc = convert_schedule_to_utc_from_local(schedule, "", self.instructor) - - assert schedule_utc == expected_schedule - - def test_convert_schedule_to_utc_from_local_with_preferred_and_browser_timezone(self): - """ - A test that verifies the behavior of the `convert_schedule_to_utc_from_local` function. Verifies that we use - the preferred timezone over the browser timezone when provided both values. - """ - schedule = "2099-05-02T14:00:00.000Z" - browser_timezone = "America/New_York" - preferred_timezone = "America/Anchorage" - set_user_preference(self.instructor, 'time_zone', preferred_timezone) - expected_schedule = self._get_expected_schedule(schedule, preferred_timezone) - - schedule_utc = convert_schedule_to_utc_from_local(schedule, browser_timezone, self.instructor) - - assert schedule_utc == expected_schedule - - def test_convert_schedule_to_utc_from_local_with_invalid_timezone(self): - """ - A test that verifies the behavior of the `convert_schedule_to_utc_from_local` function. Verifies an error - condition if the application cannot determine a timezone to use for conversion. - """ - schedule = "2099-05-02T14:00:00.000Z" - expected_error_message = "Unable to determine the time zone to use to convert the schedule to UTC" - - with self.assertRaises(ValueError) as value_err: - convert_schedule_to_utc_from_local(schedule, "Flim/Flam", self.instructor) - - assert str(value_err.exception) == expected_error_message From ad8724f91f95b8a2d58fb9235f2e934c5582c8c2 Mon Sep 17 00:00:00 2001 From: John Nagro Date: Wed, 1 Jun 2022 17:40:12 -0400 Subject: [PATCH 09/63] feat: release edx-enterprise 3.49.7 (#30528) --- requirements/constraints.txt | 2 +- requirements/edx/base.txt | 2 +- requirements/edx/development.txt | 2 +- requirements/edx/testing.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 6b2012a134..9c063105a9 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -25,7 +25,7 @@ django-storages<1.9 # The team that owns this package will manually bump this package rather than having it pulled in automatically. # This is to allow them to better control its deployment and to do it in a process that works better # for them. -edx-enterprise==3.49.6 +edx-enterprise==3.49.7 # Newer versions need a more recent version of python-dateutil freezegun==0.3.12 diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 63769732e0..6f2cc53d7d 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -467,7 +467,7 @@ edx-drf-extensions==8.0.1 # edx-rbac # edx-when # edxval -edx-enterprise==3.49.6 +edx-enterprise==3.49.7 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/base.in diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index ba460e3e37..410e6c8e4b 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -580,7 +580,7 @@ edx-drf-extensions==8.0.1 # edx-rbac # edx-when # edxval -edx-enterprise==3.49.6 +edx-enterprise==3.49.7 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/testing.txt diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index f0b9a01b2f..e59ac534ce 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -563,7 +563,7 @@ edx-drf-extensions==8.0.1 # edx-rbac # edx-when # edxval -edx-enterprise==3.49.6 +edx-enterprise==3.49.7 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt From a63d023fb62f8dff41a4805833610cefca8d95b6 Mon Sep 17 00:00:00 2001 From: Kshitij Sobti Date: Thu, 2 Jun 2022 11:34:11 +0530 Subject: [PATCH 10/63] fix: Run course discussion settings update task when settings change (#30520) When discussion settings change in a course, call the discussion settings update task so that topics are updated automatically. --- openedx/core/djangoapps/discussions/serializers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openedx/core/djangoapps/discussions/serializers.py b/openedx/core/djangoapps/discussions/serializers.py index 5f01ca457e..2f465ae15d 100644 --- a/openedx/core/djangoapps/discussions/serializers.py +++ b/openedx/core/djangoapps/discussions/serializers.py @@ -5,11 +5,12 @@ from django.core.exceptions import ValidationError from lti_consumer.api import get_lti_pii_sharing_state_for_course from lti_consumer.models import LtiConfiguration from rest_framework import serializers +from xmodule.modulestore.django import modulestore from lms.djangoapps.discussion.toggles import ENABLE_REPORTED_CONTENT_EMAIL_NOTIFICATIONS +from openedx.core.djangoapps.discussions.tasks import update_discussions_settings_from_course_task from openedx.core.djangoapps.django_comment_common.models import CourseDiscussionSettings from openedx.core.lib.courses import get_course_by_id -from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order from .models import DiscussionsConfiguration, Provider from .utils import available_division_schemes, get_divided_discussions @@ -257,6 +258,7 @@ class DiscussionsConfigurationSerializer(serializers.ModelSerializer): # have already been set instance = self._update_lti(instance, validated_data) instance.save() + update_discussions_settings_from_course_task.delay(str(instance.context_key)) return instance def _update_lti( From 1800257bcde7d53ec939dd1cf0015f9c09236687 Mon Sep 17 00:00:00 2001 From: Saad Yousaf Date: Thu, 2 Jun 2022 11:09:32 +0500 Subject: [PATCH 11/63] fix: fix issues with reported content email notifications (#30522) Co-authored-by: SaadYousaf --- lms/djangoapps/discussion/signals/handlers.py | 12 ++++++++++-- lms/djangoapps/discussion/tasks.py | 6 +++--- .../reportedcontentnotification/email/body.html | 11 +++++------ .../reportedcontentnotification/email/body.txt | 2 +- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/lms/djangoapps/discussion/signals/handlers.py b/lms/djangoapps/discussion/signals/handlers.py index d9d669b113..eb084c8665 100644 --- a/lms/djangoapps/discussion/signals/handlers.py +++ b/lms/djangoapps/discussion/signals/handlers.py @@ -7,6 +7,7 @@ import logging from django.conf import settings from django.dispatch import receiver +from django.utils.html import strip_tags from opaque_keys.edx.locator import LibraryLocator from xmodule.modulestore.django import SignalHandler @@ -103,16 +104,23 @@ def create_message_context_for_reported_content(user, post, site, sender): """ Create message context for reported content. """ + def get_comment_type(comment): + """ + Returns type of comment. + """ + return 'response' if comment.get('parent_id', None) is None else 'comment' + context = { 'user_id': user.id, 'course_id': str(post.course_id), 'thread_id': post.thread.id if sender == 'flag_abuse_for_comment' else post.id, 'title': post.thread.title if sender == 'flag_abuse_for_comment' else post.title, - 'content_type': post.type, - 'content_body': post.body, + 'content_type': 'post' if sender == 'flag_abuse_for_thread' else get_comment_type(post), + 'content_body': strip_tags(post.body), 'thread_created_at': post.created_at, 'thread_commentable_id': post.commentable_id, 'site_id': site.id, + 'comment_id': post.id if sender == 'flag_abuse_for_comment' else None, } return context diff --git a/lms/djangoapps/discussion/tasks.py b/lms/djangoapps/discussion/tasks.py index 1f00f8111f..e8aa87d653 100644 --- a/lms/djangoapps/discussion/tasks.py +++ b/lms/djangoapps/discussion/tasks.py @@ -155,9 +155,9 @@ def _should_send_message(context): def _is_content_still_reported(context): - if context.get('thread_id'): - return len(cc.Thread.find(context['thread_id']).abuse_flaggers) > 0 - return len(cc.Comment.find(context['comment_id']).abuse_flaggers) > 0 + if context.get('comment_id') is not None: + return len(cc.Comment.find(context['comment_id']).abuse_flaggers) > 0 + return len(cc.Thread.find(context['thread_id']).abuse_flaggers) > 0 def _is_not_subcomment(comment_id): diff --git a/lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html b/lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html index 535f667dc9..de8c2676bf 100644 --- a/lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +++ b/lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html @@ -7,19 +7,18 @@ - @@ -18,14 +17,6 @@ -
-

+

{% filter force_escape %} - {% blocktrans trimmed asvar replied_to_text %} + {% blocktrans %} {{ course_name }}: Reported content awaits review {% endblocktrans %} {% endfilter %} - {% interpolate_html replied_to_text start_tag=''|safe end_tag=''|safe %}

-

You are receiving this email because the following {{ content_type }} was reported for review

-

{{ title }}

+

You are receiving this email because the following {{ content_type }} was reported for review

+

Post Title: {{ title }}

- {{ content_body }} + {{ comment_body }} {% filter force_escape %} {% blocktrans asvar course_cta_text %}Go to Discussion{% endblocktrans %} diff --git a/lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt b/lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt index ae4bbbdb41..3463facd9c 100644 --- a/lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +++ b/lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt @@ -11,7 +11,7 @@ margin: 20px 20px 30px 30px; color: rgba(0,0,0,.75);">

You are receiving this email because the following {{ content_type }} was reported for review

-

{{ title }}

+

Post Title: {{ title }}

{{ content_body }} From af31e68f8edbc2e7482bdd9d4657f7c6bb417a1a Mon Sep 17 00:00:00 2001 From: SaadYousaf Date: Thu, 2 Jun 2022 11:42:02 +0500 Subject: [PATCH 12/63] fix: fix variable name in email template --- .../edx_ace/reportedcontentnotification/email/body.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html b/lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html index de8c2676bf..a66cebb6a9 100644 --- a/lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +++ b/lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html @@ -18,7 +18,7 @@

You are receiving this email because the following {{ content_type }} was reported for review

Post Title: {{ title }}

- {{ comment_body }} + {{ content_body }} {% filter force_escape %} {% blocktrans asvar course_cta_text %}Go to Discussion{% endblocktrans %} From 7d4543814d5d290176ad1e126c62c5b1dc098aea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Behmo?= Date: Thu, 2 Jun 2022 20:21:19 +0200 Subject: [PATCH 13/63] refactor: less confusing ACE configuration (#27719) The ACE_* settings from lms/envs/common.py are all ignored because they are overloaded by the plugin settings. We were recently bitten by this, as we discovered that the ACE_ROUTING_KEY was incorrectly set to 'edx.core.low'. Here, we fix this default value and remove ACE_* settings from lms/envs/common.py to avoid confusion. See: https://github.com/overhangio/tutor/issues/439 --- lms/envs/common.py | 13 ++++--------- .../core/djangoapps/ace_common/settings/common.py | 4 +++- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/lms/envs/common.py b/lms/envs/common.py index bc976d4661..f268ad6b2a 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -4921,15 +4921,10 @@ HIBP_LOGIN_BLOCK_PASSWORD_FREQUENCY_THRESHOLD = 5 ENABLE_DYNAMIC_REGISTRATION_FIELDS = False ############### Settings for the ace_common plugin ################# -ACE_ENABLED_CHANNELS = ['django_email'] -ACE_ENABLED_POLICIES = ['bulk_email_optout'] -ACE_CHANNEL_SAILTHRU_DEBUG = True -ACE_CHANNEL_SAILTHRU_TEMPLATE_NAME = None -ACE_ROUTING_KEY = 'edx.lms.core.default' -ACE_CHANNEL_DEFAULT_EMAIL = 'django_email' -ACE_CHANNEL_TRANSACTIONAL_EMAIL = 'django_email' -ACE_CHANNEL_SAILTHRU_API_KEY = "" -ACE_CHANNEL_SAILTHRU_API_SECRET = "" +# Note that all settings are actually defined by the plugin +# pylint: disable=wrong-import-position +from openedx.core.djangoapps.ace_common.settings import common as ace_common_settings +ACE_ROUTING_KEY = ace_common_settings.ACE_ROUTING_KEY ############### Settings swift ##################################### SWIFT_USERNAME = None diff --git a/openedx/core/djangoapps/ace_common/settings/common.py b/openedx/core/djangoapps/ace_common/settings/common.py index c1c751ba72..11bfbce5c5 100644 --- a/openedx/core/djangoapps/ace_common/settings/common.py +++ b/openedx/core/djangoapps/ace_common/settings/common.py @@ -2,6 +2,8 @@ Settings for ace_common app. """ +ACE_ROUTING_KEY = 'edx.lms.core.default' + def plugin_settings(settings): # lint-amnesty, pylint: disable=missing-function-docstring, missing-module-docstring settings.ACE_ENABLED_CHANNELS = [ @@ -17,6 +19,6 @@ def plugin_settings(settings): # lint-amnesty, pylint: disable=missing-function settings.ACE_CHANNEL_DEFAULT_EMAIL = 'django_email' settings.ACE_CHANNEL_TRANSACTIONAL_EMAIL = 'django_email' - settings.ACE_ROUTING_KEY = 'edx.core.low' + settings.ACE_ROUTING_KEY = ACE_ROUTING_KEY settings.FEATURES['test_django_plugin'] = True From e66036bba29278995191cc07c8fd87281fd0d201 Mon Sep 17 00:00:00 2001 From: Cristhian Garcia <33465240+Ian2012@users.noreply.github.com> Date: Fri, 3 Jun 2022 10:46:46 -0500 Subject: [PATCH 14/63] fix: dynamically generated unverified cert data (#30365) --- lms/djangoapps/courseware/views/views.py | 36 +++++++++++++----------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index a2c30fd5d5..031a8b75b5 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -203,18 +203,6 @@ REQUESTING_CERT_DATA = CertData( certificate_available_date=None ) -UNVERIFIED_CERT_DATA = CertData( - CertificateStatuses.unverified, - _('Certificate unavailable'), - _( - 'You have not received a certificate because you do not have a current {platform_name} ' - 'verified identity.' - ).format(platform_name=configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME)), - download_url=None, - cert_web_view_url=None, - certificate_available_date=None -) - def _earned_but_not_available_cert_data(cert_downloadable_status): return CertData( @@ -238,6 +226,23 @@ def _downloadable_cert_data(download_url=None, cert_web_view_url=None): ) +def _unverified_cert_data(): + """ + platform_name is dynamically updated in multi-tenant installations + """ + return CertData( + CertificateStatuses.unverified, + _('Certificate unavailable'), + _( + 'You have not received a certificate because you do not have a current {platform_name} ' + 'verified identity.' + ).format(platform_name=configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME)), + download_url=None, + cert_web_view_url=None, + certificate_available_date=None + ) + + def user_groups(user): """ TODO (vshnayder): This is not used. When we have a new plan for groups, adjust appropriately. @@ -1196,15 +1201,12 @@ def _certificate_message(student, course, enrollment_mode): # lint-amnesty, pyl if cert_downloadable_status['is_generating']: return GENERATING_CERT_DATA - if cert_downloadable_status['is_unverified']: - return UNVERIFIED_CERT_DATA + if cert_downloadable_status['is_unverified'] or _missing_required_verification(student, enrollment_mode): + return _unverified_cert_data() if cert_downloadable_status['is_downloadable']: return _downloadable_certificate_message(course, cert_downloadable_status) - if _missing_required_verification(student, enrollment_mode): - return UNVERIFIED_CERT_DATA - return REQUESTING_CERT_DATA From 7f5d8e3511ed70a3097b3114818a0e335eefb867 Mon Sep 17 00:00:00 2001 From: edx-semantic-release Date: Fri, 3 Jun 2022 17:32:49 +0000 Subject: [PATCH 15/63] chore(i18n): update translations --- conf/locale/ar/LC_MESSAGES/django.po | 4 +- conf/locale/ar/LC_MESSAGES/djangojs.po | 2 +- conf/locale/ca/LC_MESSAGES/django.po | 4 +- conf/locale/ca/LC_MESSAGES/djangojs.po | 2 +- conf/locale/de_DE/LC_MESSAGES/django.po | 4 +- conf/locale/de_DE/LC_MESSAGES/djangojs.po | 2 +- conf/locale/el/LC_MESSAGES/django.po | 5 +- conf/locale/el/LC_MESSAGES/djangojs.po | 2 +- conf/locale/en/LC_MESSAGES/django.po | 48 ++++++++------- conf/locale/en/LC_MESSAGES/djangojs.po | 4 +- conf/locale/eo/LC_MESSAGES/django.mo | Bin 1183410 -> 1183695 bytes conf/locale/eo/LC_MESSAGES/django.po | 63 ++++++++++++-------- conf/locale/eo/LC_MESSAGES/djangojs.mo | Bin 435793 -> 435793 bytes conf/locale/eo/LC_MESSAGES/djangojs.po | 4 +- conf/locale/es_419/LC_MESSAGES/django.po | 4 +- conf/locale/es_419/LC_MESSAGES/djangojs.po | 2 +- conf/locale/eu_ES/LC_MESSAGES/django.po | 4 +- conf/locale/eu_ES/LC_MESSAGES/djangojs.po | 2 +- conf/locale/fr/LC_MESSAGES/django.po | 4 +- conf/locale/fr/LC_MESSAGES/djangojs.po | 2 +- conf/locale/id/LC_MESSAGES/django.po | 4 +- conf/locale/id/LC_MESSAGES/djangojs.po | 2 +- conf/locale/it_IT/LC_MESSAGES/django.po | 4 +- conf/locale/it_IT/LC_MESSAGES/djangojs.po | 2 +- conf/locale/ja_JP/LC_MESSAGES/django.po | 4 +- conf/locale/ja_JP/LC_MESSAGES/djangojs.po | 2 +- conf/locale/ka/LC_MESSAGES/django.po | 4 +- conf/locale/ka/LC_MESSAGES/djangojs.po | 2 +- conf/locale/lt_LT/LC_MESSAGES/django.po | 4 +- conf/locale/lt_LT/LC_MESSAGES/djangojs.po | 2 +- conf/locale/lv/LC_MESSAGES/django.po | 4 +- conf/locale/lv/LC_MESSAGES/djangojs.po | 2 +- conf/locale/mn/LC_MESSAGES/django.po | 4 +- conf/locale/mn/LC_MESSAGES/djangojs.po | 2 +- conf/locale/pl/LC_MESSAGES/django.po | 5 +- conf/locale/pl/LC_MESSAGES/djangojs.po | 2 +- conf/locale/pt_BR/LC_MESSAGES/djangojs.po | 2 +- conf/locale/pt_PT/LC_MESSAGES/django.po | 4 +- conf/locale/pt_PT/LC_MESSAGES/djangojs.po | 2 +- conf/locale/rtl/LC_MESSAGES/django.mo | Bin 771843 -> 772069 bytes conf/locale/rtl/LC_MESSAGES/django.po | 59 ++++++++++-------- conf/locale/rtl/LC_MESSAGES/djangojs.mo | Bin 279194 -> 279194 bytes conf/locale/rtl/LC_MESSAGES/djangojs.po | 4 +- conf/locale/ru/LC_MESSAGES/djangojs.po | 2 +- conf/locale/sk/LC_MESSAGES/django.po | 4 +- conf/locale/sk/LC_MESSAGES/djangojs.po | 2 +- conf/locale/sw_KE/LC_MESSAGES/django.po | 4 +- conf/locale/sw_KE/LC_MESSAGES/djangojs.po | 2 +- conf/locale/th/LC_MESSAGES/django.po | 4 +- conf/locale/th/LC_MESSAGES/djangojs.po | 2 +- conf/locale/tr_TR/LC_MESSAGES/django.po | 4 +- conf/locale/tr_TR/LC_MESSAGES/djangojs.po | 2 +- conf/locale/uk/LC_MESSAGES/django.po | 4 +- conf/locale/uk/LC_MESSAGES/djangojs.po | 2 +- conf/locale/vi/LC_MESSAGES/django.po | 4 +- conf/locale/vi/LC_MESSAGES/djangojs.po | 2 +- conf/locale/zh_CN/LC_MESSAGES/django.po | 4 +- conf/locale/zh_CN/LC_MESSAGES/djangojs.po | 2 +- conf/locale/zh_HANS/LC_MESSAGES/django.po | 4 +- conf/locale/zh_HANS/LC_MESSAGES/djangojs.po | 2 +- conf/locale/zh_TW/LC_MESSAGES/django.po | 4 +- conf/locale/zh_TW/LC_MESSAGES/djangojs.po | 2 +- 62 files changed, 185 insertions(+), 153 deletions(-) diff --git a/conf/locale/ar/LC_MESSAGES/django.po b/conf/locale/ar/LC_MESSAGES/django.po index 418c6772d5..a2844fb056 100644 --- a/conf/locale/ar/LC_MESSAGES/django.po +++ b/conf/locale/ar/LC_MESSAGES/django.po @@ -252,7 +252,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: NELC Open edX Translation , 2020\n" "Language-Team: Arabic (https://www.transifex.com/open-edx/teams/6205/ar/)\n" @@ -7101,7 +7101,7 @@ msgstr "جيّد" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/ar/LC_MESSAGES/djangojs.po b/conf/locale/ar/LC_MESSAGES/djangojs.po index bcf7ee0789..6d0bcd7f6e 100644 --- a/conf/locale/ar/LC_MESSAGES/djangojs.po +++ b/conf/locale/ar/LC_MESSAGES/djangojs.po @@ -189,7 +189,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Roaa Nader , 2021\n" "Language-Team: Arabic (http://www.transifex.com/open-edx/edx-platform/language/ar/)\n" diff --git a/conf/locale/ca/LC_MESSAGES/django.po b/conf/locale/ca/LC_MESSAGES/django.po index 8e6ff7756a..96a3b2c288 100644 --- a/conf/locale/ca/LC_MESSAGES/django.po +++ b/conf/locale/ca/LC_MESSAGES/django.po @@ -66,7 +66,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Waheed Ahmed , 2019\n" "Language-Team: Catalan (https://www.transifex.com/open-edx/teams/6205/ca/)\n" @@ -6142,7 +6142,7 @@ msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/ca/LC_MESSAGES/djangojs.po b/conf/locale/ca/LC_MESSAGES/djangojs.po index 7688b8e8a1..782d44968f 100644 --- a/conf/locale/ca/LC_MESSAGES/djangojs.po +++ b/conf/locale/ca/LC_MESSAGES/djangojs.po @@ -48,7 +48,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Waheed Ahmed , 2019\n" "Language-Team: Catalan (http://www.transifex.com/open-edx/edx-platform/language/ca/)\n" diff --git a/conf/locale/de_DE/LC_MESSAGES/django.po b/conf/locale/de_DE/LC_MESSAGES/django.po index cc965f0bbb..4be53a30ed 100644 --- a/conf/locale/de_DE/LC_MESSAGES/django.po +++ b/conf/locale/de_DE/LC_MESSAGES/django.po @@ -173,7 +173,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Stefania Trabucchi , 2019\n" "Language-Team: German (Germany) (https://www.transifex.com/open-edx/teams/6205/de_DE/)\n" @@ -7149,7 +7149,7 @@ msgstr "Gut" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/de_DE/LC_MESSAGES/djangojs.po b/conf/locale/de_DE/LC_MESSAGES/djangojs.po index e115ab7fb8..78f9224af6 100644 --- a/conf/locale/de_DE/LC_MESSAGES/djangojs.po +++ b/conf/locale/de_DE/LC_MESSAGES/djangojs.po @@ -130,7 +130,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Stefania Trabucchi , 2018-2021\n" "Language-Team: German (Germany) (http://www.transifex.com/open-edx/edx-platform/language/de_DE/)\n" diff --git a/conf/locale/el/LC_MESSAGES/django.po b/conf/locale/el/LC_MESSAGES/django.po index 8f19360f1c..2e2cf2f6da 100644 --- a/conf/locale/el/LC_MESSAGES/django.po +++ b/conf/locale/el/LC_MESSAGES/django.po @@ -14,6 +14,7 @@ # Georgios Vasileiadis , 2014 # Katerina Ligkovanli , 2016-2021 # Konstantina Samara , 2015 +# Konstantinos Fragoulis, 2022 # kostas kalatzis , 2015 # Nick Gikopoulos, 2014-2017 # Panos Chronis , 2014 @@ -90,7 +91,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Waheed Ahmed , 2019\n" "Language-Team: Greek (https://www.transifex.com/open-edx/teams/6205/el/)\n" @@ -6295,7 +6296,7 @@ msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/el/LC_MESSAGES/djangojs.po b/conf/locale/el/LC_MESSAGES/djangojs.po index b3636df773..e792d28de8 100644 --- a/conf/locale/el/LC_MESSAGES/djangojs.po +++ b/conf/locale/el/LC_MESSAGES/djangojs.po @@ -83,7 +83,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Ioannis Stavrakakis , 2020\n" "Language-Team: Greek (http://www.transifex.com/open-edx/edx-platform/language/el/)\n" diff --git a/conf/locale/en/LC_MESSAGES/django.po b/conf/locale/en/LC_MESSAGES/django.po index 0d21f1b88e..ed985da500 100644 --- a/conf/locale/en/LC_MESSAGES/django.po +++ b/conf/locale/en/LC_MESSAGES/django.po @@ -38,8 +38,8 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-29 20:42+0000\n" -"PO-Revision-Date: 2022-05-29 20:42:17.222392\n" +"POT-Creation-Date: 2022-06-03 17:28+0000\n" +"PO-Revision-Date: 2022-06-03 17:28:01.509197\n" "Last-Translator: \n" "Language-Team: openedx-translation \n" "Language: en\n" @@ -5970,17 +5970,6 @@ msgstr "" msgid "You've earned a certificate for this course." msgstr "" -#: lms/djangoapps/courseware/views/views.py -msgid "Certificate unavailable" -msgstr "" - -#: lms/djangoapps/courseware/views/views.py -#, python-brace-format -msgid "" -"You have not received a certificate because you do not have a current " -"{platform_name} verified identity." -msgstr "" - #: lms/djangoapps/courseware/views/views.py msgid "Your certificate will be available soon!" msgstr "" @@ -5995,6 +5984,17 @@ msgstr "" msgid "Your certificate is available" msgstr "" +#: lms/djangoapps/courseware/views/views.py +msgid "Certificate unavailable" +msgstr "" + +#: lms/djangoapps/courseware/views/views.py +#, python-brace-format +msgid "" +"You have not received a certificate because you do not have a current " +"{platform_name} verified identity." +msgstr "" + #: lms/djangoapps/courseware/views/views.py #, python-brace-format msgid "To see course content, {sign_in_link} or {register_link}." @@ -6135,9 +6135,11 @@ msgid "Good" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html -#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s: Reported content awaits review" +msgid "" +"\n" +" %(course_name)s: Reported content awaits review\n" +" " msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html @@ -6145,6 +6147,11 @@ msgstr "" msgid "Go to Discussion" msgstr "" +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +#, python-format +msgid "%(course_name)s: Reported content awaits review" +msgstr "" + #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/subject.txt #, python-format msgid " %(course_name)s %(course_id)s moderator content for review " @@ -10208,6 +10215,11 @@ msgstr "" msgid "The '{field_name}' field cannot be edited." msgstr "" +#: openedx/core/djangoapps/user_api/accounts/api.py +#: openedx/core/djangoapps/user_authn/views/registration_form.py +msgid "Enter a valid name" +msgstr "" + #. Translators: This label appears above a field which allows the #. user to input the First Name #. Translators: This label appears above a field on the registration form @@ -10662,10 +10674,6 @@ msgstr "" msgid "Full Name cannot contain the following characters: < >" msgstr "" -#: openedx/core/djangoapps/user_authn/views/registration_form.py -msgid "Enter a valid name" -msgstr "" - #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "A properly formatted e-mail is required" msgstr "" @@ -14725,7 +14733,7 @@ msgid "Share with friends and family!" msgstr "" #: lms/templates/courseware/course_about_sidebar_header.html -msgid "I just enrolled in {number} {title} through {account}: {url}" +msgid "I just enrolled in {number} {title} through {account} {url}" msgstr "" #: lms/templates/courseware/course_about_sidebar_header.html diff --git a/conf/locale/en/LC_MESSAGES/djangojs.po b/conf/locale/en/LC_MESSAGES/djangojs.po index 4800c637c7..09abe47565 100644 --- a/conf/locale/en/LC_MESSAGES/djangojs.po +++ b/conf/locale/en/LC_MESSAGES/djangojs.po @@ -32,8 +32,8 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-29 20:41+0000\n" -"PO-Revision-Date: 2022-05-29 20:42:17.236317\n" +"POT-Creation-Date: 2022-06-03 17:27+0000\n" +"PO-Revision-Date: 2022-06-03 17:28:01.823212\n" "Last-Translator: \n" "Language-Team: openedx-translation \n" "Language: en\n" diff --git a/conf/locale/eo/LC_MESSAGES/django.mo b/conf/locale/eo/LC_MESSAGES/django.mo index c38548468648e6da0df5b3dc302bab1b948a1cce..cb4fc770fdf30af706329f5e5b4da1fe6ea7b88b 100644 GIT binary patch delta 96120 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 J@DyHS{|`9F41)jw delta 96030 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�ix(%Ifv!LuE1qkS|^!vb9_SWlpq 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

This overrides the courseware/info.html template.

diff --git a/common/test/test-theme/lms/templates/courseware/progress.html b/common/test/test-theme/lms/templates/courseware/progress.html new file mode 100644 index 0000000000..29c3baf550 --- /dev/null +++ b/common/test/test-theme/lms/templates/courseware/progress.html @@ -0,0 +1,2 @@ +<%page expression_filter="h"/> +

This overrides the courseware/progress.html template.

diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index 7f774faf62..2a67b6454e 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -13,7 +13,7 @@ from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.entrance_exams import user_can_skip_entrance_exam from lms.djangoapps.course_home_api.toggles import course_home_mfe_progress_tab_is_active from openedx.core.lib.course_tabs import CourseTabPluginManager -from openedx.features.course_experience import DISABLE_UNIFIED_COURSE_TAB_FLAG, default_course_url +from openedx.features.course_experience import default_course_url from openedx.features.course_experience.url_helpers import get_learning_mfe_home_url from common.djangoapps.student.models import CourseEnrollment @@ -50,28 +50,8 @@ class CoursewareTab(EnrolledTab): @classmethod def is_enabled(cls, course, user=None): """ - Returns true if this tab is enabled. + Courseware tabs are viewable to everyone, even anonymous users. """ - if DISABLE_UNIFIED_COURSE_TAB_FLAG.is_enabled(course.id): - return super().is_enabled(course, user) - # If this is the unified course tab then it is always enabled - return True - - -class CourseInfoTab(CourseTab): - """ - The course info view. - """ - type = 'course_info' - title = gettext_noop('Home') - priority = 10 - view_name = 'info' - tab_id = 'info' - is_movable = False - is_default = False - - @classmethod - def is_enabled(cls, course, user=None): return True @@ -355,9 +335,6 @@ def get_course_tab_list(user, course): continue tab.name = _("Entrance Exam") tab.title = _("Entrance Exam") - # TODO: LEARNER-611 - once the course_info tab is removed, remove this code - if not DISABLE_UNIFIED_COURSE_TAB_FLAG.is_enabled(course.id) and tab.type == 'course_info': - continue if tab.type == 'static_tab' and tab.course_staff_only and \ not bool(user and has_access(user, 'staff', course, course.id)): continue diff --git a/lms/djangoapps/courseware/tests/test_course_info.py b/lms/djangoapps/courseware/tests/test_course_info.py deleted file mode 100644 index fc68e5f93b..0000000000 --- a/lms/djangoapps/courseware/tests/test_course_info.py +++ /dev/null @@ -1,417 +0,0 @@ -""" -Test the course_info xblock -""" - - -from datetime import datetime - -from unittest import mock -import ddt -from ccx_keys.locator import CCXLocator -from django.conf import settings -from django.http import QueryDict -from django.test.utils import override_settings -from django.urls import reverse -from edx_toggles.toggles.testutils import override_waffle_flag -from pyquery import PyQuery as pq -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase -from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, check_mongo_calls -from xmodule.modulestore.tests.utils import TEST_DATA_DIR -from xmodule.modulestore.xml_importer import import_course_from_xml - -from lms.djangoapps.ccx.tests.factories import CcxFactory -from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration -from openedx.core.djangoapps.site_configuration.tests.test_util import with_site_configuration_context -from openedx.core.djangoapps.waffle_utils.testutils import WAFFLE_TABLES -from openedx.features.content_type_gating.models import ContentTypeGatingConfig -from openedx.features.course_experience import DISABLE_UNIFIED_COURSE_TAB_FLAG -from openedx.features.enterprise_support.tests.mixins.enterprise import EnterpriseTestConsentRequired -from common.djangoapps.student.models import CourseEnrollment -from common.djangoapps.student.tests.factories import AdminFactory -from common.djangoapps.util.date_utils import strftime_localized - -from .helpers import LoginEnrollmentTestCase - -QUERY_COUNT_TABLE_IGNORELIST = WAFFLE_TABLES - - -@override_waffle_flag(DISABLE_UNIFIED_COURSE_TAB_FLAG, active=True) -class CourseInfoTestCase(EnterpriseTestConsentRequired, LoginEnrollmentTestCase, SharedModuleStoreTestCase): - """ - Tests for the Course Info page - """ - - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.course = CourseFactory.create() - cls.page = ItemFactory.create( - category="course_info", parent_location=cls.course.location, - data="OOGIE BLOOGIE", display_name="updates" - ) - - def test_logged_in_unenrolled(self): - self.setup_user() - url = reverse('info', args=[str(self.course.id)]) - resp = self.client.get(url) - self.assertContains(resp, "OOGIE BLOOGIE") - self.assertContains(resp, "You are not currently enrolled in this course") - - def test_logged_in_enrolled(self): - self.enroll(self.course) - url = reverse('info', args=[str(self.course.id)]) - resp = self.client.get(url) - assert b'You are not currently enrolled in this course' not in resp.content - - # TODO: LEARNER-611: If this is only tested under Course Info, does this need to move? - @mock.patch('openedx.features.enterprise_support.api.enterprise_customer_for_request') - def test_redirection_missing_enterprise_consent(self, mock_enterprise_customer_for_request): - """ - Verify that users viewing the course info who are enrolled, but have not provided - data sharing consent, are first redirected to a consent page, and then, once they've - provided consent, are able to view the course info. - """ - # ENT-924: Temporary solution to replace sensitive SSO usernames. - mock_enterprise_customer_for_request.return_value = None - - self.setup_user() - self.enroll(self.course) - - url = reverse('info', args=[str(self.course.id)]) - - self.verify_consent_required(self.client, url) # lint-amnesty, pylint: disable=no-value-for-parameter - - def test_anonymous_user(self): - url = reverse('info', args=[str(self.course.id)]) - resp = self.client.get(url) - assert resp.status_code == 200 - assert b'OOGIE BLOOGIE' not in resp.content - - def test_logged_in_not_enrolled(self): - self.setup_user() - url = reverse('info', args=[str(self.course.id)]) - self.client.get(url) - - # Check whether the user has been enrolled in the course. - # There was a bug in which users would be automatically enrolled - # with is_active=False (same as if they enrolled and immediately unenrolled). - # This verifies that the user doesn't have *any* enrollment record. - enrollment_exists = CourseEnrollment.objects.filter( - user=self.user, course_id=self.course.id - ).exists() - assert not enrollment_exists - - @mock.patch.dict(settings.FEATURES, {'DISABLE_START_DATES': False}) - def test_non_live_course(self): - """Ensure that a user accessing a non-live course sees a redirect to - the student dashboard, not a 404. - """ - self.setup_user() - self.enroll(self.course) - url = reverse('info', args=[str(self.course.id)]) - response = self.client.get(url) - start_date = strftime_localized(self.course.start, 'SHORT_DATE') - expected_params = QueryDict(mutable=True) - expected_params['notlive'] = start_date - expected_url = '{url}?{params}'.format( - url=reverse('dashboard'), - params=expected_params.urlencode() - ) - self.assertRedirects(response, expected_url) - - @mock.patch.dict(settings.FEATURES, {'DISABLE_START_DATES': False}) - @mock.patch("common.djangoapps.util.date_utils.strftime_localized") - def test_non_live_course_other_language(self, mock_strftime_localized): - """Ensure that a user accessing a non-live course sees a redirect to - the student dashboard, not a 404, even if the localized date is unicode - """ - self.setup_user() - self.enroll(self.course) - fake_unicode_start_time = "üñîçø∂é_ßtå®t_tîµé" - mock_strftime_localized.return_value = fake_unicode_start_time - - url = reverse('info', args=[str(self.course.id)]) - response = self.client.get(url) - expected_params = QueryDict(mutable=True) - expected_params['notlive'] = fake_unicode_start_time - expected_url = '{url}?{params}'.format( - url=reverse('dashboard'), - params=expected_params.urlencode() - ) - self.assertRedirects(response, expected_url) - - def test_nonexistent_course(self): - self.setup_user() - url = reverse('info', args=['not/a/course']) - response = self.client.get(url) - assert response.status_code == 404 - - -@override_waffle_flag(DISABLE_UNIFIED_COURSE_TAB_FLAG, active=True) -class CourseInfoLastAccessedTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase): - """ - Tests of the CourseInfo last accessed link. - """ - - def setUp(self): - super().setUp() - self.course = CourseFactory.create() - self.page = ItemFactory.create( - category="course_info", parent_location=self.course.location, - data="OOGIE BLOOGIE", display_name="updates" - ) - - def test_last_accessed_courseware_not_shown(self): - """ - Test that the last accessed courseware link is not shown if there - is no course content. - """ - SelfPacedConfiguration(enable_course_home_improvements=True).save() - url = reverse('info', args=(str(self.course.id),)) - response = self.client.get(url) - content = pq(response.content) - assert content('.page-header-secondary a').length == 0 - - def get_resume_course_url(self, course_info_url): - """ - Retrieves course info page and returns the resume course url - or None if the button doesn't exist. - """ - info_page_response = self.client.get(course_info_url) - content = pq(info_page_response.content) - return content('.page-header-secondary .last-accessed-link').attr('href') - - def test_resume_course_visibility(self): - SelfPacedConfiguration(enable_course_home_improvements=True).save() - chapter = ItemFactory.create( - category="chapter", parent_location=self.course.location - ) - section = ItemFactory.create( - category='sequential', parent_location=chapter.location - ) - section_url = reverse( - 'courseware_section', - kwargs={ - 'section': section.url_name, - 'chapter': chapter.url_name, - 'course_id': self.course.id - } - ) - self.client.get(section_url) - info_url = reverse('info', args=(str(self.course.id),)) - - # Assuring a non-authenticated user cannot see the resume course button. - resume_course_url = self.get_resume_course_url(info_url) - assert resume_course_url is None - - # Assuring an unenrolled user cannot see the resume course button. - self.setup_user() - resume_course_url = self.get_resume_course_url(info_url) - assert resume_course_url is None - - # Assuring an enrolled user can see the resume course button. - self.enroll(self.course) - resume_course_url = self.get_resume_course_url(info_url) - assert resume_course_url == section_url - - -@override_waffle_flag(DISABLE_UNIFIED_COURSE_TAB_FLAG, active=True) -@ddt.ddt -class CourseInfoTitleTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase): - """ - Tests of the CourseInfo page title site configuration options. - """ - def setUp(self): - super().setUp() - self.course = CourseFactory.create( - org="HogwartZ", - number="Potions_3", - display_organization="HogwartsX", - display_coursenumber="Potions101", - display_name="Introduction to Potions" - ) - - @ddt.data( - # Default site configuration shows course number, org, and display name as subtitle. - ({}, - "Welcome to HogwartsX's Potions101!", "Introduction to Potions"), - - # Show org in title - (dict(COURSE_HOMEPAGE_INVERT_TITLE=False, - COURSE_HOMEPAGE_SHOW_SUBTITLE=True, - COURSE_HOMEPAGE_SHOW_ORG=True), - "Welcome to HogwartsX's Potions101!", "Introduction to Potions"), - - # Don't show org in title - (dict(COURSE_HOMEPAGE_INVERT_TITLE=False, - COURSE_HOMEPAGE_SHOW_SUBTITLE=True, - COURSE_HOMEPAGE_SHOW_ORG=False), - "Welcome to Potions101!", "Introduction to Potions"), - - # Hide subtitle and org - (dict(COURSE_HOMEPAGE_INVERT_TITLE=False, - COURSE_HOMEPAGE_SHOW_SUBTITLE=False, - COURSE_HOMEPAGE_SHOW_ORG=False), - "Welcome to Potions101!", None), - - # Show display name as title, hide subtitle and org. - (dict(COURSE_HOMEPAGE_INVERT_TITLE=True, - COURSE_HOMEPAGE_SHOW_SUBTITLE=False, - COURSE_HOMEPAGE_SHOW_ORG=False), - "Welcome to Introduction to Potions!", None), - - # Show display name as title with org, hide subtitle. - (dict(COURSE_HOMEPAGE_INVERT_TITLE=True, - COURSE_HOMEPAGE_SHOW_SUBTITLE=False, - COURSE_HOMEPAGE_SHOW_ORG=True), - "Welcome to HogwartsX's Introduction to Potions!", None), - - # Show display name as title, hide org, and show course number as subtitle. - (dict(COURSE_HOMEPAGE_INVERT_TITLE=True, - COURSE_HOMEPAGE_SHOW_SUBTITLE=True, - COURSE_HOMEPAGE_SHOW_ORG=False), - "Welcome to Introduction to Potions!", 'Potions101'), - - # Show display name as title with org, and show course number as subtitle. - (dict(COURSE_HOMEPAGE_INVERT_TITLE=True, - COURSE_HOMEPAGE_SHOW_SUBTITLE=True, - COURSE_HOMEPAGE_SHOW_ORG=True), - "Welcome to HogwartsX's Introduction to Potions!", 'Potions101'), - ) - @ddt.unpack - def test_info_title(self, site_config, expected_title, expected_subtitle): - """ - Test the info page on a course with all the multiple display options - depeding on the current site configuration - """ - url = reverse('info', args=(str(self.course.id),)) - with with_site_configuration_context(configuration=site_config): - response = self.client.get(url) - - content = pq(response.content) - - assert expected_title == content('.page-title').contents()[0].strip() - - if expected_subtitle is None: - assert not content('.page-subtitle') - else: - assert expected_subtitle == content('.page-subtitle').contents()[0].strip() - - -@override_waffle_flag(DISABLE_UNIFIED_COURSE_TAB_FLAG, active=True) -class CourseInfoTestCaseCCX(SharedModuleStoreTestCase, LoginEnrollmentTestCase): - """ - Test for unenrolled student tries to access ccx. - Note: Only CCX coach can enroll a student in CCX. In sum self-registration not allowed. - """ - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.course = CourseFactory.create() - - def setUp(self): - super().setUp() - - # Create ccx coach account - self.coach = coach = AdminFactory.create(password="test") - self.client.login(username=coach.username, password="test") - - def test_redirect_to_dashboard_unenrolled_ccx(self): - """ - Assert that when unenroll student tries to access ccx do not allow them self-register. - Redirect them to their student dashboard - """ - # create ccx - ccx = CcxFactory(course_id=self.course.id, coach=self.coach) - ccx_locator = CCXLocator.from_course_locator(self.course.id, str(ccx.id)) - - self.setup_user() - url = reverse('info', args=[ccx_locator]) - response = self.client.get(url) - expected = reverse('dashboard') - self.assertRedirects(response, expected, status_code=302, target_status_code=200) - - -@override_waffle_flag(DISABLE_UNIFIED_COURSE_TAB_FLAG, active=True) -class CourseInfoTestCaseXML(LoginEnrollmentTestCase, ModuleStoreTestCase): - """ - Tests for the Course Info page for an XML course - """ - def setUp(self): - """ - Set up the tests - """ - super().setUp() - - # The following test course (which lives at common/test/data/2014) - # is closed; we're testing that a course info page still appears when - # the course is already closed - self.xml_course_key = self.store.make_course_key('edX', 'detached_pages', '2014') - import_course_from_xml( - self.store, - self.user.id, - TEST_DATA_DIR, - source_dirs=['2014'], - static_content_store=None, - target_id=self.xml_course_key, - raise_on_failure=True, - create_if_not_present=True, - ) - - # this text appears in that course's course info page - # common/test/data/2014/info/updates.html - self.xml_data = "course info 463139" - - @mock.patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False}) - def test_logged_in_xml(self): - self.setup_user() - url = reverse('info', args=[str(self.xml_course_key)]) - resp = self.client.get(url) - self.assertContains(resp, self.xml_data) - - @mock.patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False}) - def test_anonymous_user_xml(self): - url = reverse('info', args=[str(self.xml_course_key)]) - resp = self.client.get(url) - self.assertNotContains(resp, self.xml_data) - - -@override_settings(FEATURES=dict(settings.FEATURES, EMBARGO=False)) -@override_waffle_flag(DISABLE_UNIFIED_COURSE_TAB_FLAG, active=True) -class SelfPacedCourseInfoTestCase(LoginEnrollmentTestCase, SharedModuleStoreTestCase): - """ - Tests for the info page of self-paced courses. - """ - ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache'] - - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.instructor_paced_course = CourseFactory.create(self_paced=False) - cls.self_paced_course = CourseFactory.create(self_paced=True) - - def setUp(self): - super().setUp() - ContentTypeGatingConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1)) - - self.setup_user() - - def fetch_course_info_with_queries(self, course, sql_queries, mongo_queries): - """ - Fetch the given course's info page, asserting the number of SQL - and Mongo queries. - """ - url = reverse('info', args=[str(course.id)]) - with self.assertNumQueries(sql_queries, table_ignorelist=QUERY_COUNT_TABLE_IGNORELIST): - with check_mongo_calls(mongo_queries): - with mock.patch("openedx.core.djangoapps.theming.helpers.get_current_site", return_value=None): - resp = self.client.get(url) - assert resp.status_code == 200 - - def test_num_queries_instructor_paced(self): - # TODO: decrease query count as part of REVO-28 - self.fetch_course_info_with_queries(self.instructor_paced_course, 41, 2) - - def test_num_queries_self_paced(self): - # TODO: decrease query count as part of REVO-28 - self.fetch_course_info_with_queries(self.self_paced_course, 41, 2) diff --git a/lms/djangoapps/courseware/tests/test_date_summary.py b/lms/djangoapps/courseware/tests/test_date_summary.py index b428859c17..41cc22d8de 100644 --- a/lms/djangoapps/courseware/tests/test_date_summary.py +++ b/lms/djangoapps/courseware/tests/test_date_summary.py @@ -9,7 +9,6 @@ import crum import ddt from django.conf import settings from django.test import RequestFactory -from django.urls import reverse from edx_toggles.toggles.testutils import override_waffle_flag, override_waffle_switch from freezegun import freeze_time from pytz import utc @@ -19,7 +18,7 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.course_modes.tests.factories import CourseModeFactory -from common.djangoapps.student.tests.factories import TEST_PASSWORD, CourseEnrollmentFactory, UserFactory +from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory from lms.djangoapps.certificates.config import AUTO_CERTIFICATE_GENERATION from lms.djangoapps.commerce.models import CommerceConfiguration from lms.djangoapps.courseware.courses import get_course_date_blocks @@ -43,7 +42,6 @@ from lms.djangoapps.verify_student.services import IDVerificationService from lms.djangoapps.verify_student.tests.factories import SoftwareSecurePhotoVerificationFactory from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory -from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration from openedx.features.course_duration_limits.models import CourseDurationLimitConfig from openedx.features.course_experience import RELATIVE_DATES_FLAG @@ -51,9 +49,6 @@ from openedx.features.course_experience import RELATIVE_DATES_FLAG @ddt.ddt class CourseDateSummaryTest(SharedModuleStoreTestCase): """Tests for course date summary blocks.""" - def setUp(self): - super().setUp() - SelfPacedConfiguration.objects.create(enable_course_home_improvements=True) def make_request(self, user): """ Creates a request """ @@ -63,17 +58,6 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): crum.set_current_request(request) return request - def test_course_info_feature_flag(self): - SelfPacedConfiguration(enable_course_home_improvements=False).save() - course = create_course_run() - user = create_user() - CourseEnrollmentFactory(course_id=course.id, user=user, mode=CourseMode.VERIFIED) - - self.client.login(username=user.username, password=TEST_PASSWORD) - url = reverse('info', args=(course.id,)) - response = self.client.get(url) - self.assertNotContains(response, 'date-summary', status_code=302) - # Tests for which blocks are enabled def assert_block_types(self, course, user, expected_blocks): """Assert that the enabled block types for this course are as expected.""" diff --git a/lms/djangoapps/courseware/tests/test_masquerade.py b/lms/djangoapps/courseware/tests/test_masquerade.py index 6c10cc38db..dbfdece5d9 100644 --- a/lms/djangoapps/courseware/tests/test_masquerade.py +++ b/lms/djangoapps/courseware/tests/test_masquerade.py @@ -13,7 +13,6 @@ from operator import itemgetter # lint-amnesty, pylint: disable=wrong-import-or from django.conf import settings from django.test import TestCase, RequestFactory from django.urls import reverse -from edx_toggles.toggles.testutils import override_waffle_flag from pytz import UTC from xblock.runtime import DictKeyValueStore @@ -31,9 +30,7 @@ from lms.djangoapps.courseware.tests.helpers import ( ) from lms.djangoapps.courseware.tests.test_submitting_problems import ProblemSubmissionTestMixin from openedx.core.djangoapps.lang_pref import LANGUAGE_KEY -from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration from openedx.core.djangoapps.user_api.preferences.api import get_user_preference, set_user_preference -from openedx.features.course_experience import DISABLE_UNIFIED_COURSE_TAB_FLAG from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.tests.factories import StaffFactory from common.djangoapps.student.tests.factories import UserFactory @@ -108,18 +105,6 @@ class MasqueradeTestCase(SharedModuleStoreTestCase, LoginEnrollmentTestCase, Mas ) return self.client.get(url) - def get_course_info_page(self): - """ - Returns the server response for course info page. - """ - url = reverse( - 'info', - kwargs={ - 'course_id': str(self.course.id), - } - ) - return self.client.get(url) - def get_progress_page(self): """ Returns the server response for progress page. @@ -351,27 +336,6 @@ class TestStaffMasqueradeAsSpecificStudent(StaffMasqueradeTestCase, ProblemSubmi assert get_user_preference(user, LANGUAGE_KEY) == expected_language_code assert self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value == expected_language_code - @override_waffle_flag(DISABLE_UNIFIED_COURSE_TAB_FLAG, active=True) - @patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False}) - def test_masquerade_as_specific_user_on_self_paced(self): - """ - Test masquerading as a specific user for course info page when self paced configuration - "enable_course_home_improvements" flag is set - - Login as a staff user and visit course info page. - set masquerade to view same page as a specific student and revisit the course info page. - """ - # Log in as staff, and check we can see the info page. - self.login_staff() - response = self.get_course_info_page() - self.assertContains(response, "OOGIE BLOOGIE") - - # Masquerade as the student,enable the self paced configuration, and check we can see the info page. - SelfPacedConfiguration(enable_course_home_improvements=True).save() - self.update_masquerade(role='student', username=self.student_user.username) - response = self.get_course_info_page() - self.assertContains(response, "OOGIE BLOOGIE") - @ddt.data( 'john', # Non-unicode username 'fôô@bar', # Unicode username with @, which is what the ENABLE_UNICODE_USERNAME feature allows @@ -442,25 +406,6 @@ class TestStaffMasqueradeAsSpecificStudent(StaffMasqueradeTestCase, ProblemSubmi self.get_courseware_page() self.assertExpectedLanguageInPreference(self.test_user, english_language_code) - @override_waffle_flag(DISABLE_UNIFIED_COURSE_TAB_FLAG, active=True) - @patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False}) - def test_masquerade_as_specific_student_course_info(self): - """ - Test masquerading as a specific user for course info page. - - We login with login_staff and check course info page content if it's working and then we - set masquerade to view same page as a specific student and test if it's working or not. - """ - # Log in as staff, and check we can see the info page. - self.login_staff() - content = self.get_course_info_page().content.decode('utf-8') - assert 'OOGIE BLOOGIE' in content - - # Masquerade as the student, and check we can see the info page. - self.update_masquerade(role='student', username=self.student_user.username) - content = self.get_course_info_page().content.decode('utf-8') - assert 'OOGIE BLOOGIE' in content - def test_masquerade_as_specific_student_progress(self): """ Test masquerading as a specific user for progress page. diff --git a/lms/djangoapps/courseware/tests/test_tabs.py b/lms/djangoapps/courseware/tests/test_tabs.py index b159c20b84..eefb231141 100644 --- a/lms/djangoapps/courseware/tests/test_tabs.py +++ b/lms/djangoapps/courseware/tests/test_tabs.py @@ -10,9 +10,7 @@ from django.http import Http404 from django.urls import reverse from milestones.tests.utils import MilestonesTestCaseMixin -from edx_toggles.toggles.testutils import override_waffle_flag from lms.djangoapps.courseware.tabs import ( - CourseInfoTab, CoursewareTab, DatesTab, ExternalDiscussionCourseTab, @@ -24,7 +22,6 @@ from lms.djangoapps.courseware.tests.helpers import LoginEnrollmentTestCase from lms.djangoapps.courseware.views.views import StaticCourseTabView, get_static_tab_fragment from openedx.core.djangolib.testing.utils import get_mock_request from openedx.core.lib.courses import get_course_by_id -from openedx.features.course_experience import DISABLE_UNIFIED_COURSE_TAB_FLAG from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.tests.factories import InstructorFactory from common.djangoapps.student.tests.factories import StaffFactory @@ -496,20 +493,16 @@ class TabListTestCase(TabTestCase): # invalid tabs self.invalid_tabs = [ - # less than 2 tabs - [{'type': CoursewareTab.type}], - # missing course_info - [{'type': CoursewareTab.type}, {'type': 'discussion', 'name': 'fake_name'}], + # missing courseware [{'type': 'unknown_type'}], # incorrect order [{'type': 'discussion', 'name': 'fake_name'}, - {'type': CourseInfoTab.type, 'name': 'fake_name'}, {'type': CoursewareTab.type}], + {'type': CoursewareTab.type}], ] # tab types that should appear only once unique_tab_types = [ CoursewareTab.type, - CourseInfoTab.type, 'textbooks', 'pdf_textbooks', 'html_textbooks', @@ -518,7 +511,6 @@ class TabListTestCase(TabTestCase): for unique_tab_type in unique_tab_types: self.invalid_tabs.append([ {'type': CoursewareTab.type}, - {'type': CourseInfoTab.type, 'name': 'fake_name'}, # add the unique tab multiple times {'type': unique_tab_type}, {'type': unique_tab_type}, @@ -532,7 +524,6 @@ class TabListTestCase(TabTestCase): # all valid tabs [ {'type': CoursewareTab.type}, - {'type': CourseInfoTab.type, 'name': 'fake_name'}, {'type': DatesTab.type}, # Add this even though we filter it out, for testing purposes {'type': 'discussion', 'name': 'fake_name'}, {'type': ExternalLinkCourseTab.type, 'name': 'fake_name', 'link': 'fake_link'}, @@ -547,7 +538,6 @@ class TabListTestCase(TabTestCase): # with external discussion [ {'type': CoursewareTab.type}, - {'type': CourseInfoTab.type, 'name': 'fake_name'}, {'type': ExternalDiscussionCourseTab.type, 'name': 'fake_name', 'link': 'fake_link'} ], ] @@ -575,8 +565,7 @@ class ValidateTabsTestCase(TabListTestCase): """ tab_list = xmodule_tabs.CourseTabList() assert len(tab_list.from_json([{'type': CoursewareTab.type}, - {'type': CourseInfoTab.type, 'name': 'fake_name'}, - {'type': 'no_such_type'}])) == 2 + {'type': 'no_such_type'}])) == 1 class CourseTabListTestCase(TabListTestCase): @@ -746,33 +735,6 @@ class StaticTabTestCase(TabTestCase): self.check_get_and_set_method_for_key(tab, 'url_slug') -class CourseInfoTabTestCase(TabTestCase): - """Test cases for the course info tab.""" - def setUp(self): # lint-amnesty, pylint: disable=super-method-not-called - self.user = self.create_mock_user() - self.addCleanup(set_current_request, None) - - @override_waffle_flag(DISABLE_UNIFIED_COURSE_TAB_FLAG, active=True) - def test_default_tab(self): - # Verify that the course info tab is the first tab - tabs = get_course_tab_list(self.user, self.course) - assert tabs[0].type == 'course_info' - - @override_waffle_flag(DISABLE_UNIFIED_COURSE_TAB_FLAG, active=False) - def test_default_tab_for_new_course_experience(self): - # Verify that the unified course experience hides the course info tab - tabs = get_course_tab_list(self.user, self.course) - assert tabs[0].type == 'courseware' - - # TODO: LEARNER-611 - remove once course_info is removed. - @override_waffle_flag(DISABLE_UNIFIED_COURSE_TAB_FLAG, active=False) - def test_default_tab_for_displayable(self): - tabs = xmodule_tabs.CourseTabList.iterate_displayable(self.course, self.user) - for i, tab in enumerate(tabs): - if i == 0: - assert tab.type == 'course_info' - - class DiscussionLinkTestCase(TabTestCase): """Test cases for discussion link tab.""" diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index 0db2441ef0..2ffdc46691 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -91,7 +91,6 @@ from openedx.features.content_type_gating.models import ContentTypeGatingConfig from openedx.features.course_duration_limits.models import CourseDurationLimitConfig from openedx.features.course_experience import ( DISABLE_COURSE_OUTLINE_PAGE_FLAG, - DISABLE_UNIFIED_COURSE_TAB_FLAG, ) from openedx.features.course_experience.tests.views.helpers import add_course_mode from openedx.features.course_experience.url_helpers import ( @@ -1022,19 +1021,6 @@ class ViewsTestCase(BaseViewsTestCase): response = self.client.get(url) self.assertRedirects(response, reverse('signin_user') + '?next=' + url) - @override_waffle_flag(DISABLE_UNIFIED_COURSE_TAB_FLAG, active=True) - def test_bypass_course_info(self): - course_id = str(self.course_key) - - response = self.client.get(reverse('info', args=[course_id])) - assert response.status_code == 200 - - response = self.client.get(reverse('info', args=[course_id]), HTTP_REFERER=reverse('dashboard')) - assert response.status_code == 200 - - response = self.client.get(reverse('info', args=[course_id]), HTTP_REFERER='foo') - assert response.status_code == 200 - # Patching 'lms.djangoapps.courseware.views.views.get_programs' would be ideal, # but for some unknown reason that patch doesn't seem to be applied. diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index 031a8b75b5..58387c56cf 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -67,7 +67,7 @@ from lms.djangoapps.commerce.utils import EcommerceService from lms.djangoapps.course_goals.models import UserActivity from lms.djangoapps.course_home_api.toggles import course_home_mfe_progress_tab_is_active from lms.djangoapps.courseware.access import has_access, has_ccx_coach_role -from lms.djangoapps.courseware.access_utils import check_course_open_for_learner, check_public_access +from lms.djangoapps.courseware.access_utils import check_public_access from lms.djangoapps.courseware.courses import ( can_self_enroll_in_course, course_open_for_self_enrollment, @@ -75,7 +75,6 @@ from lms.djangoapps.courseware.courses import ( get_course_overview_with_access, get_course_with_access, get_courses, - get_current_child, get_permission_for_course_about, get_studio_url, sort_by_announcement, @@ -113,7 +112,6 @@ from openedx.core.djangoapps.enrollments.permissions import ENROLL_IN_COURSE from openedx.core.djangoapps.models.course_details import CourseDetails from openedx.core.djangoapps.plugin_api.views import EdxFragmentView from openedx.core.djangoapps.programs.utils import ProgramMarketingDataExtender -from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.djangoapps.util.user_messages import PageLevelMessages from openedx.core.djangoapps.zendesk_proxy.utils import create_zendesk_ticket @@ -121,19 +119,16 @@ from openedx.core.djangolib.markup import HTML, Text from openedx.core.lib.courses import get_course_by_id from openedx.core.lib.mobile_utils import is_request_from_mobile_app from openedx.features.course_duration_limits.access import generate_course_expired_fragment -from openedx.features.course_experience import DISABLE_UNIFIED_COURSE_TAB_FLAG, course_home_url -from openedx.features.course_experience.course_tools import CourseToolsPluginManager +from openedx.features.course_experience import course_home_url from openedx.features.course_experience.url_helpers import ( get_courseware_url, get_learning_mfe_home_url, is_request_from_learning_mfe ) from openedx.features.course_experience.utils import dates_banner_should_display -from openedx.features.course_experience.views.course_dates import CourseDatesFragmentView from openedx.features.course_experience.waffle import ENABLE_COURSE_ABOUT_SIDEBAR_HTML from openedx.features.enterprise_support.api import data_sharing_consent_required -from ..entrance_exams import user_can_skip_entrance_exam from ..module_render import get_module, get_module_by_usage_id, get_module_for_descriptor from ..tabs import _get_dynamic_tabs from ..toggles import COURSEWARE_OPTIMIZED_RENDER_XBLOCK @@ -436,149 +431,6 @@ def jump_to(request, course_id, location): return redirect(redirect_url) -@ensure_csrf_cookie -@ensure_valid_course_key -@data_sharing_consent_required -def course_info(request, course_id): - """ - Display the course's info.html, or 404 if there is no such course. - Assumes the course_id is in a valid format. - """ - # TODO: LEARNER-611: This can be deleted with Course Info removal. The new - # Course Home is using its own processing of last accessed. - def get_last_accessed_courseware(course, request, user): - """ - Returns the courseware module URL that the user last accessed, or None if it cannot be found. - """ - field_data_cache = FieldDataCache.cache_for_descriptor_descendents( - course.id, request.user, course, depth=2 - ) - course_module = get_module_for_descriptor( - user, - request, - course, - field_data_cache, - course.id, - course=course, - will_recheck_access=True, - ) - chapter_module = get_current_child(course_module) - if chapter_module is not None: - section_module = get_current_child(chapter_module) - if section_module is not None: - url = reverse('courseware_section', kwargs={ - 'course_id': str(course.id), - 'chapter': chapter_module.url_name, - 'section': section_module.url_name - }) - return url - return None - - course_key = CourseKey.from_string(course_id) - - # If the unified course experience is enabled, redirect to the "Course" tab - if not DISABLE_UNIFIED_COURSE_TAB_FLAG.is_enabled(course_key): - return redirect(course_home_url(course_key)) - - with modulestore().bulk_operations(course_key): - course = get_course_with_access(request.user, 'load', course_key) - - can_masquerade = request.user.has_perm(MASQUERADE_AS_STUDENT, course) - masquerade, user = setup_masquerade(request, course_key, can_masquerade, reset_masquerade_data=True) - - # LEARNER-612: CCX redirect handled by new Course Home (DONE) - # LEARNER-1697: Transition banner messages to new Course Home (DONE) - # if user is not enrolled in a course then app will show enroll/get register link inside course info page. - user_is_enrolled = CourseEnrollment.is_enrolled(user, course.id) - show_enroll_banner = request.user.is_authenticated and not user_is_enrolled - - # If the user is not enrolled but this is a course that does not support - # direct enrollment then redirect them to the dashboard. - if not user_is_enrolled and not can_self_enroll_in_course(course_key): - return redirect(reverse('dashboard')) - - # LEARNER-170: Entrance exam is handled by new Course Outline. (DONE) - # If the user needs to take an entrance exam to access this course, then we'll need - # to send them to that specific course module before allowing them into other areas - if not user_can_skip_entrance_exam(user, course): - return redirect(reverse('courseware', args=[str(course.id)])) - - # Construct the dates fragment - dates_fragment = None - - if request.user.is_authenticated: - # TODO: LEARNER-611: Remove enable_course_home_improvements - if SelfPacedConfiguration.current().enable_course_home_improvements: - # Shared code with the new Course Home (DONE) - dates_fragment = CourseDatesFragmentView().render_to_fragment(request, course_id=course_id) - - # Shared code with the new Course Home (DONE) - # Get the course tools enabled for this user and course - course_tools = CourseToolsPluginManager.get_enabled_course_tools(request, course_key) - - course_homepage_invert_title =\ - configuration_helpers.get_value( - 'COURSE_HOMEPAGE_INVERT_TITLE', - False - ) - - course_homepage_show_subtitle =\ - configuration_helpers.get_value( - 'COURSE_HOMEPAGE_SHOW_SUBTITLE', - True - ) - - course_homepage_show_org =\ - configuration_helpers.get_value('COURSE_HOMEPAGE_SHOW_ORG', True) - - course_title = course.display_number_with_default - course_subtitle = course.display_name_with_default - if course_homepage_invert_title: - course_title = course.display_name_with_default - course_subtitle = course.display_number_with_default - - context = { - 'request': request, - 'masquerade_user': user, - 'course_id': str(course_key), - 'url_to_enroll': CourseTabView.url_to_enroll(course_key), - 'cache': None, - 'course': course, - 'course_title': course_title, - 'course_subtitle': course_subtitle, - 'show_subtitle': course_homepage_show_subtitle, - 'show_org': course_homepage_show_org, - 'can_masquerade': can_masquerade, - 'masquerade': masquerade, - 'supports_preview_menu': True, - 'studio_url': get_studio_url(course, 'course_info'), - 'show_enroll_banner': show_enroll_banner, - 'user_is_enrolled': user_is_enrolled, - 'dates_fragment': dates_fragment, - 'course_tools': course_tools, - } - context.update( - get_experiment_user_metadata_context( - course, - user, - ) - ) - - # Get the URL of the user's last position in order to display the 'where you were last' message - context['resume_course_url'] = None - # TODO: LEARNER-611: Remove enable_course_home_improvements - if SelfPacedConfiguration.current().enable_course_home_improvements: - context['resume_course_url'] = get_last_accessed_courseware(course, request, user) - - if not check_course_open_for_learner(user, course): - # Disable student view button if user is staff and - # course is not yet visible to students. - context['disable_student_access'] = True - context['supports_preview_menu'] = False - - return render_to_response('courseware/info.html', context) - - class StaticCourseTabView(EdxFragmentView): """ View that displays a static course tab with a given name. diff --git a/lms/envs/common.py b/lms/envs/common.py index f268ad6b2a..1303f351f6 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -505,8 +505,7 @@ FEATURES = { # .. toggle_implementation: DjangoSetting # .. toggle_default: True # .. toggle_description: When enabled, along with the ENABLE_MKTG_SITE feature toggle, users who attempt to access a - # course "about" page will be redirected to the course home url. This url might be the course "info" page or the - # unified course tab (when the DISABLE_UNIFIED_COURSE_TAB_FLAG waffle is not enabled). + # course "about" page will be redirected to the course home url. # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2019-01-15 # .. toggle_tickets: https://github.com/edx/edx-platform/pull/19604 @@ -3148,9 +3147,6 @@ INSTALLED_APPS = [ # Catalog integration 'openedx.core.djangoapps.catalog', - # Self-paced course configuration - 'openedx.core.djangoapps.self_paced', - 'sorl.thumbnail', # edx-milestones service diff --git a/lms/static/sass/course/_info.scss b/lms/static/sass/course/_info.scss deleted file mode 100644 index b1331985c6..0000000000 --- a/lms/static/sass/course/_info.scss +++ /dev/null @@ -1,386 +0,0 @@ -//// Notifications -// Upgrade - -$notification-highlight-border-color: $uxpl-green-base !default; -$notification-background: rgb(255, 255, 255) !default; - -.home { - @include clearfix(); - - max-width: map-get($container-max-widths, xl); - margin: 0 auto; - padding: $baseline $baseline ($baseline/2) $baseline; - - .page-header-main { - display: inline-block; - width: flex-grid(8, 12); - margin: 0; - - .page-title { - margin-bottom: 5px; - color: $dark-gray1; - text-transform: none; - } - - .page-subtitle { - color: $dark-gray1; - font-size: 14px; - text-transform: none; - } - } - - .page-header-secondary { - @include float(right); - - display: inline-block; - margin: ($baseline/2); - padding: ($baseline/2) ($baseline*0.75); - background-color: $blue; - border-radius: 2px; - - .last-accessed-link { - @extend %t-title6; - - color: $very-light-text; - } - } -} - -div.info-wrapper { - background-color: $homepage-background; - - section.updates { - @extend .content; - - @include padding-left($baseline); - - line-height: lh(); - width: 100%; - display: block; - - > p { - margin-bottom: lh(); - } - - > ol, - section, - div { - list-style: none; - margin-bottom: lh(); - padding-left: 0; - - .updates-article { - border-radius: 3px; - background-color: $white; - border: 1px solid transparent; - - &:hover { - border: 1px solid $gray-l3; - } - } - - .show-older-updates { - @extend %btn-pl-white-base; - - padding: ($baseline/2); - - @include font-size(14); - - width: 100%; - display: block; - text-align: center; - cursor: pointer; - background: none; - - &:hover, - &:focus { - background-color: unset; - color: $m-blue-d3; - border: 1px solid black; - } - } - - > li, - article { - @extend .clearfix; - - padding: $baseline; - list-style-type: none; - margin-bottom: lh(1.5); - background-color: $white; - - ol, - ul { - ol, - ul { - list-style-type: disc; - } - } - - .date { - @extend %t-title9; - - margin-bottom: ($baseline/4); - text-transform: none; - background: url('#{$static-path}/images/calendar-icon.png') 0 center no-repeat; - - @include padding-left($baseline); - @include float(left); - } - - - .toggle-visibility-button { - @extend %t-title9; - - @include float(right); - - padding: 0; - cursor: pointer; - background: none; - border: none; - color: $blue; - font-weight: normal; - } - - .toggle-visibility-element { - content: ''; - display: block; - clear: both; - } - - section.update-description { - section { - &.primary { - border: 1px solid #ddd; - background: $gray-l6; - padding: 20px; - - p { - font-weight: bold; - } - - .author { - font-weight: normal; - font-style: italic; - } - } - } - - h3 { - font-size: 1em; - font-weight: bold; - margin: lh(1.5) 0 lh(0.5); - } - - > ul { - list-style-type: disc; - } - - > ol { - list-style: decimal outside none; - padding: 0 0 0 1em; - } - - li { - margin-bottom: lh(0.5); - } - } - } - } - } - - section.handouts { - padding: 20px 30px; - margin: 0; - - @extend .sidebar; - - background: rgba(0, 0, 0, 0); - box-shadow: none; - font-size: 14px; - - a { - color: $link-color; - display: block; - font-size: 16px; - - span { - width: 20px; - text-align: center; - } - - &:not(:first-child) { - margin-top: 10px; - } - } - - &::after { - left: -1px; - right: auto; - } - - .handouts-header { - @include text-align(left); - - @extend %t-strong; - @extend %t-title6; - - margin-bottom: 0; - padding: 12px 26px 10px 0; - } - - ul { - margin-bottom: 14px; - } - - ol { - margin-bottom: 14px; - - li { - @include text-align(left); - - a { - display: block; - padding: 0; - color: $link-color; - - &:hover, - &:focus { - background: transparent; - } - } - - &.expandable, - &.collapsable { - margin: 0 16px 14px; - - @include transition(all 0.2s linear 0s); - - h4 { - color: $link-color; - font-size: 1em; - font-weight: normal; - padding-left: 30px; - } - } - - &.collapsable { - background: $white; - border-radius: 3px; - padding: 14px 0; - box-shadow: 0 0 1px 1px $shadow-l1, 0 1px 3px rgba(0, 0, 0, 0.25); - - h4 { - margin-bottom: 16px; - } - } - - &.multiple { - a { - display: inline-block; - padding: 0; - - &:hover, - &:focus { - background: transparent; - } - } - } - - ul { - background: none; - margin: 0; - - li { - border-bottom: 0; - border-top: 1px solid #e6e6e6; - font-size: 0.9em; - margin: 0; - padding: 15px 30px; - - a { - display: inline-block; - padding: 0; - - &:hover, - &:focus { - background: transparent; - } - } - } - } - - div.hitarea { - background-image: url('#{$static-path}/images/treeview-default.gif') no-repeat; - display: block; - height: 100%; - margin-left: 0; - max-height: 20px; - position: absolute; - width: 100%; - - &:hover, - &:focus { - opacity: 0.6; - filter: alpha(opacity=60); - - + h4 { - @extend a:hover; - - text-decoration: underline; - } - } - - &.expandable-hitarea { - background-position: -72px 0; - } - - &.collapsable-hitarea { - background-position: -55px -23px; - } - } - - h3 { - border-bottom: 0; - box-shadow: none; - color: #888; - font-size: 1em; - margin-bottom: 0; - } - - p { - letter-spacing: 0; - margin: 0; - text-transform: none; - - a { - padding-right: 8px; - - &::before { - color: $gray-l3; - content: "•"; - display: inline-block; - padding-right: 8px; - } - - &:first-child { - &::before { - content: ""; - padding-right: 0; - } - } - } - } - } - } - - @media print { - background: transparent !important; - } - } - - @media print { - background: transparent !important; - border: 0; - } -} diff --git a/lms/templates/courseware/info.html b/lms/templates/courseware/info.html deleted file mode 100644 index 022ef48669..0000000000 --- a/lms/templates/courseware/info.html +++ /dev/null @@ -1,125 +0,0 @@ -<%page expression_filter="h"/> -<%inherit file="../main.html" /> -<%def name="online_help_token()"><% return "courseinfo" %> -<%namespace name='static' file='../static_content.html'/> -<%! -from datetime import datetime -from pytz import timezone, utc - -from django.urls import reverse -from django.utils.translation import ugettext as _ - -from lms.djangoapps.courseware.courses import get_course_info_section -from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration -from openedx.core.djangolib.markup import HTML, Text -%> - -<%block name="pagetitle">${_("{course_number} Course Info").format(course_number=course.display_number_with_default)} - -<%block name="headextra"> -<%static:css group='style-course-vendor'/> -<%static:css group='style-course'/> - - -% if show_enroll_banner: -
-% endif - -<%include file="/courseware/course_navigation.html" args="active_page='info'" /> - -<%static:require_module_async module_name="js/courseware/toggle_element_visibility" class_name="ToggleElementVisibility"> - ToggleElementVisibility(); - -<%static:require_module_async module_name="js/courseware/course_info_events" class_name="CourseInfoEvents"> - CourseInfoEvents(); - - -<%block name="bodyclass">view-in-course view-course-info ${course.css_class or ''} - -
-
-
-
-

- % if show_org: - ${_("Welcome to {org}'s {course_title}!").format(org=course.display_org_with_default, course_title=course_title)} - % else: - ${_("Welcome to {course_title}!").format(course_title=course_title)} - % endif - % if show_subtitle: -
${course_subtitle}
- % endif -

-
- % if resume_course_url and user_is_enrolled: - - % endif -
-
- % if user.is_authenticated: -
- % if studio_url is not None and masquerade and masquerade.role == 'staff': - - % endif - -

${_("Course Updates and News")}

- ${HTML(get_course_info_section(request, masquerade_user, course, 'updates'))} - -
-
- % if course_tools: -

${_("Course Tools")}

- % for course_tool in course_tools: - - - ${course_tool.title()} - - % endfor - % endif - % if SelfPacedConfiguration.current().enable_course_home_improvements: - ${HTML(dates_fragment.body_html())} - % endif -

${_(course.info_sidebar_name)}

- ${HTML(get_course_info_section(request, masquerade_user, course, 'handouts'))} -
- % else: -
-

${_("Course Updates and News")}

- ${HTML(get_course_info_section(request, masquerade_user, course, 'guest_updates'))} -
-
-

${_("Course Handouts")}

- ${HTML(get_course_info_section(request, masquerade_user, course, 'guest_handouts'))} -
- % endif -
-
-
- -<%static:require_module_async module_name="js/dateutil_factory" class_name="DateUtilFactory"> - DateUtilFactory.transform(iterationKey=".localized-datetime"); - diff --git a/lms/urls.py b/lms/urls.py index 7c9e08a745..48f3e00ba2 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -47,7 +47,6 @@ from openedx.core.djangoapps.password_policy import compliance as password_polic from openedx.core.djangoapps.password_policy.forms import PasswordPolicyAwareAdminAuthForm from openedx.core.djangoapps.plugins.constants import ProjectType from openedx.core.djangoapps.programs.models import ProgramsApiConfig -from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.djangoapps.user_authn.views.login import redirect_to_lms_login from openedx.features.enterprise_support.api import enterprise_enabled @@ -379,16 +378,9 @@ urlpatterns += [ r'^courses/{}/$'.format( settings.COURSE_ID_PATTERN, ), - courseware_views.course_info, + courseware_views.course_about, name='course_root', ), - re_path( - r'^courses/{}/info$'.format( - settings.COURSE_ID_PATTERN, - ), - courseware_views.course_info, - name='info', - ), # TODO arjun remove when custom tabs in place, see courseware/courses.py re_path( r'^courses/{}/syllabus$'.format( @@ -892,7 +884,6 @@ if settings.FEATURES.get('ENABLE_LTI_PROVIDER'): ] urlpatterns += [ - path('config/self_paced', ConfigurationModelCurrentAPIView.as_view(model=SelfPacedConfiguration)), path('config/programs', ConfigurationModelCurrentAPIView.as_view(model=ProgramsApiConfig)), path('config/catalog', ConfigurationModelCurrentAPIView.as_view(model=CatalogIntegration)), path('config/forums', ConfigurationModelCurrentAPIView.as_view(model=ForumsConfig)), diff --git a/openedx/core/djangoapps/content/course_overviews/tests/test_course_overviews.py b/openedx/core/djangoapps/content/course_overviews/tests/test_course_overviews.py index d9b8859a60..3af01b49a3 100644 --- a/openedx/core/djangoapps/content/course_overviews/tests/test_course_overviews.py +++ b/openedx/core/djangoapps/content/course_overviews/tests/test_course_overviews.py @@ -62,7 +62,7 @@ class CourseOverviewTestCase(CatalogIntegrationMixin, ModuleStoreTestCase, Cache None: None, } - COURSE_OVERVIEW_TABS = {'courseware', 'info', 'textbooks', 'discussion', 'wiki', 'progress', 'dates'} + COURSE_OVERVIEW_TABS = {'courseware', 'textbooks', 'discussion', 'wiki', 'progress', 'dates'} ENABLED_SIGNALS = ['course_deleted', 'course_published'] diff --git a/openedx/core/djangoapps/schedules/docs/README.rst b/openedx/core/djangoapps/schedules/docs/README.rst index 9b662eb7bb..4e9f02ca39 100644 --- a/openedx/core/djangoapps/schedules/docs/README.rst +++ b/openedx/core/djangoapps/schedules/docs/README.rst @@ -236,17 +236,6 @@ Configuration Flags Configuring Schedule Creation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Self-paced Configuration -^^^^^^^^^^^^^^^^^^^^^^^^ - -Schedules will only be created for a course if it is self-paced. A -course can be configured to be self-paced by going to -``/admin/self_paced/selfpacedconfiguration/`` and adding an -enabled self paced config. Then, go to Studio settings for the course -and change the Course Pacing value to “Self-Paced”. Note that the Course -Start Date has to be set to sometime in the future in order to change -the Course Pacing. - Configuring Upgrade Deadline on Schedule ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/openedx/core/djangoapps/schedules/tests/test_resolvers.py b/openedx/core/djangoapps/schedules/tests/test_resolvers.py index 83b98e5b76..2557c3c961 100644 --- a/openedx/core/djangoapps/schedules/tests/test_resolvers.py +++ b/openedx/core/djangoapps/schedules/tests/test_resolvers.py @@ -252,7 +252,7 @@ class TestCourseNextSectionUpdateResolver(SchedulesResolverTestMixin, ModuleStor def test_schedule_context(self): resolver = self.create_resolver() # using this to make sure the select_related stays intact - with self.assertNumQueries(41): + with self.assertNumQueries(38): sc = resolver.get_schedules() schedules = list(sc) diff --git a/openedx/core/djangoapps/self_paced/__init__.py b/openedx/core/djangoapps/self_paced/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/openedx/core/djangoapps/self_paced/admin.py b/openedx/core/djangoapps/self_paced/admin.py deleted file mode 100644 index df3ff01b25..0000000000 --- a/openedx/core/djangoapps/self_paced/admin.py +++ /dev/null @@ -1,11 +0,0 @@ -""" -Admin site bindings for self-paced courses. -""" - - -from config_models.admin import ConfigurationModelAdmin -from django.contrib import admin - -from .models import SelfPacedConfiguration - -admin.site.register(SelfPacedConfiguration, ConfigurationModelAdmin) diff --git a/openedx/core/djangoapps/self_paced/migrations/0001_initial.py b/openedx/core/djangoapps/self_paced/migrations/0001_initial.py deleted file mode 100644 index 0e8c85408d..0000000000 --- a/openedx/core/djangoapps/self_paced/migrations/0001_initial.py +++ /dev/null @@ -1,27 +0,0 @@ -from django.db import migrations, models -import django.db.models.deletion -from django.conf import settings - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='SelfPacedConfiguration', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('change_date', models.DateTimeField(auto_now_add=True, verbose_name='Change date')), - ('enabled', models.BooleanField(default=False, verbose_name='Enabled')), - ('enable_course_home_improvements', models.BooleanField(default=False, verbose_name='Enable course home page improvements.')), - ('changed_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, editable=False, to=settings.AUTH_USER_MODEL, null=True, verbose_name='Changed by')), - ], - options={ - 'ordering': ('-change_date',), - 'abstract': False, - }, - ), - ] diff --git a/openedx/core/djangoapps/self_paced/migrations/__init__.py b/openedx/core/djangoapps/self_paced/migrations/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/openedx/core/djangoapps/self_paced/models.py b/openedx/core/djangoapps/self_paced/models.py deleted file mode 100644 index 333214a9c6..0000000000 --- a/openedx/core/djangoapps/self_paced/models.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -Configuration for self-paced courses. -""" - - -from config_models.models import ConfigurationModel -from django.db.models import BooleanField -from django.utils.translation import gettext_lazy as _ - - -class SelfPacedConfiguration(ConfigurationModel): - """ - Configuration for self-paced courses. - - .. no_pii: - """ - - enable_course_home_improvements = BooleanField( - default=False, - verbose_name=_("Enable course home page improvements.") - ) diff --git a/openedx/core/djangoapps/theming/tests/test_theme_style_overrides.py b/openedx/core/djangoapps/theming/tests/test_theme_style_overrides.py index 0971ac0415..21b9ba952a 100644 --- a/openedx/core/djangoapps/theming/tests/test_theme_style_overrides.py +++ b/openedx/core/djangoapps/theming/tests/test_theme_style_overrides.py @@ -124,8 +124,8 @@ class TestComprehensiveThemeLMS(TestCase): courses_url = reverse('courses') resp = self.client.get(courses_url) assert resp.status_code == 200 - # The courses.html template includes the info.html file, which is overriden in the theme. - self.assertContains(resp, "This overrides the courseware/info.html template.") + # The courses.html template includes the progress.html file, which is overriden in the theme. + self.assertContains(resp, "This overrides the courseware/progress.html template.") @with_comprehensive_theme("test-theme") def test_include_custom_template(self): diff --git a/openedx/features/course_experience/__init__.py b/openedx/features/course_experience/__init__.py index e8c0e6ac64..52b870033a 100644 --- a/openedx/features/course_experience/__init__.py +++ b/openedx/features/course_experience/__init__.py @@ -16,11 +16,6 @@ DISABLE_COURSE_OUTLINE_PAGE_FLAG = CourseWaffleFlag( # lint-amnesty, pylint: di f'{WAFFLE_FLAG_NAMESPACE}.disable_course_outline_page', __name__ ) -# Waffle flag to enable a single unified "Course" tab. -DISABLE_UNIFIED_COURSE_TAB_FLAG = CourseWaffleFlag( # lint-amnesty, pylint: disable=toggle-missing-annotation - f'{WAFFLE_FLAG_NAMESPACE}.disable_unified_course_tab', __name__ -) - # Waffle flag to enable the sock on the footer of the home and courseware pages. DISPLAY_COURSE_SOCK_FLAG = CourseWaffleFlag(f'{WAFFLE_FLAG_NAMESPACE}.display_course_sock', __name__) # lint-amnesty, pylint: disable=toggle-missing-annotation @@ -100,8 +95,4 @@ def course_home_url(course_key): course_key (CourseKey): The course key for which the home url is being requested. """ from .url_helpers import get_learning_mfe_home_url - - if DISABLE_UNIFIED_COURSE_TAB_FLAG.is_enabled(course_key): - return reverse('info', args=[str(course_key)]) - return get_learning_mfe_home_url(course_key, url_fragment='home') diff --git a/openedx/features/course_experience/plugins.py b/openedx/features/course_experience/plugins.py index 1d3adab33c..35f0cea023 100644 --- a/openedx/features/course_experience/plugins.py +++ b/openedx/features/course_experience/plugins.py @@ -11,7 +11,6 @@ from django.utils.translation import gettext as _ from common.djangoapps.student.models import CourseEnrollment from openedx.core.lib.courses import get_course_by_id -from . import DISABLE_UNIFIED_COURSE_TAB_FLAG from .course_tools import CourseTool from .views.course_updates import CourseUpdatesFragmentView @@ -46,8 +45,6 @@ class CourseUpdatesTool(CourseTool): """ Returns True if the user should be shown course updates for this course. """ - if DISABLE_UNIFIED_COURSE_TAB_FLAG.is_enabled(course_key): - return False if not CourseEnrollment.is_enrolled(request.user, course_key): return False course = get_course_by_id(course_key) diff --git a/openedx/features/enterprise_support/tests/test_api.py b/openedx/features/enterprise_support/tests/test_api.py index 08e108a67e..714c4179a9 100644 --- a/openedx/features/enterprise_support/tests/test_api.py +++ b/openedx/features/enterprise_support/tests/test_api.py @@ -704,9 +704,12 @@ class TestEnterpriseApi(EnterpriseServiceMockMixin, CacheIsolationTestCase): ) course_id = 'course-v1:edX+DemoX+Demo_Course' - return_to = None if is_return_to_null else 'info' + return_to = None if is_return_to_null else 'courseware' - expected_path = request_mock.path if is_return_to_null else '/courses/course-v1:edX+DemoX+Demo_Course/info' + if is_return_to_null: + expected_path = request_mock.path + else: + expected_path = '/courses/course-v1:edX+DemoX+Demo_Course/courseware' expected_url_args = { 'course_id': ['course-v1:edX+DemoX+Demo_Course'], 'failure_url': ['http://localhost:8000/dashboard?consent_failed=course-v1%3AedX%2BDemoX%2BDemo_Course'], diff --git a/setup.py b/setup.py index ef1d2fc033..e67f8040ef 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,6 @@ setup( "openedx.course_tab": [ "ccx = lms.djangoapps.ccx.plugins:CcxCourseTab", "courseware = lms.djangoapps.courseware.tabs:CoursewareTab", - "course_info = lms.djangoapps.courseware.tabs:CourseInfoTab", "dates = lms.djangoapps.courseware.tabs:DatesTab", "discussion = lms.djangoapps.discussion.plugins:DiscussionTab", "edxnotes = lms.djangoapps.edxnotes.plugins:EdxNotesTab", From aba1f052dfac33b3e466753bc58afffb5ee049b7 Mon Sep 17 00:00:00 2001 From: Navin Karkera Date: Mon, 6 Jun 2022 19:10:12 +0530 Subject: [PATCH 17/63] fix: handle missing COMPLETION_AGGREGATOR_URL setting (#30331) --- lms/templates/courseware/courseware.html | 4 ++-- lms/templates/seq_module.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lms/templates/courseware/courseware.html b/lms/templates/courseware/courseware.html index 882f453e76..1003efb57f 100644 --- a/lms/templates/courseware/courseware.html +++ b/lms/templates/courseware/courseware.html @@ -22,7 +22,7 @@ from openedx.features.course_experience import course_home_page_title, DISABLE_C (course.enable_proctored_exams or course.enable_timed_exams) ) - completion_aggregator_url = settings.COMPLETION_AGGREGATOR_URL if settings.FEATURES.get("SHOW_PROGRESS_BAR", False) else "" + completion_aggregator_url = getattr(settings, "COMPLETION_AGGREGATOR_URL", "") %> <%def name="course_name()"> @@ -238,7 +238,7 @@ ${HTML(fragment.foot_html())} ${sequence_title} % endif - % if settings.FEATURES.get("SHOW_PROGRESS_BAR", False): + % if settings.FEATURES.get("SHOW_PROGRESS_BAR", False) and completion_aggregator_url:
diff --git a/lms/templates/seq_module.html b/lms/templates/seq_module.html index 6a7aa6c7cc..f29f6ae062 100644 --- a/lms/templates/seq_module.html +++ b/lms/templates/seq_module.html @@ -117,7 +117,7 @@ ${gated_sequence_paywall | n, decode.utf8} % else:
- % if settings.FEATURES.get("SHOW_PROGRESS_BAR", False): + % if settings.FEATURES.get("SHOW_PROGRESS_BAR", False) and getattr(settings, 'COMPLETION_AGGREGATOR_URL', ''):
From d7a60fd21bd8e4fb3b678a2bc0acb556e11555e0 Mon Sep 17 00:00:00 2001 From: ansabgillani Date: Tue, 17 May 2022 13:30:23 +0500 Subject: [PATCH 18/63] feat: add SSO History to support --- .../decisions/0001-sso-history-in-support.rst | 48 +++++++++++++++++++ .../support/migrations/0001_initial.py | 42 ++++++++++++++++ lms/djangoapps/support/migrations/__init__.py | 0 lms/djangoapps/support/models.py | 9 ++++ lms/djangoapps/support/serializers.py | 38 +++++++++++---- lms/djangoapps/support/tests/test_views.py | 18 +++++++ lms/djangoapps/support/views/sso_records.py | 25 +++++++++- 7 files changed, 169 insertions(+), 11 deletions(-) create mode 100644 lms/djangoapps/support/docs/decisions/0001-sso-history-in-support.rst create mode 100644 lms/djangoapps/support/migrations/0001_initial.py create mode 100644 lms/djangoapps/support/migrations/__init__.py create mode 100644 lms/djangoapps/support/models.py diff --git a/lms/djangoapps/support/docs/decisions/0001-sso-history-in-support.rst b/lms/djangoapps/support/docs/decisions/0001-sso-history-in-support.rst new file mode 100644 index 0000000000..332f68af07 --- /dev/null +++ b/lms/djangoapps/support/docs/decisions/0001-sso-history-in-support.rst @@ -0,0 +1,48 @@ +1. Registering SSO History Model in Support +================================================ + +Status +------ + +Accepted + +Context +------- + +SSO History was one of the feature requested by support that provides the +historical data of any particular SSO record (based on UserSocialAuth) +in tools UI via support API. This SSO History can be utilized to track id changes, +Additional data or any other relevant data changes inside SSO model. + +Although the UserSocialAuth is applied within common apps but is not configured for +cms. This has caused major breakage and a temporary outage in the authentication flow +in cms stage. + +Decision +-------- + +The simple_django_history registration for UserSocialAuth model +is introduced in the Support app for LMS instead of the +third_party_auth in Common. + +Consequences +------------ + +The most optimum method to introduce the feature was to register the model +in support app and get the data via support API. + +Alternative/Rejected Approaches +------------ + +Addition for third_party_auth was attempted for the studio, +but failed in the stage. The primary reason was the failing migration +tests in CMS with the current configurations in the studio. +We tried to add the third_party_auth as an installed app on Studio +but later found out that Studio is not configured for third_party_auth +and configuring third_party_auth on studio would have caused auth issues. +Consequently, there was over 6 hours of pipeline outage on stage +and we had to revert the changes made in the system. + +Third party auth is primarily LMS-only app but since it has been in common, +we opted to go ahead with adding history in common, +only to later realize the impact of enabling third party auth in studio. diff --git a/lms/djangoapps/support/migrations/0001_initial.py b/lms/djangoapps/support/migrations/0001_initial.py new file mode 100644 index 0000000000..302155a6a3 --- /dev/null +++ b/lms/djangoapps/support/migrations/0001_initial.py @@ -0,0 +1,42 @@ +# Generated by Django 3.2.13 on 2022-05-17 08:26 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import simple_history.models +import social_django.fields + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='HistoricalUserSocialAuth', + fields=[ + ('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')), + ('provider', models.CharField(max_length=32)), + ('uid', models.CharField(db_index=True, max_length=255)), + ('extra_data', social_django.fields.JSONField(default=dict)), + ('created', models.DateTimeField(blank=True, editable=False)), + ('modified', models.DateTimeField(blank=True, editable=False)), + ('history_id', models.AutoField(primary_key=True, serialize=False)), + ('history_date', models.DateTimeField()), + ('history_change_reason', models.CharField(max_length=100, null=True)), + ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)), + ('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)), + ('user', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'historical user social auth', + 'ordering': ('-history_date', '-history_id'), + 'get_latest_by': 'history_date', + }, + bases=(simple_history.models.HistoricalChanges, models.Model), + ), + ] diff --git a/lms/djangoapps/support/migrations/__init__.py b/lms/djangoapps/support/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lms/djangoapps/support/models.py b/lms/djangoapps/support/models.py new file mode 100644 index 0000000000..3f2693f918 --- /dev/null +++ b/lms/djangoapps/support/models.py @@ -0,0 +1,9 @@ +""" +Models used to implement support related models in such as SSO History model +""" + +from simple_history import register +from social_django.models import UserSocialAuth + +# Registers UserSocialAuth with simple-django-history. +register(UserSocialAuth, app=__package__) diff --git a/lms/djangoapps/support/serializers.py b/lms/djangoapps/support/serializers.py index 0d4daa83e9..f1a28640ca 100644 --- a/lms/djangoapps/support/serializers.py +++ b/lms/djangoapps/support/serializers.py @@ -84,17 +84,35 @@ def serialize_user_info(user, user_social_auths=None): return user_info -def serialize_sso_records(user_social_auths): +def serialize_sso_records(user_social_auth, user_social_auths_history): """ Serialize user social auth model object """ - sso_records = [] - for user_social_auth in user_social_auths: - sso_records.append({ - 'provider': user_social_auth.provider, - 'uid': user_social_auth.uid, - 'created': user_social_auth.created, - 'modified': user_social_auth.modified, - 'extraData': json.dumps(user_social_auth.extra_data), - }) + sso_records = { + 'provider': user_social_auth.provider, + 'uid': user_social_auth.uid, + 'created': user_social_auth.created, + 'modified': user_social_auth.modified, + 'history': serialize_sso_history( + user_social_auths_history + ), + 'extraData': json.dumps(user_social_auth.extra_data), + } return sso_records + + +def serialize_sso_history(user_social_auths_history): + """ + Serialize history for user social auth model object + """ + history = [] + for sso_history in user_social_auths_history: + history.append({ + 'uid': sso_history.uid, + 'provider': sso_history.provider, + 'created': sso_history.created, + 'modified': sso_history.modified, + 'extraData': json.dumps(sso_history.extra_data), + 'history_date': sso_history.history_date + }) + return history diff --git a/lms/djangoapps/support/tests/test_views.py b/lms/djangoapps/support/tests/test_views.py index a6b8e43947..3aa56a0a76 100644 --- a/lms/djangoapps/support/tests/test_views.py +++ b/lms/djangoapps/support/tests/test_views.py @@ -1542,6 +1542,24 @@ class SsoRecordsTests(SupportViewTestCase): # lint-amnesty, pylint: disable=mis assert len(data) == 1 self.assertContains(response, '"uid": "test@example.com"') + def test_history_response(self): + '''Tests changes in SSO history for a user''' + user_social_auth = UserSocialAuth.objects.create( # lint-amnesty, pylint: disable=unused-variable + user=self.student, + uid=self.student.email, + provider='tpa-saml' + ) + sso = UserSocialAuth.objects.get(user=self.student) + sso.uid = self.student.email + ':' + sso.provider + sso.save() + response = self.client.get(self.url) + data = json.loads(response.content.decode('utf-8')) + assert response.status_code == 200 + assert len(data) == 1 + assert len(data[0].get('history')) == 2 + assert data[0].get('history')[0].get('uid') == "test@example.com:tpa-saml" + assert data[0].get('history')[1].get('uid') == "test@example.com" + class FeatureBasedEnrollmentSupportApiViewTests(SupportViewTestCase): """ diff --git a/lms/djangoapps/support/views/sso_records.py b/lms/djangoapps/support/views/sso_records.py index 372a4f4c53..b7d620a376 100644 --- a/lms/djangoapps/support/views/sso_records.py +++ b/lms/djangoapps/support/views/sso_records.py @@ -19,6 +19,7 @@ class SsoView(GenericAPIView): """ Returns a list of SSO records for a given user. Sample response: + Sample response: [ { "provider": "tpa-saml", @@ -26,6 +27,25 @@ class SsoView(GenericAPIView): "created": "2022-03-02T04:41:33.145Z", "modified": "2022-03-15T11:28:17.809Z", "extraData": "{}", + "history": + [ + { + "uid": "new-channel:testuser", + "provider": "tpa-saml", + "created": "2022-03-02T04:41:33.145Z", + "modified": "2022-03-15T11:28:17.809Z", + "extraData": "{}", + "history_date": "2022-03-15T11:28:17.832Z" + }, + { + "uid": "default-channel:testuser", + "provider": "tpa-saml", + "created": "2022-03-02T04:41:33.145Z", + "modified": "2022-03-10T12:28:32.720Z", + "extraData": "{}", + "history_date": "2022-03-15T11:12:02.420Z" + } + ] } ] """ @@ -36,5 +56,8 @@ class SsoView(GenericAPIView): except User.DoesNotExist: return JsonResponse([]) user_social_auths = UserSocialAuth.objects.filter(user=user) - sso_records = serialize_sso_records(user_social_auths) + sso_records = [] + for user_social_auth in user_social_auths: + user_social_auths_history = UserSocialAuth.history.filter(id=user_social_auth.id) + sso_records.append(serialize_sso_records(user_social_auth, user_social_auths_history)) return JsonResponse(sso_records) From 9f380b9ccd665edd3fa2287b4c74135393f3ae9d Mon Sep 17 00:00:00 2001 From: Kyle McCormick Date: Mon, 6 Jun 2022 09:54:16 -0400 Subject: [PATCH 19/63] refactor: import common/lib/ modules from canonical locations (#30533) Unfortunately, some code in edx-platform is imported relative to sub-projects instead of the repository root. The only three remaining instances of this are: * common/lib/xmodule/xmodule (imported as just 'xmodule') * common/lib/capa/capa (imported as just 'capa') * openedx/core/lib/xblock_builtin/xblock_discussion (imported as just 'xblock_discussion') For more details on the situation, see: https://openedx.atlassian.net/browse/BOM-2579 (public, but requires Atlassian account creation). We would like to get to a point where all edx-platform import paths match their folder paths, relative to the repo root. For now, though, all common/lib/capa and common/lib/xmodule code should be imported as just `from capa` and `from xmodule`, respectively. Importing using the full `common.lib.xmodule.xmodule...` path will often work, but it instantiates a second instance of all modules imported this way, which in the past has led to very difficult-to-diagnose bugs. It also confuses tooling such as import-linter, which we are trying to add to edx-platform (see https://openedx.atlassian.net/browse/BOM-2576) --- cms/envs/common.py | 4 ++-- cms/lib/xblock/test/test_authoring_mixin.py | 2 +- lms/djangoapps/discussion/tasks.py | 2 +- openedx/core/djangoapps/course_live/tab.py | 4 ++-- setup.py | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cms/envs/common.py b/cms/envs/common.py index 876fe559aa..7ec9713743 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -1112,10 +1112,10 @@ COURSES_WITH_UNSAFE_CODE = [] # Cojail REST service ENABLE_CODEJAIL_REST_SERVICE = False # .. setting_name: CODE_JAIL_REST_SERVICE_REMOTE_EXEC -# .. setting_default: 'common.lib.capa.capa.safe_exec.remote_exec.send_safe_exec_request_v0' +# .. setting_default: 'capa.safe_exec.remote_exec.send_safe_exec_request_v0' # .. setting_description: Set the python package.module.function that is reponsible of # calling the remote service in charge of jailed code execution -CODE_JAIL_REST_SERVICE_REMOTE_EXEC = 'common.lib.capa.capa.safe_exec.remote_exec.send_safe_exec_request_v0' +CODE_JAIL_REST_SERVICE_REMOTE_EXEC = 'capa.safe_exec.remote_exec.send_safe_exec_request_v0' # .. setting_name: CODE_JAIL_REST_SERVICE_HOST # .. setting_default: 'http://127.0.0.1:8550' # .. setting_description: Set the codejail remote service host diff --git a/cms/lib/xblock/test/test_authoring_mixin.py b/cms/lib/xblock/test/test_authoring_mixin.py index 9d848b06ba..6028f39614 100644 --- a/cms/lib/xblock/test/test_authoring_mixin.py +++ b/cms/lib/xblock/test/test_authoring_mixin.py @@ -14,9 +14,9 @@ from xmodule.partitions.partitions import ( Group, UserPartition ) +from xmodule.tests.test_export import PureXBlock from common.djangoapps.course_modes.tests.factories import CourseModeFactory -from common.lib.xmodule.xmodule.tests.test_export import PureXBlock class AuthoringMixinTestCase(ModuleStoreTestCase): diff --git a/lms/djangoapps/discussion/tasks.py b/lms/djangoapps/discussion/tasks.py index e8aa87d653..e60b5229db 100644 --- a/lms/djangoapps/discussion/tasks.py +++ b/lms/djangoapps/discussion/tasks.py @@ -18,10 +18,10 @@ from edx_django_utils.monitoring import set_code_owner_attribute from eventtracking import tracker from opaque_keys.edx.keys import CourseKey from six.moves.urllib.parse import urljoin +from xmodule.modulestore.django import modulestore import openedx.core.djangoapps.django_comment_common.comment_client as cc from common.djangoapps.track import segment -from common.lib.xmodule.xmodule.modulestore.django import modulestore from lms.djangoapps.discussion.django_comment_client.utils import ( permalink, get_users_with_moderator_roles, diff --git a/openedx/core/djangoapps/course_live/tab.py b/openedx/core/djangoapps/course_live/tab.py index 14a1355277..27b8e5ff29 100644 --- a/openedx/core/djangoapps/course_live/tab.py +++ b/openedx/core/djangoapps/course_live/tab.py @@ -4,8 +4,8 @@ Configurations to render Course Live Tab from django.utils.translation import gettext_lazy from lti_consumer.models import LtiConfiguration -from common.lib.xmodule.xmodule.course_module import CourseBlock -from common.lib.xmodule.xmodule.tabs import TabFragmentViewMixin +from xmodule.course_module import CourseBlock +from xmodule.tabs import TabFragmentViewMixin from lms.djangoapps.courseware.tabs import EnrolledTab from openedx.core.djangoapps.course_live.config.waffle import ENABLE_COURSE_LIVE from openedx.core.djangoapps.course_live.models import CourseLiveConfiguration diff --git a/setup.py b/setup.py index ef1d2fc033..cf2c995bc1 100644 --- a/setup.py +++ b/setup.py @@ -135,7 +135,7 @@ setup( 'lib = openedx.core.djangoapps.content_libraries.library_context:LibraryContextImpl', ], 'openedx.dynamic_partition_generator': [ - 'enrollment_track = common.lib.xmodule.xmodule.partitions.enrollment_track_partition_generator:create_enrollment_track_partition', # lint-amnesty, pylint: disable=line-too-long + 'enrollment_track = xmodule.partitions.enrollment_track_partition_generator:create_enrollment_track_partition', # lint-amnesty, pylint: disable=line-too-long 'content_type_gating = openedx.features.content_type_gating.partitions:create_content_gating_partition' ], } From 8d6e041d7e507791ebac00e27ca70624196afcf8 Mon Sep 17 00:00:00 2001 From: Alexander Sheehan Date: Fri, 3 Jun 2022 17:45:27 -0400 Subject: [PATCH 20/63] fix: allowing for multiple idp data configs --- common/djangoapps/third_party_auth/admin.py | 8 ++- common/djangoapps/third_party_auth/models.py | 15 ++++-- .../tests/test_samlproviderdata.py | 6 +-- .../samlproviderdata/views.py | 16 +++--- common/djangoapps/third_party_auth/tasks.py | 6 +-- .../third_party_auth/tests/test_utils.py | 44 +++++++++++++++-- common/djangoapps/third_party_auth/utils.py | 49 +++++++++---------- 7 files changed, 95 insertions(+), 49 deletions(-) diff --git a/common/djangoapps/third_party_auth/admin.py b/common/djangoapps/third_party_auth/admin.py index 35f43ad129..6b0ca785fd 100644 --- a/common/djangoapps/third_party_auth/admin.py +++ b/common/djangoapps/third_party_auth/admin.py @@ -108,8 +108,12 @@ class SAMLProviderConfigAdmin(KeyedConfigurationModelAdmin): """ Do we have cached metadata for this SAML provider? """ if not inst.is_active: return None # N/A - data = SAMLProviderData.current(inst.entity_id) - return bool(data and data.is_valid()) + records = SAMLProviderData.objects.filter(entity_id=inst.entity_id) + for record in records: + if record.is_valid(): + return True + return False + has_data.short_description = 'Metadata Ready' has_data.boolean = True diff --git a/common/djangoapps/third_party_auth/models.py b/common/djangoapps/third_party_auth/models.py index f0a37616a3..4d1c1f84a9 100644 --- a/common/djangoapps/third_party_auth/models.py +++ b/common/djangoapps/third_party_auth/models.py @@ -784,16 +784,23 @@ class SAMLProviderConfig(ProviderConfig): conf['attr_defaults'][field] = default # Now get the data fetched automatically from the metadata.xml: - data = SAMLProviderData.current(self.entity_id) - if not data or not data.is_valid(): + data_records = SAMLProviderData.objects.filter(entity_id=self.entity_id) + public_keys = [] + for record in data_records: + if record.is_valid(): + public_keys.append(record.public_key) + sso_url = record.sso_url + if not public_keys: log.error( 'No SAMLProviderData found for provider "%s" with entity id "%s" and IdP slug "%s". ' 'Run "manage.py saml pull" to fix or debug.', self.name, self.entity_id, self.slug ) raise AuthNotConfigured(provider_name=self.name) - conf['x509cert'] = data.public_key - conf['url'] = data.sso_url + + conf['x509certMulti'] = {'signing': public_keys} + conf['x509cert'] = '' + conf['url'] = sso_url # Add SAMLConfiguration appropriate for this IdP conf['saml_sp_configuration'] = ( diff --git a/common/djangoapps/third_party_auth/samlproviderdata/tests/test_samlproviderdata.py b/common/djangoapps/third_party_auth/samlproviderdata/tests/test_samlproviderdata.py index 8854d320ae..5dbf7a803e 100644 --- a/common/djangoapps/third_party_auth/samlproviderdata/tests/test_samlproviderdata.py +++ b/common/djangoapps/third_party_auth/samlproviderdata/tests/test_samlproviderdata.py @@ -203,7 +203,7 @@ class SAMLProviderDataTests(APITestCase): POST auth/saml/v0/provider_data/sync_provider_data -d data """ mock_fetch.return_value = 'tag' - public_key = 'askdjf;sakdjfs;adkfjas;dkfjas;dkfjas;dlkfj' + public_key = ['askdjf;sakdjfs;adkfjas;dkfjas;dkfjas;dlkfj'] sso_url = 'https://fake-test.id' expires_at = datetime.now() mock_parse.return_value = (public_key, sso_url, expires_at) @@ -219,11 +219,11 @@ class SAMLProviderDataTests(APITestCase): response = self.client.post(url, data) assert response.status_code == status.HTTP_201_CREATED - assert response.data == " Created new record for SAMLProviderData for entityID http://entity-id-1" + assert response.data == " Created new record(s) for SAMLProviderData for entityID http://entity-id-1" assert SAMLProviderData.objects.count() == orig_count + 1 # should only update this time response = self.client.post(url, data) assert response.status_code == status.HTTP_200_OK - assert response.data == (" Updated existing SAMLProviderData for entityID http://entity-id-1") + assert response.data == (" Updated existing SAMLProviderData record(s) for entityID http://entity-id-1") assert SAMLProviderData.objects.count() == orig_count + 1 diff --git a/common/djangoapps/third_party_auth/samlproviderdata/views.py b/common/djangoapps/third_party_auth/samlproviderdata/views.py index 09ad65dfa8..f61b237c12 100644 --- a/common/djangoapps/third_party_auth/samlproviderdata/views.py +++ b/common/djangoapps/third_party_auth/samlproviderdata/views.py @@ -18,7 +18,7 @@ from rest_framework.response import Response from common.djangoapps.third_party_auth.utils import ( convert_saml_slug_provider_id, - create_or_update_saml_provider_data, + create_or_update_bulk_saml_provider_data, fetch_metadata_xml, parse_metadata_xml, validate_uuid4_string @@ -110,12 +110,12 @@ class SAMLProviderDataViewSet(PermissionRequiredMixin, SAMLProviderDataMixin, vi entity_id = request.POST.get('entity_id') metadata_url = request.POST.get('metadata_url') sso_url = request.POST.get('sso_url') - public_key = request.POST.get('public_key') + public_keys = request.POST.get('public_key') if not entity_id: return Response('entity_id is required', status.HTTP_400_BAD_REQUEST) - if not metadata_url and not (sso_url and public_key): + if not metadata_url and not (sso_url and public_keys): return Response('either metadata_url or sso and public key are required', status.HTTP_400_BAD_REQUEST) - if metadata_url and (sso_url or public_key): + if metadata_url and (sso_url or public_keys): return Response( 'either metadata_url or sso and public key can be provided, not both', status.HTTP_400_BAD_REQUEST ) @@ -131,18 +131,18 @@ class SAMLProviderDataViewSet(PermissionRequiredMixin, SAMLProviderDataMixin, vi # part 2: create/update samlproviderdata log.info("Processing IdP with entityID %s", entity_id) - public_key, sso_url, expires_at = parse_metadata_xml(xml, entity_id) + public_keys, sso_url, expires_at = parse_metadata_xml(xml, entity_id) else: now = datetime.now() expires_at = now.replace(year=now.year + 10) - changed = create_or_update_saml_provider_data(entity_id, public_key, sso_url, expires_at) + changed = create_or_update_bulk_saml_provider_data(entity_id, public_keys, sso_url, expires_at) if changed: - str_message = f" Created new record for SAMLProviderData for entityID {entity_id}" + str_message = f" Created new record(s) for SAMLProviderData for entityID {entity_id}" log.info(str_message) response = str_message http_status = status.HTTP_201_CREATED else: - str_message = f" Updated existing SAMLProviderData for entityID {entity_id}" + str_message = f" Updated existing SAMLProviderData record(s) for entityID {entity_id}" log.info(str_message) response = str_message http_status = status.HTTP_200_OK diff --git a/common/djangoapps/third_party_auth/tasks.py b/common/djangoapps/third_party_auth/tasks.py index 88b118a689..d702932f4d 100644 --- a/common/djangoapps/third_party_auth/tasks.py +++ b/common/djangoapps/third_party_auth/tasks.py @@ -14,7 +14,7 @@ from requests import exceptions from common.djangoapps.third_party_auth.models import SAMLConfiguration, SAMLProviderConfig from common.djangoapps.third_party_auth.utils import ( MetadataParseError, - create_or_update_saml_provider_data, + create_or_update_bulk_saml_provider_data, parse_metadata_xml, ) @@ -87,8 +87,8 @@ def fetch_saml_metadata(): for entity_id in entity_ids: log.info("Processing IdP with entityID %s", entity_id) - public_key, sso_url, expires_at = parse_metadata_xml(xml, entity_id) - changed = create_or_update_saml_provider_data(entity_id, public_key, sso_url, expires_at) + public_keys, sso_url, expires_at = parse_metadata_xml(xml, entity_id) + changed = create_or_update_bulk_saml_provider_data(entity_id, public_keys, sso_url, expires_at) if changed: log.info(f"→ Created new record for SAMLProviderData for entityID {entity_id}") num_updated += 1 diff --git a/common/djangoapps/third_party_auth/tests/test_utils.py b/common/djangoapps/third_party_auth/tests/test_utils.py index 2d971e69d0..5d35d92b46 100644 --- a/common/djangoapps/third_party_auth/tests/test_utils.py +++ b/common/djangoapps/third_party_auth/tests/test_utils.py @@ -157,8 +157,44 @@ class TestUtils(TestCase): ''' xml = etree.fromstring(xml_text, parser) - public_key, sso_url, _ = parse_metadata_xml(xml, entity_id) - assert public_key == 'abc+hkIuUktxkg=' + public_keys, sso_url, _ = parse_metadata_xml(xml, entity_id) + assert public_keys == ['abc+hkIuUktxkg='] + assert sso_url == 'https://idp/SSOService.php' + + def test_parse_metadata_uses_multiple_signing_cert(self): + entity_id = 'http://testid' + parser = etree.XMLParser(remove_comments=True) + xml_text = ''' + + + + + + abc+hkIuUktxkg= + + + + + + + xyz+ayylmao= + + + + + + + blachabc+hkIuUktxkg=blaal;skdjf;ksd + + + + + + + ''' + xml = etree.fromstring(xml_text, parser) + public_keys, sso_url, _ = parse_metadata_xml(xml, entity_id) + assert public_keys == ['abc+hkIuUktxkg=', 'xyz+ayylmao='] assert sso_url == 'https://idp/SSOService.php' def test_parse_metadata_with_use_attribute_missing(self): @@ -179,6 +215,6 @@ class TestUtils(TestCase): ''' xml = etree.fromstring(xml_text, parser) - public_key, sso_url, _ = parse_metadata_xml(xml, entity_id) - assert public_key == 'abc+hkIuUktxkg=' + public_keys, sso_url, _ = parse_metadata_xml(xml, entity_id) + assert public_keys == ['abc+hkIuUktxkg='] assert sso_url == 'https://idp/SSOService.php' diff --git a/common/djangoapps/third_party_auth/utils.py b/common/djangoapps/third_party_auth/utils.py index 8517af0328..0cb6981030 100644 --- a/common/djangoapps/third_party_auth/utils.py +++ b/common/djangoapps/third_party_auth/utils.py @@ -101,18 +101,24 @@ def parse_metadata_xml(xml, entity_id): # Now we just need to get the public_key and sso_url # We want the use='signing' cert, not the 'encryption' one - public_key = sso_desc.findtext("./{}[@use='signing']//{}".format( + # There may be multiple signing certs returned by the server so create one record per signing cert found. + certs = sso_desc.findall("./{}[@use='signing']//{}".format( etree.QName(SAML_XML_NS, "KeyDescriptor"), "{http://www.w3.org/2000/09/xmldsig#}X509Certificate" )) - if not public_key: + + if not certs: # it's possible that there is just one keyDescription with no use attribute # that is a shortcut for both signing and encryption combined. So we can use that as fallback. - public_key = sso_desc.findtext("./{}//{}".format( + certs = sso_desc.findall("./{}//{}".format( etree.QName(SAML_XML_NS, "KeyDescriptor"), "{http://www.w3.org/2000/09/xmldsig#}X509Certificate" )) - if not public_key: + if not certs: raise MetadataParseError("Public Key missing. Expected an ") - public_key = public_key.replace(" ", "") + + public_keys = [] + for key in certs: + public_keys.append(key.text.replace(" ", "")) + binding_elements = sso_desc.iterfind("./{}".format(etree.QName(SAML_XML_NS, "SingleSignOnService"))) sso_bindings = {element.get('Binding'): element.get('Location') for element in binding_elements} try: @@ -120,7 +126,7 @@ def parse_metadata_xml(xml, entity_id): sso_url = sso_bindings['urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'] except KeyError: raise MetadataParseError("Unable to find SSO URL with HTTP-Redirect binding.") # lint-amnesty, pylint: disable=raise-missing-from - return public_key, sso_url, expires_at + return public_keys, sso_url, expires_at def user_exists(details): @@ -164,29 +170,22 @@ def get_user_from_email(details): return None -def create_or_update_saml_provider_data(entity_id, public_key, sso_url, expires_at): +def create_or_update_bulk_saml_provider_data(entity_id, public_keys, sso_url, expires_at): """ - Update/Create the SAMLProviderData for the given entity ID. - Return value: - False if nothing has changed and existing data's "fetched at" timestamp is just updated. - True if a new record was created. (Either this is a new provider or something changed.) + Placeholder """ - data_obj = SAMLProviderData.current(entity_id) fetched_at = now() - if data_obj and (data_obj.public_key == public_key and data_obj.sso_url == sso_url): - data_obj.expires_at = expires_at - data_obj.fetched_at = fetched_at - data_obj.save() - return False - else: - SAMLProviderData.objects.create( - entity_id=entity_id, - fetched_at=fetched_at, - expires_at=expires_at, - sso_url=sso_url, - public_key=public_key, + new_records_created = False + # Create a data record for each of the public keys provided + for key in public_keys: + _, created = SAMLProviderData.objects.update_or_create( + public_key=key, entity_id=entity_id, + defaults={'sso_url': sso_url, 'expires_at': expires_at, 'fetched_at': fetched_at}, ) - return True + if created: + new_records_created = True + + return new_records_created def convert_saml_slug_provider_id(provider): # lint-amnesty, pylint: disable=redefined-outer-name From 05b4aa8d4b9b5358aac72bdbf65a138b1b87a44f Mon Sep 17 00:00:00 2001 From: Rebecca Graber Date: Mon, 6 Jun 2022 11:36:27 -0400 Subject: [PATCH 21/63] docs: ADR with guidance for new applications (#30053) --- docs/decisions/0014-no-new-apps.rst | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 docs/decisions/0014-no-new-apps.rst diff --git a/docs/decisions/0014-no-new-apps.rst b/docs/decisions/0014-no-new-apps.rst new file mode 100644 index 0000000000..6c07a8e2c0 --- /dev/null +++ b/docs/decisions/0014-no-new-apps.rst @@ -0,0 +1,34 @@ +Justifying new Django applications in edx-platform +================================================== + +Status +------ +Accepted + +Context +------- +The Open edX platform is moving toward a more modular architecture. The goal is to transition from a monolithic application in edx-platform to one in which this repository represents a small, stable core with volatility pushed into extensions and plugins. To that end, much of the original edx-platform repository has been split out into micro-frontends, other microservices, plugins, and libraries. However, there are still a number of optional and non-core Django applications within edx-platform and new ones continue to be added. +For more information on plugins in particular, see the `Django Apps Plugin README`_. + +.. _Django Apps Plugin README: https://github.com/openedx/edx-django-utils/blob/master/edx_django_utils/plugins/README.rst + + +Decision +-------- +From the adoption of this ADR, no new Django applications should be added into the edx-platform repository without an accompanying ADR explaining why the application cannot or should not be created in a new repository or included in an existing external plugin or library. + +Further Guidance +---------------- + +While the preference should always be to develop outside the edx-platform repository, either by extending an existing external Django application repository or creating a new one, there are still acceptable reasons why a new application would be better developed within edx-platform: + +* The application relates directly to core functionality: course authoring, course administration, or learner-courseware interactions +* The application requires multiple imports from edx-platform + + * Note: There are strategies for plugging apps into core LMS and CMS behaviors without directly importing edx-platform code, notably the `Hooks Extension Framework`_. + * If it is truly necessary to import from edx-platform code directly, in addition to noting this in the ADR, the authors of the new application should add the libraries or applications it imports to the `Libraries we KNOW we want to move out of the monolith`_ Confluence page. + + +.. _Hooks Extension Framework: https://open-edx-proposals.readthedocs.io/en/latest/architectural-decisions/oep-0050-hooks-extension-framework.html + +.. _Libraries we KNOW we want to move out of the monolith: https://openedx.atlassian.net/wiki/spaces/AC/pages/525172740/Libraries+we+KNOW+we+want+to+move+out+of+the+monolith From ab59796a56823985a9851dedad949b2b862e34a4 Mon Sep 17 00:00:00 2001 From: connorhaugh <49422820+connorhaugh@users.noreply.github.com> Date: Wed, 1 Jun 2022 10:52:09 -0400 Subject: [PATCH 22/63] fix: python-dateutil version issue --- lms/djangoapps/courseware/access_utils.py | 8 ++++- lms/djangoapps/courseware/courses.py | 9 +++++- lms/djangoapps/instructor/tests/test_api.py | 4 +-- .../block_structure/block_structure.py | 27 +++++++++++++++-- requirements/constraints.txt | 15 +++------- requirements/edx-sandbox/py38.txt | 18 ++++-------- requirements/edx/base.txt | 13 ++++----- requirements/edx/coverage.txt | 2 +- requirements/edx/development.txt | 29 +++++++++---------- requirements/edx/doc.txt | 2 +- requirements/edx/testing.txt | 25 +++++++--------- 11 files changed, 84 insertions(+), 68 deletions(-) diff --git a/lms/djangoapps/courseware/access_utils.py b/lms/djangoapps/courseware/access_utils.py index 059a11e5b3..2e7c2fb330 100644 --- a/lms/djangoapps/courseware/access_utils.py +++ b/lms/djangoapps/courseware/access_utils.py @@ -87,7 +87,13 @@ def check_start_date(user, days_early_for_beta, start, course_key, display_error if now is None: now = datetime.now(UTC) effective_start = adjust_start_date(user, days_early_for_beta, start, course_key) - if now > effective_start: + + # Todo: This log statement is added for temporary use only + log.info('Python-dateutil logs: Comparing current date with effective start date') + should_grant_access = now > effective_start + # Todo: This log statement is added for temporary use only + log.info('Python-dateutil logs: Successfully compared current date with effective start date') + if should_grant_access: return ACCESS_GRANTED return StartDateError(start, display_error_to_user=display_error_to_user) diff --git a/lms/djangoapps/courseware/courses.py b/lms/djangoapps/courseware/courses.py index cd755a8d47..93c58f20aa 100644 --- a/lms/djangoapps/courseware/courses.py +++ b/lms/djangoapps/courseware/courses.py @@ -557,6 +557,11 @@ def get_course_assignments(course_key, user, include_access=False): # lint-amne """ if not user.id: return [] + + # Todo: This log statement is added for temporary use only + log.info('Python-dateutil logs: Trying to get course assignment for user: {} of course: {}'.format( + user.id, course_key)) + store = modulestore() course_usage_key = store.make_course_usage_key(course_key) block_data = get_course_blocks(user, course_usage_key, allow_start_dates_in_future=True, include_completion=True) @@ -658,7 +663,9 @@ def get_course_assignments(course_key, user, include_access=False): # lint-amne _("Open Response Assessment due dates are set by your instructor and can't be shifted."), first_component_block_id, )) - + # Todo: This log statement is added for temporary use only + log.info('Python-dateutil logs: Successfully got course assignments for user: {} of course: {}'.format( + user.id, course_key)) return assignments diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py index 92d9625f1c..d24e65b5c6 100644 --- a/lms/djangoapps/instructor/tests/test_api.py +++ b/lms/djangoapps/instructor/tests/test_api.py @@ -3506,8 +3506,8 @@ class TestInstructorSendEmail(SiteMixin, SharedModuleStoreTestCase, LoginEnrollm schedule = "Blub Glub" self.full_test_message['schedule'] = "Blub Glub" expected_message = ( - f"Error occurred creating a scheduled bulk email task. Schedule provided: '{schedule}'. Error: unknown " - "string format" + f"Error occurred creating a scheduled bulk email task. Schedule provided: '{schedule}'. Error: Unknown " + "string format: Blub Glub" ) url = reverse('send_email', kwargs={'course_id': str(self.course.id)}) diff --git a/openedx/core/djangoapps/content/block_structure/block_structure.py b/openedx/core/djangoapps/content/block_structure/block_structure.py index a8d10c4d81..17e06546d4 100644 --- a/openedx/core/djangoapps/content/block_structure/block_structure.py +++ b/openedx/core/djangoapps/content/block_structure/block_structure.py @@ -11,9 +11,12 @@ The following internal data structures are implemented: from copy import deepcopy +from datetime import datetime from functools import partial from logging import getLogger +from dateutil.tz import tzlocal + from openedx.core.lib.graph_traversals import traverse_post_order, traverse_topologically from .exceptions import TransformerException @@ -464,7 +467,8 @@ class BlockStructureBlockData(BlockStructure): not found. """ block_data = self._block_data_map.get(usage_key) - return getattr(block_data, field_name, default) if block_data else default + xblock_field = getattr(block_data, field_name, default) if block_data else default + return self._make_datetime_field_compatible(xblock_field) def override_xblock_field(self, usage_key, field_name, override_data): """ @@ -554,7 +558,8 @@ class BlockStructureBlockData(BlockStructure): transformer_data = self.get_transformer_block_data(usage_key, transformer) except KeyError: return default - return getattr(transformer_data, key, default) + field = getattr(transformer_data, key, default) + return self._make_datetime_field_compatible(field) def set_transformer_block_field(self, usage_key, transformer, key, value): """ @@ -763,6 +768,24 @@ class BlockStructureBlockData(BlockStructure): self._block_data_map[usage_key] = block_data return block_data + def _make_datetime_field_compatible(self, field): + """ + Creates a new datetime object to avoid issues occurring due to upgrading + python-datetuil version from 2.4.0 + + More info: https://openedx.atlassian.net/browse/BOM-2245 + """ + if isinstance(field, datetime): + if isinstance(field.tzinfo, tzlocal) and not hasattr(field.tzinfo, '_hasdst'): + # Todo: This log statement is added for temporary use only + logger.info('Python-dateutil logs: Making datetime field compatible to python-dateutil package') + return datetime( + year=field.year, month=field.month, day=field.day, + hour=field.hour, minute=field.minute, second=field.second, + tzinfo=tzlocal() + ) + return field + class BlockStructureModulestoreData(BlockStructureBlockData): """ diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 9c063105a9..63a65cfee1 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -27,23 +27,14 @@ django-storages<1.9 # for them. edx-enterprise==3.49.7 -# Newer versions need a more recent version of python-dateutil -freezegun==0.3.12 - # oauthlib>3.0.1 causes test failures ( also remove the django-oauth-toolkit constraint when this is fixed ) oauthlib==3.0.1 # django-auth-toolkit==1.3.3 requires oauthlib>=3.1.0 which is pinned because of test failures django-oauth-toolkit<=1.3.2 -# Upgrading to 2.5.3 on 2020-01-03 triggered "'tzlocal' object has no attribute '_std_offset'" errors in production -python-dateutil==2.4.0 -# matplotlib>=3.4.0 requires python-dateutil>=2.7 +# Will be updated once we update python-dateutil package matplotlib<3.4.0 -# pandas>0.22.0 requires python-dateutil>=2.5.0 -pandas==0.22.0 -# networkx>=2.6 requires pandas>=1.1 -networkx<2.6 # tests failing for pymongo==3.11 pymongo<3.11 @@ -65,6 +56,9 @@ edxval<2.1 # version of py2neo will work with Neo4j 3.5. py2neo<2022 +# pylint==2.14.0 is causing test failures +pylint==2.13.9 + # Sphinx requires docutils<0.18. This pin can be removed once https://github.com/sphinx-doc/sphinx/issues/9777 is closed. docutils<0.18 @@ -79,4 +73,3 @@ scipy<1.8.0 # This will be fixed when sphinxcontrib-openapi depends on m2r2 instead of m2r # See issue: https://github.com/sphinx-contrib/openapi/issues/123 mistune<2.0.0 - diff --git a/requirements/edx-sandbox/py38.txt b/requirements/edx-sandbox/py38.txt index 8e164568f4..fb7f568eb1 100644 --- a/requirements/edx-sandbox/py38.txt +++ b/requirements/edx-sandbox/py38.txt @@ -18,13 +18,11 @@ cryptography==37.0.2 # via -r requirements/edx-sandbox/py38.in cycler==0.11.0 # via matplotlib -decorator==4.4.2 - # via networkx joblib==1.1.0 # via nltk kiwisolver==1.4.2 # via matplotlib -lxml==4.8.0 +lxml==4.9.0 # via # -r requirements/edx-sandbox/py38.in # openedx-calc @@ -38,10 +36,8 @@ matplotlib==3.3.4 # -r requirements/edx-sandbox/py38.in mpmath==1.2.1 # via sympy -networkx==2.5.1 - # via - # -c requirements/edx-sandbox/../constraints.txt - # -r requirements/edx-sandbox/py38.in +networkx==2.8.2 + # via -r requirements/edx-sandbox/py38.in nltk==3.7 # via # -r requirements/edx-sandbox/py38.in @@ -65,13 +61,11 @@ pyparsing==3.0.9 # chem # matplotlib # openedx-calc -python-dateutil==2.4.0 - # via - # -c requirements/edx-sandbox/../constraints.txt - # matplotlib +python-dateutil==2.8.2 + # via matplotlib random2==1.0.1 # via -r requirements/edx-sandbox/py38.in -regex==2022.4.24 +regex==2022.6.2 # via nltk scipy==1.7.3 # via diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 6f2cc53d7d..3da22da3dd 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -161,7 +161,7 @@ cryptography==37.0.2 # jwcrypto # pyjwt # social-auth-core -cssutils==2.4.0 +cssutils==2.4.1 # via pynliner ddt==1.5.0 # via @@ -639,9 +639,9 @@ libsass==0.10.0 # ora2 loremipsum==1.0.5 # via ora2 -lti-consumer-xblock==4.1.0 +lti-consumer-xblock==4.1.1 # via -r requirements/edx/base.in -lxml==4.8.0 +lxml==4.9.0 # via # -r requirements/edx/base.in # edxval @@ -834,9 +834,8 @@ pysrt==1.1.2 # via # -r requirements/edx/base.in # edxval -python-dateutil==2.4.0 +python-dateutil==2.8.2 # via - # -c requirements/edx/../constraints.txt # -r requirements/edx/base.in # analytics-python # botocore @@ -897,9 +896,9 @@ random2==1.0.1 # via -r requirements/edx/base.in recommender-xblock==2.0.1 # via -r requirements/edx/base.in -redis==4.3.1 +redis==4.3.3 # via -r requirements/edx/base.in -regex==2022.4.24 +regex==2022.6.2 # via nltk requests==2.27.1 # via diff --git a/requirements/edx/coverage.txt b/requirements/edx/coverage.txt index 4255da5d7d..4385055d3f 100644 --- a/requirements/edx/coverage.txt +++ b/requirements/edx/coverage.txt @@ -6,7 +6,7 @@ # chardet==4.0.0 # via diff-cover -coverage==6.4 +coverage==6.4.1 # via -r requirements/edx/coverage.in diff-cover==6.5.0 # via -r requirements/edx/coverage.in diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 410e6c8e4b..e80885ff99 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -214,7 +214,7 @@ coreschema==0.0.4 # -r requirements/edx/testing.txt # coreapi # drf-yasg -coverage[toml]==6.4 +coverage[toml]==6.4.1 # via # -r requirements/edx/testing.txt # pytest-cov @@ -232,7 +232,7 @@ cssselect==1.1.0 # via # -r requirements/edx/testing.txt # pyquery -cssutils==2.4.0 +cssutils==2.4.1 # via # -r requirements/edx/testing.txt # pynliner @@ -693,15 +693,13 @@ fastavro==1.4.12 # via # -r requirements/edx/testing.txt # openedx-events -filelock==3.7.0 +filelock==3.7.1 # via # -r requirements/edx/testing.txt # tox # virtualenv -freezegun==0.3.12 - # via - # -c requirements/edx/../constraints.txt - # -r requirements/edx/testing.txt +freezegun==1.2.1 + # via -r requirements/edx/testing.txt frozenlist==1.3.0 # via # -r requirements/edx/testing.txt @@ -813,7 +811,7 @@ jsonfield==3.1.0 # edx-submissions # lti-consumer-xblock # ora2 -jsonschema==4.5.1 +jsonschema==4.6.0 # via sphinxcontrib-openapi jwcrypto==1.3.1 # via @@ -844,9 +842,9 @@ loremipsum==1.0.5 # via # -r requirements/edx/testing.txt # ora2 -lti-consumer-xblock==4.1.0 +lti-consumer-xblock==4.1.1 # via -r requirements/edx/testing.txt -lxml==4.8.0 +lxml==4.9.0 # via # -r requirements/edx/testing.txt # edxval @@ -1093,6 +1091,7 @@ pylatexenc==2.10 # olxcleaner pylint==2.13.9 # via + # -c requirements/edx/../constraints.txt # -r requirements/edx/testing.txt # edx-lint # pylint-celery @@ -1176,9 +1175,8 @@ pytest-randomly==3.12.0 # via -r requirements/edx/testing.txt pytest-xdist[psutil]==2.5.0 # via -r requirements/edx/testing.txt -python-dateutil==2.4.0 +python-dateutil==2.8.2 # via - # -c requirements/edx/../constraints.txt # -r requirements/edx/testing.txt # analytics-python # botocore @@ -1248,9 +1246,9 @@ random2==1.0.1 # via -r requirements/edx/testing.txt recommender-xblock==2.0.1 # via -r requirements/edx/testing.txt -redis==4.3.1 +redis==4.3.3 # via -r requirements/edx/testing.txt -regex==2022.4.24 +regex==2022.6.2 # via # -r requirements/edx/testing.txt # nltk @@ -1346,7 +1344,6 @@ six==1.16.0 # edx-rbac # edx-sphinx-theme # event-tracking - # freezegun # fs # fs-s3fs # html5lib @@ -1395,7 +1392,7 @@ soupsieve==2.3.2.post1 # via # -r requirements/edx/testing.txt # beautifulsoup4 -sphinx==5.0.0 +sphinx==5.0.1 # via # edx-sphinx-theme # sphinxcontrib-httpdomain diff --git a/requirements/edx/doc.txt b/requirements/edx/doc.txt index 7e064b98e1..89b8169eb4 100644 --- a/requirements/edx/doc.txt +++ b/requirements/edx/doc.txt @@ -62,7 +62,7 @@ smmap==5.0.0 # via gitdb snowballstemmer==2.2.0 # via sphinx -sphinx==5.0.0 +sphinx==5.0.1 # via # -r requirements/edx/doc.in # edx-sphinx-theme diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index e59ac534ce..60477eb70a 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -206,7 +206,7 @@ coreschema==0.0.4 # -r requirements/edx/base.txt # coreapi # drf-yasg -coverage[toml]==6.4 +coverage[toml]==6.4.1 # via # -r requirements/edx/coverage.txt # pytest-cov @@ -224,7 +224,7 @@ cssselect==1.1.0 # via # -r requirements/edx/testing.in # pyquery -cssutils==2.4.0 +cssutils==2.4.1 # via # -r requirements/edx/base.txt # pynliner @@ -669,14 +669,12 @@ fastavro==1.4.12 # via # -r requirements/edx/base.txt # openedx-events -filelock==3.7.0 +filelock==3.7.1 # via # tox # virtualenv -freezegun==0.3.12 - # via - # -c requirements/edx/../constraints.txt - # -r requirements/edx/testing.in +freezegun==1.2.1 + # via -r requirements/edx/testing.in frozenlist==1.3.0 # via # -r requirements/edx/base.txt @@ -806,9 +804,9 @@ loremipsum==1.0.5 # via # -r requirements/edx/base.txt # ora2 -lti-consumer-xblock==4.1.0 +lti-consumer-xblock==4.1.1 # via -r requirements/edx/base.txt -lxml==4.8.0 +lxml==4.9.0 # via # -r requirements/edx/base.txt # edxval @@ -1034,6 +1032,7 @@ pylatexenc==2.10 # olxcleaner pylint==2.13.9 # via + # -c requirements/edx/../constraints.txt # edx-lint # pylint-celery # pylint-django @@ -1107,9 +1106,8 @@ pytest-randomly==3.12.0 # via -r requirements/edx/testing.in pytest-xdist[psutil]==2.5.0 # via -r requirements/edx/testing.in -python-dateutil==2.4.0 +python-dateutil==2.8.2 # via - # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt # analytics-python # botocore @@ -1176,9 +1174,9 @@ random2==1.0.1 # via -r requirements/edx/base.txt recommender-xblock==2.0.1 # via -r requirements/edx/base.txt -redis==4.3.1 +redis==4.3.3 # via -r requirements/edx/base.txt -regex==2022.4.24 +regex==2022.6.2 # via # -r requirements/edx/base.txt # nltk @@ -1272,7 +1270,6 @@ six==1.16.0 # edx-milestones # edx-rbac # event-tracking - # freezegun # fs # fs-s3fs # html5lib From 0f4082427ee7f8cd9918b934a85d993490e25b41 Mon Sep 17 00:00:00 2001 From: jfavellar90 Date: Tue, 16 Feb 2021 13:18:39 -0500 Subject: [PATCH 23/63] fix: LI-10, improve home studio performance. Improving Studio homepage performance for users with course access role with no course_id Fixing unit tests Added create CourseOverviewFactory after creating course to course listing test Fix order import for `from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory ` (cherry picked from commit 997a0ff770744309f0ee84f3c0696a80310c5f2d) --- .../contentstore/tests/test_course_listing.py | 19 +++++++++++++++---- cms/djangoapps/contentstore/views/course.py | 14 ++++++++++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/cms/djangoapps/contentstore/tests/test_course_listing.py b/cms/djangoapps/contentstore/tests/test_course_listing.py index 3c9705fdf2..9baa1c044f 100644 --- a/cms/djangoapps/contentstore/tests/test_course_listing.py +++ b/cms/djangoapps/contentstore/tests/test_course_listing.py @@ -315,24 +315,24 @@ class TestCourseListing(ModuleStoreTestCase): all of them. """ org_course_one = self.store.make_course_key('AwesomeOrg', 'Course1', 'RunBabyRun') - CourseFactory.create( + course_1 = CourseFactory.create( org=org_course_one.org, number=org_course_one.course, run=org_course_one.run ) + CourseOverviewFactory.create(id=course_1.id, org='AwesomeOrg') org_course_two = self.store.make_course_key('AwesomeOrg', 'Course2', 'RunBabyRun') - CourseFactory.create( + course_2 = CourseFactory.create( org=org_course_two.org, number=org_course_two.course, run=org_course_two.run ) + CourseOverviewFactory.create(id=course_2.id, org='AwesomeOrg') # Two types of org-wide roles have edit permissions: staff and instructor. We test both role.add_users(self.user) - with self.assertRaises(AccessListFallback): - _accessible_courses_list_from_groups(self.request) courses_list, __ = get_courses_accessible_to_user(self.request) # Verify fetched accessible courses list is a list of CourseSummery instances and test expacted @@ -340,6 +340,17 @@ class TestCourseListing(ModuleStoreTestCase): self.assertEqual(len(list(courses_list)), 2) self.assertTrue(all(isinstance(course, CourseOverview) for course in courses_list)) + @ddt.data(OrgStaffRole(), OrgInstructorRole()) + def test_course_listing_org_permissions_exception(self, role): + """ + Create roles with no course_id neither org to make sure AccessListFallback is raised for + platform-wide permissions + """ + role.add_users(self.user) + + with self.assertRaises(AccessListFallback): + _accessible_courses_list_from_groups(self.request) + def test_course_listing_with_actions_in_progress(self): sourse_course_key = CourseLocator('source-Org', 'source-Course', 'source-Run') diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py index 10b78596ae..b8db950d74 100644 --- a/cms/djangoapps/contentstore/views/course.py +++ b/cms/djangoapps/contentstore/views/course.py @@ -483,10 +483,20 @@ def _accessible_courses_list_from_groups(request): courses_list = [] course_keys = {} + user_global_orgs = set() for course_access in all_courses: - if course_access.course_id is None: + if course_access.course_id is not None: + course_keys[course_access.course_id] = course_access.course_id + elif course_access.org: + user_global_orgs.add(course_access.org) + else: raise AccessListFallback - course_keys[course_access.course_id] = course_access.course_id + + if user_global_orgs: + # Getting courses from user global orgs + overviews = CourseOverview.get_all_courses(orgs=list(user_global_orgs)) + overviews_course_keys = {overview.id: overview.id for overview in overviews} + course_keys.update(overviews_course_keys) course_keys = list(course_keys.values()) From c9dce91b9a4e8b93d15aef84e9fa456b77eefee9 Mon Sep 17 00:00:00 2001 From: connorhaugh <49422820+connorhaugh@users.noreply.github.com> Date: Tue, 7 Jun 2022 16:30:40 -0400 Subject: [PATCH 24/63] feat: studio redirect to new editors (#30523) --- cms/static/js/views/pages/container.js | 27 +++++++++++++++---- cms/templates/studio_xblock_wrapper.html | 14 +++++----- .../xmodule/xmodule/templates/html/raw.yaml | 1 - 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/cms/static/js/views/pages/container.js b/cms/static/js/views/pages/container.js index 286111e7f0..347f7ea77b 100644 --- a/cms/static/js/views/pages/container.js +++ b/cms/static/js/views/pages/container.js @@ -187,15 +187,15 @@ define(['jquery', 'underscore', 'backbone', 'gettext', 'js/views/pages/base_page event.preventDefault(); if(!options || options.view !== 'visibility_view' ){ - var useNewTextEditor = this.$('.edit-button').attr("use-new-editor-text"), - useNewVideoEditor = this.$('.edit-button').attr("use-new-editor-video"), - useNewProblemEditor = this.$('.edit-button').attr("use-new-editor-problem"), - blockType = xblockElement.find('.xblock').attr("data-block-type"); + var useNewTextEditor = this.$('.xblock-header-primary').attr("use-new-editor-text"), + useNewVideoEditor = this.$('.xblock-header-primary').attr("use-new-editor-video"), + useNewProblemEditor = this.$('.xblock-header-primary').attr("use-new-editor-problem"), + blockType = xblockElement.find('.xblock').attr("data-block-type"); if( (useNewTextEditor === "True" && blockType === "html") || (useNewVideoEditor === "True" && blockType === "video") || (useNewProblemEditor === "True" && blockType === "problem") ) { - var destinationUrl = this.$('.edit-button').attr("authoring_MFE_base_url") + '/' + blockType + '/' + encodeURI(xblockElement.find('.xblock').attr("data-usage-id")); + var destinationUrl = this.$('.xblock-header-primary').attr("authoring_MFE_base_url") + '/' + blockType + '/' + encodeURI(xblockElement.find('.xblock').attr("data-usage-id")); window.location.href = destinationUrl; return; } @@ -322,6 +322,23 @@ define(['jquery', 'underscore', 'backbone', 'gettext', 'js/views/pages/base_page }, onNewXBlock: function(xblockElement, scrollOffset, is_duplicate, data) { + var useNewTextEditor = this.$('.xblock-header-primary').attr("use-new-editor-text"), + useNewVideoEditor = this.$('.xblock-header-primary').attr("use-new-editor-video"), + useNewProblemEditor = this.$('.xblock-header-primary').attr("use-new-editor-problem"); + + //find the block type in the locator if availible + if(data.hasOwnProperty('locator')){ + var matchBlockTypeFromLocator = /\@(.*?)\+/; + var blockType = data.locator.match(matchBlockTypeFromLocator); + } + if((useNewTextEditor === "True" && blockType.includes("html")) || + (useNewVideoEditor === "True" && blockType.includes("video"))|| + (useNewProblemEditor === "True" && blockType.includes("problem")) + ){ + var destinationUrl = this.$('.xblock-header-primary').attr("authoring_MFE_base_url") + '/' + blockType[1] + '/' + encodeURI(data.locator); + window.location.href = destinationUrl; + return; + } ViewUtils.setScrollOffset(xblockElement, scrollOffset); xblockElement.data('locator', data.locator); return this.refreshXBlock(xblockElement, true, is_duplicate); diff --git a/cms/templates/studio_xblock_wrapper.html b/cms/templates/studio_xblock_wrapper.html index 15a2d3a857..2194a5e2f0 100644 --- a/cms/templates/studio_xblock_wrapper.html +++ b/cms/templates/studio_xblock_wrapper.html @@ -59,7 +59,12 @@ block_is_unit = is_unit(xblock) % if not show_preview: is-collapsed % endif - "> + " + use-new-editor-text = ${use_new_editor_text} + use-new-editor-video = ${use_new_editor_video} + use-new-editor-problem = ${use_new_editor_problem} + authoring_MFE_base_url = ${get_editor_page_base_url(xblock.location.course_key)} + >
% if show_inline: @@ -80,12 +85,7 @@ block_is_unit = is_unit(xblock) % if can_edit: % if not show_inline:
  • - diff --git a/common/lib/xmodule/xmodule/templates/html/raw.yaml b/common/lib/xmodule/xmodule/templates/html/raw.yaml index 8d4c78ca89..d844f15403 100644 --- a/common/lib/xmodule/xmodule/templates/html/raw.yaml +++ b/common/lib/xmodule/xmodule/templates/html/raw.yaml @@ -6,7 +6,6 @@ data: |

    This template is similar to the Text template. The only difference is that this template opens in the Raw HTML editor rather than in the Visual editor.

    -

    The Raw HTML editor saves your HTML exactly as you enter it. You can switch to the Visual editor by clicking the Settings tab and changing the Editor setting to Visual. Note, however, that some of your From c0a5dac128fce5e192467fd6da2ae908f87bb4f7 Mon Sep 17 00:00:00 2001 From: muhammad-ammar Date: Thu, 26 May 2022 17:39:16 +0500 Subject: [PATCH 25/63] feat: send segment event for failed learners for a course --- ...send_segment_events_for_failed_learners.py | 136 +++++++++++++++ ...send_segment_events_for_failed_learners.py | 155 ++++++++++++++++++ 2 files changed, 291 insertions(+) create mode 100644 lms/djangoapps/grades/management/commands/send_segment_events_for_failed_learners.py create mode 100644 lms/djangoapps/grades/management/commands/tests/test_send_segment_events_for_failed_learners.py diff --git a/lms/djangoapps/grades/management/commands/send_segment_events_for_failed_learners.py b/lms/djangoapps/grades/management/commands/send_segment_events_for_failed_learners.py new file mode 100644 index 0000000000..3c1a11ac0b --- /dev/null +++ b/lms/djangoapps/grades/management/commands/send_segment_events_for_failed_learners.py @@ -0,0 +1,136 @@ +""" +Send segment events for failed learners. +""" + +import logging +from datetime import timedelta + +from django.core.management.base import BaseCommand +from django.core.paginator import Paginator +from django.utils import timezone + +from common.djangoapps.course_modes.models import CourseMode +from common.djangoapps.student.models import CourseEnrollment +from common.djangoapps.track import segment +from lms.djangoapps.grades.models import PersistentCourseGrade +from openedx.core.djangoapps.content.course_overviews.models import CourseOverview + +log = logging.getLogger(__name__) + +PAID_ENROLLMENT_MODES = [ + CourseMode.MASTERS, + CourseMode.VERIFIED, + CourseMode.CREDIT_MODE, + CourseMode.PROFESSIONAL, + CourseMode.NO_ID_PROFESSIONAL_MODE, +] +EVENT_NAME = 'edx.course.learner.failed' + + +class Command(BaseCommand): + """ + Example usage: + $ ./manage.py lms send_segment_events_for_failed_learners + """ + + help = 'Send segment events for failed learners.' + + def add_arguments(self, parser): + """ + Entry point to add arguments. + """ + parser.add_argument( + '--dry-run', + action='store_true', + dest='dry_run', + default=False, + help='Dry Run, print log messages without firing the segment event.', + ) + + def get_courses(self): + """ + Find all courses where end date has passed 31 days ago course grade override date is course.end + 30 days + but we are adding grace period of 1 day to mitigate any edge cases due to last minute grade override. + """ + thirty_one_days_ago = timezone.now().date() - timedelta(days=31) + return CourseOverview.objects.exclude(end__isnull=True).filter(end__date=thirty_one_days_ago) + + def get_course_failed_user_ids(self, course): + """ + Get list of all the enrolled users that failed the given course. This method will only consider paid enrolments. + + Arguments: + course (CourseOverview): Course overview instance whose failed enrolments should be returned. + + Returns: + (generator): An iterator with paginated user ids, each iteration will return 500 item list of user ids. + """ + failed_grade_user_ids = PersistentCourseGrade.objects.filter( + passed_timestamp__isnull=True, + course_id=course.id, + ).values_list('user_id', flat=True) + + paginator = Paginator(failed_grade_user_ids, 500) + for page_number in paginator.page_range: + page = paginator.page(page_number) + + failed_grade_user_ids = list(page.object_list) + # exclude all non-paid enrollments + failed_user_ids = CourseEnrollment.objects.filter( + course_id=course.id, + user_id__in=failed_grade_user_ids, + mode__in=PAID_ENROLLMENT_MODES, + is_active=True + ).values_list('user_id', flat=True) + failed_user_ids = list(failed_user_ids) + + yield failed_user_ids + + def handle(self, *args, **options): + """ + Command's entery point. + """ + should_fire_event = not options['dry_run'] + + log_prefix = '[SEND_SEGMENT_EVENTS_FOR_FAILED_LEARNERS]' + if not should_fire_event: + log_prefix = '[DRY RUN]' + + stats = { + 'failed_course_user_ids': {}, + } + + log.info(f'{log_prefix} Command started.') + + for course in self.get_courses(): + # course metadata for event + course_org = course.org + course_id = str(course.id) + course_display_name = course.display_name + + stats['failed_course_user_ids'][course_id] = [] + + for course_failed_user_ids in self.get_course_failed_user_ids(course): + # for each failed enrollment, send a segment event + for course_failed_user_id in course_failed_user_ids: + event_properties = { + 'LMS_USER_ID': course_failed_user_id, + 'COURSERUN_KEY': course_id, + 'COURSE_TITLE': course_display_name, + 'COURSE_ORG_NAME': course_org, + 'PASSED': 0, + } + if should_fire_event: + segment.track(course_failed_user_id, EVENT_NAME, event_properties) + + stats['failed_course_user_ids'][course_id].append(course_failed_user_id) + + log.info( + "{} Segment event fired for failed learner. Event: [{}], Data: [{}]".format( + log_prefix, + EVENT_NAME, + event_properties + ) + ) + + log.info(f"{log_prefix} Command completed. Stats: [{stats['failed_course_user_ids']}]") diff --git a/lms/djangoapps/grades/management/commands/tests/test_send_segment_events_for_failed_learners.py b/lms/djangoapps/grades/management/commands/tests/test_send_segment_events_for_failed_learners.py new file mode 100644 index 0000000000..e188a0deb9 --- /dev/null +++ b/lms/djangoapps/grades/management/commands/tests/test_send_segment_events_for_failed_learners.py @@ -0,0 +1,155 @@ +""" +Tests for `send_segment_events_for_failed_learners` management command. +""" + +import random +from datetime import timedelta +from unittest import mock +from unittest.mock import patch + +import ddt +from django.core.management import call_command +from django.utils import timezone +from xmodule.modulestore.tests.django_utils import \ + SharedModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order + +from common.djangoapps.student.models import CourseEnrollment +from common.djangoapps.student.tests.factories import UserFactory +from lms.djangoapps.grades.management.commands import send_segment_events_for_failed_learners +from lms.djangoapps.grades.management.commands.send_segment_events_for_failed_learners import ( + EVENT_NAME, + PAID_ENROLLMENT_MODES +) +from lms.djangoapps.grades.models import PersistentCourseGrade +from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory + + +@ddt.ddt +class TestSendSegmentEventsForFailedLearnersCommand(SharedModuleStoreTestCase): + """ + Tests `send_segment_events_for_failed_learners` management command. + """ + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.command = send_segment_events_for_failed_learners.Command() + # we will create enrollments for paid modes plus `audit` mode + enrollment_modes = PAID_ENROLLMENT_MODES + ['audit'] + + # import pdb ; pdb.set_trace() + cls.course_end = timezone.now() - timedelta(days=31) + cls.course_overviews = CourseOverviewFactory.create_batch(4, end=cls.course_end) + + # set end date for a course 100 days ago from the current date + course = cls.course_overviews[2] + course.end = timezone.now() - timedelta(days=100) + course.save() + + # set end date to None + course = cls.course_overviews[3] + course.end = None + course.save() + + cls.course_keys = [str(course_overview.id) for course_overview in cls.course_overviews] + cls.users = [UserFactory.create(username=f'user{idx}') for idx in range(5)] + + for user in cls.users: + for course_overview in cls.course_overviews: + CourseEnrollment.enroll(user, course_overview.id, mode=random.choice(enrollment_modes)) + params = [ + { + "user_id": user.id, + "course_id": course_overview.id, + "course_version": "Alice", + "percent_grade": 0.0, + "letter_grade": "", + "passed_timestamp": None, + }, + { + "user_id": user.id, + "course_id": course_overview.id, + "course_version": "Bob", + "percent_grade": 77.7, + "letter_grade": "Great job", + "passed_timestamp": timezone.now() - timedelta(days=1), + }, + ] + # randomly create passed and failed grades + PersistentCourseGrade.objects.create(**random.choice(params)) + + def construct_event_call_data(self): + """ + Construct segment event call data for verification. + """ + event_call_data = [] + for course in self.command.get_courses(): + for course_failed_user_ids in self.command.get_course_failed_user_ids(course): + for course_failed_user_id in course_failed_user_ids: + event_call_data.append([ + course_failed_user_id, + EVENT_NAME, + { + 'LMS_USER_ID': course_failed_user_id, + 'COURSERUN_KEY': str(course.id), + 'COURSE_TITLE': course.display_name, + 'COURSE_ORG_NAME': course.org, + 'PASSED': 0, + } + ]) + return event_call_data + + def test_get_courses(self): + """ + Verify that `get_courses` method returns correct courses. + """ + courses = self.command.get_courses() + assert len(courses) == 2 + for index in range(2): + assert courses[index].id == self.course_overviews[index].id + assert self.course_end.date() == courses[index].end.date() == self.course_overviews[index].end.date() + + def test_get_course_failed_user_ids(self): + """ + Verify that `get_course_failed_user_ids` method returns correct user ids. + + * user id must have a paid enrollment + * user id must have a failed grade + """ + for course in self.course_overviews: + for user_ids in self.command.get_course_failed_user_ids(course): + for user_id in user_ids: + # user id must have a paid enrollment + assert CourseEnrollment.objects.filter( + course_id=course.id, + user_id=user_id, + mode__in=PAID_ENROLLMENT_MODES, + is_active=True + ).exists() + + # user id must have a failed grade + assert PersistentCourseGrade.objects.filter( + passed_timestamp__isnull=True, + course_id=course.id, + user_id=user_id, + ).exists() + + @patch('lms.djangoapps.grades.management.commands.send_segment_events_for_failed_learners.segment.track') + def test_command_dry_run(self, segment_track_mock): + """ + Verify that management command does not fire any segment event in dry run mode. + """ + call_command(self.command, '--dry-run') + segment_track_mock.assert_has_calls([]) + + @patch('lms.djangoapps.grades.management.commands.send_segment_events_for_failed_learners.segment.track') + def test_command(self, segment_track_mock): + """ + Verify that management command fires segment events with correct data. + + * Event should be fired for failed learners only. + * Event should be fired for paid enrollments only. + """ + call_command(self.command) + expected_segment_event_calls = [mock.call(*event_data) for event_data in self.construct_event_call_data()] + segment_track_mock.assert_has_calls(expected_segment_event_calls) From 22e510d69b59b1139ecb046a7370c0b2f7e59a6d Mon Sep 17 00:00:00 2001 From: Mohammad Ahtasham ul Hassan <60315450+aht007@users.noreply.github.com> Date: Wed, 8 Jun 2022 20:31:52 +0500 Subject: [PATCH 26/63] fix: remove logging (#30559) --- lms/djangoapps/courseware/access_utils.py | 4 ---- lms/djangoapps/courseware/courses.py | 7 ------- .../djangoapps/content/block_structure/block_structure.py | 3 +-- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/lms/djangoapps/courseware/access_utils.py b/lms/djangoapps/courseware/access_utils.py index 2e7c2fb330..9fa9c76203 100644 --- a/lms/djangoapps/courseware/access_utils.py +++ b/lms/djangoapps/courseware/access_utils.py @@ -88,11 +88,7 @@ def check_start_date(user, days_early_for_beta, start, course_key, display_error now = datetime.now(UTC) effective_start = adjust_start_date(user, days_early_for_beta, start, course_key) - # Todo: This log statement is added for temporary use only - log.info('Python-dateutil logs: Comparing current date with effective start date') should_grant_access = now > effective_start - # Todo: This log statement is added for temporary use only - log.info('Python-dateutil logs: Successfully compared current date with effective start date') if should_grant_access: return ACCESS_GRANTED diff --git a/lms/djangoapps/courseware/courses.py b/lms/djangoapps/courseware/courses.py index 93c58f20aa..bf14f7e2fc 100644 --- a/lms/djangoapps/courseware/courses.py +++ b/lms/djangoapps/courseware/courses.py @@ -558,10 +558,6 @@ def get_course_assignments(course_key, user, include_access=False): # lint-amne if not user.id: return [] - # Todo: This log statement is added for temporary use only - log.info('Python-dateutil logs: Trying to get course assignment for user: {} of course: {}'.format( - user.id, course_key)) - store = modulestore() course_usage_key = store.make_course_usage_key(course_key) block_data = get_course_blocks(user, course_usage_key, allow_start_dates_in_future=True, include_completion=True) @@ -663,9 +659,6 @@ def get_course_assignments(course_key, user, include_access=False): # lint-amne _("Open Response Assessment due dates are set by your instructor and can't be shifted."), first_component_block_id, )) - # Todo: This log statement is added for temporary use only - log.info('Python-dateutil logs: Successfully got course assignments for user: {} of course: {}'.format( - user.id, course_key)) return assignments diff --git a/openedx/core/djangoapps/content/block_structure/block_structure.py b/openedx/core/djangoapps/content/block_structure/block_structure.py index 17e06546d4..ba9990bb79 100644 --- a/openedx/core/djangoapps/content/block_structure/block_structure.py +++ b/openedx/core/djangoapps/content/block_structure/block_structure.py @@ -777,8 +777,7 @@ class BlockStructureBlockData(BlockStructure): """ if isinstance(field, datetime): if isinstance(field.tzinfo, tzlocal) and not hasattr(field.tzinfo, '_hasdst'): - # Todo: This log statement is added for temporary use only - logger.info('Python-dateutil logs: Making datetime field compatible to python-dateutil package') + return datetime( year=field.year, month=field.month, day=field.day, hour=field.hour, minute=field.minute, second=field.second, From c54d8a81bf56eb5f2ad7f63ccf45477cce737c05 Mon Sep 17 00:00:00 2001 From: Arunmozhi Date: Thu, 9 Jun 2022 02:06:59 +1000 Subject: [PATCH 27/63] refactor: deprecate node_path attribute of ModuleSystem (#30447) The node_path attribute & constructor argument of the ModuleSystem is deprecated without any replacement service or fallback as there doesn't seem to be any core blocks using it. It also removes the references to node_path from the LMS settings, the LoncapaModuleSystem and the XBlock runtime shim. Co-authored-by: Agrendalath --- common/lib/capa/capa/capa_problem.py | 2 -- common/lib/capa/capa/tests/helpers.py | 1 - common/lib/xmodule/xmodule/capa_module.py | 3 --- common/lib/xmodule/xmodule/tests/__init__.py | 1 - common/lib/xmodule/xmodule/x_module.py | 15 +++++++++++++-- lms/djangoapps/courseware/module_render.py | 1 - lms/envs/common.py | 10 ---------- openedx/core/djangoapps/xblock/runtime/shims.py | 10 ---------- tox.ini | 2 -- 9 files changed, 13 insertions(+), 32 deletions(-) diff --git a/common/lib/capa/capa/capa_problem.py b/common/lib/capa/capa/capa_problem.py index cc1ea427f5..30295b0919 100644 --- a/common/lib/capa/capa/capa_problem.py +++ b/common/lib/capa/capa/capa_problem.py @@ -104,7 +104,6 @@ class LoncapaSystem(object): get_python_lib_zip, DEBUG, i18n, - node_path, render_template, resources_fs, seed, # Why do we do this if we have self.seed? @@ -119,7 +118,6 @@ class LoncapaSystem(object): self.get_python_lib_zip = get_python_lib_zip self.DEBUG = DEBUG # pylint: disable=invalid-name self.i18n = i18n - self.node_path = node_path self.render_template = render_template self.resources_fs = resources_fs self.seed = seed # Why do we do this if we have self.seed? diff --git a/common/lib/capa/capa/tests/helpers.py b/common/lib/capa/capa/tests/helpers.py index 1779168c1a..0d30b1b60f 100644 --- a/common/lib/capa/capa/tests/helpers.py +++ b/common/lib/capa/capa/tests/helpers.py @@ -73,7 +73,6 @@ def test_capa_system(render_template=None): get_python_lib_zip=lambda: None, DEBUG=True, i18n=gettext.NullTranslations(), - node_path=os.environ.get("NODE_PATH", "/usr/local/lib/node_modules"), render_template=render_template or tst_render_template, resources_fs=fs.osfs.OSFS(os.path.join(TEST_DIR, "test_files")), seed=0, diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py index 064c0c81f8..250fd0974f 100644 --- a/common/lib/xmodule/xmodule/capa_module.py +++ b/common/lib/xmodule/xmodule/capa_module.py @@ -618,7 +618,6 @@ class ProblemBlock( get_python_lib_zip=None, DEBUG=None, i18n=self.runtime.service(self, "i18n"), - node_path=None, render_template=None, resources_fs=self.runtime.resources_fs, seed=None, @@ -680,7 +679,6 @@ class ProblemBlock( get_python_lib_zip=(lambda: get_python_lib_zip(contentstore, self.runtime.course_id)), DEBUG=None, i18n=self.runtime.service(self, "i18n"), - node_path=None, render_template=None, resources_fs=self.runtime.resources_fs, seed=1, @@ -829,7 +827,6 @@ class ProblemBlock( get_python_lib_zip=sandbox_service.get_python_lib_zip, DEBUG=self.runtime.DEBUG, i18n=self.runtime.service(self, "i18n"), - node_path=self.runtime.node_path, render_template=self.runtime.service(self, 'mako').render_template, resources_fs=self.runtime.resources_fs, seed=seed, # Why do we do this if we have self.seed? diff --git a/common/lib/xmodule/xmodule/tests/__init__.py b/common/lib/xmodule/xmodule/tests/__init__.py index fd38c6f64d..206784dc24 100644 --- a/common/lib/xmodule/xmodule/tests/__init__.py +++ b/common/lib/xmodule/xmodule/tests/__init__.py @@ -168,7 +168,6 @@ def get_test_system( ), 'replace_urls': replace_url_service }, - node_path=os.environ.get("NODE_PATH", "/usr/local/lib/node_modules"), course_id=course_id, error_descriptor_class=ErrorBlock, descriptor_runtime=descriptor_system, diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index 307d7c8155..ffc6a58ff9 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -1609,6 +1609,18 @@ class ModuleSystemShim: ) return self.resources_fs + @property + def node_path(self): + """ + Path to node_modules. Doesn't seem to be used by any ModuleSystem dependent core XBlock anymore. + + Deprecated. + """ + warnings.warn( + 'node_path is deprecated. Please use other methods of finding the node_modules location.', + DeprecationWarning, stacklevel=3 + ) + class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemShim, Runtime): """ @@ -1626,7 +1638,7 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemShim, def __init__( self, static_url, track_function, get_module, descriptor_runtime, debug=False, hostname="", publish=None, - node_path="", course_id=None, error_descriptor_class=None, + course_id=None, error_descriptor_class=None, field_data=None, rebind_noauth_module_to_user=None, **kwargs): """ @@ -1668,7 +1680,6 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemShim, self.get_module = get_module self.DEBUG = self.debug = debug self.HOSTNAME = self.hostname = hostname - self.node_path = node_path self.course_id = course_id if publish: diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 62157ec648..4d7ad48c79 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -731,7 +731,6 @@ def get_module_system_for_user( user=user, debug=settings.DEBUG, hostname=settings.SITE_NAME, - node_path=settings.NODE_PATH, publish=publish, course_id=course_id, # TODO: When we merge the descriptor and module systems, we can stop reaching into the mixologist (cpennington) diff --git a/lms/envs/common.py b/lms/envs/common.py index f268ad6b2a..fe21b28aad 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -1087,16 +1087,6 @@ NODE_MODULES_ROOT = REPO_ROOT / "node_modules" DATA_DIR = COURSES_ROOT -# For Node.js - -system_node_path = os.environ.get("NODE_PATH", NODE_MODULES_ROOT) - -node_paths = [ - COMMON_ROOT / "static/js/vendor", - system_node_path, -] -NODE_PATH = ':'.join(node_paths) - # For geolocation ip database GEOIP_PATH = REPO_ROOT / "common/static/data/geoip/GeoLite2-Country.mmdb" # Where to look for a status message diff --git a/openedx/core/djangoapps/xblock/runtime/shims.py b/openedx/core/djangoapps/xblock/runtime/shims.py index 41b028de42..637ce63cda 100644 --- a/openedx/core/djangoapps/xblock/runtime/shims.py +++ b/openedx/core/djangoapps/xblock/runtime/shims.py @@ -145,16 +145,6 @@ class RuntimeShim: ) return self.resources_fs - @property - def node_path(self): - """ - Get the path to Node.js - - Seems only to be used by capa. Remove this if capa can be refactored. - """ - # TODO: Refactor capa to access this directly, don't bother the runtime. Then remove it from here. - return getattr(settings, 'NODE_PATH', None) # Only defined in the LMS - def render_template(self, template_name, dictionary, namespace='main'): """ Render a mako template diff --git a/tox.ini b/tox.ini index 63cbf6c4ef..0bcc2ae0bb 100644 --- a/tox.ini +++ b/tox.ini @@ -39,8 +39,6 @@ passenv = LMS_CFG REVISION_CFG MOZ_HEADLESS - NODE_PATH - NODE_VIRTUAL_ENV NO_PREREQ_INSTALL NO_PYTHON_UNINSTALL NPM_CONFIG_PREFIX From 8886f29e52bf23368a88cadc5e2c372a173ccbbe Mon Sep 17 00:00:00 2001 From: Demid Date: Wed, 8 Jun 2022 19:59:45 +0300 Subject: [PATCH 28/63] refactor: remove `debug` property from `ModuleSystem` (#30450) This also: 1. Removes this property from XBlock runtime shims. 2. Updates the minimum required version of the LTI Consumer XBlock. --- cms/djangoapps/contentstore/views/preview.py | 1 - common/lib/xmodule/xmodule/capa_module.py | 18 +++++++--- common/lib/xmodule/xmodule/lti_2_util.py | 3 +- common/lib/xmodule/xmodule/tests/__init__.py | 1 - .../xmodule/xmodule/tests/test_capa_module.py | 36 ++++++++++++++----- common/lib/xmodule/xmodule/x_module.py | 3 +- lms/djangoapps/courseware/module_render.py | 1 - .../core/djangoapps/xblock/runtime/shims.py | 8 ----- requirements/edx/base.in | 2 +- 9 files changed, 44 insertions(+), 29 deletions(-) diff --git a/cms/djangoapps/contentstore/views/preview.py b/cms/djangoapps/contentstore/views/preview.py index b64a77ddb2..0d7e8786b4 100644 --- a/cms/djangoapps/contentstore/views/preview.py +++ b/cms/djangoapps/contentstore/views/preview.py @@ -212,7 +212,6 @@ def _preview_module_system(request, descriptor, field_data): # TODO (cpennington): Do we want to track how instructors are using the preview problems? track_function=lambda event_type, event: None, get_module=partial(_load_preview_module, request), - debug=True, mixins=settings.XBLOCK_MIXINS, course_id=course_id, diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py index 250fd0974f..225d9aa46b 100644 --- a/common/lib/xmodule/xmodule/capa_module.py +++ b/common/lib/xmodule/xmodule/capa_module.py @@ -490,6 +490,15 @@ class ProblemBlock( return self.display_name + @property + def debug(self): + """ + If CAPA block fails to render, we want course authors to be able to see + the error in Studio. At the same time, in production, we don't want + to show errors to students. + """ + return getattr(self.runtime, 'is_author_mode', False) or settings.DEBUG + @classmethod def filter_templates(cls, template, course): """ @@ -825,7 +834,7 @@ class ProblemBlock( cache=cache_service, can_execute_unsafe_code=sandbox_service.can_execute_unsafe_code, get_python_lib_zip=sandbox_service.get_python_lib_zip, - DEBUG=self.runtime.DEBUG, + DEBUG=self.debug, i18n=self.runtime.service(self, "i18n"), render_template=self.runtime.service(self, 'mako').render_template, resources_fs=self.runtime.resources_fs, @@ -1060,8 +1069,7 @@ class ProblemBlock( str(err) ) - # TODO (vshnayder): another switch on DEBUG. - if self.runtime.DEBUG: + if self.debug: msg = HTML( '[courseware.capa.capa_module] ' 'Failed to generate HTML for problem {url}' @@ -1777,7 +1785,7 @@ class ProblemBlock( self.set_last_submission_time() except (StudentInputError, ResponseError, LoncapaProblemError) as inst: - if self.runtime.DEBUG: + if self.debug: log.warning( "StudentInputError in capa_module:problem_check", exc_info=True @@ -1811,7 +1819,7 @@ class ProblemBlock( self.set_state_from_lcp() self.set_score(self.score_from_lcp(self.lcp)) - if self.runtime.DEBUG: + if self.debug: msg = f"Error checking problem: {str(err)}" msg += f'\nTraceback:\n{traceback.format_exc()}' return {'success': msg} diff --git a/common/lib/xmodule/xmodule/lti_2_util.py b/common/lib/xmodule/xmodule/lti_2_util.py index 17dfe680c0..3829139b7b 100644 --- a/common/lib/xmodule/xmodule/lti_2_util.py +++ b/common/lib/xmodule/xmodule/lti_2_util.py @@ -12,6 +12,7 @@ import re from unittest import mock from urllib import parse +from django.conf import settings from oauthlib.oauth1 import Client from webob import Response from xblock.core import XBlock @@ -63,7 +64,7 @@ class LTI20BlockMixin: Returns: webob.response: response to this request. See above for details. """ - if self.system.debug: + if settings.DEBUG: self._log_correct_authorization_header(request) if not self.accept_grades_past_due and self.is_past_due(): diff --git a/common/lib/xmodule/xmodule/tests/__init__.py b/common/lib/xmodule/xmodule/tests/__init__.py index 206784dc24..0925073099 100644 --- a/common/lib/xmodule/xmodule/tests/__init__.py +++ b/common/lib/xmodule/xmodule/tests/__init__.py @@ -153,7 +153,6 @@ def get_test_system( static_url='/static', track_function=Mock(name='get_test_system.track_function'), get_module=get_module, - debug=True, hostname="edx.org", services={ 'user': user_service, diff --git a/common/lib/xmodule/xmodule/tests/test_capa_module.py b/common/lib/xmodule/xmodule/tests/test_capa_module.py index 26ff575f81..41acc05a93 100644 --- a/common/lib/xmodule/xmodule/tests/test_capa_module.py +++ b/common/lib/xmodule/xmodule/tests/test_capa_module.py @@ -17,6 +17,7 @@ import ddt import requests import webob from codejail.safe_exec import SafeExecException +from django.test import override_settings from django.utils.encoding import smart_str from edx_user_state_client.interface import XBlockUserState from lxml import etree @@ -961,6 +962,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss # but that this was considered the second attempt for grading purposes assert module.lcp.context['attempt'] == 2 + @override_settings(DEBUG=True) def test_submit_problem_other_errors(self): """ Test that errors other than the expected kinds give an appropriate message. @@ -970,9 +972,6 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss # Create the module module = CapaFactory.create(attempts=1, user_is_staff=False) - # Ensure that DEBUG is on - module.system.DEBUG = True - # Simulate answering a problem that raises the exception with patch('capa.capa_problem.LoncapaProblem.grade_answers') as mock_grade: error_msg = "Superterrible error happened: ☠" @@ -1711,9 +1710,6 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss # is asked to render itself as HTML module.lcp.get_html = Mock(side_effect=Exception("Test")) - # Turn off DEBUG - module.system.DEBUG = False - # Try to render the module with DEBUG turned off html = module.get_problem_html() @@ -1727,6 +1723,31 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss # Expect that the module has created a new dummy problem with the error assert original_problem != module.lcp + def test_get_problem_html_error_preview(self): + """ + Test the html response when an error occurs with DEBUG off in Studio. + """ + render_template = Mock(return_value="

    Test Template HTML
    ") + module = CapaFactory.create(render_template=render_template) + + # Simulate throwing an exception when the capa problem + # is asked to render itself as HTML + error_msg = "Superterrible error happened: ☠" + module.lcp.get_html = Mock(side_effect=Exception(error_msg)) + + module.system.is_author_mode = True + + # Try to render the module with the author mode turned on + html = module.get_problem_html() + + assert html is not None + + # Check the rendering context + render_args, _ = render_template.call_args + context = render_args[1] + assert error_msg in context['problem']['html'] + + @override_settings(DEBUG=True) def test_get_problem_html_error_w_debug(self): """ Test the html response when an error occurs with DEBUG on @@ -1739,9 +1760,6 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss error_msg = "Superterrible error happened: ☠" module.lcp.get_html = Mock(side_effect=Exception(error_msg)) - # Make sure DEBUG is on - module.system.DEBUG = True - # Try to render the module with DEBUG turned on html = module.get_problem_html() diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index ffc6a58ff9..ef5072c9bb 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -1637,7 +1637,7 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemShim, def __init__( self, static_url, track_function, get_module, - descriptor_runtime, debug=False, hostname="", publish=None, + descriptor_runtime, hostname="", publish=None, course_id=None, error_descriptor_class=None, field_data=None, rebind_noauth_module_to_user=None, **kwargs): @@ -1678,7 +1678,6 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemShim, self.STATIC_URL = static_url self.track_function = track_function self.get_module = get_module - self.DEBUG = self.debug = debug self.HOSTNAME = self.hostname = hostname self.course_id = course_id diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 4d7ad48c79..9b1e7bc618 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -729,7 +729,6 @@ def get_module_system_for_user( static_url=settings.STATIC_URL, get_module=inner_get_module, user=user, - debug=settings.DEBUG, hostname=settings.SITE_NAME, publish=publish, course_id=course_id, diff --git a/openedx/core/djangoapps/xblock/runtime/shims.py b/openedx/core/djangoapps/xblock/runtime/shims.py index 637ce63cda..5225d249c5 100644 --- a/openedx/core/djangoapps/xblock/runtime/shims.py +++ b/openedx/core/djangoapps/xblock/runtime/shims.py @@ -97,14 +97,6 @@ class RuntimeShim: # TODO: Refactor capa to access this directly, don't bother the runtime. Then remove it from here. return False # Change this if/when we need to support unsafe courses in the new runtime. - @property - def DEBUG(self): - """ - Should DEBUG mode (?) be used? This flag is only read by capa. - """ - # TODO: Refactor capa to access this directly, don't bother the runtime. Then remove it from here. - return False - def get_python_lib_zip(self): """ A function returning a bytestring or None. The bytestring is the diff --git a/requirements/edx/base.in b/requirements/edx/base.in index 703fc0ee97..4f834e95d4 100644 --- a/requirements/edx/base.in +++ b/requirements/edx/base.in @@ -109,7 +109,7 @@ ipaddress # Ip network support for Embargo feature jsonfield # Django model field for validated JSON; used in several apps laboratory # Library for testing that code refactors/infrastructure changes produce identical results lxml # XML parser -lti-consumer-xblock>=4.1.0 +lti-consumer-xblock>=4.1.1 mailsnake # Needed for mailchimp (mailing djangoapp) mako # Primary template language used for server-side page rendering Markdown # Convert text markup to HTML; used in capa problems, forums, and course wikis From aedcd7910db55c9a2b924313cbfcadd168fa10a6 Mon Sep 17 00:00:00 2001 From: Arunmozhi Date: Thu, 9 Jun 2022 03:49:58 +1000 Subject: [PATCH 29/63] refactor: deprecate `hostname` attribute from `ModuleSystem` (#30308) The hostname constructor argument of the XModule ModuleSystem is deprecated in favour of directly accessing the LMS_BASE value from django.conf.settings. --- common/lib/xmodule/xmodule/lti_module.py | 3 +- common/lib/xmodule/xmodule/tests/__init__.py | 1 - .../xmodule/xmodule/tests/test_lti_unit.py | 11 +++++-- common/lib/xmodule/xmodule/x_module.py | 31 +++++++++++++++---- lms/djangoapps/courseware/module_render.py | 1 - .../courseware/tests/test_lti_integration.py | 2 +- 6 files changed, 36 insertions(+), 13 deletions(-) diff --git a/common/lib/xmodule/xmodule/lti_module.py b/common/lib/xmodule/xmodule/lti_module.py index a2174f1f67..583cf54d65 100644 --- a/common/lib/xmodule/xmodule/lti_module.py +++ b/common/lib/xmodule/xmodule/lti_module.py @@ -65,6 +65,7 @@ from urllib import parse import bleach import oauthlib.oauth1 +from django.conf import settings from lxml import etree from oauthlib.oauth1.rfc5849 import signature from pkg_resources import resource_string @@ -584,7 +585,7 @@ class LTIBlock( i4x-2-3-lti-31de800015cf4afb973356dbe81496df this part of resource_link_id: makes resource_link_id to be unique among courses inside same system. """ - return str(parse.quote(f"{self.system.hostname}-{self.location.html_id()}")) # lint-amnesty, pylint: disable=line-too-long + return str(parse.quote(f"{settings.LMS_BASE}-{self.location.html_id()}")) def get_lis_result_sourcedid(self): """ diff --git a/common/lib/xmodule/xmodule/tests/__init__.py b/common/lib/xmodule/xmodule/tests/__init__.py index 0925073099..6b5f903553 100644 --- a/common/lib/xmodule/xmodule/tests/__init__.py +++ b/common/lib/xmodule/xmodule/tests/__init__.py @@ -153,7 +153,6 @@ def get_test_system( static_url='/static', track_function=Mock(name='get_test_system.track_function'), get_module=get_module, - hostname="edx.org", services={ 'user': user_service, 'mako': mako_service, diff --git a/common/lib/xmodule/xmodule/tests/test_lti_unit.py b/common/lib/xmodule/xmodule/tests/test_lti_unit.py index 103cdaeb53..cfda18a62f 100644 --- a/common/lib/xmodule/xmodule/tests/test_lti_unit.py +++ b/common/lib/xmodule/xmodule/tests/test_lti_unit.py @@ -3,12 +3,14 @@ import datetime import textwrap -import unittest from copy import copy from unittest.mock import Mock, PropertyMock, patch from urllib import parse + import pytest +from django.conf import settings +from django.test import TestCase, override_settings from lxml import etree from opaque_keys.edx.locator import BlockUsageLocator from pytz import UTC @@ -16,6 +18,7 @@ from webob.request import Request from xblock.field_data import DictFieldData from xblock.fields import ScopeIds + from common.djangoapps.xblock_django.constants import ATTR_KEY_ANONYMOUS_USER_ID from xmodule.fields import Timedelta from xmodule.lti_2_util import LTIError @@ -25,7 +28,8 @@ from xmodule.tests.helpers import StubUserService from . import get_test_system -class LTIBlockTest(unittest.TestCase): +@override_settings(LMS_BASE="edx.org") +class LTIBlockTest(TestCase): """Logic tests for LTI module.""" def setUp(self): @@ -69,8 +73,9 @@ class LTIBlockTest(unittest.TestCase): current_user = self.system.service(self.xmodule, 'user').get_current_user() self.user_id = current_user.opt_attrs.get(ATTR_KEY_ANONYMOUS_USER_ID) self.lti_id = self.xmodule.lti_id + self.unquoted_resource_link_id = '{}-i4x-2-3-lti-31de800015cf4afb973356dbe81496df'.format( - self.xmodule.runtime.hostname + settings.LMS_BASE ) sourced_id = ':'.join(parse.quote(i) for i in (self.lti_id, self.unquoted_resource_link_id, self.user_id)) # lint-amnesty, pylint: disable=line-too-long diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index ef5072c9bb..7ec451ce54 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -1621,6 +1621,19 @@ class ModuleSystemShim: DeprecationWarning, stacklevel=3 ) + @property + def hostname(self): + """ + Hostname of the site as set in the Django settings `LMS_BASE` + Deprecated in favour of direct import of `django.conf.settings` + """ + warnings.warn( + 'runtime.hostname is deprecated. Please use `LMS_BASE` from `django.conf.settings`.', + DeprecationWarning, stacklevel=3, + ) + from django.conf import settings + return settings.LMS_BASE + class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemShim, Runtime): """ @@ -1636,11 +1649,18 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemShim, """ def __init__( - self, static_url, track_function, get_module, - descriptor_runtime, hostname="", publish=None, - course_id=None, error_descriptor_class=None, - field_data=None, rebind_noauth_module_to_user=None, - **kwargs): + self, + static_url, + track_function, + get_module, + descriptor_runtime, + publish=None, + course_id=None, + error_descriptor_class=None, + field_data=None, + rebind_noauth_module_to_user=None, + **kwargs, + ): """ Create a closure around the system environment. @@ -1678,7 +1698,6 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemShim, self.STATIC_URL = static_url self.track_function = track_function self.get_module = get_module - self.HOSTNAME = self.hostname = hostname self.course_id = course_id if publish: diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 9b1e7bc618..6345011358 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -729,7 +729,6 @@ def get_module_system_for_user( static_url=settings.STATIC_URL, get_module=inner_get_module, user=user, - hostname=settings.SITE_NAME, publish=publish, course_id=course_id, # TODO: When we merge the descriptor and module systems, we can stop reaching into the mixologist (cpennington) diff --git a/lms/djangoapps/courseware/tests/test_lti_integration.py b/lms/djangoapps/courseware/tests/test_lti_integration.py index c4a2d8a7db..da4805774e 100644 --- a/lms/djangoapps/courseware/tests/test_lti_integration.py +++ b/lms/djangoapps/courseware/tests/test_lti_integration.py @@ -43,7 +43,7 @@ class TestLTI(BaseTestXmodule): context_id = str(self.item_descriptor.course_id) user_service = self.item_descriptor.xmodule_runtime.service(self.item_descriptor, 'user') user_id = str(user_service.get_current_user().opt_attrs.get(ATTR_KEY_ANONYMOUS_USER_ID)) - hostname = self.item_descriptor.xmodule_runtime.hostname + hostname = settings.LMS_BASE resource_link_id = str(urllib.parse.quote(f'{hostname}-{self.item_descriptor.location.html_id()}')) sourcedId = "{context}:{resource_link}:{user_id}".format( From ba8e98c7109373583f91aff04567b0dabe3d6ebd Mon Sep 17 00:00:00 2001 From: Arunmozhi Date: Thu, 9 Jun 2022 04:26:59 +1000 Subject: [PATCH 30/63] refactor: move noauth rebind ModuleSystem argument to service (#30320) This removes the `rebind_noauth_module_to_user` argument from the ModuleSystem constructor and moves it to a separate service called "rebinder" in the class `RebindModuleService`. This is used in the LTI module to bind calls received by its noauth endpoint to bind the module the real_user. --- common/lib/xmodule/xmodule/lti_2_util.py | 8 +- common/lib/xmodule/xmodule/lti_module.py | 1 + common/lib/xmodule/xmodule/services.py | 104 ++++++++++++++++++ .../xmodule/xmodule/tests/test_lti20_unit.py | 16 +-- .../xmodule/xmodule/tests/test_lti_unit.py | 2 +- common/lib/xmodule/xmodule/x_module.py | 21 +++- lms/djangoapps/courseware/module_render.py | 81 +++----------- .../courseware/tests/test_module_render.py | 7 +- .../core/djangoapps/xblock/runtime/runtime.py | 17 ++- 9 files changed, 171 insertions(+), 86 deletions(-) diff --git a/common/lib/xmodule/xmodule/lti_2_util.py b/common/lib/xmodule/xmodule/lti_2_util.py index 3829139b7b..93faa807c7 100644 --- a/common/lib/xmodule/xmodule/lti_2_util.py +++ b/common/lib/xmodule/xmodule/lti_2_util.py @@ -79,7 +79,7 @@ class LTI20BlockMixin: except LTIError: return Response(status=401) # Unauthorized in this case. 401 is right - real_user = self.system.service(self, 'user').get_user_by_anonymous_id(anon_id) + real_user = self.runtime.service(self, 'user').get_user_by_anonymous_id(anon_id) if not real_user: # that means we can't save to database, as we do not have real user id. msg = f"[LTI]: Real user not found against anon_id: {anon_id}" log.info(msg) @@ -171,7 +171,7 @@ class LTI20BlockMixin: "@context": "http://purl.imsglobal.org/ctx/lis/v2/Result", "@type": "Result" } - self.system.rebind_noauth_module_to_user(self, real_user) + self.runtime.service(self, 'rebind_user').rebind_noauth_module_to_user(self, real_user) if self.module_score is None: # In this case, no score has been ever set return Response(json.dumps(base_json_obj).encode('utf-8'), content_type=LTI_2_0_JSON_CONTENT_TYPE) @@ -254,10 +254,10 @@ class LTI20BlockMixin: else: scaled_score = None - self.system.rebind_noauth_module_to_user(self, user) + self.runtime.service(self, 'rebind_user').rebind_noauth_module_to_user(self, user) # have to publish for the progress page... - self.system.publish( + self.runtime.publish( self, 'grade', { diff --git a/common/lib/xmodule/xmodule/lti_module.py b/common/lib/xmodule/xmodule/lti_module.py index 583cf54d65..71be6d6b75 100644 --- a/common/lib/xmodule/xmodule/lti_module.py +++ b/common/lib/xmodule/xmodule/lti_module.py @@ -275,6 +275,7 @@ class LTIFields: @XBlock.needs("i18n") @XBlock.needs("mako") @XBlock.needs("user") +@XBlock.needs("rebind_user") class LTIBlock( LTIFields, LTI20BlockMixin, diff --git a/common/lib/xmodule/xmodule/services.py b/common/lib/xmodule/xmodule/services.py index be5534e1c1..a45ad61a44 100644 --- a/common/lib/xmodule/xmodule/services.py +++ b/common/lib/xmodule/xmodule/services.py @@ -4,10 +4,26 @@ Module contains various XModule/XBlock services import inspect +import logging + +from functools import partial from config_models.models import ConfigurationModel from django.conf import settings +from edx_when.field_data import DateLookupFieldData from xmodule.modulestore.django import modulestore +from xblock.reference.plugins import Service +from xblock.runtime import KvsFieldData + + +from lms.djangoapps.courseware.field_overrides import OverrideFieldData +from lms.djangoapps.courseware.model_data import DjangoKeyValueStore, FieldDataCache +from lms.djangoapps.lms_xblock.field_data import LmsFieldData +from lms.djangoapps.lms_xblock.models import XBlockAsidesConfig +from openedx.core.lib.courses import get_course_by_id + + +log = logging.getLogger(__name__) class SettingsService: @@ -119,3 +135,91 @@ class TeamsConfigurationService: if not self._course: self._course = self.get_course(course_id) return self._course.teams_configuration + + +class RebindUserServiceError(Exception): + pass + + +class RebindUserService(Service): + """ + An XBlock Service that allows modules to get rebound to real users if it was previously bound to an AnonymousUser. + + This used to be a local function inside the `lms.djangoapps.courseware.module_render.get_module_system_for_user` + method, and was passed as a constructor argument to x_module.ModuleSystem. This has been refactored out into a + service to simplify the ModuleSystem and lives in this module temporarily. + + TODO: Only the old LTI XBlock uses it in 2 places for LTI 2.0 integration. As the LTI XBlock is deprecated in + favour of the LTI Consumer XBlock, this should be removed when the LTI XBlock is removed. + + Arguments: + user (User) - A Django User object + course_id (str) - Course ID + course (Course) - Course Object + get_module_system_for_user (function) - The helper function that will be called to create a module system + for a specfic user. This is the parent function from which this service was reactored out. + `lms.djangoapps.courseware.module_render.get_module_system_for_user` + kwargs (dict) - all the keyword arguments that need to be passed to the `get_module_system_for_user` + function when it is called during rebinding + """ + def __init__(self, user, course_id, get_module_system_for_user, **kwargs): + super().__init__(**kwargs) + self.user = user + self.course_id = course_id + self._ref = { + "get_module_system_for_user": get_module_system_for_user + } + self._kwargs = kwargs + + def rebind_noauth_module_to_user(self, block, real_user): + """ + Function that rebinds the module to the real_user. + + Will only work within a module bound to an AnonymousUser, e.g. one that's instantiated by the noauth_handler. + + Arguments: + block (any xblock type): the module to rebind + real_user (django.contrib.auth.models.User): the user to bind to + + Returns: + nothing (but the side effect is that module is re-bound to real_user) + """ + if self.user.is_authenticated: + err_msg = "rebind_noauth_module_to_user can only be called from a module bound to an anonymous user" + log.error(err_msg) + raise RebindUserServiceError(err_msg) + + field_data_cache_real_user = FieldDataCache.cache_for_descriptor_descendents( + self.course_id, + real_user, + block, + asides=XBlockAsidesConfig.possible_asides(), + ) + student_data_real_user = KvsFieldData(DjangoKeyValueStore(field_data_cache_real_user)) + + with modulestore().bulk_operations(self.course_id): + course = modulestore().get_course(course_key=self.course_id) + + (inner_system, inner_student_data) = self._ref["get_module_system_for_user"]( + user=real_user, + student_data=student_data_real_user, # These have implicit user bindings, rest of args considered not to + descriptor=block, + course_id=self.course_id, + course=course, + **self._kwargs + ) + + block.bind_for_student( + inner_system, + real_user.id, + [ + partial(DateLookupFieldData, course_id=self.course_id, user=self.user), + partial(OverrideFieldData.wrap, real_user, course), + partial(LmsFieldData, student_data=inner_student_data), + ], + ) + + block.scope_ids = block.scope_ids._replace(user_id=real_user.id) + # now bind the module to the new ModuleSystem instance and vice-versa + block.runtime = inner_system + inner_system.xmodule_instance = block diff --git a/common/lib/xmodule/xmodule/tests/test_lti20_unit.py b/common/lib/xmodule/xmodule/tests/test_lti20_unit.py index aca04ea955..253945cb6d 100644 --- a/common/lib/xmodule/xmodule/tests/test_lti20_unit.py +++ b/common/lib/xmodule/xmodule/tests/test_lti20_unit.py @@ -24,12 +24,12 @@ class LTI20RESTResultServiceTest(unittest.TestCase): def setUp(self): super().setUp() - self.system = get_test_system(user=self.USER_STANDIN) + self.runtime = get_test_system(user=self.USER_STANDIN) self.environ = {'wsgi.url_scheme': 'http', 'REQUEST_METHOD': 'POST'} - self.system.publish = Mock() - self.system.rebind_noauth_module_to_user = Mock() + self.runtime.publish = Mock() + self.runtime._services['rebind_user'] = Mock() # pylint: disable=protected-access - self.xmodule = LTIBlock(self.system, DictFieldData({}), Mock()) + self.xmodule = LTIBlock(self.runtime, DictFieldData({}), Mock()) self.lti_id = self.xmodule.lti_id self.xmodule.due = None self.xmodule.graceperiod = None @@ -250,7 +250,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase): assert response.status_code == 200 assert self.xmodule.module_score is None assert self.xmodule.score_comment == '' - (_, evt_type, called_grade_obj), _ = self.system.publish.call_args # pylint: disable=unpacking-non-sequence + (_, evt_type, called_grade_obj), _ = self.runtime.publish.call_args # pylint: disable=unpacking-non-sequence assert called_grade_obj ==\ {'user_id': self.USER_STANDIN.id, 'value': None, 'max_value': None, 'score_deleted': True} assert evt_type == 'grade' @@ -271,7 +271,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase): assert response.status_code == 200 assert self.xmodule.module_score is None assert self.xmodule.score_comment == '' - (_, evt_type, called_grade_obj), _ = self.system.publish.call_args # pylint: disable=unpacking-non-sequence + (_, evt_type, called_grade_obj), _ = self.runtime.publish.call_args # pylint: disable=unpacking-non-sequence assert called_grade_obj ==\ {'user_id': self.USER_STANDIN.id, 'value': None, 'max_value': None, 'score_deleted': True} assert evt_type == 'grade' @@ -288,7 +288,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase): assert response.status_code == 200 assert self.xmodule.module_score == 0.1 assert self.xmodule.score_comment == 'ಠ益ಠ' - (_, evt_type, called_grade_obj), _ = self.system.publish.call_args # pylint: disable=unpacking-non-sequence + (_, evt_type, called_grade_obj), _ = self.runtime.publish.call_args # pylint: disable=unpacking-non-sequence assert evt_type == 'grade' assert called_grade_obj ==\ {'user_id': self.USER_STANDIN.id, 'value': 0.1, 'max_value': 1.0, 'score_deleted': False} @@ -370,7 +370,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase): Test that we get a 404 when the supplied user does not exist """ self.setup_system_xmodule_mocks_for_lti20_request_test() - self.system._services['user'] = StubUserService(user=None) # pylint: disable=protected-access + self.runtime._services['user'] = StubUserService(user=None) # pylint: disable=protected-access mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT) response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd") assert response.status_code == 404 diff --git a/common/lib/xmodule/xmodule/tests/test_lti_unit.py b/common/lib/xmodule/xmodule/tests/test_lti_unit.py index cfda18a62f..2ca2a6492c 100644 --- a/common/lib/xmodule/xmodule/tests/test_lti_unit.py +++ b/common/lib/xmodule/xmodule/tests/test_lti_unit.py @@ -63,7 +63,7 @@ class LTIBlockTest(TestCase): """) self.system = get_test_system() self.system.publish = Mock() - self.system.rebind_noauth_module_to_user = Mock() + self.system._services['rebind_user'] = Mock() # pylint: disable=protected-access self.xmodule = LTIBlock( self.system, diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index 7ec451ce54..adff5c8635 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -1634,6 +1634,22 @@ class ModuleSystemShim: from django.conf import settings return settings.LMS_BASE + @property + def rebind_noauth_module_to_user(self): + """ + A function that was used to bind modules initialized by AnonymousUsers to real users. Mainly used + by the LTI Module to connect the right users with the requests from LTI tools. + + Deprecated in favour of the "rebind_user" service. + """ + warnings.warn( + "rebind_noauth_module_to_user is deprecated. Please use the 'rebind_user' service instead.", + DeprecationWarning, stacklevel=3 + ) + rebind_user_service = self._services.get('rebind_user') + if rebind_user_service: + return partial(rebind_user_service.rebind_noauth_module_to_user) + class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemShim, Runtime): """ @@ -1658,7 +1674,6 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemShim, course_id=None, error_descriptor_class=None, field_data=None, - rebind_noauth_module_to_user=None, **kwargs, ): """ @@ -1684,9 +1699,6 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemShim, error_descriptor_class - The class to use to render XModules with errors field_data - the `FieldData` to use for backing XBlock storage. - - rebind_noauth_module_to_user - rebinds module bound to AnonymousUser to a real user...used in LTI - modules, which have an anonymous handler, to set legitimate users' data """ # Usage_store is unused, and field_data is often supplanted with an @@ -1706,7 +1718,6 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemShim, self.xmodule_instance = None self.descriptor_runtime = descriptor_runtime - self.rebind_noauth_module_to_user = rebind_noauth_module_to_user def get(self, attr): """ provide uniform access to attributes (like etree).""" diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 6345011358..44b77f3eab 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -45,6 +45,7 @@ from xmodule.exceptions import NotFoundError, ProcessingError from xmodule.modulestore.django import modulestore from xmodule.modulestore.exceptions import ItemNotFoundError from xmodule.util.sandboxing import SandboxService +from xmodule.services import RebindUserService from common.djangoapps.static_replace.services import ReplaceURLService from common.djangoapps.static_replace.wrapper import replace_urls_wrapper from common.djangoapps.xblock_django.constants import ATTR_KEY_USER_ID @@ -63,7 +64,6 @@ from lms.djangoapps.courseware.services import UserStateService from lms.djangoapps.grades.api import GradesUtilService from lms.djangoapps.grades.api import signals as grades_signals from lms.djangoapps.lms_xblock.field_data import LmsFieldData -from lms.djangoapps.lms_xblock.models import XBlockAsidesConfig from lms.djangoapps.lms_xblock.runtime import LmsModuleSystem from lms.djangoapps.verify_student.services import XBlockVerificationService from openedx.core.djangoapps.bookmarks.services import BookmarksService @@ -483,12 +483,12 @@ def get_module_system_for_user( student_data=student_data, course_id=course_id, track_function=track_function, + request_token=request_token, position=position, wrap_xmodule_display=wrap_xmodule_display, grade_bucket_type=grade_bucket_type, static_asset_path=static_asset_path, user_location=user_location, - request_token=request_token, course=course, will_recheck_access=will_recheck_access, ) @@ -608,65 +608,20 @@ def get_module_system_for_user( completion=1.0, ) - def rebind_noauth_module_to_user(module, real_user): - """ - A function that allows a module to get re-bound to a real user if it was previously bound to an AnonymousUser. - - Will only work within a module bound to an AnonymousUser, e.g. one that's instantiated by the noauth_handler. - - Arguments: - module (any xblock type): the module to rebind - real_user (django.contrib.auth.models.User): the user to bind to - - Returns: - nothing (but the side effect is that module is re-bound to real_user) - """ - if user.is_authenticated: - err_msg = ("rebind_noauth_module_to_user can only be called from a module bound to " - "an anonymous user") - log.error(err_msg) - raise LmsModuleRenderError(err_msg) - - field_data_cache_real_user = FieldDataCache.cache_for_descriptor_descendents( - course_id, - real_user, - module, - asides=XBlockAsidesConfig.possible_asides(), - ) - student_data_real_user = KvsFieldData(DjangoKeyValueStore(field_data_cache_real_user)) - - (inner_system, inner_student_data) = get_module_system_for_user( - user=real_user, - student_data=student_data_real_user, # These have implicit user bindings, rest of args considered not to - descriptor=module, - course_id=course_id, - track_function=track_function, - position=position, - wrap_xmodule_display=wrap_xmodule_display, - grade_bucket_type=grade_bucket_type, - static_asset_path=static_asset_path, - user_location=user_location, - request_token=request_token, - course=course, - will_recheck_access=will_recheck_access, - ) - - module.bind_for_student( - inner_system, - real_user.id, - [ - partial(DateLookupFieldData, course_id=course_id, user=user), - partial(OverrideFieldData.wrap, real_user, course), - partial(LmsFieldData, student_data=inner_student_data), - ], - ) - - module.scope_ids = ( - module.scope_ids._replace(user_id=real_user.id) - ) - # now bind the module to the new ModuleSystem instance and vice-versa - module.runtime = inner_system - inner_system.xmodule_instance = module + # Rebind module service to deal with noauth modules getting attached to users + rebind_user_service = RebindUserService( + user, + course_id, + get_module_system_for_user, + track_function=track_function, + position=position, + wrap_xmodule_display=wrap_xmodule_display, + grade_bucket_type=grade_bucket_type, + static_asset_path=static_asset_path, + user_location=user_location, + request_token=request_token, + will_recheck_access=will_recheck_access, + ) # Build a list of wrapping functions that will be applied in order # to the Fragment content coming out of the xblocks that are about to be rendered. @@ -751,10 +706,10 @@ def get_module_system_for_user( 'cache': CacheService(cache), 'sandbox': SandboxService(contentstore=contentstore, course_id=course_id), 'xqueue': xqueue_service, - 'replace_urls': replace_url_service + 'replace_urls': replace_url_service, + 'rebind_user': rebind_user_service, }, descriptor_runtime=descriptor._runtime, # pylint: disable=protected-access - rebind_noauth_module_to_user=rebind_noauth_module_to_user, request_token=request_token, ) diff --git a/lms/djangoapps/courseware/tests/test_module_render.py b/lms/djangoapps/courseware/tests/test_module_render.py index d9d8aeae0e..d01d2e3f45 100644 --- a/lms/djangoapps/courseware/tests/test_module_render.py +++ b/lms/djangoapps/courseware/tests/test_module_render.py @@ -55,6 +55,7 @@ from xmodule.modulestore.tests.django_utils import ( ) from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, ToyCourseFactory, check_mongo_calls # lint-amnesty, pylint: disable=wrong-import-order from xmodule.modulestore.tests.test_asides import AsideTestType # lint-amnesty, pylint: disable=wrong-import-order +from xmodule.services import RebindUserServiceError from xmodule.video_module import VideoBlock # lint-amnesty, pylint: disable=wrong-import-order from xmodule.x_module import STUDENT_VIEW, CombinedSystem # lint-amnesty, pylint: disable=wrong-import-order from common.djangoapps import static_replace @@ -2175,10 +2176,10 @@ class TestRebindModule(TestSubmittingProblems): user2 = UserFactory() user2.id = 2 with self.assertRaisesRegex( - render.LmsModuleRenderError, + RebindUserServiceError, "rebind_noauth_module_to_user can only be called from a module bound to an anonymous user" ): - assert module.system.rebind_noauth_module_to_user(module, user2) + assert module.runtime.service(module, 'rebind_user').rebind_noauth_module_to_user(module, user2) def test_rebind_noauth_module_to_user_anonymous(self): """ @@ -2188,7 +2189,7 @@ class TestRebindModule(TestSubmittingProblems): module = self.get_module_for_user(self.anon_user) user2 = UserFactory() user2.id = 2 - module.system.rebind_noauth_module_to_user(module, user2) + module.runtime.service(module, 'rebind_user').rebind_noauth_module_to_user(module, user2) assert module assert module.system.anonymous_student_id == anonymous_id_for_user(user2, self.course.id) assert module.scope_ids.user_id == user2.id diff --git a/openedx/core/djangoapps/xblock/runtime/runtime.py b/openedx/core/djangoapps/xblock/runtime/runtime.py index ba06df6da5..d3f98e2cb9 100644 --- a/openedx/core/djangoapps/xblock/runtime/runtime.py +++ b/openedx/core/djangoapps/xblock/runtime/runtime.py @@ -23,6 +23,7 @@ from xblock.runtime import KvsFieldData, MemoryIdManager, Runtime from xmodule.errortracker import make_error_tracker from xmodule.contentstore.django import contentstore from xmodule.modulestore.django import ModuleI18nService +from xmodule.services import RebindUserService from xmodule.util.sandboxing import SandboxService from common.djangoapps.edxmako.services import MakoService from common.djangoapps.static_replace.services import ReplaceURLService @@ -30,6 +31,7 @@ from common.djangoapps.track import contexts as track_contexts from common.djangoapps.track import views as track_views from common.djangoapps.xblock_django.user_service import DjangoXBlockUserService from lms.djangoapps.courseware.model_data import DjangoKeyValueStore, FieldDataCache +from lms.djangoapps.courseware import module_render from lms.djangoapps.grades.api import signals as grades_signals from openedx.core.djangoapps.xblock.apps import get_xblock_app_config from openedx.core.djangoapps.xblock.runtime.blockstore_field_data import BlockstoreChildrenData, BlockstoreFieldData @@ -37,7 +39,7 @@ from openedx.core.djangoapps.xblock.runtime.ephemeral_field_data import Ephemera from openedx.core.djangoapps.xblock.runtime.mixin import LmsBlockMixin from openedx.core.djangoapps.xblock.utils import get_xblock_id_for_anonymous_user from openedx.core.lib.cache_utils import CacheService -from openedx.core.lib.xblock_utils import wrap_fragment, xblock_local_resource_url +from openedx.core.lib.xblock_utils import wrap_fragment, xblock_local_resource_url, request_token from .id_managers import OpaqueKeyReader from .shims import RuntimeShim, XBlockShim @@ -217,6 +219,7 @@ class XBlockRuntime(RuntimeShim, Runtime): # TODO: Do these declarations actually help with anything? Maybe this check should # be removed from here and from XBlock.runtime declaration = block.service_declaration(service_name) + context_key = block.scope_ids.usage_id.context_key if declaration is None: raise NoSuchServiceError(f"Service {service_name!r} was not requested.") # Most common service is field-data so check that first: @@ -230,7 +233,6 @@ class XBlockRuntime(RuntimeShim, Runtime): raise return self.block_field_datas[block.scope_ids] elif service_name == "completion": - context_key = block.scope_ids.usage_id.context_key return CompletionService(user=self.user, context_key=context_key) elif service_name == "user": return DjangoXBlockUserService( @@ -253,6 +255,17 @@ class XBlockRuntime(RuntimeShim, Runtime): return CacheService(cache) elif service_name == 'replace_urls': return ReplaceURLService(xblock=block, lookup_asset_url=self._lookup_asset_url) + elif service_name == 'rebind_user': + # this service should ideally be initialized with all the arguments of get_module_system_for_user + # but only the positional arguments are passed here as the other arguments are too + # specific to the lms.module_render module + return RebindUserService( + self.user, + context_key, + module_render.get_module_system_for_user, + track_function=make_track_function(), + request_token=request_token(crum.get_current_request()), + ) # Check if the XBlockRuntimeSystem wants to handle this: service = self.system.get_service(block, service_name) From d687bc7ba22fa36264283fd91978c4c0ecec9d1d Mon Sep 17 00:00:00 2001 From: Kshitij Sobti Date: Thu, 9 Jun 2022 01:00:31 +0530 Subject: [PATCH 31/63] fix: Fix jasmine-jquery package format to avoid checking out over ssh (#30437) The npm package manager seems to try checking out over ssh unless a github dependency is specified with the git user via git@. Checking out over ssh breaks deployments in CI and deployment environments. --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 81ddbe0537..47c28e4e19 100644 --- a/package-lock.json +++ b/package-lock.json @@ -89,7 +89,7 @@ "eslint-config-edx-es5": "2.0.0", "eslint-import-resolver-webpack": "0.8.4", "jasmine-core": "2.6.4", - "jasmine-jquery": "git+https://github.com/velesin/jasmine-jquery.git#ebad463d592d3fea00c69f26ea18a930e09c7b58", + "jasmine-jquery": "git+https://git@github.com/velesin/jasmine-jquery.git#ebad463d592d3fea00c69f26ea18a930e09c7b58", "jest": "26.0.0", "jest-enzyme": "6.0.2", "karma": "0.13.22", @@ -23675,7 +23675,7 @@ }, "node_modules/jasmine-jquery": { "version": "2.1.1", - "resolved": "git+ssh://git@github.com/velesin/jasmine-jquery.git#ebad463d592d3fea00c69f26ea18a930e09c7b58", + "resolved": "git+https://git@github.com/velesin/jasmine-jquery.git#ebad463d592d3fea00c69f26ea18a930e09c7b58", "integrity": "sha512-P9aZDwDEAVgAbdHG/ViapRzAUJ6zBSq/4I1lJFluIbrld6Sv6LI+HT2J4dgWqtfaCgIyDnHBHSHiJ/anter7wQ==", "dev": true, "license": "MIT" @@ -56974,10 +56974,10 @@ "dev": true }, "jasmine-jquery": { - "version": "git+ssh://git@github.com/velesin/jasmine-jquery.git#ebad463d592d3fea00c69f26ea18a930e09c7b58", + "version": "git+https://git@github.com/velesin/jasmine-jquery.git#ebad463d592d3fea00c69f26ea18a930e09c7b58", "integrity": "sha512-P9aZDwDEAVgAbdHG/ViapRzAUJ6zBSq/4I1lJFluIbrld6Sv6LI+HT2J4dgWqtfaCgIyDnHBHSHiJ/anter7wQ==", "dev": true, - "from": "jasmine-jquery@git+https://github.com/velesin/jasmine-jquery.git#ebad463d592d3fea00c69f26ea18a930e09c7b58" + "from": "jasmine-jquery@git+https://git@github.com/velesin/jasmine-jquery.git#ebad463d592d3fea00c69f26ea18a930e09c7b58" }, "jest": { "version": "26.0.0", diff --git a/package.json b/package.json index 2f7b92e285..97740991aa 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "eslint-config-edx-es5": "2.0.0", "eslint-import-resolver-webpack": "0.8.4", "jasmine-core": "2.6.4", - "jasmine-jquery": "git+https://github.com/velesin/jasmine-jquery.git#ebad463d592d3fea00c69f26ea18a930e09c7b58", + "jasmine-jquery": "git+https://git@github.com/velesin/jasmine-jquery.git#ebad463d592d3fea00c69f26ea18a930e09c7b58", "jest": "26.0.0", "jest-enzyme": "6.0.2", "karma": "0.13.22", From 3e14628f1a13af6abfbfbc96b0e873b1441c8f7f Mon Sep 17 00:00:00 2001 From: "adeel.tajamul" Date: Mon, 6 Jun 2022 16:26:40 +0500 Subject: [PATCH 32/63] feat: created api for new learner area --- lms/djangoapps/discussion/rest_api/urls.py | 8 +++ lms/djangoapps/discussion/rest_api/views.py | 58 +++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/lms/djangoapps/discussion/rest_api/urls.py b/lms/djangoapps/discussion/rest_api/urls.py index 121ffff1ee..be956edab8 100644 --- a/lms/djangoapps/discussion/rest_api/urls.py +++ b/lms/djangoapps/discussion/rest_api/urls.py @@ -15,6 +15,7 @@ from lms.djangoapps.discussion.rest_api.views import ( CourseTopicsView, CourseTopicsViewV2, CourseView, + LearnerThreadView, ReplaceUsernamesView, RetireUserView, ThreadViewSet, @@ -33,6 +34,13 @@ urlpatterns = [ CourseDiscussionSettingsAPIView.as_view(), name="discussion_course_settings", ), + re_path( + r"^v1/courses/{}/learner/$".format( + settings.COURSE_ID_PATTERN + ), + LearnerThreadView.as_view(), + name="discussion_learner_threads", + ), re_path( fr"^v1/courses/{settings.COURSE_KEY_PATTERN}/activity_stats", CourseActivityStatsView.as_view(), diff --git a/lms/djangoapps/discussion/rest_api/views.py b/lms/djangoapps/discussion/rest_api/views.py index ff2599f852..1c7e24ec9a 100644 --- a/lms/djangoapps/discussion/rest_api/views.py +++ b/lms/djangoapps/discussion/rest_api/views.py @@ -24,7 +24,13 @@ from xmodule.modulestore.django import modulestore from common.djangoapps.util.file import store_uploaded_file from lms.djangoapps.course_goals.models import UserActivity +from lms.djangoapps.discussion.django_comment_client.permissions import has_permission from lms.djangoapps.discussion.django_comment_client import settings as cc_settings +from lms.djangoapps.discussion.django_comment_client.utils import ( + get_group_id_for_comments_service, + is_user_community_ta, + prepare_content, +) from lms.djangoapps.instructor.access import update_forum_role from openedx.core.djangoapps.discussions.serializers import DiscussionSettingsSerializer from openedx.core.djangoapps.django_comment_common import comment_client @@ -550,6 +556,58 @@ class ThreadViewSet(DeveloperErrorViewMixin, ViewSet): return Response(status=204) +class LearnerThreadView(APIView): + """ + **Use Cases** + + Fetch user's active threads + + **Example Requests**: + + GET /api/discussion/v1/courses/course-v1:ExampleX+Subject101+2015/learner/?page=1&page_size=10 + + **GET Thread List Parameters**: + + * page: The (1-indexed) page to retrieve (default is 1) + + * page_size: The number of items per page (default is 10) + """ + + def get(self, request, course_id=None): + """ + Implements the GET method as described in the class docstring. + """ + course_key = CourseKey.from_string(course_id) + page_num = request.GET.get('page', 1) + threads_per_page = request.GET.get('page_size', 10) + discussion_id = None + user_id = request.user.id + group_id = None + try: + group_id = get_group_id_for_comments_service(request, course_key, discussion_id) + except ValueError: + pass + + query_params = { + "page": page_num, + "per_page": threads_per_page, + "course_id": str(course_key), + "user_id": user_id, + } + + if group_id is not None: + query_params['group_id'] = group_id + profiled_user = comment_client.User(id=user_id, course_id=course_key, group_id=group_id) + else: + profiled_user = comment_client.User(id=user_id, course_id=course_key) + threads, page, num_pages = profiled_user.active_threads(query_params) + + is_staff = has_permission(request.user, 'openclose_thread', course_key) + is_community_ta = is_user_community_ta(request.user, course_key) + threads = [prepare_content(thread, course_key, is_staff, is_community_ta) for thread in threads] + return Response(threads) + + @view_auth_classes() class CommentViewSet(DeveloperErrorViewMixin, ViewSet): """ From 60c94ea8ca76cf86ccde7dc1d41d5432b1e0c4a3 Mon Sep 17 00:00:00 2001 From: muhammad-ammar Date: Thu, 9 Jun 2022 16:50:11 +0500 Subject: [PATCH 33/63] chore: add more logs in send_segment_events_for_failed_learners command --- .../commands/send_segment_events_for_failed_learners.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lms/djangoapps/grades/management/commands/send_segment_events_for_failed_learners.py b/lms/djangoapps/grades/management/commands/send_segment_events_for_failed_learners.py index 3c1a11ac0b..c586360072 100644 --- a/lms/djangoapps/grades/management/commands/send_segment_events_for_failed_learners.py +++ b/lms/djangoapps/grades/management/commands/send_segment_events_for_failed_learners.py @@ -53,7 +53,10 @@ class Command(BaseCommand): but we are adding grace period of 1 day to mitigate any edge cases due to last minute grade override. """ thirty_one_days_ago = timezone.now().date() - timedelta(days=31) - return CourseOverview.objects.exclude(end__isnull=True).filter(end__date=thirty_one_days_ago) + courses = CourseOverview.objects.exclude(end__isnull=True).filter(end__date=thirty_one_days_ago) + thirty_one_days_ago_ended_course_keys = [str(course) for course in courses.values_list('id', flat=True)] + log.info(f"Found {thirty_one_days_ago_ended_course_keys} courses that were ended on [{thirty_one_days_ago}]") + return courses def get_course_failed_user_ids(self, course): """ From cf6ea15ffffa16df9893ceea161294f08bf9644b Mon Sep 17 00:00:00 2001 From: Nathan Sprenkle Date: Thu, 9 Jun 2022 11:22:04 -0400 Subject: [PATCH 34/63] feat: add course listing alongside learner dashboard (#30553) * refactor: split programs into separate file space This is in preparation to allow learner dashboard routes/files to live alongside. * feat: add new empty course listing view * docs: update README and split out programs Co-authored-by: nsprenkle --- lms/djangoapps/learner_dashboard/PROGRAMS.rst | 56 +++++++++++++++++++ lms/djangoapps/learner_dashboard/README.rst | 55 +++++------------- .../learner_dashboard/courses_views.py | 15 +++++ .../{views.py => program_views.py} | 0 lms/djangoapps/learner_dashboard/urls.py | 16 ++++-- 5 files changed, 95 insertions(+), 47 deletions(-) create mode 100644 lms/djangoapps/learner_dashboard/PROGRAMS.rst create mode 100644 lms/djangoapps/learner_dashboard/courses_views.py rename lms/djangoapps/learner_dashboard/{views.py => program_views.py} (100%) diff --git a/lms/djangoapps/learner_dashboard/PROGRAMS.rst b/lms/djangoapps/learner_dashboard/PROGRAMS.rst new file mode 100644 index 0000000000..737afc1c7c --- /dev/null +++ b/lms/djangoapps/learner_dashboard/PROGRAMS.rst @@ -0,0 +1,56 @@ +.. _programs: + +================== +Programs Dashboard +================== + +Status: Maintenance + +Responsibilities +================ + +This Django app hosts dashboard pages used by edX learners. The intent is for +this Django app to include the following dashboard tabs: + + - Courses + - Programs + +Direction: Deprecate +==================== +This is being replaced by new UI that is in active development. New functionality should not be added here. + +Glossary +======== + +Courses +------- + +The learner-facing dashboard listing active and archived enrollments. The +current implementation of the dashboard resides in +``common/djangoapps/student/``. + +Programs +-------- + +A page listing programs in which the learner is engaged. The page also shows +learners' progress towards completing the programs. Programs are structured +collections of course runs which culminate into a certificate. + + +More Documentation +================== + +Implementation +^^^^^^^^^^^^^^ + +The ``views`` module contains the Django views used to serve the Program listing +page. The corresponding Backbone app is in the +``edx-platform/static/js/learner_dashboard``. + +Configuration +^^^^^^^^^^^^^ + +In order to turn on the Programs tab, you need to update the ``Programs API +Config`` object in the lms Django admin. Make sure you set the values +``Enabled``, ``Do we want to show program listing page`` and ``Do we want to +show xseries program advertising`` to be true diff --git a/lms/djangoapps/learner_dashboard/README.rst b/lms/djangoapps/learner_dashboard/README.rst index c77f096075..0daa4e0b45 100644 --- a/lms/djangoapps/learner_dashboard/README.rst +++ b/lms/djangoapps/learner_dashboard/README.rst @@ -1,50 +1,21 @@ -Status: Maintenance +================= +Learner dashboard +================= -Responsibilities -================ +This djangoapp houses 2 related dashboards owned and developed, currently by 2 separate teams: -This Django app hosts dashboard pages used by edX learners. The intent is for -this Django app to include the following dashboard tabs: +1. Courses Dashboard +2. Programs Dashboard - - Courses - - Programs +Courses Dashboard +================= -Direction: Deprecate -==================== -This is being replaced by new UI that is in active development. New functionality should not be added here. +The Courses section of the Learner Dashboard is a backend supporting a new MFE experience of the learner dashboard. -Glossary -======== +This aims to replace the existing dashboard at:: + /common/djangoapps/student/views/dashboard.py -Courses -------- - -The learner-facing dashboard listing active and archived enrollments. The -current implementation of the dashboard resides in -``common/djangoapps/student/``. - -Programs --------- - -A page listing programs in which the learner is engaged. The page also shows -learners' progress towards completing the programs. Programs are structured -collections of course runs which culminate into a certificate. - - -More Documentation +Programs Dashboard ================== -Implementation -^^^^^^^^^^^^^^ - -The ``views`` module contains the Django views used to serve the Program listing -page. The corresponding Backbone app is in the -``edx-platform/static/js/learner_dashboard``. - -Configuration -^^^^^^^^^^^^^ - -In order to turn on the Programs tab, you need to update the ``Programs API -Config`` object in the lms Django admin. Make sure you set the values -``Enabled``, ``Do we want to show program listing page`` and ``Do we want to -show xseries program advertising`` to be true +See :ref:`programs`.rst doc. diff --git a/lms/djangoapps/learner_dashboard/courses_views.py b/lms/djangoapps/learner_dashboard/courses_views.py new file mode 100644 index 0000000000..6d5837e11e --- /dev/null +++ b/lms/djangoapps/learner_dashboard/courses_views.py @@ -0,0 +1,15 @@ +""" +Views for the learner dashboard. +""" +from django.contrib.auth.decorators import login_required +from django.views.decorators.http import require_GET + +from common.djangoapps.util.json_request import JsonResponse + + +@login_required +@require_GET +def course_listing(request): # pylint: disable=unused-argument + """ List of courses a user is enrolled in or entitled to """ + course_cards = [] + return JsonResponse(course_cards) diff --git a/lms/djangoapps/learner_dashboard/views.py b/lms/djangoapps/learner_dashboard/program_views.py similarity index 100% rename from lms/djangoapps/learner_dashboard/views.py rename to lms/djangoapps/learner_dashboard/program_views.py diff --git a/lms/djangoapps/learner_dashboard/urls.py b/lms/djangoapps/learner_dashboard/urls.py index cba464b631..963f0050c1 100644 --- a/lms/djangoapps/learner_dashboard/urls.py +++ b/lms/djangoapps/learner_dashboard/urls.py @@ -2,14 +2,20 @@ from django.urls import path, re_path -from lms.djangoapps.learner_dashboard import programs, views +from lms.djangoapps.learner_dashboard import courses_views, programs, program_views +# Learner Dashboard Routing urlpatterns = [ - path('programs/', views.program_listing, name='program_listing_view'), - re_path(r'^programs/(?P[0-9a-f-]+)/$', views.program_details, name='program_details_view'), - re_path(r'^programs/(?P[0-9a-f-]+)/discussion/$', views.ProgramDiscussionIframeView.as_view(), + path('learner/', courses_views.course_listing, name='course_listing_view') +] + +# Program Dashboard Routing +urlpatterns += [ + path('programs/', program_views.program_listing, name='program_listing_view'), + re_path(r'^programs/(?P[0-9a-f-]+)/$', program_views.program_details, name='program_details_view'), + re_path(r'^programs/(?P[0-9a-f-]+)/discussion/$', program_views.ProgramDiscussionIframeView.as_view(), name='program_discussion'), - re_path(r'^programs/(?P[0-9a-f-]+)/live/$', views.ProgramLiveIframeView.as_view(), + re_path(r'^programs/(?P[0-9a-f-]+)/live/$', program_views.ProgramLiveIframeView.as_view(), name='program_live'), path('programs_fragment/', programs.ProgramsFragmentView.as_view(), name='program_listing_fragment_view'), re_path(r'^programs/(?P[0-9a-f-]+)/details_fragment/$', programs.ProgramDetailsFragmentView.as_view(), From 085526cf732ec96d7a917b4dc2fb6adc827f12ef Mon Sep 17 00:00:00 2001 From: Ahtisham Shahid Date: Thu, 9 Jun 2022 23:37:20 +0500 Subject: [PATCH 35/63] feat: added flag to enable MFE banner for learners (#30564) Co-authored-by: AhtishamShahid --- lms/djangoapps/discussion/toggles.py | 9 +++++++++ lms/djangoapps/discussion/views.py | 8 ++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lms/djangoapps/discussion/toggles.py b/lms/djangoapps/discussion/toggles.py index 0ab0638abe..1bafee3cf7 100644 --- a/lms/djangoapps/discussion/toggles.py +++ b/lms/djangoapps/discussion/toggles.py @@ -69,3 +69,12 @@ ENABLE_DISCUSSION_MODERATION_REASON_CODES = CourseWaffleFlag( ENABLE_REPORTED_CONTENT_EMAIL_NOTIFICATIONS = CourseWaffleFlag( f'{WAFFLE_FLAG_NAMESPACE}.enable_reported_content_email_notifications', __name__ ) + +# .. toggle_name: discussions.enable_mfe_banner_for_learners +# .. toggle_implementation: CourseWaffleFlag +# .. toggle_default: False +# .. toggle_description: Waffle flag to enable new MFE banner for learners +# .. toggle_use_cases: temporary, open_edx +# .. toggle_creation_date: 2022-06-08 +# .. toggle_target_removal_date: 2022-09-05 +ENABLE_DISCUSSIONS_MFE_BANNER = CourseWaffleFlag(f'{WAFFLE_FLAG_NAMESPACE}.enable_mfe_banner_for_learners', __name__) diff --git a/lms/djangoapps/discussion/views.py b/lms/djangoapps/discussion/views.py index b056c24f4b..f0935d4469 100644 --- a/lms/djangoapps/discussion/views.py +++ b/lms/djangoapps/discussion/views.py @@ -48,7 +48,11 @@ from lms.djangoapps.discussion.django_comment_client.utils import ( strip_none ) from lms.djangoapps.discussion.exceptions import TeamDiscussionHiddenFromUserException -from lms.djangoapps.discussion.toggles import ENABLE_DISCUSSIONS_MFE, ENABLE_DISCUSSIONS_MFE_FOR_EVERYONE +from lms.djangoapps.discussion.toggles import ( + ENABLE_DISCUSSIONS_MFE, + ENABLE_DISCUSSIONS_MFE_FOR_EVERYONE, + ENABLE_DISCUSSIONS_MFE_BANNER +) from lms.djangoapps.experiments.utils import get_experiment_user_metadata_context from lms.djangoapps.teams import api as team_api from openedx.core.djangoapps.discussions.url_helpers import get_discussions_mfe_url @@ -748,7 +752,7 @@ def _discussions_mfe_context(query_params: Dict, "mfe_url": f"{forum_url}?discussions_experience=new", "share_feedback_url": settings.DISCUSSIONS_MFE_FEEDBACK_URL, "course_key": course_key, - "show_banner": enable_mfe and is_privileged, + "show_banner": enable_mfe and (is_privileged or ENABLE_DISCUSSIONS_MFE_BANNER), "discussions_mfe_url": mfe_url, } From 4e74b16a41c848343bac4e0d2f5c98e16f463649 Mon Sep 17 00:00:00 2001 From: Navin Karkera Date: Wed, 13 Apr 2022 12:02:40 +0530 Subject: [PATCH 36/63] refactor: [BB-6077] allow setting celery backend in yml --- cms/envs/production.py | 4 ++-- lms/envs/production.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cms/envs/production.py b/cms/envs/production.py index 82244acbde..8a20a6ba12 100644 --- a/cms/envs/production.py +++ b/cms/envs/production.py @@ -110,8 +110,8 @@ EDX_PLATFORM_REVISION = REVISION_CONFIG.get('EDX_PLATFORM_REVISION', EDX_PLATFOR BROKER_POOL_LIMIT = 0 BROKER_CONNECTION_TIMEOUT = 1 -# For the Result Store, use the django cache named 'celery' -CELERY_RESULT_BACKEND = 'django-cache' +# Allow env to configure celery result backend with default set to django-cache +CELERY_RESULT_BACKEND = ENV_TOKENS.get('CELERY_RESULT_BACKEND', 'django-cache') # When the broker is behind an ELB, use a heartbeat to refresh the # connection and to detect if it has been dropped. diff --git a/lms/envs/production.py b/lms/envs/production.py index d989b1a48a..680c261a04 100644 --- a/lms/envs/production.py +++ b/lms/envs/production.py @@ -109,8 +109,8 @@ EDX_PLATFORM_REVISION = REVISION_CONFIG.get('EDX_PLATFORM_REVISION', EDX_PLATFOR BROKER_POOL_LIMIT = 0 BROKER_CONNECTION_TIMEOUT = 1 -# For the Result Store, use the django cache named 'celery' -CELERY_RESULT_BACKEND = 'django-cache' +# Allow env to configure celery result backend with default set to django-cache +CELERY_RESULT_BACKEND = ENV_TOKENS.get('CELERY_RESULT_BACKEND', 'django-cache') # When the broker is behind an ELB, use a heartbeat to refresh the # connection and to detect if it has been dropped. From 415291fd2740ef649d9e9428ea67616f3e0b4602 Mon Sep 17 00:00:00 2001 From: muhammad-ammar Date: Thu, 9 Jun 2022 21:28:01 +0500 Subject: [PATCH 37/63] feat: add source query param in data sharing consent url --- openedx/features/enterprise_support/api.py | 1 + openedx/features/enterprise_support/tests/test_api.py | 1 + requirements/constraints.txt | 2 +- requirements/edx/base.txt | 2 +- requirements/edx/development.txt | 2 +- requirements/edx/testing.txt | 2 +- 6 files changed, 6 insertions(+), 4 deletions(-) diff --git a/openedx/features/enterprise_support/api.py b/openedx/features/enterprise_support/api.py index a09600dfa3..373eaf4bd5 100644 --- a/openedx/features/enterprise_support/api.py +++ b/openedx/features/enterprise_support/api.py @@ -753,6 +753,7 @@ def get_enterprise_consent_url(request, course_id, user=None, return_to=None, en url_params = { 'enterprise_customer_uuid': enterprise_customer_uuid_for_request(request), 'course_id': course_id, + 'source': 'lms-courseware', 'next': request.build_absolute_uri(return_path), 'failure_url': request.build_absolute_uri( reverse('dashboard') + '?' + urlencode( diff --git a/openedx/features/enterprise_support/tests/test_api.py b/openedx/features/enterprise_support/tests/test_api.py index 08e108a67e..5114bab8b1 100644 --- a/openedx/features/enterprise_support/tests/test_api.py +++ b/openedx/features/enterprise_support/tests/test_api.py @@ -709,6 +709,7 @@ class TestEnterpriseApi(EnterpriseServiceMockMixin, CacheIsolationTestCase): expected_path = request_mock.path if is_return_to_null else '/courses/course-v1:edX+DemoX+Demo_Course/info' expected_url_args = { 'course_id': ['course-v1:edX+DemoX+Demo_Course'], + 'source': ['lms-courseware'], 'failure_url': ['http://localhost:8000/dashboard?consent_failed=course-v1%3AedX%2BDemoX%2BDemo_Course'], 'enterprise_customer_uuid': ['cf246b88-d5f6-4908-a522-fc307e0b0c59'], 'next': [f'http://localhost:8000{expected_path}'] diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 63a65cfee1..67000d939a 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -25,7 +25,7 @@ django-storages<1.9 # The team that owns this package will manually bump this package rather than having it pulled in automatically. # This is to allow them to better control its deployment and to do it in a process that works better # for them. -edx-enterprise==3.49.7 +edx-enterprise==3.49.9 # oauthlib>3.0.1 causes test failures ( also remove the django-oauth-toolkit constraint when this is fixed ) oauthlib==3.0.1 diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 3da22da3dd..9e58ca715b 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -467,7 +467,7 @@ edx-drf-extensions==8.0.1 # edx-rbac # edx-when # edxval -edx-enterprise==3.49.7 +edx-enterprise==3.49.9 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/base.in diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index e80885ff99..d327a05840 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -580,7 +580,7 @@ edx-drf-extensions==8.0.1 # edx-rbac # edx-when # edxval -edx-enterprise==3.49.7 +edx-enterprise==3.49.9 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/testing.txt diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 60477eb70a..191652642a 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -563,7 +563,7 @@ edx-drf-extensions==8.0.1 # edx-rbac # edx-when # edxval -edx-enterprise==3.49.7 +edx-enterprise==3.49.9 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt From 116431cb8106a3efdfbe5eb6551601ee30f2970d Mon Sep 17 00:00:00 2001 From: ruzniaievdm Date: Mon, 13 Jun 2022 16:43:02 +0300 Subject: [PATCH 38/63] refactor: Replace PDF course certificate view code (#30397) Co-authored-by: ruzniaievdm --- .../student/tests/test_certificates.py | 82 +---------------- lms/djangoapps/courseware/tests/test_views.py | 88 +++---------------- .../static/support/js/models/certificate.js | 1 - .../js/spec/views/certificates_spec.js | 18 ++-- .../templates/certificates_results.underscore | 9 -- lms/templates/courseware/progress.html | 2 - .../_dashboard_certificate_information.html | 21 ----- .../learner-achievements-fragment.html | 46 +++------- 8 files changed, 31 insertions(+), 236 deletions(-) diff --git a/common/djangoapps/student/tests/test_certificates.py b/common/djangoapps/student/tests/test_certificates.py index a9f6335661..f935653e34 100644 --- a/common/djangoapps/student/tests/test_certificates.py +++ b/common/djangoapps/student/tests/test_certificates.py @@ -15,7 +15,6 @@ from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODUL from xmodule.modulestore.tests.factories import CourseFactory from xmodule.data import CertificatesDisplayBehaviors -from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory from lms.djangoapps.certificates.api import get_certificate_url from lms.djangoapps.certificates.data import CertificateStatuses @@ -36,7 +35,6 @@ class CertificateDisplayTestBase(SharedModuleStoreTestCase): MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE USERNAME = "test_user" PASSWORD = "password" - DOWNLOAD_URL = "http://www.example.com/certificate.pdf" @classmethod def setUpClass(cls): @@ -63,7 +61,7 @@ class CertificateDisplayTestBase(SharedModuleStoreTestCase): else: self.assertNotContains(response, 'Add Certificate to LinkedIn Profile') - def _create_certificate(self, enrollment_mode, download_url=DOWNLOAD_URL): + def _create_certificate(self, enrollment_mode): """Simulate that the user has a generated certificate. """ CourseEnrollmentFactory.create( user=self.user, @@ -73,38 +71,10 @@ class CertificateDisplayTestBase(SharedModuleStoreTestCase): user=self.user, course_id=self.course.id, mode=enrollment_mode, - download_url=download_url, status=CertificateStatuses.downloadable, grade=0.98, ) - def _check_can_download_certificate(self): - """ - Inspect the dashboard to see if a certificate can be downloaded. - """ - response = self.client.get(reverse('dashboard')) - self.assertContains(response, 'Download my') - self.assertContains(response, self.DOWNLOAD_URL) - - def _check_can_download_certificate_no_id(self): - """ - Inspects the dashboard to see if a certificate for a non verified course enrollment - is present - """ - response = self.client.get(reverse('dashboard')) - self.assertContains(response, 'Download') - self.assertContains(response, self.DOWNLOAD_URL) - - def _check_can_not_download_certificate(self): - """ - Make sure response does not have any of the download certificate buttons - """ - response = self.client.get(reverse('dashboard')) - self.assertNotContains(response, 'View Test_Certificate') - self.assertNotContains(response, 'Download my Test_Certificate') - self.assertNotContains(response, 'Download my Test_Certificate') - self.assertNotContains(response, self.DOWNLOAD_URL) - @ddt.ddt @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @@ -131,7 +101,6 @@ class CertificateDashboardMessageDisplayTest(CertificateDisplayTestBase): if is_past: self.assertNotContains(response, test_message) self.assertNotContains(response, "View Test_Certificate") - self._check_can_download_certificate() else: self.assertContains(response, test_message) @@ -175,27 +144,6 @@ class CertificateDisplayTest(CertificateDisplayTestBase): Tests of certificate display. """ - @ddt.data('verified', 'professional') - @patch.dict('django.conf.settings.FEATURES', {'CERTIFICATES_HTML_VIEW': False}) - def test_display_verified_certificate(self, enrollment_mode): - self._create_certificate(enrollment_mode) - self._check_can_download_certificate() - - @patch.dict('django.conf.settings.FEATURES', {'CERTIFICATES_HTML_VIEW': False}) - def test_no_certificate_status_no_problem(self): - with patch('common.djangoapps.student.views.dashboard.cert_info', return_value={}): - self._create_certificate('honor') - self._check_can_not_download_certificate() - - @patch.dict('django.conf.settings.FEATURES', {'CERTIFICATES_HTML_VIEW': False}) - def test_display_verified_certificate_no_id(self): - """ - Confirm that if we get a certificate with a no-id-professional mode - we still can download our certificate - """ - self._create_certificate(CourseMode.NO_ID_PROFESSIONAL_MODE) - self._check_can_download_certificate_no_id() - @ddt.data('verified', 'honor', 'professional') def test_unverified_certificate_message(self, enrollment_mode): cert = self._create_certificate(enrollment_mode) @@ -225,34 +173,6 @@ class CertificateDisplayTest(CertificateDisplayTestBase): self._check_linkedin_visibility(True) -@ddt.ddt -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') -class CertificateDisplayTestHtmlView(CertificateDisplayTestBase): - """ - Tests of webview certificate display - """ - - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.course.cert_html_view_enabled = True - cls.course.save() - cls.store.update_item(cls.course, cls.USERNAME) - - @ddt.data('verified', 'honor') - @override_settings(CERT_NAME_SHORT='Test_Certificate') - @patch.dict('django.conf.settings.FEATURES', {'CERTIFICATES_HTML_VIEW': True}) - def test_display_download_certificate_button(self, enrollment_mode): - """ - Tests if CERTIFICATES_HTML_VIEW is True - and course has enabled web certificates via cert_html_view_enabled setting - and no active certificate configuration available - then any of the web view certificate Download button should not be visible. - """ - self._create_certificate(enrollment_mode, download_url='') - self._check_can_not_download_certificate() - - @ddt.ddt @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') class CertificateDisplayTestLinkedHtmlView(CertificateDisplayTestBase): diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index 2ffdc46691..8eea7537e9 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -1427,7 +1427,6 @@ class ProgressPageTests(ProgressPageBaseTests): user=self.user, course_id=self.course.id, status=CertificateStatuses.downloadable, - download_url="http://www.example.com/certificate.pdf", mode='honor' ) @@ -1478,34 +1477,6 @@ class ProgressPageTests(ProgressPageBaseTests): self.assertContains(resp, "Your certificate is available") self.assertContains(resp, "earned a certificate for this course.") - @patch.dict('django.conf.settings.FEATURES', {'CERTIFICATES_HTML_VIEW': False}) - def test_view_certificate_link_hidden(self): - """ - If certificate web view is disabled then certificate web view button should not appear for user who certificate - is available/generated - """ - GeneratedCertificateFactory.create( - user=self.user, - course_id=self.course.id, - status=CertificateStatuses.downloadable, - download_url="http://www.example.com/certificate.pdf", - mode='honor' - ) - - # Enable the feature, but do not enable it for this course - CertificateGenerationConfiguration(enabled=True).save() - - # Enable certificate generation for this course - certs_api.set_cert_generation_enabled(self.course.id, True) - - with patch('lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.read') as mock_create: - course_grade = mock_create.return_value - course_grade.passed = True - course_grade.summary = {'grade': 'Pass', 'percent': 0.75, 'section_breakdown': [], 'grade_breakdown': {}} - - resp = self._get_progress_page() - self.assertContains(resp, "Download Your Certificate") - @ddt.data( (True, 52), (False, 52), @@ -1585,9 +1556,7 @@ class ProgressPageTests(ProgressPageBaseTests): Verify that for html certs if certificate is marked as invalidated than re-generate button should not appear on progress page. """ - generated_certificate = self.generate_certificate( - "http://www.example.com/certificate.pdf", "honor" - ) + generated_certificate = self.generate_certificate("honor") # Course certificate configurations certificates = [ @@ -1622,9 +1591,7 @@ class ProgressPageTests(ProgressPageBaseTests): """ Verify that view certificate appears for an allowlisted user """ - generated_certificate = self.generate_certificate( - "http://www.example.com/certificate.pdf", "honor" - ) + generated_certificate = self.generate_certificate("honor") # Course certificate configurations certificates = [ @@ -1658,24 +1625,6 @@ class ProgressPageTests(ProgressPageBaseTests): self.assertContains(resp, "View Certificate") self.assert_invalidate_certificate(generated_certificate) - def test_page_with_invalidated_certificate_with_pdf(self): - """ - Verify that for pdf certs if certificate is marked as invalidated than - re-generate button should not appear on progress page. - """ - generated_certificate = self.generate_certificate( - "http://www.example.com/certificate.pdf", "honor" - ) - - with patch('lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.read') as mock_create: - course_grade = mock_create.return_value - course_grade.passed = True - course_grade.summary = {'grade': 'Pass', 'percent': 0.75, 'section_breakdown': [], 'grade_breakdown': {}} - - resp = self._get_progress_page() - self.assertContains(resp, 'Download Your Certificate') - self.assert_invalidate_certificate(generated_certificate) - @ddt.data( *itertools.product( ( @@ -1766,9 +1715,7 @@ class ProgressPageTests(ProgressPageBaseTests): """ Verify that invalidated cert data is returned if cert is invalidated. """ - generated_certificate = self.generate_certificate( - "http://www.example.com/certificate.pdf", "honor" - ) + generated_certificate = self.generate_certificate("honor") CertificateInvalidationFactory.create( generated_certificate=generated_certificate, @@ -1786,9 +1733,7 @@ class ProgressPageTests(ProgressPageBaseTests): Verify that downloadable cert data is returned if cert is downloadable even when DISABLE_HONOR_CERTIFICATES feature flag is turned ON. """ - self.generate_certificate( - "http://www.example.com/certificate.pdf", "honor" - ) + self.generate_certificate("honor") response = views.get_cert_data( self.user, self.course, CourseMode.HONOR, MagicMock(passed=True) ) @@ -1800,9 +1745,7 @@ class ProgressPageTests(ProgressPageBaseTests): """ Verify that generating cert data is returned if cert is generating. """ - self.generate_certificate( - "http://www.example.com/certificate.pdf", "honor" - ) + self.generate_certificate("honor") with patch('lms.djangoapps.certificates.api.certificate_downloadable_status', return_value=self.mock_certificate_downloadable_status(is_generating=True)): response = views.get_cert_data(self.user, self.course, CourseMode.HONOR, MagicMock(passed=True)) @@ -1814,9 +1757,7 @@ class ProgressPageTests(ProgressPageBaseTests): """ Verify that unverified cert data is returned if cert is unverified. """ - self.generate_certificate( - "http://www.example.com/certificate.pdf", "honor" - ) + self.generate_certificate("honor") with patch('lms.djangoapps.certificates.api.certificate_downloadable_status', return_value=self.mock_certificate_downloadable_status(is_unverified=True)): response = views.get_cert_data(self.user, self.course, CourseMode.HONOR, MagicMock(passed=True)) @@ -1828,9 +1769,7 @@ class ProgressPageTests(ProgressPageBaseTests): """ Verify that requested cert data is returned if cert is to be requested. """ - self.generate_certificate( - "http://www.example.com/certificate.pdf", "honor" - ) + self.generate_certificate("honor") with patch('lms.djangoapps.certificates.api.certificate_downloadable_status', return_value=self.mock_certificate_downloadable_status()): response = views.get_cert_data(self.user, self.course, CourseMode.HONOR, MagicMock(passed=True)) @@ -1842,9 +1781,7 @@ class ProgressPageTests(ProgressPageBaseTests): """ Verify that earned but not available cert data is returned if cert has been earned, but isn't available. """ - self.generate_certificate( - "http://www.example.com/certificate.pdf", "verified" - ) + self.generate_certificate("verified") with patch('lms.djangoapps.certificates.api.certificate_downloadable_status', return_value=self.mock_certificate_downloadable_status(earned_but_not_available=True)): response = views.get_cert_data(self.user, self.course, CourseMode.VERIFIED, MagicMock(passed=True)) @@ -1890,16 +1827,14 @@ class ProgressPageTests(ProgressPageBaseTests): self.assertContains(resp, 'Your certificate has been invalidated') self.assertContains(resp, 'Please contact your course team if you have any questions.') self.assertNotContains(resp, 'View my Certificate') - self.assertNotContains(resp, 'Download my Certificate') - def generate_certificate(self, url, mode): + def generate_certificate(self, mode): """ Dry method to generate certificate. """ generated_certificate = GeneratedCertificateFactory.create( user=self.user, course_id=self.course.id, status=CertificateStatuses.downloadable, - download_url=url, mode=mode ) CertificateGenerationConfiguration(enabled=True).save() @@ -1907,7 +1842,7 @@ class ProgressPageTests(ProgressPageBaseTests): return generated_certificate def mock_certificate_downloadable_status( - self, is_downloadable=False, is_generating=False, is_unverified=False, uuid=None, download_url=None, + self, is_downloadable=False, is_generating=False, is_unverified=False, uuid=None, earned_but_not_available=None, ): """Dry method to mock certificate downloadable status response.""" @@ -1915,8 +1850,7 @@ class ProgressPageTests(ProgressPageBaseTests): 'is_downloadable': is_downloadable, 'is_generating': is_generating, 'is_unverified': is_unverified, - 'download_url': uuid, - 'uuid': download_url, + 'uuid': uuid, 'earned_but_not_available': earned_but_not_available, } diff --git a/lms/djangoapps/support/static/support/js/models/certificate.js b/lms/djangoapps/support/static/support/js/models/certificate.js index da7322ff0a..b9dc6a68e1 100644 --- a/lms/djangoapps/support/static/support/js/models/certificate.js +++ b/lms/djangoapps/support/static/support/js/models/certificate.js @@ -7,7 +7,6 @@ course_key: null, type: null, status: null, - download_url: null, grade: null, created: null, modified: null diff --git a/lms/djangoapps/support/static/support/js/spec/views/certificates_spec.js b/lms/djangoapps/support/static/support/js/spec/views/certificates_spec.js index e41a8212a8..a1630f039e 100644 --- a/lms/djangoapps/support/static/support/js/spec/views/certificates_spec.js +++ b/lms/djangoapps/support/static/support/js/spec/views/certificates_spec.js @@ -16,7 +16,6 @@ define([ grade: '0.0', type: 'honor', course_key: 'course-v1:edX+DemoX+Demo_Course', - download_url: null, modified: '2015-08-06T19:47:07+00:00', regenerate: true }, @@ -27,7 +26,6 @@ define([ grade: '1.0', type: 'verified', course_key: 'edx/test/2015', - download_url: 'http://www.example.com/certificate.pdf', modified: '2015-08-06T19:47:05+00:00', regenerate: true } @@ -41,7 +39,6 @@ define([ grade: '', type: '', course_key: 'edx/test1/2016', - download_url: null, modified: '', regenerate: false } @@ -117,17 +114,15 @@ define([ expect(results[0][0]).toEqual(REGENERATE_SEARCH_RESULTS[0].course_key); expect(results[0][1]).toEqual(REGENERATE_SEARCH_RESULTS[0].type); expect(results[0][2]).toEqual(REGENERATE_SEARCH_RESULTS[0].status); - expect(results[0][3]).toContain('Not available'); - expect(results[0][4]).toEqual(REGENERATE_SEARCH_RESULTS[0].grade); - expect(results[0][5]).toEqual(REGENERATE_SEARCH_RESULTS[0].modified); + expect(results[0][3]).toEqual(REGENERATE_SEARCH_RESULTS[0].grade); + expect(results[0][4]).toEqual(REGENERATE_SEARCH_RESULTS[0].modified); // Check the second row of results expect(results[1][0]).toEqual(REGENERATE_SEARCH_RESULTS[1].course_key); expect(results[1][1]).toEqual(REGENERATE_SEARCH_RESULTS[1].type); expect(results[1][2]).toEqual(REGENERATE_SEARCH_RESULTS[1].status); - expect(results[1][3]).toContain(REGENERATE_SEARCH_RESULTS[1].download_url); - expect(results[1][4]).toEqual(REGENERATE_SEARCH_RESULTS[1].grade); - expect(results[1][5]).toEqual(REGENERATE_SEARCH_RESULTS[1].modified); + expect(results[1][3]).toEqual(REGENERATE_SEARCH_RESULTS[1].grade); + expect(results[1][4]).toEqual(REGENERATE_SEARCH_RESULTS[1].modified); searchFor('student@example.com', 'edx/test1/2016', requests, GENERATE_SEARCH_RESULTS); @@ -138,9 +133,8 @@ define([ expect(results[0][0]).toEqual(GENERATE_SEARCH_RESULTS[0].course_key); expect(results[0][1]).toEqual(GENERATE_SEARCH_RESULTS[0].type); expect(results[0][2]).toEqual(GENERATE_SEARCH_RESULTS[0].status); - expect(results[0][3]).toContain('Not available'); - expect(results[0][4]).toEqual(GENERATE_SEARCH_RESULTS[0].grade); - expect(results[0][5]).toEqual(GENERATE_SEARCH_RESULTS[0].modified); + expect(results[0][3]).toEqual(GENERATE_SEARCH_RESULTS[0].grade); + expect(results[0][4]).toEqual(GENERATE_SEARCH_RESULTS[0].modified); }); it('searches for certificates and displays a message when there are no results', function() { diff --git a/lms/djangoapps/support/static/support/templates/certificates_results.underscore b/lms/djangoapps/support/static/support/templates/certificates_results.underscore index 9ccd937239..7f1b0b9c8b 100644 --- a/lms/djangoapps/support/static/support/templates/certificates_results.underscore +++ b/lms/djangoapps/support/static/support/templates/certificates_results.underscore @@ -6,7 +6,6 @@
  • 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 diff --git a/conf/locale/eo/LC_MESSAGES/django.po b/conf/locale/eo/LC_MESSAGES/django.po index b7f584ef0c..bf66496d79 100644 --- a/conf/locale/eo/LC_MESSAGES/django.po +++ b/conf/locale/eo/LC_MESSAGES/django.po @@ -38,8 +38,8 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-29 20:42+0000\n" -"PO-Revision-Date: 2022-05-29 20:42:17.222392\n" +"POT-Creation-Date: 2022-06-03 17:28+0000\n" +"PO-Revision-Date: 2022-06-03 17:28:01.509197\n" "Last-Translator: \n" "Language-Team: openedx-translation \n" "Language: eo\n" @@ -7785,19 +7785,6 @@ msgstr "" "Ýöü'vé éärnéd ä çértïfïçäté för thïs çöürsé. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тєтυя #" -#: lms/djangoapps/courseware/views/views.py -msgid "Certificate unavailable" -msgstr "Çértïfïçäté ünäväïläßlé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σ#" - -#: lms/djangoapps/courseware/views/views.py -#, python-brace-format -msgid "" -"You have not received a certificate because you do not have a current " -"{platform_name} verified identity." -msgstr "" -"Ýöü hävé nöt réçéïvéd ä çértïfïçäté ßéçäüsé ýöü dö nöt hävé ä çürrént " -"{platform_name} vérïfïéd ïdéntïtý. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#" - #: lms/djangoapps/courseware/views/views.py msgid "Your certificate will be available soon!" msgstr "" @@ -7816,6 +7803,19 @@ msgstr "" msgid "Your certificate is available" msgstr "Ýöür çértïfïçäté ïs äväïläßlé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#" +#: lms/djangoapps/courseware/views/views.py +msgid "Certificate unavailable" +msgstr "Çértïfïçäté ünäväïläßlé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σ#" + +#: lms/djangoapps/courseware/views/views.py +#, python-brace-format +msgid "" +"You have not received a certificate because you do not have a current " +"{platform_name} verified identity." +msgstr "" +"Ýöü hävé nöt réçéïvéd ä çértïfïçäté ßéçäüsé ýöü dö nöt hävé ä çürrént " +"{platform_name} vérïfïéd ïdéntïtý. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#" + #: lms/djangoapps/courseware/views/views.py #, python-brace-format msgid "To see course content, {sign_in_link} or {register_link}." @@ -7997,6 +7997,21 @@ msgid "Good" msgstr "Gööd Ⱡ'σяєм ι#" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#, python-format +msgid "" +"\n" +" %(course_name)s: Reported content awaits review\n" +" " +msgstr "" +"\n" +" %(course_name)s: Répörtéd çöntént äwäïts révïéw\n" +" Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +msgid "Go to Discussion" +msgstr "Gö tö Dïsçüssïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#" + #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format msgid "%(course_name)s: Reported content awaits review" @@ -8004,11 +8019,6 @@ msgstr "" "%(course_name)s: Répörtéd çöntént äwäïts révïéw Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт," " ¢σηѕє¢тєт#" -#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html -#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt -msgid "Go to Discussion" -msgstr "Gö tö Dïsçüssïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#" - #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/subject.txt #, python-format msgid " %(course_name)s %(course_id)s moderator content for review " @@ -13199,6 +13209,11 @@ msgstr "" "Thé '{field_name}' fïéld çännöt ßé édïtéd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, " "¢σηѕє¢тє#" +#: openedx/core/djangoapps/user_api/accounts/api.py +#: openedx/core/djangoapps/user_authn/views/registration_form.py +msgid "Enter a valid name" +msgstr "Éntér ä välïd nämé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#" + #. Translators: This label appears above a field which allows the #. user to input the First Name #. Translators: This label appears above a field on the registration form @@ -13770,10 +13785,6 @@ msgstr "" "Füll Nämé çännöt çöntäïn thé föllöwïng çhäräçtérs: < > Ⱡ'σяєм ιρѕυм ∂σłσя " "ѕιт αмєт, ¢σηѕє¢тєтυя α#" -#: openedx/core/djangoapps/user_authn/views/registration_form.py -msgid "Enter a valid name" -msgstr "Éntér ä välïd nämé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт#" - #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "A properly formatted e-mail is required" msgstr "" @@ -18979,9 +18990,9 @@ msgid "Share with friends and family!" msgstr "Shäré wïth frïénds änd fämïlý! Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#" #: lms/templates/courseware/course_about_sidebar_header.html -msgid "I just enrolled in {number} {title} through {account}: {url}" +msgid "I just enrolled in {number} {title} through {account} {url}" msgstr "" -"Ì jüst énrölléd ïn {number} {title} thröügh {account}: {url} Ⱡ'σяєм ιρѕυм " +"Ì jüst énrölléd ïn {number} {title} thröügh {account} {url} Ⱡ'σяєм ιρѕυм " "∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #" #: lms/templates/courseware/course_about_sidebar_header.html diff --git a/conf/locale/eo/LC_MESSAGES/djangojs.mo b/conf/locale/eo/LC_MESSAGES/djangojs.mo index b8b4da1c43894ce64bf519a46cfd27e7f3bcacad..32551ca3e67bed43e192a6a5a769fbb591b63826 100644 GIT binary patch delta 56 zcmcb3M(W}jsfHHDEleF^B4)Y<#tMe!Rz?<928MbTM#e^lM(uONn1GlWh*^M`b^9DK HwypgD0Ob*G delta 56 zcmcb3M(W}jsfHHDEleF^BBr`VmI_7&RwhPPhUR)k#%9Kb=IwLDn1GlWh*^M`b^9DK HwypgD0lX1* diff --git a/conf/locale/eo/LC_MESSAGES/djangojs.po b/conf/locale/eo/LC_MESSAGES/djangojs.po index e8bcb11de2..f6a52ef53a 100644 --- a/conf/locale/eo/LC_MESSAGES/djangojs.po +++ b/conf/locale/eo/LC_MESSAGES/djangojs.po @@ -32,8 +32,8 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-29 20:41+0000\n" -"PO-Revision-Date: 2022-05-29 20:42:17.236317\n" +"POT-Creation-Date: 2022-06-03 17:27+0000\n" +"PO-Revision-Date: 2022-06-03 17:28:01.823212\n" "Last-Translator: \n" "Language-Team: openedx-translation \n" "Language: eo\n" diff --git a/conf/locale/es_419/LC_MESSAGES/django.po b/conf/locale/es_419/LC_MESSAGES/django.po index 0f0a66d1f4..0074d3a443 100644 --- a/conf/locale/es_419/LC_MESSAGES/django.po +++ b/conf/locale/es_419/LC_MESSAGES/django.po @@ -270,7 +270,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Albeiro Gonzalez , 2019\n" "Language-Team: Spanish (Latin America) (https://www.transifex.com/open-edx/teams/6205/es_419/)\n" @@ -7379,7 +7379,7 @@ msgstr "Bien" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/es_419/LC_MESSAGES/djangojs.po b/conf/locale/es_419/LC_MESSAGES/djangojs.po index 3c459ef55f..0f31ec4df7 100644 --- a/conf/locale/es_419/LC_MESSAGES/djangojs.po +++ b/conf/locale/es_419/LC_MESSAGES/djangojs.po @@ -175,7 +175,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Carolina De Mares , 2021\n" "Language-Team: Spanish (Latin America) (http://www.transifex.com/open-edx/edx-platform/language/es_419/)\n" diff --git a/conf/locale/eu_ES/LC_MESSAGES/django.po b/conf/locale/eu_ES/LC_MESSAGES/django.po index 94d84a92fe..cb654c6bb8 100644 --- a/conf/locale/eu_ES/LC_MESSAGES/django.po +++ b/conf/locale/eu_ES/LC_MESSAGES/django.po @@ -64,7 +64,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Abel Camacho , 2019\n" "Language-Team: Basque (Spain) (https://www.transifex.com/open-edx/teams/6205/eu_ES/)\n" @@ -6331,7 +6331,7 @@ msgstr "Ona" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/eu_ES/LC_MESSAGES/djangojs.po b/conf/locale/eu_ES/LC_MESSAGES/djangojs.po index 0d785bb418..3f289f3d73 100644 --- a/conf/locale/eu_ES/LC_MESSAGES/djangojs.po +++ b/conf/locale/eu_ES/LC_MESSAGES/djangojs.po @@ -50,7 +50,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Abel Camacho , 2017,2019-2020\n" "Language-Team: Basque (Spain) (http://www.transifex.com/open-edx/edx-platform/language/eu_ES/)\n" diff --git a/conf/locale/fr/LC_MESSAGES/django.po b/conf/locale/fr/LC_MESSAGES/django.po index 2b9f164b13..b44c43765e 100644 --- a/conf/locale/fr/LC_MESSAGES/django.po +++ b/conf/locale/fr/LC_MESSAGES/django.po @@ -312,7 +312,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Alexandre DS , 2020\n" "Language-Team: French (https://www.transifex.com/open-edx/teams/6205/fr/)\n" @@ -7455,7 +7455,7 @@ msgstr "Bien" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/fr/LC_MESSAGES/djangojs.po b/conf/locale/fr/LC_MESSAGES/djangojs.po index 6162317e31..93c4cd8cd3 100644 --- a/conf/locale/fr/LC_MESSAGES/djangojs.po +++ b/conf/locale/fr/LC_MESSAGES/djangojs.po @@ -216,7 +216,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: iderr , 2021-2022\n" "Language-Team: French (http://www.transifex.com/open-edx/edx-platform/language/fr/)\n" diff --git a/conf/locale/id/LC_MESSAGES/django.po b/conf/locale/id/LC_MESSAGES/django.po index 98b152d972..54712bfc7f 100644 --- a/conf/locale/id/LC_MESSAGES/django.po +++ b/conf/locale/id/LC_MESSAGES/django.po @@ -105,7 +105,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Aprisa Chrysantina , 2019\n" "Language-Team: Indonesian (https://www.transifex.com/open-edx/teams/6205/id/)\n" @@ -6759,7 +6759,7 @@ msgstr "Baik" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/id/LC_MESSAGES/djangojs.po b/conf/locale/id/LC_MESSAGES/djangojs.po index 0540569ae9..bb29ea6952 100644 --- a/conf/locale/id/LC_MESSAGES/djangojs.po +++ b/conf/locale/id/LC_MESSAGES/djangojs.po @@ -82,7 +82,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Aprisa Chrysantina , 2019\n" "Language-Team: Indonesian (http://www.transifex.com/open-edx/edx-platform/language/id/)\n" diff --git a/conf/locale/it_IT/LC_MESSAGES/django.po b/conf/locale/it_IT/LC_MESSAGES/django.po index adfb469e99..03313ac4bb 100644 --- a/conf/locale/it_IT/LC_MESSAGES/django.po +++ b/conf/locale/it_IT/LC_MESSAGES/django.po @@ -125,7 +125,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Ilaria Botti , 2021\n" "Language-Team: Italian (Italy) (https://www.transifex.com/open-edx/teams/6205/it_IT/)\n" @@ -7194,7 +7194,7 @@ msgstr "Buono" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/it_IT/LC_MESSAGES/djangojs.po b/conf/locale/it_IT/LC_MESSAGES/djangojs.po index 416d435653..9e9e352473 100644 --- a/conf/locale/it_IT/LC_MESSAGES/djangojs.po +++ b/conf/locale/it_IT/LC_MESSAGES/djangojs.po @@ -111,7 +111,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Mauri Macera, 2021\n" "Language-Team: Italian (Italy) (http://www.transifex.com/open-edx/edx-platform/language/it_IT/)\n" diff --git a/conf/locale/ja_JP/LC_MESSAGES/django.po b/conf/locale/ja_JP/LC_MESSAGES/django.po index f17d008e8c..d492ebc803 100644 --- a/conf/locale/ja_JP/LC_MESSAGES/django.po +++ b/conf/locale/ja_JP/LC_MESSAGES/django.po @@ -113,7 +113,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Waheed Ahmed , 2019\n" "Language-Team: Japanese (Japan) (https://www.transifex.com/open-edx/teams/6205/ja_JP/)\n" @@ -6276,7 +6276,7 @@ msgstr "良い" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/ja_JP/LC_MESSAGES/djangojs.po b/conf/locale/ja_JP/LC_MESSAGES/djangojs.po index 5c83e72a4f..591075406e 100644 --- a/conf/locale/ja_JP/LC_MESSAGES/djangojs.po +++ b/conf/locale/ja_JP/LC_MESSAGES/djangojs.po @@ -78,7 +78,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Kyoto University , 2017\n" "Language-Team: Japanese (Japan) (http://www.transifex.com/open-edx/edx-platform/language/ja_JP/)\n" diff --git a/conf/locale/ka/LC_MESSAGES/django.po b/conf/locale/ka/LC_MESSAGES/django.po index 755c8e2525..9f2c4a6fbd 100644 --- a/conf/locale/ka/LC_MESSAGES/django.po +++ b/conf/locale/ka/LC_MESSAGES/django.po @@ -60,7 +60,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Waheed Ahmed , 2019\n" "Language-Team: Georgian (https://www.transifex.com/open-edx/teams/6205/ka/)\n" @@ -6659,7 +6659,7 @@ msgstr "კარგია" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/ka/LC_MESSAGES/djangojs.po b/conf/locale/ka/LC_MESSAGES/djangojs.po index ff87a6e53f..ee87debfd8 100644 --- a/conf/locale/ka/LC_MESSAGES/djangojs.po +++ b/conf/locale/ka/LC_MESSAGES/djangojs.po @@ -56,7 +56,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Lasha Kokilashvili, 2018\n" "Language-Team: Georgian (http://www.transifex.com/open-edx/edx-platform/language/ka/)\n" diff --git a/conf/locale/lt_LT/LC_MESSAGES/django.po b/conf/locale/lt_LT/LC_MESSAGES/django.po index 5e96bba5f5..eab89bd5ad 100644 --- a/conf/locale/lt_LT/LC_MESSAGES/django.po +++ b/conf/locale/lt_LT/LC_MESSAGES/django.po @@ -72,7 +72,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Waheed Ahmed , 2019\n" "Language-Team: Lithuanian (Lithuania) (https://www.transifex.com/open-edx/teams/6205/lt_LT/)\n" @@ -6158,7 +6158,7 @@ msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/lt_LT/LC_MESSAGES/djangojs.po b/conf/locale/lt_LT/LC_MESSAGES/djangojs.po index a8e88c0ba2..04c222e87f 100644 --- a/conf/locale/lt_LT/LC_MESSAGES/djangojs.po +++ b/conf/locale/lt_LT/LC_MESSAGES/djangojs.po @@ -50,7 +50,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Riina , 2014-2015\n" "Language-Team: Lithuanian (Lithuania) (http://www.transifex.com/open-edx/edx-platform/language/lt_LT/)\n" diff --git a/conf/locale/lv/LC_MESSAGES/django.po b/conf/locale/lv/LC_MESSAGES/django.po index 48d7566c90..824330e8a2 100644 --- a/conf/locale/lv/LC_MESSAGES/django.po +++ b/conf/locale/lv/LC_MESSAGES/django.po @@ -49,7 +49,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Waheed Ahmed , 2019\n" "Language-Team: Latvian (https://www.transifex.com/open-edx/teams/6205/lv/)\n" @@ -6736,7 +6736,7 @@ msgstr "Labi" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/lv/LC_MESSAGES/djangojs.po b/conf/locale/lv/LC_MESSAGES/djangojs.po index fa0cee8bfa..8655de18b2 100644 --- a/conf/locale/lv/LC_MESSAGES/djangojs.po +++ b/conf/locale/lv/LC_MESSAGES/djangojs.po @@ -40,7 +40,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: LTMC Latvijas Tiesnešu mācību centrs , 2019\n" "Language-Team: Latvian (http://www.transifex.com/open-edx/edx-platform/language/lv/)\n" diff --git a/conf/locale/mn/LC_MESSAGES/django.po b/conf/locale/mn/LC_MESSAGES/django.po index 9e80fcf5a9..99031f0f1d 100644 --- a/conf/locale/mn/LC_MESSAGES/django.po +++ b/conf/locale/mn/LC_MESSAGES/django.po @@ -74,7 +74,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Waheed Ahmed , 2019\n" "Language-Team: Mongolian (https://www.transifex.com/open-edx/teams/6205/mn/)\n" @@ -6206,7 +6206,7 @@ msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/mn/LC_MESSAGES/djangojs.po b/conf/locale/mn/LC_MESSAGES/djangojs.po index a5280fa003..93c65d379a 100644 --- a/conf/locale/mn/LC_MESSAGES/djangojs.po +++ b/conf/locale/mn/LC_MESSAGES/djangojs.po @@ -63,7 +63,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Myagmarjav Enkhbileg , 2018\n" "Language-Team: Mongolian (http://www.transifex.com/open-edx/edx-platform/language/mn/)\n" diff --git a/conf/locale/pl/LC_MESSAGES/django.po b/conf/locale/pl/LC_MESSAGES/django.po index d3f2eef056..64c63ef10c 100644 --- a/conf/locale/pl/LC_MESSAGES/django.po +++ b/conf/locale/pl/LC_MESSAGES/django.po @@ -22,6 +22,7 @@ # Magdalena Dulęba , 2021-2022 # Magdalena Jarosińska , 2015-2016 # Marcin Miłek, 2021-2022 +# Marta Litwinowicz, 2022 # Martyna Boguszewicz , 2020 # Martyna Bogusz , 2020 # Mateusz , 2014 @@ -146,7 +147,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Marcin Miłek, 2022\n" "Language-Team: Polish (https://www.transifex.com/open-edx/teams/6205/pl/)\n" @@ -6892,7 +6893,7 @@ msgstr "Dobrze" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/pl/LC_MESSAGES/djangojs.po b/conf/locale/pl/LC_MESSAGES/djangojs.po index 80f179a593..89c57618cb 100644 --- a/conf/locale/pl/LC_MESSAGES/djangojs.po +++ b/conf/locale/pl/LC_MESSAGES/djangojs.po @@ -113,7 +113,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Aleks Ada, 2022\n" "Language-Team: Polish (http://www.transifex.com/open-edx/edx-platform/language/pl/)\n" diff --git a/conf/locale/pt_BR/LC_MESSAGES/djangojs.po b/conf/locale/pt_BR/LC_MESSAGES/djangojs.po index b91cd10f21..67873661b9 100644 --- a/conf/locale/pt_BR/LC_MESSAGES/djangojs.po +++ b/conf/locale/pt_BR/LC_MESSAGES/djangojs.po @@ -246,7 +246,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Rodrigo Rocha , 2020\n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/open-edx/edx-platform/language/pt_BR/)\n" diff --git a/conf/locale/pt_PT/LC_MESSAGES/django.po b/conf/locale/pt_PT/LC_MESSAGES/django.po index 9d57a08644..b1b87cabc1 100644 --- a/conf/locale/pt_PT/LC_MESSAGES/django.po +++ b/conf/locale/pt_PT/LC_MESSAGES/django.po @@ -140,7 +140,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Cátia Lopes , 2019\n" "Language-Team: Portuguese (Portugal) (https://www.transifex.com/open-edx/teams/6205/pt_PT/)\n" @@ -7140,7 +7140,7 @@ msgstr "Bom" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/pt_PT/LC_MESSAGES/djangojs.po b/conf/locale/pt_PT/LC_MESSAGES/djangojs.po index 70154ef972..4a20d1f6e5 100644 --- a/conf/locale/pt_PT/LC_MESSAGES/djangojs.po +++ b/conf/locale/pt_PT/LC_MESSAGES/djangojs.po @@ -111,7 +111,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Nika Shahidian, 2022\n" "Language-Team: Portuguese (Portugal) (http://www.transifex.com/open-edx/edx-platform/language/pt_PT/)\n" diff --git a/conf/locale/rtl/LC_MESSAGES/django.mo b/conf/locale/rtl/LC_MESSAGES/django.mo index 3c012ee8a0842b82617167c599ddda7cf515650c..4afc4c0e9662f4d467f5231f9b59b09081cbfda7 100644 GIT binary patch delta 96085 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�>O#|+GeAQ4lo5xTEIFD+9gw3p`=}=2`c8tZ^sEntgrsr-{ z3th%&3^unGN#30KuW3@99ZIl1YP7aNjrz%`(Yy-PQU_55c#7)7LM^PxE1{-uT^xy9 zQRx+FXiT~h)uj1a1-x&t9S+2-t*s!7a5$rPCu&fY zXlL`dC8i-9L8Z3z9B)F8UyhyO&4k)$0g zqhhGz^-wi!g<4>GpjvJusz3`-OZ8UNm^g%~@Crt0{{QJmc#LH^5bPLmuX0K`gS;~rsGf-tyQQdKj4S&p$Z!AqJ@b0mzj++>?nd- zoBN}#X46pxI*qe1Vb_4yAr5agVKKsSy9eBBx+PH=PeENP=AxQ>A8HyON7eiaD&8Od z@yF?Eq>H&6wAinZ{Ko&onm!yPe}@PDWbOZT!R zy&h`%eu7Hx9%@XL>dpMun*SLacQDk)B0R!Age&%Csl+YV2>(MhW!-+ZFbzRXyE9l5 zAE63VzQ48TWE?HU^kcHo~^WH|CR}s}ReNk7psi>~qg2(Va>gRdB8f?=y$p_5;VH}A0!0yjK!jCC& zykQI?{B*e0`1pqb_j36ooK5`JocA5aAL93Tcx1p^h$~0ipe-}jE=DVGGVz1s?51`u zs%3kR=k6D;McA0gM)e5+?+Bj5#kgoY*N5mM8dOCAJfY>g+YUBr`m1#SJN0| zguNL7_k#mTW(M51U*_Ox_D`M_a354?F(=?1AX?J7mfv~oMmW-Xo~_M?Q4tEx54dMM zkMJYHEf?DT`%~0QuICqVoc;5c*!}-Y?8^RCAMr#4!^`ZvuFI{a304H$Z@>)14>|8N zRwiDZmF|4r|64_0vZMHFyExQaWB2Wca18s0uC)YTuCoFzSs(CzWq;d`1McHDl{YZ0 z2w%hm_|ryPYHxmO>p+}MHl5$X92B56Cc$x-M)Q9j8)0^QhMKRt{P1ziPWYl9eu>El zhd#4-Z=$Yhxlz+?9yX=`pWu0XwK?EEqH%s}!2L$t=xsKw%X}X24zXf2z;O{GzOl;| zl%>1v_V@x8BEbi!4B!6REQ$>YSHsG<2y5d{s1-5K9-FS^QP++M7=v~8+U2|tD*jT` z!uC5xGP99$U%-7xq&8}WI)a+l-(m>=LA8Xp-JEXuirXoOZU@GaDN)sIB1MstqXg0mU5#Qua@=^mpJj5%rrsD`>9=!Cil z9D|y+vB#{1qK{h(6u=nvS3xy-7gR;Jp$6fP*c=0q6L$G+k6PKbpjNQBC+$us2KAJw zG3o}SFKXVdL3K&uQ?|AjL#=>AP&XQDFb4Ody5I(CaK}Gw>7_vB6UoPhE|axUecsbQ zFavcXu?ZL9QPg$5;~Bg6>yKI?H()nB`fb2{y1n2zdk)#yizUxtNsjdSupkJFpt=!vq+8+2(U%Y)$wr)U{z4 zszv6YuB!V{E%7I6&?dX0Sw_){u%W@#6*X$dV0@g1F}N5D;%?MBaUV5C{zJ7$va1%( zh-$%Ns9Dq!)#RQ0;{#9^rAfY<(7peEj*S8wc!Vl(*6*$64N)sqXVl;sgiUcd7RG;3 z(=N|7>#8cKnzcpUzK=r9^R1|gJwUA!aeuH1r9yZAUyTjj@eIdOxEpn&@Wc;S`Oy*@ zf$FL~SO(+$WcT~AsP$k3>ims<_%^D>DXv>f6-SM=DyYHN={oaYw^F0np_1=FO}A^P zmWcPWt!M?XCgGu|vGENK#>6)QUOxukIMj;y-&!D2lno88ewYszqel60R0~{0op2p1;2l&;`<)Hdxba_>;Sk?ZsFF`X9bbf6 z2lk)_>lxHtapJ#iG-pB0`*$#eeNYt{iYag`Cd7sQ{I0Jji3^Kjw)c%f9(7sIGb<{e1SjUY5e}NjipbX*qGUZZvKD6hDv@5 zmC#Gn=+FGG^=&;2GI%OKW$%>K&K zZ;q`9zmGb8=@s+8HXB(PVk+6Ys3wkJPMnA8ntiAidW>3V632;lH7JD|w7sz+E020s1+gwRj2nq|HC(}t;_UbWRpa}p8;5xDqTP#5IWa(Z9;${* zu?6lx4a$`9quo-S6*VS`qP_!C12v1>mA160>+K+TFjP}4SEv{fu2CMH}NwS+hF!;uASG-Jm) zR7t&Hv|HgqsG8+MwMc2y#i%~2hV4)V9*DZwOhd)ngF5d#=D=T3Yki`Sbxm%JA>0tx zsiz09F^C=M!_jWg%|s>eDJp|KzL!yb`WI@9JVg~KX+o=6jBkF_^eu-P#1%0H+u#C> z_~A5(qHX?{WaCW^^g&&nCZn4C6VyU;9rfHUW8!G{ru2>^mhdZ7LDMI-!I}qEuy?RD z_C^irkFgAXfid_uYMQ4^M%U=ps015os(z@8%R*E^cA!S}W$cORliOe%j|B)nLXCy2 zDWctL!>zC-;pM1;JV$kHij>iAy7fX;Y$s|qJ-~=EicV#tIXh}vj6zMbv#5*B3)H%> zKDBkhe$;$FiW&=7u_4|^HFZGx*EP@f18Za{E#FoVvG&4>6xs?OHu2^R#e7!F&5v-9PKVzZBZ@J z8!K`CM2y8#Z%4bg-x6oF{7y&M*i6LRxCj?yi*{c$D4adoec|vR&SQVO9MSH-TzG;% z5MG>G#pDH}-7BXH(2XtZ zt@;0gjXp%^S;+11uHpc~)eGC2y&IMB8B_s(LrtrMMQkvoMUCbjm>EZ*X2%-T5`Gc2 z)ILYeu3SZ<-MwE;%tQX(ST>ZwR_uW%P%BokVm3A!qi(_4qB0tTYJnxVfTsNlb+Kwt z!s2~^%6K^r!Na%#%a@FH?<@R{dhKXcsc1fk%7GzeqTQ#}+LyJO)h%Z=ZHX})k6;m8 zj=AsxYBqS~ZOKlLYVxe8d0))mUk6p-rvCoEsA)US-@gFe?|*G(Lo47e)RKD{)u(@< zMtR0qJKhvC5gv%|;yhG~1uNL}8i=~coIs^_71gp&P#3eL6>R}3f!g1vBJ;l-8{^rb z!E+eZ$N!*CNL$I8wgM{Qo|p*VM~#^YsJ?!J{V_*n8+40M6}g3K0k4Xkmj=~B*--Zb zWvfK2DeJRC8TUl3RMSy?{0L((X;m9M1yMC_fK6~WHp1l9?6TVh>k}S^3-A=GB3-JJ z9(_Iy^;L~eYS{h3_DD@z;f~j`X?Px+a>8xY^ebOG+WnqqW7NWwtWLCheJ@AdX!k}# z#(L52EteJeg!n(BGQ3jXE?#jOuoQD%EHd4^>J6j4cK8KO!N?nptdCb?9d=wpU9EC8 zw(E6Q)I6VtOK~3_!M07J-P7&t@7RJf7S*(8P``M73zra{)hyb*tCqjHExBiLEBgnw zaDzGGWp5enUX5;uA93Iaj>gWdqTS8n9b8DbYHREB>zImgy*75y>5LlHU!mstam^`75YOu{kT`Sh3#@aP>|Npnw(FRpI)TkYcn$OFyG;T)K>>jEH z={ng`S`2l(FKS)bfLd}dqGnU(&NdbrpstcbQPXZECd6GB(I7j@hEDhawbCW*Vq>5n zsvv#vEsUU+*rk{V_oL?d8B|l>LoG~kyIME{DqI*fTk2vBT#ahk`(2s;+DO>VnlKl( zAUp;u;7?c`Gj+F%Mh~n?cpg^6AN+9E9?|aEZZ9m){@qv-pQD!MVm+>cd5-njgXv80cp=7O|+BkHp@16tw~t>mTiYntcsw-5C6C zwELjZ8Pr%PI>1_FBx+sQkE*~OjKPRE(56c!RE;X3O4bH7P5Pq7#B{ugpQ8rTqCs|b zJct^!r?DIUhWh=02Jc0?_j-m6w!XiH#W`MRhz;f*$ZUvs3)oQ2Pog3`!D5(ys9h|& zpa$C#RG)oR`WGCGf1{iKJwLFOZW3x< zZovY00TW}?FiSWUs-_t+21{ZHTVN*ajGCU~F&nNz&6?x>{yTV(aDw4>wLFGjvi^86 zA6iK-qq^WB#$ZAQ=Np(8wQ%TSrFCE^Ho$fG0Y1fnIB0~eba$~e;kqMjA=-#)vD>JE z{fp|_jH8(UmDwoIh8Bb|sJ@B%wX^dLo2BL1c z=3_fNi5d%er&~g0uqNU5SQj_qJNOLCV#68H?lqzrIFxXrnPf;o$D;=Eky)1h4-q!h zr^#pAD33*DTo=_;qfzsI4d%mpSP0Y4G3%l}ZZ{G&J(tb3!8&%H_4RbrZ2AJVRR4h* z+@bl_(vi|^Xw-H>_0D)@I;1s`Jx zEVIZ8HVDInBS=d`yvb~6+O0tK(IM2JyX%MFSZtTiGN@5o4>g$jVmX|T8Z#GB1$%`W zyor`r-{;2KglnQ^(|pwN&s;ddJsKNo+M5`_lpk4v-b4+~Sk#i)1vPkvqpq6sP#3EW zsA(Iu)CONBR14-qEl{;k=M6@6^$b)&_h6X(`6)Ha=rU>rdx=^RqnBC2g;5JlU2KTW zQBAlJ)goV^M)_sbc~39~GcULOl~4uhfNFsVss-j_M5B5;8(Lt#!Q%KYs^$e&ScdQ5 zdcq&0x~SpGX!o}LU{pI#%0a8P7nq&?Z!ie241m zr>K_5y4A)^8`RC|Am8z*i_k*sOnx6n*wEUX%G6UPKOVZ&~GRT4I`!Bw*Elo%=Wl`Sx}c348QQ1f;LYE0Zl z4YKq*?Rk7@)ac)j8r2t38T{#+aF?}EPSp9;uoHfO>Z0qYmJ087=kxoIY-rlmN7bMi zs^&dWgXkkvUw!F^e@0ECXa4@2U)!i|gepi+)CxHPmEJDY`fwVR-V@YxO}0lXBl9m0 z8>&%9)CogSm&wVfrrwH5_@E!Yj*AFC#OXL?uf06?=02Mx6Hp($D7fFc&O2ybk`UFE z=}=30Hq5N~-hsVyRX2!7A``?zlG}C zm#FEP^Qf($EwCBk4^d;_5^lsY$1L4D$C&^6B0$39cGueSM6~H{66m!OEG6_|`6JNm1)d9_)!LQPVH+SzDOiI?MbY#*QNF zP+xCBEsY1TI0d+lBMGNDZ+AG0a1Y_)-_aEue~hYO`itC#6CQ{|2v@yq1>1`~2tPwz zgt}Z|%n)xIeoDAfB&|&ui%wvD&ie;7=p$8swL#Vr)3BotDuMB+rE~@Aa=Q;Z z<8N32>)x~`oPipgYf%|(L9KX)P=ogp>i*&`Y8pn}vh^fCw$Syz9veXpe1f`D`5cwt z@2J7_7&Th6-;Q>_cF_@ay!mhTG`th4CKpjP{2g^ak?M{Wuq0+BTn|;iL8$3H5#9Iy zH?yJ9eiT#T6I8~D?pn>uVL8HGP#LU2#XEz#FSv9MFmJ{xuZYIMK&ry9h^)HLK9ChL;RJA+geu^PN6i0CY}{r?O`P|S_4UuF`+y9OqumFS+M(9` z?@@y&_{0iQ2sKE{VlHfj`Z~^dRJ>$QqrFXWDFCL9M}ePNOL(tr;Y$39`5#5ZZ0y*N zd9e}xiCQQsF*G$O8=+>wBrJ(rQ7v>2_43*)RM!OJ2HpLCT2z6WVqF}CnpI~}>HdyI z@L7ZnjqU>Rf^OyNg<5h4p=QMb)M#FbD!^fU5AWl7>>NMne!#qBf}nd3C}C94HEn&= z;OvE3&_<)Ksw+?#pU1Koi4IT$HmagZSQk~oZm5ih_~9kkgYZVw;CUlD=-wx&jOycq zSRPXcgYGSzcTgGpiu(9|=1|a$jRN7I8%rIL}5zYPvTP2HoYdB5HQj z#Y}hu)k5(TS<7X|f9d0nIGz2ik_O%Di1)A>;YrDY?!%|&ur=YL$%F1)vf0>1*Z)7+ z(1E%sg6<-*5$6z2lQQTox1VAa!sk#;mnK!vjgdOoitq|-j4v_FU}}`wx~A=$mTut; z)-^NneF}O3I}*QsOwb#y`Tsc^U(iH_G6lW0cqg+p>5MEv_nyx$*p+zWvs%V~;t9f) zvIX4&lO%i4tH^mXupax*=diwhJ7>@>Y)$Yzj*mgz6+g>m6)Kn~Xy5-E%!cOiK~#ja zd4pao;d=RkZmpkz-w{5Cf8e_OYC0CG0@lQjFotlMf#DV=XUE^8rt#AfLHB&2KuH@rJ4;4_?p3PC?D&!h@07A8PF&iWr~{5-|9b3#xyuCI z^?nwrAiv{O%v9E<v!d?Vxvv`eFr)Y|_u4#MP(T)q)+0vpZPaU7rG+l`4x!Wo(b-A}L8eJAMd zaIRo2j^}C`^t$7FxQ}?(Q5TyP&23O7ZV~jZ6Yh;|IbOGA&^u0eQ!5)2Lt6*kE#D?w zr}>||P0))^#Pg^X?s8kE58+Dfg6`rpsD04AA(^FvO{)c{raq2sF+sNJgOT_Z z;n+Sw_sxf=ID+t$zGk9+)}+%=7q901ZN;36EeYp(*9tTaE6|e1@Fn}h0~sS28f4ZR z#Qayu=deSA;Hdj%;iA2rFMhx9qQgKu*_~W3ZOD>jhZd1b^ENi;bDmERP>&P`W+Hs)RDr=hgIDv4I)mF0w_%7kV8k>&q zqY7{rl|jk1HfGwQ2Gw@dtf;xp){k-6j&RZS)^+nxEqVi&sbnob4!R$ae1^JQKK{g} zN7)TQ_k4a7YRSBUOR?TY>!SOpF;U`ETX>G4#!9+PLH9lXcTwv=lh3Sxdr-3?Wj_K9AcPbZ-{lK-IkOHgga5A)M%Q>w;l8p70BtiDS20 zSHAIut$eYl7VCuBaMBmd|K)6KVaLbV@JqX$evb19$KPQETa2{{zeK%WP-~~P*rHu_ zHJiKJ#>l|0gYN4#oA3tlO6{>bq73_NW$lexfVQJr^uK)(yG!l2Kj`IT$0lrpmr+Y^ z@dMmk;yT=l%MaSh*XWy|x1R7@hwRSi2(Bf(Sx{T+D91pthY8*ygd?uf;1>!L(!;U9yG^ajgEzuOKv41D(g^ReSZC*z(7vUsl zYz&pcX@p1O2u%8|UA||c7Nmc13q~rPwLbX=3$r8rxuACv>!I%3-#l-FDc5&AFCd)g zf-S)rF4}Y}b;%O!k3r7cjoI-qYV6#{d|2}`Hzu4v6iee*SKQc$@Tqru0+Qi-778L} z#Y|WLbz(z*|42MWc#4k4=T_~S-F^?bZns_+ur9}I|7>GrF>WOM8-7KGb8pbXSoc>O z+&gXt`Hl(mZ^o^l`+QE#+cu~kqpnsDf3pN1+_7s!`MY+fl>B$Qh&09v#H(=6rsErb z1l{X`?Xd~_pQF08;r*aDpNzl8ve@JS6~);PnZ9~CeCc0y!;$}yEj;c2v5fEHGZHBI zm_Coo0`kOaH2kSuTyp(q^Lqe}Bi=RCH17D!u6Bn}3sU;$9A^pMjK^uY;pJGe5)?;pIu##44=#AKn6d$w8-GZU_dx^;RNwK7h}ym%2)VEk~% zJ>yA(8g$*TJkG$}_$@ZX=ctycmoVhsve}B7hKUmK`KPjMe32;R7KTTdfpE#hAvYVE z;t0Z%u`(u15^~Q48(>kw^D%&@PzAn#5Ak12j(3w37^zAuk_&mK^m2qe7aHyP-IPU6oK;>!J~;CjSas;omq3>!%C3 z52bvMYKfxhLvA5zkIHx^stY3DvC)T(+;4{5#bXg>BK#Ll$CMc?!_`=caKg7j?sdZY zsJ`ru32`2(MOLA@;tGzyI2l9kh0Rf@G14t27ED68IHtvFsDiXd4bt~9JsM&M@OXDBd0dr;xxfeL5pwhpK zi7_fW^S?D4so2Pc15hon6xC#hkv{S+qn6_Pm>)Cb2)R$O)=hHXfvcgc|Z&6txon)o$KG5>W@I9=KnhLUBi zkLRG8ay15UH%`HCP)*&SoYkNcs>KGOy6huVO%I^rok1;ZH*gciEgy0p_uYcJ1L_co zwI-g3wb-!?HEMrHP0OqmLhkAG9L!1h23Es_6+`Z7*BF(-D%89_h|MsnlAYfc6A?a* z>ho(j27gE0VMY2?4!PHC0#!op^}b%HK{W%F@UN)8k6+bVrZA2tTnTk`JAoQ(#j4r- ze;3vF>rrFn8?1tlP&cQgs)yX`2(xgQ=KoVRigDn*8g{~`IEe5Mm;)Qtv=$kL3V(rW z>Yq?862F#ZoDVgqI-#0&5XRsV->9Y^VjOGOA#0QDb5Zro@e?X}lkm-hI?c7+sg8nf$$EZ0N+YmC4UxtRZ4is<5 z{MU~6*r7o*1C{Yf)RKA~Rj?PRCQaSQN?s0?K^tt0gRmeTM=e~>QDY@>V=GW`RJb|T z#!;v)In$W=uW9z29qPlLO>9t&!>)ukV+Bm}j*Z?HsIjsYwYKlZws;iP6*-!Q+>6-d zQ0u^8R11wkEkLJH3trx4A@{VsY=jLp={{@}hbBUO&bMR>`X1}IWHw;uR<;g&-#X;g zB%HGig9rz<4Y|AA;q7eJpn`b1Bli(lwsVMYOEGP`*tCw6>}L0T z-EcDnxr^&@arcmS6f5@#xfh)h^$fY2%#%2U{f&BAmtDuQgx~CK_X{mB9~s=m9GJFm z$bCw_V!x1kdGGuFw$NR8*Tsu?nFfTs_9Re$p!MZe{DW{{5H-brQ0qbLd(;TO!0)lf z;E;PkA?pw;@HPCH{bPqR2FN)7`yuxqja2x+S~&Tzkb9}8IIbXGXn4q56NmY?k&R94 zXvkPl-^LkXeHZpkgBrzIF%x#cLO2FBD8EFtz)$}13?pp}l}E+zjtfHEXP~BCmMJzJ zD`S1~_gb-`rSVhLAWSgTrd-B#4W zsP~H3VPW?FF@xDcIMYn#|5J7}niX^6D>YTm!Z z23TdjU3BJSd%{<-IhLWiavmNbod?*D@K=lc8zQ)Y>17<>Rsr6}QRJ>}am2C#93s<3TJU&IW=n2${ddm+dUlwxj8|Ga`pKBqh z%??e&j;Mqtpl+QOV;l8qt2_3Yq2Y80ZP2m=6@`)Fv0 z)s!g@+uiOiR6;+amg4+JETj2Yh467~f=Q3slhQ7DgYaLdmGi(aZ&?Vc~m37aib z@lWFYh_Sl}GN0x3;8aI~Q`VknA{bE8e*8tSM7p zurX5$HT^cBYWz1=!$KGBTJb*4C43c&YX0}TWGmBJTu6B6Wm{@fT(Oo}gdeiM($$c+ z91q|X?D)Oi-Il#(^ZGRERq?n#*mJ=IKUzz5z^cSwk6JnZ#721HC+5Gd%NehS+<&dq z6rT{T`Liv>6>nIR%}1?(zhNuP`ip-VMb-2S>SC1gR|Y3$xM|n>!nZ>1b;O=nl6Vzw zTgJn172$7hGyf;CG4MBAP+nm-!VT_(+{d;Lw55T1%n zG0`KN*PT&o{d{bXdr=8w`p3FvBx+E4kL{^eRg5LL8ny7;#AcZ6iFIucR5}kMY_w#f z(Z3=0zT9WnpYXJ&A#VsZ@%{^WGjZrMS_H!{Y>EE(B{vd;m%Xw<_8GS$>f`&U6|rcX zu$$i>qB7owQ!!!OuzQ7M5q2URxyptLP(EJR-A*sY5rhw+TA*tDup2B(aVg=yP*25X zCJ5Ua9~E{j@c?zFQ$G-Pw`7ZOBjG=B6fTJl>-)Z5#$ec83yvU{^@vv@6n3vfY{Cgd zNDvOY*L0@&{)jW!pD$t9)75Yv6({)M0mX`V2J-ioX$d zHyQ(R3*ooYSd)K?TCmcl4ZA_y73;=jl%rc=-weB(+Mbw{coQ&-2HQe5vf>`?z+e4v zFhkg__4%S9_oa2Z8MfG{Lx5Dlwbs82Y{4HvUjm{W$*ZT_i7U4ly1m~az^D&Gp zW8)zk`q<3On6SI&OP@LH-gf&H^K!h^+hO;v)g)9GJ;8A}B8wF`kTvXHH_U?-*}n;k z;X~|&IkJV_w3~~XC9&CU@QusP=bu%Q-`TMXQ{)J{X>$fW3Y0Ww*t^aCWVyobiw93J zmhko5)?%6RP($KX!w=a1LEf-?{_q56vp<|K>|W_ymOt#C#3m_VmP4h}yFeuDUe(&f zj*0B}3-jZ!f?@ACZp3UjxR4FDrKkn!3HHQxg~RSTe-d>u%3dVwUIiPD8Y|oI96rF# zc(ACoK+a-e_ilLK2pd|nm!q0yRq?QU#qtjJAY7(I*xi<|!=r?ol?=P9WTsM<@KIdN z{>7!k?tO&VGG>CZcK&fJ&+($=Z1xPo%Y>I>8;lGsA9mO2%Q%o7DPqI!3q})gEaAs^ z0*6%yyZ3~vR}8y5qd1kq?s-5b9L({Dn2w5cuN-y@)|e_`_p2AFtJ(T+6H61XN_Cr- zBa!$KFLe!8rntNUTGN_tZ*2|`@gLM^O_>&q|;Zo{m28B^j*)OwMkg=M@1wGb`GRJgYV^FK2i7uXTP ze=!>4wX}p1qSpLEsQdcXsDgIIWH=F%;9?w)8!!es1*}ZCA*w+0Q5D;WI&W7i z=D+USPp~5=zCb0Ay|vZ6DC&tsL)4nx4_TVLk*ESs#f-QB)e>K!2HQzgyp?Uj?)k(f zREGOe>7PZ#|0%+TM)luV4zsnjF6fLJjLT6?b`|sEQ_O)m+xZ2<7{dKfgLJ09KTCVd zs3NKb>Z4ZLxu}YKjjBN8G#fS9xPlchO9$(lE|{M1Fw}Hh;D@(iUczTkUG)OfU{ptI zv5eT8a2eFf`3Wk+v#2Hd2C6IDbaDlVc-`1Y$c_Q11V^AUo``DNHU9oXs3tv)8kAR2 zUGoHWeyYyaq?u92i(ztXr>YcMwlHlu2E4OQ}gP$iD)VkSlP zWja(}=0X*q1Zo;r@vV(IuMukcwnh!Uj;QnAMfd;zj9^0x&99j8O#Cpi9s_ z?51ZHR07pdHEMy1-wBoB7*y9RLltNPsz5tYW92MrzQ01PBdL1W^v&Oc`TsUMDzHOM z(izo915h=XfJ$&7D&zHjcq^)__M-~$2WmZt?iqH^CDWneAM`zinl+bDE$j8NE-Tk7 zVtrGK9Xg=_YH+ml!(C7dPCxtxXQBGOX>Yq6cSXf7(8s!@H0rLoA~wK9sKIy-n_#f7 z<u!V`xN5Tp8d+W@Pf5G~c{Kt*cI=&Y$_dU7SjNV0XuDQ8%aaoy`B!Y^doH46_>NK{a7J-_fYiz7{nr z4x?J;CKkZ7!|jHnCTeugL`~BTsFwH!Kf`Y^FOK*y?EOrOZo>b_-^@{Nd8FMI zj~Qjpi0+_TBzCmf4RuYJfiZX-RnXs2qdV~!yJ;s~SM>T!AkE~@1qtbr|8{=BkdhrZZ;M7Z*|2nbkQhSOu7}Z3Fu|0mW z%;ssr<&0j|(gLX2Qhv4F%`U(!gug?z9g!`eE-Z{7d>#gN#OU0f= z*oa|A+4VNK+Tij}Tu&zRA92Pp{QGpH7L_mC~w^Kl^I9jLy}ci5hcHbD)}1DILY z|A%aR%Z`*s!g|i>ZKQTzu-5L^vc_Y0e5MS8?)5{p->Hj*|JcAu8T@c!E(Y6mvFGtg zfTwGOmqd{^SEtFO6O)wpe%M!p^m=i8XoQWtNhkydX0x8oVka+zdVBFZGHT18`Y|UN zv>>CCT2cPz!587YqMV_6{u&Ve zkjyhssGt9*1*enlan4_zi1trF&DV4CD^6@g!o0fbt>iB*3ACVuBZ-`V?bd7`@M{o5 z`1PYD8SsLq*UvA+R0?#>k5`lQ^jJvRHHdeew9XK2PFj4DkB8P@9!)uTk0#qhDN_*n z8QZlr82m>aTHpr~)}tA5|M4?eOFX?i7oSS3rVwfP<1>n06^=I}9VUtQoH!Hxb6;>Q zFRj6k<$4D==ZKzvHS;st?K zvyYF5xu09V%{E_f_TJ;X@&D6O`KWbm{&Yj4#{|-I^%p30$MZqbXDkPS#^F zgf!%0z;wbq z_N64VDWu0`!#y4l?&gmZ?bs4U{rCAhj*`JTi{~{W;_F8T64HZwyhd!NqOgm}{H|Y+ z%pCa5FR+WqKZ!_dxPLqu$EQ${&A5cWg>2uZK&#a?{`m9wtf9wOJ>6r4!7HQ8ZA!04 zZz8|)Yhin+p`U3+GAlwe^SQ$Rd*q{_ZT(O#($S->3eElx{mPXmz1R6$1WMeItx`lN zN#s9>@D3UGp@P>W zhO{{U?VPSN5pR#*uPw=JB8eBIi7F8J4g+r@nKtAv6B+AOGJWxcFH5>xY$e=|?VcQ; z&N)p;a59;G$G#S%`Hf#o#hb~o57;-t-#4FvZX#SYo?rhl44#QJ%?J{!{67QfKQh#Z zM=$XA11H=dp^;=(go5(d|C zwSQl1PN_E%p#p$Y`E#!*C$=CFJ+e^J%Ow5?A5(}y*paSylS1f`hXU%!LnGqs<9Is%ydK2)hV3so z_LX0W>tvLa7SbceKffH7r)ARdw^YY8{>l*0V+}hV5rOxl+yXj4Sf&OGW$e$iN$*U-FB0c@)&}Xyx zPi^_=tVP&J4KwnWl>XJDK8f(t4erAuS&66H^Djtj3;Qnn8SM7^`3M!#TP{Cv-VVP7 zruioH(>p`lT$=y+{U+?dNqyP5l>{661L_bb@t+oYRmhD0dCz@0@e>Msi8y6A_9N#s zrVts(EQZWBtA=bZqu_`9LQQ7hEk6%F%kF*4{)wb(Q4&^`Ssn zIsO$H3?r>2cF3zo+@JkIS7l$2v?DY8gJO}tU7Ca|6EQJ~yu#loNC`|pf<0);Nq%4I z!|SgfL;Y=@PFK@*7BzhAnDPDb4PG)Q@;@R6VU&$BwB&L*N--A9H90;v9Adk zZ}CqK`eQ=zp0lqUwfTeX7bAQhH`5{o`~nVA z|9?(mUCAs75$pS-bERLP4P>InN=jZ3D-h>b5}Hi{-;&u`zfe`#{*SnuITj>?r|vBK zCpB>!QOLHmL}t#fN*+IOUOnQu`M-+@3pw#azoxIx)&CXy2m5Qj-ht~0>rsycZ&JIE zUjXfUlMIq@PEHE@0plSJl?apBLiVNfYn+qwYWtOYPJtr<5_$bN=_k&&?7c_y({Dsx zMSspF;si2EOhPyO7J1CE`eay?%=F;2l@Ul zC427IA}57OK|=rfXZH6;wNjo&K~j<-ZxOf$|BZutBxN73Q+Urv{4sya$aofody{m# zQ{WKko%SoH6Sh&1Qyjm<`Th9)ac?4#^jPR;`a6;N-!i-|goktT2|MimT|zjD<4>qX zdop|Bw}uW@BH?=!hK~YxJ^i$_KN0EYB;ExI+1oG3UJ5XqxK|=X-2DIP_w4NZgcBFg zDg%kAM>-P!oP=K>Kl{Mf@VWf5|4YB{kBHZs1i$tRbeO{Fv48@vc3hq~q4V#w482FIg#0nnj}ZiIj(e@OdGxw4c~{P8#oT&%YT@a`RX1+iMxh^b#gO;`t#wH|9kA> zL#Zc-GspW?p?}3>J>+v;lQgL2-3iW`R*CydbWW2`Dke~hV+H$Nm zt+kf(7WxIOLi*j@`)?$|PyTyVIiVvFMpN4F&>qmWc4e2#!$11jOlg5vJrmy4hVySnMbX@;0i^&4Pns?p5&55!-Gk4f zc=P^0@ivmdak^*$H5^2&&4k<2G6``2nJ(gw|EYoBg=fhoLtdrv))8(*9KOHk@^^{9 z_dnf`f?8$ggcTHEDH-xVCwPOYaRHj_Z}z=KBCm*}hkn`M^`jvL*+rn1-)hq+R2lZw z@FOhq^GM-aIx+cwMoD>b+nY$@y(uC8+kzJ+{5uIhAhQY_*P{gcuMy`E1&b!po^0PB zgTc6h_$eqTFOvPg9w#WsFbb}h@)G+6okEybcD>HzHJbl_*gg2)v%Mqy@pV7%TO#lu z7<=)^yqZ7A^om$xx+&<_x<7@9BIDu2>B!&fM;;3MmLEs^){>SUy~w;UX{9F9xfEWH z6BHtnkP?1J0w18hubYsJhmi2^WY&t>9V3A+Nia;oN^&ejxCkeX=6F6!#~V*!=J0oh zbbjPG|Gk6vlC7)I>u;~*SOdR>5)-#28R;>MzxPPD6ILTmIql?ejySI$`6$@Gdj793 zjASJ66pLfV|LMcp6lf0nUO&21yLo=*Y03B^iR&?mb7s>@J^W+Z_kxP(k()Ss{cVNk zk;VmW@E8@LHhQEW(rhwn!(T5-xs=*ZqCi*GoFw`#`Z;$Q#7XhKot$AuXfFAMB)?CVR0 z@#&&pi8Gn=`m%2?=@q~eeq~R^rT?drSYZmVl}Pz0S$Y086F&PtefcIOug?BeBs$XH zU)S%`EqUq50=2-;h@*lWT)$ z?9*cl2~H-%-hOY~B9q=UPI|u)hEV7q*vAKRy_z&qavHN4=kMchG--6>{ONiT{9{g- zOCtNoaIv4*bRw^$7J6*tuM+!*lK3S~%0bKUIcKjYi7q0s&)D9NdX(e5lN7iXe|I>( zfc*tYXCUYOKV6*#SXJB8#y2U7-7VOPN*ExD-H3|aEw&TGC6x#X%Qz@3UR*p1HfO>eDSA5z;bP99^&qi)0A3X@`vCu0NqJS zOVV0YiJiumjjl^j{H;F!`xL(l$yGW?AXW$57Vsy@dqHeJt33DC#B!-1`4T~~niO+U zZr%yZI0t70erx|Nxn##F)&XD$Bb9IAZ%;SN*%zRAFak|`MS)k4HAmcBC4CBx{|_@Z zaOa0B83`=YN|Woz1Xdy{JGC;i5)-c|{|GKt4aX^xHzFbvdlnMf&{a3~g2daic~mGy~ua`;=bFT|f;z6kb#ol^M<>T23i zTM9kV0<%eIpd(#?e*%~gI`S4#5HF;V8)EqndSff+_Hbt4J`_v~@Vp12@m9Gi!zEv2 zAH-Di$Zvw3P$Kr2HP(9KPgWGz4oLnRPize&r6?peTAm+bnv(Yp+#4lM#^b81oeQo8 z;!Jx1GHC8Sq_3XbK2SYmL7#m==f}4=$Rn zd?DV%UJo9=INPYq1R}_jKj~NC9>iVj8|y4NJLU6VjGyRcxIkuFdVsIE4AB?maqf-j zW*9#CIs~yb5bj4<6srdLPE2DOlc+*5`S0O|?59{B2ra?%spUtR$A97#1 zs82xbBZN0lR}ZpQbaI#d0=w8X{BM|oBfeBRjWgiIE^#jkj&}yM8b2}2cn@Bzo<533 zG}#UzA9NDd{>!0!FOR?h&{zUJHRwu_EBa{Kvu~$BAxO(num#;;X20`qC%lfxOH59F z3c6@sJjGg(lL#DNh;OyEUNhvzgIz}qGDX3y>2qr-BIPzaHiIti+3NbCYJFy2@eLVlRB-UVcBjFjuDNVJI z&SokHNeHA;VPduMd4cVSxK@zF;M=E<;4z~v#yuN;FP3Tf@Y|aU{1vGc0`Fn-_i+L6 zJ}5?8o|OX$``D9nzlgs!olmA{K@#S3-b`#3t0=f}6yohkj5PSgejsc$qT}#4!`~Z! zX9_;&eom+G1l(aOn&)4I&bE=n+s+#2DXUp|Y4oB-Gca+)ym=E&-uBUo zw|W4!rHXSibrAxXKyJz|#lb@<>S{1l{s(_z5$t?sURivgHPBeK` zCMLiBIibphNO|`31lB|H8{$>?mYZZ083XnYzDAIxfxNaB?hbwpWdG281o45|&_eJ} z;gK&JieY)fpONO8A-*2X%x0JR#uqLdwUFFbb6*PCRf=pC2lkr+!6X!7FN*)9PQVuB zFV7qj;MlH@?s5!f#)Q?Jna3z^g~Dz?qd;_KvA*WOk)cCNBAbJ zf9)p8jYud*LOFtB4fMI~f?VFn#uJPuzA$j}A*_k0CEyDa6RS;LMa~Ieu5jnQRE=_o zeuyuWqA65>6)YcOJc>9tTR(`BV`$FBz*Hbiqrfe*9(VWi^>&D82 zkM9jL(#jbbo!Ji)f5OUXH#gz!19mHG6SxmZorFwFYI<^lU{q>Msh=h-6Ll*xF_J&!jm7KykO?iOf2);LP4=U;KZEC^VE5ilb@74 z6Ofn}NjD(L1i;=RDLMmxdk7j(;IR@3#s^XDb!ui#u;%{-R}rTlQ>7nAtj$l!D^^H0#Q!R1?6W|wW z2TAaKKzu0vbC8z+caeA^9q~=#$q>Q!30m!tZL@ytN9}(<6OuBT)Hq&}yb6-;+L?*p zz+pA<>=au^+yK`RktxYb#rj0?YQ*LLK=x`Ql3Nv=SY5D9$Th7rf*#551orlck%ZZS zQjoNrM^am#aW^`tuY?JRD9(t*4(fOxYAiDxBei3RZ%5d9@LlC%XEEmU--dH6svY%t z2_^>e<$AwISB*8X9z>CJTOHD|#LM#H8jgSm+-D;oE7(-*p5W54PeDuwv4^ZErn;AS zDbCl3zmczv+Rn4Oj#DhFcF+u93Oe9R^^AUy?*Vf+Sxl-T4r%`Vb>k2C28i4N#+e> zCxZJB`+;LRVvp$y?f?WU@MU2|=wpk3u$mS>rMT2I)t|g}S_~?y{iIlPa(BX0iQ#kw z*H_N?#Llz7kbg#VM!AcqXNmcuusaE2z3E6SFR!1jDk6sxM1q?~(Vi3!S5dK?Z>TWI zTg<&OMRVed)hBWgo~z1HQT`b{@Lso!3<|@ z)W@BRZrdYvFGa%13DE-iR2XSid&RvxHHyGJlJ!vj1lfqr<)707QFa+;SBS+{FtP=# z;+#8Ev^!^iCLy0|4LDzc>@Z}hDW0H{%8JlpV8x=e<0J4V)#=>@KLBwRsoR^lr9312 zPSAnjI@d?+@FqHig-kN98ire)K|(vn9gRsc~w3$S_r3=gbO za8p>v>Fz52$=dNm&6C`&gBPqQR~wr!Tec z5*Krk-#4ZL8p-7Zqsjqj5K4Oi%nhj@z!BPoJHC@(2D8%Ijdh*I4sA8jZ8F8KMZ4{(2BZzo?y z)l;8GZaVt{!5~D4<%e)EB)n&Y@s)(J6s^zmov6ZWD5ik_DMcoOe@(78;)m!YA0xOZ zt3JFT)bV3^)8Jt^Qd_6N=YLg{xIt0|g3=U-fMgj2X;{2hsFCPD1rxaMqToC5Vu_hf zECrg7=Zvo_1>fNx&7`u!v4_VXR*Oc`an1whY%o@nU(3a2+qQo{4%Mm14~KJuXbMGR zP`ro2krWBlDMe7YC`HOaTpaN~z}8|fXzh+aOVV6Cg>R7Gm9to91e^fZi9AaHg$CIC zMg{`06es}MQ}r!EX$p!xpvxN+yAQr9Z7~!W!hm5d8h< z?kD)#8tYAsc!cjHzK=#aTfsX28Fbx^g1-P|WF;s0I7J#zSnMH*&G7XiaSZX*z<;qFjZsYJn&$77e_UMwVF!qI(aFE2Q&>#V@jAB0 zoW=eDyFt$%C{hcdffPyuX=(CYDKHJLsql*3!uMVaKA~PyVl&|=53eNwfHOf)RBzX! zlGK`Ddb+3c?bl)W|G{X@Jg@rl}@IUI(yP zMmxedrm%s;(G;tQfHNYRA{P8&m*_Z&3OWE!8_pGoc~YY!y9f7WoW)kbZ+-nA!g12( zGq&+O4=I7VcvD&1=`w^b!4~CS2%H~X6j1DW{O^f(W;$YC`nvc?k+KL4)S|Nx+(sJ% zW-(@v^hnj80F<5%vTz@#McwJ%hon)U+bijP3NPg@Z#46WNr=tUy&$>nD(WwVMlhXf za5V&T6#fx#jDk<>r2P4BIhV&IJ zeuFQ>ZdyTooc`n&pvgnjSxa-sX( zEYm)a*El8p4*~cB_3I#U*75Wwv59uEo@BAgU|e-VTPe1lJYRfbtu?PCqi)A&FOsv7 z0#hltm&f)@;{o8?)2L}HEhMbL(TjphApEOAFD1^+_$os14uVi6NyKC-!|;a!V$)ee z!OM{L!y)DhHW%kAVACPGBRtch~fo!QTaO|JQX-M_L1^7 z2A@gH!A0yLMDmsG9st_mPlm9|sQm`fWk~BXA=5mxvtLXhjP-?Fd)o$QC7Q@&m-Cjc zGmtj`POHiM7g6vWfj#OQs2$67J|a#bq96r+fD!Y7G#N|Gf&CW3uGkehLE%`iw^Y!2 z-7kZ8gzpag8(HPSSnkl7x0Q8KP&5FJJNQp&-WFoj<$n-L;8?2T$O^C_1(!hh1G4OhTMdyptt`~v zPJB8=$}knv#xcQ$+*^QOq0_6QLg$zu-6!g#9)k^#-~VUfxJ{Bj`$W_RL2g1p(0qqK4xOBAx(e6N>sV z)xNAHoU7Y42aRDl%7^C=iGeYqv=h1ShNukAJott{SQo<5V0TieKl^;*dmz1}IbXOh zq|-@YM-gvfSL_u6O{=8!Hprj=*(U z(d{S1U81`c6f>B`2)G8(93H`Ga!mUPQ4;d~DBcWFdD$nC_fUE6a&OBLyR5z?)5nY;KS~^*v6B2A%UW6AZQVmRTuv0lN0-Ik1 zvaf=3o2?0pF`98+(^35ZAa@Beur6T6{+?f3=)Sg3c26}76B6Tco% zIG%zI?9;Sx6^-xU@kDcOM{Ee#--vj|gi5gwfiD~9O>h?mbAyRle)8cDUF4u+Cw-xm zCvk#`dJEA*I+~<~M1WW!2<7cn2C-^@sY~H*dk)&y}|+ zdu#die<#I15C{Rhl4MsEkq$w9^hGtEeFI~!O$SjF+)M{zqnH$La%!X{z8+sO9l69d zgE#Gj77fshi2!`ugWzG;kyZw1w3M5s$cE=J|*X1pMNPt@3xD9!B#^_06Rg_O9R)bD`cs$c|BC|+} z)dF?EH>Yq@NH$oZD4<_@1PB!v*c&7|wDNSU6%ZZ#b2&jrsu|II#09T)T zAviA(@2mpW$yX3;18@NWi6O|#Izw;|pjUurLwtxmJMmi-G_5*C#iCi$z(lL4z4$w; z=(@W56OY2*kvh+`u;gw)>~Z;j@gc*b(PYq1kk#=h*w}qj|4Wk*{18v%daPl8_ma!J7D0#cVT$=>CTIU#1~8hpuvg z+ra)_^8z7v;9eE{IE1HC@q)hwzt|ue$br8o)3{@O8#A2sAb3qjxfCS8Mu7I&-Njc1 z+y#nGQGrFZi+^~&g&<7Cr)PET(1WfIl4Ifij@UdVaFpE(0gK>i$v)5g{Ey-y_L=Si zD7v5L`HuY%1rAWG2_3yb;BCbnfan)Rk05eA@py{t)5&Zj_ZkIOvu8j=dlf7EwRMsS z`g-|bK8MmI&wx;@tX)DwI{HjeSBi^GrQig}dqD68aW9FjAvf+nlgh@uFt~Qaj)A>P z{&hQE;c{Xk*5^Nw!mCwTZ$OU#52eGekmQ9VBhOSUnG$s3{y+=9Lclsii4CF9cve<& zu2c9CyxUo$z~p8*D$a)HFD*%_-%?+tLrE+K=o`f=plk==KKLe4=r)~xW;M{vIgI-c zMP48}H~1q6s!zNLKCui4UCZ6HobYx*NFSQI18=a#_R66uPZ9KvV zRxG|6?Ae*p2OG{}B+(aDG|7<^GwmLSIuw|w#Tp^*wRU1+;t_ZPUv_YF5aFiSMUZ>z zWH!?2QetA6m`W%DI+C}8`(OFGkw-j}DUdtbDKCMj=BN)qX)zL}>0|haKf8|B%E*T> z73E>)--VD;G;;`!V1(S~oKrc9Q>zr5-`V%e`~x_Mx!JvVev zJCN6cSaFE=a&CjTH|(pxj)AZ<_?*hIiE|xrVuQ#(4KAAstWMF2c2o9~Z=)SSp?KC^ zR%#Neq4YI-T1a-0FqSSOQCx?3db?x?oz@-VBV?S!uF>sqaKp(fM1Di|-8zA+ni~T5 zQW{8$@EY>@znKoRaCr++0Rm!4lzgdnCBA9k&Vmt3#eRg&icq8v-F4=?k^L=2CJ~Q8 zL}u_6n63xnIx6pc1c`M7mkfLZ3x)i2Jhl+O{sTUM%H*sjGCmEgQ4+Z}#NQm^3_9xf z+Fd%`d*hD)e-Yenea%Q-cBYXJe;3YG$hWLxv=enie-Uy;JMO``3M9p}<3Rk!Nm@XX z*iHN;nc8m1GEm?dtE#@jz47g&(_CO?(Zn@!v(Tug3Mt8S7P7j^@BdvO$w-3OA%H>L ze^7iRiDFw-kURHbifhREt`_@;F^hRo;4=mDah85gQ=kMqb=g~RPfhGSYdaHq0#99h z)?fc>(@_&8i^Nrjk%=wVUCxcQNJEkzvI6zqR62!p2lsF~uFOhCm+9p7qxlu}5iQ4` z9%Ypfe~_H-GQWR3b3n6CwL z&+EA`z%}GGgXai2C-e~rpIA(Edk1GrC#pW7ng>iL$Xp0(0(Y@6GHTk6h8Ob`3qoxf zu#NPEvjt2y?jJQSn3Sj}WjDfbe9IWmR+drD{|c@u_$r+5>Nu0>9%UU9zX;5S zz@I`p>1Ypy^0E9O@Suwm6croCY6DpdlE&b7(C)(M$Qg36neap^`AVLnBSPlGxl{!; z)tu7YFTvX%jF3=S}4FLzFK+#xv@{(wVg!Rw_EGDk<-XaOUkP>sFf9`aY0V4!C=wD7 zw1k4Wb(Rvo#ry_AFcf?xVqO$jg}_|IP7?dA^FBq~-nKA`F)Cn(RjB+}Jh za~aPm9zcTFRf=yUu`h8q?Y@gXr`dA}&Q4NOr4{bsEtZgGd8DoM*o@Ps59pf|vtklLF}Z4I4&2A7!}(^ha7ThDrr zs0w;-%ASV?3V@veXSm&C7W_He#4W}*Mln)@z9bb?f>em;D=$Xr5CXA08k2Kf#EKQe z_nlP&9_8i0Tl zI$DXhgzyLJ0!6i#t|ksj>5gj$p(2t&b7d-C+E37p1OeZk?%&)Rh;uPtrqZF zVkz2B30taaQSOev8eLxCywq+glOZ+qJ{#d(G$%8KZmXi_Kss`dVJ``$16*ei7f+pW zi1@=E!k$jP5}+i{xB-NfP+l8#g-8;MrmKe}?k8~-Maz@)Kmzz`6APz}x}AG#Owg?B0(0}(h+U+~f3j>+eLF90`CHXo2_ju7pJ zWEW!Anojl=n(RsPQ$(NTF14KWku;~%!z$JSXMpC8$M+9nUg$j#;l(&xUZ~P*5cO4( z!uTBMyeFWh_j5ATlwc*Aj0_;Y0{}u9JyGcw=(=fN2eWHv;yP zD;A_v<;V}zVgg?wc#X3eB$e=Xf~c2*3KE;gvlT0Vi1b>ZC8MlLfurEA;oq&8VHBJR zr&x7usFB7(5zqzhN#MiamHNgB2$G^UKhE=qtwqbQF1B#1AvZZfj( zkR+!gvF9XJ1?x+JNBAA+UTiD=kt*zw&1H-y|2hSasz`Mk`SmrH5}vK(SZ<=MAYE2M z%~FWk$}?sy#g~TtEC~%M7NH`9D2H~E6@i;LCkL}ki7yeK3eRA~^`Jm0eO!AqNAfQb z+XLTR`RQc?7)NVFRHCc7IBQYt1;oy*mc%L%6Uz$0T0}X3xvmov{|ZEY!{3qVebFh1 zUo1D+?d(Mm^bIZ-xW(o&l_+vf$-e{*Bk&D!XGnbzAyy3ENmagnnr8YC6vUIcMH zv}3`q!}pqEVwLb0SAl`>lvi9HFgXx-1g=tuz5~}L`AV=3B$fq~8kJ%#NM68Ri7`1K z%tyQGLPA{%SHNG0Ray&Llk`Jr{9-fVt4#yxRCr2+xGDYv`(+hnIZe@pkUHXcg(}m^ zQFI_=br8^scma~~LN=E!Osj|Q8mp^5BJr0br=pTqVE;~Rvx-;=wjJlu)=xbvi^Yhc zz-Y|DAgnpYxK8Eg*0o5ua>Vqpbo09;V;39E y-|;S0?P!_}afxp>#P!E}SC4^F5#0vIqzq3KG;_gn7;#Lms?(R-0uEnirfda(~6qjNTTA)1N z-`@NF-|PC!%Ka`b_g*c3ltXRO;h$l1?F4&f^5L;40eMKDvpAm=Hz!tb$K{~%{1 zF2)*;6L2yN2y%MS&>L&xQ`7}Z3=DG0<2uv_Ut<$2GbqSui%W1hHw^tL$nojC!9h+j z+<=V5d5Vegi)VsBkP|{ZGxoron40@LODSZc;Q;DFk1#Vn#aNhdh#gOZs#ie8rZ$$r zx>yM3VmbT+)!}4Abpyxggt>4G#=~70i6=1`_jkTh$bm_Q1v%egSj9KwlR1Q7Fp_pe>kkbXXjtUAm6(~fE4sz6y zj;IUG!I-!i6_LHDxx0Ze@GhpqXQ+_I9TVh)VmPY9nY?;AREMjgJ22GsCwQ(L!yIem z`)SbJKE~Mi7Ind(u{QGPn2>sEOn`Y%Auo#>VG|6;(byf=;2cao&d%S0U8x`Q>iNb8 zIoYUJ2vAVSdZMy*B8KB~%#BA;$@vbe2ho8EHj*DEn!~Xm$LHY``~$r>x=ra9WVHmGlrw^y4jgESi|`cwjU8uNd(~M%&ME5KQ8_VW zwmBX(6|+zgT#Iq=2x|RbKy~;YM&UZoKKfLb++Q0x6PD%n1JCYl%IWTc)0(_kG;q4nR3f<`hKwc{`S2y`hUpjB2rFVV>P=BMY>OJuV00sdS|w|}`X1COIg0_!(KGLa zI14T7zr#YbXFy%J87d;}P$L|KT25qvZ&p$@(6Yo(SNW9oWoCc#)FNvDMie9}l z>UzBv2W(`+y@t7{BwK^wxD|EbOP>Ej?GFi-1UZ8-4QiP!LhT<%P!TOyvbv||RMd4hVheQE201&RC29(itqXGAlYdTS3c)l){cJZbhnnNMsN`#ficEi0 zhbDT*m!Ve4MpQ05_S)NT2y#wx!Ct8Sqr_(Wd>d49_d`WuI)-ab=2Fny?ZKvaA2q_# zTP#%7Q0w|fRQourj5F~Z-oc8vX)7HJV!7c}>S5dMx{t68_4qq1l6_DS7=wYv6!uWi z@<_7NHlV_|miiFPfmwH12O6Lv@gph+Mq(&#z%sZE^WjI_i8*%L*82eaP|vi--h38e zDe8ahA^rs@B>XkVDT$RaBO@4xN}|nsZNs^a?WsrGXIpMJ%uRhh>c(fV3dY;-J&sXX zJ{n8l4pcI~Lrp>G0h`(gz4H~Pp%4v|u@9co2?uQ%UOM2QCsT=R3zdavIwL@ zE!(W9{U9Ie{D!FH?S$Hh2B8Kv(yRXxpztpZJ5h7I<*xy3kc>pv5&r(OWN;NPg+sref(E;tw!$+M`)Tr~sE6AIe-{zWa9&=VHQ?5KxM z0n~`AqRy*}T0SjN9c_;a@gP(ZPr@y@8E0XellJ2A8M{)SeJaSgjiINNL#)4t6tt5i zJ!3b{h`Ld3uU-uGST66?C!%gR8}+%hsPlJu?MG1^`_rpG^ZbfBKkivO{vD>$`j4bg z1#6;4wg8n2%TPD^6}2OtMNQEyR0uy}R#r=l-`Q$0-?<>C676ly2RXmuFIW{jUEr%3 z?!<@K=MP&YO)s+k6|ylDlw9jk$#M#n)l2~>xlpmxfasOyAY zws*)3n3Z~O)b*C2A9ta0Xy0Ylzmo3)4a(yCs2e2x)21RVKBAr-6}m)MEa}qW5b9A_ z0S}|5Am-H|rvZ^jg8YA{+cnFbiZ|?f-=l8a7weUV_00sZDr(|W+KF|p@kY1?B1W=Kkg&A=LX2a7upqI)ISO*i{ zwhg5NDwN$&7o3C&;T+Vm+Jx%ZU#QQgykpC>AbwB14r*szg(dM8M#I#1Epi!95e=;J z3foaPIEsbwCTgTf{cR~$Gj>O1_gq|#M^Pc} z@YEfd(;bxq(@;~g5H;s7Q9EkNXF<*{TK|P8=)^~;_5B9RVVvjoBb3^x0sV$rr*~1ybFsIBxo zDq{Ch>pr>9=Y(TNRML$@-Dm+SGAmFW+K9KfzjK^|Mz|u_=YCPxgsMMBb?77NLScTN zo9*GK8|Ox?g0iTj9gPJT*;4FJ{c4EM{fS7eP@kIv_plG`>7vC#HSwC~9@RM`eACSQf$bsEFjm zm|Fh@D3r%2)CMyK)8G=+i3d>^I)U1=Z=lxwQ?LFnYHN)V+ai+!)$yEI09#;YoQ;~& zgIEGjVnA~dJ&qkngWBmbqvpCSDvPV5I?@|;!Jkka*@l{mBd7~sLG2@VPy_i7)v+XD zK6j_ggt@8L!csUq%olJ&c9e!(G`vD>FyV1+1cfn@dS_H}Eyim25_O~E@qA7MHby1s zPZ)wrQ5{~5O4g02ocbL@@j9x5cjE;tc|Lg!3FBJ_vY~RKENX+eO=tkF3A9#wo;781gA&G6{$c^f8 zQPlYrQ0Le8>TOXY?~UrnBvh!Ec=fHQ2p&Uy{!es&{`b&3;a}7ZVkfZ^lcAC)3u;O# zqAuJV6~Z4;9UbL49W}xwsN~v+y5VoAjqEBa5-(8qiIvpnWYPLhNT{>i9U*F}9%3epp4{iY`Q%1Lwl2Ese~5QrHfm&h zQ6sp33h@)vbNmBpgsD^boVu7DmAu1Ht6&x?G0q)BZbEcTu4*-cP$x&U>d?U)a*qCy%cjZIBDRJ{mlBdY1y5Y_QkSP;jc zyQ888cp^=}=JXB?8p#{fQz|svHj4PD5hwG^g!*6sRL82La-u!zbNx}FAAyS83{=OK zq0ZlhT4fioI6ez_4Ot?r17%QCP#+blA5hD0KGw&bSP|oh4hT)eN>0OpyoPTMmydD73zMd>>r0GaW>Y* zmYJ+0+p#6}3s?dpGh0V{paw7!BXK{*(DVNdg)kbvpyn)A7N4^ilVfw-jd@hh>T`cX zQU&$SHxxDJqfilPsEQ1?R52e?r8z#y&Pod5cmVZ*JE*6aKfB#H zCYGaK3^m8YP|33Z6{+i}r(uj7_C}NmH8q`31NzBxJSu{7z503#XgTbrpk;H&J8%j$ zqN}K^y^s3fS5z*<&B<~MVk^eP*esXNUBZMj_c=qc66VFz zsEz7BEP@dQY|fit7V6_rNxcn~D^CIxH1bcV5yUHKJuQfZsaM6KI0`jIhf&MwH0p*o zQ4xt-$lBAPR!2Tmvvi&$jZ6txkLz-Am@ zh`QkyRLA2LGc$RXK!vt0YF}uHir`PEj*Z01I1S5d{okTcl7{rfEvwt0yJez!zRRnh zLWTa0SO0{O)Z>=0+$e*Z^R}p*=!UxCPpFQL!w$F<7hueiKE6w`{#H}aT>DB{h-08W zm;kjL)1Yo#1{Jy{s43`!8sTWKeK~55_o0^KBhkz_=Wx^xI{|h63a|Yp2Gqj` z6qGEn%KF?djY&|;rVJ{i-B8)zA2sp`sE8~?-Dn3c!UL#CHY;aI+!od00oV{{U^Q~< z1rEVt6u0DY9}m*n)*N^3JTE>RLGW~9xhwG6JBFh>Pc%^k4s|# z>VvS7&O=4yD=JBo*0%K?iJHQqxB)9+1^j@zPsuv&KmtxJ3K?l=iHg7&)CU(}IIhD| zcp5dL*mW&A)1yXE6E*TasGJyz+G3}pa^i$nzlIuUSUo#GC&tnGFYGl`KrOdgs12i) zSMQJN*jUen-to=e@e`921cPJwy@%8RqHhS&ZG^K*aa8wDjz{s#6uZ;P6v z8J=rV8_Isv#&Hw1(fAwM=W?QQpqb}rd`5i}*2V>mwA1nJ8r6|1jeYJfxjJA#>o~HB z_pm|D;V3MN%TROm2utI?SRacw<;}>)OD0yN{*H>0vP26TKsBsMeGswK$-1uEoXJxGU>l+5Wk!B~{^W_QRvLID#AAMn$5{kLFrb zBwnCiF7x!T=X`gpOMN|##h{)(r!kJl7WfFeV8vcOXAthdsu&sQ?Q?&#IRur>k5Ly2 z>tms9gJ-C3zMNnmisGe zzc_(>p>Y00EyvfM(MH-0Q=`^@PArPmF+}Ts9EJ5XOhH|+*eH9UsD#<5cSda}voQ+K zU^xsMZRgcNZP9&D8`(PSfEQ5vMv*a=wAC>$^;xI^oWwj@|BonyV)C(eLO4dJUK=&y zCa92g#b+2my;5}^XZu7?jG#US^|^JZ8*fD|-`~9Yb+7&c7t$Uyp7pPdXE6n3^*Jnn z2`1PUSqT-gI;fqo7itS0fw6Fb*S-dI!(E16oDSt6t|;#oN%(;I0Y&fvY|RuAJvf`Q6UbX=6)LLbGuRB5f7qr>X_#r zp0`mQdae(qr{J4nNsTakD1yDB{h1ybQpyvJoDun-FIQpjAV>%tGy*et(TcaYm z7?m5lP?0)>O2WVy3R-SYQ5O!K=5v1;9fsSeH^Su@ce-W$R%}516Y2uBX4tCe?zsgw z(*70|>J>BX*{}n@r+y6ku|Fi8#oI5xe{!bG_BlN{aB_}qM8)S?eJK{AJ@GuB`zMvv zQ5Qady|LST+W{Y-a-qrs8)02k1e#$f?1>8XHmr)LQ0FIIs3~IoMNm+-W<(u`LS=Uq z)M}`Yy1*pV)T}^7Y8z_#?!|B{w#cTeDe8C|R1*GxT17)Vm!Ph95L4>{e|imXQF9e@ zu}w)jRESHWlB+3(;|Pqvm8fk04b}07sAtG4)Ep;SV#gz}6!lVA4Tqv0Lgz3rhCb^Lv^eL>LJt~Yv2mh_1>aF{RMTs z1S>7V5vYz8SsAbcRcOdeLnBOu!%-nxf_na^US%C=g|mbB?uMG%IBP7~B2e`Ls2r(` z?)L^%2m7N|!w}Ssr=dEuJU}5gg)OMLzK0rd&|1spM5qy@Ms2;3s2fy4jj*w2Yg7k1 zqq0AM`rHiE`Rh{Fq{s&*_LYv4+P?!b9@zBMp|bZRYB@gk+I>5$BPmf4s*Xy!CaCq@9X03UQ5{=^dTMUNet1XiKHdd)+LUzL z&HAszfdRX11V>Tt`9XVp?%!~Q{c0CFgzE7XRC1==%Lug$F(b~~$DHD!{r0n@-wycP z9WUBJdstP((R^+xDzaG)nLi$4{p*6eX&8VB58K=BBrHVzUwn^|M|{pb%zD)4?82~P zKIa7fh6`}YaeKPu_|4}`r5?bvbSVA_pZkXj`A+(rVYL5@^)S~dn~G5Z3MFYcjmm{s zr+v;99FJOVt&srS z^QU1W+ArX7%>IYZ{cE_u|0rysq18nTRpLvQj9pP954mhV1^vNOIV+} z@2Y*3YJ^Lu|BK3j`PXcf{DPUNA4KKWV~mbL*WH{8I58<`i%fyq(<8ikHq;05di5%( zbzBQ|fu>jr+o6`*YCMZuF$EnQdcz{I;HG^8ihawL@pR0|Mz925Ddy+y+SBUb-?j?= zMs3A!P&bTs&pMV8i%`#i8c_=@h+|Oa9YkgOY3zp|P^+W+eOpZ;xB z0Pe;o*#D*doS^k9d!NYt+LEm$*5ddi)YRU^=2+>CT{p0nLL?2*{^xTBVo_8U??ffZ zJ=C&%iL4su6K2K#(1%&x+VSkDNESd%VRsD2!Kk@kjGDT`sDb{8L@?kyr=XC;d}kv} ziNVw}qC%7vl^exT`$R+34O(C{?25|zKB(0&9F>goP)WT6b^cn^jdyyUMfdmr_b6yC zKcIS=_`P+c5NhOQP{*sG)_Z4E5-mqv_%P~S?mTMFZ=;s)Ta3W?AMAROo+VJZR0-Yp z|Be(g&@dX+feomQ;yk9quc!?p;-kG_lt;C9L$yyw?GL-W_KO%!{e#z@?2|<*5*6v9 zs2r<`0rjv61zlh;DvRfO_06c!tAzLh6c@H15}c<_v$}+^$DmXTZV0MBkDqlN!1yc z1r^f$m>GY^Joo|Ckt{*M?jNJ&K@I3IYRZ2LP|!~G4{8Ss^#!|G9*)Z5OsEg!KrOqx z7>-R*%XBd6#_O;u?m?}VXu-kmhL#TdP;Z91{$ME3`~BdLVCVN=u%Tcdj3 z0TrR{sO2;g)$>WH{b3twbsR)R=r7bVedhVbYyX70UTBCN4?|W7KmVbSo&$MNQ&1m$ z*bX(aj-LHdHyDeRa2BcqcTiLI+&k_I4R+sj;^GS0JE0y%aiiJ5#-Tnp858UIKc9lu z@n%%^A3%lZ3My${;U=6EJ=lG9DjCB<8yeF-7llgB8mO(dE2^W1P|NLi)P8Uq6~Qm4 zRS*)30djvQ0|kvBKPm!MP#R4y2kNq(xUO;8N6WgXHChFOc2KD)@sAXFi)v+$9 zRWkug;bJU=cQBx*Uh+8BvpT2~o1!An9d&`RsE(}h+IOHvbPhH5&rvxMGt45G88`39KPh-Wmk)}n3z9fcYSImc# zz2iqQ3-!CGk;Y13t0_5ZhfRa(XcX!?RlWMa0EL1yj6yBH{iu!QsCU9uRJPtjCC^K* z{t?w-e?nXDiBOTtjk-~B)OxRo8c-`#M0=sGKLI;pUIDD`$?_DZe#*ZdkVVXSk#FN?0~Zg zGgJQqgM)bI!)(;QC9x4@OKOoRj+)C#sED*dM)mcC#Tvkhtr7GpcynuhhSIZ6?3AxVqBP|u4q@h)z`z7f`;tZ8k|BQb*ZlBkWSC1%3G zsE)5f<a?}kEpqAw=)LcJ8T`xs;+oHRorfdc(nFAXs zXpY`{4JC5eelQZ1T)(3_cmoycC#We4&1uORhB~h}YF$@Go!8u}4??Z3si>S;kD9uD z)*f(fQ_u}QVJVE3%SK)imA&;*N!QeC?}>`UFnov8P&?b0+_q&eLDhGnn}nz-PL(Iv z{XN4t%o@ZO7@Vy2pCvNbnZ^mbQ6sCG&u&-;m93pnp&pEyqJ^lb*@5cdF;vJ;qXu#r zwfyd(BJ&t^{yWrp{`^)C!w~N8q^6+Iq(faGKk7zhFdUnpM*I`%yop#D7h_3$ikj=J z1uR#ZqRwxJx^W*=L`I@^#)V${Q4Hju;UWdSj|UaB5N1HlSus>{)k7_-9-ad+iuwre z_;FMY{f*iQvlg-r)J8?1H7c^*Q3LFU%KlM>SpUlAX*4L*%TYVkPSgnAp++21*i4EV zaTd&j9X;oxE_fER;Wey_Aw_H|8{MhTDp={xw(ii`kai1S6@pM_q6} z_Q%z@10#wDyFaSEib}3-B`l}OU*2}W#;DNk#R8b1g4HXbHjKrn$UHJ2J4GFG&X=0Yvk>ZlI2 zK}~57)KqUmP4yu&;9RDlIevmU@iQvvvR1P8@~Bs_2B@8@8aP@jzI z$Y#ufzoE{5jk;0Hsi)3sF8QYYB(4bsWYf#yyP9fg_`q!P`MDRmVG`a>b#=0SpO=Nr9mUC zhI+5>fa<_P%!+$46Fx$%f5SnhKj^Q z)Vg2q)dR=8hI?MaS5(%gY+w;6ii%JpRIao}t^Z!AWjX{K;sOlC_o(OpSJX&TH01Ri zGouEU9W`YIkSPo}BPi%XGf=Bw6Y2sdQ6G4SS}w0pbN(I`nb1ad!{n$Jk8o56^P`qy zd9U6C^|>xM7k@%cani=Y{Dy_~SCxW#x*c_aBd8l(LWTAbhU0tG942jI7s!Q`sJFp# z_zRZAw^$VOHMP~y9TmYDr~xiSE%P0iUF-h@1!eC$)Lef>btF+UOUev5fqE%ijAwBf zc4;2${#jkT7WUG59QC=(EiE#IQBze46``uAq-%*FMT7EIpCUa!j_|Js6+w6&dor;X*#V^k!gwY3|kKt(hs>LFLWE$d%d+L{LS za2Bcq>oEe4pdKC%P$5j$&d$q@+9#q=%d87V;yl#G^E)=fci0%~w6~3C6S^bsU>zLR zf%UKCTS|jQx({{ZW2g>2Lfz;KDk(E}v=5f^Y=fI=AC8kSeRDT_-UIhhAA#yf=^v~E^-&$|g_@Et^Wn6IlhL9>_4bb zhj+1@D36L{HPq(=^(d&PZBU^fi0avN)ZG1o>ewOFg?~ro#^0C|KchaMwX5AA3YAM0 zJsYCV>x8=DT-0)0ja)b2?4+O@9!0&1-A3K$KI+0BQ6G%k%|4hK)u9}y+$e&&VL#N! z#-cht4K=kZQ8zq<+5s=1_LZ0D{`bG1DCmYk-EHm?qqfMDsBF!T+S$rt0j%QHhoL?< z)^j21bDO>TY0ulJDf%C(BOyOpJu$}6`p-l`51Txw$7fB{RP;j4;RNh}2T;p3a}RqZ zD}l;|8K|e*0u09ksEFJ_4d694LZ@f2^BNlCb*$El^{+1ynS0ywyC*8!SKt{ukNI$6 zAA7p}fm#L8``QRHU@PhcQByb%6_M?D3Qyu5oYBuZRHMIrz6I+1pZc@@mr|HR!&WRZ zz+O0BU}5U12HJ~BJygdgq2_iEDne&bIr0D%`Y)&mCK+U*E`oY*sO(wSvjyIxz4IW} zzfP#}ldbzksO%nuN|u?Zq}uAa7j^zI)Kr}J+8?5uR9^iPKIOP?u#Nm5)D-`R2QfAG zU5kGOC}gEDW{7tq)DE^6wGrJzg*0TSeUDF$v8Z=J&24{Fa*gqvhnoAJQ8(O&Meru3 z!KA~iy&x(X1NA6q*|kGmxHIa+zTOG5Q4v|~)eoYU)p^tuJVz~0|8VO_0@RJuqn2qI z)Oj^g9qWL)aerih0cR`)jbuHl1A9;(IF1VGU#K~Mj0*i{Y=)sDg55tvY>TC-@5fFU zG?JtZ;w2QdI+l*I$gV}zx1d(l9!#m{|34JMX^1h}PRNQ1d0y1W%6si~P}$!E)sg}foJrw+>iS^*(hiVB2hOigi5~hsJ*`p=E44` z^VVZ_+=PnUEz}e}M|Ch{oP91WszU`)&xUT;6@T`QryS4vzfMDL3OXUy1p66nMf4NG zRhXal^%Lz&*!{;O=i(OXv8Gve???Si=M#QUd-@sn+T8~$QlF2x z@IFT4yhJmD-9JuGHH+n^WSBfF*!{cx!+4Z>)!Fug$oO;Yeg7bqq}?|+*zIs>)Ok}e z66?*gk&i>o^%T#gs8z59HAM&T9A5R>*97KUGHplAkNt5m zF7l3-SY$sBD36-UiKs1jKB~jpQ5`tz)o-HCdy6{Hx7Zy(z)3|xNtFXNf+}9UF>0gf zkJ=$;qO$uS>cY2B=Re2s_ys56m?gpP-v=jN8tncv9^+9P(jBaV-%!iD$}(M-_1Bz2 z6B@?hV0?tSal7RfvSFwZ%|UHYn@|_ri`oZncs@i;$!pZq`BvEZiBVY}fjU1MDgp&C zf!2Rb3Yvn}*c3aVPCS8%%tf#M8Z|XvP#5s8v}OApYGY}Pdio8<3b+il_di8_F2gG8 zcn(wtt74!Vh2|7;;W^BK-!L=gSZ&Lv9_o3$81=Z_gL*1nK!x%;Dk3lN3C3At+5Q0+ zu-xLU4R-F}hIRJ2Nk7{Z&i z@1TLm2?5rvm)9t`3&>rv2F+8@=!v8d;I z)bI9_j1E|i`U+J0Q_PO>&)M=Ufl9j8SPg&0aEx(2*!dZ=Vgz2ndiV*otZQBf4!AEK zy)W1=Ah)14qI7@Q4QgX8>O(LJFJe(le9x6@7-;B*L=T&>>n}~|wOV0$?EJFD` zo1i*A9QFBQs3|Xf-IDllfI?0h-lCE#-Hl-P&u;6XLRIaiz2&Yzt&XplFo>UA-eRM| z8h_awx4CV9oH7Zu57fP5JLYiI=jLN7yoQ>}_oyvCQ0%TPleRcTC*p3*{+%Vnpq}%I&E*HwmfP&9&G|Z1&(C0Ce22|3*E0+0WNb-tMnk_Ii0o?mSlzCyh&=lRd9 zj9PZBu`M3PWtjP!<-}>!TvQ42yAkM) zdYG(3J*DoVo&`yKe)qRxmC@Z&u_EoKP&;12V86S1TB0KJ29;A&{eEWzZo?K>IK=O6 zz4K77X7>XW^bkoC>UV#q`vd9*J5gKgUDSxeqS*!Opw@F=)QGlYDZGI>S&pfq`{^`q zw=w(<|2(9VBbMK}jw#~!-QR-03-i0l+&Zq`*8g}4dfaZqG#EFY-+k4}g~_Q`zzA%K z>gaG(R-Z@B>3?2(?)dikpHRzlAtuG+sNDDq6_LCN{O*2I7ujh8&PWPcF8feVrBA3m zzf3~EQx<1oX}p2e@w-GeC0$T+z7#cOyHKm;CF&tnA+g{6>zS^orJx85M7?_LM7<6Ff$DjcRDSoH%t+K5&vn#@(e# zI5(E3-U(OWW*m(5GWp&Aiv2PwLd`P!-9Nv*f_wyYLnN$NMSJ*LcI**qN8{xfQ>pQF}&O8!fdde{*)bq7%+yy3M+ z%Vp;^L-+HjBz%tQaEd@~o0F-iWwr(f;3-^*vw-}m@U%Izl^%! z2lQjQe17*Sml?HjmB7^415e@<)YG+5e!FiVT><-G5e(r#NmR0wLrqB|48=aE_k*8s zgO3fVpykBg!Zw#5P{~=oh|TpN)I)47hLa1aiu#>v)QcDMJ3}#Pad!#>&RhyDX-H7Q z@BVE@FPuv~eo5P4)}yx2Td2LfRVlyw*J~4T2KCHQHqw3An)++6UbnRE8)Gq;4xGWW z96w*i@4nzHD(iQ?Y5g}S=XcI?ph0=t72EThUK->jxRAj)~IbAZHbz?X{Z;KIhYU+qNeVWcl-t>r+ybp;b#oQrckVo-~IAg33cH{ zs2upgYafbAvT3Lb?8jJm6_sT7F$pHCYY(MdsJ*`~DiU3=7%suWcndpX(t51_3>1de zvm2~Nb>Jd?hYzq8`s>@4T;FpjrlEa3D(g>UVmyy}`Fw~mu}=fL-cZ!4nvPmkVGV6r zZ)?coI#E39_oV6z4|9q zM|^F}_?UotI4XA{Q6Vpf8c=)8h}}>forQ|vD)%_+Zzl!4Y##6qTty|*6I6%3dG(ZS zZ6tY68&Pr8GoXXlz5~^GBwfFyI_VCEi%aW=wYGiFuS=$F&;6QXoit6}dROH^EvOZ34oAXSl z^Kzk*xhS^Bnx4B*$r#=zV98aekFD==n4SYYu`JF(cgI3)NJ;xzM+;yP>OY`vuo|@= z?8SWe083+veir(sp6yT(?S_r;K!AcmnWDcXU47IIyP)Q7H7c3*phkQhTi|`HfaL~Q zc2C4`>f2C}yNv4aL+^OVK-;*oqdL$T^#&C9l|lrCWP|KQp$Jx{-T<`@;TnnQqM)bOMbvV;hPv=OR5r&R z>}4L4{~86&;s3l7qLUN4 zKyoiP@}iQdB&q{dy!Mt}dsnYM0M+r)s17dj>KnY{M^PicfZC{Tp!?td{NtVQ6&0$O zL+pmBQ60U&XB@@yFE zzbb{$;nwrosE%~RaySXq(@UtW^fPLMDmuc}d1=(fQW-VZ!!Qd@@s967J#G)9R@FaCmNys&_ku*HR1-Ki>jPkqxoqy@ke&;6j&zJ|Vj|5?QRHXh!jX2tL+ZXcSaq83XAU2%gcmKyNQq1(b|7AtuS@ueH6gAMm z2MSRXHqW-X{2xxHo^_5T*B-1y{V{6C$~)IyC?;Z8>WSysh)19z@elrt_2>JYiRfQo z5uS#_sISE~n0=w!v4As`f-W>+k_6vlK|2UB4`%#Aa>A z^}Al(zl84#BuyIBvfi`GR@p@?p!NTdg7)mxt8HD@Lghpo)P^(=mG!edH>0xsH0s7r zP$NpQ#*!_7dKUbQ`ut@)g0E4_ar;`o`^)PqIGy`D!2JQkon7?YB8+fh?|cB8GLxSQ;!Uo|kWfCJMh zgk$c_-o}91VEUof?+Vn$vfHbl^Xm6e8_>TP8#8aQtu;StOD=+HuZ;S9ebm0v#dGi$ z*1tBK$uwx^n~yQ@7t~wtE?kE1F%8b$Y8%UL)Ox>wo$xkliYjljfwVzQ=}6QK_uyeX zjoQ#AZMUgexIJJ=v73fy9QXru;p?7{F_`*$)P?>BcC$RG$K1n@ zV0`?vY@gp*Pw2NE@H@R|Z+?i#QonT6rtI@E8&Jl;ahucfIED-LM9u9NRA_Vm=68Ri z(F~hYKZZ)S3@6NSsK~rTO?|qSti~s$n zbAI>Vax8|*;tc2g?*DpKD;z-my9<8zHzITKGxaHd*bfjUT=cttd=_@e*87iGgyS=i z3p?jf5%`3KG0kP$$Qq&|xE$Tz|40AR@BW)Dk*FQ+7=Dl8S1j~BuqyRy*b*~d^*h6H z3^u^n*KC7oi%Y3bL_L&pUAMVzkD8iks0i)H+*tMo`+?SfZwk|KHqOIrH|-_!I4TFe zphlAQmf!tVYE9I`Xe?^||B5H@A+E-ae^~_T-}bxzCgf1m+^4u>pD%;ms1L$`lIl5y z{8;s_&DAjcf%@-w0gL`^p^bCTI#dz0Ec>7yQpxZ8-T&-<1zx3|?SVbi{15GO%}|k> ziyiPYYD(HXV*M*5iyqlVlm4;&D5WqexhA5r`wVJ*KgUuS`o!K3Dqsuh6Hz04fy$wz zPi+;{L2bdqu_P`=P4R6kibbBW{#EGn%pS8_ur&2z&;9QIR9XO)bnX7p4~zK5^TO}` zH{q>b+K=I!S2i{4un@=3V|I-3+LE#WYNQQOPsiz~j()``%ouoMdvym)LBnFKk9$xb zOz=P3$*N*w>O*k}-a_q=gWuX0mA$BC8T8Jsmj_!@?|?1v47SA_?`;)K$J*2bwoAa6tg=K%#Ruh(BK2TJ_scmAYa8`Y7l-|WWCP@x-v%H9pw6I1i;Aumovh5jg( z#n-qwh@W%>g}BS{u`k4Z?G6tPao+*+qWk_|oPt7M-)-P$JE*tU38-hm3e-rqpyuq6 zSI^=PaYNn=wc$*{w73h?;SE&se#3;ACdBHIsP~K7*f~I<6NR_NjvYc8?w6?qvQrcH`W*kM{DY9n&8c;y&-|p+o3fqdMLu zZixG;w!!lhYU6qom;e4zTVsNFA#T=}z;NobP?6Y)nu>z)L)J&mNwWu>ha@ z8TAaghf30n*+SfJRP8VU_4l4JvJ(kqXDSL>$KjX}3!q*`n_@g{i`t0#c=ZujmikPL ziPupZ%mY-!K4B~j%VGOO3iMI$gSuXS)b+-p`@jD;he8Y*)*~y|*^XLvzoK@ki(dOv zj8FX)>IS}?A@0w7!mttbq^OSfKy_>Y>Y+3eW8-%3_+ixjPUU3%r=f6(2F>YP?}WIy ztfxsmGh=j)7e?KnH1d_ssf-%=_oy4R#i7^()q%I3-@M~7b6a~-)Bw`vX8kMqa?+p; zqZ&qFPtTdC8|*}N^fV^JXQ)W{^Vsnu*pYfx)bSapj&4A$hV5SaeN@N3q9PqVkk^(? zm}hB>%Yir9ry0WNHH%4t}ZBaMgf{I{Z z7X|h7fOp_G)Q!)gvh_CVMsK|1A25viS5!x1=d%l?LUkk^YAW-fMp_lsf%>Q^YKgjW zS2N)B_8JDEl5RNaLi15`z7`dMEvSwiK~2eJ&nKvkenoXCUVbwi^|{=r4o9IrR}*!9 z8%(69LthFC=>*i=uSGq-PoqZu5_RFXs0;ZESbIX$$daMj)1o?_$7?T%T6UGZ_Nv&G zdLys>B*xeJKSM!1{Ywq_64k??g4W|is8D7`&0QqwyuzsESp_wPtxyr`gz897Oo>Ci z`a;y_)}yYs58eO$uM-sX!P}^1@z|@s_56yuacChsFE(m5Bt}IhKPnRCum#pYU1yW$ zUeu~Mf$8xss>7j$S^o-gSYZocLR503Mcpt9DiXP{FP28#Xb+CYqp0(%7O{s)ZPXTA zAM@fQ)QAsZKD>y!U-Y83Q^qOE`d33*8ggMKRA}m>Zqy1D${$b>8h{$vaL>u8&(B9i zWC<$d2T?h76E%QOs7S>wW>cLCb-f$`3hHqIRCad3!8jCCqfa`TLF-4TIH=&}Kk@^p2z?n`#C+xutcnKB4e^DDr zlCqXOc|0p)7TQ~5CY*?Qa62kOk5I|>88z}moxfV7e0*YW+VbAL9N= z#qbIii5wNpo~WMg_Pm4YV6;jW!W@{EdO6ID9dHs(#d8>5*&_7Hvr-j%YEL#twlJW!A!c5gIc?O^^Fdj9ctr(71P#yW`8BxOqP#Lwq{D}2% z7&gOe7|@$ap_(Di5kfK$>tM-RArAi|#mWYp!B?o{%huRdOPR*3|MWDpra`M<3{J)a7=<;O*fN@mJ-G2N zSd8|F<~HZeFr4}n)KqN7;&=(Q>=LxFRg?i0=`z?2kKi8|*)m{B7TU^^E&^L~pg8Wp zrKn}tptbkK0hJSrF*_bdZ7}~sbs(gTJ{tB~TzAl!$&AQqb zk`)-mc{#e-0J~ug>fltmhAV+Eh*H zW#@(Wwn$~`V;!%A&ACn|R3uJe1$=^<@;rUrTnISzD2%3|D~{s^?@=8X+TY$-F5-FW z;REa$@EVmP9S3rpocM(Ash1yYb6=b(ZN_y5Vh7r<53wDz%utK;3!FiF)nS@yvf?g< z1vHc!Zgc-PcF_e#*f*GMIF)+TNOnMOcoD%VJjUj-7-}n?g4(!Np|boihT?VHgLhFm zuwbmMio@trR(_^X5dTB%SOvz}YAB7W_eTcgjKn%P8cX6$)H_|O@s`ycQ8&1T3iUVC zy00)H#QpoB2AGEWVl0gZFrW>?H!;Nhoo_bO-1NbUINz(^$MV!;OtKB9CMv6Yp+-Cv z^|=kG>;2)?KVt;-@X6M((x`!Uz!JD*GV4Drh1)c!N4_cc1BP;_r1=qx;uO?QcLufm zUU?>+YBwx_jcIR>TK`9|F9uBuaetQ7AD2?EIX%Sv?+4$YBG+aHNumpGo?)T7in*vi z!RVNLrak}DVm|7*Q4g24sN;iC=Z{7`PIqEnJdC>TJJbME&9Zt))K1tAH8o2E6tsbC zL0#}DDzs-kpQ1t>ZMKCn9V#N_P@x=(+NgHpSL{B=BG+|pi2Fa^F%iRQFFh~B{WV@| z)Rw&g716*A3L4ortb+OG+lDa&Gx`__Y6MRfS_fh;vWG}c)Uq3i`Ek(V5cda`Td)`P z=Xe)eF0oZrW~uiB4Ak7GUgrLQBj7ZlFo=dNs2s?(+~%+cDqA<9{+rG7sN+{xgt-4Z zASqW`Ql3Vwh6Jl@Dr(_Q>ccRI&lOp1J6*9gA@1LRbjLNi4u%B<2;o}RH78D4XB)-) z^~@3Vr9a!wcyojK5|xy`Uo7b&P`OYU)zQ|dGd3 zzf*AESWtU%qD_`W6)_w2fvCsnYAl0?P;(fv*&-5&TAqDSZ$|q(AEBlu{uaA#1=M4D zAZj41FrXeDqp%KhZnd578ZM(=VH-dD!KbJYXWMQs9-T2Z_34-ym!K|u5+m>}DruAK zu-wUuxvAI1!Z-@`R6V$Z^{)&4MMGVDhH)@zr!AKnSc!Tc)Em!1OpA{(DaP7m-y70l zLh5-@kt&bcl3QRD_Ca-M7be0>m;|5fV*O{Q;Ow@!$${F*s-sTmiMru9)CD%6E_@QT z&Tpf>`z6?8^$64e>Ui~5r~%GIb$A&nLVHlxxf!6Kjo=OHg2BJqn@s`F4yecTJUoOO zP$BHL*G9Y+wIA$5jrdQO!ECU&dq3)e z>ke2Xj(Xm}t{i`ZWjWsRkmbNCR92ruCG$HxjbVo^cdnx%nBs^Hv;c;4f2Sjb;~W@= zI^p}HwzG9Xg?=UKMki1qi*w9O=UEuF=hwihI1!uRb&P=pk6Xl|Py-r>!*M3M|Nd9< z-|WpN6KWloMs2~ZFf$_!pps_I37gw}sO57SHDymx*`4}ii2D}~)o}y$3#fmHAaKgw z6SkdZUkT1DgsMUIdBB^n2mnVew30BYf~SF`UAv2u^siW2O;jiC(;{hP|xzv ze(K#H>r=mp+W7K43WPYf_~61v7LtKa?A7T2F5rY{Pi+HQfqE%@f%;&nXBLsQs8_Aj z&uxTlu?6+5sANm@k1e~LsDU&=JsSq&GkhALppgFg!a^PYmCb2d)VJUKm=0^AlCu{o z0y8i!E=JAiMpV+?L#-m`wIypREKN15SMP#-x!*w46bJtIhP|7H)c>;$qvBh;&{NFA z3DMr!g$ko?Pys7q8?1#Juq`_8E!6E$t7QkOBd1XVd4%rM^Mgeq0(o-^IAthkggvn^ z&PLt%0%~NzA8l0>L@l#Ms10U3`sw%z97%ocC!2~~|Jtu;`l6Eh6{-Wi&z6j-Q5`Ib zrS<+_lY*AlbkyFz0<|NaL~S@%Q5(q%jKGhmtWNR8zKj+^{im3{@e%FgzJ~BWEW!_= z|Fc)K*5CN`8^=@dZ9q9RGAPs?z!h|V{`X1+4)}bb?u`?nRz*5g$7Z2Iw;DB)FcQ#@#yo~`RQyqV(`=Zet!>Nx)eeh@02Yy4% zLjOLBSxtEhshmd(h=(SP=62X#13^z!Gt)W?&J6@ zYW>Fz3$_3KzY1Y?!>0e|>Mp>osQy3R4|R6YAt7<-4(aah?(Pl&X*M8T5+VqKNH<7} z(ujZvCNG*fA`Mwob#HsW@hzTGkc$X&OtT#a4g1!vr&C@EJ=)e z!1x}ulEqINh@h22Vw^-i|0@`qeRJK+`C>yP%TmhGh=Jiy<&8-XpFtBMufWH zM;uAU4>2|2-YH_-8b1N|5#EKpabQa8g3I_B=l_QMQxtFGYu1JH(^}W9z*x@Tfhq6; z7UcXpsIE&BeLcpj#!hkE&wdN%G49c78R`Mz3ml6VP_v~;#u)e5J`A-EY(iDw zGt@og465ZGVKI!!6yp}EvZ&{Pi8vgi+u6|=$Qx^YT^u#~yJH?4iq&yBs$jQK52bZ7 z+xf$AGU2tTrL{no7_Tc%Mm-7ris$ez)QWg2t9cV+HUD3*)1CvFvRRXj#c_n+!9Or* z_87NP#miw`kso!F>WF$K`~auoF;s!;<+L#|9AgQuMiuxtYJK?wD`GxwnYA?k`?2!_ z5qnT;`@GySUOc+uAFM?9Wu6%K=2WG;G46eU;i%~u&KKieT#i9y&@{i*Y#eIgT8t&} z3|7EEff)DpTMZmS`peM${m&GItWPqb*5rDqnhZnLa0M!XQ>djk{6>uT0-K=5M&rUZ zojRb#z(SmY>rpNBMiEQDAO1pk3F^G@MVbG~Xg)iG@c^nT3Kz4{Jr`AjRX6~DM6C<; zid(^Y;z`1DP=l;>i5T~~VGe3^7bzLz9zGjkMZzmk@js*1l{lrC|Jr$@RE%3Xy+0)EG)! zBgVbRyo;*|H>znZ`y3|`?o-Q-Kf2@iry9iTYEDr|a5Ex1heY%re}{ z1?w2-bTHGO4yVxh|A3kRiFmVtw3#&g^b_- zW=DOy7FDwSsCjxCRkN5DG46TbHPqm%iIuPmw#C($1LL-|yI*dM5U!58OEyLos2jdX z%T7mC@V{0uUPsOUWUZ|!-$W%e1@)w}1vOf~L?v(+2VmkhHa*9p2H|=6H8aKmm^!2YNV-$(WJI@G-1jlJ*$Ms-2q?sl_ji0Y#emINbevcXP56q0odc?RlCW~Mj!c(yd-b7`btEXjH9J3H!jw;yEp3Hv+f%gp& z>Z@m{`**09olqU?5^jdNd8|Ms@EK}sT*G4c5YY=?hfRczSD z#?XR3%zs^YiHOShFY1H}eXXx2qMGUnYK?E-FUI{mf4c7{7$p7Nj%pqrY#C<4LWE19=6i1}f|F1Qe1e+4r%?sD zjvAca5KAXLswLh)6}SVI!J()Ee~c=?Nlc^pf6G7c5=(L*^-!xxLrhAzBkICIs2WW} zwajwV-E$vm7X5;n74hCOv!E(a3Du%)QL|+zssIbo{r``he#8k>O@Bf4ZQ5aWVg=Nw zZ;Pr?6x9L?Pz74=A3uaDz|W{z6?eFejU1@+o1+GIZ+ru{qWk>c4R+K8f8#<-GQw`V zYcY8o9y(D8+#YEy@eitrQ;f0}s)VXxV^r7m!P5AF?}XWaLM5~u-LylU_yy{w^b@MdLsM+9l|WtB3^n?DqFQbu zYC12$+;|Li-EY_v(@(YdNf=8wx|JO*Fy~M!;8VkiWoB^#{C7<8mQ@4c&4>Xe{4c{EwYeBy?@y0OGLd{G473oeOQ-p>}-1& z?S~qCr%@SPM|DktcdW^aq6S|T)U;}g8iXUTC~m-Fcnvj1Qq8e+Dmj_|-Px(cff=Zb zzd|*6y16#kDxnI{3H73MC{8B4ah@eucz%rgxqo}?LHq-Z#b)ouxKF*mg>4Cchgujenp9 zU%L;iU_*STp}J(5AN~}>gwLT`;_?Un>;GSg&}fdc)G|zoT2d>Z7LInP4=Aj_P1yaz z825>Z6d%R7H<|C?ea_ptBF26A{G*jI-bTWuSK0Ktg<3cMKuz1^t8IlXwwn2`Y1W1a zHT7Glf*i%tcoB6$vNbknilRn)E3AM6Q1g2$s%t*Q>UbJ;U5d3a?#=1qsOyGc5uA>C zAUP0aN24u zvA>dw8Y>4-gZn$IjM10uWM-%GCL5()u`A)jsDk9!Y%Nq2+Y@epy18sY-E6)=_5CAE zhQTdX@O1b$T~z`#h6-=9m9`yfsecDahrj>LPB1Qm0X0u=ZnsgIZbyv!t9MmU1-yp3 zE5_Mr=0vRr^-x{*CTgXdgev$B)GRrS!|@^x!3Mi*FdxHiy8q|fZ6%tAs?k1F4Zru} z|3eiZ`yP8WTLX2^ScJ;>6lwwb(GNdET_4(O&;R*RgY!C0z^^{BG1G7#1tov4Ejvo6 zH)_z0LG{sIRMTBU^K9Z2vVCR+u8HLczmFP2mrx5* z-u=w~SazneqZ+P9HQAS_ro4{otHcLlyyaLNHEJ*604#RU?g^_=O@0`47d(r)?kaY| zm_v5FCu;P+g$Z%PA?CkUs69kf!#Ia+8r4AEY+9mfJ_L0)n~hpH_ToQy0yX`P9kCjp zLuLE~)zs;aavfvqL+phoKaX*rrYUm5&Od)5YD?jBB2@EyCu!n1JhP!bMAHA1ExliT zX`}igYGHbeS~rrNwwp~pR13C4-T$Mw8uy|;yV3ru82;!O52I&n?az7E7NiPMcGMId zP)*twb@#gB$0s^xeVz`rbk;!K-y5T*-6+&NpNDFx%c$$0q6(Db>lp7K*2HEQ{Kj5W zwnvST=oWS~?Y_a*lr(tW21%C-Hp=&43Xb1J-6Q_PDj4|Ix}pv$p*E;N81-F+nyx2N zE%p#KSQA~e7O#iIN4*K`^x(j9EQi5Mw&qvI&V*-R8~hE2V(ss2EF413f_tczN&CGO zG#l!-UQ43peZwED>rSGU=v$}?KgW!k|M@T5{H=>xYP(@eoQoQS_fU7qm@C$_RZxR) z2x<&W#HRQms!N`rrdi}iYmpA9^CzOF`Maosti?3s@9kwL3x192!zZYPDDhPrB>7S6 zK|Rz9ks+uipNVSnZI}taMK$?T)EIdET8#G-)xQ|zlB==(4+_m@l=iIk0i}S$lcIi+p*#moV z-fh&6ZW}$~ZM?XAZ1;~CZ#;&d#<&lq&3w+ih2!_1Gym0hQ~$Dze#Gt^81#3Hw-mqo z#|F_`|4|^q4^bb#>-N%apAWr&Ynj4v0`AZ448lsJcL=*-+_(WxA71H+F9;8e7jP@$ zfcOEgI${16M8N$XewqXUZwMv)2K#ZKM$p`ay$NRx*@d%Fv*CA~igm*Q?_2y9=i$ak z!2JQj@(Ba(1BO51LE@(*B7LlpIN*Lg_cK(NM*AeOgf^f~D3Ubb)u6=da1!C)lLg## zc`JFqTSa&iF5`Hk6an|p`g_WNmx1t4sRG_Dj(e#C?(clv#v23=rwMpTIleM&!0UrM z(*@ikT5S4&KAscxK4Iq)Cw`hC;8wu-8LfozGFf;#{>bqxu>o%kdYJ?6L1ZirBlsi! zM8eIo1l-SjOJ)nWhu8b43U$vOa8FW~QG@SKjKz#O0<4gXnhNY_5OzXMr`f3KwFC7C zb_omO6HJBKat7QyFO8a3jW9EgLS?WNwQd~6!gvie-IC`DxP_`S@|%zR+#%ql)TkYi zJK&z%XQTS$6lwtpaLlg0RR7_K0CSD(fxZkX28j)X}AhC>W`u>C{@U6SPfOsKB$}52F!wc zP%ZX@?{m}&nevT*y9*XXkx>(9)QpNWlH5r4TBi9;hXGBI@`y zOpQlT1-*7KJH)InsO9s5H76O3iBokM-#_))oldtcyXd0PkiRtUJq?km`f^AlIJ*)bgdBzzs! z^xs#q3OvRMgd>#$UQJfk*{IhUm#PNbAGf_;J>Y$$`9H5lzZ0#37Joqv%9w`MRb^2N)euzt zGSqCjfKm0y-|T3G%h4#{p3j?OCBoCOB%a1nn4qzBK?PKe2B8Mw1k|8Ag1X;dMBTI! zG-3U~fv6U|g=cU@Q@dFWYR3F8LPY%LHaJS+c*0#Vqzh05_#M>(xm#FGOQ4qOs#pxi1aeNY8Hi%PIjYwOz%sDeyEHT_D|{Qn9yNbjNU|M8=3tV!$OF(SsG?pl@GT0!>U z7>!!gpla5^=J9Y$L-+$!g1b;PK8tEOucKuc_RWc^U{%!3s4eP6Y;+SlvFuz$4WgHR zIAJFnB>7PpH9;Nki>m1e)B-aFmGCmudAm_d^;y)I_z6?tGmOE6o$YuEET`xH9PG^E zKv&fC`2*j?7F`0~T0DhH@XfB4@g!72^HF`f7}c~ZQ8%qas3yPWheO@0pt(>BQ3WiE zjWC1e|7>=2H`|1i$om!NVeak$uX7xJ*o4IiXX+Vn@98#2WxO8q;C57#|A<=gZlh}c z40T?(mmN=mDnJIzg#|Ic=6_3eG|wkvJzRonvb(4zeu-N1U+W#Pk7(n2gvVh;Ox?#a zY>BN2_r*&11uDHzUmH^`P{&W>UCh~!`L7d_^$)n;OzeO)37^3xn0kOUWgl!#cmZnK z-N!nZY@pc=)uiijFfDcqI}>jGX23me@5lCpGYk%RlW{bvtKtn|{%iVW8DjIdf$vyU z({9Fw_#JAHz_+Rf-7&LH8O zlkA~(2lgjCV=_;__%}|&?o$HZ7x;UWoh9t-of>fO$uyl7@D`Ks$EeTg)t$kh!DBP+ zvHapJ1{vXu?*!Z*8puB<;68@G9nTQIer~{hP+|D|fOmv+3%qL?KEj@aM=h|W`6lXk zw847;_lhU^!hrkC=7>f1{GR&#fP2gJ5q9UqT}$lwKm7;Pl#C8z8_d1TuAB6s)imq! zfcx9g^KdNJ-N&k&*XJXKfD?EgGi(dEk7zvlIN<(v+(+AOTDRU2@Oa3YPd@vUr(@0k$Ltiw#GhG)m3*6EW8%AERoshp@jujxSbM)s*LJ9T#~O^qJ_qb} zJ`;8RXQ+iObkOc0HE<;1-WUzC^9wtg*T13eZYd5~OJqdd#j0ao?2K7(HmWHY zP%GOt%#4pvOLB_C_GnfJRp8u5Y+9E^wP=qc%>QldyhX$(nDeL=>SHYNT~JLv5w(DQjT(giVk^vk%5J|=)WUXFJ6geF zzqCiM@~D?gZ=xPRW})WoQPkkfciPtWrl=M0Jyea3Vk}-mb%FPlHE|YHdT*fesf${A zd!xEMI?X?@1@$0t8W-a&OoZdl*t6d|s1@=g_QYFf1Mbu94ZgP5bQ8Y`xVLi8qXu<` z^8s%;F2zMy{(`Nfmr#Sb&$n)t(EsezBBIwt8zehWYxQwt)_9k&242MknB$Vo=X}_X za9Py7VKJ&jwqt(0hH8mK-`Suoh?-@MQC&L;lc}gH*ojZXPK?D*P>)7GpcaaR-`f~T zgKCk2ez+W}37ev3(FoM2p5Py!iyE}+d{3ha^g9;9J9-XC z^<%)j-`53|&@xnCUBR-L`Kte-6SW>JLtTH$4=1>0HGTutQq53GD1f^AHOBea1OLN+@C^R-)W*_@XEtWe zqPp-WRKepvCmqfI^z3N#SHvgS4?_%|&VMrauPN6cq zg7xq@YN4t2!ZH|!Z3!L$^B68zSRNq`hHBm~2q86HbsQKO! zHEL&IW!#5aKmJ2a+iY=yZp`FGt*B)&78_uF9EhsmK`en6;_&>Vh=g&2?!h55_9a{c z1Gp1a!_TlaUP2AZ!tsJ`sjh+=6HQRR1JVOEi$=${>nHop#{9&;hu!fQY8K^4y)&u>rlXqb5NgRx6ccpsJENBHL4J5Q zwj}&Hs-V$~!Ju2=a-nKg6V)QEP&cFgs2Yw%m3SVi0Gm+fT|r&<2y9|e4nBEG-)L0#z<;ZfeN5%R^GQBYWlWC4dRX% zi=$Bw9!vdj@q|G)|65>s;%B1!`QLhW)Z`~n3(X7EYrArZg6@aXml9jT8Io8*OQ8m9 zZPef$f@N?9YPx-aW$^;WVzQ(`_Z(0d)iupgEj1f6Y5wnFN4LpKs8Rh4`(UYLHW*i9 zA;QU%+gPZARS1v7Hh2J4kaQ`mZ{I*ox9O;geTSM&iBnoWIZ%VS8oKxYm$Rd3_7FGV z>#2fnp*W7}f@`SxehW1g{=~+Z@HK0h4yf5O3N;Ad#;!OM8{#8;iIr0a-MUgaP0;;v z`nfd0sC)H0DXleK=5&@o0o1fBfqH~$?1$e%HQih+g8Q&J{)Pjv+Ur60-q9{pe6I9X z<0!5mybN`(sFcAfST_Un|26u$8xb!!FgjzQ}*sCJMR$DC`Zu!!r={kkMP)> zLHDl~QsoM|pMHIUMM!XA?x6Pt$G^-IbhqRAd4ui==`!XcK6}2PHwH(^RF-2@_-S zEQCiJe-VDx(#s7TAZ2 zXxfXY`9Gk9o%cQ};{!MxZ{kL5S2E~+t`I5}bnhJ<#yiBnS0?B_4-_p+#Wer>mb03U zz*xddu_zuuJwiQ3&4!HSZOtx)YVs^G}xB;rh1F#wXfK9Mab-V3OL=DQt zxCnnm-Nq-@AU(#)Ce*KLoTzEf2j^?q0(YmjO~*%3c3N;jf;u+++Tmw}-$X4;1?vXw zuiMlMx*s%@s~>bfayf|4IqxMZ!{-gGX)`rsDdxKN$n^5MHwtv5J8yHs+iimGVKLB_+b`j+s6Kyzsjy!=yXm}* z8r2suKiCe(aBg_;$= z;~>n?(c<61R)lw5`PPI{y!Mi zN|&dbje!QJg3LrU)l$?F`xz#}Yp8kt0M#Yo?lzrbQQ=jQ?WYXomd0^@xxVm1>LLN=~#jIAFvdr>uu{tQ&f|W z#gYup6{rGU?qeBg&Gr^ z@fZ9CHJJ7ev75&Y)F{4>Juzk|HKBtQhtOhgT~eW*S=fhyot%!?0kHoiW>?uHvs({LxMsc)bjTK`5hb)1nw_uf%5 z)S#Y*IdC0j)%-upP9Y*5V`9uU$`USus%bfl#TFRG;ix8j8@0f!MkRO{mBAf9J}^4y z{_jUtY)<@b+=J!ESV5nmd;dSlSj!*}rsjk?sHW4M{I zY3_@q37Sc36Zu-8ysTMnyYJJfox0^R)I%8o|w1yoc1fhRH3grNIO*Im3u_}tq; z?_bc68dgR)L9q}G&EYz883AM)Bgris=PoerW?K?sDPU%1#O?V5Az`S$Fkby0p+d8|3Yy>?q^DsHXY|HSdpN0SwQ#nw9eHi~6|Thp6ef|6LobD;HQ_ zZ^q)pUqCI@k@swH=R&n~E7YK!fa66eBTzb))*o@A0xOF)e`GbOY=dbi=y7o>}b#h7h6*oL)|`Gqeg8%)L@#0 z<#89PCQnf7M200c2=k))z82QSo~YTh%Rl~=AO029vhhC9i`FRb<*=g?l}3%u_NXOu zB5Lp~LEScYqHb0vQA=mGr8f8~pjxmlYJuv7x^4lgueYEIdIi-I_fYvf!w~s<>6h8) z&w)y~5o)37i;Zy@>cUf~7P*M3=`++)n(9OAl8UJKPN)KnL$$zC)b!qk8r0`e>&s6V zEy2!f%dJH9Q5g=wb@&Bp8V&p?=zea$09BLpE3A+6pbF3hH8y6W`gk2K!UGs(Otn}U zbf2cbw94N5DZa*L)221df8B1M6VaFxORu%Z>sjmU?sfyUG?!X$HRz4g2v0?2oP2}T zxE$(Nv)W>IoVU?ha_=VVg7cW0^W$vhy&{h1Mg0xff?J~Ygwk%S-M!XgJ5CI2vj>rG zsHWS3>a)|R7Wo6!*Qr0YmZ*XnGow)tr}KSRqi#Zbup1eEfm)jL@33iKKFUsJA_k)# z92TJZ`U})bcpi1ZbyUWWP<{B?PMam!QC(6JXOTg5RNr6NWqtezHLbJnW>8|oJ+{8| z+H2`Vx3Qyndk{4!5`1EVtQ1Zn+zK`Nuc1cu6I2F?_L+H5EmQ+_eK+ii@1wft1*)ZT ze`?n^!vNv_$TW|7Z?U7APeTo&Pf>mKtsj1gnnr0qv-ldQQ9TG%kZD*L*B}Xc-=o%t z`>6C%?YFT|5VbPaMpbA$CfEFbj~(5=*Q1*H94g@(e)t70CYMi}dZX?Q$RTSe3D3jf z9PfI`3ic!RCY<&=y9rIicR25B+)R9@AFLutF5B(9Ym}X`oKX7;gAS+sXzygMx@tct zNO{d(aE!ug9Dj)oNvPTlyS=`L8s*DT_l|w2`}()2S#%d0a$Sm_Y}9xC*~Zui)O3!{ zWJd|CM%_FPqHecWQGFD1(_WzTMXl{yFpS4g8J$I~ct4{C?^DzRM(`J#hS^Xzt$NrR z`(X%AAk&fm|H_UM4BfK9loHj))$l2fM;#w_+g^rGK+WGLs2Yau*x)OIDqsuDj{Q&t zoR6B`Yf*#u3~I37!c?07sqR|Fc~LcQi{)`5Dubh_gdd>R_;~kt_{4O01E1g#y!dO- z8;9@Tw`rR0fpuj=)EGO274a(0$4tKkz2oHX?O?~v(}(^uobLrx)Bb~+1&MyQHM_KL zEmWVkL^b(fRE^(3&GVJ0QT{RN`Xi{Wc!+AzB#)T?nttinQQvJuop=Cs;jgF@|3$S# z;18R2Z(t$9Q&0upi+%A|Y>X`*+s$hu>b$+E0^Y?fnBa-s|93uN{;RKF5~1gSGEal< zlSyMyYyMxTwLIrDD@a4sAZ>$ra3t#2aaN_g8&!Ji<%-Gf2YZ*{olRZwzJ^z zo&+J+wEak*f2+LuP7%G5WQ3Z_lWk)5PjLP^uKfDin6F!9+6U71{ z_j7{Is6M`d6|iV9DX)8?@XHOL!sxA6to zjO%V-R40_k7xF3+(Jz0Q&tm$?Xv?fkoDCETw-x_tFAB8ROI_gQM zv^CK< zoIv%3ovNqZ)pr++lxCyJ43wb^95$?m*PM z3YHUVaJ)<%pH!l!r%dsGj(KT1`hM##M?&REmBxDRR!L^rcDiIT;u6>@K@O{-0q18M453oOIW zIi8?y$o*lmFY8%XyxSn;KG%B{Re`LHY{43YdTw|hwf4Wnp;)M~WxNJk6260fY5rGg z!ii*1rfJCi>9xMiLhcFYIo9FCn$1IAFMJmdao!8m&E{ZB8T|LwjuY-cN*6cU#nfni_dwF(Ea@HS$n1r5uG}O+}&w@$B_GhWaUmat#)H+ zF1&*pJXt%3+>dJC#)gDryM){alLz5)!tuI>-0O!`s1@}vX2M^vBPQr(v!grKh!U}k zo#}WB2jHOY)|WT%0O2e>LhhHzZ=lxxDLtA0*t(b9Y?h)1-+io&&3ao`F2~h`3-+-w z^DR~-oVc&GY!i$sgAdu+i|zY`+;2Xl?r#gt2H(5`tVuVarqQs0wqowUHiT;qvI4Eb zO0?u{d_jEf!IojJA!a{R!MCHv$kQRr|6S~~8EQ9;WN(Gsd$pN{SqT@So{E3Qxaf^w zfx&nqt;K4O3c1JiZ&52|i_v!dLDUjmVob>WsC6d3tINk)3npgT?;w05%8sVNf^pVI zzxqbT+bqb7%Q*fqzQl$TY>937w%xR%sP$t5*2EX6E~qilYB~=!Sii;oSb36-rH`=@ z;rmf`^uSPlvQ3LwsHOB4&QbgnYl*Wsity`GZGl>d4+*E67IME25T0%;UfLNp?;E1- zj=5%9i|oaYgbU5$ri61*OL8>fY@5%Mur3j2Q3uk$V{7#SRMVct3Rq%})npj{Ls#6w z#PN7DX&$2;A1w%ZVNCTtcR9|F{lEtEC9Fa?&C-y!0NWzZ2T|`2c5)GseVILI)JNSU zMxkcME>sH@`_P(fB90?`5w*s*SZ*22#_WX8qON<2C2;6RRhF1+Vu=(l{DoBn;vbjIpO6v6rZC8U%!pkMF}_Am}rh#cy6P{O3BS3?xK}bzR}D_5iXN%M*Tqow3|DS}Gqq%h|bzU!msns*gkNhsEA@tNAS7E2vSN zcZYSsVw^(w^_{i?u0(ZZv0b+EwMTWy1k8c!a5Gs(DJj-4y*(a#M znEn$A!0}$FCfmEu?q)kawJ|d9vyl6Bo74Cc=e68#Pef%7+HH0QYQ;N`YSA=@>>+eE z<|cglP}FWB&xp{{+w3q8m-snu#{)-frY z)H@fkU)j7~ig^gt*8a*wR0i&ORb$yU6SH!D`2z~JEw{0 zhx)bK(%;x%s(GH*1%&fnuqC+6w>I5cUbFE8+1HAZ%SXb$M5&9*`wEE)U@n<-Nwo% zxQTGg4Q^&+xC47*-=A%8U%DA`zhkoHmyr8-PS0B!Q_R1Vx9x6~OU zEOgIqB5&figgg9d)3Mn7kb7S+idqlSJ+M9lz( zd| z)cXKWFa>4_hutfl;;2D487trx%!|KaV@wwbyO!yPtqGq)O~bqi!|p}s1*}Rqc_RM) zc?Nb`BnrFvIuyqdUXMBbP4+N81OTCUqh%b)% z3yObXWx@%QhrPpu8(?C>$)YL4?&WtZ7NE}x;VcexNF8<$6c4b65=vuTvj+z`kdc5ls8LRG8@D#M}p z2Che?a~X4L{@-UuC#K9|qqjIJ!OEBfn_*h)hAK!DHAolX>$nTmGGC)c{|hXO;jDID z4O9g?p;|8Lhi9Vu|9>0U$;N@>sDyq+tlGc zNJ~^kgHSb{g{tXB)C0#}RFgkPwP-MR*qfbz3g%}1YoSJ0`Z;T`xNJ}=B@j?1%N(Xe}{>{=r1o|^y0_M|hTWZ1psau46;{GO%4?w)YJ zw5D+?{(v*_C)8LNP|j*F0o7vjQC;>as;1Xb=RH8JgkJfudo3A@ z+X$Y;95}9mweVW3LwJ9b9gW&hMVpsZP%o#qV{Y^+h3yjysJq>ps0&B7N;rGfuzPVDoz9L1)fQC3ajRM1XF>H0q;_X2-C52t9!FINqugHN^X!d5*v~UBg~KyxYyDb&DQh z_m0VA)WQ@E_OwT%Pw)g0oqL7dn@)LqhuuTwJ)BAWpgz`TFR&cp(tYiDVK^2bgJ3_p z088`_yHCk?91zy~d){9IZKZoW$j+eOHo_~vKf&cvDWyaYUYKJ<13NGTM&3e?} ztvth~V`pqgcqF#KFVTJeFY8R3cI8p`<<6*;Zxf8!2oy1gsAn_O9_a8_WTbFLY7>>s-v6V3A2h4vh z3{5_;r`>s|CcBJUnEt`cm~pA~X+^9_xEpF^+k%>&hfz!Om#C%rE^4Wbzs$mgFeBkQ zsCA?_Y8sATMjtAnHAHmAPcRN8O#h+vdB)|oFf~G5*dN#6B-8?w?<1T4?XflCg{ZsX zAE;NoiC0+P*IsE|*cr7%&q0m3JyCYFCLcqsd{>btBkwtC4gU|d(4<<$0u;le7wWE7 zVgvVaPF#xL$K$rWE$nTM%ZJQ%guOPzPv1>E1-SL8JwF`UA9g>?3LdcOSPn0dPIMYO zb=m23&{nQ3xQg(fI1!f~vgwxPu=yowHVippU9lGR!16olA+`Kb>-!O?uDypPG50a6 zd1qWlcpB1@QLpgl_O$ywDxsICrMTX4%V-x?BYX#&VSz8~Md?KRiEz>rwsJm3^=a^w zJ@e&9&6bV$5dX!Bc>haV5%Zr`#hL$0zG7a}RCjPICnP;<4~vITOKR1x!|olDOW)Xv zx9Yq#Wzh>ZW_n>&t~-sYak6i%$s1w^!i#VL{)xqK_C;Hmj^X>{&s!w6)V}eZHO*ce zOMIvA!`^bdj^E?>AMEM2&1IX{_fhYP$6m45f?0pGmKulEIsZ6n-Pa+1~3A?w)zC(Q)=B>N-YIVmwTWZ6<+KbAX z_#NjLxF7bu!oUM&1LuE>?-4HZ&=#(5a0%h;zlXgIco@|ceIJFr{dgK*nJA-i~o3#AiV#D4YIFZS|2Cm zu|z9k6D*1!U`zZOXJMW=5%&(sUhGQvPgDWg#f`WJpXev-j3eS_Y=K?lMcnIw&u|&x zr12x}rPx-~TE85qCO+l!kpQ6S=;boSv|!sUVycQ5z_hZ1fcinuo- zPUBR~|E%GNdrxPR@4q;Q6YEAIp6-S}qE@P4LaW(z>`1s&qKLbTEylZq%O#GucfWEb ziFl=Gsn2i*@z0W4MJ6PRcpnp=IeEmrCOn@a!o7vgZ?qx4*TeeQ1-syOKm1yTh@02luoCf`Q1kgW)DoK`W5nI>J77k_^HF1BJ8CfB z#t$(`rilC0%vOw^Afi;}i2Jcy+$<6IpfM8r62A`VBQI6fh#SSrP&LS&E#e*`Yhz`? zr?EID$!^zGM@_pOs9DlJhYh|}sDgxYM%-W1c_SzP|EwYr4~X#Sf&#fB-fhAKb4T1S z9;D6_amQbvnyf-zYRGxra1`P9^F`e2hgA6^-hAS7;{f9K7l^nwF!C2P+hRrHXJ8dP zjngn`p=iWCGA%9?@lFwO3UlCsH*BzdhCK?94j~+Uqe8^}g3%hB zL`2Gp5${V}jC-+rrHFen%2YYxUI$FTVZPj4tK0ezuZGQ{ zF8D6ze~3E2XiXNTxV!^e%e7q8`>_rOI3Yz{8?6QKH%{z=deCTGKjN0oNvNC9ZPfHC z+92ZI85xJV+nvDkn51FEy-oi!wjiBP8b#b^zLGVuny0~hoYw?PY5tF6r!f)xFcuRv zjkp&c1+X&V!V$;&$qB|N!0b_F}~)1H9w-ZA_zA^ zW!N0!VOu}k(YHJ5yuPRfYY=wB!`KgVHjlX98C`(7er5|he~#}0%uM`ZbbtTnGj{Zj z$8*%n@R*hn_fVP@wUCs=(rKEsrlzLl*PZ=f>Xhr0d%YGL~kv*2S4 z<7=&%|3P*#x3+}xU>?E^QP1_GP$iv&dY!)(li(*f1y5okY}Ce<*bZ2g@IX|7cA+YE z3U%H0sK@rZm>XYj%luaY)!JIko1k7u3`DKjvyr9A`w&&)jhG2{qgvu3ev9`|=N)Pn zajz#%qcXgPO8+71{QppcI$8UOdseI(Wk-+AZ=)WW4xpOsPb`S3J4D=T!5ZiahOxxY z#(B8akFVU(GU|wGf&Qqab_c2=mr)hCkG1hRR>ElIPS!UQ@pU2=qo(6-Km0Z3C;R}_ zRj+rBxECtfP-CSW_QTewmGcBD!-uFP+UsInIT}@f$(Ru5BI!lFW$Y;9wWy{&Y6rZZ zQB8UumC>K57D(0A5-5Ud(u%0#O))tR@|}np0}D|ZZ$hQF#}6OHyqf=K*h#~IzfmPm z(alPn&9?xmFH55OvL>nq%~A8Xi*Ik#pdEyozN1isZ#?R{IjD4&p%$PmSXT4@GCSok zP4|d<^SL>uCEOlWu;HkT=Asf@gnBW$7S&Y;PzC=UwJzL4wZuc*hjDvY{C-pmAMyPO zqp>=nrwzKSsQFnLl|VOCjfSHxoPf%31*$3cqY88qRiN)sW91=gzGvuV6)A$6zV$FG zc0jer+r60o>Z7?ts0M3L3GP808F z;r{k~kQ0^B7*x%tU;sB_J=_sxM;XK!UDB?&Wt08z zdekgAhpF*5RM*4|v?kAhEeYqvSd30&=L>dLV-f5(h=nH(A0S5c@z-x!4Sq!R*=^K1 z@YD~#K%JLxupLi>8ap{qU0DiskEn^NSbwaGQDlLN@_+p7g~Ah5Uw$yetTxo1bbiC> z#Ls`rUeRP6X3z7ReCrIiuDXZ1e(MOkIkg;VPsd|W52w3)@1t5S>nK&2`B$4AHQ`v_ zk5Hri7-}iLiE5d6qwN{41Xd^96E#h@qNeFdR7?DXTk$v4Y*;oX;@zM{PvhT&w=m}Z z#P#ENDkgt^57%B21t!><-QIUH>YlI#WAP5EprN;IbmzlUgqvY38N^Ps$Lvaz?0H}f z{><@&lkHyeJL>w_DXh4hUj?Ijmg_Lp9;Gf}F~XUq*&|mo)Zp2Jx^138-Bi5k)`YpR zFu?{`04Mn2k5OabCXUDFI0r|}um_g#%!qd|F87R?%>SJ1qid19zMH{zY9WWC>| zgv6J4kNHb{lSP)n+$A=j520G-1*+*weqc3ggbfG}!KQc&wO*uMY6UKex~>h@#|2C2 z3pLSAB0AxTWj0Uqe8}i!Ev=85F6~y@)9h}{M)(g@Q>I>J1uBhN@rGkooQ?Z%J8r~& ztGV4$v9xQfE8DEKu{Ao%&PYyJf_ne|wRLtN?|SRw+NeP^7}eAtp;pWbsDj)@)hO`> zf105R&>suoJRFQi@gbJjXpi|hH$~h>yrY}h=}5*CHd_KeZ?Wh2&{hT$UGN>&#d6#2 z<@WTQ5%-VE^Y1c$-5v3Ik?{Jx5%-o%icf41-at*W>ig_M?V;SmZ#_yMW~<{YyndlwENd5|xdkex#Vt9t&b~l}LGO^_4Bd!SP_2Kw%%*T5FJMr^aPUl96nrwm5|@*6M{?Z_9?8{aWeVwj_3ej?X=w&ooBl@{9^ zkN!{2$$t~5LleE)>e2#NNLX77PJZHNu$uGq8LoKLVkL!0%@?0l^r~{a1?ezJyni@n zs(+aaZ?^}i@5OyZ((el4r9Uyuv=LzUi35**F(>|C6g z3;J>Xbuvvv93KyJ|Izvu`}~5lHLZb zeYGv%oKHFTDiLQmkH1^$eZYBqtk4@9kNUSD@_Rq?oMgbXciT-rksWF#wjx|mmD+tm z0`Jh&qyJ}s>G%TTQjpmU(&M(_wugj!_~S$o+t@$ohrb~GHLm?R(3lfnZJkI+n_8IrR8VPwW5X zekvts;-ZvZTVGCo;n%`qsG*-}MlvfxGxNE^|J(9Y(Dr^PH|c0=uR;^A{~w{P{Qob# z_7phUnFFObp(H2Y=Y(ct+>eqSAIHH9wfXKFDl z=cJR0_;Q@rh$iR%&$(aE*zb31Yx0_!g!V5)6IJBoI}E(3WZHvC>x zT2Jq6-{6|h33nrN-O`7W=^_8xCR`IkI3D2$`!zUMTQnaD{plyHh%_W{j_`95AIJsm zIo^f+%=BeSj%B4kD-x&eBF*2LFa63DpRV;r_|3i6Py7So8}c=R^w#*-wC1`P&Z|d3 zsweR0Uuh!FlF1)@?ci&bOaA};R-RVc=?}0EXktB<^X~%rcWT_cDA@mQ`H6emk2}XT zZT%LgKwNeTS(NKqk%qRc>i#_NLwcV`f^yFOw;nU)IU~+eQm1_;wYLLu}!L7B*Gt7^#pG75goFVuA6e(^Kmv+Ukk;-`|vHPT4u=M#^#%hBp>c>UqF zIUIbo<>z1#65(~E_X|yZ$!{_~UG27d)Z`$?P7|M%#Itg~wo1MhvhR8gQHFD?k{Q4H z@4d_UIsNqh(I8d+d${mJN_K@>{Nx|x2cUeom{pOBJ5ZQXG~-?_PRo8_T8B?qxUD~h z>PLaHahyNx;f*4#C3eXDFzUKr=xW3TN&6lDn0TKrSO3x^T!j-8k;n_YO+iXvd=l(M zQ%>{yax6{#YSRxZwT-2Kd;CH-rC_W1(g%*Twd2|-*EaVH@qm0PkY+``{4MG}k$RZg z^9K*SrewU$zc}dkl}`MJxN_9|KKmb%NH&h0=G^$y{E45^9KtPWu@z)?k+@=nAK+G6 zq@Z8GAzZhEw7Qd5V$N%j%c3boV%4{ zK{C+m`Bz&i&TUK~+tU)6xxN~$dWGxibDp++9ACtBV^mQ;e|JFtEA~DIYPpboTT575 zeGIae?Mu>j`SV-$ z-edadHYcy3Kj(4c6f#OgLO1*tdCIW{WLT8UwDJ2V|F@Oo+}}CxRoZ%`JB2he(n^<9 zOST057%EA@{_!i3OaFf*ISD=Y4-WK4wJw-NK~j)mE7W$$&o~Kjyiei%P2x}aT1Lim zDctKM+>-)_Nbf7Z)pXr<3UZp`7rA}_UsE|p+ai}I^}ol-{MQVx8xf>)Y-$ipuRwm(JDGVP4@Ot|dP<%o%$i;aVC}dy1AO|SGJkI@&^S1geqH|sQ z=OA)D`wMB7!JMcqEs5_S;eU}o|KM$;fO_4(+b{iN&g)BppZNv)oWf~aNP$1%SSpU4 zAoJlI@5EO^3KJn6ZB0lwzhAJZ-aME~q767HF9qTALSAVu3Hm8NT4!mK@X8%#Yvb7d8%qvJKb#M|@MdX`-Jdr}F$y;3yZr+VsnW!)S>d z6yzdJm5fp^VPqZgOJ9#f`FMxhz9zw(w9KoGKk4BeA*~u*$G?1a+i=cZMZvoGGlI{q z{NJ`OK>rW(BWjY^J}zA6mo5{f9z!k1aJ(1B64v$^=cFXlbQJ0#HLpX$@00N=KSTcf zhu5BCb!aW#_VE_^1*}T?J^VuOF95u1oZngZ{|VG~1}9(V!g2o8u&j8(CH`&V-}5gV zPgvzhO2)6Y2I?9T)EiYR*uO;@Kl+)zI)^t)y)Q{e+aj*z|5v;1f7c)HH<~UxC-R?@ z-Nt88yaoQg#V`=b;3QqNkQ(akmaT+4QlbdHNv7}f#eZt>_)R=M`$2b*-WtMoLc4J;BpGElnnXL3Eo@OxFAjT2XPrlhxQLq4s z_GbSE3A}~NIX^iC<;}AH&vuG}jH2KvNK3y>r)>sd-r@DS(i#)|*5sdPd&l|uGD_lS zIe~v@?8PPX>i!_p+p19g{yBkJ9~$Z`IygZCea#U;^;TsMRCVu*WATzUVRHk|tf>Hfw!+75B7v;J#ycMil5$WBR@ zkVzH_k%sVfzxi5_&;ft{BaSunTPP9dwk9KO`a$DR67GW4IY&S9(e^dxyxQ_pF#hec z*N zzYufqDB-Sr&E@!VT5TBDq$AC;6tD&1UKHdH(pW=!SIGP}=V}|^5Ax_vPTJy^YAuO0 z^pZ zleqq57>_RcnRBLdU4P;ZkX}JN<=6H!1)51(g(<+toReSce|bu`m56iy)0g_;Lk;3r zkmxu+zMkKw+elQ~d1{o_Pq-5MH%a4nz7kS^dBpSQqP&Uh?`MBE$FK&?5q zJeei+uj%Kf-#)l7bAdQ1wC0!R^u(OPFaNvk2B!DR|BUia^6OQe>^D${c*KpR4%*Th z?)xIYbKd7zf6{!lb!C4d={NAJQowJ=?e>MQm?J_-5*f>wF|!hiNTQI6B11|gLq*f6Bq`0s z+o)7RR0t_eN@$*x6cv$DqBPLp`|anf=l#z0uIt+N-fP|KUiVu6|0$e7TjHAVw}SsL z@)LJi0v?Zs?kDamIcKO(lCBRh+@`+{^UoKJ^k=DYj1mNM(DoVAl%$OL8)RaLD+t^LG1W&h1d zsIDAqBtK0=C3|HFgLF00UQc|Gu4fQ-i+wl$J;7X(kepqB@FG0P9*I#Gvwv%nEj3ik z`c=FP{&VaP@z*J&|8EK?9jc42(a~UqwnTyH68gkQALPFUCVeKbQ4)ptA%#j1>+|!O zMb1NTR&>7>W&pe&g_zk9T*u=&Ql0juT04Et>pV)5eQVv6J^7850*ist=PQ%VLDE*C zWH%yvmzXo;{S5b05SRA2dPnC8*NwQG{h-*J)>wH{f@ij1_W2(lNiQOsL2iE2pRu2c$Jb_OjyHkP@~+|Q=-%Ev*&o(Ba-L5g z|H-}wDvB&;2Lo<*xmu^m-gG}*H`h6*ujoiN2jR30xe(Vv2kmk7kH{u>uW{ zc2IDD?mx0`_-`lPBYFGDse`I$;sx^Dz8dtqfkS!o(k269ZuZY;?wwEibwFRQ8#z5!e8IY z*^&GOttkFZYW2XoBF`^5TVoP~J*$j_m+WQSKXC1-^V<}y2m65YvtsvJ&ETde?i^@67s8cfaS+h`kJ>;RTOZb z0tXpkvZe$risyenf+9%&v6{uiu8g<2sY1z?iA@n(ia6Q*RtXsYQepOMqkmGTlWAO{ z#+fh+#TunQ^PU{)QqnpFyLrZUAnir{^+=Q5Ma<09rS6h_mGdL(8zPhc1YCPVz}}eT z0{$@}5>3_$Yx0dWvGm`+!c-MSe4PDYfq6*&M*Jk-<2f=#Cd2;2*ALl&$a_ZN3*qM= z`&9R%#jkKr_K>v|PkXp&RwMj}XzonnPu0wHd#a!L&E@GRlEQcKS2#W`P?8mIK`= z@Qrn=wN)qU?LT4esH2Ol^Qg~Rsd!H|%WVTQ1$GSqCGo80t8Kp==5j(xy5B_DdPS4f zGL75uzwUdk{%fC0?kAyxgbsqq`lPnlGUU^cREMd~Hw^9pgeMX8D11Y)WIg3|a$XPf zvAdtGn(09FCca*Z9uNYu;PlJ%CXEUe&Hj>S~0Emn;Jb4$FJ!Y;C&f!jsutz_nv*Hd8xw@W|E#L*2XMNp@MWcoWW1;26p~BD*mKbX3s2_Urx^25wtn|pP-=q zY9zx7fDVwf*dyr~&v>LxP7A{IL>z6z$zF}|Zi?8UIBtlJQ+zRD@4;V?E(L5_?)g8* zc@x!z;&~;^G~|!R{VR{*^hi7v(HPyHi1a4$W4&D06Y!1ubOH{8EoZL|SHXTeF+IdK zS>w`l#M?Tr760idM2kJE&*C{B79E@kcz_Ok$zJAicQ`o-klfV+%;pZF~?>4R~1 zgv+~_;7gJ2;kb*~m5L>M1;G=1m95e7*hVAl8pYQHuDs&o<((VF^0U3*il%ShejZO} z!?^(NvUKK4_MZLw^tWb3C@-4STgjSGc%g)3V<}E{g!kuy5OH`AjDfpf(Tf!y6{2Q1 zuM1%*?-BRo6|KQHBc8~scs>b^PQ|^q-4l|PL{d%R-jc3$zs5UpQjiT)tRJFR_@~=H zfVtj!Iv#gT-3}pkxgw+F^oRmShA?Sa+wOjx8b{&2!P=C52iZ^O*GOzb*+-lgAWrs# zkv(V~?L0!!3!Ph<#5L}HoIggk0$F***T-hJN>1~9cKwKwv$BO42 zXM}&Ip#3u>ry+Zfh`NaCIiC->UY9$9pfvIkNWQm{z2W{a!G-J>;W#;Pz3h*;UnPGt zzJj)o?=-&h=}(Z$T#_wB(q30Rb#}DvG>~^__KuarJ=B z+35f2syIwz#cow}hhi^@|LdN!D)CqbdW6a95_M5}{ueZqfRbUZckQtkzEn_64tb`PE#h(0kIdXGq7E}Yq*nU(VM(${+LM``64 z$;VW-=Bo}kAbj^JSYFZv_HGJ~miW1%BV%eeh;@hWLEK>LAGptP%n0$08Q-3snJ4Em zwKj?;E1LelaR<;1E~|{{aG)zGy#%lp(x!kDql;2}t6{FP4k|F#ry{GOX%9nV~`6>>f>iE{}}b`7Cq86yEFDO`r*TIwbMpP<7d3Hio7*{)QOfNoZwDE^ia z)>phe%zU}M5ZAVD##a-^-QrhCTb>9CSR46UVlqwgqCkolmXs{T*2ZWDAwDdtG#ko1 z0duyFCW@~Hd`m~QalFd+NO0Y5Y6m)3=9>z)J|=W~6irNbn$j;C%=64ANK?)X>bLO^4V#4{#__3f#etj?GzY||4+g7?#mSX89v#5rZYo< z{_=|OU7+C4{5P6ZRU9vR49QN`NCoHGIH$v8P5rD*k3F|t8&g?FZ3#rTD>{wh7Zo0( zNUxaEXoZ_8(gE?&#P5MU*co^Ct6n?lTAp zI9{+h;;{mE0WVW%9N#Sj+{6C})dwoD0rp|Bn$G?0g~V1MEE`2{6CWlvhOY_X$woRa zgdNIXCUCRV8JfOocCrGqk(5$&pmRaHoc}=yjSy6`Ht41kk^>~)7Sp=TIaxggK9+w# zj5_&-$uFvjzBrDM-^}>$F~z~|m!!P({+%h%PU2U9$+jp`!~K+a2M#GfxX={lOT1CB zP6WK2L@RO)f3gpCTrvc`f@hF(N3rT^w6<4sf6O`AllZgm|7#qp^L?4;JkQsHAY7T& z@gejP!XIFpxi^4os*AdTeUE>q_z2TURzKd0Ulci(&^A%@UV;ZjV_gsc3ixfDSkiX#@*mG7d9%oDW zbv5~#I`hQuaGs!n3Phcpe*bq3lHdM+B$?ldX%%9=!1jDhqDhSK2}Io#p9s?j_IYGE z+luFP>lB4n*e`&+kl=@%8#wm}QRi!>0Z-iT$ICd6JVI4^u2Av`Dde@|y4^J16p58}+$H`+=ON6}UseNtg2f;(UnnGGzCd)_ak6 zrDEk2xq{FdFyBRi$2B)RM8D=d$oUNM_OONBSEb+ojaI0u)l$)92P0ny_>g^T z8;N-!rt?xhH2Z4DF#B05gj2Z&fhL_G!ez$9yow6v8q`xk_LT%gD*g=fHi5rXE${*i=2_%`5w+Byy< zZ-dSn1=su-U%Kv%0%eVN6Y~A3E{=F#OzQ3+-4Drp*!u|lkM%a(Mm*`ozFn7dh-<89 zD;yj6*F@d|u@j5?jbwl7S%)SUQG z;1N;#_LNJ{V*5+5_v3t7liQtJ;U1s9E%X)*j0C!c$P;3!qeA5CeETcb0nbrLYnpCL z_cs+k%bJDkRI!@!|8)OQfgf?aC~v6Penef**Is-*&i;xvHN?xTN1abhUlvx--f-E5 zC|TOZMJMV00-|Fi*5$nAyarVbx50u>B)QX5DJ6EA(W9&DHl`*AL@Z4-owR)S# z^RUD6VVO^J#oe?0A1h&p;+rWyCW0R+h1}}ayDGv zF!%2KgB711Vkbtk!{m-iKa=kW84u~^4#2l{I9V6N;ytJyV!i?%WaX?O0c#Qc$0K-4 zPR{n?DJj3H;%5?dg#A`|n}TPf`(P{CM_Hf#A4O0c=urvDiXp!i(G~7X3v~1k-~RDp zCR{`JQ{_F5=rl#IAi5p@K^l25CX{doc?myIqbtnOuy;5=3|l7&OrPX>66tf%#f`?f zHb%841g(&GDBo_x$!hAnR{RYeMi<@%TF8tZowB6g(;#JeH^{ z6uK<`J;=*6r0QMkYQ)PCAAu~{x_m%pG2a#955+yjniUY+QsE`3p#9D$d_u&RdOUf~ z=Zako@;4FRnNVB%)%dC$p#Nu(Hw0Q|WP7cDbaA+j3&)FcoWxr~)DA?ObaZPJ63SWw zgpK&Fw7S9cR(PbGQFz}COkKMl)SLb1Wq-$A$az~{5T9W`N8#tKT>?FTXGty=A}SDc zX}nZ7+vgj5PaTX?@L3Hcn`Bb&$vsGX9$)hqd5S#?pR-j_v%5!;ef}p(Dx`3wNa*6e zKhOee5D}Z*Kk|5zUFUwWLKnifM{pK@G54Hx!0}56y;xqd(wZnn&|g;Dz&3I&nZ7MJ z*#gdov#0!DzC>Qt7^_R{Lirus-E`X66^tTpw2+4ms*f|&E*es^zbTHD+!M^3^X9zv_cNZ+-Ok4LjJ z`_FO%U88u;%1SsC$yJf~dx&{1CnWZt#Q!yoWdG4sO}P2?osrijjoiHp{1n2=h4_SD zi$B?w=`Xks7ieZ28-SCYir_~b)eKPb^@Dk-z&-hnfqP%k+e2WpXyQ}Pw*kK5K0Hs1 z=Uz?MugbZ`{b#ZJP2dfCUVQ={Ml{fVzrpKY&5#E=l1_DIF_jKs=ed6q1-BFM6j8~pR_JEyFgc$oyczFeYZ6Q?t5CufsGs@R z*ajL=vTG$a2l_+tj)W}*zLf7)g}&73ZmUl|H1i*M|0wc3(Y4@TC+IZs{(Q+Q5<1sC zXEpGiPspX|`ENknJ%Y;>I8^e5f;npeTqZi25aLp-wMTKMShBa|ZHlQ3!1Z9@TfqFU zb;dCqcCytXeOvf*MpJ_GWL*xm9}>y4kR~f7ejVR^_TC}vU7c;$)i>7fx=7Z+zAQu> zg6m*HzH!fUJ~X)c@m&*BDSz4lRpsF$L3Sh~2sq!R`Q7mU) zIh>-v)F{@ExF4gF9A*iDtN5zI{fCGWfqfWvqnOOo8l4%9Rx*{mUIYx6xD?C35;l98 zZbx3IfbteZoke{sLYu?i8IR!?{;DzBoQPo|s#*d6GQ4dy^BRusgnaE>BcCJBzbh?> z^iTWCSX$YWl_>D??3J)J2ww^H3G*|t$tG&xPvqYrKfgdc#r6?7S8jd#Cb(o{)SIut zH`ABMRiKdRA`B{(JC*YE2Tf$4??m`!cDpyL+~l$2N%fA zey=E^4dN5iG{x59yB_X(c@5+C2+F4f%#=cnyE6uDJ=8WD%WcQoB<#0?ML2hyMalMM$fEuoJ> zO=CRSfM1RUeuc0yR{u1<2+RqRbnVN37UGIA>YdSDh1kdPkB0vM?uB?~QeM^c7u-h* zobPf1f~SmjYK-V#LOza;FLFKsN%QEq4gZ^R9+Z>pbN<$*_5!Yo3VdgE$$!H$jrg87 z`kFBJYGSS2${MYngrxpk8_z@51qz&x85# z#+7XB7^dfNxMmlxY<If_fa}N-YTuj3dHOSOs9B6kMkc~SpS`=e^t_-I$IUpbs*v$g$9aM zLb{NkyG>$9#FL1h_d3gyC)k)=t=pko&VmeIz`eW*SyW!a=!dF@W`*YempJox0MFLRy2#k3cq<9XK2iK>iI<6&i0;pi=QIm0*>saR z(0(DVN0FZsg3pMFOm^>K(zS8cCw5j6nd;XWzEo@nq5;nLSVwv!uZcHM zteQfz5hc6Z`6clQIJTNXvcqBb!0w634#l-n-d_qn2h)t8zpc6Ad8H6^k@T2^>PYec z8v$O7w4kM_&C&U8xI^XS>PE$3E169_mUMw{XT5$>_xSM)dW%RPJasi8-{u_>U)`k=T|X`A!$posWiV`-x*msuP|CIVez%_HJ%k%fwl z3qcc*BUhfeP$aFF|K{z~?*-Cs&?XxQg)=E`|E$lf4gn^+O}VjG0zeH z0^C0_r8D_{NFV=ufW|AbIbO0qjdW6U{Hyar$ZAMl9t9_aklf^7H^C_iUm~Xp^1jX| z!_1SjEkM2TA1S|tqE9;4F|7f3^JXY|c@Pc^)k%3N{;s-w-+5+%soaKiUjne{gr6Td zhbr_X;$+*b;qKGytzm}ZdYiZ<>P#WxAA1jbh4iWZ)}C=61v*pSlez|pfu+AA+9dI1 ziBBqeoTP8~_c`|z8>NG%<^ActT(KYFP9oq({$a4&V$4^%@8>Nt`Pr&uacJn2>JGxtlBv~&Lx!3xDuw*;z`x9|;{x!2m(aLhW$BWxo_sN>zy#vP; z1l~`4vOKtz>Er(rmvxjq0F<*rh+aUljF`DOr~QdYt}b~i(eJpYT7`*7c9u?8gxG6v zw#s*BZsz-xnD67>hVbUjdEbZ9wTLbYl7?AE{|^8lC~PXR;Hcp?(qTMZo#EZ-pO*SO0#ahhTqd>u|p3 ze1rXS`)3L?b)GMwf_MWYEu(|$#2fM_o5%mXDRhFVq+kzC^ylj(e{en|Gs69sc=_tW z{UCozYDE3a3!(OLiWa)xiueQTb0hl`Nf{j_+a{?CY!d}G^JjFQY!UwrA#8KLD|55_ z&lG$kM20(4C*HBLcoxaY`<$|Ry6jBNOhkiqu+o~zccA?p34IkC9U>CZ;nB%q1U}yN=eWSthB=(T*KxHa zdIPR!(%*y)m3S;rc`B0)ko=&%b9%mnHIA;%m(W|`j{FU*c2O|p8`tQHaWWOVNjr7UI}WRn9sndIhpm2sm53uB0Q7-KUG3oyxb?x*#4=^0$`L zDabq8{}g*RM9hLc*ZIcmhhCN?FEdSnFBN{A+VaLeu3Vqz` zDRLk3`-12b@qO|hQ(&ifvab{_CH^t~^YUGpr{r7`JWuogy#Ej%^OBQ2DDX8Azvf>v zg9F$O(Od-&w;!WGL-@1pA6kDI>#t(7bhX<(XQ!FcZ1-Xsx_Ie^v4vI_nOtOip`}H} z7rv!kp|+E6TU6L8vh=n^MLVvn(Bi0OZK^kG()Q?PZJV}g)T~*v=53lS-8{b7mSU5S f%`3L_*u3I\n" "Language: rtl\n" @@ -6713,19 +6713,6 @@ msgstr "Ȼønƃɹɐʇnlɐʇᴉøns, ʎøn bnɐlᴉɟᴉǝd ɟøɹ ɐ ɔǝɹʇᴉ msgid "You've earned a certificate for this course." msgstr "Ɏøn'ʌǝ ǝɐɹnǝd ɐ ɔǝɹʇᴉɟᴉɔɐʇǝ ɟøɹ ʇɥᴉs ɔønɹsǝ." -#: lms/djangoapps/courseware/views/views.py -msgid "Certificate unavailable" -msgstr "Ȼǝɹʇᴉɟᴉɔɐʇǝ nnɐʌɐᴉlɐblǝ" - -#: lms/djangoapps/courseware/views/views.py -#, python-brace-format -msgid "" -"You have not received a certificate because you do not have a current " -"{platform_name} verified identity." -msgstr "" -"Ɏøn ɥɐʌǝ nøʇ ɹǝɔǝᴉʌǝd ɐ ɔǝɹʇᴉɟᴉɔɐʇǝ bǝɔɐnsǝ ʎøn dø nøʇ ɥɐʌǝ ɐ ɔnɹɹǝnʇ " -"{platform_name} ʌǝɹᴉɟᴉǝd ᴉdǝnʇᴉʇʎ." - #: lms/djangoapps/courseware/views/views.py msgid "Your certificate will be available soon!" msgstr "Ɏønɹ ɔǝɹʇᴉɟᴉɔɐʇǝ ʍᴉll bǝ ɐʌɐᴉlɐblǝ søøn!" @@ -6742,6 +6729,19 @@ msgstr "" msgid "Your certificate is available" msgstr "Ɏønɹ ɔǝɹʇᴉɟᴉɔɐʇǝ ᴉs ɐʌɐᴉlɐblǝ" +#: lms/djangoapps/courseware/views/views.py +msgid "Certificate unavailable" +msgstr "Ȼǝɹʇᴉɟᴉɔɐʇǝ nnɐʌɐᴉlɐblǝ" + +#: lms/djangoapps/courseware/views/views.py +#, python-brace-format +msgid "" +"You have not received a certificate because you do not have a current " +"{platform_name} verified identity." +msgstr "" +"Ɏøn ɥɐʌǝ nøʇ ɹǝɔǝᴉʌǝd ɐ ɔǝɹʇᴉɟᴉɔɐʇǝ bǝɔɐnsǝ ʎøn dø nøʇ ɥɐʌǝ ɐ ɔnɹɹǝnʇ " +"{platform_name} ʌǝɹᴉɟᴉǝd ᴉdǝnʇᴉʇʎ." + #: lms/djangoapps/courseware/views/views.py #, python-brace-format msgid "To see course content, {sign_in_link} or {register_link}." @@ -6898,16 +6898,26 @@ msgid "Good" msgstr "Ǥøød" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html -#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s: Reported content awaits review" -msgstr "%(course_name)s: Ɍǝdøɹʇǝd ɔønʇǝnʇ ɐʍɐᴉʇs ɹǝʌᴉǝʍ" +msgid "" +"\n" +" %(course_name)s: Reported content awaits review\n" +" " +msgstr "" +"\n" +" %(course_name)s: Ɍǝdøɹʇǝd ɔønʇǝnʇ ɐʍɐᴉʇs ɹǝʌᴉǝʍ\n" +" " #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt msgid "Go to Discussion" msgstr "Ǥø ʇø Đᴉsɔnssᴉøn" +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +#, python-format +msgid "%(course_name)s: Reported content awaits review" +msgstr "%(course_name)s: Ɍǝdøɹʇǝd ɔønʇǝnʇ ɐʍɐᴉʇs ɹǝʌᴉǝʍ" + #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/subject.txt #, python-format msgid " %(course_name)s %(course_id)s moderator content for review " @@ -11361,6 +11371,11 @@ msgstr "" msgid "The '{field_name}' field cannot be edited." msgstr "Ŧɥǝ '{field_name}' ɟᴉǝld ɔɐnnøʇ bǝ ǝdᴉʇǝd." +#: openedx/core/djangoapps/user_api/accounts/api.py +#: openedx/core/djangoapps/user_authn/views/registration_form.py +msgid "Enter a valid name" +msgstr "Ɇnʇǝɹ ɐ ʌɐlᴉd nɐɯǝ" + #. Translators: This label appears above a field which allows the #. user to input the First Name #. Translators: This label appears above a field on the registration form @@ -11860,10 +11875,6 @@ msgstr "Ŧɥǝ dɹøʌᴉdǝd ɐɔɔǝss_ʇøʞǝn ᴉs nøʇ ʌɐlᴉd." msgid "Full Name cannot contain the following characters: < >" msgstr "Fnll Nɐɯǝ ɔɐnnøʇ ɔønʇɐᴉn ʇɥǝ ɟølløʍᴉnƃ ɔɥɐɹɐɔʇǝɹs: < >" -#: openedx/core/djangoapps/user_authn/views/registration_form.py -msgid "Enter a valid name" -msgstr "Ɇnʇǝɹ ɐ ʌɐlᴉd nɐɯǝ" - #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "A properly formatted e-mail is required" msgstr "Ⱥ dɹødǝɹlʎ ɟøɹɯɐʇʇǝd ǝ-ɯɐᴉl ᴉs ɹǝbnᴉɹǝd" @@ -16490,8 +16501,8 @@ msgid "Share with friends and family!" msgstr "Sɥɐɹǝ ʍᴉʇɥ ɟɹᴉǝnds ɐnd ɟɐɯᴉlʎ!" #: lms/templates/courseware/course_about_sidebar_header.html -msgid "I just enrolled in {number} {title} through {account}: {url}" -msgstr "Ɨ ɾnsʇ ǝnɹøllǝd ᴉn {number} {title} ʇɥɹønƃɥ {account}: {url}" +msgid "I just enrolled in {number} {title} through {account} {url}" +msgstr "Ɨ ɾnsʇ ǝnɹøllǝd ᴉn {number} {title} ʇɥɹønƃɥ {account} {url}" #: lms/templates/courseware/course_about_sidebar_header.html msgid "I just enrolled in {number} {title} through {platform} {url}" diff --git a/conf/locale/rtl/LC_MESSAGES/djangojs.mo b/conf/locale/rtl/LC_MESSAGES/djangojs.mo index 636b10fb32b7c2d842b7afd3e41a83cf37e1703c..0dcc2626674cc5129ec3695d13d846139eba81ed 100644 GIT binary patch delta 48 zcmbQ$DmbfEu%U%<3sZ-fh?%Z|v4Wwwm63&&fuWv-k+G4XQTrS*CLm_sK1Yn@pEdwe Cjt$5F delta 48 zcmbQ$DmbfEu%U%<3sZ-fh^elTrGk-xm5Gs+p}C%sv6-=\n" "Language: rtl\n" diff --git a/conf/locale/ru/LC_MESSAGES/djangojs.po b/conf/locale/ru/LC_MESSAGES/djangojs.po index eeed26b030..90bb69360a 100644 --- a/conf/locale/ru/LC_MESSAGES/djangojs.po +++ b/conf/locale/ru/LC_MESSAGES/djangojs.po @@ -191,7 +191,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: ashed , 2022\n" "Language-Team: Russian (http://www.transifex.com/open-edx/edx-platform/language/ru/)\n" diff --git a/conf/locale/sk/LC_MESSAGES/django.po b/conf/locale/sk/LC_MESSAGES/django.po index 9c6c419855..1e16f9f11a 100644 --- a/conf/locale/sk/LC_MESSAGES/django.po +++ b/conf/locale/sk/LC_MESSAGES/django.po @@ -55,7 +55,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Waheed Ahmed , 2019\n" "Language-Team: Slovak (https://www.transifex.com/open-edx/teams/6205/sk/)\n" @@ -6217,7 +6217,7 @@ msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/sk/LC_MESSAGES/djangojs.po b/conf/locale/sk/LC_MESSAGES/djangojs.po index 525e5fec90..3234bd518b 100644 --- a/conf/locale/sk/LC_MESSAGES/djangojs.po +++ b/conf/locale/sk/LC_MESSAGES/djangojs.po @@ -46,7 +46,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: \n" "Language-Team: Slovak (http://www.transifex.com/open-edx/edx-platform/language/sk/)\n" diff --git a/conf/locale/sw_KE/LC_MESSAGES/django.po b/conf/locale/sw_KE/LC_MESSAGES/django.po index 8bf8264fc2..d0d536ab49 100644 --- a/conf/locale/sw_KE/LC_MESSAGES/django.po +++ b/conf/locale/sw_KE/LC_MESSAGES/django.po @@ -85,7 +85,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Waheed Ahmed , 2019\n" "Language-Team: Swahili (Kenya) (https://www.transifex.com/open-edx/teams/6205/sw_KE/)\n" @@ -6320,7 +6320,7 @@ msgstr "Vizuri" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/sw_KE/LC_MESSAGES/djangojs.po b/conf/locale/sw_KE/LC_MESSAGES/djangojs.po index 81035fbca9..5cf9e47d00 100644 --- a/conf/locale/sw_KE/LC_MESSAGES/djangojs.po +++ b/conf/locale/sw_KE/LC_MESSAGES/djangojs.po @@ -71,7 +71,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: YAHAYA MWAVURIZI , 2017\n" "Language-Team: Swahili (Kenya) (http://www.transifex.com/open-edx/edx-platform/language/sw_KE/)\n" diff --git a/conf/locale/th/LC_MESSAGES/django.po b/conf/locale/th/LC_MESSAGES/django.po index 90bd76b48b..b93b6341fe 100644 --- a/conf/locale/th/LC_MESSAGES/django.po +++ b/conf/locale/th/LC_MESSAGES/django.po @@ -115,7 +115,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Waheed Ahmed , 2019\n" "Language-Team: Thai (https://www.transifex.com/open-edx/teams/6205/th/)\n" @@ -6098,7 +6098,7 @@ msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/th/LC_MESSAGES/djangojs.po b/conf/locale/th/LC_MESSAGES/djangojs.po index 8b6cacddf1..04e522ef7a 100644 --- a/conf/locale/th/LC_MESSAGES/djangojs.po +++ b/conf/locale/th/LC_MESSAGES/djangojs.po @@ -73,7 +73,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: edx demo , 2019\n" "Language-Team: Thai (http://www.transifex.com/open-edx/edx-platform/language/th/)\n" diff --git a/conf/locale/tr_TR/LC_MESSAGES/django.po b/conf/locale/tr_TR/LC_MESSAGES/django.po index 61a2deb856..241192a602 100644 --- a/conf/locale/tr_TR/LC_MESSAGES/django.po +++ b/conf/locale/tr_TR/LC_MESSAGES/django.po @@ -132,7 +132,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Ali Işıngör , 2021\n" "Language-Team: Turkish (Turkey) (https://www.transifex.com/open-edx/teams/6205/tr_TR/)\n" @@ -6965,7 +6965,7 @@ msgstr "İyi" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/tr_TR/LC_MESSAGES/djangojs.po b/conf/locale/tr_TR/LC_MESSAGES/djangojs.po index ee3e678452..421c8f363b 100644 --- a/conf/locale/tr_TR/LC_MESSAGES/djangojs.po +++ b/conf/locale/tr_TR/LC_MESSAGES/djangojs.po @@ -108,7 +108,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Ali Işıngör , 2018,2020-2021\n" "Language-Team: Turkish (Turkey) (http://www.transifex.com/open-edx/edx-platform/language/tr_TR/)\n" diff --git a/conf/locale/uk/LC_MESSAGES/django.po b/conf/locale/uk/LC_MESSAGES/django.po index 2027a51cdd..ab28eae8cb 100644 --- a/conf/locale/uk/LC_MESSAGES/django.po +++ b/conf/locale/uk/LC_MESSAGES/django.po @@ -124,7 +124,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Danylo Shcherbak , 2020\n" "Language-Team: Ukrainian (https://www.transifex.com/open-edx/teams/6205/uk/)\n" @@ -6882,7 +6882,7 @@ msgstr "Добре" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/uk/LC_MESSAGES/djangojs.po b/conf/locale/uk/LC_MESSAGES/djangojs.po index dad769af15..33de87fd45 100644 --- a/conf/locale/uk/LC_MESSAGES/djangojs.po +++ b/conf/locale/uk/LC_MESSAGES/djangojs.po @@ -102,7 +102,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Andrey Kryachko, 2018\n" "Language-Team: Ukrainian (http://www.transifex.com/open-edx/edx-platform/language/uk/)\n" diff --git a/conf/locale/vi/LC_MESSAGES/django.po b/conf/locale/vi/LC_MESSAGES/django.po index 7c697b65da..7951aa59db 100644 --- a/conf/locale/vi/LC_MESSAGES/django.po +++ b/conf/locale/vi/LC_MESSAGES/django.po @@ -198,7 +198,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Le Minh Tri , 2020\n" "Language-Team: Vietnamese (https://www.transifex.com/open-edx/teams/6205/vi/)\n" @@ -6163,7 +6163,7 @@ msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/vi/LC_MESSAGES/djangojs.po b/conf/locale/vi/LC_MESSAGES/djangojs.po index 669cb14df2..9076ac42dc 100644 --- a/conf/locale/vi/LC_MESSAGES/djangojs.po +++ b/conf/locale/vi/LC_MESSAGES/djangojs.po @@ -113,7 +113,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Le Minh Tri , 2020\n" "Language-Team: Vietnamese (http://www.transifex.com/open-edx/edx-platform/language/vi/)\n" diff --git a/conf/locale/zh_CN/LC_MESSAGES/django.po b/conf/locale/zh_CN/LC_MESSAGES/django.po index d2f0829519..fa42704379 100644 --- a/conf/locale/zh_CN/LC_MESSAGES/django.po +++ b/conf/locale/zh_CN/LC_MESSAGES/django.po @@ -397,7 +397,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: ifLab , 2019\n" "Language-Team: Chinese (China) (https://www.transifex.com/open-edx/teams/6205/zh_CN/)\n" @@ -6551,7 +6551,7 @@ msgstr "好" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/zh_CN/LC_MESSAGES/djangojs.po b/conf/locale/zh_CN/LC_MESSAGES/djangojs.po index cd73439999..35ed23a08f 100644 --- a/conf/locale/zh_CN/LC_MESSAGES/djangojs.po +++ b/conf/locale/zh_CN/LC_MESSAGES/djangojs.po @@ -226,7 +226,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: jsgang , 2015-2017,2020\n" "Language-Team: Chinese (China) (http://www.transifex.com/open-edx/edx-platform/language/zh_CN/)\n" diff --git a/conf/locale/zh_HANS/LC_MESSAGES/django.po b/conf/locale/zh_HANS/LC_MESSAGES/django.po index d2f0829519..fa42704379 100644 --- a/conf/locale/zh_HANS/LC_MESSAGES/django.po +++ b/conf/locale/zh_HANS/LC_MESSAGES/django.po @@ -397,7 +397,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: ifLab , 2019\n" "Language-Team: Chinese (China) (https://www.transifex.com/open-edx/teams/6205/zh_CN/)\n" @@ -6551,7 +6551,7 @@ msgstr "好" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/zh_HANS/LC_MESSAGES/djangojs.po b/conf/locale/zh_HANS/LC_MESSAGES/djangojs.po index cd73439999..35ed23a08f 100644 --- a/conf/locale/zh_HANS/LC_MESSAGES/djangojs.po +++ b/conf/locale/zh_HANS/LC_MESSAGES/djangojs.po @@ -226,7 +226,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: jsgang , 2015-2017,2020\n" "Language-Team: Chinese (China) (http://www.transifex.com/open-edx/edx-platform/language/zh_CN/)\n" diff --git a/conf/locale/zh_TW/LC_MESSAGES/django.po b/conf/locale/zh_TW/LC_MESSAGES/django.po index 443cba801e..5f030a5964 100644 --- a/conf/locale/zh_TW/LC_MESSAGES/django.po +++ b/conf/locale/zh_TW/LC_MESSAGES/django.po @@ -177,7 +177,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Waheed Ahmed , 2019\n" "Language-Team: Chinese (Taiwan) (https://www.transifex.com/open-edx/teams/6205/zh_TW/)\n" @@ -6278,7 +6278,7 @@ msgstr "好" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt #, python-format -msgid "%(course_name)s %(course_id)s Reported content awaits review" +msgid "%(course_name)s: Reported content awaits review" msgstr "" #: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html diff --git a/conf/locale/zh_TW/LC_MESSAGES/djangojs.po b/conf/locale/zh_TW/LC_MESSAGES/djangojs.po index 5aa06768f8..cb6750e90e 100644 --- a/conf/locale/zh_TW/LC_MESSAGES/djangojs.po +++ b/conf/locale/zh_TW/LC_MESSAGES/djangojs.po @@ -132,7 +132,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-05-22 20:43+0000\n" +"POT-Creation-Date: 2022-05-29 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Andrew Lau , 2017\n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/open-edx/edx-platform/language/zh_TW/)\n" From 92ca176fde41fe2fb1827b51293bb96ae9a21b3f Mon Sep 17 00:00:00 2001 From: Sagirov Eugeniy Date: Mon, 18 Apr 2022 16:50:51 +0300 Subject: [PATCH 16/63] refactor: Remove legacy course info page & related code --- .github/workflows/pylint-checks.yml | 2 +- .github/workflows/unit-test-shards.json | 2 - .../management/commands/edit_course_tabs.py | 4 +- .../tests/test_backfill_course_tabs.py | 24 +- .../contentstore/tests/test_import.py | 2 +- cms/djangoapps/contentstore/views/tabs.py | 4 +- .../contentstore/views/tests/test_tabs.py | 12 +- cms/envs/common.py | 3 - common/djangoapps/util/views.py | 5 - common/lib/xmodule/xmodule/course_module.py | 8 - .../tests/test_split_modulestore.py | 14 +- common/lib/xmodule/xmodule/tabs.py | 22 +- common/lib/xmodule/xmodule/tests/test_tabs.py | 117 +++++ .../scoreable/policies/course/policy.json | 4 - .../lms/templates/courseware/courses.html | 2 +- .../lms/templates/courseware/info.html | 2 - .../lms/templates/courseware/progress.html | 2 + lms/djangoapps/courseware/tabs.py | 27 +- .../courseware/tests/test_course_info.py | 417 ------------------ .../courseware/tests/test_date_summary.py | 18 +- .../courseware/tests/test_masquerade.py | 55 --- lms/djangoapps/courseware/tests/test_tabs.py | 44 +- lms/djangoapps/courseware/tests/test_views.py | 14 - lms/djangoapps/courseware/views/views.py | 152 +------ lms/envs/common.py | 6 +- lms/static/sass/course/_info.scss | 386 ---------------- lms/templates/courseware/info.html | 125 ------ lms/urls.py | 11 +- .../tests/test_course_overviews.py | 2 +- .../core/djangoapps/schedules/docs/README.rst | 11 - .../schedules/tests/test_resolvers.py | 2 +- .../core/djangoapps/self_paced/__init__.py | 0 openedx/core/djangoapps/self_paced/admin.py | 11 - .../self_paced/migrations/0001_initial.py | 27 -- .../self_paced/migrations/__init__.py | 0 openedx/core/djangoapps/self_paced/models.py | 21 - .../tests/test_theme_style_overrides.py | 4 +- .../features/course_experience/__init__.py | 9 - openedx/features/course_experience/plugins.py | 3 - .../enterprise_support/tests/test_api.py | 7 +- setup.py | 1 - 41 files changed, 176 insertions(+), 1406 deletions(-) create mode 100644 common/lib/xmodule/xmodule/tests/test_tabs.py delete mode 100644 common/test/test-theme/lms/templates/courseware/info.html create mode 100644 common/test/test-theme/lms/templates/courseware/progress.html delete mode 100644 lms/djangoapps/courseware/tests/test_course_info.py delete mode 100644 lms/static/sass/course/_info.scss delete mode 100644 lms/templates/courseware/info.html delete mode 100644 openedx/core/djangoapps/self_paced/__init__.py delete mode 100644 openedx/core/djangoapps/self_paced/admin.py delete mode 100644 openedx/core/djangoapps/self_paced/migrations/0001_initial.py delete mode 100644 openedx/core/djangoapps/self_paced/migrations/__init__.py delete mode 100644 openedx/core/djangoapps/self_paced/models.py diff --git a/.github/workflows/pylint-checks.yml b/.github/workflows/pylint-checks.yml index 4f95444df5..e64999afb4 100644 --- a/.github/workflows/pylint-checks.yml +++ b/.github/workflows/pylint-checks.yml @@ -21,7 +21,7 @@ jobs: - module-name: openedx-1 path: "openedx/core/types/ openedx/core/djangoapps/ace_common/ openedx/core/djangoapps/agreements/ openedx/core/djangoapps/api_admin/ openedx/core/djangoapps/auth_exchange/ openedx/core/djangoapps/bookmarks/ openedx/core/djangoapps/cache_toolbox/ openedx/core/djangoapps/catalog/ openedx/core/djangoapps/ccxcon/ openedx/core/djangoapps/commerce/ openedx/core/djangoapps/common_initialization/ openedx/core/djangoapps/common_views/ openedx/core/djangoapps/config_model_utils/ openedx/core/djangoapps/content/ openedx/core/djangoapps/content_libraries/ openedx/core/djangoapps/contentserver/ openedx/core/djangoapps/cookie_metadata/ openedx/core/djangoapps/cors_csrf/ openedx/core/djangoapps/course_apps/ openedx/core/djangoapps/course_date_signals/ openedx/core/djangoapps/course_groups/ openedx/core/djangoapps/courseware_api/ openedx/core/djangoapps/crawlers/ openedx/core/djangoapps/credentials/ openedx/core/djangoapps/credit/ openedx/core/djangoapps/dark_lang/ openedx/core/djangoapps/debug/ openedx/core/djangoapps/demographics/ openedx/core/djangoapps/discussions/ openedx/core/djangoapps/django_comment_common/ openedx/core/djangoapps/embargo/ openedx/core/djangoapps/enrollments/ openedx/core/djangoapps/external_user_ids/ openedx/core/djangoapps/zendesk_proxy/ openedx/core/djangolib/ openedx/core/lib/ openedx/core/tests/ openedx/core/djangoapps/course_live/" - module-name: openedx-2 - path: "openedx/core/djangoapps/geoinfo/ openedx/core/djangoapps/header_control/ openedx/core/djangoapps/heartbeat/ openedx/core/djangoapps/lang_pref/ openedx/core/djangoapps/models/ openedx/core/djangoapps/monkey_patch/ openedx/core/djangoapps/oauth_dispatch/ openedx/core/djangoapps/olx_rest_api/ openedx/core/djangoapps/password_policy/ openedx/core/djangoapps/plugin_api/ openedx/core/djangoapps/plugins/ openedx/core/djangoapps/profile_images/ openedx/core/djangoapps/programs/ openedx/core/djangoapps/safe_sessions/ openedx/core/djangoapps/schedules/ openedx/core/djangoapps/self_paced/ openedx/core/djangoapps/service_status/ openedx/core/djangoapps/session_inactivity_timeout/ openedx/core/djangoapps/signals/ openedx/core/djangoapps/site_configuration/ openedx/core/djangoapps/system_wide_roles/ openedx/core/djangoapps/theming/ openedx/core/djangoapps/user_api/ openedx/core/djangoapps/user_authn/ openedx/core/djangoapps/util/ openedx/core/djangoapps/verified_track_content/ openedx/core/djangoapps/video_config/ openedx/core/djangoapps/video_pipeline/ openedx/core/djangoapps/waffle_utils/ openedx/core/djangoapps/xblock/ openedx/core/djangoapps/xmodule_django/ openedx/core/tests/ openedx/features/ openedx/testing/ openedx/tests/ openedx/core/djangoapps/learner_pathway/" + path: "openedx/core/djangoapps/geoinfo/ openedx/core/djangoapps/header_control/ openedx/core/djangoapps/heartbeat/ openedx/core/djangoapps/lang_pref/ openedx/core/djangoapps/models/ openedx/core/djangoapps/monkey_patch/ openedx/core/djangoapps/oauth_dispatch/ openedx/core/djangoapps/olx_rest_api/ openedx/core/djangoapps/password_policy/ openedx/core/djangoapps/plugin_api/ openedx/core/djangoapps/plugins/ openedx/core/djangoapps/profile_images/ openedx/core/djangoapps/programs/ openedx/core/djangoapps/safe_sessions/ openedx/core/djangoapps/schedules/ openedx/core/djangoapps/service_status/ openedx/core/djangoapps/session_inactivity_timeout/ openedx/core/djangoapps/signals/ openedx/core/djangoapps/site_configuration/ openedx/core/djangoapps/system_wide_roles/ openedx/core/djangoapps/theming/ openedx/core/djangoapps/user_api/ openedx/core/djangoapps/user_authn/ openedx/core/djangoapps/util/ openedx/core/djangoapps/verified_track_content/ openedx/core/djangoapps/video_config/ openedx/core/djangoapps/video_pipeline/ openedx/core/djangoapps/waffle_utils/ openedx/core/djangoapps/xblock/ openedx/core/djangoapps/xmodule_django/ openedx/core/tests/ openedx/features/ openedx/testing/ openedx/tests/ openedx/core/djangoapps/learner_pathway/" - module-name: common path: "common" - module-name: cms diff --git a/.github/workflows/unit-test-shards.json b/.github/workflows/unit-test-shards.json index 838d0fe261..d106c71e04 100644 --- a/.github/workflows/unit-test-shards.json +++ b/.github/workflows/unit-test-shards.json @@ -132,7 +132,6 @@ "openedx/core/djangoapps/programs/", "openedx/core/djangoapps/safe_sessions/", "openedx/core/djangoapps/schedules/", - "openedx/core/djangoapps/self_paced/", "openedx/core/djangoapps/service_status/", "openedx/core/djangoapps/session_inactivity_timeout/", "openedx/core/djangoapps/signals/", @@ -212,7 +211,6 @@ "openedx/core/djangoapps/programs/", "openedx/core/djangoapps/safe_sessions/", "openedx/core/djangoapps/schedules/", - "openedx/core/djangoapps/self_paced/", "openedx/core/djangoapps/service_status/", "openedx/core/djangoapps/session_inactivity_timeout/", "openedx/core/djangoapps/signals/", diff --git a/cms/djangoapps/contentstore/management/commands/edit_course_tabs.py b/cms/djangoapps/contentstore/management/commands/edit_course_tabs.py index feb624ce49..0381d638d8 100644 --- a/cms/djangoapps/contentstore/management/commands/edit_course_tabs.py +++ b/cms/djangoapps/contentstore/management/commands/edit_course_tabs.py @@ -33,7 +33,7 @@ def print_course(course): # course.tabs looks like this -# [{u'type': u'courseware'}, {u'type': u'course_info', u'name': u'Course Info'}, {u'type': u'textbooks'}, +# [{u'type': u'courseware'}, {u'type': u'textbooks'}, # {u'type': u'discussion', u'name': u'Discussion'}, {u'type': u'wiki', u'name': u'Wiki'}, # {u'type': u'progress', u'name': u'Progress'}] @@ -53,7 +53,7 @@ command again, adding --insert or --delete to edit the list. course_help = '--course required, e.g. Stanford/CS99/2013_spring' delete_help = '--delete ' - insert_help = '--insert , e.g. 4 "course_info" "Course Info"' + insert_help = '--insert , e.g. 4 "discussion" "Discussion"' def add_arguments(self, parser): parser.add_argument('--course', diff --git a/cms/djangoapps/contentstore/management/commands/tests/test_backfill_course_tabs.py b/cms/djangoapps/contentstore/management/commands/tests/test_backfill_course_tabs.py index 258f00a133..a83eb621b3 100644 --- a/cms/djangoapps/contentstore/management/commands/tests/test_backfill_course_tabs.py +++ b/cms/djangoapps/contentstore/management/commands/tests/test_backfill_course_tabs.py @@ -40,13 +40,13 @@ class BackfillCourseTabsTest(ModuleStoreTestCase): course = CourseFactory() course.tabs = [tab for tab in course.tabs if tab.type != 'dates'] self.update_course(course, ModuleStoreEnum.UserID.test) - assert len(course.tabs) == 6 + assert len(course.tabs) == 5 assert 'dates' not in {tab.type for tab in course.tabs} call_command('backfill_course_tabs') course = self.store.get_course(course.id) - assert len(course.tabs) == 7 + assert len(course.tabs) == 6 assert 'dates' in {tab.type for tab in course.tabs} mock_logger.info.assert_any_call(f'Updating tabs for {course.id}.') mock_logger.info.assert_any_call(f'Successfully updated tabs for {course.id}.') @@ -66,16 +66,16 @@ class BackfillCourseTabsTest(ModuleStoreTestCase): CourseFactory() CourseFactory() course = CourseFactory() - course.tabs = [tab for tab in course.tabs if tab.type in ('course_info', 'courseware')] + course.tabs = [tab for tab in course.tabs if tab.type == 'courseware'] self.update_course(course, ModuleStoreEnum.UserID.test) - assert len(course.tabs) == 2 + assert len(course.tabs) == 1 assert 'dates' not in {tab.type for tab in course.tabs} assert 'progress' not in {tab.type for tab in course.tabs} call_command('backfill_course_tabs') course = self.store.get_course(course.id) - assert len(course.tabs) == 7 + assert len(course.tabs) == 6 assert 'dates' in {tab.type for tab in course.tabs} assert 'progress' in {tab.type for tab in course.tabs} mock_logger.info.assert_any_call('4 courses read from modulestore. Processing 0 to 4.') @@ -99,8 +99,8 @@ class BackfillCourseTabsTest(ModuleStoreTestCase): course_2 = CourseFactory() course_2.tabs = [tab for tab in course_2.tabs if tab.type != 'progress'] self.update_course(course_2, ModuleStoreEnum.UserID.test) - assert len(course_1.tabs) == 6 - assert len(course_2.tabs) == 6 + assert len(course_1.tabs) == 5 + assert len(course_2.tabs) == 5 assert 'dates' not in {tab.type for tab in course_1.tabs} assert 'progress' not in {tab.type for tab in course_2.tabs} @@ -108,8 +108,8 @@ class BackfillCourseTabsTest(ModuleStoreTestCase): course_1 = self.store.get_course(course_1.id) course_2 = self.store.get_course(course_2.id) - assert len(course_1.tabs) == 7 - assert len(course_2.tabs) == 7 + assert len(course_1.tabs) == 6 + assert len(course_2.tabs) == 6 assert 'dates' in {tab.type for tab in course_1.tabs} assert 'progress' in {tab.type for tab in course_2.tabs} mock_logger.info.assert_any_call('2 courses read from modulestore. Processing 0 to 2.') @@ -168,13 +168,13 @@ class BackfillCourseTabsTest(ModuleStoreTestCase): def test_arguments_batching(self, start, count, expected_tabs_modified): courses = CourseFactory.create_batch(4) for course in courses: - course.tabs = [tab for tab in course.tabs if tab.type in ('course_info', 'courseware')] + course.tabs = [tab for tab in course.tabs if tab.type == 'courseware'] course = self.update_course(course, ModuleStoreEnum.UserID.test) - assert len(course.tabs) == 2 + assert len(course.tabs) == 1 BackfillCourseTabsConfig.objects.create(enabled=True, start_index=start, count=count) call_command('backfill_course_tabs') for i, course in enumerate(courses): course = self.store.get_course(course.id) - assert len(course.tabs) == (7 if expected_tabs_modified[i] else 2), f'Wrong tabs for course index {i}' + assert len(course.tabs) == (6 if expected_tabs_modified[i] else 1), f'Wrong tabs for course index {i}' diff --git a/cms/djangoapps/contentstore/tests/test_import.py b/cms/djangoapps/contentstore/tests/test_import.py index 41b06729ac..4c63ecd735 100644 --- a/cms/djangoapps/contentstore/tests/test_import.py +++ b/cms/djangoapps/contentstore/tests/test_import.py @@ -173,7 +173,7 @@ class ContentStoreImportTest(ModuleStoreTestCase): def test_tab_name_imports_correctly(self): _module_store, _content_store, course = self.load_test_import_course() print(f"course tabs = {course.tabs}") - self.assertEqual(course.tabs[2]['name'], 'Syllabus') + self.assertEqual(course.tabs[1]['name'], 'Syllabus') def test_import_performance_mongo(self): store = modulestore()._get_modulestore_by_type(ModuleStoreEnum.Type.mongo) diff --git a/cms/djangoapps/contentstore/views/tabs.py b/cms/djangoapps/contentstore/views/tabs.py index 5482be63dc..85f6b89850 100644 --- a/cms/djangoapps/contentstore/views/tabs.py +++ b/cms/djangoapps/contentstore/views/tabs.py @@ -220,8 +220,8 @@ def get_tab_by_locator(tab_list: List[CourseTab], tab_location: Union[str, Usage def validate_args(num, tab_type): "Throws for the disallowed cases." - if num <= 1: - raise ValueError('Tabs 1 and 2 cannot be edited') + if num < 1: + raise ValueError('Tab 1 cannot be edited') if tab_type == 'static_tab': raise ValueError('Tabs of type static_tab cannot be edited here (use Studio)') diff --git a/cms/djangoapps/contentstore/views/tests/test_tabs.py b/cms/djangoapps/contentstore/views/tests/test_tabs.py index e366420d22..58a6393585 100644 --- a/cms/djangoapps/contentstore/views/tests/test_tabs.py +++ b/cms/djangoapps/contentstore/views/tests/test_tabs.py @@ -113,7 +113,7 @@ class TabsPageTests(CourseTestCase): def test_reorder_tabs_invalid_tab(self): """Test re-ordering of tabs with invalid tab""" - invalid_tab_ids = ['courseware', 'info', 'invalid_tab_id'] + invalid_tab_ids = ['courseware', 'invalid_tab_id'] # post the request resp = self.client.ajax_post( @@ -189,16 +189,14 @@ class PrimitiveTabEdit(ModuleStoreTestCase): course = CourseFactory.create() with self.assertRaises(ValueError): tabs.primitive_delete(course, 0) - with self.assertRaises(ValueError): - tabs.primitive_delete(course, 1) with self.assertRaises(IndexError): - tabs.primitive_delete(course, 7) + tabs.primitive_delete(course, 6) - assert course.tabs[2] != {'type': 'dates', 'name': 'Dates'} - tabs.primitive_delete(course, 2) + assert course.tabs[1] != {'type': 'dates', 'name': 'Dates'} + tabs.primitive_delete(course, 1) assert {'type': 'progress'} not in course.tabs # Check that dates has shifted up - assert course.tabs[2] == {'type': 'dates', 'name': 'Dates'} + assert course.tabs[1] == {'type': 'dates', 'name': 'Dates'} def test_insert(self): """Test primitive tab insertion.""" diff --git a/cms/envs/common.py b/cms/envs/common.py index 876fe559aa..5ae71ecce4 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -1661,9 +1661,6 @@ INSTALLED_APPS = [ # edx-milestones service 'milestones', - # Self-paced course configuration - 'openedx.core.djangoapps.self_paced', - # Coursegraph 'cms.djangoapps.coursegraph.apps.CoursegraphConfig', diff --git a/common/djangoapps/util/views.py b/common/djangoapps/util/views.py index 3cbaaf018e..4bc4fd5522 100644 --- a/common/djangoapps/util/views.py +++ b/common/djangoapps/util/views.py @@ -167,11 +167,6 @@ def calculate(request): return HttpResponse(json.dumps({'result': str(result)})) # lint-amnesty, pylint: disable=http-response-with-json-dumps -def info(request): - """ Info page (link from main header) """ - return render_to_response("info.html", {}) - - def add_p3p_header(view_func): """ This decorator should only be used with views which may be displayed through the iframe. diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py index 8136ad3c50..417b9060cc 100644 --- a/common/lib/xmodule/xmodule/course_module.py +++ b/common/lib/xmodule/xmodule/course_module.py @@ -532,14 +532,6 @@ class CourseFields: # lint-amnesty, pylint: disable=missing-class-docstring scope=Scope.settings ) has_children = True - info_sidebar_name = String( - display_name=_("Course Home Sidebar Name"), - help=_( - "Enter the heading that you want students to see above your course handouts on the Course Home page. " - "Your course handouts appear in the right panel of the page." - ), - deprecated=True, - scope=Scope.settings, default=_('Course Handouts')) show_timezone = Boolean( help=_( "True if timezones should be shown on dates in the course. " diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py b/common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py index 55623b217e..4b6331589e 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py @@ -97,7 +97,6 @@ class SplitModuleTest(unittest.TestCase): "fields": { "tabs": [ CourseTab.load('courseware'), - CourseTab.load('course_info'), CourseTab.load('discussion'), CourseTab.load('wiki'), ], @@ -147,7 +146,6 @@ class SplitModuleTest(unittest.TestCase): "end": _date_field.from_json("2013-04-13T04:30"), "tabs": [ CourseTab.load('courseware'), - CourseTab.load('course_info'), CourseTab.load('discussion'), CourseTab.load('wiki'), CourseTab.load( @@ -320,7 +318,6 @@ class SplitModuleTest(unittest.TestCase): "fields": { "tabs": [ CourseTab.load('courseware'), - CourseTab.load('course_info'), CourseTab.load('discussion'), CourseTab.load('wiki'), ], @@ -417,7 +414,6 @@ class SplitModuleTest(unittest.TestCase): "fields": { "tabs": [ CourseTab.load('courseware'), - CourseTab.load('course_info'), CourseTab.load('discussion'), CourseTab.load('wiki'), ], @@ -581,7 +577,7 @@ class SplitModuleCourseTests(SplitModuleTest): course = self.findByIdInResult(courses, "head12345") assert course.location.org == 'testx' assert course.category == 'course', 'wrong category' - assert len(course.tabs) == 6, 'wrong number of tabs' + assert len(course.tabs) == 5, 'wrong number of tabs' assert course.display_name == 'The Ancient Greek Hero', 'wrong display name' assert course.advertised_start == 'Fall 2013', 'advertised_start' assert len(course.children) == 4, 'children' @@ -635,7 +631,7 @@ class SplitModuleCourseTests(SplitModuleTest): assert course.location.course_key.org == 'testx' assert course.location.course_key.course == 'wonderful' assert course.category == 'course', 'wrong category' - assert len(course.tabs) == 4, 'wrong number of tabs' + assert len(course.tabs) == 3, 'wrong number of tabs' assert course.display_name == 'The most wonderful course', course.display_name assert course.advertised_start is None assert len(course.children) == 0, 'children' @@ -665,7 +661,7 @@ class SplitModuleCourseTests(SplitModuleTest): assert course.location.course_key.org is None assert course.location.version_guid == head_course.previous_version assert course.category == 'course' - assert len(course.tabs) == 6 + assert len(course.tabs) == 5 assert course.display_name == 'The Ancient Greek Hero' assert course.graceperiod == datetime.timedelta(hours=2) assert course.advertised_start is None @@ -681,7 +677,7 @@ class SplitModuleCourseTests(SplitModuleTest): assert course.location.course_key.course == 'GreekHero' assert course.location.course_key.run == 'run' assert course.category == 'course' - assert len(course.tabs) == 6 + assert len(course.tabs) == 5 assert course.display_name == 'The Ancient Greek Hero' assert course.advertised_start == 'Fall 2013' assert len(course.children) == 4 @@ -933,7 +929,7 @@ class SplitModuleItemTests(SplitModuleTest): assert block.location.org == 'testx' assert block.location.course == 'GreekHero' assert block.location.run == 'run' - assert len(block.tabs) == 6, 'wrong number of tabs' + assert len(block.tabs) == 5, 'wrong number of tabs' assert block.display_name == 'The Ancient Greek Hero' assert block.advertised_start == 'Fall 2013' assert len(block.children) == 4 diff --git a/common/lib/xmodule/xmodule/tabs.py b/common/lib/xmodule/xmodule/tabs.py index 1292db60ac..56c3faaf08 100644 --- a/common/lib/xmodule/xmodule/tabs.py +++ b/common/lib/xmodule/xmodule/tabs.py @@ -382,7 +382,6 @@ class CourseTabList(List): within the course. """ course_tabs = [ - CourseTab.load('course_info'), CourseTab.load('courseware') ] @@ -481,14 +480,18 @@ class CourseTabList(List): @classmethod def upgrade_tabs(cls, tabs): """ - Reverse and Rename Courseware to Course and Course Info to Home Tabs. + Remove course_info tab, and rename courseware tab to Course if needed. """ if tabs and len(tabs) > 1: + # Reverse them so that course_info is first, and rename courseware to Course if tabs[0].get('type') == 'courseware' and tabs[1].get('type') == 'course_info': tabs[0], tabs[1] = tabs[1], tabs[0] - tabs[0]['name'] = _('Home') tabs[1]['name'] = _('Course') + # NOTE: this check used for legacy courses containing the course_info tab. course_info + # should be removed according to https://github.com/openedx/public-engineering/issues/56. + if tabs[0].get('type') == 'course_info': + tabs.pop(0) return tabs @classmethod @@ -499,22 +502,15 @@ class CourseTabList(List): Specific rules checked: - if no tabs specified, that's fine - - if tabs specified, first two must have type 'courseware' and 'course_info', in that order. + - if tabs specified, first must have type 'courseware'. """ if tabs is None or len(tabs) == 0: return - if len(tabs) < 2: - raise InvalidTabsException(f"Expected at least two tabs. tabs: '{tabs}'") - - if tabs[0].get('type') != 'course_info': + if tabs[0].get('type') != 'courseware': raise InvalidTabsException( - f"Expected first tab to have type 'course_info'. tabs: '{tabs}'") - - if tabs[1].get('type') != 'courseware': - raise InvalidTabsException( - f"Expected second tab to have type 'courseware'. tabs: '{tabs}'") + f"Expected first tab to have type 'courseware'. tabs: '{tabs}'") # the following tabs should appear only once # TODO: don't import openedx capabilities from common diff --git a/common/lib/xmodule/xmodule/tests/test_tabs.py b/common/lib/xmodule/xmodule/tests/test_tabs.py new file mode 100644 index 0000000000..b38292d659 --- /dev/null +++ b/common/lib/xmodule/xmodule/tests/test_tabs.py @@ -0,0 +1,117 @@ +""" +Tests for CourseTabsListTestCase. +""" +from unittest import TestCase +import ddt + +from xmodule.tabs import CourseTabList, InvalidTabsException + + +@ddt.ddt +class CourseTabsListTestCase(TestCase): + """ + Class containing CourseTabsListTestCase tests. + """ + + @ddt.data( + [ + [], + [] + ], + [ + [ + {'type': 'courseware', 'course_staff_only': False, 'name': 'Courseware'}, + {'type': 'course_info', 'course_staff_only': False, 'name': 'Course Info'}, + {'type': 'discussion', 'course_staff_only': False, 'name': 'Discussion'}, + {'type': 'wiki', 'course_staff_only': False, 'name': 'Wiki'}, + {'type': 'textbooks', 'course_staff_only': False, 'name': 'Textbooks'}, + {'type': 'progress', 'course_staff_only': False, 'name': 'Progress'} + ], + [ + {'type': 'courseware', 'course_staff_only': False, 'name': 'Course'}, + {'type': 'discussion', 'course_staff_only': False, 'name': 'Discussion'}, + {'type': 'wiki', 'course_staff_only': False, 'name': 'Wiki'}, + {'type': 'textbooks', 'course_staff_only': False, 'name': 'Textbooks'}, + {'type': 'progress', 'course_staff_only': False, 'name': 'Progress'} + ], + ], + [ + [ + {'type': 'course_info', 'course_staff_only': False, 'name': 'Home'}, + {'type': 'courseware', 'course_staff_only': False, 'name': 'Course'}, + {'type': 'discussion', 'course_staff_only': False, 'name': 'Discussion'}, + {'type': 'wiki', 'course_staff_only': False, 'name': 'Wiki'}, + {'type': 'textbooks', 'course_staff_only': False, 'name': 'Textbooks'}, + {'type': 'progress', 'course_staff_only': False, 'name': 'Progress'} + ], + [ + {'type': 'courseware', 'course_staff_only': False, 'name': 'Course'}, + {'type': 'discussion', 'course_staff_only': False, 'name': 'Discussion'}, + {'type': 'wiki', 'course_staff_only': False, 'name': 'Wiki'}, + {'type': 'textbooks', 'course_staff_only': False, 'name': 'Textbooks'}, + {'type': 'progress', 'course_staff_only': False, 'name': 'Progress'} + ], + ] + ) + @ddt.unpack + def test_upgrade_tabs(self, tabs, expected_result): + CourseTabList.upgrade_tabs(tabs) + self.assertEqual(tabs, expected_result) + + @ddt.data( + [ + [], + True + ], + [ + [ + {'type': 'courseware', 'course_staff_only': False, 'name': 'Course'}, + ], + True + ], + [ + [ + {'type': 'course_info', 'course_staff_only': False, 'name': 'Home'}, + ], + False + ], + [ + [ + {'type': 'course_info', 'course_staff_only': False, 'name': 'Home'}, + {'type': 'courseware', 'course_staff_only': False, 'name': 'Course'}, + {'type': 'discussion', 'course_staff_only': False, 'name': 'Discussion'}, + {'type': 'wiki', 'course_staff_only': False, 'name': 'Wiki'}, + {'type': 'textbooks', 'course_staff_only': False, 'name': 'Textbooks'}, + {'type': 'progress', 'course_staff_only': False, 'name': 'Progress'} + ], + False + ], + [ + [ + {'type': 'courseware', 'course_staff_only': False, 'name': 'Course'}, + {'type': 'courseware', 'course_staff_only': False, 'name': 'Course'}, + {'type': 'discussion', 'course_staff_only': False, 'name': 'Discussion'}, + {'type': 'wiki', 'course_staff_only': False, 'name': 'Wiki'}, + {'type': 'textbooks', 'course_staff_only': False, 'name': 'Textbooks'}, + {'type': 'progress', 'course_staff_only': False, 'name': 'Progress'} + ], + False + ], + [ + [ + {'type': 'courseware', 'course_staff_only': False, 'name': 'Course'}, + {'type': 'discussion', 'course_staff_only': False, 'name': 'Discussion'}, + {'type': 'wiki', 'course_staff_only': False, 'name': 'Wiki'}, + {'type': 'textbooks', 'course_staff_only': False, 'name': 'Textbooks'}, + {'type': 'progress', 'course_staff_only': False, 'name': 'Progress'} + ], + True + ] + ) + @ddt.unpack + def test_validate_tabs(self, tabs, expected_success): + if not expected_success: + with self.assertRaises(InvalidTabsException): + CourseTabList.validate_tabs(tabs) + else: + CourseTabList.validate_tabs(tabs) diff --git a/common/test/data/scoreable/policies/course/policy.json b/common/test/data/scoreable/policies/course/policy.json index e177e5d444..714366c0f0 100644 --- a/common/test/data/scoreable/policies/course/policy.json +++ b/common/test/data/scoreable/policies/course/policy.json @@ -27,10 +27,6 @@ "minimum_grade_credit": 0.8, "start": "2030-01-01T00:00:00Z", "tabs": [ - { - "name": "Home", - "type": "course_info" - }, { "name": "Course", "type": "courseware" diff --git a/common/test/test-theme/lms/templates/courseware/courses.html b/common/test/test-theme/lms/templates/courseware/courses.html index 0500a293df..c21f247d89 100644 --- a/common/test/test-theme/lms/templates/courseware/courses.html +++ b/common/test/test-theme/lms/templates/courseware/courses.html @@ -3,6 +3,6 @@ # Include template which does not exist in the theme. <%include file="/courseware/error-message.html" /> # Include template which is overriden in the theme. -<%include file="/courseware/info.html" /> +<%include file="/courseware/progress.html" /> # Include custom template which only exists in the theme. <%include file="/courseware/test-theme-custom.html" /> diff --git a/common/test/test-theme/lms/templates/courseware/info.html b/common/test/test-theme/lms/templates/courseware/info.html deleted file mode 100644 index b47b665532..0000000000 --- a/common/test/test-theme/lms/templates/courseware/info.html +++ /dev/null @@ -1,2 +0,0 @@ -<%page expression_filter="h"/> -

    <%- gettext("Course Key") %> <%- gettext("Type") %> <%- gettext("Status") %><%- gettext("Download URL") %> <%- gettext("Grade") %> <%- gettext("Last Updated") %> <%- cert.get("course_key") %> <%- cert.get("type") %> <%- cert.get("status") %> - <% if (cert.get("download_url")) { %> - ">Download - <%- gettext("Download the user's certificate") %> - <% } else { %> - <%- gettext("Not available") %> - <% } %> - <%- cert.get("grade") %> <%- cert.get("modified") %> diff --git a/lms/templates/courseware/progress.html b/lms/templates/courseware/progress.html index 63b340c1e4..f0f1850e6e 100644 --- a/lms/templates/courseware/progress.html +++ b/lms/templates/courseware/progress.html @@ -83,8 +83,6 @@ username = get_enterprise_learner_generic_name(request) or student.username
    %if certificate_data.cert_web_view_url: ${_("View Certificate")} ${_("Opens in a new browser window")} - %elif certificate_data.cert_status == CertificateStatuses.downloadable and certificate_data.download_url: - ${_("Download Your Certificate")} ${_("Opens in a new browser window")} %elif certificate_data.cert_status == CertificateStatuses.requesting: %endif diff --git a/lms/templates/dashboard/_dashboard_certificate_information.html b/lms/templates/dashboard/_dashboard_certificate_information.html index 51e2c58dc6..5f3436a7f7 100644 --- a/lms/templates/dashboard/_dashboard_certificate_information.html +++ b/lms/templates/dashboard/_dashboard_certificate_information.html @@ -107,27 +107,6 @@ else: ${_("View my {cert_name_short}").format(cert_name_short=cert_name_short)} - % elif cert_status['status'] == CertificateStatuses.downloadable and enrollment.mode in CourseMode.NON_VERIFIED_MODES: -
  • - - ${_("Download my {cert_name_short}").format(cert_name_short=cert_name_short,)} - -
  • - % elif cert_status['status'] == CertificateStatuses.downloadable and enrollment.mode == 'verified' and cert_status['mode'] == 'honor': -
  • - - ${_("Download my {cert_name_short}").format(cert_name_short=cert_name_short)} - -
  • - % elif cert_status['status'] == CertificateStatuses.downloadable and enrollment.mode in CourseMode.VERIFIED_MODES: -
  • - - ${_("Download my {cert_name_short}").format(cert_name_short=cert_name_short)} - -
  • % endif % if cert_status['show_survey_button']: diff --git a/openedx/features/learner_profile/templates/learner_profile/learner-achievements-fragment.html b/openedx/features/learner_profile/templates/learner_profile/learner-achievements-fragment.html index 8818a284fe..33fe77186f 100644 --- a/openedx/features/learner_profile/templates/learner_profile/learner-achievements-fragment.html +++ b/openedx/features/learner_profile/templates/learner_profile/learner-achievements-fragment.html @@ -15,7 +15,6 @@ from openedx.core.djangolib.markup import HTML, Text % if course_certificates: % for certificate in course_certificates: <% - certificate_url = certificate['download_url'] course = certificate['course'] completion_date_message_html = Text(_('Completed {completion_date_html}')).format( @@ -34,39 +33,20 @@ from openedx.core.djangolib.markup import HTML, Text ), ) %> - % if certificate_url: - -
    - -
    -
    ${course.display_org_with_default}
    -
    ${course.display_name_with_default}
    -

    ${completion_date_message_html}

    -
    -
    -
    - % else: -
    - -
    -
    ${course.display_org_with_default}
    -
    ${course.display_name_with_default}
    -

    ${completion_date_message_html}

    -
    +
    + - % endif +
    +
    ${course.display_org_with_default}
    +
    ${course.display_name_with_default}
    +

    ${completion_date_message_html}

    +
    +
    % endfor % elif own_profile:
    From ec69659253060aaaf398eb90d4f64deb569f3201 Mon Sep 17 00:00:00 2001 From: Maria Grimaldi Date: Wed, 18 May 2022 14:34:07 -0400 Subject: [PATCH 39/63] feat: integrate cohort assignment filter definition to cohort model --- lms/static/js/groups/views/cohort_editor.js | 15 ++- .../js/spec/groups/views/cohorts_spec.js | 20 +++- .../core/djangoapps/course_groups/models.py | 13 ++- .../course_groups/tests/test_filters.py | 96 ++++++++++++++++++- .../core/djangoapps/course_groups/views.py | 12 ++- 5 files changed, 145 insertions(+), 11 deletions(-) diff --git a/lms/static/js/groups/views/cohort_editor.js b/lms/static/js/groups/views/cohort_editor.js index feb4513281..9da4a0c92a 100644 --- a/lms/static/js/groups/views/cohort_editor.js +++ b/lms/static/js/groups/views/cohort_editor.js @@ -260,16 +260,17 @@ // Show error messages. this.undelegateViewEvents(this.errorNotifications); - numErrors = modifiedUsers.unknown.length + modifiedUsers.invalid.length; + numErrors = modifiedUsers.unknown.length + modifiedUsers.invalid.length + modifiedUsers.not_allowed.length; if (numErrors > 0) { - createErrorDetails = function(unknownUsers, invalidEmails, showAllErrors) { + createErrorDetails = function(unknownUsers, invalidEmails, notAllowed, showAllErrors) { var unknownErrorsShown = showAllErrors ? unknownUsers.length : Math.min(errorLimit, unknownUsers.length); var invalidErrorsShown = showAllErrors ? invalidEmails.length : Math.min(errorLimit - unknownUsers.length, invalidEmails.length); + var notAllowedErrorsShown = showAllErrors ? notAllowed.length : + Math.min(errorLimit - notAllowed.length, notAllowed.length); details = []; - for (i = 0; i < unknownErrorsShown; i++) { details.push(interpolate_text(gettext('Unknown username: {user}'), {user: unknownUsers[i]})); @@ -278,6 +279,10 @@ details.push(interpolate_text(gettext('Invalid email address: {email}'), {email: invalidEmails[i]})); } + for (i = 0; i < notAllowedErrorsShown; i++) { + details.push(interpolate_text(gettext('Cohort assignment not allowed: {email_or_username}'), + {email_or_username: notAllowed[i]})); + } return details; }; @@ -286,12 +291,12 @@ '{numErrors} learners could not be added to this cohort:', numErrors), {numErrors: numErrors} ); - details = createErrorDetails(modifiedUsers.unknown, modifiedUsers.invalid, false); + details = createErrorDetails(modifiedUsers.unknown, modifiedUsers.invalid, modifiedUsers.not_allowed, false); errorActionCallback = function(view) { view.model.set('actionText', null); view.model.set('details', - createErrorDetails(modifiedUsers.unknown, modifiedUsers.invalid, true)); + createErrorDetails(modifiedUsers.unknown, modifiedUsers.invalid, modifiedUsers.not_allowed, true)); view.render(); }; diff --git a/lms/static/js/spec/groups/views/cohorts_spec.js b/lms/static/js/spec/groups/views/cohorts_spec.js index 709930814b..51579701b5 100644 --- a/lms/static/js/spec/groups/views/cohorts_spec.js +++ b/lms/static/js/spec/groups/views/cohorts_spec.js @@ -14,6 +14,7 @@ define(['backbone', 'jquery', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers var catLoversInitialCount = 123, dogLoversInitialCount = 456, unknownUserMessage, + notAllowedUserMessage, invalidEmailMessage, createMockCohort, createMockCohorts, createMockContentGroups, createMockCohortSettingsJson, createCohortsView, cohortsView, requests, respondToRefresh, verifyMessage, verifyNoMessage, @@ -210,6 +211,10 @@ define(['backbone', 'jquery', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers return 'Invalid email address: ' + name; }; + notAllowedUserMessage = function(email) { + return 'Cohort assignment not allowed: ' + email; + }; + beforeEach(function() { setFixtures('
    &G@ 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\n" "Language: rtl\n" @@ -49,6 +49,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "Generated-By: Babel 2.8.0\n" +#: cms/djangoapps/contentstore/utils.py +#: cms/djangoapps/contentstore/views/component.py +#: cms/djangoapps/contentstore/views/item.py +#: common/lib/xmodule/xmodule/html_module.py +msgid "Text" +msgstr "Ŧǝxʇ" + #. #-#-#-#-# django-partial.po (0.1a) #-#-#-#-# #. Translators: 'Discussion' refers to the tab in the courseware that leads to #. the discussion forums @@ -62,11 +69,6 @@ msgstr "" msgid "Discussion" msgstr "Đᴉsɔnssᴉøn" -#: cms/djangoapps/contentstore/views/component.py -#: common/lib/xmodule/xmodule/html_module.py -msgid "Text" -msgstr "Ŧǝxʇ" - #: cms/djangoapps/contentstore/views/component.py #: openedx/core/djangoapps/content_libraries/constants.py msgid "Problem" @@ -2929,25 +2931,6 @@ msgstr "Ⱥdʌɐnɔǝd Mødnlǝ Łᴉsʇ" msgid "Enter the names of the advanced modules to use in your course." msgstr "Ɇnʇǝɹ ʇɥǝ nɐɯǝs øɟ ʇɥǝ ɐdʌɐnɔǝd ɯødnlǝs ʇø nsǝ ᴉn ʎønɹ ɔønɹsǝ." -#: common/lib/xmodule/xmodule/course_module.py -msgid "Course Home Sidebar Name" -msgstr "Ȼønɹsǝ Ħøɯǝ Sᴉdǝbɐɹ Nɐɯǝ" - -#: common/lib/xmodule/xmodule/course_module.py -msgid "" -"Enter the heading that you want students to see above your course handouts " -"on the Course Home page. Your course handouts appear in the right panel of " -"the page." -msgstr "" -"Ɇnʇǝɹ ʇɥǝ ɥǝɐdᴉnƃ ʇɥɐʇ ʎøn ʍɐnʇ sʇndǝnʇs ʇø sǝǝ ɐbøʌǝ ʎønɹ ɔønɹsǝ ɥɐndønʇs " -"øn ʇɥǝ Ȼønɹsǝ Ħøɯǝ dɐƃǝ. Ɏønɹ ɔønɹsǝ ɥɐndønʇs ɐddǝɐɹ ᴉn ʇɥǝ ɹᴉƃɥʇ dɐnǝl øɟ " -"ʇɥǝ dɐƃǝ." - -#: common/lib/xmodule/xmodule/course_module.py -#: lms/templates/courseware/info.html -msgid "Course Handouts" -msgstr "Ȼønɹsǝ Ħɐndønʇs" - #: common/lib/xmodule/xmodule/course_module.py msgid "" "True if timezones should be shown on dates in the course. Deprecated in " @@ -4530,11 +4513,6 @@ msgstr "Ŧɥᴉs ɔønʇǝnʇ ǝxdǝɹᴉɯǝnʇ ɥɐs ᴉssnǝs ʇɥɐʇ ɐɟɟ msgid "External Discussion" msgstr "Ɇxʇǝɹnɐl Đᴉsɔnssᴉøn" -#: common/lib/xmodule/xmodule/tabs.py lms/djangoapps/courseware/tabs.py -#: openedx/features/enterprise_support/templates/enterprise_support/admin/enrollment_attributes_override.html -msgid "Home" -msgstr "Ħøɯǝ" - #: common/lib/xmodule/xmodule/tabs.py lms/djangoapps/courseware/tabs.py #: lms/djangoapps/courseware/views/views.py #: openedx/features/course_experience/__init__.py @@ -11193,10 +11171,6 @@ msgstr "Ʉdƃɹɐdǝ ʇø ǝɐɹn ɐ ʌǝɹᴉɟᴉǝd ɔǝɹʇᴉɟᴉɔɐʇǝ msgid "Upgrade to earn a verified certificate in %(first_course_name)s" msgstr "Ʉdƃɹɐdǝ ʇø ǝɐɹn ɐ ʌǝɹᴉɟᴉǝd ɔǝɹʇᴉɟᴉɔɐʇǝ ᴉn %(first_course_name)s" -#: openedx/core/djangoapps/self_paced/models.py -msgid "Enable course home page improvements." -msgstr "Ɇnɐblǝ ɔønɹsǝ ɥøɯǝ dɐƃǝ ᴉɯdɹøʌǝɯǝnʇs." - #: openedx/core/djangoapps/theming/views.py #, python-brace-format msgid "Site theme changed to {site_theme}" @@ -12452,6 +12426,10 @@ msgstr "" "Ɨɟ ʎøn ɥɐʌǝ ɔønɔǝɹns ɐbønʇ sɥɐɹᴉnƃ ʎønɹ dɐʇɐ, dlǝɐsǝ ɔønʇɐɔʇ ʎønɹ " "ɐdɯᴉnᴉsʇɹɐʇøɹ ɐʇ {enterprise_customer_name}." +#: openedx/features/enterprise_support/templates/enterprise_support/admin/enrollment_attributes_override.html +msgid "Home" +msgstr "Ħøɯǝ" + #: openedx/features/enterprise_support/templates/enterprise_support/admin/enrollment_attributes_override.html msgid "Enterprise Course Enrollments" msgstr "Ɇnʇǝɹdɹᴉsǝ Ȼønɹsǝ Ɇnɹøllɯǝnʇs" @@ -16646,51 +16624,6 @@ msgstr "øɟ" msgid "next page" msgstr "nǝxʇ dɐƃǝ" -#: lms/templates/courseware/info.html -msgid "{course_number} Course Info" -msgstr "{course_number} Ȼønɹsǝ Ɨnɟø" - -#: lms/templates/courseware/info.html -msgid "You are not enrolled yet" -msgstr "Ɏøn ɐɹǝ nøʇ ǝnɹøllǝd ʎǝʇ" - -#: lms/templates/courseware/info.html -msgid "" -"You are not currently enrolled in this course. {link_start}Enroll " -"now!{link_end}" -msgstr "" -"Ɏøn ɐɹǝ nøʇ ɔnɹɹǝnʇlʎ ǝnɹøllǝd ᴉn ʇɥᴉs ɔønɹsǝ. {link_start}Ɇnɹøll " -"nøʍ!{link_end}" - -#: lms/templates/courseware/info.html -msgid "Welcome to {org}'s {course_title}!" -msgstr "Wǝlɔøɯǝ ʇø {org}'s {course_title}!" - -#: lms/templates/courseware/info.html -msgid "Welcome to {course_title}!" -msgstr "Wǝlɔøɯǝ ʇø {course_title}!" - -#: lms/templates/courseware/info.html -#: lms/templates/dashboard/_dashboard_course_resume.html -msgid "Resume Course" -msgstr "Ɍǝsnɯǝ Ȼønɹsǝ" - -#: lms/templates/courseware/info.html -msgid "View Updates in Studio" -msgstr "Vᴉǝʍ Ʉddɐʇǝs ᴉn Sʇndᴉø" - -#: lms/templates/courseware/info.html -msgid "Course Updates and News" -msgstr "Ȼønɹsǝ Ʉddɐʇǝs ɐnd Nǝʍs" - -#: lms/templates/courseware/info.html -msgid "Handout Navigation" -msgstr "Ħɐndønʇ Nɐʌᴉƃɐʇᴉøn" - -#: lms/templates/courseware/info.html -msgid "Course Tools" -msgstr "Ȼønɹsǝ Ŧøøls" - #: lms/templates/courseware/news.html msgid "News - MITx 6.002x" msgstr "Nǝʍs - MƗŦx 6.002x" @@ -16831,10 +16764,6 @@ msgstr "Vᴉǝʍ Ȼǝɹʇᴉɟᴉɔɐʇǝ" msgid "Opens in a new browser window" msgstr "Ødǝns ᴉn ɐ nǝʍ bɹøʍsǝɹ ʍᴉndøʍ" -#: lms/templates/courseware/progress.html -msgid "Download Your Certificate" -msgstr "Đøʍnløɐd Ɏønɹ Ȼǝɹʇᴉɟᴉɔɐʇǝ" - #: lms/templates/courseware/progress.html #: lms/templates/dashboard/_dashboard_certificate_information.html msgid "Request Certificate" @@ -17104,22 +17033,6 @@ msgstr "Ŧɥᴉs lᴉnʞ ʍᴉll ødǝn ʇɥǝ ɔǝɹʇᴉɟᴉɔɐʇǝ ʍǝb ʌ msgid "View my {cert_name_short}" msgstr "Vᴉǝʍ ɯʎ {cert_name_short}" -#: lms/templates/dashboard/_dashboard_certificate_information.html -msgid "This link will open/download a PDF document" -msgstr "Ŧɥᴉs lᴉnʞ ʍᴉll ødǝn/døʍnløɐd ɐ ⱣĐF døɔnɯǝnʇ" - -#: lms/templates/dashboard/_dashboard_certificate_information.html -msgid "Download my {cert_name_short}" -msgstr "Đøʍnløɐd ɯʎ {cert_name_short}" - -#: lms/templates/dashboard/_dashboard_certificate_information.html -msgid "" -"This link will open/download a PDF document of your verified " -"{cert_name_long}." -msgstr "" -"Ŧɥᴉs lᴉnʞ ʍᴉll ødǝn/døʍnløɐd ɐ ⱣĐF døɔnɯǝnʇ øɟ ʎønɹ ʌǝɹᴉɟᴉǝd " -"{cert_name_long}." - #: lms/templates/dashboard/_dashboard_certificate_information.html msgid "Complete our course feedback survey" msgstr "Ȼøɯdlǝʇǝ ønɹ ɔønɹsǝ ɟǝǝdbɐɔʞ snɹʌǝʎ" @@ -17274,6 +17187,10 @@ msgstr "" msgid "Upgrade" msgstr "Ʉdƃɹɐdǝ" +#: lms/templates/dashboard/_dashboard_course_resume.html +msgid "Resume Course" +msgstr "Ɍǝsnɯǝ Ȼønɹsǝ" + #. Translators: provider_name is the name of a credit provider or university #. (e.g. State University) #: lms/templates/dashboard/_dashboard_credit_info.html diff --git a/conf/locale/rtl/LC_MESSAGES/djangojs.mo b/conf/locale/rtl/LC_MESSAGES/djangojs.mo index 1e07f48678cd8a53c420d4054e6f3de044ba78ca..e2519b5293bb28d9bd9e9e71462ffa9e0c0f0dd9 100644 GIT binary patch delta 46767 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 delta 46794 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\n" "Language: rtl\n" @@ -3792,6 +3792,10 @@ msgstr "Ʉnʞnøʍn nsǝɹnɐɯǝ: {user}" msgid "Invalid email address: {email}" msgstr "Ɨnʌɐlᴉd ǝɯɐᴉl ɐddɹǝss: {email}" +#: lms/static/js/groups/views/cohort_editor.js +msgid "Cohort assignment not allowed: {email_or_username}" +msgstr "Ȼøɥøɹʇ ɐssᴉƃnɯǝnʇ nøʇ ɐlløʍǝd: {email_or_username}" + #: lms/static/js/groups/views/cohort_editor.js msgid "There was an error when trying to add learners:" msgid_plural "{numErrors} learners could not be added to this cohort:" @@ -7627,10 +7631,6 @@ msgstr "Ȼønɹsǝ Ꝁǝʎ" msgid "Status" msgstr "Sʇɐʇns" -#: lms/djangoapps/support/static/support/templates/certificates_results.underscore -msgid "Download URL" -msgstr "Đøʍnløɐd ɄɌŁ" - #: lms/djangoapps/support/static/support/templates/certificates_results.underscore msgid "Grade" msgstr "Ǥɹɐdǝ" @@ -7639,14 +7639,6 @@ msgstr "Ǥɹɐdǝ" msgid "Last Updated" msgstr "Łɐsʇ Ʉddɐʇǝd" -#: lms/djangoapps/support/static/support/templates/certificates_results.underscore -msgid "Download the user's certificate" -msgstr "Đøʍnløɐd ʇɥǝ nsǝɹ's ɔǝɹʇᴉɟᴉɔɐʇǝ" - -#: lms/djangoapps/support/static/support/templates/certificates_results.underscore -msgid "Not available" -msgstr "Nøʇ ɐʌɐᴉlɐblǝ" - #: lms/djangoapps/support/static/support/templates/certificates_results.underscore msgid "Regenerate" msgstr "Ɍǝƃǝnǝɹɐʇǝ" diff --git a/conf/locale/ru/LC_MESSAGES/djangojs.mo b/conf/locale/ru/LC_MESSAGES/djangojs.mo index 2d13d86a749f0412bbf6700708346eec76276ef9..f7cf93f999de529db38beba77051e4a1a81fa75d 100644 GIT binary patch delta 25 hcmdnEjd$ZV-i9rVH%pl<^bFeXlrnC=Q_2+j6abM^3nBmj delta 25 hcmdnEjd$ZV-i9rVH%pl<^$gqZlrnC=Q_2+j6abNH3nTyl diff --git a/conf/locale/ru/LC_MESSAGES/djangojs.po b/conf/locale/ru/LC_MESSAGES/djangojs.po index f79b2ea188..919e66ac55 100644 --- a/conf/locale/ru/LC_MESSAGES/djangojs.po +++ b/conf/locale/ru/LC_MESSAGES/djangojs.po @@ -191,7 +191,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: ashed , 2022\n" "Language-Team: Russian (http://www.transifex.com/open-edx/edx-platform/language/ru/)\n" @@ -200,7 +200,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js #: cms/static/js/views/video_transcripts.js @@ -246,7 +246,6 @@ msgstr "Удалить" #: common/lib/xmodule/xmodule/js/src/html/edit.js #: common/static/common/js/components/utils/view_utils.js #: lms/static/js/Markdown.Editor.js -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx #: lms/static/js/student_account/components/StudentAccountDeletionModal.jsx #: cms/templates/js/add-xblock-component-menu-problem.underscore #: cms/templates/js/add-xblock-component-menu.underscore @@ -431,6 +430,14 @@ msgstr "Ошибка" msgid "Updating with latest library content" msgstr "Обновление содержимого из актуальной версии библиотеки" +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Loading..." +msgstr "" + +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Selected blocks" +msgstr "" + #: common/lib/xmodule/xmodule/assets/library_source_block/public/js/library_source_block.js msgid "Unable to update settings" msgstr "" @@ -1355,6 +1362,7 @@ msgstr "Новое окно" #. Translators: this is a message from the raw HTML editor displayed in the #. browser when a user needs to edit HTML #: common/lib/xmodule/xmodule/js/src/html/edit.js +#: lms/static/js/demographics_collection/Wizard.jsx #: cms/templates/js/paging-header.underscore #: common/static/common/templates/components/paging-footer.underscore #: common/static/common/templates/discussion/templates.underscore @@ -2142,6 +2150,10 @@ msgstr "Просмотр дочерних элементов" msgid "Navigate up" msgstr "" +#: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx +msgid "Browsing" +msgstr "" + #: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx msgid "Select" msgstr "" @@ -2703,10 +2715,30 @@ msgid "" "within the Discussion Forum where the Course Staff can directly respond." msgstr "" +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Details" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "the more quickly and helpfully we can respond!" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Create Support Ticket" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "What can we help you with, {username}?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx msgid "Sign in to {platform} so we can help you better." msgstr "" +#: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx +msgid "Need help logging in?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/single_support_form.jsx msgid "" "Select a course or select \"Not specific to a course\" for your support " @@ -3568,20 +3600,52 @@ msgstr "" msgid "Get started" msgstr "" -#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx -msgid "Section {currentPage} of {totalPages}" -msgstr "" - #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "Help make edX better for everyone!" msgstr "" +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Why does edX collect this information?" +msgstr "" + #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "" -"Welcome to edX! Before you get started, please take a few minutes to fill-in" -" the additional information below to help us understand a bit more about " -"your background. You can always edit this information later in Account " -"Settings." +"An error occurred while attempting to retrieve or save the information " +"below. Please try again later." +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What was the total combined income, during the last 12 months, of all " +"members of your family? " +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"Have you ever served on active duty in the U.S. Armed Forces, Reserves, or " +"National Guard?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What is the highest level of education that you have achieved so far?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What is the highest level of education that any of your parents or guardians" +" have achieved?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Select employment status" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you currently work in?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you want to work in?" msgstr "" #: lms/static/js/demographics_collection/MultiselectDropdown.jsx @@ -3596,6 +3660,22 @@ msgstr "" msgid "close questionnaire" msgstr "" +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Return to my dashboard" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "next page" +msgstr "" + #: lms/static/js/discovery/views/search_form.js #, javascript-format msgid "Viewing %s course" @@ -3913,27 +3993,6 @@ msgstr "Группы включены" msgid "Cohorts Disabled" msgstr "Группы отключены" -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course uses automatic cohorting for verified track learners. You cannot" -" disable cohorts, and you cannot rename the manual cohort named " -"'{verifiedCohortName}'. To change the configuration for verified track " -"cohorts, contact your edX partner manager." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" the required cohort does not exist. You must create a manually-assigned " -"cohort named '{verifiedCohortName}' for the feature to work." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" cohorts are disabled. You must enable cohorts for the feature to work." -msgstr "" - #: lms/static/js/instructor_dashboard/certificates.js msgid "Allow students to generate certificates for this course?" msgstr "Разрешить обучающимся создавать сертификаты этого курса?" @@ -4695,10 +4754,6 @@ msgstr "" "Ссылки создаются по требованию и остаются действительными в течение 5 минут " "в связи с деликатностью предоставленной слушателями информации." -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx -msgid "You have access to the {enterpriseName} dashboard" -msgstr "" - #: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx msgid "" "To access the courses available to you through {enterpriseName}, visit the " @@ -5571,42 +5626,6 @@ msgstr "Итоговая оценка" msgid "Bookmark this page" msgstr "Добавить страницу в мои закладки" -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "Thank you for setting your course goal to {goal}!" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "" -"There was an error in setting your goal, please reload the page and try " -"again." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "You have successfully updated your goal." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "There was an error updating your goal." -msgstr "" - -#: lms/templates/ccx/schedule.underscore -msgid "Expand All" -msgstr "Развернуть всё" - -#: lms/templates/ccx/schedule.underscore -msgid "Collapse All" -msgstr "Свернуть все" - -#: openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show More" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show Less" -msgstr "" - #: openedx/features/course_search/static/course_search/js/views/search_results_view.js msgid "{total_results} result found for \"{search_term}\"" msgid_plural "{total_results} results found for \"{search_term}\"" @@ -5899,6 +5918,30 @@ msgstr "" msgid "There was an error with the upload" msgstr "" +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Organization:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Number:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Run:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "(Read-only)" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Re-run Course" +msgstr "" + +#: cms/templates/js/show-textbook.underscore +msgid "View Live" +msgstr "Просмотр курса" + #: cms/static/js/maintenance/force_publish_course.js msgid "Internal Server Error." msgstr "Внутренняя ошибка сервера." @@ -7419,10 +7462,6 @@ msgstr "" msgid "follow this post" msgstr "" -#: common/static/common/templates/discussion/templates.underscore -msgid "post anonymously" -msgstr "" - #: common/static/common/templates/discussion/templates.underscore msgid "post anonymously to classmates" msgstr "" @@ -7876,6 +7915,14 @@ msgstr "" msgid "This catalog's courses:" msgstr "Курсы в данном каталоге:" +#: lms/templates/ccx/schedule.underscore +msgid "Expand All" +msgstr "Развернуть всё" + +#: lms/templates/ccx/schedule.underscore +msgid "Collapse All" +msgstr "Свернуть все" + #: lms/templates/ccx/schedule.underscore msgid "Start Date" msgstr "Дата начала" @@ -7962,6 +8009,14 @@ msgstr "" "каждого отдельного задания, прежде чем вы выберете «Завершить сдачу " "экзамена»" +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show More" +msgstr "" + +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show Less" +msgstr "" + #: lms/templates/discovery/course_card.underscore msgid "LEARN MORE" msgstr "ПОДРОБНЕЕ" @@ -10783,10 +10838,6 @@ msgstr "" msgid "PDF Chapters" msgstr "" -#: cms/templates/js/show-textbook.underscore -msgid "View Live" -msgstr "Просмотр курса" - #: cms/templates/js/signatory-details.underscore #: cms/templates/js/signatory-editor.underscore msgid "Signatory" diff --git a/conf/locale/sk/LC_MESSAGES/django.mo b/conf/locale/sk/LC_MESSAGES/django.mo index cf1a51f855c191d25c0f75205333605466524b2f..fea883feed139d08e438df70a3292b57ac9865f7 100644 GIT binary patch delta 18 acmdlypK0@arVUfVnJx4THctb%_F9y;8 delta 18 acmdlypK0@arVUfVnJx7UH%||ju>b%_JqFYO diff --git a/conf/locale/sk/LC_MESSAGES/django.po b/conf/locale/sk/LC_MESSAGES/django.po index 7104eb733c..d4773e23af 100644 --- a/conf/locale/sk/LC_MESSAGES/django.po +++ b/conf/locale/sk/LC_MESSAGES/django.po @@ -55,7 +55,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:44+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Waheed Ahmed , 2019\n" "Language-Team: Slovak (https://www.transifex.com/open-edx/teams/6205/sk/)\n" @@ -64,7 +64,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# #. Translators: 'Discussion' refers to the tab in the courseware that leads to @@ -650,6 +650,10 @@ msgstr "" msgid "Could not enroll" msgstr "" +#: common/djangoapps/student/views/management.py +msgid "Unenrollment is currently disabled" +msgstr "" + #: common/djangoapps/student/views/management.py msgid "You are not enrolled in this course" msgstr "Nie ste prihlásený v tomto kurze" @@ -1765,7 +1769,6 @@ msgstr "" #. to the site. #: common/lib/capa/capa/responsetypes.py #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html #: themes/stanford-style/lms/templates/register-form.html msgid "or" msgstr "alebo" @@ -1988,7 +1991,6 @@ msgid "Never" msgstr "" #: common/lib/xmodule/xmodule/capa_module.py -#: lms/templates/courseware/dates.html msgid "Past Due" msgstr "" @@ -2054,6 +2056,7 @@ msgid "Whether to force the save button to appear on the page" msgstr "" #: common/lib/xmodule/xmodule/capa_module.py +#: common/lib/xmodule/xmodule/library_content_module.py msgid "Show Reset Button" msgstr "" @@ -2771,7 +2774,6 @@ msgstr "" #: common/lib/xmodule/xmodule/course_module.py #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Handouts" msgstr "" @@ -3409,6 +3411,12 @@ msgid "" " no filtering is applied." msgstr "" +#: common/lib/xmodule/xmodule/library_content_module.py +msgid "" +"Determines whether a 'Reset Problems' button is shown, so users may reset " +"their answers and reshuffle selected items." +msgstr "" + #: common/lib/xmodule/xmodule/library_content_module.py msgid "This component is out of date. The library has new content." msgstr "" @@ -4515,8 +4523,7 @@ msgstr "" #: lms/templates/instructor/instructor_dashboard_2/invalidate_registration_code_modal.html #: lms/templates/instructor/instructor_dashboard_2/set_course_mode_price_modal.html #: lms/templates/modal/_modal-settings-language.html -#: lms/templates/signup_modal.html themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html +#: lms/templates/signup_modal.html msgid "Close" msgstr "Zatvoriť" @@ -4928,7 +4935,6 @@ msgstr "" #. Translators: 'Open edX' is a brand, please keep this untranslated. See #. http://openedx.org for more information. #: lms/djangoapps/branding/api.py cms/templates/widgets/footer.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html #: themes/red-theme/lms/templates/footer.html msgid "Powered by Open edX" msgstr "" @@ -4938,7 +4944,6 @@ msgid "Blog" msgstr "" #: lms/djangoapps/branding/api.py cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html #: themes/stanford-style/lms/templates/static_templates/about.html msgid "Contact Us" msgstr "" @@ -4987,7 +4992,6 @@ msgid "News" msgstr "" #: lms/djangoapps/branding/api.py lms/djangoapps/certificates/views/webview.py -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html msgid "Terms of Service & Honor Code" msgstr "" @@ -4997,7 +5001,6 @@ msgstr "" #: lms/djangoapps/branding/api.py lms/djangoapps/certificates/views/webview.py #: cms/templates/widgets/footer.html #: lms/templates/static_templates/privacy.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html #: themes/red-theme/lms/templates/footer.html #: themes/stanford-style/lms/templates/footer.html #: themes/stanford-style/lms/templates/static_templates/tos.html @@ -5012,6 +5015,7 @@ msgstr "" #. Translators: This is a legal document users must agree to #. in order to register a new account. #: lms/djangoapps/branding/api.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: cms/templates/widgets/footer.html lms/templates/static_templates/tos.html #: themes/red-theme/lms/templates/footer.html @@ -5517,23 +5521,6 @@ msgid "" "this request, please visit the link(s) below." msgstr "" -#: lms/djangoapps/course_goals/models.py -#: lms/templates/course_modes/track_selection.html -msgid "Earn a certificate" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Complete the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Explore the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Not sure yet" -msgstr "" - #: lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/body.html msgid "" "\n" @@ -5636,7 +5623,6 @@ msgid "Disabled" msgstr "" #: lms/djangoapps/course_home_api/outline/serializers.py -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html #, python-brace-format msgid "({number} Question)" msgid_plural "({number} Questions)" @@ -5652,6 +5638,11 @@ msgid "" "have questions." msgstr "" +#: lms/djangoapps/course_home_api/outline/views.py +#: lms/templates/courseware/course_about.html +msgid "Course is full" +msgstr "" + #: lms/djangoapps/course_home_api/outline/views.py msgid "'course_id' is required." msgstr "" @@ -5794,20 +5785,6 @@ msgstr "" msgid "Course starts" msgstr "" -#: lms/djangoapps/courseware/date_summary.py -msgid "Don't forget to add a calendar reminder!" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} on {course_start_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} at {course_start_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Course ends" msgstr "" @@ -5831,16 +5808,6 @@ msgid "" " no longer active." msgstr "" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} on {course_end_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} at {course_end_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "You lose all access to this course, including your progress." msgstr "" @@ -5857,23 +5824,6 @@ msgstr "" msgid "Day certificates will become available for passing verified learners." msgstr "" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"If you have earned a certificate, you will be able to access it " -"{time_remaining_string} from now. You will also be able to view your " -"certificates on your {learner_profile_link}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html -msgid "Learner Profile" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -msgid "We are working on generating course certificates." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Upgrade to Verified Certificate" msgstr "" @@ -5903,36 +5853,9 @@ msgstr "" msgid "by {date}" msgstr "" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"Don't forget, you have {time_remaining_string} left to upgrade to a Verified" -" Certificate." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Don't forget to upgrade to a verified certificate by {localized_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"In order to qualify for a certificate, you must meet all course grading " -"requirements, upgrade before the course deadline, and successfully verify " -"your identity on {platform_name} if you have not done so " -"already.{button_panel}" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Upgrade ({upgrade_price})" -msgstr "" - #: lms/djangoapps/courseware/date_summary.py #: cms/templates/group_configurations.html #: lms/templates/courseware/program_marketing.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Learn More" msgstr "" @@ -5992,6 +5915,24 @@ msgstr "" msgid "Disable the dynamic upgrade deadline for this organization." msgstr "" +#: lms/djangoapps/courseware/models.py +msgid "Internal API Base URL" +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Financial Assistance Backend API Base URL." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "" +"Username created for Financial Assistance Backend, e.g. " +"financial_assistance_service_user." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Percentage of courses allowed to use edx-financial-assistance" +msgstr "" + #: lms/djangoapps/courseware/plugins.py lms/djangoapps/courseware/tabs.py #: lms/templates/peer_grading/peer_grading.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html @@ -6067,7 +6008,6 @@ msgstr "" #: lms/djangoapps/courseware/views/index.py #: lms/djangoapps/courseware/views/views.py #: openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "register" msgstr "" @@ -6117,17 +6057,6 @@ msgstr "" msgid "You've earned a certificate for this course." msgstr "" -#: lms/djangoapps/courseware/views/views.py -msgid "Certificate unavailable" -msgstr "" - -#: lms/djangoapps/courseware/views/views.py -#, python-brace-format -msgid "" -"You have not received a certificate because you do not have a current " -"{platform_name} verified identity." -msgstr "" - #: lms/djangoapps/courseware/views/views.py msgid "Your certificate will be available soon!" msgstr "" @@ -6142,23 +6071,31 @@ msgstr "" msgid "Your certificate is available" msgstr "" +#: lms/djangoapps/courseware/views/views.py +msgid "Certificate unavailable" +msgstr "" + +#: lms/djangoapps/courseware/views/views.py +#, python-brace-format +msgid "" +"You have not received a certificate because you do not have a current " +"{platform_name} verified identity." +msgstr "" + #: lms/djangoapps/courseware/views/views.py #, python-brace-format msgid "To see course content, {sign_in_link} or {register_link}." msgstr "" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py #, python-brace-format msgid "{sign_in_link} or {register_link}." msgstr "" #: lms/djangoapps/courseware/views/views.py #: openedx/core/djangoapps/user_authn/templates/user_authn/edx_ace/passwordresetsuccess/email/body.html -#: openedx/features/course_experience/views/course_home_messages.py #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html msgid "Sign in" msgstr "" @@ -6170,7 +6107,6 @@ msgid "" msgstr "" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "You must be enrolled in the course to see course content." msgstr "" @@ -6285,6 +6221,29 @@ msgstr "" msgid "Good" msgstr "" +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#, python-format +msgid "" +"\n" +" %(course_name)s: Reported content awaits review\n" +" " +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +msgid "Go to Discussion" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +#, python-format +msgid "%(course_name)s: Reported content awaits review" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/subject.txt +#, python-format +msgid " %(course_name)s %(course_id)s moderator content for review " +msgstr "" + #: lms/djangoapps/discussion/templates/discussion/edx_ace/responsenotification/email/body.html #, python-format, python-brace-format msgid "%(comment_username)s replied to {start_tag}%(thread_title)s{end_tag}:" @@ -6613,10 +6572,13 @@ msgid "Team" msgstr "" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# +#. Translators: This label appears above a field +#. which allows the user to input the city in which they live. #. Translators: This label appears above a field on the registration form #. which allows the user to input the city in which they live. #: lms/djangoapps/instructor/views/api.py #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: lms/templates/instructor/instructor_dashboard_2/generate_registarion_codes_modal.html #: themes/stanford-style/lms/templates/register-form.html @@ -7408,7 +7370,6 @@ msgstr "" #: lms/templates/learner_dashboard/programs.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Programs" msgstr "" @@ -8266,7 +8227,6 @@ msgstr "" #: lms/templates/courseware/course_about.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "View Course" msgstr "Pozrieť kury" @@ -8516,8 +8476,6 @@ msgstr "" #: lms/templates/wiki/includes/cheatsheet.html lms/templates/dashboard.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/modal/_modal-settings-language.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "window open" msgstr "Otvorené okno" @@ -8759,9 +8717,6 @@ msgstr "" #: lms/templates/courseware/courseware.html lms/templates/dashboard.html #: lms/templates/edxnotes/edxnotes.html lms/templates/index.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -#: themes/edx.org/lms/templates/dashboard.html #: themes/stanford-style/lms/templates/index.html msgid "Search" msgstr "Hľadať" @@ -8865,7 +8820,6 @@ msgstr "" #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Courses" msgstr "Kurzy" @@ -9715,7 +9669,6 @@ msgid "Student" msgstr "Študent" #: openedx/core/djangoapps/embargo/forms.py -#: openedx/core/djangoapps/verified_track_content/forms.py msgid "COURSE NOT FOUND. Please check that the course ID is valid." msgstr "" @@ -9767,6 +9720,10 @@ msgstr "" msgid "Blacklist {country} for {course}" msgstr "" +#: openedx/core/djangoapps/learner_pathway/apps.py +msgid "Learner Pathways" +msgstr "" + #: openedx/core/djangoapps/oauth_dispatch/models.py msgid "" "Comma-separated list of scopes that this application will be allowed to " @@ -10097,7 +10054,6 @@ msgid "" msgstr "" #: openedx/core/djangoapps/schedules/templates/schedules/edx_ace/upgradereminder/email/body.html -#: lms/templates/dates_banner.html msgid "Upgrade now" msgstr "" @@ -10246,6 +10202,14 @@ msgstr "" msgid "Enter your full name." msgstr "" +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your first name." +msgstr "" + +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your last name." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "The email addresses do not match." msgstr "" @@ -10270,6 +10234,10 @@ msgstr "" msgid "Enter your specialty." msgstr "" +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your state." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "Enter your city." msgstr "" @@ -10311,24 +10279,39 @@ msgstr "" msgid "The '{field_name}' field cannot be edited." msgstr "" +#: openedx/core/djangoapps/user_api/accounts/api.py +#: openedx/core/djangoapps/user_authn/views/registration_form.py +msgid "Enter a valid name" +msgstr "" + +#. Translators: This label appears above a field which allows the +#. user to input the First Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "First Name" msgstr "" +#. Translators: This label appears above a field which allows the +#. user to input the Last Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "Last Name" msgstr "" +#. Translators: This label appears above a field +#. which allows the user to input the State/Province/Region in which they +#. live. #. Translators: This label appears above a field on the registration form #. which allows the user to input the State/Province/Region in which they #. live. #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "State/Province/Region" msgstr "" @@ -10366,9 +10349,12 @@ msgid "Job Title" msgstr "" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# +#. Translators: This label appears above a field +#. meant to hold the user's mailing address. #. Translators: This label appears above a field on the registration form #. meant to hold the user's mailing address. #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: lms/templates/signup_modal.html msgid "Mailing address" @@ -10634,7 +10620,6 @@ msgstr "" #: openedx/core/djangoapps/user_authn/views/login.py #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html #: themes/stanford-style/lms/templates/register-form.html msgid "Register" msgstr "" @@ -10753,10 +10738,6 @@ msgstr "" msgid "Full Name cannot contain the following characters: < >" msgstr "" -#: openedx/core/djangoapps/user_authn/views/registration_form.py -msgid "Enter a valid name" -msgstr "" - #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "A properly formatted e-mail is required" msgstr "" @@ -10928,15 +10909,9 @@ msgstr "" #: openedx/core/djangoapps/util/user_messages.py #: cms/templates/course_outline.html cms/templates/index.html -#: openedx/features/course_experience/templates/course_experience/latest-update-fragment.html -#: openedx/features/course_experience/templates/course_experience/welcome-message-fragment.html msgid "Dismiss" msgstr "" -#: openedx/core/djangoapps/verified_track_content/models.py -msgid "The course key for the course we would like to be auto-cohorted." -msgstr "" - #: openedx/core/djangoapps/video_pipeline/models.py msgid "Oauth client name of VEM service." msgstr "" @@ -11196,51 +11171,6 @@ msgstr "" msgid "Updates" msgstr "" -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{sign_in_link} or {register_link} and then enroll in this course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Welcome to {course_display_name}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"You must be enrolled in the course to see course content. Please contact " -"your degree administrator or {platform_name} Support if you have questions." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"{open_enroll_link}Enroll now{close_enroll_link} to access the full course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"To start, set a course goal by selecting the option below that best " -"describes your learning plan. {goal_options_container}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {goal_text}" -msgstr "" - #: openedx/features/discounts/admin.py msgid "" "These define the context to disable lms-controlled discounts on. If no " @@ -11340,12 +11270,10 @@ msgid "Continue" msgstr "" #: openedx/features/personalized_learner_schedules/call_to_action.py -#: lms/templates/dates_banner.html msgid "Shift due dates" msgstr "" #: openedx/features/personalized_learner_schedules/call_to_action.py -#: lms/templates/dates_banner.html msgid "" "It looks like you missed some important deadlines based on our suggested " "schedule." @@ -12356,11 +12284,6 @@ msgstr "Názov kurzu" msgid "Course Number" msgstr "Číslo kurzu" -#: cms/templates/course_outline.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Course Outline" -msgstr "" - #: cms/templates/html_error.html lms/templates/course_modes/error.html #: lms/templates/module-error.html msgid "Error:" @@ -12448,62 +12371,10 @@ msgstr "Účet" #: lms/templates/header/navbar-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: lms/templates/static_templates/help.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -#: wiki/plugins/help/wiki_plugin.py +#: lms/templates/static_templates/help.html wiki/plugins/help/wiki_plugin.py msgid "Help" msgstr "Pomoc" -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Looking for help with {studio_name}?" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Hide {studio_name} Help" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "{studio_name} Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Access documentation on http://docs.edx.org" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101: Overview of Creating an edX Course" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX: Creating a Course with edX Studio" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Send an email to {email}" -msgstr "" - #: cms/templates/widgets/tabs-aggregator.html #: lms/templates/courseware/static_tab.html #: lms/templates/courseware/tab-view.html @@ -12679,19 +12550,18 @@ msgstr "Zobraziť všetky kurzy" #: lms/templates/dashboard.html lms/templates/header/user_dropdown.html #: lms/templates/user_dropdown.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Dashboard" msgstr "Panel" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "results successfully populated," msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Click to load all enrolled courses" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "You are not enrolled in any courses yet." msgstr "" @@ -12699,7 +12569,6 @@ msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore courses" msgstr "" @@ -12708,16 +12577,15 @@ msgstr "" msgid "Activate your account!" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Course-loading errors" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Search Your Courses" msgstr "Hľadať v kurzoch" #: lms/templates/courseware/courseware.html lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Clear search" msgstr "Vyčistiť hľadanie" @@ -12740,15 +12608,15 @@ msgstr "" msgid "Continue to {platform_name}" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Email Settings for {course_number}" msgstr "Nastavenie e-mailu pre {course_number}" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Receive course emails" msgstr "Prijímať e-maily z kurzu" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Save Settings" msgstr "Uložiť nastavenia" @@ -12757,83 +12625,9 @@ msgstr "Uložiť nastavenia" #: lms/templates/dashboard/_dashboard_entitlement_actions.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/instructor/instructor_dashboard_2/membership.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "Unenroll" msgstr "Odregistrovať" -#: lms/templates/dates_banner.html -msgid "" -"It looks like you missed some important deadlines based on our suggested " -"schedule. " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future by visiting " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" Don't worry—you won't lose any of the progress you've made when you shift " -"your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future. Don't worry—you won't lose any of the " -"progress you've made when you shift your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "You are auditing this course," -msgstr "" - -#: lms/templates/dates_banner.html -msgid " which means that you are unable to participate in graded assignments." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. Graded assignments and schedule adjustment are available to " -"Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. To complete graded assignments as part of this course and shift " -"the past due assignments into the future, you can upgrade today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Upgrade to shift due dates" -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Graded assignments are available to Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" To complete graded assignments as part of this course, you can upgrade " -"today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "We've built a suggested schedule to help you stay on track." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"But don't worry—it's flexible so you can learn at your own pace. If you " -"happen to fall behind on our suggested dates, you'll be able to adjust them " -"to keep yourself on track." -msgstr "" - #: lms/templates/email_change_failed.html lms/templates/email_exists.html msgid "E-mail change failed" msgstr "Zmena e-mailu neúspešná!" @@ -13158,10 +12952,6 @@ msgstr "" msgid "You are now viewing the course as {i_start}{user_name}{i_end}." msgstr "" -#: lms/templates/preview_menu.html -msgid "View in the new experience" -msgstr "" - #: lms/templates/preview_menu.html msgid "View in Studio" msgstr "" @@ -13282,9 +13072,7 @@ msgstr "" msgid "Sequence" msgstr "" -#: lms/templates/courseware/dates.html lms/templates/seq_module.html -#: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html +#: lms/templates/seq_module.html lms/templates/vert_module.html msgid "Completed" msgstr "" @@ -13550,7 +13338,6 @@ msgid "" msgstr "" #: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "{subsection_format} due {{date}}" msgstr "" @@ -13562,6 +13349,10 @@ msgstr "" msgid "Past due" msgstr "" +#: lms/templates/vert_module.html +msgid "Reset Problems" +msgstr "" + #: lms/templates/video.html msgid "Loading video player" msgstr "" @@ -14611,7 +14402,6 @@ msgid "Download student grades" msgstr "" #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Print or share your certificate:" msgstr "" @@ -14625,7 +14415,6 @@ msgstr "" #: lms/templates/certificates/_accomplishment-banner.html #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Twitter" msgstr "" @@ -14634,7 +14423,6 @@ msgid "Tweet this Accomplishment. Pop up window." msgstr "" #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Add to LinkedIn Profile" msgstr "" @@ -14725,40 +14513,31 @@ msgstr "" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue the Verified Track" msgstr "" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue a Verified Certificate" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Enroll In {course_name} | Choose Your Track" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Sorry, there was an error when trying to enroll you" msgstr "Ospravedlňujeme sa, ale došlo ku chybe pri pokuse zapísať Vás." #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with the Verified Track" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with a Verified Certificate" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Become eligible for academic credit and highlight your new skills and " "knowledge with a verified certificate. Use this valuable credential to " @@ -14767,59 +14546,50 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of the Verified Track" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Eligible for credit:{b_end} Receive academic credit after " "successfully completing the course" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Unlimited Course Access: {b_end}Learn at your own pace, and access " "materials anytime to brush up on what you've learned." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Graded Assignments: {b_end}Build your skills through graded " "assignments and projects." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily Sharable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of a Verified Certificate" msgstr "Výhody overeného certifikátu" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official:{b_end} Receive an instructor-signed certificate with the " "institution's logo" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable:{b_end} Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Highlight your new knowledge and skills with a verified certificate. Use " "this valuable credential to improve your job prospects and advance your " @@ -14827,45 +14597,38 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official: {b_end}Receive an instructor-signed certificate with the " "institution's logo" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Motivating: {b_end}Give yourself an additional incentive to " "complete the course" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course" msgstr "Auditovať tento kurz" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course (No Certificate)" msgstr "Sledovať tento kurz (Žiaden certifikát)" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded assignments," @@ -14873,7 +14636,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded " @@ -14881,7 +14643,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include unlimited course " @@ -14889,7 +14650,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums. {b_start}Please note that this " @@ -14973,6 +14733,10 @@ msgstr "" msgid "Choose a path for your course in" msgstr "" +#: lms/templates/course_modes/track_selection.html +msgid "Earn a certificate" +msgstr "" + #: lms/templates/course_modes/track_selection.html msgid "" "Studies show that those who choose this option are {start_bold}more engaged" @@ -14997,7 +14761,6 @@ msgstr "" #: lms/templates/courseware/accordion.html #: lms/templates/courseware/progress.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "due {date}" msgstr "" @@ -15006,7 +14769,6 @@ msgid "{section_format} due {{date}}" msgstr "" #: lms/templates/courseware/accordion.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "This content is graded" msgstr "" @@ -15018,10 +14780,6 @@ msgstr "" msgid "You are enrolled in this course" msgstr "" -#: lms/templates/courseware/course_about.html -msgid "Course is full" -msgstr "" - #: lms/templates/courseware/course_about.html msgid "Enrollment in this course is by invitation only" msgstr "" @@ -15177,30 +14935,6 @@ msgstr "" msgid "Your score is {current_score}%. You have passed the entrance exam." msgstr "" -#: lms/templates/courseware/dates.html lms/templates/courseware/syllabus.html -msgid "{course.display_number_with_default} Course Info" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Important Dates" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Today" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Verified Only" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Due Next" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Not yet released" -msgstr "" - #: lms/templates/courseware/gradebook.html msgid "Gradebook" msgstr "" @@ -15250,8 +14984,6 @@ msgstr "" #: lms/templates/courseware/info.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "Resume Course" msgstr "" @@ -15268,7 +15000,6 @@ msgid "Handout Navigation" msgstr "" #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Tools" msgstr "" @@ -15514,6 +15245,10 @@ msgstr "" msgid "No problem scores in this section" msgstr "" +#: lms/templates/courseware/syllabus.html +msgid "{course.display_number_with_default} Course Info" +msgstr "" + #: lms/templates/courseware/welcome-back.html msgid "" "You were most recently in {section_link}. If you're done with that, choose " @@ -15744,7 +15479,6 @@ msgid "Share {course_name} on Facebook" msgstr "" #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Facebook" msgstr "" @@ -15792,6 +15526,12 @@ msgid "" "showcase on your resumé." msgstr "" +#: lms/templates/dashboard/_dashboard_course_listing.html +msgid "" +"{start_bold}Get the most out of your course!{end_bold} Upgrade to earn a " +"{link_start}verified certificate{link_end} to showcase on your resumé." +msgstr "" + #: lms/templates/dashboard/_dashboard_course_listing.html msgid "Upgrade" msgstr "" @@ -16567,7 +16307,6 @@ msgid "" msgstr "" #: lms/templates/header/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Discover New" msgstr "" @@ -16581,7 +16320,6 @@ msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "How it Works" msgstr "" @@ -17987,7 +17725,6 @@ msgid "" msgstr "" #: lms/templates/learner_dashboard/_dashboard_navigation_courses.html -#: themes/edx.org/lms/templates/dashboard.html msgid "My Courses" msgstr "Moje kurzy" @@ -18397,13 +18134,10 @@ msgid "Skeleton Page" msgstr "" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html msgid "Search the course" msgstr "" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Start Course" msgstr "" @@ -18576,36 +18310,6 @@ msgstr "" msgid "View all course dates" msgstr "" -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Goal: " -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Edit your course goal:" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Pursue a verified certificate" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "" -"Sample verified certificate with your name, the course title, the logo of " -"the institution and the signatures of the instructors for this course." -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Upgrade ({price})" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Expand All" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Prerequisite: " -msgstr "" - #: openedx/features/course_experience/templates/course_experience/course-sock-fragment.html msgid "Learn About Verified Certificates" msgstr "" @@ -18686,18 +18390,6 @@ msgstr "" msgid "This course does not have any updates." msgstr "" -#: openedx/features/course_experience/templates/course_experience/latest-update-fragment.html -msgid "Latest Update" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/welcome-message-fragment.html -msgid "Show More" -msgstr "" - -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -msgid "Search Results" -msgstr "" - #. Translators: this section lists all the third-party authentication #. providers #. (for example, Google and LinkedIn) the user can link with or unlink from @@ -18741,10 +18433,13 @@ msgid "You haven't earned any certificates yet." msgstr "" #: openedx/features/learner_profile/templates/learner_profile/learner-achievements-fragment.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore New Courses" msgstr "" +#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html +msgid "Learner Profile" +msgstr "" + #: openedx/features/learner_profile/templates/learner_profile/learner_profile.html msgid "View My Records" msgstr "" @@ -18762,138 +18457,6 @@ msgstr "" msgid "An error occurred. Try loading the page again." msgstr "" -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "" -"Access Course Staff Support on the Partner Portal to submit or review " -"support tickets" -msgstr "" - -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Partner Portal" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "" -"Browse recently launched courses and see what's new in your favorite " -"subjects." -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Take advantage of free coaching!" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Get Started" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Page Footer" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "edX Home Page" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Connect" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "© {year} edX Inc. All rights reserved." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "About edX Verified Certificates" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "" -"An edX Verified Certificate signifies that the learner has agreed to abide " -"by the edX honor code and completed all of the required tasks of this course" -" under its guidelines, as well as having their photo ID checked to verify " -"their identity." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "About edX" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "" -"{link_start}edX{link_end} offers interactive online classes and MOOCs from " -"the world's best universities, including MIT, Harvard, Berkeley, University " -"of Texas, and many others. edX is a mission driven initiative created by " -"founding partners Harvard and MIT." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Congratulations, {user_name}!" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "" -"You worked hard to earn your certificate from " -"{accomplishment_copy_course_org} {dash} share it with colleagues, friends, " -"and family to get the word out about what you mastered in " -"{accomplishment_course_title}." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Share this certificate on Facebook (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Tweet this certificate (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Add this certificate to your LinkedIn profile (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print this certificate" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "edX Inc." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "" -"All rights reserved except where noted. edX, Open edX and the edX and Open " -"edX logos are registered trademarks of edX Inc." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end}EdX relies on verified certificates to " -"help fund affordable education to everyone globally." -msgstr "" - -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end} EdX, a mission driven initiative, " -"relies on verified certificates to help fund free education for everyone " -"globally" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Find Courses" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Schools & Partners" -msgstr "" - #: themes/red-theme/lms/templates/footer.html msgid "" "{tos_link_start}Terms of Service{tos_link_end} and {honor_link_start}Honor " @@ -19529,6 +19092,10 @@ msgid "" "respond to student questions. You add or edit updates in HTML." msgstr "" +#: cms/templates/course_outline.html +msgid "Course Outline" +msgstr "" + #: cms/templates/course_outline.html msgid "" "This course was created as a re-run. Some manual configuration is needed." @@ -22197,6 +21764,26 @@ msgstr "" msgid "Label" msgstr "" +#: cms/templates/widgets/sock.html +msgid "Looking for help with {studio_name}?" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "Hide {studio_name} Help" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "{studio_name} Documentation" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Access documentation on http://docs.edx.org" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "edX Documentation" +msgstr "" + #: cms/templates/widgets/sock_links.html msgid "Access the Open edX Portal" msgstr "" @@ -22205,6 +21792,26 @@ msgstr "" msgid "Open edX Portal" msgstr "" +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101: Overview of Creating an edX Course" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX: Creating a Course with edX Studio" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Send an email to {email}" +msgstr "" + #: cms/templates/widgets/user_dropdown.html msgid "Currently signed in as:" msgstr "" diff --git a/conf/locale/sk/LC_MESSAGES/djangojs.mo b/conf/locale/sk/LC_MESSAGES/djangojs.mo index 39186c20f1fd5fc54ab353725069ae7b7a7c3f24..f25265ec5ee21a0aeaeb473d864002b9dd5f105f 100644 GIT binary patch delta 18 Ycmdn+lyL(P1$i-B=oxGd^@`R2089`D=Kufz delta 18 Ycmdn+lyL(P1$i-B>KSeh^@`R208AbR=>Px# diff --git a/conf/locale/sk/LC_MESSAGES/djangojs.po b/conf/locale/sk/LC_MESSAGES/djangojs.po index 5d535c8337..d3672296d2 100644 --- a/conf/locale/sk/LC_MESSAGES/djangojs.po +++ b/conf/locale/sk/LC_MESSAGES/djangojs.po @@ -46,7 +46,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: \n" "Language-Team: Slovak (http://www.transifex.com/open-edx/edx-platform/language/sk/)\n" @@ -55,7 +55,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js #: cms/static/js/views/video_transcripts.js @@ -101,7 +101,6 @@ msgstr "Odstrániť" #: common/lib/xmodule/xmodule/js/src/html/edit.js #: common/static/common/js/components/utils/view_utils.js #: lms/static/js/Markdown.Editor.js -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx #: lms/static/js/student_account/components/StudentAccountDeletionModal.jsx #: cms/templates/js/add-xblock-component-menu-problem.underscore #: cms/templates/js/add-xblock-component-menu.underscore @@ -270,6 +269,14 @@ msgstr "Chyba" msgid "Updating with latest library content" msgstr "Aktualizujem s najnovším obsahom knižnice" +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Loading..." +msgstr "" + +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Selected blocks" +msgstr "" + #: common/lib/xmodule/xmodule/assets/library_source_block/public/js/library_source_block.js msgid "Unable to update settings" msgstr "" @@ -1186,6 +1193,7 @@ msgstr "Nové okno" #. Translators: this is a message from the raw HTML editor displayed in the #. browser when a user needs to edit HTML #: common/lib/xmodule/xmodule/js/src/html/edit.js +#: lms/static/js/demographics_collection/Wizard.jsx msgid "Next" msgstr "Ďalej" @@ -1932,6 +1940,10 @@ msgstr "" msgid "Navigate up" msgstr "" +#: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx +msgid "Browsing" +msgstr "" + #: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx msgid "Select" msgstr "" @@ -2470,10 +2482,30 @@ msgid "" "within the Discussion Forum where the Course Staff can directly respond." msgstr "" +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Details" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "the more quickly and helpfully we can respond!" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Create Support Ticket" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "What can we help you with, {username}?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx msgid "Sign in to {platform} so we can help you better." msgstr "" +#: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx +msgid "Need help logging in?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/single_support_form.jsx msgid "" "Select a course or select \"Not specific to a course\" for your support " @@ -3297,20 +3329,52 @@ msgstr "" msgid "Get started" msgstr "" -#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx -msgid "Section {currentPage} of {totalPages}" -msgstr "" - #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "Help make edX better for everyone!" msgstr "" +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Why does edX collect this information?" +msgstr "" + #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "" -"Welcome to edX! Before you get started, please take a few minutes to fill-in" -" the additional information below to help us understand a bit more about " -"your background. You can always edit this information later in Account " -"Settings." +"An error occurred while attempting to retrieve or save the information " +"below. Please try again later." +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What was the total combined income, during the last 12 months, of all " +"members of your family? " +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"Have you ever served on active duty in the U.S. Armed Forces, Reserves, or " +"National Guard?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What is the highest level of education that you have achieved so far?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What is the highest level of education that any of your parents or guardians" +" have achieved?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Select employment status" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you currently work in?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you want to work in?" msgstr "" #: lms/static/js/demographics_collection/MultiselectDropdown.jsx @@ -3325,6 +3389,22 @@ msgstr "" msgid "close questionnaire" msgstr "" +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Return to my dashboard" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "next page" +msgstr "" + #: lms/static/js/discovery/views/search_form.js #, javascript-format msgid "Viewing %s course" @@ -3625,27 +3705,6 @@ msgstr "" msgid "Cohorts Disabled" msgstr "" -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course uses automatic cohorting for verified track learners. You cannot" -" disable cohorts, and you cannot rename the manual cohort named " -"'{verifiedCohortName}'. To change the configuration for verified track " -"cohorts, contact your edX partner manager." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" the required cohort does not exist. You must create a manually-assigned " -"cohort named '{verifiedCohortName}' for the feature to work." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" cohorts are disabled. You must enable cohorts for the feature to work." -msgstr "" - #: lms/static/js/instructor_dashboard/certificates.js msgid "Allow students to generate certificates for this course?" msgstr "" @@ -4305,10 +4364,6 @@ msgid "" "sensitive nature of student information." msgstr "" -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx -msgid "You have access to the {enterpriseName} dashboard" -msgstr "" - #: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx msgid "" "To access the courses available to you through {enterpriseName}, visit the " @@ -5139,44 +5194,6 @@ msgstr "" msgid "Bookmark this page" msgstr "" -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "Thank you for setting your course goal to {goal}!" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "" -"There was an error in setting your goal, please reload the page and try " -"again." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "You have successfully updated your goal." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "There was an error updating your goal." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseOutline.js -#: lms/templates/ccx/schedule.underscore -msgid "Expand All" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseOutline.js -#: lms/templates/ccx/schedule.underscore -msgid "Collapse All" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show More" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show Less" -msgstr "" - #: openedx/features/course_search/static/course_search/js/views/search_results_view.js msgid "{total_results} result found for \"{search_term}\"" msgid_plural "{total_results} results found for \"{search_term}\"" @@ -5460,6 +5477,30 @@ msgstr "" msgid "There was an error with the upload" msgstr "" +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Organization:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Number:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Run:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "(Read-only)" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Re-run Course" +msgstr "" + +#: cms/templates/js/show-textbook.underscore +msgid "View Live" +msgstr "Zobraziť aktuálne údaje" + #: cms/static/js/maintenance/force_publish_course.js msgid "Internal Server Error." msgstr "" @@ -6953,10 +6994,6 @@ msgstr "" msgid "follow this post" msgstr "" -#: common/static/common/templates/discussion/templates.underscore -msgid "post anonymously" -msgstr "" - #: common/static/common/templates/discussion/templates.underscore msgid "post anonymously to classmates" msgstr "" @@ -7401,6 +7438,14 @@ msgstr "" msgid "This catalog's courses:" msgstr "" +#: lms/templates/ccx/schedule.underscore +msgid "Expand All" +msgstr "" + +#: lms/templates/ccx/schedule.underscore +msgid "Collapse All" +msgstr "" + #: lms/templates/ccx/schedule.underscore msgid "Start Date" msgstr "Dátum začiatku" @@ -7484,6 +7529,14 @@ msgid "" "before you select \"End My Exam\"." msgstr "" +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show More" +msgstr "" + +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show Less" +msgstr "" + #: lms/templates/discovery/course_card.underscore msgid "LEARN MORE" msgstr "DOZVEDIEŤ SA VIAC" @@ -10129,10 +10182,6 @@ msgstr "" msgid "PDF Chapters" msgstr "" -#: cms/templates/js/show-textbook.underscore -msgid "View Live" -msgstr "Zobraziť aktuálne údaje" - #: cms/templates/js/signatory-details.underscore #: cms/templates/js/signatory-editor.underscore msgid "Signatory" diff --git a/conf/locale/sw_KE/LC_MESSAGES/django.mo b/conf/locale/sw_KE/LC_MESSAGES/django.mo index 8917352d62b2b9312f971c9379ccc236955b1199..8d7d8184894dd050accd13c7035698fb52720345 100644 GIT binary patch delta 26 icmexxg8#z_{)QIDB}|UY7J3Hl%#KXknH`yP7Xtu|stE4@ delta 26 icmexxg8#z_{)QIDB}|UYmU@Qm%#KXknH`yP7Xtu|!U*vI diff --git a/conf/locale/sw_KE/LC_MESSAGES/django.po b/conf/locale/sw_KE/LC_MESSAGES/django.po index 60db4d7f83..bdee88f21d 100644 --- a/conf/locale/sw_KE/LC_MESSAGES/django.po +++ b/conf/locale/sw_KE/LC_MESSAGES/django.po @@ -85,7 +85,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:44+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Waheed Ahmed , 2019\n" "Language-Team: Swahili (Kenya) (https://www.transifex.com/open-edx/teams/6205/sw_KE/)\n" @@ -94,7 +94,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# #. Translators: 'Discussion' refers to the tab in the courseware that leads to @@ -692,6 +692,10 @@ msgstr "Kitambulisho cha kozi ni batili" msgid "Could not enroll" msgstr "Haikuweza kusajili" +#: common/djangoapps/student/views/management.py +msgid "Unenrollment is currently disabled" +msgstr "" + #: common/djangoapps/student/views/management.py msgid "You are not enrolled in this course" msgstr "Hujasajiliwa kwenye kozi hii" @@ -1791,7 +1795,6 @@ msgstr "" #. to the site. #: common/lib/capa/capa/responsetypes.py #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html #: themes/stanford-style/lms/templates/register-form.html msgid "or" msgstr "au" @@ -2017,7 +2020,6 @@ msgid "Never" msgstr "Kamwe" #: common/lib/xmodule/xmodule/capa_module.py -#: lms/templates/courseware/dates.html msgid "Past Due" msgstr "" @@ -2083,6 +2085,7 @@ msgid "Whether to force the save button to appear on the page" msgstr "" #: common/lib/xmodule/xmodule/capa_module.py +#: common/lib/xmodule/xmodule/library_content_module.py msgid "Show Reset Button" msgstr "" @@ -2824,7 +2827,6 @@ msgstr "" #: common/lib/xmodule/xmodule/course_module.py #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Handouts" msgstr "Kitini cha Kozi" @@ -3493,6 +3495,12 @@ msgid "" " no filtering is applied." msgstr "" +#: common/lib/xmodule/xmodule/library_content_module.py +msgid "" +"Determines whether a 'Reset Problems' button is shown, so users may reset " +"their answers and reshuffle selected items." +msgstr "" + #: common/lib/xmodule/xmodule/library_content_module.py msgid "This component is out of date. The library has new content." msgstr "" @@ -4607,8 +4615,7 @@ msgstr "" #: lms/templates/instructor/instructor_dashboard_2/invalidate_registration_code_modal.html #: lms/templates/instructor/instructor_dashboard_2/set_course_mode_price_modal.html #: lms/templates/modal/_modal-settings-language.html -#: lms/templates/signup_modal.html themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html +#: lms/templates/signup_modal.html msgid "Close" msgstr "Funga" @@ -5014,7 +5021,6 @@ msgstr "" #. Translators: 'Open edX' is a brand, please keep this untranslated. See #. http://openedx.org for more information. #: cms/templates/widgets/footer.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html #: themes/red-theme/lms/templates/footer.html msgid "Powered by Open edX" msgstr "Imewezeshwa na edX ya Wazi" @@ -5024,7 +5030,6 @@ msgid "Blog" msgstr "Blogi" #: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html #: themes/stanford-style/lms/templates/static_templates/about.html msgid "Contact Us" msgstr "Wasiliana Nasi" @@ -5071,7 +5076,6 @@ msgid "News" msgstr "Habari" #: lms/djangoapps/branding/api.py lms/djangoapps/certificates/views/webview.py -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html msgid "Terms of Service & Honor Code" msgstr "" @@ -5081,7 +5085,6 @@ msgstr "" #: lms/djangoapps/branding/api.py lms/djangoapps/certificates/views/webview.py #: cms/templates/widgets/footer.html #: lms/templates/static_templates/privacy.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html #: themes/red-theme/lms/templates/footer.html #: themes/stanford-style/lms/templates/footer.html #: themes/stanford-style/lms/templates/static_templates/tos.html @@ -5096,6 +5099,7 @@ msgstr "" #. Translators: This is a legal document users must agree to #. in order to register a new account. #: lms/djangoapps/branding/api.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: cms/templates/widgets/footer.html lms/templates/static_templates/tos.html #: themes/red-theme/lms/templates/footer.html @@ -5609,23 +5613,6 @@ msgid "" "this request, please visit the link(s) below." msgstr "" -#: lms/djangoapps/course_goals/models.py -#: lms/templates/course_modes/track_selection.html -msgid "Earn a certificate" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Complete the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Explore the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Not sure yet" -msgstr "" - #: lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/body.html msgid "" "\n" @@ -5726,7 +5713,6 @@ msgid "Disabled" msgstr "" #: lms/djangoapps/course_home_api/outline/serializers.py -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html #, python-brace-format msgid "({number} Question)" msgid_plural "({number} Questions)" @@ -5740,6 +5726,10 @@ msgid "" "have questions." msgstr "" +#: lms/templates/courseware/course_about.html +msgid "Course is full" +msgstr "Kozi imejaa wanafunzi" + #: lms/djangoapps/course_home_api/outline/views.py msgid "'course_id' is required." msgstr "" @@ -5882,20 +5872,6 @@ msgstr "Tarehe ya Usajili" msgid "Course starts" msgstr "" -#: lms/djangoapps/courseware/date_summary.py -msgid "Don't forget to add a calendar reminder!" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} on {course_start_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} at {course_start_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Course ends" msgstr "" @@ -5921,16 +5897,6 @@ msgstr "" "Kozi hii iko kwenye hifadhi ya nyaraka, ikimaanisha unaweza kutizama " "yaliyomo ya kozi lakini haitumiki tena." -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} on {course_end_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} at {course_end_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "You lose all access to this course, including your progress." msgstr "" @@ -5947,22 +5913,6 @@ msgstr "" msgid "Day certificates will become available for passing verified learners." msgstr "" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"If you have earned a certificate, you will be able to access it " -"{time_remaining_string} from now. You will also be able to view your " -"certificates on your {learner_profile_link}." -msgstr "" - -#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html -msgid "Learner Profile" -msgstr "Wasifu wa Mwanafunzi" - -#: lms/djangoapps/courseware/date_summary.py -msgid "We are working on generating course certificates." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Upgrade to Verified Certificate" msgstr "" @@ -5994,36 +5944,9 @@ msgstr "" msgid "by {date}" msgstr "" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"Don't forget, you have {time_remaining_string} left to upgrade to a Verified" -" Certificate." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Don't forget to upgrade to a verified certificate by {localized_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"In order to qualify for a certificate, you must meet all course grading " -"requirements, upgrade before the course deadline, and successfully verify " -"your identity on {platform_name} if you have not done so " -"already.{button_panel}" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Upgrade ({upgrade_price})" -msgstr "" - #: lms/djangoapps/courseware/date_summary.py #: cms/templates/group_configurations.html #: lms/templates/courseware/program_marketing.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Learn More" msgstr "Jifunze Zaidi" @@ -6087,6 +6010,24 @@ msgstr "" msgid "Disable the dynamic upgrade deadline for this organization." msgstr "" +#: lms/djangoapps/courseware/models.py +msgid "Internal API Base URL" +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Financial Assistance Backend API Base URL." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "" +"Username created for Financial Assistance Backend, e.g. " +"financial_assistance_service_user." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Percentage of courses allowed to use edx-financial-assistance" +msgstr "" + #: lms/djangoapps/courseware/plugins.py lms/djangoapps/courseware/tabs.py #: lms/templates/peer_grading/peer_grading.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html @@ -6162,7 +6103,6 @@ msgstr "" #: lms/djangoapps/courseware/views/index.py #: lms/djangoapps/courseware/views/views.py #: openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "register" msgstr "" @@ -6216,19 +6156,6 @@ msgstr "" msgid "You've earned a certificate for this course." msgstr "" -#: lms/djangoapps/courseware/views/views.py -msgid "Certificate unavailable" -msgstr "Cheti hakipatikani" - -#: lms/djangoapps/courseware/views/views.py -#, python-brace-format -msgid "" -"You have not received a certificate because you do not have a current " -"{platform_name} verified identity." -msgstr "" -"Hujapokea cheti kwasababu huna utambulisho wa sasa wa {platform_name} " -"uliohakikiwa." - #: lms/djangoapps/courseware/views/views.py msgid "Your certificate will be available soon!" msgstr "" @@ -6243,20 +6170,31 @@ msgstr "" msgid "Your certificate is available" msgstr "Cheti chako kinapatikana" +#: lms/djangoapps/courseware/views/views.py +msgid "Certificate unavailable" +msgstr "Cheti hakipatikani" + +#: lms/djangoapps/courseware/views/views.py +#, python-brace-format +msgid "" +"You have not received a certificate because you do not have a current " +"{platform_name} verified identity." +msgstr "" +"Hujapokea cheti kwasababu huna utambulisho wa sasa wa {platform_name} " +"uliohakikiwa." + #: lms/djangoapps/courseware/views/views.py #, python-brace-format msgid "To see course content, {sign_in_link} or {register_link}." msgstr "" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py #, python-brace-format msgid "{sign_in_link} or {register_link}." msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html msgid "Sign in" msgstr "Ingia mtandaoni " @@ -6268,7 +6206,6 @@ msgid "" msgstr "" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "You must be enrolled in the course to see course content." msgstr "" @@ -6387,6 +6324,29 @@ msgstr "" msgid "Good" msgstr "Vizuri" +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#, python-format +msgid "" +"\n" +" %(course_name)s: Reported content awaits review\n" +" " +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +msgid "Go to Discussion" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +#, python-format +msgid "%(course_name)s: Reported content awaits review" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/subject.txt +#, python-format +msgid " %(course_name)s %(course_id)s moderator content for review " +msgstr "" + #: lms/djangoapps/discussion/templates/discussion/edx_ace/responsenotification/email/body.html #, python-format, python-brace-format msgid "%(comment_username)s replied to {start_tag}%(thread_title)s{end_tag}:" @@ -7503,7 +7463,6 @@ msgstr "" #: lms/templates/learner_dashboard/programs.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Programs" msgstr "Programu" @@ -8369,7 +8328,6 @@ msgstr "" #: lms/templates/courseware/course_about.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "View Course" msgstr "Angalia Kozi" @@ -8618,8 +8576,6 @@ msgstr "Pitia 'Wiki' " #: lms/templates/wiki/includes/cheatsheet.html lms/templates/dashboard.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/modal/_modal-settings-language.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "window open" msgstr "dirisha likowazi" @@ -8861,9 +8817,6 @@ msgstr "" #: lms/templates/courseware/courseware.html lms/templates/dashboard.html #: lms/templates/edxnotes/edxnotes.html lms/templates/index.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -#: themes/edx.org/lms/templates/dashboard.html #: themes/stanford-style/lms/templates/index.html msgid "Search" msgstr "Tafuta" @@ -8957,7 +8910,6 @@ msgstr "" #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Courses" msgstr "Kozi" @@ -9819,7 +9771,6 @@ msgid "Student" msgstr "Mwanafunzi" #: openedx/core/djangoapps/embargo/forms.py -#: openedx/core/djangoapps/verified_track_content/forms.py msgid "COURSE NOT FOUND. Please check that the course ID is valid." msgstr "" "KOZI HAIKUPATIKANA. Tafadhali angalia ikiwa Kitambulisho cha kozi ni halali." @@ -9879,6 +9830,10 @@ msgstr "Orodha ya {country} zinazokubaliwa kwenye {course}" msgid "Blacklist {country} for {course}" msgstr "Orodha ya {country} zisizokubaliwa kwenye {course}" +#: openedx/core/djangoapps/learner_pathway/apps.py +msgid "Learner Pathways" +msgstr "" + #: openedx/core/djangoapps/oauth_dispatch/models.py msgid "" "Comma-separated list of scopes that this application will be allowed to " @@ -10214,7 +10169,6 @@ msgid "" msgstr "" #: openedx/core/djangoapps/schedules/templates/schedules/edx_ace/upgradereminder/email/body.html -#: lms/templates/dates_banner.html msgid "Upgrade now" msgstr "" @@ -10367,6 +10321,14 @@ msgstr "" msgid "Enter your full name." msgstr "" +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your first name." +msgstr "" + +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your last name." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "The email addresses do not match." msgstr "Anwani za barua pepe hazilingani." @@ -10391,6 +10353,10 @@ msgstr "" msgid "Enter your specialty." msgstr "" +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your state." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "Enter your city." msgstr "" @@ -10432,24 +10398,39 @@ msgstr "" msgid "The '{field_name}' field cannot be edited." msgstr "Hii '{field_name}' sehemu haiwezi kuhaririwa." +#: openedx/core/djangoapps/user_api/accounts/api.py +#: openedx/core/djangoapps/user_authn/views/registration_form.py +msgid "Enter a valid name" +msgstr "" + +#. Translators: This label appears above a field which allows the +#. user to input the First Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "First Name" msgstr "Jina la Kwanza" +#. Translators: This label appears above a field which allows the +#. user to input the Last Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "Last Name" msgstr "Jina la Mwisho" +#. Translators: This label appears above a field +#. which allows the user to input the State/Province/Region in which they +#. live. #. Translators: This label appears above a field on the registration form #. which allows the user to input the State/Province/Region in which they #. live. #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "State/Province/Region" msgstr "Jimbo/Mkoa" @@ -10479,9 +10460,12 @@ msgid "Job Title" msgstr "" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# +#. Translators: This label appears above a field +#. meant to hold the user's mailing address. #. Translators: This label appears above a field on the registration form #. meant to hold the user's mailing address. #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: lms/templates/signup_modal.html msgid "Mailing address" @@ -10752,7 +10736,6 @@ msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html #: themes/stanford-style/lms/templates/register-form.html msgid "Register" msgstr "Sajili" @@ -10883,10 +10866,6 @@ msgstr "Alama_ya kuingia mtandaoni iliyotolewa ni batili." msgid "Full Name cannot contain the following characters: < >" msgstr "" -#: openedx/core/djangoapps/user_authn/views/registration_form.py -msgid "Enter a valid name" -msgstr "" - #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "A properly formatted e-mail is required" msgstr "Anwani ya barua pepe iliyo na mfumo sahihi inahitajika" @@ -11062,15 +11041,9 @@ msgstr "" #: openedx/core/djangoapps/util/user_messages.py #: cms/templates/course_outline.html cms/templates/index.html -#: openedx/features/course_experience/templates/course_experience/latest-update-fragment.html -#: openedx/features/course_experience/templates/course_experience/welcome-message-fragment.html msgid "Dismiss" msgstr "" -#: openedx/core/djangoapps/verified_track_content/models.py -msgid "The course key for the course we would like to be auto-cohorted." -msgstr "" - #: openedx/core/djangoapps/video_pipeline/models.py msgid "Oauth client name of VEM service." msgstr "" @@ -11334,51 +11307,6 @@ msgstr "" msgid "Updates" msgstr "Ukimilishaji" -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{sign_in_link} or {register_link} and then enroll in this course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Welcome to {course_display_name}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"You must be enrolled in the course to see course content. Please contact " -"your degree administrator or {platform_name} Support if you have questions." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"{open_enroll_link}Enroll now{close_enroll_link} to access the full course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"To start, set a course goal by selecting the option below that best " -"describes your learning plan. {goal_options_container}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {goal_text}" -msgstr "" - #: openedx/features/discounts/admin.py msgid "" "These define the context to disable lms-controlled discounts on. If no " @@ -11477,12 +11405,10 @@ msgid "Continue" msgstr "Endelea" #: openedx/features/personalized_learner_schedules/call_to_action.py -#: lms/templates/dates_banner.html msgid "Shift due dates" msgstr "" #: openedx/features/personalized_learner_schedules/call_to_action.py -#: lms/templates/dates_banner.html msgid "" "It looks like you missed some important deadlines based on our suggested " "schedule." @@ -12495,11 +12421,6 @@ msgstr "Jina la Kozi" msgid "Course Number" msgstr "Namba ya Kozi" -#: cms/templates/course_outline.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Course Outline" -msgstr "" - #: cms/templates/html_error.html lms/templates/course_modes/error.html #: lms/templates/module-error.html msgid "Error:" @@ -12587,62 +12508,10 @@ msgstr "Akaunti" #: lms/templates/header/navbar-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: lms/templates/static_templates/help.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -#: wiki/plugins/help/wiki_plugin.py +#: lms/templates/static_templates/help.html wiki/plugins/help/wiki_plugin.py msgid "Help" msgstr "Usaidizi / Msaada" -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Looking for help with {studio_name}?" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Hide {studio_name} Help" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "{studio_name} Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Access documentation on http://docs.edx.org" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101: Overview of Creating an edX Course" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX: Creating a Course with edX Studio" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Send an email to {email}" -msgstr "" - #: cms/templates/widgets/tabs-aggregator.html #: lms/templates/courseware/static_tab.html #: lms/templates/courseware/tab-view.html @@ -12814,19 +12683,18 @@ msgstr "Angalia Kozi zote" #: lms/templates/dashboard.html lms/templates/header/user_dropdown.html #: lms/templates/user_dropdown.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Dashboard" msgstr "Dashibodi" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "results successfully populated," msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Click to load all enrolled courses" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "You are not enrolled in any courses yet." msgstr "Bado haujasajiliwa katika kozi yoyote." @@ -12834,7 +12702,6 @@ msgstr "Bado haujasajiliwa katika kozi yoyote." #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore courses" msgstr "Tafuta kozi" @@ -12843,16 +12710,15 @@ msgstr "Tafuta kozi" msgid "Activate your account!" msgstr "Amsha akaunti yako!" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Course-loading errors" msgstr "Hitilafu za upakiaji kozi" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Search Your Courses" msgstr "Tafuta Kozi Zako" #: lms/templates/courseware/courseware.html lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Clear search" msgstr "Futa utautaji" @@ -12875,15 +12741,15 @@ msgstr "" msgid "Continue to {platform_name}" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Email Settings for {course_number}" msgstr "Mitegesho ya Barua pepe {course_number}" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Receive course emails" msgstr "Pokea barua pepe za kozi" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Save Settings" msgstr "Hifadhi mitegesho" @@ -12892,83 +12758,9 @@ msgstr "Hifadhi mitegesho" #: lms/templates/dashboard/_dashboard_entitlement_actions.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/instructor/instructor_dashboard_2/membership.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "Unenroll" msgstr "Tengua usajili" -#: lms/templates/dates_banner.html -msgid "" -"It looks like you missed some important deadlines based on our suggested " -"schedule. " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future by visiting " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" Don't worry—you won't lose any of the progress you've made when you shift " -"your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future. Don't worry—you won't lose any of the " -"progress you've made when you shift your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "You are auditing this course," -msgstr "" - -#: lms/templates/dates_banner.html -msgid " which means that you are unable to participate in graded assignments." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. Graded assignments and schedule adjustment are available to " -"Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. To complete graded assignments as part of this course and shift " -"the past due assignments into the future, you can upgrade today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Upgrade to shift due dates" -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Graded assignments are available to Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" To complete graded assignments as part of this course, you can upgrade " -"today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "We've built a suggested schedule to help you stay on track." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"But don't worry—it's flexible so you can learn at your own pace. If you " -"happen to fall behind on our suggested dates, you'll be able to adjust them " -"to keep yourself on track." -msgstr "" - #: lms/templates/email_change_failed.html lms/templates/email_exists.html msgid "E-mail change failed" msgstr "Ubadilishaji wa barua pepe haukufaulu" @@ -13314,10 +13106,6 @@ msgstr "Weka mtindo wa 'kutazama' ukurasa" msgid "You are now viewing the course as {i_start}{user_name}{i_end}." msgstr "Sasa Unaangalia kozi kama{i_start}{user_name}{i_end}." -#: lms/templates/preview_menu.html -msgid "View in the new experience" -msgstr "" - #: lms/templates/preview_menu.html msgid "View in Studio" msgstr "" @@ -13443,9 +13231,7 @@ msgstr "" msgid "Sequence" msgstr "Mfululizo" -#: lms/templates/courseware/dates.html lms/templates/seq_module.html -#: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html +#: lms/templates/seq_module.html lms/templates/vert_module.html msgid "Completed" msgstr "" @@ -13726,7 +13512,6 @@ msgstr "" "alama ya kuongeza, au ctrl-alama ya kuondoa kwa wakati mmoja." #: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "{subsection_format} due {{date}}" msgstr "" @@ -13738,6 +13523,10 @@ msgstr "" msgid "Past due" msgstr "" +#: lms/templates/vert_module.html +msgid "Reset Problems" +msgstr "" + #: lms/templates/video.html msgid "Loading video player" msgstr "Kupakia uchezeshaji wa video" @@ -14900,7 +14689,6 @@ msgid "Download student grades" msgstr "'Pakua mtandaoni' madaraja ya mwanafunzi" #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Print or share your certificate:" msgstr "Chapisha au tuma cheti chako:" @@ -14914,7 +14702,6 @@ msgstr "Bandika kwenye Facebook" #: lms/templates/certificates/_accomplishment-banner.html #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Twitter" msgstr "Bandika chapisho kwenye Twitter" @@ -14923,7 +14710,6 @@ msgid "Tweet this Accomplishment. Pop up window." msgstr "Toa taarifa ya Kukamilisha kazi kwenye Tweeter. Onesha dirisha jipya." #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Add to LinkedIn Profile" msgstr "Ongeza kwenye Wasifu wa Linkedln " @@ -15022,40 +14808,31 @@ msgstr "" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue the Verified Track" msgstr "" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue a Verified Certificate" msgstr "Tafuta Cheti Kilichothibitishwa" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Enroll In {course_name} | Choose Your Track" msgstr "Sajili kwenye {course_name} | Chagua Mtindo Wako" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Sorry, there was an error when trying to enroll you" msgstr "Samahani, kulikuwa na hitilafu wakati wa kukusajili" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with the Verified Track" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with a Verified Certificate" msgstr "Fuatilia Mkopo wa Kusoma na Cheti Kilicho Thibitishwa" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Become eligible for academic credit and highlight your new skills and " "knowledge with a verified certificate. Use this valuable credential to " @@ -15067,12 +14844,10 @@ msgstr "" "masomo, boresha kazi yako, au jadidisha maombi yako ya shule." #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of the Verified Track" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Eligible for credit:{b_end} Receive academic credit after " "successfully completing the course" @@ -15081,33 +14856,28 @@ msgstr "" "kukamilisha kozi" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Unlimited Course Access: {b_end}Learn at your own pace, and access " "materials anytime to brush up on what you've learned." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Graded Assignments: {b_end}Build your skills through graded " "assignments and projects." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily Sharable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of a Verified Certificate" msgstr "Faida za Cheti Kilichothibitishwa" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official:{b_end} Receive an instructor-signed certificate with the " "institution's logo" @@ -15116,14 +14886,12 @@ msgstr "" "nembo ya taasisi" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable:{b_end} Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Highlight your new knowledge and skills with a verified certificate. Use " "this valuable credential to improve your job prospects and advance your " @@ -15134,7 +14902,6 @@ msgstr "" "angazia cheti chako kwenye maombi ya shule. " #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official: {b_end}Receive an instructor-signed certificate with the " "institution's logo" @@ -15143,14 +14910,12 @@ msgstr "" "ya taasisi" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Motivating: {b_end}Give yourself an additional incentive to " "complete the course" @@ -15158,12 +14923,10 @@ msgstr "" "{b_start}Hamasisha: {b_end}Jipe nyongeza ya kichocheo kukamilisha kozi" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course" msgstr "Kagua Kozi Hii" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums." @@ -15172,12 +14935,10 @@ msgstr "" "mazoezi, majaribio na majukwaa." #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course (No Certificate)" msgstr "Kagua Kozi Hii (Hakuna Cheti)" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded assignments," @@ -15185,7 +14946,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded " @@ -15193,7 +14953,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include unlimited course " @@ -15201,7 +14960,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums. {b_start}Please note that this " @@ -15289,6 +15047,10 @@ msgstr "" msgid "Choose a path for your course in" msgstr "" +#: lms/templates/course_modes/track_selection.html +msgid "Earn a certificate" +msgstr "" + #: lms/templates/course_modes/track_selection.html msgid "" "Studies show that those who choose this option are {start_bold}more engaged" @@ -15313,7 +15075,6 @@ msgstr "{span_start}kifungu cha sasa{span_end}" #: lms/templates/courseware/accordion.html #: lms/templates/courseware/progress.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "due {date}" msgstr "Tarehe husika {date}" @@ -15322,7 +15083,6 @@ msgid "{section_format} due {{date}}" msgstr "{section_format} inatazamiwa {{date}}" #: lms/templates/courseware/accordion.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "This content is graded" msgstr "Maudhui haya yamepangwa kwenye madaraja" @@ -15334,10 +15094,6 @@ msgstr "Hitilafu imetokea. Tafadhali jaribu tena baadae." msgid "You are enrolled in this course" msgstr "Umesajiliwa katika kozi hii" -#: lms/templates/courseware/course_about.html -msgid "Course is full" -msgstr "Kozi imejaa wanafunzi" - #: lms/templates/courseware/course_about.html msgid "Enrollment in this course is by invitation only" msgstr "Usajili katika kozi hii ni kwa ukaribisho pekee" @@ -15497,30 +15253,6 @@ msgstr "" msgid "Your score is {current_score}%. You have passed the entrance exam." msgstr "Alama ulizopata ni %{current_score}. Umefaulu mtihani wa kujiunga." -#: lms/templates/courseware/dates.html lms/templates/courseware/syllabus.html -msgid "{course.display_number_with_default} Course Info" -msgstr "{course.display_number_with_default} Taarifa ya Kozi" - -#: lms/templates/courseware/dates.html -msgid "Important Dates" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Today" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Verified Only" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Due Next" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Not yet released" -msgstr "" - #: lms/templates/courseware/gradebook.html msgid "Gradebook" msgstr "Kitabu cha madaraja" @@ -15570,8 +15302,6 @@ msgstr "" #: lms/templates/courseware/info.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "Resume Course" msgstr "Anza tena Kozi" @@ -15588,7 +15318,6 @@ msgid "Handout Navigation" msgstr "Uabiri wa Vitini" #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Tools" msgstr "Mpangilio wa Kozi " @@ -15836,6 +15565,10 @@ msgstr "Matokeo ya zoezi yamefichwa." msgid "No problem scores in this section" msgstr "Hakuna matokeo ya swali katika kifungu hiki" +#: lms/templates/courseware/syllabus.html +msgid "{course.display_number_with_default} Course Info" +msgstr "{course.display_number_with_default} Taarifa ya Kozi" + #: lms/templates/courseware/welcome-back.html msgid "" "You were most recently in {section_link}. If you're done with that, choose " @@ -16091,7 +15824,6 @@ msgid "Share {course_name} on Facebook" msgstr "" #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Facebook" msgstr "Chapisha kwenye Facebook" @@ -16139,6 +15871,12 @@ msgid "" "showcase on your resumé." msgstr "" +#: lms/templates/dashboard/_dashboard_course_listing.html +msgid "" +"{start_bold}Get the most out of your course!{end_bold} Upgrade to earn a " +"{link_start}verified certificate{link_end} to showcase on your resumé." +msgstr "" + #: lms/templates/dashboard/_dashboard_course_listing.html msgid "Upgrade" msgstr "" @@ -16989,7 +16727,6 @@ msgstr "" "Tunashauri utumie {chrome_link} au {ff_link}." #: lms/templates/header/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Discover New" msgstr "" @@ -17003,7 +16740,6 @@ msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "How it Works" msgstr "Inavyo fanya Kazi" @@ -18514,7 +18250,6 @@ msgid "" msgstr "" #: lms/templates/learner_dashboard/_dashboard_navigation_courses.html -#: themes/edx.org/lms/templates/dashboard.html msgid "My Courses" msgstr "Kozi Zangu" @@ -18964,13 +18699,10 @@ msgid "Skeleton Page" msgstr "" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html msgid "Search the course" msgstr "" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Start Course" msgstr "Anza Kozi" @@ -19152,36 +18884,6 @@ msgstr "" msgid "View all course dates" msgstr "" -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Goal: " -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Edit your course goal:" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Pursue a verified certificate" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "" -"Sample verified certificate with your name, the course title, the logo of " -"the institution and the signatures of the instructors for this course." -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Upgrade ({price})" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Expand All" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Prerequisite: " -msgstr "" - #: openedx/features/course_experience/templates/course_experience/course-sock-fragment.html msgid "Learn About Verified Certificates" msgstr "" @@ -19262,18 +18964,6 @@ msgstr "" msgid "This course does not have any updates." msgstr "" -#: openedx/features/course_experience/templates/course_experience/latest-update-fragment.html -msgid "Latest Update" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/welcome-message-fragment.html -msgid "Show More" -msgstr "" - -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -msgid "Search Results" -msgstr "" - #. Translators: this section lists all the third-party authentication #. providers #. (for example, Google and LinkedIn) the user can link with or unlink from @@ -19317,10 +19007,13 @@ msgid "You haven't earned any certificates yet." msgstr "" #: openedx/features/learner_profile/templates/learner_profile/learner-achievements-fragment.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore New Courses" msgstr "Tafuta Kozi Mpya" +#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html +msgid "Learner Profile" +msgstr "Wasifu wa Mwanafunzi" + #: openedx/features/learner_profile/templates/learner_profile/learner_profile.html msgid "View My Records" msgstr "" @@ -19338,138 +19031,6 @@ msgstr "" msgid "An error occurred. Try loading the page again." msgstr "Hitlafu imetokea. Jaribu kupakia ukurasa tena." -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "" -"Access Course Staff Support on the Partner Portal to submit or review " -"support tickets" -msgstr "" - -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Partner Portal" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "" -"Browse recently launched courses and see what's new in your favorite " -"subjects." -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Take advantage of free coaching!" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Get Started" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Page Footer" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "edX Home Page" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Connect" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "© {year} edX Inc. All rights reserved." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "About edX Verified Certificates" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "" -"An edX Verified Certificate signifies that the learner has agreed to abide " -"by the edX honor code and completed all of the required tasks of this course" -" under its guidelines, as well as having their photo ID checked to verify " -"their identity." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "About edX" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "" -"{link_start}edX{link_end} offers interactive online classes and MOOCs from " -"the world's best universities, including MIT, Harvard, Berkeley, University " -"of Texas, and many others. edX is a mission driven initiative created by " -"founding partners Harvard and MIT." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Congratulations, {user_name}!" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "" -"You worked hard to earn your certificate from " -"{accomplishment_copy_course_org} {dash} share it with colleagues, friends, " -"and family to get the word out about what you mastered in " -"{accomplishment_course_title}." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Share this certificate on Facebook (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Tweet this certificate (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Add this certificate to your LinkedIn profile (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print this certificate" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "edX Inc." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "" -"All rights reserved except where noted. edX, Open edX and the edX and Open " -"edX logos are registered trademarks of edX Inc." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end}EdX relies on verified certificates to " -"help fund affordable education to everyone globally." -msgstr "" - -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end} EdX, a mission driven initiative, " -"relies on verified certificates to help fund free education for everyone " -"globally" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Find Courses" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Schools & Partners" -msgstr "" - #: themes/red-theme/lms/templates/footer.html msgid "" "{tos_link_start}Terms of Service{tos_link_end} and {honor_link_start}Honor " @@ -20160,6 +19721,10 @@ msgstr "" "ya ratiba, na majibu kwa maswali ya wanafunzi. Utaongeza au kuhariri taarifa" " katika HTML." +#: cms/templates/course_outline.html +msgid "Course Outline" +msgstr "" + #: cms/templates/course_outline.html msgid "" "This course was created as a re-run. Some manual configuration is needed." @@ -22946,6 +22511,26 @@ msgstr "" msgid "Label" msgstr "" +#: cms/templates/widgets/sock.html +msgid "Looking for help with {studio_name}?" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "Hide {studio_name} Help" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "{studio_name} Documentation" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Access documentation on http://docs.edx.org" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "edX Documentation" +msgstr "" + #: cms/templates/widgets/sock_links.html msgid "Access the Open edX Portal" msgstr "" @@ -22954,6 +22539,26 @@ msgstr "" msgid "Open edX Portal" msgstr "" +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101: Overview of Creating an edX Course" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX: Creating a Course with edX Studio" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Send an email to {email}" +msgstr "" + #: cms/templates/widgets/user_dropdown.html msgid "Currently signed in as:" msgstr "" diff --git a/conf/locale/sw_KE/LC_MESSAGES/djangojs.mo b/conf/locale/sw_KE/LC_MESSAGES/djangojs.mo index b577039df2f522011054f7e850915b33d5ccc814..72d04dcece271335aa50c500a16e1183d6d5d700 100644 GIT binary patch delta 18 acmbQ=!#2N%ZNuBA%ochEn?F3&UjP75y$IC+ delta 18 acmbQ=!#2N%ZNuBA%$9nFn?F3&UjP75%Lvy1 diff --git a/conf/locale/sw_KE/LC_MESSAGES/djangojs.po b/conf/locale/sw_KE/LC_MESSAGES/djangojs.po index 1f591e34ec..eaa676aa68 100644 --- a/conf/locale/sw_KE/LC_MESSAGES/djangojs.po +++ b/conf/locale/sw_KE/LC_MESSAGES/djangojs.po @@ -71,7 +71,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: YAHAYA MWAVURIZI , 2017\n" "Language-Team: Swahili (Kenya) (http://www.transifex.com/open-edx/edx-platform/language/sw_KE/)\n" @@ -80,7 +80,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js #: cms/static/js/views/video_transcripts.js @@ -126,7 +126,6 @@ msgstr "Futa" #: common/lib/xmodule/xmodule/js/src/html/edit.js #: common/static/common/js/components/utils/view_utils.js #: lms/static/js/Markdown.Editor.js -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx #: lms/static/js/student_account/components/StudentAccountDeletionModal.jsx #: cms/templates/js/add-xblock-component-menu-problem.underscore #: cms/templates/js/add-xblock-component-menu.underscore @@ -290,6 +289,14 @@ msgstr "Kosa" msgid "Updating with latest library content" msgstr "Sasisha kwa kutumia taarifa mpya za maktaba" +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Loading..." +msgstr "" + +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Selected blocks" +msgstr "" + #: common/lib/xmodule/xmodule/assets/library_source_block/public/js/library_source_block.js msgid "Unable to update settings" msgstr "" @@ -1930,6 +1937,10 @@ msgstr "Angalia vifungu vya mtoto" msgid "Navigate up" msgstr "" +#: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx +msgid "Browsing" +msgstr "" + #: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx msgid "Select" msgstr "" @@ -2475,10 +2486,30 @@ msgid "" "within the Discussion Forum where the Course Staff can directly respond." msgstr "" +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Details" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "the more quickly and helpfully we can respond!" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Create Support Ticket" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "What can we help you with, {username}?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx msgid "Sign in to {platform} so we can help you better." msgstr "" +#: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx +msgid "Need help logging in?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/single_support_form.jsx msgid "" "Select a course or select \"Not specific to a course\" for your support " @@ -3332,20 +3363,52 @@ msgstr "" msgid "Get started" msgstr "" -#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx -msgid "Section {currentPage} of {totalPages}" -msgstr "" - #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "Help make edX better for everyone!" msgstr "" +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Why does edX collect this information?" +msgstr "" + #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "" -"Welcome to edX! Before you get started, please take a few minutes to fill-in" -" the additional information below to help us understand a bit more about " -"your background. You can always edit this information later in Account " -"Settings." +"An error occurred while attempting to retrieve or save the information " +"below. Please try again later." +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What was the total combined income, during the last 12 months, of all " +"members of your family? " +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"Have you ever served on active duty in the U.S. Armed Forces, Reserves, or " +"National Guard?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What is the highest level of education that you have achieved so far?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What is the highest level of education that any of your parents or guardians" +" have achieved?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Select employment status" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you currently work in?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you want to work in?" msgstr "" #: lms/static/js/demographics_collection/MultiselectDropdown.jsx @@ -3360,6 +3423,22 @@ msgstr "" msgid "close questionnaire" msgstr "" +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Return to my dashboard" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "next page" +msgstr "" + #: lms/static/js/discovery/views/search_form.js #, javascript-format msgid "Viewing %s course" @@ -3650,27 +3729,6 @@ msgstr "" msgid "Cohorts Disabled" msgstr "" -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course uses automatic cohorting for verified track learners. You cannot" -" disable cohorts, and you cannot rename the manual cohort named " -"'{verifiedCohortName}'. To change the configuration for verified track " -"cohorts, contact your edX partner manager." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" the required cohort does not exist. You must create a manually-assigned " -"cohort named '{verifiedCohortName}' for the feature to work." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" cohorts are disabled. You must enable cohorts for the feature to work." -msgstr "" - #: lms/static/js/instructor_dashboard/certificates.js msgid "Allow students to generate certificates for this course?" msgstr "" @@ -4381,10 +4439,6 @@ msgid "" "sensitive nature of student information." msgstr "" -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx -msgid "You have access to the {enterpriseName} dashboard" -msgstr "" - #: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx msgid "" "To access the courses available to you through {enterpriseName}, visit the " @@ -5247,42 +5301,6 @@ msgstr "Alama za Jumla" msgid "Bookmark this page" msgstr "" -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "Thank you for setting your course goal to {goal}!" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "" -"There was an error in setting your goal, please reload the page and try " -"again." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "You have successfully updated your goal." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "There was an error updating your goal." -msgstr "" - -#: lms/templates/ccx/schedule.underscore -msgid "Expand All" -msgstr "Refusha Zote" - -#: lms/templates/ccx/schedule.underscore -msgid "Collapse All" -msgstr "\"Futa\" Zote" - -#: openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show More" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show Less" -msgstr "" - #: openedx/features/course_search/static/course_search/js/views/search_results_view.js msgid "{total_results} result found for \"{search_term}\"" msgid_plural "{total_results} results found for \"{search_term}\"" @@ -5566,6 +5584,30 @@ msgstr "" msgid "There was an error with the upload" msgstr "" +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Organization:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Number:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Run:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "(Read-only)" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Re-run Course" +msgstr "" + +#: cms/templates/js/show-textbook.underscore +msgid "View Live" +msgstr "Angalia Mubashara" + #: cms/static/js/maintenance/force_publish_course.js msgid "Internal Server Error." msgstr "Hitilafu ya Seva ya Ndani." @@ -7056,10 +7098,6 @@ msgstr "" msgid "follow this post" msgstr "" -#: common/static/common/templates/discussion/templates.underscore -msgid "post anonymously" -msgstr "" - #: common/static/common/templates/discussion/templates.underscore msgid "post anonymously to classmates" msgstr "" @@ -7506,6 +7544,14 @@ msgstr "" msgid "This catalog's courses:" msgstr "Kozi za kwenye Katalogi hii:" +#: lms/templates/ccx/schedule.underscore +msgid "Expand All" +msgstr "Refusha Zote" + +#: lms/templates/ccx/schedule.underscore +msgid "Collapse All" +msgstr "\"Futa\" Zote" + #: lms/templates/ccx/schedule.underscore msgid "Start Date" msgstr "Tarehe ya Kuanza" @@ -7589,6 +7635,14 @@ msgid "" "before you select \"End My Exam\"." msgstr "" +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show More" +msgstr "" + +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show Less" +msgstr "" + #: lms/templates/discovery/course_card.underscore msgid "LEARN MORE" msgstr "JIFUNZE ZAIDI" @@ -10343,10 +10397,6 @@ msgstr "" msgid "PDF Chapters" msgstr "" -#: cms/templates/js/show-textbook.underscore -msgid "View Live" -msgstr "Angalia Mubashara" - #: cms/templates/js/signatory-details.underscore #: cms/templates/js/signatory-editor.underscore msgid "Signatory" diff --git a/conf/locale/th/LC_MESSAGES/django.mo b/conf/locale/th/LC_MESSAGES/django.mo index 71efc39f6cef72d884763d20093e930c2646b342..dd71ce0bd89f97182873ee371e373a926c65fbb9 100644 GIT binary patch delta 29 jcmbO}O, 2019\n" "Language-Team: Thai (https://www.transifex.com/open-edx/teams/6205/th/)\n" @@ -124,7 +124,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# #. Translators: 'Discussion' refers to the tab in the courseware that leads to @@ -678,6 +678,10 @@ msgstr "" msgid "Could not enroll" msgstr "" +#: common/djangoapps/student/views/management.py +msgid "Unenrollment is currently disabled" +msgstr "" + #: common/djangoapps/student/views/management.py msgid "You are not enrolled in this course" msgstr "" @@ -1715,7 +1719,6 @@ msgstr "" #. in #. to the site. #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html #: themes/stanford-style/lms/templates/register-form.html msgid "or" msgstr "หรือ" @@ -1937,7 +1940,6 @@ msgid "Never" msgstr "" #: common/lib/xmodule/xmodule/capa_module.py -#: lms/templates/courseware/dates.html msgid "Past Due" msgstr "" @@ -2003,6 +2005,7 @@ msgid "Whether to force the save button to appear on the page" msgstr "" #: common/lib/xmodule/xmodule/capa_module.py +#: common/lib/xmodule/xmodule/library_content_module.py msgid "Show Reset Button" msgstr "" @@ -2699,7 +2702,6 @@ msgid "" msgstr "" #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Handouts" msgstr "เอกสารหลักสูตร" @@ -3336,6 +3338,12 @@ msgid "" " no filtering is applied." msgstr "" +#: common/lib/xmodule/xmodule/library_content_module.py +msgid "" +"Determines whether a 'Reset Problems' button is shown, so users may reset " +"their answers and reshuffle selected items." +msgstr "" + #: common/lib/xmodule/xmodule/library_content_module.py msgid "This component is out of date. The library has new content." msgstr "" @@ -4430,8 +4438,7 @@ msgstr "" #: lms/templates/instructor/instructor_dashboard_2/invalidate_registration_code_modal.html #: lms/templates/instructor/instructor_dashboard_2/set_course_mode_price_modal.html #: lms/templates/modal/_modal-settings-language.html -#: lms/templates/signup_modal.html themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html +#: lms/templates/signup_modal.html msgid "Close" msgstr "ปิด" @@ -4836,7 +4843,6 @@ msgstr "" #. Translators: 'Open edX' is a brand, please keep this untranslated. See #. http://openedx.org for more information. #: cms/templates/widgets/footer.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html #: themes/red-theme/lms/templates/footer.html msgid "Powered by Open edX" msgstr "โดย Open edX" @@ -4846,7 +4852,6 @@ msgid "Blog" msgstr "บล็อก " #: lms/djangoapps/branding/api.py cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html #: themes/stanford-style/lms/templates/static_templates/about.html msgid "Contact Us" msgstr "" @@ -4893,13 +4898,11 @@ msgid "News" msgstr "ข่าวสาร" #: lms/djangoapps/branding/api.py lms/djangoapps/certificates/views/webview.py -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html msgid "Terms of Service & Honor Code" msgstr "" #: cms/templates/widgets/footer.html #: lms/templates/static_templates/privacy.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html #: themes/red-theme/lms/templates/footer.html #: themes/stanford-style/lms/templates/footer.html #: themes/stanford-style/lms/templates/static_templates/tos.html @@ -5414,23 +5417,6 @@ msgid "" "this request, please visit the link(s) below." msgstr "" -#: lms/djangoapps/course_goals/models.py -#: lms/templates/course_modes/track_selection.html -msgid "Earn a certificate" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Complete the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Explore the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Not sure yet" -msgstr "" - #: lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/body.html msgid "" "\n" @@ -5530,7 +5516,6 @@ msgid "Disabled" msgstr "" #: lms/djangoapps/course_home_api/outline/serializers.py -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html #, python-brace-format msgid "({number} Question)" msgid_plural "({number} Questions)" @@ -5543,6 +5528,10 @@ msgid "" "have questions." msgstr "" +#: lms/templates/courseware/course_about.html +msgid "Course is full" +msgstr "หลักสูตรนี้เต็มแล้ว" + #: lms/djangoapps/course_home_api/outline/views.py msgid "'course_id' is required." msgstr "" @@ -5684,20 +5673,6 @@ msgstr "" msgid "Course starts" msgstr "" -#: lms/djangoapps/courseware/date_summary.py -msgid "Don't forget to add a calendar reminder!" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} on {course_start_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} at {course_start_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Course ends" msgstr "" @@ -5721,16 +5696,6 @@ msgid "" " no longer active." msgstr "" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} on {course_end_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} at {course_end_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "You lose all access to this course, including your progress." msgstr "" @@ -5747,23 +5712,6 @@ msgstr "" msgid "Day certificates will become available for passing verified learners." msgstr "" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"If you have earned a certificate, you will be able to access it " -"{time_remaining_string} from now. You will also be able to view your " -"certificates on your {learner_profile_link}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html -msgid "Learner Profile" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -msgid "We are working on generating course certificates." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Upgrade to Verified Certificate" msgstr "" @@ -5793,36 +5741,9 @@ msgstr "" msgid "by {date}" msgstr "" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"Don't forget, you have {time_remaining_string} left to upgrade to a Verified" -" Certificate." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Don't forget to upgrade to a verified certificate by {localized_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"In order to qualify for a certificate, you must meet all course grading " -"requirements, upgrade before the course deadline, and successfully verify " -"your identity on {platform_name} if you have not done so " -"already.{button_panel}" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Upgrade ({upgrade_price})" -msgstr "" - #: lms/djangoapps/courseware/date_summary.py #: cms/templates/group_configurations.html #: lms/templates/courseware/program_marketing.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Learn More" msgstr "" @@ -5882,6 +5803,24 @@ msgstr "" msgid "Disable the dynamic upgrade deadline for this organization." msgstr "" +#: lms/djangoapps/courseware/models.py +msgid "Internal API Base URL" +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Financial Assistance Backend API Base URL." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "" +"Username created for Financial Assistance Backend, e.g. " +"financial_assistance_service_user." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Percentage of courses allowed to use edx-financial-assistance" +msgstr "" + #: lms/templates/peer_grading/peer_grading.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html msgid "Progress" @@ -5952,7 +5891,6 @@ msgstr "" #: lms/djangoapps/courseware/views/index.py #: lms/djangoapps/courseware/views/views.py #: openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "register" msgstr "" @@ -6002,17 +5940,6 @@ msgstr "" msgid "You've earned a certificate for this course." msgstr "" -#: lms/djangoapps/courseware/views/views.py -msgid "Certificate unavailable" -msgstr "" - -#: lms/djangoapps/courseware/views/views.py -#, python-brace-format -msgid "" -"You have not received a certificate because you do not have a current " -"{platform_name} verified identity." -msgstr "" - #: lms/djangoapps/courseware/views/views.py msgid "Your certificate will be available soon!" msgstr "" @@ -6027,20 +5954,29 @@ msgstr "" msgid "Your certificate is available" msgstr "" +#: lms/djangoapps/courseware/views/views.py +msgid "Certificate unavailable" +msgstr "" + +#: lms/djangoapps/courseware/views/views.py +#, python-brace-format +msgid "" +"You have not received a certificate because you do not have a current " +"{platform_name} verified identity." +msgstr "" + #: lms/djangoapps/courseware/views/views.py #, python-brace-format msgid "To see course content, {sign_in_link} or {register_link}." msgstr "" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py #, python-brace-format msgid "{sign_in_link} or {register_link}." msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html msgid "Sign in" msgstr "เข้าสู่ระบบ" @@ -6052,7 +5988,6 @@ msgid "" msgstr "" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "You must be enrolled in the course to see course content." msgstr "" @@ -6167,6 +6102,29 @@ msgstr "" msgid "Good" msgstr "" +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#, python-format +msgid "" +"\n" +" %(course_name)s: Reported content awaits review\n" +" " +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +msgid "Go to Discussion" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +#, python-format +msgid "%(course_name)s: Reported content awaits review" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/subject.txt +#, python-format +msgid " %(course_name)s %(course_id)s moderator content for review " +msgstr "" + #: lms/djangoapps/discussion/templates/discussion/edx_ace/responsenotification/email/body.html #, python-format, python-brace-format msgid "%(comment_username)s replied to {start_tag}%(thread_title)s{end_tag}:" @@ -7246,7 +7204,6 @@ msgstr "" #: lms/templates/learner_dashboard/programs.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Programs" msgstr "" @@ -8101,7 +8058,6 @@ msgstr "" #: lms/templates/courseware/course_about.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "View Course" msgstr "ดูหลักสูตร" @@ -8354,8 +8310,6 @@ msgstr "ตัวอย่างวิกิ" #: lms/templates/wiki/includes/cheatsheet.html lms/templates/dashboard.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/modal/_modal-settings-language.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "window open" msgstr "เปิดหน้าต่าง" @@ -8600,9 +8554,6 @@ msgstr "" #: lms/templates/courseware/courseware.html lms/templates/dashboard.html #: lms/templates/edxnotes/edxnotes.html lms/templates/index.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -#: themes/edx.org/lms/templates/dashboard.html #: themes/stanford-style/lms/templates/index.html msgid "Search" msgstr "ค้นหา" @@ -8694,7 +8645,6 @@ msgstr "" #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Courses" msgstr "หลักสูตร" @@ -9542,7 +9492,6 @@ msgid "Student" msgstr "" #: openedx/core/djangoapps/embargo/forms.py -#: openedx/core/djangoapps/verified_track_content/forms.py msgid "COURSE NOT FOUND. Please check that the course ID is valid." msgstr "" @@ -9594,6 +9543,10 @@ msgstr "" msgid "Blacklist {country} for {course}" msgstr "" +#: openedx/core/djangoapps/learner_pathway/apps.py +msgid "Learner Pathways" +msgstr "" + #: openedx/core/djangoapps/oauth_dispatch/models.py msgid "" "Comma-separated list of scopes that this application will be allowed to " @@ -9922,7 +9875,6 @@ msgid "" msgstr "" #: openedx/core/djangoapps/schedules/templates/schedules/edx_ace/upgradereminder/email/body.html -#: lms/templates/dates_banner.html msgid "Upgrade now" msgstr "" @@ -10071,6 +10023,14 @@ msgstr "" msgid "Enter your full name." msgstr "" +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your first name." +msgstr "" + +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your last name." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "The email addresses do not match." msgstr "" @@ -10095,6 +10055,10 @@ msgstr "" msgid "Enter your specialty." msgstr "" +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your state." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "Enter your city." msgstr "" @@ -10136,24 +10100,39 @@ msgstr "" msgid "The '{field_name}' field cannot be edited." msgstr "" +#: openedx/core/djangoapps/user_api/accounts/api.py +#: openedx/core/djangoapps/user_authn/views/registration_form.py +msgid "Enter a valid name" +msgstr "" + +#. Translators: This label appears above a field which allows the +#. user to input the First Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "First Name" msgstr "" +#. Translators: This label appears above a field which allows the +#. user to input the Last Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "Last Name" msgstr "" +#. Translators: This label appears above a field +#. which allows the user to input the State/Province/Region in which they +#. live. #. Translators: This label appears above a field on the registration form #. which allows the user to input the State/Province/Region in which they #. live. #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "State/Province/Region" msgstr "" @@ -10434,7 +10413,6 @@ msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html #: themes/stanford-style/lms/templates/register-form.html msgid "Register" msgstr "ลงทะเบียน" @@ -10553,10 +10531,6 @@ msgstr "" msgid "Full Name cannot contain the following characters: < >" msgstr "" -#: openedx/core/djangoapps/user_authn/views/registration_form.py -msgid "Enter a valid name" -msgstr "" - #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "A properly formatted e-mail is required" msgstr "" @@ -10724,15 +10698,9 @@ msgstr "" #: openedx/core/djangoapps/util/user_messages.py #: cms/templates/course_outline.html cms/templates/index.html -#: openedx/features/course_experience/templates/course_experience/latest-update-fragment.html -#: openedx/features/course_experience/templates/course_experience/welcome-message-fragment.html msgid "Dismiss" msgstr "" -#: openedx/core/djangoapps/verified_track_content/models.py -msgid "The course key for the course we would like to be auto-cohorted." -msgstr "" - #: openedx/core/djangoapps/video_pipeline/models.py msgid "Oauth client name of VEM service." msgstr "" @@ -10992,51 +10960,6 @@ msgstr "" msgid "Updates" msgstr "" -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{sign_in_link} or {register_link} and then enroll in this course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Welcome to {course_display_name}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"You must be enrolled in the course to see course content. Please contact " -"your degree administrator or {platform_name} Support if you have questions." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"{open_enroll_link}Enroll now{close_enroll_link} to access the full course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"To start, set a course goal by selecting the option below that best " -"describes your learning plan. {goal_options_container}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {goal_text}" -msgstr "" - #: openedx/features/discounts/admin.py msgid "" "These define the context to disable lms-controlled discounts on. If no " @@ -11135,12 +11058,10 @@ msgid "Continue" msgstr "ต่อเนื่อง" #: openedx/features/personalized_learner_schedules/call_to_action.py -#: lms/templates/dates_banner.html msgid "Shift due dates" msgstr "" #: openedx/features/personalized_learner_schedules/call_to_action.py -#: lms/templates/dates_banner.html msgid "" "It looks like you missed some important deadlines based on our suggested " "schedule." @@ -12144,11 +12065,6 @@ msgstr "ชื่อหลักสูตร" msgid "Course Number" msgstr "หมายเลขหลักสูตร" -#: cms/templates/course_outline.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Course Outline" -msgstr "" - #: cms/templates/html_error.html lms/templates/course_modes/error.html #: lms/templates/module-error.html msgid "Error:" @@ -12236,62 +12152,10 @@ msgstr "บัญชี" #: lms/templates/header/navbar-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: lms/templates/static_templates/help.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -#: wiki/plugins/help/wiki_plugin.py +#: lms/templates/static_templates/help.html wiki/plugins/help/wiki_plugin.py msgid "Help" msgstr "ช่วยเหลือ" -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Looking for help with {studio_name}?" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Hide {studio_name} Help" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "{studio_name} Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Access documentation on http://docs.edx.org" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101: Overview of Creating an edX Course" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX: Creating a Course with edX Studio" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Send an email to {email}" -msgstr "" - #: cms/templates/widgets/tabs-aggregator.html #: lms/templates/courseware/static_tab.html #: lms/templates/courseware/tab-view.html @@ -12461,19 +12325,18 @@ msgstr "ดูหลักสูตรทั้งหมด" #: lms/templates/dashboard.html lms/templates/header/user_dropdown.html #: lms/templates/user_dropdown.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Dashboard" msgstr "แดชบอร์ด" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "results successfully populated," msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Click to load all enrolled courses" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "You are not enrolled in any courses yet." msgstr "" @@ -12481,7 +12344,6 @@ msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore courses" msgstr "" @@ -12490,16 +12352,15 @@ msgstr "" msgid "Activate your account!" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Course-loading errors" msgstr "หลักสูตรทำการโหลดผิดพลาด" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Search Your Courses" msgstr "ค้นหาหลักสูตรของคุณ" #: lms/templates/courseware/courseware.html lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Clear search" msgstr "ล้างการค้นหา" @@ -12522,15 +12383,15 @@ msgstr "" msgid "Continue to {platform_name}" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Email Settings for {course_number}" msgstr "ตั้งค่าอีเมลสำหรับ {course_number}" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Receive course emails" msgstr "รับอีเมลหลักสูตร" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Save Settings" msgstr "บันทึกการตั้งค่า" @@ -12539,83 +12400,9 @@ msgstr "บันทึกการตั้งค่า" #: lms/templates/dashboard/_dashboard_entitlement_actions.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/instructor/instructor_dashboard_2/membership.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "Unenroll" msgstr "ยกเลิกการลงทะเบียน" -#: lms/templates/dates_banner.html -msgid "" -"It looks like you missed some important deadlines based on our suggested " -"schedule. " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future by visiting " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" Don't worry—you won't lose any of the progress you've made when you shift " -"your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future. Don't worry—you won't lose any of the " -"progress you've made when you shift your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "You are auditing this course," -msgstr "" - -#: lms/templates/dates_banner.html -msgid " which means that you are unable to participate in graded assignments." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. Graded assignments and schedule adjustment are available to " -"Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. To complete graded assignments as part of this course and shift " -"the past due assignments into the future, you can upgrade today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Upgrade to shift due dates" -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Graded assignments are available to Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" To complete graded assignments as part of this course, you can upgrade " -"today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "We've built a suggested schedule to help you stay on track." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"But don't worry—it's flexible so you can learn at your own pace. If you " -"happen to fall behind on our suggested dates, you'll be able to adjust them " -"to keep yourself on track." -msgstr "" - #: lms/templates/email_change_failed.html lms/templates/email_exists.html msgid "E-mail change failed" msgstr "การเปลี่ยนอีเมล์ล้มเหลว" @@ -12942,10 +12729,6 @@ msgstr "ตั้งโหมดแสดงตัวอย่าง" msgid "You are now viewing the course as {i_start}{user_name}{i_end}." msgstr "" -#: lms/templates/preview_menu.html -msgid "View in the new experience" -msgstr "" - #: lms/templates/preview_menu.html msgid "View in Studio" msgstr "" @@ -13067,9 +12850,7 @@ msgstr "" msgid "Sequence" msgstr "" -#: lms/templates/courseware/dates.html lms/templates/seq_module.html -#: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html +#: lms/templates/seq_module.html lms/templates/vert_module.html msgid "Completed" msgstr "" @@ -13346,7 +13127,6 @@ msgstr "" " ctrl-plus, หรือ ctrl-minus ได้เลย" #: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "{subsection_format} due {{date}}" msgstr "" @@ -13358,6 +13138,10 @@ msgstr "" msgid "Past due" msgstr "" +#: lms/templates/vert_module.html +msgid "Reset Problems" +msgstr "" + #: lms/templates/video.html msgid "Loading video player" msgstr "กำลังโหลดเครื่องเล่นวิดิโอ" @@ -14416,7 +14200,6 @@ msgid "Download student grades" msgstr "ดาวน์โหลดเกรดของผู้เรียน" #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Print or share your certificate:" msgstr "ปริ้นท์หรือแบ่งปันประกาศนียบัตร" @@ -14430,7 +14213,6 @@ msgstr "โพสต์บน Facebook" #: lms/templates/certificates/_accomplishment-banner.html #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Twitter" msgstr "แชร์บน Twitter" @@ -14439,7 +14221,6 @@ msgid "Tweet this Accomplishment. Pop up window." msgstr "ทวีตความสำเร็จนี้ เปิดหน้าต่างใหม่" #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Add to LinkedIn Profile" msgstr "เพิ่มไปยังประวัติของ LinkedIn" @@ -14536,40 +14317,31 @@ msgstr "" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue the Verified Track" msgstr "" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue a Verified Certificate" msgstr "ติดตามตรวจสอบใบรับรองแล้ว" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Enroll In {course_name} | Choose Your Track" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Sorry, there was an error when trying to enroll you" msgstr "ขออภัย เกิดข้อผิดพลาดขึ้นขณะกำลังลงทะเบียน" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with the Verified Track" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with a Verified Certificate" msgstr "ติดตามหน่วยกิตที่ได้รับการรับรอง" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Become eligible for academic credit and highlight your new skills and " "knowledge with a verified certificate. Use this valuable credential to " @@ -14578,12 +14350,10 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of the Verified Track" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Eligible for credit:{b_end} Receive academic credit after " "successfully completing the course" @@ -14592,33 +14362,28 @@ msgstr "" "ได้รับหน่วยกิตทางวิชาการหลังจากจบหลักสูตรนี้สำเร็จ" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Unlimited Course Access: {b_end}Learn at your own pace, and access " "materials anytime to brush up on what you've learned." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Graded Assignments: {b_end}Build your skills through graded " "assignments and projects." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily Sharable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of a Verified Certificate" msgstr "ประโยชน์ของใบรับรอง" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official:{b_end} Receive an instructor-signed certificate with the " "institution's logo" @@ -14627,14 +14392,12 @@ msgstr "" "ได้รับการรับรองจากอาจารย์ผู้สอนที่เซ็นสัญญากับสัญลักษณ์ของสถาบัน" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable:{b_end} Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Highlight your new knowledge and skills with a verified certificate. Use " "this valuable credential to improve your job prospects and advance your " @@ -14644,7 +14407,6 @@ msgstr "" "ใช้ข้อมูลประจำตัวที่มีคุณค่าเพื่อความก้าวหน้าในงานของคุณและก้าวหน้าในอาชีพของคุณหรือเน้นใบรับรองของคุณในการสมัครโรงเรียน" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official: {b_end}Receive an instructor-signed certificate with the " "institution's logo" @@ -14653,14 +14415,12 @@ msgstr "" "ได้รับการรับรองจากอาจารย์ผู้สอนที่เซ็นสัญญากับโลโก้ของสถาบัน" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Motivating: {b_end}Give yourself an additional incentive to " "complete the course" @@ -14669,24 +14429,20 @@ msgstr "" "{b_end}ให้ตัวเองเป็นแรงจูงใจเพิ่มเติมในการสำเร็จหลักสูตร" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course" msgstr "ตรวจสอบหลักสูตรนี้" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course (No Certificate)" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded assignments," @@ -14694,7 +14450,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded " @@ -14702,7 +14457,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include unlimited course " @@ -14710,7 +14464,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums. {b_start}Please note that this " @@ -14794,6 +14547,10 @@ msgstr "" msgid "Choose a path for your course in" msgstr "" +#: lms/templates/course_modes/track_selection.html +msgid "Earn a certificate" +msgstr "" + #: lms/templates/course_modes/track_selection.html msgid "" "Studies show that those who choose this option are {start_bold}more engaged" @@ -14818,7 +14575,6 @@ msgstr "" #: lms/templates/courseware/accordion.html #: lms/templates/courseware/progress.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "due {date}" msgstr "กำหนดส่ง {date}" @@ -14827,7 +14583,6 @@ msgid "{section_format} due {{date}}" msgstr "" #: lms/templates/courseware/accordion.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "This content is graded" msgstr "เนื้อหาส่วนนี้ได้รับการให้คะแนนแล้ว" @@ -14839,10 +14594,6 @@ msgstr "เกิดข้อผิดพลาด กรุณาลองใ msgid "You are enrolled in this course" msgstr "คุณได้ลงทะเบียนเข้าเรียนในวิชานี้" -#: lms/templates/courseware/course_about.html -msgid "Course is full" -msgstr "หลักสูตรนี้เต็มแล้ว" - #: lms/templates/courseware/course_about.html msgid "Enrollment in this course is by invitation only" msgstr "การลงทะเบียนในหลักสูตรนี้ต้องได้รับการเชื้อเชิญเท่านั้น" @@ -15000,30 +14751,6 @@ msgstr "" msgid "Your score is {current_score}%. You have passed the entrance exam." msgstr "คะแนนของคุณคือ {current_score}% คุณสอบผ่านการสอบเข้า" -#: lms/templates/courseware/dates.html lms/templates/courseware/syllabus.html -msgid "{course.display_number_with_default} Course Info" -msgstr "{course.display_number_with_default} รายละเอียดหลักสูตร" - -#: lms/templates/courseware/dates.html -msgid "Important Dates" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Today" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Verified Only" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Due Next" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Not yet released" -msgstr "" - #: lms/templates/courseware/gradebook.html msgid "Gradebook" msgstr "สมุดคะแนน" @@ -15073,8 +14800,6 @@ msgstr "" #: lms/templates/courseware/info.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "Resume Course" msgstr "" @@ -15091,7 +14816,6 @@ msgid "Handout Navigation" msgstr "การนำทางเอกสาร" #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Tools" msgstr "" @@ -15337,6 +15061,10 @@ msgstr "" msgid "No problem scores in this section" msgstr "ไม่มีคะแนนปัญหาในส่วนนี้" +#: lms/templates/courseware/syllabus.html +msgid "{course.display_number_with_default} Course Info" +msgstr "{course.display_number_with_default} รายละเอียดหลักสูตร" + #: lms/templates/courseware/welcome-back.html msgid "" "You were most recently in {section_link}. If you're done with that, choose " @@ -15586,7 +15314,6 @@ msgid "Share {course_name} on Facebook" msgstr "" #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Facebook" msgstr "แบ่งปันบน Facebook" @@ -15634,6 +15361,12 @@ msgid "" "showcase on your resumé." msgstr "" +#: lms/templates/dashboard/_dashboard_course_listing.html +msgid "" +"{start_bold}Get the most out of your course!{end_bold} Upgrade to earn a " +"{link_start}verified certificate{link_end} to showcase on your resumé." +msgstr "" + #: lms/templates/dashboard/_dashboard_course_listing.html msgid "Upgrade" msgstr "" @@ -16449,7 +16182,6 @@ msgid "" msgstr "" #: lms/templates/header/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Discover New" msgstr "" @@ -16463,7 +16195,6 @@ msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "How it Works" msgstr "วิธีการทำงาน" @@ -17915,7 +17646,6 @@ msgid "" msgstr "" #: lms/templates/learner_dashboard/_dashboard_navigation_courses.html -#: themes/edx.org/lms/templates/dashboard.html msgid "My Courses" msgstr "หลักสูตรของฉัน" @@ -18354,13 +18084,10 @@ msgid "Skeleton Page" msgstr "" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html msgid "Search the course" msgstr "" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Start Course" msgstr "" @@ -18534,36 +18261,6 @@ msgstr "" msgid "View all course dates" msgstr "" -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Goal: " -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Edit your course goal:" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Pursue a verified certificate" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "" -"Sample verified certificate with your name, the course title, the logo of " -"the institution and the signatures of the instructors for this course." -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Upgrade ({price})" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Expand All" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Prerequisite: " -msgstr "" - #: openedx/features/course_experience/templates/course_experience/course-sock-fragment.html msgid "Learn About Verified Certificates" msgstr "" @@ -18644,18 +18341,6 @@ msgstr "" msgid "This course does not have any updates." msgstr "" -#: openedx/features/course_experience/templates/course_experience/latest-update-fragment.html -msgid "Latest Update" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/welcome-message-fragment.html -msgid "Show More" -msgstr "" - -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -msgid "Search Results" -msgstr "" - #. Translators: this section lists all the third-party authentication #. providers #. (for example, Google and LinkedIn) the user can link with or unlink from @@ -18699,10 +18384,13 @@ msgid "You haven't earned any certificates yet." msgstr "" #: openedx/features/learner_profile/templates/learner_profile/learner-achievements-fragment.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore New Courses" msgstr "" +#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html +msgid "Learner Profile" +msgstr "" + #: openedx/features/learner_profile/templates/learner_profile/learner_profile.html msgid "View My Records" msgstr "" @@ -18720,138 +18408,6 @@ msgstr "" msgid "An error occurred. Try loading the page again." msgstr "" -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "" -"Access Course Staff Support on the Partner Portal to submit or review " -"support tickets" -msgstr "" - -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Partner Portal" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "" -"Browse recently launched courses and see what's new in your favorite " -"subjects." -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Take advantage of free coaching!" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Get Started" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Page Footer" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "edX Home Page" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Connect" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "© {year} edX Inc. All rights reserved." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "About edX Verified Certificates" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "" -"An edX Verified Certificate signifies that the learner has agreed to abide " -"by the edX honor code and completed all of the required tasks of this course" -" under its guidelines, as well as having their photo ID checked to verify " -"their identity." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "About edX" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "" -"{link_start}edX{link_end} offers interactive online classes and MOOCs from " -"the world's best universities, including MIT, Harvard, Berkeley, University " -"of Texas, and many others. edX is a mission driven initiative created by " -"founding partners Harvard and MIT." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Congratulations, {user_name}!" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "" -"You worked hard to earn your certificate from " -"{accomplishment_copy_course_org} {dash} share it with colleagues, friends, " -"and family to get the word out about what you mastered in " -"{accomplishment_course_title}." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Share this certificate on Facebook (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Tweet this certificate (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Add this certificate to your LinkedIn profile (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print this certificate" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "edX Inc." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "" -"All rights reserved except where noted. edX, Open edX and the edX and Open " -"edX logos are registered trademarks of edX Inc." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end}EdX relies on verified certificates to " -"help fund affordable education to everyone globally." -msgstr "" - -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end} EdX, a mission driven initiative, " -"relies on verified certificates to help fund free education for everyone " -"globally" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Find Courses" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Schools & Partners" -msgstr "" - #: themes/red-theme/lms/templates/footer.html msgid "" "{tos_link_start}Terms of Service{tos_link_end} and {honor_link_start}Honor " @@ -19535,6 +19091,10 @@ msgstr "" "เน้นกระทู้ที่น่าสนใจในกระดานถาม-ตอบ ประกาศการปรับเปลี่ยนตารางเรียน " "และตอบคำถามนักเรียน คุณสามารถเพิ่มหรือแก้ไขการอัพเดตนี้ในรูปแบบ HTML ได้" +#: cms/templates/course_outline.html +msgid "Course Outline" +msgstr "" + #: cms/templates/course_outline.html msgid "" "This course was created as a re-run. Some manual configuration is needed." @@ -22423,6 +21983,26 @@ msgstr "" msgid "Label" msgstr "ป้าย" +#: cms/templates/widgets/sock.html +msgid "Looking for help with {studio_name}?" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "Hide {studio_name} Help" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "{studio_name} Documentation" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Access documentation on http://docs.edx.org" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "edX Documentation" +msgstr "" + #: cms/templates/widgets/sock_links.html msgid "Access the Open edX Portal" msgstr "เข้าถึงOpen edX Portal" @@ -22431,6 +22011,26 @@ msgstr "เข้าถึงOpen edX Portal" msgid "Open edX Portal" msgstr "Open edX Portal" +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101: Overview of Creating an edX Course" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX: Creating a Course with edX Studio" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Send an email to {email}" +msgstr "" + #: cms/templates/widgets/user_dropdown.html msgid "Currently signed in as:" msgstr "เข้าระบบในปัจจุบันเป็น:" diff --git a/conf/locale/th/LC_MESSAGES/djangojs.mo b/conf/locale/th/LC_MESSAGES/djangojs.mo index bf028aed831fd7c6d3568f6d6a10df088c015122..a59ecf5c67b015ee69144982febb1a8252f2282d 100644 GIT binary patch delta 18 acmcbyk@dz#)(tB=m@V`SHm~W>xc~rD=?HoN delta 18 acmcbyk@dz#)(tB=m@V}TH?Qf?xc~rD_XvCd diff --git a/conf/locale/th/LC_MESSAGES/djangojs.po b/conf/locale/th/LC_MESSAGES/djangojs.po index 45127a03e4..4a03811bac 100644 --- a/conf/locale/th/LC_MESSAGES/djangojs.po +++ b/conf/locale/th/LC_MESSAGES/djangojs.po @@ -73,7 +73,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: edx demo , 2019\n" "Language-Team: Thai (http://www.transifex.com/open-edx/edx-platform/language/th/)\n" @@ -82,7 +82,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js #: cms/static/js/views/video_transcripts.js @@ -128,7 +128,6 @@ msgstr "ลบ" #: common/lib/xmodule/xmodule/js/src/html/edit.js #: common/static/common/js/components/utils/view_utils.js #: lms/static/js/Markdown.Editor.js -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx #: lms/static/js/student_account/components/StudentAccountDeletionModal.jsx #: cms/templates/js/add-xblock-component-menu-problem.underscore #: cms/templates/js/add-xblock-component-menu.underscore @@ -304,6 +303,14 @@ msgstr "ผิดพลาด" msgid "Updating with latest library content" msgstr "อัพเดทส่วนเนื้อหาจากห้องสมุดล่าสุด" +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Loading..." +msgstr "" + +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Selected blocks" +msgstr "" + #: common/lib/xmodule/xmodule/assets/library_source_block/public/js/library_source_block.js msgid "Unable to update settings" msgstr "" @@ -1944,6 +1951,10 @@ msgstr "" msgid "Navigate up" msgstr "" +#: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx +msgid "Browsing" +msgstr "" + #: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx msgid "Select" msgstr "" @@ -2451,10 +2462,30 @@ msgid "" "within the Discussion Forum where the Course Staff can directly respond." msgstr "" +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Details" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "the more quickly and helpfully we can respond!" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Create Support Ticket" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "What can we help you with, {username}?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx msgid "Sign in to {platform} so we can help you better." msgstr "" +#: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx +msgid "Need help logging in?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/single_support_form.jsx msgid "" "Select a course or select \"Not specific to a course\" for your support " @@ -3278,20 +3309,52 @@ msgstr "" msgid "Get started" msgstr "" -#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx -msgid "Section {currentPage} of {totalPages}" -msgstr "" - #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "Help make edX better for everyone!" msgstr "" +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Why does edX collect this information?" +msgstr "" + #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "" -"Welcome to edX! Before you get started, please take a few minutes to fill-in" -" the additional information below to help us understand a bit more about " -"your background. You can always edit this information later in Account " -"Settings." +"An error occurred while attempting to retrieve or save the information " +"below. Please try again later." +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What was the total combined income, during the last 12 months, of all " +"members of your family? " +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"Have you ever served on active duty in the U.S. Armed Forces, Reserves, or " +"National Guard?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What is the highest level of education that you have achieved so far?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What is the highest level of education that any of your parents or guardians" +" have achieved?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Select employment status" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you currently work in?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you want to work in?" msgstr "" #: lms/static/js/demographics_collection/MultiselectDropdown.jsx @@ -3306,6 +3369,22 @@ msgstr "" msgid "close questionnaire" msgstr "" +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Return to my dashboard" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "next page" +msgstr "" + #: lms/static/js/discovery/views/search_form.js #, javascript-format msgid "Viewing %s course" @@ -3593,27 +3672,6 @@ msgstr "เปิดการทำงานกลุ่ม" msgid "Cohorts Disabled" msgstr "ยกเลิกการทำงานกลุ่ม" -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course uses automatic cohorting for verified track learners. You cannot" -" disable cohorts, and you cannot rename the manual cohort named " -"'{verifiedCohortName}'. To change the configuration for verified track " -"cohorts, contact your edX partner manager." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" the required cohort does not exist. You must create a manually-assigned " -"cohort named '{verifiedCohortName}' for the feature to work." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" cohorts are disabled. You must enable cohorts for the feature to work." -msgstr "" - #: lms/static/js/instructor_dashboard/certificates.js msgid "Allow students to generate certificates for this course?" msgstr "อนุญาตให้นักเรียนสามารถสร้างใบรับรองสำหรับหลักสูตรนี้ ?" @@ -4296,10 +4354,6 @@ msgstr "" "ลิ้งค์นี้ถูกสร้างขึ้นเพื่อสนองความต้องการและจะหมดอายุภายใน 5 นาที " "เนื่องจากความสำคัญของข้อมูลนักเรียน" -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx -msgid "You have access to the {enterpriseName} dashboard" -msgstr "" - #: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx msgid "" "To access the courses available to you through {enterpriseName}, visit the " @@ -5137,42 +5191,6 @@ msgstr "" msgid "Bookmark this page" msgstr "" -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "Thank you for setting your course goal to {goal}!" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "" -"There was an error in setting your goal, please reload the page and try " -"again." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "You have successfully updated your goal." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "There was an error updating your goal." -msgstr "" - -#: lms/templates/ccx/schedule.underscore -msgid "Expand All" -msgstr "แสดงทั้งหมด" - -#: lms/templates/ccx/schedule.underscore -msgid "Collapse All" -msgstr "ซ่อนทั้งหมด" - -#: openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show More" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show Less" -msgstr "" - #: openedx/features/course_search/static/course_search/js/views/search_results_view.js msgid "{total_results} result found for \"{search_term}\"" msgid_plural "{total_results} results found for \"{search_term}\"" @@ -5451,6 +5469,31 @@ msgstr "" msgid "There was an error with the upload" msgstr "" +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Organization:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Number:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Run:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "(Read-only)" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Re-run Course" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +#: cms/templates/js/show-textbook.underscore +msgid "View Live" +msgstr "" + #: cms/static/js/maintenance/force_publish_course.js msgid "Internal Server Error." msgstr "" @@ -6931,10 +6974,6 @@ msgstr "" msgid "follow this post" msgstr "" -#: common/static/common/templates/discussion/templates.underscore -msgid "post anonymously" -msgstr "" - #: common/static/common/templates/discussion/templates.underscore msgid "post anonymously to classmates" msgstr "" @@ -7383,6 +7422,14 @@ msgstr "" msgid "This catalog's courses:" msgstr "" +#: lms/templates/ccx/schedule.underscore +msgid "Expand All" +msgstr "แสดงทั้งหมด" + +#: lms/templates/ccx/schedule.underscore +msgid "Collapse All" +msgstr "ซ่อนทั้งหมด" + #: lms/templates/ccx/schedule.underscore msgid "Start Date" msgstr "วันที่เริ่ม" @@ -7466,6 +7513,14 @@ msgid "" "before you select \"End My Exam\"." msgstr "" +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show More" +msgstr "" + +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show Less" +msgstr "" + #: lms/templates/discovery/course_card.underscore msgid "LEARN MORE" msgstr "เรียนรู้เพิ่มเติม" @@ -10129,10 +10184,6 @@ msgstr "" msgid "PDF Chapters" msgstr "" -#: cms/templates/js/show-textbook.underscore -msgid "View Live" -msgstr "" - #: cms/templates/js/signatory-details.underscore #: cms/templates/js/signatory-editor.underscore msgid "Signatory" diff --git a/conf/locale/tr_TR/LC_MESSAGES/django.mo b/conf/locale/tr_TR/LC_MESSAGES/django.mo index fa95843b5c4523780b485fcbd91bf5120d4e664f..ad6040edf89d7e1ad500573a34508f2b96e23da8 100644 GIT binary patch delta 49 zcmX@vqkOVQxuJ!zg{g&k3(J&?EEakOT+<(3WD%QofSJ90>qQnIW(8ul?OQLhPx%4> D@&px$ delta 49 zcmX@vqkOVQxuJ!zg{g&k3(J&?ES7qPT+<(3WD%QofSJ90>qQnIW(8ul?OQLhPx%4> D@<0`f diff --git a/conf/locale/tr_TR/LC_MESSAGES/django.po b/conf/locale/tr_TR/LC_MESSAGES/django.po index 447c6e374d..e86cc49f51 100644 --- a/conf/locale/tr_TR/LC_MESSAGES/django.po +++ b/conf/locale/tr_TR/LC_MESSAGES/django.po @@ -132,7 +132,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:44+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Ali Işıngör , 2021\n" "Language-Team: Turkish (Turkey) (https://www.transifex.com/open-edx/teams/6205/tr_TR/)\n" @@ -141,7 +141,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# #. Translators: 'Discussion' refers to the tab in the courseware that leads to @@ -779,6 +779,10 @@ msgstr "Ders no geçersiz" msgid "Could not enroll" msgstr "Kayıtlanılamadı" +#: common/djangoapps/student/views/management.py +msgid "Unenrollment is currently disabled" +msgstr "" + #: common/djangoapps/student/views/management.py msgid "You are not enrolled in this course" msgstr "Bu derse kaydolmadınız" @@ -1915,7 +1919,6 @@ msgstr "Çalışanların bu soruya cevap vermesinde sorun yaşandı: boş sını #. to the site. #: common/lib/capa/capa/responsetypes.py #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html #: themes/stanford-style/lms/templates/register-form.html msgid "or" msgstr "veya" @@ -2220,6 +2223,7 @@ msgid "Whether to force the save button to appear on the page" msgstr "Kaydet düğmesinin sayfada görünmesini zorlayıp zorlamadığı " #: common/lib/xmodule/xmodule/capa_module.py +#: common/lib/xmodule/xmodule/library_content_module.py msgid "Show Reset Button" msgstr "Sıfırla Düğmesini Göster" @@ -3032,7 +3036,6 @@ msgstr "" #: common/lib/xmodule/xmodule/course_module.py #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Handouts" msgstr "Ders Notları" @@ -3787,6 +3790,12 @@ msgstr "" "Kütüphaneden getirmek için problem türünü seçin. Eğer \"Herhangi Bir Tür\" " "seçiliyse filtreleme uygulanmaz." +#: common/lib/xmodule/xmodule/library_content_module.py +msgid "" +"Determines whether a 'Reset Problems' button is shown, so users may reset " +"their answers and reshuffle selected items." +msgstr "" + #: common/lib/xmodule/xmodule/library_content_module.py msgid "This component is out of date. The library has new content." msgstr "Bu bileşen güncel değil. Kütüphane yeni içeriğe sahip." @@ -5087,8 +5096,7 @@ msgstr "Hesap Kilidini Aç" #: lms/templates/instructor/instructor_dashboard_2/invalidate_registration_code_modal.html #: lms/templates/instructor/instructor_dashboard_2/set_course_mode_price_modal.html #: lms/templates/modal/_modal-settings-language.html -#: lms/templates/signup_modal.html themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html +#: lms/templates/signup_modal.html msgid "Close" msgstr "Kapa" @@ -5584,7 +5592,6 @@ msgstr "" #. Translators: 'Open edX' is a brand, please keep this untranslated. See #. http://openedx.org for more information. #: lms/djangoapps/branding/api.py cms/templates/widgets/footer.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html #: themes/red-theme/lms/templates/footer.html msgid "Powered by Open edX" msgstr "İçinde Open edX Var" @@ -5594,7 +5601,6 @@ msgid "Blog" msgstr "Blog" #: lms/djangoapps/branding/api.py cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html #: themes/stanford-style/lms/templates/static_templates/about.html msgid "Contact Us" msgstr "Bizimle İletişime Geçin" @@ -5652,7 +5658,6 @@ msgstr "Kullanım Şartları & Onur Kodu" #: lms/djangoapps/branding/api.py lms/djangoapps/certificates/views/webview.py #: cms/templates/widgets/footer.html #: lms/templates/static_templates/privacy.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html #: themes/red-theme/lms/templates/footer.html #: themes/stanford-style/lms/templates/footer.html #: themes/stanford-style/lms/templates/static_templates/tos.html @@ -5667,6 +5672,7 @@ msgstr "Erişilebilirlik İlkesi" #. Translators: This is a legal document users must agree to #. in order to register a new account. #: lms/djangoapps/branding/api.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: cms/templates/widgets/footer.html lms/templates/static_templates/tos.html #: themes/red-theme/lms/templates/footer.html @@ -6218,22 +6224,6 @@ msgstr "" "{username} ({email}) kullanıcısı için geri ödeme isteği başlatıldı. Bu " "isteği işleme koymak için, lütfen aşağıdaki bağlantı(ları) ziyaret edin." -#: lms/templates/course_modes/track_selection.html -msgid "Earn a certificate" -msgstr "Bir sertifika kazanın" - -#: lms/djangoapps/course_goals/models.py -msgid "Complete the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Explore the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Not sure yet" -msgstr "" - #: lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/body.html msgid "" "\n" @@ -6354,6 +6344,10 @@ msgid "" "have questions." msgstr "" +#: lms/templates/courseware/course_about.html +msgid "Course is full" +msgstr "Ders Dolu" + #: lms/djangoapps/course_home_api/outline/views.py msgid "'course_id' is required." msgstr "'course_id' gerekli." @@ -6498,20 +6492,6 @@ msgstr "Kayıt Tarihi" msgid "Course starts" msgstr "Ders başlangıcı" -#: lms/djangoapps/courseware/date_summary.py -msgid "Don't forget to add a calendar reminder!" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} on {course_start_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} at {course_start_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Course ends" msgstr "Ders sonu" @@ -6537,16 +6517,6 @@ msgstr "" "Bu ders arşivlendi, bir başka deyişle ders içeriğini gözden geçirebilirsiniz" " ancak bu ders artık aktif değil." -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} on {course_end_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} at {course_end_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "You lose all access to this course, including your progress." msgstr "Bu derse ilerlemeniz dahil, tüm erişiminizi kaybedeceksiniz." @@ -6564,22 +6534,6 @@ msgid "Day certificates will become available for passing verified learners." msgstr "" "Dersten geçmiş doğrulanmış öğrenciler için günlük sertifikalar sunulacak." -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"If you have earned a certificate, you will be able to access it " -"{time_remaining_string} from now. You will also be able to view your " -"certificates on your {learner_profile_link}." -msgstr "" - -#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html -msgid "Learner Profile" -msgstr "Öğrenci Profili" - -#: lms/djangoapps/courseware/date_summary.py -msgid "We are working on generating course certificates." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Upgrade to Verified Certificate" msgstr "Onaylı Sertifikaya Yükselt" @@ -6614,36 +6568,9 @@ msgstr "" msgid "by {date}" msgstr "{date} itibariyle" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"Don't forget, you have {time_remaining_string} left to upgrade to a Verified" -" Certificate." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Don't forget to upgrade to a verified certificate by {localized_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"In order to qualify for a certificate, you must meet all course grading " -"requirements, upgrade before the course deadline, and successfully verify " -"your identity on {platform_name} if you have not done so " -"already.{button_panel}" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Upgrade ({upgrade_price})" -msgstr "" - #: lms/djangoapps/courseware/date_summary.py #: cms/templates/group_configurations.html #: lms/templates/courseware/program_marketing.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Learn More" msgstr "Daha Fazlasını Öğren" @@ -6713,6 +6640,24 @@ msgstr "Bu ders yayını için dinamik yükseltme işlemini devre dışı bırak msgid "Disable the dynamic upgrade deadline for this organization." msgstr "Bu kurum için dinamik yükseltme işlemini devre dışı bırak." +#: lms/djangoapps/courseware/models.py +msgid "Internal API Base URL" +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Financial Assistance Backend API Base URL." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "" +"Username created for Financial Assistance Backend, e.g. " +"financial_assistance_service_user." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Percentage of courses allowed to use edx-financial-assistance" +msgstr "" + #: lms/djangoapps/courseware/plugins.py lms/djangoapps/courseware/tabs.py #: lms/templates/peer_grading/peer_grading.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html @@ -6787,7 +6732,6 @@ msgstr "giriş yap" #: lms/djangoapps/courseware/views/index.py #: lms/djangoapps/courseware/views/views.py #: openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "register" msgstr "kaydol" @@ -6845,18 +6789,6 @@ msgstr "Tebrikler, siz bir sertifika için niteliklisiniz!" msgid "You've earned a certificate for this course." msgstr "Bu ders için sertifikaya hak kazandınız." -#: lms/djangoapps/courseware/views/views.py -msgid "Certificate unavailable" -msgstr "Sertifika mevcut değil" - -#: lms/djangoapps/courseware/views/views.py -#, python-brace-format -msgid "" -"You have not received a certificate because you do not have a current " -"{platform_name} verified identity." -msgstr "" -"Sertifika alamazsınız çünkü {platform_name} kimliğiniz doğrulanmış değil." - #: lms/djangoapps/courseware/views/views.py msgid "Your certificate will be available soon!" msgstr "Sertifikanız yakında hazır olacak!" @@ -6873,23 +6805,32 @@ msgstr "" msgid "Your certificate is available" msgstr "Sertifikanız hazır" +#: lms/djangoapps/courseware/views/views.py +msgid "Certificate unavailable" +msgstr "Sertifika mevcut değil" + +#: lms/djangoapps/courseware/views/views.py +#, python-brace-format +msgid "" +"You have not received a certificate because you do not have a current " +"{platform_name} verified identity." +msgstr "" +"Sertifika alamazsınız çünkü {platform_name} kimliğiniz doğrulanmış değil." + #: lms/djangoapps/courseware/views/views.py #, python-brace-format msgid "To see course content, {sign_in_link} or {register_link}." msgstr "Ders içeriğini görmek için, {sign_in_link} ya da {register_link}." #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py #, python-brace-format msgid "{sign_in_link} or {register_link}." msgstr "{sign_in_link} ya da {register_link}." #: lms/djangoapps/courseware/views/views.py #: openedx/core/djangoapps/user_authn/templates/user_authn/edx_ace/passwordresetsuccess/email/body.html -#: openedx/features/course_experience/views/course_home_messages.py #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html msgid "Sign in" msgstr "Giriş Yap" @@ -6901,7 +6842,6 @@ msgid "" msgstr "" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "You must be enrolled in the course to see course content." msgstr "Ders içeriğini görmek için önce derse kayıt olmalısınız." @@ -7028,6 +6968,29 @@ msgstr "" msgid "Good" msgstr "İyi" +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#, python-format +msgid "" +"\n" +" %(course_name)s: Reported content awaits review\n" +" " +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +msgid "Go to Discussion" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +#, python-format +msgid "%(course_name)s: Reported content awaits review" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/subject.txt +#, python-format +msgid " %(course_name)s %(course_id)s moderator content for review " +msgstr "" + #: lms/djangoapps/discussion/templates/discussion/edx_ace/responsenotification/email/body.html #, python-format, python-brace-format msgid "%(comment_username)s replied to {start_tag}%(thread_title)s{end_tag}:" @@ -7372,10 +7335,13 @@ msgid "Team" msgstr "Takım" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# +#. Translators: This label appears above a field +#. which allows the user to input the city in which they live. #. Translators: This label appears above a field on the registration form #. which allows the user to input the city in which they live. #: lms/djangoapps/instructor/views/api.py #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: lms/templates/instructor/instructor_dashboard_2/generate_registarion_codes_modal.html #: themes/stanford-style/lms/templates/register-form.html @@ -8215,7 +8181,6 @@ msgstr " ({total} içinde)" #: lms/templates/learner_dashboard/programs.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Programs" msgstr "Programlar" @@ -9166,7 +9131,6 @@ msgstr "Hemen kaydol" #: lms/templates/save_for_later/edx_ace/saveforlater/email/body.html #: lms/templates/courseware/course_about.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "View Course" msgstr "Derse Gözat" @@ -9443,8 +9407,6 @@ msgstr "Wiki Önizleme" #: lms/templates/wiki/includes/cheatsheet.html lms/templates/dashboard.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/modal/_modal-settings-language.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "window open" msgstr "pencere açık" @@ -9709,9 +9671,6 @@ msgstr "" #: lms/templates/courseware/courseware.html lms/templates/dashboard.html #: lms/templates/edxnotes/edxnotes.html lms/templates/index.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -#: themes/edx.org/lms/templates/dashboard.html #: themes/stanford-style/lms/templates/index.html #: wiki/plugins/attachments/templates/wiki/plugins/attachments/index.html msgid "Search" @@ -9830,7 +9789,6 @@ msgstr "%(platform_name)s Ana Sayfasına Git" #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Courses" msgstr "Dersler" @@ -10751,7 +10709,6 @@ msgid "Student" msgstr "Öğrenci" #: openedx/core/djangoapps/embargo/forms.py -#: openedx/core/djangoapps/verified_track_content/forms.py msgid "COURSE NOT FOUND. Please check that the course ID is valid." msgstr "" "DERS BULUNAMADI. Lütfen ders ID bilgisinin geçerliliğini kontrol ediniz." @@ -10812,6 +10769,10 @@ msgstr "{course} dersi için {country} beyaz listede" msgid "Blacklist {country} for {course}" msgstr "{course} dersi için {country} kara listede" +#: openedx/core/djangoapps/learner_pathway/apps.py +msgid "Learner Pathways" +msgstr "" + #: openedx/core/djangoapps/oauth_dispatch/models.py msgid "" "Comma-separated list of scopes that this application will be allowed to " @@ -11374,6 +11335,14 @@ msgstr "En az {min} karakter içeren geçerli bir e-posta adresi girin." msgid "Enter your full name." msgstr "Tam adınızı girin." +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your first name." +msgstr "" + +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your last name." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "The email addresses do not match." msgstr "Bu e-posta adresleri uyuşmuyor." @@ -11398,6 +11367,10 @@ msgstr "Mesleğinizi girin." msgid "Enter your specialty." msgstr "Uzmanlığınızı girin." +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your state." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "Enter your city." msgstr "Şehrinizi girin." @@ -11439,24 +11412,39 @@ msgstr "" msgid "The '{field_name}' field cannot be edited." msgstr "'{field_name}' alanı düzenlenemez." +#: openedx/core/djangoapps/user_api/accounts/api.py +#: openedx/core/djangoapps/user_authn/views/registration_form.py +msgid "Enter a valid name" +msgstr "Geçerli bir ad giriniz" + +#. Translators: This label appears above a field which allows the +#. user to input the First Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "First Name" msgstr "Ad" +#. Translators: This label appears above a field which allows the +#. user to input the Last Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "Last Name" msgstr "Soyad" +#. Translators: This label appears above a field +#. which allows the user to input the State/Province/Region in which they +#. live. #. Translators: This label appears above a field on the registration form #. which allows the user to input the State/Province/Region in which they #. live. #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "State/Province/Region" msgstr "Eyalet/Şehir/Bölge" @@ -11494,9 +11482,12 @@ msgid "Job Title" msgstr "Mesleki Ünvan" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# +#. Translators: This label appears above a field +#. meant to hold the user's mailing address. #. Translators: This label appears above a field on the registration form #. meant to hold the user's mailing address. #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: lms/templates/signup_modal.html msgid "Mailing address" @@ -11789,7 +11780,6 @@ msgstr "" #: openedx/core/djangoapps/user_authn/views/login.py #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html #: themes/stanford-style/lms/templates/register-form.html msgid "Register" msgstr "Kayıt Ol" @@ -11930,10 +11920,6 @@ msgstr "Sağlanan erişim belirteci geçerli değildir." msgid "Full Name cannot contain the following characters: < >" msgstr "Tam isim şu karakterleri içeremez: < >" -#: openedx/core/djangoapps/user_authn/views/registration_form.py -msgid "Enter a valid name" -msgstr "Geçerli bir ad giriniz" - #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "A properly formatted e-mail is required" msgstr "Geçerli biçimde e-posta adresi gerekiyor" @@ -12120,10 +12106,6 @@ msgstr "" msgid "Dismiss" msgstr "İptal" -#: openedx/core/djangoapps/verified_track_content/models.py -msgid "The course key for the course we would like to be auto-cohorted." -msgstr "" - #: openedx/core/djangoapps/video_pipeline/models.py msgid "Oauth client name of VEM service." msgstr "VEM servisi için Oauth istemci adı." @@ -12412,51 +12394,6 @@ msgstr "Bitiş tarihleri başarıyla sıfırlandı." msgid "Updates" msgstr "Güncellemeler" -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{sign_in_link} or {register_link} and then enroll in this course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Welcome to {course_display_name}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"You must be enrolled in the course to see course content. Please contact " -"your degree administrator or {platform_name} Support if you have questions." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"{open_enroll_link}Enroll now{close_enroll_link} to access the full course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"To start, set a course goal by selecting the option below that best " -"describes your learning plan. {goal_options_container}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {goal_text}" -msgstr "" - #: openedx/features/discounts/admin.py msgid "" "These define the context to disable lms-controlled discounts on. If no " @@ -13628,11 +13565,6 @@ msgstr "Ders Adı" msgid "Course Number" msgstr "Ders Numarası" -#: cms/templates/course_outline.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Course Outline" -msgstr "" - #: cms/templates/html_error.html lms/templates/course_modes/error.html #: lms/templates/module-error.html msgid "Error:" @@ -13724,62 +13656,10 @@ msgstr "Hesap" #: lms/templates/header/navbar-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: lms/templates/static_templates/help.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -#: wiki/plugins/help/wiki_plugin.py +#: lms/templates/static_templates/help.html wiki/plugins/help/wiki_plugin.py msgid "Help" msgstr "Yardım" -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Looking for help with {studio_name}?" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Hide {studio_name} Help" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "{studio_name} Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Access documentation on http://docs.edx.org" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101: Overview of Creating an edX Course" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX: Creating a Course with edX Studio" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Send an email to {email}" -msgstr "" - #: cms/templates/widgets/tabs-aggregator.html #: lms/templates/courseware/static_tab.html #: lms/templates/courseware/tab-view.html @@ -13957,19 +13837,18 @@ msgstr "Tüm Dersleri Görüntüle" #: lms/templates/dashboard.html lms/templates/header/user_dropdown.html #: lms/templates/user_dropdown.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Dashboard" msgstr "Ana Panel" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "results successfully populated," msgstr "sonuçlar başarıyla dolduruldu," -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Click to load all enrolled courses" msgstr "Kayıtlanılmış tüm dersleri yüklemek için tıklayın" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "You are not enrolled in any courses yet." msgstr "Henüz bir derse kayıt olmadınız." @@ -13977,7 +13856,6 @@ msgstr "Henüz bir derse kayıt olmadınız." #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore courses" msgstr "Dersleri keşfedin" @@ -13986,16 +13864,15 @@ msgstr "Dersleri keşfedin" msgid "Activate your account!" msgstr "Hesabınızı etkinleştirin!" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Course-loading errors" msgstr "Ders-yükleme hataları" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Search Your Courses" msgstr "Derslerimde Ara" #: lms/templates/courseware/courseware.html lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Clear search" msgstr "Aramayı temizle" @@ -14018,15 +13895,15 @@ msgstr "" msgid "Continue to {platform_name}" msgstr "{platform_name} platformuna devam edin" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Email Settings for {course_number}" msgstr "{course_number} için E-posta Ayarları" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Receive course emails" msgstr "Ders e-postalarını al" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Save Settings" msgstr "Ayarları Kaydet" @@ -14035,83 +13912,9 @@ msgstr "Ayarları Kaydet" #: lms/templates/dashboard/_dashboard_entitlement_actions.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/instructor/instructor_dashboard_2/membership.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "Unenroll" msgstr "Kaydı iptal et" -#: lms/templates/dates_banner.html -msgid "" -"It looks like you missed some important deadlines based on our suggested " -"schedule. " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future by visiting " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" Don't worry—you won't lose any of the progress you've made when you shift " -"your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future. Don't worry—you won't lose any of the " -"progress you've made when you shift your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "You are auditing this course," -msgstr "" - -#: lms/templates/dates_banner.html -msgid " which means that you are unable to participate in graded assignments." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. Graded assignments and schedule adjustment are available to " -"Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. To complete graded assignments as part of this course and shift " -"the past due assignments into the future, you can upgrade today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Upgrade to shift due dates" -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Graded assignments are available to Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" To complete graded assignments as part of this course, you can upgrade " -"today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "We've built a suggested schedule to help you stay on track." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"But don't worry—it's flexible so you can learn at your own pace. If you " -"happen to fall behind on our suggested dates, you'll be able to adjust them " -"to keep yourself on track." -msgstr "" - #: lms/templates/email_change_failed.html lms/templates/email_exists.html msgid "E-mail change failed" msgstr "E-posta değiştirme başarısız" @@ -14456,10 +14259,6 @@ msgid "You are now viewing the course as {i_start}{user_name}{i_end}." msgstr "" "Dersi {i_start}{user_name}{i_end} kullanıcısı olarak görüntülüyorsunuz." -#: lms/templates/preview_menu.html -msgid "View in the new experience" -msgstr "" - #: lms/templates/preview_menu.html msgid "View in Studio" msgstr "Studio İçinde Görüntüle" @@ -14587,9 +14386,7 @@ msgstr "Sonraki" msgid "Sequence" msgstr "Sıralı" -#: lms/templates/courseware/dates.html lms/templates/seq_module.html -#: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html +#: lms/templates/seq_module.html lms/templates/vert_module.html msgid "Completed" msgstr "Tamamlandı" @@ -14869,7 +14666,6 @@ msgstr "" "yapılabilir." #: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "{subsection_format} due {{date}}" msgstr "{subsection_format} {{date}} tarihine dek" @@ -14881,6 +14677,10 @@ msgstr "Son gün {date}" msgid "Past due" msgstr "Zaman aşımına uğramış" +#: lms/templates/vert_module.html +msgid "Reset Problems" +msgstr "" + #: lms/templates/video.html msgid "Loading video player" msgstr "Video oynatıcısı yükleniyor" @@ -16080,7 +15880,6 @@ msgid "Download student grades" msgstr "Öğrenci notlarını indir" #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Print or share your certificate:" msgstr "Sertifikanı yazdır veya paylaş:" @@ -16094,7 +15893,6 @@ msgstr "Facebook'ta paylaş" #: lms/templates/certificates/_accomplishment-banner.html #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Twitter" msgstr "Twitter'da paylaş" @@ -16103,7 +15901,6 @@ msgid "Tweet this Accomplishment. Pop up window." msgstr "Bu Başarı Belgesini Twitle" #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Add to LinkedIn Profile" msgstr "LinkedIn Profiline Ekle" @@ -16209,40 +16006,31 @@ msgstr "" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue the Verified Track" msgstr "Doğrulanmış Kayıtlanma Yolunu Takip Edin" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue a Verified Certificate" msgstr "Bir Onaylı Sertifikayı takip edin" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Enroll In {course_name} | Choose Your Track" msgstr "{course_name} dersine kaydol | Kayıtlanma Yolunuzu Seçin" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Sorry, there was an error when trying to enroll you" msgstr "Üzgünüm, kayıt işleminizi yaparken bir problem oluştu" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with the Verified Track" msgstr "Doğrulanmış Kayıtlanma Yolu ile Akademik Kredi Edinin" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with a Verified Certificate" msgstr "Onaylı Sertifika ile Akademik Kredi Takibi" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Become eligible for academic credit and highlight your new skills and " "knowledge with a verified certificate. Use this valuable credential to " @@ -16255,12 +16043,10 @@ msgstr "" "güçlendirmek için kullanın. " #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of the Verified Track" msgstr "Doğrulanmış Kayıtlanma Yolunun Faydaları" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Eligible for credit:{b_end} Receive academic credit after " "successfully completing the course" @@ -16269,7 +16055,6 @@ msgstr "" "akademik krediyi alın" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Unlimited Course Access: {b_end}Learn at your own pace, and access " "materials anytime to brush up on what you've learned." @@ -16278,7 +16063,6 @@ msgstr "" "öğrendiklerinizi tazelemek için istediğiniz zaman materyallere erişin." #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Graded Assignments: {b_end}Build your skills through graded " "assignments and projects." @@ -16287,19 +16071,16 @@ msgstr "" "görev ve projelerle geliştirin." #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily Sharable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of a Verified Certificate" msgstr "Onaylı Sertifikanın Faydaları" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official:{b_end} Receive an instructor-signed certificate with the " "institution's logo" @@ -16307,14 +16088,12 @@ msgstr "" "{b_start}Resmi:{b_end} Kurumun logosu ile eğitmen imzalı bir sertifika alın" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable:{b_end} Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Highlight your new knowledge and skills with a verified certificate. Use " "this valuable credential to improve your job prospects and advance your " @@ -16325,7 +16104,6 @@ msgstr "" "kimlik bilgisini kullanın veya okul başvurularında sertifikanızı vurgulayın." #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official: {b_end}Receive an instructor-signed certificate with the " "institution's logo" @@ -16333,14 +16111,12 @@ msgstr "" "{b_start}Resmi:{b_end} Kurumun logosu ile eğitmen imzalı bir sertifika alın" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Motivating: {b_end}Give yourself an additional incentive to " "complete the course" @@ -16348,12 +16124,10 @@ msgstr "" "{b_start}Motive Edici: {b_end}Dersi tamamlamak için ek bir teşvik kaynağı" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course" msgstr "Bu Dersi Gözlemleyin" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums." @@ -16362,12 +16136,10 @@ msgstr "" "testlere ve forumlara tam erişim hakkına sahip olun." #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course (No Certificate)" msgstr "Bu Dersi Gözlemleyin (Sertifikasız)" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded assignments," @@ -16378,7 +16150,6 @@ msgstr "" "görevleri ya da derse sınırsız erişimi içermez.{b_end}" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded " @@ -16389,7 +16160,6 @@ msgstr "" " görevler içermez.{b_end}" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include unlimited course " @@ -16400,7 +16170,6 @@ msgstr "" " erişim içermez.{b_end}" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums. {b_start}Please note that this " @@ -16487,6 +16256,10 @@ msgstr "" msgid "Choose a path for your course in" msgstr "" +#: lms/templates/course_modes/track_selection.html +msgid "Earn a certificate" +msgstr "Bir sertifika kazanın" + #: lms/templates/course_modes/track_selection.html msgid "" "Studies show that those who choose this option are {start_bold}more engaged" @@ -16511,7 +16284,6 @@ msgstr "{span_start}şu anki bölüm{span_end}" #: lms/templates/courseware/accordion.html #: lms/templates/courseware/progress.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "due {date}" msgstr "teslim {date}" @@ -16520,7 +16292,6 @@ msgid "{section_format} due {{date}}" msgstr "{section_format} son tarihi {{date}}" #: lms/templates/courseware/accordion.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "This content is graded" msgstr "Bu içerik puanlandı" @@ -16532,10 +16303,6 @@ msgstr "Bir hata oluştu. Lütfen daha sonra tekrar deneyin." msgid "You are enrolled in this course" msgstr "Bu derse kaydoldunuz" -#: lms/templates/courseware/course_about.html -msgid "Course is full" -msgstr "Ders Dolu" - #: lms/templates/courseware/course_about.html msgid "Enrollment in this course is by invitation only" msgstr "Bu derse sadece davet ile kayıtlanılır" @@ -16697,30 +16464,6 @@ msgstr "" msgid "Your score is {current_score}%. You have passed the entrance exam." msgstr "Puanınız {current_score}%. Giriş sınavını geçtiniz." -#: lms/templates/courseware/dates.html lms/templates/courseware/syllabus.html -msgid "{course.display_number_with_default} Course Info" -msgstr "{course.display_number_with_default} Ders Bilgisi" - -#: lms/templates/courseware/dates.html -msgid "Important Dates" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Today" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Verified Only" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Due Next" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Not yet released" -msgstr "" - #: lms/templates/courseware/gradebook.html msgid "Gradebook" msgstr "Karne" @@ -16771,8 +16514,6 @@ msgstr "{course_title} dersine hoş geldiniz!" #: lms/templates/courseware/info.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "Resume Course" msgstr "Derse Devam Et" @@ -16789,7 +16530,6 @@ msgid "Handout Navigation" msgstr "Yardımcı Metinler Navigasyonu" #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Tools" msgstr "Ders Araçları" @@ -17040,6 +16780,10 @@ msgstr "Alıştırma puanları gizlidir." msgid "No problem scores in this section" msgstr "Bu bölümde problemlerin notları bulunmuyor" +#: lms/templates/courseware/syllabus.html +msgid "{course.display_number_with_default} Course Info" +msgstr "{course.display_number_with_default} Ders Bilgisi" + #: lms/templates/courseware/welcome-back.html msgid "" "You were most recently in {section_link}. If you're done with that, choose " @@ -17311,7 +17055,6 @@ msgid "Share {course_name} on Facebook" msgstr "{course_name} dersini Facebook'ta paylaş" #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Facebook" msgstr "Facebook'ta Paylaş" @@ -17363,6 +17106,12 @@ msgid "" "showcase on your resumé." msgstr "" +#: lms/templates/dashboard/_dashboard_course_listing.html +msgid "" +"{start_bold}Get the most out of your course!{end_bold} Upgrade to earn a " +"{link_start}verified certificate{link_end} to showcase on your resumé." +msgstr "" + #: lms/templates/dashboard/_dashboard_course_listing.html msgid "Upgrade" msgstr "Yükselt" @@ -18236,7 +17985,6 @@ msgstr "" "{chrome_link} veya {ff_link} kullanmanızı şiddetle tavsiye ediyoruz." #: lms/templates/header/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Discover New" msgstr "Dersleri Keşfet" @@ -18250,7 +17998,6 @@ msgstr "Ek Bağlantılar" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "How it Works" msgstr "Nasıl Çalışır" @@ -19858,7 +19605,6 @@ msgstr "" " dosyasını oluşturmak için tıklayın." #: lms/templates/learner_dashboard/_dashboard_navigation_courses.html -#: themes/edx.org/lms/templates/dashboard.html msgid "My Courses" msgstr "Derslerim" @@ -20314,13 +20060,10 @@ msgid "Skeleton Page" msgstr "Skeleton Sayfası" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html msgid "Search the course" msgstr "Ders ara" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Start Course" msgstr "Derse Başla" @@ -20506,36 +20249,6 @@ msgstr "Yaklaşan Tarihler" msgid "View all course dates" msgstr "" -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Goal: " -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Edit your course goal:" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Pursue a verified certificate" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "" -"Sample verified certificate with your name, the course title, the logo of " -"the institution and the signatures of the instructors for this course." -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Upgrade ({price})" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Expand All" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Prerequisite: " -msgstr "" - #: openedx/features/course_experience/templates/course_experience/course-sock-fragment.html msgid "Learn About Verified Certificates" msgstr "Onaylı Sertifikalar Hakkında Daha Fazla Bilgi" @@ -20620,18 +20333,6 @@ msgstr "Yükselt ({course_price})" msgid "This course does not have any updates." msgstr "Bu derste herhangi bir güncelleme yok." -#: openedx/features/course_experience/templates/course_experience/latest-update-fragment.html -msgid "Latest Update" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/welcome-message-fragment.html -msgid "Show More" -msgstr "" - -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -msgid "Search Results" -msgstr "" - #. Translators: this section lists all the third-party authentication #. providers #. (for example, Google and LinkedIn) the user can link with or unlink from @@ -20675,10 +20376,13 @@ msgid "You haven't earned any certificates yet." msgstr "Henüz bir sertifikaya hak kazanmadınız." #: openedx/features/learner_profile/templates/learner_profile/learner-achievements-fragment.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore New Courses" msgstr "Yeni Dersleri Keşfet" +#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html +msgid "Learner Profile" +msgstr "Öğrenci Profili" + #: openedx/features/learner_profile/templates/learner_profile/learner_profile.html msgid "View My Records" msgstr "Kayıtlarımı Göster" @@ -20698,138 +20402,6 @@ msgstr "" msgid "An error occurred. Try loading the page again." msgstr "Bir hata oluştu. Sayfayı yeniden yüklemeyi deneyin." -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "" -"Access Course Staff Support on the Partner Portal to submit or review " -"support tickets" -msgstr "" - -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Partner Portal" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "" -"Browse recently launched courses and see what's new in your favorite " -"subjects." -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Take advantage of free coaching!" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Get Started" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Page Footer" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "edX Home Page" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Connect" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "© {year} edX Inc. All rights reserved." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "About edX Verified Certificates" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "" -"An edX Verified Certificate signifies that the learner has agreed to abide " -"by the edX honor code and completed all of the required tasks of this course" -" under its guidelines, as well as having their photo ID checked to verify " -"their identity." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "About edX" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "" -"{link_start}edX{link_end} offers interactive online classes and MOOCs from " -"the world's best universities, including MIT, Harvard, Berkeley, University " -"of Texas, and many others. edX is a mission driven initiative created by " -"founding partners Harvard and MIT." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Congratulations, {user_name}!" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "" -"You worked hard to earn your certificate from " -"{accomplishment_copy_course_org} {dash} share it with colleagues, friends, " -"and family to get the word out about what you mastered in " -"{accomplishment_course_title}." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Share this certificate on Facebook (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Tweet this certificate (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Add this certificate to your LinkedIn profile (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print this certificate" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "edX Inc." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "" -"All rights reserved except where noted. edX, Open edX and the edX and Open " -"edX logos are registered trademarks of edX Inc." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end}EdX relies on verified certificates to " -"help fund affordable education to everyone globally." -msgstr "" - -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end} EdX, a mission driven initiative, " -"relies on verified certificates to help fund free education for everyone " -"globally" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Find Courses" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Schools & Partners" -msgstr "" - #: themes/red-theme/lms/templates/footer.html msgid "" "{tos_link_start}Terms of Service{tos_link_end} and {honor_link_start}Honor " @@ -21554,6 +21126,10 @@ msgstr "" "kullanın. Güncellemeleri HTML içinde değiştirebilir, yenilerini " "ekleyebilirsiniz." +#: cms/templates/course_outline.html +msgid "Course Outline" +msgstr "" + #: cms/templates/course_outline.html msgid "" "This course was created as a re-run. Some manual configuration is needed." @@ -24635,6 +24211,26 @@ msgstr "Markdown İşaretleme Dili Yardımı" msgid "Label" msgstr "Etiket" +#: cms/templates/widgets/sock.html +msgid "Looking for help with {studio_name}?" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "Hide {studio_name} Help" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "{studio_name} Documentation" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Access documentation on http://docs.edx.org" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "edX Documentation" +msgstr "" + #: cms/templates/widgets/sock_links.html msgid "Access the Open edX Portal" msgstr "Open edX Portal'ına Erişim" @@ -24643,6 +24239,26 @@ msgstr "Open edX Portal'ına Erişim" msgid "Open edX Portal" msgstr "Open edX Portalı" +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101: Overview of Creating an edX Course" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX: Creating a Course with edX Studio" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Send an email to {email}" +msgstr "" + #: cms/templates/widgets/user_dropdown.html msgid "Currently signed in as:" msgstr "Şu an giriş yapılan hesap:" diff --git a/conf/locale/tr_TR/LC_MESSAGES/djangojs.mo b/conf/locale/tr_TR/LC_MESSAGES/djangojs.mo index e94bd238e53266b56a540087bb8f2608913581af..46faf26ded40eb5d3bacefd5e572f52fbd36d374 100644 GIT binary patch delta 25 hcmca`i}%7U-i9rV(w~_v^bFeNJ~M8Y`^;oi1pt$+3R(aF delta 25 hcmca`i}%7U-i9rV(w~_v^$gqPJ~M8Y`^;oi1pt%93S0mH diff --git a/conf/locale/tr_TR/LC_MESSAGES/djangojs.po b/conf/locale/tr_TR/LC_MESSAGES/djangojs.po index 048cab58a8..f327c99555 100644 --- a/conf/locale/tr_TR/LC_MESSAGES/djangojs.po +++ b/conf/locale/tr_TR/LC_MESSAGES/djangojs.po @@ -108,7 +108,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Ali Işıngör , 2018,2020-2021\n" "Language-Team: Turkish (Turkey) (http://www.transifex.com/open-edx/edx-platform/language/tr_TR/)\n" @@ -117,7 +117,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js #: cms/static/js/views/video_transcripts.js @@ -182,7 +182,6 @@ msgstr "Sil" #: common/lib/xmodule/xmodule/js/src/html/edit.js #: common/static/common/js/components/utils/view_utils.js #: lms/static/js/Markdown.Editor.js -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx #: lms/static/js/student_account/components/StudentAccountDeletionModal.jsx #: cms/templates/js/add-xblock-component-menu-problem.underscore #: cms/templates/js/add-xblock-component-menu.underscore @@ -367,6 +366,14 @@ msgstr "Hata" msgid "Updating with latest library content" msgstr "Son kütüphane içeriğiyle güncelleniyor" +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Loading..." +msgstr "" + +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Selected blocks" +msgstr "" + #: common/lib/xmodule/xmodule/assets/library_source_block/public/js/library_source_block.js msgid "Unable to update settings" msgstr "Ayarlar güncellenemedi" @@ -1293,6 +1300,7 @@ msgstr "Yeni pencere" #. Translators: this is a message from the raw HTML editor displayed in the #. browser when a user needs to edit HTML #: common/lib/xmodule/xmodule/js/src/html/edit.js +#: lms/static/js/demographics_collection/Wizard.jsx #: cms/templates/js/paging-header.underscore #: common/static/common/templates/components/paging-footer.underscore #: common/static/common/templates/discussion/templates.underscore @@ -2077,6 +2085,10 @@ msgstr "Alt öğeleri görüntüleyin" msgid "Navigate up" msgstr "Yukarı git" +#: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx +msgid "Browsing" +msgstr "" + #: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx msgid "Select" msgstr "Seç" @@ -2629,12 +2641,32 @@ msgstr "" "süreçler konusunda uzmanlığa sahiptir. Lütfen dersle ilgili tüm soruları " "Ders Personeli'nin doğrudan yanıtlayabileceği Tartışma Forumu'na gönderin." +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Details" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "the more quickly and helpfully we can respond!" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Create Support Ticket" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "What can we help you with, {username}?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx msgid "Sign in to {platform} so we can help you better." msgstr "" "{platform} platformuna kaydolarak size daha iyi yardım etmemizi " "sağlayabilirsiniz." +#: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx +msgid "Need help logging in?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/single_support_form.jsx msgid "" "Select a course or select \"Not specific to a course\" for your support " @@ -3521,20 +3553,52 @@ msgstr "edX'i herkes için daha iyi hale getirmek mi istiyorsunuz?" msgid "Get started" msgstr "Başlayalım" -#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx -msgid "Section {currentPage} of {totalPages}" -msgstr "" - #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "Help make edX better for everyone!" msgstr "edX'i herkes için daha iyi bir hale getirmemize yardım edin!" +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Why does edX collect this information?" +msgstr "" + #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "" -"Welcome to edX! Before you get started, please take a few minutes to fill-in" -" the additional information below to help us understand a bit more about " -"your background. You can always edit this information later in Account " -"Settings." +"An error occurred while attempting to retrieve or save the information " +"below. Please try again later." +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What was the total combined income, during the last 12 months, of all " +"members of your family? " +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"Have you ever served on active duty in the U.S. Armed Forces, Reserves, or " +"National Guard?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What is the highest level of education that you have achieved so far?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What is the highest level of education that any of your parents or guardians" +" have achieved?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Select employment status" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you currently work in?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you want to work in?" msgstr "" #: lms/static/js/demographics_collection/MultiselectDropdown.jsx @@ -3549,6 +3613,22 @@ msgstr "demografi anketi" msgid "close questionnaire" msgstr "anketi kapat" +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Return to my dashboard" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "next page" +msgstr "" + #: lms/static/js/discovery/views/search_form.js #, javascript-format msgid "Viewing %s course" @@ -3863,27 +3943,6 @@ msgstr "Topluluklar Etkin" msgid "Cohorts Disabled" msgstr "Topluluklar Devre Dışı" -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course uses automatic cohorting for verified track learners. You cannot" -" disable cohorts, and you cannot rename the manual cohort named " -"'{verifiedCohortName}'. To change the configuration for verified track " -"cohorts, contact your edX partner manager." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" the required cohort does not exist. You must create a manually-assigned " -"cohort named '{verifiedCohortName}' for the feature to work." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" cohorts are disabled. You must enable cohorts for the feature to work." -msgstr "" - #: lms/static/js/instructor_dashboard/certificates.js msgid "Allow students to generate certificates for this course?" msgstr "Öğrencilerin bu ders için sertifika oluşturmasına izin ver?" @@ -4616,10 +4675,6 @@ msgstr "" "Bağlantılar talep geldiğinde oluşturulur ve öğrenci bilgilerinin hassas " "durumu nedeniyle 5 dakika içinde zaman aşımına uğrar." -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx -msgid "You have access to the {enterpriseName} dashboard" -msgstr "" - #: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx msgid "" "To access the courses available to you through {enterpriseName}, visit the " @@ -5562,40 +5617,6 @@ msgstr "Toplam Skor" msgid "Bookmark this page" msgstr "Bu sayfaya yer imi koy" -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "Thank you for setting your course goal to {goal}!" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "" -"There was an error in setting your goal, please reload the page and try " -"again." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "You have successfully updated your goal." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "There was an error updating your goal." -msgstr "" - -#: lms/templates/ccx/schedule.underscore -msgid "Expand All" -msgstr "Tümünü Aç" - -#: lms/templates/ccx/schedule.underscore -msgid "Collapse All" -msgstr "Tümünü Kapa" - -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show More" -msgstr "Daha Fazla Göster" - -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show Less" -msgstr "Daha Az Göster" - #: openedx/features/course_search/static/course_search/js/views/search_results_view.js msgid "{total_results} result found for \"{search_term}\"" msgid_plural "{total_results} results found for \"{search_term}\"" @@ -5892,6 +5913,30 @@ msgstr "Dersi içe aktarırken hata " msgid "There was an error with the upload" msgstr "Yüklemede bir sorun oluştu" +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Organization:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Number:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Run:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "(Read-only)" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Re-run Course" +msgstr "" + +#: cms/templates/js/show-textbook.underscore +msgid "View Live" +msgstr "Canlı Görüntüle" + #: cms/static/js/maintenance/force_publish_course.js msgid "Internal Server Error." msgstr "Sunucu Hatası" @@ -7463,10 +7508,6 @@ msgstr "Bütün Gruplar" msgid "follow this post" msgstr "bu iletiyi takip et" -#: common/static/common/templates/discussion/templates.underscore -msgid "post anonymously" -msgstr "" - #: common/static/common/templates/discussion/templates.underscore msgid "post anonymously to classmates" msgstr "sınıf arkadaşlarına anonim olarak ileti gönder" @@ -7923,6 +7964,14 @@ msgstr "" msgid "This catalog's courses:" msgstr "Bu katalogdaki dersler:" +#: lms/templates/ccx/schedule.underscore +msgid "Expand All" +msgstr "Tümünü Aç" + +#: lms/templates/ccx/schedule.underscore +msgid "Collapse All" +msgstr "Tümünü Kapa" + #: lms/templates/ccx/schedule.underscore msgid "Start Date" msgstr "Başlama Tarihi" @@ -8008,6 +8057,14 @@ msgstr "" "Problemlerden kredi almak için, \"Sınavımı Bitir\"i seçmeden önce her " "problem için \"Gönder\"e tıklamalısınız." +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show More" +msgstr "Daha Fazla Göster" + +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show Less" +msgstr "Daha Az Göster" + #: lms/templates/discovery/course_card.underscore msgid "LEARN MORE" msgstr "AYRINTILI BİLGİ" @@ -10849,10 +10906,6 @@ msgstr "" msgid "PDF Chapters" msgstr "PDF Bölümleri" -#: cms/templates/js/show-textbook.underscore -msgid "View Live" -msgstr "Canlı Görüntüle" - #: cms/templates/js/signatory-details.underscore #: cms/templates/js/signatory-editor.underscore msgid "Signatory" diff --git a/conf/locale/uk/LC_MESSAGES/django.mo b/conf/locale/uk/LC_MESSAGES/django.mo index 9974bc2dc7d8f2acf27db11e8b970d90d36c591d..e3f9294451d7fbff660e774cf04c57a0a8f7d4b4 100644 GIT binary patch delta 43 wcmZ4ZL2}^-$%YojElkdP*(~%7xEQ#mC-Si=x999-0%B$$X4#&zmv!qd0ABzQTmS$7 delta 43 wcmZ4ZL2}^-$%YojElkdP*(~)8xfr;nC-Si=x999-0%B$$X4#&zmv!qd0ADx|UH||9 diff --git a/conf/locale/uk/LC_MESSAGES/django.po b/conf/locale/uk/LC_MESSAGES/django.po index 9805751c0e..ca93357edf 100644 --- a/conf/locale/uk/LC_MESSAGES/django.po +++ b/conf/locale/uk/LC_MESSAGES/django.po @@ -124,7 +124,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:44+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Danylo Shcherbak , 2020\n" "Language-Team: Ukrainian (https://www.transifex.com/open-edx/teams/6205/uk/)\n" @@ -133,7 +133,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# #. Translators: 'Discussion' refers to the tab in the courseware that leads to @@ -742,6 +742,10 @@ msgstr "Ідентифікатор курсу невірний" msgid "Could not enroll" msgstr "Неможливо зареєструватися на курс" +#: common/djangoapps/student/views/management.py +msgid "Unenrollment is currently disabled" +msgstr "" + #: common/djangoapps/student/views/management.py msgid "You are not enrolled in this course" msgstr "Ви не записані на цей курс" @@ -2241,6 +2245,7 @@ msgid "Whether to force the save button to appear on the page" msgstr "Умови відображення кнопки \"Зберегти\" на сторінці" #: common/lib/xmodule/xmodule/capa_module.py +#: common/lib/xmodule/xmodule/library_content_module.py msgid "Show Reset Button" msgstr "Показати кнопку скидання" @@ -3062,7 +3067,6 @@ msgstr "" #: common/lib/xmodule/xmodule/course_module.py #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Handouts" msgstr "Роздаткові матеріали курсу" @@ -3808,6 +3812,12 @@ msgstr "" "Виберіть вид завдання, який має повертати бібліотека. Якщо вибрано «Будь-" "який», фільтри не застосовуються." +#: common/lib/xmodule/xmodule/library_content_module.py +msgid "" +"Determines whether a 'Reset Problems' button is shown, so users may reset " +"their answers and reshuffle selected items." +msgstr "" + #: common/lib/xmodule/xmodule/library_content_module.py msgid "This component is out of date. The library has new content." msgstr "Цей компонент застарів. Оновлено вміст бібліотеки." @@ -5544,7 +5554,6 @@ msgid "Blog" msgstr "Блог" #: lms/djangoapps/branding/api.py cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html #: themes/stanford-style/lms/templates/static_templates/about.html msgid "Contact Us" msgstr "Зв'яжіться з нами" @@ -5606,6 +5615,7 @@ msgstr "Політика щодо доступності матеріалів" #. Translators: This is a legal document users must agree to #. in order to register a new account. #: lms/djangoapps/branding/api.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "Terms of Service" msgstr "Умови надання послуг" @@ -6146,23 +6156,6 @@ msgstr "" "Користувач {username} ({email}) подав запит на повернення коштів. Для " "обробки цього запиту, будь ласка, перейдіть по посиланню (посиланням) нижче." -#: lms/djangoapps/course_goals/models.py -#: lms/templates/course_modes/track_selection.html -msgid "Earn a certificate" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Complete the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Explore the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Not sure yet" -msgstr "" - #: lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/body.html msgid "" "\n" @@ -6265,7 +6258,6 @@ msgid "Disabled" msgstr "" #: lms/djangoapps/course_home_api/outline/serializers.py -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html #, python-brace-format msgid "({number} Question)" msgid_plural "({number} Questions)" @@ -6281,6 +6273,11 @@ msgid "" "have questions." msgstr "" +#: lms/djangoapps/course_home_api/outline/views.py +#: lms/templates/courseware/course_about.html +msgid "Course is full" +msgstr "" + #: lms/djangoapps/course_home_api/outline/views.py msgid "'course_id' is required." msgstr "" @@ -6422,20 +6419,6 @@ msgstr "Дата запису на курс" msgid "Course starts" msgstr "" -#: lms/djangoapps/courseware/date_summary.py -msgid "Don't forget to add a calendar reminder!" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} on {course_start_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} at {course_start_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Course ends" msgstr "" @@ -6461,16 +6444,6 @@ msgstr "" "Курс знаходиться в архіві, тобто у вас є доступ до матеріалів курсу, але " "фактично курс завершений." -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} on {course_end_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} at {course_end_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "You lose all access to this course, including your progress." msgstr "" @@ -6488,23 +6461,6 @@ msgid "Day certificates will become available for passing verified learners." msgstr "" "Денні сертифікати стануть доступними для передачі підтвердженим учасникам." -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"If you have earned a certificate, you will be able to access it " -"{time_remaining_string} from now. You will also be able to view your " -"certificates on your {learner_profile_link}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html -msgid "Learner Profile" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -msgid "We are working on generating course certificates." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Upgrade to Verified Certificate" msgstr "Підвищити до рівня «Підтверджений сертифікат»" @@ -6538,32 +6494,6 @@ msgstr "" msgid "by {date}" msgstr "до {date}" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"Don't forget, you have {time_remaining_string} left to upgrade to a Verified" -" Certificate." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Don't forget to upgrade to a verified certificate by {localized_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"In order to qualify for a certificate, you must meet all course grading " -"requirements, upgrade before the course deadline, and successfully verify " -"your identity on {platform_name} if you have not done so " -"already.{button_panel}" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Upgrade ({upgrade_price})" -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Learn More" msgstr "Дізнатися більше" @@ -6634,6 +6564,24 @@ msgstr "Вимкнути динамічне оновлення дедлайна msgid "Disable the dynamic upgrade deadline for this organization." msgstr "Вимкнути динамічне оновлення дедлайна для цієї організації." +#: lms/djangoapps/courseware/models.py +msgid "Internal API Base URL" +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Financial Assistance Backend API Base URL." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "" +"Username created for Financial Assistance Backend, e.g. " +"financial_assistance_service_user." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Percentage of courses allowed to use edx-financial-assistance" +msgstr "" + #: lms/djangoapps/courseware/plugins.py lms/djangoapps/courseware/tabs.py #: lms/templates/peer_grading/peer_grading.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html @@ -6711,7 +6659,6 @@ msgstr "увійти" #: lms/djangoapps/courseware/views/index.py #: lms/djangoapps/courseware/views/views.py #: openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "register" msgstr "зареєструватися" @@ -6767,19 +6714,6 @@ msgstr "Вітаємо, ви атестовані для отримання се msgid "You've earned a certificate for this course." msgstr "Ви отримали сертіфікат з даного курсу." -#: lms/djangoapps/courseware/views/views.py -msgid "Certificate unavailable" -msgstr "Сертифікат не доступний" - -#: lms/djangoapps/courseware/views/views.py -#, python-brace-format -msgid "" -"You have not received a certificate because you do not have a current " -"{platform_name} verified identity." -msgstr "" -"Ви не отримали сертифікат, оскільки у вас немає перевіреної ідентифікації на" -" {platform_name}." - #: lms/djangoapps/courseware/views/views.py msgid "Your certificate will be available soon!" msgstr "" @@ -6794,20 +6728,31 @@ msgstr "" msgid "Your certificate is available" msgstr "Ваш сертифікат доступний" +#: lms/djangoapps/courseware/views/views.py +msgid "Certificate unavailable" +msgstr "Сертифікат не доступний" + +#: lms/djangoapps/courseware/views/views.py +#, python-brace-format +msgid "" +"You have not received a certificate because you do not have a current " +"{platform_name} verified identity." +msgstr "" +"Ви не отримали сертифікат, оскільки у вас немає перевіреної ідентифікації на" +" {platform_name}." + #: lms/djangoapps/courseware/views/views.py #, python-brace-format msgid "To see course content, {sign_in_link} or {register_link}." msgstr "Для перегляду змісту курсу, {sign_in_link} або {register_link}" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py #, python-brace-format msgid "{sign_in_link} or {register_link}." msgstr "" #: lms/djangoapps/courseware/views/views.py #: openedx/core/djangoapps/user_authn/templates/user_authn/edx_ace/passwordresetsuccess/email/body.html -#: openedx/features/course_experience/views/course_home_messages.py msgid "Sign in" msgstr "Увійти" @@ -6819,7 +6764,6 @@ msgid "" msgstr "" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "You must be enrolled in the course to see course content." msgstr "Ви повинні записатися на курс аби бачити контент курсу." @@ -6942,6 +6886,29 @@ msgstr "" msgid "Good" msgstr "Добре" +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#, python-format +msgid "" +"\n" +" %(course_name)s: Reported content awaits review\n" +" " +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +msgid "Go to Discussion" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +#, python-format +msgid "%(course_name)s: Reported content awaits review" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/subject.txt +#, python-format +msgid " %(course_name)s %(course_id)s moderator content for review " +msgstr "" + #: lms/djangoapps/discussion/templates/discussion/edx_ace/responsenotification/email/body.html #, python-format, python-brace-format msgid "%(comment_username)s replied to {start_tag}%(thread_title)s{end_tag}:" @@ -7282,10 +7249,13 @@ msgstr "Когорта" msgid "Team" msgstr "Команда" +#. Translators: This label appears above a field +#. which allows the user to input the city in which they live. #. Translators: This label appears above a field on the registration form #. which allows the user to input the city in which they live. #: lms/djangoapps/instructor/views/api.py #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "City" msgstr "Місто" @@ -8113,7 +8083,6 @@ msgstr " (з {total})" #: lms/templates/learner_dashboard/programs.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Programs" msgstr "Програми" @@ -9051,7 +9020,6 @@ msgstr "" #: lms/templates/courseware/course_about.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "View Course" msgstr "Переглянути курс" @@ -9679,7 +9647,6 @@ msgstr "Перейти на домашню сторінку %(platform_name)s" #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Courses" msgstr "Курси" @@ -10568,7 +10535,6 @@ msgid "Student" msgstr "Студент" #: openedx/core/djangoapps/embargo/forms.py -#: openedx/core/djangoapps/verified_track_content/forms.py msgid "COURSE NOT FOUND. Please check that the course ID is valid." msgstr "КУРС НЕ ЗНАЙДЕНО. Будь ласка, перевірте, що ID курсу є дійсним." @@ -10628,6 +10594,10 @@ msgstr "Занести до білого списку країну {country} д msgid "Blacklist {country} for {course}" msgstr "Занести до чорного списку країну {country} для курсу {course}" +#: openedx/core/djangoapps/learner_pathway/apps.py +msgid "Learner Pathways" +msgstr "" + #: openedx/core/djangoapps/oauth_dispatch/models.py msgid "" "Comma-separated list of scopes that this application will be allowed to " @@ -11151,6 +11121,14 @@ msgstr "" msgid "Enter your full name." msgstr "Введіть Ваше ім'я та призвище." +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your first name." +msgstr "" + +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your last name." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "The email addresses do not match." msgstr "Електронні адреси не збігаються." @@ -11175,6 +11153,10 @@ msgstr "Введіть Вашу професію." msgid "Enter your specialty." msgstr "Введіть Вашу спеціальність." +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your state." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "Enter your city." msgstr "Введіть своє місто." @@ -11216,24 +11198,39 @@ msgstr "" msgid "The '{field_name}' field cannot be edited." msgstr "Поле '{field_name}' не може бути відредаговано." +#: openedx/core/djangoapps/user_api/accounts/api.py +#: openedx/core/djangoapps/user_authn/views/registration_form.py +msgid "Enter a valid name" +msgstr "" + +#. Translators: This label appears above a field which allows the +#. user to input the First Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "First Name" msgstr "Ім'я" +#. Translators: This label appears above a field which allows the +#. user to input the Last Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "Last Name" msgstr "Прізвище" +#. Translators: This label appears above a field +#. which allows the user to input the State/Province/Region in which they +#. live. #. Translators: This label appears above a field on the registration form #. which allows the user to input the State/Province/Region in which they #. live. #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "State/Province/Region" msgstr "Штат/регіон/область" @@ -11271,9 +11268,12 @@ msgid "Job Title" msgstr "Назва посади" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# +#. Translators: This label appears above a field +#. meant to hold the user's mailing address. #. Translators: This label appears above a field on the registration form #. meant to hold the user's mailing address. #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: lms/templates/signup_modal.html msgid "Mailing address" @@ -11554,7 +11554,6 @@ msgstr "" #: openedx/core/djangoapps/user_authn/views/login.py #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html #: themes/stanford-style/lms/templates/register-form.html msgid "Register" msgstr "" @@ -11684,10 +11683,6 @@ msgstr "Наданий access_token неприпустимий." msgid "Full Name cannot contain the following characters: < >" msgstr "Повне им'я не може містити наступних символів: < >" -#: openedx/core/djangoapps/user_authn/views/registration_form.py -msgid "Enter a valid name" -msgstr "" - #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "A properly formatted e-mail is required" msgstr "Потрібен e-mail встановленої форми" @@ -11870,10 +11865,6 @@ msgstr "{header_open}{title}{header_close}" msgid "Dismiss" msgstr "Відхилити" -#: openedx/core/djangoapps/verified_track_content/models.py -msgid "The course key for the course we would like to be auto-cohorted." -msgstr "" - #: openedx/core/djangoapps/video_pipeline/models.py msgid "Oauth client name of VEM service." msgstr "" @@ -12153,51 +12144,6 @@ msgstr "" msgid "Updates" msgstr "Оновлення" -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{sign_in_link} or {register_link} and then enroll in this course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Welcome to {course_display_name}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"You must be enrolled in the course to see course content. Please contact " -"your degree administrator or {platform_name} Support if you have questions." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"{open_enroll_link}Enroll now{close_enroll_link} to access the full course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"To start, set a course goal by selecting the option below that best " -"describes your learning plan. {goal_options_container}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {goal_text}" -msgstr "" - #: openedx/features/discounts/admin.py msgid "" "These define the context to disable lms-controlled discounts on. If no " @@ -12303,12 +12249,10 @@ msgid "Continue" msgstr "Продовжити" #: openedx/features/personalized_learner_schedules/call_to_action.py -#: lms/templates/dates_banner.html msgid "Shift due dates" msgstr "" #: openedx/features/personalized_learner_schedules/call_to_action.py -#: lms/templates/dates_banner.html msgid "" "It looks like you missed some important deadlines based on our suggested " "schedule." @@ -13344,11 +13288,6 @@ msgstr "Назва курсу" msgid "Course Number" msgstr "Номер Курсу" -#: cms/templates/course_outline.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Course Outline" -msgstr "" - #: cms/templates/html_error.html lms/templates/course_modes/error.html #: lms/templates/module-error.html msgid "Error:" @@ -13434,62 +13373,10 @@ msgstr "Обліковий запис" #: lms/templates/header/navbar-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: lms/templates/static_templates/help.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -#: wiki/plugins/help/wiki_plugin.py +#: lms/templates/static_templates/help.html wiki/plugins/help/wiki_plugin.py msgid "Help" msgstr "Допомога" -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Looking for help with {studio_name}?" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Hide {studio_name} Help" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "{studio_name} Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Access documentation on http://docs.edx.org" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101: Overview of Creating an edX Course" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX: Creating a Course with edX Studio" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Send an email to {email}" -msgstr "" - #: cms/templates/widgets/tabs-aggregator.html #: lms/templates/courseware/static_tab.html #: lms/templates/courseware/tab-view.html @@ -13665,19 +13552,18 @@ msgstr "Переглянути усі курси" #: lms/templates/dashboard.html lms/templates/header/user_dropdown.html #: lms/templates/user_dropdown.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Dashboard" msgstr "Панель управління" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "results successfully populated," msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Click to load all enrolled courses" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "You are not enrolled in any courses yet." msgstr "" @@ -13685,7 +13571,6 @@ msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore courses" msgstr "Обрати курси" @@ -13694,16 +13579,15 @@ msgstr "Обрати курси" msgid "Activate your account!" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Course-loading errors" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Search Your Courses" msgstr "" #: lms/templates/courseware/courseware.html lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Clear search" msgstr "" @@ -13726,15 +13610,15 @@ msgstr "" msgid "Continue to {platform_name}" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Email Settings for {course_number}" msgstr "Налаштування електронної пошти для {course_number}" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Receive course emails" msgstr "Отримувати листи від курсу" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Save Settings" msgstr "Зберегти налаштування" @@ -13743,83 +13627,9 @@ msgstr "Зберегти налаштування" #: lms/templates/dashboard/_dashboard_entitlement_actions.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/instructor/instructor_dashboard_2/membership.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "Unenroll" msgstr "Відписатися від курсу" -#: lms/templates/dates_banner.html -msgid "" -"It looks like you missed some important deadlines based on our suggested " -"schedule. " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future by visiting " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" Don't worry—you won't lose any of the progress you've made when you shift " -"your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future. Don't worry—you won't lose any of the " -"progress you've made when you shift your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "You are auditing this course," -msgstr "" - -#: lms/templates/dates_banner.html -msgid " which means that you are unable to participate in graded assignments." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. Graded assignments and schedule adjustment are available to " -"Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. To complete graded assignments as part of this course and shift " -"the past due assignments into the future, you can upgrade today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Upgrade to shift due dates" -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Graded assignments are available to Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" To complete graded assignments as part of this course, you can upgrade " -"today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "We've built a suggested schedule to help you stay on track." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"But don't worry—it's flexible so you can learn at your own pace. If you " -"happen to fall behind on our suggested dates, you'll be able to adjust them " -"to keep yourself on track." -msgstr "" - #: lms/templates/email_change_failed.html lms/templates/email_exists.html msgid "E-mail change failed" msgstr "" @@ -14144,10 +13954,6 @@ msgstr "" msgid "You are now viewing the course as {i_start}{user_name}{i_end}." msgstr "" -#: lms/templates/preview_menu.html -msgid "View in the new experience" -msgstr "" - #: lms/templates/preview_menu.html msgid "View in Studio" msgstr "" @@ -14268,9 +14074,7 @@ msgstr "" msgid "Sequence" msgstr "" -#: lms/templates/courseware/dates.html lms/templates/seq_module.html -#: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html +#: lms/templates/seq_module.html lms/templates/vert_module.html msgid "Completed" msgstr "" @@ -14538,7 +14342,6 @@ msgid "" msgstr "" #: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "{subsection_format} due {{date}}" msgstr "" @@ -14550,6 +14353,10 @@ msgstr "" msgid "Past due" msgstr "" +#: lms/templates/vert_module.html +msgid "Reset Problems" +msgstr "" + #: lms/templates/video.html msgid "Loading video player" msgstr "" @@ -15609,7 +15416,6 @@ msgid "Download student grades" msgstr "" #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Print or share your certificate:" msgstr "" @@ -15623,7 +15429,6 @@ msgstr "Опублікувати у Facebook" #: lms/templates/certificates/_accomplishment-banner.html #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Twitter" msgstr "" @@ -15632,7 +15437,6 @@ msgid "Tweet this Accomplishment. Pop up window." msgstr "Поширити це досягнення у Twitter. З'явиться додаткове вікно." #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Add to LinkedIn Profile" msgstr "" @@ -15727,40 +15531,31 @@ msgstr "" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue the Verified Track" msgstr "" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue a Verified Certificate" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Enroll In {course_name} | Choose Your Track" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Sorry, there was an error when trying to enroll you" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with the Verified Track" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with a Verified Certificate" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Become eligible for academic credit and highlight your new skills and " "knowledge with a verified certificate. Use this valuable credential to " @@ -15769,59 +15564,50 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of the Verified Track" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Eligible for credit:{b_end} Receive academic credit after " "successfully completing the course" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Unlimited Course Access: {b_end}Learn at your own pace, and access " "materials anytime to brush up on what you've learned." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Graded Assignments: {b_end}Build your skills through graded " "assignments and projects." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily Sharable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of a Verified Certificate" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official:{b_end} Receive an instructor-signed certificate with the " "institution's logo" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable:{b_end} Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Highlight your new knowledge and skills with a verified certificate. Use " "this valuable credential to improve your job prospects and advance your " @@ -15829,45 +15615,38 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official: {b_end}Receive an instructor-signed certificate with the " "institution's logo" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Motivating: {b_end}Give yourself an additional incentive to " "complete the course" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course" msgstr "Безкоштовне прослуховування курсу" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course (No Certificate)" msgstr "Безкоштовне прослуховування курсу (сертифікат не видається)" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded assignments," @@ -15875,7 +15654,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded " @@ -15883,7 +15661,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include unlimited course " @@ -15891,7 +15668,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums. {b_start}Please note that this " @@ -15975,6 +15751,10 @@ msgstr "" msgid "Choose a path for your course in" msgstr "" +#: lms/templates/course_modes/track_selection.html +msgid "Earn a certificate" +msgstr "" + #: lms/templates/course_modes/track_selection.html msgid "" "Studies show that those who choose this option are {start_bold}more engaged" @@ -15999,7 +15779,6 @@ msgstr "" #: lms/templates/courseware/accordion.html #: lms/templates/courseware/progress.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "due {date}" msgstr "" @@ -16008,7 +15787,6 @@ msgid "{section_format} due {{date}}" msgstr "" #: lms/templates/courseware/accordion.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "This content is graded" msgstr "" @@ -16020,10 +15798,6 @@ msgstr "" msgid "You are enrolled in this course" msgstr "" -#: lms/templates/courseware/course_about.html -msgid "Course is full" -msgstr "" - #: lms/templates/courseware/course_about.html msgid "Enrollment in this course is by invitation only" msgstr "" @@ -16179,30 +15953,6 @@ msgstr "" msgid "Your score is {current_score}%. You have passed the entrance exam." msgstr "" -#: lms/templates/courseware/dates.html lms/templates/courseware/syllabus.html -msgid "{course.display_number_with_default} Course Info" -msgstr "{course.display_number_with_default} Інформація про курс" - -#: lms/templates/courseware/dates.html -msgid "Important Dates" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Today" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Verified Only" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Due Next" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Not yet released" -msgstr "" - #: lms/templates/courseware/gradebook.html msgid "Gradebook" msgstr "" @@ -16252,8 +16002,6 @@ msgstr "" #: lms/templates/courseware/info.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "Resume Course" msgstr "Продовжити курс" @@ -16270,7 +16018,6 @@ msgid "Handout Navigation" msgstr "" #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Tools" msgstr "" @@ -16516,6 +16263,10 @@ msgstr "" msgid "No problem scores in this section" msgstr "Немає балів за виконання у цьому розділі" +#: lms/templates/courseware/syllabus.html +msgid "{course.display_number_with_default} Course Info" +msgstr "{course.display_number_with_default} Інформація про курс" + #: lms/templates/courseware/welcome-back.html msgid "" "You were most recently in {section_link}. If you're done with that, choose " @@ -16746,7 +16497,6 @@ msgid "Share {course_name} on Facebook" msgstr "" #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Facebook" msgstr "" @@ -16794,6 +16544,12 @@ msgid "" "showcase on your resumé." msgstr "" +#: lms/templates/dashboard/_dashboard_course_listing.html +msgid "" +"{start_bold}Get the most out of your course!{end_bold} Upgrade to earn a " +"{link_start}verified certificate{link_end} to showcase on your resumé." +msgstr "" + #: lms/templates/dashboard/_dashboard_course_listing.html msgid "Upgrade" msgstr "" @@ -17569,7 +17325,6 @@ msgid "" msgstr "" #: lms/templates/header/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Discover New" msgstr "" @@ -17583,7 +17338,6 @@ msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "How it Works" msgstr "" @@ -19040,7 +18794,6 @@ msgid "" msgstr "" #: lms/templates/learner_dashboard/_dashboard_navigation_courses.html -#: themes/edx.org/lms/templates/dashboard.html msgid "My Courses" msgstr "Мої курси" @@ -19450,13 +19203,10 @@ msgid "Skeleton Page" msgstr "" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html msgid "Search the course" msgstr "" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Start Course" msgstr "" @@ -19628,36 +19378,6 @@ msgstr "" msgid "View all course dates" msgstr "" -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Goal: " -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Edit your course goal:" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Pursue a verified certificate" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "" -"Sample verified certificate with your name, the course title, the logo of " -"the institution and the signatures of the instructors for this course." -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Upgrade ({price})" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Expand All" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Prerequisite: " -msgstr "" - #: openedx/features/course_experience/templates/course_experience/course-sock-fragment.html msgid "Learn About Verified Certificates" msgstr "" @@ -19738,18 +19458,6 @@ msgstr "" msgid "This course does not have any updates." msgstr "" -#: openedx/features/course_experience/templates/course_experience/latest-update-fragment.html -msgid "Latest Update" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/welcome-message-fragment.html -msgid "Show More" -msgstr "" - -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -msgid "Search Results" -msgstr "" - #. Translators: this section lists all the third-party authentication #. providers #. (for example, Google and LinkedIn) the user can link with or unlink from @@ -19793,10 +19501,13 @@ msgid "You haven't earned any certificates yet." msgstr "" #: openedx/features/learner_profile/templates/learner_profile/learner-achievements-fragment.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore New Courses" msgstr "Обрати нові курси" +#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html +msgid "Learner Profile" +msgstr "" + #: openedx/features/learner_profile/templates/learner_profile/learner_profile.html msgid "View My Records" msgstr "" @@ -19814,138 +19525,6 @@ msgstr "" msgid "An error occurred. Try loading the page again." msgstr "" -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "" -"Access Course Staff Support on the Partner Portal to submit or review " -"support tickets" -msgstr "" - -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Partner Portal" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "" -"Browse recently launched courses and see what's new in your favorite " -"subjects." -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Take advantage of free coaching!" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Get Started" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Page Footer" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "edX Home Page" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Connect" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "© {year} edX Inc. All rights reserved." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "About edX Verified Certificates" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "" -"An edX Verified Certificate signifies that the learner has agreed to abide " -"by the edX honor code and completed all of the required tasks of this course" -" under its guidelines, as well as having their photo ID checked to verify " -"their identity." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "About edX" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "" -"{link_start}edX{link_end} offers interactive online classes and MOOCs from " -"the world's best universities, including MIT, Harvard, Berkeley, University " -"of Texas, and many others. edX is a mission driven initiative created by " -"founding partners Harvard and MIT." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Congratulations, {user_name}!" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "" -"You worked hard to earn your certificate from " -"{accomplishment_copy_course_org} {dash} share it with colleagues, friends, " -"and family to get the word out about what you mastered in " -"{accomplishment_course_title}." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Share this certificate on Facebook (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Tweet this certificate (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Add this certificate to your LinkedIn profile (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print this certificate" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "edX Inc." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "" -"All rights reserved except where noted. edX, Open edX and the edX and Open " -"edX logos are registered trademarks of edX Inc." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end}EdX relies on verified certificates to " -"help fund affordable education to everyone globally." -msgstr "" - -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end} EdX, a mission driven initiative, " -"relies on verified certificates to help fund free education for everyone " -"globally" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Find Courses" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Schools & Partners" -msgstr "" - #: themes/red-theme/lms/templates/footer.html msgid "" "{tos_link_start}Terms of Service{tos_link_end} and {honor_link_start}Honor " @@ -20592,6 +20171,10 @@ msgstr "" "в розкладі та відповісти на питання студента. Додавання чи редагування " "оновлень у форматі HTML." +#: cms/templates/course_outline.html +msgid "Course Outline" +msgstr "" + #: cms/templates/course_outline.html msgid "" "This course was created as a re-run. Some manual configuration is needed." @@ -23412,6 +22995,26 @@ msgstr "" msgid "Label" msgstr "" +#: cms/templates/widgets/sock.html +msgid "Looking for help with {studio_name}?" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "Hide {studio_name} Help" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "{studio_name} Documentation" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Access documentation on http://docs.edx.org" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "edX Documentation" +msgstr "" + #: cms/templates/widgets/sock_links.html msgid "Access the Open edX Portal" msgstr "" @@ -23420,6 +23023,26 @@ msgstr "" msgid "Open edX Portal" msgstr "" +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101: Overview of Creating an edX Course" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX: Creating a Course with edX Studio" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Send an email to {email}" +msgstr "" + #: cms/templates/widgets/user_dropdown.html msgid "Currently signed in as:" msgstr "" diff --git a/conf/locale/uk/LC_MESSAGES/djangojs.mo b/conf/locale/uk/LC_MESSAGES/djangojs.mo index d803a09f29880c94e3bd4836737e63f7d764ff4e..eca69165017fa4c130b87cd86937dfb4cdeea415 100644 GIT binary patch delta 25 hcmaEOgzMoEu7)j)leL*G^bFdkX)|u0rpLi3GV;^ delta 25 hcmaEOgzMoEu7)j)leL*G^$gpmX)|u0rpL)3Gn~` diff --git a/conf/locale/uk/LC_MESSAGES/djangojs.po b/conf/locale/uk/LC_MESSAGES/djangojs.po index 7a643d40eb..8f5d53a286 100644 --- a/conf/locale/uk/LC_MESSAGES/djangojs.po +++ b/conf/locale/uk/LC_MESSAGES/djangojs.po @@ -102,7 +102,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Andrey Kryachko, 2018\n" "Language-Team: Ukrainian (http://www.transifex.com/open-edx/edx-platform/language/uk/)\n" @@ -111,7 +111,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js #: cms/static/js/views/video_transcripts.js @@ -157,7 +157,6 @@ msgstr "Видалити" #: common/lib/xmodule/xmodule/js/src/html/edit.js #: common/static/common/js/components/utils/view_utils.js #: lms/static/js/Markdown.Editor.js -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx #: lms/static/js/student_account/components/StudentAccountDeletionModal.jsx #: cms/templates/js/add-xblock-component-menu-problem.underscore #: cms/templates/js/add-xblock-component-menu.underscore @@ -329,6 +328,14 @@ msgstr "Помилка" msgid "Updating with latest library content" msgstr "Оновлення за допомогою найновішого вмісту бібліотеки" +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Loading..." +msgstr "" + +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Selected blocks" +msgstr "" + #: common/lib/xmodule/xmodule/assets/library_source_block/public/js/library_source_block.js msgid "Unable to update settings" msgstr "" @@ -1246,6 +1253,7 @@ msgstr "Нове вікно" #. Translators: this is a message from the raw HTML editor displayed in the #. browser when a user needs to edit HTML #: common/lib/xmodule/xmodule/js/src/html/edit.js +#: lms/static/js/demographics_collection/Wizard.jsx msgid "Next" msgstr "Наступний" @@ -2017,6 +2025,10 @@ msgstr "Переглянути підлеглі елементи" msgid "Navigate up" msgstr "" +#: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx +msgid "Browsing" +msgstr "" + #: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx msgid "Select" msgstr "" @@ -2591,10 +2603,30 @@ msgid "" "within the Discussion Forum where the Course Staff can directly respond." msgstr "" +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Details" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "the more quickly and helpfully we can respond!" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Create Support Ticket" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "What can we help you with, {username}?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx msgid "Sign in to {platform} so we can help you better." msgstr "Увійдіть до {platform}, щоб ми змогли вам краще допомогти." +#: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx +msgid "Need help logging in?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/single_support_form.jsx msgid "" "Select a course or select \"Not specific to a course\" for your support " @@ -3449,20 +3481,52 @@ msgstr "" msgid "Get started" msgstr "" -#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx -msgid "Section {currentPage} of {totalPages}" -msgstr "" - #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "Help make edX better for everyone!" msgstr "" +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Why does edX collect this information?" +msgstr "" + #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "" -"Welcome to edX! Before you get started, please take a few minutes to fill-in" -" the additional information below to help us understand a bit more about " -"your background. You can always edit this information later in Account " -"Settings." +"An error occurred while attempting to retrieve or save the information " +"below. Please try again later." +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What was the total combined income, during the last 12 months, of all " +"members of your family? " +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"Have you ever served on active duty in the U.S. Armed Forces, Reserves, or " +"National Guard?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What is the highest level of education that you have achieved so far?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What is the highest level of education that any of your parents or guardians" +" have achieved?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Select employment status" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you currently work in?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you want to work in?" msgstr "" #: lms/static/js/demographics_collection/MultiselectDropdown.jsx @@ -3477,6 +3541,22 @@ msgstr "" msgid "close questionnaire" msgstr "" +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Return to my dashboard" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "next page" +msgstr "" + #: lms/static/js/discovery/views/search_form.js #, javascript-format msgid "Viewing %s course" @@ -3800,27 +3880,6 @@ msgstr "Когорти увімкнені" msgid "Cohorts Disabled" msgstr "Когорти вимкнені" -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course uses automatic cohorting for verified track learners. You cannot" -" disable cohorts, and you cannot rename the manual cohort named " -"'{verifiedCohortName}'. To change the configuration for verified track " -"cohorts, contact your edX partner manager." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" the required cohort does not exist. You must create a manually-assigned " -"cohort named '{verifiedCohortName}' for the feature to work." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" cohorts are disabled. You must enable cohorts for the feature to work." -msgstr "" - #: lms/static/js/instructor_dashboard/certificates.js msgid "Allow students to generate certificates for this course?" msgstr "Дозволити студентам генерувати сертифікати для цього курсу?" @@ -4577,10 +4636,6 @@ msgstr "" "Посилання генеруються на вимогу та зникнуть протягом 5 хвилин через " "чутливість інформації про оцінки студентів." -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx -msgid "You have access to the {enterpriseName} dashboard" -msgstr "" - #: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx msgid "" "To access the courses available to you through {enterpriseName}, visit the " @@ -5490,44 +5545,6 @@ msgstr "Загальна оцінка " msgid "Bookmark this page" msgstr "Додати цю сторінку до закладок" -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "Thank you for setting your course goal to {goal}!" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "" -"There was an error in setting your goal, please reload the page and try " -"again." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "You have successfully updated your goal." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "There was an error updating your goal." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseOutline.js -#: lms/templates/ccx/schedule.underscore -msgid "Expand All" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseOutline.js -#: lms/templates/ccx/schedule.underscore -msgid "Collapse All" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show More" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show Less" -msgstr "" - #: openedx/features/course_search/static/course_search/js/views/search_results_view.js msgid "{total_results} result found for \"{search_term}\"" msgid_plural "{total_results} results found for \"{search_term}\"" @@ -5821,6 +5838,31 @@ msgstr "Помилка при імпорті курсу" msgid "There was an error with the upload" msgstr "Помилка завантаження" +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Organization:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Number:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Run:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "(Read-only)" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Re-run Course" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +#: cms/templates/js/show-textbook.underscore +msgid "View Live" +msgstr "" + #: cms/static/js/maintenance/force_publish_course.js msgid "Internal Server Error." msgstr "Помилка сервера" @@ -7380,10 +7422,6 @@ msgstr "" msgid "follow this post" msgstr "" -#: common/static/common/templates/discussion/templates.underscore -msgid "post anonymously" -msgstr "" - #: common/static/common/templates/discussion/templates.underscore msgid "post anonymously to classmates" msgstr "" @@ -7830,6 +7868,14 @@ msgstr "" msgid "This catalog's courses:" msgstr "" +#: lms/templates/ccx/schedule.underscore +msgid "Expand All" +msgstr "" + +#: lms/templates/ccx/schedule.underscore +msgid "Collapse All" +msgstr "" + #: lms/templates/ccx/schedule.underscore msgid "Start Date" msgstr "" @@ -7913,6 +7959,14 @@ msgid "" "before you select \"End My Exam\"." msgstr "" +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show More" +msgstr "" + +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show Less" +msgstr "" + #: lms/templates/discovery/course_card.underscore msgid "LEARN MORE" msgstr "Дізнатися більше" @@ -10581,10 +10635,6 @@ msgstr "" msgid "PDF Chapters" msgstr "" -#: cms/templates/js/show-textbook.underscore -msgid "View Live" -msgstr "" - #: cms/templates/js/signatory-details.underscore #: cms/templates/js/signatory-editor.underscore msgid "Signatory" diff --git a/conf/locale/vi/LC_MESSAGES/django.mo b/conf/locale/vi/LC_MESSAGES/django.mo index 27b7852d2239abfd80c0f4c2c36e885061b68486..83cb940ba079c89d68b31577b10e17622ad04e62 100644 GIT binary patch delta 31 lcmX^6Rq*Ur!G;#bElh3h%ochE?VavSK+L?o)1Ae|7y#0R3w;0p delta 31 lcmX^6Rq*Ur!G;#bElh3h%$9nF?VavSK+L?o)1Ae|7y#0x3x5Cr diff --git a/conf/locale/vi/LC_MESSAGES/django.po b/conf/locale/vi/LC_MESSAGES/django.po index c18f602160..1743737fc8 100644 --- a/conf/locale/vi/LC_MESSAGES/django.po +++ b/conf/locale/vi/LC_MESSAGES/django.po @@ -198,7 +198,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:44+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Le Minh Tri , 2020\n" "Language-Team: Vietnamese (https://www.transifex.com/open-edx/teams/6205/vi/)\n" @@ -207,7 +207,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #: lms/djangoapps/discussion/templates/discussion/discussion_profile_page.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html @@ -746,6 +746,10 @@ msgstr "" msgid "Could not enroll" msgstr "" +#: common/djangoapps/student/views/management.py +msgid "Unenrollment is currently disabled" +msgstr "" + #: common/djangoapps/student/views/management.py msgid "You are not enrolled in this course" msgstr "" @@ -1783,7 +1787,6 @@ msgstr "" #. in #. to the site. #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html #: themes/stanford-style/lms/templates/register-form.html msgid "or" msgstr "hoặc" @@ -2005,7 +2008,6 @@ msgid "Never" msgstr "" #: common/lib/xmodule/xmodule/capa_module.py -#: lms/templates/courseware/dates.html msgid "Past Due" msgstr "" @@ -2071,6 +2073,7 @@ msgid "Whether to force the save button to appear on the page" msgstr "" #: common/lib/xmodule/xmodule/capa_module.py +#: common/lib/xmodule/xmodule/library_content_module.py msgid "Show Reset Button" msgstr "" @@ -2767,7 +2770,6 @@ msgid "" msgstr "" #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Handouts" msgstr " Tài liệu khoá học" @@ -3404,6 +3406,12 @@ msgid "" " no filtering is applied." msgstr "" +#: common/lib/xmodule/xmodule/library_content_module.py +msgid "" +"Determines whether a 'Reset Problems' button is shown, so users may reset " +"their answers and reshuffle selected items." +msgstr "" + #: common/lib/xmodule/xmodule/library_content_module.py msgid "This component is out of date. The library has new content." msgstr "" @@ -4497,8 +4505,7 @@ msgstr "" #: lms/templates/instructor/instructor_dashboard_2/invalidate_registration_code_modal.html #: lms/templates/instructor/instructor_dashboard_2/set_course_mode_price_modal.html #: lms/templates/modal/_modal-settings-language.html -#: lms/templates/signup_modal.html themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html +#: lms/templates/signup_modal.html msgid "Close" msgstr "Đóng" @@ -4904,7 +4911,6 @@ msgstr "" #. Translators: 'Open edX' is a brand, please keep this untranslated. See #. http://openedx.org for more information. #: cms/templates/widgets/footer.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html #: themes/red-theme/lms/templates/footer.html msgid "Powered by Open edX" msgstr "Powered by Open edX" @@ -4914,7 +4920,6 @@ msgid "Blog" msgstr "Blog" #: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html #: themes/stanford-style/lms/templates/static_templates/about.html msgid "Contact Us" msgstr "Liên Hệ" @@ -4960,13 +4965,11 @@ msgid "News" msgstr "Tin Tức" #: lms/djangoapps/branding/api.py lms/djangoapps/certificates/views/webview.py -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html msgid "Terms of Service & Honor Code" msgstr "" #: cms/templates/widgets/footer.html #: lms/templates/static_templates/privacy.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html #: themes/red-theme/lms/templates/footer.html #: themes/stanford-style/lms/templates/footer.html #: themes/stanford-style/lms/templates/static_templates/tos.html @@ -5479,23 +5482,6 @@ msgid "" "this request, please visit the link(s) below." msgstr "" -#: lms/djangoapps/course_goals/models.py -#: lms/templates/course_modes/track_selection.html -msgid "Earn a certificate" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Complete the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Explore the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Not sure yet" -msgstr "" - #: lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/body.html msgid "" "\n" @@ -5595,7 +5581,6 @@ msgid "Disabled" msgstr "" #: lms/djangoapps/course_home_api/outline/serializers.py -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html #, python-brace-format msgid "({number} Question)" msgid_plural "({number} Questions)" @@ -5608,6 +5593,10 @@ msgid "" "have questions." msgstr "" +#: lms/templates/courseware/course_about.html +msgid "Course is full" +msgstr "Khóa học đã đầy" + #: lms/djangoapps/course_home_api/outline/views.py msgid "'course_id' is required." msgstr "" @@ -5750,20 +5739,6 @@ msgstr "" msgid "Course starts" msgstr "" -#: lms/djangoapps/courseware/date_summary.py -msgid "Don't forget to add a calendar reminder!" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} on {course_start_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} at {course_start_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Course ends" msgstr "" @@ -5787,16 +5762,6 @@ msgid "" " no longer active." msgstr "" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} on {course_end_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} at {course_end_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "You lose all access to this course, including your progress." msgstr "" @@ -5813,22 +5778,6 @@ msgstr "" msgid "Day certificates will become available for passing verified learners." msgstr "" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"If you have earned a certificate, you will be able to access it " -"{time_remaining_string} from now. You will also be able to view your " -"certificates on your {learner_profile_link}." -msgstr "" - -#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html -msgid "Learner Profile" -msgstr "Hồ sơ cá nhân học viên" - -#: lms/djangoapps/courseware/date_summary.py -msgid "We are working on generating course certificates." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Upgrade to Verified Certificate" msgstr "" @@ -5858,35 +5807,8 @@ msgstr "" msgid "by {date}" msgstr "" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"Don't forget, you have {time_remaining_string} left to upgrade to a Verified" -" Certificate." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Don't forget to upgrade to a verified certificate by {localized_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"In order to qualify for a certificate, you must meet all course grading " -"requirements, upgrade before the course deadline, and successfully verify " -"your identity on {platform_name} if you have not done so " -"already.{button_panel}" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Upgrade ({upgrade_price})" -msgstr "" - #: cms/templates/group_configurations.html #: lms/templates/courseware/program_marketing.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Learn More" msgstr "Tìm hiểu thêm" @@ -5946,6 +5868,24 @@ msgstr "" msgid "Disable the dynamic upgrade deadline for this organization." msgstr "" +#: lms/djangoapps/courseware/models.py +msgid "Internal API Base URL" +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Financial Assistance Backend API Base URL." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "" +"Username created for Financial Assistance Backend, e.g. " +"financial_assistance_service_user." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Percentage of courses allowed to use edx-financial-assistance" +msgstr "" + #: lms/templates/peer_grading/peer_grading.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html msgid "Progress" @@ -6016,7 +5956,6 @@ msgstr "" #: lms/djangoapps/courseware/views/index.py #: lms/djangoapps/courseware/views/views.py #: openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "register" msgstr "" @@ -6066,17 +6005,6 @@ msgstr "" msgid "You've earned a certificate for this course." msgstr "" -#: lms/djangoapps/courseware/views/views.py -msgid "Certificate unavailable" -msgstr "" - -#: lms/djangoapps/courseware/views/views.py -#, python-brace-format -msgid "" -"You have not received a certificate because you do not have a current " -"{platform_name} verified identity." -msgstr "" - #: lms/djangoapps/courseware/views/views.py msgid "Your certificate will be available soon!" msgstr "" @@ -6091,20 +6019,29 @@ msgstr "" msgid "Your certificate is available" msgstr "" +#: lms/djangoapps/courseware/views/views.py +msgid "Certificate unavailable" +msgstr "" + +#: lms/djangoapps/courseware/views/views.py +#, python-brace-format +msgid "" +"You have not received a certificate because you do not have a current " +"{platform_name} verified identity." +msgstr "" + #: lms/djangoapps/courseware/views/views.py #, python-brace-format msgid "To see course content, {sign_in_link} or {register_link}." msgstr "" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py #, python-brace-format msgid "{sign_in_link} or {register_link}." msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html msgid "Sign in" msgstr "Đăng nhập" @@ -6116,7 +6053,6 @@ msgid "" msgstr "" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "You must be enrolled in the course to see course content." msgstr "" @@ -6231,6 +6167,29 @@ msgstr "" msgid "Good" msgstr "" +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#, python-format +msgid "" +"\n" +" %(course_name)s: Reported content awaits review\n" +" " +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +msgid "Go to Discussion" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +#, python-format +msgid "%(course_name)s: Reported content awaits review" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/subject.txt +#, python-format +msgid " %(course_name)s %(course_id)s moderator content for review " +msgstr "" + #: lms/djangoapps/discussion/templates/discussion/edx_ace/responsenotification/email/body.html #, python-format, python-brace-format msgid "%(comment_username)s replied to {start_tag}%(thread_title)s{end_tag}:" @@ -7307,7 +7266,6 @@ msgstr "" #: lms/templates/learner_dashboard/programs.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Programs" msgstr "Chương trình học" @@ -8161,7 +8119,6 @@ msgstr "" #: lms/templates/courseware/course_about.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "View Course" msgstr "Xem khóa học" @@ -8414,8 +8371,6 @@ msgstr "Xem trước Wiki" #: lms/templates/wiki/includes/cheatsheet.html lms/templates/dashboard.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/modal/_modal-settings-language.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "window open" msgstr "mở cửa sổ" @@ -8662,9 +8617,6 @@ msgstr "" #: lms/templates/courseware/courseware.html lms/templates/dashboard.html #: lms/templates/edxnotes/edxnotes.html lms/templates/index.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -#: themes/edx.org/lms/templates/dashboard.html #: themes/stanford-style/lms/templates/index.html msgid "Search" msgstr "Tìm kiếm" @@ -8757,7 +8709,6 @@ msgstr "" #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Courses" msgstr "Các khóa học" @@ -9601,7 +9552,6 @@ msgid "Student" msgstr "" #: openedx/core/djangoapps/embargo/forms.py -#: openedx/core/djangoapps/verified_track_content/forms.py msgid "COURSE NOT FOUND. Please check that the course ID is valid." msgstr "" @@ -9653,6 +9603,10 @@ msgstr "" msgid "Blacklist {country} for {course}" msgstr "" +#: openedx/core/djangoapps/learner_pathway/apps.py +msgid "Learner Pathways" +msgstr "" + #: openedx/core/djangoapps/oauth_dispatch/models.py msgid "" "Comma-separated list of scopes that this application will be allowed to " @@ -9981,7 +9935,6 @@ msgid "" msgstr "" #: openedx/core/djangoapps/schedules/templates/schedules/edx_ace/upgradereminder/email/body.html -#: lms/templates/dates_banner.html msgid "Upgrade now" msgstr "" @@ -10129,6 +10082,14 @@ msgstr "" msgid "Enter your full name." msgstr "" +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your first name." +msgstr "" + +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your last name." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "The email addresses do not match." msgstr "" @@ -10153,6 +10114,10 @@ msgstr "" msgid "Enter your specialty." msgstr "" +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your state." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "Enter your city." msgstr "" @@ -10194,24 +10159,39 @@ msgstr "" msgid "The '{field_name}' field cannot be edited." msgstr "" +#: openedx/core/djangoapps/user_api/accounts/api.py +#: openedx/core/djangoapps/user_authn/views/registration_form.py +msgid "Enter a valid name" +msgstr "" + +#. Translators: This label appears above a field which allows the +#. user to input the First Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "First Name" msgstr "" +#. Translators: This label appears above a field which allows the +#. user to input the Last Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "Last Name" msgstr "" +#. Translators: This label appears above a field +#. which allows the user to input the State/Province/Region in which they +#. live. #. Translators: This label appears above a field on the registration form #. which allows the user to input the State/Province/Region in which they #. live. #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "State/Province/Region" msgstr "" @@ -10492,7 +10472,6 @@ msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html #: themes/stanford-style/lms/templates/register-form.html msgid "Register" msgstr "Đăng ký" @@ -10611,10 +10590,6 @@ msgstr "" msgid "Full Name cannot contain the following characters: < >" msgstr "" -#: openedx/core/djangoapps/user_authn/views/registration_form.py -msgid "Enter a valid name" -msgstr "" - #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "A properly formatted e-mail is required" msgstr "" @@ -10782,15 +10757,9 @@ msgstr "" #: openedx/core/djangoapps/util/user_messages.py #: cms/templates/course_outline.html cms/templates/index.html -#: openedx/features/course_experience/templates/course_experience/latest-update-fragment.html -#: openedx/features/course_experience/templates/course_experience/welcome-message-fragment.html msgid "Dismiss" msgstr "" -#: openedx/core/djangoapps/verified_track_content/models.py -msgid "The course key for the course we would like to be auto-cohorted." -msgstr "" - #: openedx/core/djangoapps/video_pipeline/models.py msgid "Oauth client name of VEM service." msgstr "" @@ -11049,51 +11018,6 @@ msgstr "" msgid "Updates" msgstr "Cập Nhật" -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{sign_in_link} or {register_link} and then enroll in this course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Welcome to {course_display_name}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"You must be enrolled in the course to see course content. Please contact " -"your degree administrator or {platform_name} Support if you have questions." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"{open_enroll_link}Enroll now{close_enroll_link} to access the full course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"To start, set a course goal by selecting the option below that best " -"describes your learning plan. {goal_options_container}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {goal_text}" -msgstr "" - #: openedx/features/discounts/admin.py msgid "" "These define the context to disable lms-controlled discounts on. If no " @@ -11192,12 +11116,10 @@ msgid "Continue" msgstr "Tiếp tục" #: openedx/features/personalized_learner_schedules/call_to_action.py -#: lms/templates/dates_banner.html msgid "Shift due dates" msgstr "" #: openedx/features/personalized_learner_schedules/call_to_action.py -#: lms/templates/dates_banner.html msgid "" "It looks like you missed some important deadlines based on our suggested " "schedule." @@ -12225,11 +12147,6 @@ msgstr "Tên khóa học" msgid "Course Number" msgstr "Mã khóa học" -#: cms/templates/course_outline.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Course Outline" -msgstr "" - #: cms/templates/html_error.html lms/templates/course_modes/error.html #: lms/templates/module-error.html msgid "Error:" @@ -12317,62 +12234,10 @@ msgstr "Tài khoản" #: lms/templates/header/navbar-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: lms/templates/static_templates/help.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -#: wiki/plugins/help/wiki_plugin.py +#: lms/templates/static_templates/help.html wiki/plugins/help/wiki_plugin.py msgid "Help" msgstr "Trợ giúp" -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Looking for help with {studio_name}?" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Hide {studio_name} Help" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "{studio_name} Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Access documentation on http://docs.edx.org" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101: Overview of Creating an edX Course" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX: Creating a Course with edX Studio" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Send an email to {email}" -msgstr "" - #: cms/templates/widgets/tabs-aggregator.html #: lms/templates/courseware/static_tab.html #: lms/templates/courseware/tab-view.html @@ -12549,19 +12414,18 @@ msgstr "Xem tất cả khóa học" #: lms/templates/dashboard.html lms/templates/header/user_dropdown.html #: lms/templates/user_dropdown.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Dashboard" msgstr "Bảng thông tin" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "results successfully populated," msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Click to load all enrolled courses" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "You are not enrolled in any courses yet." msgstr "Bạn chưa được ghi danh vào khóa học nào" @@ -12569,7 +12433,6 @@ msgstr "Bạn chưa được ghi danh vào khóa học nào" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore courses" msgstr "Khám phá khóa học" @@ -12578,16 +12441,15 @@ msgstr "Khám phá khóa học" msgid "Activate your account!" msgstr "Kích hoạt tài khoản của bạn!" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Course-loading errors" msgstr "Lỗi khi tải khóa học" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Search Your Courses" msgstr "Tìm khóa học của bạn" #: lms/templates/courseware/courseware.html lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Clear search" msgstr "Xoá tìm kiếm" @@ -12610,15 +12472,15 @@ msgstr "" msgid "Continue to {platform_name}" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Email Settings for {course_number}" msgstr "Cài đặt Email cho {course_number}" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Receive course emails" msgstr "Nhận email cho khóa học" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Save Settings" msgstr "Lưu cài đặt" @@ -12627,83 +12489,9 @@ msgstr "Lưu cài đặt" #: lms/templates/dashboard/_dashboard_entitlement_actions.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/instructor/instructor_dashboard_2/membership.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "Unenroll" msgstr "Hủy ghi danh" -#: lms/templates/dates_banner.html -msgid "" -"It looks like you missed some important deadlines based on our suggested " -"schedule. " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future by visiting " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" Don't worry—you won't lose any of the progress you've made when you shift " -"your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future. Don't worry—you won't lose any of the " -"progress you've made when you shift your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "You are auditing this course," -msgstr "" - -#: lms/templates/dates_banner.html -msgid " which means that you are unable to participate in graded assignments." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. Graded assignments and schedule adjustment are available to " -"Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. To complete graded assignments as part of this course and shift " -"the past due assignments into the future, you can upgrade today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Upgrade to shift due dates" -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Graded assignments are available to Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" To complete graded assignments as part of this course, you can upgrade " -"today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "We've built a suggested schedule to help you stay on track." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"But don't worry—it's flexible so you can learn at your own pace. If you " -"happen to fall behind on our suggested dates, you'll be able to adjust them " -"to keep yourself on track." -msgstr "" - #: lms/templates/email_change_failed.html lms/templates/email_exists.html msgid "E-mail change failed" msgstr "Thay đổi Email không thành công" @@ -13035,10 +12823,6 @@ msgstr "Thiết lập chế độ xem trước" msgid "You are now viewing the course as {i_start}{user_name}{i_end}." msgstr "Bạn đang xem khoá học với tên là {i_start}{user_name}{i_end}." -#: lms/templates/preview_menu.html -msgid "View in the new experience" -msgstr "" - #: lms/templates/preview_menu.html msgid "View in Studio" msgstr "" @@ -13165,9 +12949,7 @@ msgstr "" msgid "Sequence" msgstr "Trình tự" -#: lms/templates/courseware/dates.html lms/templates/seq_module.html -#: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html +#: lms/templates/seq_module.html lms/templates/vert_module.html msgid "Completed" msgstr "" @@ -13446,7 +13228,6 @@ msgstr "" "dấu cộng, hoặc Ctrl-dấu trừ." #: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "{subsection_format} due {{date}}" msgstr "{subsection_format} hạn chót {{date}}" @@ -13458,6 +13239,10 @@ msgstr "" msgid "Past due" msgstr "" +#: lms/templates/vert_module.html +msgid "Reset Problems" +msgstr "" + #: lms/templates/video.html msgid "Loading video player" msgstr "Đang tải trình xem video" @@ -14684,7 +14469,6 @@ msgid "Download student grades" msgstr "Tải bảng điểm học viên" #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Print or share your certificate:" msgstr "In hoặc chia sẻ giấy chứng nhận của bạn:" @@ -14698,7 +14482,6 @@ msgstr "Post lên Facebook" #: lms/templates/certificates/_accomplishment-banner.html #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Twitter" msgstr "Chia sẻ lên Twitter" @@ -14707,7 +14490,6 @@ msgid "Tweet this Accomplishment. Pop up window." msgstr "Tweet thành tựu này lên Twitter." #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Add to LinkedIn Profile" msgstr "Thêm vào hồ sơ trên LinkedIn" @@ -14808,40 +14590,31 @@ msgstr "" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue the Verified Track" msgstr "" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue a Verified Certificate" msgstr "Theo đuổi Giấy chứng nhận được xác thực" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Enroll In {course_name} | Choose Your Track" msgstr "Đăng ký vào {course_name} | Chọn Trương trình Của bạn" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Sorry, there was an error when trying to enroll you" msgstr "Rất tiếc, đã có lỗi trong việc ghi danh" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with the Verified Track" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with a Verified Certificate" msgstr "Lấy tín chỉ với Giấy chứng nhận được xác thực." #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Become eligible for academic credit and highlight your new skills and " "knowledge with a verified certificate. Use this valuable credential to " @@ -14854,12 +14627,10 @@ msgstr "" "cường giá trị các đơn xin học." #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of the Verified Track" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Eligible for credit:{b_end} Receive academic credit after " "successfully completing the course" @@ -14868,33 +14639,28 @@ msgstr "" " này. " #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Unlimited Course Access: {b_end}Learn at your own pace, and access " "materials anytime to brush up on what you've learned." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Graded Assignments: {b_end}Build your skills through graded " "assignments and projects." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily Sharable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of a Verified Certificate" msgstr "Lợi ích của một Giấy chứng nhận được xác thực " #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official:{b_end} Receive an instructor-signed certificate with the " "institution's logo" @@ -14903,14 +14669,12 @@ msgstr "" "cùng logo của tổ chức giáo dục." #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable:{b_end} Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Highlight your new knowledge and skills with a verified certificate. Use " "this valuable credential to improve your job prospects and advance your " @@ -14921,7 +14685,6 @@ msgstr "" "trong sự nghiệp." #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official: {b_end}Receive an instructor-signed certificate with the " "institution's logo" @@ -14930,14 +14693,12 @@ msgstr "" "cùng logo của tổ chức giáo dục." #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Motivating: {b_end}Give yourself an additional incentive to " "complete the course" @@ -14946,12 +14707,10 @@ msgstr "" "học." #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course" msgstr "Dự thính khoá học này" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums." @@ -14960,12 +14719,10 @@ msgstr "" "liệu, hoạt động, bài kiểm tra và diễn đàn." #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course (No Certificate)" msgstr "Kiểm tra Khóa học này (Không có Chứng chỉ)" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded assignments," @@ -14973,7 +14730,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded " @@ -14981,7 +14737,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include unlimited course " @@ -14989,7 +14744,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums. {b_start}Please note that this " @@ -15076,6 +14830,10 @@ msgstr "" msgid "Choose a path for your course in" msgstr "" +#: lms/templates/course_modes/track_selection.html +msgid "Earn a certificate" +msgstr "" + #: lms/templates/course_modes/track_selection.html msgid "" "Studies show that those who choose this option are {start_bold}more engaged" @@ -15100,7 +14858,6 @@ msgstr "{span_start}phần hiện tại{span_end}" #: lms/templates/courseware/accordion.html #: lms/templates/courseware/progress.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "due {date}" msgstr "hạn {date}" @@ -15109,7 +14866,6 @@ msgid "{section_format} due {{date}}" msgstr "{section_format} hạn chót {{date}}" #: lms/templates/courseware/accordion.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "This content is graded" msgstr "Nội dung đã được chấm điểm" @@ -15121,10 +14877,6 @@ msgstr "Có lỗi xảy ra. Vui lòng thử lại sau." msgid "You are enrolled in this course" msgstr "Bạn đã ghi danh vào khoá học này." -#: lms/templates/courseware/course_about.html -msgid "Course is full" -msgstr "Khóa học đã đầy" - #: lms/templates/courseware/course_about.html msgid "Enrollment in this course is by invitation only" msgstr "Chỉ có thể ghi danh vào khóa học này qua thư mời." @@ -15289,30 +15041,6 @@ msgid "Your score is {current_score}%. You have passed the entrance exam." msgstr "" "Điểm của bạn là {current_score}%. Chúc mừng bạn đã đậu kiểm tra đầu vào." -#: lms/templates/courseware/dates.html lms/templates/courseware/syllabus.html -msgid "{course.display_number_with_default} Course Info" -msgstr "{course.display_number_with_default} Thông tin khoá học" - -#: lms/templates/courseware/dates.html -msgid "Important Dates" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Today" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Verified Only" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Due Next" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Not yet released" -msgstr "" - #: lms/templates/courseware/gradebook.html msgid "Gradebook" msgstr "Sổ Điểm" @@ -15364,8 +15092,6 @@ msgstr "" #: lms/templates/courseware/info.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "Resume Course" msgstr "Tiếp tục Học" @@ -15382,7 +15108,6 @@ msgid "Handout Navigation" msgstr "Tài liệu handout" #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Tools" msgstr "Công cụ Khoá học" @@ -15636,6 +15361,10 @@ msgstr "Điểm thực hành bị ẩn." msgid "No problem scores in this section" msgstr "Phần này không có bài tập tính điểm" +#: lms/templates/courseware/syllabus.html +msgid "{course.display_number_with_default} Course Info" +msgstr "{course.display_number_with_default} Thông tin khoá học" + #: lms/templates/courseware/welcome-back.html msgid "" "You were most recently in {section_link}. If you're done with that, choose " @@ -15886,7 +15615,6 @@ msgid "Share {course_name} on Facebook" msgstr "Chia sẻ {course_name} trên Facebook" #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Facebook" msgstr "Chia sẻ trên Facebook" @@ -15934,6 +15662,12 @@ msgid "" "showcase on your resumé." msgstr "" +#: lms/templates/dashboard/_dashboard_course_listing.html +msgid "" +"{start_bold}Get the most out of your course!{end_bold} Upgrade to earn a " +"{link_start}verified certificate{link_end} to showcase on your resumé." +msgstr "" + #: lms/templates/dashboard/_dashboard_course_listing.html msgid "Upgrade" msgstr "" @@ -16788,7 +16522,6 @@ msgstr "" "đầy đủ. Chúng tôi khuyên bạn nên sử dụng {chrome_link} hoặc {ff_link}." #: lms/templates/header/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Discover New" msgstr "" @@ -16802,7 +16535,6 @@ msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "How it Works" msgstr "Phương thức hoạt động" @@ -18330,7 +18062,6 @@ msgid "" msgstr "" #: lms/templates/learner_dashboard/_dashboard_navigation_courses.html -#: themes/edx.org/lms/templates/dashboard.html msgid "My Courses" msgstr "Các khóa học " @@ -18780,13 +18511,10 @@ msgid "Skeleton Page" msgstr "Trang Bộ xương" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html msgid "Search the course" msgstr "Tìm kiếm khóa học" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Start Course" msgstr "Bắt đầu Khóa học" @@ -18971,36 +18699,6 @@ msgstr "" msgid "View all course dates" msgstr "" -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Goal: " -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Edit your course goal:" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Pursue a verified certificate" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "" -"Sample verified certificate with your name, the course title, the logo of " -"the institution and the signatures of the instructors for this course." -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Upgrade ({price})" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Expand All" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Prerequisite: " -msgstr "" - #: openedx/features/course_experience/templates/course_experience/course-sock-fragment.html msgid "Learn About Verified Certificates" msgstr "" @@ -19081,18 +18779,6 @@ msgstr "" msgid "This course does not have any updates." msgstr "Khóa học này không có thông tin cập nhật." -#: openedx/features/course_experience/templates/course_experience/latest-update-fragment.html -msgid "Latest Update" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/welcome-message-fragment.html -msgid "Show More" -msgstr "" - -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -msgid "Search Results" -msgstr "" - #. Translators: this section lists all the third-party authentication #. providers #. (for example, Google and LinkedIn) the user can link with or unlink from @@ -19136,10 +18822,13 @@ msgid "You haven't earned any certificates yet." msgstr "Bạn chưa kiếm được chứng chỉ nào." #: openedx/features/learner_profile/templates/learner_profile/learner-achievements-fragment.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore New Courses" msgstr "Khám phá Các Khóa Học Mới" +#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html +msgid "Learner Profile" +msgstr "Hồ sơ cá nhân học viên" + #: openedx/features/learner_profile/templates/learner_profile/learner_profile.html msgid "View My Records" msgstr "" @@ -19159,138 +18848,6 @@ msgstr "" msgid "An error occurred. Try loading the page again." msgstr "Đã xảy ra lỗi. Thử tải lại trang." -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "" -"Access Course Staff Support on the Partner Portal to submit or review " -"support tickets" -msgstr "" - -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Partner Portal" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "" -"Browse recently launched courses and see what's new in your favorite " -"subjects." -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Take advantage of free coaching!" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Get Started" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Page Footer" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "edX Home Page" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Connect" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "© {year} edX Inc. All rights reserved." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "About edX Verified Certificates" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "" -"An edX Verified Certificate signifies that the learner has agreed to abide " -"by the edX honor code and completed all of the required tasks of this course" -" under its guidelines, as well as having their photo ID checked to verify " -"their identity." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "About edX" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "" -"{link_start}edX{link_end} offers interactive online classes and MOOCs from " -"the world's best universities, including MIT, Harvard, Berkeley, University " -"of Texas, and many others. edX is a mission driven initiative created by " -"founding partners Harvard and MIT." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Congratulations, {user_name}!" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "" -"You worked hard to earn your certificate from " -"{accomplishment_copy_course_org} {dash} share it with colleagues, friends, " -"and family to get the word out about what you mastered in " -"{accomplishment_course_title}." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Share this certificate on Facebook (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Tweet this certificate (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Add this certificate to your LinkedIn profile (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print this certificate" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "edX Inc." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "" -"All rights reserved except where noted. edX, Open edX and the edX and Open " -"edX logos are registered trademarks of edX Inc." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end}EdX relies on verified certificates to " -"help fund affordable education to everyone globally." -msgstr "" - -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end} EdX, a mission driven initiative, " -"relies on verified certificates to help fund free education for everyone " -"globally" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Find Courses" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Schools & Partners" -msgstr "" - #: themes/red-theme/lms/templates/footer.html msgid "" "{tos_link_start}Terms of Service{tos_link_end} and {honor_link_start}Honor " @@ -20005,6 +19562,10 @@ msgstr "" "những thay đổi trong lịch trình, và phản hồi câu hỏi của học viên. Bạn thêm " "hoặc thay đổi cập nhật bằng mã HTML." +#: cms/templates/course_outline.html +msgid "Course Outline" +msgstr "" + #: cms/templates/course_outline.html msgid "" "This course was created as a re-run. Some manual configuration is needed." @@ -23066,6 +22627,26 @@ msgstr "" msgid "Label" msgstr "Nhãn" +#: cms/templates/widgets/sock.html +msgid "Looking for help with {studio_name}?" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "Hide {studio_name} Help" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "{studio_name} Documentation" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Access documentation on http://docs.edx.org" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "edX Documentation" +msgstr "" + #: cms/templates/widgets/sock_links.html msgid "Access the Open edX Portal" msgstr "Truy cập Open EDX Portal" @@ -23074,6 +22655,26 @@ msgstr "Truy cập Open EDX Portal" msgid "Open edX Portal" msgstr "Open edX Portal" +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101: Overview of Creating an edX Course" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX: Creating a Course with edX Studio" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Send an email to {email}" +msgstr "" + #: cms/templates/widgets/user_dropdown.html msgid "Currently signed in as:" msgstr "Hiện đang đăng nhập như là:" diff --git a/conf/locale/vi/LC_MESSAGES/djangojs.mo b/conf/locale/vi/LC_MESSAGES/djangojs.mo index 8cfe9eb75f5037a9d0397f47e14d68b767ebed72..d31383bdd94dca61b5085ee5457524a8a8e0afc8 100644 GIT binary patch delta 34 ocmZqp#MJ;qTNqWUI4txGxERU~FPLoCVb~s9#kf7TifOSO0OM#3rvLx| delta 34 ocmZqp#MJ;qTNqWUI4t!Hxfse0FPLoCVb~s9#kf7TifOSO0OOJjsQ>@~ diff --git a/conf/locale/vi/LC_MESSAGES/djangojs.po b/conf/locale/vi/LC_MESSAGES/djangojs.po index d0ce2240a6..2870f24cb2 100644 --- a/conf/locale/vi/LC_MESSAGES/djangojs.po +++ b/conf/locale/vi/LC_MESSAGES/djangojs.po @@ -113,7 +113,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Le Minh Tri , 2020\n" "Language-Team: Vietnamese (http://www.transifex.com/open-edx/edx-platform/language/vi/)\n" @@ -122,7 +122,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js #: cms/static/js/views/video_transcripts.js @@ -168,7 +168,6 @@ msgstr "Xóa" #: common/lib/xmodule/xmodule/js/src/html/edit.js #: common/static/common/js/components/utils/view_utils.js #: lms/static/js/Markdown.Editor.js -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx #: lms/static/js/student_account/components/StudentAccountDeletionModal.jsx #: cms/templates/js/add-xblock-component-menu-problem.underscore #: cms/templates/js/add-xblock-component-menu.underscore @@ -344,6 +343,14 @@ msgstr "Lỗi" msgid "Updating with latest library content" msgstr "Đang cập nhật nội dung thư viện mới nhất" +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Loading..." +msgstr "" + +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Selected blocks" +msgstr "" + #: common/lib/xmodule/xmodule/assets/library_source_block/public/js/library_source_block.js msgid "Unable to update settings" msgstr "" @@ -1247,6 +1254,7 @@ msgstr "Cửa sổ mới" #. Translators: this is a message from the raw HTML editor displayed in the #. browser when a user needs to edit HTML #: common/lib/xmodule/xmodule/js/src/html/edit.js +#: lms/static/js/demographics_collection/Wizard.jsx #: cms/templates/js/paging-header.underscore #: common/static/common/templates/components/paging-footer.underscore #: common/static/common/templates/discussion/templates.underscore @@ -2020,6 +2028,10 @@ msgstr "Xem các mục con" msgid "Navigate up" msgstr "" +#: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx +msgid "Browsing" +msgstr "" + #: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx msgid "Select" msgstr "Chọn" @@ -2540,10 +2552,30 @@ msgid "" "within the Discussion Forum where the Course Staff can directly respond." msgstr "" +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Details" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "the more quickly and helpfully we can respond!" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Create Support Ticket" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "What can we help you with, {username}?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx msgid "Sign in to {platform} so we can help you better." msgstr "Đăng nhập vào {platform} để chúng tôi có thể hỗ trợ bạn tốt hơn." +#: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx +msgid "Need help logging in?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/single_support_form.jsx msgid "" "Select a course or select \"Not specific to a course\" for your support " @@ -3394,20 +3426,52 @@ msgstr "" msgid "Get started" msgstr "" -#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx -msgid "Section {currentPage} of {totalPages}" -msgstr "" - #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "Help make edX better for everyone!" msgstr "" +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Why does edX collect this information?" +msgstr "" + #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "" -"Welcome to edX! Before you get started, please take a few minutes to fill-in" -" the additional information below to help us understand a bit more about " -"your background. You can always edit this information later in Account " -"Settings." +"An error occurred while attempting to retrieve or save the information " +"below. Please try again later." +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What was the total combined income, during the last 12 months, of all " +"members of your family? " +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"Have you ever served on active duty in the U.S. Armed Forces, Reserves, or " +"National Guard?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What is the highest level of education that you have achieved so far?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What is the highest level of education that any of your parents or guardians" +" have achieved?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Select employment status" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you currently work in?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you want to work in?" msgstr "" #: lms/static/js/demographics_collection/MultiselectDropdown.jsx @@ -3422,6 +3486,22 @@ msgstr "" msgid "close questionnaire" msgstr "" +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Return to my dashboard" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "next page" +msgstr "" + #: lms/static/js/discovery/views/search_form.js #, javascript-format msgid "Viewing %s course" @@ -3720,27 +3800,6 @@ msgstr "Cho phép phân nhóm học viên" msgid "Cohorts Disabled" msgstr "Không cho phép phân nhóm học viên" -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course uses automatic cohorting for verified track learners. You cannot" -" disable cohorts, and you cannot rename the manual cohort named " -"'{verifiedCohortName}'. To change the configuration for verified track " -"cohorts, contact your edX partner manager." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" the required cohort does not exist. You must create a manually-assigned " -"cohort named '{verifiedCohortName}' for the feature to work." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" cohorts are disabled. You must enable cohorts for the feature to work." -msgstr "" - #: lms/static/js/instructor_dashboard/certificates.js msgid "Allow students to generate certificates for this course?" msgstr "Cho phép cấp chứng chỉ cho khóa học này?" @@ -4471,10 +4530,6 @@ msgstr "" "Các đường dẫn đang được xuất theo yêu cầu nhưng sẽ hết hạn trong vòng 5 phút" " vì độ nhạy cảm của thông tin về học viên." -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx -msgid "You have access to the {enterpriseName} dashboard" -msgstr "" - #: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx msgid "" "To access the courses available to you through {enterpriseName}, visit the " @@ -5374,42 +5429,6 @@ msgstr "Tổng Điểm" msgid "Bookmark this page" msgstr "Đánh dấu trang này" -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "Thank you for setting your course goal to {goal}!" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "" -"There was an error in setting your goal, please reload the page and try " -"again." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "You have successfully updated your goal." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "There was an error updating your goal." -msgstr "" - -#: lms/templates/ccx/schedule.underscore -msgid "Expand All" -msgstr "Mở rộng tất cả" - -#: lms/templates/ccx/schedule.underscore -msgid "Collapse All" -msgstr "Thu gọn tất cả" - -#: openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show More" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show Less" -msgstr "" - #: openedx/features/course_search/static/course_search/js/views/search_results_view.js msgid "{total_results} result found for \"{search_term}\"" msgid_plural "{total_results} results found for \"{search_term}\"" @@ -5702,6 +5721,30 @@ msgstr "Xảy ra lỗi khi nhập khóa học" msgid "There was an error with the upload" msgstr "Có lỗi trong quá trình tải lên" +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Organization:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Number:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Run:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "(Read-only)" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Re-run Course" +msgstr "" + +#: cms/templates/js/show-textbook.underscore +msgid "View Live" +msgstr "Xem bản thực" + #: cms/static/js/maintenance/force_publish_course.js msgid "Internal Server Error." msgstr "Lỗi Máy chủ Nội bộ." @@ -7249,10 +7292,6 @@ msgstr "" msgid "follow this post" msgstr "" -#: common/static/common/templates/discussion/templates.underscore -msgid "post anonymously" -msgstr "" - #: common/static/common/templates/discussion/templates.underscore msgid "post anonymously to classmates" msgstr "" @@ -7704,6 +7743,14 @@ msgstr "" msgid "This catalog's courses:" msgstr "" +#: lms/templates/ccx/schedule.underscore +msgid "Expand All" +msgstr "Mở rộng tất cả" + +#: lms/templates/ccx/schedule.underscore +msgid "Collapse All" +msgstr "Thu gọn tất cả" + #: lms/templates/ccx/schedule.underscore msgid "Start Date" msgstr "Ngày bắt đầu" @@ -7787,6 +7834,14 @@ msgid "" "before you select \"End My Exam\"." msgstr "" +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show More" +msgstr "" + +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show Less" +msgstr "" + #: lms/templates/discovery/course_card.underscore msgid "LEARN MORE" msgstr "Tìm hiểu thêm" @@ -10514,10 +10569,6 @@ msgstr "" msgid "PDF Chapters" msgstr "" -#: cms/templates/js/show-textbook.underscore -msgid "View Live" -msgstr "Xem bản thực" - #: cms/templates/js/signatory-details.underscore #: cms/templates/js/signatory-editor.underscore msgid "Signatory" diff --git a/conf/locale/zh_CN/LC_MESSAGES/django.mo b/conf/locale/zh_CN/LC_MESSAGES/django.mo index 04efd45822bee2a750a0429fcf2d1882cfa62034..c27452fcd6cb46660886f24c6f5c6f0ce65d145d 100644 GIT binary patch delta 35 pcmX@VQTF^s*@hOz7N!>FEi5th%ochE?eX<2K+L*5zMie%CIIxV4KM%z delta 35 pcmX@VQTF^s*@hOz7N!>FEi5th%$9nF?eX<2K+L*5zMie%CIIx#4Ke@# diff --git a/conf/locale/zh_CN/LC_MESSAGES/django.po b/conf/locale/zh_CN/LC_MESSAGES/django.po index c3ad4640f0..beea4c18d6 100644 --- a/conf/locale/zh_CN/LC_MESSAGES/django.po +++ b/conf/locale/zh_CN/LC_MESSAGES/django.po @@ -397,7 +397,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:44+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: ifLab , 2019\n" "Language-Team: Chinese (China) (https://www.transifex.com/open-edx/teams/6205/zh_CN/)\n" @@ -406,7 +406,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# #. Translators: 'Discussion' refers to the tab in the courseware that leads to @@ -992,6 +992,10 @@ msgstr "课程编号无效" msgid "Could not enroll" msgstr "无法选修" +#: common/djangoapps/student/views/management.py +msgid "Unenrollment is currently disabled" +msgstr "" + #: common/djangoapps/student/views/management.py msgid "You are not enrolled in this course" msgstr "您还没有选修本课程" @@ -2052,7 +2056,6 @@ msgstr "工作人员对此问题的解答存在问题:边界未设置。" #. to the site. #: common/lib/capa/capa/responsetypes.py #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html #: themes/stanford-style/lms/templates/register-form.html msgid "or" msgstr "或者" @@ -2340,6 +2343,7 @@ msgid "Whether to force the save button to appear on the page" msgstr "是否强制显示保存按钮" #: common/lib/xmodule/xmodule/capa_module.py +#: common/lib/xmodule/xmodule/library_content_module.py msgid "Show Reset Button" msgstr "显示重置按钮" @@ -3053,7 +3057,6 @@ msgstr "输入您想要学生可以在课程首页看到此课程讲义的标题 #: common/lib/xmodule/xmodule/course_module.py #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Handouts" msgstr "课程讲义" @@ -3714,6 +3717,12 @@ msgid "" " no filtering is applied." msgstr "选择一个要从知识库中获取的问题类型,如果选择了“任意类型”,则不应用任何筛选。" +#: common/lib/xmodule/xmodule/library_content_module.py +msgid "" +"Determines whether a 'Reset Problems' button is shown, so users may reset " +"their answers and reshuffle selected items." +msgstr "" + #: common/lib/xmodule/xmodule/library_content_module.py msgid "This component is out of date. The library has new content." msgstr "该组件已过时。知识库有新的内容。" @@ -4838,8 +4847,7 @@ msgstr "解锁账户" #: lms/templates/instructor/instructor_dashboard_2/invalidate_registration_code_modal.html #: lms/templates/instructor/instructor_dashboard_2/set_course_mode_price_modal.html #: lms/templates/modal/_modal-settings-language.html -#: lms/templates/signup_modal.html themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html +#: lms/templates/signup_modal.html msgid "Close" msgstr "关闭" @@ -5260,7 +5268,6 @@ msgstr "" #. Translators: 'Open edX' is a brand, please keep this untranslated. See #. http://openedx.org for more information. #: lms/djangoapps/branding/api.py cms/templates/widgets/footer.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html #: themes/red-theme/lms/templates/footer.html msgid "Powered by Open edX" msgstr "Powered by Open edX" @@ -5270,7 +5277,6 @@ msgid "Blog" msgstr "博客" #: lms/djangoapps/branding/api.py cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html #: themes/stanford-style/lms/templates/static_templates/about.html msgid "Contact Us" msgstr "联系我们" @@ -5328,7 +5334,6 @@ msgstr "服务条款 & 荣誉准则" #: lms/djangoapps/branding/api.py lms/djangoapps/certificates/views/webview.py #: cms/templates/widgets/footer.html #: lms/templates/static_templates/privacy.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html #: themes/red-theme/lms/templates/footer.html #: themes/stanford-style/lms/templates/footer.html #: themes/stanford-style/lms/templates/static_templates/tos.html @@ -5343,6 +5348,7 @@ msgstr "可访问策略" #. Translators: This is a legal document users must agree to #. in order to register a new account. #: lms/djangoapps/branding/api.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: cms/templates/widgets/footer.html lms/templates/static_templates/tos.html #: themes/red-theme/lms/templates/footer.html @@ -5853,23 +5859,6 @@ msgid "" "this request, please visit the link(s) below." msgstr "{username} ({email}) 的退款要求已经建立。为了处理此请求,请访问以下联结(s) 。" -#: lms/djangoapps/course_goals/models.py -#: lms/templates/course_modes/track_selection.html -msgid "Earn a certificate" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Complete the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Explore the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Not sure yet" -msgstr "" - #: lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/body.html msgid "" "\n" @@ -5969,7 +5958,6 @@ msgid "Disabled" msgstr "" #: lms/djangoapps/course_home_api/outline/serializers.py -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html #, python-brace-format msgid "({number} Question)" msgid_plural "({number} Questions)" @@ -5982,6 +5970,10 @@ msgid "" "have questions." msgstr "" +#: lms/templates/courseware/course_about.html +msgid "Course is full" +msgstr "该课程已满" + #: lms/djangoapps/course_home_api/outline/views.py msgid "'course_id' is required." msgstr "" @@ -6124,20 +6116,6 @@ msgstr "选课日期" msgid "Course starts" msgstr "" -#: lms/djangoapps/courseware/date_summary.py -msgid "Don't forget to add a calendar reminder!" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} on {course_start_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} at {course_start_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Course ends" msgstr "" @@ -6161,16 +6139,6 @@ msgid "" " no longer active." msgstr "这门课程已经归档:您可以复习课程内容,但该课程不再有活动(active)。" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} on {course_end_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} at {course_end_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "You lose all access to this course, including your progress." msgstr "" @@ -6187,22 +6155,6 @@ msgstr "可申请的证书" msgid "Day certificates will become available for passing verified learners." msgstr "合格的已认证学员可获得证书的时间。" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"If you have earned a certificate, you will be able to access it " -"{time_remaining_string} from now. You will also be able to view your " -"certificates on your {learner_profile_link}." -msgstr "" - -#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html -msgid "Learner Profile" -msgstr "学生用户资料" - -#: lms/djangoapps/courseware/date_summary.py -msgid "We are working on generating course certificates." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Upgrade to Verified Certificate" msgstr "身份认证升级" @@ -6232,36 +6184,9 @@ msgstr "您仍有资格升级至认证证书!获得认证证书以突显您从 msgid "by {date}" msgstr "截止于{date}" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"Don't forget, you have {time_remaining_string} left to upgrade to a Verified" -" Certificate." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Don't forget to upgrade to a verified certificate by {localized_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"In order to qualify for a certificate, you must meet all course grading " -"requirements, upgrade before the course deadline, and successfully verify " -"your identity on {platform_name} if you have not done so " -"already.{button_panel}" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Upgrade ({upgrade_price})" -msgstr "" - #: lms/djangoapps/courseware/date_summary.py #: cms/templates/group_configurations.html #: lms/templates/courseware/program_marketing.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Learn More" msgstr "了解更多" @@ -6321,6 +6246,24 @@ msgstr "禁用此开课时间的动态升级截止日期。" msgid "Disable the dynamic upgrade deadline for this organization." msgstr "禁用此组织的动态升级截止日期。" +#: lms/djangoapps/courseware/models.py +msgid "Internal API Base URL" +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Financial Assistance Backend API Base URL." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "" +"Username created for Financial Assistance Backend, e.g. " +"financial_assistance_service_user." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Percentage of courses allowed to use edx-financial-assistance" +msgstr "" + #: lms/djangoapps/courseware/plugins.py lms/djangoapps/courseware/tabs.py #: lms/templates/peer_grading/peer_grading.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html @@ -6396,7 +6339,6 @@ msgstr "登录" #: lms/djangoapps/courseware/views/index.py #: lms/djangoapps/courseware/views/views.py #: openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "register" msgstr "注册" @@ -6446,17 +6388,6 @@ msgstr "恭喜!您已获得证书!" msgid "You've earned a certificate for this course." msgstr "您已获得此门课程的证书。" -#: lms/djangoapps/courseware/views/views.py -msgid "Certificate unavailable" -msgstr "无法查看证书" - -#: lms/djangoapps/courseware/views/views.py -#, python-brace-format -msgid "" -"You have not received a certificate because you do not have a current " -"{platform_name} verified identity." -msgstr "未进行{platform_name}身份认证无法获得证书。" - #: lms/djangoapps/courseware/views/views.py msgid "Your certificate will be available soon!" msgstr "" @@ -6471,23 +6402,31 @@ msgstr "" msgid "Your certificate is available" msgstr "您的证书已可用" +#: lms/djangoapps/courseware/views/views.py +msgid "Certificate unavailable" +msgstr "无法查看证书" + +#: lms/djangoapps/courseware/views/views.py +#, python-brace-format +msgid "" +"You have not received a certificate because you do not have a current " +"{platform_name} verified identity." +msgstr "未进行{platform_name}身份认证无法获得证书。" + #: lms/djangoapps/courseware/views/views.py #, python-brace-format msgid "To see course content, {sign_in_link} or {register_link}." msgstr "请{sign_in_link}或{register_link}以查看课程内容。" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py #, python-brace-format msgid "{sign_in_link} or {register_link}." msgstr "" #: lms/djangoapps/courseware/views/views.py #: openedx/core/djangoapps/user_authn/templates/user_authn/edx_ace/passwordresetsuccess/email/body.html -#: openedx/features/course_experience/views/course_home_messages.py #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html msgid "Sign in" msgstr "登录" @@ -6499,7 +6438,6 @@ msgid "" msgstr "" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "You must be enrolled in the course to see course content." msgstr "您必须报读此课程才能查看课程内容。" @@ -6617,6 +6555,29 @@ msgstr "上传文件出错,请联系网站管理员,谢谢。" msgid "Good" msgstr "好" +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#, python-format +msgid "" +"\n" +" %(course_name)s: Reported content awaits review\n" +" " +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +msgid "Go to Discussion" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +#, python-format +msgid "%(course_name)s: Reported content awaits review" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/subject.txt +#, python-format +msgid " %(course_name)s %(course_id)s moderator content for review " +msgstr "" + #: lms/djangoapps/discussion/templates/discussion/edx_ace/responsenotification/email/body.html #, python-format, python-brace-format msgid "%(comment_username)s replied to {start_tag}%(thread_title)s{end_tag}:" @@ -6949,10 +6910,13 @@ msgid "Team" msgstr "团队" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# +#. Translators: This label appears above a field +#. which allows the user to input the city in which they live. #. Translators: This label appears above a field on the registration form #. which allows the user to input the city in which they live. #: lms/djangoapps/instructor/views/api.py #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: lms/templates/instructor/instructor_dashboard_2/generate_registarion_codes_modal.html #: themes/stanford-style/lms/templates/register-form.html @@ -7737,7 +7701,6 @@ msgstr "( /{total} )" #: lms/templates/learner_dashboard/programs.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Programs" msgstr "程式" @@ -8611,7 +8574,6 @@ msgstr "" #: lms/templates/courseware/course_about.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "View Course" msgstr "查看课程" @@ -8874,8 +8836,6 @@ msgstr "Wiki预览" #: lms/templates/wiki/includes/cheatsheet.html lms/templates/dashboard.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/modal/_modal-settings-language.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "window open" msgstr "窗口打开" @@ -9121,9 +9081,6 @@ msgstr "您可以从其他文章中重用一些文件。但是该文件的更新 #: lms/templates/courseware/courseware.html lms/templates/dashboard.html #: lms/templates/edxnotes/edxnotes.html lms/templates/index.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -#: themes/edx.org/lms/templates/dashboard.html #: themes/stanford-style/lms/templates/index.html #: wiki/plugins/attachments/templates/wiki/plugins/attachments/index.html msgid "Search" @@ -9237,7 +9194,6 @@ msgstr "前往%(platform_name)s主页" #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Courses" msgstr "课程" @@ -10088,7 +10044,6 @@ msgid "Student" msgstr "学生" #: openedx/core/djangoapps/embargo/forms.py -#: openedx/core/djangoapps/verified_track_content/forms.py msgid "COURSE NOT FOUND. Please check that the course ID is valid." msgstr "课程未找到,请检查课程 ID 是否有效。" @@ -10140,6 +10095,10 @@ msgstr "课程{course}的白名单国家: {country}" msgid "Blacklist {country} for {course}" msgstr "课程{course}的黑名单国家: {country}" +#: openedx/core/djangoapps/learner_pathway/apps.py +msgid "Learner Pathways" +msgstr "" + #: openedx/core/djangoapps/oauth_dispatch/models.py msgid "" "Comma-separated list of scopes that this application will be allowed to " @@ -10625,6 +10584,14 @@ msgstr "请输入有效的邮箱,不少于{min}个字符。" msgid "Enter your full name." msgstr "请输入您的全名。" +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your first name." +msgstr "" + +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your last name." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "The email addresses do not match." msgstr "邮箱不一致。" @@ -10649,6 +10616,10 @@ msgstr "请输入您的职业。" msgid "Enter your specialty." msgstr "请输入您的专业技能。" +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your state." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "Enter your city." msgstr "请输入您的城市。" @@ -10690,24 +10661,39 @@ msgstr "" msgid "The '{field_name}' field cannot be edited." msgstr "'{field_name}'字段无法编辑。" +#: openedx/core/djangoapps/user_api/accounts/api.py +#: openedx/core/djangoapps/user_authn/views/registration_form.py +msgid "Enter a valid name" +msgstr "" + +#. Translators: This label appears above a field which allows the +#. user to input the First Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "First Name" msgstr "名" +#. Translators: This label appears above a field which allows the +#. user to input the Last Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "Last Name" msgstr "姓" +#. Translators: This label appears above a field +#. which allows the user to input the State/Province/Region in which they +#. live. #. Translators: This label appears above a field on the registration form #. which allows the user to input the State/Province/Region in which they #. live. #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "State/Province/Region" msgstr "州/省/地区" @@ -10745,9 +10731,12 @@ msgid "Job Title" msgstr "职业头衔" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# +#. Translators: This label appears above a field +#. meant to hold the user's mailing address. #. Translators: This label appears above a field on the registration form #. meant to hold the user's mailing address. #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: lms/templates/signup_modal.html msgid "Mailing address" @@ -11013,7 +11002,6 @@ msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html #: themes/stanford-style/lms/templates/register-form.html msgid "Register" msgstr "注册" @@ -11133,10 +11121,6 @@ msgstr "提供的access_token无效。" msgid "Full Name cannot contain the following characters: < >" msgstr "全名中不能包含这些字符:< >" -#: openedx/core/djangoapps/user_authn/views/registration_form.py -msgid "Enter a valid name" -msgstr "" - #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "A properly formatted e-mail is required" msgstr "需要正确的邮件格式" @@ -11312,10 +11296,6 @@ msgstr "{header_open}{title}{header_close}" msgid "Dismiss" msgstr "忽略" -#: openedx/core/djangoapps/verified_track_content/models.py -msgid "The course key for the course we would like to be auto-cohorted." -msgstr "" - #: openedx/core/djangoapps/video_pipeline/models.py msgid "Oauth client name of VEM service." msgstr "" @@ -11580,51 +11560,6 @@ msgstr "" msgid "Updates" msgstr "更新" -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{sign_in_link} or {register_link} and then enroll in this course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Welcome to {course_display_name}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"You must be enrolled in the course to see course content. Please contact " -"your degree administrator or {platform_name} Support if you have questions." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"{open_enroll_link}Enroll now{close_enroll_link} to access the full course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"To start, set a course goal by selecting the option below that best " -"describes your learning plan. {goal_options_container}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {goal_text}" -msgstr "" - #: openedx/features/discounts/admin.py msgid "" "These define the context to disable lms-controlled discounts on. If no " @@ -11725,12 +11660,10 @@ msgid "Continue" msgstr "继续" #: openedx/features/personalized_learner_schedules/call_to_action.py -#: lms/templates/dates_banner.html msgid "Shift due dates" msgstr "" #: openedx/features/personalized_learner_schedules/call_to_action.py -#: lms/templates/dates_banner.html msgid "" "It looks like you missed some important deadlines based on our suggested " "schedule." @@ -12720,11 +12653,6 @@ msgstr "课程名称" msgid "Course Number" msgstr "课程代码" -#: cms/templates/course_outline.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Course Outline" -msgstr "" - #: cms/templates/html_error.html lms/templates/course_modes/error.html #: lms/templates/module-error.html msgid "Error:" @@ -12814,62 +12742,10 @@ msgstr "账号" #: lms/templates/header/navbar-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: lms/templates/static_templates/help.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -#: wiki/plugins/help/wiki_plugin.py +#: lms/templates/static_templates/help.html wiki/plugins/help/wiki_plugin.py msgid "Help" msgstr "帮助" -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Looking for help with {studio_name}?" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Hide {studio_name} Help" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "{studio_name} Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Access documentation on http://docs.edx.org" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101: Overview of Creating an edX Course" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX: Creating a Course with edX Studio" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Send an email to {email}" -msgstr "" - #: cms/templates/widgets/tabs-aggregator.html #: lms/templates/courseware/static_tab.html #: lms/templates/courseware/tab-view.html @@ -13039,19 +12915,18 @@ msgstr "浏览所有课程" #: lms/templates/dashboard.html lms/templates/header/user_dropdown.html #: lms/templates/user_dropdown.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Dashboard" msgstr "课程面板" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "results successfully populated," msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Click to load all enrolled courses" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "You are not enrolled in any courses yet." msgstr "您尚未参加任何课程。" @@ -13059,7 +12934,6 @@ msgstr "您尚未参加任何课程。" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore courses" msgstr "探索课程" @@ -13068,16 +12942,15 @@ msgstr "探索课程" msgid "Activate your account!" msgstr "激活您的账号!" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Course-loading errors" msgstr "课程加载错误" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Search Your Courses" msgstr "查找课程" #: lms/templates/courseware/courseware.html lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Clear search" msgstr "清空搜索结果" @@ -13100,15 +12973,15 @@ msgstr "" msgid "Continue to {platform_name}" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Email Settings for {course_number}" msgstr "{course_number}的电子邮件设置" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Receive course emails" msgstr "接收课程邮件" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Save Settings" msgstr "保存设置" @@ -13117,83 +12990,9 @@ msgstr "保存设置" #: lms/templates/dashboard/_dashboard_entitlement_actions.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/instructor/instructor_dashboard_2/membership.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "Unenroll" msgstr "放弃选修" -#: lms/templates/dates_banner.html -msgid "" -"It looks like you missed some important deadlines based on our suggested " -"schedule. " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future by visiting " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" Don't worry—you won't lose any of the progress you've made when you shift " -"your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future. Don't worry—you won't lose any of the " -"progress you've made when you shift your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "You are auditing this course," -msgstr "" - -#: lms/templates/dates_banner.html -msgid " which means that you are unable to participate in graded assignments." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. Graded assignments and schedule adjustment are available to " -"Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. To complete graded assignments as part of this course and shift " -"the past due assignments into the future, you can upgrade today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Upgrade to shift due dates" -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Graded assignments are available to Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" To complete graded assignments as part of this course, you can upgrade " -"today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "We've built a suggested schedule to help you stay on track." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"But don't worry—it's flexible so you can learn at your own pace. If you " -"happen to fall behind on our suggested dates, you'll be able to adjust them " -"to keep yourself on track." -msgstr "" - #: lms/templates/email_change_failed.html lms/templates/email_exists.html msgid "E-mail change failed" msgstr "邮箱变更失败" @@ -13519,10 +13318,6 @@ msgstr "设为预览模式" msgid "You are now viewing the course as {i_start}{user_name}{i_end}." msgstr "您正在以 {i_start}{user_name}{i_end} 身份查看课程。" -#: lms/templates/preview_menu.html -msgid "View in the new experience" -msgstr "" - #: lms/templates/preview_menu.html msgid "View in Studio" msgstr "" @@ -13641,9 +13436,7 @@ msgstr "" msgid "Sequence" msgstr "序列" -#: lms/templates/courseware/dates.html lms/templates/seq_module.html -#: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html +#: lms/templates/seq_module.html lms/templates/vert_module.html msgid "Completed" msgstr "" @@ -13912,7 +13705,6 @@ msgstr "" "Chrome浏览器为例,可以通过按键“Ctrl”和“+”,“Ctrl”和“-”来使用放大和缩小功能。" #: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "{subsection_format} due {{date}}" msgstr "{subsection_format} 截止日期{{date}}" @@ -13924,6 +13716,10 @@ msgstr "" msgid "Past due" msgstr "" +#: lms/templates/vert_module.html +msgid "Reset Problems" +msgstr "" + #: lms/templates/video.html msgid "Loading video player" msgstr "正在加载视频播放器" @@ -15032,7 +14828,6 @@ msgid "Download student grades" msgstr "下载学生评分" #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Print or share your certificate:" msgstr "打印或分享您的证书:" @@ -15046,7 +14841,6 @@ msgstr "发布到Facebook" #: lms/templates/certificates/_accomplishment-banner.html #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Twitter" msgstr "分享到Twitter" @@ -15055,7 +14849,6 @@ msgid "Tweet this Accomplishment. Pop up window." msgstr "推特该项成就。弹出窗口。" #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Add to LinkedIn Profile" msgstr "添加到LinkedIn的个人资料" @@ -15148,40 +14941,31 @@ msgstr "" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue the Verified Track" msgstr "跟踪已经过身份认证的的轨迹" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue a Verified Certificate" msgstr "选择认证证书" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Enroll In {course_name} | Choose Your Track" msgstr "选择 {course_name} | 选择您的方向" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Sorry, there was an error when trying to enroll you" msgstr "抱歉,在录取您时发生了错误" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with the Verified Track" msgstr "在已经过身份认证的的轨道上追求学术学分" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with a Verified Certificate" msgstr "选择认证证书并获取专业学分。" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Become eligible for academic credit and highlight your new skills and " "knowledge with a verified certificate. Use this valuable credential to " @@ -15190,59 +14974,50 @@ msgid "" msgstr "使用验证证书,让您有资格获得学分并突显您的新技能和新知识。使用这件有价值的凭证,帮助您获得学分、促进您的职业发展或增强您的学校申请竞争力。" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of the Verified Track" msgstr "已经过身份认证的轨道的好处" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Eligible for credit:{b_end} Receive academic credit after " "successfully completing the course" msgstr "{b_start}获取学分资格:{b_end} 成功完成课程后获取学分" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Unlimited Course Access: {b_end}Learn at your own pace, and access " "materials anytime to brush up on what you've learned." msgstr "{b_start}无限制的课程访问:{b_end}按照您自己的进度学习,并随时访问材料,以复习您所学到的内容。" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Graded Assignments: {b_end}Build your skills through graded " "assignments and projects." msgstr "{b_start}分级作业:{b_end}通过分级作业和项目建立您的技能。" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily Sharable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of a Verified Certificate" msgstr "认证证书的优势" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official:{b_end} Receive an instructor-signed certificate with the " "institution's logo" msgstr "{b_start}官方:{b_end} 获取带有机构徽章和导师签名的证书" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable:{b_end} Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Highlight your new knowledge and skills with a verified certificate. Use " "this valuable credential to improve your job prospects and advance your " @@ -15250,45 +15025,38 @@ msgid "" msgstr "用您的认证证书突出您的新知识和技能。使用这件有价值的凭证来改善您的就业前景,推进您的职业发展,或者在申请学校时突出您的证书。" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official: {b_end}Receive an instructor-signed certificate with the " "institution's logo" msgstr "{b_start}官方:{b_end} 获取带有机构徽章和导师签名的证书" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Motivating: {b_end}Give yourself an additional incentive to " "complete the course" msgstr "{b_start}激励: {b_end}给自己额外的动力去完成课程" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course" msgstr "旁听这门课程" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums." msgstr "免费旁听此课程并获得访问所有课程资料、活动、测试及论坛的所有权限。" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course (No Certificate)" msgstr "旁听此课程(无证书)" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded assignments," @@ -15296,7 +15064,6 @@ msgid "" msgstr "免费旁听本课程,并可访问课程资料和讨论论坛。{b_start}此轨道不包括分级作业或无限制的课程访问。{b_end}" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded " @@ -15304,7 +15071,6 @@ msgid "" msgstr "免费旁听该课程,并可访问课程材料和讨论论坛。 {b_start}此方法不包含评分作业。{b_end}" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include unlimited course " @@ -15312,7 +15078,6 @@ msgid "" msgstr "免费旁听本课程,并可访问课程资料和讨论论坛。{b_start}此轨道不包括无限制的课程访问。{b_end}" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums. {b_start}Please note that this " @@ -15397,6 +15162,10 @@ msgstr "" msgid "Choose a path for your course in" msgstr "" +#: lms/templates/course_modes/track_selection.html +msgid "Earn a certificate" +msgstr "" + #: lms/templates/course_modes/track_selection.html msgid "" "Studies show that those who choose this option are {start_bold}more engaged" @@ -15421,7 +15190,6 @@ msgstr "{span_start}当前部分{span_end}" #: lms/templates/courseware/accordion.html #: lms/templates/courseware/progress.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "due {date}" msgstr "截止日期{date}" @@ -15430,7 +15198,6 @@ msgid "{section_format} due {{date}}" msgstr "{section_format} 截止日期{{date}} " #: lms/templates/courseware/accordion.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "This content is graded" msgstr "该内容计入总分。" @@ -15442,10 +15209,6 @@ msgstr "出现错误,请稍后再试。" msgid "You are enrolled in this course" msgstr "您选修了本课程" -#: lms/templates/courseware/course_about.html -msgid "Course is full" -msgstr "该课程已满" - #: lms/templates/courseware/course_about.html msgid "Enrollment in this course is by invitation only" msgstr "该课程只能通过邀请选修" @@ -15601,30 +15364,6 @@ msgstr "如需访问课程材料,您本次考试成绩必须为{required_score msgid "Your score is {current_score}%. You have passed the entrance exam." msgstr "您的分数为 {current_score}%,通过了入门测试" -#: lms/templates/courseware/dates.html lms/templates/courseware/syllabus.html -msgid "{course.display_number_with_default} Course Info" -msgstr "{course.display_number_with_default}课程信息" - -#: lms/templates/courseware/dates.html -msgid "Important Dates" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Today" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Verified Only" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Due Next" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Not yet released" -msgstr "" - #: lms/templates/courseware/gradebook.html msgid "Gradebook" msgstr "成绩簿" @@ -15674,8 +15413,6 @@ msgstr "欢迎来到{course_title}!" #: lms/templates/courseware/info.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "Resume Course" msgstr "继续课程" @@ -15692,7 +15429,6 @@ msgid "Handout Navigation" msgstr "讲义导航" #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Tools" msgstr "课程工具" @@ -15938,6 +15674,10 @@ msgstr "不显示模拟考试成绩。" msgid "No problem scores in this section" msgstr "这部分中没有问题得分" +#: lms/templates/courseware/syllabus.html +msgid "{course.display_number_with_default} Course Info" +msgstr "{course.display_number_with_default}课程信息" + #: lms/templates/courseware/welcome-back.html msgid "" "You were most recently in {section_link}. If you're done with that, choose " @@ -16174,7 +15914,6 @@ msgid "Share {course_name} on Facebook" msgstr "分享{course_name}至Facebook" #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Facebook" msgstr "分享到Facebook" @@ -16222,6 +15961,12 @@ msgid "" "showcase on your resumé." msgstr "" +#: lms/templates/dashboard/_dashboard_course_listing.html +msgid "" +"{start_bold}Get the most out of your course!{end_bold} Upgrade to earn a " +"{link_start}verified certificate{link_end} to showcase on your resumé." +msgstr "" + #: lms/templates/dashboard/_dashboard_course_listing.html msgid "Upgrade" msgstr "" @@ -17008,7 +16753,6 @@ msgstr "" "{begin_strong}警告:{end_strong}并不完全支持您的浏览器。我们强烈推荐使用 {chrome_link} 或 {ff_link}。" #: lms/templates/header/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Discover New" msgstr "马上探索课程" @@ -17022,7 +16766,6 @@ msgstr "补充内容链接" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "How it Works" msgstr "运行机制" @@ -18440,7 +18183,6 @@ msgid "" msgstr "" #: lms/templates/learner_dashboard/_dashboard_navigation_courses.html -#: themes/edx.org/lms/templates/dashboard.html msgid "My Courses" msgstr "我的课程" @@ -18860,13 +18602,10 @@ msgid "Skeleton Page" msgstr "框架页面" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html msgid "Search the course" msgstr "搜索课程" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Start Course" msgstr "开始学习课程" @@ -19040,36 +18779,6 @@ msgstr "" msgid "View all course dates" msgstr "" -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Goal: " -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Edit your course goal:" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Pursue a verified certificate" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "" -"Sample verified certificate with your name, the course title, the logo of " -"the institution and the signatures of the instructors for this course." -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Upgrade ({price})" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Expand All" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Prerequisite: " -msgstr "" - #: openedx/features/course_experience/templates/course_experience/course-sock-fragment.html msgid "Learn About Verified Certificates" msgstr "认证证书是什么?" @@ -19150,18 +18859,6 @@ msgstr "升级({course_price})" msgid "This course does not have any updates." msgstr "此门课程没有任何更新。" -#: openedx/features/course_experience/templates/course_experience/latest-update-fragment.html -msgid "Latest Update" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/welcome-message-fragment.html -msgid "Show More" -msgstr "" - -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -msgid "Search Results" -msgstr "" - #. Translators: this section lists all the third-party authentication #. providers #. (for example, Google and LinkedIn) the user can link with or unlink from @@ -19205,10 +18902,13 @@ msgid "You haven't earned any certificates yet." msgstr "您尚未获得证书。" #: openedx/features/learner_profile/templates/learner_profile/learner-achievements-fragment.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore New Courses" msgstr "探索新课程" +#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html +msgid "Learner Profile" +msgstr "学生用户资料" + #: openedx/features/learner_profile/templates/learner_profile/learner_profile.html msgid "View My Records" msgstr "查看我的记录" @@ -19226,138 +18926,6 @@ msgstr "自定义您的{platform_name}身份。" msgid "An error occurred. Try loading the page again." msgstr "出现一个错误。尝试重试加载页面。" -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "" -"Access Course Staff Support on the Partner Portal to submit or review " -"support tickets" -msgstr "" - -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Partner Portal" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "" -"Browse recently launched courses and see what's new in your favorite " -"subjects." -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Take advantage of free coaching!" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Get Started" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Page Footer" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "edX Home Page" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Connect" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "© {year} edX Inc. All rights reserved." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "About edX Verified Certificates" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "" -"An edX Verified Certificate signifies that the learner has agreed to abide " -"by the edX honor code and completed all of the required tasks of this course" -" under its guidelines, as well as having their photo ID checked to verify " -"their identity." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "About edX" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "" -"{link_start}edX{link_end} offers interactive online classes and MOOCs from " -"the world's best universities, including MIT, Harvard, Berkeley, University " -"of Texas, and many others. edX is a mission driven initiative created by " -"founding partners Harvard and MIT." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Congratulations, {user_name}!" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "" -"You worked hard to earn your certificate from " -"{accomplishment_copy_course_org} {dash} share it with colleagues, friends, " -"and family to get the word out about what you mastered in " -"{accomplishment_course_title}." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Share this certificate on Facebook (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Tweet this certificate (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Add this certificate to your LinkedIn profile (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print this certificate" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "edX Inc." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "" -"All rights reserved except where noted. edX, Open edX and the edX and Open " -"edX logos are registered trademarks of edX Inc." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end}EdX relies on verified certificates to " -"help fund affordable education to everyone globally." -msgstr "" - -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end} EdX, a mission driven initiative, " -"relies on verified certificates to help fund free education for everyone " -"globally" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Find Courses" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Schools & Partners" -msgstr "" - #: themes/red-theme/lms/templates/footer.html msgid "" "{tos_link_start}Terms of Service{tos_link_end} and {honor_link_start}Honor " @@ -20003,6 +19571,10 @@ msgid "" "respond to student questions. You add or edit updates in HTML." msgstr "使用课程更新来通知学生重要的日期或者考试,高亮显示论坛中的特别讨论,发布进度变更,以及回复学生问题。您可以用HTML来编辑更新。" +#: cms/templates/course_outline.html +msgid "Course Outline" +msgstr "" + #: cms/templates/course_outline.html msgid "" "This course was created as a re-run. Some manual configuration is needed." @@ -22725,6 +22297,26 @@ msgstr "" msgid "Label" msgstr "标签" +#: cms/templates/widgets/sock.html +msgid "Looking for help with {studio_name}?" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "Hide {studio_name} Help" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "{studio_name} Documentation" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Access documentation on http://docs.edx.org" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "edX Documentation" +msgstr "" + #: cms/templates/widgets/sock_links.html msgid "Access the Open edX Portal" msgstr "访问 Open edX Portal" @@ -22733,6 +22325,26 @@ msgstr "访问 Open edX Portal" msgid "Open edX Portal" msgstr "Open edX Portal" +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101: Overview of Creating an edX Course" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX: Creating a Course with edX Studio" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Send an email to {email}" +msgstr "" + #: cms/templates/widgets/user_dropdown.html msgid "Currently signed in as:" msgstr "当前登录用户:" diff --git a/conf/locale/zh_CN/LC_MESSAGES/djangojs.mo b/conf/locale/zh_CN/LC_MESSAGES/djangojs.mo index b53f683f2a36a8bb45f05e67113592f5f2f97fff..3b1727886499143423f2ce86d6ec88202a0115c8 100644 GIT binary patch delta 25 hcmX>)f&1tL?uIRltBx^S=oz%HJ;u0w?J=eqi~x|P3cmmV delta 25 hcmX>)f&1tL?uIRltBx^S>KV4LJ;u0w?J=eqi~x|n3c&yX diff --git a/conf/locale/zh_CN/LC_MESSAGES/djangojs.po b/conf/locale/zh_CN/LC_MESSAGES/djangojs.po index 8c4ae71cfe..a792a847e6 100644 --- a/conf/locale/zh_CN/LC_MESSAGES/djangojs.po +++ b/conf/locale/zh_CN/LC_MESSAGES/djangojs.po @@ -226,7 +226,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: jsgang , 2015-2017,2020\n" "Language-Team: Chinese (China) (http://www.transifex.com/open-edx/edx-platform/language/zh_CN/)\n" @@ -235,7 +235,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js #: cms/static/js/views/video_transcripts.js @@ -281,7 +281,6 @@ msgstr "删除" #: common/lib/xmodule/xmodule/js/src/html/edit.js #: common/static/common/js/components/utils/view_utils.js #: lms/static/js/Markdown.Editor.js -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx #: lms/static/js/student_account/components/StudentAccountDeletionModal.jsx #: cms/templates/js/add-xblock-component-menu-problem.underscore #: cms/templates/js/add-xblock-component-menu.underscore @@ -466,6 +465,14 @@ msgstr "错误" msgid "Updating with latest library content" msgstr "更新最新的库内容" +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Loading..." +msgstr "" + +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Selected blocks" +msgstr "" + #: common/lib/xmodule/xmodule/assets/library_source_block/public/js/library_source_block.js msgid "Unable to update settings" msgstr "" @@ -1365,6 +1372,7 @@ msgstr "新建窗口" #. Translators: this is a message from the raw HTML editor displayed in the #. browser when a user needs to edit HTML #: common/lib/xmodule/xmodule/js/src/html/edit.js +#: lms/static/js/demographics_collection/Wizard.jsx #: cms/templates/js/paging-header.underscore #: common/static/common/templates/components/paging-footer.underscore #: common/static/common/templates/discussion/templates.underscore @@ -2117,6 +2125,10 @@ msgstr "查看子类目" msgid "Navigate up" msgstr "向上导航" +#: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx +msgid "Browsing" +msgstr "" + #: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx msgid "Select" msgstr "选择" @@ -2623,10 +2635,30 @@ msgid "" "within the Discussion Forum where the Course Staff can directly respond." msgstr "" +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Details" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "the more quickly and helpfully we can respond!" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Create Support Ticket" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "What can we help you with, {username}?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx msgid "Sign in to {platform} so we can help you better." msgstr "请登录{platform},以获得更好的帮助。" +#: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx +msgid "Need help logging in?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/single_support_form.jsx msgid "" "Select a course or select \"Not specific to a course\" for your support " @@ -3445,20 +3477,52 @@ msgstr "" msgid "Get started" msgstr "" -#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx -msgid "Section {currentPage} of {totalPages}" -msgstr "" - #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "Help make edX better for everyone!" msgstr "" +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Why does edX collect this information?" +msgstr "" + #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "" -"Welcome to edX! Before you get started, please take a few minutes to fill-in" -" the additional information below to help us understand a bit more about " -"your background. You can always edit this information later in Account " -"Settings." +"An error occurred while attempting to retrieve or save the information " +"below. Please try again later." +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What was the total combined income, during the last 12 months, of all " +"members of your family? " +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"Have you ever served on active duty in the U.S. Armed Forces, Reserves, or " +"National Guard?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What is the highest level of education that you have achieved so far?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What is the highest level of education that any of your parents or guardians" +" have achieved?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Select employment status" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you currently work in?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you want to work in?" msgstr "" #: lms/static/js/demographics_collection/MultiselectDropdown.jsx @@ -3473,6 +3537,22 @@ msgstr "" msgid "close questionnaire" msgstr "" +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Return to my dashboard" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "next page" +msgstr "" + #: lms/static/js/discovery/views/search_form.js #, javascript-format msgid "Viewing %s course" @@ -3757,27 +3837,6 @@ msgstr "群组已启用" msgid "Cohorts Disabled" msgstr "群组已禁用" -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course uses automatic cohorting for verified track learners. You cannot" -" disable cohorts, and you cannot rename the manual cohort named " -"'{verifiedCohortName}'. To change the configuration for verified track " -"cohorts, contact your edX partner manager." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" the required cohort does not exist. You must create a manually-assigned " -"cohort named '{verifiedCohortName}' for the feature to work." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" cohorts are disabled. You must enable cohorts for the feature to work." -msgstr "" - #: lms/static/js/instructor_dashboard/certificates.js msgid "Allow students to generate certificates for this course?" msgstr "是否允许学生生成该课程证书?" @@ -4450,10 +4509,6 @@ msgid "" "sensitive nature of student information." msgstr "由于包含涉及学生的敏感信息,生成的链接将在5分钟后失效。" -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx -msgid "You have access to the {enterpriseName} dashboard" -msgstr "" - #: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx msgid "" "To access the courses available to you through {enterpriseName}, visit the " @@ -5290,40 +5345,6 @@ msgstr "总成绩" msgid "Bookmark this page" msgstr "收藏此页" -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "Thank you for setting your course goal to {goal}!" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "" -"There was an error in setting your goal, please reload the page and try " -"again." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "You have successfully updated your goal." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "There was an error updating your goal." -msgstr "" - -#: lms/templates/ccx/schedule.underscore -msgid "Expand All" -msgstr "展开全部" - -#: lms/templates/ccx/schedule.underscore -msgid "Collapse All" -msgstr "折叠全部" - -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show More" -msgstr "显示更多" - -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show Less" -msgstr "查看收起" - #: openedx/features/course_search/static/course_search/js/views/search_results_view.js msgid "{total_results} result found for \"{search_term}\"" msgid_plural "{total_results} results found for \"{search_term}\"" @@ -5602,6 +5623,30 @@ msgstr "导入课程时出错" msgid "There was an error with the upload" msgstr "文件上传错误" +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Organization:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Number:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Run:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "(Read-only)" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Re-run Course" +msgstr "" + +#: cms/templates/js/show-textbook.underscore +msgid "View Live" +msgstr "查看在线版" + #: cms/static/js/maintenance/force_publish_course.js msgid "Internal Server Error." msgstr "内部服务器出错" @@ -7092,10 +7137,6 @@ msgstr "" msgid "follow this post" msgstr "" -#: common/static/common/templates/discussion/templates.underscore -msgid "post anonymously" -msgstr "" - #: common/static/common/templates/discussion/templates.underscore msgid "post anonymously to classmates" msgstr "" @@ -7540,6 +7581,14 @@ msgstr "在获取这个目录的预览结果时发生错误。请检查您的指 msgid "This catalog's courses:" msgstr "此目录下的课程:" +#: lms/templates/ccx/schedule.underscore +msgid "Expand All" +msgstr "展开全部" + +#: lms/templates/ccx/schedule.underscore +msgid "Collapse All" +msgstr "折叠全部" + #: lms/templates/ccx/schedule.underscore msgid "Start Date" msgstr "开始日期" @@ -7623,6 +7672,14 @@ msgid "" "before you select \"End My Exam\"." msgstr "在点击 “结束我的考试” 之前,您必须点击 \"提交\" 按钮以获得学分。" +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show More" +msgstr "显示更多" + +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show Less" +msgstr "查看收起" + #: lms/templates/discovery/course_card.underscore msgid "LEARN MORE" msgstr "了解更多" @@ -10269,10 +10326,6 @@ msgstr "如果节不设有截止日期,那么只要学员提交答案至评分 msgid "PDF Chapters" msgstr "PDF各章节" -#: cms/templates/js/show-textbook.underscore -msgid "View Live" -msgstr "查看在线版" - #: cms/templates/js/signatory-details.underscore #: cms/templates/js/signatory-editor.underscore msgid "Signatory" diff --git a/conf/locale/zh_HANS/LC_MESSAGES/django.mo b/conf/locale/zh_HANS/LC_MESSAGES/django.mo index 04efd45822bee2a750a0429fcf2d1882cfa62034..c27452fcd6cb46660886f24c6f5c6f0ce65d145d 100644 GIT binary patch delta 35 pcmX@VQTF^s*@hOz7N!>FEi5th%ochE?eX<2K+L*5zMie%CIIxV4KM%z delta 35 pcmX@VQTF^s*@hOz7N!>FEi5th%$9nF?eX<2K+L*5zMie%CIIx#4Ke@# diff --git a/conf/locale/zh_HANS/LC_MESSAGES/django.po b/conf/locale/zh_HANS/LC_MESSAGES/django.po index c3ad4640f0..beea4c18d6 100644 --- a/conf/locale/zh_HANS/LC_MESSAGES/django.po +++ b/conf/locale/zh_HANS/LC_MESSAGES/django.po @@ -397,7 +397,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:44+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: ifLab , 2019\n" "Language-Team: Chinese (China) (https://www.transifex.com/open-edx/teams/6205/zh_CN/)\n" @@ -406,7 +406,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# #. Translators: 'Discussion' refers to the tab in the courseware that leads to @@ -992,6 +992,10 @@ msgstr "课程编号无效" msgid "Could not enroll" msgstr "无法选修" +#: common/djangoapps/student/views/management.py +msgid "Unenrollment is currently disabled" +msgstr "" + #: common/djangoapps/student/views/management.py msgid "You are not enrolled in this course" msgstr "您还没有选修本课程" @@ -2052,7 +2056,6 @@ msgstr "工作人员对此问题的解答存在问题:边界未设置。" #. to the site. #: common/lib/capa/capa/responsetypes.py #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html #: themes/stanford-style/lms/templates/register-form.html msgid "or" msgstr "或者" @@ -2340,6 +2343,7 @@ msgid "Whether to force the save button to appear on the page" msgstr "是否强制显示保存按钮" #: common/lib/xmodule/xmodule/capa_module.py +#: common/lib/xmodule/xmodule/library_content_module.py msgid "Show Reset Button" msgstr "显示重置按钮" @@ -3053,7 +3057,6 @@ msgstr "输入您想要学生可以在课程首页看到此课程讲义的标题 #: common/lib/xmodule/xmodule/course_module.py #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Handouts" msgstr "课程讲义" @@ -3714,6 +3717,12 @@ msgid "" " no filtering is applied." msgstr "选择一个要从知识库中获取的问题类型,如果选择了“任意类型”,则不应用任何筛选。" +#: common/lib/xmodule/xmodule/library_content_module.py +msgid "" +"Determines whether a 'Reset Problems' button is shown, so users may reset " +"their answers and reshuffle selected items." +msgstr "" + #: common/lib/xmodule/xmodule/library_content_module.py msgid "This component is out of date. The library has new content." msgstr "该组件已过时。知识库有新的内容。" @@ -4838,8 +4847,7 @@ msgstr "解锁账户" #: lms/templates/instructor/instructor_dashboard_2/invalidate_registration_code_modal.html #: lms/templates/instructor/instructor_dashboard_2/set_course_mode_price_modal.html #: lms/templates/modal/_modal-settings-language.html -#: lms/templates/signup_modal.html themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html +#: lms/templates/signup_modal.html msgid "Close" msgstr "关闭" @@ -5260,7 +5268,6 @@ msgstr "" #. Translators: 'Open edX' is a brand, please keep this untranslated. See #. http://openedx.org for more information. #: lms/djangoapps/branding/api.py cms/templates/widgets/footer.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html #: themes/red-theme/lms/templates/footer.html msgid "Powered by Open edX" msgstr "Powered by Open edX" @@ -5270,7 +5277,6 @@ msgid "Blog" msgstr "博客" #: lms/djangoapps/branding/api.py cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html #: themes/stanford-style/lms/templates/static_templates/about.html msgid "Contact Us" msgstr "联系我们" @@ -5328,7 +5334,6 @@ msgstr "服务条款 & 荣誉准则" #: lms/djangoapps/branding/api.py lms/djangoapps/certificates/views/webview.py #: cms/templates/widgets/footer.html #: lms/templates/static_templates/privacy.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html #: themes/red-theme/lms/templates/footer.html #: themes/stanford-style/lms/templates/footer.html #: themes/stanford-style/lms/templates/static_templates/tos.html @@ -5343,6 +5348,7 @@ msgstr "可访问策略" #. Translators: This is a legal document users must agree to #. in order to register a new account. #: lms/djangoapps/branding/api.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: cms/templates/widgets/footer.html lms/templates/static_templates/tos.html #: themes/red-theme/lms/templates/footer.html @@ -5853,23 +5859,6 @@ msgid "" "this request, please visit the link(s) below." msgstr "{username} ({email}) 的退款要求已经建立。为了处理此请求,请访问以下联结(s) 。" -#: lms/djangoapps/course_goals/models.py -#: lms/templates/course_modes/track_selection.html -msgid "Earn a certificate" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Complete the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Explore the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Not sure yet" -msgstr "" - #: lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/body.html msgid "" "\n" @@ -5969,7 +5958,6 @@ msgid "Disabled" msgstr "" #: lms/djangoapps/course_home_api/outline/serializers.py -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html #, python-brace-format msgid "({number} Question)" msgid_plural "({number} Questions)" @@ -5982,6 +5970,10 @@ msgid "" "have questions." msgstr "" +#: lms/templates/courseware/course_about.html +msgid "Course is full" +msgstr "该课程已满" + #: lms/djangoapps/course_home_api/outline/views.py msgid "'course_id' is required." msgstr "" @@ -6124,20 +6116,6 @@ msgstr "选课日期" msgid "Course starts" msgstr "" -#: lms/djangoapps/courseware/date_summary.py -msgid "Don't forget to add a calendar reminder!" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} on {course_start_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} at {course_start_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Course ends" msgstr "" @@ -6161,16 +6139,6 @@ msgid "" " no longer active." msgstr "这门课程已经归档:您可以复习课程内容,但该课程不再有活动(active)。" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} on {course_end_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} at {course_end_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "You lose all access to this course, including your progress." msgstr "" @@ -6187,22 +6155,6 @@ msgstr "可申请的证书" msgid "Day certificates will become available for passing verified learners." msgstr "合格的已认证学员可获得证书的时间。" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"If you have earned a certificate, you will be able to access it " -"{time_remaining_string} from now. You will also be able to view your " -"certificates on your {learner_profile_link}." -msgstr "" - -#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html -msgid "Learner Profile" -msgstr "学生用户资料" - -#: lms/djangoapps/courseware/date_summary.py -msgid "We are working on generating course certificates." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Upgrade to Verified Certificate" msgstr "身份认证升级" @@ -6232,36 +6184,9 @@ msgstr "您仍有资格升级至认证证书!获得认证证书以突显您从 msgid "by {date}" msgstr "截止于{date}" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"Don't forget, you have {time_remaining_string} left to upgrade to a Verified" -" Certificate." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Don't forget to upgrade to a verified certificate by {localized_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"In order to qualify for a certificate, you must meet all course grading " -"requirements, upgrade before the course deadline, and successfully verify " -"your identity on {platform_name} if you have not done so " -"already.{button_panel}" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Upgrade ({upgrade_price})" -msgstr "" - #: lms/djangoapps/courseware/date_summary.py #: cms/templates/group_configurations.html #: lms/templates/courseware/program_marketing.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Learn More" msgstr "了解更多" @@ -6321,6 +6246,24 @@ msgstr "禁用此开课时间的动态升级截止日期。" msgid "Disable the dynamic upgrade deadline for this organization." msgstr "禁用此组织的动态升级截止日期。" +#: lms/djangoapps/courseware/models.py +msgid "Internal API Base URL" +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Financial Assistance Backend API Base URL." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "" +"Username created for Financial Assistance Backend, e.g. " +"financial_assistance_service_user." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Percentage of courses allowed to use edx-financial-assistance" +msgstr "" + #: lms/djangoapps/courseware/plugins.py lms/djangoapps/courseware/tabs.py #: lms/templates/peer_grading/peer_grading.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html @@ -6396,7 +6339,6 @@ msgstr "登录" #: lms/djangoapps/courseware/views/index.py #: lms/djangoapps/courseware/views/views.py #: openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "register" msgstr "注册" @@ -6446,17 +6388,6 @@ msgstr "恭喜!您已获得证书!" msgid "You've earned a certificate for this course." msgstr "您已获得此门课程的证书。" -#: lms/djangoapps/courseware/views/views.py -msgid "Certificate unavailable" -msgstr "无法查看证书" - -#: lms/djangoapps/courseware/views/views.py -#, python-brace-format -msgid "" -"You have not received a certificate because you do not have a current " -"{platform_name} verified identity." -msgstr "未进行{platform_name}身份认证无法获得证书。" - #: lms/djangoapps/courseware/views/views.py msgid "Your certificate will be available soon!" msgstr "" @@ -6471,23 +6402,31 @@ msgstr "" msgid "Your certificate is available" msgstr "您的证书已可用" +#: lms/djangoapps/courseware/views/views.py +msgid "Certificate unavailable" +msgstr "无法查看证书" + +#: lms/djangoapps/courseware/views/views.py +#, python-brace-format +msgid "" +"You have not received a certificate because you do not have a current " +"{platform_name} verified identity." +msgstr "未进行{platform_name}身份认证无法获得证书。" + #: lms/djangoapps/courseware/views/views.py #, python-brace-format msgid "To see course content, {sign_in_link} or {register_link}." msgstr "请{sign_in_link}或{register_link}以查看课程内容。" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py #, python-brace-format msgid "{sign_in_link} or {register_link}." msgstr "" #: lms/djangoapps/courseware/views/views.py #: openedx/core/djangoapps/user_authn/templates/user_authn/edx_ace/passwordresetsuccess/email/body.html -#: openedx/features/course_experience/views/course_home_messages.py #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html msgid "Sign in" msgstr "登录" @@ -6499,7 +6438,6 @@ msgid "" msgstr "" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "You must be enrolled in the course to see course content." msgstr "您必须报读此课程才能查看课程内容。" @@ -6617,6 +6555,29 @@ msgstr "上传文件出错,请联系网站管理员,谢谢。" msgid "Good" msgstr "好" +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#, python-format +msgid "" +"\n" +" %(course_name)s: Reported content awaits review\n" +" " +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +msgid "Go to Discussion" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +#, python-format +msgid "%(course_name)s: Reported content awaits review" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/subject.txt +#, python-format +msgid " %(course_name)s %(course_id)s moderator content for review " +msgstr "" + #: lms/djangoapps/discussion/templates/discussion/edx_ace/responsenotification/email/body.html #, python-format, python-brace-format msgid "%(comment_username)s replied to {start_tag}%(thread_title)s{end_tag}:" @@ -6949,10 +6910,13 @@ msgid "Team" msgstr "团队" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# +#. Translators: This label appears above a field +#. which allows the user to input the city in which they live. #. Translators: This label appears above a field on the registration form #. which allows the user to input the city in which they live. #: lms/djangoapps/instructor/views/api.py #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: lms/templates/instructor/instructor_dashboard_2/generate_registarion_codes_modal.html #: themes/stanford-style/lms/templates/register-form.html @@ -7737,7 +7701,6 @@ msgstr "( /{total} )" #: lms/templates/learner_dashboard/programs.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Programs" msgstr "程式" @@ -8611,7 +8574,6 @@ msgstr "" #: lms/templates/courseware/course_about.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "View Course" msgstr "查看课程" @@ -8874,8 +8836,6 @@ msgstr "Wiki预览" #: lms/templates/wiki/includes/cheatsheet.html lms/templates/dashboard.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/modal/_modal-settings-language.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "window open" msgstr "窗口打开" @@ -9121,9 +9081,6 @@ msgstr "您可以从其他文章中重用一些文件。但是该文件的更新 #: lms/templates/courseware/courseware.html lms/templates/dashboard.html #: lms/templates/edxnotes/edxnotes.html lms/templates/index.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -#: themes/edx.org/lms/templates/dashboard.html #: themes/stanford-style/lms/templates/index.html #: wiki/plugins/attachments/templates/wiki/plugins/attachments/index.html msgid "Search" @@ -9237,7 +9194,6 @@ msgstr "前往%(platform_name)s主页" #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Courses" msgstr "课程" @@ -10088,7 +10044,6 @@ msgid "Student" msgstr "学生" #: openedx/core/djangoapps/embargo/forms.py -#: openedx/core/djangoapps/verified_track_content/forms.py msgid "COURSE NOT FOUND. Please check that the course ID is valid." msgstr "课程未找到,请检查课程 ID 是否有效。" @@ -10140,6 +10095,10 @@ msgstr "课程{course}的白名单国家: {country}" msgid "Blacklist {country} for {course}" msgstr "课程{course}的黑名单国家: {country}" +#: openedx/core/djangoapps/learner_pathway/apps.py +msgid "Learner Pathways" +msgstr "" + #: openedx/core/djangoapps/oauth_dispatch/models.py msgid "" "Comma-separated list of scopes that this application will be allowed to " @@ -10625,6 +10584,14 @@ msgstr "请输入有效的邮箱,不少于{min}个字符。" msgid "Enter your full name." msgstr "请输入您的全名。" +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your first name." +msgstr "" + +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your last name." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "The email addresses do not match." msgstr "邮箱不一致。" @@ -10649,6 +10616,10 @@ msgstr "请输入您的职业。" msgid "Enter your specialty." msgstr "请输入您的专业技能。" +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your state." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "Enter your city." msgstr "请输入您的城市。" @@ -10690,24 +10661,39 @@ msgstr "" msgid "The '{field_name}' field cannot be edited." msgstr "'{field_name}'字段无法编辑。" +#: openedx/core/djangoapps/user_api/accounts/api.py +#: openedx/core/djangoapps/user_authn/views/registration_form.py +msgid "Enter a valid name" +msgstr "" + +#. Translators: This label appears above a field which allows the +#. user to input the First Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "First Name" msgstr "名" +#. Translators: This label appears above a field which allows the +#. user to input the Last Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "Last Name" msgstr "姓" +#. Translators: This label appears above a field +#. which allows the user to input the State/Province/Region in which they +#. live. #. Translators: This label appears above a field on the registration form #. which allows the user to input the State/Province/Region in which they #. live. #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "State/Province/Region" msgstr "州/省/地区" @@ -10745,9 +10731,12 @@ msgid "Job Title" msgstr "职业头衔" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# +#. Translators: This label appears above a field +#. meant to hold the user's mailing address. #. Translators: This label appears above a field on the registration form #. meant to hold the user's mailing address. #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: lms/templates/signup_modal.html msgid "Mailing address" @@ -11013,7 +11002,6 @@ msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html #: themes/stanford-style/lms/templates/register-form.html msgid "Register" msgstr "注册" @@ -11133,10 +11121,6 @@ msgstr "提供的access_token无效。" msgid "Full Name cannot contain the following characters: < >" msgstr "全名中不能包含这些字符:< >" -#: openedx/core/djangoapps/user_authn/views/registration_form.py -msgid "Enter a valid name" -msgstr "" - #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "A properly formatted e-mail is required" msgstr "需要正确的邮件格式" @@ -11312,10 +11296,6 @@ msgstr "{header_open}{title}{header_close}" msgid "Dismiss" msgstr "忽略" -#: openedx/core/djangoapps/verified_track_content/models.py -msgid "The course key for the course we would like to be auto-cohorted." -msgstr "" - #: openedx/core/djangoapps/video_pipeline/models.py msgid "Oauth client name of VEM service." msgstr "" @@ -11580,51 +11560,6 @@ msgstr "" msgid "Updates" msgstr "更新" -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{sign_in_link} or {register_link} and then enroll in this course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Welcome to {course_display_name}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"You must be enrolled in the course to see course content. Please contact " -"your degree administrator or {platform_name} Support if you have questions." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"{open_enroll_link}Enroll now{close_enroll_link} to access the full course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"To start, set a course goal by selecting the option below that best " -"describes your learning plan. {goal_options_container}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {goal_text}" -msgstr "" - #: openedx/features/discounts/admin.py msgid "" "These define the context to disable lms-controlled discounts on. If no " @@ -11725,12 +11660,10 @@ msgid "Continue" msgstr "继续" #: openedx/features/personalized_learner_schedules/call_to_action.py -#: lms/templates/dates_banner.html msgid "Shift due dates" msgstr "" #: openedx/features/personalized_learner_schedules/call_to_action.py -#: lms/templates/dates_banner.html msgid "" "It looks like you missed some important deadlines based on our suggested " "schedule." @@ -12720,11 +12653,6 @@ msgstr "课程名称" msgid "Course Number" msgstr "课程代码" -#: cms/templates/course_outline.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Course Outline" -msgstr "" - #: cms/templates/html_error.html lms/templates/course_modes/error.html #: lms/templates/module-error.html msgid "Error:" @@ -12814,62 +12742,10 @@ msgstr "账号" #: lms/templates/header/navbar-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: lms/templates/static_templates/help.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -#: wiki/plugins/help/wiki_plugin.py +#: lms/templates/static_templates/help.html wiki/plugins/help/wiki_plugin.py msgid "Help" msgstr "帮助" -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Looking for help with {studio_name}?" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Hide {studio_name} Help" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "{studio_name} Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Access documentation on http://docs.edx.org" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101: Overview of Creating an edX Course" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX: Creating a Course with edX Studio" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Send an email to {email}" -msgstr "" - #: cms/templates/widgets/tabs-aggregator.html #: lms/templates/courseware/static_tab.html #: lms/templates/courseware/tab-view.html @@ -13039,19 +12915,18 @@ msgstr "浏览所有课程" #: lms/templates/dashboard.html lms/templates/header/user_dropdown.html #: lms/templates/user_dropdown.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Dashboard" msgstr "课程面板" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "results successfully populated," msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Click to load all enrolled courses" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "You are not enrolled in any courses yet." msgstr "您尚未参加任何课程。" @@ -13059,7 +12934,6 @@ msgstr "您尚未参加任何课程。" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore courses" msgstr "探索课程" @@ -13068,16 +12942,15 @@ msgstr "探索课程" msgid "Activate your account!" msgstr "激活您的账号!" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Course-loading errors" msgstr "课程加载错误" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Search Your Courses" msgstr "查找课程" #: lms/templates/courseware/courseware.html lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Clear search" msgstr "清空搜索结果" @@ -13100,15 +12973,15 @@ msgstr "" msgid "Continue to {platform_name}" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Email Settings for {course_number}" msgstr "{course_number}的电子邮件设置" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Receive course emails" msgstr "接收课程邮件" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Save Settings" msgstr "保存设置" @@ -13117,83 +12990,9 @@ msgstr "保存设置" #: lms/templates/dashboard/_dashboard_entitlement_actions.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/instructor/instructor_dashboard_2/membership.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "Unenroll" msgstr "放弃选修" -#: lms/templates/dates_banner.html -msgid "" -"It looks like you missed some important deadlines based on our suggested " -"schedule. " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future by visiting " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" Don't worry—you won't lose any of the progress you've made when you shift " -"your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future. Don't worry—you won't lose any of the " -"progress you've made when you shift your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "You are auditing this course," -msgstr "" - -#: lms/templates/dates_banner.html -msgid " which means that you are unable to participate in graded assignments." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. Graded assignments and schedule adjustment are available to " -"Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. To complete graded assignments as part of this course and shift " -"the past due assignments into the future, you can upgrade today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Upgrade to shift due dates" -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Graded assignments are available to Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" To complete graded assignments as part of this course, you can upgrade " -"today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "We've built a suggested schedule to help you stay on track." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"But don't worry—it's flexible so you can learn at your own pace. If you " -"happen to fall behind on our suggested dates, you'll be able to adjust them " -"to keep yourself on track." -msgstr "" - #: lms/templates/email_change_failed.html lms/templates/email_exists.html msgid "E-mail change failed" msgstr "邮箱变更失败" @@ -13519,10 +13318,6 @@ msgstr "设为预览模式" msgid "You are now viewing the course as {i_start}{user_name}{i_end}." msgstr "您正在以 {i_start}{user_name}{i_end} 身份查看课程。" -#: lms/templates/preview_menu.html -msgid "View in the new experience" -msgstr "" - #: lms/templates/preview_menu.html msgid "View in Studio" msgstr "" @@ -13641,9 +13436,7 @@ msgstr "" msgid "Sequence" msgstr "序列" -#: lms/templates/courseware/dates.html lms/templates/seq_module.html -#: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html +#: lms/templates/seq_module.html lms/templates/vert_module.html msgid "Completed" msgstr "" @@ -13912,7 +13705,6 @@ msgstr "" "Chrome浏览器为例,可以通过按键“Ctrl”和“+”,“Ctrl”和“-”来使用放大和缩小功能。" #: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "{subsection_format} due {{date}}" msgstr "{subsection_format} 截止日期{{date}}" @@ -13924,6 +13716,10 @@ msgstr "" msgid "Past due" msgstr "" +#: lms/templates/vert_module.html +msgid "Reset Problems" +msgstr "" + #: lms/templates/video.html msgid "Loading video player" msgstr "正在加载视频播放器" @@ -15032,7 +14828,6 @@ msgid "Download student grades" msgstr "下载学生评分" #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Print or share your certificate:" msgstr "打印或分享您的证书:" @@ -15046,7 +14841,6 @@ msgstr "发布到Facebook" #: lms/templates/certificates/_accomplishment-banner.html #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Twitter" msgstr "分享到Twitter" @@ -15055,7 +14849,6 @@ msgid "Tweet this Accomplishment. Pop up window." msgstr "推特该项成就。弹出窗口。" #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Add to LinkedIn Profile" msgstr "添加到LinkedIn的个人资料" @@ -15148,40 +14941,31 @@ msgstr "" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue the Verified Track" msgstr "跟踪已经过身份认证的的轨迹" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue a Verified Certificate" msgstr "选择认证证书" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Enroll In {course_name} | Choose Your Track" msgstr "选择 {course_name} | 选择您的方向" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Sorry, there was an error when trying to enroll you" msgstr "抱歉,在录取您时发生了错误" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with the Verified Track" msgstr "在已经过身份认证的的轨道上追求学术学分" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with a Verified Certificate" msgstr "选择认证证书并获取专业学分。" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Become eligible for academic credit and highlight your new skills and " "knowledge with a verified certificate. Use this valuable credential to " @@ -15190,59 +14974,50 @@ msgid "" msgstr "使用验证证书,让您有资格获得学分并突显您的新技能和新知识。使用这件有价值的凭证,帮助您获得学分、促进您的职业发展或增强您的学校申请竞争力。" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of the Verified Track" msgstr "已经过身份认证的轨道的好处" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Eligible for credit:{b_end} Receive academic credit after " "successfully completing the course" msgstr "{b_start}获取学分资格:{b_end} 成功完成课程后获取学分" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Unlimited Course Access: {b_end}Learn at your own pace, and access " "materials anytime to brush up on what you've learned." msgstr "{b_start}无限制的课程访问:{b_end}按照您自己的进度学习,并随时访问材料,以复习您所学到的内容。" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Graded Assignments: {b_end}Build your skills through graded " "assignments and projects." msgstr "{b_start}分级作业:{b_end}通过分级作业和项目建立您的技能。" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily Sharable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of a Verified Certificate" msgstr "认证证书的优势" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official:{b_end} Receive an instructor-signed certificate with the " "institution's logo" msgstr "{b_start}官方:{b_end} 获取带有机构徽章和导师签名的证书" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable:{b_end} Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Highlight your new knowledge and skills with a verified certificate. Use " "this valuable credential to improve your job prospects and advance your " @@ -15250,45 +15025,38 @@ msgid "" msgstr "用您的认证证书突出您的新知识和技能。使用这件有价值的凭证来改善您的就业前景,推进您的职业发展,或者在申请学校时突出您的证书。" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official: {b_end}Receive an instructor-signed certificate with the " "institution's logo" msgstr "{b_start}官方:{b_end} 获取带有机构徽章和导师签名的证书" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Motivating: {b_end}Give yourself an additional incentive to " "complete the course" msgstr "{b_start}激励: {b_end}给自己额外的动力去完成课程" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course" msgstr "旁听这门课程" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums." msgstr "免费旁听此课程并获得访问所有课程资料、活动、测试及论坛的所有权限。" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course (No Certificate)" msgstr "旁听此课程(无证书)" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded assignments," @@ -15296,7 +15064,6 @@ msgid "" msgstr "免费旁听本课程,并可访问课程资料和讨论论坛。{b_start}此轨道不包括分级作业或无限制的课程访问。{b_end}" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded " @@ -15304,7 +15071,6 @@ msgid "" msgstr "免费旁听该课程,并可访问课程材料和讨论论坛。 {b_start}此方法不包含评分作业。{b_end}" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include unlimited course " @@ -15312,7 +15078,6 @@ msgid "" msgstr "免费旁听本课程,并可访问课程资料和讨论论坛。{b_start}此轨道不包括无限制的课程访问。{b_end}" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums. {b_start}Please note that this " @@ -15397,6 +15162,10 @@ msgstr "" msgid "Choose a path for your course in" msgstr "" +#: lms/templates/course_modes/track_selection.html +msgid "Earn a certificate" +msgstr "" + #: lms/templates/course_modes/track_selection.html msgid "" "Studies show that those who choose this option are {start_bold}more engaged" @@ -15421,7 +15190,6 @@ msgstr "{span_start}当前部分{span_end}" #: lms/templates/courseware/accordion.html #: lms/templates/courseware/progress.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "due {date}" msgstr "截止日期{date}" @@ -15430,7 +15198,6 @@ msgid "{section_format} due {{date}}" msgstr "{section_format} 截止日期{{date}} " #: lms/templates/courseware/accordion.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "This content is graded" msgstr "该内容计入总分。" @@ -15442,10 +15209,6 @@ msgstr "出现错误,请稍后再试。" msgid "You are enrolled in this course" msgstr "您选修了本课程" -#: lms/templates/courseware/course_about.html -msgid "Course is full" -msgstr "该课程已满" - #: lms/templates/courseware/course_about.html msgid "Enrollment in this course is by invitation only" msgstr "该课程只能通过邀请选修" @@ -15601,30 +15364,6 @@ msgstr "如需访问课程材料,您本次考试成绩必须为{required_score msgid "Your score is {current_score}%. You have passed the entrance exam." msgstr "您的分数为 {current_score}%,通过了入门测试" -#: lms/templates/courseware/dates.html lms/templates/courseware/syllabus.html -msgid "{course.display_number_with_default} Course Info" -msgstr "{course.display_number_with_default}课程信息" - -#: lms/templates/courseware/dates.html -msgid "Important Dates" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Today" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Verified Only" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Due Next" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Not yet released" -msgstr "" - #: lms/templates/courseware/gradebook.html msgid "Gradebook" msgstr "成绩簿" @@ -15674,8 +15413,6 @@ msgstr "欢迎来到{course_title}!" #: lms/templates/courseware/info.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "Resume Course" msgstr "继续课程" @@ -15692,7 +15429,6 @@ msgid "Handout Navigation" msgstr "讲义导航" #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Tools" msgstr "课程工具" @@ -15938,6 +15674,10 @@ msgstr "不显示模拟考试成绩。" msgid "No problem scores in this section" msgstr "这部分中没有问题得分" +#: lms/templates/courseware/syllabus.html +msgid "{course.display_number_with_default} Course Info" +msgstr "{course.display_number_with_default}课程信息" + #: lms/templates/courseware/welcome-back.html msgid "" "You were most recently in {section_link}. If you're done with that, choose " @@ -16174,7 +15914,6 @@ msgid "Share {course_name} on Facebook" msgstr "分享{course_name}至Facebook" #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Facebook" msgstr "分享到Facebook" @@ -16222,6 +15961,12 @@ msgid "" "showcase on your resumé." msgstr "" +#: lms/templates/dashboard/_dashboard_course_listing.html +msgid "" +"{start_bold}Get the most out of your course!{end_bold} Upgrade to earn a " +"{link_start}verified certificate{link_end} to showcase on your resumé." +msgstr "" + #: lms/templates/dashboard/_dashboard_course_listing.html msgid "Upgrade" msgstr "" @@ -17008,7 +16753,6 @@ msgstr "" "{begin_strong}警告:{end_strong}并不完全支持您的浏览器。我们强烈推荐使用 {chrome_link} 或 {ff_link}。" #: lms/templates/header/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Discover New" msgstr "马上探索课程" @@ -17022,7 +16766,6 @@ msgstr "补充内容链接" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "How it Works" msgstr "运行机制" @@ -18440,7 +18183,6 @@ msgid "" msgstr "" #: lms/templates/learner_dashboard/_dashboard_navigation_courses.html -#: themes/edx.org/lms/templates/dashboard.html msgid "My Courses" msgstr "我的课程" @@ -18860,13 +18602,10 @@ msgid "Skeleton Page" msgstr "框架页面" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html msgid "Search the course" msgstr "搜索课程" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Start Course" msgstr "开始学习课程" @@ -19040,36 +18779,6 @@ msgstr "" msgid "View all course dates" msgstr "" -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Goal: " -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Edit your course goal:" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Pursue a verified certificate" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "" -"Sample verified certificate with your name, the course title, the logo of " -"the institution and the signatures of the instructors for this course." -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Upgrade ({price})" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Expand All" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Prerequisite: " -msgstr "" - #: openedx/features/course_experience/templates/course_experience/course-sock-fragment.html msgid "Learn About Verified Certificates" msgstr "认证证书是什么?" @@ -19150,18 +18859,6 @@ msgstr "升级({course_price})" msgid "This course does not have any updates." msgstr "此门课程没有任何更新。" -#: openedx/features/course_experience/templates/course_experience/latest-update-fragment.html -msgid "Latest Update" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/welcome-message-fragment.html -msgid "Show More" -msgstr "" - -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -msgid "Search Results" -msgstr "" - #. Translators: this section lists all the third-party authentication #. providers #. (for example, Google and LinkedIn) the user can link with or unlink from @@ -19205,10 +18902,13 @@ msgid "You haven't earned any certificates yet." msgstr "您尚未获得证书。" #: openedx/features/learner_profile/templates/learner_profile/learner-achievements-fragment.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore New Courses" msgstr "探索新课程" +#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html +msgid "Learner Profile" +msgstr "学生用户资料" + #: openedx/features/learner_profile/templates/learner_profile/learner_profile.html msgid "View My Records" msgstr "查看我的记录" @@ -19226,138 +18926,6 @@ msgstr "自定义您的{platform_name}身份。" msgid "An error occurred. Try loading the page again." msgstr "出现一个错误。尝试重试加载页面。" -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "" -"Access Course Staff Support on the Partner Portal to submit or review " -"support tickets" -msgstr "" - -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Partner Portal" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "" -"Browse recently launched courses and see what's new in your favorite " -"subjects." -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Take advantage of free coaching!" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Get Started" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Page Footer" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "edX Home Page" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Connect" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "© {year} edX Inc. All rights reserved." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "About edX Verified Certificates" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "" -"An edX Verified Certificate signifies that the learner has agreed to abide " -"by the edX honor code and completed all of the required tasks of this course" -" under its guidelines, as well as having their photo ID checked to verify " -"their identity." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "About edX" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "" -"{link_start}edX{link_end} offers interactive online classes and MOOCs from " -"the world's best universities, including MIT, Harvard, Berkeley, University " -"of Texas, and many others. edX is a mission driven initiative created by " -"founding partners Harvard and MIT." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Congratulations, {user_name}!" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "" -"You worked hard to earn your certificate from " -"{accomplishment_copy_course_org} {dash} share it with colleagues, friends, " -"and family to get the word out about what you mastered in " -"{accomplishment_course_title}." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Share this certificate on Facebook (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Tweet this certificate (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Add this certificate to your LinkedIn profile (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print this certificate" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "edX Inc." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "" -"All rights reserved except where noted. edX, Open edX and the edX and Open " -"edX logos are registered trademarks of edX Inc." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end}EdX relies on verified certificates to " -"help fund affordable education to everyone globally." -msgstr "" - -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end} EdX, a mission driven initiative, " -"relies on verified certificates to help fund free education for everyone " -"globally" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Find Courses" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Schools & Partners" -msgstr "" - #: themes/red-theme/lms/templates/footer.html msgid "" "{tos_link_start}Terms of Service{tos_link_end} and {honor_link_start}Honor " @@ -20003,6 +19571,10 @@ msgid "" "respond to student questions. You add or edit updates in HTML." msgstr "使用课程更新来通知学生重要的日期或者考试,高亮显示论坛中的特别讨论,发布进度变更,以及回复学生问题。您可以用HTML来编辑更新。" +#: cms/templates/course_outline.html +msgid "Course Outline" +msgstr "" + #: cms/templates/course_outline.html msgid "" "This course was created as a re-run. Some manual configuration is needed." @@ -22725,6 +22297,26 @@ msgstr "" msgid "Label" msgstr "标签" +#: cms/templates/widgets/sock.html +msgid "Looking for help with {studio_name}?" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "Hide {studio_name} Help" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "{studio_name} Documentation" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Access documentation on http://docs.edx.org" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "edX Documentation" +msgstr "" + #: cms/templates/widgets/sock_links.html msgid "Access the Open edX Portal" msgstr "访问 Open edX Portal" @@ -22733,6 +22325,26 @@ msgstr "访问 Open edX Portal" msgid "Open edX Portal" msgstr "Open edX Portal" +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101: Overview of Creating an edX Course" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX: Creating a Course with edX Studio" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Send an email to {email}" +msgstr "" + #: cms/templates/widgets/user_dropdown.html msgid "Currently signed in as:" msgstr "当前登录用户:" diff --git a/conf/locale/zh_HANS/LC_MESSAGES/djangojs.mo b/conf/locale/zh_HANS/LC_MESSAGES/djangojs.mo index b53f683f2a36a8bb45f05e67113592f5f2f97fff..3b1727886499143423f2ce86d6ec88202a0115c8 100644 GIT binary patch delta 25 hcmX>)f&1tL?uIRltBx^S=oz%HJ;u0w?J=eqi~x|P3cmmV delta 25 hcmX>)f&1tL?uIRltBx^S>KV4LJ;u0w?J=eqi~x|n3c&yX diff --git a/conf/locale/zh_HANS/LC_MESSAGES/djangojs.po b/conf/locale/zh_HANS/LC_MESSAGES/djangojs.po index 8c4ae71cfe..a792a847e6 100644 --- a/conf/locale/zh_HANS/LC_MESSAGES/djangojs.po +++ b/conf/locale/zh_HANS/LC_MESSAGES/djangojs.po @@ -226,7 +226,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: jsgang , 2015-2017,2020\n" "Language-Team: Chinese (China) (http://www.transifex.com/open-edx/edx-platform/language/zh_CN/)\n" @@ -235,7 +235,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js #: cms/static/js/views/video_transcripts.js @@ -281,7 +281,6 @@ msgstr "删除" #: common/lib/xmodule/xmodule/js/src/html/edit.js #: common/static/common/js/components/utils/view_utils.js #: lms/static/js/Markdown.Editor.js -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx #: lms/static/js/student_account/components/StudentAccountDeletionModal.jsx #: cms/templates/js/add-xblock-component-menu-problem.underscore #: cms/templates/js/add-xblock-component-menu.underscore @@ -466,6 +465,14 @@ msgstr "错误" msgid "Updating with latest library content" msgstr "更新最新的库内容" +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Loading..." +msgstr "" + +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Selected blocks" +msgstr "" + #: common/lib/xmodule/xmodule/assets/library_source_block/public/js/library_source_block.js msgid "Unable to update settings" msgstr "" @@ -1365,6 +1372,7 @@ msgstr "新建窗口" #. Translators: this is a message from the raw HTML editor displayed in the #. browser when a user needs to edit HTML #: common/lib/xmodule/xmodule/js/src/html/edit.js +#: lms/static/js/demographics_collection/Wizard.jsx #: cms/templates/js/paging-header.underscore #: common/static/common/templates/components/paging-footer.underscore #: common/static/common/templates/discussion/templates.underscore @@ -2117,6 +2125,10 @@ msgstr "查看子类目" msgid "Navigate up" msgstr "向上导航" +#: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx +msgid "Browsing" +msgstr "" + #: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx msgid "Select" msgstr "选择" @@ -2623,10 +2635,30 @@ msgid "" "within the Discussion Forum where the Course Staff can directly respond." msgstr "" +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Details" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "the more quickly and helpfully we can respond!" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Create Support Ticket" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "What can we help you with, {username}?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx msgid "Sign in to {platform} so we can help you better." msgstr "请登录{platform},以获得更好的帮助。" +#: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx +msgid "Need help logging in?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/single_support_form.jsx msgid "" "Select a course or select \"Not specific to a course\" for your support " @@ -3445,20 +3477,52 @@ msgstr "" msgid "Get started" msgstr "" -#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx -msgid "Section {currentPage} of {totalPages}" -msgstr "" - #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "Help make edX better for everyone!" msgstr "" +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Why does edX collect this information?" +msgstr "" + #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "" -"Welcome to edX! Before you get started, please take a few minutes to fill-in" -" the additional information below to help us understand a bit more about " -"your background. You can always edit this information later in Account " -"Settings." +"An error occurred while attempting to retrieve or save the information " +"below. Please try again later." +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What was the total combined income, during the last 12 months, of all " +"members of your family? " +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"Have you ever served on active duty in the U.S. Armed Forces, Reserves, or " +"National Guard?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What is the highest level of education that you have achieved so far?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What is the highest level of education that any of your parents or guardians" +" have achieved?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Select employment status" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you currently work in?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you want to work in?" msgstr "" #: lms/static/js/demographics_collection/MultiselectDropdown.jsx @@ -3473,6 +3537,22 @@ msgstr "" msgid "close questionnaire" msgstr "" +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Return to my dashboard" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "next page" +msgstr "" + #: lms/static/js/discovery/views/search_form.js #, javascript-format msgid "Viewing %s course" @@ -3757,27 +3837,6 @@ msgstr "群组已启用" msgid "Cohorts Disabled" msgstr "群组已禁用" -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course uses automatic cohorting for verified track learners. You cannot" -" disable cohorts, and you cannot rename the manual cohort named " -"'{verifiedCohortName}'. To change the configuration for verified track " -"cohorts, contact your edX partner manager." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" the required cohort does not exist. You must create a manually-assigned " -"cohort named '{verifiedCohortName}' for the feature to work." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" cohorts are disabled. You must enable cohorts for the feature to work." -msgstr "" - #: lms/static/js/instructor_dashboard/certificates.js msgid "Allow students to generate certificates for this course?" msgstr "是否允许学生生成该课程证书?" @@ -4450,10 +4509,6 @@ msgid "" "sensitive nature of student information." msgstr "由于包含涉及学生的敏感信息,生成的链接将在5分钟后失效。" -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx -msgid "You have access to the {enterpriseName} dashboard" -msgstr "" - #: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx msgid "" "To access the courses available to you through {enterpriseName}, visit the " @@ -5290,40 +5345,6 @@ msgstr "总成绩" msgid "Bookmark this page" msgstr "收藏此页" -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "Thank you for setting your course goal to {goal}!" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "" -"There was an error in setting your goal, please reload the page and try " -"again." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "You have successfully updated your goal." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "There was an error updating your goal." -msgstr "" - -#: lms/templates/ccx/schedule.underscore -msgid "Expand All" -msgstr "展开全部" - -#: lms/templates/ccx/schedule.underscore -msgid "Collapse All" -msgstr "折叠全部" - -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show More" -msgstr "显示更多" - -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show Less" -msgstr "查看收起" - #: openedx/features/course_search/static/course_search/js/views/search_results_view.js msgid "{total_results} result found for \"{search_term}\"" msgid_plural "{total_results} results found for \"{search_term}\"" @@ -5602,6 +5623,30 @@ msgstr "导入课程时出错" msgid "There was an error with the upload" msgstr "文件上传错误" +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Organization:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Number:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Run:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "(Read-only)" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Re-run Course" +msgstr "" + +#: cms/templates/js/show-textbook.underscore +msgid "View Live" +msgstr "查看在线版" + #: cms/static/js/maintenance/force_publish_course.js msgid "Internal Server Error." msgstr "内部服务器出错" @@ -7092,10 +7137,6 @@ msgstr "" msgid "follow this post" msgstr "" -#: common/static/common/templates/discussion/templates.underscore -msgid "post anonymously" -msgstr "" - #: common/static/common/templates/discussion/templates.underscore msgid "post anonymously to classmates" msgstr "" @@ -7540,6 +7581,14 @@ msgstr "在获取这个目录的预览结果时发生错误。请检查您的指 msgid "This catalog's courses:" msgstr "此目录下的课程:" +#: lms/templates/ccx/schedule.underscore +msgid "Expand All" +msgstr "展开全部" + +#: lms/templates/ccx/schedule.underscore +msgid "Collapse All" +msgstr "折叠全部" + #: lms/templates/ccx/schedule.underscore msgid "Start Date" msgstr "开始日期" @@ -7623,6 +7672,14 @@ msgid "" "before you select \"End My Exam\"." msgstr "在点击 “结束我的考试” 之前,您必须点击 \"提交\" 按钮以获得学分。" +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show More" +msgstr "显示更多" + +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show Less" +msgstr "查看收起" + #: lms/templates/discovery/course_card.underscore msgid "LEARN MORE" msgstr "了解更多" @@ -10269,10 +10326,6 @@ msgstr "如果节不设有截止日期,那么只要学员提交答案至评分 msgid "PDF Chapters" msgstr "PDF各章节" -#: cms/templates/js/show-textbook.underscore -msgid "View Live" -msgstr "查看在线版" - #: cms/templates/js/signatory-details.underscore #: cms/templates/js/signatory-editor.underscore msgid "Signatory" diff --git a/conf/locale/zh_TW/LC_MESSAGES/django.mo b/conf/locale/zh_TW/LC_MESSAGES/django.mo index 90b35e563b60bf541f7feaddf9ded79bed48b72d..16f36c08f3b61207a0d20b276e6f32f57bb71879 100644 GIT binary patch delta 27 icmaFR#{Zy=zoCV33zKI!vxS~PyH7aNcAs!&ksJVyDG2BQ delta 27 icmaFR#{Zy=zoCV33zKI!v!$M4yH7aNcAs!&ksJVyK?v#q diff --git a/conf/locale/zh_TW/LC_MESSAGES/django.po b/conf/locale/zh_TW/LC_MESSAGES/django.po index d2fae9f026..c83427d85a 100644 --- a/conf/locale/zh_TW/LC_MESSAGES/django.po +++ b/conf/locale/zh_TW/LC_MESSAGES/django.po @@ -177,7 +177,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1a\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:44+0000\n" "PO-Revision-Date: 2019-01-20 20:43+0000\n" "Last-Translator: Waheed Ahmed , 2019\n" "Language-Team: Chinese (Taiwan) (https://www.transifex.com/open-edx/teams/6205/zh_TW/)\n" @@ -186,7 +186,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #. Translators: 'Discussion' refers to the tab in the courseware that leads to #. the discussion forums @@ -761,6 +761,10 @@ msgstr "課程編號無效" msgid "Could not enroll" msgstr "不能註冊" +#: common/djangoapps/student/views/management.py +msgid "Unenrollment is currently disabled" +msgstr "" + #: common/djangoapps/student/views/management.py msgid "You are not enrolled in this course" msgstr "您還沒有註冊本課程" @@ -1813,7 +1817,6 @@ msgstr "存在與工作人員回答了這個問題的一個問題:空邊界。 #. to the site. #: common/lib/capa/capa/responsetypes.py #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html #: themes/stanford-style/lms/templates/register-form.html msgid "or" msgstr "或者" @@ -2101,6 +2104,7 @@ msgid "Whether to force the save button to appear on the page" msgstr "是否強制 儲存按鈕 顯示在這個頁面上" #: common/lib/xmodule/xmodule/capa_module.py +#: common/lib/xmodule/xmodule/library_content_module.py msgid "Show Reset Button" msgstr "顯示重新設定按鈕" @@ -2811,7 +2815,6 @@ msgstr "輸入您想要學生可以在課程首頁看到此課程講義的標題 #: common/lib/xmodule/xmodule/course_module.py #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Handouts" msgstr "課程講義" @@ -3462,6 +3465,12 @@ msgid "" " no filtering is applied." msgstr "從課程組件庫中選擇一個問題類型,如果選擇“任何類型”則不進行過濾。" +#: common/lib/xmodule/xmodule/library_content_module.py +msgid "" +"Determines whether a 'Reset Problems' button is shown, so users may reset " +"their answers and reshuffle selected items." +msgstr "" + #: common/lib/xmodule/xmodule/library_content_module.py msgid "This component is out of date. The library has new content." msgstr "此組件已過期,課程組件庫中有新的內容。" @@ -4583,8 +4592,7 @@ msgstr "" #: lms/templates/instructor/instructor_dashboard_2/invalidate_registration_code_modal.html #: lms/templates/instructor/instructor_dashboard_2/set_course_mode_price_modal.html #: lms/templates/modal/_modal-settings-language.html -#: lms/templates/signup_modal.html themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html +#: lms/templates/signup_modal.html msgid "Close" msgstr "關閉" @@ -4998,7 +5006,6 @@ msgstr "" #. Translators: 'Open edX' is a brand, please keep this untranslated. See #. http://openedx.org for more information. #: lms/djangoapps/branding/api.py cms/templates/widgets/footer.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html #: themes/red-theme/lms/templates/footer.html msgid "Powered by Open edX" msgstr "由 Open edX 技術支援" @@ -5008,7 +5015,6 @@ msgid "Blog" msgstr "部落格" #: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html #: themes/stanford-style/lms/templates/static_templates/about.html msgid "Contact Us" msgstr "聯繫我們" @@ -5063,7 +5069,6 @@ msgstr "服務條款和榮譽守則" #: lms/djangoapps/branding/api.py lms/djangoapps/certificates/views/webview.py #: cms/templates/widgets/footer.html #: lms/templates/static_templates/privacy.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html #: themes/red-theme/lms/templates/footer.html #: themes/stanford-style/lms/templates/footer.html #: themes/stanford-style/lms/templates/static_templates/tos.html @@ -5078,6 +5083,7 @@ msgstr "可訪性政策" #. Translators: This is a legal document users must agree to #. in order to register a new account. #: lms/djangoapps/branding/api.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: cms/templates/widgets/footer.html lms/templates/static_templates/tos.html #: themes/red-theme/lms/templates/footer.html @@ -5585,23 +5591,6 @@ msgid "" "this request, please visit the link(s) below." msgstr "{username} ({email}) 的退款要求已經建立。為了處理此請求,請訪問以下聯結(s) 。" -#: lms/djangoapps/course_goals/models.py -#: lms/templates/course_modes/track_selection.html -msgid "Earn a certificate" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Complete the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Explore the course" -msgstr "" - -#: lms/djangoapps/course_goals/models.py -msgid "Not sure yet" -msgstr "" - #: lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/body.html msgid "" "\n" @@ -5701,7 +5690,6 @@ msgid "Disabled" msgstr "" #: lms/djangoapps/course_home_api/outline/serializers.py -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html #, python-brace-format msgid "({number} Question)" msgid_plural "({number} Questions)" @@ -5714,6 +5702,10 @@ msgid "" "have questions." msgstr "" +#: lms/templates/courseware/course_about.html +msgid "Course is full" +msgstr "課程已滿" + #: lms/djangoapps/course_home_api/outline/views.py msgid "'course_id' is required." msgstr "" @@ -5855,20 +5847,6 @@ msgstr "註冊日期" msgid "Course starts" msgstr "" -#: lms/djangoapps/courseware/date_summary.py -msgid "Don't forget to add a calendar reminder!" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} on {course_start_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Course starts in {time_remaining_string} at {course_start_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Course ends" msgstr "" @@ -5892,16 +5870,6 @@ msgid "" " no longer active." msgstr "這門課程已經歸檔:您可以複習課程內容,但該課程不再有活動(active)。" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} on {course_end_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "This course is ending in {time_remaining_string} at {course_end_time}." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "You lose all access to this course, including your progress." msgstr "" @@ -5918,23 +5886,6 @@ msgstr "" msgid "Day certificates will become available for passing verified learners." msgstr "" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"If you have earned a certificate, you will be able to access it " -"{time_remaining_string} from now. You will also be able to view your " -"certificates on your {learner_profile_link}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html -msgid "Learner Profile" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -msgid "We are working on generating course certificates." -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Upgrade to Verified Certificate" msgstr "身分認證升級" @@ -5964,32 +5915,6 @@ msgstr "您仍有機會升級至認證學程!藉由升級您可以獲得證書 msgid "by {date}" msgstr "" -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"Don't forget, you have {time_remaining_string} left to upgrade to a Verified" -" Certificate." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Don't forget to upgrade to a verified certificate by {localized_date}." -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "" -"In order to qualify for a certificate, you must meet all course grading " -"requirements, upgrade before the course deadline, and successfully verify " -"your identity on {platform_name} if you have not done so " -"already.{button_panel}" -msgstr "" - -#: lms/djangoapps/courseware/date_summary.py -#, python-brace-format -msgid "Upgrade ({upgrade_price})" -msgstr "" - #: lms/djangoapps/courseware/date_summary.py msgid "Learn More" msgstr "了解更多" @@ -6050,6 +5975,24 @@ msgstr "" msgid "Disable the dynamic upgrade deadline for this organization." msgstr "" +#: lms/djangoapps/courseware/models.py +msgid "Internal API Base URL" +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Financial Assistance Backend API Base URL." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "" +"Username created for Financial Assistance Backend, e.g. " +"financial_assistance_service_user." +msgstr "" + +#: lms/djangoapps/courseware/models.py +msgid "Percentage of courses allowed to use edx-financial-assistance" +msgstr "" + #: lms/djangoapps/courseware/plugins.py lms/djangoapps/courseware/tabs.py #: lms/templates/peer_grading/peer_grading.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html @@ -6125,7 +6068,6 @@ msgstr "" #: lms/djangoapps/courseware/views/index.py #: lms/djangoapps/courseware/views/views.py #: openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "register" msgstr "" @@ -6175,17 +6117,6 @@ msgstr "恭喜,您已符合認證資格。" msgid "You've earned a certificate for this course." msgstr "" -#: lms/djangoapps/courseware/views/views.py -msgid "Certificate unavailable" -msgstr "不提供修課證書" - -#: lms/djangoapps/courseware/views/views.py -#, python-brace-format -msgid "" -"You have not received a certificate because you do not have a current " -"{platform_name} verified identity." -msgstr "您尚未收到證書,因為您沒有當前{platform_name}的驗證身分。 " - #: lms/djangoapps/courseware/views/views.py msgid "Your certificate will be available soon!" msgstr "" @@ -6200,20 +6131,29 @@ msgstr "" msgid "Your certificate is available" msgstr "您的證書已可取得" +#: lms/djangoapps/courseware/views/views.py +msgid "Certificate unavailable" +msgstr "不提供修課證書" + +#: lms/djangoapps/courseware/views/views.py +#, python-brace-format +msgid "" +"You have not received a certificate because you do not have a current " +"{platform_name} verified identity." +msgstr "您尚未收到證書,因為您沒有當前{platform_name}的驗證身分。 " + #: lms/djangoapps/courseware/views/views.py #, python-brace-format msgid "To see course content, {sign_in_link} or {register_link}." msgstr "" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py #, python-brace-format msgid "{sign_in_link} or {register_link}." msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html msgid "Sign in" msgstr "登入" @@ -6225,7 +6165,6 @@ msgid "" msgstr "" #: lms/djangoapps/courseware/views/views.py -#: openedx/features/course_experience/views/course_home_messages.py msgid "You must be enrolled in the course to see course content." msgstr "" @@ -6343,6 +6282,29 @@ msgstr "上傳文件出現問題,請聯絡網站管理員,謝謝。" msgid "Good" msgstr "好" +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#, python-format +msgid "" +"\n" +" %(course_name)s: Reported content awaits review\n" +" " +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.html +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +msgid "Go to Discussion" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/body.txt +#, python-format +msgid "%(course_name)s: Reported content awaits review" +msgstr "" + +#: lms/djangoapps/discussion/templates/discussion/edx_ace/reportedcontentnotification/email/subject.txt +#, python-format +msgid " %(course_name)s %(course_id)s moderator content for review " +msgstr "" + #: lms/djangoapps/discussion/templates/discussion/edx_ace/responsenotification/email/body.html #, python-format, python-brace-format msgid "%(comment_username)s replied to {start_tag}%(thread_title)s{end_tag}:" @@ -6673,10 +6635,13 @@ msgid "Team" msgstr "團隊" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# +#. Translators: This label appears above a field +#. which allows the user to input the city in which they live. #. Translators: This label appears above a field on the registration form #. which allows the user to input the city in which they live. #: lms/djangoapps/instructor/views/api.py #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: lms/templates/instructor/instructor_dashboard_2/generate_registarion_codes_modal.html #: themes/stanford-style/lms/templates/register-form.html @@ -7465,7 +7430,6 @@ msgstr "(out of {total})" #: lms/templates/learner_dashboard/programs.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Programs" msgstr "" @@ -8329,7 +8293,6 @@ msgstr "" #: lms/templates/courseware/course_about.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "View Course" msgstr "檢視課程" @@ -8578,8 +8541,6 @@ msgstr "Wiki預覽" #: lms/templates/wiki/includes/cheatsheet.html lms/templates/dashboard.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/modal/_modal-settings-language.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "window open" msgstr "視窗開啟" @@ -8816,9 +8777,6 @@ msgstr "您可以從其他文章中重複使用檔案。" #: lms/templates/courseware/courseware.html lms/templates/dashboard.html #: lms/templates/edxnotes/edxnotes.html lms/templates/index.html #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -#: themes/edx.org/lms/templates/dashboard.html #: themes/stanford-style/lms/templates/index.html msgid "Search" msgstr "搜尋" @@ -8909,7 +8867,6 @@ msgstr "" #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Courses" msgstr "課程" @@ -9754,7 +9711,6 @@ msgid "Student" msgstr "學生" #: openedx/core/djangoapps/embargo/forms.py -#: openedx/core/djangoapps/verified_track_content/forms.py msgid "COURSE NOT FOUND. Please check that the course ID is valid." msgstr "找不到課程。請確認課程ID是有效的。" @@ -9807,6 +9763,10 @@ msgstr "課程{course}的白名單國家: {country} " msgid "Blacklist {country} for {course}" msgstr "課程{course}的黑名單國家: {country} " +#: openedx/core/djangoapps/learner_pathway/apps.py +msgid "Learner Pathways" +msgstr "" + #: openedx/core/djangoapps/oauth_dispatch/models.py msgid "" "Comma-separated list of scopes that this application will be allowed to " @@ -10136,7 +10096,6 @@ msgid "" msgstr "" #: openedx/core/djangoapps/schedules/templates/schedules/edx_ace/upgradereminder/email/body.html -#: lms/templates/dates_banner.html msgid "Upgrade now" msgstr "" @@ -10285,6 +10244,14 @@ msgstr "" msgid "Enter your full name." msgstr "" +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your first name." +msgstr "" + +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your last name." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "The email addresses do not match." msgstr "" @@ -10309,6 +10276,10 @@ msgstr "" msgid "Enter your specialty." msgstr "" +#: openedx/core/djangoapps/user_api/accounts/__init__.py +msgid "Enter your state." +msgstr "" + #: openedx/core/djangoapps/user_api/accounts/__init__.py msgid "Enter your city." msgstr "" @@ -10350,24 +10321,39 @@ msgstr "" msgid "The '{field_name}' field cannot be edited." msgstr " '{field_name}' 欄位不可被編輯。" +#: openedx/core/djangoapps/user_api/accounts/api.py +#: openedx/core/djangoapps/user_authn/views/registration_form.py +msgid "Enter a valid name" +msgstr "" + +#. Translators: This label appears above a field which allows the +#. user to input the First Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "First Name" msgstr "名" +#. Translators: This label appears above a field which allows the +#. user to input the Last Name #. Translators: This label appears above a field on the registration form #. which allows the user to input the First Name #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "Last Name" msgstr "姓" +#. Translators: This label appears above a field +#. which allows the user to input the State/Province/Region in which they +#. live. #. Translators: This label appears above a field on the registration form #. which allows the user to input the State/Province/Region in which they #. live. #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "State/Province/Region" msgstr "縣市/鄉鎮/地區" @@ -10405,9 +10391,12 @@ msgid "Job Title" msgstr "" #. #-#-#-#-# django-partial.po (edx-platform) #-#-#-#-# +#. Translators: This label appears above a field +#. meant to hold the user's mailing address. #. Translators: This label appears above a field on the registration form #. meant to hold the user's mailing address. #: openedx/core/djangoapps/user_api/accounts/settings_views.py +#: openedx/core/djangoapps/user_authn/api/form_fields.py #: openedx/core/djangoapps/user_authn/views/registration_form.py #: lms/templates/signup_modal.html msgid "Mailing address" @@ -10670,7 +10659,6 @@ msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-not-authenticated.html #: themes/stanford-style/lms/templates/register-form.html msgid "Register" msgstr "註冊" @@ -10789,10 +10777,6 @@ msgstr "所提供的access_token無效。" msgid "Full Name cannot contain the following characters: < >" msgstr "" -#: openedx/core/djangoapps/user_authn/views/registration_form.py -msgid "Enter a valid name" -msgstr "" - #: openedx/core/djangoapps/user_authn/views/registration_form.py msgid "A properly formatted e-mail is required" msgstr "一個正確格式的電子郵件是必需的" @@ -10962,15 +10946,9 @@ msgstr "" #: openedx/core/djangoapps/util/user_messages.py #: cms/templates/course_outline.html cms/templates/index.html -#: openedx/features/course_experience/templates/course_experience/latest-update-fragment.html -#: openedx/features/course_experience/templates/course_experience/welcome-message-fragment.html msgid "Dismiss" msgstr "" -#: openedx/core/djangoapps/verified_track_content/models.py -msgid "The course key for the course we would like to be auto-cohorted." -msgstr "" - #: openedx/core/djangoapps/video_pipeline/models.py msgid "Oauth client name of VEM service." msgstr "" @@ -11230,51 +11208,6 @@ msgstr "" msgid "Updates" msgstr "" -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{sign_in_link} or {register_link} and then enroll in this course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Welcome to {course_display_name}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"You must be enrolled in the course to see course content. Please contact " -"your degree administrator or {platform_name} Support if you have questions." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"{open_enroll_link}Enroll now{close_enroll_link} to access the full course." -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "" -"To start, set a course goal by selecting the option below that best " -"describes your learning plan. {goal_options_container}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "{choice}" -msgstr "" - -#: openedx/features/course_experience/views/course_home_messages.py -#, python-brace-format -msgid "Set goal to: {goal_text}" -msgstr "" - #: openedx/features/discounts/admin.py msgid "" "These define the context to disable lms-controlled discounts on. If no " @@ -11373,12 +11306,10 @@ msgid "Continue" msgstr "繼續" #: openedx/features/personalized_learner_schedules/call_to_action.py -#: lms/templates/dates_banner.html msgid "Shift due dates" msgstr "" #: openedx/features/personalized_learner_schedules/call_to_action.py -#: lms/templates/dates_banner.html msgid "" "It looks like you missed some important deadlines based on our suggested " "schedule." @@ -12365,11 +12296,6 @@ msgstr "課程名稱" msgid "Course Number" msgstr "課程編號" -#: cms/templates/course_outline.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Course Outline" -msgstr "" - #: cms/templates/html_error.html lms/templates/course_modes/error.html #: lms/templates/module-error.html msgid "Error:" @@ -12457,62 +12383,10 @@ msgstr "帳號" #: lms/templates/header/navbar-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: lms/templates/static_templates/help.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -#: wiki/plugins/help/wiki_plugin.py +#: lms/templates/static_templates/help.html wiki/plugins/help/wiki_plugin.py msgid "Help" msgstr "幫助" -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Looking for help with {studio_name}?" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Hide {studio_name} Help" -msgstr "" - -#: cms/templates/widgets/sock.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "{studio_name} Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Access documentation on http://docs.edx.org" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Documentation" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101: Overview of Creating an edX Course" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in edX101" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX: Creating a Course with edX Studio" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Enroll in StudioX" -msgstr "" - -#: cms/templates/widgets/sock_links.html -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "Send an email to {email}" -msgstr "" - #: cms/templates/widgets/tabs-aggregator.html #: lms/templates/courseware/static_tab.html #: lms/templates/courseware/tab-view.html @@ -12682,19 +12556,18 @@ msgstr "檢視所有課程" #: lms/templates/dashboard.html lms/templates/header/user_dropdown.html #: lms/templates/user_dropdown.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Dashboard" msgstr "我的課程" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "results successfully populated," msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Click to load all enrolled courses" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "You are not enrolled in any courses yet." msgstr "" @@ -12702,7 +12575,6 @@ msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/bootstrap/navbar-authenticated.html #: lms/templates/navigation/navbar-authenticated.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore courses" msgstr "探索課程" @@ -12711,16 +12583,15 @@ msgstr "探索課程" msgid "Activate your account!" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Course-loading errors" msgstr "課程讀取錯誤" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Search Your Courses" msgstr "搜尋您的課程" #: lms/templates/courseware/courseware.html lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Clear search" msgstr "清除搜尋" @@ -12743,15 +12614,15 @@ msgstr "" msgid "Continue to {platform_name}" msgstr "" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Email Settings for {course_number}" msgstr "{course_number} 的電子郵件通知設定" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Receive course emails" msgstr "接收課程郵件" -#: lms/templates/dashboard.html themes/edx.org/lms/templates/dashboard.html +#: lms/templates/dashboard.html msgid "Save Settings" msgstr "儲存設定" @@ -12760,83 +12631,9 @@ msgstr "儲存設定" #: lms/templates/dashboard/_dashboard_entitlement_actions.html #: lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html #: lms/templates/instructor/instructor_dashboard_2/membership.html -#: themes/edx.org/lms/templates/dashboard.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_entitlement_unenrollment_modal.html msgid "Unenroll" msgstr "取消註冊" -#: lms/templates/dates_banner.html -msgid "" -"It looks like you missed some important deadlines based on our suggested " -"schedule. " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future by visiting " -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" Don't worry—you won't lose any of the progress you've made when you shift " -"your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"To keep yourself on track, you can update this schedule and shift the past " -"due assignments into the future. Don't worry—you won't lose any of the " -"progress you've made when you shift your due dates." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "You are auditing this course," -msgstr "" - -#: lms/templates/dates_banner.html -msgid " which means that you are unable to participate in graded assignments." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. Graded assignments and schedule adjustment are available to " -"Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" It looks like you missed some important deadlines based on our suggested " -"schedule. To complete graded assignments as part of this course and shift " -"the past due assignments into the future, you can upgrade today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Upgrade to shift due dates" -msgstr "" - -#: lms/templates/dates_banner.html -msgid "Graded assignments are available to Verified Track learners." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -" To complete graded assignments as part of this course, you can upgrade " -"today." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "We've built a suggested schedule to help you stay on track." -msgstr "" - -#: lms/templates/dates_banner.html -msgid "" -"But don't worry—it's flexible so you can learn at your own pace. If you " -"happen to fall behind on our suggested dates, you'll be able to adjust them " -"to keep yourself on track." -msgstr "" - #: lms/templates/email_change_failed.html lms/templates/email_exists.html msgid "E-mail change failed" msgstr "電子郵件信箱變更失敗" @@ -13158,10 +12955,6 @@ msgstr "設定預覽模式" msgid "You are now viewing the course as {i_start}{user_name}{i_end}." msgstr "您現在正以 {i_start}{user_name}{i_end}查看課程。" -#: lms/templates/preview_menu.html -msgid "View in the new experience" -msgstr "" - #: lms/templates/preview_menu.html msgid "View in Studio" msgstr "" @@ -13279,9 +13072,7 @@ msgstr "" msgid "Sequence" msgstr "" -#: lms/templates/courseware/dates.html lms/templates/seq_module.html -#: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html +#: lms/templates/seq_module.html lms/templates/vert_module.html msgid "Completed" msgstr "" @@ -13549,7 +13340,6 @@ msgstr "" "-來完成放大和縮小功能。" #: lms/templates/vert_module.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "{subsection_format} due {{date}}" msgstr "" @@ -13561,6 +13351,10 @@ msgstr "" msgid "Past due" msgstr "" +#: lms/templates/vert_module.html +msgid "Reset Problems" +msgstr "" + #: lms/templates/video.html msgid "Loading video player" msgstr "正在載入影片撥放器" @@ -14610,7 +14404,6 @@ msgid "Download student grades" msgstr "下載學生成績" #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Print or share your certificate:" msgstr "顯示或共享您的證書:" @@ -14624,7 +14417,6 @@ msgstr "發表在Facebook" #: lms/templates/certificates/_accomplishment-banner.html #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Twitter" msgstr "分享到Twitter" @@ -14633,7 +14425,6 @@ msgid "Tweet this Accomplishment. Pop up window." msgstr "發布成績的訊息。將彈跳出視窗。" #: lms/templates/certificates/_accomplishment-banner.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Add to LinkedIn Profile" msgstr "加入LinkedIn的個人檔案" @@ -14724,40 +14515,31 @@ msgstr "" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue the Verified Track" msgstr "" #: lms/templates/course_modes/_upgrade_button.html #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/_upgrade_button.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue a Verified Certificate" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Enroll In {course_name} | Choose Your Track" msgstr "註冊到 {course_name} | 選擇您的追蹤" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Sorry, there was an error when trying to enroll you" msgstr "很抱歉,當您要註冊時發生錯誤" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with the Verified Track" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Pursue Academic Credit with a Verified Certificate" msgstr "升級為有學分的認證學程" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Become eligible for academic credit and highlight your new skills and " "knowledge with a verified certificate. Use this valuable credential to " @@ -14766,59 +14548,50 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of the Verified Track" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Eligible for credit:{b_end} Receive academic credit after " "successfully completing the course" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Unlimited Course Access: {b_end}Learn at your own pace, and access " "materials anytime to brush up on what you've learned." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Graded Assignments: {b_end}Build your skills through graded " "assignments and projects." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily Sharable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Benefits of a Verified Certificate" msgstr "合格證書的好處" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official:{b_end} Receive an instructor-signed certificate with the " "institution's logo" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable:{b_end} Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Highlight your new knowledge and skills with a verified certificate. Use " "this valuable credential to improve your job prospects and advance your " @@ -14826,45 +14599,38 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Official: {b_end}Receive an instructor-signed certificate with the " "institution's logo" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Easily shareable: {b_end}Add the certificate to your CV or resumé, " "or post it directly on LinkedIn" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "{b_start}Motivating: {b_end}Give yourself an additional incentive to " "complete the course" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course" msgstr "旁聽這門課程" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums." msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "Audit This Course (No Certificate)" msgstr "旁聽這門課 (沒有證書)" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded assignments," @@ -14872,7 +14638,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include graded " @@ -14880,7 +14645,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have access to course materials and " "discussions forums. {b_start}This track does not include unlimited course " @@ -14888,7 +14652,6 @@ msgid "" msgstr "" #: lms/templates/course_modes/choose.html -#: themes/edx.org/lms/templates/course_modes/choose.html msgid "" "Audit this course for free and have complete access to all the course " "material, activities, tests, and forums. {b_start}Please note that this " @@ -14972,6 +14735,10 @@ msgstr "" msgid "Choose a path for your course in" msgstr "" +#: lms/templates/course_modes/track_selection.html +msgid "Earn a certificate" +msgstr "" + #: lms/templates/course_modes/track_selection.html msgid "" "Studies show that those who choose this option are {start_bold}more engaged" @@ -14996,7 +14763,6 @@ msgstr "" #: lms/templates/courseware/accordion.html #: lms/templates/courseware/progress.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "due {date}" msgstr "到期日 {date}" @@ -15005,7 +14771,6 @@ msgid "{section_format} due {{date}}" msgstr "" #: lms/templates/courseware/accordion.html -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html msgid "This content is graded" msgstr "" @@ -15017,10 +14782,6 @@ msgstr "發生錯誤。請稍後再試一次。" msgid "You are enrolled in this course" msgstr "您參加此課程" -#: lms/templates/courseware/course_about.html -msgid "Course is full" -msgstr "課程已滿" - #: lms/templates/courseware/course_about.html msgid "Enrollment in this course is by invitation only" msgstr "只能經由邀請註冊這課程" @@ -15176,30 +14937,6 @@ msgstr "" msgid "Your score is {current_score}%. You have passed the entrance exam." msgstr "" -#: lms/templates/courseware/dates.html lms/templates/courseware/syllabus.html -msgid "{course.display_number_with_default} Course Info" -msgstr "{course.display_number_with_default}課程資訊" - -#: lms/templates/courseware/dates.html -msgid "Important Dates" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Today" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Verified Only" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Due Next" -msgstr "" - -#: lms/templates/courseware/dates.html -msgid "Not yet released" -msgstr "" - #: lms/templates/courseware/gradebook.html msgid "Gradebook" msgstr "成績單" @@ -15249,8 +14986,6 @@ msgstr "" #: lms/templates/courseware/info.html #: lms/templates/dashboard/_dashboard_course_resume.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: themes/edx.org/lms/templates/dashboard/_dashboard_course_resume.html msgid "Resume Course" msgstr "" @@ -15267,7 +15002,6 @@ msgid "Handout Navigation" msgstr "講義導覽" #: lms/templates/courseware/info.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Course Tools" msgstr "" @@ -15513,6 +15247,10 @@ msgstr "" msgid "No problem scores in this section" msgstr "本章節尚未有問題計分結果" +#: lms/templates/courseware/syllabus.html +msgid "{course.display_number_with_default} Course Info" +msgstr "{course.display_number_with_default}課程資訊" + #: lms/templates/courseware/welcome-back.html msgid "" "You were most recently in {section_link}. If you're done with that, choose " @@ -15743,7 +15481,6 @@ msgid "Share {course_name} on Facebook" msgstr "" #: lms/templates/dashboard/_dashboard_course_listing.html -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html msgid "Share on Facebook" msgstr "分享到Facebook" @@ -15791,6 +15528,12 @@ msgid "" "showcase on your resumé." msgstr "" +#: lms/templates/dashboard/_dashboard_course_listing.html +msgid "" +"{start_bold}Get the most out of your course!{end_bold} Upgrade to earn a " +"{link_start}verified certificate{link_end} to showcase on your resumé." +msgstr "" + #: lms/templates/dashboard/_dashboard_course_listing.html msgid "Upgrade" msgstr "" @@ -16567,7 +16310,6 @@ msgstr "" "{begin_strong}警告:{end_strong} 您的瀏覽器僅部分支援。強烈建議您使用 {chrome_link} 或 {ff_link}。" #: lms/templates/header/navbar-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "Discover New" msgstr "" @@ -16581,7 +16323,6 @@ msgstr "" #: lms/templates/header/navbar-not-authenticated.html #: lms/templates/navigation/navbar-not-authenticated.html -#: themes/edx.org/lms/templates/header/navbar-authenticated.html msgid "How it Works" msgstr "運行機制" @@ -17988,7 +17729,6 @@ msgid "" msgstr "" #: lms/templates/learner_dashboard/_dashboard_navigation_courses.html -#: themes/edx.org/lms/templates/dashboard.html msgid "My Courses" msgstr "我的課程" @@ -18399,13 +18139,10 @@ msgid "Skeleton Page" msgstr "" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -#: openedx/features/course_search/templates/course_search/course-search-fragment.html msgid "Search the course" msgstr "" #: lms/templates/ux/reference/bootstrap/course-skeleton.html -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html msgid "Start Course" msgstr "" @@ -18579,36 +18316,6 @@ msgstr "" msgid "View all course dates" msgstr "" -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Goal: " -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Edit your course goal:" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Pursue a verified certificate" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "" -"Sample verified certificate with your name, the course title, the logo of " -"the institution and the signatures of the instructors for this course." -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-home-fragment.html -msgid "Upgrade ({price})" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Expand All" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/course-outline-fragment.html -msgid "Prerequisite: " -msgstr "" - #: openedx/features/course_experience/templates/course_experience/course-sock-fragment.html msgid "Learn About Verified Certificates" msgstr "" @@ -18689,18 +18396,6 @@ msgstr "" msgid "This course does not have any updates." msgstr "" -#: openedx/features/course_experience/templates/course_experience/latest-update-fragment.html -msgid "Latest Update" -msgstr "" - -#: openedx/features/course_experience/templates/course_experience/welcome-message-fragment.html -msgid "Show More" -msgstr "" - -#: openedx/features/course_search/templates/course_search/course-search-fragment.html -msgid "Search Results" -msgstr "" - #. Translators: this section lists all the third-party authentication #. providers #. (for example, Google and LinkedIn) the user can link with or unlink from @@ -18744,10 +18439,13 @@ msgid "You haven't earned any certificates yet." msgstr "" #: openedx/features/learner_profile/templates/learner_profile/learner-achievements-fragment.html -#: themes/edx.org/lms/templates/dashboard.html msgid "Explore New Courses" msgstr "探索新課程" +#: openedx/features/learner_profile/templates/learner_profile/learner_profile.html +msgid "Learner Profile" +msgstr "" + #: openedx/features/learner_profile/templates/learner_profile/learner_profile.html msgid "View My Records" msgstr "" @@ -18765,138 +18463,6 @@ msgstr "" msgid "An error occurred. Try loading the page again." msgstr "" -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "" -"Access Course Staff Support on the Partner Portal to submit or review " -"support tickets" -msgstr "" - -#: themes/edx.org/cms/templates/widgets/sock.html -msgid "edX Partner Portal" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "" -"Browse recently launched courses and see what's new in your favorite " -"subjects." -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Take advantage of free coaching!" -msgstr "" - -#: themes/edx.org/lms/templates/dashboard.html -msgid "Get Started" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Page Footer" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "edX Home Page" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "Connect" -msgstr "" - -#: themes/edx.org/lms/templates/footer.html -msgid "© {year} edX Inc. All rights reserved." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "About edX Verified Certificates" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-accomplishments.html -msgid "" -"An edX Verified Certificate signifies that the learner has agreed to abide " -"by the edX honor code and completed all of the required tasks of this course" -" under its guidelines, as well as having their photo ID checked to verify " -"their identity." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "About edX" -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/certificates/_about-edx.html -msgid "" -"{link_start}edX{link_end} offers interactive online classes and MOOCs from " -"the world's best universities, including MIT, Harvard, Berkeley, University " -"of Texas, and many others. edX is a mission driven initiative created by " -"founding partners Harvard and MIT." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Congratulations, {user_name}!" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "" -"You worked hard to earn your certificate from " -"{accomplishment_copy_course_org} {dash} share it with colleagues, friends, " -"and family to get the word out about what you mastered in " -"{accomplishment_course_title}." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Share this certificate on Facebook (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Tweet this certificate (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Add this certificate to your LinkedIn profile (opens a new tab/window)" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-banner.html -msgid "Print this certificate" -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "edX Inc." -msgstr "" - -#: themes/edx.org/lms/templates/certificates/_accomplishment-footer.html -msgid "" -"All rights reserved except where noted. edX, Open edX and the edX and Open " -"edX logos are registered trademarks of edX Inc." -msgstr "" - -#. Translators: This string will not be used in Open edX installations. -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end}EdX relies on verified certificates to " -"help fund affordable education to everyone globally." -msgstr "" - -#: themes/edx.org/lms/templates/course_modes/choose.html -msgid "" -"{b_start}Support our Mission: {b_end} EdX, a mission driven initiative, " -"relies on verified certificates to help fund free education for everyone " -"globally" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Find Courses" -msgstr "" - -#: themes/edx.org/lms/templates/header/navbar-authenticated.html -msgid "Schools & Partners" -msgstr "" - #: themes/red-theme/lms/templates/footer.html msgid "" "{tos_link_start}Terms of Service{tos_link_end} and {honor_link_start}Honor " @@ -19532,6 +19098,10 @@ msgid "" "respond to student questions. You add or edit updates in HTML." msgstr "使用公佈欄以提醒學生重要日期或考試、強調討論區中特定的討論內容、公告時間表的改變和回答學生問題。以HTML新增或編輯公告。" +#: cms/templates/course_outline.html +msgid "Course Outline" +msgstr "" + #: cms/templates/course_outline.html msgid "" "This course was created as a re-run. Some manual configuration is needed." @@ -22221,6 +21791,26 @@ msgstr "" msgid "Label" msgstr "" +#: cms/templates/widgets/sock.html +msgid "Looking for help with {studio_name}?" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "Hide {studio_name} Help" +msgstr "" + +#: cms/templates/widgets/sock.html +msgid "{studio_name} Documentation" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Access documentation on http://docs.edx.org" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "edX Documentation" +msgstr "" + #: cms/templates/widgets/sock_links.html msgid "Access the Open edX Portal" msgstr "" @@ -22229,6 +21819,26 @@ msgstr "" msgid "Open edX Portal" msgstr "" +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101: Overview of Creating an edX Course" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in edX101" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX: Creating a Course with edX Studio" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Enroll in StudioX" +msgstr "" + +#: cms/templates/widgets/sock_links.html +msgid "Send an email to {email}" +msgstr "" + #: cms/templates/widgets/user_dropdown.html msgid "Currently signed in as:" msgstr "" diff --git a/conf/locale/zh_TW/LC_MESSAGES/djangojs.mo b/conf/locale/zh_TW/LC_MESSAGES/djangojs.mo index e21c8553218c97dbd713c342f8764066cde7199d..970aa5a9ad28f0932704d6472f16328f24b05981 100644 GIT binary patch delta 22 ecmeyqk>&eFmIa$xEc6VxCU0<3+N`$uVk!W1)d{%( delta 22 ecmeyqk>&eFmIa$xEcFbzCU0<3+N`$uVk!W1?FqX8 diff --git a/conf/locale/zh_TW/LC_MESSAGES/djangojs.po b/conf/locale/zh_TW/LC_MESSAGES/djangojs.po index 8072fa02c4..6cf10f387a 100644 --- a/conf/locale/zh_TW/LC_MESSAGES/djangojs.po +++ b/conf/locale/zh_TW/LC_MESSAGES/djangojs.po @@ -132,7 +132,7 @@ msgid "" msgstr "" "Project-Id-Version: edx-platform\n" "Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n" -"POT-Creation-Date: 2022-06-09 16:44-0400\n" +"POT-Creation-Date: 2022-06-12 20:43+0000\n" "PO-Revision-Date: 2014-06-11 15:18+0000\n" "Last-Translator: Andrew Lau , 2017\n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/open-edx/edx-platform/language/zh_TW/)\n" @@ -141,7 +141,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.8.0\n" #: cms/static/cms/js/main.js cms/static/js/views/active_video_upload_list.js #: cms/static/js/views/video_transcripts.js @@ -187,7 +187,6 @@ msgstr "刪除" #: common/lib/xmodule/xmodule/js/src/html/edit.js #: common/static/common/js/components/utils/view_utils.js #: lms/static/js/Markdown.Editor.js -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx #: lms/static/js/student_account/components/StudentAccountDeletionModal.jsx #: cms/templates/js/add-xblock-component-menu-problem.underscore #: cms/templates/js/add-xblock-component-menu.underscore @@ -357,6 +356,14 @@ msgstr "錯誤" msgid "Updating with latest library content" msgstr "以最新的課程組件庫內容更新中" +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Loading..." +msgstr "" + +#: common/lib/xmodule/xmodule/assets/library_source_block/LibrarySourcedBlockPicker.jsx +msgid "Selected blocks" +msgstr "" + #: common/lib/xmodule/xmodule/assets/library_source_block/public/js/library_source_block.js msgid "Unable to update settings" msgstr "" @@ -1997,6 +2004,10 @@ msgstr "" msgid "Navigate up" msgstr "" +#: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx +msgid "Browsing" +msgstr "" + #: common/static/common/js/components/BlockBrowser/components/BlockBrowser/BlockBrowser.jsx msgid "Select" msgstr "" @@ -2504,10 +2515,30 @@ msgid "" "within the Discussion Forum where the Course Staff can directly respond." msgstr "" +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Details" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "the more quickly and helpfully we can respond!" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "Create Support Ticket" +msgstr "" + +#: lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +msgid "What can we help you with, {username}?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx msgid "Sign in to {platform} so we can help you better." msgstr "" +#: lms/djangoapps/support/static/support/jsx/logged_out_user.jsx +msgid "Need help logging in?" +msgstr "" + #: lms/djangoapps/support/static/support/jsx/single_support_form.jsx msgid "" "Select a course or select \"Not specific to a course\" for your support " @@ -3322,20 +3353,52 @@ msgstr "" msgid "Get started" msgstr "" -#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx -msgid "Section {currentPage} of {totalPages}" -msgstr "" - #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "Help make edX better for everyone!" msgstr "" +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Why does edX collect this information?" +msgstr "" + #: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx msgid "" -"Welcome to edX! Before you get started, please take a few minutes to fill-in" -" the additional information below to help us understand a bit more about " -"your background. You can always edit this information later in Account " -"Settings." +"An error occurred while attempting to retrieve or save the information " +"below. Please try again later." +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What was the total combined income, during the last 12 months, of all " +"members of your family? " +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"Have you ever served on active duty in the U.S. Armed Forces, Reserves, or " +"National Guard?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What is the highest level of education that you have achieved so far?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "" +"What is the highest level of education that any of your parents or guardians" +" have achieved?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "Select employment status" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you currently work in?" +msgstr "" + +#: lms/static/js/demographics_collection/DemographicsCollectionModal.jsx +msgid "What industry do you want to work in?" msgstr "" #: lms/static/js/demographics_collection/MultiselectDropdown.jsx @@ -3350,6 +3413,22 @@ msgstr "" msgid "close questionnaire" msgstr "" +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Return to my dashboard" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "Finish later" +msgstr "" + +#: lms/static/js/demographics_collection/Wizard.jsx +msgid "next page" +msgstr "" + #: lms/static/js/discovery/views/search_form.js #, javascript-format msgid "Viewing %s course" @@ -3633,27 +3712,6 @@ msgstr "學習夥伴功能已啟用" msgid "Cohorts Disabled" msgstr "學習夥伴功能未啟用" -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course uses automatic cohorting for verified track learners. You cannot" -" disable cohorts, and you cannot rename the manual cohort named " -"'{verifiedCohortName}'. To change the configuration for verified track " -"cohorts, contact your edX partner manager." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" the required cohort does not exist. You must create a manually-assigned " -"cohort named '{verifiedCohortName}' for the feature to work." -msgstr "" - -#: lms/static/js/groups/views/verified_track_settings_notification.js -msgid "" -"This course has automatic cohorting enabled for verified track learners, but" -" cohorts are disabled. You must enable cohorts for the feature to work." -msgstr "" - #: lms/static/js/instructor_dashboard/certificates.js msgid "Allow students to generate certificates for this course?" msgstr "允許學生為這門課程取得證明?" @@ -4316,10 +4374,6 @@ msgid "" "sensitive nature of student information." msgstr "連結將在有需求時才產生,並僅維持5分鐘以維護學生訊息隱私。" -#: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx -msgid "You have access to the {enterpriseName} dashboard" -msgstr "" - #: lms/static/js/learner_dashboard/EnterpriseLearnerPortalModal.jsx msgid "" "To access the courses available to you through {enterpriseName}, visit the " @@ -5152,42 +5206,6 @@ msgstr "" msgid "Bookmark this page" msgstr "" -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "Thank you for setting your course goal to {goal}!" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseGoals.js -msgid "" -"There was an error in setting your goal, please reload the page and try " -"again." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "You have successfully updated your goal." -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/CourseHome.js -msgid "There was an error updating your goal." -msgstr "" - -#: lms/templates/ccx/schedule.underscore -msgid "Expand All" -msgstr "展開全部" - -#: lms/templates/ccx/schedule.underscore -msgid "Collapse All" -msgstr "折疊所有" - -#: openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show More" -msgstr "" - -#: openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js -#: lms/templates/courseware/proctored-exam-status.underscore -msgid "Show Less" -msgstr "" - #: openedx/features/course_search/static/course_search/js/views/search_results_view.js msgid "{total_results} result found for \"{search_term}\"" msgid_plural "{total_results} results found for \"{search_term}\"" @@ -5465,6 +5483,31 @@ msgstr "" msgid "There was an error with the upload" msgstr "" +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Organization:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Number:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Course Run:" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "(Read-only)" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +msgid "Re-run Course" +msgstr "" + +#: cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +#: cms/templates/js/show-textbook.underscore +msgid "View Live" +msgstr "" + #: cms/static/js/maintenance/force_publish_course.js msgid "Internal Server Error." msgstr "內部伺服器錯誤" @@ -6936,10 +6979,6 @@ msgstr "" msgid "follow this post" msgstr "" -#: common/static/common/templates/discussion/templates.underscore -msgid "post anonymously" -msgstr "" - #: common/static/common/templates/discussion/templates.underscore msgid "post anonymously to classmates" msgstr "" @@ -7384,6 +7423,14 @@ msgstr "" msgid "This catalog's courses:" msgstr "" +#: lms/templates/ccx/schedule.underscore +msgid "Expand All" +msgstr "展開全部" + +#: lms/templates/ccx/schedule.underscore +msgid "Collapse All" +msgstr "折疊所有" + #: lms/templates/ccx/schedule.underscore msgid "Start Date" msgstr "開始日期" @@ -7467,6 +7514,14 @@ msgid "" "before you select \"End My Exam\"." msgstr "如收到信用的問題,在您選擇\"結束我的測驗\"之前,您必須為每個問題點擊\"提交\"按鈕。" +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show More" +msgstr "" + +#: lms/templates/courseware/proctored-exam-status.underscore +msgid "Show Less" +msgstr "" + #: lms/templates/discovery/course_card.underscore msgid "LEARN MORE" msgstr "學習更多" @@ -10111,10 +10166,6 @@ msgstr "" msgid "PDF Chapters" msgstr "" -#: cms/templates/js/show-textbook.underscore -msgid "View Live" -msgstr "" - #: cms/templates/js/signatory-details.underscore #: cms/templates/js/signatory-editor.underscore msgid "Signatory" diff --git a/lms/static/js/i18n/eo/djangojs.js b/lms/static/js/i18n/eo/djangojs.js index 404d096061..6f35d08ce8 100644 --- a/lms/static/js/i18n/eo/djangojs.js +++ b/lms/static/js/i18n/eo/djangojs.js @@ -434,6 +434,7 @@ "Code block": "\u00c7\u00f6d\u00e9 \u00dfl\u00f6\u00e7k \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3#", "Cohort Assignment Method": "\u00c7\u00f6h\u00f6rt \u00c0ss\u00efgnm\u00e9nt M\u00e9th\u00f6d \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7#", "Cohort Name": "\u00c7\u00f6h\u00f6rt N\u00e4m\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f #", + "Cohort assignment not allowed: {email_or_username}": "\u00c7\u00f6h\u00f6rt \u00e4ss\u00efgnm\u00e9nt n\u00f6t \u00e4ll\u00f6w\u00e9d: {email_or_username} \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442#", "Cohorts": "\u00c7\u00f6h\u00f6rts \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c #", "Cohorts Disabled": "\u00c7\u00f6h\u00f6rts D\u00efs\u00e4\u00dfl\u00e9d \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c#", "Cohorts Enabled": "\u00c7\u00f6h\u00f6rts \u00c9n\u00e4\u00dfl\u00e9d \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1#", @@ -622,9 +623,7 @@ "Download Memberships": "D\u00f6wnl\u00f6\u00e4d M\u00e9m\u00df\u00e9rsh\u00efps \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, #", "Download Software Clicked": "D\u00f6wnl\u00f6\u00e4d S\u00f6ftw\u00e4r\u00e9 \u00c7l\u00ef\u00e7k\u00e9d \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455#", "Download Transcript for Editing": "D\u00f6wnl\u00f6\u00e4d Tr\u00e4ns\u00e7r\u00efpt f\u00f6r \u00c9d\u00eft\u00efng \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442#", - "Download URL": "D\u00f6wnl\u00f6\u00e4d \u00dbRL \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455#", "Download available encodings (.csv)": "D\u00f6wnl\u00f6\u00e4d \u00e4v\u00e4\u00efl\u00e4\u00dfl\u00e9 \u00e9n\u00e7\u00f6d\u00efngs (.\u00e7sv) \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442#", - "Download the user's certificate": "D\u00f6wnl\u00f6\u00e4d th\u00e9 \u00fcs\u00e9r's \u00e7\u00e9rt\u00eff\u00ef\u00e7\u00e4t\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442#", "Draft (Never published)": "Dr\u00e4ft (N\u00e9v\u00e9r p\u00fc\u00dfl\u00efsh\u00e9d) \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3#", "Draft (Unpublished changes)": "Dr\u00e4ft (\u00dbnp\u00fc\u00dfl\u00efsh\u00e9d \u00e7h\u00e4ng\u00e9s) \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454#", "Draft saved on {lastSavedStart}{editedOn}{lastSavedEnd} by {editedByStart}{editedBy}{editedByEnd}": "Dr\u00e4ft s\u00e4v\u00e9d \u00f6n {lastSavedStart}{editedOn}{lastSavedEnd} \u00df\u00fd {editedByStart}{editedBy}{editedByEnd} \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5#", @@ -1173,7 +1172,6 @@ "Not Started": "N\u00f6t St\u00e4rt\u00e9d \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f #", "Not Supported": "N\u00f6t S\u00fcpp\u00f6rt\u00e9d \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9#", "Not able to set passing grade to less than %(minimum_grade_cutoff)s%.": "N\u00f6t \u00e4\u00dfl\u00e9 t\u00f6 s\u00e9t p\u00e4ss\u00efng gr\u00e4d\u00e9 t\u00f6 l\u00e9ss th\u00e4n %(minimum_grade_cutoff)s%. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f \u03b1#", - "Not available": "N\u00f6t \u00e4v\u00e4\u00efl\u00e4\u00dfl\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9#", "Not divided": "N\u00f6t d\u00efv\u00efd\u00e9d \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f #", "Not in Use": "N\u00f6t \u00efn \u00dbs\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3#", "Not selected": "N\u00f6t s\u00e9l\u00e9\u00e7t\u00e9d \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455#", diff --git a/lms/static/js/i18n/rtl/djangojs.js b/lms/static/js/i18n/rtl/djangojs.js index fd178a6ae9..316b90b64c 100644 --- a/lms/static/js/i18n/rtl/djangojs.js +++ b/lms/static/js/i18n/rtl/djangojs.js @@ -403,6 +403,7 @@ "Code block": "\u023b\u00f8d\u01dd bl\u00f8\u0254\u029e", "Cohort Assignment Method": "\u023b\u00f8\u0265\u00f8\u0279\u0287 \u023ass\u1d09\u0183n\u026f\u01ddn\u0287 M\u01dd\u0287\u0265\u00f8d", "Cohort Name": "\u023b\u00f8\u0265\u00f8\u0279\u0287 N\u0250\u026f\u01dd", + "Cohort assignment not allowed: {email_or_username}": "\u023b\u00f8\u0265\u00f8\u0279\u0287 \u0250ss\u1d09\u0183n\u026f\u01ddn\u0287 n\u00f8\u0287 \u0250ll\u00f8\u028d\u01ddd: {email_or_username}", "Cohorts": "\u023b\u00f8\u0265\u00f8\u0279\u0287s", "Cohorts Disabled": "\u023b\u00f8\u0265\u00f8\u0279\u0287s \u0110\u1d09s\u0250bl\u01ddd", "Cohorts Enabled": "\u023b\u00f8\u0265\u00f8\u0279\u0287s \u0246n\u0250bl\u01ddd", @@ -577,9 +578,7 @@ "Download": "\u0110\u00f8\u028dnl\u00f8\u0250d", "Download Memberships": "\u0110\u00f8\u028dnl\u00f8\u0250d M\u01dd\u026fb\u01dd\u0279s\u0265\u1d09ds", "Download Transcript for Editing": "\u0110\u00f8\u028dnl\u00f8\u0250d \u0166\u0279\u0250ns\u0254\u0279\u1d09d\u0287 \u025f\u00f8\u0279 \u0246d\u1d09\u0287\u1d09n\u0183", - "Download URL": "\u0110\u00f8\u028dnl\u00f8\u0250d \u0244\u024c\u0141", "Download available encodings (.csv)": "\u0110\u00f8\u028dnl\u00f8\u0250d \u0250\u028c\u0250\u1d09l\u0250bl\u01dd \u01ddn\u0254\u00f8d\u1d09n\u0183s (.\u0254s\u028c)", - "Download the user's certificate": "\u0110\u00f8\u028dnl\u00f8\u0250d \u0287\u0265\u01dd ns\u01dd\u0279's \u0254\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dd", "Draft (Never published)": "\u0110\u0279\u0250\u025f\u0287 (N\u01dd\u028c\u01dd\u0279 dnbl\u1d09s\u0265\u01ddd)", "Draft (Unpublished changes)": "\u0110\u0279\u0250\u025f\u0287 (\u0244ndnbl\u1d09s\u0265\u01ddd \u0254\u0265\u0250n\u0183\u01dds)", "Draft saved on {lastSavedStart}{editedOn}{lastSavedEnd} by {editedByStart}{editedBy}{editedByEnd}": "\u0110\u0279\u0250\u025f\u0287 s\u0250\u028c\u01ddd \u00f8n {lastSavedStart}{editedOn}{lastSavedEnd} b\u028e {editedByStart}{editedBy}{editedByEnd}", @@ -1094,7 +1093,6 @@ "Not Graded": "N\u00f8\u0287 \u01e4\u0279\u0250d\u01ddd", "Not Supported": "N\u00f8\u0287 Sndd\u00f8\u0279\u0287\u01ddd", "Not able to set passing grade to less than %(minimum_grade_cutoff)s%.": "N\u00f8\u0287 \u0250bl\u01dd \u0287\u00f8 s\u01dd\u0287 d\u0250ss\u1d09n\u0183 \u0183\u0279\u0250d\u01dd \u0287\u00f8 l\u01ddss \u0287\u0265\u0250n %(minimum_grade_cutoff)s%.", - "Not available": "N\u00f8\u0287 \u0250\u028c\u0250\u1d09l\u0250bl\u01dd", "Not divided": "N\u00f8\u0287 d\u1d09\u028c\u1d09d\u01ddd", "Not in Use": "N\u00f8\u0287 \u1d09n \u0244s\u01dd", "Not selected": "N\u00f8\u0287 s\u01ddl\u01dd\u0254\u0287\u01ddd", From a10661ddbc868b9c6f3636e2d928c6b0792838ce Mon Sep 17 00:00:00 2001 From: edX requirements bot <49161187+edx-requirements-bot@users.noreply.github.com> Date: Tue, 14 Jun 2022 06:12:57 -0400 Subject: [PATCH 45/63] chore: Updating Python Requirements (#30581) --- requirements/edx-sandbox/py38.txt | 4 ++-- requirements/edx/base.txt | 25 ++++++++++++----------- requirements/edx/development.txt | 33 ++++++++++++++++--------------- requirements/edx/doc.txt | 2 +- requirements/edx/paver.txt | 4 ++-- requirements/edx/testing.txt | 31 +++++++++++++++-------------- scripts/xblock/requirements.txt | 2 +- 7 files changed, 52 insertions(+), 49 deletions(-) diff --git a/requirements/edx-sandbox/py38.txt b/requirements/edx-sandbox/py38.txt index fb7f568eb1..7364982ff3 100644 --- a/requirements/edx-sandbox/py38.txt +++ b/requirements/edx-sandbox/py38.txt @@ -20,7 +20,7 @@ cycler==0.11.0 # via matplotlib joblib==1.1.0 # via nltk -kiwisolver==1.4.2 +kiwisolver==1.4.3 # via matplotlib lxml==4.9.0 # via @@ -36,7 +36,7 @@ matplotlib==3.3.4 # -r requirements/edx-sandbox/py38.in mpmath==1.2.1 # via sympy -networkx==2.8.2 +networkx==2.8.3 # via -r requirements/edx-sandbox/py38.in nltk==3.7 # via diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 5838e88540..5c3e18121d 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -161,7 +161,7 @@ cryptography==37.0.2 # jwcrypto # pyjwt # social-auth-core -cssutils==2.4.1 +cssutils==2.4.2 # via pynliner ddt==1.5.0 # via @@ -175,6 +175,7 @@ defusedxml==0.7.1 # python3-openid # python3-saml # social-auth-core + # tableauserverclient deprecated==1.2.13 # via # jwcrypto @@ -258,7 +259,7 @@ django-config-models==2.3.0 # edx-enterprise # edx-name-affirmation # lti-consumer-xblock -django-cors-headers==3.12.0 +django-cors-headers==3.13.0 # via -r requirements/edx/base.in django-countries==7.3.2 # via @@ -319,7 +320,7 @@ django-mptt==0.13.4 # django-wiki django-multi-email-field==0.6.2 # via edx-enterprise -django-mysql==4.6.0 +django-mysql==4.7.0 # via -r requirements/edx/base.in django-oauth-toolkit==1.3.2 # via @@ -339,7 +340,7 @@ django-sekizai==3.0.1 # via # -r requirements/edx/base.in # django-wiki -django-ses==3.0.1 +django-ses==3.1.0 # via -r requirements/edx/base.in django-simple-history==3.0.0 # via @@ -361,7 +362,7 @@ django-storages==1.8 # edxval django-user-tasks==3.0.0 # via -r requirements/edx/base.in -django-waffle==2.4.1 +django-waffle==2.5.0 # via # -r requirements/edx/base.in # blockstore @@ -549,7 +550,7 @@ event-tracking==2.1.0 # -r requirements/edx/base.in # edx-proctoring # edx-search -fastavro==1.4.12 +fastavro==1.5.1 # via openedx-events frozenlist==1.3.0 # via @@ -701,7 +702,7 @@ mysqlclient==2.1.0 # via # -r requirements/edx/base.in # blockstore -newrelic==7.10.0.175 +newrelic==7.12.0.176 # via # -r requirements/edx/base.in # edx-django-utils @@ -726,7 +727,7 @@ oauthlib==3.0.1 # social-auth-core openedx-calc==3.0.1 # via -r requirements/edx/base.in -openedx-events==0.9.1 +openedx-events==0.10.0 # via -r requirements/edx/base.in openedx-filters==0.7.0 # via @@ -900,7 +901,7 @@ redis==4.3.3 # via -r requirements/edx/base.in regex==2022.6.2 # via nltk -requests==2.27.1 +requests==2.28.0 # via # -r requirements/edx/paver.txt # analytics-python @@ -992,7 +993,7 @@ social-auth-app-django==5.0.0 # via # -r requirements/edx/base.in # edx-auth-backends -social-auth-core==4.2.0 +social-auth-core==4.3.0 # via # -r requirements/edx/base.in # edx-auth-backends @@ -1027,7 +1028,7 @@ super-csv==3.0.0 # edx-bulk-grades sympy==1.10.1 # via openedx-calc -tableauserverclient==0.18.0 +tableauserverclient==0.19.0 # via edx-enterprise testfixtures==6.18.5 # via edx-enterprise @@ -1063,7 +1064,7 @@ vine==5.0.0 # kombu voluptuous==0.13.1 # via ora2 -watchdog==2.1.8 +watchdog==2.1.9 # via -r requirements/edx/paver.txt wcwidth==0.2.5 # via prompt-toolkit diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index a4da79a545..76c9b3ea8c 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -63,7 +63,7 @@ asgiref==3.5.2 # -r requirements/edx/testing.txt # django # uvicorn -astroid==2.11.5 +astroid==2.11.6 # via # -r requirements/edx/testing.txt # pylint @@ -232,7 +232,7 @@ cssselect==1.1.0 # via # -r requirements/edx/testing.txt # pyquery -cssutils==2.4.1 +cssutils==2.4.2 # via # -r requirements/edx/testing.txt # pynliner @@ -249,6 +249,7 @@ defusedxml==0.7.1 # python3-openid # python3-saml # social-auth-core + # tableauserverclient deprecated==1.2.13 # via # -r requirements/edx/testing.txt @@ -348,7 +349,7 @@ django-config-models==2.3.0 # edx-enterprise # edx-name-affirmation # lti-consumer-xblock -django-cors-headers==3.12.0 +django-cors-headers==3.13.0 # via -r requirements/edx/testing.txt django-countries==7.3.2 # via @@ -417,7 +418,7 @@ django-multi-email-field==0.6.2 # via # -r requirements/edx/testing.txt # edx-enterprise -django-mysql==4.6.0 +django-mysql==4.7.0 # via -r requirements/edx/testing.txt django-oauth-toolkit==1.3.2 # via @@ -439,7 +440,7 @@ django-sekizai==3.0.1 # via # -r requirements/edx/testing.txt # django-wiki -django-ses==3.0.1 +django-ses==3.1.0 # via -r requirements/edx/testing.txt django-simple-history==3.0.0 # via @@ -461,7 +462,7 @@ django-storages==1.8 # edxval django-user-tasks==3.0.0 # via -r requirements/edx/testing.txt -django-waffle==2.4.1 +django-waffle==2.5.0 # via # -r requirements/edx/testing.txt # blockstore @@ -588,7 +589,7 @@ edx-i18n-tools==0.9.1 # via # -r requirements/edx/testing.txt # ora2 -edx-lint==5.2.2 +edx-lint==5.2.4 # via -r requirements/edx/testing.txt edx-milestones==0.4.0 # via -r requirements/edx/testing.txt @@ -681,7 +682,7 @@ execnet==1.9.0 # pytest-xdist factory-boy==3.2.1 # via -r requirements/edx/testing.txt -faker==13.12.0 +faker==13.13.0 # via # -r requirements/edx/testing.txt # factory-boy @@ -689,7 +690,7 @@ fastapi==0.78.0 # via # -r requirements/edx/testing.txt # pact-python -fastavro==1.4.12 +fastavro==1.5.1 # via # -r requirements/edx/testing.txt # openedx-events @@ -919,7 +920,7 @@ multidict==6.0.2 # -r requirements/edx/testing.txt # aiohttp # yarl -mypy==0.960 +mypy==0.961 # via -r requirements/edx/development.in mypy-extensions==0.4.3 # via mypy @@ -927,7 +928,7 @@ mysqlclient==2.1.0 # via # -r requirements/edx/testing.txt # blockstore -newrelic==7.10.0.175 +newrelic==7.12.0.176 # via # -r requirements/edx/testing.txt # edx-django-utils @@ -953,7 +954,7 @@ oauthlib==3.0.1 # social-auth-core openedx-calc==3.0.1 # via -r requirements/edx/testing.txt -openedx-events==0.9.1 +openedx-events==0.10.0 # via -r requirements/edx/testing.txt openedx-filters==0.7.0 # via @@ -1252,7 +1253,7 @@ regex==2022.6.2 # via # -r requirements/edx/testing.txt # nltk -requests==2.27.1 +requests==2.28.0 # via # -r requirements/edx/testing.txt # analytics-python @@ -1377,7 +1378,7 @@ social-auth-app-django==5.0.0 # via # -r requirements/edx/testing.txt # edx-auth-backends -social-auth-core==4.2.0 +social-auth-core==4.3.0 # via # -r requirements/edx/testing.txt # edx-auth-backends @@ -1440,7 +1441,7 @@ sympy==1.10.1 # via # -r requirements/edx/testing.txt # openedx-calc -tableauserverclient==0.18.0 +tableauserverclient==0.19.0 # via # -r requirements/edx/testing.txt # edx-enterprise @@ -1531,7 +1532,7 @@ voluptuous==0.13.1 # ora2 vulture==2.4 # via -r requirements/edx/development.in -watchdog==2.1.8 +watchdog==2.1.9 # via -r requirements/edx/testing.txt wcwidth==0.2.5 # via diff --git a/requirements/edx/doc.txt b/requirements/edx/doc.txt index 89b8169eb4..efd98c1678 100644 --- a/requirements/edx/doc.txt +++ b/requirements/edx/doc.txt @@ -54,7 +54,7 @@ pytz==2022.1 # via babel pyyaml==6.0 # via code-annotations -requests==2.27.1 +requests==2.28.0 # via sphinx six==1.16.0 # via edx-sphinx-theme diff --git a/requirements/edx/paver.txt b/requirements/edx/paver.txt index a6c888df66..f99edb8d89 100644 --- a/requirements/edx/paver.txt +++ b/requirements/edx/paver.txt @@ -35,7 +35,7 @@ pymongo==3.10.1 # edx-opaque-keys python-memcached==1.59 # via -r requirements/edx/paver.in -requests==2.27.1 +requests==2.28.0 # via -r requirements/edx/paver.in six==1.16.0 # via @@ -48,7 +48,7 @@ stevedore==3.5.0 # edx-opaque-keys urllib3==1.26.9 # via requests -watchdog==2.1.8 +watchdog==2.1.9 # via -r requirements/edx/paver.in wrapt==1.14.1 # via -r requirements/edx/paver.in diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index c07df5069c..3831c1ad72 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -59,7 +59,7 @@ asgiref==3.5.2 # -r requirements/edx/base.txt # django # uvicorn -astroid==2.11.5 +astroid==2.11.6 # via # pylint # pylint-celery @@ -224,7 +224,7 @@ cssselect==1.1.0 # via # -r requirements/edx/testing.in # pyquery -cssutils==2.4.1 +cssutils==2.4.2 # via # -r requirements/edx/base.txt # pynliner @@ -242,6 +242,7 @@ defusedxml==0.7.1 # python3-openid # python3-saml # social-auth-core + # tableauserverclient deprecated==1.2.13 # via # -r requirements/edx/base.txt @@ -335,7 +336,7 @@ django-config-models==2.3.0 # edx-enterprise # edx-name-affirmation # lti-consumer-xblock -django-cors-headers==3.12.0 +django-cors-headers==3.13.0 # via -r requirements/edx/base.txt django-countries==7.3.2 # via @@ -402,7 +403,7 @@ django-multi-email-field==0.6.2 # via # -r requirements/edx/base.txt # edx-enterprise -django-mysql==4.6.0 +django-mysql==4.7.0 # via -r requirements/edx/base.txt django-oauth-toolkit==1.3.2 # via @@ -424,7 +425,7 @@ django-sekizai==3.0.1 # via # -r requirements/edx/base.txt # django-wiki -django-ses==3.0.1 +django-ses==3.1.0 # via -r requirements/edx/base.txt django-simple-history==3.0.0 # via @@ -446,7 +447,7 @@ django-storages==1.8 # edxval django-user-tasks==3.0.0 # via -r requirements/edx/base.txt -django-waffle==2.4.1 +django-waffle==2.5.0 # via # -r requirements/edx/base.txt # blockstore @@ -572,7 +573,7 @@ edx-i18n-tools==0.9.1 # -r requirements/edx/base.txt # -r requirements/edx/testing.in # ora2 -edx-lint==5.2.2 +edx-lint==5.2.4 # via -r requirements/edx/testing.in edx-milestones==0.4.0 # via -r requirements/edx/base.txt @@ -661,11 +662,11 @@ execnet==1.9.0 # via pytest-xdist factory-boy==3.2.1 # via -r requirements/edx/testing.in -faker==13.12.0 +faker==13.13.0 # via factory-boy fastapi==0.78.0 # via pact-python -fastavro==1.4.12 +fastavro==1.5.1 # via # -r requirements/edx/base.txt # openedx-events @@ -878,7 +879,7 @@ mysqlclient==2.1.0 # via # -r requirements/edx/base.txt # blockstore -newrelic==7.10.0.175 +newrelic==7.12.0.176 # via # -r requirements/edx/base.txt # edx-django-utils @@ -904,7 +905,7 @@ oauthlib==3.0.1 # social-auth-core openedx-calc==3.0.1 # via -r requirements/edx/base.txt -openedx-events==0.9.1 +openedx-events==0.10.0 # via -r requirements/edx/base.txt openedx-filters==0.7.0 # via @@ -1180,7 +1181,7 @@ regex==2022.6.2 # via # -r requirements/edx/base.txt # nltk -requests==2.27.1 +requests==2.28.0 # via # -r requirements/edx/base.txt # analytics-python @@ -1298,7 +1299,7 @@ social-auth-app-django==5.0.0 # via # -r requirements/edx/base.txt # edx-auth-backends -social-auth-core==4.2.0 +social-auth-core==4.3.0 # via # -r requirements/edx/base.txt # edx-auth-backends @@ -1338,7 +1339,7 @@ sympy==1.10.1 # via # -r requirements/edx/base.txt # openedx-calc -tableauserverclient==0.18.0 +tableauserverclient==0.19.0 # via # -r requirements/edx/base.txt # edx-enterprise @@ -1416,7 +1417,7 @@ voluptuous==0.13.1 # via # -r requirements/edx/base.txt # ora2 -watchdog==2.1.8 +watchdog==2.1.9 # via -r requirements/edx/base.txt wcwidth==0.2.5 # via diff --git a/scripts/xblock/requirements.txt b/scripts/xblock/requirements.txt index 464507e0f8..285b676cc3 100644 --- a/scripts/xblock/requirements.txt +++ b/scripts/xblock/requirements.txt @@ -10,7 +10,7 @@ charset-normalizer==2.0.12 # via requests idna==3.3 # via requests -requests==2.27.1 +requests==2.28.0 # via -r scripts/xblock/requirements.in urllib3==1.26.9 # via requests From 5688ad0ba77d7352fa3475c2af2279a318e44395 Mon Sep 17 00:00:00 2001 From: Jillian Vogel Date: Wed, 15 Jun 2022 01:40:08 +0930 Subject: [PATCH 46/63] fix: call blockstore APIs in atomic transactions. [BD-14] (#30456) * fix: call blockstore APIs in atomic transactions. To ensure database integry when using the blockstore APIs, the Content Library views which invoke blockstore API methods are wrapped in database transactions. * fix: assert create_library is called inside an atomic transaction block --- .../core/djangoapps/content_libraries/api.py | 26 +++++----- .../tests/test_content_libraries.py | 17 ++++++- .../content_libraries/tests/test_runtime.py | 48 ++++++++++--------- .../djangoapps/content_libraries/views.py | 34 +++++++++++++ 4 files changed, 87 insertions(+), 38 deletions(-) diff --git a/openedx/core/djangoapps/content_libraries/api.py b/openedx/core/djangoapps/content_libraries/api.py index c1d95c9d68..1604a4f85c 100644 --- a/openedx/core/djangoapps/content_libraries/api.py +++ b/openedx/core/djangoapps/content_libraries/api.py @@ -426,6 +426,10 @@ def create_library( """ assert isinstance(collection_uuid, UUID) assert isinstance(org, Organization) + assert not transaction.get_autocommit(), ( + "Call within a django.db.transaction.atomic block so that all created objects are rolled back on error." + ) + validate_unicode_slug(slug) # First, create the blockstore bundle: bundle = create_bundle( @@ -436,20 +440,16 @@ def create_library( ) # Now create the library reference in our database: try: - # Atomic transaction required because if this fails, - # we need to delete the bundle in the exception handler. - with transaction.atomic(): - ref = ContentLibrary.objects.create( - org=org, - slug=slug, - type=library_type, - bundle_uuid=bundle.uuid, - allow_public_learning=allow_public_learning, - allow_public_read=allow_public_read, - license=library_license, - ) + ref = ContentLibrary.objects.create( + org=org, + slug=slug, + type=library_type, + bundle_uuid=bundle.uuid, + allow_public_learning=allow_public_learning, + allow_public_read=allow_public_read, + license=library_license, + ) except IntegrityError: - delete_bundle(bundle.uuid) raise LibraryAlreadyExists(slug) # lint-amnesty, pylint: disable=raise-missing-from CONTENT_LIBRARY_CREATED.send(sender=None, library_key=ref.library_key) return ContentLibraryMetadata( diff --git a/openedx/core/djangoapps/content_libraries/tests/test_content_libraries.py b/openedx/core/djangoapps/content_libraries/tests/test_content_libraries.py index a39c5371e8..594c7b0f02 100644 --- a/openedx/core/djangoapps/content_libraries/tests/test_content_libraries.py +++ b/openedx/core/djangoapps/content_libraries/tests/test_content_libraries.py @@ -30,6 +30,7 @@ from openedx.core.djangoapps.content_libraries.tests.base import ( ) from openedx.core.djangoapps.content_libraries.constants import VIDEO, COMPLEX, PROBLEM, CC_4_BY, ALL_RIGHTS_RESERVED from openedx.core.djangolib.blockstore_cache import cache +from openedx.core.lib import blockstore_api from common.djangoapps.student.tests.factories import UserFactory @@ -189,10 +190,22 @@ class ContentLibrariesTestMixin: You can't create a library with the same slug as an existing library, or an invalid slug. """ + assert 0 == len(blockstore_api.get_bundles(text_search='some-slug')) self._create_library(slug="some-slug", title="Existing Library") - self._create_library(slug="some-slug", title="Duplicate Library", expect_response=400) + assert 1 == len(blockstore_api.get_bundles(text_search='some-slug')) - self._create_library(slug="Invalid Slug!", title="Library with Bad Slug", expect_response=400) + # Try to create a library+bundle with a duplicate slug + response = self._create_library(slug="some-slug", title="Duplicate Library", expect_response=400) + assert response == { + 'slug': 'A library with that ID already exists.', + } + # The second bundle created with that slug is removed when the transaction rolls back. + assert 1 == len(blockstore_api.get_bundles(text_search='some-slug')) + + response = self._create_library(slug="Invalid Slug!", title="Library with Bad Slug", expect_response=400) + assert response == { + 'slug': ['Enter a valid “slug” consisting of Unicode letters, numbers, underscores, or hyphens.'], + } @ddt.data(True, False) @patch("openedx.core.djangoapps.content_libraries.views.LibraryApiPagination.page_size", new=2) diff --git a/openedx/core/djangoapps/content_libraries/tests/test_runtime.py b/openedx/core/djangoapps/content_libraries/tests/test_runtime.py index cf9da3dff3..e21fd1edd8 100644 --- a/openedx/core/djangoapps/content_libraries/tests/test_runtime.py +++ b/openedx/core/djangoapps/content_libraries/tests/test_runtime.py @@ -5,7 +5,7 @@ import json from gettext import GNUTranslations from completion.test_utils import CompletionWaffleTestMixin -from django.db import connections +from django.db import connections, transaction from django.test import LiveServerTestCase, TestCase from django.utils.text import slugify from organizations.models import Organization @@ -51,17 +51,18 @@ class ContentLibraryContentTestMixin: short_name="CL-TEST", ) _, slug = self.id().rsplit('.', 1) - self.library = library_api.create_library( - collection_uuid=self.collection.uuid, - library_type=COMPLEX, - org=self.organization, - slug=slugify(slug), - title=(f"{slug} Test Lib"), - description="", - allow_public_learning=True, - allow_public_read=False, - library_license=ALL_RIGHTS_RESERVED, - ) + with transaction.atomic(): + self.library = library_api.create_library( + collection_uuid=self.collection.uuid, + library_type=COMPLEX, + org=self.organization, + slug=slugify(slug), + title=(f"{slug} Test Lib"), + description="", + allow_public_learning=True, + allow_public_read=False, + library_license=ALL_RIGHTS_RESERVED, + ) class ContentLibraryRuntimeTestMixin(ContentLibraryContentTestMixin): @@ -83,17 +84,18 @@ class ContentLibraryRuntimeTestMixin(ContentLibraryContentTestMixin): library_api.create_library_block_child(unit_block_key, "problem", "p1") library_api.publish_changes(self.library.key) # Now do the same in a different library: - library2 = library_api.create_library( - collection_uuid=self.collection.uuid, - org=self.organization, - slug="idolx", - title=("Identical OLX Test Lib 2"), - description="", - library_type=COMPLEX, - allow_public_learning=True, - allow_public_read=False, - library_license=CC_4_BY, - ) + with transaction.atomic(): + library2 = library_api.create_library( + collection_uuid=self.collection.uuid, + org=self.organization, + slug="idolx", + title=("Identical OLX Test Lib 2"), + description="", + library_type=COMPLEX, + allow_public_learning=True, + allow_public_read=False, + library_license=CC_4_BY, + ) unit_block2_key = library_api.create_library_block(library2.key, "unit", "u1").usage_key library_api.create_library_block_child(unit_block2_key, "problem", "p1") library_api.publish_changes(library2.key) diff --git a/openedx/core/djangoapps/content_libraries/views.py b/openedx/core/djangoapps/content_libraries/views.py index a71ac03998..c83a9c4fcb 100644 --- a/openedx/core/djangoapps/content_libraries/views.py +++ b/openedx/core/djangoapps/content_libraries/views.py @@ -18,6 +18,7 @@ from django.contrib.auth import authenticate from django.contrib.auth import get_user_model from django.contrib.auth import login from django.contrib.auth.models import Group +from django.db.transaction import atomic from django.http import Http404 from django.http import HttpResponseBadRequest from django.http import JsonResponse @@ -142,6 +143,7 @@ class LibraryRootView(APIView): Views to list, search for, and create content libraries. """ + @atomic @apidocs.schema( parameters=[ *LibraryApiPagination.apidoc_params, @@ -184,6 +186,7 @@ class LibraryRootView(APIView): return paginator.get_paginated_response(serializer.data) return Response(serializer.data) + @atomic def post(self, request): """ Create a new content library. @@ -223,6 +226,7 @@ class LibraryDetailsView(APIView): """ Views to work with a specific content library """ + @atomic @convert_exceptions def get(self, request, lib_key_str): """ @@ -233,6 +237,7 @@ class LibraryDetailsView(APIView): result = api.get_library(key) return Response(ContentLibraryMetadataSerializer(result).data) + @atomic @convert_exceptions def patch(self, request, lib_key_str): """ @@ -255,6 +260,7 @@ class LibraryDetailsView(APIView): result = api.get_library(key) return Response(ContentLibraryMetadataSerializer(result).data) + @atomic @convert_exceptions def delete(self, request, lib_key_str): # pylint: disable=unused-argument """ @@ -275,6 +281,7 @@ class LibraryTeamView(APIView): Note also the 'allow_public_' settings which can be edited by PATCHing the library itself (LibraryDetailsView.patch). """ + @atomic @convert_exceptions def post(self, request, lib_key_str): """ @@ -302,6 +309,7 @@ class LibraryTeamView(APIView): grant = api.get_library_user_permissions(key, user) return Response(ContentLibraryPermissionSerializer(grant).data) + @atomic @convert_exceptions def get(self, request, lib_key_str): """ @@ -320,6 +328,7 @@ class LibraryTeamUserView(APIView): View to add/remove/edit an individual user's permissions for a content library. """ + @atomic @convert_exceptions def put(self, request, lib_key_str, username): """ @@ -338,6 +347,7 @@ class LibraryTeamUserView(APIView): grant = api.get_library_user_permissions(key, user) return Response(ContentLibraryPermissionSerializer(grant).data) + @atomic @convert_exceptions def get(self, request, lib_key_str, username): """ @@ -351,6 +361,7 @@ class LibraryTeamUserView(APIView): raise NotFound return Response(ContentLibraryPermissionSerializer(grant).data) + @atomic @convert_exceptions def delete(self, request, lib_key_str, username): """ @@ -372,6 +383,7 @@ class LibraryTeamGroupView(APIView): """ View to add/remove/edit a group's permissions for a content library. """ + @atomic @convert_exceptions def put(self, request, lib_key_str, group_name): """ @@ -386,6 +398,7 @@ class LibraryTeamGroupView(APIView): api.set_library_group_permissions(key, group, access_level=serializer.validated_data["access_level"]) return Response({}) + @atomic @convert_exceptions def delete(self, request, lib_key_str, username): """ @@ -404,6 +417,7 @@ class LibraryBlockTypesView(APIView): """ View to get the list of XBlock types that can be added to this library """ + @atomic @convert_exceptions def get(self, request, lib_key_str): """ @@ -428,6 +442,7 @@ class LibraryLinksView(APIView): Links always point to a specific published version of the target bundle. Links are identified by a slug-like ID, e.g. "link1" """ + @atomic @convert_exceptions def get(self, request, lib_key_str): """ @@ -438,6 +453,7 @@ class LibraryLinksView(APIView): result = api.get_bundle_links(key) return Response(LibraryBundleLinkSerializer(result, many=True).data) + @atomic @convert_exceptions def post(self, request, lib_key_str): """ @@ -462,6 +478,7 @@ class LibraryLinkDetailView(APIView): """ View to update/delete an existing library link """ + @atomic @convert_exceptions def patch(self, request, lib_key_str, link_id): """ @@ -478,6 +495,7 @@ class LibraryLinkDetailView(APIView): api.update_bundle_link(key, link_id, version=serializer.validated_data['version']) return Response({}) + @atomic @convert_exceptions def delete(self, request, lib_key_str, link_id): # pylint: disable=unused-argument """ @@ -494,6 +512,7 @@ class LibraryCommitView(APIView): """ Commit/publish or revert all of the draft changes made to the library. """ + @atomic @convert_exceptions def post(self, request, lib_key_str): """ @@ -505,6 +524,7 @@ class LibraryCommitView(APIView): api.publish_changes(key) return Response({}) + @atomic @convert_exceptions def delete(self, request, lib_key_str): # pylint: disable=unused-argument """ @@ -522,6 +542,7 @@ class LibraryBlocksView(APIView): """ Views to work with XBlocks in a specific content library. """ + @atomic @apidocs.schema( parameters=[ *LibraryApiPagination.apidoc_params, @@ -560,6 +581,7 @@ class LibraryBlocksView(APIView): return Response(LibraryXBlockMetadataSerializer(result, many=True).data) + @atomic @convert_exceptions def post(self, request, lib_key_str): """ @@ -592,6 +614,7 @@ class LibraryBlockView(APIView): """ Views to work with an existing XBlock in a content library. """ + @atomic @convert_exceptions def get(self, request, usage_key_str): """ @@ -602,6 +625,7 @@ class LibraryBlockView(APIView): result = api.get_library_block(key) return Response(LibraryXBlockMetadataSerializer(result).data) + @atomic @convert_exceptions def delete(self, request, usage_key_str): # pylint: disable=unused-argument """ @@ -628,6 +652,7 @@ class LibraryBlockLtiUrlView(APIView): Returns 404 in case the block not found by the given key. """ + @atomic @convert_exceptions def get(self, request, usage_key_str): """ @@ -647,6 +672,7 @@ class LibraryBlockOlxView(APIView): """ Views to work with an existing XBlock's OLX """ + @atomic @convert_exceptions def get(self, request, usage_key_str): """ @@ -657,6 +683,7 @@ class LibraryBlockOlxView(APIView): xml_str = api.get_library_block_olx(key) return Response(LibraryXBlockOlxSerializer({"olx": xml_str}).data) + @atomic @convert_exceptions def post(self, request, usage_key_str): """ @@ -682,6 +709,7 @@ class LibraryBlockAssetListView(APIView): """ Views to list an existing XBlock's static asset files """ + @atomic @convert_exceptions def get(self, request, usage_key_str): """ @@ -700,6 +728,7 @@ class LibraryBlockAssetView(APIView): """ parser_classes = (MultiPartParser, ) + @atomic @convert_exceptions def get(self, request, usage_key_str, file_path): """ @@ -713,6 +742,7 @@ class LibraryBlockAssetView(APIView): return Response(LibraryXBlockStaticFileSerializer(f).data) raise NotFound + @atomic @convert_exceptions def put(self, request, usage_key_str, file_path): """ @@ -735,6 +765,7 @@ class LibraryBlockAssetView(APIView): raise ValidationError("Invalid file path") # lint-amnesty, pylint: disable=raise-missing-from return Response(LibraryXBlockStaticFileSerializer(result).data) + @atomic @convert_exceptions def delete(self, request, usage_key_str, file_path): """ @@ -757,6 +788,7 @@ class LibraryImportTaskViewSet(ViewSet): Import blocks from Courseware through modulestore. """ + @atomic @convert_exceptions def list(self, request, lib_key_str): """ @@ -775,6 +807,7 @@ class LibraryImportTaskViewSet(ViewSet): paginator.paginate_queryset(result, request) ) + @atomic @convert_exceptions def create(self, request, lib_key_str): """ @@ -795,6 +828,7 @@ class LibraryImportTaskViewSet(ViewSet): import_task = api.import_blocks_create_task(library_key, course_key) return Response(ContentLibraryBlockImportTaskSerializer(import_task).data) + @atomic @convert_exceptions def retrieve(self, request, lib_key_str, pk=None): """ From 6c6dabaa3c7a2ef5684c97bbaaa556c6b253e3c9 Mon Sep 17 00:00:00 2001 From: Zaman Afzal Date: Wed, 15 Jun 2022 00:58:22 +0500 Subject: [PATCH 47/63] Feat: Add Learner pathway progress update signal (#30547) * feat: Add Learner pathway progress update signal --- .../certificates/tests/test_signals.py | 83 +++++++++++++++++++ ...rs_for_old_enterprise_course_enrollmnet.py | 33 +++++--- .../tests/test_submitting_problems.py | 23 ++++- lms/djangoapps/grades/course_grade_factory.py | 10 +++ lms/djangoapps/grades/models.py | 11 ++- lms/djangoapps/grades/signals/signals.py | 1 + .../grades/tests/test_course_grade_factory.py | 26 ++++-- lms/djangoapps/grades/tests/test_models.py | 20 ++++- lms/djangoapps/grades/tests/test_signals.py | 4 + .../instructor/tests/test_spoc_gradebook.py | 17 +++- .../tests/test_tasks_helper.py | 62 +++++++------- .../api/v0/tests/test_views.py | 12 ++- lms/djangoapps/support/tests/test_views.py | 12 ++- .../accounts/tests/test_retirement_views.py | 14 ++++ .../enterprise_support/tests/test_api.py | 12 ++- .../enterprise_support/tests/test_context.py | 24 ++++-- .../tests/test_serializers.py | 25 ++++-- .../enterprise_support/tests/test_signals.py | 16 +++- requirements/common_constraints.txt | 10 +++ requirements/constraints.txt | 1 + requirements/edx-sandbox/py38.txt | 2 +- requirements/edx/base.in | 1 + requirements/edx/base.txt | 11 ++- requirements/edx/development.txt | 11 ++- requirements/edx/doc.txt | 2 +- requirements/edx/testing.txt | 11 ++- 26 files changed, 369 insertions(+), 85 deletions(-) diff --git a/lms/djangoapps/certificates/tests/test_signals.py b/lms/djangoapps/certificates/tests/test_signals.py index abc10411ec..4a85f895d8 100644 --- a/lms/djangoapps/certificates/tests/test_signals.py +++ b/lms/djangoapps/certificates/tests/test_signals.py @@ -57,9 +57,23 @@ class AllowlistGeneratedCertificatesTest(ModuleStoreTestCase): Tests for allowlisted student auto-certificate generation """ + def setup_patch(self, function_name, return_value): + """ + Patch a function with a given return value, and return the mock + """ + magic_mock = mock.MagicMock(return_value=return_value) + new_patch = mock.patch(function_name, new=magic_mock) + new_patch.start() + self.addCleanup(new_patch.stop) + return magic_mock + def setUp(self): super().setUp() self.user = UserFactory.create() + self.mock_pathways_with_course = self.setup_patch( + 'learner_pathway_progress.signals.get_learner_pathways_associated_with_course', + None, + ) # Instructor paced course self.ip_course = CourseFactory.create(self_paced=False) CourseEnrollmentFactory( @@ -105,11 +119,29 @@ class PassingGradeCertsTest(ModuleStoreTestCase): Tests for certificate generation task firing on passing grade receipt """ + def setup_patch(self, function_name, return_value): + """ + Patch a function with a given return value, and return the mock + """ + magic_mock = mock.MagicMock(return_value=return_value) + new_patch = mock.patch(function_name, new=magic_mock) + new_patch.start() + self.addCleanup(new_patch.stop) + return magic_mock + def setUp(self): super().setUp() self.course = CourseFactory.create( self_paced=True, ) + self.mock_pathways_with_course = self.setup_patch( + 'learner_pathway_progress.signals.get_learner_pathways_associated_with_course', + None, + ) + self.signal_mock_course_passed_pathway_progress = self.setup_patch( + 'learner_pathway_progress.signals.update_learner_pathway_progress', + None, + ) self.course_key = self.course.id self.user = UserFactory.create() self.enrollment = CourseEnrollmentFactory( @@ -222,12 +254,26 @@ class FailingGradeCertsTest(ModuleStoreTestCase): status """ + def setup_patch(self, function_name, return_value): + """ + Patch a function with a given return value, and return the mock + """ + magic_mock = mock.MagicMock(return_value=return_value) + new_patch = mock.patch(function_name, new=magic_mock) + new_patch.start() + self.addCleanup(new_patch.stop) + return magic_mock + def setUp(self): super().setUp() self.course = CourseFactory.create( self_paced=True, ) self.user = UserFactory.create() + self.mock_pathways_with_course = self.setup_patch( + 'learner_pathway_progress.signals.get_learner_pathways_associated_with_course', + None, + ) self.enrollment = CourseEnrollmentFactory( user=self.user, course_id=self.course.id, @@ -304,10 +350,28 @@ class LearnerIdVerificationTest(ModuleStoreTestCase): Tests for certificate generation task firing on learner id verification """ + def setup_patch(self, function_name, return_value): + """ + Patch a function with a given return value, and return the mock + """ + magic_mock = mock.MagicMock(return_value=return_value) + new_patch = mock.patch(function_name, new=magic_mock) + new_patch.start() + self.addCleanup(new_patch.stop) + return magic_mock + def setUp(self): super().setUp() self.course_one = CourseFactory.create(self_paced=True) self.user_one = UserFactory.create() + self.mock_pathways_with_course = self.setup_patch( + 'learner_pathway_progress.signals.get_learner_pathways_associated_with_course', + None, + ) + self.signal_mock_course_passed_pathway_progress = self.setup_patch( + 'learner_pathway_progress.signals.update_learner_pathway_progress', + None, + ) self.enrollment_one = CourseEnrollmentFactory( user=self.user_one, course_id=self.course_one.id, @@ -386,12 +450,31 @@ class EnrollmentModeChangeCertsTest(ModuleStoreTestCase): """ Tests for certificate generation task firing when the user's enrollment mode changes """ + + def setup_patch(self, function_name, return_value): + """ + Patch a function with a given return value, and return the mock + """ + magic_mock = mock.MagicMock(return_value=return_value) + new_patch = mock.patch(function_name, new=magic_mock) + new_patch.start() + self.addCleanup(new_patch.stop) + return magic_mock + def setUp(self): super().setUp() self.user = UserFactory.create() self.verified_course = CourseFactory.create( self_paced=True, ) + self.mock_update_pathway_progress = self.setup_patch( + 'learner_pathway_progress.signals.update_learner_pathway_progress', + None, + ) + self.signal_mock_course_passed_pathway_progress = self.setup_patch( + 'learner_pathway_progress.signals.listen_for_course_grade_upgrade_in_learner_pathway', + None, + ) self.verified_course_key = self.verified_course.id # pylint: disable=no-member self.verified_enrollment = CourseEnrollmentFactory( user=self.user, diff --git a/lms/djangoapps/commerce/management/commands/tests/test_create_orders_for_old_enterprise_course_enrollmnet.py b/lms/djangoapps/commerce/management/commands/tests/test_create_orders_for_old_enterprise_course_enrollmnet.py index 8b2472f214..7af3cdcf69 100644 --- a/lms/djangoapps/commerce/management/commands/tests/test_create_orders_for_old_enterprise_course_enrollmnet.py +++ b/lms/djangoapps/commerce/management/commands/tests/test_create_orders_for_old_enterprise_course_enrollmnet.py @@ -37,24 +37,31 @@ class TestEnterpriseCourseEnrollmentCreateOldOrder(TestCase): """ Creates `count` test enrollments plus 1 invalid and 1 Audit enrollment """ - for _ in range(count): + with patch( + 'learner_pathway_progress.signals.get_learner_pathways_associated_with_course', + return_value=None + ): + for _ in range(count): + user = UserFactory() + course_enrollment = CourseEnrollmentFactory(mode=CourseMode.VERIFIED, user=user) + course = course_enrollment.course + enterprise_customer_user = EnterpriseCustomerUserFactory(user_id=user.id) + EnterpriseCourseEnrollmentFactory( + enterprise_customer_user=enterprise_customer_user, + course_id=course.id + ) + + # creating audit enrollment user = UserFactory() - course_enrollment = CourseEnrollmentFactory(mode=CourseMode.VERIFIED, user=user) + course_enrollment = CourseEnrollmentFactory(mode=CourseMode.AUDIT, user=user) course = course_enrollment.course enterprise_customer_user = EnterpriseCustomerUserFactory(user_id=user.id) EnterpriseCourseEnrollmentFactory(enterprise_customer_user=enterprise_customer_user, course_id=course.id) - # creating audit enrollment - user = UserFactory() - course_enrollment = CourseEnrollmentFactory(mode=CourseMode.AUDIT, user=user) - course = course_enrollment.course - enterprise_customer_user = EnterpriseCustomerUserFactory(user_id=user.id) - EnterpriseCourseEnrollmentFactory(enterprise_customer_user=enterprise_customer_user, course_id=course.id) - - # creating invalid enrollment (with no CourseEnrollment) - user = UserFactory() - enterprise_customer_user = EnterpriseCustomerUserFactory(user_id=user.id) - EnterpriseCourseEnrollmentFactory(enterprise_customer_user=enterprise_customer_user, course_id=course.id) + # creating invalid enrollment (with no CourseEnrollment) + user = UserFactory() + enterprise_customer_user = EnterpriseCustomerUserFactory(user_id=user.id) + EnterpriseCourseEnrollmentFactory(enterprise_customer_user=enterprise_customer_user, course_id=course.id) @patch('lms.djangoapps.commerce.management.commands.create_orders_for_old_enterprise_course_enrollment' '.Command._create_manual_enrollment_orders') diff --git a/lms/djangoapps/courseware/tests/test_submitting_problems.py b/lms/djangoapps/courseware/tests/test_submitting_problems.py index fa9f381160..3ab728bb8e 100644 --- a/lms/djangoapps/courseware/tests/test_submitting_problems.py +++ b/lms/djangoapps/courseware/tests/test_submitting_problems.py @@ -9,7 +9,7 @@ import json import os from datetime import datetime from textwrap import dedent -from unittest.mock import patch +from unittest.mock import patch, MagicMock import ddt import pytz @@ -345,6 +345,27 @@ class TestCourseGrader(TestSubmittingProblems): """ Suite of tests for the course grader. """ + def setup_patch(self, function_name, return_value): + """ + Patch a function with a given return value, and return the mock + """ + magic_mock = MagicMock(return_value=return_value) + new_patch = patch(function_name, new=magic_mock) + new_patch.start() + self.addCleanup(new_patch.stop) + return magic_mock + + def setUp(self): + super().setUp() + self.mock_pathways_with_course = self.setup_patch( + 'learner_pathway_progress.signals.get_learner_pathways_associated_with_course', + None, + ) + self.signal_mock_course_passed_pathway_progress = self.setup_patch( + 'learner_pathway_progress.signals.update_learner_pathway_progress', + None, + ) + # Tell Django to clean out all databases, not just default databases = set(connections) diff --git a/lms/djangoapps/grades/course_grade_factory.py b/lms/djangoapps/grades/course_grade_factory.py index 65f3a9c4cc..a68331860b 100644 --- a/lms/djangoapps/grades/course_grade_factory.py +++ b/lms/djangoapps/grades/course_grade_factory.py @@ -10,6 +10,10 @@ from openedx.core.djangoapps.signals.signals import ( COURSE_GRADE_NOW_PASSED ) +from lms.djangoapps.grades.signals.signals import ( + COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY, +) + from .config import assume_zero_if_absent, should_persist_grades from .course_data import CourseData from .course_grade import CourseGrade, ZeroCourseGrade @@ -171,6 +175,7 @@ class CourseGradeFactory: COURSE_GRADE_CHANGED signal to listeners and COURSE_GRADE_NOW_PASSED if learner has passed course or COURSE_GRADE_NOW_FAILED if learner is now failing course + COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY if learner has passed course """ should_persist = should_persist_grades(course_data.course_key) if should_persist and force_update_subsections: @@ -211,6 +216,11 @@ class CourseGradeFactory: user=user, course_id=course_data.course_key, ) + COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY.send( + sender=CourseGradeFactory, + user_id=user.id, + course_id=course_data.course_key, + ) else: COURSE_GRADE_NOW_FAILED.send( sender=CourseGradeFactory, diff --git a/lms/djangoapps/grades/models.py b/lms/djangoapps/grades/models.py index 0d87873f20..76b2e37cb0 100644 --- a/lms/djangoapps/grades/models.py +++ b/lms/djangoapps/grades/models.py @@ -27,7 +27,11 @@ from simple_history.models import HistoricalRecords from lms.djangoapps.courseware.fields import UnsignedBigIntAutoField from lms.djangoapps.grades import events # lint-amnesty, pylint: disable=unused-import from openedx.core.lib.cache_utils import get_cache -from lms.djangoapps.grades.signals.signals import COURSE_GRADE_PASSED_FIRST_TIME +from lms.djangoapps.grades.signals.signals import ( + COURSE_GRADE_PASSED_FIRST_TIME, + COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY +) + log = logging.getLogger(__name__) @@ -650,6 +654,11 @@ class PersistentCourseGrade(TimeStampedModel): course_id=course_id, user_id=user_id ) + COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY.send( + sender=None, + user_id=user_id, + course_id=course_id, + ) grade.passed_timestamp = now() grade.save() diff --git a/lms/djangoapps/grades/signals/signals.py b/lms/djangoapps/grades/signals/signals.py index 0edd48b4d5..73a31f937c 100644 --- a/lms/djangoapps/grades/signals/signals.py +++ b/lms/djangoapps/grades/signals/signals.py @@ -111,3 +111,4 @@ SUBSECTION_OVERRIDE_CHANGED = Signal() # 'user_id', # User object id # ] COURSE_GRADE_PASSED_FIRST_TIME = Signal() +COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY = Signal() diff --git a/lms/djangoapps/grades/tests/test_course_grade_factory.py b/lms/djangoapps/grades/tests/test_course_grade_factory.py index 39b2cfb60c..080caf3ff8 100644 --- a/lms/djangoapps/grades/tests/test_course_grade_factory.py +++ b/lms/djangoapps/grades/tests/test_course_grade_factory.py @@ -13,6 +13,7 @@ from common.djangoapps.student.tests.factories import UserFactory from lms.djangoapps.certificates.config import AUTO_CERTIFICATE_GENERATION from lms.djangoapps.courseware.access import has_access from lms.djangoapps.grades.config.tests.utils import persistent_grades_feature_flags +from lms.djangoapps.grades.signals.signals import COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY from openedx.core.djangoapps.content.block_structure.factory import BlockStructureFactory from openedx.core.djangoapps.signals.signals import COURSE_GRADE_NOW_PASSED from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order @@ -95,16 +96,25 @@ class TestCourseGradeFactory(GradeTestBase): course_id=self.course.id, enabled_for_course=False ): - with override_waffle_switch(AUTO_CERTIFICATE_GENERATION, active=True), mock_get_score(2, 2): - COURSE_GRADE_NOW_PASSED.connect(handler) - try: - CourseGradeFactory().update(self.request.user, self.course) - except RecursionError: - pytest.fail("The COURSE_GRADE_NOW_PASSED signal fired recursively.") + with patch( + 'lms.djangoapps.grades.signals.signals.COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY.send', + return_value=None + ) as mock_course_passed_pathway: + with override_waffle_switch(AUTO_CERTIFICATE_GENERATION, active=True), mock_get_score(2, 2): + COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY.connect(handler) + COURSE_GRADE_NOW_PASSED.connect(handler) + try: + CourseGradeFactory().update(self.request.user, self.course) + except RecursionError: + pytest.fail("The COURSE_GRADE_NOW_PASSED signal fired recursively.") + mock_course_passed_pathway.assert_called_once() self.mock_process_signal.assert_called_once() + COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY.disconnect(handler) COURSE_GRADE_NOW_PASSED.disconnect(handler) + @patch('lms.djangoapps.grades.signals.signals.COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY.send', + Mock(return_value=None)) def test_read_and_update(self): grade_factory = CourseGradeFactory() @@ -170,6 +180,8 @@ class TestCourseGradeFactory(GradeTestBase): else: assert course_grade is None + @patch('lms.djangoapps.grades.signals.signals.COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY.send', + Mock(return_value=None)) def test_read_optimization(self): grade_factory = CourseGradeFactory() with patch('lms.djangoapps.grades.course_data.get_course_blocks') as mocked_course_blocks: @@ -188,6 +200,8 @@ class TestCourseGradeFactory(GradeTestBase): assert not mocked_course_blocks.called # no user-specific transformer calculation + @patch('lms.djangoapps.grades.signals.signals.COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY.send', + Mock(return_value=None)) def test_subsection_grade(self): grade_factory = CourseGradeFactory() with mock_get_score(1, 2): diff --git a/lms/djangoapps/grades/tests/test_models.py b/lms/djangoapps/grades/tests/test_models.py index 5405b03e94..3ea25b178f 100644 --- a/lms/djangoapps/grades/tests/test_models.py +++ b/lms/djangoapps/grades/tests/test_models.py @@ -8,7 +8,7 @@ from base64 import b64encode from collections import OrderedDict from datetime import datetime from hashlib import sha1 -from unittest.mock import patch +from unittest.mock import patch, MagicMock import ddt import pytest @@ -373,6 +373,20 @@ class PersistentCourseGradesTest(GradesModelTestCase): "letter_grade": "Great job", "passed": True, } + self.signal_mock_pathway_progress = self.setup_patch( + 'lms.djangoapps.grades.signals.signals.COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY.send', + None, + ) + + def setup_patch(self, function_name, return_value): + """ + Patch a function with a given return value, and return the mock + """ + mock = MagicMock(return_value=return_value) + new_patch = patch(function_name, new=mock) + new_patch.start() + self.addCleanup(new_patch.stop) + return mock def test_update(self): created_grade = PersistentCourseGrade.update_or_create(**self.params) @@ -425,12 +439,14 @@ class PersistentCourseGradesTest(GradesModelTestCase): assert grade.letter_grade == '' assert grade.passed_timestamp == passed_timestamp + @patch('lms.djangoapps.grades.signals.signals.COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY.send') @patch('lms.djangoapps.grades.signals.signals.COURSE_GRADE_PASSED_FIRST_TIME.send') - def test_passed_timestamp_is_now(self, mock): + def test_passed_timestamp_is_now(self, mock, mock_grade_update_in_learner_pathway): with freeze_time(now()): grade = PersistentCourseGrade.update_or_create(**self.params) assert now() == grade.passed_timestamp self.assertEqual(mock.call_count, 1) + self.assertEqual(mock_grade_update_in_learner_pathway.call_count, 1) def test_create_and_read_grade(self): created_grade = PersistentCourseGrade.update_or_create(**self.params) diff --git a/lms/djangoapps/grades/tests/test_signals.py b/lms/djangoapps/grades/tests/test_signals.py index 8c161d86ac..4e16c0bdbf 100644 --- a/lms/djangoapps/grades/tests/test_signals.py +++ b/lms/djangoapps/grades/tests/test_signals.py @@ -285,6 +285,10 @@ class CourseEventsSignalsTest(ModuleStoreTestCase): Configure mocks for all the dependencies of the render method """ super().setUp() + self.signal_mock_pathway_progress = self.setup_patch( + 'lms.djangoapps.grades.signals.signals.COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY.send', + None, + ) self.user_mock = MagicMock() self.user_mock.id = 42 self.get_user_mock = self.setup_patch( diff --git a/lms/djangoapps/instructor/tests/test_spoc_gradebook.py b/lms/djangoapps/instructor/tests/test_spoc_gradebook.py index 1f2485f1b3..d063c056e2 100644 --- a/lms/djangoapps/instructor/tests/test_spoc_gradebook.py +++ b/lms/djangoapps/instructor/tests/test_spoc_gradebook.py @@ -1,6 +1,8 @@ """ Tests of the instructor dashboard spoc gradebook """ +from unittest.mock import patch, MagicMock + from django.urls import reverse from capa.tests.response_xml_factory import StringResponseXMLFactory @@ -21,6 +23,16 @@ class TestGradebook(SharedModuleStoreTestCase): """ grading_policy = None + def setup_patch(self, function_name, return_value): + """ + Patch a function with a given return value, and return the mock + """ + mock = MagicMock(return_value=return_value) + new_patch = patch(function_name, new=mock) + new_patch.start() + self.addCleanup(new_patch.stop) + return mock + @classmethod def setUpClass(cls): super().setUpClass() @@ -58,7 +70,10 @@ class TestGradebook(SharedModuleStoreTestCase): instructor = AdminFactory.create() self.client.login(username=instructor.username, password='test') self.users = [UserFactory.create() for _ in range(USER_COUNT)] - + self.signal_mock_pathway_progress = self.setup_patch( + 'lms.djangoapps.grades.signals.signals.COURSE_GRADE_PASSED_UPDATE_IN_LEARNER_PATHWAY.send', + None, + ) for user in self.users: CourseEnrollmentFactory.create(user=user, course_id=self.course.id) diff --git a/lms/djangoapps/instructor_task/tests/test_tasks_helper.py b/lms/djangoapps/instructor_task/tests/test_tasks_helper.py index 1807a8af96..14d49fb24f 100644 --- a/lms/djangoapps/instructor_task/tests/test_tasks_helper.py +++ b/lms/djangoapps/instructor_task/tests/test_tasks_helper.py @@ -338,36 +338,40 @@ class TestInstructorGradeReport(InstructorGradeReportTestCase): audit_user = CourseEnrollment.enroll(UserFactory.create(), course.id) self._verify_cell_data_for_user(audit_user.username, course.id, 'Certificate Eligible', 'N', num_rows=1) grading_policy_hash = GradesTransformer.grading_policy_hash(course) - PersistentCourseGrade.update_or_create( - user_id=audit_user.user_id, - course_id=course.id, - passed=False, - percent_grade=0.0, - grading_policy_hash=grading_policy_hash, - ) - self._verify_cell_data_for_user(audit_user.username, course.id, 'Certificate Eligible', 'N', num_rows=1) - PersistentCourseGrade.update_or_create( - user_id=audit_user.user_id, - course_id=course.id, - passed=True, - percent_grade=0.8, - letter_grade="pass", - grading_policy_hash=grading_policy_hash, - ) - # verifies that audit passing learner is not eligible for certificate - self._verify_cell_data_for_user(audit_user.username, course.id, 'Certificate Eligible', 'N', num_rows=1) + with patch( + 'learner_pathway_progress.signals.update_learner_pathway_progress', + return_value=None + ): + PersistentCourseGrade.update_or_create( + user_id=audit_user.user_id, + course_id=course.id, + passed=False, + percent_grade=0.0, + grading_policy_hash=grading_policy_hash, + ) + self._verify_cell_data_for_user(audit_user.username, course.id, 'Certificate Eligible', 'N', num_rows=1) + PersistentCourseGrade.update_or_create( + user_id=audit_user.user_id, + course_id=course.id, + passed=True, + percent_grade=0.8, + letter_grade="pass", + grading_policy_hash=grading_policy_hash, + ) + # verifies that audit passing learner is not eligible for certificate + self._verify_cell_data_for_user(audit_user.username, course.id, 'Certificate Eligible', 'N', num_rows=1) - verified_user = CourseEnrollment.enroll(UserFactory.create(), course.id, 'verified') - PersistentCourseGrade.update_or_create( - user_id=verified_user.user_id, - course_id=course.id, - passed=True, - percent_grade=0.8, - letter_grade="pass", - grading_policy_hash=grading_policy_hash, - ) - # verifies that verified passing learner is eligible for certificate - self._verify_cell_data_for_user(verified_user.username, course.id, 'Certificate Eligible', 'Y', num_rows=2) + verified_user = CourseEnrollment.enroll(UserFactory.create(), course.id, 'verified') + PersistentCourseGrade.update_or_create( + user_id=verified_user.user_id, + course_id=course.id, + passed=True, + percent_grade=0.8, + letter_grade="pass", + grading_policy_hash=grading_policy_hash, + ) + # verifies that verified passing learner is eligible for certificate + self._verify_cell_data_for_user(verified_user.username, course.id, 'Certificate Eligible', 'Y', num_rows=2) @ddt.data( (ModuleStoreEnum.Type.mongo, 4, 47), diff --git a/lms/djangoapps/learner_dashboard/api/v0/tests/test_views.py b/lms/djangoapps/learner_dashboard/api/v0/tests/test_views.py index 7072235ef1..eb985f058e 100644 --- a/lms/djangoapps/learner_dashboard/api/v0/tests/test_views.py +++ b/lms/djangoapps/learner_dashboard/api/v0/tests/test_views.py @@ -155,10 +155,14 @@ class TestProgramsView(SharedModuleStoreTestCase, ProgramCacheMixin): course_id=modulestore_course.id, user=cls.user ) - EnterpriseCourseEnrollmentFactory( - course_id=modulestore_course.id, - enterprise_customer_user=enterprise_customer_user - ) + with mock.patch( + 'learner_pathway_progress.signals.get_learner_pathways_associated_with_course', + return_value=None + ): + EnterpriseCourseEnrollmentFactory( + course_id=modulestore_course.id, + enterprise_customer_user=enterprise_customer_user + ) cls.program = ProgramFactory( uuid=cls.program_uuid, diff --git a/lms/djangoapps/support/tests/test_views.py b/lms/djangoapps/support/tests/test_views.py index 3aa56a0a76..f6b4206aa6 100644 --- a/lms/djangoapps/support/tests/test_views.py +++ b/lms/djangoapps/support/tests/test_views.py @@ -343,10 +343,14 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase enterprise_customer_user = EnterpriseCustomerUserFactory( user_id=self.student.id ) - enterprise_course_enrollment = EnterpriseCourseEnrollmentFactory( - course_id=self.course.id, - enterprise_customer_user=enterprise_customer_user - ) + with patch( + 'learner_pathway_progress.signals.get_learner_pathways_associated_with_course', + return_value=None + ): + enterprise_course_enrollment = EnterpriseCourseEnrollmentFactory( + course_id=self.course.id, + enterprise_customer_user=enterprise_customer_user + ) data_sharing_consent = DataSharingConsent( course_id=self.course.id, enterprise_customer=enterprise_customer_user.enterprise_customer, diff --git a/openedx/core/djangoapps/user_api/accounts/tests/test_retirement_views.py b/openedx/core/djangoapps/user_api/accounts/tests/test_retirement_views.py index c1ee73a970..c416b7a4c2 100644 --- a/openedx/core/djangoapps/user_api/accounts/tests/test_retirement_views.py +++ b/openedx/core/djangoapps/user_api/accounts/tests/test_retirement_views.py @@ -1310,6 +1310,10 @@ class TestAccountRetirementPost(RetirementTestCase): self.cache_key = UserProfile.country_cache_key_name(self.test_user.id) cache.set(self.cache_key, 'Timor-leste') + self.mock_pathways_with_course = self.setup_patch( + 'learner_pathway_progress.signals.get_learner_pathways_associated_with_course', + None, + ) # Enterprise model setup self.course_id = 'course-v1:edX+DemoX.1+2T2017' @@ -1371,6 +1375,16 @@ class TestAccountRetirementPost(RetirementTestCase): self.headers['content_type'] = "application/json" self.url = reverse('accounts_retire') + def setup_patch(self, function_name, return_value): + """ + Patch a function with a given return value, and return the mock + """ + magic_mock = mock.MagicMock(return_value=return_value) + new_patch = mock.patch(function_name, new=magic_mock) + new_patch.start() + self.addCleanup(new_patch.stop) + return magic_mock + def post_and_assert_status(self, data, expected_status=status.HTTP_204_NO_CONTENT): """ Helper function for making a request to the retire subscriptions endpoint, and asserting the status. diff --git a/openedx/features/enterprise_support/tests/test_api.py b/openedx/features/enterprise_support/tests/test_api.py index 3731e81a1b..cd1958353e 100644 --- a/openedx/features/enterprise_support/tests/test_api.py +++ b/openedx/features/enterprise_support/tests/test_api.py @@ -447,10 +447,14 @@ class TestEnterpriseApi(EnterpriseServiceMockMixin, CacheIsolationTestCase): if not is_enterprise_enabled: assert get_enterprise_course_enrollments(self.user) == [] else: - ece = EnterpriseCourseEnrollmentFactory(enterprise_customer_user=enterprise_customer_user) - enterprise_course_enrollments = get_enterprise_course_enrollments(self.user) - assert len(enterprise_course_enrollments) == 1 - assert enterprise_course_enrollments[0].id == ece.id + with mock.patch( + 'learner_pathway_progress.signals.get_learner_pathways_associated_with_course', + return_value=None + ): + ece = EnterpriseCourseEnrollmentFactory(enterprise_customer_user=enterprise_customer_user) + enterprise_course_enrollments = get_enterprise_course_enrollments(self.user) + assert len(enterprise_course_enrollments) == 1 + assert enterprise_course_enrollments[0].id == ece.id @httpretty.activate @mock.patch('openedx.features.enterprise_support.api.get_enterprise_learner_data_from_db') diff --git a/openedx/features/enterprise_support/tests/test_context.py b/openedx/features/enterprise_support/tests/test_context.py index d775859b1b..6a671bd9a2 100644 --- a/openedx/features/enterprise_support/tests/test_context.py +++ b/openedx/features/enterprise_support/tests/test_context.py @@ -1,6 +1,8 @@ """ Test the enterprise support APIs. """ +from unittest.mock import patch + from django.conf import settings from django.test.utils import override_settings @@ -33,12 +35,16 @@ class TestEnterpriseContext(EnterpriseServiceMockMixin, CacheIsolationTestCase): super().setUpTestData() def test_get_enterprise_event_context(self): - course_enrollment = CourseEnrollmentFactory(user=self.user) - course = course_enrollment.course - enterprise_customer_user = EnterpriseCustomerUserFactory(user_id=self.user.id) - EnterpriseCourseEnrollmentFactory( - enterprise_customer_user=enterprise_customer_user, - course_id=course.id - ) - assert get_enterprise_event_context(course_id=course.id, user_id=self.user.id) == \ - {'enterprise_uuid': str(enterprise_customer_user.enterprise_customer_id)} + with patch( + 'learner_pathway_progress.signals.get_learner_pathways_associated_with_course', + return_value=None + ): + course_enrollment = CourseEnrollmentFactory(user=self.user) + course = course_enrollment.course + enterprise_customer_user = EnterpriseCustomerUserFactory(user_id=self.user.id) + EnterpriseCourseEnrollmentFactory( + enterprise_customer_user=enterprise_customer_user, + course_id=course.id + ) + assert get_enterprise_event_context(course_id=course.id, user_id=self.user.id) == \ + {'enterprise_uuid': str(enterprise_customer_user.enterprise_customer_id)} diff --git a/openedx/features/enterprise_support/tests/test_serializers.py b/openedx/features/enterprise_support/tests/test_serializers.py index aa82b8dbb0..876bf3e348 100644 --- a/openedx/features/enterprise_support/tests/test_serializers.py +++ b/openedx/features/enterprise_support/tests/test_serializers.py @@ -1,7 +1,7 @@ """ Tests for custom enterprise_support Serializers. """ - +from unittest.mock import patch, MagicMock from uuid import uuid4 from django.test import TestCase @@ -19,14 +19,29 @@ class EnterpriseCourseEnrollmentSerializerTests(TestCase): Tests for EnterpriseCourseEnrollmentSerializer. """ - @classmethod - def setUpTestData(cls): # lint-amnesty, pylint: disable=super-method-not-called + def setup_patch(self, function_name, return_value): + """ + Patch a function with a given return value, and return the mock + """ + mock = MagicMock(return_value=return_value) + new_patch = patch(function_name, new=mock) + new_patch.start() + self.addCleanup(new_patch.stop) + return mock + + def setUp(self): + self.mock_pathways_with_course = self.setup_patch( + 'learner_pathway_progress.signals.get_learner_pathways_associated_with_course', + None, + ) enterprise_customer_user = EnterpriseCustomerUserFactory() enterprise_course_enrollment = EnterpriseCourseEnrollmentFactory( enterprise_customer_user=enterprise_customer_user ) - cls.enterprise_customer_user = enterprise_customer_user - cls.enterprise_course_enrollment = enterprise_course_enrollment + self.enterprise_customer_user = enterprise_customer_user + self.enterprise_course_enrollment = enterprise_course_enrollment + + super().setUp() def test_data_with_license(self): """ Verify the correct fields are serialized when the enrollment is licensed. """ diff --git a/openedx/features/enterprise_support/tests/test_signals.py b/openedx/features/enterprise_support/tests/test_signals.py index 5ebb1123e1..a4545dff70 100644 --- a/openedx/features/enterprise_support/tests/test_signals.py +++ b/openedx/features/enterprise_support/tests/test_signals.py @@ -3,7 +3,7 @@ import logging from datetime import timedelta -from unittest.mock import patch +from unittest.mock import patch, MagicMock import ddt from django.test.utils import override_settings @@ -46,12 +46,26 @@ class EnterpriseSupportSignals(SharedModuleStoreTestCase): Tests for the enterprise support signals. """ + def setup_patch(self, function_name, return_value): + """ + Patch a function with a given return value, and return the mock + """ + mock = MagicMock(return_value=return_value) + new_patch = patch(function_name, new=mock) + new_patch.start() + self.addCleanup(new_patch.stop) + return mock + def setUp(self): UserFactory.create(username=TEST_ECOMMERCE_WORKER) self.user = UserFactory.create(username='test', email=TEST_EMAIL) self.course_id = 'course-v1:edX+DemoX+Demo_Course' self.enterprise_customer = EnterpriseCustomerFactory() self.enterprise_customer_uuid = str(self.enterprise_customer.uuid) + self.mock_pathways_with_course = self.setup_patch( + 'learner_pathway_progress.signals.get_learner_pathways_associated_with_course', + None, + ) super().setUp() @staticmethod diff --git a/requirements/common_constraints.txt b/requirements/common_constraints.txt index 93ecbec605..30ba0afaed 100644 --- a/requirements/common_constraints.txt +++ b/requirements/common_constraints.txt @@ -3,6 +3,16 @@ # See BOM-2721 for more details. # Below is the copied and edited version of common_constraints +# This is a temporary solution to override the real common_constraints.txt +# In edx-lint, until the pyjwt constraint in edx-lint has been removed. +# See BOM-2721 for more details. +# Below is the copied and edited version of common_constraints + +# This is a temporary solution to override the real common_constraints.txt +# In edx-lint, until the pyjwt constraint in edx-lint has been removed. +# See BOM-2721 for more details. +# Below is the copied and edited version of common_constraints + # A central location for most common version constraints # (across edx repos) for pip-installation. # diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 78b1bb4d3f..c4259ab7e8 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -73,3 +73,4 @@ scipy<1.8.0 # This will be fixed when sphinxcontrib-openapi depends on m2r2 instead of m2r # See issue: https://github.com/sphinx-contrib/openapi/issues/123 mistune<2.0.0 + diff --git a/requirements/edx-sandbox/py38.txt b/requirements/edx-sandbox/py38.txt index 7364982ff3..808482e7a3 100644 --- a/requirements/edx-sandbox/py38.txt +++ b/requirements/edx-sandbox/py38.txt @@ -36,7 +36,7 @@ matplotlib==3.3.4 # -r requirements/edx-sandbox/py38.in mpmath==1.2.1 # via sympy -networkx==2.8.3 +networkx==2.8.4 # via -r requirements/edx-sandbox/py38.in nltk==3.7 # via diff --git a/requirements/edx/base.in b/requirements/edx/base.in index 4f834e95d4..5acb033d18 100644 --- a/requirements/edx/base.in +++ b/requirements/edx/base.in @@ -109,6 +109,7 @@ ipaddress # Ip network support for Embargo feature jsonfield # Django model field for validated JSON; used in several apps laboratory # Library for testing that code refactors/infrastructure changes produce identical results lxml # XML parser +learner-pathway-progress # A plugin for lms to track learners progress in pathays lti-consumer-xblock>=4.1.1 mailsnake # Needed for mailchimp (mailing djangoapp) mako # Primary template language used for server-side page rendering diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 5c3e18121d..ec4b5b7231 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -55,7 +55,7 @@ attrs==21.4.0 # blockstore # edx-ace # openedx-events -babel==2.10.1 +babel==2.10.2 # via # -r requirements/edx/base.in # enmerkar @@ -237,6 +237,7 @@ django==3.2.13 # event-tracking # help-tokens # jsonfield + # learner-pathway-progress # lti-consumer-xblock # openedx-events # openedx-filters @@ -312,6 +313,7 @@ django-model-utils==4.2.0 # edx-submissions # edx-when # edxval + # learner-pathway-progress # ora2 # super-csv django-mptt==0.13.4 @@ -350,6 +352,7 @@ django-simple-history==3.0.0 # edx-name-affirmation # edx-organizations # edx-proctoring + # learner-pathway-progress # ora2 django-splash==1.2.1 # via -r requirements/edx/base.in @@ -455,6 +458,7 @@ edx-django-utils==5.0.0 # edx-toggles # edx-when # event-tracking + # learner-pathway-progress # ora2 # super-csv edx-drf-extensions==8.0.1 @@ -491,6 +495,7 @@ edx-opaque-keys[django]==2.3.0 # edx-proctoring # edx-user-state-client # edx-when + # learner-pathway-progress # lti-consumer-xblock # openedx-events # ora2 @@ -620,6 +625,7 @@ jsonfield==3.1.0 # edx-enterprise # edx-proctoring # edx-submissions + # learner-pathway-progress # lti-consumer-xblock # ora2 jwcrypto==1.3.1 @@ -634,6 +640,8 @@ lazy==1.4 # acid-xblock # lti-consumer-xblock # ora2 +learner-pathway-progress==1.2.0 + # via -r requirements/edx/base.in libsass==0.10.0 # via # -r requirements/edx/paver.txt @@ -881,6 +889,7 @@ pytz==2022.1 # fs # icalendar # interchange + # learner-pathway-progress # olxcleaner # ora2 # xblock diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 76c9b3ea8c..4ce53ec003 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -82,7 +82,7 @@ attrs==21.4.0 # jsonschema # openedx-events # pytest -babel==2.10.1 +babel==2.10.2 # via # -r requirements/edx/testing.txt # enmerkar @@ -323,6 +323,7 @@ django==3.2.13 # event-tracking # help-tokens # jsonfield + # learner-pathway-progress # lti-consumer-xblock # openedx-events # openedx-filters @@ -408,6 +409,7 @@ django-model-utils==4.2.0 # edx-submissions # edx-when # edxval + # learner-pathway-progress # ora2 # super-csv django-mptt==0.13.4 @@ -450,6 +452,7 @@ django-simple-history==3.0.0 # edx-name-affirmation # edx-organizations # edx-proctoring + # learner-pathway-progress # ora2 django-splash==1.2.1 # via -r requirements/edx/testing.txt @@ -568,6 +571,7 @@ edx-django-utils==5.0.0 # edx-toggles # edx-when # event-tracking + # learner-pathway-progress # ora2 # super-csv edx-drf-extensions==8.0.1 @@ -608,6 +612,7 @@ edx-opaque-keys[django]==2.3.0 # edx-proctoring # edx-user-state-client # edx-when + # learner-pathway-progress # lti-consumer-xblock # openedx-events # ora2 @@ -810,6 +815,7 @@ jsonfield==3.1.0 # edx-enterprise # edx-proctoring # edx-submissions + # learner-pathway-progress # lti-consumer-xblock # ora2 jsonschema==4.6.0 @@ -835,6 +841,8 @@ lazy-object-proxy==1.7.1 # via # -r requirements/edx/testing.txt # astroid +learner-pathway-progress==1.2.0 + # via -r requirements/edx/testing.txt libsass==0.10.0 # via # -r requirements/edx/testing.txt @@ -1228,6 +1236,7 @@ pytz==2022.1 # fs # icalendar # interchange + # learner-pathway-progress # olxcleaner # ora2 # xblock diff --git a/requirements/edx/doc.txt b/requirements/edx/doc.txt index efd98c1678..e2a875b30b 100644 --- a/requirements/edx/doc.txt +++ b/requirements/edx/doc.txt @@ -6,7 +6,7 @@ # alabaster==0.7.12 # via sphinx -babel==2.10.1 +babel==2.10.2 # via sphinx certifi==2022.5.18.1 # via requests diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 3831c1ad72..c6f5e50fc7 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -77,7 +77,7 @@ attrs==21.4.0 # openedx-events # outcome # pytest -babel==2.10.1 +babel==2.10.2 # via # -r requirements/edx/base.txt # enmerkar @@ -310,6 +310,7 @@ distlib==0.3.4 # event-tracking # help-tokens # jsonfield + # learner-pathway-progress # lti-consumer-xblock # openedx-events # openedx-filters @@ -393,6 +394,7 @@ django-model-utils==4.2.0 # edx-submissions # edx-when # edxval + # learner-pathway-progress # ora2 # super-csv django-mptt==0.13.4 @@ -435,6 +437,7 @@ django-simple-history==3.0.0 # edx-name-affirmation # edx-organizations # edx-proctoring + # learner-pathway-progress # ora2 django-splash==1.2.1 # via -r requirements/edx/base.txt @@ -551,6 +554,7 @@ edx-django-utils==5.0.0 # edx-toggles # edx-when # event-tracking + # learner-pathway-progress # ora2 # super-csv edx-drf-extensions==8.0.1 @@ -592,6 +596,7 @@ edx-opaque-keys[django]==2.3.0 # edx-proctoring # edx-user-state-client # edx-when + # learner-pathway-progress # lti-consumer-xblock # openedx-events # ora2 @@ -776,6 +781,7 @@ jsonfield==3.1.0 # edx-enterprise # edx-proctoring # edx-submissions + # learner-pathway-progress # lti-consumer-xblock # ora2 jwcrypto==1.3.1 @@ -797,6 +803,8 @@ lazy==1.4 # ora2 lazy-object-proxy==1.7.1 # via astroid +learner-pathway-progress==1.2.0 + # via -r requirements/edx/base.txt libsass==0.10.0 # via # -r requirements/edx/base.txt @@ -1159,6 +1167,7 @@ pytz==2022.1 # fs # icalendar # interchange + # learner-pathway-progress # olxcleaner # ora2 # xblock From ce765a7db1d8e702b0dcb56b1248b9965ad89475 Mon Sep 17 00:00:00 2001 From: Long Lin Date: Tue, 14 Jun 2022 19:45:49 +0000 Subject: [PATCH 48/63] chore: bump edx-enterprise version --- requirements/constraints.txt | 2 +- requirements/edx/base.txt | 2 +- requirements/edx/development.txt | 2 +- requirements/edx/testing.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/requirements/constraints.txt b/requirements/constraints.txt index c4259ab7e8..088eb46c3e 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -25,7 +25,7 @@ django-storages<1.9 # The team that owns this package will manually bump this package rather than having it pulled in automatically. # This is to allow them to better control its deployment and to do it in a process that works better # for them. -edx-enterprise==3.49.10 +edx-enterprise==3.50.0 # oauthlib>3.0.1 causes test failures ( also remove the django-oauth-toolkit constraint when this is fixed ) oauthlib==3.0.1 diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index ec4b5b7231..72bd1b23de 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -472,7 +472,7 @@ edx-drf-extensions==8.0.1 # edx-rbac # edx-when # edxval -edx-enterprise==3.49.10 +edx-enterprise==3.50.0 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/base.in diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 4ce53ec003..5786ec490c 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -585,7 +585,7 @@ edx-drf-extensions==8.0.1 # edx-rbac # edx-when # edxval -edx-enterprise==3.49.10 +edx-enterprise==3.50.0 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/testing.txt diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index c6f5e50fc7..616136d392 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -568,7 +568,7 @@ edx-drf-extensions==8.0.1 # edx-rbac # edx-when # edxval -edx-enterprise==3.49.10 +edx-enterprise==3.50.0 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt From 8592ef4c3e5e7e45acfcfd684bc17adb8c148fa7 Mon Sep 17 00:00:00 2001 From: Jillian Vogel Date: Wed, 15 Jun 2022 14:50:53 +0930 Subject: [PATCH 49/63] chore: bumps blockstore version to add logging to debug blockstore app storage configuration --- requirements/edx/base.txt | 2 +- requirements/edx/development.txt | 2 +- requirements/edx/github.in | 2 +- requirements/edx/testing.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 72bd1b23de..e25b7484e7 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -4,7 +4,7 @@ # # make upgrade # --e git+https://github.com/openedx/blockstore.git@1.2.1#egg=blockstore==1.2.1 +-e git+https://github.com/openedx/blockstore.git@1.2.2#egg=blockstore==1.2.2 # via -r requirements/edx/github.in -e common/lib/capa # via diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 5786ec490c..c897d803a3 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -4,7 +4,7 @@ # # make upgrade # --e git+https://github.com/openedx/blockstore.git@1.2.1#egg=blockstore==1.2.1 +-e git+https://github.com/openedx/blockstore.git@1.2.2#egg=blockstore==1.2.2 # via -r requirements/edx/testing.txt -e common/lib/capa # via diff --git a/requirements/edx/github.in b/requirements/edx/github.in index 36ba3a4e02..36b629f173 100644 --- a/requirements/edx/github.in +++ b/requirements/edx/github.in @@ -63,7 +63,7 @@ git+https://github.com/edx/MongoDBProxy.git@d92bafe9888d2940f647a7b2b2383b29c752 git+https://github.com/edx/django-require.git@0c54adb167142383b26ea6b3edecc3211822a776#egg=django-require==1.0.12 # Our libraries: --e git+https://github.com/openedx/blockstore.git@1.2.1#egg=blockstore==1.2.1 +-e git+https://github.com/openedx/blockstore.git@1.2.2#egg=blockstore==1.2.2 -e git+https://github.com/edx/codejail.git@3.1.3#egg=codejail==3.1.3 -e git+https://github.com/edx/RateXBlock.git@2.0.1#egg=rate-xblock -e git+https://github.com/edx-solutions/xblock-google-drive.git@2d176468e33c0713c911b563f8f65f7cf232f5b6#egg=xblock-google-drive diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 616136d392..08c9ac383a 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -4,7 +4,7 @@ # # make upgrade # --e git+https://github.com/openedx/blockstore.git@1.2.1#egg=blockstore==1.2.1 +-e git+https://github.com/openedx/blockstore.git@1.2.2#egg=blockstore==1.2.2 # via -r requirements/edx/base.txt -e common/lib/capa # via From 7b1f402199133c30591e67dded93d1ad359bea6b Mon Sep 17 00:00:00 2001 From: Attiya Ishaque Date: Wed, 15 Jun 2022 19:16:33 +0500 Subject: [PATCH 50/63] feat: [VAN-953] Update MFE context API (#30516) --- .../core/djangoapps/user_authn/api/helper.py | 19 ++-- .../api/tests/test_optional_fields.py | 106 ------------------ .../user_authn/api/tests/test_views.py | 82 +++++++++++++- .../core/djangoapps/user_authn/api/urls.py | 2 - .../core/djangoapps/user_authn/api/views.py | 70 ++++-------- 5 files changed, 107 insertions(+), 172 deletions(-) delete mode 100644 openedx/core/djangoapps/user_authn/api/tests/test_optional_fields.py diff --git a/openedx/core/djangoapps/user_authn/api/helper.py b/openedx/core/djangoapps/user_authn/api/helper.py index e5f8092f1d..4186d2d716 100644 --- a/openedx/core/djangoapps/user_authn/api/helper.py +++ b/openedx/core/djangoapps/user_authn/api/helper.py @@ -15,8 +15,6 @@ class RegistrationFieldsContext(APIView): """ Registration Fields View used by optional and required fields view. """ - # allow to define custom set of required/optional/hidden fields via configuration - FIELD_TYPE = 'hidden' EXTRA_FIELDS = [ 'confirm_email', @@ -58,8 +56,9 @@ class RegistrationFieldsContext(APIView): return field_order - def __init__(self): + def __init__(self, field_type='required'): super().__init__() + self.field_type = field_type self._fields_setting = copy.deepcopy(configuration_helpers.get_value('REGISTRATION_EXTRA_FIELDS')) if not self._fields_setting: self._fields_setting = copy.deepcopy(settings.REGISTRATION_EXTRA_FIELDS) @@ -70,18 +69,18 @@ class RegistrationFieldsContext(APIView): ordered_extra_fields.remove('year_of_birth') self.valid_fields = [ - field for field in ordered_extra_fields if self._fields_setting.get(field) == self.FIELD_TYPE + field for field in ordered_extra_fields if self._fields_setting.get(field) == self.field_type ] custom_form = get_registration_extension_form() if custom_form: for field_name, field in custom_form.fields.items(): - # If the FIELD_TYPE is required make sure the custom field is required in the form and if the - # FIELD_TYPE is optional only add field if it is not required. This is to make sure field is + # If the field_type is required make sure the custom field is required in the form and if the + # field_type is optional only add field if it is not required. This is to make sure field is # added only once either on Registration Page or Progressive Profiling page. if ( - field.required and self.FIELD_TYPE == 'required' or - not field.required and self.FIELD_TYPE == 'optional' + field.required and self.field_type == 'required' or + not field.required and self.field_type == 'optional' ): self.valid_fields.append(field_name) @@ -95,11 +94,11 @@ class RegistrationFieldsContext(APIView): for field in self.valid_fields: if custom_form and field in custom_form.fields: response[field] = form_fields.add_extension_form_field( - field, custom_form, custom_form.fields[field], self.FIELD_TYPE + field, custom_form, custom_form.fields[field], self.field_type ) else: field_handler = getattr(form_fields, f'add_{field}_field', None) if field_handler: - response[field] = field_handler(self.FIELD_TYPE == 'required') + response[field] = field_handler(self.field_type == 'required') return response diff --git a/openedx/core/djangoapps/user_authn/api/tests/test_optional_fields.py b/openedx/core/djangoapps/user_authn/api/tests/test_optional_fields.py deleted file mode 100644 index 412a2c9364..0000000000 --- a/openedx/core/djangoapps/user_authn/api/tests/test_optional_fields.py +++ /dev/null @@ -1,106 +0,0 @@ -""" -Tests for OptionalFieldsData View -""" -from django.conf import settings -from django.test.utils import override_settings -from django.urls import reverse -from rest_framework import status -from rest_framework.test import APITestCase - -from openedx.core.djangoapps.site_configuration.tests.test_util import with_site_configuration -from openedx.core.djangolib.testing.utils import skip_unless_lms -from common.djangoapps.student.tests.factories import UserFactory - - -@skip_unless_lms -class OptionalFieldsDataViewTest(APITestCase): - """ - Tests for the end-point that returns optional fields. - """ - - def setUp(self): - super().setUp() - - self.user = UserFactory.create(username='test_user', password='password123') - self.client.force_authenticate(user=self.user) - self.url = reverse('optional_fields') - - def test_unauthenticated_request_is_forbidden(self): - """ - Test that unauthenticated user should not be able to access the endpoint. - """ - self.client.logout() - response = self.client.get(self.url) - assert response.status_code == status.HTTP_401_UNAUTHORIZED - - @override_settings(REGISTRATION_EXTRA_FIELDS={"goals": "required", "level_of_education": "required"}) - def test_optional_fields_not_configured(self): - """ - Test that when no optional fields are configured in REGISTRATION_EXTRA_FIELDS - settings, then API returns proper response. - """ - response = self.client.get(self.url) - assert response.status_code == status.HTTP_400_BAD_REQUEST - assert response.data.get('error_code') == 'optional_fields_configured_incorrectly' - - @override_settings(REGISTRATION_EXTRA_FIELDS={"new_field_with_no_description": "optional", "goals": "optional"}) - def test_optional_field_has_no_description(self): - """ - Test that if a new optional field is added to REGISTRATION_EXTRA_FIELDS without - adding field description then that field is omitted from the final response. - """ - expected_response = { - 'goals': { - 'name': 'goals', - 'type': 'textarea', - 'label': "Tell us why you're interested in {platform_name}".format( - platform_name=settings.PLATFORM_NAME - ), - 'error_message': '', - } - } - response = self.client.get(self.url) - assert response.status_code == status.HTTP_200_OK - assert response.data.get('fields') == expected_response - - @with_site_configuration( - configuration={ - 'EXTRA_FIELD_OPTIONS': {'profession': ['Software Engineer', 'Teacher', 'Other']} - } - ) - @override_settings(REGISTRATION_EXTRA_FIELDS={'profession': 'optional', 'specialty': 'optional'}) - def test_configurable_select_option_fields(self): - """ - Test that if optional fields have configurable options present in EXTRA_FIELD_OPTIONS, - they are returned in response as "select" fields otherwise as "text" field. - """ - expected_response = { - 'profession': { - 'name': 'profession', - 'label': 'Profession', - 'error_message': '', - 'type': 'select', - 'options': [('software engineer', 'Software Engineer'), ('teacher', 'Teacher'), ('other', 'Other')], - }, - 'specialty': { - 'name': 'specialty', - 'label': 'Specialty', - 'error_message': '', - 'type': 'text', - } - } - response = self.client.get(self.url) - assert response.status_code == status.HTTP_200_OK - assert response.data.get('fields') == expected_response - - @override_settings( - REGISTRATION_EXTRA_FIELDS={'goals': 'optional', 'specialty': 'optional'}, - REGISTRATION_FIELD_ORDER=['specialty', 'goals'], - ) - def test_field_order(self): - """ - Test that order of fields - """ - response = self.client.get(self.url) - assert response.status_code == status.HTTP_200_OK - assert list(response.data['fields'].keys()) == ['specialty', 'goals'] diff --git a/openedx/core/djangoapps/user_authn/api/tests/test_views.py b/openedx/core/djangoapps/user_authn/api/tests/test_views.py index dd2c24f099..c7aff51071 100644 --- a/openedx/core/djangoapps/user_authn/api/tests/test_views.py +++ b/openedx/core/djangoapps/user_authn/api/tests/test_views.py @@ -16,6 +16,7 @@ from common.djangoapps.student.models import Registration from common.djangoapps.student.tests.factories import UserFactory from common.djangoapps.third_party_auth import pipeline from common.djangoapps.third_party_auth.tests.testutil import ThirdPartyAuthTestMixin, simulate_running_pipeline +from openedx.core.djangoapps.site_configuration.tests.test_util import with_site_configuration from openedx.core.djangoapps.geoinfo.api import country_code_from_ip from openedx.core.djangoapps.user_api.tests.test_views import UserAPITestCase from openedx.core.djangolib.testing.utils import skip_unless_lms @@ -34,6 +35,7 @@ class MFEContextViewTest(ThirdPartyAuthTestMixin, APITestCase): """ super().setUp() + self.user = UserFactory.create(username='test_user', password='password123') self.url = reverse('mfe_context') self.query_params = {'next': '/dashboard'} @@ -103,6 +105,7 @@ class MFEContextViewTest(ThirdPartyAuthTestMixin, APITestCase): 'countryCode': self.country_code }, 'registration_fields': {}, + 'optional_fields': {}, } @patch.dict(settings.FEATURES, {'ENABLE_THIRD_PARTY_AUTH': False}) @@ -194,7 +197,8 @@ class MFEContextViewTest(ThirdPartyAuthTestMixin, APITestCase): Test that when no required fields are configured in REGISTRATION_EXTRA_FIELDS settings, then API returns proper response. """ - response = self.client.get(self.url) + self.query_params.update({'is_registered': True}) + response = self.client.get(self.url, self.query_params) assert response.status_code == status.HTTP_200_OK assert response.data['registration_fields']['fields'] == {} @@ -203,13 +207,83 @@ class MFEContextViewTest(ThirdPartyAuthTestMixin, APITestCase): REGISTRATION_EXTRA_FIELDS={'state': 'required', 'last_name': 'required', 'first_name': 'required'}, REGISTRATION_FIELD_ORDER=['first_name', 'last_name', 'state'], ) - def test_field_order(self): + def test_required_field_order(self): """ - Test that order of fields + Test that order of required fields + """ + self.query_params.update({'is_registered': True}) + response = self.client.get(self.url, self.query_params) + assert response.status_code == status.HTTP_200_OK + assert list(response.data['registration_fields']['fields'].keys()) == ['first_name', 'last_name', 'state'] + + @override_settings( + ENABLE_DYNAMIC_REGISTRATION_FIELDS=True, + REGISTRATION_EXTRA_FIELDS={"new_field_with_no_description": "optional", "goals": "optional"} + ) + def test_optional_field_has_no_description(self): + """ + Test that if a new optional field is added to REGISTRATION_EXTRA_FIELDS without + adding field description then that field is omitted from the final response. + """ + expected_response = { + 'goals': { + 'name': 'goals', + 'type': 'textarea', + 'label': "Tell us why you're interested in {platform_name}".format( + platform_name=settings.PLATFORM_NAME + ), + 'error_message': '', + } + } + response = self.client.get(self.url) + assert response.status_code == status.HTTP_200_OK + assert response.data['optional_fields']['fields'] == expected_response + + @with_site_configuration( + configuration={ + 'EXTRA_FIELD_OPTIONS': {'profession': ['Software Engineer', 'Teacher', 'Other']} + } + ) + @override_settings( + ENABLE_DYNAMIC_REGISTRATION_FIELDS=True, + REGISTRATION_EXTRA_FIELDS={'profession': 'optional', 'specialty': 'optional'} + ) + def test_configurable_select_option_fields(self): + """ + Test that if optional fields have configurable options present in EXTRA_FIELD_OPTIONS, + they are returned in response as "select" fields otherwise as "text" field. + """ + expected_response = { + 'profession': { + 'name': 'profession', + 'label': 'Profession', + 'error_message': '', + 'type': 'select', + 'options': [('software engineer', 'Software Engineer'), ('teacher', 'Teacher'), ('other', 'Other')], + }, + 'specialty': { + 'name': 'specialty', + 'label': 'Specialty', + 'error_message': '', + 'type': 'text', + } + } + response = self.client.get(self.url) + assert response.status_code == status.HTTP_200_OK + assert response.data['optional_fields']['fields'] == expected_response + + @override_settings( + ENABLE_DYNAMIC_REGISTRATION_FIELDS=True, + REGISTRATION_EXTRA_FIELDS={'goals': 'optional', 'specialty': 'optional'}, + REGISTRATION_FIELD_ORDER=['specialty', 'goals'], + ) + def test_optional_field_order(self): + """ + Test that order of optional fields """ response = self.client.get(self.url) assert response.status_code == status.HTTP_200_OK - assert list(response.data['registration_fields']['fields'].keys()) == ['first_name', 'last_name', 'state'] + assert list(response.data['optional_fields']['fields'].keys()) == ['specialty', 'goals'] @skip_unless_lms diff --git a/openedx/core/djangoapps/user_authn/api/urls.py b/openedx/core/djangoapps/user_authn/api/urls.py index c4ac9dc57c..212249d1c8 100644 --- a/openedx/core/djangoapps/user_authn/api/urls.py +++ b/openedx/core/djangoapps/user_authn/api/urls.py @@ -5,7 +5,6 @@ from django.urls import path from openedx.core.djangoapps.user_authn.api.views import ( MFEContextView, SendAccountActivationEmail, - OptionalFieldsView, ) urlpatterns = [ path('third_party_auth_context', MFEContextView.as_view(), name='third_party_auth_context'), @@ -13,5 +12,4 @@ urlpatterns = [ path('send_account_activation_email', SendAccountActivationEmail.as_view(), name='send_account_activation_email' ), - path('optional_fields', OptionalFieldsView.as_view(), name='optional_fields'), ] diff --git a/openedx/core/djangoapps/user_authn/api/views.py b/openedx/core/djangoapps/user_authn/api/views.py index 6c9176dcca..93f37a1a26 100644 --- a/openedx/core/djangoapps/user_authn/api/views.py +++ b/openedx/core/djangoapps/user_authn/api/views.py @@ -4,12 +4,10 @@ Authn API Views from django.conf import settings -from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication from rest_framework import status from rest_framework.response import Response -from rest_framework.throttling import AnonRateThrottle, UserRateThrottle +from rest_framework.throttling import AnonRateThrottle from rest_framework.views import APIView -from rest_framework.authentication import SessionAuthentication from rest_framework.permissions import IsAuthenticated from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser @@ -18,7 +16,6 @@ from common.djangoapps.student.views import compose_and_send_activation_email from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.djangoapps.user_authn.api.helper import RegistrationFieldsContext from openedx.core.djangoapps.user_authn.views.utils import get_mfe_context -from openedx.core.lib.api.authentication import BearerAuthentication class MFEContextThrottle(AnonRateThrottle): @@ -28,17 +25,18 @@ class MFEContextThrottle(AnonRateThrottle): rate = settings.LOGISTRATION_API_RATELIMIT -class MFEContextView(RegistrationFieldsContext): +class MFEContextView(APIView): """ - API to get third party auth providers, user country code and the currently running pipeline. + API to get third party auth providers, optional fields, required fields, + user country code and the currently running pipeline. """ - FIELD_TYPE = 'required' throttle_classes = [MFEContextThrottle] def get(self, request, **kwargs): # lint-amnesty, pylint: disable=unused-argument """ Returns - dynamic registration fields + - dynamic optional fields - the context for third party auth providers - user country code - the currently running pipeline. @@ -48,22 +46,31 @@ class MFEContextView(RegistrationFieldsContext): is currently running. tpa_hint (string): An override flag that will return a matching provider as long as its configuration has been enabled + is_register_page (boolen): Determine the call is from register or login page """ request_params = request.GET redirect_to = get_next_url_for_login_page(request) third_party_auth_hint = request_params.get('tpa_hint') - + is_register_page = request_params.get('is_registered') context = { 'context_data': get_mfe_context(request, redirect_to, third_party_auth_hint), 'registration_fields': {}, + 'optional_fields': {}, } if settings.ENABLE_DYNAMIC_REGISTRATION_FIELDS: - registration_fields = self._get_fields() - context['registration_fields'].update({ - 'fields': registration_fields, - 'extended_profile': configuration_helpers.get_value('extended_profile_fields', []), - }) + if is_register_page: + registration_fields = RegistrationFieldsContext()._get_fields() # pylint: disable=protected-access + context['registration_fields'].update({ + 'fields': registration_fields, + 'extended_profile': configuration_helpers.get_value('extended_profile_fields', []), + }) + optional_fields = RegistrationFieldsContext('optional')._get_fields() # pylint: disable=protected-access + if optional_fields: + context['optional_fields'].update({ + 'fields': optional_fields, + 'extended_profile': configuration_helpers.get_value('extended_profile_fields', []), + }) return Response( status=status.HTTP_200_OK, @@ -95,40 +102,3 @@ class SendAccountActivationEmail(APIView): return Response( status=status.HTTP_500_INTERNAL_SERVER_ERROR ) - - -class OptionalFieldsThrottle(UserRateThrottle): - """ - Setting rate limit for OptionalFieldsData API - """ - rate = settings.OPTIONAL_FIELD_API_RATELIMIT - - -class OptionalFieldsView(RegistrationFieldsContext): - """ - Construct Registration forms and associated fields. - """ - FIELD_TYPE = 'optional' - - throttle_classes = [OptionalFieldsThrottle] - authentication_classes = (JwtAuthentication, BearerAuthentication, SessionAuthentication,) - permission_classes = (IsAuthenticated,) - - def get(self, request): # lint-amnesty, pylint: disable=unused-argument - """ - Returns Optional fields to be shown on Progressive Profiling page - """ - response = self._get_fields() - if not self.valid_fields or not response: - return Response( - status=status.HTTP_400_BAD_REQUEST, - data={'error_code': f'{self.FIELD_TYPE}_fields_configured_incorrectly'} - ) - - return Response( - status=status.HTTP_200_OK, - data={ - 'fields': response, - 'extended_profile': configuration_helpers.get_value('extended_profile_fields', []), - }, - ) From 541065c54226509c3731748acc8e57ec352cc2c7 Mon Sep 17 00:00:00 2001 From: Waheed Ahmad Date: Wed, 15 Jun 2022 19:39:23 +0500 Subject: [PATCH 51/63] fix: [VAN-980] changing the email address sync with Braze (#30590) Currently, changing the email address in LMS does not reflect in Braze and the transaction emails sent through Braze are delivering to user's old/previous email address. Added a signal/receiver to sync the new email address upon confirm email change. --- common/djangoapps/student/signals/__init__.py | 3 +- .../djangoapps/student/signals/receivers.py | 22 +++++++++++++- common/djangoapps/student/signals/signals.py | 2 ++ common/djangoapps/student/tests/test_email.py | 4 ++- .../student/tests/test_receivers.py | 29 ++++++++++++------- common/djangoapps/student/views/management.py | 3 ++ .../save_for_later/api/v1/tests/test_views.py | 12 ++++++-- lms/djangoapps/save_for_later/helper.py | 12 ++++---- .../tests/test_send_course_reminder_emails.py | 7 ++++- .../test_send_program_reminder_emails.py | 7 ++++- lms/djangoapps/utils.py | 18 ++++++++++++ 11 files changed, 95 insertions(+), 24 deletions(-) diff --git a/common/djangoapps/student/signals/__init__.py b/common/djangoapps/student/signals/__init__.py index 0ae2390011..9d134198f0 100644 --- a/common/djangoapps/student/signals/__init__.py +++ b/common/djangoapps/student/signals/__init__.py @@ -4,5 +4,6 @@ from common.djangoapps.student.signals.signals import ( ENROLL_STATUS_CHANGE, ENROLLMENT_TRACK_UPDATED, REFUND_ORDER, - UNENROLL_DONE + UNENROLL_DONE, + USER_EMAIL_CHANGED ) diff --git a/common/djangoapps/student/signals/receivers.py b/common/djangoapps/student/signals/receivers.py index c05813dc2d..569f4a21dc 100644 --- a/common/djangoapps/student/signals/receivers.py +++ b/common/djangoapps/student/signals/receivers.py @@ -3,7 +3,8 @@ Signal receivers for the "student" application. """ # pylint: disable=unused-argument - +import logging +from asyncio.log import logger from django.conf import settings from django.contrib.auth import get_user_model from django.db import IntegrityError @@ -11,6 +12,7 @@ from django.db.models.signals import post_save, pre_save from django.dispatch import receiver from lms.djangoapps.courseware.toggles import courseware_mfe_progress_milestones_are_active +from lms.djangoapps.utils import get_braze_client from common.djangoapps.student.helpers import EMAIL_EXISTS_MSG_FMT, USERNAME_EXISTS_MSG_FMT, AccountValidationError from common.djangoapps.student.models import ( CourseEnrollment, @@ -20,8 +22,11 @@ from common.djangoapps.student.models import ( is_username_retired ) from common.djangoapps.student.models_api import confirm_name_change +from common.djangoapps.student.signals import USER_EMAIL_CHANGED from openedx.features.name_affirmation_api.utils import is_name_affirmation_installed +logger = logging.getLogger(__name__) + @receiver(pre_save, sender=get_user_model()) def on_user_updated(sender, instance, **kwargs): @@ -97,3 +102,18 @@ if is_name_affirmation_installed(): # pylint: disable=import-error from edx_name_affirmation.signals import VERIFIED_NAME_APPROVED VERIFIED_NAME_APPROVED.connect(listen_for_verified_name_approved) + + +@receiver(USER_EMAIL_CHANGED) +def _listen_for_user_email_changed(sender, user, **kwargs): + """ If user has changed their email, update that in email Braze. """ + email = user.email + user_id = user.id + attributes = {'email': email, 'external_id': user_id} + + try: + braze_client = get_braze_client() + if braze_client: + braze_client.track_user(attributes=attributes) + except Exception: # pylint: disable=broad-except + logger.warning(f'Unable to sync new email [{email}] with Braze for user [{user_id}]') diff --git a/common/djangoapps/student/signals/signals.py b/common/djangoapps/student/signals/signals.py index 0682bb5ea9..49745ca48c 100644 --- a/common/djangoapps/student/signals/signals.py +++ b/common/djangoapps/student/signals/signals.py @@ -19,3 +19,5 @@ ENROLL_STATUS_CHANGE = Signal() # providing_args=["course_enrollment"] REFUND_ORDER = Signal() + +USER_EMAIL_CHANGED = Signal() diff --git a/common/djangoapps/student/tests/test_email.py b/common/djangoapps/student/tests/test_email.py index 940d54e77a..22f1197576 100644 --- a/common/djangoapps/student/tests/test_email.py +++ b/common/djangoapps/student/tests/test_email.py @@ -562,6 +562,7 @@ class EmailChangeConfirmationTests(EmailTestMixin, EmailTemplateTagMixin, CacheI @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', "Test only valid in LMS") @override_settings(MKTG_URLS={'ROOT': 'https://dummy-root', 'CONTACT': '/help/contact-us'}) + @patch('common.djangoapps.student.signals.signals.USER_EMAIL_CHANGED.send') @ddt.data( ('plain_text', False), ('plain_text', True), @@ -569,9 +570,10 @@ class EmailChangeConfirmationTests(EmailTestMixin, EmailTemplateTagMixin, CacheI ('html', True) ) @ddt.unpack - def test_successful_email_change(self, test_body_type, test_marketing_enabled): + def test_successful_email_change(self, test_body_type, test_marketing_enabled, mock_email_change_signal): with patch.dict(settings.FEATURES, {'ENABLE_MKTG_SITE': test_marketing_enabled}): self.assertChangeEmailSent(test_body_type) + assert mock_email_change_signal.called meta = json.loads(UserProfile.objects.get(user=self.user).meta) assert 'old_emails' in meta diff --git a/common/djangoapps/student/tests/test_receivers.py b/common/djangoapps/student/tests/test_receivers.py index 39e654adeb..fb8d285fdb 100644 --- a/common/djangoapps/student/tests/test_receivers.py +++ b/common/djangoapps/student/tests/test_receivers.py @@ -1,18 +1,15 @@ """ Tests for student signal receivers. """ from unittest import skipUnless +from unittest.mock import patch + +from django.conf import settings from edx_toggles.toggles.testutils import override_waffle_flag + +from common.djangoapps.student.models import CourseEnrollmentCelebration, PendingNameChange, UserProfile +from common.djangoapps.student.signals.signals import USER_EMAIL_CHANGED +from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory, UserProfileFactory from lms.djangoapps.courseware.toggles import COURSEWARE_MICROFRONTEND_PROGRESS_MILESTONES -from common.djangoapps.student.models import ( - CourseEnrollmentCelebration, - PendingNameChange, - UserProfile -) -from common.djangoapps.student.tests.factories import ( - CourseEnrollmentFactory, - UserFactory, - UserProfileFactory -) from openedx.features.name_affirmation_api.utils import is_name_affirmation_installed from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order @@ -73,3 +70,15 @@ class ReceiversTest(SharedModuleStoreTestCase): assert PendingNameChange.objects.count() == 0 profile = UserProfile.objects.get(user=user) assert profile.name == new_name + + @skipUnless(settings.ROOT_URLCONF == 'lms.urls', "Test only valid in LMS") + @patch('common.djangoapps.student.signals.receivers.get_braze_client') + def test_listen_for_user_email_changed(self, mock_get_braze_client): + """ + Ensure that USER_EMAIL_CHANGED signal triggers correct calls to get_braze_client. + """ + user = UserFactory(email='email@test.com', username='jdoe') + + USER_EMAIL_CHANGED.send(sender=None, user=user) + + assert mock_get_braze_client.called diff --git a/common/djangoapps/student/views/management.py b/common/djangoapps/student/views/management.py index 1d918ac57a..5ec791ba27 100644 --- a/common/djangoapps/student/views/management.py +++ b/common/djangoapps/student/views/management.py @@ -79,6 +79,7 @@ from common.djangoapps.student.models import ( # lint-amnesty, pylint: disable= from common.djangoapps.student.signals import REFUND_ORDER from common.djangoapps.util.db import outer_atomic from common.djangoapps.util.json_request import JsonResponse +from common.djangoapps.student.signals import USER_EMAIL_CHANGED from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order log = logging.getLogger("edx.student") @@ -902,6 +903,8 @@ def confirm_email_change(request, key): return response response = render_to_response("email_change_successful.html", address_context) + + USER_EMAIL_CHANGED.send(sender=None, user=user) return response diff --git a/lms/djangoapps/save_for_later/api/v1/tests/test_views.py b/lms/djangoapps/save_for_later/api/v1/tests/test_views.py index bf93c23dc5..038016cd09 100644 --- a/lms/djangoapps/save_for_later/api/v1/tests/test_views.py +++ b/lms/djangoapps/save_for_later/api/v1/tests/test_views.py @@ -39,7 +39,11 @@ class CourseSaveForLaterApiViewTest(ThirdPartyAuthTestMixin, APITestCase): self.course_key = CourseKey.from_string(self.course_id) CourseOverviewFactory.create(id=self.course_key) - @patch('lms.djangoapps.save_for_later.helper.BrazeClient', MagicMock()) + @override_settings( + EDX_BRAZE_API_KEY='test-key', + EDX_BRAZE_API_SERVER='http://test.url' + ) + @patch('lms.djangoapps.utils.BrazeClient', MagicMock()) def test_save_course_using_email(self): """ Test successfully email sent @@ -116,7 +120,11 @@ class ProgramSaveForLaterApiViewTest(ThirdPartyAuthTestMixin, APITestCase): self.uuid = '587f6abe-bfa4-4125-9fbe-4789bf3f97f1' self.program = ProgramFactory(uuid=self.uuid) - @patch('lms.djangoapps.save_for_later.helper.BrazeClient', MagicMock()) + @override_settings( + EDX_BRAZE_API_KEY='test-key', + EDX_BRAZE_API_SERVER='http://test.url' + ) + @patch('lms.djangoapps.utils.BrazeClient', MagicMock()) @patch('lms.djangoapps.save_for_later.api.v1.views.get_programs') def test_save_program_using_email(self, mock_get_programs): """ diff --git a/lms/djangoapps/save_for_later/helper.py b/lms/djangoapps/save_for_later/helper.py index cb69bb1933..e023f203ee 100644 --- a/lms/djangoapps/save_for_later/helper.py +++ b/lms/djangoapps/save_for_later/helper.py @@ -5,12 +5,11 @@ helper functions import logging from datetime import datetime from django.conf import settings -from braze.client import BrazeClient from eventtracking import tracker from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers - from common.djangoapps.course_modes.models import CourseMode +from lms.djangoapps.utils import get_braze_client log = logging.getLogger(__name__) @@ -100,11 +99,10 @@ def send_email(email, data): Send email through Braze """ event_properties = _get_event_properties(data) - braze_client = BrazeClient( - api_key=settings.EDX_BRAZE_API_KEY, - api_url=settings.EDX_BRAZE_API_SERVER, - app_id='', - ) + braze_client = get_braze_client() + + if not braze_client: + return False try: attributes = None diff --git a/lms/djangoapps/save_for_later/management/commands/tests/test_send_course_reminder_emails.py b/lms/djangoapps/save_for_later/management/commands/tests/test_send_course_reminder_emails.py index 6bdc8a6637..2c93492ae3 100644 --- a/lms/djangoapps/save_for_later/management/commands/tests/test_send_course_reminder_emails.py +++ b/lms/djangoapps/save_for_later/management/commands/tests/test_send_course_reminder_emails.py @@ -4,6 +4,7 @@ from unittest.mock import patch import ddt from django.core.management import call_command +from django.test.utils import override_settings from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from openedx.core.djangolib.testing.utils import skip_unless_lms @@ -29,8 +30,12 @@ class SavedCourseReminderEmailsTest(SharedModuleStoreTestCase): CourseOverviewFactory.create(id=self.saved_course.course_id) CourseOverviewFactory.create(id=self.saved_course_1.course_id) + @override_settings( + EDX_BRAZE_API_KEY='test-key', + EDX_BRAZE_API_SERVER='http://test.url' + ) def test_send_reminder_emails(self): - with patch('lms.djangoapps.save_for_later.helper.BrazeClient') as mock_task: + with patch('lms.djangoapps.utils.BrazeClient') as mock_task: call_command('send_course_reminder_emails', '--batch-size=1') mock_task.assert_called() diff --git a/lms/djangoapps/save_for_later/management/commands/tests/test_send_program_reminder_emails.py b/lms/djangoapps/save_for_later/management/commands/tests/test_send_program_reminder_emails.py index 2501ccdb9f..b3665a0456 100644 --- a/lms/djangoapps/save_for_later/management/commands/tests/test_send_program_reminder_emails.py +++ b/lms/djangoapps/save_for_later/management/commands/tests/test_send_program_reminder_emails.py @@ -5,6 +5,7 @@ from unittest.mock import patch import ddt from django.core.management import call_command +from django.test.utils import override_settings from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from openedx.core.djangolib.testing.utils import skip_unless_lms @@ -26,10 +27,14 @@ class SavedProgramReminderEmailsTest(SharedModuleStoreTestCase): self.program = ProgramFactory(uuid=self.uuid) self.saved_program = SavedPogramFactory.create(program_uuid=self.uuid) + @override_settings( + EDX_BRAZE_API_KEY='test-key', + EDX_BRAZE_API_SERVER='http://test.url' + ) @patch('lms.djangoapps.save_for_later.management.commands.send_program_reminder_emails.get_programs') def test_send_reminder_emails(self, mock_get_programs): mock_get_programs.return_value = self.program - with patch('lms.djangoapps.save_for_later.helper.BrazeClient') as mock_task: + with patch('lms.djangoapps.utils.BrazeClient') as mock_task: call_command('send_program_reminder_emails', '--batch-size=1') mock_task.assert_called() diff --git a/lms/djangoapps/utils.py b/lms/djangoapps/utils.py index e034b6ed51..182c382ca2 100644 --- a/lms/djangoapps/utils.py +++ b/lms/djangoapps/utils.py @@ -2,6 +2,9 @@ Helper Methods """ +from braze.client import BrazeClient +from django.conf import settings + def _get_key(key_or_id, key_cls): """ @@ -13,3 +16,18 @@ def _get_key(key_or_id, key_cls): if isinstance(key_or_id, str) else key_or_id ) + + +def get_braze_client(): + """ Returns a Braze client. """ + braze_api_key = settings.EDX_BRAZE_API_KEY + braze_api_url = settings.EDX_BRAZE_API_SERVER + + if not braze_api_key or not braze_api_url: + return None + + return BrazeClient( + api_key=braze_api_key, + api_url=braze_api_url, + app_id='', + ) From 19ed61b6c2cb46db88a1623228060a9684b6a82a Mon Sep 17 00:00:00 2001 From: Maria Grimaldi Date: Tue, 14 Jun 2022 11:56:12 -0400 Subject: [PATCH 52/63] fix: add () to print statement so template works in newer versions --- .../xmodule/xmodule/templates/problem/problem_with_hint.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/lib/xmodule/xmodule/templates/problem/problem_with_hint.yaml b/common/lib/xmodule/xmodule/templates/problem/problem_with_hint.yaml index 1f04d45f73..52e02c42bf 100644 --- a/common/lib/xmodule/xmodule/templates/problem/problem_with_hint.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/problem_with_hint.yaml @@ -11,7 +11,7 @@ data: |