@eifi1/ui-kit 0.44.0 → 0.45.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 +10 -6
- package/dist/admin/admin-action-log-labels.js +9 -0
- package/dist/admin/admin-action-log-labels.js.map +1 -1
- package/dist/admin/admin-action-log.d.ts +18 -1
- package/dist/admin/admin-action-log.js +25 -16
- package/dist/admin/admin-action-log.js.map +1 -1
- package/dist/admin/admin-area-labels.d.ts +6 -0
- package/dist/admin/admin-area-labels.js +1 -0
- package/dist/admin/admin-area-labels.js.map +1 -1
- package/dist/admin/mail-test-card-labels.d.ts +3 -0
- package/dist/admin/mail-test-card-labels.js +17 -0
- package/dist/admin/mail-test-card-labels.js.map +1 -0
- package/dist/admin/mail-test-card.d.ts +74 -0
- package/dist/admin/mail-test-card.js +80 -0
- package/dist/admin/mail-test-card.js.map +1 -0
- package/dist/components/data-table-mobile.js +17 -2
- package/dist/components/data-table-mobile.js.map +1 -1
- package/dist/components/data-table-shared.d.ts +2 -0
- package/dist/components/data-table-shared.js +8 -0
- package/dist/components/data-table-shared.js.map +1 -1
- package/dist/components/data-table.js +1 -6
- package/dist/components/data-table.js.map +1 -1
- package/dist/eslint/index.js +1 -1
- package/dist/i18n/defaults.js +9 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.js +40 -0
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +13 -0
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/en.js +57 -1
- package/dist/i18n/locales/en.js.map +3 -3
- package/dist/i18n/locales/es.js +40 -0
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.js +40 -0
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.js +40 -0
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.js +40 -0
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.js +40 -0
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.js +13 -1
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/format.d.ts +2 -1
- package/dist/lib/format.js +6 -1
- package/dist/lib/format.js.map +1 -1
- package/dist/offline/pwa-update-prompt-labels.d.ts +2 -0
- package/dist/offline/pwa-update-prompt-labels.js +9 -0
- package/dist/offline/pwa-update-prompt-labels.js.map +1 -0
- package/dist/offline/pwa-update-prompt.d.ts +32 -0
- package/dist/offline/pwa-update-prompt.js +36 -0
- package/dist/offline/pwa-update-prompt.js.map +1 -0
- package/dist/offline/query-persistence.d.ts +100 -0
- package/dist/offline/query-persistence.js +179 -0
- package/dist/offline/query-persistence.js.map +1 -0
- package/dist/offline/shared-computer-labels.d.ts +2 -0
- package/dist/offline/shared-computer-labels.js +9 -0
- package/dist/offline/shared-computer-labels.js.map +1 -0
- package/dist/offline/shared-computer.d.ts +44 -0
- package/dist/offline/shared-computer.js +51 -0
- package/dist/offline/shared-computer.js.map +1 -0
- package/dist/offline/sign-out-pending-dialog-labels.d.ts +2 -0
- package/dist/offline/sign-out-pending-dialog-labels.js +14 -0
- package/dist/offline/sign-out-pending-dialog-labels.js.map +1 -0
- package/dist/offline/sign-out-pending-dialog.d.ts +58 -0
- package/dist/offline/sign-out-pending-dialog.js +66 -0
- package/dist/offline/sign-out-pending-dialog.js.map +1 -0
- package/dist/offline.d.ts +8 -0
- package/dist/offline.js +24 -0
- package/dist/offline.js.map +1 -0
- package/dist/shell/admin-menu.d.ts +24 -0
- package/dist/shell/admin-menu.js +12 -3
- package/dist/shell/admin-menu.js.map +1 -1
- package/dist/shell.d.ts +2 -0
- package/dist/shell.js +2 -0
- package/dist/shell.js.map +1 -1
- package/dist/tour/tour-catalogue.d.ts +7 -1
- package/dist/tour/tour-catalogue.js.map +1 -1
- package/dist/tour/tour.js +4 -2
- package/dist/tour/tour.js.map +1 -1
- package/dist/tour/use-tour-progress.d.ts +99 -1
- package/dist/tour/use-tour-progress.js +228 -12
- package/dist/tour/use-tour-progress.js.map +1 -1
- package/dist/tour.d.ts +2 -0
- package/dist/tour.js +2 -0
- package/dist/tour.js.map +1 -1
- package/package.json +25 -1
- package/src/admin/admin-action-log-labels.ts +9 -0
- package/src/admin/admin-action-log.tsx +41 -5
- package/src/admin/admin-area-labels.ts +7 -0
- package/src/admin/mail-test-card-labels.ts +19 -0
- package/src/admin/mail-test-card.tsx +186 -0
- package/src/components/data-table-mobile.tsx +26 -3
- package/src/components/data-table-shared.tsx +18 -1
- package/src/components/data-table.tsx +1 -15
- package/src/i18n/defaults.ts +8 -0
- package/src/i18n/german.ts +46 -0
- package/src/i18n/kit-labels.tsx +13 -0
- package/src/i18n/locales/en.ts +12 -0
- package/src/i18n/locales/es.ts +46 -0
- package/src/i18n/locales/fr.ts +46 -0
- package/src/i18n/locales/hu.ts +42 -0
- package/src/i18n/locales/it.ts +46 -0
- package/src/i18n/locales/zh.ts +40 -0
- package/src/i18n/review.ts +12 -0
- package/src/index.ts +3 -0
- package/src/lib/format.ts +13 -2
- package/src/offline/pwa-update-prompt-labels.ts +9 -0
- package/src/offline/pwa-update-prompt.tsx +72 -0
- package/src/offline/query-persistence.ts +323 -0
- package/src/offline/shared-computer-labels.ts +8 -0
- package/src/offline/shared-computer.tsx +87 -0
- package/src/offline/sign-out-pending-dialog-labels.ts +21 -0
- package/src/offline/sign-out-pending-dialog.tsx +135 -0
- package/src/offline.ts +26 -0
- package/src/shell/admin-menu.tsx +40 -3
- package/src/shell.ts +4 -0
- package/src/tour/tour-catalogue.tsx +7 -1
- package/src/tour/tour.tsx +5 -2
- package/src/tour/use-tour-progress.ts +378 -12
- package/src/tour.ts +3 -0
package/src/i18n/locales/es.ts
CHANGED
|
@@ -1375,11 +1375,14 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
|
|
|
1375
1375
|
// 0.34 (§11.5): whole phrases per noun. The group's own agree with the noun
|
|
1376
1376
|
// ("Empresa creada"), a member's with "cuenta", as `actions` do. `team` is
|
|
1377
1377
|
// Kurvenschmiede's "equipo"; `company` keeps `actions.membership_remove`'s string.
|
|
1378
|
+
renamedFromTo: (from, to) => `de ${from} a ${to}`,
|
|
1378
1379
|
groupActions: {
|
|
1379
1380
|
group: {
|
|
1380
1381
|
group_create: "Grupo creado",
|
|
1381
1382
|
group_rename: "Grupo renombrado",
|
|
1382
1383
|
group_delete: "Grupo eliminado",
|
|
1384
|
+
group_deactivate: "Grupo desactivado",
|
|
1385
|
+
group_reactivate: "Grupo reactivado",
|
|
1383
1386
|
membership_add: "Añadida al grupo",
|
|
1384
1387
|
membership_role: "Rol en el grupo cambiado",
|
|
1385
1388
|
membership_remove: "Quitada del grupo",
|
|
@@ -1389,6 +1392,8 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
|
|
|
1389
1392
|
group_create: "Equipo creado",
|
|
1390
1393
|
group_rename: "Equipo renombrado",
|
|
1391
1394
|
group_delete: "Equipo eliminado",
|
|
1395
|
+
group_deactivate: "Equipo desactivado",
|
|
1396
|
+
group_reactivate: "Equipo reactivado",
|
|
1392
1397
|
membership_add: "Añadida al equipo",
|
|
1393
1398
|
membership_role: "Rol en el equipo cambiado",
|
|
1394
1399
|
membership_remove: "Quitada del equipo",
|
|
@@ -1398,6 +1403,8 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
|
|
|
1398
1403
|
group_create: "Empresa creada",
|
|
1399
1404
|
group_rename: "Empresa renombrada",
|
|
1400
1405
|
group_delete: "Empresa eliminada",
|
|
1406
|
+
group_deactivate: "Empresa desactivada",
|
|
1407
|
+
group_reactivate: "Empresa reactivada",
|
|
1401
1408
|
membership_add: "Añadida a la empresa",
|
|
1402
1409
|
membership_role: "Rol en la empresa cambiado",
|
|
1403
1410
|
membership_remove: "Quitada de la empresa",
|
|
@@ -1407,6 +1414,8 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
|
|
|
1407
1414
|
group_create: "Presupuesto creado",
|
|
1408
1415
|
group_rename: "Presupuesto renombrado",
|
|
1409
1416
|
group_delete: "Presupuesto eliminado",
|
|
1417
|
+
group_deactivate: "Presupuesto desactivado",
|
|
1418
|
+
group_reactivate: "Presupuesto reactivado",
|
|
1410
1419
|
membership_add: "Añadida al presupuesto",
|
|
1411
1420
|
membership_role: "Rol en el presupuesto cambiado",
|
|
1412
1421
|
membership_remove: "Quitada del presupuesto",
|
|
@@ -1831,9 +1840,21 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
|
|
|
1831
1840
|
},
|
|
1832
1841
|
// 0.42.0 — docs/admin-harmonization.md §3.1: the admin area's shared words. "Usted",
|
|
1833
1842
|
// as the rest of the catalogue.
|
|
1843
|
+
mailTestCard: {
|
|
1844
|
+
title: "Correo de prueba",
|
|
1845
|
+
description: "Envía un correo a su propia dirección, por el mismo transporte con el que esta instalación envía todo su correo.",
|
|
1846
|
+
transport: (backend) => `Transporte: ${backend}`,
|
|
1847
|
+
action: "Enviarme un correo de prueba",
|
|
1848
|
+
sent: (address) => `Enviado a ${address}. Revise la bandeja de entrada.`,
|
|
1849
|
+
console: "El transporte de consola solo registra el correo; no se ha enviado nada.",
|
|
1850
|
+
failed: "No se pudo enviar. El registro del servidor tiene la respuesta del proveedor.",
|
|
1851
|
+
rateLimited,
|
|
1852
|
+
keywords: "correo prueba email e-mail transporte smtp resend consola enviar entrega",
|
|
1853
|
+
},
|
|
1834
1854
|
adminArea: {
|
|
1835
1855
|
title: "Administración",
|
|
1836
1856
|
waiting: (count) => `${n(count)} ${plural(count, "pendiente", "pendientes")}`,
|
|
1857
|
+
waitingLabel: (label, count) => `${label}, ${n(count)} ${plural(count, "pendiente", "pendientes")}`,
|
|
1837
1858
|
forbiddenTitle: "Solo para administradores",
|
|
1838
1859
|
forbiddenBody: (appName) =>
|
|
1839
1860
|
`Aquí es donde los administradores gestionan ${appName}. Su cuenta no puede abrir esta página.`,
|
|
@@ -1902,6 +1923,31 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
|
|
|
1902
1923
|
billingOff: "La facturación está desactivada en local: los planes no cambian nada",
|
|
1903
1924
|
},
|
|
1904
1925
|
},
|
|
1926
|
+
// 0.45.0 — docs/local-first-harmonization.md §1.6 (`@eifi1/ui-kit/offline`): keksdose's
|
|
1927
|
+
// reviewed words (nav.logout_queued_*, pwa.*) where it has the language.
|
|
1928
|
+
signOutPending: {
|
|
1929
|
+
title: "Algunos cambios aún no se han guardado en el servidor",
|
|
1930
|
+
lost: (count) =>
|
|
1931
|
+
count === 1
|
|
1932
|
+
? `${n(count)} cambio sigue pendiente de sincronizar. Al cerrar sesión se borra la copia de este dispositivo, y es la única.`
|
|
1933
|
+
: `${n(count)} cambios siguen pendientes de sincronizar. Al cerrar sesión se borra la copia de este dispositivo, y es la única.`,
|
|
1934
|
+
kept: (count) =>
|
|
1935
|
+
count === 1
|
|
1936
|
+
? `${n(count)} cambio sigue pendiente de sincronizar. Se queda en este dispositivo para usted y se sincronizará la próxima vez que inicie sesión aquí.`
|
|
1937
|
+
: `${n(count)} cambios siguen pendientes de sincronizar. Se quedan en este dispositivo para usted y se sincronizarán la próxima vez que inicie sesión aquí.`,
|
|
1938
|
+
syncNow: "Sincronizar ahora",
|
|
1939
|
+
signOutAnyway: "Cerrar sesión de todos modos",
|
|
1940
|
+
discardWaiting: "Descartar los cambios en espera",
|
|
1941
|
+
cancel: "Cancelar",
|
|
1942
|
+
},
|
|
1943
|
+
pwaUpdate: {
|
|
1944
|
+
updateAvailable: "Hay una nueva versión disponible.",
|
|
1945
|
+
reload: "Recargar",
|
|
1946
|
+
},
|
|
1947
|
+
sharedComputer: {
|
|
1948
|
+
label: "Este es un ordenador compartido",
|
|
1949
|
+
hint: "No queda ninguna copia de sus datos en este dispositivo. Las páginas solo se abren entonces con conexión.",
|
|
1950
|
+
},
|
|
1905
1951
|
};
|
|
1906
1952
|
}
|
|
1907
1953
|
|
package/src/i18n/locales/fr.ts
CHANGED
|
@@ -1403,11 +1403,14 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
|
|
|
1403
1403
|
// ("Équipe créée", Kurvenschmiede's feminine "équipe"), a member's with "compte",
|
|
1404
1404
|
// as `actions` do. `budget` is keksdose's; `company` keeps
|
|
1405
1405
|
// `actions.membership_remove`'s string.
|
|
1406
|
+
renamedFromTo: (from, to) => `de ${from} en ${to}`,
|
|
1406
1407
|
groupActions: {
|
|
1407
1408
|
group: {
|
|
1408
1409
|
group_create: "Groupe créé",
|
|
1409
1410
|
group_rename: "Groupe renommé",
|
|
1410
1411
|
group_delete: "Groupe supprimé",
|
|
1412
|
+
group_deactivate: "Groupe désactivé",
|
|
1413
|
+
group_reactivate: "Groupe réactivé",
|
|
1411
1414
|
membership_add: "Ajouté au groupe",
|
|
1412
1415
|
membership_role: "Rôle dans le groupe modifié",
|
|
1413
1416
|
membership_remove: "Retiré du groupe",
|
|
@@ -1417,6 +1420,8 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
|
|
|
1417
1420
|
group_create: "Équipe créée",
|
|
1418
1421
|
group_rename: "Équipe renommée",
|
|
1419
1422
|
group_delete: "Équipe supprimée",
|
|
1423
|
+
group_deactivate: "Équipe désactivée",
|
|
1424
|
+
group_reactivate: "Équipe réactivée",
|
|
1420
1425
|
membership_add: "Ajouté à l’équipe",
|
|
1421
1426
|
membership_role: "Rôle dans l’équipe modifié",
|
|
1422
1427
|
membership_remove: "Retiré de l’équipe",
|
|
@@ -1426,6 +1431,8 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
|
|
|
1426
1431
|
group_create: "Entreprise créée",
|
|
1427
1432
|
group_rename: "Entreprise renommée",
|
|
1428
1433
|
group_delete: "Entreprise supprimée",
|
|
1434
|
+
group_deactivate: "Entreprise désactivée",
|
|
1435
|
+
group_reactivate: "Entreprise réactivée",
|
|
1429
1436
|
membership_add: "Ajouté à l’entreprise",
|
|
1430
1437
|
membership_role: "Rôle dans l’entreprise modifié",
|
|
1431
1438
|
membership_remove: "Retiré de l’entreprise",
|
|
@@ -1435,6 +1442,8 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
|
|
|
1435
1442
|
group_create: "Budget créé",
|
|
1436
1443
|
group_rename: "Budget renommé",
|
|
1437
1444
|
group_delete: "Budget supprimé",
|
|
1445
|
+
group_deactivate: "Budget désactivé",
|
|
1446
|
+
group_reactivate: "Budget réactivé",
|
|
1438
1447
|
membership_add: "Ajouté au budget",
|
|
1439
1448
|
membership_role: "Rôle dans le budget modifié",
|
|
1440
1449
|
membership_remove: "Retiré du budget",
|
|
@@ -1870,9 +1879,21 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
|
|
|
1870
1879
|
moreTitle: "Autres pages",
|
|
1871
1880
|
},
|
|
1872
1881
|
// 0.42.0 — docs/admin-harmonization.md §3.1: the admin area's shared words.
|
|
1882
|
+
mailTestCard: {
|
|
1883
|
+
title: "E-mail de test",
|
|
1884
|
+
description: "Envoie un e-mail à votre propre adresse, par le transport avec lequel cette installation envoie tous ses e-mails.",
|
|
1885
|
+
transport: (backend) => `Transport : ${backend}`,
|
|
1886
|
+
action: "M’envoyer un e-mail de test",
|
|
1887
|
+
sent: (address) => `Envoyé à ${address}. Vérifiez la boîte de réception.`,
|
|
1888
|
+
console: "Le transport console ne fait que journaliser les e-mails ; rien n’a été envoyé.",
|
|
1889
|
+
failed: "Envoi impossible. Le journal du serveur contient la réponse du fournisseur.",
|
|
1890
|
+
rateLimited,
|
|
1891
|
+
keywords: "e-mail test courriel transport smtp resend console envoyer distribution",
|
|
1892
|
+
},
|
|
1873
1893
|
adminArea: {
|
|
1874
1894
|
title: "Administration",
|
|
1875
1895
|
waiting: (count) => `${n(count)} en attente`,
|
|
1896
|
+
waitingLabel: (label, count) => `${label}, ${n(count)} en attente`,
|
|
1876
1897
|
forbiddenTitle: "Réservé aux administrateurs",
|
|
1877
1898
|
forbiddenBody: (appName) =>
|
|
1878
1899
|
`C’est ici que les administrateurs gèrent ${appName}. Votre compte ne peut pas ouvrir cette page.`,
|
|
@@ -1941,6 +1962,31 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
|
|
|
1941
1962
|
billingOff: "La facturation est désactivée en local\u00a0: les formules ne changent rien",
|
|
1942
1963
|
},
|
|
1943
1964
|
},
|
|
1965
|
+
// 0.45.0 — docs/local-first-harmonization.md §1.6 (`@eifi1/ui-kit/offline`): keksdose's
|
|
1966
|
+
// reviewed words (nav.logout_queued_*, pwa.*) where it has the language.
|
|
1967
|
+
signOutPending: {
|
|
1968
|
+
title: "Certaines modifications ne sont pas encore enregistrées sur le serveur",
|
|
1969
|
+
lost: (count) =>
|
|
1970
|
+
count < 2
|
|
1971
|
+
? `${n(count)} modification attend encore la synchronisation. La déconnexion efface la copie de cet appareil, et c’est la seule.`
|
|
1972
|
+
: `${n(count)} modifications attendent encore la synchronisation. La déconnexion efface la copie de cet appareil, et c’est la seule.`,
|
|
1973
|
+
kept: (count) =>
|
|
1974
|
+
count < 2
|
|
1975
|
+
? `${n(count)} modification attend encore la synchronisation. Elle reste sur cet appareil pour vous et sera synchronisée à votre prochaine connexion ici.`
|
|
1976
|
+
: `${n(count)} modifications attendent encore la synchronisation. Elles restent sur cet appareil pour vous et seront synchronisées à votre prochaine connexion ici.`,
|
|
1977
|
+
syncNow: "Synchroniser maintenant",
|
|
1978
|
+
signOutAnyway: "Se déconnecter quand même",
|
|
1979
|
+
discardWaiting: "Abandonner les modifications en attente",
|
|
1980
|
+
cancel: "Annuler",
|
|
1981
|
+
},
|
|
1982
|
+
pwaUpdate: {
|
|
1983
|
+
updateAvailable: "Une nouvelle version est disponible.",
|
|
1984
|
+
reload: "Recharger",
|
|
1985
|
+
},
|
|
1986
|
+
sharedComputer: {
|
|
1987
|
+
label: "C’est un ordinateur partagé",
|
|
1988
|
+
hint: "Aucune copie de vos données ne reste sur cet appareil. Les pages ne s’ouvrent alors qu’avec une connexion.",
|
|
1989
|
+
},
|
|
1944
1990
|
};
|
|
1945
1991
|
}
|
|
1946
1992
|
|
package/src/i18n/locales/hu.ts
CHANGED
|
@@ -1376,11 +1376,14 @@ export function uiKitLabelsHu(numberLocale = "hu-HU"): UiKitLabels {
|
|
|
1376
1376
|
// 0.34 (§11.5): whole phrases per noun, each noun with its own suffix ("a
|
|
1377
1377
|
// csapatból", "a cégből"). `team` is Kurvenschmiede's "csapat"; `company` keeps
|
|
1378
1378
|
// `actions.membership_remove`'s string.
|
|
1379
|
+
renamedFromTo: (from, to) => `${from} → ${to}`,
|
|
1379
1380
|
groupActions: {
|
|
1380
1381
|
group: {
|
|
1381
1382
|
group_create: "Csoport létrehozva",
|
|
1382
1383
|
group_rename: "Csoport átnevezve",
|
|
1383
1384
|
group_delete: "Csoport törölve",
|
|
1385
|
+
group_deactivate: "Csoport inaktiválva",
|
|
1386
|
+
group_reactivate: "Csoport újraaktiválva",
|
|
1384
1387
|
membership_add: "Hozzáadva a csoporthoz",
|
|
1385
1388
|
membership_role: "Szerepkör a csoportban módosítva",
|
|
1386
1389
|
membership_remove: "Eltávolítva a csoportból",
|
|
@@ -1390,6 +1393,8 @@ export function uiKitLabelsHu(numberLocale = "hu-HU"): UiKitLabels {
|
|
|
1390
1393
|
group_create: "Csapat létrehozva",
|
|
1391
1394
|
group_rename: "Csapat átnevezve",
|
|
1392
1395
|
group_delete: "Csapat törölve",
|
|
1396
|
+
group_deactivate: "Csapat inaktiválva",
|
|
1397
|
+
group_reactivate: "Csapat újraaktiválva",
|
|
1393
1398
|
membership_add: "Hozzáadva a csapathoz",
|
|
1394
1399
|
membership_role: "Szerepkör a csapatban módosítva",
|
|
1395
1400
|
membership_remove: "Eltávolítva a csapatból",
|
|
@@ -1399,6 +1404,8 @@ export function uiKitLabelsHu(numberLocale = "hu-HU"): UiKitLabels {
|
|
|
1399
1404
|
group_create: "Cég létrehozva",
|
|
1400
1405
|
group_rename: "Cég átnevezve",
|
|
1401
1406
|
group_delete: "Cég törölve",
|
|
1407
|
+
group_deactivate: "Cég inaktiválva",
|
|
1408
|
+
group_reactivate: "Cég újraaktiválva",
|
|
1402
1409
|
membership_add: "Hozzáadva a céghez",
|
|
1403
1410
|
membership_role: "Szerepkör a cégben módosítva",
|
|
1404
1411
|
membership_remove: "Eltávolítva a cégből",
|
|
@@ -1408,6 +1415,8 @@ export function uiKitLabelsHu(numberLocale = "hu-HU"): UiKitLabels {
|
|
|
1408
1415
|
group_create: "Költségvetés létrehozva",
|
|
1409
1416
|
group_rename: "Költségvetés átnevezve",
|
|
1410
1417
|
group_delete: "Költségvetés törölve",
|
|
1418
|
+
group_deactivate: "Költségvetés inaktiválva",
|
|
1419
|
+
group_reactivate: "Költségvetés újraaktiválva",
|
|
1411
1420
|
membership_add: "Hozzáadva a költségvetéshez",
|
|
1412
1421
|
membership_role: "Szerepkör a költségvetésben módosítva",
|
|
1413
1422
|
membership_remove: "Eltávolítva a költségvetésből",
|
|
@@ -1837,9 +1846,21 @@ export function uiKitLabelsHu(numberLocale = "hu-HU"): UiKitLabels {
|
|
|
1837
1846
|
},
|
|
1838
1847
|
// 0.42.0 — docs/admin-harmonization.md §3.1: the admin area's shared words. "Ön", as
|
|
1839
1848
|
// the rest of the catalogue.
|
|
1849
|
+
mailTestCard: {
|
|
1850
|
+
title: "Tesztlevél",
|
|
1851
|
+
description: "Egy levelet küld a saját címére, azon a csatornán, amelyen ez a telepítés minden levelét küldi.",
|
|
1852
|
+
transport: (backend) => `Küldés módja: ${backend}`,
|
|
1853
|
+
action: "Tesztlevél küldése magamnak",
|
|
1854
|
+
sent: (address) => `Elküldve ide: ${address}. Nézze meg a beérkező leveleket.`,
|
|
1855
|
+
console: "A konzolos küldés csak naplózza a leveleket; semmi sem lett elküldve.",
|
|
1856
|
+
failed: "A küldés nem sikerült. A szolgáltató válasza a szervernaplóban található.",
|
|
1857
|
+
rateLimited,
|
|
1858
|
+
keywords: "tesztlevél teszt e-mail levél küldés smtp resend konzol kézbesítés",
|
|
1859
|
+
},
|
|
1840
1860
|
adminArea: {
|
|
1841
1861
|
title: "Adminisztráció",
|
|
1842
1862
|
waiting: (count) => `${n(count)} várakozik`,
|
|
1863
|
+
waitingLabel: (label, count) => `${label}, ${n(count)} várakozik`,
|
|
1843
1864
|
forbiddenTitle: "Csak adminisztrátoroknak",
|
|
1844
1865
|
forbiddenBody: (appName) =>
|
|
1845
1866
|
`Itt kezelik az adminisztrátorok a(z) ${appName} alkalmazást. Az Ön fiókja nem nyithatja meg ezt az oldalt.`,
|
|
@@ -1906,6 +1927,27 @@ export function uiKitLabelsHu(numberLocale = "hu-HU"): UiKitLabels {
|
|
|
1906
1927
|
billingOff: "A számlázás helyben ki van kapcsolva: a csomagok semmin nem változtatnak",
|
|
1907
1928
|
},
|
|
1908
1929
|
},
|
|
1930
|
+
// 0.45.0 — docs/local-first-harmonization.md §1.6 (`@eifi1/ui-kit/offline`): keksdose's
|
|
1931
|
+
// reviewed words (nav.logout_queued_*, pwa.*) where it has the language.
|
|
1932
|
+
signOutPending: {
|
|
1933
|
+
title: "Néhány módosítás még nincs elmentve a szerveren",
|
|
1934
|
+
lost: (count) =>
|
|
1935
|
+
`${n(count)} módosítás még szinkronizálásra vár. Kijelentkezéskor törlődik az eszközön lévő másolat, pedig ez az egyetlen.`,
|
|
1936
|
+
kept: (count) =>
|
|
1937
|
+
`${n(count)} módosítás még szinkronizálásra vár. Ezen az eszközön megmarad az Ön számára, és a következő itteni bejelentkezésekor szinkronizálódik.`,
|
|
1938
|
+
syncNow: "Szinkronizálás most",
|
|
1939
|
+
signOutAnyway: "Kijelentkezés mindenképp",
|
|
1940
|
+
discardWaiting: "Várakozó módosítások elvetése",
|
|
1941
|
+
cancel: "Mégse",
|
|
1942
|
+
},
|
|
1943
|
+
pwaUpdate: {
|
|
1944
|
+
updateAvailable: "Új verzió érhető el.",
|
|
1945
|
+
reload: "Újratöltés",
|
|
1946
|
+
},
|
|
1947
|
+
sharedComputer: {
|
|
1948
|
+
label: "Ez egy közös használatú számítógép",
|
|
1949
|
+
hint: "Az adatairól nem marad másolat ezen az eszközön. Az oldalak így csak kapcsolattal nyílnak meg.",
|
|
1950
|
+
},
|
|
1909
1951
|
};
|
|
1910
1952
|
}
|
|
1911
1953
|
|
package/src/i18n/locales/it.ts
CHANGED
|
@@ -1385,11 +1385,14 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
|
|
|
1385
1385
|
// ("Azienda creata"; Kurvenschmiede's "il team" is masculine, never "squadra"), a
|
|
1386
1386
|
// member's with "account", as `actions` do. `budget` is keksdose's; `company` keeps
|
|
1387
1387
|
// `actions.membership_remove`'s string.
|
|
1388
|
+
renamedFromTo: (from, to) => `da ${from} a ${to}`,
|
|
1388
1389
|
groupActions: {
|
|
1389
1390
|
group: {
|
|
1390
1391
|
group_create: "Gruppo creato",
|
|
1391
1392
|
group_rename: "Gruppo rinominato",
|
|
1392
1393
|
group_delete: "Gruppo eliminato",
|
|
1394
|
+
group_deactivate: "Gruppo disattivato",
|
|
1395
|
+
group_reactivate: "Gruppo riattivato",
|
|
1393
1396
|
membership_add: "Aggiunto al gruppo",
|
|
1394
1397
|
membership_role: "Ruolo nel gruppo cambiato",
|
|
1395
1398
|
membership_remove: "Rimosso dal gruppo",
|
|
@@ -1399,6 +1402,8 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
|
|
|
1399
1402
|
group_create: "Team creato",
|
|
1400
1403
|
group_rename: "Team rinominato",
|
|
1401
1404
|
group_delete: "Team eliminato",
|
|
1405
|
+
group_deactivate: "Team disattivato",
|
|
1406
|
+
group_reactivate: "Team riattivato",
|
|
1402
1407
|
membership_add: "Aggiunto al team",
|
|
1403
1408
|
membership_role: "Ruolo nel team cambiato",
|
|
1404
1409
|
membership_remove: "Rimosso dal team",
|
|
@@ -1408,6 +1413,8 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
|
|
|
1408
1413
|
group_create: "Azienda creata",
|
|
1409
1414
|
group_rename: "Azienda rinominata",
|
|
1410
1415
|
group_delete: "Azienda eliminata",
|
|
1416
|
+
group_deactivate: "Azienda disattivata",
|
|
1417
|
+
group_reactivate: "Azienda riattivata",
|
|
1411
1418
|
membership_add: "Aggiunto all’azienda",
|
|
1412
1419
|
membership_role: "Ruolo nell’azienda cambiato",
|
|
1413
1420
|
membership_remove: "Rimosso dall’azienda",
|
|
@@ -1417,6 +1424,8 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
|
|
|
1417
1424
|
group_create: "Budget creato",
|
|
1418
1425
|
group_rename: "Budget rinominato",
|
|
1419
1426
|
group_delete: "Budget eliminato",
|
|
1427
|
+
group_deactivate: "Budget disattivato",
|
|
1428
|
+
group_reactivate: "Budget riattivato",
|
|
1420
1429
|
membership_add: "Aggiunto al budget",
|
|
1421
1430
|
membership_role: "Ruolo nel budget cambiato",
|
|
1422
1431
|
membership_remove: "Rimosso dal budget",
|
|
@@ -1850,9 +1859,21 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
|
|
|
1850
1859
|
},
|
|
1851
1860
|
// 0.42.0 — docs/admin-harmonization.md §3.1: the admin area's shared words. "Lei", as
|
|
1852
1861
|
// the rest of the catalogue.
|
|
1862
|
+
mailTestCard: {
|
|
1863
|
+
title: "Email di prova",
|
|
1864
|
+
description: "Invia un’email al Suo indirizzo, tramite il trasporto con cui questa installazione invia tutte le sue email.",
|
|
1865
|
+
transport: (backend) => `Trasporto: ${backend}`,
|
|
1866
|
+
action: "Inviami un’email di prova",
|
|
1867
|
+
sent: (address) => `Inviata a ${address}. Controlli la posta in arrivo.`,
|
|
1868
|
+
console: "Il trasporto console registra solo le email; non è stato inviato nulla.",
|
|
1869
|
+
failed: "Invio non riuscito. Il log del server contiene la risposta del provider.",
|
|
1870
|
+
rateLimited,
|
|
1871
|
+
keywords: "email prova test posta trasporto smtp resend console inviare consegna",
|
|
1872
|
+
},
|
|
1853
1873
|
adminArea: {
|
|
1854
1874
|
title: "Amministrazione",
|
|
1855
1875
|
waiting: (count) => `${n(count)} in attesa`,
|
|
1876
|
+
waitingLabel: (label, count) => `${label}, ${n(count)} in attesa`,
|
|
1856
1877
|
forbiddenTitle: "Solo per gli amministratori",
|
|
1857
1878
|
forbiddenBody: (appName) =>
|
|
1858
1879
|
`Qui gli amministratori gestiscono ${appName}. Il Suo account non può aprire questa pagina.`,
|
|
@@ -1921,6 +1942,31 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
|
|
|
1921
1942
|
billingOff: "La fatturazione è disattivata in locale: i piani non cambiano nulla",
|
|
1922
1943
|
},
|
|
1923
1944
|
},
|
|
1945
|
+
// 0.45.0 — docs/local-first-harmonization.md §1.6 (`@eifi1/ui-kit/offline`): keksdose's
|
|
1946
|
+
// reviewed words (nav.logout_queued_*, pwa.*) where it has the language.
|
|
1947
|
+
signOutPending: {
|
|
1948
|
+
title: "Alcune modifiche non sono ancora state salvate sul server",
|
|
1949
|
+
lost: (count) =>
|
|
1950
|
+
count === 1
|
|
1951
|
+
? `${n(count)} modifica è ancora in attesa di sincronizzazione. Uscendo, la copia su questo dispositivo viene cancellata, ed è l’unica.`
|
|
1952
|
+
: `${n(count)} modifiche sono ancora in attesa di sincronizzazione. Uscendo, la copia su questo dispositivo viene cancellata, ed è l’unica.`,
|
|
1953
|
+
kept: (count) =>
|
|
1954
|
+
count === 1
|
|
1955
|
+
? `${n(count)} modifica è ancora in attesa di sincronizzazione. Resta per Lei su questo dispositivo e verrà sincronizzata al Suo prossimo accesso qui.`
|
|
1956
|
+
: `${n(count)} modifiche sono ancora in attesa di sincronizzazione. Restano per Lei su questo dispositivo e verranno sincronizzate al Suo prossimo accesso qui.`,
|
|
1957
|
+
syncNow: "Sincronizza ora",
|
|
1958
|
+
signOutAnyway: "Esci comunque",
|
|
1959
|
+
discardWaiting: "Scarta le modifiche in attesa",
|
|
1960
|
+
cancel: "Annulla",
|
|
1961
|
+
},
|
|
1962
|
+
pwaUpdate: {
|
|
1963
|
+
updateAvailable: "È disponibile una nuova versione.",
|
|
1964
|
+
reload: "Ricarica",
|
|
1965
|
+
},
|
|
1966
|
+
sharedComputer: {
|
|
1967
|
+
label: "Questo è un computer condiviso",
|
|
1968
|
+
hint: "Su questo dispositivo non resta alcuna copia dei Suoi dati. Le pagine si aprono quindi solo con una connessione.",
|
|
1969
|
+
},
|
|
1924
1970
|
};
|
|
1925
1971
|
}
|
|
1926
1972
|
|
package/src/i18n/locales/zh.ts
CHANGED
|
@@ -1321,11 +1321,14 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
|
|
|
1321
1321
|
},
|
|
1322
1322
|
// 0.34 (§11.5): whole phrases per noun. `team` is Kurvenschmiede's "团队"; `company`
|
|
1323
1323
|
// keeps `actions.membership_remove`'s string.
|
|
1324
|
+
renamedFromTo: (from, to) => `从 ${from} 改为 ${to}`,
|
|
1324
1325
|
groupActions: {
|
|
1325
1326
|
group: {
|
|
1326
1327
|
group_create: "群组已创建",
|
|
1327
1328
|
group_rename: "群组已重命名",
|
|
1328
1329
|
group_delete: "群组已删除",
|
|
1330
|
+
group_deactivate: "群组已停用",
|
|
1331
|
+
group_reactivate: "群组已重新激活",
|
|
1329
1332
|
membership_add: "已添加到群组",
|
|
1330
1333
|
membership_role: "群组中的角色已更改",
|
|
1331
1334
|
membership_remove: "已从群组移除",
|
|
@@ -1335,6 +1338,8 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
|
|
|
1335
1338
|
group_create: "团队已创建",
|
|
1336
1339
|
group_rename: "团队已重命名",
|
|
1337
1340
|
group_delete: "团队已删除",
|
|
1341
|
+
group_deactivate: "团队已停用",
|
|
1342
|
+
group_reactivate: "团队已重新激活",
|
|
1338
1343
|
membership_add: "已添加到团队",
|
|
1339
1344
|
membership_role: "团队中的角色已更改",
|
|
1340
1345
|
membership_remove: "已从团队移除",
|
|
@@ -1344,6 +1349,8 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
|
|
|
1344
1349
|
group_create: "公司已创建",
|
|
1345
1350
|
group_rename: "公司已重命名",
|
|
1346
1351
|
group_delete: "公司已删除",
|
|
1352
|
+
group_deactivate: "公司已停用",
|
|
1353
|
+
group_reactivate: "公司已重新激活",
|
|
1347
1354
|
membership_add: "已添加到公司",
|
|
1348
1355
|
membership_role: "公司中的角色已更改",
|
|
1349
1356
|
membership_remove: "已从公司移除",
|
|
@@ -1353,6 +1360,8 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
|
|
|
1353
1360
|
group_create: "预算已创建",
|
|
1354
1361
|
group_rename: "预算已重命名",
|
|
1355
1362
|
group_delete: "预算已删除",
|
|
1363
|
+
group_deactivate: "预算已停用",
|
|
1364
|
+
group_reactivate: "预算已重新激活",
|
|
1356
1365
|
membership_add: "已添加到预算",
|
|
1357
1366
|
membership_role: "预算中的角色已更改",
|
|
1358
1367
|
membership_remove: "已从预算移除",
|
|
@@ -1754,9 +1763,21 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
|
|
|
1754
1763
|
moreTitle: "更多页面",
|
|
1755
1764
|
},
|
|
1756
1765
|
// 0.42.0 — docs/admin-harmonization.md §3.1: the admin area's shared words.
|
|
1766
|
+
mailTestCard: {
|
|
1767
|
+
title: "测试邮件",
|
|
1768
|
+
description: "通过本安装发送所有邮件所用的传输方式,向您自己的地址发送一封邮件。",
|
|
1769
|
+
transport: (backend) => `传输方式:${backend}`,
|
|
1770
|
+
action: "给我发送测试邮件",
|
|
1771
|
+
sent: (address) => `已发送至 ${address}。请查看收件箱。`,
|
|
1772
|
+
console: "控制台传输只记录邮件,未发送任何邮件。",
|
|
1773
|
+
failed: "无法发送。服务器日志中有服务商的回复。",
|
|
1774
|
+
rateLimited,
|
|
1775
|
+
keywords: "测试邮件 邮件 电子邮件 传输 smtp resend 控制台 发送 投递",
|
|
1776
|
+
},
|
|
1757
1777
|
adminArea: {
|
|
1758
1778
|
title: "管理",
|
|
1759
1779
|
waiting: (count) => `${n(count)} 项待处理`,
|
|
1780
|
+
waitingLabel: (label, count) => `${label},${n(count)} 项待处理`,
|
|
1760
1781
|
forbiddenTitle: "仅限管理员",
|
|
1761
1782
|
forbiddenBody: (appName) => `管理员在这里管理 ${appName}。您的账户无法打开此页面。`,
|
|
1762
1783
|
forbiddenHome: "前往首页",
|
|
@@ -1822,6 +1843,25 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
|
|
|
1822
1843
|
billingOff: "本地已关闭计费:切换套餐不会改变任何内容",
|
|
1823
1844
|
},
|
|
1824
1845
|
},
|
|
1846
|
+
// 0.45.0 — docs/local-first-harmonization.md §1.6 (`@eifi1/ui-kit/offline`): keksdose's
|
|
1847
|
+
// reviewed words (nav.logout_queued_*, pwa.*) where it has the language.
|
|
1848
|
+
signOutPending: {
|
|
1849
|
+
title: "部分修改尚未保存到服务器",
|
|
1850
|
+
lost: (count) => `${n(count)} 项修改仍在等待同步。退出登录会清除此设备上的副本,而这是唯一的副本。`,
|
|
1851
|
+
kept: (count) => `${n(count)} 项修改仍在等待同步。它们会为您保留在此设备上,并在您下次在此登录时同步。`,
|
|
1852
|
+
syncNow: "立即同步",
|
|
1853
|
+
signOutAnyway: "仍然退出登录",
|
|
1854
|
+
discardWaiting: "放弃等待中的修改",
|
|
1855
|
+
cancel: "取消",
|
|
1856
|
+
},
|
|
1857
|
+
pwaUpdate: {
|
|
1858
|
+
updateAvailable: "有新版本可用。",
|
|
1859
|
+
reload: "重新加载",
|
|
1860
|
+
},
|
|
1861
|
+
sharedComputer: {
|
|
1862
|
+
label: "这是一台共用电脑",
|
|
1863
|
+
hint: "此设备上不会保留您的数据副本。页面将只能在联网时打开。",
|
|
1864
|
+
},
|
|
1825
1865
|
};
|
|
1826
1866
|
}
|
|
1827
1867
|
|
package/src/i18n/review.ts
CHANGED
|
@@ -353,6 +353,8 @@ export const KIT_LABEL_SAMPLES: Readonly<Record<string, readonly (readonly unkno
|
|
|
353
353
|
"adminActionLog.by": [["{{actor}}"]],
|
|
354
354
|
"adminActionLog.filteredTo": [["{{target}}"]],
|
|
355
355
|
"adminActionLog.filterBy": [["{{target}}"]],
|
|
356
|
+
// 0.45.0 (admin §9.4): a company rename that logged both names.
|
|
357
|
+
"adminActionLog.renamedFromTo": [["{{from}}", "{{to}}"]],
|
|
356
358
|
"transferOwnership.title": [["{{name}}"]],
|
|
357
359
|
"transferOwnership.unavailable": [["{{account}}", "{{reason}}"]],
|
|
358
360
|
"invitations.sent": [["{{date}}"]],
|
|
@@ -406,6 +408,12 @@ export const KIT_LABEL_SAMPLES: Readonly<Record<string, readonly (readonly unkno
|
|
|
406
408
|
// 0.42.0 (docs/admin-harmonization.md §3.1): the menu row's count, the 403 page's app,
|
|
407
409
|
// the users tile's new accounts.
|
|
408
410
|
"adminArea.waiting": one,
|
|
411
|
+
// 0.45.0 (admin §9.3.4): an IconButton's name with its waiting count.
|
|
412
|
+
"adminArea.waitingLabel": [["{{label}}", 1], ["{{label}}", 3]],
|
|
413
|
+
// 0.45.0 (admin §9.2.4): the test mail's transport, masked address and limiter.
|
|
414
|
+
"mailTestCard.transport": [["{{backend}}"]],
|
|
415
|
+
"mailTestCard.sent": [["{{address}}"]],
|
|
416
|
+
"mailTestCard.rateLimited": [[], [30], [300]],
|
|
409
417
|
"adminArea.forbiddenBody": [["{{app}}"]],
|
|
410
418
|
"adminArea.tiles.usersNew": one,
|
|
411
419
|
// 0.42.0 (docs/top-bar-harmonization.md §3.1): the sync indicator's counts, its time, the
|
|
@@ -431,4 +439,8 @@ export const KIT_LABEL_SAMPLES: Readonly<Record<string, readonly (readonly unkno
|
|
|
431
439
|
"tourCatalogue.steps": one,
|
|
432
440
|
"tourCatalogue.duration": one,
|
|
433
441
|
"tourCatalogue.completedOn": [["{{date}}"]],
|
|
442
|
+
// 0.45.0 (docs/local-first-harmonization.md §1.6): the sign-out question's count, in
|
|
443
|
+
// both word sets.
|
|
444
|
+
"signOutPending.lost": one,
|
|
445
|
+
"signOutPending.kept": one,
|
|
434
446
|
};
|
package/src/index.ts
CHANGED
|
@@ -811,6 +811,9 @@ export type {
|
|
|
811
811
|
} from "./admin/admin-overview";
|
|
812
812
|
export { AdminToolLinks } from "./admin/admin-tool-links";
|
|
813
813
|
export type { AdminToolLink, AdminToolLinksProps } from "./admin/admin-tool-links";
|
|
814
|
+
// 0.45.0 (docs/admin-harmonization.md §9.2.4): "Send a test mail to me".
|
|
815
|
+
export { MailTestCard, DEFAULT_MAIL_TEST_CARD_LABELS, MAIL_TEST_ANCHOR, maskMailAddress } from "./admin/mail-test-card";
|
|
816
|
+
export type { MailTestCardProps, MailTestCardLabels, MailTestAnswer } from "./admin/mail-test-card";
|
|
814
817
|
// 0.33.0: the operator's plan parts (docs/billing-harmonization.md §14.12).
|
|
815
818
|
export {
|
|
816
819
|
planColumn,
|
package/src/lib/format.ts
CHANGED
|
@@ -182,10 +182,14 @@ const DATE_STYLES: Record<FormatDateStyle, Intl.DateTimeFormatOptions> = {
|
|
|
182
182
|
};
|
|
183
183
|
|
|
184
184
|
export interface FormatDateOptions extends BaseOptions {
|
|
185
|
-
/** An IANA zone ("Europe/Zurich") for a timestamp. Left out: the device's.
|
|
185
|
+
/** An IANA zone ("Europe/Zurich") for a timestamp. Left out: the device's. A bare
|
|
186
|
+
* "YYYY-MM-DD" ignores it: a calendar day is the day it names in every zone. */
|
|
186
187
|
timeZone?: string;
|
|
187
188
|
}
|
|
188
189
|
|
|
190
|
+
/** A bare ISO calendar day, `"YYYY-MM-DD"`. */
|
|
191
|
+
const BARE_ISO_DAY = /^\d{4}-\d{2}-\d{2}$/;
|
|
192
|
+
|
|
189
193
|
/** What {@link formatDate} and {@link formatRelativeTime} accept. */
|
|
190
194
|
export type DateInput = string | number | Date | null | undefined;
|
|
191
195
|
|
|
@@ -197,7 +201,7 @@ export type DateInput = string | number | Date | null | undefined;
|
|
|
197
201
|
*/
|
|
198
202
|
export function toDate(value: DateInput): Date | null {
|
|
199
203
|
if (value === null || value === undefined || value === "") return null;
|
|
200
|
-
if (typeof value === "string" &&
|
|
204
|
+
if (typeof value === "string" && BARE_ISO_DAY.test(value)) return parseIsoDate(value);
|
|
201
205
|
const d = value instanceof Date ? value : new Date(value);
|
|
202
206
|
return Number.isNaN(d.getTime()) ? null : d;
|
|
203
207
|
}
|
|
@@ -229,6 +233,13 @@ export function formatDate(
|
|
|
229
233
|
const d = toDate(value);
|
|
230
234
|
if (!d) return options.empty ?? EMPTY_FORMATTED_VALUE;
|
|
231
235
|
const base = typeof style === "string" ? DATE_STYLES[style] : style;
|
|
236
|
+
// A bare "YYYY-MM-DD" is a calendar day, which has no zone: it is the day it names
|
|
237
|
+
// wherever it is read, so a `timeZone` (in `options` or the style) never moves it — the
|
|
238
|
+
// device's local midnight shown in a zone west of it was the day before (round 0.45, N9).
|
|
239
|
+
if (typeof value === "string" && BARE_ISO_DAY.test(value)) {
|
|
240
|
+
const day = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
|
|
241
|
+
return dateFormatter(options.locale, { ...base, timeZone: "UTC" }).format(day);
|
|
242
|
+
}
|
|
232
243
|
return dateFormatter(options.locale, options.timeZone ? { ...base, timeZone: options.timeZone } : base).format(d);
|
|
233
244
|
}
|
|
234
245
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// The English words of ./pwa-update-prompt, in a module with no component code (0.34, KS U8).
|
|
2
|
+
// keksdose's reviewed words (pwa.updateAvailable, pwa.reload) are the canon.
|
|
3
|
+
|
|
4
|
+
import type { PwaUpdatePromptLabels } from "./pwa-update-prompt";
|
|
5
|
+
|
|
6
|
+
export const DEFAULT_PWA_UPDATE_PROMPT_LABELS: PwaUpdatePromptLabels = {
|
|
7
|
+
updateAvailable: "A new version is available.",
|
|
8
|
+
reload: "Reload",
|
|
9
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
import { useKitLabels, type LabelOverride } from "../i18n/kit-labels";
|
|
3
|
+
import { toast } from "../components/toast";
|
|
4
|
+
import { DEFAULT_PWA_UPDATE_PROMPT_LABELS } from "./pwa-update-prompt-labels";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* "A new version is available. — Reload": keksdose's service-worker toast
|
|
8
|
+
* (app/pwa-update-prompt.tsx) as a kit component (docs/local-first-harmonization.md §1.5
|
|
9
|
+
* D8). The app keeps `useRegisterSW` (vite-plugin-pwa, `registerType: "prompt"`) and hands
|
|
10
|
+
* its state in: `needRefresh` from it, `onReload` = `updateServiceWorker(true)`,
|
|
11
|
+
* `onDismiss` = `setNeedRefresh(false)`.
|
|
12
|
+
*
|
|
13
|
+
* `hold` defers the prompt while a reload would hurt — a handover being signed, a tour
|
|
14
|
+
* running. Nothing shows while it holds; the toast appears once it drops. A hold that
|
|
15
|
+
* starts while the toast is up takes it down again until it drops.
|
|
16
|
+
*
|
|
17
|
+
* Renders nothing itself: the toast needs a mounted `<Toaster>`.
|
|
18
|
+
*/
|
|
19
|
+
export interface PwaUpdatePromptLabels {
|
|
20
|
+
updateAvailable: string;
|
|
21
|
+
reload: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Defined in ./pwa-update-prompt-labels, which holds no component code (0.34, KS U8).
|
|
25
|
+
export { DEFAULT_PWA_UPDATE_PROMPT_LABELS };
|
|
26
|
+
|
|
27
|
+
export interface PwaUpdatePromptProps {
|
|
28
|
+
/** A new service worker is waiting. */
|
|
29
|
+
needRefresh: boolean;
|
|
30
|
+
/** Activates it and reloads — `updateServiceWorker(true)`. */
|
|
31
|
+
onReload: () => void;
|
|
32
|
+
/** The toast was closed without reloading. */
|
|
33
|
+
onDismiss?: () => void;
|
|
34
|
+
/** Wait: a handover is open, a tour runs. */
|
|
35
|
+
hold?: boolean;
|
|
36
|
+
labels?: LabelOverride<PwaUpdatePromptLabels>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The toast's id: one prompt at a time, replaced in place. */
|
|
40
|
+
const PWA_UPDATE_TOAST_ID = "pwa-update";
|
|
41
|
+
|
|
42
|
+
export function PwaUpdatePrompt({ needRefresh, onReload, onDismiss, hold = false, labels: labelsProp }: PwaUpdatePromptProps) {
|
|
43
|
+
const labels = useKitLabels("pwaUpdate", DEFAULT_PWA_UPDATE_PROMPT_LABELS, labelsProp);
|
|
44
|
+
// The callbacks are read at click time, so a new function each render does not
|
|
45
|
+
// re-raise the toast.
|
|
46
|
+
const handlers = useRef({ onReload, onDismiss });
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
handlers.current = { onReload, onDismiss };
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const show = needRefresh && !hold;
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (!show) return;
|
|
54
|
+
// sonner calls `onDismiss` for a programmatic dismiss too: the one this effect makes
|
|
55
|
+
// when a hold starts must not tell the app the person waved the update away.
|
|
56
|
+
let ours = false;
|
|
57
|
+
toast(labels.updateAvailable, {
|
|
58
|
+
id: PWA_UPDATE_TOAST_ID,
|
|
59
|
+
duration: Infinity,
|
|
60
|
+
action: { label: labels.reload, onClick: () => handlers.current.onReload() },
|
|
61
|
+
onDismiss: () => {
|
|
62
|
+
if (!ours) handlers.current.onDismiss?.();
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
return () => {
|
|
66
|
+
ours = true;
|
|
67
|
+
toast.dismiss(PWA_UPDATE_TOAST_ID);
|
|
68
|
+
};
|
|
69
|
+
}, [show, labels.updateAvailable, labels.reload]);
|
|
70
|
+
|
|
71
|
+
return null;
|
|
72
|
+
}
|