@protobase/ui 0.63.4 → 0.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/dist/account/change-email-dialog.js +1 -1
  2. package/dist/account/devices-section.js +12 -6
  3. package/dist/account/messages.js +2 -333
  4. package/dist/account/passkeys-section.js +3 -3
  5. package/dist/account/password-change-dialog.js +3 -3
  6. package/dist/account/sign-in-policy-form.js +6 -3
  7. package/dist/account/sign-in-providers-section.js +1 -1
  8. package/dist/account/staff-sign-in-log.js +5 -5
  9. package/dist/action-card/messages.js +2 -5
  10. package/dist/activity-chart/activity-chart.js +5 -7
  11. package/dist/activity-chart/activity-tooltip.js +1 -1
  12. package/dist/activity-chart/messages.js +2 -11
  13. package/dist/app/app.js +2 -3
  14. package/dist/app/batch-failure.js +5 -1
  15. package/dist/app/change-confirm/messages.js +2 -13
  16. package/dist/app/change-confirm/use-change-confirm.js +15 -18
  17. package/dist/app/charts/chart-groups.js +3 -1
  18. package/dist/app/charts/chart-view.js +1 -1
  19. package/dist/app/charts/group-bars.js +1 -1
  20. package/dist/app/charts/messages.js +2 -23
  21. package/dist/app/charts/period-chart.js +1 -1
  22. package/dist/app/comments/comment-composer.js +1 -1
  23. package/dist/app/comments/comments-section.js +2 -2
  24. package/dist/app/comments/messages.js +2 -19
  25. package/dist/app/confirm-sign-in-messages.js +2 -19
  26. package/dist/app/confirm-sign-in.js +1 -1
  27. package/dist/app/create/create-page.js +3 -3
  28. package/dist/app/create/create-record-form.js +3 -3
  29. package/dist/app/create/create-route.js +1 -1
  30. package/dist/app/create/messages.js +2 -29
  31. package/dist/app/custom-section.js +2 -3
  32. package/dist/app/delete/blocked-delete.js +5 -2
  33. package/dist/app/delete/dialogs.js +21 -8
  34. package/dist/app/delete/messages.js +2 -63
  35. package/dist/app/delete/use-delete-flow.js +6 -5
  36. package/dist/app/displays/board-column.js +2 -2
  37. package/dist/app/displays/board-columns.js +1 -1
  38. package/dist/app/displays/board-display.js +21 -9
  39. package/dist/app/displays/calendar-display.js +16 -7
  40. package/dist/app/displays/cards-display.js +2 -2
  41. package/dist/app/displays/custom-display.js +1 -2
  42. package/dist/app/displays/list-cards.js +2 -2
  43. package/dist/app/displays/map-display.js +19 -6
  44. package/dist/app/displays/messages.js +2 -147
  45. package/dist/app/displays/period-controls.js +2 -2
  46. package/dist/app/displays/timeline-display.js +16 -7
  47. package/dist/app/displays/timeline-range.js +1 -1
  48. package/dist/app/displays/use-board-move.js +4 -4
  49. package/dist/app/displays/use-calendar-move.js +2 -2
  50. package/dist/app/document-title.js +1 -1
  51. package/dist/app/embedded-list/cut-off-note.js +7 -1
  52. package/dist/app/embedded-list/embedded-list.js +1 -1
  53. package/dist/app/embedded-list/embedded-row-targets.js +3 -3
  54. package/dist/app/embedded-list/messages.js +2 -21
  55. package/dist/app/export/builder-port.js +1 -1
  56. package/dist/app/export/export-dialog.js +14 -8
  57. package/dist/app/export/messages.js +2 -75
  58. package/dist/app/export/use-export-flow.js +9 -3
  59. package/dist/app/field-editor.js +3 -3
  60. package/dist/app/field-errors.js +18 -7
  61. package/dist/app/field-messages.js +2 -45
  62. package/dist/app/field-types/members/messages.js +2 -15
  63. package/dist/app/field-types/messages.js +2 -5
  64. package/dist/app/field-types/widget-part.js +1 -1
  65. package/dist/app/file-field.js +3 -3
  66. package/dist/app/gallery/gallery-section.js +6 -3
  67. package/dist/app/gallery/messages.js +2 -27
  68. package/dist/app/gallery/photo-details.js +3 -3
  69. package/dist/app/hand-order/hand-sorted-list.js +2 -3
  70. package/dist/app/hand-order/messages.js +2 -29
  71. package/dist/app/hand-order/use-hand-order.js +2 -2
  72. package/dist/app/history/describe-change.js +1 -1
  73. package/dist/app/history/history-section.js +1 -1
  74. package/dist/app/history/messages.js +2 -29
  75. package/dist/app/import/convert.js +19 -10
  76. package/dist/app/import/import-check-step.js +5 -5
  77. package/dist/app/import/import-dialog.js +5 -2
  78. package/dist/app/import/import-file-step.js +1 -1
  79. package/dist/app/import/import-mapping-step.js +3 -3
  80. package/dist/app/import/messages.js +2 -197
  81. package/dist/app/import/prepare-rows.js +11 -4
  82. package/dist/app/import/sheet-cell.js +1 -1
  83. package/dist/app/import/xlsx-reader.js +2 -2
  84. package/dist/app/import/zip-reader.js +4 -1
  85. package/dist/app/incoming-card.js +1 -1
  86. package/dist/app/list-actions/use-list-actions.js +4 -1
  87. package/dist/app/list-edit/messages.js +2 -11
  88. package/dist/app/list-edit/use-list-edits.js +1 -1
  89. package/dist/app/list-empty-state.js +7 -4
  90. package/dist/app/list-group-chart.js +1 -1
  91. package/dist/app/list-messages.js +2 -53
  92. package/dist/app/list-page.js +9 -9
  93. package/dist/app/live-update/messages.js +2 -11
  94. package/dist/app/map/messages.js +2 -11
  95. package/dist/app/messages.js +2 -139
  96. package/dist/app/meta-gate-messages.js +2 -13
  97. package/dist/app/nav-from-meta.js +2 -2
  98. package/dist/app/new-version/messages.js +2 -21
  99. package/dist/app/new-version/new-version-banner.js +1 -2
  100. package/dist/app/new-version/new-version-toast.js +1 -1
  101. package/dist/app/pages/action-inputs/action-inputs-dialog.js +1 -1
  102. package/dist/app/pages/action-inputs/input-answers.js +1 -1
  103. package/dist/app/pages/blocks/field.js +1 -1
  104. package/dist/app/pages/blocks/modal-form.js +3 -3
  105. package/dist/app/pages/blocks/settings.js +3 -3
  106. package/dist/app/pages/blocks/tabs.js +1 -1
  107. package/dist/app/pages/composed-page.js +1 -2
  108. package/dist/app/pages/custom-boundary.js +1 -2
  109. package/dist/app/pages/messages.js +2 -79
  110. package/dist/app/pages/record-actions.js +1 -1
  111. package/dist/app/pages/render-node.js +2 -3
  112. package/dist/app/pages/use-run-action.js +15 -7
  113. package/dist/app/picker/picker-combobox.js +1 -1
  114. package/dist/app/rank-after/dependency-rule.js +8 -2
  115. package/dist/app/rank-after/messages.js +2 -5
  116. package/dist/app/rank-after/ranked-place.js +7 -1
  117. package/dist/app/record-chart/messages.js +2 -25
  118. package/dist/app/record-chart/record-chart-section.js +2 -2
  119. package/dist/app/record-lines-cell.js +4 -1
  120. package/dist/app/record-lines.js +5 -5
  121. package/dist/app/record-messages.js +2 -83
  122. package/dist/app/record-page.js +8 -8
  123. package/dist/app/record-row/messages.js +2 -23
  124. package/dist/app/record-row/record-row-body.js +2 -2
  125. package/dist/app/record-row/record-row.js +3 -3
  126. package/dist/app/record-row/saved-record-row.js +3 -3
  127. package/dist/app/related-cards/messages.js +2 -15
  128. package/dist/app/related-cards/related-card.js +1 -1
  129. package/dist/app/related-cards/related-cards.js +1 -1
  130. package/dist/app/related-dots/dots-summary.js +1 -1
  131. package/dist/app/related-dots/messages.js +2 -5
  132. package/dist/app/related-dots/related-dots.js +2 -3
  133. package/dist/app/related-section.js +1 -1
  134. package/dist/app/relation-picker.js +1 -1
  135. package/dist/app/runtime/messages.js +2 -55
  136. package/dist/app/runtime/runtime-status.js +12 -3
  137. package/dist/app/saved/messages.js +2 -19
  138. package/dist/app/saved/saved-list.js +3 -3
  139. package/dist/app/search/messages.js +2 -19
  140. package/dist/app/search/navigation-hits.js +1 -1
  141. package/dist/app/search/search-model.js +9 -3
  142. package/dist/app/searches/messages.js +2 -93
  143. package/dist/app/searches/save-search-button.js +3 -3
  144. package/dist/app/searches/saved-search-rows.js +3 -3
  145. package/dist/app/searches/saved-search-section.js +4 -4
  146. package/dist/app/searches/saved-searches.js +14 -12
  147. package/dist/app/searches/search-controls.js +2 -2
  148. package/dist/app/searches/search-diff.js +8 -2
  149. package/dist/app/searches/update-search-dialog.js +10 -4
  150. package/dist/app/searches/use-save-search.js +2 -2
  151. package/dist/app/searches/use-search-row.js +2 -2
  152. package/dist/app/sensitive-field.js +3 -3
  153. package/dist/app/source-notice.js +3 -3
  154. package/dist/app/staff-banner.js +12 -8
  155. package/dist/app/use-live-save.js +2 -2
  156. package/dist/app/value-badge.js +3 -4
  157. package/dist/app-shell/global-search.js +2 -2
  158. package/dist/app-shell/messages.js +2 -63
  159. package/dist/app-shell/profile-menu.js +2 -2
  160. package/dist/app-shell/sidebar-group.js +2 -2
  161. package/dist/app-shell/sidebar.js +1 -2
  162. package/dist/app-shell/top-bar.js +1 -1
  163. package/dist/assistant-dock/messages.js +2 -23
  164. package/dist/auth/auth-gate.js +1 -1
  165. package/dist/auth/auth-messages.js +9 -88
  166. package/dist/auth/email-code-form.js +2 -3
  167. package/dist/auth/forgot-password-form.js +3 -4
  168. package/dist/auth/messages.js +2 -203
  169. package/dist/auth/provider-sign-in-page.js +3 -3
  170. package/dist/auth/resend-code-button.js +1 -1
  171. package/dist/auth/reset-password-form.js +1 -1
  172. package/dist/auth/reset-password-page.js +1 -1
  173. package/dist/auth/sign-in-form.js +3 -3
  174. package/dist/auth/sign-up-code-form.js +2 -3
  175. package/dist/auth/sign-up-details-form.js +3 -4
  176. package/dist/auth/staff-sign-in-form.js +3 -3
  177. package/dist/calls/call-guests-panel.js +2 -2
  178. package/dist/calls/call-lobby-notice.js +1 -1
  179. package/dist/calls/call-mark.js +1 -1
  180. package/dist/calls/call-people.js +1 -1
  181. package/dist/calls/call-rings.js +1 -1
  182. package/dist/calls/call-tile.js +2 -2
  183. package/dist/calls/messages.js +2 -139
  184. package/dist/carousel/carousel-controls.js +4 -1
  185. package/dist/carousel/messages.js +2 -13
  186. package/dist/chat/chat-message.js +1 -1
  187. package/dist/chat/messages.js +2 -19
  188. package/dist/compact-table/compact-table.js +1 -1
  189. package/dist/compact-table/messages.js +2 -15
  190. package/dist/data-grid/cell-text.js +8 -7
  191. package/dist/data-grid/cells.js +9 -6
  192. package/dist/data-grid/grid-footer.js +1 -1
  193. package/dist/data-grid/grid-row.js +2 -2
  194. package/dist/data-grid/header-menu.js +1 -1
  195. package/dist/data-grid/messages.js +2 -49
  196. package/dist/data-grid/resize-handle.js +1 -1
  197. package/dist/data-grid/row-reorder.js +20 -5
  198. package/dist/filter-panel/active-filter-chips.js +1 -1
  199. package/dist/filter-panel/date-presets.js +2 -2
  200. package/dist/filter-panel/facet-combobox.js +1 -1
  201. package/dist/filter-panel/facet-group.js +1 -1
  202. package/dist/filter-panel/messages.js +2 -49
  203. package/dist/filter-panel/range-filter.js +1 -1
  204. package/dist/format/date.js +4 -4
  205. package/dist/format/messages.js +2 -21
  206. package/dist/format/money.js +1 -1
  207. package/dist/format/number.js +5 -2
  208. package/dist/forms/messages.js +2 -21
  209. package/dist/forms/public-form-page.js +1 -1
  210. package/dist/index.js +3 -3
  211. package/dist/inline-child-table/inline-child-table.js +19 -4
  212. package/dist/inline-child-table/line-row.js +2 -2
  213. package/dist/inline-child-table/messages.js +2 -51
  214. package/dist/invitations/link-notice.js +2 -3
  215. package/dist/invitations/messages.js +2 -21
  216. package/dist/invitations/pending-invitation-row.js +1 -1
  217. package/dist/lists/messages.js +2 -5
  218. package/dist/live/columns-from-model.js +14 -31
  219. package/dist/live/display-value.js +1 -1
  220. package/dist/live/messages.js +2 -15
  221. package/dist/live/value-color.js +13 -3
  222. package/dist/live/view-fields.js +4 -2
  223. package/dist/locale/en.js +1399 -0
  224. package/dist/locale/messages.js +38 -7
  225. package/dist/locale/nl.js +1399 -0
  226. package/dist/markdown/messages.js +2 -13
  227. package/dist/mentions/messages.js +2 -13
  228. package/dist/notifications/bell/messages.js +2 -35
  229. package/dist/notifications/bell/notification-item.js +1 -1
  230. package/dist/notifications/bell/unread-label.js +1 -1
  231. package/dist/organizations/invitation-page.js +32 -14
  232. package/dist/organizations/invitations-page.js +1 -1
  233. package/dist/organizations/members-page.js +2 -2
  234. package/dist/organizations/messages.js +2 -187
  235. package/dist/organizations/organization-page.js +4 -4
  236. package/dist/organizations/organizations-page.js +1 -1
  237. package/dist/package.js +1 -1
  238. package/dist/plugins/load-plugin.js +2 -2
  239. package/dist/plugins/messages.js +2 -33
  240. package/dist/plugins/plugin-notice.js +7 -5
  241. package/dist/primitives/badge.d.ts +2 -1
  242. package/dist/primitives/dialog.d.ts +7 -2
  243. package/dist/primitives/dialog.js +9 -4
  244. package/dist/primitives/messages.js +2 -13
  245. package/dist/primitives/token.js +1 -1
  246. package/dist/record-view/field.js +3 -3
  247. package/dist/record-view/messages.js +2 -37
  248. package/dist/record-view/record-header.js +4 -4
  249. package/dist/roles/messages.js +2 -11
  250. package/dist/shell/assets/app-CN_7en9q.js +8 -0
  251. package/dist/shell/assets/{calls-BIXaKTs0.js → calls-D5RK7EJu.js} +2 -2
  252. package/dist/shell/assets/export-worker-ClXdfeuq.js +15 -0
  253. package/dist/shell/assets/{index-BshKxX1Z.js → index-DMaCBpbN.js} +2 -2
  254. package/dist/shell/assets/index-Or2wt-ck.css +2 -0
  255. package/dist/shell/assets/{maplibre-CjNYwEqW.js → maplibre-CRmpQfDl.js} +3 -3
  256. package/dist/shell/assets/parse-worker-DxsmAjef.js +18 -0
  257. package/dist/shell/assets/preload-helper-BgLOXTzV.js +2 -0
  258. package/dist/shell/assets/{record-map-DjqQGqZ2.js → record-map-DsP4sXes.js} +2 -2
  259. package/dist/shell/assets/{records-map-D1SJKyvj.js → records-map-WFMHgKdf.js} +2 -2
  260. package/dist/shell/assets/shared-protobase-ui-CP2mMFbh.js +2 -0
  261. package/dist/shell/assets/vendor-Kvdo8Jrw.js +73 -0
  262. package/dist/shell/index.html +6 -6
  263. package/dist/shell/protobase.shell.json +2 -2
  264. package/dist/shell/protobase.sw.js +2 -2
  265. package/dist/shell-source-maps/assets/app-CN_7en9q.js.map +1 -0
  266. package/dist/shell-source-maps/assets/{calls-BIXaKTs0.js.map → calls-D5RK7EJu.js.map} +1 -1
  267. package/dist/shell-source-maps/assets/export-worker-ClXdfeuq.js.map +1 -0
  268. package/dist/shell-source-maps/assets/{index-BshKxX1Z.js.map → index-DMaCBpbN.js.map} +1 -1
  269. package/dist/shell-source-maps/assets/{maplibre-CjNYwEqW.js.map → maplibre-CRmpQfDl.js.map} +1 -1
  270. package/dist/shell-source-maps/assets/parse-worker-DxsmAjef.js.map +1 -0
  271. package/dist/shell-source-maps/assets/preload-helper-BgLOXTzV.js.map +1 -0
  272. package/dist/shell-source-maps/assets/{record-map-DjqQGqZ2.js.map → record-map-DsP4sXes.js.map} +1 -1
  273. package/dist/shell-source-maps/assets/{records-map-D1SJKyvj.js.map → records-map-WFMHgKdf.js.map} +1 -1
  274. package/dist/shell-source-maps/assets/shared-protobase-ui-CP2mMFbh.js.map +1 -0
  275. package/dist/shell-source-maps/assets/vendor-Kvdo8Jrw.js.map +1 -0
  276. package/dist/side-panel/messages.js +2 -5
  277. package/dist/status/messages.js +2 -59
  278. package/dist/status/status-dialog.js +1 -1
  279. package/dist/toasts/messages.js +2 -5
  280. package/dist/users/create-user-form.js +1 -1
  281. package/dist/users/messages.js +2 -49
  282. package/package.json +5 -4
  283. package/dist/app-shell/nav.js +0 -85
  284. package/dist/locale/slotted.js +0 -14
  285. package/dist/mocks/activity.js +0 -24
  286. package/dist/mocks/rng.js +0 -20
  287. package/dist/mocks/users.js +0 -63
  288. package/dist/shell/assets/app-CBYlZ19-.js +0 -9
  289. package/dist/shell/assets/export-worker-3e4Zsv0a.js +0 -3
  290. package/dist/shell/assets/index-BvT0X9o1.css +0 -2
  291. package/dist/shell/assets/parse-worker-UhbwEjS0.js +0 -6
  292. package/dist/shell/assets/preload-helper-SYSsmQ2O.js +0 -2
  293. package/dist/shell/assets/shared-protobase-ui-DibYt-TM.js +0 -2
  294. package/dist/shell/assets/vendor-xNCj9Gc_.js +0 -63
  295. package/dist/shell-source-maps/assets/app-CBYlZ19-.js.map +0 -1
  296. package/dist/shell-source-maps/assets/export-worker-3e4Zsv0a.js.map +0 -1
  297. package/dist/shell-source-maps/assets/parse-worker-UhbwEjS0.js.map +0 -1
  298. package/dist/shell-source-maps/assets/preload-helper-SYSsmQ2O.js.map +0 -1
  299. package/dist/shell-source-maps/assets/shared-protobase-ui-DibYt-TM.js.map +0 -1
  300. package/dist/shell-source-maps/assets/vendor-xNCj9Gc_.js.map +0 -1
