import { formatFileSize } from "../kit-labels";
import type { UiKitLabels } from "../kit-labels";

/**
 * The kit's words in Spanish: every namespace of {@link UiKitLabels}, for
 * `<UiKitProvider labels={UI_KIT_LABELS_ES}>`.
 *
 * Self-contained on purpose — nothing but the kit's own `formatFileSize` — so it works
 * as a starting point to copy and adjust. Counts and sizes are formatted with
 * `es-ES` digits; {@link uiKitLabelsEs} takes another number locale
 * (e.g. `"de-CH"` for 1’234) without touching the words.
 */
export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
  const num = new Intl.NumberFormat(numberLocale);
  const n = (value: number) => num.format(value);
  const plural = (count: number, one: string, many: string) => (count === 1 ? one : many);

  return {
    feedbackAttachment: {
      attachmentAdd: "Añadir adjunto",
      attachmentCapture: "Capturar pantalla",
      attachmentPaste:
        "…o pegue una captura de pantalla directamente desde el portapapeles, para mostrar solo un detalle en lugar de toda la página.",
      attachmentRemove: "Quitar adjunto",
      attachmentList: "Adjuntos",
      attachmentScreenshot: "Captura de pantalla",
      attachmentRemoveFile: (name) => `Quitar ${name}`,
      attachmentLimit: (max) =>
        max === 1
          ? `Máximo ${n(max)} adjunto: quítelo para añadir otro.`
          : `Máximo ${n(max)} adjuntos: quite uno para añadir otro.`,
      attachmentUploading: "Subiendo…",
      attachmentUploadFailed: (name) => `No se ha podido subir «${name}»`,
    },
    feedbackDialog: {
      title: "Enviar comentarios",
      category: "Categoría",
      subject: "Asunto",
      body: "¿Qué ha pasado?",
      bodyOptional: "¿Qué ha pasado? (opcional)",
      attachment: "Adjunto",
      submitHint: (apple) => (apple ? "⌘ Intro para enviar" : "Ctrl+Intro para enviar"),
      cancel: "Cancelar",
      save: "Enviar",
    },
    feedbackThread: {
      thread: "Comentarios",
      empty: "Aún no hay comentarios",
      loading: "Cargando comentarios…",
      you: "Usted",
      staff: "Equipo",
      attachments: "Adjuntos",
    },
    feedbackComposer: {
      field: "Escriba un comentario",
      placeholder: "Escriba un comentario…",
      send: "Enviar",
      sendHint: (modifier) => `${modifier} + Intro para enviar`,
      sendHintEnter: "Intro para enviar, Mayús + Intro para una nueva línea",
    },
    // 0.27.0. "Comentarios" for feedback, as `feedbackDialog`; "corrección" for rework.
    feedbackStatus: {
      OPEN: "Abierto",
      IN_PROGRESS: "En curso",
      IN_EVALUATION: "En evaluación",
      NEEDS_LIVE_TEST: "Probar en producción",
      POSTPONED: "Pospuesto",
      DONE: "Hecho",
      WONT_DO: "No se hará",
    },
    feedbackCategory: {
      CRASH: "Bloqueo",
      BUG: "Error",
      IDEA: "Idea",
      QUESTION: "Pregunta",
      OTHER: "Otro",
    },
    feedbackToast: {
      submitted: "¡Gracias por sus comentarios!",
      submitFailed: "No se han podido enviar los comentarios",
      attachmentUnsupported: "Solo se admiten imágenes, PDF o archivos de texto",
      attachmentTooLarge: "El archivo supera los 10 MB",
      attachmentTooMany: (count) =>
        count === 1
          ? "Solo cabe 1 adjunto: el resto se ha omitido."
          : `Solo caben ${n(count)} adjuntos: el resto se ha omitido.`,
      captureFailed: "No se ha podido capturar la pantalla",
      updateFailed: "No se ha podido guardar el cambio.",
      statusChanged: (status, title) => `Cambiado a «${status}»: ${title}`,
      statusUndo: "Deshacer",
      statusRestored: (status, title) => `De vuelta a «${status}»: ${title}`,
    },
    feedbackMenu: {
      trigger: "Enviar comentarios",
      myFeedback: "Mis comentarios",
      viewFeedback: "Ver comentarios",
    },
    feedbackContext: {
      user: "Usuario",
      attachUrl: "Adjuntar la URL de la página actual",
    },
    feedbackPage: {
      title: "Comentarios",
      myTitle: "Mis comentarios",
      columnId: "#",
      columnDate: "Fecha",
      columnCategory: "Categoría",
      columnSubject: "Asunto",
      columnUser: "Usuario",
      columnEmail: "Correo electrónico",
      columnUrl: "URL",
      columnStatus: "Estado",
      columnResolved: "Resuelto el",
      openPage: "Abrir página",
      empty: "Ninguno",
      deletedUser: "<usuario eliminado>",
      // An id, not a count: printed as it is, like the "#" column.
      userFallback: (id) => `usuario #${id}`,
      environment: (environment) => String(environment ?? "").toUpperCase(),
      reworkChip: (count) => (count === 1 ? "Corrección" : `Corrección ×${n(count)}`),
      awaitingFilter: "Solo lo que está pendiente de usted",
      phoneActions: "Acciones de comentarios",
    },
    feedbackDetail: {
      body: "Descripción",
      edit: "Editar",
      editDescription: "Editar descripción",
      save: "Guardar",
      cancel: "Cancelar",
      url: "URL",
      copyUrl: "Copiar URL",
      attachment: "Adjunto",
      download: (name) => `Descargar ${name}`,
      downloadFailed: "No se ha podido descargar el adjunto.",
      outcome: "Resultado",
      resolvedAt: (date) => `Resuelto el ${date}`,
      outcomeAdd: "Añadir resultado",
      outcomeUpdate: "Actualizar",
      outcomePlaceholder: "Qué se ha hecho o decidido, o por qué no se abordará.",
      rework: "Corrección",
      openPage: "Abrir página",
      reworkTitle: "Devolver para corrección",
      reworkSend: "Solicitar corrección",
      reworkPlaceholder: "¿Qué falta por pulir? Nuevos requisitos o cambios de rumbo.",
      reworkUploadFailed: "No se ha podido subir el archivo. La solicitud de corrección no se ha enviado.",
      status: "Estado",
    },
    accountSettings: {
      profile: {
        title: "Perfil",
        email: "Correo electrónico",
        role: "Rol",
        memberSince: "Miembro desde",
        displayName: "Nombre visible",
        save: "Guardar",
      },
      password: {
        title: "Cambiar contraseña",
        current: "Contraseña actual",
        next: "Nueva contraseña",
        confirm: "Confirmar nueva contraseña",
        submit: "Cambiar contraseña",
        tooShort: "La nueva contraseña es demasiado corta.",
        mismatch: "Las contraseñas no coinciden.",
      },
      twoFactor: {
        status: "Verificación en dos pasos",
        enabledText: "Activada",
        disabledText: "Desactivada",
        enable: "Configurar la verificación en dos pasos",
        scanHint: "Escanee este código con su app de autenticación e introduzca el código que muestra.",
        codeLabel: "Código de verificación",
        verify: "Verificar y activar",
        disableSection: "Desactivar la verificación en dos pasos",
        password: "Contraseña actual",
        disable: "Desactivar",
        qrAlt: "Código QR para su app de autenticación",
        secretHint: "¿No puede escanearlo? Introduzca esta clave en la app:",
        copySecret: "Copiar clave",
      },
      passkeys: {
        title: "Llaves de acceso",
        description: "Inicie sesión con su huella, su cara o el PIN del dispositivo en lugar de una contraseña.",
        descriptionAlongside: "Inicie sesión con su huella, su cara o el PIN del dispositivo. Su contraseña sigue funcionando.",
        empty: "Aún no hay llaves de acceso",
        loading: "Cargando llaves de acceso…",
        list: "Sus llaves de acceso",
        nameLabel: "Nombre (opcional)",
        namePlaceholder: "p. ej. Portátil, Móvil",
        add: "Añadir llave de acceso",
        adding: "Esperando al dispositivo…",
        rename: "Cambiar nombre",
        renameItem: (name) => `Cambiar nombre de ${name}`,
        renameField: (name) => `Nuevo nombre para ${name}`,
        save: "Guardar",
        cancel: "Cancelar",
        delete: "Eliminar",
        deleteItem: (name) => `Eliminar ${name}`,
        deleteConfirm: (name) => `¿Eliminar «${name}»? Ya no podrá iniciar sesión con ella.`,
        confirmDelete: "Eliminar llave de acceso",
        created: (date) => `Añadida el ${date}`,
        lastUsed: (date) => `Último uso: ${date}`,
        neverUsed: "Nunca usada",
      },
    },
    measuredGrid: {
      view: "Vista de tabla",
      cellsView: "Celdas",
      textView: "Texto",
      addRow: "Añadir fila",
      removeRow: (row) => `Quitar la fila ${row}`,
      clear: "Vaciar tabla",
      pasteHint: "Pegue un bloque de una hoja de cálculo en cualquier celda",
      cell: (column, row) => `${column}, fila ${row}`,
      rowNumber: "Fila",
      rowActions: "Acciones de fila",
      keyboardHint:
        "Las flechas mueven entre celdas. Escriba para reemplazar una celda, F2 para editarla, Escape para deshacer la edición. Intro baja y añade una fila al final.",
      lineError: (line) => `No se pudo leer la línea ${line}`,
      points: (count) => (count === 1 ? "1 punto" : `${count} puntos`),
      problems: (count) =>
        count === 1 ? "1 celda no es un número" : `${count} celdas no son números`,
    },
    pageContents: { title: "En esta página" },
    common: {
      dismiss: "Cerrar",
      close: "Cerrar",
      clear: "Borrar",
      search: "Buscar",
      done: "Listo",
      cancel: "Cancelar",
      save: "Guardar",
      back: "Atrás",
      next: "Siguiente",
      remove: "Quitar",
      loading: "Cargando…",
      noResults: "Sin resultados",
      fieldValue: (field, value) => `${field}: ${value}`,
      opensInNewTab: "se abre en una pestaña nueva",
    },
    dataTable: {
      columns: "Columnas",
      selectAllRows: "Seleccionar todas las filas",
      sortHint: "Haga clic para ordenar · Mayús+clic para añadir un criterio",
      filter: "Filtrar",
      close: "Cerrar",
      selectRow: "Seleccionar fila",
      autoSize: "Ajustar ancho de columnas",
      loading: "Cargando…",
      filters: "Filtros",
      clearAll: "Borrar todo",
      done: "Listo",
      pageSize: "Filas por página",
      pageSizeAll: "Todas",
      prevPage: "Página anterior",
      nextPage: "Página siguiente",
      clearFilter: "Borrar filtro",
      filterPlaceholder: "Filtrar…",
      selectFilter: "Seleccionar",
      selectAll: "Todos",
      selectNone: "Ninguno",
      dateFrom: "Desde",
      dateTo: "Hasta",
      numberMin: "Mín.",
      numberMax: "Máx.",
      numberAbs: "Valor absoluto",
      presets: {
        today: "Hoy",
        yesterday: "Ayer",
        this_week: "Esta semana",
        last_week: "Semana pasada",
        last_7_days: "Últimos 7 días",
        last_30_days: "Últimos 30 días",
        this_month: "Este mes",
        last_month: "Mes pasado",
        last_3_months: "Últimos 3 meses",
        ytd: "En lo que va de año",
        last_year: "Año pasado",
      },
      table: "Tabla de datos",
      filterResults: (shown, total) =>
        `${n(shown)} de ${n(total)} ${plural(total, "fila", "filas")}`,
      sortedAscending: (column) => `Ordenado por ${column}, ascendente`,
      sortedDescending: (column) => `Ordenado por ${column}, descendente`,
      sortCleared: (column) => `Orden por ${column} eliminado`,
      pageChanged: (page, totalPages) => `Página ${n(page)} de ${n(totalPages)}`,
      pageRange: (from, to, total) => `${n(from)}–${n(to)} / ${n(total)}`,
      rowCount: (total) => n(total),
      columnsCount: (visible, total) => `Columnas (${n(visible)}/${n(total)})`,
      empty: "No hay entradas",
      actions: "Acciones",
      edit: "Editar",
      delete: "Eliminar",
      booleanTrue: "Sí",
      booleanFalse: "No",
      booleanUnset: "Sin definir",
      sortBy: "Ordenar por",
      sortDefault: "Orden predeterminado",
      sortAscending: "Ascendente",
      sortDescending: "Descendente",
    },
    miniCalendar: {
      previousMonth: "Mes anterior",
      nextMonth: "Mes siguiente",
      // Already formatted in the provider's locale ("lunes, 14 de septiembre de 2026").
      day: (date) => date,
      chooseStart: "Elija una fecha de inicio",
      chooseEnd: "Elija una fecha de fin",
      // "Fecha" is feminine; the date follows a label rather than being the subject of
      // a participle it cannot agree with.
      startSelected: (date) => `Fecha de inicio: ${date}. Elija una fecha de fin.`,
      rangeSelected: (from, to) =>
        `Periodo seleccionado: del ${from} al ${to}. Elija una fecha de inicio para empezar de nuevo.`,
    },
    monthPicker: {
      previousYear: "Año anterior",
      nextYear: "Año siguiente",
      panel: "Elegir un mes",
      month: (monthYear) => monthYear,
      previousMonth: "Mes anterior",
      nextMonth: "Mes siguiente",
      today: "Hoy",
      yearPanel: "Elegir un año",
      earlierYears: "Años anteriores",
      laterYears: "Años posteriores",
      thisYear: "Este año",
    },
    calendarHeatmap: {
      grid: "Valores diarios",
      day: (date, value) => `${date}: ${value}`,
      less: "Menos",
      more: "Más",
      truncated: (count) =>
        `Se muestran los días más recientes; ${count === 1 ? "no se muestra 1 día anterior" : `no se muestran ${n(count)} días anteriores`}.`,
    },
    datePicker: {
      apply: "Aplicar",
      cancel: "Cancelar",
      presets: "Rangos rápidos",
      panel: "Elegir una fecha",
      rangePanel: "Elegir un intervalo de fechas",
      clear: "Borrar",
      previousDay: "Día anterior",
      nextDay: "Día siguiente",
      today: "Hoy",
    },
    popover: {
      panel: "Ventana emergente",
    },
    combobox: {
      search: "Buscar",
      noResults: "Sin resultados",
      clear: "Borrar",
      loading: "Cargando…",
      create: (query) => `Crear «${query}»`,
      selectedCount: (count) => `${n(count)} ${plural(count, "seleccionado", "seleccionados")}`,
      loadError: "No se han podido cargar los resultados",
      resultCount: (count) => `${n(count)} ${plural(count, "resultado", "resultados")}`,
      minChars: (count) =>
        `Escriba al menos ${n(count)} ${plural(count, "carácter", "caracteres")}`,
    },
    multiSelect: {
      search: "Buscar",
      selectAll: "Seleccionar todo",
      clear: "Borrar",
      all: "Todos",
      // The bare count, as in English: the trigger has always shown just the number.
      selectedCount: (count) => n(count),
    },
    calculator: {
      open: "Abrir calculadora",
      panel: "Calculadora",
      calculation: "Cálculo",
      backspace: "Retroceso",
      clear: "Borrar",
      equals: "Igual",
      done: "Listo",
      plus: "Más",
      minus: "Menos",
      times: "Por",
      divide: "Entre",
      decimal: "Separador decimal",
    },
    currency: {
      currency: "Moneda",
      search: "Buscar moneda",
    },
    chipInput: {
      added: (value) => `«${value}» añadido`,
      removed: (value) => `«${value}» quitado`,
      remove: "Quitar",
      atLimit: (max) => `Límite de ${n(max)} ${plural(max, "elemento", "elementos")} alcanzado`,
      duplicate: (value) => `«${value}» ya está en la lista`,
    },
    swatchPicker: {
      none: "Sin color",
      mixed: "Mixto: los elementos seleccionados tienen colores distintos",
    },
    iconPicker: {
      none: "Sin icono",
      mixed: "Mixto: los elementos seleccionados tienen iconos distintos",
      search: "Buscar iconos",
      noResults: "Ningún icono coincide",
      resultCount: (count) => `${n(count)} ${plural(count, "icono", "iconos")}`,
    },
    fieldSync: {
      synced: "Guardado",
      edited: "Cambios sin guardar",
      pending: "Guardando…",
      error: "No se pudo guardar",
      retry: "Reintentar",
    },
    passwordReveal: {
      show: "Mostrar contraseña",
      hide: "Ocultar contraseña",
    },
    dangerConfirm: {
      arm: "Eliminar…",
      confirm: "Eliminar",
      cancel: "Cancelar",
      prompt: "Esta acción no se puede deshacer.",
      password: "Contraseña",
      phrase: (phrase) => `Escriba «${phrase}» para confirmar`,
      acknowledge: "He leído lo que hace esta acción y deseo continuar.",
      needsPhrase: (phrase) => `Escriba «${phrase}» para confirmar`,
      needsAcknowledge: "Marque la casilla para confirmar",
      needsPassword: "Introduzca su contraseña para confirmar",
    },
    tabs: {
      add: "Añadir pestaña",
      remove: (tab) => `Quitar ${tab}`,
    },
    appShell: {
      collapse: "Contraer barra lateral",
      expand: "Expandir barra lateral",
      toggleGroup: (groupLabel) => `${groupLabel}: páginas`,
    },
    topBar: {
      theme: "Cambiar de tema",
      palette: "Ajuste de apariencia",
      language: "Idioma",
      switchRole: "Cambiar de rol",
      role: (value) => `Rol: ${value}`,
    },
    pickerSheet: {
      close: "Cerrar",
    },
    dialogFrame: {
      close: "Cerrar",
    },
    bulkActionBar: {
      selected: (count) => `${n(count)} ${count === 1 ? "seleccionado" : "seleccionados"}`,
      clear: "Borrar selección",
      cleared: "Selección borrada",
    },
    swipeableRow: {
      actions: "Acciones de la fila",
    },
    file: {
      // The kit's own `Intl` unit formatting, pinned to this locale ("3,4 MB").
      size: (bytes) => formatFileSize(bytes, numberLocale),
    },
    filePicker: {
      dropzone: "Carga de archivos",
      browse: "Examinar",
      empty: "Suelte un archivo aquí",
      emptyMultiple: "Suelte archivos aquí",
      hint: (accept) => (accept ? `Aceptados: ${accept}` : "Cualquier tipo de archivo"),
      busy: "Subiendo…",
      rejectedPick: (count) =>
        count === 1 ? "El archivo no se añadió" : `No se añadió ninguno de los ${count} archivos`,
      rejectedType: (name) => `El tipo de archivo de «${name}» no es compatible`,
      rejectedTypeOnly: (accept) => `Solo archivos ${accept}`,
      rejectedSize: (name, maxSize) => `«${name}» supera ${maxSize}`,
      rejectedCount: (name, maxFiles) =>
        `«${name}» no se ha añadido: como máximo ${n(maxFiles)} ${plural(maxFiles, "archivo", "archivos")}`,
      rejectedInvalid: (name) => `«${name}» no se puede usar aquí`,
      rejectedMany: (count) =>
        count === 1 ? "1 archivo no se ha añadido" : `${n(count)} archivos no se han añadido`,
      selected: (count, firstName) =>
        count === 1 ? `«${firstName}» seleccionado` : `${n(count)} archivos seleccionados`,
      remove: (name) => `Quitar «${name}»`,
      clearAll: "Quitar todos los archivos",
      removed: (name) => `«${name}» quitado`,
      cleared: "Se han quitado todos los archivos",
    },
    wizard: {
      done: "Listo",
      cancel: "Cancelar",
      back: "Atrás",
      next: "Siguiente",
      skip: "Omitir",
      finish: "Finalizar",
      submitting: "Creando…",
      steps: "Pasos",
      step: (current, total) => `Paso ${n(current)} de ${n(total)}`,
      cancelTitle: "¿Descartar este formulario?",
      confirmCancel: "Se perderán los datos introducidos.",
      cancelConfirmLabel: "Descartar",
      cancelDismissLabel: "Seguir editando",
      reviewTitle: "Revisión",
      edit: "Editar",
      missingRequired: "Rellene todos los campos obligatorios.",
      genericError: "Se ha producido un error",
    },
    tour: {
      next: "Siguiente",
      back: "Atrás",
      skip: "Omitir",
      done: "Listo",
      awaitClickHint: "Haga clic en el elemento resaltado para continuar",
      step: (current, total) => `${n(current)} / ${n(total)}`,
    },
    commandPalette: {
      clear: "Borrar búsqueda",
      submit: "Buscar",
      close: "Cerrar",
      placeholder: "Buscar…",
      empty: "Sin resultados",
      loading: "Buscando…",
      dialog: "Búsqueda",
      error: "La búsqueda ha fallado. Inténtelo de nuevo.",
    },
    globalSearch: {
      trigger: "Buscar",
      placeholder: "Buscar o ir a…",
      shortcut: (keys) => `Buscar (${keys})`,
      suggestions: "Pruebe",
      results: "Resultados",
    },
    sparkline: {
      rising: (first, last) => `Sube de ${first} a ${last}`,
      falling: (first, last) => `Baja de ${first} a ${last}`,
      flat: (value) => `Estable en ${value}`,
      single: (value) => `Un único valor: ${value}`,
      noData: "Sin datos",
      named: (name, summary) => `${name}: ${summary}`,
    },
    statTile: {
      increase: (amount) => `Sube ${amount}`,
      decrease: (amount) => `Baja ${amount}`,
      unchanged: "Sin cambios",
      better: (change) => `${change} (favorable)`,
      worse: (change) => `${change} (desfavorable)`,
      noValue: "Sin datos",
      loading: "Cargando…",
    },
    signaturePad: {
      label: "Firma",
      instructions: "Firme en el recuadro con el ratón, el dedo o un lápiz.",
      typedFallbackHint: "Si no puede dibujar, escriba su nombre.",
      empty: "Aún no hay nada dibujado",
      signed: "Firma dibujada",
      undo: "Deshacer el último trazo",
      clear: "Borrar",
      save: "Guardar firma",
      useTyped: "Escribir el nombre",
      useDrawn: "Dibujar la firma",
      typedName: "Nombre completo",
      cleared: "Firma borrada",
      undone: "Último trazo eliminado",
      viewEmpty: "Sin firmar",
      viewDrawn: "Firma manuscrita",
      viewTyped: (name) => `Firmado con el nombre escrito ${name}`,
    },
    passwordStrength: {
      // Agrees with "contraseña" (feminine).
      tooShort: "Demasiado corta",
      weak: "Débil",
      fair: "Aceptable",
      good: "Buena",
      strong: "Fuerte",
      announcement: (level) => `Seguridad de la contraseña: ${level}`,
      // Unformatted, as in the English default.
      ruleLength: (minLength) =>
        `Al menos ${minLength} ${plural(minLength, "carácter", "caracteres")}`,
      ruleCase: "Mayúsculas y minúsculas",
      ruleDigit: "Un número",
      ruleSymbol: "Un símbolo",
      optional: (rule) => `${rule} (opcional)`,
      met: "Cumplido:",
      notMet: "No cumplido:",
      tooLong: (maxBytes) =>
        `Como máximo ${maxBytes} ${plural(maxBytes, "carácter", "caracteres")} (las letras con tilde y los emojis cuentan como más de uno).`,
    },
    seriesChart: {
      resetZoom: "Restablecer zoom",
      zoomHint:
        "Arrastre para ampliar: una selección más o menos cuadrada amplía ambos ejes; una larga y estrecha, solo el suyo. Haga doble clic para restablecer.",
      empty: "Sin datos",
      legend: "Series",
      points: "Valores del gráfico",
    },
    pieChart: {
      slices: "Sectores del gráfico",
      slice: (label, value, percent) => `${label}: ${value} (${percent})`,
      total: "Total",
      empty: "Sin datos",
      legend: "Categorías",
    },
    confirmDialog: {
      confirm: "Confirmar",
      cancel: "Cancelar",
      typed: (text) => `Escriba «${text}» para confirmar`,
    },
    floatingPanel: {
      close: "Cerrar",
      badge: (count) => `${n(count)} ${plural(count, "nuevo", "nuevos")}`,
    },
    copyButton: {
      copy: "Copiar",
      copied: "Copiado",
      failed: "No se pudo copiar",
      copiedAnnouncement: "Copiado al portapapeles",
      failedAnnouncement: "No se pudo copiar al portapapeles",
    },
    list: {
      unread: "No leído",
      opensInNewTab: "se abre en una pestaña nueva",
    },
    breadcrumbs: {
      label: "Ruta de navegación",
      showAll: "Mostrar la ruta completa",
    },
    toast: {
      close: "Cerrar notificación",
      notifications: "Notificaciones",
      undo: "Deshacer",
      redo: "Rehacer",
    },
    form: {
      save: "Guardar",
      cancel: "Cancelar",
      submitShortcut: (apple) => (apple ? "⌘ Intro" : "Ctrl+Intro"),
    },
    descriptionList: {
      empty: "—",
    },
    lineItems: {
      add: "Añadir fila",
      remove: (row) => `Eliminar fila ${row}`,
      confirmRemove: (row) => `¿Eliminar fila ${row}? Pulse de nuevo para confirmar`,
      row: (row) => `Fila ${row}`,
      cell: (column, row) => `${column}, fila ${row}`,
      totals: "Total",
    },
    progressBar: {
      unlimited: "Ilimitado",
      overLimit: (amount) => `${amount} por encima del límite`,
    },
    signedAmount: {
      positive: (amount) => `más ${amount}`,
      negative: (amount) => `menos ${amount}`,
    },
    errorBoundary: {
      title: "Algo salió mal",
      message: "No se pudo mostrar esta parte de la página. Inténtelo de nuevo o recargue la página.",
      retry: "Reintentar",
      details: "Detalles del error",
      reload: "Recargar",
      updateTitle: "Hay una nueva versión disponible",
      updateMessage: "Una parte de la aplicación ha cambiado desde que se cargó esta página. Recárguela para obtener la nueva versión.",
      offlineTitle: "Sin conexión",
      offlineMessage: "No se pudo cargar esta página sin conexión. Vuelva a conectarse y recargue la página.",
      copyReport: "Copiar informe de error",
      reported: "El error se ha notificado automáticamente.",
      reportedAs: (reference) => `Notificado con la referencia ${reference}`,
    },
    authedImage: {
      loading: "Cargando imagen…",
      loadError: "No se pudo cargar la imagen",
      failedImage: (alt) => `${alt}: no se pudo cargar la imagen`,
    },
    imageGrid: {
      list: "Imágenes",
      item: (index, count) => `Imagen ${n(index)} de ${n(count)}`,
      actions: (name) => `Acciones para ${name}`,
    },
    lightbox: {
      dialog: "Visor de imágenes",
      close: "Cerrar",
      previous: "Imagen anterior",
      next: "Imagen siguiente",
      counter: (index, count) => `${n(index)} / ${n(count)}`,
      position: (index, count) => `Imagen ${n(index)} de ${n(count)}`,
      download: "Descargar",
      zoom: "Ampliar",
      noPreview: "No hay vista previa disponible para este archivo",
      openInNewTab: "Abrir en una pestaña nueva",
    },
    writeLock: {
      reason: "Puede verlo, pero no modificarlo.",
    },
    accountState: {
      // Agreeing with "cuenta" (feminine): the chip is the state of an account.
      active: "Activa",
      inactive: "Inactiva",
      invited: "Invitación enviada",
      registered: "Registrada",
      unverified: "Sin verificar",
      passwordChange: "Debe cambiar la contraseña",
    },
    shareCard: {
      dialogTitle: "Compartir",
      close: "Cerrar",
      email: "Correo electrónico",
      emailOptional: "Correo electrónico (opcional)",
      // example.com is reserved for examples (RFC 2606); a localised domain is real.
      emailPlaceholder: "nombre@example.com",
      invalidEmail: "Introduzca una dirección de correo completa.",
      role: "Rol",
      roleOf: (name) => `Rol de ${name}`,
      add: "Compartir",
      whoHasAccess: "Quién tiene acceso",
      nobodyYet: "Nadie más tiene acceso todavía.",
      pending: "Pendiente",
      openInvite: "Enlace de invitación abierto",
      copyLink: "Copiar enlace",
      team: "Equipo",
      teamHint: (name) => `Todos los miembros de ${name} tendrán acceso.`,
      remove: "Quitar acceso",
      removeConfirm: (name) => `¿Quitar el acceso a ${name}?`,
      revokePending: "Retirar invitación",
      revokePendingConfirm: (name) => `¿Retirar la invitación para ${name}?`,
      failed: "No ha funcionado. Inténtelo de nuevo.",
      loading: "Cargando…",
    },
    reauthDialog: {
      title: "Confirme que es usted",
      description: "Introduzca su contraseña actual para continuar.",
      password: "Contraseña actual",
      submit: "Continuar",
      cancel: "Cancelar",
    },
    serverWake: {
      slow: "Sigue cargando: está tardando más de lo habitual.",
      waking: (appName) =>
        `El servidor se duerme cuando nadie usa ${appName ?? "la aplicación"}, así que la primera solicitud tras una pausa tiene que volver a arrancarlo. Puede tardar un momento; no se pierde nada y la página se completará sola.`,
    },
    // 0.28.0 — docs/legal-harmonization.md §4.3/§4.4: Kurvenschmiede's reviewed Spanish
    // (formal "usted"), brought into line with the kit's English; it goes back to
    // Kurvenschmiede for review.
    legal: {
      navLabel: "Información legal",
      links: {
        impressum: "Aviso legal",
        privacy: "Política de privacidad",
        terms: "Condiciones de uso",
      },
      titles: {
        impressum: "Aviso legal",
        privacy: "Política de privacidad",
        terms: "Condiciones de uso",
      },
      backHome: "Volver al inicio",
      accept: "Acepto las {terms} y la {privacy}",
      notice: {
        beta: "Beta cerrada. Estos textos aún no han sido revisados por un abogado y lo serán antes de un lanzamiento público.",
        privacy:
          "Beta cerrada. La redacción jurídica que sigue aún no ha sido revisada por un abogado y lo será antes de un lanzamiento público. Las descripciones técnicas —qué se guarda, dónde y quién puede leerlo— describen lo que el software hace realmente hoy y deben poder contrastarse con él.",
      },
      translation: {
        note: (o) =>
          `Esta es una traducción ofrecida para su comodidad. La versión vinculante es la versión en ${o.bindingLanguage}.`,
        show: (o) => `Ver la versión en ${o.bindingLanguage}`,
      },
      sections: {
        impressum: {
          operator: {
            title: "Responsable del sitio",
            body: (o) =>
              `${o.name}\n${o.postalCode} ${o.city}\n${o.country}\n\nLa dirección postal completa se facilita, previa solicitud, a quien tenga un interés jurídico legítimo; escriba a la dirección de contacto indicada abajo.`,
          },
          contact: {
            title: "Contacto",
            body: (o) => `Correo electrónico: ${o.email}`,
          },
          disclaimer: {
            title: "Responsabilidad por contenidos y enlaces",
            body: "Este es un proyecto privado y sin fines comerciales, que se ofrece sin garantía durante una beta cerrada. Los sitios externos que enlazamos son responsabilidad de sus respectivos operadores; no tenemos control sobre su contenido.",
          },
        },
        privacy: {
          controller: {
            title: "Responsable del tratamiento",
            body: (o) =>
              `El responsable del tratamiento de los datos personales en este servicio es:\n${o.name}\n${o.postalCode} ${o.city}, ${o.country}\nCorreo electrónico: ${o.email}\n\nLa dirección postal completa se facilita, previa solicitud, a los interesados y a las autoridades de control.`,
          },
          legal_basis: {
            title: "Base jurídica",
            body: "Como el responsable reside en Suiza, el tratamiento se rige por la Ley Federal suiza de Protección de Datos (LPD). Cuando le sea aplicable el Reglamento General de Protección de Datos de la UE (RGPD), nos basamos en la ejecución de un contrato para prestar el servicio (art. 6.1.b RGPD) y en nuestro interés legítimo en operarlo y protegerlo (art. 6.1.f RGPD).",
          },
          browser: {
            title: "Qué guarda su navegador",
            lead: "Ninguna cookie. La aplicación guarda lo siguiente en el almacenamiento de su navegador:",
            tail: "Nada de ello se usa para rastrearle. Las entradas pendientes de envío se nos envían en cuanto sea posible; todo lo demás permanece en su dispositivo. Todo ello desaparece cuando borra los datos del sitio, y al cerrar sesión se eliminan los tokens de inicio de sesión.",
          },
          rights: {
            title: "Sus derechos",
            lead: "Tiene derecho de acceso, rectificación, supresión, limitación, portabilidad y oposición.",
            tail: "Si se encuentra en Suiza, puede dirigirse al Comisionado Federal de Protección de Datos e Información (FDPIC); si se encuentra en la UE, puede presentar una reclamación ante su autoridad de control local.",
          },
          contact: {
            title: "Contacto para la protección de datos",
            body: (o) => `Para cualquier solicitud sobre privacidad, escriba a: ${o.email}`,
          },
        },
        terms: {
          warranty: {
            title: "Sin garantía",
            body: "El servicio se ofrece «tal cual» y «según disponibilidad», sin garantías de ningún tipo, en la medida en que lo permita la ley. Al ser una beta, puede contener errores, cambiar o interrumpirse en cualquier momento; conserve usted mismo copias de seguridad de los datos importantes.",
          },
          liability: {
            title: "Limitación de responsabilidad",
            body: "En la medida en que lo permita la legislación aplicable, el operador no responde de los daños indirectos o consecuentes derivados del uso o de la imposibilidad de uso del servicio. Nada de lo aquí dispuesto limita la responsabilidad que la ley no permite limitar.",
          },
          changes: {
            title: "Cambios en estas condiciones",
            body: "Estas condiciones pueden actualizarse a medida que evolucione el servicio. Los cambios importantes se anunciarán por correo electrónico o en la aplicación; si sigue usando el servicio después de un cambio, lo acepta.",
          },
          language: {
            title: "Idioma",
            body: (o) =>
              `Estas condiciones están redactadas en ${o.bindingLanguage}. Las traducciones a otros idiomas se ofrecen solo por comodidad; en caso de discrepancia, prevalece la versión en ${o.bindingLanguage}.`,
          },
          law: {
            title: "Legislación aplicable",
            body: (o) =>
              `Estas condiciones se rigen por el derecho suizo, con exclusión de sus normas de conflicto de leyes. En la medida en que lo permita la ley, el fuero competente es ${o.city} (${o.region}), ${o.country}.`,
          },
        },
      },
    },
    characterCount: {
      count: (used, max) => `${n(used)} de ${n(max)} ${plural(max, "carácter", "caracteres")}`,
      remaining: (left) =>
        left === 1 ? "Queda 1 carácter" : `Quedan ${n(left)} caracteres`,
      limitReached: "Límite de caracteres alcanzado",
    },
    countrySelect: {
      country: "País",
      search: "Buscar país",
      others: "Otros países",
    },
    inlineEdit: {
      edit: (label) => `Editar ${label}`,
      failed: "No se ha podido guardar el cambio.",
      empty: "Vacío",
    },
    ibanInput: {
      format: "Un IBAN empieza por un código de país de dos letras y dos dígitos de control.",
      country: (code) => `«${code}» no es el código de país de un IBAN.`,
      length: (actual, expected) =>
        `Un IBAN de este país tiene ${n(expected)} caracteres; este tiene ${n(actual)}.`,
      checksum: "Los dígitos de control no coinciden: probablemente hay un carácter mal escrito.",
      qrRequired: "Este es un IBAN normal. Una factura QR requiere el QR-IBAN de la cuenta.",
      qrNotAllowed:
        "Este es un QR-IBAN, que solo recibe pagos de facturas QR. Introduzca el IBAN normal de la cuenta.",
    },
    phoneInput: {
      countryCode: "Prefijo del país",
      other: "Otro",
    },
    signChip: {
      outflow: "Salida",
      inflow: "Entrada",
      direction: (current, next) => `Dirección: ${current} — cambiar a ${next}`,
    },
    columnMapper: {
      paste: "Pegar una tabla",
      pasteHint:
        "Copie las filas de una hoja de cálculo y péguelas aquí, o suelte un archivo CSV o de texto.",
      chooseFile: "Elegir un archivo",
      readError: (name) => `No se ha podido leer «${name}»`,
      headerRow: "La primera línea contiene los nombres de las columnas",
      summary: (columns, rows) =>
        `${n(columns)} ${plural(columns, "columna", "columnas")}, ${n(rows)} ${plural(rows, "fila", "filas")}`,
      // Fragments of the summary line. "Separado por…" would have to agree with a noun the
      // line does not name, so the separator is stated as a value.
      separatorSemicolon: "separador: punto y coma",
      separatorComma: "separador: coma",
      separatorTab: "separador: tabulación",
      separatorSpace: "separador: espacio",
      // The examples stay as written: they show the convention, not the reader's locale.
      decimalComma: "coma decimal (1,5)",
      decimalPoint: "punto decimal (1.5)",
      unreadCount: (count) =>
        count === 1 ? "No se ha podido leer 1 línea" : `No se han podido leer ${n(count)} líneas`,
      unreadLine: (line) => `No se pudo leer la línea ${line}`,
      unreadMore: (count) => `…y ${n(count)} más`,
      noRows: "Ninguna línea de este texto se puede leer como una fila de la tabla.",
      table: "Columnas y sus funciones",
      columnN: (column) => `Columna ${column}`,
      roleOf: (column) => `¿Qué contiene la columna «${column}»?`,
      ignore: "Ignorar",
      requiredRole: (role) => `${role} (obligatorio)`,
      requiredRoleShort: (role) => `${role} *`,
      previewOf: (shown, total) =>
        shown === 1
          ? `La primera de ${n(total)} filas`
          : `Las primeras ${n(shown)} de ${n(total)} filas`,
      // `roles` arrives joined with "o" ("Debe o Haber").
      oneOf: (roles) => `${roles} (a elegir)`,
      // "Falta" + infinitive: no verb to agree with however many roles follow.
      missing: (roles) => `Falta asignar: ${roles}.`,
    },
    translationReview: {
      statusMissing: "Falta",
      statusUnreviewed: "Sin revisar",
      statusChanged: "Cambiado desde la revisión",
      statusNeedsChange: "Requiere cambios",
      statusApproved: "Aprobado",
      statusFilter: "Estado",
      all: "Todos",
      filterCount: (label, count) => `${label} · ${n(count)}`,
      source: "Textos",
      allSources: "Todos los textos",
      namespace: "Área",
      allNamespaces: "Todas las áreas",
      search: "Buscar en claves y textos",
      placeholdersOnly: (count) => `Solo problemas de marcadores (${n(count)})`,
      placeholderChip: "Marcadores",
      key: "Clave",
      statusColumn: "Estado",
      empty: "Ningún texto coincide con estos filtros.",
      missingText: "Falta en este idioma",
      progress: (approved, total) => `${n(approved)} de ${n(total)} ${plural(approved, "aprobado", "aprobados")}`,
      localeProgress: (approved, total) => `${n(approved)}/${n(total)}`,
      locales: "Idiomas",
      approve: "Aprobar",
      flag: "Requiere cambios",
      suggest: "Proponer traducción",
      reset: "Marcar como sin revisar",
      cancel: "Cancelar",
      approveSelected: "Aprobar la selección",
      resetSelected: "Marcar la selección como sin revisar",
      selectShown: "Seleccionar todo lo mostrado",
      changedSince: "Este texto cambió después de revisarse. Vuelva a leerlo, por favor.",
      reviewedWording: "Redacción al revisarse",
      reviewedReference: "Referencia al revisarse",
      placeholderMismatch: (reference, text) =>
        `Los marcadores no coinciden con la referencia — referencia: ${reference}; este texto: ${text}. La aplicación los rellena, así que deben quedar exactamente como están.`,
      lastApproved: (name, date) => `Aprobado por ${name} el ${date}`,
      lastFlagged: (name, date) => `Marcado para cambiar por ${name} el ${date}`,
      erasedReviewer: "una cuenta eliminada",
      suggestion: "Mejor redacción",
      translation: "Traducción",
      note: "Nota (opcional)",
      notePlaceholder: "Qué está mal o qué hay que tener en cuenta",
      readOnly: "Puede leer este idioma, pero no revisarlo.",
      scope: (areas) => `Su revisión se limita a: ${areas}.`,
      exportCorrections: (count) => `Exportar correcciones (${n(count)})`,
      failed: "No ha funcionado. Inténtelo de nuevo.",
      approvedToast: (count) => (count === 1 ? "Texto aprobado" : `${n(count)} textos aprobados`),
      clearedToast: (count) => (count === 1 ? "Texto marcado como sin revisar" : `${n(count)} textos marcados como sin revisar`),
      // "sin revisar" does not agree with the count, so one form serves both.
      groupCount: (unreviewed, total) => `${n(unreviewed)} sin revisar / ${n(total)}`,
      approveGroup: (count) => `Aprobar los sin revisar (${n(count)})`,
      confirmGroup: (count, group) =>
        count === 1
          ? `¿Aprobar el texto sin revisar de «${group}»?`
          : `¿Aprobar los ${n(count)} textos sin revisar de «${group}», incluidos los que no están en pantalla?`,
    },
  };
}

export const UI_KIT_LABELS_ES: UiKitLabels = uiKitLabelsEs();
