feat: multi language support (#254)

* feat: multitranslational support

* - completion of settings page
- completion of sidebar

* sidebar rerendering bug fix

* completion of the lesson navigation & materials page

* completion of the course navigation

* completion of requested languages

* - Implementation of Language Picker
- Rename Bug Fixes

* checkpoint save

* - addition of the language picker to the onboarding.
- addition of the language switcher for the lesson notes.

* merge completion

* initialization of the new branch

* add transition.svelte file

* lesson note bug fix

* feat: add translation migration

* completion of translation

* fix height issue of dropdown

* refactoring

* fix: improve code with LOCALE from db

* finally get it fully functional

* connect with AI

* backward compatibility for lesson note

* preserve old content, when generating AI content

* undo translations in upgrade modal

* fix duplicate key issue from codacy trigger

---------

Co-authored-by: Rotimi Best <best@classroomio.com>
This commit is contained in:
Adeyemi Adetunji
2024-04-19 05:45:48 +01:00
committed by GitHub
co-authored by Rotimi Best
parent ff7d2cee35
commit d75e2f258e
153 changed files with 11264 additions and 1130 deletions
@@ -26,6 +26,7 @@
import { currentOrg } from '$lib/utils/store/org';
import UploadWidget from '$lib/components/UploadWidget/index.svelte';
import { course } from '$lib/components/Course/store';
import { t } from '$lib/utils/functions/translations';
export let editMode = false;
export let courseData: Course;
@@ -124,7 +125,7 @@
{get(courseData, 'metadata.instructor.name', '')}
</p>
<PrimaryButton
label="Start Course"
label={$t('course.navItem.landing_page.start_course')}
className="px-6 py-5 mt-6 sm:w-fit hidden md:block"
onClick={() => {
if (editMode) return;
@@ -207,14 +208,17 @@
class="{navItem.key === activeNav &&
'active text-primary-700'} z-0 mr-6 rounded-lg px-2 font-normal text-slate-700 hover:bg-gray-200 dark:text-white dark:hover:text-slate-900"
>
{navItem.label}
{$t(navItem.label)}
</a>
{/each}
</nav>
<!-- Sections - Requirement -->
<section id="requirement" class="mt-8 border-b border-gray-300 pb-10">
<h3 class="mb-3 mt-0 text-2xl font-bold">Requirement</h3>
<h3 class="mb-3 mt-0 text-2xl font-bold">
{$t('course.navItem.landing_page.requirement')}
</h3>
<ul class="list font-light">
<HtmlRender content={get(courseData, 'metadata.requirements', '')} />
</ul>
@@ -222,7 +226,10 @@
<!-- Sections - Course Description -->
<section id="description" class="mt-8 border-b border-gray-300 pb-10">
<h3 class="mb-3 mt-0 text-2xl font-bold">Course Description</h3>
<h3 class="mb-3 mt-0 text-2xl font-bold">
{$t('course.navItem.landing_page.description')}
</h3>
<HtmlRender
className="dark:text-white text-sm font-light"
content={get(courseData, 'metadata.description', '')}
@@ -231,27 +238,28 @@
<!-- Sections - Goal -->
<section id="goals" class="mt-8 pb-10">
<h3 class="mb-3 mt-0 text-2xl font-bold">What you'll learn</h3>
<h3 class="text-2xl font-bold mt-0 mb-3">{$t('course.navItem.landing_page.learn')}</h3>
<ul class="list font-light">
<HtmlRender content={get(courseData, 'metadata.goals', '')} />
</ul>
</section>
<!-- Sections - Certificate -->
<section class="mt-8 border-b border-gray-300 pb-10">
<h3 class="mt-0 text-2xl font-bold">Certificate</h3>
<p class="mb-3 text-sm font-light dark:text-white">
When you complete all of the courses in the program, you'll earn a Certificate to share
with your professional network.
<section class="border-b border-gray-300 mt-8 pb-10">
<h3 class="text-2xl font-bold mt-0">{$t('course.navItem.landing_page.certificate')}</h3>
<p class="dark:text-white text-sm font-light mb-3">
{$t('course.navItem.landing_page.certificate_text')}
</p>
<img src="/images/certificate-template.svg" alt="certificate template" />
</section>
<!-- Sections - Lessons -->
<section id="lessons" class="mt-8 border-b border-gray-300 pb-10">
<div class="mb-3 flex w-full items-center justify-between">
<h3 class="mb-3 mt-0 text-2xl font-bold">Course Content</h3>
<p class="text-sm font-light dark:text-white">
<section id="lessons" class="border-b border-gray-300 mt-8 pb-10">
<div class="flex items-center justify-between w-full mb-3">
<h3 class="text-2xl font-bold mt-0 mb-3">
{$t('course.navItem.landing_page.content')}
</h3>
<p class="dark:text-white text-sm font-light">
<!-- {lessons.length} lessons -->
{pluralize('lesson', lessons.length, true)}
</p>
@@ -271,23 +279,25 @@
<div class="w-2/4">
<div class="flex items-center">
{#if lesson.slide_url}
<span class="flex w-2/4 text-sm font-light"
><PresentationFile size={16} class="mr-1" />1 slide</span
<span class="text-sm font-light flex w-2/4"
><PresentationFile size={16} class="mr-1" />{$t(
'course.navItem.landing_page.slide'
)}</span
>
{/if}
{#if lesson.note}
<span class="flex w-2/4 text-sm font-light"
><Notebook size={16} class="mr-1" />note</span
<span class="text-sm font-light flex w-2/4"
><Notebook size={16} class="mr-1" />{$t(
'course.navItem.landing_page.note'
)}</span
>
{/if}
</div>
<div class="flex items-center">
{#if lesson.videos}
<span class="flex w-2/4 text-sm font-light"
><Video size={16} class="mr-1" />{lesson.videos.length} video{lesson.videos
.length > 1
? 's'
: ''}
<span class="text-sm font-light flex w-2/4"
><Video size={16} class="mr-1" />{lesson.videos.length}
{$t('course.navItem.landing_page.video')}{lesson.videos.length > 1 ? 's' : ''}
</span>
{/if}
{#if get(lesson, 'totalExercises[0].count')}
@@ -308,7 +318,9 @@
<!-- Sections - Reviews -->
{#if reviews && reviews.length > 0}
<section id="reviews">
<h2 class="my-16 mb-6 ml-0 mr-0 font-semibold">Reviews</h2>
<h2 class="my-16 mr-0 mb-6 ml-0 font-semibold">
{$t('course.navItem.landing_page.reviews')}
</h2>
<div class="flex flex-wrap">
{#each reviews.slice(0, 4) as review, id}
{#if !review.hide}
@@ -355,7 +367,7 @@
</div>
{#if reviews.length > 4}
<PrimaryButton
label="See All"
label={$t('course.navItem.landing_page.see_all')}
className="w-3/12 p-4 mt-2"
variant={VARIANTS.OUTLINED}
onClick={() => ($reviewsModalStore.open = true)}
@@ -367,16 +379,18 @@
onClose={() => ($reviewsModalStore.open = false)}
bind:open={$reviewsModalStore.open}
width="w-9/12"
modalHeading="Reviews"
modalHeading={$t('course.navItem.landing_page.reviews_modal.title')}
>
<div class="flex">
<!-- ratings -->
<div class="w-1/3">
<h2 class="text-xl font-bold">
{averageRating} Rating
{averageRating}
{$t('course.navItem.landing_page.reviews_modal.rating')}
</h2>
<h2 class="mt-2 text-lg font-semibold">
{reviews.length} Ratings
<h2 class="text-lg font-semibold mt-2">
{reviews.length}
{$t('course.navItem.landing_page.reviews_modal.ratings')}
</h2>
</div>
<!-- reviews -->
@@ -418,8 +432,10 @@
<!-- Sections - Instructor -->
<section id="instructor" class="mt-8 pb-10">
<h3 class="mb-3 mt-0 text-2xl font-bold">Instructor</h3>
<div class="mb-4 flex items-center">
<h3 class="text-2xl font-bold mt-0 mb-3">
{$t('course.navItem.landing_page.instructor')}
</h3>
<div class="flex items-center mb-4">
<img
alt="Author Avatar"
class="mr-3 block h-20 w-20 rounded-full"
@@ -434,7 +450,10 @@
</p>
<p class="text-md flex items-center font-light dark:text-white">
<PlayFilled size={16} class="text-primary-700" />
<span class="ml-1">{get(instructor, 'courseNo', 10)} courses</span>
<span class="ml-1"
>{get(instructor, 'courseNo', '')}
{$t('course.navItem.landing_page.courses')}</span
>
</p>
</div>
</div>