From d75e2f258ee1e3156429c059a4b50228de74860e Mon Sep 17 00:00:00 2001 From: Adeyemi Adetunji Date: Fri, 19 Apr 2024 05:45:48 +0100 Subject: [PATCH] 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 --- .../src/routes/transition.svelte | 1 - apps/dashboard/package.json | 1 + .../Apps/components/Comments/index.svelte | 9 +- .../Poll/components/CreatePollForm.svelte | 21 +- .../components/Poll/components/Poll.svelte | 39 +- .../Apps/components/Poll/index.svelte | 19 +- .../Apps/components/Poll/service.ts | 10 +- .../components/Buttons/Logout/index.svelte | 27 +- .../components/Buttons/VisitOrgSite.svelte | 3 +- .../lib/components/ComingSoon/index.svelte | 3 +- .../components/Ceritficate/Design.svelte | 35 +- .../LockedCertificate.svelte | 9 +- .../UnlockedCertificate.svelte | 7 +- .../components/Lesson/AddLessonModal.svelte | 15 +- .../Lesson/DeleteLessonConfirmation.svelte | 10 +- .../Lesson/Exercise/DeleteConfirmation.svelte | 11 +- .../Lesson/Exercise/EditMode.svelte | 31 +- .../Lesson/Exercise/MarkExerciseModal.svelte | 2 +- .../Lesson/Exercise/OrderModal.svelte | 3 +- .../Exercise/Submissions/Individual.svelte | 7 +- .../Exercise/Submissions/Summary.svelte | 5 +- .../Lesson/Exercise/Submissions/index.svelte | 16 +- .../Lesson/Exercise/UpdateDescription.svelte | 26 +- .../components/Lesson/Exercise/index.svelte | 26 +- .../Lesson/Exercises/NewExerciseModal.svelte | 80 +- .../components/Lesson/Exercises/index.svelte | 21 +- .../components/Lesson/Materials/Loader.svelte | 12 + .../Lesson/Materials/Video/EmbedLink.svelte | 12 +- .../Lesson/Materials/Video/Index.svelte | 5 +- .../Lesson/Materials/Video/LocalVideo.svelte | 41 +- .../Materials/Video/YoutubeVideo.svelte | 12 +- .../Lesson/Materials/Video/constants.js | 7 +- .../Materials/components/ComponentNote.svelte | 28 +- .../components/Lesson/Materials/constants.js | 16 +- .../components/Lesson/Materials/index.svelte | 263 ++-- .../Course/components/Lesson/store/lessons.ts | 9 +- .../Course/components/Navigation/index.svelte | 19 +- .../components/NewsFeed/NewFeedModal.svelte | 28 +- .../People/DeleteConfirmation.svelte | 9 +- .../components/People/InvitationModal.svelte | 31 +- .../Course/components/Settings/index.svelte | 85 +- .../Course/components/Settings/store.js | 6 +- .../src/lib/components/Course/store.ts | 6 +- .../components/Editor/HeaderForm.svelte | 20 +- .../components/Editor/InstructorForm.svelte | 17 +- .../components/Editor/PricingForm.svelte | 29 +- .../components/Editor/ReviewFormEditor.svelte | 13 +- .../components/Editor/index.svelte | 24 +- .../components/PricingSection.svelte | 26 +- .../components/CourseLandingPage/constants.ts | 14 +- .../components/CourseLandingPage/index.svelte | 83 +- .../Courses/components/Card/index.svelte | 46 +- .../components/NewCourseModal/index.svelte | 13 +- .../src/lib/components/Courses/index.svelte | 6 +- .../src/lib/components/Form/TextArea.svelte | 3 +- .../src/lib/components/LMS/SideBar.svelte | 24 +- .../components/LMS/components/Learning.svelte | 11 +- .../components/LMS/components/Profile.svelte | 48 +- .../components/LMS/components/Schedule.svelte | 13 +- .../components/MarkdownEditor/index.svelte | 6 +- .../src/lib/components/Navigation/app.svelte | 5 +- .../lib/components/Navigation/index.svelte | 22 +- .../src/lib/components/Navigation/lms.svelte | 3 +- .../Org/AddOrgModal/AddOrgModal.svelte | 17 +- .../Org/Audience/AudienceList.svelte | 23 +- .../lib/components/Org/Audience/index.svelte | 5 +- .../Org/Community/DeleteModal.svelte | 12 +- .../lib/components/Org/Community/index.svelte | 11 +- .../Org/LandingPage/PageHeader.svelte | 10 +- .../components/Org/LandingPage/index.svelte | 39 +- .../components/Org/Quiz/DeleteModal.svelte | 13 +- .../components/Org/Quiz/NewQuizModal.svelte | 15 +- .../lib/components/Org/Quiz/QuizCard.svelte | 9 +- .../components/Org/Quiz/QuizQuestion.svelte | 10 +- .../lib/components/Org/Quiz/Quizzes.svelte | 5 +- .../components/Org/Settings/Billing.svelte | 13 +- .../components/Org/Settings/Domains.svelte | 17 +- .../Org/Settings/Integrations.svelte | 26 +- .../Org/Settings/LandingpageSettings.svelte | 229 ++-- .../Org/Settings/LanguagePicker.svelte | 28 + .../Org/Settings/OrgSettings.svelte | 50 +- .../components/Org/Settings/Profile.svelte | 47 +- .../Org/Settings/TeamMembers.svelte | 8 +- .../lib/components/Org/Settings/index.svelte | 11 +- .../src/lib/components/Org/SideBar.svelte | 124 +- .../Org/VerifyEmail/VerifyEmailModal.svelte | 21 +- .../src/lib/components/PageNav/index.svelte | 3 +- .../Question/CheckboxQuestion/index.svelte | 3 +- .../src/lib/components/Question/Grade.svelte | 4 +- .../Question/RadioQuestion/index.svelte | 3 +- .../Question/TextareaQuestion/index.svelte | 11 +- .../src/lib/components/Question/constants.ts | 6 +- .../components/QuestionContainer/index.svelte | 5 +- .../src/lib/components/Snackbar/index.svelte | 7 +- .../src/lib/components/Snackbar/store.js | 6 +- .../src/lib/components/Tabs/index.svelte | 11 +- .../lib/components/TextEditor/index.svelte | 23 +- .../src/lib/components/Upgrade/Modal.svelte | 36 +- .../lib/components/UploadImage/index.svelte | 4 +- .../lib/components/UploadWidget/index.svelte | 29 +- .../WelcomeModal/WelcomeModal.svelte | 34 +- .../src/lib/utils/constants/roles.js | 8 +- .../src/lib/utils/constants/translation.ts | 17 + .../dashboard/src/lib/utils/functions/date.ts | 2 +- .../src/lib/utils/functions/translations.ts | 104 ++ .../src/lib/utils/services/courses/index.ts | 2 +- apps/dashboard/src/lib/utils/store/user.ts | 3 + .../src/lib/utils/translations/de.json | 1066 +++++++++++++++ .../src/lib/utils/translations/en.json | 1217 +++++++++++++++++ .../src/lib/utils/translations/es.json | 1091 +++++++++++++++ .../src/lib/utils/translations/fr.json | 1209 ++++++++++++++++ .../src/lib/utils/translations/hi.json | 1209 ++++++++++++++++ .../src/lib/utils/translations/pt.json | 1095 +++++++++++++++ .../src/lib/utils/translations/ru.json | 1035 ++++++++++++++ .../src/lib/utils/translations/vi.json | 1139 +++++++++++++++ apps/dashboard/src/lib/utils/types/index.ts | 15 +- apps/dashboard/src/routes/+layout.server.ts | 21 +- apps/dashboard/src/routes/+layout.svelte | 7 + .../src/routes/api/completion/+server.js | 5 +- apps/dashboard/src/routes/api/i18n/+server.ts | 13 + .../src/routes/courses/[id]/+page.svelte | 38 +- .../courses/[id]/attendance/+page.svelte | 25 +- .../courses/[id]/certificates/+page.svelte | 3 +- .../routes/courses/[id]/lessons/+page.svelte | 47 +- .../lessons/[...lessonParams]/+page.svelte | 128 +- .../routes/courses/[id]/marks/+page.svelte | 13 +- .../routes/courses/[id]/people/+page.svelte | 32 +- .../routes/courses/[id]/settings/+page.svelte | 3 +- .../courses/[id]/submissions/+page.svelte | 17 +- .../src/routes/invite/s/[hash]/+page.svelte | 2 +- apps/dashboard/src/routes/lms/+page.svelte | 21 +- .../src/routes/lms/community/+page.svelte | 5 +- .../routes/lms/community/[slug]/+page.svelte | 23 +- .../src/routes/lms/community/ask/+page.svelte | 18 +- .../src/routes/lms/exercises/+page.svelte | 15 +- .../src/routes/lms/mylearning/+page.svelte | 17 +- .../src/routes/lms/settings/+page.svelte | 10 +- apps/dashboard/src/routes/login/+page.svelte | 11 +- .../src/routes/onboarding/+page.svelte | 68 +- .../src/routes/org/[slug]/+layout.svelte | 2 + .../src/routes/org/[slug]/+page.svelte | 30 +- .../routes/org/[slug]/audience/+page.svelte | 10 +- .../routes/org/[slug]/community/+page.svelte | 5 +- .../org/[slug]/community/[slug]/+page.svelte | 36 +- .../org/[slug]/community/ask/+page.svelte | 28 +- .../routes/org/[slug]/courses/+page.svelte | 17 +- .../org/[slug]/quiz/[slug]/+page.svelte | 4 +- .../routes/org/[slug]/settings/+page.svelte | 3 +- .../src/routes/org/[slug]/setup/+page.svelte | 20 +- .../src/routes/org/[slug]/setup/+page.ts | 36 +- pnpm-lock.yaml | 54 +- .../migrations/20240323154037_translation.sql | 13 + supabase/seed.sql | 2 + 153 files changed, 11264 insertions(+), 1130 deletions(-) create mode 100644 apps/dashboard/src/lib/components/Course/components/Lesson/Materials/Loader.svelte create mode 100644 apps/dashboard/src/lib/components/Org/Settings/LanguagePicker.svelte create mode 100644 apps/dashboard/src/lib/utils/constants/translation.ts create mode 100644 apps/dashboard/src/lib/utils/functions/translations.ts create mode 100644 apps/dashboard/src/lib/utils/translations/de.json create mode 100644 apps/dashboard/src/lib/utils/translations/en.json create mode 100644 apps/dashboard/src/lib/utils/translations/es.json create mode 100644 apps/dashboard/src/lib/utils/translations/fr.json create mode 100644 apps/dashboard/src/lib/utils/translations/hi.json create mode 100644 apps/dashboard/src/lib/utils/translations/pt.json create mode 100644 apps/dashboard/src/lib/utils/translations/ru.json create mode 100644 apps/dashboard/src/lib/utils/translations/vi.json create mode 100644 apps/dashboard/src/routes/api/i18n/+server.ts create mode 100644 supabase/migrations/20240323154037_translation.sql diff --git a/apps/classroomio-com/src/routes/transition.svelte b/apps/classroomio-com/src/routes/transition.svelte index 2f21313a..78c4f719 100644 --- a/apps/classroomio-com/src/routes/transition.svelte +++ b/apps/classroomio-com/src/routes/transition.svelte @@ -1,6 +1,5 @@ diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json index 32757de0..de0ed00a 100644 --- a/apps/dashboard/package.json +++ b/apps/dashboard/package.json @@ -54,6 +54,7 @@ "stripe": "^14.22.0", "svelte-email": "^0.0.4", "svelte-ui": "workspace:*", + "sveltekit-i18n": "^2.4.2", "unsplash-js": "^7.0.18", "wait-on": "^7.0.1", "zod": "^3.21.4" diff --git a/apps/dashboard/src/lib/components/Apps/components/Comments/index.svelte b/apps/dashboard/src/lib/components/Apps/components/Comments/index.svelte index c4060285..64055cc3 100644 --- a/apps/dashboard/src/lib/components/Apps/components/Comments/index.svelte +++ b/apps/dashboard/src/lib/components/Apps/components/Comments/index.svelte @@ -14,6 +14,7 @@ import { group } from '$lib/components/Course/store'; import { profile } from '$lib/utils/store/user'; import { calDateDiff } from '$lib/utils/functions/date'; + import { t } from '$lib/utils/functions/translations'; export let handleClose = () => {}; @@ -49,7 +50,7 @@ ...comments, { comment: comment, - name: 'You', + name: $t('course.navItem.lessons.comments.you'), avatar: $profile.avatar_url, commentAt: new Date() } @@ -165,7 +166,7 @@ commentAt: lessonComment.created_at, name: lessonComment.groupmember.id === groupmember?.id - ? 'You' + ? $t('course.navItem.lessons.comments.you') : lessonComment.groupmember.profile.fullname }; }); @@ -191,7 +192,7 @@ $: !isFetched && fetchComments($group.people, $lesson.id); - +
@@ -224,7 +225,7 @@ {/each} {/if} diff --git a/apps/dashboard/src/lib/components/Apps/components/Poll/service.ts b/apps/dashboard/src/lib/components/Apps/components/Poll/service.ts index 516e35a5..ed79ad94 100644 --- a/apps/dashboard/src/lib/components/Apps/components/Poll/service.ts +++ b/apps/dashboard/src/lib/components/Apps/components/Poll/service.ts @@ -45,7 +45,7 @@ export const updatePollStatus = async (pollId: string, status: PollType['status' if (error) { console.log(error); - snackbar.error('An error occurred while updating poll status'); + snackbar.error('snackbar.poll.error.updating_poll'); return; } }; @@ -64,7 +64,7 @@ export const togglePollSubmission = async ( }); if (error) { console.log(error); - snackbar.error('An error occurred while submitting poll'); + snackbar.error('snackbar.poll.error.submitting_poll'); return; } } else { @@ -76,7 +76,7 @@ export const togglePollSubmission = async ( if (error) { console.log(error); - snackbar.error('An error occurred while submitting poll'); + snackbar.error('snackbar.poll.error.submitting_poll'); return; } } @@ -101,7 +101,7 @@ export function handleVote(pollId: string, groupmemberId: string, author: PollTy if (poll.id === pollId) { // Prevent user from voting on a poll that the status is not published if (poll.status !== 'published') { - snackbar.info('Poll is not published yet'); + snackbar.info('snackbar.poll.info.not_published'); return poll; } @@ -109,7 +109,7 @@ export function handleVote(pollId: string, groupmemberId: string, author: PollTy if ( poll.options.some((option) => isOptionSelectedByCurrentUser(option, groupmemberId)) ) { - snackbar.info('You can only vote once'); + snackbar.info('snackbar.poll.info.vote_once'); return poll; } diff --git a/apps/dashboard/src/lib/components/Buttons/Logout/index.svelte b/apps/dashboard/src/lib/components/Buttons/Logout/index.svelte index 2332d4c7..597aa905 100644 --- a/apps/dashboard/src/lib/components/Buttons/Logout/index.svelte +++ b/apps/dashboard/src/lib/components/Buttons/Logout/index.svelte @@ -1,7 +1,30 @@ - + diff --git a/apps/dashboard/src/lib/components/Buttons/VisitOrgSite.svelte b/apps/dashboard/src/lib/components/Buttons/VisitOrgSite.svelte index e5f43849..e772f585 100644 --- a/apps/dashboard/src/lib/components/Buttons/VisitOrgSite.svelte +++ b/apps/dashboard/src/lib/components/Buttons/VisitOrgSite.svelte @@ -4,6 +4,7 @@ import ArrowUpRightIcon from '$lib/components/Icons/ArrowTopRight.svelte'; import { currentOrgDomain } from '$lib/utils/store/org'; import { isMobile } from '$lib/utils/store/useMobile'; + import { t } from '$lib/utils/functions/translations'; export let className = ''; @@ -11,7 +12,7 @@ {#if !$isMobile} - View site + {$t('settings.subheadings.view_site')} {/if} diff --git a/apps/dashboard/src/lib/components/ComingSoon/index.svelte b/apps/dashboard/src/lib/components/ComingSoon/index.svelte index fc7a8aeb..146fd056 100644 --- a/apps/dashboard/src/lib/components/ComingSoon/index.svelte +++ b/apps/dashboard/src/lib/components/ComingSoon/index.svelte @@ -1,5 +1,6 @@

Certificate settings{$t('course.navItem.certificates.certificate_settings')} -

Choose a theme

+

+ {$t('course.navItem.certificates.theme')} +

-

Brand Logo

+

+ {$t('course.navItem.certificates.logo')} +

- To update your brand image, go to Settings > Organisation settings and upload your brand logo + {$t('course.navItem.certificates.to_update')} + {$t('course.navItem.certificates.settings')} + {$t('course.navItem.certificates.and_upload')}

goto(`/org/${$currentOrg.siteName}/settings`)} />
-

Course Description

+

+ {$t('course.navItem.certificates.description')} +