@eifi1/ui-kit 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/README.md +60 -6
  2. package/dist/chart.d.ts +4 -1
  3. package/dist/components/amount-input.d.ts +4 -1
  4. package/dist/components/button-group.d.ts +4 -1
  5. package/dist/components/calculator.d.ts +4 -1
  6. package/dist/components/copy-button.d.ts +4 -1
  7. package/dist/components/facing-pair.d.ts +4 -1
  8. package/dist/components/file-button.d.ts +4 -1
  9. package/dist/components/file-dropzone.d.ts +4 -1
  10. package/dist/components/floating-panel.d.ts +4 -1
  11. package/dist/components/floating-panel.js +15 -1
  12. package/dist/components/floating-panel.js.map +1 -1
  13. package/dist/components/form-actions.d.ts +4 -1
  14. package/dist/components/legal.d.ts +84 -0
  15. package/dist/components/legal.js +55 -0
  16. package/dist/components/legal.js.map +1 -0
  17. package/dist/components/money-field.d.ts +4 -1
  18. package/dist/components/number-field.d.ts +4 -1
  19. package/dist/components/number-input.d.ts +4 -1
  20. package/dist/components/numpad-sheet.d.ts +4 -1
  21. package/dist/components/series-chart.d.ts +4 -1
  22. package/dist/components/server-wake.d.ts +4 -2
  23. package/dist/components/server-wake.js +23 -2
  24. package/dist/components/server-wake.js.map +1 -1
  25. package/dist/components/settings-fields.d.ts +4 -1
  26. package/dist/components/share-card.d.ts +4 -1
  27. package/dist/components/text-link.d.ts +4 -1
  28. package/dist/components/time-input.d.ts +4 -1
  29. package/dist/components/translation-review-editor.d.ts +56 -0
  30. package/dist/components/translation-review-editor.js +159 -0
  31. package/dist/components/translation-review-editor.js.map +1 -0
  32. package/dist/components/translation-review-labels.d.ts +92 -0
  33. package/dist/components/translation-review-labels.js +67 -0
  34. package/dist/components/translation-review-labels.js.map +1 -0
  35. package/dist/components/translation-review-parts.d.ts +97 -0
  36. package/dist/components/translation-review-parts.js +163 -0
  37. package/dist/components/translation-review-parts.js.map +1 -0
  38. package/dist/components/translation-review.d.ts +94 -0
  39. package/dist/components/translation-review.js +344 -0
  40. package/dist/components/translation-review.js.map +1 -0
  41. package/dist/components/ui.d.ts +4 -1
  42. package/dist/hooks/use-file-drop.d.ts +4 -1
  43. package/dist/i18n/defaults.d.ts +4 -1
  44. package/dist/i18n/defaults.js +5 -1
  45. package/dist/i18n/defaults.js.map +1 -1
  46. package/dist/i18n/german.d.ts +4 -1
  47. package/dist/i18n/german.js +51 -0
  48. package/dist/i18n/german.js.map +1 -1
  49. package/dist/i18n/kit-labels.d.ts +4 -1
  50. package/dist/i18n/kit-labels.js.map +1 -1
  51. package/dist/i18n/languages.d.ts +243 -0
  52. package/dist/i18n/languages.js +70 -0
  53. package/dist/i18n/languages.js.map +1 -0
  54. package/dist/i18n/locales/de-CH.d.ts +4 -1
  55. package/dist/i18n/locales/en.d.ts +4 -1
  56. package/dist/i18n/locales/en.js +8 -0
  57. package/dist/i18n/locales/en.js.map +1 -1
  58. package/dist/i18n/locales/es.d.ts +4 -1
  59. package/dist/i18n/locales/es.js +83 -33
  60. package/dist/i18n/locales/es.js.map +1 -1
  61. package/dist/i18n/locales/fr.d.ts +4 -1
  62. package/dist/i18n/locales/fr.js +50 -0
  63. package/dist/i18n/locales/fr.js.map +1 -1
  64. package/dist/i18n/locales/hu.d.ts +4 -1
  65. package/dist/i18n/locales/hu.js +51 -0
  66. package/dist/i18n/locales/hu.js.map +1 -1
  67. package/dist/i18n/locales/it.d.ts +4 -1
  68. package/dist/i18n/locales/it.js +90 -40
  69. package/dist/i18n/locales/it.js.map +1 -1
  70. package/dist/i18n/locales/zh.d.ts +4 -1
  71. package/dist/i18n/locales/zh.js +51 -0
  72. package/dist/i18n/locales/zh.js.map +1 -1
  73. package/dist/i18n/review.d.ts +102 -0
  74. package/dist/i18n/review.js +158 -0
  75. package/dist/i18n/review.js.map +1 -0
  76. package/dist/index.d.ts +9 -1
  77. package/dist/index.js +64 -0
  78. package/dist/index.js.map +1 -1
  79. package/dist/{kit-labels-CPbsjlXr.d.ts → kit-labels-D1J2_jyD.d.ts} +7 -0
  80. package/dist/lib/floating-stack.d.ts +31 -0
  81. package/dist/lib/floating-stack.js +42 -0
  82. package/dist/lib/floating-stack.js.map +1 -0
  83. package/dist/lib/server-wake.d.ts +24 -8
  84. package/dist/lib/server-wake.js +6 -5
  85. package/dist/lib/server-wake.js.map +1 -1
  86. package/dist/lib/translation-review.d.ts +232 -0
  87. package/dist/lib/translation-review.js +194 -0
  88. package/dist/lib/translation-review.js.map +1 -0
  89. package/dist/rhf/fields.d.ts +4 -1
  90. package/dist/rhf/form.d.ts +4 -1
  91. package/dist/rhf.d.ts +4 -1
  92. package/dist/shell/app-shell.d.ts +4 -1
  93. package/dist/shell/top-bar-brand.d.ts +4 -1
  94. package/dist/shell.d.ts +4 -1
  95. package/dist/wizard/stepper-nav.d.ts +4 -1
  96. package/dist/wizard.d.ts +4 -1
  97. package/package.json +1 -1
  98. package/src/components/floating-panel.tsx +19 -1
  99. package/src/components/legal.tsx +159 -0
  100. package/src/components/server-wake.tsx +37 -5
  101. package/src/components/translation-review-editor.tsx +261 -0
  102. package/src/components/translation-review-labels.ts +152 -0
  103. package/src/components/translation-review-parts.tsx +269 -0
  104. package/src/components/translation-review.tsx +502 -0
  105. package/src/i18n/defaults.ts +4 -0
  106. package/src/i18n/german.ts +52 -0
  107. package/src/i18n/kit-labels.tsx +7 -0
  108. package/src/i18n/languages.ts +285 -0
  109. package/src/i18n/locales/en.ts +8 -0
  110. package/src/i18n/locales/es.ts +84 -33
  111. package/src/i18n/locales/fr.ts +51 -0
  112. package/src/i18n/locales/hu.ts +52 -0
  113. package/src/i18n/locales/it.ts +91 -40
  114. package/src/i18n/locales/zh.ts +52 -0
  115. package/src/i18n/review.ts +193 -0
  116. package/src/index.ts +63 -0
  117. package/src/lib/floating-stack.ts +66 -0
  118. package/src/lib/server-wake.ts +34 -13
  119. package/src/lib/translation-review.ts +465 -0