@@ -18,16 +18,16 @@ const toNumberText = (cell, options) => {
18
18
  };
19
19
  const integerValue = (field, cell, options) => {
20
20
  const text$1 = toNumberText(cell, options);
21
- if (text$1 === void 0) return problem(text("notNumber", quoted(cell)));
21
+ if (text$1 === void 0) return problem(text("notNumber", { cell: quoted(cell) }));
22
22
  const [whole, fraction = ""] = text$1.split(".");
23
- if (/[1-9]/.test(fraction) || /e/i.test(text$1)) return problem(text("notWholeNumber", quoted(cell)));
23
+ if (/[1-9]/.test(fraction) || /e/i.test(text$1)) return problem(text("notWholeNumber", { cell: quoted(cell) }));
24
24
  if (field.type === "bigint") return ok(String(BigInt(whole)));
25
25
  const value = Number(whole);
26
- return Number.isSafeInteger(value) ? ok(value) : problem(text("tooLarge", quoted(cell)));
26
+ return Number.isSafeInteger(value) ? ok(value) : problem(text("tooLarge", { cell: quoted(cell) }));
27
27
  };
28
28
  const decimalValue = (cell, options) => {
29
29
  const text$2 = toNumberText(cell, options);
30
- return text$2 === void 0 ? problem(text("notNumber", quoted(cell))) : ok(text$2);
30
+ return text$2 === void 0 ? problem(text("notNumber", { cell: quoted(cell) })) : ok(text$2);
31
31
  };
