Compare commits

..

1 Commits

Author SHA1 Message Date
connorhaugh
fbca354df7 feat: remove jumpnav-flags 2021-10-08 11:03:43 -04:00
30 changed files with 4717 additions and 4307 deletions

2
.env
View File

@@ -20,7 +20,6 @@ LOGO_URL=''
LOGO_TRADEMARK_URL='' LOGO_TRADEMARK_URL=''
LOGO_WHITE_URL='' LOGO_WHITE_URL=''
FAVICON_URL='' FAVICON_URL=''
LEGACY_THEME_NAME=''
MARKETING_SITE_BASE_URL='' MARKETING_SITE_BASE_URL=''
ORDER_HISTORY_URL='' ORDER_HISTORY_URL=''
REFRESH_ACCESS_TOKEN_ENDPOINT='' REFRESH_ACCESS_TOKEN_ENDPOINT=''
@@ -38,5 +37,4 @@ TWITTER_HASHTAG=''
TWITTER_URL='' TWITTER_URL=''
USER_INFO_COOKIE_NAME='' USER_INFO_COOKIE_NAME=''
SESSION_COOKIE_DOMAIN='' SESSION_COOKIE_DOMAIN=''
ENABLE_JUMPNAV='true'
ENABLE_NOTICES='' ENABLE_NOTICES=''

View File

@@ -19,7 +19,6 @@ LOGO_URL=https://edx-cdn.org/v3/default/logo.svg
LOGO_TRADEMARK_URL=https://edx-cdn.org/v3/default/logo-trademark.svg LOGO_TRADEMARK_URL=https://edx-cdn.org/v3/default/logo-trademark.svg
LOGO_WHITE_URL=https://edx-cdn.org/v3/default/logo-white.svg LOGO_WHITE_URL=https://edx-cdn.org/v3/default/logo-white.svg
FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico
LEGACY_THEME_NAME=''
MARKETING_SITE_BASE_URL='http://localhost:18000' MARKETING_SITE_BASE_URL='http://localhost:18000'
ORDER_HISTORY_URL='http://localhost:1996/orders' ORDER_HISTORY_URL='http://localhost:1996/orders'
PORT=2000 PORT=2000
@@ -38,5 +37,4 @@ TWITTER_HASHTAG='myedxjourney'
TWITTER_URL='https://twitter.com/edXOnline' TWITTER_URL='https://twitter.com/edXOnline'
USER_INFO_COOKIE_NAME='edx-user-info' USER_INFO_COOKIE_NAME='edx-user-info'
SESSION_COOKIE_DOMAIN='localhost' SESSION_COOKIE_DOMAIN='localhost'
ENABLE_JUMPNAV='true'
ENABLE_NOTICES='' ENABLE_NOTICES=''

View File

@@ -19,7 +19,6 @@ LOGO_URL=https://edx-cdn.org/v3/default/logo.svg
LOGO_TRADEMARK_URL=https://edx-cdn.org/v3/default/logo-trademark.svg LOGO_TRADEMARK_URL=https://edx-cdn.org/v3/default/logo-trademark.svg
LOGO_WHITE_URL=https://edx-cdn.org/v3/default/logo-white.svg LOGO_WHITE_URL=https://edx-cdn.org/v3/default/logo-white.svg
FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico
LEGACY_THEME_NAME=''
MARKETING_SITE_BASE_URL='http://localhost:18000' MARKETING_SITE_BASE_URL='http://localhost:18000'
ORDER_HISTORY_URL='http://localhost:1996/orders' ORDER_HISTORY_URL='http://localhost:1996/orders'
PORT=2000 PORT=2000
@@ -37,5 +36,4 @@ TERMS_OF_SERVICE_URL='https://www.edx.org/edx-terms-service'
TWITTER_HASHTAG='myedxjourney' TWITTER_HASHTAG='myedxjourney'
TWITTER_URL='https://twitter.com/edXOnline' TWITTER_URL='https://twitter.com/edXOnline'
USER_INFO_COOKIE_NAME='edx-user-info' USER_INFO_COOKIE_NAME='edx-user-info'
ENABLE_JUMPNAV='true'
ENABLE_NOTICES='' ENABLE_NOTICES=''

View File

@@ -109,9 +109,3 @@ TWITTER_URL
unless this is set. Optional. unless this is set. Optional.
Example: https://twitter.com/edXOnline Example: https://twitter.com/edXOnline
ENABLE_JUMPNAV
Enables the new Jump Navigation feature in the course breadcrumbs, defaulted to the string 'true'.
Disable to have simple hyperlinks for breadcrumbs. Setting it to any other value but 'true' ('false','I love flags', 'etc' would disable the Jumpnav).
This feature flag is slated to be removed as jumpnav becomes default. Follow the progress of this ticket here:
https://openedx.atlassian.net/browse/TNL-8678

7789
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -33,21 +33,20 @@
"dependencies": { "dependencies": {
"@edx/brand": "npm:@edx/brand-openedx@1.1.0", "@edx/brand": "npm:@edx/brand-openedx@1.1.0",
"@edx/frontend-component-footer": "10.1.6", "@edx/frontend-component-footer": "10.1.6",
"@edx/frontend-enterprise-utils": "1.1.1", "@edx/frontend-enterprise-utils": "1.0.0",
"@edx/frontend-lib-special-exams": "1.14.1", "@edx/frontend-lib-special-exams": "1.13.3",
"@edx/frontend-platform": "1.14.3", "@edx/frontend-platform": "1.12.7",
"@edx/paragon": "16.19.0", "@edx/paragon": "16.13.3",
"@edx/frontend-component-header": "^2.4.3",
"@fortawesome/fontawesome-svg-core": "1.2.36", "@fortawesome/fontawesome-svg-core": "1.2.36",
"@fortawesome/free-brands-svg-icons": "5.15.4", "@fortawesome/free-brands-svg-icons": "5.15.4",
"@fortawesome/free-regular-svg-icons": "5.15.4", "@fortawesome/free-regular-svg-icons": "5.15.4",
"@fortawesome/free-solid-svg-icons": "5.15.4", "@fortawesome/free-solid-svg-icons": "5.15.4",
"@fortawesome/react-fontawesome": "0.1.15", "@fortawesome/react-fontawesome": "0.1.15",
"@pact-foundation/pact": "9.16.4", "@pact-foundation/pact": "9.16.3",
"@reduxjs/toolkit": "1.6.2", "@reduxjs/toolkit": "1.6.2",
"classnames": "2.3.1", "classnames": "2.3.1",
"core-js": "3.18.3", "core-js": "3.16.4",
"js-cookie": "3.0.1", "js-cookie": "2.2.1",
"lodash.camelcase": "4.3.0", "lodash.camelcase": "4.3.0",
"prop-types": "15.7.2", "prop-types": "15.7.2",
"react": "17.0.2", "react": "17.0.2",
@@ -56,7 +55,7 @@
"react-helmet": "6.1.0", "react-helmet": "6.1.0",
"react-redux": "7.2.5", "react-redux": "7.2.5",
"react-router": "5.2.1", "react-router": "5.2.1",
"react-router-dom": "5.3.0", "react-router-dom": "5.2.1",
"react-share": "4.4.0", "react-share": "4.4.0",
"redux": "4.1.1", "redux": "4.1.1",
"regenerator-runtime": "0.13.9", "regenerator-runtime": "0.13.9",
@@ -65,17 +64,17 @@
"util": "0.12.4" "util": "0.12.4"
}, },
"devDependencies": { "devDependencies": {
"@edx/frontend-build": "9.0.5", "@edx/frontend-build": "8.0.4",
"@testing-library/dom": "7.16.3", "@testing-library/dom": "7.16.3",
"@testing-library/jest-dom": "5.14.1", "@testing-library/jest-dom": "5.14.1",
"@testing-library/react": "10.3.0", "@testing-library/react": "10.3.0",
"@testing-library/user-event": "13.4.1", "@testing-library/user-event": "13.2.1",
"axios-mock-adapter": "1.20.0", "axios-mock-adapter": "1.20.0",
"codecov": "3.8.3", "codecov": "3.8.3",
"es-check": "6.0.0", "es-check": "6.0.0",
"glob": "7.2.0", "glob": "7.1.7",
"husky": "7.0.2", "husky": "7.0.2",
"jest": "27.2.5", "jest": "27.0.6",
"jest-chain": "1.1.5", "jest-chain": "1.1.5",
"reactifex": "1.1.1", "reactifex": "1.1.1",
"rosie": "2.1.0" "rosie": "2.1.0"

View File

@@ -0,0 +1,34 @@
import React from 'react';
import { getConfig } from '@edx/frontend-platform';
import { getLoginRedirectUrl } from '@edx/frontend-platform/auth';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Button } from '@edx/paragon';
import genericMessages from '../generic/messages';
function AnonymousUserMenu({ intl }) {
return (
<div>
<Button
className="mr-3"
variant="outline-primary"
href={`${getConfig().LMS_BASE_URL}/register?next=${encodeURIComponent(global.location.href)}`}
>
{intl.formatMessage(genericMessages.registerSentenceCase)}
</Button>
<Button
variant="primary"
href={`${getLoginRedirectUrl(global.location.href)}`}
>
{intl.formatMessage(genericMessages.signInSentenceCase)}
</Button>
</div>
);
}
AnonymousUserMenu.propTypes = {
intl: intlShape.isRequired,
};
export default injectIntl(AnonymousUserMenu);

View File

@@ -0,0 +1,76 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faUserCircle } from '@fortawesome/free-solid-svg-icons';
import { getConfig } from '@edx/frontend-platform';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Dropdown } from '@edx/paragon';
import messages from './messages';
function AuthenticatedUserDropdown({ enterpriseLearnerPortalLink, intl, username }) {
let dashboardMenuItem = (
<Dropdown.Item href={`${getConfig().LMS_BASE_URL}/dashboard`}>
{intl.formatMessage(messages.dashboard)}
</Dropdown.Item>
);
if (enterpriseLearnerPortalLink && Object.keys(enterpriseLearnerPortalLink).length > 0) {
dashboardMenuItem = (
<Dropdown.Item href={enterpriseLearnerPortalLink.href}>
{enterpriseLearnerPortalLink.content}
</Dropdown.Item>
);
}
return (
<>
<a className="text-gray-700 mr-3" href={`${getConfig().SUPPORT_URL}`}>{intl.formatMessage(messages.help)}</a>
<Dropdown className="user-dropdown">
<Dropdown.Toggle variant="outline-primary">
<FontAwesomeIcon icon={faUserCircle} className="d-md-none" size="lg" />
<span data-hj-suppress className="d-none d-md-inline">
{username}
</span>
</Dropdown.Toggle>
<Dropdown.Menu className="dropdown-menu-right">
{dashboardMenuItem}
<Dropdown.Item href={`${getConfig().LMS_BASE_URL}/u/${username}`}>
{intl.formatMessage(messages.profile)}
</Dropdown.Item>
<Dropdown.Item href={`${getConfig().LMS_BASE_URL}/account/settings`}>
{intl.formatMessage(messages.account)}
</Dropdown.Item>
{!enterpriseLearnerPortalLink && (
// Users should only see Order History if they do not have an available
// learner portal, because an available learner portal currently means
// that they access content via Subscriptions, in which context an "order"
// is not relevant.
<Dropdown.Item href={getConfig().ORDER_HISTORY_URL}>
{intl.formatMessage(messages.orderHistory)}
</Dropdown.Item>
)}
<Dropdown.Item href={getConfig().LOGOUT_URL}>
{intl.formatMessage(messages.signOut)}
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</>
);
}
AuthenticatedUserDropdown.propTypes = {
intl: intlShape.isRequired,
username: PropTypes.string.isRequired,
enterpriseLearnerPortalLink: PropTypes.shape({
type: PropTypes.string,
href: PropTypes.string,
content: PropTypes.string,
}),
};
AuthenticatedUserDropdown.defaultProps = {
enterpriseLearnerPortalLink: undefined,
};
export default injectIntl(AuthenticatedUserDropdown);

View File

