Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: mark course about page static strings for i18n #991

Merged
merged 1 commit into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# For all changes

- [ ] Ensure adequate tests are in place (or reviewed existing tests cover changes)
- [ ] Ensure English strings are marked for translation. See [documentation](https://openedx.atlassian.net/wiki/spaces/LOC/pages/3103293538/MFE+Translation+How+To+s#How-to-internationalize-your-React-App) for more details.

# Only if submitting a visual change

Expand Down
10 changes: 8 additions & 2 deletions src/components/course/CourseAssociatedPrograms.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useContext } from 'react';
import { Hyperlink } from '@openedx/paragon';
import { sendEnterpriseTrackEvent } from '@edx/frontend-enterprise-utils';
import { AppContext } from '@edx/frontend-platform/react';
import { FormattedMessage } from '@edx/frontend-platform/i18n';

import { CourseContext } from './CourseContextProvider';
import { getProgramIcon, formatProgramType } from './data/utils';
Expand All @@ -11,10 +12,15 @@ const CourseAssociatedPrograms = () => {
const { state } = useContext(CourseContext);
const { course } = state;
const { enterpriseConfig } = useContext(AppContext);

return (
<div className="associated-programs mb-5">
<h3>Associated Programs</h3>
<h3>
<FormattedMessage
id="enterprise.course.about.course.sidebar.associated.programs"
defaultMessage="Associated Programs"
description="Title for the section that lists the programs that are associated with the course."
/>
</h3>
<ul className="pl-0 list-unstyled">
{course.programs.map(program => (
<li key={program.uuid} className="mb-3 row">
Expand Down
131 changes: 108 additions & 23 deletions src/components/course/CourseMainContent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useContext } from 'react';
import { breakpoints, Hyperlink, MediaQuery } from '@openedx/paragon';
import { AppContext } from '@edx/frontend-platform/react';

import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
import { PreviewExpand } from '../preview-expand';
import { CourseContext } from './CourseContextProvider';
import CourseSidebar from './CourseSidebar';
Expand Down Expand Up @@ -32,7 +33,7 @@ const CourseMainContent = () => {
const { config } = useContext(AppContext);
const { state } = useContext(CourseContext);
const { course, activeCourseRun } = state;

const intl = useIntl();
return (
<>
<MediaQuery minWidth={breakpoints.large.minWidth}>
Expand All @@ -46,19 +47,41 @@ const CourseMainContent = () => {
<PreviewExpand
className="mb-5"
cta={{
labelToExpand: 'More about this course',
labelToMinimize: 'Collapse about this course',
labelToExpand: intl.formatMessage({
id: 'enterprise.course.about.course.sidebar.about.expand',
defaultMessage: 'More about this course',
description: 'Label for the expand button to show more about the course.',
}),
labelToMinimize: intl.formatMessage({
id: 'enterprise.course.about.course.sidebar.about.collapse',
defaultMessage: 'Collapse about this course',
description: 'Label for the collapse button to hide more about the course.',
}),
id: 'about-this-course',
}}
heading={<h3>About this course</h3>}
heading={(
<h3>
{intl.formatMessage({
id: 'enterprise.course.about.course.sidebar.about.heading',
defaultMessage: 'About this course',
description: 'Heading for the section that describes the course.',
})}
</h3>
)}
>
{/* eslint-disable-next-line react/no-danger */}
<div dangerouslySetInnerHTML={{ __html: course.fullDescription }} />
</PreviewExpand>
)}
{course.sponsors && course.sponsors.length > 0 && (
<div className="mb-5">
<h3>Sponsored by</h3>
<h3>
<FormattedMessage
id="enterprise.course.about.course.sidebar.sponsored.by"
defaultMessage="Sponsored by"
description="Heading for the section that lists the sponsors of the course."
/>
</h3>
<div className="row no-gutters mt-3">
{course.sponsors.map((sponsor) => (
<div className="col-lg-6 mb-3" key={sponsor.name}>
Expand All @@ -83,20 +106,42 @@ const CourseMainContent = () => {
))}
</div>
<p>
The production of this course would not have been possible without the
generous contributions of {formatSponsorTextList(course.sponsors)}.
<FormattedMessage
id="enterprise.course.about.course.sidebar.sponsored.by.description"
defaultMessage="The production of this course would not have been possible without the generous contributions of {sponsersList}."
description="Description for the section that lists the contributions sponsors of the course."
values={{
sponsersList: formatSponsorTextList(course.sponsors),
}}
/>
</p>
</div>
)}
{course.outcome && (
<PreviewExpand
className="mb-5"
cta={{
labelToExpand: 'Expand what you\'ll learn',
labelToMinimize: 'Collapse what you\'ll learn',
labelToExpand: intl.formatMessage({
id: 'enterprise.course.about.course.sidebar.outcome.expand',
defaultMessage: "Expand what you'll learn",
description: 'Label for the expand button to show what you will learn in the course.',
}),
labelToMinimize: intl.formatMessage({
id: 'enterprise.course.about.course.sidebar.outcome.collapse',
defaultMessage: "Collapse what you'll learn",
description: 'Label for the collapse button to hide what you will learn in the course.',
}),
id: 'what-youll-learn',
}}
heading={<h3>What you&apos;ll learn</h3>}
heading={(
<h3>
{intl.formatMessage({
id: 'enterprise.course.about.course.sidebar.outcome.heading',
defaultMessage: "What you'll learn",
description: 'Heading for the section that lists what you will learn in the course.',
})}
</h3>
)}
>
{/* eslint-disable-next-line react/no-danger */}
<div dangerouslySetInnerHTML={{ __html: course.outcome }} />
Expand All @@ -106,11 +151,29 @@ const CourseMainContent = () => {
<PreviewExpand
className="mb-5"
cta={{
labelToExpand: 'Expand syllabus',
labelToMinimize: 'Collapse syllabus',
labelToExpand: intl.formatMessage({
id: 'enterprise.course.about.course.sidebar.syllabus.expand',
defaultMessage: 'Expand syllabus',
description: 'Label for the expand button to show the syllabus of the course.',
}),
labelToMinimize: intl.formatMessage({
id: 'enterprise.course.about.course.sidebar.syllabus.collapse',
defaultMessage: 'Collapse syllabus',
description: 'Label for the collapse button to hide the syllabus of the course.',
}),
id: 'course-syllabus',
}}
heading={<h3>Syllabus</h3>}
heading={(
<h3>
{
intl.formatMessage({
id: 'enterprise.course.about.course.sidebar.syllabus.heading',
defaultMessage: 'Syllabus',
description: 'Heading for the section that lists the syllabus of the course.',
})
}
</h3>
)}
>
{/* eslint-disable-next-line react/no-danger */}
<div dangerouslySetInnerHTML={{ __html: course.syllabusRaw }} />
Expand All @@ -122,14 +185,26 @@ const CourseMainContent = () => {
)}
{course.learnerTestimonials && (
<div className="mb-5">
<h3>Learner testimonials</h3>
<h3>
<FormattedMessage
id="enterprise.course.about.course.sidebar.learner.testimonials"
defaultMessage="Learner testimonials"
description="Heading for the section that lists learner testimonials."
/>
</h3>
{/* eslint-disable-next-line react/no-danger */}
<div dangerouslySetInnerHTML={{ __html: course.learnerTestimonials }} />
</div>
)}
{course.faq && (
<div className="mb-5">
<h3>Frequently asked questions</h3>
<h3>
<FormattedMessage
id="enterprise.course.about.course.sidebar.frequently.asked.questions"
defaultMessage="Frequently asked questions"
description="Heading for the section that lists frequently asked questions."
/>
</h3>
{/* eslint-disable-next-line react/no-danger */}
<div dangerouslySetInnerHTML={{ __html: course.faq }} />
</div>
Expand All @@ -142,15 +217,25 @@ const CourseMainContent = () => {
)}
{activeCourseRun.hasOfacRestrictions && (
<div className="mb-5">
<h3>Who can take this course?</h3>
<h3>
<FormattedMessage
id="enterprise.course.about.course.sidebar.who.can.take.this.course"
defaultMessage="Who can take this course?"
description="Heading for the section that lists who can take this course."
/>
</h3>
<p>
Unfortunately, learners from one or more of the following countries or regions will not
be able to register for this course: Iran, Cuba and the Crimea region of Ukraine.
While edX has sought licenses from the U.S. Office of Foreign Assets Control (OFAC) to
offer our courses to learners in these countries and regions, the licenses we have
received are not broad enough to allow us to offer this course in all locations. EdX
truly regrets that U.S. sanctions prevent us from offering all of our courses to
everyone, no matter where they live.
<FormattedMessage
id="enterprise.course.about.course.sidebar.who.can.take.this.course.description"
defaultMessage="Unfortunately, learners from one or more of the following countries or regions will not
be able to register for this course: Iran, Cuba and the Crimea region of Ukraine.
While edX has sought licenses from the U.S. Office of Foreign Assets Control (OFAC) to
offer our courses to learners in these countries and regions, the licenses we have
received are not broad enough to allow us to offer this course in all locations. EdX
truly regrets that U.S. sanctions prevent us from offering all of our courses to
everyone, no matter where they live."
description="Description for the section that lists who can take this course. OFAC is the brnad name"
/>
</p>
</div>
)}
Expand Down
11 changes: 8 additions & 3 deletions src/components/course/CourseMaterialsButton.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useContext } from 'react';
import { Button } from '@openedx/paragon';
import { useIntl } from '@edx/frontend-platform/i18n';
import { findUserEnrollmentForCourseRun } from './data/utils';
import { CourseContext } from './CourseContextProvider';

Expand All @@ -10,7 +11,7 @@ const CourseMaterialsButton = () => {
userEnrollments,
},
} = useContext(CourseContext);

const intl = useIntl();
let userEnrollment;
for (const courseRun of course.courseRuns) { // eslint-disable-line no-restricted-syntax
const userEnrollmentForCourseRun = findUserEnrollmentForCourseRun({
Expand All @@ -29,8 +30,12 @@ const CourseMaterialsButton = () => {
return (
<>
<br />
<Button variant="brand" href={userEnrollment.courseRunUrl}>
View course materials
<Button variant="brand" href={userEnrollment?.courseRunUrl}>
{intl.formatMessage({
id: 'enterprise.course.about.course.materials.button.label',
defaultMessage: 'View course materials',
description: 'Label for the button that allows the learner to view the course materials.',
jajjibhai008 marked this conversation as resolved.
Show resolved Hide resolved
})}
</Button>
</>
);
Expand Down
19 changes: 16 additions & 3 deletions src/components/course/CourseRecommendations.jsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import React, { useContext } from 'react';
import { CardGrid } from '@openedx/paragon';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { CourseContext } from './CourseContextProvider';
import CourseRecommendationCard from './CourseRecommendationCard';

const CourseRecommendations = () => {
const { state } = useContext(CourseContext);
const { course, courseRecommendations } = state;
const { allRecommendations, samePartnerRecommendations } = courseRecommendations;

return (
<div className="mt-1">
{allRecommendations?.length > 0 && (
<div className="mb-3">
<h3 className="mb-3">Courses you may like:</h3>
<h3 className="mb-3">
<FormattedMessage
id="enterprise.course.about.course.sidebar.recommendations"
defaultMessage="Courses you may like:"
description="Title for the section that lists the courses that are recommended."
jajjibhai008 marked this conversation as resolved.
Show resolved Hide resolved
/>
</h3>
<CardGrid>
{allRecommendations.map(recommendation => (
<CourseRecommendationCard key={recommendation.key} course={recommendation} />
Expand All @@ -22,7 +28,14 @@ const CourseRecommendations = () => {
)}
{samePartnerRecommendations?.length > 0 && (
<div className="mb-3">
<h3 className="mb-3">More from { course.owners[0].name }:</h3>
<h3 className="mb-3">
<FormattedMessage
id="enterprise.course.about.course.sidebar.recommendations.same.partner"
defaultMessage="More from { firtstCourseOwner }:"
description="Title for the section that lists the courses that are recommended from the same partner."
jajjibhai008 marked this conversation as resolved.
Show resolved Hide resolved
values={{ firtstCourseOwner: course.owners[0].name }}
/>
</h3>
<CardGrid>
{samePartnerRecommendations.map(recommendation => (
<CourseRecommendationCard
Expand Down
Loading
Loading