32
32
  const trueWords = /* @__PURE__ */ new Set([
33
33
  "true",
@@ -44,7 +44,7 @@ const booleanValue = (cell) => {
44
44
  const text$3 = typeof cell === "string" || typeof cell === "number" ? String(cell).trim().toLowerCase() : "";
45
45
  if (trueWords.has(text$3)) return ok(true);
46
46
  if (falseWords.has(text$3)) return ok(false);
47
- return problem(text("notBoolean", quoted(cell)));
47
+ return problem(text("notBoolean", { cell: quoted(cell) }));
48
48
  };
49
49
  const pad = (value) => String(value).padStart(2, "0");
50
50
  const calendarDate = (year, month, day) => {
@@ -91,11 +91,14 @@ const wallTimeOf = (cell, options) => {
91
91
  }
92
92
  return typeof cell === "string" ? readWallTime(cell, options.dateOrder) : void 0;
93
93
  };
94
- const notDate = (cell, options) => problem(text("notDate", quoted(cell), options.dateOrder === "dmy"));
94
+ const notDate = (cell, options) => problem(text("notDate", {
95
+ cell: quoted(cell),
96
+ dayFirst: options.dateOrder === "dmy"
97
+ }));
95
98
  const dateValue = (cell, options) => {
96
99
  const at = wallTimeOf(cell, options);
97
100
  if (!at) return notDate(cell, options);
98
- if (at.time && at.time !== "00:00:00") return problem(text("hasTime", quoted(cell)));
101
+ if (at.time && at.time !== "00:00:00") return problem(text("hasTime", { cell: quoted(cell) }));
99
102
  return ok(at.date);
100
103
  };
101
104
  const timestampValue = (cell, options) => {
@@ -112,10 +115,16 @@ const enumValue = (field, hints, cell) => {
112
115
  const text$4 = normalized(cellText(cell));
113
116
  const matches = values.filter((value) => normalized(value) === text$4 || normalized(enumLabel(value, hints?.valueLabels)) === text$4);
114
117
  if (matches.length === 1) return ok(matches[0]);
115
- if (matches.length > 1) return problem(text("severalValues", quoted(cell), matches.map((value) => enumLabel(value, hints?.valueLabels)).join(", ")));
116
- return problem(text("notOneOf", quoted(cell), values.map((value) => enumLabel(value, hints?.valueLabels)).join(", ")));
118
+ if (matches.length > 1) return problem(text("severalValues", {
119
+ cell: quoted(cell),
120
+ values: matches.map((value) => enumLabel(value, hints?.valueLabels)).join(", ")
121
+ }));
122
+ return problem(text("notOneOf", {
123
+ cell: quoted(cell),
124
+ values: values.map((value) => enumLabel(value, hints?.valueLabels)).join(", ")
125
+ }));
117
126
  };
118
- const textValue = (cell) => typeof cell === "boolean" ? problem(text("notText", quoted(cell))) : ok(cellText(cell));
127
+ const textValue = (cell) => typeof cell === "boolean" ? problem(text("notText", { cell: quoted(cell) })) : ok(cellText(cell));
119
128
  /**
120
129
  * The value a cell gives a field, as the API takes it, or the problem that keeps it from being one: never a guess, and an
121
130
  * empty cell is null, never a default. A relation's cell is the value of the field its records are found by, so it
@@ -13,7 +13,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
13
13
  /** How many rows with problems the check lists; the file of them holds every one. */
14
14
  const listedProblems = 50;
15
15
  /** Saves the rows with their problems as a CSV named after the imported file. */
16
- const downloadRows = (fileName, headers, rows) => saveFile(failedRowsCsv(headers, rows), text("notImportedFile", (fileName ?? "import").replace(/\.[^.]+$/, "")), "text/csv");
16
+ const downloadRows = (fileName, headers, rows) => saveFile(failedRowsCsv(headers, rows), text("notImportedFile", { name: (fileName ?? "import").replace(/\.[^.]+$/, "") }), "text/csv");
17
17
  /** The rows with what keeps each from being imported, at most `listedProblems` of them. */
18
18
  const ProblemList = ({ rows }) => /* @__PURE__ */ jsxs("ul", {
19
19
  "aria-label": text("rowsNotImported"),
@@ -21,19 +21,19 @@ const ProblemList = ({ rows }) => /* @__PURE__ */ jsxs("ul", {
21
21
  children: [rows.slice(0, listedProblems).map((row) => /* @__PURE__ */ jsxs("li", { children: [
22
22
  /* @__PURE__ */ jsx("span", {
23
23
  className: "font-medium",
24
- children: text("rowProblems", row.line)
24
+ children: text("rowProblems", { line: row.line })
25
25
  }),
26
26
  " ",
27
27
  row.problems.join("; ")
28
28
  ] }, row.line)), rows.length > listedProblems && /* @__PURE__ */ jsx("li", {
29
29
  className: "text-muted-foreground",
30
- children: text("andMore", (rows.length - listedProblems).toLocaleString(formatTag()))
30
+ children: text("andMore", { count: (rows.length - listedProblems).toLocaleString(formatTag()) })
31
31
  })]
32
32
  });
33
33
  const ImportChecking = ({ rows }) => /* @__PURE__ */ jsxs("p", {
34
34
  className: "flex items-center gap-2 text-muted-foreground",
35
35
  role: "status",
36
- children: [/* @__PURE__ */ jsx(Spinner, { className: "size-3.5" }), text("checkingRows", rows.toLocaleString(formatTag()))]
36
+ children: [/* @__PURE__ */ jsx(Spinner, { className: "size-3.5" }), text("checkingRows", { count: rows.toLocaleString(formatTag()) })]
37
37
  });
38
38
  /**
39
39
  * What the import would do, before it writes anything: how many rows create or update a record, the first rows as they
@@ -99,7 +99,7 @@ const ImportCheckStep = ({ check, model, resources, views, columns, headers, fil
99
99
  }),
100
100
  /* @__PURE__ */ jsx("p", {
101
101
  className: "text-xs text-muted-foreground",
102
- children: text("batches", 100)
102
+ children: text("batches", { size: 100 })
103
103
  })
104
104
  ]
105
105
  });
@@ -73,7 +73,10 @@ const ImportDialog = ({ model, resources, views, canUpdate, onClose, sourceFor }
73
73
  variant: "primary",
74
74
  disabled: rows === 0,
75
75
  onClick: () => flow.start(rows),
76
- children: text("importRows", rows.toLocaleString(formatTag()), rows)
76
+ children: text("importRows", {
77
+ count: rows.toLocaleString(formatTag()),
78
+ rows
79
+ })
77
80
  })] });