@@ -0,0 +1,99 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import { useEnterpriseConfig } from '@edx/frontend-enterprise-utils';
import { getConfig } from '@edx/frontend-platform';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { AppContext } from '@edx/frontend-platform/react';
import AnonymousUserMenu from './AnonymousUserMenu';
import AuthenticatedUserDropdown from './AuthenticatedUserDropdown';
import messages from './messages';
function LinkedLogo({
href,
src,
alt,
...attributes
}) {
return (
<a href={href} {...attributes}>
<img className="d-block" src={src} alt={alt} />
</a>
);
}
LinkedLogo.propTypes = {
href: PropTypes.string.isRequired,
src: PropTypes.string.isRequired,
alt: PropTypes.string.isRequired,
};
function Header({
courseOrg, courseNumber, courseTitle, intl, showUserDropdown,
}) {
const { authenticatedUser } = useContext(AppContext);
const { enterpriseLearnerPortalLink, enterpriseCustomerBrandingConfig } = useEnterpriseConfig(
authenticatedUser,
getConfig().ENTERPRISE_LEARNER_PORTAL_HOSTNAME,
getConfig().LMS_BASE_URL,
);
let headerLogo = (
<LinkedLogo
className="logo"
href={`${getConfig().LMS_BASE_URL}/dashboard`}
src={getConfig().LOGO_URL}
alt={getConfig().SITE_NAME}
/>
);
if (enterpriseCustomerBrandingConfig && Object.keys(enterpriseCustomerBrandingConfig).length > 0) {
headerLogo = (
<LinkedLogo
className="logo"
href={enterpriseCustomerBrandingConfig.logoDestination}
src={enterpriseCustomerBrandingConfig.logo}
alt={enterpriseCustomerBrandingConfig.logoAltText}
/>
);
}
return (
<header className="course-header">
<a className="sr-only sr-only-focusable" href="#main-content">{intl.formatMessage(messages.skipNavLink)}</a>
<div className="container-xl py-2 d-flex align-items-center">
{headerLogo}
<div className="flex-grow-1 course-title-lockup" style={{ lineHeight: 1 }}>
<span className="d-block small m-0">{courseOrg} {courseNumber}</span>
<span className="d-block m-0 font-weight-bold course-title">{courseTitle}</span>
</div>
{showUserDropdown && authenticatedUser && (
<AuthenticatedUserDropdown
enterpriseLearnerPortalLink={enterpriseLearnerPortalLink}
username={authenticatedUser.username}
/>
)}
{showUserDropdown && !authenticatedUser && (
<AnonymousUserMenu />
)}
</div>
</header>
);
}
Header.propTypes = {
courseOrg: PropTypes.string,
courseNumber: PropTypes.string,
courseTitle: PropTypes.string,
intl: intlShape.isRequired,
showUserDropdown: PropTypes.bool,
};
Header.defaultProps = {
courseOrg: null,
courseNumber: null,
courseTitle: null,
showUserDropdown: true,
};
export default injectIntl(Header);

View File

@@ -0,0 +1,29 @@
import React from 'react';
import {
authenticatedUser, initializeMockApp, render, screen,
} from '../setupTest';
import { Header } from './index';
describe('Header', () => {
beforeAll(async () => {
// We need to mock AuthService to implicitly use `getAuthenticatedUser` within `AppContext.Provider`.
await initializeMockApp();
});
it('displays user button', () => {
render(<Header />);
expect(screen.getByRole('button')).toHaveTextContent(authenticatedUser.username);
});
it('displays course data', () => {
const courseData = {
courseOrg: 'course-org',
courseNumber: 'course-number',
courseTitle: 'course-title',
};
render(<Header {...courseData} />);
expect(screen.getByText(`${courseData.courseOrg} ${courseData.courseNumber}`)).toBeInTheDocument();
expect(screen.getByText(courseData.courseTitle)).toBeInTheDocument();
});
});

View File

@@ -1,2 +1,2 @@
/* eslint-disable import/prefer-default-export */ export { default as Header } from './Header';
export { default as CourseTabsNavigation } from './CourseTabsNavigation'; export { default as CourseTabsNavigation } from './CourseTabsNavigation';

View File

@@ -0,0 +1,46 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
courseMaterial: {
id: 'learn.navigation.course.tabs.label',
defaultMessage: 'Course Material',
description: 'The accessible label for course tabs navigation',
},
dashboard: {
id: 'header.menu.dashboard.label',
defaultMessage: 'Dashboard',
description: 'The text for the user menu Dashboard navigation link.',
},
help: {
id: 'header.help.label',
defaultMessage: 'Help',
description: 'The text for the link to the Help Center',
},
profile: {
id: 'header.menu.profile.label',
defaultMessage: 'Profile',
description: 'The text for the user menu Profile navigation link.',
},
account: {
id: 'header.menu.account.label',
defaultMessage: 'Account',
description: 'The text for the user menu Account navigation link.',
},
orderHistory: {
id: 'header.menu.orderHistory.label',
defaultMessage: 'Order History',
description: 'The text for the user menu Order History navigation link.',
},
skipNavLink: {
id: 'header.navigation.skipNavLink',
defaultMessage: 'Skip to main content.',
description: 'A link used by screen readers to allow users to skip to the main content of the page.',
},
signOut: {
id: 'header.menu.signOut.label',
defaultMessage: 'Sign Out',
description: 'The label for the user menu Sign Out action.',
},
});
export default messages;

View File

@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { LearningHeader as Header } from '@edx/frontend-component-header'; import { Header } from '../../course-header';
import PageLoading from '../../generic/PageLoading'; import PageLoading from '../../generic/PageLoading';
import { unsubscribeFromCourseGoal } from '../data/api'; import { unsubscribeFromCourseGoal } from '../data/api';

View File

@@ -13,7 +13,7 @@ export default function LmsHtmlFragment({
<html> <html>
<head> <head>
<base href="${getConfig().LMS_BASE_URL}" target="_parent"> <base href="${getConfig().LMS_BASE_URL}" target="_parent">
<link rel="stylesheet" href="/static/${getConfig().LEGACY_THEME_NAME ? `${getConfig().LEGACY_THEME_NAME}/` : ''}css/bootstrap/lms-main.css"> <link rel="stylesheet" href="/static/css/bootstrap/lms-main.css">
<link rel="stylesheet" type="text/css" href="${getConfig().BASE_URL}/src/course-home/outline-tab/LmsHtmlFragment.css"> <link rel="stylesheet" type="text/css" href="${getConfig().BASE_URL}/src/course-home/outline-tab/LmsHtmlFragment.css">
</head> </head>
<body class="${className}">${html}</body> <body class="${className}">${html}</body>

View File

@@ -2,9 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
getLocale, injectIntl, intlShape, isRtl,
} from '@edx/frontend-platform/i18n';
import { OverlayTrigger, Popover } from '@edx/paragon'; import { OverlayTrigger, Popover } from '@edx/paragon';
import { useModel } from '../../../../generic/model-store'; import { useModel } from '../../../../generic/model-store';
@@ -25,14 +23,6 @@ function CurrentGradeTooltip({ intl, tooltipClassName }) {
const currentGrade = Number((visiblePercent * 100).toFixed(0)); const currentGrade = Number((visiblePercent * 100).toFixed(0));
let currentGradeDirection = currentGrade < 50 ? '' : '-';
const isLocaleRtl = isRtl(getLocale());
if (isLocaleRtl) {
currentGradeDirection = currentGrade < 50 ? '-' : '';
}
return ( return (
<> <>
<OverlayTrigger <OverlayTrigger
@@ -47,16 +37,16 @@ function CurrentGradeTooltip({ intl, tooltipClassName }) {
)} )}
> >
<g> <g>
<circle cx={`${Math.min(...[isLocaleRtl ? 100 - currentGrade : currentGrade, 100])}%`} cy="50%" r="8.5" fill="transparent" /> <circle cx={`${Math.min(...[currentGrade, 100])}%`} cy="50%" r="8.5" fill="transparent" />
<rect className="grade-bar__divider" x={`${Math.min(...[isLocaleRtl ? 100 - currentGrade : currentGrade, 100])}%`} style={{ transform: 'translateY(2.61em)' }} /> <rect className="grade-bar__divider" x={`${Math.min(...[currentGrade, 100])}%`} style={{ transform: 'translateY(2.61em)' }} />
</g> </g>
</OverlayTrigger> </OverlayTrigger>
<text <text
className="x-small" className="x-small"
textAnchor={currentGrade < 50 ? 'start' : 'end'} textAnchor={currentGrade < 50 ? 'start' : 'end'}
x={`${Math.min(...[isLocaleRtl ? 100 - currentGrade : currentGrade, 100])}%`} x={`${Math.min(...[currentGrade, 100])}%`}
y="20px" y="20px"
style={{ transform: `translateX(${currentGradeDirection}3.4em)` }} style={{ transform: `translateX(${currentGrade < 50 ? '' : '-'}3.4em)` }}
> >
{intl.formatMessage(messages.currentGradeLabel)} {intl.formatMessage(messages.currentGradeLabel)}
</text> </text>

View File

@@ -1,22 +1,12 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
getLocale, injectIntl, intlShape, isRtl,
} from '@edx/frontend-platform/i18n';
import { OverlayTrigger, Popover } from '@edx/paragon'; import { OverlayTrigger, Popover } from '@edx/paragon';
import messages from '../messages'; import messages from '../messages';
function PassingGradeTooltip({ intl, passingGrade, tooltipClassName }) { function PassingGradeTooltip({ intl, passingGrade, tooltipClassName }) {
const isLocaleRtl = isRtl(getLocale());
let passingGradeDirection = passingGrade < 50 ? '' : '-';
if (isLocaleRtl) {
passingGradeDirection = passingGrade < 50 ? '-' : '';
}
return ( return (
<> <>
<OverlayTrigger <OverlayTrigger
@@ -31,17 +21,17 @@ function PassingGradeTooltip({ intl, passingGrade, tooltipClassName }) {
)} )}
> >
<g> <g>
<circle cx={`${isLocaleRtl ? 100 - passingGrade : passingGrade}%`} cy="50%" r="8.5" fill="transparent" /> <circle cx={`${passingGrade}%`} cy="50%" r="8.5" fill="transparent" />
<circle className="grade-bar--passing" cx={`${isLocaleRtl ? 100 - passingGrade : passingGrade}%`} cy="50%" r="4.5" /> <circle className="grade-bar--passing" cx={`${passingGrade}%`} cy="50%" r="4.5" />
</g> </g>
</OverlayTrigger> </OverlayTrigger>
<text <text
className="x-small" className="x-small"
textAnchor={passingGrade < 50 ? 'start' : 'end'} textAnchor={passingGrade < 50 ? 'start' : 'end'}
x={`${isLocaleRtl ? 100 - passingGrade : passingGrade}%`} x={`${passingGrade}%`}
y="90px" y="90px"
style={{ transform: `translateX(${passingGradeDirection}3.4em)` }} style={{ transform: `translateX(${passingGrade < 50 ? '' : '-'}3.4em)` }}
> >
{intl.formatMessage(messages.passingGradeLabel)} {intl.formatMessage(messages.passingGradeLabel)}
</text> </text>

View File

@@ -1,11 +0,0 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
courseMaterial: {
id: 'learn.navigation.course.tabs.label',
defaultMessage: 'Course Material',
description: 'The accessible label for course tabs navigation',
},
});
export default messages;

View File

