diff --git a/client/src/pages/dashboard/statistic/AssignmentList.vue b/client/src/pages/dashboard/statistic/AssignmentList.vue index 3d72eff4..6e5b528f 100644 --- a/client/src/pages/dashboard/statistic/AssignmentList.vue +++ b/client/src/pages/dashboard/statistic/AssignmentList.vue @@ -49,7 +49,7 @@ async function exportData() { return; } const filteredItems = statisticFilter.value.getFilteredItems(); - await exportDataAsXls(filteredItems, exportCompetenceElements); + await exportDataAsXls(filteredItems, exportCompetenceElements, userStore.language); } diff --git a/client/src/pages/dashboard/statistic/AttendanceList.vue b/client/src/pages/dashboard/statistic/AttendanceList.vue index c8b57ed1..f5369042 100644 --- a/client/src/pages/dashboard/statistic/AttendanceList.vue +++ b/client/src/pages/dashboard/statistic/AttendanceList.vue @@ -36,7 +36,7 @@ async function exportData() { return; } const filteredItems = statisticFilter.value.getFilteredItems(); - await exportDataAsXls(filteredItems, exportAttendance); + await exportDataAsXls(filteredItems, exportAttendance, userStore.language); } diff --git a/client/src/pages/dashboard/statistic/FeedbackList.vue b/client/src/pages/dashboard/statistic/FeedbackList.vue index 1bacde78..efd01dea 100644 --- a/client/src/pages/dashboard/statistic/FeedbackList.vue +++ b/client/src/pages/dashboard/statistic/FeedbackList.vue @@ -27,7 +27,7 @@ async function exportData() { return; } const filteredItems = statisticFilter.value.getFilteredItems(); - await exportDataAsXls(filteredItems, exportFeedback); + await exportDataAsXls(filteredItems, exportFeedback, userStore.language); } diff --git a/client/src/services/dashboard.ts b/client/src/services/dashboard.ts index 82bab340..422bf2dc 100644 --- a/client/src/services/dashboard.ts +++ b/client/src/services/dashboard.ts @@ -195,21 +195,30 @@ export async function fetchOpenTasksCount(courseId: string) { } export async function exportFeedback( - data: XlsExportRequestData + data: XlsExportRequestData, + language: string ): Promise { - return await itPost("/api/dashboard/export/feedback/", data); + return await itPost("/api/dashboard/export/feedback/", data, { + headers: { "Accept-Language": language }, + }); } export async function exportAttendance( - data: XlsExportRequestData + data: XlsExportRequestData, + language: string ): Promise { - return await itPost("/api/dashboard/export/attendance/", data); + return await itPost("/api/dashboard/export/attendance/", data, { + headers: { "Accept-Language": language }, + }); } export async function exportCompetenceElements( - data: XlsExportRequestData + data: XlsExportRequestData, + language: string ): Promise { - return await itPost("/api/dashboard/export/competence_elements/", data); + return await itPost("/api/dashboard/export/competence_elements/", data, { + headers: { "Accept-Language": language }, + }); } export function courseIdForCourseSlug( diff --git a/client/src/utils/export.ts b/client/src/utils/export.ts index 67069455..bf72e286 100644 --- a/client/src/utils/export.ts +++ b/client/src/utils/export.ts @@ -5,15 +5,16 @@ import type { } from "@/types"; interface exportApiCall { - (data: XlsExportRequestData): Promise; + (data: XlsExportRequestData, language: string): Promise; } export async function exportDataAsXls( items: StatisticsFilterItem[], - apiCall: exportApiCall + apiCall: exportApiCall, + language: string ) { const itemIds = extractUniqueIds(items); - const data = await apiCall(itemIds); + const data = await apiCall(itemIds, language); openDataAsXls(data.encoded_data, data.file_name); } diff --git a/server/locale/de/LC_MESSAGES/django.po b/server/locale/de/LC_MESSAGES/django.po index abac3a2b..826c9f35 100644 --- a/server/locale/de/LC_MESSAGES/django.po +++ b/server/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-17 15:43+0200\n" +"POT-Creation-Date: 2024-06-18 15:24+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -22,16 +22,24 @@ msgstr "" msgid "export_kompetenznachweis_elemente" msgstr "" -#: vbv_lernwelt/assignment/export.py:183 +#: vbv_lernwelt/assignment/export.py:142 +msgid "Resultat" +msgstr "" + +#: vbv_lernwelt/assignment/export.py:143 +msgid "bestanden" +msgstr "" + +#: vbv_lernwelt/assignment/export.py:187 msgid "Bestanden" msgstr "" -#: vbv_lernwelt/assignment/export.py:185 +#: vbv_lernwelt/assignment/export.py:189 msgid "Nicht bestanden" msgstr "" -#: vbv_lernwelt/assignment/export.py:199 vbv_lernwelt/assignment/export.py:202 -#: vbv_lernwelt/assignment/export.py:203 +#: vbv_lernwelt/assignment/export.py:203 vbv_lernwelt/assignment/export.py:206 +#: vbv_lernwelt/assignment/export.py:207 msgid "Keine Daten" msgstr "" @@ -111,28 +119,31 @@ msgstr "" msgid "export_anwesenheit" msgstr "" -#: vbv_lernwelt/course_session/services/export_attendance.py:113 +#: vbv_lernwelt/course_session/services/export_attendance.py:92 +msgid "Anwesenheit" +msgstr "" + +#: vbv_lernwelt/course_session/services/export_attendance.py:116 msgid "Anwesend" msgstr "" -#: vbv_lernwelt/course_session/services/export_attendance.py:113 +#: vbv_lernwelt/course_session/services/export_attendance.py:116 msgid "Nicht anwesend" msgstr "" -#: vbv_lernwelt/course_session/services/export_attendance.py:120 +#: vbv_lernwelt/course_session/services/export_attendance.py:123 msgid "Vorname" msgstr "" -#: vbv_lernwelt/course_session/services/export_attendance.py:121 +#: vbv_lernwelt/course_session/services/export_attendance.py:124 msgid "Nachname" msgstr "" -#: vbv_lernwelt/course_session/services/export_attendance.py:122 +#: vbv_lernwelt/course_session/services/export_attendance.py:125 msgid "Email" msgstr "Email" -#: vbv_lernwelt/course_session/services/export_attendance.py:123 -#: vbv_lernwelt/course_session/services/export_attendance.py:135 +#: vbv_lernwelt/course_session/services/export_attendance.py:126 msgid "Lehrvertragsnummer" msgstr "" diff --git a/server/locale/fr/LC_MESSAGES/django.mo b/server/locale/fr/LC_MESSAGES/django.mo index 43c07650..4bf66c9d 100644 Binary files a/server/locale/fr/LC_MESSAGES/django.mo and b/server/locale/fr/LC_MESSAGES/django.mo differ diff --git a/server/locale/fr/LC_MESSAGES/django.po b/server/locale/fr/LC_MESSAGES/django.po index 209a4b6e..d338278e 100644 --- a/server/locale/fr/LC_MESSAGES/django.po +++ b/server/locale/fr/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-17 15:43+0200\n" +"POT-Creation-Date: 2024-06-18 15:24+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -22,16 +22,24 @@ msgstr "" msgid "export_kompetenznachweis_elemente" msgstr "export_elements_de_controle" -#: vbv_lernwelt/assignment/export.py:183 +#: vbv_lernwelt/assignment/export.py:142 +msgid "Resultat" +msgstr "Résultats" + +#: vbv_lernwelt/assignment/export.py:143 +msgid "bestanden" +msgstr "réussi" + +#: vbv_lernwelt/assignment/export.py:187 msgid "Bestanden" msgstr "Réussi" -#: vbv_lernwelt/assignment/export.py:185 +#: vbv_lernwelt/assignment/export.py:189 msgid "Nicht bestanden" msgstr "Échoué" -#: vbv_lernwelt/assignment/export.py:199 vbv_lernwelt/assignment/export.py:202 -#: vbv_lernwelt/assignment/export.py:203 +#: vbv_lernwelt/assignment/export.py:203 vbv_lernwelt/assignment/export.py:206 +#: vbv_lernwelt/assignment/export.py:207 msgid "Keine Daten" msgstr "Aucune donnée" @@ -111,28 +119,32 @@ msgstr "" msgid "export_anwesenheit" msgstr "export_presence" -#: vbv_lernwelt/course_session/services/export_attendance.py:113 +#: vbv_lernwelt/course_session/services/export_attendance.py:92 +#| msgid "Anwesend" +msgid "Anwesenheit" +msgstr "Présence" + +#: vbv_lernwelt/course_session/services/export_attendance.py:116 msgid "Anwesend" msgstr "Présent" -#: vbv_lernwelt/course_session/services/export_attendance.py:113 +#: vbv_lernwelt/course_session/services/export_attendance.py:116 msgid "Nicht anwesend" msgstr "Pas présent" -#: vbv_lernwelt/course_session/services/export_attendance.py:120 +#: vbv_lernwelt/course_session/services/export_attendance.py:123 msgid "Vorname" msgstr "Prénom" -#: vbv_lernwelt/course_session/services/export_attendance.py:121 +#: vbv_lernwelt/course_session/services/export_attendance.py:124 msgid "Nachname" msgstr "Nom de famille" -#: vbv_lernwelt/course_session/services/export_attendance.py:122 +#: vbv_lernwelt/course_session/services/export_attendance.py:125 msgid "Email" msgstr "Email" -#: vbv_lernwelt/course_session/services/export_attendance.py:123 -#: vbv_lernwelt/course_session/services/export_attendance.py:135 +#: vbv_lernwelt/course_session/services/export_attendance.py:126 msgid "Lehrvertragsnummer" msgstr "Numéro de contrat d'apprentissage" diff --git a/server/locale/it/LC_MESSAGES/django.mo b/server/locale/it/LC_MESSAGES/django.mo index 0993e981..e565176b 100644 Binary files a/server/locale/it/LC_MESSAGES/django.mo and b/server/locale/it/LC_MESSAGES/django.mo differ diff --git a/server/locale/it/LC_MESSAGES/django.po b/server/locale/it/LC_MESSAGES/django.po index bd4d61d5..522df647 100644 --- a/server/locale/it/LC_MESSAGES/django.po +++ b/server/locale/it/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-17 15:43+0200\n" +"POT-Creation-Date: 2024-06-18 15:24+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -22,16 +22,24 @@ msgstr "" msgid "export_kompetenznachweis_elemente" msgstr "esportazione_elementi_del_controllo" -#: vbv_lernwelt/assignment/export.py:183 +#: vbv_lernwelt/assignment/export.py:142 +msgid "Resultat" +msgstr "Risultato" + +#: vbv_lernwelt/assignment/export.py:143 +msgid "bestanden" +msgstr "superato" + +#: vbv_lernwelt/assignment/export.py:187 msgid "Bestanden" msgstr "Superato" -#: vbv_lernwelt/assignment/export.py:185 +#: vbv_lernwelt/assignment/export.py:189 msgid "Nicht bestanden" msgstr "Fallito" -#: vbv_lernwelt/assignment/export.py:199 vbv_lernwelt/assignment/export.py:202 -#: vbv_lernwelt/assignment/export.py:203 +#: vbv_lernwelt/assignment/export.py:203 vbv_lernwelt/assignment/export.py:206 +#: vbv_lernwelt/assignment/export.py:207 msgid "Keine Daten" msgstr "Nessun dato" @@ -111,28 +119,32 @@ msgstr "" msgid "export_anwesenheit" msgstr "esportazione_presenza" -#: vbv_lernwelt/course_session/services/export_attendance.py:113 +#: vbv_lernwelt/course_session/services/export_attendance.py:92 +#| msgid "Anwesend" +msgid "Anwesenheit" +msgstr "Presenza" + +#: vbv_lernwelt/course_session/services/export_attendance.py:116 msgid "Anwesend" msgstr "Presente" -#: vbv_lernwelt/course_session/services/export_attendance.py:113 +#: vbv_lernwelt/course_session/services/export_attendance.py:116 msgid "Nicht anwesend" msgstr "Non presente" -#: vbv_lernwelt/course_session/services/export_attendance.py:120 +#: vbv_lernwelt/course_session/services/export_attendance.py:123 msgid "Vorname" msgstr "Nome" -#: vbv_lernwelt/course_session/services/export_attendance.py:121 +#: vbv_lernwelt/course_session/services/export_attendance.py:124 msgid "Nachname" msgstr "Cognome" -#: vbv_lernwelt/course_session/services/export_attendance.py:122 +#: vbv_lernwelt/course_session/services/export_attendance.py:125 msgid "Email" msgstr "E-mail" -#: vbv_lernwelt/course_session/services/export_attendance.py:123 -#: vbv_lernwelt/course_session/services/export_attendance.py:135 +#: vbv_lernwelt/course_session/services/export_attendance.py:126 msgid "Lehrvertragsnummer" msgstr "Numero di contratto di tirocinio" diff --git a/server/vbv_lernwelt/assignment/export.py b/server/vbv_lernwelt/assignment/export.py index f8cbc205..230cb661 100644 --- a/server/vbv_lernwelt/assignment/export.py +++ b/server/vbv_lernwelt/assignment/export.py @@ -2,7 +2,7 @@ from dataclasses import dataclass from io import BytesIO import structlog -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from openpyxl import Workbook from vbv_lernwelt.assignment.models import ( @@ -138,16 +138,20 @@ def _create_sheet( col_prefix = f'Circle "{circle.title}" {cse.learning_content.title}' + # add translation strings here as they are not picked up in f-strings + result_str = str(_("Resultat")) + success_str = str(_("bestanden")) + sheet.cell( row=1, column=col_idx, - value=f"{col_prefix} {_('bestanden')}", + value=f"{col_prefix} {success_str}", ) sheet.cell( row=1, column=col_idx + 1, - value=f"{col_prefix} {_('Resultat')} %", + value=f"{col_prefix} {result_str} %", ) ordered_assignement_ids.append(cse.assignment.id) @@ -180,9 +184,9 @@ def _add_rows( if user_ac: status_text = ( - _("Bestanden") + str(_("Bestanden")) if user_ac.evaluation_passed - else _("Nicht bestanden") + else str(_("Nicht bestanden")) ) sheet.cell(row=row_idx, column=col_idx, value=status_text) try: @@ -196,11 +200,13 @@ def _add_rows( ), ) except (ZeroDivisionError, TypeError): - sheet.cell(row=row_idx, column=col_idx + 1, value=_("Keine Daten")) + sheet.cell( + row=row_idx, column=col_idx + 1, value=str(_("Keine Daten")) + ) else: - sheet.cell(row=row_idx, column=col_idx, value=_("Keine Daten")) - sheet.cell(row=row_idx, column=col_idx + 1, value=_("Keine Daten")) + sheet.cell(row=row_idx, column=col_idx, value=str(_("Keine Daten"))) + sheet.cell(row=row_idx, column=col_idx + 1, value=str(_("Keine Daten"))) col_idx += 2 diff --git a/server/vbv_lernwelt/assignment/tests/test_assignment_completions_export.py b/server/vbv_lernwelt/assignment/tests/test_assignment_completions_export.py index 550bf67f..95528bcc 100644 --- a/server/vbv_lernwelt/assignment/tests/test_assignment_completions_export.py +++ b/server/vbv_lernwelt/assignment/tests/test_assignment_completions_export.py @@ -1,5 +1,6 @@ import io +from django.utils.translation import activate from openpyxl import load_workbook from vbv_lernwelt.assignment.export import export_competence_elements @@ -50,7 +51,7 @@ class AssignmentCompletionExportTestCase(ExportBaseTestCase): self.test_student2.additional_json_data = {"Lehrvertragsnummer": 1987654321} self.test_student2.save() - test_student3 = User.objects.get(email="test-student3@example.com") + self.test_student3 = User.objects.get(email="test-student3@example.com") # Bern assignments update_assignment_completion( @@ -102,9 +103,9 @@ class AssignmentCompletionExportTestCase(ExportBaseTestCase): "Keine Daten", ], [ - test_student3.first_name, - test_student3.last_name, - test_student3.email, + self.test_student3.first_name, + self.test_student3.last_name, + self.test_student3.email, None, "Keine Daten", "Keine Daten", @@ -122,15 +123,7 @@ class AssignmentCompletionExportTestCase(ExportBaseTestCase): def _make_header( self, ): - casework_assignment = CourseSessionAssignment.objects.filter( - course_session__id=self.course_session_be.id, - learning_content__content_assignment__competence_certificate__isnull=False, - ).first() - - edoniq_assignment = CourseSessionEdoniqTest.objects.filter( - course_session__id=self.course_session_be.id, - learning_content__content_assignment__competence_certificate__isnull=False, - ).first() + casework_assignment, edoniq_assignment = self._get_assignments() return [ "Vorname", @@ -143,6 +136,19 @@ class AssignmentCompletionExportTestCase(ExportBaseTestCase): f'Circle "{self.casework.get_attached_circle_title()}" {casework_assignment.learning_content.title} Resultat %', ] + def _get_assignments(self): + casework_assignment = CourseSessionAssignment.objects.filter( + course_session__id=self.course_session_be.id, + learning_content__content_assignment__competence_certificate__isnull=False, + ).first() + + edoniq_assignment = CourseSessionEdoniqTest.objects.filter( + course_session__id=self.course_session_be.id, + learning_content__content_assignment__competence_certificate__isnull=False, + ).first() + + return casework_assignment, edoniq_assignment + def test_export_single_cs(self): wb = self._generate_workbook([self.course_session_be.id]) self.assertEqual(len(wb.sheetnames), 1) @@ -212,3 +218,107 @@ class AssignmentCompletionExportTestCase(ExportBaseTestCase): wb.active = wb["Test Zürich 2022 a"] self._check_export(wb, expected_data, 2, 5) + + def test_french_export(self): + activate("fr") + wb = self._generate_workbook([self.course_session_be.id]) + + casework_assignment, edoniq_assignment = self._get_assignments() + + header = [ + "Prénom", + "Nom de famille", + "E-mail", + "Numéro de contrat d'apprentissage", + f'Circle "{self.edoniq_test.get_attached_circle_title()}" {edoniq_assignment.learning_content.title} réussi', + f'Circle "{self.edoniq_test.get_attached_circle_title()}" {edoniq_assignment.learning_content.title} Résultats %', + f'Circle "{self.casework.get_attached_circle_title()}" {casework_assignment.learning_content.title} réussi', + f'Circle "{self.casework.get_attached_circle_title()}" {casework_assignment.learning_content.title} Résultats %', + ] + + expected_data_be = [ + header, + [ + self.test_student1.first_name, + self.test_student1.last_name, + self.test_student1.email, + self.test_student1.additional_json_data["Lehrvertragsnummer"], + "Échoué", + 58, + "Réussi", + 83, + ], + [ + self.test_student2.first_name, + self.test_student2.last_name, + self.test_student2.email, + self.test_student2.additional_json_data["Lehrvertragsnummer"], + "Réussi", + 100, + "Aucune donnée", + "Aucune donnée", + ], + [ + self.test_student3.first_name, + self.test_student3.last_name, + self.test_student3.email, + None, + "Aucune donnée", + "Aucune donnée", + "Aucune donnée", + "Aucune donnée", + ], + ] + self._check_export(wb, expected_data_be, 4, 8) + + def test_italian_export(self): + activate("it") + wb = self._generate_workbook([self.course_session_be.id]) + + casework_assignment, edoniq_assignment = self._get_assignments() + + header = [ + "Nome", + "Cognome", + "Email", + "Numero di contratto di tirocinio", + f'Circle "{self.edoniq_test.get_attached_circle_title()}" {edoniq_assignment.learning_content.title} superato', + f'Circle "{self.edoniq_test.get_attached_circle_title()}" {edoniq_assignment.learning_content.title} Risultato %', + f'Circle "{self.casework.get_attached_circle_title()}" {casework_assignment.learning_content.title} superato', + f'Circle "{self.casework.get_attached_circle_title()}" {casework_assignment.learning_content.title} Risultato %', + ] + + expected_data_be = [ + header, + [ + self.test_student1.first_name, + self.test_student1.last_name, + self.test_student1.email, + self.test_student1.additional_json_data["Lehrvertragsnummer"], + "Fallito", + 58, + "Superato", + 83, + ], + [ + self.test_student2.first_name, + self.test_student2.last_name, + self.test_student2.email, + self.test_student2.additional_json_data["Lehrvertragsnummer"], + "Superato", + 100, + "Nessun dato", + "Nessun dato", + ], + [ + self.test_student3.first_name, + self.test_student3.last_name, + self.test_student3.email, + None, + "Nessun dato", + "Nessun dato", + "Nessun dato", + "Nessun dato", + ], + ] + self._check_export(wb, expected_data_be, 4, 8) diff --git a/server/vbv_lernwelt/course_session/services/export_attendance.py b/server/vbv_lernwelt/course_session/services/export_attendance.py index 4ce81de1..71587217 100644 --- a/server/vbv_lernwelt/course_session/services/export_attendance.py +++ b/server/vbv_lernwelt/course_session/services/export_attendance.py @@ -4,7 +4,7 @@ from io import BytesIO from itertools import groupby import structlog -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from openpyxl import Workbook from vbv_lernwelt.course.models import CourseSessionUser @@ -83,15 +83,18 @@ def _create_sheet( # common user headers..., , status , .. col_idx = add_user_headers(sheet) attendance_data = {} + for course in attendance_courses: circle = course.get_circle() if circle_ids and circle.id not in circle_ids: continue + presence_str = str(_("Anwesenheit")) # f-strings are not picked up by gettext + sheet.cell( row=1, column=col_idx, - value=f"{_('Anwesenheit')} {circle.title} {course.due_date.start.strftime('%d.%m.%Y')}", + value=f"{presence_str} {circle.title} {course.due_date.start.strftime('%d.%m.%Y')}", ) user_dict_map = {d["user_id"]: d for d in course.attendance_user_list} attendance_data[circle.title] = user_dict_map @@ -110,17 +113,18 @@ def _add_rows(sheet, users: list[CourseSessionUser], attendance_data): for key, user_dict_map in attendance_data.items(): user_dict = user_dict_map.get(str(user.user.id), {}) status = user_dict.get("status", "") if user_dict else "" - status_text = _("Anwesend") if status == "PRESENT" else _("Nicht anwesend") + status_text = ( + str(_("Anwesend")) if status == "PRESENT" else str(_("Nicht anwesend")) + ) sheet.cell(row=row_idx, column=col_idx, value=status_text) col_idx += 1 def add_user_headers(sheet): - # todo: translate headers - sheet.cell(row=1, column=1, value=_("Vorname")) - sheet.cell(row=1, column=2, value=_("Nachname")) - sheet.cell(row=1, column=3, value=_("Email")) - sheet.cell(row=1, column=4, value=_("Lehrvertragsnummer")) + sheet.cell(row=1, column=1, value=str(_("Vorname"))) + sheet.cell(row=1, column=2, value=str(_("Nachname"))) + sheet.cell(row=1, column=3, value=str(_("Email"))) + sheet.cell(row=1, column=4, value=str(_("Lehrvertragsnummer"))) return 5 # return the next column index @@ -132,7 +136,7 @@ def add_user_export_data(sheet, user: CourseSessionUser, row_idx: int) -> int: sheet.cell( row=row_idx, column=4, - value=user.user.additional_json_data.get(_("Lehrvertragsnummer"), ""), + value=user.user.additional_json_data.get("Lehrvertragsnummer", ""), ) return 5 # return the next column index diff --git a/server/vbv_lernwelt/course_session/tests/test_attendance_export.py b/server/vbv_lernwelt/course_session/tests/test_attendance_export.py index 242febc3..350ffaa4 100644 --- a/server/vbv_lernwelt/course_session/tests/test_attendance_export.py +++ b/server/vbv_lernwelt/course_session/tests/test_attendance_export.py @@ -1,6 +1,7 @@ import io from django.test import TestCase +from django.utils.translation import activate, deactivate from openpyxl import load_workbook from vbv_lernwelt.core.constants import TEST_STUDENT1_USER_ID, TEST_STUDENT2_USER_ID @@ -19,6 +20,10 @@ class ExportBaseTestCase(TestCase): cell.value, expected_data[row[0].row - 1][row.index(cell)] ) + def tearDown(self): + # Deactivate the language after the test + deactivate() + class AttendanceExportTestCase(ExportBaseTestCase): def setUp(self): @@ -41,7 +46,7 @@ class AttendanceExportTestCase(ExportBaseTestCase): self.test_student2.additional_json_data = {"Lehrvertragsnummer": 1987654321} self.test_student2.save() - test_student3 = User.objects.get(email="test-student3@example.com") + self.test_student3 = User.objects.get(email="test-student3@example.com") self.attendance_course_be.attendance_user_list = [ { "email": self.test_student1.email, @@ -69,9 +74,9 @@ class AttendanceExportTestCase(ExportBaseTestCase): "Nicht anwesend", ], [ - test_student3.first_name, - test_student3.last_name, - test_student3.email, + self.test_student3.first_name, + self.test_student3.last_name, + self.test_student3.email, None, "Nicht anwesend", ], @@ -135,3 +140,79 @@ class AttendanceExportTestCase(ExportBaseTestCase): wb.active = wb["Test Zürich 2022 a"] self._check_export(wb, expected_data_zh, 2, 5) + + def test_french_export(self): + activate("fr") + wb = self._generate_workbook([self.course_session_be.id]) + + header = [ + "Prénom", + "Nom de famille", + "E-mail", + "Numéro de contrat d'apprentissage", + f"Présence {self.attendance_course_be.get_circle().title} {self.attendance_course_be.due_date.start.strftime('%d.%m.%Y')}", + ] + + expected_data_be = [ + header, + [ + self.test_student1.first_name, + self.test_student1.last_name, + self.test_student1.email, + self.test_student1.additional_json_data["Lehrvertragsnummer"], + "Présent", + ], + [ + self.test_student2.first_name, + self.test_student2.last_name, + self.test_student2.email, + self.test_student2.additional_json_data["Lehrvertragsnummer"], + "Pas présent", + ], + [ + self.test_student3.first_name, + self.test_student3.last_name, + self.test_student3.email, + None, + "Pas présent", + ], + ] + self._check_export(wb, expected_data_be, 4, 5) + + def test_italian_export(self): + activate("it") + wb = self._generate_workbook([self.course_session_be.id]) + + header = [ + "Nome", + "Cognome", + "Email", + "Numero di contratto di tirocinio", + f"Presenza {self.attendance_course_be.get_circle().title} {self.attendance_course_be.due_date.start.strftime('%d.%m.%Y')}", + ] + + expected_data_be = [ + header, + [ + self.test_student1.first_name, + self.test_student1.last_name, + self.test_student1.email, + self.test_student1.additional_json_data["Lehrvertragsnummer"], + "Presente", + ], + [ + self.test_student2.first_name, + self.test_student2.last_name, + self.test_student2.email, + self.test_student2.additional_json_data["Lehrvertragsnummer"], + "Non presente", + ], + [ + self.test_student3.first_name, + self.test_student3.last_name, + self.test_student3.email, + None, + "Non presente", + ], + ] + self._check_export(wb, expected_data_be, 4, 5) diff --git a/server/vbv_lernwelt/feedback/export.py b/server/vbv_lernwelt/feedback/export.py index 2dab9cb6..879906a7 100644 --- a/server/vbv_lernwelt/feedback/export.py +++ b/server/vbv_lernwelt/feedback/export.py @@ -5,7 +5,7 @@ from typing import List, Tuple import structlog from django.db.models import QuerySet -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from openpyxl import Workbook from vbv_lernwelt.course_session.services.export_attendance import ( @@ -147,11 +147,11 @@ def _create_sheet(wb: Workbook, title: str, data: list[FeedbackResponse]): ) # add header - sheet.cell(row=1, column=1, value=_("Durchführung")) - sheet.cell(row=1, column=2, value=_("Datum")) + sheet.cell(row=1, column=1, value=str(_("Durchführung"))) + sheet.cell(row=1, column=2, value=str(_("Datum"))) questions = [q[1] for q in question_data] for col_idx, title in enumerate(questions, start=3): - sheet.cell(row=1, column=col_idx, value=title) + sheet.cell(row=1, column=col_idx, value=str(title)) _add_rows(sheet, data, question_data) return sheet diff --git a/server/vbv_lernwelt/feedback/tests/test_feedback_export.py b/server/vbv_lernwelt/feedback/tests/test_feedback_export.py index c24a7f93..d9785dac 100644 --- a/server/vbv_lernwelt/feedback/tests/test_feedback_export.py +++ b/server/vbv_lernwelt/feedback/tests/test_feedback_export.py @@ -1,6 +1,7 @@ import datetime import io +from django.utils.translation import activate from openpyxl import load_workbook from vbv_lernwelt.core.constants import TEST_STUDENT1_USER_ID, TEST_STUDENT2_USER_ID @@ -201,3 +202,53 @@ class FeedbackExportTestCase(ExportBaseTestCase): self.assertEqual(wb.sheetnames[0], "Fahrzeug") self._check_export(wb, self.expected_data_fahrzeug, 3, 12) + + def test_french_export(self): + activate("fr") + wb = self._generate_workbook( + [self.course_session_be.id, self.course_session_zh.id] + ) + + header = [ + "Opérations", + "Date", + "Degré de satisfaction au global", + "Degré de réalisation des objectifs", + "As-tu l’impression de bien maîtriser les sujets qui ont été abordés pendant le cours ?", + "Les travaux préparatoires étaient-ils clairs et compréhensibles ?", + "Que penses-tu des compétences techniques de la personne chargée du cours et de sa maîtrise du sujet ?", + "Les questions et les suggestions des participants ont-elles été prises au sérieux et traitées correctement ?", + "Souhaites-tu ajouter quelque chose à l’intention de la personne chargée du cours ?", + "Est-ce que tu recommandes ce cours ?", + "Qu’est-ce qui t’a particulièrement plu ?", + "À ton avis, quels sont les points qui pourraient être améliorés ?", + ] + + self.expected_data_fahrzeug[0] = header + + self._check_export(wb, self.expected_data_fahrzeug, 3, 12) + + def test_italian_export(self): + activate("it") + wb = self._generate_workbook( + [self.course_session_be.id, self.course_session_zh.id] + ) + + header = [ + "Svolgimenti", + "Data", + "Soddisfazione complessiva", + "Raggiungimento complessivo degli obiettivi", + "Come valuti il tuo livello di preparazione sui temi dopo il corso?", + "Gli incarichi di preparazione erano chiari e comprensibili?", + "Come valuti il livello di preparazione sui temi e le competenze specialistiche dell’istruttore/istruttrice del corso?", + "Le domande e i suggerimenti dei/delle partecipanti al corso sono stati accolti e presi sul serio?", + "Cos’altro vorresti ancora dire all’istruttore/istruttrice del corso?", + "Raccomanderesti il corso?", + "Cos’hai apprezzato particolarmente?", + "Dove vedi un potenziale di miglioramento?", + ] + + self.expected_data_fahrzeug[0] = header + + self._check_export(wb, self.expected_data_fahrzeug, 3, 12) diff --git a/server/vbv_lernwelt/static/icons/icon-export.svg b/server/vbv_lernwelt/static/icons/icon-export.svg new file mode 100644 index 00000000..9e90e74d --- /dev/null +++ b/server/vbv_lernwelt/static/icons/icon-export.svg @@ -0,0 +1,4 @@ + + + +