@protobase/ui 0.25.2 → 0.25.3

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 (255) hide show
  1. package/dist/account/account-pages.js +3 -2
  2. package/dist/account/account-security-page.js +9 -4
  3. package/dist/account/backup-codes.js +7 -6
  4. package/dist/account/messages.js +214 -0
  5. package/dist/account/passkeys-section.js +23 -22
  6. package/dist/account/password-dialog.js +3 -2
  7. package/dist/account/sign-in-policy-form.js +11 -10
  8. package/dist/account/sign-in-policy-labels.js +30 -29
  9. package/dist/account/sign-in-policy-page.js +11 -6
  10. package/dist/account/sign-in-providers-section.js +6 -5
  11. package/dist/account/staff-sign-in-log.js +11 -10
  12. package/dist/account/totp-qr.js +2 -1
  13. package/dist/account/two-factor-section.js +24 -23
  14. package/dist/account/two-factor-setup.js +18 -17
  15. package/dist/action-card/action-card.js +2 -1
  16. package/dist/action-card/messages.js +8 -0
  17. package/dist/activity-chart/activity-chart.js +3 -2
  18. package/dist/activity-chart/messages.js +14 -0
  19. package/dist/app/app.d.ts +1 -1
  20. package/dist/app/app.js +20 -21
  21. package/dist/app/assistant-shell.js +2 -1
  22. package/dist/app/batch-failure.js +2 -1
  23. package/dist/app/breadcrumb-for.js +4 -3
  24. package/dist/app/charts/chart-groups.js +3 -2
  25. package/dist/app/charts/chart-view.js +3 -2
  26. package/dist/app/charts/group-bars.js +2 -1
  27. package/dist/app/charts/messages.js +26 -0
  28. package/dist/app/charts/period-chart.js +3 -2
  29. package/dist/app/charts/split-points.js +2 -1
  30. package/dist/app/comments/comment-composer.js +19 -18
  31. package/dist/app/comments/comments-section.js +4 -3
  32. package/dist/app/comments/messages.js +26 -0
  33. package/dist/app/create/create-page.js +11 -18
  34. package/dist/app/custom-section.js +4 -6
  35. package/dist/app/displays/board-column.js +6 -5
  36. package/dist/app/displays/board-columns.js +3 -2
  37. package/dist/app/displays/board-display.js +13 -15
  38. package/dist/app/displays/calendar-controls.js +3 -2
  39. package/dist/app/displays/calendar-display.js +12 -17
  40. package/dist/app/displays/card-carousel.js +4 -3
  41. package/dist/app/displays/cards-display.js +2 -1
  42. package/dist/app/displays/custom-display.js +4 -6
  43. package/dist/app/displays/display-frame.js +3 -2
  44. package/dist/app/displays/list-cards.js +5 -8
  45. package/dist/app/displays/list-displays.js +3 -3
  46. package/dist/app/displays/map-display.js +15 -14
  47. package/dist/app/displays/messages.js +128 -2
  48. package/dist/app/displays/period-controls.js +4 -3
  49. package/dist/app/displays/record-card.js +7 -6
  50. package/dist/app/displays/timeline-display.js +17 -26
  51. package/dist/app/displays/timeline-range.js +2 -1
  52. package/dist/app/displays/use-board-move.js +2 -2
  53. package/dist/app/displays/use-calendar-move.js +2 -1
  54. package/dist/app/document-title.js +2 -1
  55. package/dist/app/export/builder-port.js +2 -1
  56. package/dist/app/export/export-dialog.js +36 -40
  57. package/dist/app/export/export-worker.js +2 -0
  58. package/dist/app/export/messages.js +78 -0
  59. package/dist/app/export/run-export.js +5 -2
  60. package/dist/app/export/sink.js +4 -3
  61. package/dist/app/export/use-export-flow.js +4 -3
  62. package/dist/app/field-editor.js +4 -3
  63. package/dist/app/field-types/messages.js +8 -0
  64. package/dist/app/field-types/widget-part.js +2 -1
  65. package/dist/app/file-field.js +11 -14
  66. package/dist/app/gallery/gallery-section.js +4 -3
  67. package/dist/app/gallery/lightbox.js +5 -4
  68. package/dist/app/gallery/messages.js +30 -0
  69. package/dist/app/gallery/photo-details.js +3 -2
  70. package/dist/app/hand-order/hand-sorted-list.js +3 -6
  71. package/dist/app/hand-order/messages.js +4 -2
  72. package/dist/app/history/describe-change.js +3 -8
  73. package/dist/app/history/messages.js +32 -0
  74. package/dist/app/import/convert.js +20 -19
  75. package/dist/app/import/failed-rows.js +3 -2
  76. package/dist/app/import/import-button.js +2 -1
  77. package/dist/app/import/import-check-step.js +19 -35
  78. package/dist/app/import/import-dialog.js +13 -17
  79. package/dist/app/import/import-file-step.js +5 -9
  80. package/dist/app/import/import-mapping-step.js +32 -35
  81. package/dist/app/import/import-result-step.js +13 -12
  82. package/dist/app/import/messages.js +200 -0
  83. package/dist/app/import/parse-worker.js +2 -0
  84. package/dist/app/import/prepare-rows.js +5 -4
  85. package/dist/app/import/sheet-cell.js +2 -1
  86. package/dist/app/import/sheet-file.js +3 -2
  87. package/dist/app/import/sheet-source.js +7 -3
  88. package/dist/app/import/xlsx-reader.js +4 -3
  89. package/dist/app/import/xlsx-xml.js +2 -1
  90. package/dist/app/import/zip-reader.js +4 -3
  91. package/dist/app/list-edit/use-list-edits.js +1 -1
  92. package/dist/app/list-group-chart.js +2 -1
  93. package/dist/app/list-page.js +1 -1
  94. package/dist/app/map/map-layer-switch.js +3 -2
  95. package/dist/app/map/messages.js +14 -0
  96. package/dist/app/messages.js +116 -2
  97. package/dist/app/meta-gate.js +1 -1
  98. package/dist/app/nav-from-meta.js +11 -10
  99. package/dist/app/pages/action-inputs/action-inputs-dialog.js +3 -2
  100. package/dist/app/pages/action-inputs/input-answers.js +6 -5
  101. package/dist/app/pages/blocks/card-row.js +3 -2
  102. package/dist/app/pages/blocks/modal-form.js +5 -4
  103. package/dist/app/pages/blocks/record-card.js +3 -2
  104. package/dist/app/pages/blocks/stat.js +2 -1
  105. package/dist/app/pages/composed-page.js +6 -8
  106. package/dist/app/pages/confirm-action.js +2 -1
  107. package/dist/app/pages/custom-boundary.js +4 -2
  108. package/dist/app/pages/messages.js +64 -0
  109. package/dist/app/pages/render-node.js +5 -7
  110. package/dist/app/pages/use-run-action.js +11 -10
  111. package/dist/app/record-page.js +1 -1
  112. package/dist/app/record-row/messages.js +26 -0
  113. package/dist/app/record-row/record-row-body.js +12 -7
  114. package/dist/app/record-row/record-row.js +4 -3
  115. package/dist/app/record-row/saved-record-row.js +3 -2
  116. package/dist/app/related-dots/dots-summary.js +2 -1
  117. package/dist/app/related-dots/messages.js +8 -0
  118. package/dist/app/relation-picker.js +9 -8
  119. package/dist/app/router.js +5 -4
  120. package/dist/app/runtime/messages.js +58 -0
  121. package/dist/app/runtime/runtime-status.js +10 -23
  122. package/dist/app/runtime/runtime-update-dialog.js +7 -6
  123. package/dist/app/runtime/runtime-update.js +4 -3
  124. package/dist/app/saved/favorite-button.js +2 -1
  125. package/dist/app/saved/messages.js +22 -0
  126. package/dist/app/saved/saved-list.js +4 -7
  127. package/dist/app/saved/use-favorite.js +3 -2
  128. package/dist/app/search/messages.js +6 -2
  129. package/dist/app/search/navigation-hits.js +9 -7
  130. package/dist/app/searches/filter-chip-list.js +2 -1
  131. package/dist/app/searches/messages.js +96 -0
  132. package/dist/app/searches/save-search-button.js +5 -4
  133. package/dist/app/searches/saved-search-rows.js +3 -2
  134. package/dist/app/searches/saved-search-section.js +6 -5
  135. package/dist/app/searches/saved-search.js +4 -3
  136. package/dist/app/searches/saved-searches.js +15 -25
  137. package/dist/app/searches/search-controls.js +5 -4
  138. package/dist/app/searches/search-diff.js +4 -2
  139. package/dist/app/searches/search-name-dialog.js +4 -3
  140. package/dist/app/searches/update-search-dialog.js +15 -30
  141. package/dist/app/searches/use-save-search.js +8 -7
  142. package/dist/app/searches/use-search-row.js +4 -3
  143. package/dist/app/sensitive-field.js +5 -4
  144. package/dist/app/source-notice.js +13 -8
  145. package/dist/app/staff-banner.js +12 -19
  146. package/dist/app-shell/global-search.js +2 -2
  147. package/dist/app-shell/messages.js +4 -2
  148. package/dist/assistant-dock/assistant-dock.js +5 -5
  149. package/dist/assistant-dock/messages.js +26 -0
  150. package/dist/assistant-dock/use-assistant.js +2 -1
  151. package/dist/assistant-dock/use-backend-data.js +2 -1
  152. package/dist/assistant-dock/widget-view.js +3 -2
  153. package/dist/auth/auth-gate.js +10 -5
  154. package/dist/auth/auth-locale.js +14 -0
  155. package/dist/auth/auth-messages.js +122 -43
  156. package/dist/auth/auth-provider.js +6 -1
  157. package/dist/auth/code-form.js +2 -1
  158. package/dist/auth/email-code-form.js +11 -13
  159. package/dist/auth/email-code-page.js +2 -1
  160. package/dist/auth/first-run-page.js +6 -5
  161. package/dist/auth/forgot-password-form.js +14 -16
  162. package/dist/auth/forgot-password-page.js +2 -1
  163. package/dist/auth/messages.js +200 -0
  164. package/dist/auth/provider-sign-in-page.js +5 -5
  165. package/dist/auth/resend-code-button.js +2 -1
  166. package/dist/auth/reset-password-form.js +11 -10
  167. package/dist/auth/reset-password-page.js +4 -3
  168. package/dist/auth/setup-required-form.js +7 -9
  169. package/dist/auth/setup-required-page.js +7 -2
  170. package/dist/auth/sign-in-form.js +15 -18
  171. package/dist/auth/sign-in-prompt.js +4 -3
  172. package/dist/auth/sign-up-code-form.js +11 -13
  173. package/dist/auth/sign-up-details-form.js +14 -21
  174. package/dist/auth/sign-up-email-form.js +8 -7
  175. package/dist/auth/sign-up-page.js +2 -1
  176. package/dist/auth/staff-sign-in-form.js +14 -17
  177. package/dist/auth/two-factor-form.js +17 -16
  178. package/dist/auth/user-to-shell.js +2 -1
  179. package/dist/chat/composer.js +8 -7
  180. package/dist/chat/messages.js +14 -0
  181. package/dist/compact-table/compact-table.js +4 -8
  182. package/dist/compact-table/messages.js +18 -0
  183. package/dist/data/meta-data.d.ts +1 -1
  184. package/dist/data/use-update-record.js +1 -1
  185. package/dist/inline-child-table/inline-child-table.js +12 -12
  186. package/dist/inline-child-table/line-row.js +10 -9
  187. package/dist/inline-child-table/messages.js +52 -0
  188. package/dist/inline-child-table/totals-footer.js +5 -8
  189. package/dist/invitations/invite-form.js +3 -2
  190. package/dist/invitations/link-notice.js +6 -4
  191. package/dist/invitations/messages.js +24 -0
  192. package/dist/invitations/pending-invitation-row.js +4 -3
  193. package/dist/lists/messages.js +8 -0
  194. package/dist/lists/paged-search-list.js +2 -1
  195. package/dist/locale/slotted.js +14 -0
  196. package/dist/markdown/markdown-editor.js +6 -5
  197. package/dist/markdown/messages.js +16 -0
  198. package/dist/organizations/all-organizations.js +6 -5
  199. package/dist/organizations/app-roles-picker.js +2 -1
  200. package/dist/organizations/invitation-page.js +39 -49
  201. package/dist/organizations/invitations-page.js +11 -10
  202. package/dist/organizations/members-page.js +15 -10
  203. package/dist/organizations/messages.js +180 -0
  204. package/dist/organizations/organization-page.js +27 -26
  205. package/dist/organizations/organization-paths.js +16 -13
  206. package/dist/organizations/organization-row.js +3 -2
  207. package/dist/organizations/organizations-page.js +17 -16
  208. package/dist/organizations/use-organizations.js +2 -1
  209. package/dist/package.js +1 -1
  210. package/dist/plugins/before-sign-in.js +6 -1
  211. package/dist/plugins/load-plugin.d.ts +1 -1
  212. package/dist/plugins/load-plugin.js +3 -2
  213. package/dist/plugins/messages.js +36 -0
  214. package/dist/plugins/plugin-gate.js +6 -1
  215. package/dist/plugins/plugin-manifest.js +8 -7
  216. package/dist/plugins/plugin-notice.js +8 -12
  217. package/dist/primitives/messages.js +16 -0
  218. package/dist/primitives/sheet.js +2 -1
  219. package/dist/primitives/spinner.js +2 -1
  220. package/dist/primitives/token.js +2 -1
  221. package/dist/record-view/messages.js +4 -2
  222. package/dist/record-view/record-tabs.js +2 -1
  223. package/dist/roles/messages.js +14 -0
  224. package/dist/roles/use-active-role.js +3 -2
  225. package/dist/shell/assets/app-CW3U56yM.js +69 -0
  226. package/dist/shell/assets/cn-Bi0ZEjD9.js +1 -0
  227. package/dist/shell/assets/export-worker-ClACk00b.js +2 -0
  228. package/dist/shell/assets/{index-xY0Mvv6V.js → index-B7cIjCuz.js} +2 -2
  229. package/dist/shell/assets/maplibre-CVG5L9FD.js +814 -0
  230. package/dist/shell/assets/{markdown-content-ukDTCu6u.js → markdown-content-CtGUP4W6.js} +1 -1
  231. package/dist/shell/assets/parse-worker-UhbwEjS0.js +5 -0
  232. package/dist/shell/assets/preload-helper-BX9CcZkY.js +1 -0
  233. package/dist/shell/assets/{record-map-BJmYZ7kQ.js → record-map-Cw3_NcUl.js} +1 -1
  234. package/dist/shell/assets/records-map-D4f3ZeDL.js +1 -0
  235. package/dist/shell/assets/shared-protobase-ui-CB_i50NP.js +1 -0
  236. package/dist/shell/index.html +5 -3
  237. package/dist/shell/protobase.shell.json +1 -1
  238. package/dist/shell/protobase.sw.js +2 -2
  239. package/dist/side-panel/messages.js +8 -0
  240. package/dist/side-panel/side-panel.js +2 -1
  241. package/dist/toasts/messages.js +8 -0
  242. package/dist/toasts/toast.js +2 -1
  243. package/dist/users/app-invitations.js +5 -4
  244. package/dist/users/create-user-form.js +9 -8
  245. package/dist/users/messages.js +52 -0
  246. package/dist/users/use-user-roles.js +2 -1
  247. package/dist/users/user-list.js +6 -5
  248. package/dist/users/user-row.js +5 -4
  249. package/package.json +4 -4
  250. package/dist/shell/assets/app-C-OLrsRR.js +0 -69
  251. package/dist/shell/assets/export-worker-Bz57Pf5g.js +0 -2
  252. package/dist/shell/assets/maplibre-Dov6nhPX.js +0 -814
  253. package/dist/shell/assets/parse-worker-BtcY0dQw.js +0 -5
  254. package/dist/shell/assets/records-map-C1_gDKHR.js +0 -1
  255. package/dist/shell/assets/shared-protobase-ui-CFYJAbMR.js +0 -1