@@ -637,6 +637,58 @@ export function uiKitLabelsHu(numberLocale = "hu-HU"): UiKitLabels {
637
637
  waking: (appName) =>
638
638
  `A szerver elalszik, ha senki sem használja ${appName ? `a(z) ${appName} alkalmazást` : "az alkalmazást"}, ezért egy szünet utáni első kérésnek újra el kell indítania. Ez eltarthat egy ideig – semmi sem vész el, az oldal magától betöltődik.`,
639
639
  },
640
+ legal: {
641
+ navLabel: "Jogi információk",
642
+ },
643
+ translationReview: {
644
+ statusMissing: "Hiányzik",
645
+ statusUnreviewed: "Nincs ellenőrizve",
646
+ statusChanged: "Ellenőrzés óta módosult",
647
+ statusNeedsChange: "Módosítandó",
648
+ statusApproved: "Jóváhagyva",
649
+ statusFilter: "Állapot",
650
+ all: "Mind",
651
+ filterCount: (label, count) => `${label} · ${n(count)}`,
652
+ source: "Szövegek",
653
+ allSources: "Minden szöveg",
654
+ namespace: "Terület",
655
+ allNamespaces: "Minden terület",
656
+ search: "Keresés kulcsokban és szövegekben",
657
+ placeholdersOnly: (count) => `Csak a helyőrző-problémák (${n(count)})`,
658
+ placeholderChip: "Helyőrzők",
659
+ key: "Kulcs",
660
+ statusColumn: "Állapot",
661
+ empty: "Egy szöveg sem felel meg ezeknek a szűrőknek.",
662
+ missingText: "Ezen a nyelven hiányzik",
663
+ progress: (approved, total) => `${n(approved)} / ${n(total)} jóváhagyva`,
664
+ localeProgress: (approved, total) => `${n(approved)}/${n(total)}`,
665
+ locales: "Nyelvek",
666
+ approve: "Jóváhagyás",
667
+ flag: "Módosítandó",
668
+ suggest: "Fordítás javaslata",
669
+ reset: "Megjelölés ellenőrizetlenként",
670
+ cancel: "Mégse",
671
+ approveSelected: "Kijelöltek jóváhagyása",
672
+ resetSelected: "Kijelöltek megjelölése ellenőrizetlenként",
673
+ selectShown: "Az összes megjelenített kijelölése",
674
+ changedSince: "Ez a szöveg az ellenőrzés után megváltozott. Kérjük, olvassa el újra.",
675
+ reviewedWording: "Megfogalmazás az ellenőrzéskor",
676
+ reviewedReference: "Referencia az ellenőrzéskor",
677
+ placeholderMismatch: (reference, text) =>
678
+ `A helyőrzők eltérnek a referenciától – referencia: ${reference}; ez a szöveg: ${text}. Ezekbe az alkalmazás értékeket illeszt be, ezért pontosan így kell maradniuk.`,
679
+ // The name after a colon, never inflected — as `shareCard.removeConfirm`.
680
+ lastApproved: (name, date) => `Jóváhagyta: ${name}, ${date}`,
681
+ lastFlagged: (name, date) => `Módosításra jelölte: ${name}, ${date}`,
682
+ erasedReviewer: "egy törölt fiók",
683
+ suggestion: "Jobb megfogalmazás",
684
+ translation: "Fordítás",
685
+ note: "Megjegyzés (nem kötelező)",
686
+ notePlaceholder: "Mi a hiba, vagy mire kell figyelni",
687
+ readOnly: "Ezt a nyelvet olvashatja, de nem ellenőrizheti.",
688
+ scope: (areas) => `Az Ön ellenőrzése a következőkre korlátozódik: ${areas}.`,
689
+ exportCorrections: (count) => `Javítások exportálása (${n(count)})`,
690
+ failed: "Ez nem sikerült. Kérjük, próbálja újra.",
691
+ },
640
692
  };
