diff --git a/lang/en/archives.php b/lang/en/archives.php new file mode 100644 index 00000000..fb95de47 --- /dev/null +++ b/lang/en/archives.php @@ -0,0 +1,89 @@ + 'Document archives', + 'title' => 'Document archives', + 'subtitle_docs' => ':count archived document(s)', + 'trashed_suffix' => ' · :count in trash', + 'view_active' => 'View active', + 'trash' => 'Trash', + 'archive_doc' => 'Archive a document', + 'search' => 'Search', + 'search_ph' => 'Title, reference…', + 'category' => 'Category', + 'all_categories' => 'All', + 'from' => 'From', + 'to' => 'To', + 'reset' => 'Reset', + 'th_reference' => 'Reference', + 'th_document' => 'Document', + 'th_tags' => 'Tags', + 'th_linked' => 'Linked to', + 'th_size' => 'Size', + 'th_archived' => 'Archived', + 'th_actions' => 'Actions', + 'empty_trash' => 'Trash is empty.', + 'empty' => 'No archived document.', + 'restore' => 'Restore', + 'delete_forever' => 'Delete permanently', + 'download' => 'Download', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'prev' => 'Previous', + 'next' => 'Next', + 'page_of' => 'Page :current / :last', + 'edit_title' => 'Edit document', + 'create_title' => 'Archive a document', + 'edit_desc' => 'Update the metadata and tags.', + 'create_desc' => 'Add a file to the document vault with its metadata and tags.', + 'f_title' => 'Title', + 'f_category' => 'Category', + 'retention' => 'Retain until', + 'description' => 'Description', + 'file' => 'File', + 'tags' => 'Tags', + 'add_tag_ph' => 'Add a tag then Enter…', + 'linked_to' => 'Linked to', + 'link_none' => 'None', + 'link_classroom' => 'Class', + 'link_student' => 'Student (ID number)', + 'classroom' => 'Class', + 'choose' => 'Choose', + 'student_matricule' => 'Student ID number', + 'cancel' => 'Cancel', + 'save' => 'Save', + 'archive' => 'Archive', + 'delete_forever_q' => 'Delete permanently?', + 'delete_forever_desc' => 'The file ":title" will be removed from storage. This action is irreversible.', + + // Tags + 'tags_page' => [ + 'head' => 'Archive tags', + 'title' => 'Archive tags', + 'subtitle' => 'Organize archived documents by reusable keywords.', + 'new_tag' => 'New tag', + 'total' => 'Total tags', + 'search_ph' => 'Search a tag by name...', + 'th_tag' => 'Tag', + 'th_documents' => 'Documents', + 'th_color' => 'Color', + 'th_actions' => 'Actions', + 'documents_count' => ':count document(s)', + 'change_color' => 'Change color', + 'color_aria' => 'Color :color', + 'delete' => 'Delete', + 'empty' => 'No tag found', + 'showing' => 'Showing :from to :to of :total', + 'new_tag_desc' => 'A reusable keyword to classify archived documents.', + 'name' => 'Tag name', + 'name_ph' => 'e.g. Contract, Inspection…', + 'color' => 'Color', + 'preview' => 'Preview:', + 'default_name' => 'Tag name', + 'cancel' => 'Cancel', + 'create' => 'Create', + 'delete_q' => 'Delete this tag?', + 'delete_desc' => 'The tag will be removed from all associated documents. The documents are not deleted.', + ], +]; diff --git a/lang/en/errors.php b/lang/en/errors.php new file mode 100644 index 00000000..c592218e --- /dev/null +++ b/lang/en/errors.php @@ -0,0 +1,36 @@ + 'Dashboard', + 'home' => 'Back to home', + 'previous' => 'Previous page', + + 'fallback' => [ + 'title' => 'An error occurred', + 'message' => 'Something went wrong. Please try again.', + ], + '403' => [ + 'title' => 'Access denied', + 'message' => 'You do not have permission to access this page.', + ], + '404' => [ + 'title' => 'Page not found', + 'message' => 'The page you are looking for does not exist or has been moved.', + ], + '419' => [ + 'title' => 'Session expired', + 'message' => 'Your session has expired. Please sign in again, then retry.', + ], + '429' => [ + 'title' => 'Too many requests', + 'message' => 'You have made too many requests. Please wait a moment before trying again.', + ], + '500' => [ + 'title' => 'Server error', + 'message' => 'An unexpected error occurred. Try again in a moment; if the problem persists, contact your school administrator.', + ], + '503' => [ + 'title' => 'Under maintenance', + 'message' => 'The service is temporarily unavailable. Please come back in a few moments.', + ], +]; diff --git a/lang/en/statistiques.php b/lang/en/statistiques.php new file mode 100644 index 00000000..4f3be7fc --- /dev/null +++ b/lang/en/statistiques.php @@ -0,0 +1,169 @@ + 'Statistics', + 'subtitle' => 'School indicators — enrollment, finances and success.', + 'year_ph' => 'Year', + 'class_ph' => 'Class', + 'gender_ph' => 'Gender', + 'all_classes' => 'All classes', + 'all' => 'All', + 'boys' => 'Boys', + 'girls' => 'Girls', + 'other' => 'Other', + 'active_suffix' => ' · active', + 'all_cycles' => 'All', + 'sort' => 'Sort', + 'sort_level' => 'By level', + 'sort_headcount' => 'By headcount', + 'sort_amount' => 'By amount', + 'sort_rate' => 'By rate', + 'years_old' => ':value yrs', + + // Tabs + 'tab_effectifs' => 'Enrollment & parity', + 'tab_finances' => 'Finances & recovery', + 'tab_reussite' => 'Success & exams', + 'tab_encadrement' => 'Supervision', + 'tab_assiduite' => 'Attendance', + 'tab_comparaisons' => 'Comparisons', + 'tab_geographie' => 'Geography', + + // Enrollment + 'kpi_total' => 'Total headcount', + 'kpi_total_sub' => ':boys B · :girls G', + 'kpi_ips' => 'Parity index (GPI)', + 'kpi_ips_sub' => ':pct% girls', + 'kpi_redoublement' => 'Repetition rate', + 'kpi_promotion_sub' => 'Promotion :pct%', + 'kpi_abandon' => 'Dropout rate', + 'kpi_age_sub' => 'Average age :age', + 'card_by_class' => 'Headcount by class (boys / girls)', + 'card_by_gender' => 'Breakdown by gender', + 'card_age_pyramid' => 'Age pyramid (boys / girls)', + 'overage_label' => 'Over-age rate (≥ +:threshold yrs)', + 'overage_hint' => 'Set the expected age on classes to enable this calculation.', + 'card_city' => 'Geographic origin (top cities, by gender)', + 'not_filled' => 'Not filled in', + + // Finances + 'kpi_billed' => 'Total billed', + 'kpi_billed_sub' => ':count invoices', + 'kpi_collected' => 'Collected', + 'kpi_recovery' => 'Recovery rate', + 'kpi_remaining_sub' => ':amount remaining', + 'kpi_unpaid' => 'Unpaid', + 'kpi_unpaid_sub' => ':count partial', + 'card_monthly' => 'Monthly collections', + 'card_methods' => 'Payment methods', + 'recovery_by_class' => 'Recovery by class', + 'card_billed_split' => 'Billed: collected / remaining', + 'series_collected' => 'Collected', + 'series_remaining' => 'Remaining', + 'card_recovery_rate' => 'Recovery rate by class', + 'rate_label' => 'Rate', + 'avg_prefix' => 'avg. :rate%', + 'legend_high' => '≥ 80 %', + 'legend_mid' => '60–79 %', + 'legend_low' => '< 60 %', + 'card_detail' => 'Detail by class', + 'th_class' => 'Class', + 'th_billed' => 'Billed', + 'th_collected' => 'Collected', + 'th_remaining' => 'Remaining', + 'th_rate' => 'Rate', + 'method_cash' => 'Cash', + 'method_mobile_money' => 'Mobile Money', + 'method_bank_transfer' => 'Transfer', + 'method_cheque' => 'Cheque', + + // Success + 'kpi_bulletins' => 'Validated reports', + 'kpi_average' => 'Overall average', + 'kpi_passrate' => 'Internal pass rate (≥10)', + 'kpi_admission' => 'Official exam admission', + 'card_mentions' => 'Distinction breakdown', + 'mention_passable' => 'Pass', + 'mention_assez_bien' => 'Fairly good', + 'mention_bien' => 'Good', + 'mention_tres_bien' => 'Very good', + 'card_exams' => 'Official exams (CEPD / BEPC / BAC)', + 'no_exams' => 'No official exam for this year', + 'th_exam' => 'Exam', + 'th_registered' => 'Registered', + 'th_admitted' => 'Admitted', + 'th_admission' => 'Admission', + + // Supervision + 'kpi_rem' => 'Student / teacher ratio', + 'kpi_rem_sub' => ':count teachers', + 'kpi_students' => 'Total headcount', + 'kpi_avg_class' => 'Average class size', + 'kpi_avg_class_sub' => ':count classes', + 'kpi_overcrowded' => 'Overcrowded classes', + 'kpi_overcrowded_sub' => '> :threshold students', + 'card_class_sizes' => 'Headcount by class (red = overcrowded)', + 'series_students' => 'Students', + 'card_overcrowded' => 'Overcrowded classes to watch', + 'students_count' => ':count students', + + // Attendance + 'no_attendance' => 'No attendance data for this period.', + 'kpi_presence' => 'Attendance rate', + 'kpi_presence_sub' => ':count present', + 'kpi_absence' => 'Absence rate', + 'kpi_absence_sub' => ':count absences', + 'kpi_late' => 'Lateness rate', + 'kpi_late_sub' => ':count late', + 'kpi_chronic' => 'Chronic absenteeism', + 'kpi_chronic_sub' => '> :threshold absences', + 'card_by_period' => 'Attendance by term', + 'series_present' => 'Present', + 'series_absent' => 'Absent', + 'series_late' => 'Late', + 'card_absence_by_class' => 'Absence rate by class', + + // Comparisons + 'need_two_years' => 'Trends become meaningful with at least two academic years filled in.', + 'kpi_effectif' => 'Headcount', + 'kpi_reussite' => 'Success', + 'kpi_recouvrement' => 'Recovery', + 'kpi_abandon_short' => 'Dropout', + 'card_effectif_evol' => 'Headcount trend', + 'series_effectif' => 'Headcount', + 'card_performance' => 'Performance (%)', + 'series_reussite' => 'Success', + 'series_recouvrement' => 'Recovery', + 'card_deperdition' => 'School wastage (%)', + 'series_redoublement' => 'Repetition', + 'series_abandon' => 'Dropout', + 'deperdition_hint' => 'The current year is not plotted: end-of-year decisions (repetition, dropout) are not yet finalized.', + 'card_comparison' => 'Comparison table', + 'th_year' => 'Year', + 'th_effectif' => 'Headcount', + 'th_girls_pct' => '% girls', + 'th_redoubl' => 'Repet.', + 'th_abandon' => 'Dropout', + 'th_recouvr' => 'Recov.', + 'th_reussite' => 'Success', + 'in_progress' => 'in progress', + + // Geography + 'coverage_note_1' => 'Origin filled in for', + 'coverage_note_2' => 'of students', + 'coverage_note_3' => 'Complete the region/prefecture on the student record to refine.', + 'no_geo' => 'No geographic origin filled in.', + 'kpi_coverage' => 'Coverage', + 'kpi_coverage_sub' => ':localized / :total students', + 'kpi_grand_lome' => 'Greater Lomé', + 'kpi_grand_lome_sub' => 'Golfe + Agoè-Nyivé', + 'kpi_regions' => 'Regions', + 'kpi_regions_sub' => 'represented', + 'kpi_prefectures' => 'Prefectures', + 'kpi_prefectures_sub' => 'of origin', + 'card_origin' => 'Student origin — regions and prefectures', + 'students_tooltip' => ':value students', + 'headcount_label' => 'Headcount', + 'shade_note' => '· shade = prefecture headcount', + 'card_by_region' => 'Headcount by region', +]; diff --git a/lang/en/welcome.php b/lang/en/welcome.php new file mode 100644 index 00000000..221e8259 --- /dev/null +++ b/lang/en/welcome.php @@ -0,0 +1,34 @@ + 'Dalibi — School management', + 'dashboard' => 'Dashboard', + 'logout' => 'Log out', + 'login' => 'Sign in', + 'hello' => 'Hello', + 'welcome_to' => 'Welcome to', + 'subtitle_authed' => 'Choose a module to get started.', + 'subtitle_guest' => 'Sign in to access your school\'s modules.', + 'no_modules' => 'No module accessible with your profile.', + 'open' => 'Open', + 'footer' => 'Dalibi — Open source school management software for Africa.', + + 'modules' => [ + 'students' => ['title' => 'Students', 'desc' => 'Enrollments, records and headcounts'], + 'bulletins' => ['title' => 'Grades & Reports', 'desc' => 'Grade entry and report cards'], + 'exams' => ['title' => 'Exams', 'desc' => 'Assessments and official exams'], + 'attendances' => ['title' => 'Attendance', 'desc' => 'Roll call and attendance tracking'], + 'accounting' => ['title' => 'Accounting', 'desc' => 'Tuition, payments and cash'], + 'payroll' => ['title' => 'Staff & Payroll', 'desc' => 'Employees, pay runs and payslips'], + 'archives' => ['title' => 'Documents & Archives', 'desc' => 'Certificates and archiving'], + 'statistics' => ['title' => 'Statistics', 'desc' => 'Indicators and steering'], + 'calendar' => ['title' => 'Calendar', 'desc' => 'School year events'], + 'timetable' => ['title' => 'Timetable', 'desc' => 'Weekly grid per class'], + 'scholarships' => ['title' => 'Scholarships', 'desc' => 'Student scholarships and aid'], + 'note_reclamations' => ['title' => 'Grade appeals', 'desc' => 'Grade requests and reviews'], + 'absence_permissions' => ['title' => 'Absence permissions', 'desc' => 'Requests and supporting documents'], + 'portal' => ['title' => 'Portal access', 'desc' => 'Parent and student accounts'], + 'users' => ['title' => 'Users', 'desc' => 'Staff accounts and roles'], + 'audit' => ['title' => 'Audit log', 'desc' => 'Action traceability'], + ], +]; diff --git a/lang/fr/archives.php b/lang/fr/archives.php new file mode 100644 index 00000000..4c8c648a --- /dev/null +++ b/lang/fr/archives.php @@ -0,0 +1,89 @@ + 'Archives documentaires', + 'title' => 'Archives documentaires', + 'subtitle_docs' => ':count document(s) archivé(s)', + 'trashed_suffix' => ' · :count en corbeille', + 'view_active' => 'Voir actifs', + 'trash' => 'Corbeille', + 'archive_doc' => 'Archiver un document', + 'search' => 'Recherche', + 'search_ph' => 'Titre, référence…', + 'category' => 'Catégorie', + 'all_categories' => 'Toutes', + 'from' => 'Du', + 'to' => 'Au', + 'reset' => 'Réinitialiser', + 'th_reference' => 'Référence', + 'th_document' => 'Document', + 'th_tags' => 'Tags', + 'th_linked' => 'Lié à', + 'th_size' => 'Taille', + 'th_archived' => 'Archivé', + 'th_actions' => 'Actions', + 'empty_trash' => 'Corbeille vide.', + 'empty' => 'Aucun document archivé.', + 'restore' => 'Restaurer', + 'delete_forever' => 'Supprimer définitivement', + 'download' => 'Télécharger', + 'edit' => 'Modifier', + 'delete' => 'Supprimer', + 'prev' => 'Précédent', + 'next' => 'Suivant', + 'page_of' => 'Page :current / :last', + 'edit_title' => 'Modifier le document', + 'create_title' => 'Archiver un document', + 'edit_desc' => 'Mettez à jour les métadonnées et les tags.', + 'create_desc' => 'Ajoutez un fichier au coffre documentaire avec ses métadonnées et tags.', + 'f_title' => 'Titre', + 'f_category' => 'Catégorie', + 'retention' => 'Conservation jusqu\'au', + 'description' => 'Description', + 'file' => 'Fichier', + 'tags' => 'Tags', + 'add_tag_ph' => 'Ajouter un tag puis Entrée…', + 'linked_to' => 'Lié à', + 'link_none' => 'Aucun', + 'link_classroom' => 'Classe', + 'link_student' => 'Élève (matricule)', + 'classroom' => 'Classe', + 'choose' => 'Choisir', + 'student_matricule' => 'Matricule élève', + 'cancel' => 'Annuler', + 'save' => 'Enregistrer', + 'archive' => 'Archiver', + 'delete_forever_q' => 'Supprimer définitivement ?', + 'delete_forever_desc' => 'Le fichier « :title » sera supprimé du stockage. Cette action est irréversible.', + + // Tags + 'tags_page' => [ + 'head' => 'Tags d\'archivage', + 'title' => 'Tags d\'archivage', + 'subtitle' => 'Organisez les documents archivés par mots-clés réutilisables.', + 'new_tag' => 'Nouveau tag', + 'total' => 'Tags au total', + 'search_ph' => 'Rechercher un tag par nom...', + 'th_tag' => 'Tag', + 'th_documents' => 'Documents', + 'th_color' => 'Couleur', + 'th_actions' => 'Actions', + 'documents_count' => ':count document(s)', + 'change_color' => 'Changer la couleur', + 'color_aria' => 'Couleur :color', + 'delete' => 'Supprimer', + 'empty' => 'Aucun tag trouvé', + 'showing' => 'Affichage :from à :to sur :total', + 'new_tag_desc' => 'Un mot-clé réutilisable pour classer les documents archivés.', + 'name' => 'Nom du tag', + 'name_ph' => 'Ex : Contrat, Inspection…', + 'color' => 'Couleur', + 'preview' => 'Aperçu :', + 'default_name' => 'Nom du tag', + 'cancel' => 'Annuler', + 'create' => 'Créer', + 'delete_q' => 'Supprimer ce tag ?', + 'delete_desc' => 'Le tag sera retiré de tous les documents associés. Les documents ne sont pas supprimés.', + ], +]; diff --git a/lang/fr/errors.php b/lang/fr/errors.php new file mode 100644 index 00000000..225b8cfc --- /dev/null +++ b/lang/fr/errors.php @@ -0,0 +1,36 @@ + 'Tableau de bord', + 'home' => 'Retour à l\'accueil', + 'previous' => 'Page précédente', + + 'fallback' => [ + 'title' => 'Une erreur est survenue', + 'message' => 'Quelque chose s\'est mal passé. Veuillez réessayer.', + ], + '403' => [ + 'title' => 'Accès refusé', + 'message' => 'Vous n\'avez pas l\'autorisation d\'accéder à cette page.', + ], + '404' => [ + 'title' => 'Page introuvable', + 'message' => 'La page que vous recherchez n\'existe pas ou a été déplacée.', + ], + '419' => [ + 'title' => 'Session expirée', + 'message' => 'Votre session a expiré. Veuillez vous reconnecter, puis réessayer.', + ], + '429' => [ + 'title' => 'Trop de requêtes', + 'message' => 'Vous avez effectué trop de requêtes. Patientez un instant avant de réessayer.', + ], + '500' => [ + 'title' => 'Erreur serveur', + 'message' => 'Une erreur inattendue s\'est produite. Réessayez dans un instant ; si le problème persiste, contactez l\'administrateur de votre établissement.', + ], + '503' => [ + 'title' => 'Maintenance en cours', + 'message' => 'Le service est momentanément indisponible. Merci de revenir dans quelques instants.', + ], +]; diff --git a/lang/fr/statistiques.php b/lang/fr/statistiques.php new file mode 100644 index 00000000..29cbb930 --- /dev/null +++ b/lang/fr/statistiques.php @@ -0,0 +1,169 @@ + 'Statistiques', + 'subtitle' => 'Indicateurs de l\'établissement — effectifs, finances et réussite.', + 'year_ph' => 'Année', + 'class_ph' => 'Classe', + 'gender_ph' => 'Sexe', + 'all_classes' => 'Toutes les classes', + 'all' => 'Tous', + 'boys' => 'Garçons', + 'girls' => 'Filles', + 'other' => 'Autre', + 'active_suffix' => ' · active', + 'all_cycles' => 'Tous', + 'sort' => 'Tri', + 'sort_level' => 'Par niveau', + 'sort_headcount' => 'Par effectif', + 'sort_amount' => 'Par montant', + 'sort_rate' => 'Par taux', + 'years_old' => ':value ans', + + // Onglets + 'tab_effectifs' => 'Effectifs & parité', + 'tab_finances' => 'Finances & recouvrement', + 'tab_reussite' => 'Réussite & examens', + 'tab_encadrement' => 'Encadrement', + 'tab_assiduite' => 'Assiduité', + 'tab_comparaisons' => 'Comparaisons', + 'tab_geographie' => 'Géographie', + + // Effectifs + 'kpi_total' => 'Effectif total', + 'kpi_total_sub' => ':boys G · :girls F', + 'kpi_ips' => 'Indice de parité (IPS)', + 'kpi_ips_sub' => ':pct% de filles', + 'kpi_redoublement' => 'Taux de redoublement', + 'kpi_promotion_sub' => 'Promotion :pct%', + 'kpi_abandon' => 'Taux d\'abandon', + 'kpi_age_sub' => 'Âge moyen :age', + 'card_by_class' => 'Effectifs par classe (garçons / filles)', + 'card_by_gender' => 'Répartition par sexe', + 'card_age_pyramid' => 'Pyramide des âges (garçons / filles)', + 'overage_label' => 'Taux de sur-âge (≥ +:threshold ans)', + 'overage_hint' => 'Renseignez l\'âge attendu sur les classes pour activer ce calcul.', + 'card_city' => 'Origine géographique (top villes, par sexe)', + 'not_filled' => 'Non renseigné', + + // Finances + 'kpi_billed' => 'Total facturé', + 'kpi_billed_sub' => ':count factures', + 'kpi_collected' => 'Encaissé', + 'kpi_recovery' => 'Taux de recouvrement', + 'kpi_remaining_sub' => ':amount restant', + 'kpi_unpaid' => 'Impayés', + 'kpi_unpaid_sub' => ':count partiels', + 'card_monthly' => 'Encaissements mensuels', + 'card_methods' => 'Modes de paiement', + 'recovery_by_class' => 'Recouvrement par classe', + 'card_billed_split' => 'Facturé : encaissé / reste à recouvrer', + 'series_collected' => 'Encaissé', + 'series_remaining' => 'Reste à recouvrer', + 'card_recovery_rate' => 'Taux de recouvrement par classe', + 'rate_label' => 'Taux', + 'avg_prefix' => 'moy. :rate%', + 'legend_high' => '≥ 80 %', + 'legend_mid' => '60–79 %', + 'legend_low' => '< 60 %', + 'card_detail' => 'Détail par classe', + 'th_class' => 'Classe', + 'th_billed' => 'Facturé', + 'th_collected' => 'Encaissé', + 'th_remaining' => 'Reste', + 'th_rate' => 'Taux', + 'method_cash' => 'Espèces', + 'method_mobile_money' => 'Mobile Money', + 'method_bank_transfer' => 'Virement', + 'method_cheque' => 'Chèque', + + // Réussite + 'kpi_bulletins' => 'Bulletins validés', + 'kpi_average' => 'Moyenne générale', + 'kpi_passrate' => 'Réussite interne (≥10)', + 'kpi_admission' => 'Admission examens off.', + 'card_mentions' => 'Répartition des mentions', + 'mention_passable' => 'Passable', + 'mention_assez_bien' => 'Assez bien', + 'mention_bien' => 'Bien', + 'mention_tres_bien' => 'Très bien', + 'card_exams' => 'Examens officiels (CEPD / BEPC / BAC)', + 'no_exams' => 'Aucun examen officiel pour cette année', + 'th_exam' => 'Examen', + 'th_registered' => 'Inscrits', + 'th_admitted' => 'Admis', + 'th_admission' => 'Admission', + + // Encadrement + 'kpi_rem' => 'Ratio élèves / enseignant', + 'kpi_rem_sub' => ':count enseignants', + 'kpi_students' => 'Effectif total', + 'kpi_avg_class' => 'Taille moyenne / classe', + 'kpi_avg_class_sub' => ':count classes', + 'kpi_overcrowded' => 'Classes pléthoriques', + 'kpi_overcrowded_sub' => '> :threshold élèves', + 'card_class_sizes' => 'Effectif par classe (rouge = pléthorique)', + 'series_students' => 'Élèves', + 'card_overcrowded' => 'Classes pléthoriques à surveiller', + 'students_count' => ':count élèves', + + // Assiduité + 'no_attendance' => 'Aucune donnée de présence pour cette période.', + 'kpi_presence' => 'Taux de présence', + 'kpi_presence_sub' => ':count présences', + 'kpi_absence' => 'Taux d\'absence', + 'kpi_absence_sub' => ':count absences', + 'kpi_late' => 'Taux de retard', + 'kpi_late_sub' => ':count retards', + 'kpi_chronic' => 'Absentéisme chronique', + 'kpi_chronic_sub' => '> :threshold absences', + 'card_by_period' => 'Présences par période', + 'series_present' => 'Présents', + 'series_absent' => 'Absents', + 'series_late' => 'Retards', + 'card_absence_by_class' => 'Taux d\'absence par classe', + + // Comparaisons + 'need_two_years' => 'Les tendances se précisent avec au moins deux années académiques renseignées.', + 'kpi_effectif' => 'Effectif', + 'kpi_reussite' => 'Réussite', + 'kpi_recouvrement' => 'Recouvrement', + 'kpi_abandon_short' => 'Abandon', + 'card_effectif_evol' => 'Évolution de l\'effectif', + 'series_effectif' => 'Effectif', + 'card_performance' => 'Performance (%)', + 'series_reussite' => 'Réussite', + 'series_recouvrement' => 'Recouvrement', + 'card_deperdition' => 'Déperdition scolaire (%)', + 'series_redoublement' => 'Redoublement', + 'series_abandon' => 'Abandon', + 'deperdition_hint' => 'L\'année en cours n\'est pas tracée : les décisions de fin d\'année (redoublement, abandon) ne sont pas encore arrêtées.', + 'card_comparison' => 'Tableau comparatif', + 'th_year' => 'Année', + 'th_effectif' => 'Effectif', + 'th_girls_pct' => '% filles', + 'th_redoubl' => 'Redoubl.', + 'th_abandon' => 'Abandon', + 'th_recouvr' => 'Recouvr.', + 'th_reussite' => 'Réussite', + 'in_progress' => 'en cours', + + // Géographie + 'coverage_note_1' => 'Origine renseignée pour', + 'coverage_note_2' => 'des élèves', + 'coverage_note_3' => 'Complétez la région/préfecture sur la fiche élève pour affiner.', + 'no_geo' => 'Aucune origine géographique renseignée.', + 'kpi_coverage' => 'Couverture', + 'kpi_coverage_sub' => ':localized / :total élèves', + 'kpi_grand_lome' => 'Grand Lomé', + 'kpi_grand_lome_sub' => 'Golfe + Agoè-Nyivé', + 'kpi_regions' => 'Régions', + 'kpi_regions_sub' => 'représentées', + 'kpi_prefectures' => 'Préfectures', + 'kpi_prefectures_sub' => 'd\'origine', + 'card_origin' => 'Origine des élèves — régions et préfectures', + 'students_tooltip' => ':value élèves', + 'headcount_label' => 'Effectif', + 'shade_note' => '· nuance = effectif de la préfecture', + 'card_by_region' => 'Effectif par région', +]; diff --git a/lang/fr/welcome.php b/lang/fr/welcome.php new file mode 100644 index 00000000..c88a07a2 --- /dev/null +++ b/lang/fr/welcome.php @@ -0,0 +1,34 @@ + 'Dalibi — Gestion scolaire', + 'dashboard' => 'Tableau de bord', + 'logout' => 'Se déconnecter', + 'login' => 'Se connecter', + 'hello' => 'Bonjour', + 'welcome_to' => 'Bienvenue sur', + 'subtitle_authed' => 'Choisissez un module pour commencer.', + 'subtitle_guest' => 'Connectez-vous pour accéder aux modules de votre établissement.', + 'no_modules' => 'Aucun module accessible avec votre profil.', + 'open' => 'Ouvrir', + 'footer' => 'Dalibi — Logiciel de gestion scolaire open source pour l\'Afrique.', + + 'modules' => [ + 'students' => ['title' => 'Élèves', 'desc' => 'Inscriptions, dossiers et effectifs'], + 'bulletins' => ['title' => 'Notes & Bulletins', 'desc' => 'Saisie des notes et bulletins'], + 'exams' => ['title' => 'Examens', 'desc' => 'Évaluations et examens officiels'], + 'attendances' => ['title' => 'Présences', 'desc' => 'Appel et suivi de l\'assiduité'], + 'accounting' => ['title' => 'Comptabilité', 'desc' => 'Écolage, paiements et caisses'], + 'payroll' => ['title' => 'Personnel & Paie', 'desc' => 'Employés, cycles de paie et bulletins'], + 'archives' => ['title' => 'Documents & Archives', 'desc' => 'Certificats et archivage'], + 'statistics' => ['title' => 'Statistiques', 'desc' => 'Indicateurs et pilotage'], + 'calendar' => ['title' => 'Calendrier', 'desc' => 'Événements de l\'année scolaire'], + 'timetable' => ['title' => 'Emploi du temps', 'desc' => 'Grille hebdomadaire par classe'], + 'scholarships' => ['title' => 'Bourses', 'desc' => 'Bourses et aides d\'étudiants'], + 'note_reclamations' => ['title' => 'Réclamations de notes', 'desc' => 'Demandes et révisions de notes'], + 'absence_permissions' => ['title' => 'Permissions d\'absence', 'desc' => 'Demandes et justificatifs'], + 'portal' => ['title' => 'Accès portail', 'desc' => 'Comptes parents et élèves'], + 'users' => ['title' => 'Utilisateurs', 'desc' => 'Comptes et rôles du personnel'], + 'audit' => ['title' => 'Journal d\'audit', 'desc' => 'Traçabilité des actions'], + ], +]; diff --git a/resources/js/pages/Archives/Index.tsx b/resources/js/pages/Archives/Index.tsx index 1bd43597..68b18e7a 100644 --- a/resources/js/pages/Archives/Index.tsx +++ b/resources/js/pages/Archives/Index.tsx @@ -15,6 +15,7 @@ import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { route } from '@/helpers/route'; +import { useTranslation } from '@/helpers/i18n'; import AppLayout from '@/layouts/app-layout'; interface Tag { id: string; name: string; color: string; } @@ -39,6 +40,7 @@ const ALL = 'all'; const fmtSize = (b: number) => b > 1048576 ? `${(b / 1048576).toFixed(1)} Mo` : `${Math.max(1, Math.round(b / 1024))} Ko`; export default function Index({ documents, tags, categories, classrooms, filters, stats }: Readonly) { + const { t } = useTranslation(); const [search, setSearch] = useState(filters.search || ''); const [category, setCategory] = useState(filters.category || ALL); const [selectedTags, setSelectedTags] = useState(filters.tags || []); @@ -55,7 +57,7 @@ export default function Index({ documents, tags, categories, classrooms, filters }; const toggleTag = (id: string) => { - const next = selectedTags.includes(id) ? selectedTags.filter(t => t !== id) : [...selectedTags, id]; + const next = selectedTags.includes(id) ? selectedTags.filter(x => x !== id) : [...selectedTags, id]; setSelectedTags(next); apply({ tags: next }); }; @@ -74,7 +76,7 @@ export default function Index({ documents, tags, categories, classrooms, filters setEditing(d); setData({ title: d.title, description: d.description ?? '', category: d.category, - file: null as File | null, tags: d.tags.map(t => t.name), + file: null as File | null, tags: d.tags.map(x => x.name), retention_until: d.retention_until ?? '', link_type: '', link_classroom_id: '', link_student_matricule: '', }); @@ -94,7 +96,7 @@ export default function Index({ documents, tags, categories, classrooms, filters if (n && !data.tags.includes(n)) setData('tags', [...data.tags, n]); setTagInput(''); }; - const removeTag = (name: string) => setData('tags', data.tags.filter(t => t !== name)); + const removeTag = (name: string) => setData('tags', data.tags.filter(x => x !== name)); const submit = (e: React.FormEvent) => { e.preventDefault(); @@ -106,23 +108,23 @@ export default function Index({ documents, tags, categories, classrooms, filters return ( - +

