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
@@ -4,6 +4,7 @@
import Modal from '$lib/components/Modal/index.svelte';
import { deleteModal, quizesStore } from '$lib/utils/store/org';
import { supabase } from '$lib/utils/functions/supabase';
import { t } from '$lib/utils/functions/translations';
export let onDelete = () => {};
@@ -34,24 +35,26 @@
onClose={closeModal}
bind:open={$deleteModal.open}
width="w-2/5"
modalHeading={$deleteModal.isQuestion ? 'Delete Question' : 'Delete Quiz'}
modalHeading={$deleteModal.isQuestion
? $t('components.quiz.question_delete')
: $t('components.quiz.quiz_delete')}
size="sm"
>
<div class="w-full flex flex-col items-center my-10">
<h1 class="dark:text-white text-lg text-center">
{#if $deleteModal.isQuestion}
Are you sure you want to delete this question?
{$t('components.quiz.delete_question')}
{:else}
Are you sure you want to delete this quiz?
{$t('components.quiz.delete_quiz')}
{/if}
You will lose your content and this action can’t be undone.
{$t('components.quiz.lose_content')}
</h1>
<div class="mt-5">
<PrimaryButton
className="px-6 py-3"
variant={VARIANTS.CONTAINED}
label="Delete"
label={$t('components.quiz.delete')}
onClick={() => {
if ($deleteModal.isQuestion) {
onDelete();
@@ -7,6 +7,7 @@
import { supabase } from '$lib/utils/functions/supabase';
import { currentOrg, createQuizModal, currentOrgPath, quizesStore } from '$lib/utils/store/org';
import { createQuizValidation } from '$lib/utils/functions/validator';
import { t } from '$lib/utils/functions/translations';
let open = false;
let errors = {
@@ -97,21 +98,23 @@
</script>
<svelte:head>
<title>Quizzes - ClassroomIO</title>
<title>{$t('components.quiz.title')} - ClassroomIO</title>
</svelte:head>
<Modal
onClose={handleClose}
bind:open
width="w-4/5 md:w-2/5"
modalHeading="{$createQuizModal.openEdit ? 'Update' : 'Create'} a Quiz"
modalHeading="{$createQuizModal.openEdit
? $t('components.quiz.update')
: $t('components.quiz.create')} {$t('components.quiz.a_quiz')}"
>
<form on:submit|preventDefault={createQuiz}>
<TextField
label="Quiz Title"
label={$t('components.quiz.quiz_title')}
bind:value={$createQuizModal.title}
autofocus={true}
placeholder="Your quiz title"
placeholder={$t('components.quiz.placehoolder')}
className="mb-4"
isRequired={true}
errorMessage={errors.title}
@@ -121,7 +124,9 @@
<div class="mt-5 flex items-center justify-end">
<PrimaryButton
className="px-6 py-3"
label={$createQuizModal.openEdit ? 'Save Changes' : 'Continue'}
label={$createQuizModal.openEdit
? $t('components.quiz.save')
: $t('components.quiz.continue')}
type="submit"
isDisabled={isLoading}
{isLoading}
@@ -9,6 +9,7 @@
import { onRename, onDelete } from '$lib/utils/services/org/quiz';
import { themeImages } from '$lib/utils/constants/quiz';
import { calDateDiff } from '$lib/utils/functions/date';
import { t } from '$lib/utils/functions/translations';
export let quiz;
export let totalQuestions;
@@ -28,7 +29,7 @@
// onClick: onReport(quiz),
// },
{
label: 'Rename',
label: $t('components.quiz.rename'),
onClick() {
onRename(quiz);
}
@@ -40,7 +41,7 @@
// },
// },
{
label: 'Delete',
label: $t('components.quiz.delete'),
onClick() {
onDelete(quiz);
}
@@ -77,13 +78,13 @@
<div class="flex md:flex-row flex-col justify-between">
<div>
<p class="mb-2">{pluralize('question', totalQuestions, true)}</p>
<p class="mb-2 md:mb-0">Updated {calDateDiff(quiz.updated_at)}</p>
<p class="mb-2 md:mb-0">{$t('components.quiz.updated')} {calDateDiff(quiz.updated_at)}</p>
</div>
<PrimaryButton
className="px-6 py-3"
variant={VARIANTS.OUTLINED}
label="Start Quiz"
label={$t('components.quiz.start')}
onClick={startQuiz}
/>
</div>
@@ -4,6 +4,7 @@
import { optionImage } from '$lib/utils/constants/quiz';
import TextField from '$lib/components/Form/TextField.svelte';
import IconButton from '$lib/components/IconButton/index.svelte';
import { t } from '$lib/utils/functions/translations';
export let currentQuestion = {
label: ''
@@ -17,10 +18,10 @@
<h1 class="text-white mb-5 font-bold">{currentQuestion.label}</h1>
{:else}
<TextField
placeholder="Start typing your question"
placeholder={$t('components.quiz.start_typing')}
bind:value={currentQuestion.label}
className="w-full my-4"
errorMessage={currentError.isLabelEmpty && 'This field is required'}
errorMessage={currentError.isLabelEmpty && $t('components.quiz.required_field')}
isRequired={true}
bgColor="bg-white"
/>
@@ -37,11 +38,12 @@
{:else}
<TextField
bind:value={option.label}
placeholder="Type answer"
placeholder={$t('components.quiz.type_answer')}
bgColor="bg-white"
className="mt-3"
isDisabled={currentQuestion.type === 'boolean'}
errorMessage={optionHasError(option.id, currentError.options) && 'Please enter a label'}
errorMessage={optionHasError(option.id, currentError.options) &&
$t('components.quiz.label')}
/>
<div class="flex justify-end absolute top-2 right-2">
<IconButton
@@ -7,6 +7,7 @@
import { snackbar } from '$lib/components/Snackbar/store';
import { supabase } from '$lib/utils/functions/supabase';
import { currentOrg, quizesStore } from '$lib/utils/store/org';
import { t } from '$lib/utils/functions/translations';
let isLoading = false;
@@ -43,9 +44,9 @@
{:else}
<Box>
<CoursesEmptyIcon />
<h3 class="dark:text-white text-2xl my-5">No Quiz Created</h3>
<h3 class="dark:text-white text-2xl my-5">{$t('components.quiz.no_quizz')}</h3>
<p class="dark:text-white w-1/3 text-center">
Create interactive quizzes with scoreboard for your students.
{$t('components.quiz.interactive')}
</p>
</Box>
{/each}