Spreadsheet-UX op een echte relationele engine

main

Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.

11.5 kB Ruw bestand
import { formatCount, type Locale } from '@wellformed/shared';
import type { MessageCatalog } from './entry';

/** The grid and the strips around it: cells, menus, filters, views, the SQL echo. */
export const grid = {
  /* the grid's own states */
  'grid.noTable': { en: 'No table selected.', nl: 'Geen tabel geselecteerd.' },
  'grid.rowsFailed': {
    en: 'Could not load rows.',
    nl: 'De rijen konden niet worden geladen.',
  },
  'grid.loadingTable': {
    en: (label: string) => `Loading ${label}…`,
    nl: (label: string) => `${label} wordt geladen…`,
  },
  'grid.loadingMore': { en: 'Loading more…', nl: 'Meer laden…' },
  'grid.noRowsMatch': {
    en: 'No rows match these filters.',
    nl: 'Geen rijen voldoen aan deze filters.',
  },
  'grid.noRowsYet': {
    en: (label: string) => `No rows in ${label} yet.`,
    nl: (label: string) => `Nog geen rijen in ${label}.`,
  },
  'grid.gridLabel': {
    en: (label: string) => `${label} grid`,
    nl: (label: string) => `Raster van ${label}`,
  },

  /* rows: adding, composing, deleting */
  'grid.newRow': { en: 'New row', nl: 'Nieuwe rij' },
  'grid.demoReadOnly': {
    en: 'This is the published demo, read-only. Make your own workspace to edit — the button is top right.',
    nl: 'Dit is de gepubliceerde demo, alleen-lezen. Maak er zelf een om te bewerken — de knop staat rechtsboven.',
  },
  'grid.viewerReadOnly': {
    en: 'You are a viewer in this workspace, so the grid is read-only.',
    nl: 'Je bent kijker in deze werkruimte, dus het raster is alleen-lezen.',
  },
  'grid.draftFillIn': {
    en: (cols: string) => `Fill in ${cols} to create the row`,
    nl: (cols: string) => `Vul ${cols} in om de rij aan te maken`,
  },
  'grid.draftDiscard': { en: 'Esc to discard', nl: 'Esc om te verwerpen' },
  'grid.notSavedYet': { en: 'Not saved yet', nl: 'Nog niet opgeslagen' },
  'grid.deletedRow': {
    en: (label: string) => `Deleted ${label}.`,
    nl: (label: string) => `${label} is verwijderd.`,
  },
  'grid.ruleFired': {
    en: (workflow: string) => `Rule fired — ${workflow}`,
    nl: (workflow: string) => `Regel uitgevoerd — ${workflow}`,
  },

  /* what the undo history calls each change */
  'grid.undoCellEdit': {
    en: (col: string, row: string) => `${col} on ${row}`,
    nl: (col: string, row: string) => `${col} van ${row}`,
  },
  'grid.undoNewRow': {
    en: (table: string) => `new row in ${table}`,
    nl: (table: string) => `nieuwe rij in ${table}`,
  },
  'grid.undoDeleteRow': {
    en: (label: string) => `delete ${label}`,
    nl: (label: string) => `${label} verwijderen`,
  },
  'grid.undoPaste': {
    en: (row: string) => `paste into ${row}`,
    nl: (row: string) => `plakken in ${row}`,
  },

  /* clipboard */
  'grid.copied': { en: 'Copied.', nl: 'Gekopieerd.' },
  'grid.copiedCells': {
    en: (n: number, locale: Locale) => `Copied ${formatCount(n, locale)} cells.`,
    nl: (n: number, locale: Locale) => `${formatCount(n, locale)} cellen gekopieerd.`,
  },

  /* hiding columns from the grid */
  'grid.hideColumn': { en: 'Hide column', nl: 'Kolom verbergen' },
  'grid.showHiddenColumns': {
    en: (n: number) => `Show hidden columns (${n})`,
    nl: (n: number) => `Verborgen kolommen tonen (${n})`,
  },

  /* the block selection */
  'grid.selectionMenu': { en: 'Selection', nl: 'Selectie' },
  'grid.copySelection': { en: 'Copy selection', nl: 'Selectie kopiëren' },
  'grid.clearSelection': { en: 'Clear selection', nl: 'Selectie opheffen' },
  'grid.clipboardRefused': {
    en: 'The browser would not give Wellformed clipboard access.',
    nl: 'De browser geeft Wellformed geen toegang tot het klembord.',
  },
  'grid.pasteTooBig': {
    en: (n: number, max: number, locale: Locale) =>
      `That is ${formatCount(n, locale)} cells; paste at most ${formatCount(max, locale)} at a time.`,
    nl: (n: number, max: number, locale: Locale) =>
      `Dat zijn ${formatCount(n, locale)} cellen; plak er hoogstens ${formatCount(max, locale)} tegelijk.`,
  },
  'grid.pasted': {
    en: (n: number, locale: Locale) =>
      `Pasted into ${formatCount(n, locale)} row${n === 1 ? '' : 's'}.`,
    nl: (n: number, locale: Locale) =>
      `Geplakt in ${formatCount(n, locale)} rij${n === 1 ? '' : 'en'}.`,
  },
  'grid.pastedSkipped': {
    en: (n: number, locale: Locale) =>
      `${formatCount(n, locale)} computed cell${n === 1 ? '' : 's'} skipped.`,
    nl: (n: number, locale: Locale) =>
      `${formatCount(n, locale)} berekende cel${n === 1 ? '' : 'len'} overgeslagen.`,
  },

  /* column headers */
  'grid.colRequired': {
    en: (name: string) => `${name} is required`,
    nl: (name: string) => `${name} is verplicht`,
  },
  'grid.colUnique': {
    en: (name: string) => `${name} must be unique`,
    nl: (name: string) => `${name} moet uniek zijn`,
  },
  'grid.resizeCol': {
    en: (name: string) => `Resize ${name}`,
    nl: (name: string) => `Breedte van ${name} aanpassen`,
  },

  /* the header, summary and row menus */
  'grid.columnMenu': {
    en: (name: string) => `${name} column`,
    nl: (name: string) => `Kolom ${name}`,
  },
  'grid.rowActions': { en: 'Row actions', nl: 'Rijacties' },
  'grid.sortAsc': { en: 'Sort ascending', nl: 'Oplopend sorteren' },
  'grid.sortDesc': { en: 'Sort descending', nl: 'Aflopend sorteren' },
  'grid.clearSort': { en: 'Clear sort', nl: 'Sortering wissen' },
  'grid.filterByColumn': { en: 'Filter by this column', nl: 'Filteren op deze kolom' },
  'grid.resetWidth': { en: 'Reset width', nl: 'Breedte herstellen' },
  'grid.useAsRowLabel': { en: 'Use as row label', nl: 'Als rijlabel gebruiken' },
  'grid.editColumn': { en: 'Edit column…', nl: 'Kolom bewerken…' },
  'grid.tightenColumn': { en: 'Tighten column…', nl: 'Kolom aanscherpen…' },
  'grid.addColumn': { en: 'Add column…', nl: 'Kolom toevoegen…' },
  'grid.deleteColumn': { en: 'Delete column', nl: 'Kolom verwijderen' },
  'grid.showHistory': {
    en: 'Show this row’s history',
    nl: 'Geschiedenis van deze rij tonen',
  },
  'grid.copyRowId': { en: 'Copy row id', nl: 'Rij-id kopiëren' },
  'grid.deleteRow': { en: 'Delete row', nl: 'Rij verwijderen' },

  /* the aggregate row and its functions */
  'grid.rowCountTitle': {
    en: (n: number, locale: Locale) => `${formatCount(n, locale)} row${n === 1 ? '' : 's'}`,
    nl: (n: number, locale: Locale) => `${formatCount(n, locale)} rij${n === 1 ? '' : 'en'}`,
  },
  'grid.summarise': {
    en: (name: string) => `Summarise ${name}`,
    nl: (name: string) => `${name} samenvatten`,
  },
  'grid.summariseThis': { en: 'Summarise this column', nl: 'Deze kolom samenvatten' },
  'grid.summaryOf': {
    en: (fn: string, col: string, text: string) => `${fn} of ${col}: ${text}`,
    nl: (fn: string, col: string, text: string) => `${fn} van ${col}: ${text}`,
  },
  'grid.noSummary': { en: 'No summary', nl: 'Geen samenvatting' },
  'grid.agg.sum': { en: 'Sum', nl: 'Som' },
  'grid.agg.avg': { en: 'Average', nl: 'Gemiddelde' },
  'grid.agg.min': { en: 'Min', nl: 'Min' },
  'grid.agg.max': { en: 'Max', nl: 'Max' },
  'grid.agg.filled': { en: 'Filled', nl: 'Gevuld' },
  'grid.agg.empty': { en: 'Empty', nl: 'Leeg' },
  'grid.agg.unique': { en: 'Unique', nl: 'Uniek' },
  'grid.agg.checked': { en: 'Checked', nl: 'Aangevinkt' },
  'grid.agg.unchecked': { en: 'Unchecked', nl: 'Niet aangevinkt' },
  'grid.agg.earliest': { en: 'Earliest', nl: 'Vroegste' },
  'grid.agg.latest': { en: 'Latest', nl: 'Laatste' },

  /* cells */
  'grid.cellError': { en: '#ERROR', nl: '#FOUT' },
  'grid.openLink': {
    en: (label: string) => `Open ${label}`,
    nl: (label: string) => `${label} openen`,
  },

  /* the link picker */
  'grid.searchPlaceholder': { en: 'Search…', nl: 'Zoeken…' },
  'grid.linkRows': {
    en: (col: string) => `${col} rows`,
    nl: (col: string) => `Rijen voor ${col}`,
  },
  'grid.noLinkMatches': { en: 'No rows match.', nl: 'Geen rijen gevonden.' },
  'grid.linkCapped': {
    en: (n: number, locale: Locale) =>
      `Searching the first ${formatCount(n, locale)} rows only.`,
    nl: (n: number, locale: Locale) =>
      `Er wordt alleen in de eerste ${formatCount(n, locale)} rijen gezocht.`,
  },

  /* the record panel behind a link */
  'grid.openInTable': {
    en: (label: string) => `Open in ${label}`,
    nl: (label: string) => `Openen in ${label}`,
  },
  'grid.linkRowNotLoaded': {
    en: (n: number, label: string, locale: Locale) =>
      `This row is not among the first ${formatCount(n, locale)} of ${label}, so there is nothing loaded to show. Open the table to find it.`,
    nl: (n: number, label: string, locale: Locale) =>
      `Deze rij zit niet bij de eerste ${formatCount(n, locale)} van ${label}, dus er is niets geladen om te tonen. Open de tabel om hem te vinden.`,
  },

  /* the formula bar */
  'grid.noSelection': { en: 'no selection', nl: 'geen selectie' },
  'grid.cellValue': { en: 'Cell value', nl: 'Celwaarde' },
  'grid.typeColumn': {
    en: (type: string) => `${type} column`,
    nl: (type: string) => `${type}-kolom`,
  },
  'grid.evaluatedInSql': {
    en: (type: string) => `evaluated in SQL · ${type}`,
    nl: (type: string) => `berekend in SQL · ${type}`,
  },
  'grid.foreignKey': {
    en: (target: string) => `foreign key → ${target}`,
    nl: (target: string) => `koppeling → ${target}`,
  },
  'grid.anotherTable': { en: 'another table', nl: 'een andere tabel' },

  /* the SQL bar: the query itself stays SQL; only the frame speaks */
  'grid.sqlRowCount': {
    en: (n: number, locale: Locale) => `${formatCount(n, locale)} ROW${n === 1 ? '' : 'S'}`,
    nl: (n: number, locale: Locale) => `${formatCount(n, locale)} RIJ${n === 1 ? '' : 'EN'}`,
  },
  'grid.viewSql': { en: 'view SQL ▸', nl: 'SQL bekijken ▸' },
  'grid.hideSql': { en: 'hide SQL ▾', nl: 'SQL verbergen ▾' },
  'grid.copySql': { en: 'COPY', nl: 'KOPIËREN' },
  'grid.sqlCopied': { en: 'SQL copied.', nl: 'SQL gekopieerd.' },
  'grid.sqlForView': { en: 'SQL for the current view', nl: 'SQL voor de huidige weergave' },
  'grid.sqlForSummary': { en: 'SQL for the aggregate row', nl: 'SQL voor de samenvattingsrij' },

  /* the view bar: filters and saved views */
  'grid.addFilterOption': { en: '+ filter…', nl: '+ filter…' },
  'grid.filterColumn': { en: 'Filter column', nl: 'Filterkolom' },
  'grid.filterOperator': { en: 'Filter operator', nl: 'Filteroperator' },
  'grid.filterValue': { en: 'Filter value', nl: 'Filterwaarde' },
  'grid.valuePlaceholder': { en: 'value', nl: 'waarde' },
  'grid.applyFilter': { en: 'Apply', nl: 'Toepassen' },
  'grid.removeFilter': {
    en: (filter: string) => `Remove filter ${filter}`,
    nl: (filter: string) => `Filter ${filter} verwijderen`,
  },
  'grid.op.contains': { en: 'contains', nl: 'bevat' },
  'grid.op.isEmpty': { en: 'is empty', nl: 'is leeg' },
  'grid.op.isNotEmpty': { en: 'is not empty', nl: 'is niet leeg' },
  'grid.nameThisView': { en: 'Name this view', nl: 'Geef deze weergave een naam' },
  'grid.newView': { en: 'New view', nl: 'Nieuwe weergave' },
  'grid.saveAsView': { en: 'Save as view', nl: 'Opslaan als weergave' },
  'grid.updateView': {
    en: (name: string) => `Update “${name}”`,
    nl: (name: string) => `“${name}” bijwerken`,
  },
  'grid.savedView': {
    en: (name: string) => `Saved view “${name}”.`,
    nl: (name: string) => `Weergave “${name}” opgeslagen.`,
  },
  'grid.updatedView': {
    en: (name: string) => `Updated “${name}”.`,
    nl: (name: string) => `“${name}” bijgewerkt.`,
  },
  'grid.deleteView': { en: 'Delete view', nl: 'Weergave verwijderen' },
  'grid.deleteViewConfirm': {
    en: (name: string) => `Delete the view “${name}”?`,
    nl: (name: string) => `De weergave “${name}” verwijderen?`,
  },
} as const satisfies MessageCatalog;