diff --git a/src/glob/tests/glob.test.ts b/src/glob/tests/glob.test.ts index d5d96e5..c6869bf 100644 --- a/src/glob/tests/glob.test.ts +++ b/src/glob/tests/glob.test.ts @@ -41,7 +41,9 @@ function makeGlob(locale = 'es') { numr : { minDecimals: 0, maxDecimals: 2 }, curr : { definitions: currDefinitions, selectedCurrency: 'EUR' }, dati : { selectedTimeFormat: '24h' }, - unit : { selectedSystem: 'metric' }, + unit : { + selectedSystem: 'metric' + }, }); } diff --git a/src/mtas/lib/translations.ts b/src/mtas/lib/translations.ts new file mode 100644 index 0000000..6a38f7b --- /dev/null +++ b/src/mtas/lib/translations.ts @@ -0,0 +1,132 @@ +import type { LingRecord } from '@/ling/lib'; +import { p } from '@/ling/lib'; + +/** + * Traducciones del editor de metadata. + * Namespace: vcen.editor.mtas + * + * Para registrar en ling: + * ling.extend('vcen', { editor: { mtas: mtasTranslations } }) + * + * Los componentes reciben la instancia glob completa: + * + * + * Y acceden a las traducciones via: + * glob.t('vcen.editor.mtas.header.title') + * glob.t('vcen.editor.mtas.field.nestedCount', { count: 3 }) + * glob.numr.f(1234.5) + * glob.curr.f(99.5) + * glob.dati.f(new Date('2024-01-15')) + */ +export const translations = { + + // ── Tipos de campo ──────────────────────────────────────────────── + types: { + string: { es: 'Texto', en: 'Text' } satisfies LingRecord, + number: { es: 'Número', en: 'Number' } satisfies LingRecord, + boolean: { es: 'Bool', en: 'Bool' } satisfies LingRecord, + ling: { es: 'i18n', en: 'i18n' } satisfies LingRecord, + date: { es: 'Fecha', en: 'Date' } satisfies LingRecord, + datetime: { es: 'DateTime', en: 'DateTime' } satisfies LingRecord, + url: { es: 'URL', en: 'URL' } satisfies LingRecord, + currency: { es: 'Moneda', en: 'Currency' } satisfies LingRecord, + image: { es: 'Imagen', en: 'Image' } satisfies LingRecord, + video: { es: 'Vídeo', en: 'Video' } satisfies LingRecord, + audio: { es: 'Audio', en: 'Audio' } satisfies LingRecord, + pdf: { es: 'PDF', en: 'PDF' } satisfies LingRecord, + file: { es: 'Fichero', en: 'File' } satisfies LingRecord, + html: { es: 'HTML', en: 'HTML' } satisfies LingRecord, + group: { es: 'Grupo', en: 'Group' } satisfies LingRecord, + }, + + // ── Grupos del menú ─────────────────────────────────────────────── + typeGroups: { + text: { es: 'Texto', en: 'Text' } satisfies LingRecord, + number: { es: 'Número', en: 'Number' } satisfies LingRecord, + date: { es: 'Fecha', en: 'Date' } satisfies LingRecord, + logical: { es: 'Lógico', en: 'Boolean' } satisfies LingRecord, + media: { es: 'Media', en: 'Media' } satisfies LingRecord, + group: { es: 'Grupo', en: 'Group' } satisfies LingRecord, + }, + + // ── Encabezado ──────────────────────────────────────────────────── + header: { + title: { es: 'Metadata', en: 'Metadata' } satisfies LingRecord, + addField: { es: 'Añadir', en: 'Add' } satisfies LingRecord, + addFieldTitle: { es: 'Añadir campo', en: 'Add field' } satisfies LingRecord, + fieldCount: p({ + es: { one: '{{count}} campo', other: '{{count}} campos' }, + en: { one: '{{count}} field', other: '{{count}} fields' }, + }), + }, + + // ── Validación ──────────────────────────────────────────────────── + validation: { + valid: { es: 'Válido', en: 'Valid' } satisfies LingRecord, + errorsTitle: { es: 'Errores de validación', en: 'Validation errors' } satisfies LingRecord, + errorCount: p({ + es: { one: '{{count}} error', other: '{{count}} errores' }, + en: { one: '{{count}} error', other: '{{count}} errors' }, + }), + }, + + // ── Fila de campo ───────────────────────────────────────────────── + field: { + moveUp: { es: 'Subir', en: 'Move up' } satisfies LingRecord, + moveDown: { es: 'Bajar', en: 'Move down' } satisfies LingRecord, + edit: { es: 'Editar', en: 'Edit' } satisfies LingRecord, + delete: { es: 'Eliminar', en: 'Delete' } satisfies LingRecord, + expand: { es: 'Expandir', en: 'Expand' } satisfies LingRecord, + collapse: { es: 'Colapsar', en: 'Collapse' } satisfies LingRecord, + hidden: { es: 'oculto', en: 'hidden' } satisfies LingRecord, + fieldValid: { es: 'Campo válido', en: 'Valid field' } satisfies LingRecord, + fieldInvalid: { es: 'Campo inválido', en: 'Invalid field' } satisfies LingRecord, + boolTrue: { es: 'Verdadero', en: 'True' } satisfies LingRecord, + boolFalse: { es: 'Falso', en: 'False' } satisfies LingRecord, + empty: { es: 'Usa el botón Añadir para crear campos', en: 'Use the Add button to create fields' } satisfies LingRecord, + emptyGroup: { es: 'Grupo vacío — añade campos con el botón +', en: 'Empty group — add fields with the + button' } satisfies LingRecord, + nestedCount: p({ + es: { one: '{{count}} campo anidado', other: '{{count}} campos anidados' }, + en: { one: '{{count}} nested field', other: '{{count}} nested fields' }, + }), + }, + + // ── Editor de campo ─────────────────────────────────────────────── + editor: { + keyLabel: { es: 'Clave del campo', en: 'Field key' } satisfies LingRecord, + keyPlaceholder: { es: 'nombre_campo', en: 'field_name' } satisfies LingRecord, + keyEmpty: { es: 'La clave no puede estar vacía', en: 'Key cannot be empty' } satisfies LingRecord, + keyExists: { es: '"{{key}}" ya existe', en: '"{{key}}" already exists' } satisfies LingRecord, + hideField: { es: 'Ocultar campo', en: 'Hide field' } satisfies LingRecord, + valueLing: { es: 'Valor multiidioma', en: 'Multilingual value' } satisfies LingRecord, + valueHtml: { es: 'Contenido HTML', en: 'HTML content' } satisfies LingRecord, + amountLabel: { es: 'Importe', en: 'Amount' } satisfies LingRecord, + currencyLabel: { es: 'Divisa', en: 'Currency' } satisfies LingRecord, + mediaUrlLabel: { es: 'URL del recurso', en: 'Resource URL' } satisfies LingRecord, + }, + + // ── Drawer ──────────────────────────────────────────────────────── + drawer: { + title: { es: 'Añadir campo', en: 'Add field' } satisfies LingRecord, + cancel: { es: 'Cancelar', en: 'Cancel' } satisfies LingRecord, + confirm: { es: 'Añadir campo', en: 'Add field' } satisfies LingRecord, + }, + + // ── Paginación ──────────────────────────────────────────────────── + pagination: { + rowsPerPage: { es: 'Filas por página', en: 'Rows per page' } satisfies LingRecord, + all: { es: 'Todos', en: 'All' } satisfies LingRecord, + prevPage: { es: 'Página anterior', en: 'Previous page' } satisfies LingRecord, + nextPage: { es: 'Página siguiente', en: 'Next page' } satisfies LingRecord, + pageN: { es: 'Página {{page}}', en: 'Page {{page}}' } satisfies LingRecord, + range: { es: '{{from}}–{{to}} de {{total}}', en: '{{from}}–{{to}} of {{total}}' } satisfies LingRecord, + }, + + // ── LingInput ───────────────────────────────────────────────────── + lingInput: { + requiredLocale: { es: 'El campo {{locale}} es obligatorio', en: 'The {{locale}} field is required' } satisfies LingRecord, + }, + +} as const; + +export type Translations = typeof translations; diff --git a/src/mtas/svelte/components/AddFieldDrawer.svelte b/src/mtas/svelte/components/AddFieldDrawer.svelte index 45124a6..f7f2e4d 100644 --- a/src/mtas/svelte/components/AddFieldDrawer.svelte +++ b/src/mtas/svelte/components/AddFieldDrawer.svelte @@ -158,5 +158,5 @@ - + diff --git a/src/mtas/svelte/components/AddFieldMenu.svelte b/src/mtas/svelte/components/AddFieldMenu.svelte new file mode 100644 index 0000000..b0a5e44 --- /dev/null +++ b/src/mtas/svelte/components/AddFieldMenu.svelte @@ -0,0 +1,60 @@ + + + \ No newline at end of file diff --git a/src/mtas/svelte/components/FieldRow.svelte b/src/mtas/svelte/components/FieldRow.svelte index 77c8a18..ffc0005 100644 --- a/src/mtas/svelte/components/FieldRow.svelte +++ b/src/mtas/svelte/components/FieldRow.svelte @@ -5,6 +5,7 @@ import FieldEditor from './FieldEditor.svelte'; import FieldRowRecursive from './FieldRow.svelte'; import AddFieldDrawer from "@/mtas/svelte/components/AddFieldDrawer.svelte"; + import AddFieldMenu from "@/mtas/svelte/components/AddFieldMenu.svelte"; let { fieldKey, field, locales, defaultLocale, @@ -150,7 +151,7 @@ id="field-row-{fieldKey}" class={[ 'card bg-base-100 border transition-all duration-150 flex-row focus-within:border-base-content w-full', - depth > 0 ? 'ml-5' : '', + depth > 0 ? 'w-full' : '', !validationResult.valid ? 'border-error' : expanded ? 'border-base-300 shadow-sm' : 'border-base-200 hover:border-base-300', @@ -224,7 +225,7 @@
-
- {#each ALL_TYPES as type (type)} - - {/each} + +
+ +
{#if groupOpen} -
+
{#if Object.keys(field.value).length === 0}
Grupo vacío — añade campos con los botones de arriba diff --git a/src/mtas/svelte/components/FieldTypeIcon.svelte b/src/mtas/svelte/components/FieldTypeIcon.svelte index 0a1fc19..d9cd2a1 100644 --- a/src/mtas/svelte/components/FieldTypeIcon.svelte +++ b/src/mtas/svelte/components/FieldTypeIcon.svelte @@ -1,6 +1,6 @@ -
-
+
+
-
-
-

Metadata

- - {keyOrder.length} {keyOrder.length === 1 ? 'campo' : 'campos'} - -
-
- {validation.valid ? 'Válido' : `${validation.errors.length} errores`} -
-
- -
- {#each typeGroups as group} -
- {group.label} - {#each group.types as type} - - {/each} -
- {/each} +
+ +

Metadata

+ + {keyOrder.length} {keyOrder.length === 1 ? 'campo' : 'campos'} + +
+
-
+
{#if keyOrder.length === 0}
-

Añade campos usando los botones de arriba

+

Usa el botón Añadir para crear campos

{:else} {#each pageKeys as key (key)} @@ -217,7 +188,7 @@
{#if !validation.valid} -
+
Errores de validación @@ -230,16 +201,16 @@ {/if} - {#if keyOrder.length > 0} -
+ {#if pagination && keyOrder.length > 0} +
Filas por página