- Archives documentaires + {t('archives.title')}

-

{stats.total} document(s) archivé(s){stats.trashed > 0 ? ` · ${stats.trashed} en corbeille` : ''}.

+

{t('archives.subtitle_docs', { count: stats.total })}{stats.trashed > 0 ? t('archives.trashed_suffix', { count: stats.trashed }) : ''}.

@@ -131,26 +133,26 @@ export default function Index({ documents, tags, categories, classrooms, filters
- + - setSearch(e.target.value)} onKeyDown={e => e.key === 'Enter' && apply()} placeholder="Titre, référence…" className="pl-9 bg-white" /> + setSearch(e.target.value)} onKeyDown={e => e.key === 'Enter' && apply()} placeholder={t('archives.search_ph')} className="pl-9 bg-white" />
- +
- + setDateFrom(e.target.value)} onBlur={() => apply()} className="bg-white" />
- + setDateTo(e.target.value)} onBlur={() => apply()} className="bg-white" />
@@ -169,7 +171,7 @@ export default function Index({ documents, tags, categories, classrooms, filters })} {activeFilters > 0 && ( )}
@@ -181,20 +183,20 @@ export default function Index({ documents, tags, categories, classrooms, filters - Référence - Document - Tags - Lié à - Taille - Archivé - Actions + {t('archives.th_reference')} + {t('archives.th_document')} + {t('archives.th_tags')} + {t('archives.th_linked')} + {t('archives.th_size')} + {t('archives.th_archived')} + {t('archives.th_actions')} {documents.data.length === 0 ? ( - {filters.trashed ? 'Corbeille vide.' : 'Aucun document archivé.'} + {filters.trashed ? t('archives.empty_trash') : t('archives.empty')} ) : documents.data.map(d => ( @@ -217,16 +219,16 @@ export default function Index({ documents, tags, categories, classrooms, filters
{filters.trashed ? ( <> - } className="gap-1 text-xs" onClick={() => router.post(route('archives.restore', d.id), {}, { preserveScroll: true })} /> - } className="border-red-200 text-red-500 hover:bg-red-50" onClick={() => setDeleteDoc(d)} /> + } className="gap-1 text-xs" onClick={() => router.post(route('archives.restore', d.id), {}, { preserveScroll: true })} /> + } className="border-red-200 text-red-500 hover:bg-red-50" onClick={() => setDeleteDoc(d)} /> ) : ( <> - } className="text-xs" /> + } className="text-xs" /> - } onClick={() => openEdit(d)} /> - } className="border-red-200 text-red-500 hover:bg-red-50" onClick={() => router.delete(route('archives.destroy', d.id), { preserveScroll: true })} /> + } onClick={() => openEdit(d)} /> + } className="border-red-200 text-red-500 hover:bg-red-50" onClick={() => router.delete(route('archives.destroy', d.id), { preserveScroll: true })} /> )}
@@ -239,9 +241,9 @@ export default function Index({ documents, tags, categories, classrooms, filters {documents.last_page > 1 && (
- - Page {documents.current_page} / {documents.last_page} - + + {t('archives.page_of', { current: documents.current_page, last: documents.last_page })} +
)} @@ -250,38 +252,38 @@ export default function Index({ documents, tags, categories, classrooms, filters - {editing ? 'Modifier le document' : 'Archiver un document'} + {editing ? t('archives.edit_title') : t('archives.create_title')} - {editing ? 'Mettez à jour les métadonnées et les tags.' : 'Ajoutez un fichier au coffre documentaire avec ses métadonnées et tags.'} + {editing ? t('archives.edit_desc') : t('archives.create_desc')}
- + setData('title', e.target.value)} className={errors.title ? 'border-red-400' : ''} /> {errors.title &&

{errors.title}

}
- +
- + setData('retention_until', e.target.value)} />
- +