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
@@ -13,6 +13,7 @@
import CopyFile from 'carbon-icons-svelte/lib/CopyFile.svelte';
import Share from 'carbon-icons-svelte/lib/Share.svelte';
import UserFollow from 'carbon-icons-svelte/lib/UserFollow.svelte';
import { t } from '$lib/utils/functions/translations';
export let bannerImage: string | undefined;
export let id = '';
@@ -55,11 +56,30 @@
{#if showContextMenu}
<ContextMenu {target}>
<ContextMenuOption indented labelText="Clone" icon={CopyFile} on:click={handleCloneCourse} />
<ContextMenuOption indented labelText="Share" icon={Share} on:click={handleShareCourse} />
<ContextMenuOption indented labelText="Invite" icon={UserFollow} on:click={handleInvite} />
<ContextMenuOption
indented
labelText={$t('courses.lesson_card.context_menu.clone')}
icon={CopyFile}
on:click={handleCloneCourse}
/>
<ContextMenuOption
indented
labelText={$t('courses.lesson_card.context_menu.share')}
icon={Share}
on:click={handleShareCourse}
/>
<ContextMenuOption
indented
labelText={$t('courses.lesson_card.context_menu.invite')}
icon={UserFollow}
on:click={handleInvite}
/>
<ContextMenuDivider />
<ContextMenuOption kind="danger" labelText="Delete" on:click={handleDeleteCourse} />
<ContextMenuOption
kind="danger"
labelText={$t('courses.lesson_card.context_menu.delete')}
on:click={handleDeleteCourse}
/>
</ContextMenu>
{/if}
@@ -79,7 +99,7 @@
<svelte:fragment slot="loading">
<SkeletonPlaceholder style="width: 100%; height: 200px;" />
</svelte:fragment>
<svelte:fragment slot="error">An error occurred.</svelte:fragment>
<svelte:fragment slot="error">{$t('courses.lesson_card.error_message')}</svelte:fragment>
</ImageLoader>
</div>
@@ -94,7 +114,10 @@
'items-center'}"
>
<div>
<p class="text-xs pt-2 {!isLMS && 'pl-2'} dark:text-white">{totalLessons} lessons</p>
<p class="text-xs pt-2 {!isLMS && 'pl-2'} dark:text-white">
{totalLessons}
{$t('courses.lesson_card.lessons_number')}
</p>
<p class="text-xs py-2">
{#if isOnLandingPage}
<span class="px-2">{!cost ? 'Free' : formatter.format(cost)}</span>
@@ -111,9 +134,9 @@
{:else}
<Tag type={isPublished ? 'green' : 'cool-gray'}>
{#if isPublished}
Published
{$t('courses.lesson_card.published')}
{:else}
Unpublished
{$t('courses.lesson_card.unpublished')}
{/if}
</Tag>
{/if}
@@ -122,13 +145,16 @@
{#if isLMS}
<PrimaryButton
label="Continue Course"
label={$t('courses.lesson_card.continue_course')}
variant={VARIANTS.OUTLINED}
className="rounded-none text-primary-600"
/>
{:else if !isOnLandingPage}
<div class="flex flex-col justify-between">
<p class="text-xs pt-2 pl-2 dark:text-white">{totalStudents} students</p>
<p class="text-xs pt-2 pl-2 dark:text-white">
{totalStudents}
{$t('courses.lesson_card.students')}
</p>
<div></div>
</div>
{/if}
@@ -12,6 +12,7 @@
import { currentOrg } from '$lib/utils/store/org';
import { goto } from '$app/navigation';
import { capturePosthogEvent } from '$lib/utils/services/posthog';
import { t } from '$lib/utils/functions/translations';
let isLoading = false;
let errors = {
@@ -118,13 +119,13 @@
{onClose}
bind:open={$createCourseModal.open}
width="w-4/5 md:w-2/5"
modalHeading="Create a Course"
modalHeading={$t('courses.new_course_modal.heading')}
>
<form on:submit|preventDefault={createCourse}>
<TextField
label="Course name"
label={$t('courses.new_course_modal.course_name')}
bind:value={$createCourseModal.title}
placeholder="Your course name"
placeholder={$t('courses.new_course_modal.course_name_placeholder')}
className="mb-4"
isRequired={true}
errorMessage={errors.title}
@@ -132,10 +133,10 @@
/>
<TextArea
label="Short description"
label={$t('courses.new_course_modal.short_description')}
bind:value={$createCourseModal.description}
rows={4}
placeholder="A little description about this course"
placeholder={$t('courses.new_course_modal.short_description_placeholder')}
className="mb-4"
isRequired={true}
errorMessage={errors.description}
@@ -146,7 +147,7 @@
<div class="mt-5 flex items-center">
<PrimaryButton
className="px-6 py-3"
label="Finish"
label={$t('courses.new_course_modal.button')}
type="submit"
isDisabled={isLoading}
{isLoading}
@@ -6,11 +6,11 @@
import { courseMetaDeta } from './store';
import type { Course } from '$lib/utils/types';
import { globalStore } from '$lib/utils/store/app';
import { t } from '$lib/utils/functions/translations';
export let courses: Course[] = [];
export let emptyTitle = 'No Courses Created';
export let emptyDescription =
'Share your knowledge with the world by creating engaging courses for your students.';
export let emptyTitle = $t('courses.lesson_card.empty_title');
export let emptyDescription = $t('courses.lesson_card.empty_description');
function calcProgressRate(progressRate?: number, totalLessons?: number): number {
if (!progressRate || !totalLessons) {