@@ -0,0 +1,18 @@
1
+ import { defineMessages } from "../locale/messages.js";
2
+ //#region src/compact-table/messages.ts
3
+ const text = defineMessages({
4
+ en: {
5
+ table: "Table",
6
+ noRows: "No rows.",
7
+ rows: (count) => `${count} ${count === 1 ? "row" : "rows"}`,
8
+ cutOff: ", cut off at the limit"
9
+ },
10
+ nl: {
11
+ table: "Tabel",
12
+ noRows: "Geen rijen.",
13
+ rows: (count) => `${count} ${count === 1 ? "rij" : "rijen"}`,
14
+ cutOff: ", afgekapt bij de limiet"
15
+ }
16
+ });
17
+ //#endregion
18
+ export { text };
@@ -1,5 +1,5 @@
1
- import { MapLayerModel, PluginRef, ResourcePermissions, SourceRef } from "@protobase/client";
2
1
  import { Locale } from "@protobase/schema/internal";
2
+ import { MapLayerModel, PluginRef, ResourcePermissions, SourceRef } from "@protobase/client";
3
3
  import { BottomBarModel, ResourceModel, SignInViewModel, UserMenuModel, ViewModel } from "@protobase/schema";
4
4
  import { PageModel } from "@protobase/layout";
5
5
  //#region src/data/meta-data.d.ts
