refactor(i18n) : sidebar.sites.admin + cles audit.entity.*

T-011 — deplace la cle sidebar.core.sites sous son module owner
(sidebar.sites.admin). Aligne sur la convention naming.md : les cles
sidebar doivent vivre sous le namespace du module qui expose l'item.

T-015 — traduit entityType dans la page d'audit via des cles i18n
audit.entity.core_user / core_role / core_permission / sites_site.
Helper formatEntityType avec fallback sur l'identifiant brut pour
rester debug-friendly si une traduction manque. Applique sur :
- la cellule du tableau (tooltip garde l'identifiant technique)
- les options du filtre multi-select MalioSelectCheckbox
- le titre du drawer de detail + h3 interne
This commit is contained in:
Matthieu
2026-04-23 11:47:16 +02:00
parent 4c142aecbb
commit e933c31e0f
3 changed files with 30 additions and 9 deletions

View File

@@ -77,7 +77,7 @@ return [
'permission' => 'core.users.view',
],
[
'label' => 'sidebar.core.sites',
'label' => 'sidebar.sites.admin',
'to' => '/admin/sites',
'icon' => 'mdi:domain',
'module' => 'sites',

View File

@@ -28,8 +28,10 @@
"core": {
"roles": "Gestion des rôles",
"users": "Utilisateurs",
"sites": "Sites",
"audit_log": "Journal d'audit"
},
"sites": {
"admin": "Sites"
}
},
"dashboard": {
@@ -76,7 +78,10 @@
"delete": "Suppression"
},
"entity": {
"user": "Utilisateur"
"core_user": "Utilisateur",
"core_role": "Rôle",
"core_permission": "Permission",
"sites_site": "Site"
},
"empty": "Aucune activité enregistrée",
"no_results": "Aucun résultat pour ces filtres",

View File

@@ -115,7 +115,10 @@
</span>
</template>
<template #cell-entityType="{ item }">
<span class="font-mono text-xs">{{ item.entityType }}</span>
<span
class="text-xs"
:title="item.entityType as string"
>{{ formatEntityType(item.entityType as string) }}</span>
</template>
<template #cell-entityId="{ item }">
<span class="font-mono text-xs">{{ item.entityId }}</span>
@@ -134,8 +137,11 @@
<div v-if="selectedEntry">
<AuditLogDetail :entry="selectedEntry" />
<div class="mt-4 border-t border-gray-200 pt-3">
<h3 class="text-sm font-medium text-gray-700 mb-2">
{{ selectedEntry.entityType }} #{{ selectedEntry.entityId }}
<h3
class="text-sm font-medium text-gray-700 mb-2"
:title="selectedEntry.entityType"
>
{{ formatEntityType(selectedEntry.entityType) }} #{{ selectedEntry.entityId }}
</h3>
<AuditTimeline
:entity-type="selectedEntry.entityType"
@@ -151,10 +157,18 @@
import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue'
import type { AuditLogEntry, AuditLogFilters } from '~/shared/types'
const { t } = useI18n()
const { t, te } = useI18n()
const { can } = usePermissions()
const { fetchLogsCached, fetchEntityTypes } = useAuditLog()
// Traduit un identifiant `module.Entity` (ex: `core.User`, `sites.Site`) en
// libelle lisible via la cle i18n `audit.entity.<module>_<entity>`. Si aucune
// traduction n'existe, on retombe sur l'identifiant brut pour rester debug-friendly.
function formatEntityType(type: string): string {
const key = `audit.entity.${type.toLowerCase().replace(/\./g, '_')}`
return te(key) ? t(key) : type
}
// Protection cote UI : le middleware `modules.global.ts` filtre deja les
// routes desactivees, mais si quelqu'un atterit ici sans la permission on
// renvoie une 403 plutot que de flasher un ecran vide.
@@ -180,8 +194,10 @@ const filters = reactive<AuditLogFilters>({
// Attention : les composants Malio attendent `{ label, value }` (pas `{ text }`).
const selectedEntityTypes = ref<(string | number)[]>([])
const entityTypes = ref<string[]>([])
// On garde l'identifiant technique comme `value` pour l'envoi API, mais on
// affiche le libelle traduit quand il existe (fallback: identifiant brut).
const entityTypeOptions = computed(() =>
entityTypes.value.map(t => ({ value: t, label: t })),
entityTypes.value.map(type => ({ value: type, label: formatEntityType(type) })),
)
// Bind champ performedBy : MalioInputText attend `string | null`, on ne peut
@@ -230,7 +246,7 @@ const rows = computed(() =>
const drawerTitle = computed(() =>
selectedEntry.value
? `${selectedEntry.value.entityType} #${selectedEntry.value.entityId}`
? `${formatEntityType(selectedEntry.value.entityType)} #${selectedEntry.value.entityId}`
: t('audit.detail_title'),
)