78
81
  }
79
82
  case "importing": return /* @__PURE__ */ jsx(Button, {
@@ -132,7 +135,7 @@ const ImportDialog = ({ model, resources, views, canUpdate, onClose, sourceFor }
132
135
  return /* @__PURE__ */ jsx(ResponsiveDialog, {
133
136
  open: true,
134
137
  wide: true,
135
- title: text("importPlural", plural),
138
+ title: text("importPlural", { plural }),
136
139
  description: flow.file && step.kind !== "file" ? flow.file.name : void 0,
137
140
  onClose: close,
138
141
  actions: actions(),
@@ -39,7 +39,7 @@ const ImportFileStep = ({ file, sheets, sheet, reading, onChoose, onSheet }) =>
39
39
  reading && /* @__PURE__ */ jsxs("p", {
40
40
  className: "flex items-center gap-2 text-muted-foreground",
41
41
  role: "status",
42
- children: [/* @__PURE__ */ jsx(Spinner, { className: "size-3.5" }), text("reading", file?.name ?? text("theFile"))]
42
+ children: [/* @__PURE__ */ jsx(Spinner, { className: "size-3.5" }), text("reading", { name: file?.name ?? text("theFile") })]
43
43
  }),
44
44
  !reading && sheets.length > 1 && /* @__PURE__ */ jsxs("div", {
45
45
  className: "flex items-end gap-3",
@@ -162,13 +162,13 @@ const ImportMappingStep = ({ flow, model, resources, views, canUpdate }) => {
162
162
  className: "flex min-w-0 flex-col gap-2",
163
163
  children: [/* @__PURE__ */ jsx(ImportSelect, {
164
164
  label: text("field"),
165
- name: text("fieldFor", name),
165
+ name: text("fieldFor", { name }),
166
166
  value: mapped?.field ?? skip,
167
167
  options: fieldOptions,
168
168
  onChange: (next) => flow.mapColumn(column, next || void 0)
169
169
  }), target && /* @__PURE__ */ jsx(ImportSelect, {
170
170
  label: text("foundBy"),
171
- name: text("pluralFoundBy", views[target.name]?.names?.plural ?? fieldLabel(view, field.name)),
171
+ name: text("pluralFoundBy", { plural: views[target.name]?.names?.plural ?? fieldLabel(view, field.name) }),
172
172
  value: mapped.matchBy ?? target.primaryKey[0],
173
173
  options: matchFields(target).map((candidate) => ({
174
174
  value: candidate.name,
@@ -183,7 +183,7 @@ const ImportMappingStep = ({ flow, model, resources, views, canUpdate }) => {
183
183
  missing.length > 0 && /* @__PURE__ */ jsxs("p", {
184
184
  role: "alert",
185
185
  className: "flex gap-2 rounded-lg border border-warning/30 bg-warning-soft px-3 py-2 text-warning-text",
186
- children: [/* @__PURE__ */ jsx(TriangleAlert, { className: "mt-0.5 size-4 shrink-0" }), /* @__PURE__ */ jsx("span", { children: text("noColumnFills", missing.map((field) => fieldLabel(view, field.name)).join(", ")) })]
186
+ children: [/* @__PURE__ */ jsx(TriangleAlert, { className: "mt-0.5 size-4 shrink-0" }), /* @__PURE__ */ jsx("span", { children: text("noColumnFills", { fields: missing.map((field) => fieldLabel(view, field.name)).join(", ") }) })]
187
187
  })
188
188
  ]
189
189
  });
@@ -1,200 +1,5 @@
1
- import { defineMessages } from "../../locale/messages.js";
1
+ import { messages } from "../../locale/messages.js";
2
2
  //#region src/app/import/messages.ts
3
- const text = defineMessages({
4
- en: {
5
- import: "Import",
6
- importPlural: (plural) => `Import ${plural.toLowerCase()}`,
7
- couldNotReadFile: "Could not read the file",
8
- couldNotCheck: "Could not check the rows",
9
- cancel: "Cancel",
10
- next: "Next",
11
- checkRows: "Check rows",
12
- back: "Back",
13
- checking: "Checking",
14
- importRows: (count, rows) => `Import ${count} ${rows === 1 ? "row" : "rows"}`,
15
- cancelImport: "Cancel import",
16
- done: "Done",
17
- file: "File",
18
- fileHint: "An Excel workbook (.xlsx) or a CSV file saved as UTF-8. Its first row names the columns.",
19
- reading: (name) => `Reading ${name}…`,
20
- theFile: "the file",
21
- sheet: "Sheet",
22
- create: "Create",
23
- update: "Update",
24
- upsert: "Create or update",
25
- createHint: "Each row creates a record.",
26
- updateHint: "Each row updates the record its value finds; a row that finds none is not imported.",
27
- upsertHint: "Each row updates the record its value finds, or creates one when it finds none.",
28
- doNotImport: "Do not import",
29
- rows: "Rows",
30
- whatEachRowDoes: "What each row does",
31
- findBy: "Find records by",
32
- chooseField: "Choose a field",
33
- findByHint: "A field no two records share, such as the key or an email.",
34
- foundInColumn: "Found in column",
35
- chooseColumn: "Choose a column",
36
- numbers: "Numbers",
37
- dates: "Dates",
38
- dayFirst: "Day first (31/12/2026)",
39
- monthFirst: "Month first (12/31/2026)",
40
- datesHint: "Dates written as 2026-12-31 read the same either way. Times without a zone are your own time.",
41
- requiredMarked: "New records need the fields marked *.",
42
- columns: "Columns",
43
- emptyInFirstRows: "Empty in the first rows",
44
- field: "Field",
45
- fieldFor: (name) => `Field for ${name}`,
46
- foundBy: "Found by",
47
- pluralFoundBy: (plural) => `${plural} found by`,
48
- noColumnFills: (fields) => `No column fills ${fields}, which new records need.`,
49
- rowsNotImported: "Rows not imported",
50
- rowProblems: (line) => `Row ${line}:`,
51
- andMore: (count) => `And ${count} more rows, all in the file.`,
52
- checkingRows: (count) => `Checking rows… ${count} read`,
53
- check: "Check",
54
- toCreate: "To create",
55
- toUpdate: "To update",
56
- withProblems: "With problems",
57
- firstRows: "First rows",
58
- row: "Row",
59
- problemRows: "Rows with problems, which are skipped",
60
- download: "Download",
61
- batches: (size) => `Rows are saved in batches of ${size}. Cancelling, or an error, keeps the batches already saved; a row the server refuses is listed and the others are saved.`,
62
- stopping: "Stopping after this batch…",
63
- saving: "Saving rows…",
64
- rowsSaved: "Rows saved",
65
- stopped: "The import stopped. The rows counted below were saved.",
66
- cancelled: "Cancelled. The rows counted below were saved.",
67
- summary: "Import summary",
68
- created: "Created",
69
- updated: "Updated",
70
- skipped: "Skipped",
71
- failed: "Failed",
72
- notWrittenHint: "Skipped rows had problems in the file; the server refused the failed ones. The file holds each with the reason, to fix and import again.",
73
- notImportedFile: (name) => `${name} - not imported.csv`,
74
- line: "Line",
75
- problems: "Problems",
76
- notNumber: (cell) => `${cell} is not a number`,
77
- notWholeNumber: (cell) => `${cell} is not a whole number`,
78
- tooLarge: (cell) => `${cell} is too large`,
79
- notBoolean: (cell) => `${cell} is not true or false (true, false, yes, no, 1 or 0)`,
80
- notDate: (cell, dayFirst) => `${cell} is not a date (2026-04-03 or ${dayFirst ? "day/month/year" : "month/day/year"})`,
81
- hasTime: (cell) => `${cell} has a time of day; the field holds a date`,
82
- severalValues: (cell, values) => `${cell} matches more than one value: ${values}`,
83
- notOneOf: (cell, values) => `${cell} is not one of ${values}`,
84
- notText: (cell) => `${cell} is true or false, not text`,
85
- emptyRequired: "is empty, and it is required",
86
- noneHas: (singular, named) => `no ${singular.toLowerCase()} has ${named}`,
87
- severalHave: (count, plural, named) => `${count} ${plural.toLowerCase()} have ${named}`,
88
- notOneRecord: (found) => `Not one record: ${found}`,
89
- nothingToUpdate: (found) => `Nothing to update: ${found}`,
90
- fileNotUtf8: "The file is not UTF-8 text. Save it as \"CSV UTF-8\" and choose it again.",
91
- noSheets: "The workbook has no sheets",
92
- missingSheetPart: "The workbook names a sheet it does not hold",
93
- notZip: "The file is not an Excel workbook (.xlsx): it is no ZIP archive",
94
- zip64: "The workbook is too large to read: it is a ZIP64 archive",
95
- compression: (part, method) => `The workbook's part ${part} is compressed in a way that cannot be read (method ${method})`,
96
- notWorkbook: (part) => `The file is not an Excel workbook (.xlsx): it has no ${part}`,
97
- noSheetCalled: (name) => `The workbook has no sheet called ${name}`,
98
- unreadable: "The file could not be read",
99
- column: (letters) => `Column ${letters}`
100
- },
101
- nl: {
102
- import: "Importeren",
103
- importPlural: (plural) => `${plural} importeren`,
104
- couldNotReadFile: "Kon het bestand niet lezen",
105
- couldNotCheck: "Kon de rijen niet controleren",
106
- cancel: "Annuleren",
107
- next: "Volgende",
108
- checkRows: "Rijen controleren",
109
- back: "Terug",
110
- checking: "Controleren",
111
- importRows: (count, rows) => `${count} ${rows === 1 ? "rij" : "rijen"} importeren`,
112
- cancelImport: "Import annuleren",
113
- done: "Klaar",
114
- file: "Bestand",
115
- fileHint: "Een Excel-werkmap (.xlsx) of een CSV-bestand bewaard als UTF-8. De eerste rij noemt de kolommen.",
116
- reading: (name) => `${name} lezen…`,
117
- theFile: "het bestand",
118
- sheet: "Werkblad",
119
- create: "Maken",
120
- update: "Bijwerken",
121
- upsert: "Maken of bijwerken",
122
- createHint: "Elke rij maakt een record.",
123
- updateHint: "Elke rij werkt het record bij dat haar waarde vindt; een rij die er geen vindt, wordt niet geïmporteerd.",
124
- upsertHint: "Elke rij werkt het record bij dat haar waarde vindt, of maakt er een als ze er geen vindt.",
125
- doNotImport: "Niet importeren",
126
- rows: "Rijen",
127
- whatEachRowDoes: "Wat elke rij doet",
128
- findBy: "Records vinden op",
129
- chooseField: "Kies een veld",
130
- findByHint: "Een veld dat geen twee records delen, zoals de sleutel of een e-mailadres.",
131
- foundInColumn: "Gevonden in kolom",
132
- chooseColumn: "Kies een kolom",
133
- numbers: "Getallen",
134
- dates: "Datums",
135
- dayFirst: "Dag eerst (31/12/2026)",
136
- monthFirst: "Maand eerst (12/31/2026)",
137
- datesHint: "Datums geschreven als 2026-12-31 lezen hoe dan ook hetzelfde. Tijden zonder zone zijn in je eigen tijd.",
138
- requiredMarked: "Nieuwe records hebben de velden met * nodig.",
139
- columns: "Kolommen",
140
- emptyInFirstRows: "Leeg in de eerste rijen",
141
- field: "Veld",
142
- fieldFor: (name) => `Veld voor ${name}`,
143
- foundBy: "Gevonden op",
144
- pluralFoundBy: (plural) => `${plural} gevonden op`,
145
- noColumnFills: (fields) => `Geen kolom vult ${fields}, wat nieuwe records nodig hebben.`,
146
- rowsNotImported: "Niet geïmporteerde rijen",
147
- rowProblems: (line) => `Rij ${line}:`,
148
- andMore: (count) => `En nog ${count} rijen, allemaal in het bestand.`,
149
- checkingRows: (count) => `Rijen controleren… ${count} gelezen`,
150
- check: "Controle",
151
- toCreate: "Te maken",
152
- toUpdate: "Bij te werken",
153
- withProblems: "Met problemen",
154
- firstRows: "Eerste rijen",
155
- row: "Rij",
156
- problemRows: "Rijen met problemen, die worden overgeslagen",
157
- download: "Downloaden",
158
- batches: (size) => `Rijen worden bewaard in groepen van ${size}. Annuleren, of een fout, houdt de groepen die al bewaard zijn; een rij die de server weigert, wordt vermeld en de andere worden bewaard.`,
159
- stopping: "Stoppen na deze groep…",
160
- saving: "Rijen bewaren…",
161
- rowsSaved: "Bewaarde rijen",
162
- stopped: "De import is gestopt. De rijen die hieronder zijn geteld, zijn bewaard.",
163
- cancelled: "Geannuleerd. De rijen die hieronder zijn geteld, zijn bewaard.",
164
- summary: "Samenvatting van de import",
165
- created: "Gemaakt",
166
- updated: "Bijgewerkt",
167
- skipped: "Overgeslagen",
168
- failed: "Mislukt",
169
- notWrittenHint: "Overgeslagen rijen hadden problemen in het bestand; de mislukte weigerde de server. Het bestand bevat elke rij met de reden, om te verbeteren en opnieuw te importeren.",
170
- notImportedFile: (name) => `${name} - niet geïmporteerd.csv`,
171
- line: "Regel",
172
- problems: "Problemen",
173
- notNumber: (cell) => `${cell} is geen getal`,
174
- notWholeNumber: (cell) => `${cell} is geen geheel getal`,
175
- tooLarge: (cell) => `${cell} is te groot`,
176
- notBoolean: (cell) => `${cell} is niet waar of onwaar (true, false, yes, no, 1 of 0)`,
177
- notDate: (cell, dayFirst) => `${cell} is geen datum (2026-04-03 of ${dayFirst ? "dag/maand/jaar" : "maand/dag/jaar"})`,
178
- hasTime: (cell) => `${cell} heeft een tijd van de dag; het veld bevat een datum`,
179
- severalValues: (cell, values) => `${cell} past bij meer dan één waarde: ${values}`,
180
- notOneOf: (cell, values) => `${cell} is niet een van ${values}`,
181
- notText: (cell) => `${cell} is waar of onwaar, geen tekst`,
182
- emptyRequired: "is leeg, en is verplicht",
183
- noneHas: (singular, named) => `geen ${singular.toLowerCase()} heeft ${named}`,
184
- severalHave: (count, plural, named) => `${count} ${plural.toLowerCase()} hebben ${named}`,
185
- notOneRecord: (found) => `Niet één record: ${found}`,
186
- nothingToUpdate: (found) => `Niets om bij te werken: ${found}`,
187
- fileNotUtf8: "Het bestand is geen UTF-8-tekst. Bewaar het als \"CSV UTF-8\" en kies het opnieuw.",
188
- noSheets: "De werkmap heeft geen werkbladen",
189
- missingSheetPart: "De werkmap noemt een werkblad dat er niet in zit",
190
- notZip: "Het bestand is geen Excel-werkmap (.xlsx): het is geen ZIP-archief",
191
- zip64: "De werkmap is te groot om te lezen: het is een ZIP64-archief",
192
- compression: (part, method) => `Het deel ${part} van de werkmap is gecomprimeerd op een manier die niet kan worden gelezen (methode ${method})`,
193
- notWorkbook: (part) => `Het bestand is geen Excel-werkmap (.xlsx): het heeft geen ${part}`,
194
- noSheetCalled: (name) => `De werkmap heeft geen werkblad met de naam ${name}`,
195
- unreadable: "Het bestand kon niet worden gelezen",
196
- column: (letters) => `Kolom ${letters}`
197
- }
198
- });
3
+ const text = messages("app/import");
199
4
  //#endregion
200
5
  export { text };
@@ -63,8 +63,15 @@ const foundOne = (context, finding) => {
63
63
  const keys = context.lookups.keysOf(finding.model.name, finding.field, finding.value);
64
64
  const named = `${fieldLabel(context.views[finding.model.name], finding.field).toLowerCase()} “${String(finding.value)}”`;
65
65
  if (keys.length === 1) return { key: keys[0] };
66
- if (keys.length === 0) return { none: text("noneHas", singularOf(context.views, finding.model.name), named) };
67
- return { several: text("severalHave", keys.length, pluralOf(context.views, finding.model.name), named) };
66
+ if (keys.length === 0) return { none: text("noneHas", {
67
+ singular: singularOf(context.views, finding.model.name),
68
+ named
69
+ }) };
70
+ return { several: text("severalHave", {
71
+ count: keys.length,
72
+ plural: pluralOf(context.views, finding.model.name),
73
+ named
74
+ }) };
68
75
  };
69
76
  const isBlank = (row) => row.cells.every(isEmptyCell);
70
77
  /**
@@ -97,8 +104,8 @@ const prepareRows = async (rows, plan, context) => {
97
104
  else problems.push(`${fieldLabel(views[model.name], field)}: ${found.none ?? found.several}`);
98
105
  }
99
106
  const existing = match && foundOne(context, match);
100
- if (existing?.several) problems.push(text("notOneRecord", existing.several));
101
- if (existing?.none && plan.mode === "update") problems.push(text("nothingToUpdate", existing.none));
107
+ if (existing?.several) problems.push(text("notOneRecord", { found: existing.several }));
108
+ if (existing?.none && plan.mode === "update") problems.push(text("nothingToUpdate", { found: existing.none }));
102
109
  const prepared = {
103
110
  line: row.line,
104
111
  cells: row.cells,
@@ -13,6 +13,6 @@ const cellText = (cell) => {
13
13
  /** A column's letters as a spreadsheet names it: 0 is A, 27 is AB. */
14
14
  const columnLetters = (index) => index < 26 ? String.fromCharCode(65 + index) : columnLetters(Math.floor(index / 26) - 1) + columnLetters(index % 26);
15
15
  /** How the import names a column: its header, or "Column C" when the header cell is empty. */
16
- const columnName = (headers, index) => headers[index]?.trim() ? headers[index] : text("column", columnLetters(index));
16
+ const columnName = (headers, index) => headers[index]?.trim() ? headers[index] : text("column", { letters: columnLetters(index) });
17
17
  //#endregion
18
18
  export { cellText, columnLetters, columnName, isEmptyCell, isSheetDate };
@@ -4,7 +4,7 @@ import { zipEntries, zipText, zipTextChunks } from "./zip-reader.js";
4
4
  //#region src/app/import/xlsx-reader.ts
5
5
  const part = (entries, name) => {
6
6
  const entry = entries.get(name);
7
- if (!entry) throw new Error(text("notWorkbook", name));
7
+ if (!entry) throw new Error(text("notWorkbook", { part: name }));
8
8
  return entry;
9
9
  };
10
10
  /**
@@ -25,7 +25,7 @@ const openWorkbook = async (blob) => {
25
25
  };
26
26
  async function* rows(name) {
27
27
  const sheet = sheets.find((candidate) => candidate.name === name);
28
- if (!sheet) throw new Error(text("noSheetCalled", name));
28
+ if (!sheet) throw new Error(text("noSheetCalled", { name }));
29
29
  const shared = context ?? await sheetContext();
30
30
  const scan = createRowScanner();
31
31
  let line = 0;
@@ -48,7 +48,10 @@ const zipEntryStream = async (blob, entry) => {
48
48
  const raw = blob.slice(dataStart, dataStart + entry.size).stream();
49
49
  if (entry.method === 0) return raw;
50
50
  if (entry.method === 8) return raw.pipeThrough(new DecompressionStream("deflate-raw"));
51
- throw new Error(text("compression", entry.name, entry.method));
51
+ throw new Error(text("compression", {
52
+ part: entry.name,
53
+ method: entry.method
54
+ }));
52
55
  };
53
56
  /** The entry's content as text, decoded as UTF-8 a chunk at a time. */
54
57
  async function* zipTextChunks(blob, entry) {
@@ -1,8 +1,8 @@
1
1
  import { useAdminMeta } from "./meta-gate.js";
2
2
  import { formatInt } from "../format/number.js";
3
3
  import { Skeleton } from "../primitives/skeleton.js";
4
- import { SidebarCard } from "../record-view/record-sidebar.js";
5
4
  import { AppLink } from "./use-app-address.js";
5
+ import { SidebarCard } from "../record-view/record-sidebar.js";
6
6
  import { text } from "./record-messages.js";
7
7
  import { incomingAddress, incomingRelations } from "./incoming-relations.js";
8
8
  import { useIncomingCounts } from "./use-incoming-counts.js";
@@ -54,7 +54,10 @@ const useListActions = (model) => {
54
54
  };
55
55
  }),
56
56
  bulkActions: listed.filter((action) => action.bulk && action.run?.kind !== "link").map((action) => ({
57
- label: (count) => text("actionCount", action.label, count),
57
+ label: (count) => text("actionCount", {
58
+ label: action.label,
59
+ count
60
+ }),
58
61
  destructive: isDanger(action),
59
62
  available: (row) => runner.appliesOn(action, rowRecord(model, row)),
60
63
  onRun: (rows, skipped) => start({
@@ -1,14 +1,5 @@
1
- import { defineMessages } from "../../locale/messages.js";
1
+ import { messages } from "../../locale/messages.js";
2
2
  //#region src/app/list-edit/messages.ts
3
- const text = defineMessages({
4
- en: {
5
- changedBySomeoneElse: "Changed by someone else",
6
- couldNotSave: "Could not save"
7
- },
8
- nl: {
9
- changedBySomeoneElse: "Gewijzigd door iemand anders",
10
- couldNotSave: "Kon niet bewaren"
11
- }
12
- });
3
+ const text = messages("app/list-edit");
13
4
  //#endregion
14
5
  export { text };
@@ -1,7 +1,7 @@
1
1
  import { keys } from "../../data/query-keys.js";
2
2
  import { useClient } from "../../data/api-provider.js";
3
- import { useToast } from "../../toasts/toast-provider.js";
4
3
  import { recordKey } from "../../live/model-helpers.js";
4
+ import { useToast } from "../../toasts/toast-provider.js";
5
5
  import { text } from "./messages.js";
6
6
  import { useRef, useState } from "react";
7
7
  import { encodeKey } from "@protobase/schema/internal";
@@ -3,25 +3,28 @@ import { text } from "./list-messages.js";
3
3
  /** Why a list has no rows, and the buttons that help: clear the search, clear the filters, or create the first record. */
4
4
  const listEmptyState = ({ plural, search, filtered, scoped, canCreate }) => {
5
5
  if (search) return {
6
- message: text("noMatchSearch", plural, search),
6
+ message: text("noMatchSearch", {
7
+ plural,
8
+ search
9
+ }),
7
10
  clearSearch: true,
8
11
  clearFilters: filtered,
9
12
  create: false
10
13
  };
11
14
  if (filtered) return {
12
- message: text("noMatchFilters", plural),
15
+ message: text("noMatchFilters", { plural }),
13
16
  clearSearch: false,
14
17
  clearFilters: true,
15
18
  create: false
16
19
  };
17
20
  if (scoped) return {
18
- message: text("noMatch", plural),
21
+ message: text("noMatch", { plural }),
19
22
  clearSearch: false,
20
23
  clearFilters: false,
21
24
  create: false
22
25
  };
23
26
  return {
24
- message: text("noneYet", plural),
27
+ message: text("noneYet", { plural }),
25
28
  clearSearch: false,
26
29
  clearFilters: false,
27
30
  create: canCreate
@@ -7,7 +7,7 @@ const measureTitle = (chart, view, plural) => {
7
7
  const name = chart.sum ?? chart.average;
8
8
  if (name === void 0) return plural;
9
9
  const label = view?.fields[name]?.label ?? humanize(name);
10
- return chart.sum !== void 0 ? `${label}` : text("average", label);
10
+ return chart.sum !== void 0 ? `${label}` : text("average", { label });
11
11
  };
12
12
  /** The view's chart per value of a field, above the list and following its filter. */
13
13
  const ListGroupChart = ({ model, view, chart, plural, filter }) => {
@@ -1,56 +1,5 @@
1
- import { defineMessages } from "../locale/messages.js";
1
+ import { messages } from "../locale/messages.js";
2
2
  //#region src/app/list-messages.ts
3
- const text = defineMessages({
4
- en: {
5
- noList: (name) => `There is no list called ${name}.`,
6
- searchPlural: (plural) => `Search ${plural.toLowerCase()}`,
7
- search: "Search",
8
- sort: "Sort",
9
- filters: "Filters",
10
- filtersCount: (count) => `Filters (${count})`,
11
- newRecord: (singular) => `New ${singular.toLowerCase()}`,
12
- export: "Export",
13
- openRecord: (singular) => `Open ${singular.toLowerCase()}`,
14
- delete: "Delete",
15
- exportCount: (count) => `Export ${count}`,
16
- deleteCount: (count) => `Delete ${count}`,
17
- actionCount: (label, count) => `${label} (${count})`,
18
- dragToSort: "Drag a row by its handle to move it. Every move is saved as you drop it.",
19
- unreadableFilter: "The filter in the address could not be read",
20
- couldNotLoadRows: "Could not load rows",
21
- created: (plural) => `${plural} created`,
22
- noMatchSearch: (plural, search) => `No ${plural.toLowerCase()} match “${search}”.`,
23
- noMatchFilters: (plural) => `No ${plural.toLowerCase()} match these filters.`,
24
- noMatch: (plural) => `No ${plural.toLowerCase()} match.`,
25
- noneYet: (plural) => `No ${plural.toLowerCase()} yet.`,
26
- clearSearch: "Clear search",
27
- clearFilters: "Clear filters"
28
- },
29
- nl: {
30
- noList: (name) => `Er is geen lijst met de naam ${name}.`,
31
- searchPlural: (plural) => `Zoeken in ${plural.toLowerCase()}`,
32
- search: "Zoeken",
33
- sort: "Sorteren",
34
- filters: "Filters",
35
- filtersCount: (count) => `Filters (${count})`,
36
- newRecord: (singular) => `${singular} toevoegen`,
37
- export: "Exporteren",
38
- openRecord: (singular) => `${singular} openen`,
39
- delete: "Verwijderen",
40
- exportCount: (count) => `${count} exporteren`,
41
- deleteCount: (count) => `${count} verwijderen`,
42
- actionCount: (label, count) => `${label} (${count})`,
43
- dragToSort: "Sleep een rij aan de greep om hem te verplaatsen. Elke verplaatsing wordt bewaard zodra je loslaat.",
44
- unreadableFilter: "Het filter in het adres kon niet worden gelezen",
45
- couldNotLoadRows: "Kon de rijen niet laden",
46
- created: (plural) => `${plural} aangemaakt`,
47
- noMatchSearch: (plural, search) => `Geen ${plural.toLowerCase()} gevonden voor “${search}”.`,
48
- noMatchFilters: (plural) => `Geen ${plural.toLowerCase()} gevonden met deze filters.`,
49
- noMatch: (plural) => `Geen ${plural.toLowerCase()} gevonden.`,
50
- noneYet: (plural) => `Nog geen ${plural.toLowerCase()}.`,
51
- clearSearch: "Zoekopdracht wissen",
52
- clearFilters: "Filters wissen"
53
- }
54
- });
3
+ const text = messages("app/list");
55
4
  //#endregion
56
5
  export { text };