feat: entry list at /content/:key

This commit is contained in:
Florian Sylvain committed 2026-10-20 21:05:03 +02:00
1 parent b4cbcb0395
commit 91d916fb74
44 files changed
+4984 -32

No files matched your search

+56
View File
@@ -0,0 +1,56 @@
import { readFileSync } from 'node:fs'
import { join } from 'node:path'
import { describe, expect, it } from 'vitest'
import { messages } from './messages'
const SOURCES = [
'components/ColumnPicker.vue',
'components/ColumnPickerList.vue',
'components/ContentEmpty.vue',
'components/ContentEntries.vue',
'components/ContentState.vue',
'components/ContentToolbar.vue',
'components/EntryCardList.vue',
'components/EntrySkeleton.vue',
'components/EntryTable.vue',
'components/FieldCell.vue',
'components/SortSelect.vue',
'lib/entryCells.ts',
'lib/entryListQuery.ts',
'views/ContentListView.vue',
]
const SAME_IN_FRENCH = new Set(['ID'])
const LITERAL = /\bt\(\s*(?:'((?:\\.|[^'\\])*)'|"((?:\\.|[^"\\])*)")/g
function keysIn(source: string) {
return [...source.matchAll(LITERAL)].map((match) =>
(match[1] ?? match[2] ?? '').replace(/\\(['"\\])/g, '$1'),
)
}
describe('Entry list messages', () => {
const keys = SOURCES.flatMap((file) =>
keysIn(readFileSync(join(import.meta.dirname, '..', file), 'utf8')).map((key) => ({
file,
key,
})),
)
it('finds the strings of the screen', () => {
expect(keys.length).toBeGreaterThan(30)
})
it.each(keys.map(({ file, key }) => [file, key]))(
'%s: "%s" has its own French entry',
(_file, key) => {
const french = (messages as Record<string, string>)[key as string]
expect(french).toMatch(/\S/)
if (!SAME_IN_FRENCH.has(key as string)) {
expect(french).not.toBe(key)
}
},
)
})
+28
View File
@@ -2503,6 +2503,34 @@ export const messages = {
'View entries': 'Voir les entrées',
'Content type deleted': 'Type de contenu supprimé',
'{0} was deleted.': '{0} a été supprimé.',
Columns: 'Colonnes',
'Choose up to {0} fields to show. {1} selected.':
'Choisissez jusqu’à {0} champs à afficher. {1} sélectionné(s).',
'Created and updated dates always show':
'Les dates de création et de modification sont toujours affichées',
'You can show up to {0} fields.': 'Vous pouvez afficher jusqu’à {0} champs.',
'No entries yet': 'Aucune entrée pour le moment',
'Use New entry to add the first entry. Each entry follows the fields of this content type.':
'Utilisez Nouvelle entrée pour ajouter la première entrée. Chaque entrée suit les champs de ce type de contenu.',
'New entry': 'Nouvelle entrée',
'1 entry': '1 entrée',
'{0} entries': '{0} entrées',
'GET /v1/content-type/{0} failed. Check your connection and try again.':
'GET /v1/content-type/{0} a échoué. Vérifiez votre connexion et réessayez.',
"Couldn't load entries": 'Impossible de charger les entrées',
"You don't have access to {0}": 'Vous n’avez pas accès à {0}',
"Your account can't open this content right now. If you think this is a mistake, ask an owner or an admin.":
'Votre compte ne peut pas ouvrir ce contenu pour le moment. Si vous pensez qu’il s’agit d’une erreur, contactez un propriétaire ou un administrateur.',
'Edit content type': 'Modifier le type de contenu',
ID: 'ID',
'Updated by': 'Modifié par',
'Sort by': 'Trier par',
'Sort descending': 'Trier par ordre décroissant',
'Sort ascending': 'Trier par ordre croissant',
'{0}, sorted by last updated, newest first':
'{0}, trié par dernière modification, plus récent en premier',
'{0}, sorted by {1}, {2}': '{0}, trié par {1}, {2}',
id: 'identifiant',
} as const
export type MessageKey = keyof typeof messages