@eifi1/ui-kit 0.6.1 → 0.7.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.
- package/README.md +69 -33
- package/dist/chart.d.ts +1 -0
- package/dist/components/account-settings.js +3 -2
- package/dist/components/account-settings.js.map +1 -1
- package/dist/components/amount-input.d.ts +3 -0
- package/dist/components/amount-input.js +6 -4
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/autocomplete.d.ts +33 -6
- package/dist/components/autocomplete.js +62 -16
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/calculator.d.ts +3 -0
- package/dist/components/calculator.js +2 -1
- package/dist/components/calculator.js.map +1 -1
- package/dist/components/chart-zoom.js +2 -1
- package/dist/components/chart-zoom.js.map +1 -1
- package/dist/components/chart.d.ts +33 -2
- package/dist/components/chart.js +20 -8
- package/dist/components/chart.js.map +1 -1
- package/dist/components/chip.d.ts +34 -14
- package/dist/components/chip.js +63 -28
- package/dist/components/chip.js.map +1 -1
- package/dist/components/choice-card.d.ts +18 -1
- package/dist/components/choice-card.js +21 -8
- package/dist/components/choice-card.js.map +1 -1
- package/dist/components/combobox-core.d.ts +61 -2
- package/dist/components/combobox-core.js +68 -17
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.d.ts +11 -7
- package/dist/components/combobox.js +51 -28
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/currency-select.js +3 -3
- package/dist/components/currency-select.js.map +1 -1
- package/dist/components/danger-confirm.d.ts +30 -6
- package/dist/components/danger-confirm.js +51 -32
- package/dist/components/danger-confirm.js.map +1 -1
- package/dist/components/data-table-filter-popover.d.ts +1 -1
- package/dist/components/data-table-filters.d.ts +1 -1
- package/dist/components/data-table-pagination.d.ts +6 -3
- package/dist/components/data-table-pagination.js +6 -5
- package/dist/components/data-table-pagination.js.map +1 -1
- package/dist/components/data-table.d.ts +1 -1
- package/dist/components/data-table.js +332 -248
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.js +17 -7
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/dialog-frame.d.ts +28 -3
- package/dist/components/dialog-frame.js +47 -11
- package/dist/components/dialog-frame.js.map +1 -1
- package/dist/components/disclosure.d.ts +22 -2
- package/dist/components/disclosure.js +41 -8
- package/dist/components/disclosure.js.map +1 -1
- package/dist/components/dropdown.d.ts +7 -3
- package/dist/components/dropdown.js +6 -2
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/entity-combobox.d.ts +17 -8
- package/dist/components/entity-combobox.js +7 -5
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/file-button.d.ts +36 -5
- package/dist/components/file-button.js +23 -2
- package/dist/components/file-button.js.map +1 -1
- package/dist/components/file-dropzone.d.ts +9 -5
- package/dist/components/file-dropzone.js +14 -19
- package/dist/components/file-dropzone.js.map +1 -1
- package/dist/components/grouped-picker.js +2 -2
- package/dist/components/grouped-picker.js.map +1 -1
- package/dist/components/hover-menu.d.ts +8 -3
- package/dist/components/hover-menu.js +88 -4
- package/dist/components/hover-menu.js.map +1 -1
- package/dist/components/icon-picker.d.ts +10 -1
- package/dist/components/icon-picker.js +5 -1
- package/dist/components/icon-picker.js.map +1 -1
- package/dist/components/measured-grid.d.ts +165 -0
- package/dist/components/measured-grid.js +559 -0
- package/dist/components/measured-grid.js.map +1 -0
- package/dist/components/mini-calendar.js +7 -8
- package/dist/components/mini-calendar.js.map +1 -1
- package/dist/components/month-picker.js +13 -9
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.js +2 -2
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/multi-select.d.ts +9 -1
- package/dist/components/multi-select.js +22 -8
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/number-field.d.ts +3 -0
- package/dist/components/number-input.d.ts +3 -0
- package/dist/components/number-input.js +3 -3
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +3 -0
- package/dist/components/numpad-sheet.js +3 -3
- package/dist/components/numpad-sheet.js.map +1 -1
- package/dist/components/picker-sheet.js +1 -1
- package/dist/components/picker-sheet.js.map +1 -1
- package/dist/components/popover.js +11 -2
- package/dist/components/popover.js.map +1 -1
- package/dist/components/series-chart-ticks.d.ts +13 -0
- package/dist/components/series-chart-ticks.js +29 -0
- package/dist/components/series-chart-ticks.js.map +1 -0
- package/dist/components/series-chart.js +33 -27
- package/dist/components/series-chart.js.map +1 -1
- package/dist/components/swatch-picker.d.ts +10 -1
- package/dist/components/swatch-picker.js +2 -0
- package/dist/components/swatch-picker.js.map +1 -1
- package/dist/components/swipeable-row.d.ts +11 -2
- package/dist/components/swipeable-row.js +5 -3
- package/dist/components/swipeable-row.js.map +1 -1
- package/dist/components/tile-radio.js +5 -7
- package/dist/components/tile-radio.js.map +1 -1
- package/dist/components/toggle-group.d.ts +13 -3
- package/dist/components/toggle-group.js +21 -1
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle-legend.js +1 -2
- package/dist/components/toggle-legend.js.map +1 -1
- package/dist/components/treemap.d.ts +6 -1
- package/dist/components/treemap.js +16 -6
- package/dist/components/treemap.js.map +1 -1
- package/dist/components/ui.d.ts +31 -7
- package/dist/components/ui.js +26 -18
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-anchor-dir.d.ts +15 -0
- package/dist/components/use-anchor-dir.js +14 -0
- package/dist/components/use-anchor-dir.js.map +1 -0
- package/dist/components/use-mobile-reveal.d.ts +8 -1
- package/dist/components/use-mobile-reveal.js +3 -2
- package/dist/components/use-mobile-reveal.js.map +1 -1
- package/dist/components/use-table-state.d.ts +4 -4
- package/dist/components/use-table-state.js +12 -5
- package/dist/components/use-table-state.js.map +1 -1
- package/dist/{data-table-filters-DM1auUfH.d.ts → data-table-filters-noy0Abvi.d.ts} +40 -7
- package/dist/data-table.d.ts +1 -1
- package/dist/data-table.js.map +1 -1
- package/dist/feedback/feedback-attachment.d.ts +22 -3
- package/dist/feedback/feedback-attachment.js +15 -7
- package/dist/feedback/feedback-attachment.js.map +1 -1
- package/dist/feedback/feedback-dialog.d.ts +3 -2
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback.d.ts +1 -1
- package/dist/hooks/use-windowed-rows.d.ts +29 -0
- package/dist/hooks/use-windowed-rows.js +31 -0
- package/dist/hooks/use-windowed-rows.js.map +1 -0
- package/dist/i18n/defaults.d.ts +3 -0
- package/dist/i18n/defaults.js +5 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +5 -0
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/de-CH.d.ts +43 -0
- package/dist/i18n/locales/de-CH.js +21 -0
- package/dist/i18n/locales/de-CH.js.map +1 -0
- package/dist/i18n/locales/de.d.ts +43 -0
- package/dist/i18n/locales/de.js +344 -0
- package/dist/i18n/locales/de.js.map +1 -0
- package/dist/i18n/locales/es.d.ts +43 -0
- package/dist/i18n/locales/es.js +339 -0
- package/dist/i18n/locales/es.js.map +1 -0
- package/dist/i18n/locales/fr.d.ts +43 -0
- package/dist/i18n/locales/fr.js +344 -0
- package/dist/i18n/locales/fr.js.map +1 -0
- package/dist/i18n/locales/hu.d.ts +43 -0
- package/dist/i18n/locales/hu.js +343 -0
- package/dist/i18n/locales/hu.js.map +1 -0
- package/dist/i18n/locales/it.d.ts +43 -0
- package/dist/i18n/locales/it.js +342 -0
- package/dist/i18n/locales/it.js.map +1 -0
- package/dist/i18n/locales/zh.d.ts +43 -0
- package/dist/i18n/locales/zh.js +338 -0
- package/dist/i18n/locales/zh.js.map +1 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/direction.d.ts +24 -0
- package/dist/lib/direction.js +19 -0
- package/dist/lib/direction.js.map +1 -0
- package/dist/rhf/form.js.map +1 -1
- package/dist/search/command-palette.d.ts +5 -0
- package/dist/search/command-palette.js +80 -50
- package/dist/search/command-palette.js.map +1 -1
- package/dist/shell/app-shell.d.ts +13 -1
- package/dist/shell/app-shell.js +133 -84
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/topbar-action-menu.js +1 -1
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell/topbar-controls.d.ts +7 -3
- package/dist/shell/topbar-controls.js +38 -31
- package/dist/shell/topbar-controls.js.map +1 -1
- package/dist/theme/chart-palette.d.ts +7 -1
- package/dist/theme/chart-palette.js +2 -1
- package/dist/theme/chart-palette.js.map +1 -1
- package/dist/tour/tour.d.ts +11 -5
- package/dist/tour/tour.js +124 -58
- package/dist/tour/tour.js.map +1 -1
- package/dist/wizard/use-wizard.js +30 -13
- package/dist/wizard/use-wizard.js.map +1 -1
- package/dist/wizard/wizard-summary.js +1 -1
- package/dist/wizard/wizard-summary.js.map +1 -1
- package/package.json +12 -2
- package/src/components/account-settings.tsx +6 -2
- package/src/components/amount-input.tsx +10 -8
- package/src/components/autocomplete.tsx +110 -24
- package/src/components/calculator.tsx +5 -1
- package/src/components/chart-zoom.tsx +8 -1
- package/src/components/chart.tsx +68 -7
- package/src/components/chip.tsx +131 -49
- package/src/components/choice-card.tsx +77 -36
- package/src/components/combobox-core.tsx +147 -20
- package/src/components/combobox.tsx +100 -44
- package/src/components/currency-select.tsx +6 -6
- package/src/components/danger-confirm.tsx +90 -36
- package/src/components/data-table-pagination.tsx +32 -19
- package/src/components/data-table.tsx +198 -36
- package/src/components/date-picker.tsx +24 -7
- package/src/components/dialog-frame.tsx +97 -22
- package/src/components/disclosure.tsx +75 -13
- package/src/components/dropdown.tsx +17 -5
- package/src/components/entity-combobox.tsx +26 -13
- package/src/components/file-button.tsx +74 -5
- package/src/components/file-dropzone.tsx +44 -35
- package/src/components/grouped-picker.tsx +2 -2
- package/src/components/hover-menu.tsx +139 -10
- package/src/components/icon-picker.tsx +14 -1
- package/src/components/measured-grid.tsx +852 -0
- package/src/components/mini-calendar.tsx +11 -8
- package/src/components/month-picker.tsx +18 -11
- package/src/components/multi-entity-combobox.tsx +2 -2
- package/src/components/multi-select.tsx +34 -7
- package/src/components/number-input.tsx +4 -4
- package/src/components/numpad-sheet.tsx +5 -3
- package/src/components/picker-sheet.tsx +1 -1
- package/src/components/popover.tsx +18 -3
- package/src/components/series-chart-ticks.ts +52 -0
- package/src/components/series-chart.tsx +39 -31
- package/src/components/swatch-picker.tsx +11 -0
- package/src/components/swipeable-row.tsx +21 -6
- package/src/components/tile-radio.tsx +5 -7
- package/src/components/toggle-group.tsx +39 -3
- package/src/components/toggle-legend.tsx +5 -2
- package/src/components/treemap.tsx +28 -5
- package/src/components/ui.tsx +74 -30
- package/src/components/use-anchor-dir.ts +20 -0
- package/src/components/use-mobile-reveal.ts +10 -2
- package/src/components/use-table-state.ts +44 -7
- package/src/data-table.ts +1 -0
- package/src/feedback/feedback-attachment.tsx +36 -9
- package/src/feedback/feedback-dialog.tsx +3 -2
- package/src/hooks/use-windowed-rows.ts +69 -0
- package/src/i18n/defaults.ts +4 -0
- package/src/i18n/kit-labels.tsx +4 -0
- package/src/i18n/locales/de-CH.ts +30 -0
- package/src/i18n/locales/de.ts +365 -0
- package/src/i18n/locales/es.ts +358 -0
- package/src/i18n/locales/fr.ts +371 -0
- package/src/i18n/locales/hu.ts +359 -0
- package/src/i18n/locales/it.ts +360 -0
- package/src/i18n/locales/zh.ts +348 -0
- package/src/index.ts +10 -1
- package/src/lib/direction.ts +37 -0
- package/src/rhf/form.tsx +21 -0
- package/src/search/command-palette.tsx +77 -19
- package/src/shell/app-shell.tsx +200 -129
- package/src/shell/topbar-action-menu.tsx +1 -1
- package/src/shell/topbar-controls.tsx +19 -8
- package/src/theme/chart-palette.ts +9 -2
- package/src/tour/tour.tsx +119 -18
- package/src/wizard/use-wizard.ts +55 -17
- package/src/wizard/wizard-summary.tsx +1 -1
|
@@ -2,12 +2,36 @@ import { cn } from "../lib/cn";
|
|
|
2
2
|
import { useEffect, useRef, useState, type RefObject } from "react";
|
|
3
3
|
import { Camera, FileText, Paperclip, X } from "lucide-react";
|
|
4
4
|
import { Button } from "../components/ui";
|
|
5
|
-
import { useKitFileLabels } from "../i18n/kit-labels";
|
|
5
|
+
import { useKitFileLabels, useKitLabels } from "../i18n/kit-labels";
|
|
6
6
|
import type { FeedbackAttachmentLabels } from "./feedback-dialog";
|
|
7
7
|
|
|
8
8
|
export const DEFAULT_ATTACHMENT_ACCEPT = ["image/png", "image/jpeg", "image/webp", "image/gif"];
|
|
9
9
|
export const DEFAULT_MAX_ATTACHMENT_BYTES = 10 * 1024 * 1024;
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* The field's own strings — the `feedbackAttachment` namespace of `<UiKitProvider
|
|
13
|
+
* labels>`. The keys are {@link FeedbackAttachmentLabels}' own, so the `labels` prop
|
|
14
|
+
* (and a whole `FeedbackDialogLabels` handed down by the dialog) merges over them
|
|
15
|
+
* one to one. The optional heading, `attachment`, stays a prop: a note editor puts
|
|
16
|
+
* the buttons straight under its textarea and wants none.
|
|
17
|
+
*
|
|
18
|
+
* Before 0.7.0 the two optional keys fell back to hard-coded English, so a German app
|
|
19
|
+
* that relied on its provider got "Capture screenshot" under a German form.
|
|
20
|
+
*/
|
|
21
|
+
export interface FeedbackAttachmentFieldLabels {
|
|
22
|
+
attachmentAdd: string;
|
|
23
|
+
attachmentCapture: string;
|
|
24
|
+
attachmentPaste: string;
|
|
25
|
+
attachmentRemove: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const DEFAULT_FEEDBACK_ATTACHMENT_LABELS: FeedbackAttachmentFieldLabels = {
|
|
29
|
+
attachmentAdd: "Attach image",
|
|
30
|
+
attachmentCapture: "Capture screenshot",
|
|
31
|
+
attachmentPaste: "…or paste a screenshot from the clipboard.",
|
|
32
|
+
attachmentRemove: "Remove attachment",
|
|
33
|
+
};
|
|
34
|
+
|
|
11
35
|
/**
|
|
12
36
|
* Picking one picture: the file dialog, a capture of the app view, or a paste.
|
|
13
37
|
*
|
|
@@ -40,7 +64,7 @@ export const DEFAULT_MAX_ATTACHMENT_BYTES = 10 * 1024 * 1024;
|
|
|
40
64
|
export function FeedbackAttachmentField({
|
|
41
65
|
value,
|
|
42
66
|
onChange,
|
|
43
|
-
labels,
|
|
67
|
+
labels: labelsProp,
|
|
44
68
|
accept = DEFAULT_ATTACHMENT_ACCEPT,
|
|
45
69
|
maxBytes = DEFAULT_MAX_ATTACHMENT_BYTES,
|
|
46
70
|
onError,
|
|
@@ -51,7 +75,9 @@ export function FeedbackAttachmentField({
|
|
|
51
75
|
}: {
|
|
52
76
|
value: File | null;
|
|
53
77
|
onChange: (file: File | null) => void;
|
|
54
|
-
labels
|
|
78
|
+
/** Prop > `<UiKitProvider labels={{ feedbackAttachment }}>` > English. Optional
|
|
79
|
+
* since 0.7.0; `attachment` (the heading) is only ever read from here. */
|
|
80
|
+
labels?: Partial<FeedbackAttachmentLabels>;
|
|
55
81
|
accept?: string[];
|
|
56
82
|
maxBytes?: number;
|
|
57
83
|
onError?: (kind: "type" | "size") => void;
|
|
@@ -73,6 +99,7 @@ export function FeedbackAttachmentField({
|
|
|
73
99
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
74
100
|
// `file.size` from `<UiKitProvider labels>`, formatted in its locale — see FileDropzone.
|
|
75
101
|
const fileText = useKitFileLabels();
|
|
102
|
+
const text = useKitLabels("feedbackAttachment", DEFAULT_FEEDBACK_ATTACHMENT_LABELS, labelsProp);
|
|
76
103
|
|
|
77
104
|
// Object-URL preview lifecycle (create on change, revoke on cleanup).
|
|
78
105
|
useEffect(() => {
|
|
@@ -151,9 +178,9 @@ export function FeedbackAttachmentField({
|
|
|
151
178
|
: (event) => takeImage(event.clipboardData, () => event.preventDefault())
|
|
152
179
|
}
|
|
153
180
|
>
|
|
154
|
-
{
|
|
181
|
+
{labelsProp?.attachment && (
|
|
155
182
|
<div className="mb-1 text-xs font-medium uppercase tracking-wide text-[var(--text-muted)]">
|
|
156
|
-
{
|
|
183
|
+
{labelsProp.attachment}
|
|
157
184
|
</div>
|
|
158
185
|
)}
|
|
159
186
|
{value ? (
|
|
@@ -180,7 +207,7 @@ export function FeedbackAttachmentField({
|
|
|
180
207
|
<button
|
|
181
208
|
type="button"
|
|
182
209
|
onClick={() => onChange(null)}
|
|
183
|
-
aria-label={
|
|
210
|
+
aria-label={text.attachmentRemove}
|
|
184
211
|
className="rounded p-1.5 text-[var(--text-placeholder)] hover:bg-[var(--bg-hover)] hover:text-[var(--text-secondary)]"
|
|
185
212
|
>
|
|
186
213
|
<X className="size-4" />
|
|
@@ -190,7 +217,7 @@ export function FeedbackAttachmentField({
|
|
|
190
217
|
<div className="space-y-1.5">
|
|
191
218
|
<div className="flex flex-wrap gap-2">
|
|
192
219
|
<Button type="button" variant="secondary" onClick={() => fileInputRef.current?.click()}>
|
|
193
|
-
<Paperclip className="size-4" /> {
|
|
220
|
+
<Paperclip className="size-4" /> {text.attachmentAdd}
|
|
194
221
|
</Button>
|
|
195
222
|
{onCaptureScreenshot && (
|
|
196
223
|
<Button
|
|
@@ -208,14 +235,14 @@ export function FeedbackAttachmentField({
|
|
|
208
235
|
}}
|
|
209
236
|
>
|
|
210
237
|
<Camera className="size-4" />{" "}
|
|
211
|
-
{capturing ? "…" :
|
|
238
|
+
{capturing ? "…" : text.attachmentCapture}
|
|
212
239
|
</Button>
|
|
213
240
|
)}
|
|
214
241
|
</div>
|
|
215
242
|
{/* Said out loud, because a gesture with no affordance is a gesture
|
|
216
243
|
nobody finds. */}
|
|
217
244
|
<p className="text-xs text-[var(--text-muted)]">
|
|
218
|
-
{
|
|
245
|
+
{text.attachmentPaste}
|
|
219
246
|
</p>
|
|
220
247
|
</div>
|
|
221
248
|
)}
|
|
@@ -19,10 +19,11 @@ export interface FeedbackAttachmentLabels {
|
|
|
19
19
|
* straight under its textarea, where a second heading is noise. */
|
|
20
20
|
attachment?: string;
|
|
21
21
|
attachmentAdd: string;
|
|
22
|
-
/** Label for the "capture screenshot" button. Optional — falls back to
|
|
22
|
+
/** Label for the "capture screenshot" button. Optional — falls back to the provider's
|
|
23
|
+
* `feedbackAttachment.attachmentCapture`, then English. */
|
|
23
24
|
attachmentCapture?: string;
|
|
24
25
|
/** The line under the attachment buttons saying a screenshot can be pasted
|
|
25
|
-
* straight in. Optional — falls back to
|
|
26
|
+
* straight in. Optional — falls back to the provider's `feedbackAttachment`, then English. */
|
|
26
27
|
attachmentPaste?: string;
|
|
27
28
|
attachmentRemove: string;
|
|
28
29
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import type { RefObject } from "react";
|
|
3
|
+
|
|
4
|
+
/** Rows kept mounted beyond each edge, so a flick-scroll has something to show
|
|
5
|
+
* before the next render lands. */
|
|
6
|
+
const OVERSCAN = 6;
|
|
7
|
+
|
|
8
|
+
/** What {@link useWindowedRows} answers: render rows `first` up to (not including)
|
|
9
|
+
* `last`, inside a scroll body `totalHeight` pixels tall. */
|
|
10
|
+
export interface WindowedRows {
|
|
11
|
+
first: number;
|
|
12
|
+
last: number;
|
|
13
|
+
totalHeight: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Which rows of a fixed-height list are worth rendering.
|
|
18
|
+
*
|
|
19
|
+
* Hand-rolled rather than pulled from a virtualization library, for two reasons. With
|
|
20
|
+
* a fixed row height the whole problem is two divisions — a library earns its keep on
|
|
21
|
+
* measured, variable-height rows, and there are none here. And the obvious library for
|
|
22
|
+
* it (`@tanstack/react-virtual`) returns functions that cannot be memoized safely, so
|
|
23
|
+
* the React Compiler skips optimising any component that calls it: a list that exists
|
|
24
|
+
* to stay fast would opt out of the consumer's main source of speed.
|
|
25
|
+
*
|
|
26
|
+
* `scrollRef` is the element that scrolls. The rows are assumed to start at its top;
|
|
27
|
+
* a sticky header above them costs a row or two of the overscan, not correctness.
|
|
28
|
+
*
|
|
29
|
+
* Moved from Lenkbank, where `MeasuredGrid` and a segment list window the same way over
|
|
30
|
+
* rows of different heights — two copies of this would be two places to fix the day
|
|
31
|
+
* the overscan turns out to be wrong.
|
|
32
|
+
*/
|
|
33
|
+
export function useWindowedRows(
|
|
34
|
+
count: number,
|
|
35
|
+
rowHeight: number,
|
|
36
|
+
scrollRef: RefObject<HTMLElement | null>,
|
|
37
|
+
): WindowedRows {
|
|
38
|
+
const [scrollTop, setScrollTop] = useState(0);
|
|
39
|
+
const [viewport, setViewport] = useState(0);
|
|
40
|
+
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
const element = scrollRef.current;
|
|
43
|
+
if (!element) return;
|
|
44
|
+
const measure = () => {
|
|
45
|
+
setScrollTop(element.scrollTop);
|
|
46
|
+
setViewport(element.clientHeight);
|
|
47
|
+
};
|
|
48
|
+
measure();
|
|
49
|
+
element.addEventListener("scroll", measure, { passive: true });
|
|
50
|
+
// The pane usually sits in a responsive layout, so its height changes without the
|
|
51
|
+
// window's — a resize listener alone would miss every one of those. Guarded:
|
|
52
|
+
// jsdom and older embedded webviews have no ResizeObserver, and the list still
|
|
53
|
+
// has to render there.
|
|
54
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(measure);
|
|
55
|
+
observer?.observe(element);
|
|
56
|
+
return () => {
|
|
57
|
+
element.removeEventListener("scroll", measure);
|
|
58
|
+
observer?.disconnect();
|
|
59
|
+
};
|
|
60
|
+
}, [scrollRef]);
|
|
61
|
+
|
|
62
|
+
const first = Math.max(0, Math.floor(scrollTop / rowHeight) - OVERSCAN);
|
|
63
|
+
// A viewport of 0 is the first render, before the pane has been laid out (and every
|
|
64
|
+
// render under jsdom). Rendering nothing then would leave the list blank until
|
|
65
|
+
// something scrolled it, so fall back to a screenful.
|
|
66
|
+
const visible = Math.ceil((viewport || 600) / rowHeight) + OVERSCAN * 2;
|
|
67
|
+
const last = Math.min(count, first + visible);
|
|
68
|
+
return { first, last, totalHeight: count * rowHeight };
|
|
69
|
+
}
|
package/src/i18n/defaults.ts
CHANGED
|
@@ -19,6 +19,8 @@ import { DEFAULT_SWATCH_PICKER_LABELS } from "../components/swatch-picker";
|
|
|
19
19
|
import { DEFAULT_ICON_PICKER_LABELS } from "../components/icon-picker";
|
|
20
20
|
import { DEFAULT_DIALOG_FRAME_LABELS } from "../components/dialog-frame";
|
|
21
21
|
import { DEFAULT_FILE_PICKER_LABELS } from "../components/file-button";
|
|
22
|
+
import { DEFAULT_MEASURED_GRID_LABELS } from "../components/measured-grid";
|
|
23
|
+
import { DEFAULT_FEEDBACK_ATTACHMENT_LABELS } from "../feedback/feedback-attachment";
|
|
22
24
|
import {
|
|
23
25
|
DEFAULT_APP_SHELL_LABELS,
|
|
24
26
|
DEFAULT_CALCULATOR_LABELS,
|
|
@@ -76,4 +78,6 @@ export const DEFAULT_UI_KIT_LABELS: UiKitLabels = {
|
|
|
76
78
|
iconPicker: DEFAULT_ICON_PICKER_LABELS,
|
|
77
79
|
dialogFrame: DEFAULT_DIALOG_FRAME_LABELS,
|
|
78
80
|
filePicker: DEFAULT_FILE_PICKER_LABELS,
|
|
81
|
+
measuredGrid: DEFAULT_MEASURED_GRID_LABELS,
|
|
82
|
+
feedbackAttachment: DEFAULT_FEEDBACK_ATTACHMENT_LABELS,
|
|
79
83
|
};
|
package/src/i18n/kit-labels.tsx
CHANGED
|
@@ -21,6 +21,8 @@ import type { SwatchPickerLabels } from "../components/swatch-picker";
|
|
|
21
21
|
import type { IconPickerLabels } from "../components/icon-picker";
|
|
22
22
|
import type { DialogFrameLabels } from "../components/dialog-frame";
|
|
23
23
|
import type { FilePickerLabels } from "../components/file-button";
|
|
24
|
+
import type { MeasuredGridLabels } from "../components/measured-grid";
|
|
25
|
+
import type { FeedbackAttachmentFieldLabels } from "../feedback/feedback-attachment";
|
|
24
26
|
|
|
25
27
|
/**
|
|
26
28
|
* EVERY string the kit renders, as one typed tree — and an optional provider that
|
|
@@ -208,6 +210,8 @@ export interface UiKitLabels {
|
|
|
208
210
|
iconPicker: IconPickerLabels;
|
|
209
211
|
dialogFrame: DialogFrameLabels;
|
|
210
212
|
filePicker: FilePickerLabels;
|
|
213
|
+
measuredGrid: MeasuredGridLabels;
|
|
214
|
+
feedbackAttachment: FeedbackAttachmentFieldLabels;
|
|
211
215
|
}
|
|
212
216
|
|
|
213
217
|
/** Any subset of the tree, one level deep — each namespace may be partial, and a
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { UiKitLabels } from "../kit-labels";
|
|
2
|
+
import { uiKitLabelsDe } from "./de";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Swiss Standard German: the German labels with Swiss spelling — "ss" for every "ß"
|
|
6
|
+
* (Schliessen, Grösse), which is the one systematic difference in UI text — and
|
|
7
|
+
* `de-CH` number formatting (1’234.5).
|
|
8
|
+
*
|
|
9
|
+
* Derived rather than duplicated, so a key added to the German labels is Swiss the
|
|
10
|
+
* moment it lands. Function labels are wrapped: their RESULT is respelled, so an
|
|
11
|
+
* argument the app passes in (a file name, a phrase to type) is respelled too — which
|
|
12
|
+
* is what a Swiss app writing "ss" everywhere wants.
|
|
13
|
+
*/
|
|
14
|
+
export const UI_KIT_LABELS_DE_CH: UiKitLabels = swiss(uiKitLabelsDe("de-CH"));
|
|
15
|
+
|
|
16
|
+
function respell(text: string): string {
|
|
17
|
+
return text.replace(/ß/g, "ss").replace(/ẞ/g, "SS");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function swiss<T>(value: T): T {
|
|
21
|
+
if (typeof value === "string") return respell(value) as T;
|
|
22
|
+
if (typeof value === "function") {
|
|
23
|
+
const fn = value as (...args: unknown[]) => unknown;
|
|
24
|
+
return ((...args: unknown[]) => swiss(fn(...args))) as T;
|
|
25
|
+
}
|
|
26
|
+
if (value && typeof value === "object") {
|
|
27
|
+
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, swiss(v)])) as T;
|
|
28
|
+
}
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import { formatFileSize } from "../kit-labels";
|
|
2
|
+
import type { UiKitLabels } from "../kit-labels";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The kit's words in German: every namespace of {@link UiKitLabels}, for
|
|
6
|
+
* `<UiKitProvider labels={UI_KIT_LABELS_DE}>`.
|
|
7
|
+
*
|
|
8
|
+
* Self-contained on purpose — nothing but the kit's own `formatFileSize` — so it works
|
|
9
|
+
* as a starting point to copy and adjust. Counts and sizes are formatted with
|
|
10
|
+
* `de-DE` digits; {@link uiKitLabelsDe} takes another number locale
|
|
11
|
+
* (e.g. `"de-CH"` for 1’234) without touching the words.
|
|
12
|
+
*/
|
|
13
|
+
export function uiKitLabelsDe(numberLocale = "de-DE"): UiKitLabels {
|
|
14
|
+
const num = new Intl.NumberFormat(numberLocale);
|
|
15
|
+
const n = (value: number) => num.format(value);
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
feedbackAttachment: {
|
|
19
|
+
attachmentAdd: "Bild anhängen",
|
|
20
|
+
attachmentCapture: "Screenshot aufnehmen",
|
|
21
|
+
attachmentPaste: "…oder einen Screenshot aus der Zwischenablage einfügen.",
|
|
22
|
+
attachmentRemove: "Anhang entfernen",
|
|
23
|
+
},
|
|
24
|
+
measuredGrid: {
|
|
25
|
+
view: "Tabellenansicht",
|
|
26
|
+
cellsView: "Zellen",
|
|
27
|
+
textView: "Text",
|
|
28
|
+
addRow: "Zeile hinzufügen",
|
|
29
|
+
removeRow: (row) => `Zeile ${row} entfernen`,
|
|
30
|
+
clear: "Tabelle leeren",
|
|
31
|
+
pasteHint: "Einen Block aus einer Tabellenkalkulation in eine beliebige Zelle einfügen",
|
|
32
|
+
cell: (column, row) => `${column}, Zeile ${row}`,
|
|
33
|
+
rowNumber: "Zeile",
|
|
34
|
+
rowActions: "Zeilenaktionen",
|
|
35
|
+
keyboardHint:
|
|
36
|
+
"Pfeiltasten wechseln zwischen Zellen. Tippen ersetzt eine Zelle, F2 bearbeitet sie, Escape macht die Bearbeitung rückgängig. Enter geht nach unten und fügt am Ende eine Zeile hinzu.",
|
|
37
|
+
lineError: (line) => `Zeile ${line} konnte nicht gelesen werden`,
|
|
38
|
+
points: (count) => (count === 1 ? "1 Punkt" : `${count} Punkte`),
|
|
39
|
+
problems: (count) =>
|
|
40
|
+
count === 1 ? "1 Zelle ist keine Zahl" : `${count} Zellen sind keine Zahlen`,
|
|
41
|
+
},
|
|
42
|
+
pageContents: { title: "Auf dieser Seite" },
|
|
43
|
+
common: {
|
|
44
|
+
close: "Schließen",
|
|
45
|
+
clear: "Leeren",
|
|
46
|
+
search: "Suchen",
|
|
47
|
+
done: "Fertig",
|
|
48
|
+
cancel: "Abbrechen",
|
|
49
|
+
save: "Speichern",
|
|
50
|
+
back: "Zurück",
|
|
51
|
+
next: "Weiter",
|
|
52
|
+
remove: "Entfernen",
|
|
53
|
+
loading: "Wird geladen…",
|
|
54
|
+
noResults: "Keine Ergebnisse",
|
|
55
|
+
fieldValue: (field, value) => `${field}: ${value}`,
|
|
56
|
+
},
|
|
57
|
+
dataTable: {
|
|
58
|
+
columns: "Spalten",
|
|
59
|
+
selectAllRows: "Alle Zeilen auswählen",
|
|
60
|
+
sortHint: "Klicken zum Sortieren · Umschalt-Klick für weitere Sortierung",
|
|
61
|
+
filter: "Filter",
|
|
62
|
+
close: "Schließen",
|
|
63
|
+
selectRow: "Zeile auswählen",
|
|
64
|
+
autoSize: "Spaltenbreiten anpassen",
|
|
65
|
+
loading: "Wird geladen…",
|
|
66
|
+
filters: "Filter",
|
|
67
|
+
// Resets every active filter; "Alle löschen" would read as deleting the filters.
|
|
68
|
+
clearAll: "Alle zurücksetzen",
|
|
69
|
+
done: "Fertig",
|
|
70
|
+
pageSize: "Zeilen pro Seite",
|
|
71
|
+
// Sits among 10 / 25 / 50 counting "Zeilen", so the plural "Alle", not "Alles".
|
|
72
|
+
pageSizeAll: "Alle",
|
|
73
|
+
prevPage: "Vorherige Seite",
|
|
74
|
+
nextPage: "Nächste Seite",
|
|
75
|
+
clearFilter: "Filter zurücksetzen",
|
|
76
|
+
filterPlaceholder: "Filtern…",
|
|
77
|
+
selectFilter: "Auswählen",
|
|
78
|
+
selectAll: "Alle",
|
|
79
|
+
selectNone: "Keine",
|
|
80
|
+
dateFrom: "Von",
|
|
81
|
+
dateTo: "Bis",
|
|
82
|
+
numberMin: "Min.",
|
|
83
|
+
numberMax: "Max.",
|
|
84
|
+
numberAbs: "Betrag",
|
|
85
|
+
presets: {
|
|
86
|
+
today: "Heute",
|
|
87
|
+
yesterday: "Gestern",
|
|
88
|
+
this_week: "Diese Woche",
|
|
89
|
+
last_week: "Letzte Woche",
|
|
90
|
+
last_7_days: "Letzte 7 Tage",
|
|
91
|
+
last_30_days: "Letzte 30 Tage",
|
|
92
|
+
this_month: "Dieser Monat",
|
|
93
|
+
last_month: "Letzter Monat",
|
|
94
|
+
last_3_months: "Letzte 3 Monate",
|
|
95
|
+
ytd: "Seit Jahresbeginn",
|
|
96
|
+
last_year: "Letztes Jahr",
|
|
97
|
+
},
|
|
98
|
+
table: "Datentabelle",
|
|
99
|
+
filterResults: (shown, total) =>
|
|
100
|
+
`${n(shown)} von ${n(total)} ${total === 1 ? "Zeile" : "Zeilen"}`,
|
|
101
|
+
sortedAscending: (column) => `Sortiert nach ${column}, aufsteigend`,
|
|
102
|
+
sortedDescending: (column) => `Sortiert nach ${column}, absteigend`,
|
|
103
|
+
sortCleared: (column) => `Sortierung nach ${column} aufgehoben`,
|
|
104
|
+
pageChanged: (page, totalPages) => `Seite ${n(page)} von ${n(totalPages)}`,
|
|
105
|
+
pageRange: (from, to, total) => `${n(from)}–${n(to)} / ${n(total)}`,
|
|
106
|
+
rowCount: (total) => n(total),
|
|
107
|
+
columnsCount: (visible, total) => `Spalten (${n(visible)}/${n(total)})`,
|
|
108
|
+
},
|
|
109
|
+
miniCalendar: {
|
|
110
|
+
previousMonth: "Vorheriger Monat",
|
|
111
|
+
nextMonth: "Nächster Monat",
|
|
112
|
+
// Already formatted in the provider's locale ("Montag, 14. September 2026").
|
|
113
|
+
day: (date) => date,
|
|
114
|
+
chooseStart: "Startdatum wählen",
|
|
115
|
+
chooseEnd: "Enddatum wählen",
|
|
116
|
+
startSelected: (date) => `${date} als Startdatum gewählt. Wählen Sie jetzt ein Enddatum.`,
|
|
117
|
+
rangeSelected: (from, to) =>
|
|
118
|
+
`Zeitraum ${from} bis ${to} gewählt. Wählen Sie ein Startdatum, um neu zu beginnen.`,
|
|
119
|
+
},
|
|
120
|
+
datePicker: {
|
|
121
|
+
panel: "Datum wählen",
|
|
122
|
+
rangePanel: "Zeitraum wählen",
|
|
123
|
+
clear: "Leeren",
|
|
124
|
+
previousDay: "Vorheriger Tag",
|
|
125
|
+
nextDay: "Nächster Tag",
|
|
126
|
+
today: "Heute",
|
|
127
|
+
},
|
|
128
|
+
monthPicker: {
|
|
129
|
+
previousYear: "Vorheriges Jahr",
|
|
130
|
+
nextYear: "Nächstes Jahr",
|
|
131
|
+
panel: "Monat wählen",
|
|
132
|
+
month: (monthYear) => monthYear,
|
|
133
|
+
},
|
|
134
|
+
popover: {
|
|
135
|
+
panel: "Aufklappfenster",
|
|
136
|
+
},
|
|
137
|
+
combobox: {
|
|
138
|
+
search: "Suchen",
|
|
139
|
+
noResults: "Keine Ergebnisse",
|
|
140
|
+
clear: "Leeren",
|
|
141
|
+
loading: "Wird geladen…",
|
|
142
|
+
create: (query) => `„${query}“ anlegen`,
|
|
143
|
+
selectedCount: (count) => `${n(count)} ausgewählt`,
|
|
144
|
+
loadError: "Ergebnisse konnten nicht geladen werden",
|
|
145
|
+
resultCount: (count) => `${n(count)} ${count === 1 ? "Ergebnis" : "Ergebnisse"}`,
|
|
146
|
+
// "Zeichen" is the same in singular and plural.
|
|
147
|
+
minChars: (count) => `Mindestens ${n(count)} Zeichen eingeben`,
|
|
148
|
+
},
|
|
149
|
+
multiSelect: {
|
|
150
|
+
search: "Suchen",
|
|
151
|
+
selectAll: "Alle auswählen",
|
|
152
|
+
clear: "Leeren",
|
|
153
|
+
all: "Alle",
|
|
154
|
+
// The bare count, as in English: the trigger has always shown just the number.
|
|
155
|
+
selectedCount: (count) => n(count),
|
|
156
|
+
},
|
|
157
|
+
calculator: {
|
|
158
|
+
open: "Taschenrechner öffnen",
|
|
159
|
+
panel: "Taschenrechner",
|
|
160
|
+
calculation: "Rechnung",
|
|
161
|
+
backspace: "Rücktaste",
|
|
162
|
+
clear: "Löschen",
|
|
163
|
+
equals: "Ist gleich",
|
|
164
|
+
done: "Fertig",
|
|
165
|
+
plus: "Plus",
|
|
166
|
+
minus: "Minus",
|
|
167
|
+
times: "Mal",
|
|
168
|
+
divide: "Geteilt durch",
|
|
169
|
+
decimal: "Dezimaltrennzeichen",
|
|
170
|
+
},
|
|
171
|
+
currency: {
|
|
172
|
+
currency: "Währung",
|
|
173
|
+
search: "Währung suchen",
|
|
174
|
+
},
|
|
175
|
+
chipInput: {
|
|
176
|
+
// The value is arbitrary user text, quoted as a citation, so the participle agrees
|
|
177
|
+
// with the implied "Eintrag" whatever the chip says.
|
|
178
|
+
added: (value) => `„${value}“ hinzugefügt`,
|
|
179
|
+
removed: (value) => `„${value}“ entfernt`,
|
|
180
|
+
remove: "Entfernen",
|
|
181
|
+
// `von` governs the dative, visible only in the plural: "von 1 Eintrag", "von 2 Einträgen".
|
|
182
|
+
atLimit: (max) => `Grenze von ${n(max)} ${max === 1 ? "Eintrag" : "Einträgen"} erreicht`,
|
|
183
|
+
duplicate: (value) => `„${value}“ steht bereits in der Liste`,
|
|
184
|
+
},
|
|
185
|
+
swatchPicker: {
|
|
186
|
+
none: "Keine Farbe",
|
|
187
|
+
mixed: "Gemischt: Die ausgewählten Elemente haben unterschiedliche Farben",
|
|
188
|
+
},
|
|
189
|
+
iconPicker: {
|
|
190
|
+
none: "Kein Symbol",
|
|
191
|
+
mixed: "Gemischt: Die ausgewählten Elemente haben unterschiedliche Symbole",
|
|
192
|
+
search: "Symbole suchen",
|
|
193
|
+
noResults: "Keine passenden Symbole",
|
|
194
|
+
resultCount: (count) => `${n(count)} ${count === 1 ? "Symbol" : "Symbole"}`,
|
|
195
|
+
},
|
|
196
|
+
fieldSync: {
|
|
197
|
+
synced: "Gespeichert",
|
|
198
|
+
edited: "Nicht gespeicherte Änderungen",
|
|
199
|
+
pending: "Wird gespeichert…",
|
|
200
|
+
error: "Speichern fehlgeschlagen",
|
|
201
|
+
retry: "Erneut versuchen",
|
|
202
|
+
},
|
|
203
|
+
passwordReveal: {
|
|
204
|
+
show: "Passwort anzeigen",
|
|
205
|
+
hide: "Passwort verbergen",
|
|
206
|
+
},
|
|
207
|
+
dangerConfirm: {
|
|
208
|
+
arm: "Löschen…",
|
|
209
|
+
confirm: "Löschen",
|
|
210
|
+
cancel: "Abbrechen",
|
|
211
|
+
prompt: "Dies kann nicht rückgängig gemacht werden.",
|
|
212
|
+
password: "Passwort",
|
|
213
|
+
phrase: (phrase) => `Geben Sie zur Bestätigung „${phrase}“ ein`,
|
|
214
|
+
},
|
|
215
|
+
tabs: {
|
|
216
|
+
// "Tab" is what German UIs say; "Registerkarte" reads like a 1990s manual.
|
|
217
|
+
add: "Tab hinzufügen",
|
|
218
|
+
remove: (tab) => `${tab} entfernen`,
|
|
219
|
+
},
|
|
220
|
+
appShell: {
|
|
221
|
+
collapse: "Seitenleiste einklappen",
|
|
222
|
+
expand: "Seitenleiste ausklappen",
|
|
223
|
+
toggleGroup: (groupLabel) => `${groupLabel}: Seiten`,
|
|
224
|
+
},
|
|
225
|
+
topBar: {
|
|
226
|
+
theme: "Theme wechseln",
|
|
227
|
+
palette: "Darstellungsvorlage",
|
|
228
|
+
language: "Sprache",
|
|
229
|
+
switchRole: "Rolle wechseln",
|
|
230
|
+
role: (value) => `Rolle: ${value}`,
|
|
231
|
+
},
|
|
232
|
+
pickerSheet: {
|
|
233
|
+
close: "Schließen",
|
|
234
|
+
},
|
|
235
|
+
dialogFrame: {
|
|
236
|
+
close: "Schließen",
|
|
237
|
+
},
|
|
238
|
+
swipeableRow: {
|
|
239
|
+
actions: "Zeilenaktionen",
|
|
240
|
+
},
|
|
241
|
+
file: {
|
|
242
|
+
// The kit's own `Intl` unit formatting, pinned to this locale ("3,4 MB").
|
|
243
|
+
size: (bytes) => formatFileSize(bytes, numberLocale),
|
|
244
|
+
},
|
|
245
|
+
filePicker: {
|
|
246
|
+
rejectedPick: (count) =>
|
|
247
|
+
count === 1
|
|
248
|
+
? "Die Datei wurde nicht hinzugefügt"
|
|
249
|
+
: `Keine der ${count} Dateien wurde hinzugefügt`,
|
|
250
|
+
rejectedType: (name) => `„${name}“ hat einen nicht unterstützten Dateityp`,
|
|
251
|
+
rejectedTypeOnly: (accept) => `Nur ${accept}-Dateien`,
|
|
252
|
+
rejectedSize: (name, maxSize) => `„${name}“ ist größer als ${maxSize}`,
|
|
253
|
+
rejectedCount: (name, maxFiles) =>
|
|
254
|
+
`„${name}“ wurde nicht hinzugefügt: höchstens ${n(maxFiles)} ${maxFiles === 1 ? "Datei" : "Dateien"}`,
|
|
255
|
+
rejectedInvalid: (name) => `„${name}“ kann hier nicht verwendet werden`,
|
|
256
|
+
rejectedMany: (count) =>
|
|
257
|
+
count === 1
|
|
258
|
+
? "1 Datei wurde nicht hinzugefügt"
|
|
259
|
+
: `${n(count)} Dateien wurden nicht hinzugefügt`,
|
|
260
|
+
selected: (count, firstName) =>
|
|
261
|
+
count === 1 ? `„${firstName}“ ausgewählt` : `${n(count)} Dateien ausgewählt`,
|
|
262
|
+
remove: (name) => `„${name}“ entfernen`,
|
|
263
|
+
clearAll: "Alle Dateien entfernen",
|
|
264
|
+
removed: (name) => `„${name}“ entfernt`,
|
|
265
|
+
cleared: "Alle Dateien entfernt",
|
|
266
|
+
},
|
|
267
|
+
wizard: {
|
|
268
|
+
cancel: "Abbrechen",
|
|
269
|
+
back: "Zurück",
|
|
270
|
+
next: "Weiter",
|
|
271
|
+
skip: "Überspringen",
|
|
272
|
+
finish: "Abschließen",
|
|
273
|
+
submitting: "Wird erstellt…",
|
|
274
|
+
steps: "Schritte",
|
|
275
|
+
step: (current, total) => `Schritt ${n(current)} von ${n(total)}`,
|
|
276
|
+
cancelTitle: "Formular verwerfen?",
|
|
277
|
+
confirmCancel: "Ihre Eingaben gehen verloren.",
|
|
278
|
+
cancelConfirmLabel: "Verwerfen",
|
|
279
|
+
cancelDismissLabel: "Weiter bearbeiten",
|
|
280
|
+
reviewTitle: "Überprüfen",
|
|
281
|
+
edit: "Bearbeiten",
|
|
282
|
+
missingRequired: "Bitte füllen Sie alle Pflichtfelder aus.",
|
|
283
|
+
genericError: "Ein Fehler ist aufgetreten",
|
|
284
|
+
},
|
|
285
|
+
tour: {
|
|
286
|
+
next: "Weiter",
|
|
287
|
+
back: "Zurück",
|
|
288
|
+
skip: "Überspringen",
|
|
289
|
+
done: "Fertig",
|
|
290
|
+
awaitClickHint: "Klicken Sie auf das hervorgehobene Element, um fortzufahren",
|
|
291
|
+
step: (current, total) => `${n(current)} / ${n(total)}`,
|
|
292
|
+
},
|
|
293
|
+
commandPalette: {
|
|
294
|
+
placeholder: "Suchen…",
|
|
295
|
+
empty: "Keine Ergebnisse",
|
|
296
|
+
loading: "Wird gesucht…",
|
|
297
|
+
dialog: "Suche",
|
|
298
|
+
error: "Die Suche ist fehlgeschlagen. Bitte erneut versuchen.",
|
|
299
|
+
},
|
|
300
|
+
sparkline: {
|
|
301
|
+
rising: (first, last) => `Steigend von ${first} auf ${last}`,
|
|
302
|
+
falling: (first, last) => `Fallend von ${first} auf ${last}`,
|
|
303
|
+
flat: (value) => `Unverändert bei ${value}`,
|
|
304
|
+
single: (value) => `Ein Wert: ${value}`,
|
|
305
|
+
noData: "Keine Daten",
|
|
306
|
+
named: (name, summary) => `${name}: ${summary}`,
|
|
307
|
+
},
|
|
308
|
+
statTile: {
|
|
309
|
+
// `amount` arrives formatted and unsigned ("5 %", "1.200 €").
|
|
310
|
+
increase: (amount) => `Um ${amount} gestiegen`,
|
|
311
|
+
decrease: (amount) => `Um ${amount} gesunken`,
|
|
312
|
+
unchanged: "Keine Veränderung",
|
|
313
|
+
better: (change) => `${change} (besser)`,
|
|
314
|
+
worse: (change) => `${change} (schlechter)`,
|
|
315
|
+
noValue: "Keine Daten",
|
|
316
|
+
loading: "Wird geladen…",
|
|
317
|
+
},
|
|
318
|
+
signaturePad: {
|
|
319
|
+
label: "Unterschrift",
|
|
320
|
+
instructions: "Unterschreiben Sie im Feld mit der Maus, dem Finger oder einem Stift.",
|
|
321
|
+
typedFallbackHint: "Wenn Sie nicht zeichnen können, geben Sie stattdessen Ihren Namen ein.",
|
|
322
|
+
empty: "Noch nichts gezeichnet",
|
|
323
|
+
signed: "Unterschrift gezeichnet",
|
|
324
|
+
undo: "Letzten Strich rückgängig machen",
|
|
325
|
+
clear: "Leeren",
|
|
326
|
+
save: "Unterschrift speichern",
|
|
327
|
+
useTyped: "Stattdessen Namen eingeben",
|
|
328
|
+
useDrawn: "Stattdessen zeichnen",
|
|
329
|
+
typedName: "Vollständiger Name",
|
|
330
|
+
cleared: "Unterschrift gelöscht",
|
|
331
|
+
undone: "Letzter Strich entfernt",
|
|
332
|
+
viewEmpty: "Nicht unterschrieben",
|
|
333
|
+
viewDrawn: "Handschriftliche Unterschrift",
|
|
334
|
+
viewTyped: (name) => `Unterschrieben mit dem eingegebenen Namen ${name}`,
|
|
335
|
+
},
|
|
336
|
+
passwordStrength: {
|
|
337
|
+
tooShort: "Zu kurz",
|
|
338
|
+
weak: "Schwach",
|
|
339
|
+
fair: "Mittel",
|
|
340
|
+
good: "Gut",
|
|
341
|
+
strong: "Stark",
|
|
342
|
+
announcement: (level) => `Passwortstärke: ${level}`,
|
|
343
|
+
// "Zeichen" is the same in singular and plural. The English default does not
|
|
344
|
+
// format these counts, so neither does this file.
|
|
345
|
+
ruleLength: (minLength) => `Mindestens ${minLength} Zeichen`,
|
|
346
|
+
ruleCase: "Groß- und Kleinbuchstaben",
|
|
347
|
+
ruleDigit: "Eine Ziffer",
|
|
348
|
+
ruleSymbol: "Ein Sonderzeichen",
|
|
349
|
+
optional: (rule) => `${rule} (optional)`,
|
|
350
|
+
met: "Erfüllt:",
|
|
351
|
+
notMet: "Nicht erfüllt:",
|
|
352
|
+
tooLong: (maxBytes) =>
|
|
353
|
+
`Höchstens ${maxBytes} Zeichen (Buchstaben mit Akzent und Emojis zählen mehrfach).`,
|
|
354
|
+
},
|
|
355
|
+
seriesChart: {
|
|
356
|
+
resetZoom: "Zoom zurücksetzen",
|
|
357
|
+
zoomHint:
|
|
358
|
+
"Zum Zoomen ziehen: Eine annähernd quadratische Auswahl zoomt beide Achsen, eine lange, schmale nur ihre eigene. Doppelklick setzt zurück.",
|
|
359
|
+
empty: "Keine Daten",
|
|
360
|
+
legend: "Datenreihen",
|
|
361
|
+
},
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export const UI_KIT_LABELS_DE: UiKitLabels = uiKitLabelsDe();
|