@@ -1,7 +1,7 @@
1
1
  import { keys } from "./query-keys.js";
2
2
  import { useClient } from "./api-provider.js";
3
- import { PreconditionFailedError } from "@protobase/client";
4
3
  import { encodeKey } from "@protobase/schema/internal";
4
+ import { PreconditionFailedError } from "@protobase/client";
5
5
  import { useMutation, useQueryClient } from "@tanstack/react-query";
6
6
  //#region src/data/use-update-record.ts
7
7
  /**
@@ -1,6 +1,7 @@
1
1
  import { Button } from "../primitives/button.js";
2
2
  import { productAt } from "../mocks/products.js";
3
3
  import { lineGrid } from "./columns.js";
4
+ import { text } from "./messages.js";
4
5
  import { LineRow } from "./line-row.js";
5
6
  import { reorder } from "./reorder.js";
6
7
  import { TotalsFooter } from "./totals-footer.js";
@@ -10,15 +11,14 @@ import { DndContext, KeyboardSensor, MouseSensor, TouchSensor, closestCenter, us
10
11
  import { SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy } from "@dnd-kit/sortable";
11
12
  //#region src/inline-child-table/inline-child-table.tsx
12
13
  const headerCell = "px-2 text-[11px] font-medium uppercase tracking-wide text-muted-foreground";
13
- const instructions = "To pick up a line, press space or enter on its drag handle. Use the up and down arrow keys to move it, space or enter to drop it, and escape to cancel. The row menu also has Move up and Move down.";
14
14
  const announcementsFor = (lines) => {
15
- const name = (id) => lines.find((line) => line.id === id)?.description ?? "line";
15
+ const name = (id) => lines.find((line) => line.id === id)?.description ?? text("line");
16
16
  const place = (id) => lines.findIndex((line) => line.id === id) + 1;
17
17
  return {
18
- onDragStart: ({ active }) => `Picked up ${name(active.id)}, line ${place(active.id)} of ${lines.length}.`,
19
- onDragOver: ({ active, over }) => over ? `${name(active.id)} is over line ${place(over.id)} of ${lines.length}.` : void 0,
20
- onDragEnd: ({ active, over }) => over ? `${name(active.id)} was dropped at line ${place(over.id)} of ${lines.length}.` : `${name(active.id)} was dropped where it started.`,
21
- onDragCancel: ({ active }) => `Moving ${name(active.id)} was cancelled. It is back at line ${place(active.id)}.`
18
+ onDragStart: ({ active }) => text("pickedUp", name(active.id), place(active.id), lines.length),
19
+ onDragOver: ({ active, over }) => over ? text("over", name(active.id), place(over.id), lines.length) : void 0,
20
+ onDragEnd: ({ active, over }) => over ? text("dropped", name(active.id), place(over.id), lines.length) : text("droppedAtStart", name(active.id)),
21
+ onDragCancel: ({ active }) => text("cancelled", name(active.id), place(active.id))
22
22
  };
23
23
  };
24
24
  const InlineChildTable = ({ lines, onChange, onReorder, vatRate = .21, readOnly, reorderable = !readOnly }) => {
@@ -58,19 +58,19 @@ const InlineChildTable = ({ lines, onChange, onReorder, vatRate = .21, readOnly,
58
58
  /* @__PURE__ */ jsx("span", {}),