@@ -159,7 +159,7 @@ describe('CoursewareContainer', () => {
const courseId = defaultCourseId; const courseId = defaultCourseId;
function assertLoadedHeader(container) { function assertLoadedHeader(container) {
const courseHeader = container.querySelector('.learning-header'); const courseHeader = container.querySelector('.course-header');
// Ensure the course number and org appear - this proves we loaded course metadata properly. // Ensure the course number and org appear - this proves we loaded course metadata properly.
expect(courseHeader).toHaveTextContent(courseMetadata.number); expect(courseHeader).toHaveTextContent(courseMetadata.number);
expect(courseHeader).toHaveTextContent(courseMetadata.org); expect(courseHeader).toHaveTextContent(courseMetadata.org);

View File

@@ -1,12 +1,10 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { getConfig } from '@edx/frontend-platform';
import { FormattedMessage } from '@edx/frontend-platform/i18n'; import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faHome } from '@fortawesome/free-solid-svg-icons'; import { faHome } from '@fortawesome/free-solid-svg-icons';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { SelectMenu } from '@edx/paragon'; import { SelectMenu } from '@edx/paragon';
import { Link } from 'react-router-dom';
import { useModel, useModels } from '../../generic/model-store'; import { useModel, useModels } from '../../generic/model-store';
/** [MM-P2P] Experiment */ /** [MM-P2P] Experiment */
import { MMP2PFlyoverTrigger } from '../../experiments/mm-p2p'; import { MMP2PFlyoverTrigger } from '../../experiments/mm-p2p';
@@ -29,14 +27,11 @@ function CourseBreadcrumb({
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
}} }}
> >
{ getConfig().ENABLE_JUMPNAV !== 'true' || content.length < 2 || !isStaff {content.length < 2 || !isStaff
? ( ? (
<Link <a className="text-primary-500" href={`/course/${courseId}/${defaultContent.id}`}>
className="text-primary-500"
to={`/course/${courseId}/${defaultContent.id}`}
>
{defaultContent.label} {defaultContent.label}
</Link> </a>
) )
: ( : (
<SelectMenu isLink defaultMessage={defaultContent.label}> <SelectMenu isLink defaultMessage={defaultContent.label}>
@@ -126,9 +121,9 @@ export default function CourseBreadcrumbs({
<nav aria-label="breadcrumb" className="my-4 d-inline-block col-sm-10"> <nav aria-label="breadcrumb" className="my-4 d-inline-block col-sm-10">
<ol className="list-unstyled d-flex flex-nowrap align-items-center m-0"> <ol className="list-unstyled d-flex flex-nowrap align-items-center m-0">
<li className="list-unstyled d-flex m-0"> <li className="list-unstyled d-flex m-0">
<Link <a
href={`/course/${courseId}/home`}
className="flex-shrink-0 text-primary" className="flex-shrink-0 text-primary"
to={`/course/${courseId}/home`}
> >
<FontAwesomeIcon icon={faHome} className="mr-2" /> <FontAwesomeIcon icon={faHome} className="mr-2" />
<FormattedMessage <FormattedMessage
@@ -136,7 +131,7 @@ export default function CourseBreadcrumbs({
description="The course home link in breadcrumbs nav" description="The course home link in breadcrumbs nav"
defaultMessage="Course" defaultMessage="Course"
/> />
</Link> </a>
</li> </li>
{links.map(content => ( {links.map(content => (
<CourseBreadcrumb <CourseBreadcrumb

View File

@@ -1,8 +1,6 @@
import React from 'react'; import React from 'react';
import { screen, render } from '@testing-library/react'; import { screen, render } from '@testing-library/react';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { getConfig } from '@edx/frontend-platform';
import { BrowserRouter } from 'react-router-dom';
import { useModel, useModels } from '../../generic/model-store'; import { useModel, useModels } from '../../generic/model-store';
import CourseBreadcrumbs from './CourseBreadcrumbs'; import CourseBreadcrumbs from './CourseBreadcrumbs';
@@ -12,7 +10,6 @@ jest.mock('@edx/frontend-platform/analytics');
// Remove When Fully rolled out>>> // Remove When Fully rolled out>>>
jest.mock('../../generic/model-store'); jest.mock('../../generic/model-store');
jest.mock('@edx/frontend-platform/auth'); jest.mock('@edx/frontend-platform/auth');
getConfig.mockImplementation(() => ({ ENABLE_JUMPNAV: 'true' }));
getAuthenticatedUser.mockImplementation(() => ({ administrator: true })); getAuthenticatedUser.mockImplementation(() => ({ administrator: true }));
// ^^^^Remove When Fully rolled out // ^^^^Remove When Fully rolled out
@@ -106,14 +103,12 @@ describe('CourseBreadcrumbs', () => {
], ],
]); ]);
render( render(
<BrowserRouter> <CourseBreadcrumbs
<CourseBreadcrumbs courseId="course-v1:edX+DemoX+Demo_Course"
courseId="course-v1:edX+DemoX+Demo_Course" sectionId="block-v1:edX+DemoX+Demo_Course+type@chapter+block@interactive_demonstrations"
sectionId="block-v1:edX+DemoX+Demo_Course+type@chapter+block@interactive_demonstrations" sequenceId="block-v1:edX+DemoX+Demo_Course+type@sequential+block@basic_questions"
sequenceId="block-v1:edX+DemoX+Demo_Course+type@sequential+block@basic_questions" isStaff
isStaff />,
/>
</BrowserRouter>,
); );
it('renders course breadcrumbs as expected', async () => { it('renders course breadcrumbs as expected', async () => {
expect(screen.queryAllByRole('link')).toHaveLength(1); expect(screen.queryAllByRole('link')).toHaveLength(1);

View File

@@ -237,13 +237,7 @@ export function fetchSequence(sequenceId) {
dispatch(fetchSequenceSuccess({ sequenceId })); dispatch(fetchSequenceSuccess({ sequenceId }));
} }
} catch (error) { } catch (error) {
// Some errors are expected - for example, CoursewareContainer may request sequence metadata for a unit and rely logError(error);
// on the request failing to notice that it actually does have a unit (mostly so it doesn't have to know anything
// about the opaque key structure). In such cases, the backend gives us a 422.
const isExpected = error.response && error.response.status === 422;
if (!isExpected) {
logError(error);
}
dispatch(fetchSequenceFailure({ sequenceId })); dispatch(fetchSequenceFailure({ sequenceId }));
} }
}; };

View File

@@ -11,6 +11,16 @@ const messages = defineMessages({
defaultMessage: 'register', defaultMessage: 'register',
description: 'Text in a link, prompting the user to create an account. Used in "learning.logistration.alert"', description: 'Text in a link, prompting the user to create an account. Used in "learning.logistration.alert"',
}, },
registerSentenceCase: {
id: 'general.register.sentenceCase',
defaultMessage: 'Register',
description: 'Text in a button, prompting the user to register.',
},
signInLowercase: {
id: 'learning.logistration.login', // ID left for historical purposes
defaultMessage: 'sign in',
description: 'Text in a link, prompting the user to log in. Used in "learning.logistration.alert"',
},
signInSentenceCase: { signInSentenceCase: {
id: 'general.signIn.sentenceCase', id: 'general.signIn.sentenceCase',
defaultMessage: 'Sign in', defaultMessage: 'Sign in',

View File

@@ -1,399 +1,399 @@
{ {
"learning.accessExpiration.deadline": "Mettez à niveau avant le {date} pour obtenir un accès illimité au cours tant qu'il existe sur le site.", "learning.accessExpiration.deadline": "Upgrade by {date} to get unlimited access to the course as long as it exists on the site.",
"learning.accessExpiration.header": "Laccès à laudit expire le {date}", "learning.accessExpiration.header": "Audit Access Expires {date}",
"learning.accessExpiration.body": "Vous perdez tout accès à ce cours, y compris votre progression, le {date}.", "learning.accessExpiration.body": "You lose all access to this course, including your progress, on {date}.",
"instructorToolbar.pageBanner.courseHasExpired": "Cet apprenant n'a plus accès à ce cours. Leur accès a expiré le {date}.", "instructorToolbar.pageBanner.courseHasExpired": "This learner no longer has access to this course. Their access expired on {date}.",
"learning.accessExpiration.upgradeNow": "Mettre à jour dès maintenant", "learning.accessExpiration.upgradeNow": "Upgrade now",
"learning.outline.alert.start.short": "Le cours commence dans {timeRemaining} à {courseStartTime}.", "learning.outline.alert.start.short": "Course starts {timeRemaining} at {courseStartTime}.",
"learning.outline.alert.end.long": "Ce cours se termine dans {timeRemaining}, le {courseEndDate}.", "learning.outline.alert.end.long": "This course is ending {timeRemaining} on {courseEndDate}.",
"learning.outline.alert.end.calendar": "N'oubliez pas d'ajouter un rappel dans le calendrier!", "learning.outline.alert.end.calendar": "Dont forget to add a calendar reminder!",
"instructorToolbar.pageBanner.courseHasNotStarted": "Cet apprenant n'a pas encore accès à ce cours. Le cours commencera le {date}.", "instructorToolbar.pageBanner.courseHasNotStarted": "This learner does not yet have access to this course. The course starts on {date}.",
"learning.enrollment.alert": "Vous devez être inscrit à ce cours pour voir le contenu du cours.", "learning.enrollment.alert": "You must be enrolled in the course to see course content.",
"learning.staff.enrollment.alert": "Vous regardez ce cours en tant que membre de l'équipe, vous n'êtes pas inscrits.", "learning.staff.enrollment.alert": "You are viewing this course as staff, and are not enrolled.",
"learning.enrollment.enrollNow.Inline": "Inscrivez-vous maintenant.", "learning.enrollment.enrollNow.Inline": "Enroll now",
"learning.enrollment.enrollNow.Sentence": "Inscrivez-vous maintenant.", "learning.enrollment.enrollNow.Sentence": "Enroll now.",
"learning.enrollment.success": "Vous vous êtes inscrits avec succès à ce cours!", "learning.enrollment.success": "You've successfully enrolled in this course!",
"account-activation.alert.title": "Activez votre compte afin de pouvoir vous reconnecter", "account-activation.alert.title": "Activate your account so you can log back in",
"account-activation.alert.button": "Continuer vers {siteName}", "account-activation.alert.button": "Continue to {siteName}",
"account-activation.alert.message": "Nous avons envoyé un courriel à {boldEmail} contenant un lien pour activer votre compte. Il est introuvable ? Vérifiez votre dossier de pourriel ou\n {sendEmailTag}.", "account-activation.alert.message": "We sent an email to {boldEmail} with a link to activate your account. Cant find it? Check your spam folder or\n {sendEmailTag}.",
"account-activation.resend.link": "renvoyer le courriel", "account-activation.resend.link": "resend the email",
"learning.logistration.alert": "Pour afficher le contenu du cours, {signIn} ou {register}.", "learning.logistration.alert": "To see course content, {signIn} or {register}.",
"learn.navigation.course.tabs.label": "Matériel de cours", "learn.navigation.course.tabs.label": "Course Material",
"header.menu.dashboard.label": "Tableau de bord", "header.menu.dashboard.label": "Dashboard",
"header.help.label": "Aide", "header.help.label": "Help",
"header.menu.profile.label": "Profil", "header.menu.profile.label": "Profile",
"header.menu.account.label": "Compte", "header.menu.account.label": "Account",
"header.menu.orderHistory.label": "Historique des commandes", "header.menu.orderHistory.label": "Order History",
"header.navigation.skipNavLink": "Passer au contenu principal", "header.navigation.skipNavLink": "Skip to main content.",
"header.menu.signOut.label": "Se déconnecter", "header.menu.signOut.label": "Sign Out",
"learning.dates.badge.completed": "Terminé", "learning.dates.badge.completed": "Completed",
"learning.dates.badge.dueNext": "À venir", "learning.dates.badge.dueNext": "Due next",
"learning.dates.badge.pastDue": "En retard", "learning.dates.badge.pastDue": "Past due",
"learning.dates.title": "Dates importantes", "learning.dates.title": "Important dates",
"learning.dates.badge.today": "Aujourd'hui", "learning.dates.badge.today": "Today",
"learning.dates.badge.unreleased": "Pas encore publié", "learning.dates.badge.unreleased": "Not yet released",
"learning.dates.badge.verifiedOnly": "Vérifié seulement", "learning.dates.badge.verifiedOnly": "Verified only",
"learning.goals.unsubscribe.contact": "contacter le support", "learning.goals.unsubscribe.contact": "contact support",
"learning.goals.unsubscribe.description": "Vous ne recevrez plus de rappels par courriel au sujet de votre objectif pour {courseTitle}.", "learning.goals.unsubscribe.description": "You will no longer receive email reminders about your goal for {courseTitle}.",
"learning.goals.unsubscribe.errorHeader": "Quelque chose s'est mal passé", "learning.goals.unsubscribe.errorHeader": "Something went wrong",
"learning.goals.unsubscribe.goToDashboard": "Aller au tableau de bord", "learning.goals.unsubscribe.goToDashboard": "Go to dashboard",
"learning.goals.unsubscribe.header": "Vous vous êtes désabonné des rappels d'objectifs", "learning.goals.unsubscribe.header": "Youve unsubscribed from goal reminders",
"learning.goals.unsubscribe.loading": "Désinscription...", "learning.goals.unsubscribe.loading": "Unsubscribing…",
"learning.goals.unsubscribe.errorDescription": "Nous n'avons pas pu vous désinscrire des courriels de rappel d'objectif. Veuillez réessayer plus tard ou {contactSupport} pour obtenir de l'aide.", "learning.goals.unsubscribe.errorDescription": "We were unable to unsubscribe you from goal reminder emails. Please try again later or {contactSupport} for help.",
"learning.outline.alert.cert.when": "Ce cours se termine le {courseEndDateFormatted}. Les notes finales et les attestations\n devraient être disponibles après {certificateAvailableDate}.", "learning.outline.alert.cert.when": "This course ends on {courseEndDateFormatted}. Final grades and certificates are\n scheduled to be available after {certificateAvailableDate}.",
"cert.alert.earned.unavailable.header": "Votre note et votre attestation seront bientôt prêtes !", "cert.alert.earned.unavailable.header": "Your grade and certificate will be ready soon!",
"cert.alert.earned.ready.header": "Félicitations ! Votre attestation est prête.", "cert.alert.earned.ready.header": "Congratulations! Your certificate is ready.",
"cert.alert.notPassing.header": "Vous n'êtes pas éligible pour une attestation", "cert.alert.notPassing.header": "You are not eligible for a certificate",
"cert.alert.notPassing.button": "Voir les notes", "cert.alert.notPassing.button": "View grades",
"learning.outline.alert.end.short": "Le cours termine dans {timeRemaining} à {courseEndTime}.", "learning.outline.alert.end.short": "This course is ending {timeRemaining} at {courseEndTime}.",
"alert.enroll": " pour accéder au cours complet.", "alert.enroll": " to access the full course.",
"learning.privateCourse.signInOrRegister": "{signIn} ou {register}, puis inscrivez-vous à ce cours.", "learning.privateCourse.signInOrRegister": "{signIn} or {register} and then enroll in this course.",
"learning.outline.alert.scheduled-content.heading": "Plus de contenu sera bientôt disponible!", "learning.outline.alert.scheduled-content.heading": "More content is coming soon!",
"learning.outline.alert.scheduled-content.body": "Ce cours aura plus de contenu publié à une date future. Surveillez les mises à jour par courriel ou revenez voir ce cours pour les mises à jour.", "learning.outline.alert.scheduled-content.body": "This course will have more content released at a future date. Look out for email updates or check back on this course for updates.",
"learning.outline.alert.scheduled-content.button": "Voir l'horaire du cours", "learning.outline.alert.scheduled-content.button": "View Course Schedule",
"learning.outline.dates.all": "Voir toutes les dates de cours", "learning.outline.dates.all": "View all course dates",
"learning.outline.collapseAll": "Tout replier", "learning.outline.collapseAll": "Collapse all",
"learning.outline.completedAssignment": "Terminé", "learning.outline.completedAssignment": "Completed",
"learning.outline.completedSection": "Section complétée", "learning.outline.completedSection": "Completed section",
"learning.outline.dates": "Dates importantes", "learning.outline.dates": "Important dates",
"learning.outline.editGoal": "Modifier l'objectif", "learning.outline.editGoal": "Edit goal",
"learning.outline.expandAll": "Tout développer", "learning.outline.expandAll": "Expand all",
"learning.outline.goal": "Objectif", "learning.outline.goal": "Goal",
"learning.outline.goalUnsure": "Décider plus tard", "learning.outline.goalUnsure": "Not sure yet",
"learning.outline.handouts": "Documents de cours", "learning.outline.handouts": "Course Handouts",
"learning.outline.incompleteAssignment": "Inachevé", "learning.outline.incompleteAssignment": "Incomplete",
"learning.outline.incompleteSection": "Section incomplète", "learning.outline.incompleteSection": "Incomplete section",
"learning.outline.learnMore": "En savoir plus", "learning.outline.learnMore": "Learn More",
"learning.outline.altText.openSection": "Ouvrir", "learning.outline.altText.openSection": "Open",
"learning.outline.resume": "Poursuivre le cours", "learning.outline.resume": "Resume course",
"learning.outline.setGoal": "Pour commencer, définissez un objectif de cours en sélectionnant l'option ci-dessous qui décrit le mieux votre plan d'apprentissage.", "learning.outline.setGoal": "To start, set a course goal by selecting the option below that best describes your learning plan.",
"learning.outline.start": "Commencer le cours", "learning.outline.start": "Start Course",
"learning.outline.tools": "Outils de cours", "learning.outline.tools": "Course Tools",
"learning.outline.upgradeButton": "Mise-à-jour ({symbol}{price})", "learning.outline.upgradeButton": "Upgrade ({symbol}{price})",
"learning.outline.upgradeTitle": "Obtenir un certificat vérifié", "learning.outline.upgradeTitle": "Pursue a verified certificate",
"learning.outline.certificateAlt": "Exemple d'attestation", "learning.outline.certificateAlt": "Example Certificate",
"learning.outline.welcomeMessage": "Message de bienvenue", "learning.outline.welcomeMessage": "Welcome Message",
"learning.outline.welcomeMessageShowMoreButton": "Montrer plus", "learning.outline.welcomeMessageShowMoreButton": "Show More",
"learning.outline.welcomeMessageShowLessButton": "Montrer moins", "learning.outline.welcomeMessageShowLessButton": "Show Less",
"learning.outline.goalWelcome": "Bienvenue sur", "learning.outline.goalWelcome": "Welcome to",
"learning.proctoringPanel.header": "Ce cours contient des examens surveillés", "learning.proctoringPanel.header": "This course contains proctored exams",
"learning.proctoringPanel.status.notStarted": "Non démarré", "learning.proctoringPanel.status.notStarted": "Not Started",
"learning.proctoringPanel.status.started": "Débuté", "learning.proctoringPanel.status.started": "Started",
"learning.proctoringPanel.status.submitted": "Soumis", "learning.proctoringPanel.status.submitted": "Submitted",
"learning.proctoringPanel.status.verified": "Vérifié", "learning.proctoringPanel.status.verified": "Verified",
"learning.proctoringPanel.status.rejected": "Reje", "learning.proctoringPanel.status.rejected": "Rejected",
"learning.proctoringPanel.status.error": "Erreur", "learning.proctoringPanel.status.error": "Error",
"learning.proctoringPanel.status.otherCourseApproved": "Approuvé dans un autre cours", "learning.proctoringPanel.status.otherCourseApproved": "Approved in Another Course",
"learning.proctoringPanel.status.expiringSoon": "Expire bientôt", "learning.proctoringPanel.status.expiringSoon": "Expiring Soon",
"learning.proctoringPanel.status": "Statut actuel d'intégration :", "learning.proctoringPanel.status": "Current Onboarding Status:",
"learning.proctoringPanel.message.notStarted": "Vous n'avez pas commencé votre examen d'intégration.", "learning.proctoringPanel.message.notStarted": "You have not started your onboarding exam.",
"learning.proctoringPanel.message.started": "Vous avez commencé votre examen d'intégration.", "learning.proctoringPanel.message.started": "You have started your onboarding exam.",
"learning.proctoringPanel.message.submitted": "Vous avez soumis votre examen d'intégration.", "learning.proctoringPanel.message.submitted": "You have submitted your onboarding exam.",
"learning.proctoringPanel.message.verified": "Votre examen d'intégration a été approuvé pour ce cours.", "learning.proctoringPanel.message.verified": "Your onboarding exam has been approved in this course.",
"learning.proctoringPanel.message.rejected": "Votre examen d'intégration a été rejeté. Veuillez réessayer l'intégration.", "learning.proctoringPanel.message.rejected": "Your onboarding exam has been rejected. Please retry onboarding.",
"learning.proctoringPanel.message.error": "Une erreur s'est produite lors de votre examen d'intégration. Veuillez réessayer l'intégration.", "learning.proctoringPanel.message.error": "An error has occurred during your onboarding exam. Please retry onboarding.",
"learning.proctoringPanel.message.otherCourseApproved": "Votre examen d'intégration a été approuvé dans un autre cours.", "learning.proctoringPanel.message.otherCourseApproved": "Your onboarding exam has been approved in another course.",
"learning.proctoringPanel.detail.otherCourseApproved": "Si votre appareil a changé, nous vous recommandons de passer l'examen d'intégration de ce cours afin de vous assurer que votre configuration répond toujours aux exigences de surveillance.", "learning.proctoringPanel.detail.otherCourseApproved": "If your device has changed, we recommend that you complete this course's onboarding exam in order to ensure that your setup still meets the requirements for proctoring.",
"learning.proctoringPanel.message.expiringSoon": "Votre profil d'intégration a été approuvé dans un autre cours. Cependant, votre statut d'intégration expire bientôt. Veuillez compléter à nouveau l'intégration afin que vous soyez en mesure de continuer à passer des examens surveillés.", "learning.proctoringPanel.message.expiringSoon": "Your onboarding profile has been approved in another course. However, your onboarding status is expiring soon. Please complete onboarding again to ensure that you will be able to continue taking proctored exams.",
"learning.proctoringPanel.generalInfo": "Vous devez terminer le processus d'intégration avant de passer un examen surveillé.", "learning.proctoringPanel.generalInfo": "You must complete the onboarding process prior to taking any proctored exam. ",
"learning.proctoringPanel.generalInfoSubmitted": "Votre profil soumis est en cours de révision.", "learning.proctoringPanel.generalInfoSubmitted": "Your submitted profile is in review.",
"learning.proctoringPanel.generalTime": "L'examen du profil d'intégration peut prendre plus de 2 jours ouvrables.", "learning.proctoringPanel.generalTime": "Onboarding profile review can take 2+ business days.",
"learning.proctoringPanel.onboardingButton": "Complétez l'intégration", "learning.proctoringPanel.onboardingButton": "Complete Onboarding",
"learning.proctoringPanel.onboardingPracticeButton": "Voir l'examen d'intégration", "learning.proctoringPanel.onboardingPracticeButton": "View Onboarding Exam",
"learning.proctoringPanel.onboardingButtonNotOpen": "Ouverture de l'intégration : {releaseDate}", "learning.proctoringPanel.onboardingButtonNotOpen": "Onboarding Opens: {releaseDate}",
"learning.proctoringPanel.reviewRequirementsButton": "Examiner les instructions et la configuration système requise", "learning.proctoringPanel.reviewRequirementsButton": "Review instructions and system requirements",
"learning.proctoringPanel.onboardingButtonPastDue": "Intégration en retard", "learning.proctoringPanel.onboardingButtonPastDue": "Onboarding Past Due",
"learning.outline.sequence-due": "{description} échéance {assignmentDue}", "learning.outline.sequence-due": "{description} due {assignmentDue}",
"progress.certificateStatus.unverifiedBody": "Afin de générer une attestation, vous devez effectuer une vérification d'identité. {idVerificationSupportLink}.", "progress.certificateStatus.unverifiedBody": "In order to generate a certificate, you must complete ID verification. {idVerificationSupportLink}.",
"progress.certificateStatus.downloadableBody": "Présentez vos réalisations sur LinkedIn ou votre curriculum vitae aujourd'hui. Vous pouvez télécharger votre certificat maintenant et y accéder à tout moment depuis votre tableau de bord et votre profil.", "progress.certificateStatus.downloadableBody": "Showcase your accomplishment on LinkedIn or your resumé today. You can download your certificate now and access it any time from your Dashboard and Profile.",
"courseCelebration.certificateBody.notAvailable.endDate": "Ce cours se termine le {endDate} et les notes finales et les attestations sont programmées pour être\n disponibles après le {certAvailableDate}.", "courseCelebration.certificateBody.notAvailable.endDate": "This course ended on {endDate} and final grades and certificates are scheduled to be\n available after {certAvailableDate}.",
"progress.certificateStatus.notPassingHeader": "État de l'attestation", "progress.certificateStatus.notPassingHeader": "Certificate status",
"progress.certificateStatus.notPassingBody": "Pour être admissible à une attestation, vous devez avoir la note de passage.", "progress.certificateStatus.notPassingBody": "In order to qualify for a certificate, you must have a passing grade.",
"progress.certificateStatus.inProgressHeader": "Plus de contenu sera bientôt disponible!", "progress.certificateStatus.inProgressHeader": "More content is coming soon!",
"progress.certificateStatus.inProgressBody": "Il semble qu'il y ait plus de contenu dans ce cours qui sera publié dans le futur. Attendez les mises à jour par courriel ou revenez sur votre cours pour savoir quand ce contenu sera disponible.", "progress.certificateStatus.inProgressBody": "It looks like there is more content in this course that will be released in the future. Look out for email updates or check back on your course for when this content will be available.",
"progress.certificateStatus.requestableHeader": "État de l'attestation", "progress.certificateStatus.requestableHeader": "Certificate status",
"progress.certificateStatus.requestableBody": "Félicitations, vous vous qualifiez pour une attestation! Pour accéder à votre attestation, demandez-la ci-dessous.", "progress.certificateStatus.requestableBody": "Congratulations, you qualified for a certificate! In order to access your certificate, request it below.",
"progress.certificateStatus.requestableButton": "Demander une attestation", "progress.certificateStatus.requestableButton": "Request certificate",
"progress.certificateStatus.unverifiedHeader": "État de l'attestation", "progress.certificateStatus.unverifiedHeader": "Certificate status",
"progress.certificateStatus.unverifiedButton": "Vérifiez votre identité", "progress.certificateStatus.unverifiedButton": "Verify ID",
"progress.certificateStatus.courseCelebration.verificationPending": "La vérification de votre identité est en attente et votre attestation sera disponible une fois approuvé.", "progress.certificateStatus.courseCelebration.verificationPending": "Your ID verification is pending and your certificate will be available once approved.",
"progress.certificateStatus.downloadableHeader": "Votre attestation est disponible!", "progress.certificateStatus.downloadableHeader": "Your certificate is available!",
"progress.certificateStatus.downloadableButton": "Téléchargez mon attestation", "progress.certificateStatus.downloadableButton": "Download my certificate",
"progress.certificateStatus.viewableButton": "Voir mon attestation", "progress.certificateStatus.viewableButton": "View my certificate",
"progress.certificateStatus.notAvailableHeader": "État de l'attestation", "progress.certificateStatus.notAvailableHeader": "Certificate status",
"progress.certificateStatus.upgradeHeader": "Obtenir un certificat", "progress.certificateStatus.upgradeHeader": "Earn a certificate",
"progress.certificateStatus.upgradeBody": "Vous êtes dans une piste d'audit et n'êtes pas admissible à une attestation. Afin d'obtenir vers une attestation, mettez à niveau votre cours dès aujourd'hui.", "progress.certificateStatus.upgradeBody": "You are in an audit track and do not qualify for a certificate. In order to work towards a certificate, upgrade your course today.",
"progress.certificateStatus.upgradeButton": "Mettre à jour dès maintenant", "progress.certificateStatus.upgradeButton": "Upgrade now",
"progress.certificateStatus.unverifiedHomeHeader": "Vérifiez votre identité pour obtenir une attestation !", "progress.certificateStatus.unverifiedHomeHeader": "Verify your identity to earn a certificate!",
"progress.certificateStatus.unverifiedHomeButton": "Vérifiez mon identité", "progress.certificateStatus.unverifiedHomeButton": "Verify my ID",
"progress.certificateStatus.unverifiedHomeBody": "Afin de générer une attestation pour ce cours, vous devez compléter le processus de vérification d'identité.", "progress.certificateStatus.unverifiedHomeBody": "In order to generate a certificate for this course, you must complete the ID verification process.",
"progress.completion.donut.label": "achevée", "progress.completion.donut.label": "completed",
"progress.completion.body": "Cela représente la part du contenu du cours que vous avez terminé. Notez que certains contenus peuvent ne pas encore être publiés.", "progress.completion.body": "This represents how much of the course content you have completed. Note that some content may not yet be released.",
"progress.completion.tooltip.locked": "Contenu que vous avez terminé.", "progress.completion.tooltip.locked": "Content that you have completed.",
"progress.completion.header": "Achèvement du cours", "progress.completion.header": "Course completion",
"progress.completion.tooltip": "Contenu auquel vous avez accès et que vous n'avez pas terminé.", "progress.completion.tooltip": "Content that you have access to and have not completed.",
"progress.completion.tooltip.complete": "Contenu verrouillé et disponible uniquement pour ceux qui effectuent une mise à niveau.", "progress.completion.tooltip.complete": "Content that is locked and available only to those who upgrade.",
"progress.completion.donut.percentComplete": "Vous avez terminé {percent}% du contenu de ce cours.", "progress.completion.donut.percentComplete": "You have completed {percent}% of content in this course.",
"progress.completion.donut.percentIncomplete": "Vous n'avez pas terminé {percent}% du contenu de ce cours auquel vous avez accès.", "progress.completion.donut.percentIncomplete": "You have not completed {percent}% of content in this course that you have access to.",
"progress.completion.donut.percentLocked": "{percent}% du contenu de ce cours est verrouillé et disponible uniquement pour ceux qui effectuent une mise à niveau.", "progress.completion.donut.percentLocked": "{percent}% of content in this course is locked and available only for those who upgrade.",
"progress.ungradedAlert": "Pour connaître la progression des aspects non notés du cours, consultez votre {outlineLink}.", "progress.ungradedAlert": "For progress on ungraded aspects of the course, view your {outlineLink}.",
"progress.footnotes.droppableAssignments": "Le plus bas {numDroppable, plural, one{# {assignmentType} score} autre{# {assignmentType} scores}} supprimé.", "progress.footnotes.droppableAssignments": "The lowest {numDroppable, plural, one{# {assignmentType} score is} other{# {assignmentType} scores are}} dropped.",
"progress.assignmentType": "Type d'évaluation", "progress.assignmentType": "Assignment type",
"progress.footnotes.backToContent": "Retour au contenu", "progress.footnotes.backToContent": "Back to content",
"progress.courseGrade.body": "Cela représente votre note pondérée par rapport à la note nécessaire pour réussir ce cours.", "progress.courseGrade.body": "This represents your weighted grade against the grade needed to pass this course.",
"progress.courseGrade.gradeBar.altText": "Votre note actuelle est {currentGrade}%. Une note pondérée de {passingGrade}% est nécessaire afin de réussir ce cours.", "progress.courseGrade.gradeBar.altText": "Your current grade is {currentGrade}%. A weighted grade of {passingGrade}% is required to pass in this course.",
"progress.courseGrade.footer.generic.passing": "Vous réussissez actuellement ce cours", "progress.courseGrade.footer.generic.passing": "Youre currently passing this course",
"progress.courseGrade.footer.nonPassing": "Une note pondérée de {passingGrade}% est nécessaire pour réussir ce cours.", "progress.courseGrade.footer.nonPassing": "A weighted grade of {passingGrade}% is required to pass in this course",
"progress.courseGrade.footer.passing": "Vous réussissez actuellement ce cours avec une note de {letterGrade} ({minGrade}-{maxGrade}%)", "progress.courseGrade.footer.passing": "Youre currently passing this course with a grade of {letterGrade} ({minGrade}-{maxGrade}%)",
"progress.courseGrade.preview.headerLocked": "fonction verrouillée", "progress.courseGrade.preview.headerLocked": "locked feature",
"progress.courseGrade.preview.headerLimited": "fonctionnalité limitée", "progress.courseGrade.preview.headerLimited": "limited feature",
"progress.courseGrade.preview.header.ariaHidden": "Aperçu d'un ", "progress.courseGrade.preview.header.ariaHidden": "Preview of a ",
"progress.courseGrade.preview.body.unlockCertificate": "Déverrouillez pour afficher les notes et obtenir une attestation.", "progress.courseGrade.preview.body.unlockCertificate": "Unlock to view grades and work towards a certificate.",
"progress.courseGrade.partialpreview.body.unlockCertificate": "Déverrouillez pour travailler en vue d'une attestation.", "progress.courseGrade.partialpreview.body.unlockCertificate": "Unlock to work towards a certificate.",
"progress.courseGrade.preview.body.upgradeDeadlinePassed": "La date limite de mise à niveau dans ce cours est écoulée.", "progress.courseGrade.preview.body.upgradeDeadlinePassed": "The deadline to upgrade in this course has passed.",
"progress.courseGrade.preview.button.upgrade": "Mettre à jour dès maintenant", "progress.courseGrade.preview.button.upgrade": "Upgrade now",
"progress.courseGrade.gradeRange.tooltip": "Plage de notes pour ce cours :", "progress.courseGrade.gradeRange.tooltip": "Grade ranges for this course:",
"progress.courseOutline": "Plan du Cours", "progress.courseOutline": "Course Outline",
"progress.courseGrade.label.currentGrade": "Votre note actuelle", "progress.courseGrade.label.currentGrade": "Your current grade",
"progress.detailedGrades": "Notes détaillées", "progress.detailedGrades": "Detailed grades",
"progress.detailedGrades.emptyTable": "Vous n'avez actuellement aucun score de problème noté.", "progress.detailedGrades.emptyTable": "You currently have no graded problem scores.",
"progress.footnotes.title": "Notes de bas de page du résumé des notes", "progress.footnotes.title": "Grade summary footnotes",
"progress.gradeSummary.grade": "Note", "progress.gradeSummary.grade": "Grade",
"progress.courseGrade.grades": "Notes", "progress.courseGrade.grades": "Grades",
"progress.courseGrade.gradeRange.Tooltip": "Info-bulle de plage de notes", "progress.courseGrade.gradeRange.Tooltip": "Grade range tooltip",
"progress.gradeSummary": "Relevé de notes", "progress.gradeSummary": "Grade summary",
"progress.gradeSummary.limitedAccessExplanation": "Vous avez un accès limité aux devoirs notés dans le cadre du parcours audit de ce cours.", "progress.gradeSummary.limitedAccessExplanation": "You have limited access to graded assignments as part of the audit track in this course.",
"progress.gradeSummary.tooltip.alt": "Info-bulle des résumés de notes", "progress.gradeSummary.tooltip.alt": "Grade summary tooltip",
"progress.gradeSummary.tooltip.body": "La pondération de ce travail est déterminé par votre instructeur. En multipliant votre note par la pondération du travail, une note pondérée est calculée. Cette note pondérée servira à déterminer si vous réussissez le cours.", "progress.gradeSummary.tooltip.body": "Your course assignment's weight is determined by your instructor. By multiplying your grade by the weight for that assignment type, your weighted grade is calculated. Your weighted grade is what's used to determine if you pass the course.",
"progress.courseGrade.label.passingGrade": "Note de passage", "progress.courseGrade.label.passingGrade": "Passing grade",
"progress.detailedGrades.problemScore.label": "Score aux exercices : ", "progress.detailedGrades.problemScore.label": "Problem Scores:",
"progress.detailedGrades.problemScore.toggleButton": "Basculer les scores des problèmes individuels pour {subsectionTitle}", "progress.detailedGrades.problemScore.toggleButton": "Toggle individual problem scores for {subsectionTitle}",
"progress.score": "Note", "progress.score": "Score",
"progress.weight": "Pondération", "progress.weight": "Weight",
"progress.weightedGrade": "Note pondérée", "progress.weightedGrade": "Weighted grade",
"progress.weightedGradeSummary": "Votre résumé de note pondéré actuel", "progress.weightedGradeSummary": "Your current weighted grade summary",
"progress.noAcessToAssignmentType": "Vous n'avez pas accès aux devoirs de type {assignmentType}", "progress.noAcessToAssignmentType": "You do not have access to assignments of type {assignmentType}",
"progress.noAcessToSubsection": "Vous n'avez pas accès à la sous-section {displayName}", "progress.noAcessToSubsection": "You do not have access to subsection {displayName}",
"progress.header": "Votre progression", "progress.header": "Your progress",
"progress.header.targetUser": "Progression pour {username}", "progress.header.targetUser": "Course progress for {username}",
"progress.link.studio": "Voir la notation dans Studio", "progress.link.studio": "View grading in Studio",
"progress.relatedLinks.datesCard.description": "Une vue du calendrier des dates d'échéance de vos cours et des devoirs à venir.", "progress.relatedLinks.datesCard.description": "A schedule view of your course due dates and upcoming assignments.",
"progress.relatedLinks.datesCard.link": "Dates", "progress.relatedLinks.datesCard.link": "Dates",
"progress.relatedLinks.outlineCard.description": "Une vue d'ensemble du contenu de votre cours.", "progress.relatedLinks.outlineCard.description": "A birds-eye view of your course content.",
"progress.relatedLinks.outlineCard.link": "Plan du Cours", "progress.relatedLinks.outlineCard.link": "Course Outline",
"progress.relatedLinks": "Liens connexes", "progress.relatedLinks": "Related links",
"datesBanner.suggestedSchedule": "Nous avons établi un calendrier suggéré pour vous aider à rester sur la bonne voie. Mais ne vous inquiétez pas—il est flexible et vous permet d'apprendre à votre rythme.", "datesBanner.suggestedSchedule": "Weve built a suggested schedule to help you stay on track. But dont worry—its flexible so you can learn at your own pace.",
"datesBanner.upgradeToCompleteGradedBanner.header": "Upgrade to unlock", "datesBanner.upgradeToCompleteGradedBanner.header": "Upgrade to unlock",
"datesBanner.upgradeToCompleteGradedBanner.body": "Vous auditez ce cours, ce qui signifie que vous ne pouvez pas participer aux devoirs notés. Pour terminer les devoirs notés dans le cadre de ce cours, vous pouvez mettre à niveau dès aujourd'hui.", "datesBanner.upgradeToCompleteGradedBanner.body": "You are auditing this course, which means that you are unable to participate in graded assignments. To complete graded assignments as part of this course, you can upgrade today.",
"datesBanner.upgradeToCompleteGradedBanner.button": "Mettre à jour dès maintenant", "datesBanner.upgradeToCompleteGradedBanner.button": "Upgrade now",
"datesBanner.upgradeToResetBanner.body": "To keep yourself on track, you can update this schedule and shift the past due assignments into the future. Dont worry—you wont lose any of the progress youve made when you shift your due dates.", "datesBanner.upgradeToResetBanner.body": "To keep yourself on track, you can update this schedule and shift the past due assignments into the future. Dont worry—you wont lose any of the progress youve made when you shift your due dates.",
"datesBanner.upgradeToResetBanner.button": "Réviser votre type d'inscription pour déplacer les dates limites", "datesBanner.upgradeToResetBanner.button": "Upgrade to shift due dates",
"datesBanner.resetDatesBanner.header": "Il semble que vous ayez manqué des dates limites importantes en fonction de notre calendrier suggéré.", "datesBanner.resetDatesBanner.header": "It looks like you missed some important deadlines based on our suggested schedule.",
"datesBanner.resetDatesBanner.body": "To keep yourself on track, you can update this schedule and shift the past due assignments into the future. Dont worry—you wont lose any of the progress youve made when you shift your due dates.", "datesBanner.resetDatesBanner.body": "To keep yourself on track, you can update this schedule and shift the past due assignments into the future. Dont worry—you wont lose any of the progress youve made when you shift your due dates.",
"datesBanner.resetDatesBanner.button": "Déplacer les dates limites", "datesBanner.resetDatesBanner.button": "Shift due dates",
"unit.bookmark.button.add.bookmark": "Ajouter cette page aux favoris", "unit.bookmark.button.add.bookmark": "Bookmark this page",
"unit.bookmark.button.remove.bookmark": "Ajouté aux favoris", "unit.bookmark.button.remove.bookmark": "Bookmarked",
"learning.celebration.completed": "Vous avez complété la première section de votre cours.", "learning.celebration.completed": "You just completed the first section of your course.",
"learning.celebration.congrats": "Félicitations !", "learning.celebration.congrats": "Congratulations!",
"learning.celebration.earned": "Vous l'avez mérité!", "learning.celebration.earned": "You earned it!",
"learning.celebration.emailSubject": "Je complèterai bientôt {title} en ligne avec {platform}!", "learning.celebration.emailSubject": "I'm on my way to completing {title} online with {platform}!",
"learning.celebration.forward": "Continuer", "learning.celebration.forward": "Keep going",
"learning.celebration.share": "Prenez un moment pour célébrer et partager votre progrès.", "learning.celebration.share": "Take a moment to celebrate and share your progress.",
"learning.celebration.social": "Je suis sur le point de terminer {title} en ligne avec {platform}. Que passez-vous votre temps à apprendre?", "learning.celebration.social": "Im on my way to completing {title} online with {platform}. What are you spending your time learning?",
"calculator.instructions.button.label": "Instructions de la calculatrice", "calculator.instructions.button.label": "Calculator Instructions",
"calculator.instructions": "Pour plus d'informations, consultez le {expressions_link}.", "calculator.instructions": "For detailed information, see the {expressions_link}.",
"calculator.instructions.support.title": "Centre d'aide", "calculator.instructions.support.title": "Help Center",
"calculator.instructions.useful.tips": "Conseils utiles:", "calculator.instructions.useful.tips": "Useful tips:",
"calculator.hint1": "Utilisez les parenthèses () pour clarifier vos expressions. Vous pouvez utiliser des parenthèses au sein d'autres parenthèses.", "calculator.hint1": "Use parentheses () to make expressions clear. You can use parentheses inside other parentheses.",
"calculator.hint2": "Ne pas utiliser d'espaces dans ces expressions.", "calculator.hint2": "Do not use spaces in expressions.",
"calculator.hint3": "Pour les constantes, indiquer explicitement la multiplication (par exemple: 5*c).", "calculator.hint3": "For constants, indicate multiplication explicitly (example: 5*c).",
"calculator.hint4": "Pour les suffixes, indiquer le nombre et le suffixe sans espace (exemple : 5c).", "calculator.hint4": "For affixes, type the number and affix without a space (example: 5c).",
"calculator.hint5": "Pour les fonctions, taper le nom de la fonction, puis l'expression entre parenthèses.", "calculator.hint5": "For functions, type the name of the function, then the expression in parentheses.",
"calculator.instruction.table.to.use.heading": "À utiliser", "calculator.instruction.table.to.use.heading": "To Use",
"calculator.instruction.table.type.heading": "Type", "calculator.instruction.table.type.heading": "Type",
"calculator.instruction.table.examples.heading": "Exemples", "calculator.instruction.table.examples.heading": "Examples",
"calculator.instruction.table.to.use.numbers": "Nombres", "calculator.instruction.table.to.use.numbers": "Numbers",
"calculator.instruction.table.to.use.numbers.type1": "Nombres entiers", "calculator.instruction.table.to.use.numbers.type1": "Integers",
"calculator.instruction.table.to.use.numbers.type2": "Fractions", "calculator.instruction.table.to.use.numbers.type2": "Fractions",
"calculator.instruction.table.to.use.numbers.type3": "Nombres décimaux", "calculator.instruction.table.to.use.numbers.type3": "Decimals",
"calculator.instruction.table.to.use.operators": "Opérateurs", "calculator.instruction.table.to.use.operators": "Operators",
"calculator.instruction.table.to.use.operators.type1": "(additionner, soustraire, multiplier, diviser)", "calculator.instruction.table.to.use.operators.type1": "(add, subtract, multiply, divide)",
"calculator.instruction.table.to.use.operators.type2": "(élever à une puissance)", "calculator.instruction.table.to.use.operators.type2": "(raise to a power)",
"calculator.instruction.table.to.use.operators.type3": "(résistances parallèles)", "calculator.instruction.table.to.use.operators.type3": "(parallel resistors)",
"calculator.instruction.table.to.use.constants": "Constantes", "calculator.instruction.table.to.use.constants": "Constants",
"calculator.instruction.table.to.use.affixes": "Affixes", "calculator.instruction.table.to.use.affixes": "Affixes",
"calculator.instruction.table.to.use.affixes.type": "Pourcentage (%) et suffixes métriques ({affixes})", "calculator.instruction.table.to.use.affixes.type": "Percent sign (%) and metric affixes ({affixes})",
"calculator.instruction.table.to.use.basic.functions": "Fonctions de base", "calculator.instruction.table.to.use.basic.functions": "Basic functions",
"calculator.instruction.table.to.use.trig.functions": "Fonctions trigonométriques", "calculator.instruction.table.to.use.trig.functions": "Trigonometric functions",
"calculator.instruction.table.to.use.scientific.notation": "Notation scientifique", "calculator.instruction.table.to.use.scientific.notation": "Scientific notation",
"calculator.instruction.table.to.use.scientific.notation.type1": "{exponentSyntax} et l'exposant", "calculator.instruction.table.to.use.scientific.notation.type1": "{exponentSyntax} and the exponent",
"calculator.instruction.table.to.use.scientific.notation.type2": "notation {notationSyntax}", "calculator.instruction.table.to.use.scientific.notation.type2": "{notationSyntax} notation",
"calculator.instruction.table.to.use.scientific.notation.type3": "{notationSyntax} et l'exposant", "calculator.instruction.table.to.use.scientific.notation.type3": "{notationSyntax} and the exponent",
"calculator.button.label": "Calculatrice", "calculator.button.label": "Calculator",
"calculator.input.field.label": "Sasie Calculatrice", "calculator.input.field.label": "Calculator Input",
"calculator.submit.button.label": "Calculer", "calculator.submit.button.label": "Calculate",
"calculator.result.field.label": "Résultat de la calculatrice", "calculator.result.field.label": "Calculator Result",
"calculator.result.field.placeholder": "Résultat", "calculator.result.field.placeholder": "Result",
"notes.button.show": "Afficher les notes", "notes.button.show": "Show Notes",
"notes.button.hide": "Masquer les notes", "notes.button.hide": "Hide Notes",
"courseExit.catalogSearchSuggestion": "Vous souhaitez en apprendre plus? {searchOurCatalogLink} pour trouver plus de cours et de programmes à explorer.", "courseExit.catalogSearchSuggestion": "Looking to learn more? {searchOurCatalogLink} to find more courses and programs to explore.",
"courseCelebration.certificateBody.available": "\n Affichez vos accomplissements sur LinkedIn ou votre CV dès aujourd'hui.\n Vous pouvez télécharger votre attestation maintenant et y accéder à tout moment depuis vos\n {dashboardLink} et {profileLink}.", "courseCelebration.certificateBody.available": "\n Showcase your accomplishment on LinkedIn or your resumé today.\n You can download your certificate now and access it any time from your\n {dashboardLink} and {profileLink}.",
"courseCelebration.certificateBody.unverified": "Afin de générer une attestation, vous devez effectuer une vérification d'identité.\n {idVerificationSupportLink} maintenant.", "courseCelebration.certificateBody.unverified": "In order to generate a certificate, you must complete ID verification.\n {idVerificationSupportLink} now.",
"courseCelebration.certificateBody.upgradable": "Il nest pas trop tard pour effectuer une mise à niveau. Pour {price}, vous débloquerez l'accès à tous les\n devoirs dans ce cours. À la fin, vous recevrez une attestation qui est une source\n d'informations précieuses pour améliorer vos perspectives d'emploi et faire progresser votre carrière, ou mettre en valeur votre\n attestation dans des demandes d'admission.", "courseCelebration.certificateBody.upgradable": "Its not too late to upgrade. For {price} you will unlock access to all graded\n assignments in this course. Upon completion, you will receive a verified certificate which is a\n valuable credential to improve your job prospects and advance your career, or highlight your\n certificate in school applications.",
"courseCelebration.upgradeDiscountCodePrompt": "Utilisez le code {code} lors du paiement pour {percent}% de réduction!", "courseCelebration.upgradeDiscountCodePrompt": "Use code {code} at checkout for {percent}% off!",
"courseCelebration.recommendations.heading": "Continuez à développer vos compétences avec ces cours!", "courseCelebration.recommendations.heading": "Keep building your skills with these courses!",
"courseCelebration.recommendations.formatting.list_join": "{style, select, punctuation {, } conjunction { {sp}and } other { }}", "courseCelebration.recommendations.formatting.list_join": "{style, select, punctuation {, } conjunction { {sp}and } other { }}",
"courseCelebration.recommendations.browse_catalog": "Explorez plus de cours", "courseCelebration.recommendations.browse_catalog": "Explore more courses",
"courseCelebration.recommendations.loading_recommendations": "Chargement des recommandations", "courseCelebration.recommendations.loading_recommendations": "Loading recommendations",
"courseCelebration.recommendations.card.schools.label": "Écoles et Partenaires", "courseCelebration.recommendations.card.schools.label": "Schools and Partners",
"courseCelebration.recommendations.label": "Cours", "courseCelebration.recommendations.label": "Course",
"courseCelebration.dashboardInfo": "Vous pouvez accéder à ce cours et à ses supports sur votre {dashboardLink}.", "courseCelebration.dashboardInfo": "You can access this course and its materials on your {dashboardLink}.",
"courseExit.programs.applyForCredit": "Demander un crédit", "courseExit.programs.applyForCredit": "Apply for credit",
"courseCelebration.certificateHeader.downloadable": "Votre attestation est disponible!", "courseCelebration.certificateHeader.downloadable": "Your certificate is available!",
"courseCelebration.certificateHeader.notAvailable": "Votre note et votre attestation seront bientôt prêtes !", "courseCelebration.certificateHeader.notAvailable": "Your grade and certificate will be ready soon!",
"courseCelebration.certificateBody.notAvailable.accessCertificate": "Si vous avez obtenu une note de passage, votre attestation sera automatiquement générée.", "courseCelebration.certificateBody.notAvailable.accessCertificate": "If you have earned a passing grade, your certificate will be automatically issued.",
"courseCelebration.certificateHeader.unverified": "Vous devez avoir complété votre vérification pour recevoir votre attestation.", "courseCelebration.certificateHeader.unverified": "You must complete verification to receive your certificate.",
"courseCelebration.certificateHeader.requestable": "Félicitations, vous avez terminé le processus pour passer un certificat !", "courseCelebration.certificateHeader.requestable": "Congratulations, you qualified for a certificate!",
"courseCelebration.certificateHeader.upgradable": "Mettre à niveau pour obtenir une attestation", "courseCelebration.certificateHeader.upgradable": "Upgrade to pursue a verified certificate",
"courseCelebration.certificateImage": "Exemple d'attestation", "courseCelebration.certificateImage": "Sample certificate",
"courseCelebration.completedCourseHeader": "Vous avez complété ce cours.", "courseCelebration.completedCourseHeader": "You have completed your course.",
"courseCelebration.congratulationsHeader": "Félicitations !", "courseCelebration.congratulationsHeader": "Congratulations!",
"courseCelebration.congratulationsImage": "Quatre personnes levant leurs mains pour célébrer", "courseCelebration.congratulationsImage": "Four people raising their hands in celebration",
"courseExit.courseInProgressDescription": "Il semble qu'il y ait plus de contenu dans ce cours qui sera publié dans le futur. Attendez les mises à jour par courriel ou revenez sur votre cours pour savoir quand ce contenu sera disponible.", "courseExit.courseInProgressDescription": "It looks like there is more content in this course that will be released in the future. Look out for email updates or check back on your course for when this content will be available.",
"courseExit.courseInProgressHeader": "Plus de contenu sera bientôt disponible!", "courseExit.courseInProgressHeader": "More content is coming soon!",
"courseExit.dashboardLink": "Tableau de bord", "courseExit.dashboardLink": "Dashboard",
"courseCelebration.downloadButton": "Téléchargez mon attestation", "courseCelebration.downloadButton": "Download my certificate",
"courseExit.endOfCourseDescription": "Malheureusement, vous n'êtes actuellement pas éligible pour une attestatation. Vous devez recevoir une note de passage pour être admissible à une attestation.", "courseExit.endOfCourseDescription": "Unfortunately, you are not currently eligible for a certificate. You need to receive a passing grade to be eligible for a certificate.",
"courseExit.endOfCourseHeader": "Vous avez atteint la fin du cours!", "courseExit.endOfCourseHeader": "Youve reached the end of the course!",
"courseExit.endOfCourseTitle": "Fin du cours", "courseExit.endOfCourseTitle": "End of Course",
"courseExit.idVerificationSupportLink": "En savoir plus sur la vérification d'identité", "courseExit.idVerificationSupportLink": "Learn more about ID verification",
"courseCelebration.linkedinAddToProfileButton": "Ajouter au profil LinkedIn", "courseCelebration.linkedinAddToProfileButton": "Add to LinkedIn profile",
"courseExit.programs.microBachelors.learnMore": "Apprenez-en davantage sur la façon dont votre accréditation MicroBachelors peut être utilisée pour demander un crédit.", "courseExit.programs.microBachelors.learnMore": "Learn more about how your MicroBachelors credential can be applied for credit.",
"courseExit.programs.microMasters.learnMore": "En savoir plus sur le processus dapplication des attestations MicroMasters aux diplômes de maîtrise.", "courseExit.programs.microMasters.learnMore": "Learn more about the process of applying MicroMasters certificates to Masters degrees.",
"courseExit.programs.microMasters.mastersMessage": "Si vous souhaitez utiliser votre attestation MicroMasters en vue d'un programme de maîtrise, vous pouvez commencer dès aujourd'hui!", "courseExit.programs.microMasters.mastersMessage": "If youre interested in using your MicroMasters certificate towards a Masters program, you can get started today!",
"learn.sequence.navigation.complete.button": "Compléter le cours", "learn.sequence.navigation.complete.button": "Complete the course",
"courseExit.nextButton.endOfCourse": "Suivant (fin du cours)", "courseExit.nextButton.endOfCourse": "Next (end of course)",
"courseExit.profileLink": "Profil", "courseExit.profileLink": "Profile",
"courseExit.programs.lastCourse": "Vous avez terminé le dernier cours de {title}!", "courseExit.programs.lastCourse": "You have completed the last course in {title}!",
"courseCelebration.requestCertificateBodyText": "Pour accéder à votre certificat, demandez-le ci-dessous.", "courseCelebration.requestCertificateBodyText": "In order to access your certificate, request it below.",
"courseCelebration.requestCertificateButton": "Demander une attestation", "courseCelebration.requestCertificateButton": "Request certificate",
"courseExit.searchOurCatalogLink": "Rechercher dans notre catalogue", "courseExit.searchOurCatalogLink": "Search our catalog",
"courseCelebration.shareMessage": "Partagez votre succès sur les réseaux sociaux ou par courriel.", "courseCelebration.shareMessage": "Share your success on social media or email.",
"courseExit.social.shareCompletionMessage": "Je viens de terminer {title} avec {platform}!", "courseExit.social.shareCompletionMessage": "I just completed {title} with {platform}!",
"courseExit.upgradeButton": "Mettre à jour dès maintenant", "courseExit.upgradeButton": "Upgrade now",
"courseExit.upgradeLink": "mettre à jour maintenant", "courseExit.upgradeLink": "upgrade now",
"courseCelebration.verificationPending": "La vérification de votre identité est en attente et votre attestation sera disponible une fois approuvé.", "courseCelebration.verificationPending": "Your ID verification is pending and your certificate will be available once approved.",
"courseExit.verifiedCertificateSupportLink": "En savoir plus sur les attestations", "courseExit.verifiedCertificateSupportLink": "Learn more about verified certificates",
"courseCelebration.verifyIdentityButton": "Vérifiez votre identité maintenant", "courseCelebration.verifyIdentityButton": "Verify ID now",
"courseCelebration.viewCertificateButton": "Voir mon attestation", "courseCelebration.viewCertificateButton": "View my certificate",
"courseExit.viewCourseScheduleButton": "Voir le calendrier de cours", "courseExit.viewCourseScheduleButton": "View course schedule",
"courseExit.viewCoursesButton": "Voir mes cours", "courseExit.viewCoursesButton": "View my courses",
"courseExit.viewGradesButton": "Voir les notes", "courseExit.viewGradesButton": "View grades",
"courseExit.programCompletion.dashboardMessage": "Pour afficher l'état de votre attestation, consultez la section Programmes de votre {programLink}.", "courseExit.programCompletion.dashboardMessage": "To view your certificate status, check the Programs section of your {programLink}.",
"courseExit.upgradeFootnote": "L'accès à ce cours et à ses supports est disponible sur votre tableau de bord jusqu'au {expirationDate}. Pour étendre l'accès, {upgradeLink}.", "courseExit.upgradeFootnote": "Access to this course and its materials are available on your dashboard until {expirationDate}. To extend access, {upgradeLink}.",
"learn.course.license.allRightsReserved.text": "Tous droits servés", "learn.course.license.allRightsReserved.text": "All Rights Reserved",
"learn.course.license.creativeCommons.terms.preamble": "Contenu sous license Creative Commons, avec les conditions suivantes:", "learn.course.license.creativeCommons.terms.preamble": "Creative Commons licensed content, with terms as follows:",
"learn.course.license.creativeCommons.terms.by": "Crédit", "learn.course.license.creativeCommons.terms.by": "Attribution",
"learn.course.license.creativeCommons.terms.nc": "Non commercial", "learn.course.license.creativeCommons.terms.nc": "Noncommercial",
"learn.course.license.creativeCommons.terms.nd": "Pas de travaux dérivés", "learn.course.license.creativeCommons.terms.nd": "No Derivatives",
"learn.course.license.creativeCommons.terms.sa": "Partage à l'identique", "learn.course.license.creativeCommons.terms.sa": "Share Alike",
"learn.course.license.creativeCommons.terms.zero": "Aucun termes", "learn.course.license.creativeCommons.terms.zero": "No terms",
"learn.course.license.creativeCommons.text": "Quelques droits servés", "learn.course.license.creativeCommons.text": "Some Rights Reserved",
"learn.breadcrumb.navigation.course.home": "Cours", "learn.breadcrumb.navigation.course.home": "Course",
"notification.tray.container": "Barre de notification", "notification.tray.container": "Notification tray",
"notification.open.button": "Afficher la barre de notification", "notification.open.button": "Show notification tray",
"notification.close.button": "Fermer la barre de notification", "notification.close.button": "Close notification tray",
"responsive.close.notification": "Retour au cours", "responsive.close.notification": "Back to course",
"notification.tray.title": "Notifications", "notification.tray.title": "Notifications",
"notification.tray.no.message": "Vous n'avez aucune nouvelle notification pour le moment.", "notification.tray.no.message": "You have no new notifications at this time.",
"learn.contentLock.content.locked": "Contenu vérouillé", "learn.contentLock.content.locked": "Content Locked",
"learn.contentLock.complete.prerequisite": "Vous devez compléter le prérequis: '{prereqSectionName}' pour accéder à ce contenu.", "learn.contentLock.complete.prerequisite": "You must complete the prerequisite: '{prereqSectionName}' to access this content.",
"learn.contentLock.goToSection": "Aller à la section des prérequis", "learn.contentLock.goToSection": "Go To Prerequisite Section",
"learn.hiddenAfterDue.gradeAvailable": "Si vous avez complété ce travail, votre note est disponible sur {progressPage}.", "learn.hiddenAfterDue.gradeAvailable": "If you have completed this assignment, your grade is available on the {progressPage}.",
"learn.hiddenAfterDue.header": "La date d'échéance de ce devoir est passée.", "learn.hiddenAfterDue.header": "The due date for this assignment has passed.",
"learn.hiddenAfterDue.description": "Ce devoir n'est plus disponible, car la date limite est passée.", "learn.hiddenAfterDue.description": "Because the due date has passed, this assignment is no longer available.",
"learn.hiddenAfterDue.progressPage": "page de progression", "learn.hiddenAfterDue.progressPage": "progress page",
"learn.honorCode.content": "L'honnêteté et l'intégrité académique sont importantes pour {siteName} et les institutions offrant des cours et des programmes sur le site {siteName}. En cliquant sur « J'accepte » ci-dessous, je confirme que j'ai lu, compris et respecterai le {link} pour le site {siteName}.", "learn.honorCode.content": "Honesty and academic integrity are important to {siteName} and the institutions providing courses and programs on the {siteName} site. By clicking “I agree” below, I confirm that I have read, understand, and will abide by the {link} for the {siteName} Site.",
"learn.honorCode.name": "Code d'honneur", "learn.honorCode.name": "Honor Code",
"learn.honorCode.cancel": "Annuler", "learn.honorCode.cancel": "Cancel",
"learn.honorCode.agree": "Je suis d'accord", "learn.honorCode.agree": "I agree",
"gatedContent.paragraph.bulletOne": "Obtenez un {verifiedCertLink} d'achèvement pour le mettre en valeur sur votre CV", "gatedContent.paragraph.bulletOne": "Earn a {verifiedCertLink} of completion to showcase on your resumé",
"gatedContent.paragraph.bulletTwo": "Déverrouillez l'accès à toutes les activités du cours, y compris {gradedAssignments}", "gatedContent.paragraph.bulletTwo": "Unlock access to all course activities, including {gradedAssignments}",
"gatedContent.paragraph.bulletThree": "{fullAccess} au contenu et aux supports du cours, même après la fin du cours", "gatedContent.paragraph.bulletThree": "{fullAccess} to course content and materials, even after the course ends",
"gatedContent.paragraph.bulletFour": "Soutenez notre {nonProfitMission} sur edX", "gatedContent.paragraph.bulletFour": "Support our {nonProfitMission} at edX",
"learn.lockPaywall.title": "Les devoirs notés sont verrouillés", "learn.lockPaywall.title": "Graded assignments are locked",
"learn.lockPaywall.content": "Mettez à niveau pour accéder à des fonctionnalités verrouillées comme celle-ci et tirer le meilleur parti de votre cours.", "learn.lockPaywall.content": "Upgrade to gain access to locked features like this one and get the most out of your course.",
"learn.lockPaywall.example.alt": "Exemple d'attestation", "learn.lockPaywall.example.alt": "Example Certificate",
"learn.lockPaywall.list.intro": "Lorsque vous effectuez une mise à niveau, vous :", "learn.lockPaywall.list.intro": "When you upgrade, you:",
"learn.lockPaywall.list.bullet1.linktext": "attestation vérifiée", "learn.lockPaywall.list.bullet1.linktext": "verified certificate",
"learn.lockPaywall.list.bullet2.boldtext": "évaluations notées", "learn.lockPaywall.list.bullet2.boldtext": "graded assignments",
"learn.lockPaywall.list.bullet3.boldtext": "Accès complet", "learn.lockPaywall.list.bullet3.boldtext": "Full access",
"learn.lockPaywall.list.bullet4.boldtext": "mission à but non lucratif", "learn.lockPaywall.list.bullet4.boldtext": "non-profit mission",
"learn.loading.content.lock": "Chargement du contenu bloqué de messagerie...", "learn.loading.content.lock": "Loading locked content messaging...",
"learn.loading.honor.codk": "Chargement de la messagerie du code d'honneur...", "learn.loading.honor.codk": "Loading honor code messaging...",
"learn.loading.learning.sequence": "Chargement de la séquence d'apprentissage...", "learn.loading.learning.sequence": "Loading learning sequence...",
"learn.course.load.failure": "Il y a eu une erreur lors du chargement de ce cours.", "learn.course.load.failure": "There was an error loading this course.",
"learn.sequence.no.content": "Il n'y a pas de contenu ici.", "learn.sequence.no.content": "There is no content here.",
"learn.sequence.navigation.next.button": "Suivant", "learn.sequence.navigation.next.button": "Next",
"learn.sequence.navigation.next.up.button": "Prochaine étape : {title}", "learn.sequence.navigation.next.up.button": "Next Up: {title}",
"learn.sequence.navigation.previous.button": "Précédent", "learn.sequence.navigation.previous.button": "Previous",
"learn.course.sequence.navigation.mobile.menu": "{current} de {total}", "learn.course.sequence.navigation.mobile.menu": "{current} of {total}",
"learn.redirect.interstitial.message": "Redirection...", "learn.redirect.interstitial.message": "Redirecting...",
"learn.loading.error": "Erreur : {error}", "learn.loading.error": "Error: {error}",
"learning.celebration.emailBody": "Qu'apprenez-vous durant votre temps libre?", "learning.celebration.emailBody": "What are you spending your time learning?",
"learning.social.shareEmail": "Partagez vos progrès par courriel.", "learning.social.shareEmail": "Share your progress via email.",
"learning.social.shareService": "Partagez vos progrès sur {service}.", "learning.social.shareService": "Share your progress on {service}.",
"general.altText.close": "Fermer", "general.altText.close": "Close",
"learning.logistration.register": "inscription", "learning.logistration.register": "register",
"general.register.sentenceCase": "S'inscrire", "general.register.sentenceCase": "Register",
"learning.logistration.login": "connexion", "learning.logistration.login": "sign in",
"general.signIn.sentenceCase": "Connectez-vous", "general.signIn.sentenceCase": "Sign in",
"learn.course.tabs.navigation.overflow.menu": "Plus...", "learn.course.tabs.navigation.overflow.menu": "More...",
"learning.offer.screenReaderPrices": "Prix d'origine: {originalPrice}, prix réduit : {discountedPrice}", "learning.offer.screenReaderPrices": "Original price: {originalPrice}, discount price: {discountedPrice}",
"learning.upgradeButton.screenReaderInlinePrices": "Prix d'origine : {originalPrice}", "learning.upgradeButton.screenReaderInlinePrices": "Original price: {originalPrice}",
"learning.upgradeButton.buttonText": "Mise à niveau pour {pricing}", "learning.upgradeButton.buttonText": "Upgrade for {pricing}",
"learning.upgradeNowButton.buttonText": "Mettez à niveau maintenant pour {pricing}", "learning.upgradeNowButton.buttonText": "Upgrade now for {pricing}",
"learning.generic.upgradeNotification.verifiedCertLink": "attestation vérifiée", "learning.generic.upgradeNotification.verifiedCertLink": "verified certificate",
"learning.generic.upgradeNotification.verifiedCertMessage": "Obtenez un {verifiedCertLink} d'achèvement pour le mettre en valeur sur votre CV", "learning.generic.upgradeNotification.verifiedCertMessage": "Earn a {verifiedCertLink} of completion to showcase on your resumé",
"learning.generic.upgradeNotification.noFBE.nonProfitMission": "Soutenez notre {nonProfitMission} sur edX", "learning.generic.upgradeNotification.noFBE.nonProfitMission": "Support our {nonProfitMission} at edX",
"learning.generic.upgradeNotification.gradedAssignments": "évaluations notées", "learning.generic.upgradeNotification.gradedAssignments": "graded assignments",
"learning.generic.upgradeNotification.verifiedCertLink.fullAccess": "Accès complet", "learning.generic.upgradeNotification.verifiedCertLink.fullAccess": "Full access",
"learning.generic.upgradeNotification.FBE.nonProfitMission": "mission à but non lucratif", "learning.generic.upgradeNotification.FBE.nonProfitMission": "non-profit mission",
"learning.generic.upgradeNotification.unlockGraded": "Déverrouillez l'accès à toutes les activités du cours, y compris {gradedAssignments}", "learning.generic.upgradeNotification.unlockGraded": "Unlock your access to all course activities, including {gradedAssignments}",
"learning.generic.upgradeNotification.fullAccess": "{fullAccess} au contenu et aux supports du cours, même après la fin du cours", "learning.generic.upgradeNotification.fullAccess": "{fullAccess} to course content and materials, even after the course ends",
"learning.generic.upgradeNotification.nonProfitMission": "Soutenez notre {nonProfitMission} sur edX", "learning.generic.upgradeNotification.nonProfitMission": "Support our {nonProfitMission} at edX",
"learning.generic.upgradeNotification.expirationAccessLoss.progress": "incluant tous les progrès", "learning.generic.upgradeNotification.expirationAccessLoss.progress": "including any progress",
"learning.generic.upgradeNotification.expirationVerifiedCert.benefits": "bénéfices d'une mise à niveau", "learning.generic.upgradeNotification.expirationVerifiedCert.benefits": "benefits of upgrading",
"learning.generic.upgradeNotification.expirationAccessLoss": "Vous perdez tout accès à ce cours, {includingAnyProgress}, le {date}.", "learning.generic.upgradeNotification.expirationAccessLoss": "You will lose all access to this course, {includingAnyProgress}, on {date}.",
"learning.generic.upgradeNotification.expirationVerifiedCert": "Mettre à niveau votre cours vous permettra de tenter d'obtenir une attestation vérifié et d'avoir accès à beaucoup d'autres fonctionnalités. Apprenez en plus à propos des {benefitsOfUpgrading}.", "learning.generic.upgradeNotification.expirationVerifiedCert": "Upgrading your course enables you to pursue a verified certificate and unlocks numerous features. Learn more about the {benefitsOfUpgrading}.",
"learning.generic.upgradeNotification.expirationDays": "{dayCount, number} {dayCount, plural, \n one {day}\n other {days}} restant", "learning.generic.upgradeNotification.expirationDays": "{dayCount, number} {dayCount, plural, \n one {day}\n other {days}} left",
"learning.generic.upgradeNotification.expirationHours": "{hourCount, number} {hourCount, plural,\n one {hour}\n other {hours}} restant", "learning.generic.upgradeNotification.expirationHours": "{hourCount, number} {hourCount, plural,\n one {hour}\n other {hours}} left",
"learning.generic.upgradeNotification.expirationMinutes": "Il reste moins de 1 heure", "learning.generic.upgradeNotification.expirationMinutes": "Less than 1 hour left",
"learning.generic.upgradeNotification.expiration": "L'accès au cours expirera le {date}", "learning.generic.upgradeNotification.expiration": "Course access will expire {date}",
"learning.generic.upgradeNotification.firstTimeLearnerDiscount": "{percentage}% de rabais pour les nouveaux apprenants", "learning.generic.upgradeNotification.firstTimeLearnerDiscount": "{percentage}% First-Time Learner Discount",
"learning.generic.upgradeNotification.accessExpiration": "Mettre à niveau votre cours aujourd'hui", "learning.generic.upgradeNotification.accessExpiration": "Upgrade your course today",
"learning.generic.upgradeNotification.accessExpirationUrgent": "L'accès au cours expire", "learning.generic.upgradeNotification.accessExpirationUrgent": "Course Access Expiration",
"learning.generic.upgradeNotification.pursueAverifiedCertificate": "Obtenir un certificat vérifié", "learning.generic.upgradeNotification.pursueAverifiedCertificate": "Pursue a verified certificate",
"learning.generic.upgradeNotification.code": "Utilisez le code {code} lors du paiement", "learning.generic.upgradeNotification.code": "Use code {code} at checkout",
"masquerade-widget.userName.error.generic": "Une erreur est survenue; veuillez réessayer.", "masquerade-widget.userName.error.generic": "An error has occurred; please try again.",
"masquerade-widget.userName.input.placeholder": "Nom d'utilisateur ou courriel", "masquerade-widget.userName.input.placeholder": "Username or email",
"masquerade-widget.userName.input.label": "Se faire passer pour cet utilisateur", "masquerade-widget.userName.input.label": "Masquerade as this user",
"learning.effortEstimation.combinedEstimate": "{minutes} + {activities}", "learning.effortEstimation.combinedEstimate": "{minutes} + {activities}",
"learning.effortEstimation.activities": "{activityCount, plural, one {# activité} other {# activités}}", "learning.effortEstimation.activities": "{activityCount, plural, one {# activity} other {# activities}}",
"learning.effortEstimation.minutesAbbreviated": "{minuteCount, plural, one {# min} other {# min}}", "learning.effortEstimation.minutesAbbreviated": "{minuteCount, plural, one {# min} other {# min}}",
"learning.effortEstimation.minutesFull": "{minuteCount, plural, one {# minute} other {# minutes}}", "learning.effortEstimation.minutesFull": "{minuteCount, plural, one {# minute} other {# minutes}}",
"learning.streakCelebration.congratulations": "Félicitations !", "learning.streakCelebration.congratulations": "Congratulations!",
"learning.streakCelebration.body": "Continuez comme ça, vous êtes sur une lancée!", "learning.streakCelebration.body": "Keep it up, youre on a roll!",
"learning.streakCelebration.button": "Continuez ainsi", "learning.streakCelebration.button": "Keep it up",
"learning.streakCelebration.buttonSrOnly": "Fermer le modal et continuer", "learning.streakCelebration.buttonSrOnly": "Close modal and continue",
"learning.streakCelebration.buttonAA759": "Continuer le cours", "learning.streakCelebration.buttonAA759": "Continue with course",
"learning.streakCelebration.header": "série de jours", "learning.streakCelebration.header": "day streak",
"learning.streakCelebration.factoidABoldedSection": "ont 20 fois plus de chances de réussir leur cours", "learning.streakCelebration.factoidABoldedSection": "are 20x more likely to pass their course",
"learning.streakCelebration.factoidBBoldedSection": "termine 5 fois plus de contenu de cours en moyenne", "learning.streakCelebration.factoidBBoldedSection": "complete 5x as much course content on average",
"learning.streakCelebration.streakDiscountMessage": "Vous avez droit à 15% de rabais si vous mettez à jour ce cours pour un temps limité seulement.", "learning.streakCelebration.streakDiscountMessage": "Youve unlocked a 15% off discount when you upgrade this course for a limited time only.",
"learning.streakcelebration.factoida": "Les utilisateurs qui apprennent {streak_length} jours d'affilée {bolded_section} que ceux qui n'apprennent pas.", "learning.streakcelebration.factoida": "Users who learn {streak_length} days in a row {bolded_section} than those who dont.",
"learning.streakcelebration.factoidb": "Les utilisateurs qui apprennent {streak_length} jours d'affilée {bolded_section} par rapport à ceux qui ne le font pas.", "learning.streakcelebration.factoidb": "Users who learn {streak_length} days in a row {bolded_section} vs. those who dont.",
"learning.streakCelebration.streakCelebrationCouponEndDateMessage": "Termine {date}.", "learning.streakCelebration.streakCelebrationCouponEndDateMessage": "Ends {date}.",
"learning.loading.failure": "Il y a eu une erreur lors du chargement de ce cours.", "learning.loading.failure": "There was an error loading this course.",
"learning.loading": "Chargement de vos cours..." "learning.loading": "Loading course page…"
} }

View File

@@ -95,7 +95,6 @@ initialize({
CONTACT_URL: process.env.CONTACT_URL || null, CONTACT_URL: process.env.CONTACT_URL || null,
CREDENTIALS_BASE_URL: process.env.CREDENTIALS_BASE_URL || null, CREDENTIALS_BASE_URL: process.env.CREDENTIALS_BASE_URL || null,
ENTERPRISE_LEARNER_PORTAL_HOSTNAME: process.env.ENTERPRISE_LEARNER_PORTAL_HOSTNAME || null, ENTERPRISE_LEARNER_PORTAL_HOSTNAME: process.env.ENTERPRISE_LEARNER_PORTAL_HOSTNAME || null,
ENABLE_JUMPNAV: process.env.ENABLE_JUMPNAV || null,
ENABLE_NOTICES: process.env.ENABLE_NOTICES || null, ENABLE_NOTICES: process.env.ENABLE_NOTICES || null,
INSIGHTS_BASE_URL: process.env.INSIGHTS_BASE_URL || null, INSIGHTS_BASE_URL: process.env.INSIGHTS_BASE_URL || null,
SEARCH_CATALOG_URL: process.env.SEARCH_CATALOG_URL || null, SEARCH_CATALOG_URL: process.env.SEARCH_CATALOG_URL || null,
@@ -108,7 +107,6 @@ initialize({
TERMS_OF_SERVICE_URL: process.env.TERMS_OF_SERVICE_URL || null, TERMS_OF_SERVICE_URL: process.env.TERMS_OF_SERVICE_URL || null,
TWITTER_HASHTAG: process.env.TWITTER_HASHTAG || null, TWITTER_HASHTAG: process.env.TWITTER_HASHTAG || null,
TWITTER_URL: process.env.TWITTER_URL || null, TWITTER_URL: process.env.TWITTER_URL || null,
LEGACY_THEME_NAME: process.env.LEGACY_THEME_NAME || null,
}, 'LearnerAppConfig'); }, 'LearnerAppConfig');
}, },
}, },

View File

@@ -36,6 +36,29 @@
} }
} }
.course-header {
min-width: 0;
.course-title-lockup {
min-width: 0;
span {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding-bottom: 0.1rem;
}
}
.user-dropdown {
.btn {
height: 3rem;
@media (max-width: -1 + map-get($grid-breakpoints, "sm")) {
padding: 0 0.5rem;
}
}
}
}
.course-tabs-navigation { .course-tabs-navigation {
border-bottom: solid 1px #eaeaea; border-bottom: solid 1px #eaeaea;

View File

@@ -5,7 +5,7 @@ import { Helmet } from 'react-helmet';
import { getConfig } from '@edx/frontend-platform'; import { getConfig } from '@edx/frontend-platform';
import { useToggle } from '@edx/paragon'; import { useToggle } from '@edx/paragon';
import { CourseTabsNavigation } from '../course-tabs'; import { CourseTabsNavigation } from '../course-header';
import { useModel } from '../generic/model-store'; import { useModel } from '../generic/model-store';
import { AlertList } from '../generic/user-messages'; import { AlertList } from '../generic/user-messages';
import StreakModal from '../shared/streak-celebration'; import StreakModal from '../shared/streak-celebration';

View File

@@ -3,7 +3,7 @@ import { Factory } from 'rosie';
import { initializeTestStore, render, screen } from '../setupTest'; import { initializeTestStore, render, screen } from '../setupTest';
import LoadedTabPage from './LoadedTabPage'; import LoadedTabPage from './LoadedTabPage';
jest.mock('../course-tabs/CourseTabsNavigation', () => () => <div data-testid="CourseTabsNavigation" />); jest.mock('../course-header/CourseTabsNavigation', () => () => <div data-testid="CourseTabsNavigation" />);
jest.mock('../instructor-toolbar/InstructorToolbar', () => () => <div data-testid="InstructorToolbar" />); jest.mock('../instructor-toolbar/InstructorToolbar', () => () => <div data-testid="InstructorToolbar" />);
jest.mock('../shared/streak-celebration/StreakCelebrationModal', () => () => <div data-testid="StreakModal" />); jest.mock('../shared/streak-celebration/StreakCelebrationModal', () => () => <div data-testid="StreakModal" />);

View File

@@ -6,9 +6,9 @@ import { Redirect } from 'react-router';
import Footer from '@edx/frontend-component-footer'; import Footer from '@edx/frontend-component-footer';
import { Toast } from '@edx/paragon'; import { Toast } from '@edx/paragon';
import { LearningHeader as Header } from '@edx/frontend-component-header'; import { Header } from '../course-header';
import PageLoading from '../generic/PageLoading';
import { getAccessDeniedRedirectUrl } from '../shared/access'; import { getAccessDeniedRedirectUrl } from '../shared/access';
import PageLoading from '../generic/PageLoading';
import { useModel } from '../generic/model-store'; import { useModel } from '../generic/model-store';
import genericMessages from '../generic/messages'; import genericMessages from '../generic/messages';