641
693
  }
642
694
 
@@ -19,12 +19,12 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
19
19
  feedbackAttachment: {
20
20
  attachmentAdd: "Allega immagine",
21
21
  attachmentCapture: "Cattura schermata",
22
- attachmentPaste: "…oppure incolla uno screenshot dagli appunti.",
22
+ attachmentPaste: "…oppure incolli uno screenshot dagli appunti.",
23
23
  attachmentRemove: "Rimuovi allegato",
24
24
  attachmentList: "Allegati",
25
25
  attachmentScreenshot: "Screenshot",
26
26
  attachmentRemoveFile: (name) => `Rimuovi ${name}`,
27
- attachmentLimit: (max) => `Massimo ${n(max)} ${max === 1 ? "allegato" : "allegati"}: rimuovine uno per aggiungerne un altro.`,
27
+ attachmentLimit: (max) => `Massimo ${n(max)} ${max === 1 ? "allegato" : "allegati"}: ne rimuova uno per aggiungerne un altro.`,
28
28
  },
29
29
  feedbackDialog: {
30
30
  title: "Invia feedback",
@@ -41,13 +41,13 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
41
41
  thread: "Commenti",
42
42
  empty: "Ancora nessun commento",
43
43
  loading: "Caricamento dei commenti…",
44
- you: "Tu",
44
+ you: "Lei",
45
45
  staff: "Team",
46
46
  attachments: "Allegati",
47
47
  },
48
48
  feedbackComposer: {
49
- field: "Scrivi un commento",
50
- placeholder: "Scrivi un commento…",
49
+ field: "Scriva un commento",
50
+ placeholder: "Scriva un commento…",
51
51
  send: "Invia",
52
52
  sendHint: (modifier) => `${modifier} + Invio per inviare`,
53
53
  sendHintEnter: "Invio per inviare, Maiusc + Invio per andare a capo",
@@ -76,23 +76,23 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
76
76
  disabledText: "Non attiva",
77
77
  enable: "Configura l’autenticazione a due fattori",
78
78
  scanHint:
79
- "Scansiona questo codice con la tua app di autenticazione, poi inserisci il codice che mostra.",
79
+ "Scansioni questo codice con la Sua app di autenticazione, poi inserisca il codice che mostra.",
80
80
  codeLabel: "Codice di verifica",
81
81
  verify: "Verifica e attiva",
82
82
  disableSection: "Disattiva l’autenticazione a due fattori",
83
83
  password: "Password attuale",
84
84
  disable: "Disattiva",
85
- qrAlt: "Codice QR per la tua app di autenticazione",
86
- secretHint: "Non riesci a scansionarlo? Inserisci invece questa chiave nell’app:",
85
+ qrAlt: "Codice QR per la Sua app di autenticazione",
86
+ secretHint: "Non riesce a scansionarlo? Inserisca invece questa chiave nell’app:",
87
87
  copySecret: "Copia chiave",
88
88
  },