59
59
  /* @__PURE__ */ jsx("span", {
60
60
  className: headerCell,
61
- children: "Item"
61
+ children: text("item")
62
62
  }),
63
63
  /* @__PURE__ */ jsx("span", {
64
64
  className: `${headerCell} text-right`,
65
- children: "Qty"
65
+ children: text("qty")
66
66
  }),
67
67
  /* @__PURE__ */ jsx("span", {
68
68
  className: `${headerCell} text-right`,
69
- children: "Unit price"
69
+ children: text("unitPrice")
70
70
  }),
71
71
  /* @__PURE__ */ jsx("span", {
72
72
  className: `${headerCell} text-right`,
73
- children: "Line total"
73
+ children: text("lineTotal")
74
74
  }),
75
75
  /* @__PURE__ */ jsx("span", {})
76
76
  ]
@@ -81,7 +81,7 @@ const InlineChildTable = ({ lines, onChange, onReorder, vatRate = .21, readOnly,
81
81
  onDragEnd,
82
82
  accessibility: {
83
83
  announcements: announcementsFor(lines),
84
- screenReaderInstructions: { draggable: instructions }
84
+ screenReaderInstructions: { draggable: text("instructions") }
85
85
  },
86
86
  children: /* @__PURE__ */ jsx(SortableContext, {
87
87
  items: lines.map((line) => line.id),
@@ -107,7 +107,7 @@ const InlineChildTable = ({ lines, onChange, onReorder, vatRate = .21, readOnly,
107
107
  variant: "ghost",
108
108
  size: "sm",
109
109
  onClick: addLine,
110
- children: [/* @__PURE__ */ jsx(Plus, { className: "size-3.5" }), "Add line"]
110
+ children: [/* @__PURE__ */ jsx(Plus, { className: "size-3.5" }), text("addLine")]
111
111
  })
112
112
  })
113
113
  ]
@@ -4,26 +4,27 @@ import { lineTotalCents } from "../mocks/invoices.js";
4
4
  import { lineGrid } from "./columns.js";
5
5
  import { LineMenu } from "./line-menu.js";
6
6
  import { NumberCell } from "./number-cell.js";
7
+ import { text } from "./messages.js";
7
8
  import { GripVertical } from "lucide-react";
8
9
  import { jsx, jsxs } from "react/jsx-runtime";
9
10
  import { useSortable } from "@dnd-kit/sortable";
10
11
  //#region src/inline-child-table/line-row.tsx
11
- const parseEuros = (text) => Math.round(Number(text.replace(",", ".").replace(/[^0-9.]/g, "")) * 100);
12
+ const parseEuros = (typed) => Math.round(Number(typed.replace(",", ".").replace(/[^0-9.]/g, "")) * 100);
12
13
  const LineRow = ({ line, position, count, reorderable, editable, onChange, onRemove, onMove }) => {
13
14
  const { attributes, listeners, setNodeRef, setActivatorNodeRef, transform, transition, isDragging } = useSortable({
14
15
  id: line.id,
15
16
  disabled: !reorderable
16
17
  });
17
18
  const menu = [...reorderable ? [{
18
- label: "Move up",
19
+ label: text("moveUp"),
19
20
  disabled: position === 0,
20
21
  onSelect: () => onMove(position - 1)
21
22
  }, {
22
- label: "Move down",
23
+ label: text("moveDown"),
23
24
  disabled: position === count - 1,
24
25
  onSelect: () => onMove(position + 1)
25
26
  }] : [], ...editable ? [{
26
- label: "Remove line",
27
+ label: text("removeLine"),
27
28
  destructive: true,
28
29
  onSelect: onRemove
29
30
  }] : []];
@@ -39,7 +40,7 @@ const LineRow = ({ line, position, count, reorderable, editable, onChange, onRem
39
40
  reorderable ? /* @__PURE__ */ jsx("button", {
40
41
  ref: setActivatorNodeRef,
41
42
  type: "button",
42
- "aria-label": `Drag to reorder ${line.description}`,
43
+ "aria-label": text("dragToReorder", line.description),
43
44
  ...attributes,
44
45
  ...listeners,
45
46
  style: { touchAction: "none" },
@@ -57,17 +58,17 @@ const LineRow = ({ line, position, count, reorderable, editable, onChange, onRem
57
58
  })]
58
59
  }),
59
60
  editable ? /* @__PURE__ */ jsx(NumberCell, {
60
- label: "Quantity",
61
+ label: text("quantity"),
61
62
  value: line.quantity,
62
63
  format: String,
63
- parse: (text) => Math.round(Number(text)),
64
+ parse: (typed) => Math.round(Number(typed)),
64
65
  onCommit: (quantity) => onChange({ quantity })
65
66
  }) : /* @__PURE__ */ jsx("span", {
66
67
  className: "px-2 text-right tabular-nums",
67
68
  children: line.quantity
68
69
  }),
69
70
  editable ? /* @__PURE__ */ jsx(NumberCell, {
70
- label: "Unit price",
71
+ label: text("unitPrice"),
71
72
  value: line.unitPriceCents,
72
73
  format: (cents) => (cents / 100).toFixed(2),
73
74
  parse: parseEuros,
@@ -81,7 +82,7 @@ const LineRow = ({ line, position, count, reorderable, editable, onChange, onRem
81
82
  children: formatMoney(lineTotalCents(line))
82
83
  }),
83
84
  menu.length > 0 ? /* @__PURE__ */ jsx(LineMenu, {
84
- label: `Actions for ${line.description}`,
85
+ label: text("actionsFor", line.description),
85
86
  items: menu
86
87
  }) : /* @__PURE__ */ jsx("span", {})
87
88
  ]
@@ -0,0 +1,52 @@
1
+ import { defineMessages } from "../locale/messages.js";
2
+ //#region src/inline-child-table/messages.ts
3
+ const text = defineMessages({
4
+ en: {
5
+ instructions: "To pick up a line, press space or enter on its drag handle. Use the up and down arrow keys to move it, space or enter to drop it, and escape to cancel. The row menu also has Move up and Move down.",
6
+ line: "line",
7
+ pickedUp: (name, place, count) => `Picked up ${name}, line ${place} of ${count}.`,
8
+ over: (name, place, count) => `${name} is over line ${place} of ${count}.`,
9
+ dropped: (name, place, count) => `${name} was dropped at line ${place} of ${count}.`,
10
+ droppedAtStart: (name) => `${name} was dropped where it started.`,
11
+ cancelled: (name, place) => `Moving ${name} was cancelled. It is back at line ${place}.`,
12
+ item: "Item",
13
+ qty: "Qty",
14
+ quantity: "Quantity",
15
+ unitPrice: "Unit price",
16
+ lineTotal: "Line total",
17
+ addLine: "Add line",
18
+ moveUp: "Move up",
19
+ moveDown: "Move down",
20
+ removeLine: "Remove line",
21
+ dragToReorder: (name) => `Drag to reorder ${name}`,
22
+ actionsFor: (name) => `Actions for ${name}`,
23
+ subtotal: "Subtotal",
24
+ vat: (percent) => `VAT ${percent}%`,
25
+ total: "Total"
26
+ },
27
+ nl: {
28
+ instructions: "Druk op spatie of enter op de sleepgreep om een regel op te pakken. Verplaats hem met de pijltjestoetsen omhoog en omlaag, zet hem neer met spatie of enter, en annuleer met escape. Het regelmenu heeft ook Omhoog en Omlaag.",
29
+ line: "regel",
30
+ pickedUp: (name, place, count) => `${name} opgepakt, regel ${place} van ${count}.`,
31
+ over: (name, place, count) => `${name} is boven regel ${place} van ${count}.`,
32
+ dropped: (name, place, count) => `${name} is neergezet op regel ${place} van ${count}.`,
33
+ droppedAtStart: (name) => `${name} is neergezet waar hij begon.`,
34
+ cancelled: (name, place) => `Verplaatsen van ${name} is geannuleerd. Hij staat weer op regel ${place}.`,
35
+ item: "Artikel",
36
+ qty: "Aantal",
37
+ quantity: "Aantal",
38
+ unitPrice: "Stukprijs",
39
+ lineTotal: "Regeltotaal",
40
+ addLine: "Regel toevoegen",
41
+ moveUp: "Omhoog",
42
+ moveDown: "Omlaag",
43
+ removeLine: "Regel verwijderen",
44
+ dragToReorder: (name) => `Sleep om ${name} te verplaatsen`,
45
+ actionsFor: (name) => `Acties voor ${name}`,
46
+ subtotal: "Subtotaal",
47
+ vat: (percent) => `Btw ${percent}%`,
48
+ total: "Totaal"
49
+ }
50
+ });
51
+ //#endregion
52
+ export { text };
@@ -1,5 +1,6 @@
1
1
  import { formatMoney } from "../format/money.js";
2
2
  import { invoiceTotals } from "../mocks/invoices.js";
3
+ import { text } from "./messages.js";
3
4
  import { jsx, jsxs } from "react/jsx-runtime";
4
5
  //#region src/inline-child-table/totals-footer.tsx
5
6
  const TotalsFooter = ({ lines, vatRate }) => {
@@ -9,19 +10,15 @@ const TotalsFooter = ({ lines, vatRate }) => {
9
10
  children: [
10
11
  /* @__PURE__ */ jsx("dt", {
11
12
  className: "text-muted-foreground",
12
- children: "Subtotal"
13
+ children: text("subtotal")
13
14
  }),
14
15
  /* @__PURE__ */ jsx("dd", {
15
16
  className: "text-right text-foreground",
16
17
  children: formatMoney(totals.subtotalCents)
17
18
  }),
18
- /* @__PURE__ */ jsxs("dt", {
19
+ /* @__PURE__ */ jsx("dt", {
19
20
  className: "text-muted-foreground",
20
- children: [
21
- "VAT ",
22
- Math.round(vatRate * 100),
23
- "%"
24
- ]
21
+ children: text("vat", Math.round(vatRate * 100))
25
22
  }),
26
23
  /* @__PURE__ */ jsx("dd", {
27
24
  className: "text-right text-foreground",
@@ -29,7 +26,7 @@ const TotalsFooter = ({ lines, vatRate }) => {
29
26
  }),
30
27
  /* @__PURE__ */ jsx("dt", {
31
28
  className: "mt-1 border-t border-border pt-2 font-semibold text-foreground",
32
- children: "Total"
29
+ children: text("total")
33
30
  }),
34
31
  /* @__PURE__ */ jsx("dd", {
35
32
  className: "mt-1 border-t border-border pt-2 text-right text-[16px] font-semibold text-foreground",
@@ -2,6 +2,7 @@ import { Input } from "../primitives/input.js";
2
2
  import { Button } from "../primitives/button.js";
3
3
  import { AccountSection, SectionError } from "../account/account-section.js";
4
4
  import { useAction } from "../organizations/use-action.js";
5
+ import { text } from "./messages.js";
5
6
  import { LinkNotice } from "./link-notice.js";
6
7
  import { useState } from "react";
7
8
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -30,7 +31,7 @@ const InviteForm = ({ title, description, onInvite, beside, children, incomplete
30
31
  className: "flex flex-col gap-2 sm:flex-row",
31
32
  children: [
32
33
  /* @__PURE__ */ jsx(Input, {
33
- "aria-label": "Email",
34
+ "aria-label": text("email"),
34
35
  type: "email",
35
36
  placeholder: "name@example.com",
36
37
  value: email,
@@ -43,7 +44,7 @@ const InviteForm = ({ title, description, onInvite, beside, children, incomplete
43
44
  variant: "primary",
44
45
  loading: busy,
45
46
  disabled: !email.trim() || incomplete,
46
- children: "Invite"
47
+ children: text("invite")
47
48
  })
48
49
  ]
49
50
  }), children]
@@ -1,12 +1,14 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
1
+ import { slotted } from "../locale/slotted.js";
2
+ import { text } from "./messages.js";
3
+ import { jsx } from "react/jsx-runtime";
2
4
  //#region src/invitations/link-notice.tsx
3
5
  /** The invitation link to pass on, when the app cannot email it. */
4
- const LinkNotice = ({ link }) => link ? /* @__PURE__ */ jsxs("p", {
6
+ const LinkNotice = ({ link }) => link ? /* @__PURE__ */ jsx("p", {
5
7
  className: "mt-3 break-all rounded-md border bg-muted px-3 py-2 text-xs",
6
- children: ["This app cannot send email, so pass this link on yourself. It works once, until the invitation expires: ", /* @__PURE__ */ jsx("span", {
8
+ children: slotted(text("passLinkOn"), /* @__PURE__ */ jsx("span", {
7
9
  className: "font-mono",
8
10
  children: link
9
- })]
11
+ }))
10
12
  }) : null;
11
13
  //#endregion
12
14
  export { LinkNotice };
@@ -0,0 +1,24 @@
1
+ import { defineMessages } from "../locale/messages.js";
2
+ //#region src/invitations/messages.ts
3
+ const text = defineMessages({
4
+ en: {
5
+ email: "Email",
6
+ invite: "Invite",
7
+ expired: "Expired",
8
+ until: (date) => `Until ${date}`,
9
+ sendAgain: "Send again",
10
+ revoke: "Revoke",
11
+ passLinkOn: "This app cannot send email, so pass this link on yourself. It works once, until the invitation expires: {}"
12
+ },
13
+ nl: {
14
+ email: "E-mailadres",
15
+ invite: "Uitnodigen",
16
+ expired: "Verlopen",
17
+ until: (date) => `Tot ${date}`,
18
+ sendAgain: "Opnieuw sturen",
19
+ revoke: "Intrekken",
20
+ passLinkOn: "Deze app kan geen e-mail sturen, dus geef deze link zelf door. Die werkt één keer, tot de uitnodiging verloopt: {}"
21
+ }
22
+ });
23
+ //#endregion
24
+ export { text };
@@ -2,6 +2,7 @@ import { formatTag } from "../locale/active-locale.js";
2
2
  import { Button } from "../primitives/button.js";
3
3
  import { SectionError } from "../account/account-section.js";
4
4
  import { useAction } from "../organizations/use-action.js";
5
+ import { text } from "./messages.js";
5
6
  import { LinkNotice } from "./link-notice.js";
6
7
  import { useState } from "react";
7
8
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -27,7 +28,7 @@ const PendingInvitationRow = ({ email, gives, expiresAt, onResend, onRevoke }) =
27
28
  children: [
28
29
  gives,
29
30
  " · ",
30
- expired ? "Expired" : `Until ${new Date(expiresAt).toLocaleDateString(formatTag())}`
31
+ expired ? text("expired") : text("until", new Date(expiresAt).toLocaleDateString(formatTag()))
31
32
  ]
32
33
  })]
33
34
  }),
@@ -35,14 +36,14 @@ const PendingInvitationRow = ({ email, gives, expiresAt, onResend, onRevoke }) =
35
36
  size: "sm",
36
37
  loading: busy,
37
38
  onClick: () => void run(async () => setLink((await onResend()).link)),
38
- children: "Send again"
39
+ children: text("sendAgain")
39
40
  }),
40
41
  /* @__PURE__ */ jsx(Button, {
41
42
  size: "sm",
42
43
  variant: "danger",
43
44
  loading: busy,
44
45
  onClick: () => void run(onRevoke),
45
- children: "Revoke"
46
+ children: text("revoke")
46
47
  })
47
48
  ]
48
49
  }),
@@ -0,0 +1,8 @@
1
+ import { defineMessages } from "../locale/messages.js";
2
+ //#region src/lists/messages.ts
3
+ const text = defineMessages({
4
+ en: { showMore: "Show more" },
5
+ nl: { showMore: "Meer tonen" }
6
+ });
7
+ //#endregion
8
+ export { text };
@@ -1,6 +1,7 @@
1
1
  import { Input } from "../primitives/input.js";
2
2
  import { Button } from "../primitives/button.js";
3
3
  import { AccountSection, SectionError } from "../account/account-section.js";
4
+ import { text } from "./messages.js";
4
5
  import { Search } from "lucide-react";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
  //#region src/lists/paged-search-list.tsx
@@ -34,7 +35,7 @@ const PagedSearchList = ({ title, description, searchLabel, placeholder, query,
34
35
  className: "mt-3",
35
36
  loading: list.loading,
36
37
  onClick: () => void list.more(),
37
- children: "Show more"
38
+ children: text("showMore")
38
39
  })
39
40
  ]
40
41
  });
@@ -0,0 +1,14 @@
1
+ import { Fragment } from "react";
2
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
3
+ //#region src/locale/slotted.tsx
4
+ /**
5
+ * A built-in text with a `{}` for each element that goes in it, such as a highlighted address, rendered with the
6
+ * elements in their places in order: each language puts them where its sentence needs them.
7
+ */
8
+ const slotted = (message, ...slots) => {
9
+ const parts = message.split("{}");
10
+ if (parts.length !== slots.length + 1) throw new Error(`The text "${message}" has ${parts.length - 1} places for ${slots.length} elements`);
11
+ return /* @__PURE__ */ jsx(Fragment$1, { children: parts.map((part, index) => /* @__PURE__ */ jsxs(Fragment, { children: [part, index < slots.length && slots[index]] }, index)) });
12
+ };
13
+ //#endregion
14
+ export { slotted };
@@ -1,15 +1,16 @@
1
1
  import { Segmented } from "../primitives/segmented.js";
2
2
  import { Textarea } from "../primitives/textarea.js";
3
3
  import { Markdown } from "./markdown.js";
4
+ import { text } from "./messages.js";
4
5
  import { useState } from "react";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
  //#region src/markdown/markdown-editor.tsx
7
- const modes = [{
8
+ const modes = () => [{
8
9
  value: "write",
9
- label: "Write"
10
+ label: text("write")
10
11
  }, {
11
12
  value: "preview",
12
- label: "Preview"
13
+ label: text("preview")
13
14
  }];
14
15
  /**
15
16
  * Markdown source in a box that grows with it, as GitHub edits a comment, and a switch to its rendered preview: the
@@ -23,7 +24,7 @@ const MarkdownEditor = ({ value, onChange, label, invalid, placeholder }) => {
23
24
  className: "self-start",
24
25
  children: /* @__PURE__ */ jsx(Segmented, {
25
26
  value: mode,
26
- options: modes,
27
+ options: modes(),
27
28
  onChange: setMode,
28
29
  label
29
30
  })
@@ -37,7 +38,7 @@ const MarkdownEditor = ({ value, onChange, label, invalid, placeholder }) => {
37
38
  className: "min-h-[7.5rem] rounded-md border border-border px-2.5 py-1.5",
38
39
  children: value.trim() === "" ? /* @__PURE__ */ jsx("span", {
39
40
  className: "text-faint-foreground",
40
- children: "Nothing to preview"
41
+ children: text("nothingToPreview")
41
42
  }) : /* @__PURE__ */ jsx(Markdown, { source: value })
42
43
  })]
43
44
  });
