@eifi1/ui-kit 0.40.1 → 0.42.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 +19 -6
- package/dist/admin/admin-area-labels.d.ts +55 -0
- package/dist/admin/admin-area-labels.js +33 -0
- package/dist/admin/admin-area-labels.js.map +1 -0
- package/dist/admin/admin-forbidden.d.ts +35 -0
- package/dist/admin/admin-forbidden.js +36 -0
- package/dist/admin/admin-forbidden.js.map +1 -0
- package/dist/admin/admin-overview.d.ts +93 -0
- package/dist/admin/admin-overview.js +69 -0
- package/dist/admin/admin-overview.js.map +1 -0
- package/dist/admin/admin-sections.d.ts +63 -0
- package/dist/admin/admin-sections.js +64 -0
- package/dist/admin/admin-sections.js.map +1 -0
- package/dist/admin/admin-tool-links.d.ts +48 -0
- package/dist/admin/admin-tool-links.js +31 -0
- package/dist/admin/admin-tool-links.js.map +1 -0
- package/dist/billing/billing-banner.d.ts +25 -2
- package/dist/billing/billing-banner.js +5 -2
- package/dist/billing/billing-banner.js.map +1 -1
- package/dist/billing/billing-labels.d.ts +32 -0
- package/dist/billing/billing-labels.js +9 -0
- package/dist/billing/billing-labels.js.map +1 -1
- package/dist/billing/billing-overview.d.ts +33 -0
- package/dist/billing/billing-overview.js +6 -0
- package/dist/billing/billing-overview.js.map +1 -1
- package/dist/billing/billing-standing.d.ts +8 -0
- package/dist/billing/billing-standing.js.map +1 -1
- package/dist/billing/cancel-subscription.d.ts +46 -0
- package/dist/billing/cancel-subscription.js +57 -0
- package/dist/billing/cancel-subscription.js.map +1 -0
- package/dist/billing/plan-card.d.ts +45 -1
- package/dist/billing/plan-card.js +53 -2
- package/dist/billing/plan-card.js.map +1 -1
- package/dist/billing/plan-switch.d.ts +10 -1
- package/dist/billing/plan-switch.js +22 -13
- package/dist/billing/plan-switch.js.map +1 -1
- package/dist/billing/subscription-actions.d.ts +37 -4
- package/dist/billing/subscription-actions.js +10 -3
- package/dist/billing/subscription-actions.js.map +1 -1
- package/dist/components/account-chips.d.ts +42 -1
- package/dist/components/account-chips.js +33 -0
- package/dist/components/account-chips.js.map +1 -1
- package/dist/components/empty-state.d.ts +2 -1
- package/dist/components/empty-state.js.map +1 -1
- package/dist/components/nav-pills.d.ts +2 -2
- package/dist/components/nav-pills.js.map +1 -1
- package/dist/components/tabs.d.ts +4 -32
- package/dist/components/tabs.js +30 -66
- package/dist/components/tabs.js.map +1 -1
- package/dist/components/translation-review-parts.d.ts +2 -2
- package/dist/components/translation-review-parts.js.map +1 -1
- package/dist/eslint/index.js +1 -1
- package/dist/feedback/feedback-menu-labels.js +0 -2
- package/dist/feedback/feedback-menu-labels.js.map +1 -1
- package/dist/feedback/feedback-menu.d.ts +0 -6
- package/dist/feedback/feedback-menu.js.map +1 -1
- package/dist/i18n/defaults.js +5 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.js +79 -2
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +9 -0
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/en.js +93 -3
- package/dist/i18n/locales/en.js.map +3 -3
- package/dist/i18n/locales/es.js +76 -2
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.js +75 -2
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.js +76 -2
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.js +76 -2
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.js +75 -2
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.js +20 -1
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +18 -2
- package/dist/index.js +23 -1
- package/dist/index.js.map +1 -1
- package/dist/settings/settings-layout.d.ts +7 -1
- package/dist/settings/settings-layout.js +35 -27
- package/dist/settings/settings-layout.js.map +1 -1
- package/dist/shell/account-menu-language.d.ts +46 -0
- package/dist/shell/account-menu-language.js +64 -0
- package/dist/shell/account-menu-language.js.map +1 -0
- package/dist/shell/admin-menu.d.ts +46 -0
- package/dist/shell/admin-menu.js +60 -0
- package/dist/shell/admin-menu.js.map +1 -0
- package/dist/shell/app-shell.d.ts +10 -0
- package/dist/shell/app-shell.js +22 -4
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/dev-switchers.d.ts +53 -0
- package/dist/shell/dev-switchers.js +102 -0
- package/dist/shell/dev-switchers.js.map +1 -0
- package/dist/shell/sync-status-indicator.d.ts +86 -0
- package/dist/shell/sync-status-indicator.js +170 -0
- package/dist/shell/sync-status-indicator.js.map +1 -0
- package/dist/shell/top-bar-actions.d.ts +49 -0
- package/dist/shell/top-bar-actions.js +31 -0
- package/dist/shell/top-bar-actions.js.map +1 -0
- package/dist/shell/top-bar-parts-labels.d.ts +84 -0
- package/dist/shell/top-bar-parts-labels.js +48 -0
- package/dist/shell/top-bar-parts-labels.js.map +1 -0
- package/dist/shell/topbar-action-menu.d.ts +13 -1
- package/dist/shell/topbar-action-menu.js +5 -2
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell/topbar-controls.d.ts +16 -3
- package/dist/shell/topbar-controls.js +5 -1
- package/dist/shell/topbar-controls.js.map +1 -1
- package/dist/shell/tour-menu.d.ts +58 -0
- package/dist/shell/tour-menu.js +73 -0
- package/dist/shell/tour-menu.js.map +1 -0
- package/dist/shell.d.ts +14 -0
- package/dist/shell.js +19 -0
- package/dist/shell.js.map +1 -1
- package/package.json +1 -1
- package/src/admin/admin-area-labels.ts +85 -0
- package/src/admin/admin-forbidden.tsx +75 -0
- package/src/admin/admin-overview.tsx +166 -0
- package/src/admin/admin-sections.tsx +137 -0
- package/src/admin/admin-tool-links.tsx +84 -0
- package/src/billing/billing-banner.tsx +32 -4
- package/src/billing/billing-labels.ts +53 -0
- package/src/billing/billing-overview.ts +37 -0
- package/src/billing/billing-standing.ts +8 -0
- package/src/billing/cancel-subscription.tsx +102 -0
- package/src/billing/plan-card.tsx +97 -1
- package/src/billing/plan-switch.tsx +16 -0
- package/src/billing/subscription-actions.tsx +64 -15
- package/src/components/account-chips.tsx +81 -1
- package/src/components/empty-state.tsx +2 -1
- package/src/components/nav-pills.tsx +2 -2
- package/src/components/tabs.tsx +19 -110
- package/src/components/translation-review-parts.tsx +2 -2
- package/src/feedback/feedback-menu-labels.ts +0 -2
- package/src/feedback/feedback-menu.tsx +0 -6
- package/src/i18n/defaults.ts +4 -0
- package/src/i18n/german.ts +92 -2
- package/src/i18n/kit-labels.tsx +9 -0
- package/src/i18n/locales/en.ts +19 -0
- package/src/i18n/locales/es.ts +86 -2
- package/src/i18n/locales/fr.ts +86 -2
- package/src/i18n/locales/hu.ts +84 -2
- package/src/i18n/locales/it.ts +87 -2
- package/src/i18n/locales/zh.ts +79 -2
- package/src/i18n/review.ts +19 -0
- package/src/index.ts +30 -2
- package/src/settings/settings-layout.tsx +58 -34
- package/src/shell/account-menu-language.tsx +116 -0
- package/src/shell/admin-menu.tsx +117 -0
- package/src/shell/app-shell.tsx +44 -3
- package/src/shell/dev-switchers.tsx +171 -0
- package/src/shell/sync-status-indicator.tsx +301 -0
- package/src/shell/top-bar-actions.tsx +79 -0
- package/src/shell/top-bar-parts-labels.ts +133 -0
- package/src/shell/topbar-action-menu.tsx +15 -2
- package/src/shell/topbar-controls.tsx +20 -3
- package/src/shell/tour-menu.tsx +144 -0
- package/src/shell.ts +24 -0
package/src/components/tabs.tsx
CHANGED
|
@@ -77,34 +77,6 @@ export interface TabsProps<T extends string>
|
|
|
77
77
|
active: T;
|
|
78
78
|
onChange: (id: T) => void;
|
|
79
79
|
className?: string;
|
|
80
|
-
/** Let the strip WRAP onto as many rows as it needs below `md`, instead of
|
|
81
|
-
* scrolling sideways — for a strip carrying more tabs than fit on a phone row.
|
|
82
|
-
* Keksdose live #262: ten reports on a 406px screen showed about three, and the
|
|
83
|
-
* round-2 answer (a <select> below `md`) cost a tap to open and a tap to choose.
|
|
84
|
-
* *"I would rather keep the tabs but have multirow tabs depending on the screen
|
|
85
|
-
* size, I will not loose the function to see all reports at once and navigate by
|
|
86
|
-
* single click rather by double click."*
|
|
87
|
-
*
|
|
88
|
-
* The active MARKER has to change with the layout, which is why this cannot be
|
|
89
|
-
* done from a call site with a `className`: the default marker is a `border-b-2`
|
|
90
|
-
* underline riding the container's own bottom rule, and a tab sitting in a row
|
|
91
|
-
* that does not touch that rule cannot wear it — every row but the last would
|
|
92
|
-
* show a stray line floating mid-strip, and `-mb-px` would pull each chip a
|
|
93
|
-
* pixel into the row beneath it. A wrapped strip marks the active tab with a
|
|
94
|
-
* filled brand chip instead, which is also the only thing findable at a glance
|
|
95
|
-
* among ten same-weight labels on three rows.
|
|
96
|
-
*
|
|
97
|
-
* From `md` up NOTHING changes: same single-line underline strip, same paddings,
|
|
98
|
-
* same colours as every other strip in the app.
|
|
99
|
-
*
|
|
100
|
-
* Opt-in on purpose. The three-tab strips (invoices, statements, bank imports)
|
|
101
|
-
* already fit a phone row, and turning those into chips would be an unrequested
|
|
102
|
-
* redesign of three other pages.
|
|
103
|
-
*
|
|
104
|
-
* @deprecated 0.40 — use the scrolling strip with `overflowCue`; removed in 0.41. No
|
|
105
|
-
* consumer is left (keksdose went back to one scrolling row, live #410); the caret
|
|
106
|
-
* says a phone's row goes on. */
|
|
107
|
-
wrap?: boolean;
|
|
108
80
|
/**
|
|
109
81
|
* The caret beside a SCROLLING strip below `md` (0.40, kk run 79 gap 1): a › while
|
|
110
82
|
* tabs lie past the strip's end — a tap scrolls it on by three quarters of its width —
|
|
@@ -117,7 +89,7 @@ export interface TabsProps<T extends string>
|
|
|
117
89
|
* turns round rather than two that come and go, so the strip's width never changes
|
|
118
90
|
* under the thumb. Out of the tab order — the keyboard walks the strip with the arrow
|
|
119
91
|
* keys, which bring the focused tab into view. From `md` up nothing changes. Ignored on
|
|
120
|
-
* a
|
|
92
|
+
* a vertical strip (a side nav is a column, not a row). Names:
|
|
121
93
|
* `tabs.more` / `tabs.backToFirst`.
|
|
122
94
|
*/
|
|
123
95
|
overflowCue?: boolean;
|
|
@@ -203,8 +175,8 @@ export interface TabsProps<T extends string>
|
|
|
203
175
|
* `onRemove`, `onAdd` — means exactly what it means on the horizontal strip; the
|
|
204
176
|
* badge moves to the row's end.
|
|
205
177
|
*
|
|
206
|
-
* **On a phone (`usePhoneLayout()`) it becomes the horizontal strip**,
|
|
207
|
-
*
|
|
178
|
+
* **On a phone (`usePhoneLayout()`) it becomes the horizontal strip**, rather than
|
|
179
|
+
* staying a column. A side nav only works beside its content; on
|
|
208
180
|
* a phone it has to go ABOVE it, and eight full-width rows there push the panel
|
|
209
181
|
* the user picked below the fold on every visit — the two keksdose pages both
|
|
210
182
|
* collapsed theirs into a scrolling row by hand for exactly that reason. The
|
|
@@ -220,14 +192,6 @@ export interface TabsProps<T extends string>
|
|
|
220
192
|
ref?: Ref<HTMLDivElement>;
|
|
221
193
|
}
|
|
222
194
|
|
|
223
|
-
// The two shapes are written out as whole strings rather than as one base plus a
|
|
224
|
-
// pile of `md:` overrides. The unwrapped pair is character-for-character what the
|
|
225
|
-
// three strips that do not opt in get, so those cannot drift; the wrapped pair is
|
|
226
|
-
// authored from scratch, so no unprefixed utility has to be beaten by its own `md:`
|
|
227
|
-
// twin through tailwind-merge. The only ordering this relies on is Tailwind's own:
|
|
228
|
-
// unprefixed utilities are emitted first, then `md:` — so from 768px up the wrapped
|
|
229
|
-
// strip resolves to exactly the paint of the default one. Both themes come free now
|
|
230
|
-
// that the colours are tokens: there is no `md:dark:` tier left to keep in step.
|
|
231
195
|
const TABLIST_CLASSES =
|
|
232
196
|
"flex gap-1 overflow-x-auto overflow-y-hidden border-b border-subtle";
|
|
233
197
|
// The side nav. A column of full-width rows with the open one FILLED rather than
|
|
@@ -242,9 +206,6 @@ const TAB_VERTICAL_ACTIVE_CLASSES = "bg-active text-primary";
|
|
|
242
206
|
const TAB_VERTICAL_INACTIVE_CLASSES =
|
|
243
207
|
"text-muted hover:bg-hover hover:text-primary";
|
|
244
208
|
|
|
245
|
-
const TABLIST_WRAP_CLASSES =
|
|
246
|
-
"flex flex-wrap gap-1.5 md:flex-nowrap md:gap-1 md:overflow-x-auto md:overflow-y-hidden md:border-b md:border-subtle";
|
|
247
|
-
|
|
248
209
|
// `max-w-full`: no tab outgrows its strip. A sheet's `detail` line ("Spurstangenkraft
|
|
249
210
|
// links · … · 31 Punkte") made one tab 448px wide in a 390px strip, and a tab wider
|
|
250
211
|
// than the strip cannot be scrolled into view — its end was simply off screen
|
|
@@ -256,31 +217,13 @@ const TAB_ACTIVE_CLASSES = "border-[var(--text-primary)] text-primary";
|
|
|
256
217
|
const TAB_INACTIVE_CLASSES =
|
|
257
218
|
"border-transparent text-muted hover:text-secondary hover:border-strong";
|
|
258
219
|
|
|
259
|
-
// Below `md`, a chip: `py-2` on `text-xs` is exactly 32px tall, and ten German
|
|
260
|
-
// report labels then land in three rows on a 406px screen (four at `text-sm`). The
|
|
261
|
-
// active fill is the app's own selected pair, `--brand` / `--brand-contrast`: the
|
|
262
|
-
// palette store writes both halves of it together for every preset and both themes,
|
|
263
|
-
// so the contrast holds everywhere (5.1:1 at its worst preset) without a hard-coded
|
|
264
|
-
// colour. Inactive chips take the raised card surface with full-strength body text —
|
|
265
|
-
// all ten have to stay readable; it is the FILL, not the text weight, that says
|
|
266
|
-
// which one is open.
|
|
267
|
-
const TAB_WRAP_CLASSES =
|
|
268
|
-
FOCUS_RING_WIDTH +
|
|
269
|
-
" max-w-full whitespace-nowrap rounded-md px-2.5 py-2 text-xs font-medium transition-colors focus:outline-none focus-visible:ring-strong md:rounded-none md:border-b-2 md:-mb-px md:bg-transparent md:px-3 md:py-2 md:text-sm";
|
|
270
|
-
const TAB_WRAP_ACTIVE_CLASSES =
|
|
271
|
-
"bg-brand text-brand-contrast md:border-[var(--text-primary)] md:text-primary";
|
|
272
|
-
const TAB_WRAP_INACTIVE_CLASSES =
|
|
273
|
-
"bg-surface text-primary md:border-transparent md:text-muted md:hover:border-strong md:hover:text-secondary";
|
|
274
|
-
|
|
275
220
|
// The add/remove chrome. The × reserves its gutter on every removable tab (see
|
|
276
|
-
// `onRemove`)
|
|
277
|
-
|
|
278
|
-
const TAB_REMOVABLE_CLASSES = "pe-8 md:pe-8";
|
|
221
|
+
// `onRemove`).
|
|
222
|
+
const TAB_REMOVABLE_CLASSES = "pe-8";
|
|
279
223
|
const TAB_EMPTY_CLASSES = "-mx-1.5 rounded border border-dashed border-strong px-1.5";
|
|
280
224
|
const TAB_ADD_CLASSES =
|
|
281
225
|
FOCUS_RING_WIDTH +
|
|
282
226
|
" inline-flex items-center gap-1 whitespace-nowrap rounded-md px-3 py-2 text-sm font-medium text-muted transition-colors hover:text-primary focus:outline-none focus-visible:ring-strong disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:size-4";
|
|
283
|
-
const TAB_ADD_WRAP_CLASSES = "px-2.5 text-xs md:px-3 md:text-sm";
|
|
284
227
|
// `relative`: the phone's visually hidden label needs a positioned ancestor (see the
|
|
285
228
|
// sr-only rule in CONTRIBUTING); `max-md:px-2` squares the lone "+".
|
|
286
229
|
const TAB_ADD_PHONE_CLASSES = "relative max-md:px-2";
|
|
@@ -290,7 +233,6 @@ export function Tabs<T extends string>({
|
|
|
290
233
|
active,
|
|
291
234
|
onChange,
|
|
292
235
|
className,
|
|
293
|
-
wrap = false,
|
|
294
236
|
overflowCue = false,
|
|
295
237
|
panelId,
|
|
296
238
|
onRemove,
|
|
@@ -312,7 +254,7 @@ export function Tabs<T extends string>({
|
|
|
312
254
|
const setStrip = useMemo(() => mergeRefs(stripRef, ref), [ref]);
|
|
313
255
|
const fade = useStripFade(stripRef);
|
|
314
256
|
// See `overflowCue`. `start` alone means the strip is scrolled to its end.
|
|
315
|
-
const cue = overflowCue && !
|
|
257
|
+
const cue = overflowCue && !vertical && fade.overflow !== undefined;
|
|
316
258
|
const cueAtEnd = fade.overflow === "start";
|
|
317
259
|
const onCue = () => {
|
|
318
260
|
const strip = stripRef.current;
|
|
@@ -394,9 +336,7 @@ export function Tabs<T extends string>({
|
|
|
394
336
|
strip.querySelectorAll<HTMLElement>('[role="tab"]')[index]?.focus();
|
|
395
337
|
}, [tabs, active]);
|
|
396
338
|
|
|
397
|
-
// Arrow keys walk the strip in DOM order (ARIA tabs pattern)
|
|
398
|
-
// a WRAPPED strip navigable: the rows flow in DOM order too, so Right off the end
|
|
399
|
-
// of row one lands on the first chip of row two rather than nowhere. Home/End jump
|
|
339
|
+
// Arrow keys walk the strip in DOM order (ARIA tabs pattern). Home/End jump
|
|
400
340
|
// to the ends. Focus only — activation stays on click/Enter/Space, because a tab
|
|
401
341
|
// here can be a real route and moving focus must not navigate.
|
|
402
342
|
//
|
|
@@ -465,8 +405,8 @@ export function Tabs<T extends string>({
|
|
|
465
405
|
// With an add button the strip gains an outer box, and `className` goes there
|
|
466
406
|
// — it is the box a caller's margin or width is meant for.
|
|
467
407
|
className={cn(
|
|
468
|
-
vertical ? TABLIST_VERTICAL_CLASSES :
|
|
469
|
-
onAdd ? "min-w-0" : overflowCue && !
|
|
408
|
+
vertical ? TABLIST_VERTICAL_CLASSES : TABLIST_CLASSES,
|
|
409
|
+
onAdd ? "min-w-0" : overflowCue && !vertical ? "min-w-0 flex-1" : className,
|
|
470
410
|
)}
|
|
471
411
|
>
|
|
472
412
|
{tabs.map((tab) => {
|
|
@@ -502,14 +442,8 @@ export function Tabs<T extends string>({
|
|
|
502
442
|
removable && "pe-8",
|
|
503
443
|
)
|
|
504
444
|
: cn(
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
? isActive
|
|
508
|
-
? TAB_WRAP_ACTIVE_CLASSES
|
|
509
|
-
: TAB_WRAP_INACTIVE_CLASSES
|
|
510
|
-
: isActive
|
|
511
|
-
? TAB_ACTIVE_CLASSES
|
|
512
|
-
: TAB_INACTIVE_CLASSES,
|
|
445
|
+
TAB_CLASSES,
|
|
446
|
+
isActive ? TAB_ACTIVE_CLASSES : TAB_INACTIVE_CLASSES,
|
|
513
447
|
removable && TAB_REMOVABLE_CLASSES,
|
|
514
448
|
),
|
|
515
449
|
};
|
|
@@ -537,16 +471,7 @@ export function Tabs<T extends string>({
|
|
|
537
471
|
{/* A separator for the NAME only — whitespace between flex items is
|
|
538
472
|
not drawn, and without it the two lines ran together into one
|
|
539
473
|
word for a screen reader ("80 km/hloop 2"). */}{" "}
|
|
540
|
-
<span
|
|
541
|
-
className={cn(
|
|
542
|
-
"max-w-full truncate-until-large text-caption font-normal leading-tight text-muted",
|
|
543
|
-
// On a wrapped strip's filled chip (below `md`) the muted grey
|
|
544
|
-
// was dark text on the brand fill — "loop 2" all but vanished
|
|
545
|
-
// under the one label that most needed reading. It takes the
|
|
546
|
-
// chip's own ink instead, as the label and the × already do.
|
|
547
|
-
wrap && isActive && !vertical && "text-brand-contrast md:text-muted",
|
|
548
|
-
)}
|
|
549
|
-
>
|
|
474
|
+
<span className="max-w-full truncate-until-large text-caption font-normal leading-tight text-muted">
|
|
550
475
|
{tab.detail}
|
|
551
476
|
</span>
|
|
552
477
|
</span>
|
|
@@ -620,12 +545,7 @@ export function Tabs<T extends string>({
|
|
|
620
545
|
type="button"
|
|
621
546
|
disabled={busy}
|
|
622
547
|
onClick={() => requestRemove(tab.id)}
|
|
623
|
-
className=
|
|
624
|
-
"absolute inset-y-0 end-1 my-auto",
|
|
625
|
-
// On a wrapped strip's filled chip the quiet grey would vanish into
|
|
626
|
-
// the brand fill below `md`.
|
|
627
|
-
wrap && "text-brand-contrast md:text-placeholder",
|
|
628
|
-
)}
|
|
548
|
+
className="absolute inset-y-0 end-1 my-auto"
|
|
629
549
|
>
|
|
630
550
|
<X />
|
|
631
551
|
</IconButton>
|
|
@@ -654,7 +574,7 @@ export function Tabs<T extends string>({
|
|
|
654
574
|
{text.remove(nameOf(activeTab))}
|
|
655
575
|
</button>
|
|
656
576
|
) : null;
|
|
657
|
-
if (!onAdd && overflowCue && !
|
|
577
|
+
if (!onAdd && overflowCue && !vertical) {
|
|
658
578
|
// The caret needs a row to sit in beside the strip, and `className` goes there — it
|
|
659
579
|
// is the box a caller's margin or width is meant for, as with an add button. The box
|
|
660
580
|
// is there whether or not the strip overflows right now, so a resize never moves
|
|
@@ -692,37 +612,26 @@ export function Tabs<T extends string>({
|
|
|
692
612
|
);
|
|
693
613
|
}
|
|
694
614
|
return (
|
|
695
|
-
<div
|
|
696
|
-
className={cn(
|
|
697
|
-
wrap ? "flex flex-wrap items-end gap-1.5 md:flex-nowrap md:gap-0" : "flex items-end",
|
|
698
|
-
className,
|
|
699
|
-
)}
|
|
700
|
-
>
|
|
615
|
+
<div className={cn("flex items-end", className)}>
|
|
701
616
|
{tablist}
|
|
702
617
|
{removeButton}
|
|
703
618
|
{cueButton}
|
|
704
619
|
{/* Outside the tablist: an action, not a tab — and a tablist may own only
|
|
705
620
|
tabs. The rule under the strip carries on beneath it. */}
|
|
706
621
|
<div
|
|
707
|
-
className=
|
|
708
|
-
"flex flex-1 items-center",
|
|
709
|
-
wrap
|
|
710
|
-
? "md:self-stretch md:border-b md:border-subtle"
|
|
711
|
-
: "self-stretch border-b border-subtle",
|
|
712
|
-
)}
|
|
622
|
+
className="flex flex-1 items-center self-stretch border-b border-subtle"
|
|
713
623
|
>
|
|
714
624
|
<button
|
|
715
625
|
type="button"
|
|
716
626
|
onClick={onAdd}
|
|
717
627
|
disabled={busy}
|
|
718
|
-
className={cn(TAB_ADD_CLASSES,
|
|
628
|
+
className={cn(TAB_ADD_CLASSES, TAB_ADD_PHONE_CLASSES)}
|
|
719
629
|
>
|
|
720
630
|
<Plus aria-hidden />
|
|
721
631
|
{/* Below md a scrolling strip keeps the room for tabs: the label is visually
|
|
722
632
|
hidden and the "+" carries it as its name. Beside "+ Add loop" a 390px strip
|
|
723
|
-
showed the open tab and a sliver of the next (showcase audit).
|
|
724
|
-
|
|
725
|
-
<span className={wrap ? undefined : "max-md:sr-only"}>{addLabel ?? text.add}</span>
|
|
633
|
+
showed the open tab and a sliver of the next (showcase audit). */}
|
|
634
|
+
<span className="max-md:sr-only">{addLabel ?? text.add}</span>
|
|
726
635
|
</button>
|
|
727
636
|
</div>
|
|
728
637
|
</div>
|
|
@@ -170,8 +170,8 @@ export interface TranslationLocaleTabsProps {
|
|
|
170
170
|
|
|
171
171
|
/**
|
|
172
172
|
* One tab per locale with its approved/total, one scrolling row on a phone with the
|
|
173
|
-
* strip's caret saying it goes on (`overflowCue
|
|
174
|
-
*
|
|
173
|
+
* strip's caret saying it goes on (`overflowCue`). Nothing for a single locale:
|
|
174
|
+
* a strip with one tab is a heading that looks clickable.
|
|
175
175
|
*/
|
|
176
176
|
export function TranslationLocaleTabs({ locales, active, onChange, className, labels: labelsProp }: TranslationLocaleTabsProps) {
|
|
177
177
|
const labels = useKitLabels("translationReview", DEFAULT_TRANSLATION_REVIEW_LABELS, labelsProp);
|
|
@@ -7,8 +7,6 @@ import type { FeedbackMenuLabels } from "./feedback-menu";
|
|
|
7
7
|
export const DEFAULT_FEEDBACK_MENU_LABELS: FeedbackMenuLabels = {
|
|
8
8
|
trigger: "Send feedback",
|
|
9
9
|
myFeedback: "My feedback",
|
|
10
|
-
viewFeedback: "View feedback",
|
|
11
|
-
allFeedback: "All feedback",
|
|
12
10
|
discussion: "Feedback discussion",
|
|
13
11
|
inbox: "Feedback inbox",
|
|
14
12
|
};
|
|
@@ -28,12 +28,6 @@ export interface FeedbackMenuLabels {
|
|
|
28
28
|
/** 0.40: the admin's link to the triage list, {@link FeedbackMenuProps.inboxHref}
|
|
29
29
|
* ("View feedback" before). de-CH "Feedback-Eingang". */
|
|
30
30
|
inbox: string;
|
|
31
|
-
/** @deprecated 0.40 — use {@link inbox}; removed in 0.41. Unused: the inbox row reads
|
|
32
|
-
* `inbox` (feedback §10.6). */
|
|
33
|
-
viewFeedback?: string;
|
|
34
|
-
/** @deprecated 0.40 — use {@link discussion}; removed in 0.41. Unused: the public row
|
|
35
|
-
* reads `discussion` (feedback §10.6). */
|
|
36
|
-
allFeedback?: string;
|
|
37
31
|
}
|
|
38
32
|
|
|
39
33
|
// Defined in ./feedback-menu-labels, which holds no component code (0.34, KS U8).
|
package/src/i18n/defaults.ts
CHANGED
|
@@ -98,6 +98,8 @@ import { DEFAULT_DEVICE_RESET_LABELS } from "../settings/device-reset-setting-la
|
|
|
98
98
|
import { DEFAULT_ROW_ACTIONS_LABELS } from "../components/row-actions-labels";
|
|
99
99
|
import { DEFAULT_APP_SHELL_MORE_LABELS } from "../shell/app-shell-labels";
|
|
100
100
|
import { DEFAULT_ACCOUNT_STATE_LABELS } from "../components/account-chips-labels";
|
|
101
|
+
import { DEFAULT_ADMIN_AREA_LABELS } from "../admin/admin-area-labels";
|
|
102
|
+
import { DEFAULT_TOP_BAR_PARTS_LABELS } from "../shell/top-bar-parts-labels";
|
|
101
103
|
import { DEFAULT_SHARE_CARD_LABELS } from "../components/share-card-labels";
|
|
102
104
|
import { DEFAULT_REAUTH_DIALOG_LABELS } from "../components/reauth-dialog-labels";
|
|
103
105
|
import { DEFAULT_SERVER_WAKE_LABELS } from "../components/server-wake-labels";
|
|
@@ -256,4 +258,6 @@ export const DEFAULT_UI_KIT_LABELS: UiKitLabels = {
|
|
|
256
258
|
signChip: DEFAULT_SIGN_CHIP_LABELS,
|
|
257
259
|
columnMapper: DEFAULT_COLUMN_MAPPER_LABELS,
|
|
258
260
|
notifications: DEFAULT_NOTIFICATIONS_LABELS,
|
|
261
|
+
adminArea: DEFAULT_ADMIN_AREA_LABELS,
|
|
262
|
+
topBarParts: DEFAULT_TOP_BAR_PARTS_LABELS,
|
|
259
263
|
};
|
package/src/i18n/german.ts
CHANGED
|
@@ -121,8 +121,6 @@ export function germanLabels(numberLocale: string): UiKitLabels {
|
|
|
121
121
|
feedbackMenu: {
|
|
122
122
|
trigger: "Feedback senden",
|
|
123
123
|
myFeedback: "Mein Feedback",
|
|
124
|
-
viewFeedback: "Feedback ansehen",
|
|
125
|
-
allFeedback: "Alle Rückmeldungen",
|
|
126
124
|
discussion: "Feedback-Diskussion",
|
|
127
125
|
inbox: "Feedback-Eingang",
|
|
128
126
|
},
|
|
@@ -1731,6 +1729,12 @@ export function germanLabels(numberLocale: string): UiKitLabels {
|
|
|
1731
1729
|
"Ihre Zahlung wird verarbeitet. Ihr Tarif beginnt, sobald sie bestätigt ist; diese Seite aktualisiert sich von selbst.",
|
|
1732
1730
|
choosePlan: "Tarif wählen",
|
|
1733
1731
|
updatePayment: "Zahlungsmethode aktualisieren",
|
|
1732
|
+
// 0.42 (§16.7 A): for an admin who isn't the buyer. "Das Admin-Konto", which gives the
|
|
1733
|
+
// reader no gender.
|
|
1734
|
+
paymentFailedAskBuyer: (buyer) =>
|
|
1735
|
+
buyer
|
|
1736
|
+
? `Die Zahlung ist fehlgeschlagen. ${buyer} kann die Zahlungsmethode aktualisieren.`
|
|
1737
|
+
: "Die Zahlung ist fehlgeschlagen. Die Zahlungsmethode kann über das Admin-Konto aktualisiert werden, mit dem das Abonnement abgeschlossen wurde.",
|
|
1734
1738
|
checkAgain: "Erneut prüfen",
|
|
1735
1739
|
lockReason: "Ihr Tarif ist abgelaufen. Wählen Sie einen Tarif, um wieder Änderungen vorzunehmen.",
|
|
1736
1740
|
// As `characterCount.limitReached` ("Zeichenlimit erreicht").
|
|
@@ -1765,6 +1769,20 @@ export function germanLabels(numberLocale: string): UiKitLabels {
|
|
|
1765
1769
|
switchCredited: "Gutschrift auf die nächsten Belastungen",
|
|
1766
1770
|
switchNextCharge: (date) => `Nächste Belastung am ${date}`,
|
|
1767
1771
|
switchConfirm: "Tarif ändern",
|
|
1772
|
+
// 0.42 (§16): the portal for the buyer only, the in-app cancel, the grant warning.
|
|
1773
|
+
buyerHolds: (buyer) =>
|
|
1774
|
+
buyer
|
|
1775
|
+
? `Zahlungsmethode und Rechnungen liegen bei ${buyer}: Das Abonnement wurde über dieses Konto abgeschlossen.`
|
|
1776
|
+
: "Zahlungsmethode und Rechnungen liegen beim Admin-Konto, mit dem das Abonnement abgeschlossen wurde.",
|
|
1777
|
+
cancelConfirmTitle: "Abonnement kündigen",
|
|
1778
|
+
cancelConfirmBody: (date) => `Ihr Abonnement endet am ${date}. Bis dahin funktioniert alles wie bisher.`,
|
|
1779
|
+
// §312k BGB: the confirmation button says exactly this.
|
|
1780
|
+
cancelConfirmAction: "Jetzt kündigen",
|
|
1781
|
+
keepSubscription: "Abonnement behalten",
|
|
1782
|
+
grantWarningTitle: "Ihr kostenloser Zugang läuft weiter",
|
|
1783
|
+
grantWarningBody:
|
|
1784
|
+
"Ihr kostenloser Zugang hat kein Enddatum. Solange er läuft, ändert ein Kauf Ihren Tarif nicht: Sie würden für einen Tarif bezahlen, der nicht gilt.",
|
|
1785
|
+
grantWarningAction: "Trotzdem kaufen",
|
|
1768
1786
|
waitingChanges: (count) =>
|
|
1769
1787
|
count === 1
|
|
1770
1788
|
? `${n(count)} Änderung wartet auf einen Tarif`
|
|
@@ -1841,5 +1859,77 @@ export function germanLabels(numberLocale: string): UiKitLabels {
|
|
|
1841
1859
|
more: "Mehr",
|
|
1842
1860
|
moreTitle: "Weitere Seiten",
|
|
1843
1861
|
},
|
|
1862
|
+
// 0.42.0 — docs/admin-harmonization.md §3.1: the admin area's shared words. "Verwaltung"
|
|
1863
|
+
// as settings §5 names the page; "mit Administratorrechten" rather than "für
|
|
1864
|
+
// Administratoren", which would give the reader a gender (as `transferOwnership`).
|
|
1865
|
+
adminArea: {
|
|
1866
|
+
title: "Verwaltung",
|
|
1867
|
+
waiting: (count) => `${n(count)} offen`,
|
|
1868
|
+
forbiddenTitle: "Nur mit Administratorrechten",
|
|
1869
|
+
forbiddenBody: (appName) => `Hier wird ${appName} verwaltet. Ihr Konto kann diese Seite nicht öffnen.`,
|
|
1870
|
+
forbiddenHome: "Zur Startseite",
|
|
1871
|
+
forbiddenReviewer: "Übersetzungen prüfen",
|
|
1872
|
+
sections: {
|
|
1873
|
+
overview: { title: "Übersicht", help: "Was gerade wartet, auf einen Blick." },
|
|
1874
|
+
users: { title: "Benutzer", help: "Wer ein Konto hat und was jede Person darf." },
|
|
1875
|
+
invitations: { title: "Einladungen", help: "Die Links, mit denen neue Personen dazukommen." },
|
|
1876
|
+
billing: { title: "Abrechnung", help: "Tarif, Zahlung und Rechnungen." },
|
|
1877
|
+
activity: { title: "Aktivität", help: "Was in der Verwaltung getan wurde, das Neueste zuerst." },
|
|
1878
|
+
},
|
|
1879
|
+
tiles: {
|
|
1880
|
+
feedbackWaiting: "Zu sichten",
|
|
1881
|
+
deletionRequests: "Löschanfragen",
|
|
1882
|
+
invitationsPending: "Offene Einladungen",
|
|
1883
|
+
users: "Benutzer",
|
|
1884
|
+
usersNew: (count) => `${n(count)} neu in 7 Tagen`,
|
|
1885
|
+
},
|
|
1886
|
+
tools: "Werkzeuge",
|
|
1887
|
+
},
|
|
1888
|
+
// 0.42.0 — docs/top-bar-harmonization.md §3.1: the top bar's shared parts. keksdose's
|
|
1889
|
+
// reviewed sync words where they are not about its budgets; "Tarif" as `billing`.
|
|
1890
|
+
topBarParts: {
|
|
1891
|
+
tours: {
|
|
1892
|
+
menu: "Geführte Touren",
|
|
1893
|
+
newDot: "Neue Touren",
|
|
1894
|
+
thisPage: "Auf dieser Seite",
|
|
1895
|
+
newTours: "Neue Touren",
|
|
1896
|
+
allTours: "Alle Touren…",
|
|
1897
|
+
badgeNew: "Neu",
|
|
1898
|
+
completed: "Abgeschlossen",
|
|
1899
|
+
},
|
|
1900
|
+
sync: {
|
|
1901
|
+
blocked: (count) =>
|
|
1902
|
+
count === 1
|
|
1903
|
+
? `${n(count)} Änderung kann von diesem Gerät nicht gesendet werden`
|
|
1904
|
+
: `${n(count)} Änderungen können von diesem Gerät nicht gesendet werden`,
|
|
1905
|
+
offline: "Offline – Änderungen werden auf diesem Gerät gespeichert und bei erneuter Verbindung synchronisiert",
|
|
1906
|
+
refused: "Der Server hat den letzten Abgleich abgelehnt",
|
|
1907
|
+
syncing: "Wird synchronisiert…",
|
|
1908
|
+
pending: (count) =>
|
|
1909
|
+
count === 1
|
|
1910
|
+
? `${n(count)} Änderung wartet auf Synchronisierung`
|
|
1911
|
+
: `${n(count)} Änderungen warten auf Synchronisierung`,
|
|
1912
|
+
syncedAt: (time) => `Synchronisiert um ${time}`,
|
|
1913
|
+
idle: "Aktuell",
|
|
1914
|
+
syncHint: "Tippen, um jetzt zu synchronisieren",
|
|
1915
|
+
offlineHint: "offline gibt es nichts zu synchronisieren",
|
|
1916
|
+
withHint: (state, hint) => `${state} – ${hint}`,
|
|
1917
|
+
scoped: (scope, state) => `${scope}: ${state}`,
|
|
1918
|
+
offlineShort: "Offline",
|
|
1919
|
+
syncingShort: "Sync läuft…",
|
|
1920
|
+
waitingShort: (count) => `${n(count)} ausstehend`,
|
|
1921
|
+
refusedShort: "Nicht synchronisiert",
|
|
1922
|
+
offlineUnsaved: "Offline – Änderungen können erst nach erneuter Verbindung gespeichert werden",
|
|
1923
|
+
saving: "Wird gespeichert…",
|
|
1924
|
+
},
|
|
1925
|
+
dev: {
|
|
1926
|
+
roleHeading: "Dev · Rolle",
|
|
1927
|
+
switchPlan: "Tarif wechseln",
|
|
1928
|
+
plan: (value) => `Tarif: ${value}`,
|
|
1929
|
+
planHeading: "Dev · Tarif",
|
|
1930
|
+
backTo: (role) => `Zurück zu ${role}`,
|
|
1931
|
+
billingOff: "Die Abrechnung ist lokal aus: Tarife ändern nichts",
|
|
1932
|
+
},
|
|
1933
|
+
},
|
|
1844
1934
|
};
|
|
1845
1935
|
}
|
package/src/i18n/kit-labels.tsx
CHANGED
|
@@ -118,6 +118,8 @@ import type { PhoneInputLabels } from "../components/phone-input";
|
|
|
118
118
|
import type { SignChipLabels } from "../components/sign-chip";
|
|
119
119
|
import type { ColumnMapperLabels } from "../components/column-mapper";
|
|
120
120
|
import type { NotificationsLabels } from "../notifications/notifications-labels";
|
|
121
|
+
import type { AdminAreaLabels } from "../admin/admin-area-labels";
|
|
122
|
+
import type { TopBarPartsLabels } from "../shell/top-bar-parts-labels";
|
|
121
123
|
|
|
122
124
|
/**
|
|
123
125
|
* EVERY string the kit renders, as one typed tree — and an optional provider that
|
|
@@ -475,6 +477,13 @@ export interface UiKitLabels {
|
|
|
475
477
|
* device's push, the device list, and the unsubscribe page
|
|
476
478
|
* (docs/notifications-harmonization.md §4.2). */
|
|
477
479
|
notifications: NotificationsLabels;
|
|
480
|
+
/** 0.42.0: the admin area's shared words — the account menu's "Administration" row, the
|
|
481
|
+
* 403 page, the shared sections, the overview's tiles and the Tools list
|
|
482
|
+
* (docs/admin-harmonization.md §3.1). */
|
|
483
|
+
adminArea: AdminAreaLabels;
|
|
484
|
+
/** 0.42.0: the top bar's shared parts — `TourMenu`, `SyncStatusIndicator`, `DevSwitchers`
|
|
485
|
+
* (docs/top-bar-harmonization.md §3.1). */
|
|
486
|
+
topBarParts: TopBarPartsLabels;
|
|
478
487
|
}
|
|
479
488
|
|
|
480
489
|
/**
|
package/src/i18n/locales/en.ts
CHANGED
|
@@ -216,6 +216,25 @@ export function uiKitLabelsEn(numberLocale = "en-US"): UiKitLabels {
|
|
|
216
216
|
...d.settings,
|
|
217
217
|
matchCount: (count) => (count === 1 ? "1 match" : `${n(count)} matches`),
|
|
218
218
|
},
|
|
219
|
+
// 0.42.0: the admin area's two counts (docs/admin-harmonization.md §3.1).
|
|
220
|
+
adminArea: {
|
|
221
|
+
...d.adminArea,
|
|
222
|
+
waiting: (count) => `${n(count)} waiting`,
|
|
223
|
+
tiles: { ...d.adminArea.tiles, usersNew: (count) => `${n(count)} new in 7 days` },
|
|
224
|
+
},
|
|
225
|
+
// 0.42.0: the top bar's three counts (docs/top-bar-harmonization.md §3.1).
|
|
226
|
+
topBarParts: {
|
|
227
|
+
...d.topBarParts,
|
|
228
|
+
sync: {
|
|
229
|
+
...d.topBarParts.sync,
|
|
230
|
+
blocked: (count) =>
|
|
231
|
+
count === 1
|
|
232
|
+
? "1 change cannot be sent from this device"
|
|
233
|
+
: `${n(count)} changes cannot be sent from this device`,
|
|
234
|
+
pending: (count) => (count === 1 ? "1 change waiting to sync" : `${n(count)} changes waiting to sync`),
|
|
235
|
+
waitingShort: (count) => `${n(count)} waiting`,
|
|
236
|
+
},
|
|
237
|
+
},
|
|
219
238
|
demo: {
|
|
220
239
|
...d.demo,
|
|
221
240
|
rateLimited: (minutes) =>
|
package/src/i18n/locales/es.ts
CHANGED
|
@@ -112,8 +112,6 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
|
|
|
112
112
|
feedbackMenu: {
|
|
113
113
|
trigger: "Enviar comentarios",
|
|
114
114
|
myFeedback: "Mis comentarios",
|
|
115
|
-
viewFeedback: "Ver comentarios",
|
|
116
|
-
allFeedback: "Todos los comentarios",
|
|
117
115
|
discussion: "Debate de comentarios",
|
|
118
116
|
inbox: "Comentarios recibidos",
|
|
119
117
|
},
|
|
@@ -1685,6 +1683,11 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
|
|
|
1685
1683
|
"Su pago se está procesando. Su plan empieza en cuanto se confirme; esta página se actualiza sola.",
|
|
1686
1684
|
choosePlan: "Elegir un plan",
|
|
1687
1685
|
updatePayment: "Actualizar el método de pago",
|
|
1686
|
+
// 0.42 (§16.7 A): for an admin who isn't the buyer.
|
|
1687
|
+
paymentFailedAskBuyer: (buyer) =>
|
|
1688
|
+
buyer
|
|
1689
|
+
? `El pago no se ha completado. ${buyer} puede actualizar el método de pago.`
|
|
1690
|
+
: "El pago no se ha completado. El administrador que contrató la suscripción puede actualizar el método de pago.",
|
|
1688
1691
|
checkAgain: "Volver a comprobar",
|
|
1689
1692
|
lockReason: "Su plan ha terminado. Elija un plan para volver a hacer cambios.",
|
|
1690
1693
|
// As `characterCount.limitReached` ("Límite de caracteres alcanzado").
|
|
@@ -1715,6 +1718,19 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
|
|
|
1715
1718
|
switchCredited: "Abonado a sus próximos cargos",
|
|
1716
1719
|
switchNextCharge: (date) => `Próximo cargo el ${date}`,
|
|
1717
1720
|
switchConfirm: "Cambiar de plan",
|
|
1721
|
+
// 0.42 (§16): the portal for the buyer only, the in-app cancel, the grant warning.
|
|
1722
|
+
buyerHolds: (buyer) =>
|
|
1723
|
+
buyer
|
|
1724
|
+
? `El método de pago y las facturas los gestiona ${buyer}, que contrató la suscripción.`
|
|
1725
|
+
: "El método de pago y las facturas los gestiona el administrador que contrató la suscripción.",
|
|
1726
|
+
cancelConfirmTitle: "Cancelar la suscripción",
|
|
1727
|
+
cancelConfirmBody: (date) => `Su suscripción termina el ${date}. Hasta entonces, todo funciona como antes.`,
|
|
1728
|
+
cancelConfirmAction: "Cancelar ahora la suscripción",
|
|
1729
|
+
keepSubscription: "Mantener la suscripción",
|
|
1730
|
+
grantWarningTitle: "Su acceso gratuito continúa",
|
|
1731
|
+
grantWarningBody:
|
|
1732
|
+
"Su acceso gratuito no tiene fecha de fin. Mientras dure, una compra no cambia su plan: pagaría por un plan que no se aplica.",
|
|
1733
|
+
grantWarningAction: "Comprar de todos modos",
|
|
1718
1734
|
waitingChanges: (count) => `${n(count)} ${plural(count, "cambio", "cambios")} a la espera de un plan`,
|
|
1719
1735
|
// "Descartar", as `wizard.cancelConfirmLabel`.
|
|
1720
1736
|
discardWaiting: "Descartar los cambios en espera",
|
|
@@ -1783,6 +1799,74 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
|
|
|
1783
1799
|
more: "Más",
|
|
1784
1800
|
moreTitle: "Más páginas",
|
|
1785
1801
|
},
|
|
1802
|
+
// 0.42.0 — docs/admin-harmonization.md §3.1: the admin area's shared words. "Usted",
|
|
1803
|
+
// as the rest of the catalogue.
|
|
1804
|
+
adminArea: {
|
|
1805
|
+
title: "Administración",
|
|
1806
|
+
waiting: (count) => `${n(count)} ${plural(count, "pendiente", "pendientes")}`,
|
|
1807
|
+
forbiddenTitle: "Solo para administradores",
|
|
1808
|
+
forbiddenBody: (appName) =>
|
|
1809
|
+
`Aquí es donde los administradores gestionan ${appName}. Su cuenta no puede abrir esta página.`,
|
|
1810
|
+
forbiddenHome: "Ir a la página de inicio",
|
|
1811
|
+
forbiddenReviewer: "Revisar traducciones",
|
|
1812
|
+
sections: {
|
|
1813
|
+
overview: { title: "Resumen", help: "Lo que está pendiente, de un vistazo." },
|
|
1814
|
+
users: { title: "Usuarios", help: "Quién tiene una cuenta y qué puede hacer cada uno." },
|
|
1815
|
+
invitations: { title: "Invitaciones", help: "Los enlaces con los que entra una persona nueva." },
|
|
1816
|
+
billing: { title: "Facturación", help: "El plan, el pago y las facturas." },
|
|
1817
|
+
activity: { title: "Actividad", help: "Lo que hicieron los administradores, lo más reciente primero." },
|
|
1818
|
+
},
|
|
1819
|
+
tiles: {
|
|
1820
|
+
feedbackWaiting: "Por clasificar",
|
|
1821
|
+
deletionRequests: "Solicitudes de eliminación",
|
|
1822
|
+
invitationsPending: "Invitaciones pendientes",
|
|
1823
|
+
users: "Usuarios",
|
|
1824
|
+
usersNew: (count) => `${n(count)} ${plural(count, "nuevo", "nuevos")} en 7 días`,
|
|
1825
|
+
},
|
|
1826
|
+
tools: "Herramientas",
|
|
1827
|
+
},
|
|
1828
|
+
// 0.42.0 — docs/top-bar-harmonization.md §3.1: the top bar's shared parts; "plan" as
|
|
1829
|
+
// `billing`, "usted" as the rest of the catalogue.
|
|
1830
|
+
topBarParts: {
|
|
1831
|
+
tours: {
|
|
1832
|
+
menu: "Visitas guiadas",
|
|
1833
|
+
newDot: "Visitas nuevas",
|
|
1834
|
+
thisPage: "En esta página",
|
|
1835
|
+
newTours: "Visitas nuevas",
|
|
1836
|
+
allTours: "Todas las visitas…",
|
|
1837
|
+
badgeNew: "Nuevo",
|
|
1838
|
+
completed: "Completada",
|
|
1839
|
+
},
|
|
1840
|
+
sync: {
|
|
1841
|
+
blocked: (count) =>
|
|
1842
|
+
`${n(count)} ${plural(count, "cambio no se puede enviar", "cambios no se pueden enviar")} desde este dispositivo`,
|
|
1843
|
+
offline: "Sin conexión: los cambios se guardan en este dispositivo y se sincronizarán al volver a conectarse",
|
|
1844
|
+
refused: "El servidor rechazó la última sincronización",
|
|
1845
|
+
syncing: "Sincronizando…",
|
|
1846
|
+
pending: (count) =>
|
|
1847
|
+
`${n(count)} ${plural(count, "cambio", "cambios")} a la espera de sincronizarse`,
|
|
1848
|
+
syncedAt: (time) => `Sincronizado a las ${time}`,
|
|
1849
|
+
idle: "Al día",
|
|
1850
|
+
syncHint: "Toque para sincronizar ahora",
|
|
1851
|
+
offlineHint: "no hay nada que sincronizar sin conexión",
|
|
1852
|
+
withHint: (state, hint) => `${state} — ${hint}`,
|
|
1853
|
+
scoped: (scope, state) => `${scope}: ${state}`,
|
|
1854
|
+
offlineShort: "Sin conexión",
|
|
1855
|
+
syncingShort: "Sincronizando…",
|
|
1856
|
+
waitingShort: (count) => `${n(count)} en espera`,
|
|
1857
|
+
refusedShort: "Sin sincronizar",
|
|
1858
|
+
offlineUnsaved: "Sin conexión: los cambios no se pueden guardar hasta que vuelva a conectarse",
|
|
1859
|
+
saving: "Guardando…",
|
|
1860
|
+
},
|
|
1861
|
+
dev: {
|
|
1862
|
+
roleHeading: "Dev · rol",
|
|
1863
|
+
switchPlan: "Cambiar de plan",
|
|
1864
|
+
plan: (value) => `Plan: ${value}`,
|
|
1865
|
+
planHeading: "Dev · plan",
|
|
1866
|
+
backTo: (role) => `Volver a ${role}`,
|
|
1867
|
+
billingOff: "La facturación está desactivada en local: los planes no cambian nada",
|
|
1868
|
+
},
|
|
1869
|
+
},
|
|
1786
1870
|
};
|
|
1787
1871
|
}
|
|
1788
1872
|
|