89
89
  passkeys: {
90
90
  title: "Passkey",
91
- description: "Accedi con impronta, volto o PIN del dispositivo invece che con una password.",
92
- descriptionAlongside: "Accedi con impronta, volto o PIN del dispositivo. La tua password continua a funzionare.",
91
+ description: "Acceda con impronta, volto o PIN del dispositivo invece che con una password.",
92
+ descriptionAlongside: "Acceda con impronta, volto o PIN del dispositivo. La Sua password continua a funzionare.",
93
93
  empty: "Ancora nessuna passkey",
94
94
  loading: "Caricamento delle passkey…",
95
- list: "Le tue passkey",
95
+ list: "Le Sue passkey",
96
96
  nameLabel: "Nome (facoltativo)",
97
97
  namePlaceholder: "ad es. Portatile, Telefono",
98
98
  add: "Aggiungi passkey",
@@ -118,12 +118,12 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
118
118
  addRow: "Aggiungi riga",
119
119
  removeRow: (row) => `Rimuovi riga ${row}`,
120
120
  clear: "Svuota tabella",
121
- pasteHint: "Incolla un blocco da un foglio di calcolo in qualsiasi cella",
121
+ pasteHint: "Incolli un blocco da un foglio di calcolo in qualsiasi cella",
122
122
  cell: (column, row) => `${column}, riga ${row}`,
123
123
  rowNumber: "Riga",
124
124
  rowActions: "Azioni riga",
125
125
  keyboardHint:
126
- "I tasti freccia spostano tra le celle. Digita per sostituire una cella, F2 per modificarla, Esc per annullare la modifica. Invio scende e aggiunge una riga alla fine.",
126
+ "I tasti freccia spostano tra le celle. Digiti per sostituire una cella, F2 per modificarla, Esc per annullare la modifica. Invio scende e aggiunge una riga alla fine.",
127
127
  lineError: (line) => `Impossibile leggere la riga ${line}`,
128
128
  points: (count) => (count === 1 ? "1 punto" : `${count} punti`),
129
129
  problems: (count) =>
@@ -149,7 +149,7 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
149
149
  dataTable: {
150
150
  columns: "Colonne",
151
151
  selectAllRows: "Seleziona tutte le righe",
152
- sortHint: "Fai clic per ordinare · Maiusc+clic per aggiungere un ordinamento",
152
+ sortHint: "Faccia clic per ordinare · Maiusc+clic per aggiungere un ordinamento",
153
153
  filter: "Filtra",
154
154
  close: "Chiudi",
155
155
  selectRow: "Seleziona riga",
@@ -208,13 +208,13 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
208
208
  nextMonth: "Mese successivo",
209
209
  // Already formatted in the provider's locale ("lunedì 14 settembre 2026").
210
210
  day: (date) => date,
211
- chooseStart: "Scegli una data di inizio",
212
- chooseEnd: "Scegli una data di fine",
211
+ chooseStart: "Scelga una data di inizio",
212
+ chooseEnd: "Scelga una data di fine",
213
213
  // "Data" is feminine and the formatted day cannot agree with a participle, so the
214
214
  // date follows a label instead of being the subject.
215
- startSelected: (date) => `Data di inizio: ${date}. Scegli una data di fine.`,
215
+ startSelected: (date) => `Data di inizio: ${date}. Scelga una data di fine.`,
216
216
  rangeSelected: (from, to) =>
217
- `Periodo selezionato: da ${from} a ${to}. Scegli una data di inizio per ricominciare.`,
217
+ `Periodo selezionato: da ${from} a ${to}. Scelga una data di inizio per ricominciare.`,
218
218
  },
219
219
  monthPicker: {
220
220
  previousYear: "Anno precedente",
@@ -256,7 +256,7 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
256
256
  selectedCount: (count) => `${n(count)} ${plural(count, "selezionato", "selezionati")}`,
257
257
  loadError: "Impossibile caricare i risultati",
258
258
  resultCount: (count) => `${n(count)} ${plural(count, "risultato", "risultati")}`,
259
- minChars: (count) => `Digita almeno ${n(count)} ${plural(count, "carattere", "caratteri")}`,
259
+ minChars: (count) => `Digiti almeno ${n(count)} ${plural(count, "carattere", "caratteri")}`,
260
260
  },
261
261
  multiSelect: {
262
262
  search: "Cerca",
@@ -321,7 +321,7 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
321
321
  cancel: "Annulla",
322
322
  prompt: "Questa operazione non può essere annullata.",
323
323
  password: "Password",
324
- phrase: (phrase) => `Digita «${phrase}» per confermare`,
324
+ phrase: (phrase) => `Digiti «${phrase}» per confermare`,
325
325
  },
326
326
  tabs: {
327
327
  add: "Aggiungi scheda",
@@ -360,8 +360,8 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
360
360
  filePicker: {
361
361
  dropzone: "Caricamento file",
362
362
  browse: "Sfoglia",
363
- empty: "Trascina qui un file",
364
- emptyMultiple: "Trascina qui i file",
363
+ empty: "Trascini qui un file",
364
+ emptyMultiple: "Trascini qui i file",
365
365
  hint: (accept) => (accept ? `Accettati: ${accept}` : "Qualsiasi tipo di file"),
366
366
  busy: "Caricamento…",
367
367
  rejectedPick: (count) =>
@@ -398,7 +398,7 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
398
398
  cancelDismissLabel: "Continua a modificare",
399
399
  reviewTitle: "Riepilogo",
400
400
  edit: "Modifica",
401
- missingRequired: "Compila tutti i campi obbligatori.",
401
+ missingRequired: "Compili tutti i campi obbligatori.",
402
402
  genericError: "Si è verificato un errore",
403
403
  },
404
404
  tour: {
@@ -406,7 +406,7 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
406
406
  back: "Indietro",
407
407
  skip: "Salta",
408
408
  done: "Fine",
409
- awaitClickHint: "Fai clic sull’elemento evidenziato per continuare",
409
+ awaitClickHint: "Faccia clic sull’elemento evidenziato per continuare",
410
410
  step: (current, total) => `${n(current)} / ${n(total)}`,
411
411
  },
412
412
  commandPalette: {
@@ -417,13 +417,13 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
417
417
  empty: "Nessun risultato",
418
418
  loading: "Ricerca in corso…",
419
419
  dialog: "Ricerca",
420
- error: "Ricerca non riuscita. Riprova.",
420
+ error: "Ricerca non riuscita. Riprovi.",
421
421
  },
422
422
  globalSearch: {
423
423
  trigger: "Cerca",
424
424
  placeholder: "Cerca o vai a…",
425
425
  shortcut: (keys) => `Cerca (${keys})`,
426
- suggestions: "Prova",
426
+ suggestions: "Provi",
427
427
  results: "Risultati",
428
428
  },
429
429
  sparkline: {
@@ -445,8 +445,8 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
445
445
  },
446
446
  signaturePad: {
447
447
  label: "Firma",
448
- instructions: "Firma nel riquadro con il mouse, il dito o una penna.",
449
- typedFallbackHint: "Se non puoi disegnare, scrivi invece il tuo nome.",
448
+ instructions: "Firmi nel riquadro con il mouse, il dito o una penna.",
449
+ typedFallbackHint: "Se non può disegnare, scriva invece il Suo nome.",
450
450
  empty: "Ancora nessun tratto",
451
451
  signed: "Firma tracciata",
452
452
  undo: "Annulla l’ultimo tratto",
@@ -484,7 +484,7 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
484
484
  seriesChart: {
485
485
  resetZoom: "Reimposta zoom",
486
486
  zoomHint:
487
- "Trascina per ingrandire: una selezione più o meno quadrata ingrandisce entrambi gli assi, una lunga e sottile solo il proprio. Fai doppio clic per ripristinare.",
487
+ "Trascini per ingrandire: una selezione più o meno quadrata ingrandisce entrambi gli assi, una lunga e sottile solo il proprio. Faccia doppio clic per ripristinare.",
488
488
  empty: "Nessun dato",
489
489
  legend: "Serie",
490
490
  points: "Valori del grafico",
@@ -499,7 +499,7 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
499
499
  confirmDialog: {
500
500
  confirm: "Conferma",
501
501
  cancel: "Annulla",
502
- typed: (text) => `Digita «${text}» per confermare`,
502
+ typed: (text) => `Digiti «${text}» per confermare`,
503
503
  },
504
504
  floatingPanel: {
505
505
  close: "Chiudi",
@@ -536,7 +536,7 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
536
536
  lineItems: {
537
537
  add: "Aggiungi riga",
538
538
  remove: (row) => `Rimuovi riga ${row}`,
539
- confirmRemove: (row) => `Rimuovere la riga ${row}? Premi di nuovo per confermare`,
539
+ confirmRemove: (row) => `Rimuovere la riga ${row}? Prema di nuovo per confermare`,
540
540
  row: (row) => `Riga ${row}`,
541
541
  cell: (column, row) => `${column}, riga ${row}`,
542
542
  totals: "Totale",
@@ -551,14 +551,14 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
551
551
  },
552
552
  errorBoundary: {
553
553
  title: "Si è verificato un errore",
554
- message: "Impossibile mostrare questa parte della pagina. Riprova o ricarica la pagina.",
554
+ message: "Impossibile mostrare questa parte della pagina. Riprovi o ricarichi la pagina.",
555
555
  retry: "Riprova",
556
556
  details: "Dettagli dell’errore",
557
557
  reload: "Ricarica",
558
558
  updateTitle: "È disponibile una nuova versione",
559
- updateMessage: "Una parte dell’app è cambiata da quando questa pagina è stata caricata. Ricarica per ottenere la nuova versione.",
560
- offlineTitle: "Sei offline",
561
- offlineMessage: "Impossibile caricare questa pagina senza connessione. Riconnettiti, poi ricarica la pagina.",
559
+ updateMessage: "Una parte dell’app è cambiata da quando questa pagina è stata caricata. Ricarichi per ottenere la nuova versione.",
560
+ offlineTitle: "Nessuna connessione",
561
+ offlineMessage: "Impossibile caricare questa pagina senza connessione. Si riconnetta, poi ricarichi la pagina.",
562
562
  copyReport: "Copia il rapporto di errore",
563
563
  reported: "L’errore è stato segnalato automaticamente.",
564
564
  reportedAs: (reference) => `Segnalato con riferimento ${reference}`,
@@ -586,7 +586,7 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
586
586
  openInNewTab: "Apri in una nuova scheda",
587
587
  },
588
588
  writeLock: {
589
- reason: "Puoi visualizzarlo, ma non modificarlo.",
589
+ reason: "Può visualizzarlo, ma non modificarlo.",
590
590
  },
591
591
  accountState: {
592
592
  // Agreeing with "account" (masculine): the chip is the state of an account.
@@ -604,7 +604,7 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
604
604
  emailOptional: "Indirizzo email (facoltativo)",
605
605
  // example.com is reserved for examples (RFC 2606); a localised domain is real.
606
606
  emailPlaceholder: "nome@example.com",
607
- invalidEmail: "Inserisci un indirizzo email completo.",
607
+ invalidEmail: "Inserisca un indirizzo email completo.",
608
608
  role: "Ruolo",
609
609
  roleOf: (name) => `Ruolo di ${name}`,
610
610
  add: "Condividi",
@@ -619,12 +619,12 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
619
619
  removeConfirm: (name) => `Rimuovere l’accesso di ${name}?`,
620
620
  revokePending: "Ritira invito",
621
621
  revokePendingConfirm: (name) => `Ritirare l’invito per ${name}?`,
622
- failed: "Non ha funzionato. Riprova.",
622
+ failed: "Non ha funzionato. Riprovi.",
623
623
  loading: "Caricamento…",
624
624
  },
625
625
  reauthDialog: {
626
- title: "Conferma la tua identità",
627
- description: "Inserisci la password attuale per continuare.",
626
+ title: "Confermi la Sua identità",
627
+ description: "Inserisca la password attuale per continuare.",
628
628
  password: "Password attuale",
629
629
  submit: "Continua",
630
630
  cancel: "Annulla",
@@ -634,6 +634,57 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
634
634
  waking: (appName) =>
635
635
  `Il server va in sospensione quando nessuno usa ${appName ?? "l’app"}, quindi la prima richiesta dopo una pausa deve riavviarlo. Può volerci un momento: non si perde nulla, la pagina si completa da sola.`,
636
636
  },
637
+ legal: {
638
+ navLabel: "Note legali",
639
+ },
640
+ translationReview: {
641
+ statusMissing: "Mancante",
642
+ statusUnreviewed: "Non rivisto",
643
+ statusChanged: "Modificato dopo la revisione",
644
+ statusNeedsChange: "Da modificare",
645
+ statusApproved: "Approvato",
646
+ statusFilter: "Stato",
647
+ all: "Tutti",
648
+ filterCount: (label, count) => `${label} · ${n(count)}`,
649
+ source: "Testi",
650
+ allSources: "Tutti i testi",
651
+ namespace: "Area",
652
+ allNamespaces: "Tutte le aree",
653
+ search: "Cerca nelle chiavi e nei testi",
654
+ placeholdersOnly: (count) => `Solo problemi di segnaposto (${n(count)})`,
655
+ placeholderChip: "Segnaposto",
656
+ key: "Chiave",
657
+ statusColumn: "Stato",
658
+ empty: "Nessun testo corrisponde a questi filtri.",
659
+ missingText: "Mancante in questa lingua",
660
+ progress: (approved, total) => `${n(approved)} di ${n(total)} ${plural(approved, "approvato", "approvati")}`,
661
+ localeProgress: (approved, total) => `${n(approved)}/${n(total)}`,
662
+ locales: "Lingue",
663
+ approve: "Approva",
664
+ flag: "Da modificare",
665
+ suggest: "Proponi una traduzione",
666
+ reset: "Segna come non rivisto",
667
+ cancel: "Annulla",
668
+ approveSelected: "Approva i selezionati",
669
+ resetSelected: "Segna i selezionati come non rivisti",
670
+ selectShown: "Seleziona tutti quelli mostrati",
671
+ changedSince: "Questo testo è stato modificato dopo la revisione. Lo rilegga, per favore.",
672
+ reviewedWording: "Formulazione al momento della revisione",
673
+ reviewedReference: "Riferimento al momento della revisione",
674
+ placeholderMismatch: (reference, text) =>
675
+ `I segnaposto differiscono dal riferimento — riferimento: ${reference}; questo testo: ${text}. L’app vi inserisce dei valori, quindi devono restare esattamente come sono.`,
676
+ lastApproved: (name, date) => `Approvato da ${name} il ${date}`,
677
+ lastFlagged: (name, date) => `Segnato da modificare da ${name} il ${date}`,
678
+ erasedReviewer: "un account eliminato",
679
+ suggestion: "Formulazione migliore",
680
+ translation: "Traduzione",
681
+ note: "Nota (facoltativa)",
682
+ notePlaceholder: "Cosa non va, o di cosa tenere conto",
683
+ readOnly: "Può leggere questa lingua, ma non rivederla.",
684
+ scope: (areas) => `La Sua revisione è limitata a: ${areas}.`,
685
+ exportCorrections: (count) => `Esporta le correzioni (${n(count)})`,
686
+ failed: "Non ha funzionato. Riprovi.",
687
+ },
637
688
  };
638
689
  }
639
690
 
@@ -620,6 +620,58 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
620
620
  waking: (appName) =>
621
621
  `无人使用${appName ? ` ${appName} ` : "本应用"}时,服务器会进入休眠,因此暂停后的第一个请求需要重新启动它。这可能需要一点时间——不会丢失任何内容,页面会自动加载完成。`,
622
622
  },
623
+ legal: {
624
+ navLabel: "法律信息",
625
+ },
626
+ translationReview: {
627
+ statusMissing: "缺失",
628
+ statusUnreviewed: "未审校",
629
+ statusChanged: "审校后已更改",
630
+ statusNeedsChange: "需要修改",
631
+ statusApproved: "已通过",
632
+ statusFilter: "状态",
633
+ all: "全部",
634
+ filterCount: (label, count) => `${label} · ${n(count)}`,
635
+ source: "文本",
636
+ allSources: "全部文本",
637
+ namespace: "区域",
638
+ allNamespaces: "全部区域",
639
+ search: "搜索键名和文本",
640
+ placeholdersOnly: (count) => `仅显示占位符问题(${n(count)})`,
641
+ placeholderChip: "占位符",
642
+ key: "键名",
643
+ statusColumn: "状态",
644
+ empty: "没有符合这些筛选条件的文本。",
645
+ missingText: "此语言中缺失",
646
+ progress: (approved, total) => `已通过 ${n(approved)} / ${n(total)}`,
647
+ localeProgress: (approved, total) => `${n(approved)}/${n(total)}`,
648
+ locales: "语言",
649
+ approve: "通过",
650
+ flag: "需要修改",
651
+ suggest: "建议译文",
652
+ reset: "标记为未审校",
653
+ cancel: "取消",
654
+ approveSelected: "通过所选项",
655
+ resetSelected: "将所选项标记为未审校",
656
+ selectShown: "选择所有显示项",
657
+ changedSince: "此文本在审校后已更改,请重新阅读。",
658
+ reviewedWording: "审校时的措辞",
659
+ reviewedReference: "审校时的参考文本",
660
+ placeholderMismatch: (reference, text) =>
661
+ `占位符与参考文本不一致——参考文本:${reference};此文本:${text}。应用会在这些位置填入内容,因此必须保持原样。`,
662
+ // A Latin name gets a space either side, as everywhere in this catalogue.
663
+ lastApproved: (name, date) => `${name} 于 ${date} 通过`,
664
+ lastFlagged: (name, date) => `${name} 于 ${date} 标记为需要修改`,
665
+ erasedReviewer: "已删除的账户",
666
+ suggestion: "更好的措辞",
667
+ translation: "译文",
668
+ note: "备注(可选)",
669
+ notePlaceholder: "哪里有问题,或需要注意什么",
670
+ readOnly: "此语言仅可查看,无法审校。",
671
+ scope: (areas) => `审校范围仅限于:${areas}。`,
672
+ exportCorrections: (count) => `导出更正(${n(count)})`,
673
+ failed: "操作未成功,请重试。",
674
+ },
623
675
  };
624
676
  }