@@ -0,0 +1,16 @@
1
+ import { defineMessages } from "../locale/messages.js";
2
+ //#region src/markdown/messages.ts
3
+ const text = defineMessages({
4
+ en: {
5
+ write: "Write",
6
+ preview: "Preview",
7
+ nothingToPreview: "Nothing to preview"
8
+ },
9
+ nl: {
10
+ write: "Schrijven",
11
+ preview: "Voorbeeld",
12
+ nothingToPreview: "Niets om te tonen"
13
+ }
14
+ });
15
+ //#endregion
16
+ export { text };
@@ -1,4 +1,5 @@
1
1
  import { useAuth } from "../auth/auth-provider.js";
2
+ import { text } from "./messages.js";
2
3
  import { useAction } from "./use-action.js";
3
4
  import { PagedSearchList } from "../lists/paged-search-list.js";
4
5
  import { usePagedSearch } from "../lists/use-paged-search.js";
@@ -11,17 +12,17 @@ import { jsx } from "react/jsx-runtime";
11
12
  const AllOrganizations = ({ basePath, currentId }) => {
12
13
  const { session } = useAuth();
13
14
  const [query, setQuery] = useState("");
14
- const search = useCallback((text, offset) => session.organizations.search(text, offset).then((page) => ({
15
+ const search = useCallback((term, offset) => session.organizations.search(term, offset).then((page) => ({
15
16
  items: page.organizations,
16
17
  total: page.total
17
18
  })), [session]);
18
19
  const list = usePagedSearch(search, query);
19
20
  const { busy, error, run } = useAction();
20
21
  return /* @__PURE__ */ jsx(PagedSearchList, {
21
- title: "All organizations",
22
- description: "Every organization in the app. Your global roles let you work in any of them, with what those roles allow there. Opening one you are not a member of is written to the audit log.",
23
- searchLabel: "Find an organization",
24
- placeholder: "Name or slug",
22
+ title: text("allOrganizations"),
23
+ description: text("allOrganizationsDescription"),
24
+ searchLabel: text("findOrganization"),
25
+ placeholder: text("nameOrSlug"),
25
26
  query,
26
27
  onQuery: setQuery,
27
28
  list,
@@ -1,5 +1,6 @@
1
1
  import { cn } from "../lib/cn.js";
2
2
  import { Checkbox } from "../primitives/checkbox.js";
3
+ import { text } from "./messages.js";
3
4
  import { jsx, jsxs } from "react/jsx-runtime";
4
5
  //#region src/organizations/app-roles-picker.tsx
5
6
  /**
@@ -12,7 +13,7 @@ const AppRolesPicker = ({ roles, selected, grantable, disabled, onChange }) => /
12
13
  const held = selected.includes(role.name);
13
14
  const locked = disabled || !grantable.has(role.name);
14
15
  return /* @__PURE__ */ jsxs("label", {
15
- title: locked && !disabled ? "You cannot give or take away this role" : void 0,
16
+ title: locked && !disabled ? text("cannotChangeRole") : void 0,
16
17
  className: cn("inline-flex items-center gap-1.5", locked && "text-muted-foreground"),
17
18
  children: [/* @__PURE__ */ jsx(Checkbox, {
18
19
  checked: held,