625
677
 
@@ -0,0 +1,193 @@
1
+ import type { UiKitLabels } from "./kit-labels";
2
+
3
+ /**
4
+ * The kit's words as a flat `key → text` list, for an app's translation review.
5
+ *
6
+ * keksdose reviews its own locale bundles on its /translations page — one verdict per
7
+ * locale and key, stored with the text the reviewer saw, so a later change re-opens it.
8
+ * The kit's words appear on the same screens but live in TypeScript, not in the app's
9
+ * bundles, and 94 of them are functions (`(count) => "3 results"`), which a bundle
10
+ * flattener skips. This turns a label tree into rows that page can join on.
11
+ *
12
+ * - A string label is one row under its dot path: `common.close`. An array of words
13
+ * (weekday names) is one row per entry: `miniCalendar.weekdays.0`.
14
+ * - A function label is called with fixed samples. Text arguments are i18next-style
15
+ * placeholders (`{{name}}`), so a translation that drops one is caught by the same
16
+ * placeholder check the app runs on its own strings. Counts are real numbers, twice
17
+ * where the wording may depend on them — 1 and 3 — so a reviewer sees singular and
18
+ * plural. The key names the sample: `combobox.resultCount(1)`,
19
+ * `shareCard.removeConfirm(name)`, `serverWake.waking()`.
20
+ *
21
+ * Keys depend only on the samples, never on the locale, so the rows of `de-CH` and of the
22
+ * English reference line up key by key. Pass exactly the tree the app hands
23
+ * `UiKitProvider` — its overrides included — and review what users see:
24
+ *
25
+ * kitLabelStrings(UI_KIT_LABELS_DE_CH) // the rows for de-CH
26
+ * kitLabelStrings(DEFAULT_UI_KIT_LABELS) // the English reference
27
+ *
28
+ * A label that throws on its sample becomes a row starting with "⚠", so one broken
29
+ * override shows up on the page instead of taking the page down.
30
+ */
31
+ export function kitLabelStrings(labels: UiKitLabels): Record<string, string> {
32
+ const out: Record<string, string> = {};
33
+ const walk = (node: unknown, path: string) => {
34
+ if (typeof node === "string") {
35
+ out[path] = node;
36
+ } else if (typeof node === "function") {
37
+ for (const args of KIT_LABEL_SAMPLES[path] ?? [[]]) {
38
+ out[`${path}(${args.map(sampleName).filter((a) => a !== "").join(", ")})`] = render(
39
+ node as (...args: unknown[]) => unknown,
40
+ args,
41
+ );
42
+ }
43
+ } else if (node !== null && typeof node === "object") {
44
+ for (const [key, value] of Object.entries(node)) walk(value, path ? `${path}.${key}` : key);
45
+ }
46
+ };
47
+ walk(labels, "");
48
+ return out;
49
+ }
50
+
51
+ function render(label: (...args: unknown[]) => unknown, args: readonly unknown[]): string {
52
+ try {
53
+ return String(label(...args));
54
+ } catch (error) {
55
+ return `⚠ ${error instanceof Error ? error.message : String(error)}`;
56
+ }
57
+ }
58
+
59
+ /** How a sample argument is written in the key: a placeholder by its name, a number as
60
+ * itself, an empty string as `""`, a missing optional argument not at all. */
61
+ function sampleName(arg: unknown): string {
62
+ if (arg === undefined) return "";
63
+ if (typeof arg === "string") return /^\{\{(\w+)\}\}$/.exec(arg)?.[1] ?? JSON.stringify(arg);
64
+ return String(arg);
65
+ }
66
+
67
+ const one = [[1], [3]] as const;
68
+
69
+ /**
70
+ * The sample arguments of every function label in {@link UiKitLabels}, by dot path.
71
+ * `src/i18n/__tests__/review.test.ts` fails when a function label has no entry here, so
72
+ * a new one cannot ship un-reviewable.
73
+ */
74
+ export const KIT_LABEL_SAMPLES: Readonly<Record<string, readonly (readonly unknown[])[]>> = {
75
+ "common.fieldValue": [["{{field}}", "{{value}}"]],
76
+ "dataTable.filterResults": [
77
+ [1, 1],
78
+ [3, 12],
79
+ ],
80
+ "dataTable.sortedAscending": [["{{column}}"]],
81
+ "dataTable.sortedDescending": [["{{column}}"]],
82
+ "dataTable.sortCleared": [["{{column}}"]],
83
+ "dataTable.pageChanged": [[2, 5]],
84
+ "dataTable.pageRange": [[1, 25, 1240]],
85
+ "dataTable.rowCount": [[1], [1240]],
86
+ "dataTable.columnsCount": [[3, 8]],
87
+ "miniCalendar.day": [["{{date}}"]],
88
+ "miniCalendar.startSelected": [["{{date}}"]],
89
+ "miniCalendar.rangeSelected": [["{{from}}", "{{to}}"]],
90
+ "calendarHeatmap.day": [["{{date}}", "{{value}}"]],
91
+ "calendarHeatmap.truncated": one,
92
+ "monthPicker.month": [["{{monthYear}}"]],
93
+ "combobox.create": [["{{query}}"]],
94
+ "combobox.selectedCount": one,
95
+ "combobox.resultCount": one,
96
+ "combobox.minChars": one,
97
+ "multiSelect.selectedCount": one,
98
+ "chipInput.added": [["{{value}}"]],
99
+ "chipInput.removed": [["{{value}}"]],
100
+ "chipInput.atLimit": one,
101
+ "chipInput.duplicate": [["{{value}}"]],
102
+ "tabs.remove": [["{{tab}}"]],
103
+ "appShell.toggleGroup": [["{{group}}"]],
104
+ "topBar.role": [["{{role}}"]],
105
+ "file.size": [[2_500_000]],
106
+ "wizard.step": [[2, 4]],
107
+ "tour.step": [[2, 4]],
108
+ "globalSearch.shortcut": [["{{keys}}"]],
109
+ "pieChart.slice": [["{{label}}", "{{value}}", "{{percent}}"]],
110
+ "sparkline.rising": [["{{first}}", "{{last}}"]],
111
+ "sparkline.falling": [["{{first}}", "{{last}}"]],
112
+ "sparkline.flat": [["{{value}}"]],
113
+ "sparkline.single": [["{{value}}"]],
114
+ "sparkline.named": [["{{name}}", "{{summary}}"]],
115
+ "statTile.increase": [["{{amount}}"]],
116
+ "statTile.decrease": [["{{amount}}"]],
117
+ "statTile.better": [["{{change}}"]],
118
+ "statTile.worse": [["{{change}}"]],
119
+ "signaturePad.viewTyped": [["{{name}}"]],
120
+ "passwordStrength.announcement": [["{{level}}"]],
121
+ "passwordStrength.ruleLength": [[12]],
122
+ "passwordStrength.optional": [["{{rule}}"]],
123
+ "passwordStrength.tooLong": [[72]],
124
+ "dangerConfirm.phrase": [["{{phrase}}"]],
125
+ "iconPicker.resultCount": one,
126
+ "filePicker.rejectedType": [["{{name}}"]],
127
+ "filePicker.rejectedTypeOnly": [["{{accept}}", "{{name}}"]],
128
+ "filePicker.rejectedSize": [["{{name}}", "{{maxSize}}"]],
129
+ "filePicker.rejectedCount": [
130
+ ["{{name}}", 1],
131
+ ["{{name}}", 3],
132
+ ],
133
+ "filePicker.rejectedInvalid": [["{{name}}"]],
134
+ "filePicker.rejectedMany": one,
135
+ "filePicker.rejectedPick": one,
136
+ "filePicker.selected": [
137
+ [1, "{{firstName}}"],
138
+ [3, "{{firstName}}"],
139
+ ],
140
+ "filePicker.remove": [["{{name}}"]],
141
+ "filePicker.removed": [["{{name}}"]],
142
+ "filePicker.hint": [["{{accept}}"], [""]],
143
+ "measuredGrid.removeRow": [[3]],
144
+ "measuredGrid.cell": [["{{column}}", 3]],
145
+ "measuredGrid.lineError": [[3]],
146
+ "measuredGrid.points": one,
147
+ "measuredGrid.problems": one,
148
+ "feedbackAttachment.attachmentRemoveFile": [["{{name}}"]],
149
+ "feedbackAttachment.attachmentLimit": one,
150
+ "feedbackComposer.sendHint": [["{{modifier}}"]],
151
+ "accountSettings.passkeys.renameItem": [["{{name}}"]],
152
+ "accountSettings.passkeys.renameField": [["{{name}}"]],
153
+ "accountSettings.passkeys.deleteItem": [["{{name}}"]],
154
+ "accountSettings.passkeys.deleteConfirm": [["{{name}}"]],
155
+ "accountSettings.passkeys.created": [["{{date}}"]],
156
+ "accountSettings.passkeys.lastUsed": [["{{date}}"]],
157
+ "confirmDialog.typed": [["{{text}}"]],
158
+ "floatingPanel.badge": one,
159
+ "bulkActionBar.selected": one,
160
+ "lineItems.remove": [[3]],
161
+ "lineItems.confirmRemove": [[3]],
162
+ "lineItems.row": [[3]],
163
+ "lineItems.cell": [["{{column}}", 3]],
164
+ "progressBar.overLimit": [["{{amount}}"]],
165
+ "signedAmount.positive": [["{{amount}}"]],
166
+ "signedAmount.negative": [["{{amount}}"]],
167
+ "errorBoundary.reportedAs": [["{{reference}}"]],
168
+ "authedImage.failedImage": [["{{alt}}"]],
169
+ "imageGrid.item": [[2, 5]],
170
+ "imageGrid.actions": [["{{name}}"]],
171
+ "lightbox.counter": [[2, 5]],
172
+ "lightbox.position": [[2, 5]],
173
+ "shareCard.roleOf": [["{{name}}"]],
174
+ "shareCard.teamHint": [["{{name}}"]],
175
+ "shareCard.removeConfirm": [["{{name}}"]],
176
+ "shareCard.revokePendingConfirm": [["{{name}}"]],
177
+ "serverWake.waking": [["{{appName}}"], [undefined]],
178
+ "translationReview.filterCount": [
179
+ ["{{status}}", 1],
180
+ ["{{status}}", 3],
181
+ ],
182
+ "translationReview.placeholdersOnly": one,
183
+ "translationReview.progress": [
184
+ [1, 1],
185
+ [3, 12],
186
+ ],
187
+ "translationReview.localeProgress": [[3, 12]],
188
+ "translationReview.placeholderMismatch": [["{{reference}}", "{{text}}"]],
189
+ "translationReview.lastApproved": [["{{name}}", "{{date}}"]],
190
+ "translationReview.lastFlagged": [["{{name}}", "{{date}}"]],
191
+ "translationReview.scope": [["{{areas}}"]],
192
+ "translationReview.exportCorrections": [[0], [1], [3]],
193
+ };