@firecms/core 3.4.0 → 3.5.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 +4 -0
- package/dist/components/LicenseBanner.d.ts +24 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/contexts/LicenseStatusContext.d.ts +16 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/plugin_translations.d.ts +38 -0
- package/dist/core/pro_plugins.d.ts +40 -0
- package/dist/de-CBOjCvsy.js +707 -0
- package/dist/de-CBOjCvsy.js.map +1 -0
- package/dist/editor/extensions/Image.d.ts +11 -0
- package/dist/editor/index.d.ts +2 -1
- package/dist/editor/lazy_editor.d.ts +6 -0
- package/dist/editor-BSo_aS1I.js +4563 -0
- package/dist/editor-BSo_aS1I.js.map +1 -0
- package/dist/fr-DRfttcG0.js +707 -0
- package/dist/fr-DRfttcG0.js.map +1 -0
- package/dist/hi-DwieOZNf.js +707 -0
- package/dist/hi-DwieOZNf.js.map +1 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/useLicenseStatus.d.ts +16 -0
- package/dist/hooks/useProjectLog.d.ts +11 -6
- package/dist/hooks/useTranslation.d.ts +1 -1
- package/dist/index.es.js +2373 -10281
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +13166 -12269
- package/dist/index.umd.js.map +1 -1
- package/dist/it-l2KXtx9n.js +707 -0
- package/dist/it-l2KXtx9n.js.map +1 -0
- package/dist/pl-DPZrdKhi.js +709 -0
- package/dist/pl-DPZrdKhi.js.map +1 -0
- package/dist/pt-BoHpabw1.js +709 -0
- package/dist/pt-BoHpabw1.js.map +1 -0
- package/dist/types/analytics.d.ts +1 -1
- package/dist/types/firecms.d.ts +18 -1
- package/dist/types/firecms_context.d.ts +8 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/license.d.ts +81 -0
- package/dist/types/plugins.d.ts +9 -1
- package/dist/types/translations.d.ts +45 -2
- package/dist/util/date_fns_locales.d.ts +18 -0
- package/dist/util/index.d.ts +1 -0
- package/dist/util/lazy_eager.d.ts +3 -3
- package/dist/util/local_storage.d.ts +23 -0
- package/package.json +4 -5
- package/src/app/Scaffold.tsx +7 -0
- package/src/components/EntityCollectionView/utils.ts +4 -4
- package/src/components/LicenseBanner.tsx +287 -0
- package/src/components/index.tsx +1 -0
- package/src/contexts/LicenseStatusContext.tsx +50 -0
- package/src/core/DefaultAppBar.tsx +28 -16
- package/src/core/FireCMS.tsx +73 -47
- package/src/core/SideDialogs.tsx +44 -1
- package/src/core/index.tsx +1 -0
- package/src/core/plugin_translations.ts +87 -0
- package/src/core/pro_plugins.ts +79 -0
- package/src/editor/components/SlashCommandMenu.tsx +4 -1
- package/src/editor/extensions/Image.ts +17 -1
- package/src/editor/hooks/useProseMirror.ts +5 -0
- package/src/editor/index.ts +11 -1
- package/src/editor/lazy_editor.tsx +33 -0
- package/src/hooks/index.tsx +2 -0
- package/src/hooks/useBuildLocalConfigurationPersistence.tsx +9 -9
- package/src/hooks/useBuildModeController.tsx +6 -4
- package/src/hooks/useBuildNavigationController.tsx +47 -7
- package/src/hooks/useFireCMSContext.tsx +7 -3
- package/src/hooks/useLicenseStatus.tsx +32 -0
- package/src/hooks/useProjectLog.tsx +27 -9
- package/src/hooks/useTranslation.ts +3 -1
- package/src/i18n/FireCMSi18nProvider.tsx +169 -42
- package/src/locales/de.ts +23 -2
- package/src/locales/en.ts +28 -5
- package/src/locales/es.ts +23 -2
- package/src/locales/fr.ts +23 -2
- package/src/locales/hi.ts +23 -2
- package/src/locales/it.ts +23 -2
- package/src/locales/pl.ts +23 -2
- package/src/locales/pt.ts +23 -2
- package/src/preview/components/DatePreview.tsx +2 -4
- package/src/types/analytics.ts +3 -0
- package/src/types/firecms.tsx +19 -1
- package/src/types/firecms_context.tsx +9 -0
- package/src/types/index.ts +1 -0
- package/src/types/license.ts +90 -0
- package/src/types/plugins.tsx +10 -1
- package/src/types/translations.ts +45 -2
- package/src/util/date_fns_locales.ts +168 -0
- package/src/util/entity_cache.ts +10 -2
- package/src/util/index.ts +1 -0
- package/src/util/lazy_eager.tsx +30 -8
- package/src/util/local_storage.ts +52 -0
- package/src/util/navigation_utils.ts +6 -1
- package/src/util/useStorageUploadController.tsx +6 -1
package/src/locales/it.ts
CHANGED
|
@@ -65,8 +65,23 @@ export const it: FireCMSTranslations = {
|
|
|
65
65
|
select_from: "Seleziona da {{name}}",
|
|
66
66
|
done: "Fatto",
|
|
67
67
|
log_out: "Esci",
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
license_trial_banner: "Prova di FireCMS PRO: restano {{days}} giorni in produzione.",
|
|
69
|
+
license_trial_banner_one: "Prova di FireCMS PRO: resta {{days}} giorno in produzione.",
|
|
70
|
+
license_expired_banner: "La tua prova PRO è terminata il {{date}}. Le funzioni PRO, come l'editor degli schemi, l'importazione/esportazione e la cronologia, sono in pausa; i tuoi dati e le tue collezioni continuano a funzionare.",
|
|
71
|
+
license_expired_banner_undated: "La tua prova PRO è terminata. Le funzioni PRO, come l'editor degli schemi, l'importazione/esportazione e la cronologia, sono in pausa; i tuoi dati e le tue collezioni continuano a funzionare.",
|
|
72
|
+
license_invalid_project_banner: "Questa chiave di licenza non è collegata al progetto {{projectId}}. Le funzionalità PRO restano in pausa finché non lo sarà.",
|
|
73
|
+
license_invalid_project_banner_unnamed: "Questa chiave di licenza non è collegata a questo progetto. Le funzionalità PRO restano in pausa finché non lo sarà.",
|
|
74
|
+
license_over_quota_banner: "La licenza di questo progetto copre {{licensed}} progetti in produzione, e questo non è tra quelli. Le funzioni PRO, come l'editor degli schemi, l'importazione/esportazione e la cronologia, sono in pausa; i tuoi dati e le tue collezioni continuano a funzionare.",
|
|
75
|
+
license_over_quota_banner_one: "La licenza di questo progetto copre {{licensed}} progetto in produzione, ed è un altro. Le funzioni PRO, come l'editor degli schemi, l'importazione/esportazione e la cronologia, sono in pausa; i tuoi dati e le tue collezioni continuano a funzionare.",
|
|
76
|
+
license_get_license: "Ottieni una licenza",
|
|
77
|
+
license_update_license: "Aggiorna la tua licenza",
|
|
78
|
+
license_add_project_to_license: "Aggiungilo alla tua licenza",
|
|
79
|
+
pro_suggestion_user_management: "{{users}} persone usano questo CMS. FireCMS PRO aggiunge la gestione degli utenti, con ruoli e permessi per collezione, gratis per 30 giorni in produzione.",
|
|
80
|
+
pro_suggestion_user_management_uncounted: "FireCMS PRO aggiunge la gestione degli utenti, con ruoli e permessi per collezione, gratis per 30 giorni in produzione.",
|
|
81
|
+
pro_suggestion_entity_history: "FireCMS PRO conserva la cronologia di ogni modifica ai tuoi contenuti e di chi l'ha fatta, e ti permette di annullarla. Gratis per 30 giorni in produzione.",
|
|
82
|
+
pro_suggestion_learn_more: "Come aggiungerlo",
|
|
83
|
+
pro_features_paused: "Funzionalità PRO in pausa",
|
|
84
|
+
user_management_paused_description: "La gestione di utenti e ruoli fa parte di FireCMS PRO. I tuoi utenti e ruoli attuali continuano a decidere chi può accedere e cosa può fare, e potrai modificarli di nuovo quando questo progetto avrà una licenza.",
|
|
70
85
|
column_cannot_be_edited: "Questa colonna non può essere modificata direttamente",
|
|
71
86
|
close: "Chiudi",
|
|
72
87
|
unsaved_local_changes: "Modifiche locali non salvate",
|
|
@@ -390,6 +405,9 @@ export const it: FireCMSTranslations = {
|
|
|
390
405
|
large_number_of_documents: "Questa collezione contiene un numero elevato di documenti ({{count}})",
|
|
391
406
|
include_undefined_values: "Includi valori non definiti",
|
|
392
407
|
export_apply_filter_sort: "Esporta solo i risultati che corrispondono al filtro/ordinamento attuale",
|
|
408
|
+
export_all_entities: "Tutte le entità",
|
|
409
|
+
export_selected_entities: "Entità selezionate ({{count}})",
|
|
410
|
+
export_error: "Impossibile esportare i dati: {{message}}",
|
|
393
411
|
submit: "Invia",
|
|
394
412
|
|
|
395
413
|
no_filterable_properties: "Nessuna proprietà filtrabile disponibile",
|
|
@@ -439,6 +457,7 @@ export const it: FireCMSTranslations = {
|
|
|
439
457
|
roles_menu: "Ruoli",
|
|
440
458
|
project_settings: "Impostazioni del progetto",
|
|
441
459
|
firestore_manager: "Gestore Firestore",
|
|
460
|
+
datatalk: "DataTalk",
|
|
442
461
|
manage_your_firestore_data: "Gestisci i tuoi dati Firestore",
|
|
443
462
|
|
|
444
463
|
// ─── FireCMS Cloud Login ──────────────────────────────────────
|
|
@@ -455,6 +474,7 @@ export const it: FireCMSTranslations = {
|
|
|
455
474
|
not_the_admin_panel: "non sul pannello di amministrazione.",
|
|
456
475
|
join_our_newsletter: "Iscriviti alla nostra newsletter. Niente spam, solo aggiornamenti importanti!",
|
|
457
476
|
by_signing_in_you_agree_to_our: "Accedendo accetti i nostri",
|
|
477
|
+
please_accept_the_terms_to_continue: "Accetta i termini e le condizioni per continuare",
|
|
458
478
|
terms_and_conditions: "Termini e Condizioni",
|
|
459
479
|
and_our: "e la nostra",
|
|
460
480
|
privacy_policy: "Informativa sulla privacy",
|
|
@@ -497,6 +517,7 @@ export const it: FireCMSTranslations = {
|
|
|
497
517
|
licensed_projects_lowercase: "progetti con licenza",
|
|
498
518
|
manage: "Gestisci",
|
|
499
519
|
update_payment_method: "Aggiorna metodo di pagamento",
|
|
520
|
+
stripe_portal_error: "Impossibile aprire Stripe: {{message}}",
|
|
500
521
|
your_firecms_cloud_projects: "I tuoi progetti FireCMS Cloud",
|
|
501
522
|
status_active: "Attivo",
|
|
502
523
|
status_trialing: "In prova",
|
package/src/locales/pl.ts
CHANGED
|
@@ -65,8 +65,23 @@ export const pl: FireCMSTranslations = {
|
|
|
65
65
|
select_from: "Wybierz z {{name}}",
|
|
66
66
|
done: "Gotowe",
|
|
67
67
|
log_out: "Wyloguj się",
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
license_trial_banner: "Okres próbny FireCMS PRO w produkcji kończy się za {{days}} dni.",
|
|
69
|
+
license_trial_banner_one: "Okres próbny FireCMS PRO w produkcji kończy się za {{days}} dzień.",
|
|
70
|
+
license_expired_banner: "Twój okres próbny PRO zakończył się {{date}}. Funkcje PRO, takie jak edytor schematów, import/eksport i historia, są wstrzymane; Twoje dane i kolekcje nadal działają.",
|
|
71
|
+
license_expired_banner_undated: "Twój okres próbny PRO się zakończył. Funkcje PRO, takie jak edytor schematów, import/eksport i historia, są wstrzymane; Twoje dane i kolekcje nadal działają.",
|
|
72
|
+
license_invalid_project_banner: "Ten klucz licencyjny nie jest powiązany z projektem {{projectId}}. Do tego czasu funkcje PRO są wstrzymane.",
|
|
73
|
+
license_invalid_project_banner_unnamed: "Ten klucz licencyjny nie jest powiązany z tym projektem. Do tego czasu funkcje PRO są wstrzymane.",
|
|
74
|
+
license_over_quota_banner: "Liczba projektów w produkcji objętych licencją tego projektu: {{licensed}}. Ten projekt do nich nie należy. Funkcje PRO, takie jak edytor schematów, import/eksport i historia, są wstrzymane; Twoje dane i kolekcje nadal działają.",
|
|
75
|
+
license_over_quota_banner_one: "Licencja tego projektu obejmuje {{licensed}} projekt w produkcji i jest to inny projekt. Funkcje PRO, takie jak edytor schematów, import/eksport i historia, są wstrzymane; Twoje dane i kolekcje nadal działają.",
|
|
76
|
+
license_get_license: "Kup licencję",
|
|
77
|
+
license_update_license: "Zaktualizuj licencję",
|
|
78
|
+
license_add_project_to_license: "Dodaj go do licencji",
|
|
79
|
+
pro_suggestion_user_management: "Liczba osób korzystających z tego CMS: {{users}}. FireCMS PRO dodaje zarządzanie użytkownikami z rolami i uprawnieniami dla każdej kolekcji, bezpłatnie przez 30 dni w produkcji.",
|
|
80
|
+
pro_suggestion_user_management_uncounted: "FireCMS PRO dodaje zarządzanie użytkownikami z rolami i uprawnieniami dla każdej kolekcji, bezpłatnie przez 30 dni w produkcji.",
|
|
81
|
+
pro_suggestion_entity_history: "FireCMS PRO zapisuje historię każdej zmiany treści wraz z jej autorem i pozwala ją cofnąć. Bezpłatnie przez 30 dni w produkcji.",
|
|
82
|
+
pro_suggestion_learn_more: "Zobacz, jak to dodać",
|
|
83
|
+
pro_features_paused: "Funkcje PRO wstrzymane",
|
|
84
|
+
user_management_paused_description: "Zarządzanie użytkownikami i rolami jest częścią FireCMS PRO. Dotychczasowi użytkownicy i role nadal decydują o tym, kto może się zalogować i co może robić. Edytować je będzie można ponownie, gdy ten projekt otrzyma licencję.",
|
|
70
85
|
column_cannot_be_edited: "Ta kolumna nie może być edytowana bezpośrednio",
|
|
71
86
|
close: "Zamknij",
|
|
72
87
|
unsaved_local_changes: "Niezapisane zmiany lokalne",
|
|
@@ -390,6 +405,9 @@ export const pl: FireCMSTranslations = {
|
|
|
390
405
|
large_number_of_documents: "Ta kolekcja zawiera dużą liczbę dokumentów ({{count}}).",
|
|
391
406
|
include_undefined_values: "Uwzględnij niezdefiniowane wartości",
|
|
392
407
|
export_apply_filter_sort: "Eksportuj tylko wyniki zgodne z aktualnym filtrem/sortowaniem",
|
|
408
|
+
export_all_entities: "Wszystkie encje",
|
|
409
|
+
export_selected_entities: "Zaznaczone encje ({{count}})",
|
|
410
|
+
export_error: "Nie udało się wyeksportować danych: {{message}}",
|
|
393
411
|
submit: "Wyślij",
|
|
394
412
|
|
|
395
413
|
no_filterable_properties: "Brak dostępnych właściwości do filtrowania",
|
|
@@ -439,6 +457,7 @@ export const pl: FireCMSTranslations = {
|
|
|
439
457
|
roles_menu: "Role",
|
|
440
458
|
project_settings: "Ustawienia projektu",
|
|
441
459
|
firestore_manager: "Menedżer Firestore",
|
|
460
|
+
datatalk: "DataTalk",
|
|
442
461
|
manage_your_firestore_data: "Zarządzaj danymi w Firestore",
|
|
443
462
|
|
|
444
463
|
// ─── FireCMS Cloud Login ──────────────────────────────────────
|
|
@@ -455,6 +474,7 @@ export const pl: FireCMSTranslations = {
|
|
|
455
474
|
not_the_admin_panel: "a nie na panelu administracyjnym.",
|
|
456
475
|
join_our_newsletter: "Dołącz do naszego newslettera. Bez spamu, tylko ważne aktualizacje!",
|
|
457
476
|
by_signing_in_you_agree_to_our: "Logując się, akceptujesz nasz",
|
|
477
|
+
please_accept_the_terms_to_continue: "Zaakceptuj regulamin, aby kontynuować",
|
|
458
478
|
terms_and_conditions: "Regulamin",
|
|
459
479
|
and_our: "oraz naszą",
|
|
460
480
|
privacy_policy: "Politykę prywatności",
|
|
@@ -497,6 +517,7 @@ export const pl: FireCMSTranslations = {
|
|
|
497
517
|
licensed_projects_lowercase: "licencjonowanych projektów",
|
|
498
518
|
manage: "Zarządzaj",
|
|
499
519
|
update_payment_method: "Zaktualizuj metodę płatności",
|
|
520
|
+
stripe_portal_error: "Nie udało się otworzyć Stripe: {{message}}",
|
|
500
521
|
your_firecms_cloud_projects: "Twoje projekty FireCMS Cloud",
|
|
501
522
|
status_active: "Aktywna",
|
|
502
523
|
status_trialing: "Okres próbny",
|
package/src/locales/pt.ts
CHANGED
|
@@ -70,8 +70,23 @@ export const pt: FireCMSTranslations = {
|
|
|
70
70
|
select_from: "Selecionar de {{name}}",
|
|
71
71
|
done: "Concluído",
|
|
72
72
|
log_out: "Terminar sessão",
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
license_trial_banner: "Avaliação do FireCMS PRO: faltam {{days}} dias em produção.",
|
|
74
|
+
license_trial_banner_one: "Avaliação do FireCMS PRO: falta {{days}} dia em produção.",
|
|
75
|
+
license_expired_banner: "A sua avaliação PRO terminou a {{date}}. As funcionalidades PRO, como o editor de esquemas, a importação/exportação e o histórico, estão em pausa; os seus dados e coleções continuam a funcionar.",
|
|
76
|
+
license_expired_banner_undated: "A sua avaliação PRO terminou. As funcionalidades PRO, como o editor de esquemas, a importação/exportação e o histórico, estão em pausa; os seus dados e coleções continuam a funcionar.",
|
|
77
|
+
license_invalid_project_banner: "Esta chave de licença não está associada ao projeto {{projectId}}. As funcionalidades PRO ficam em pausa até que esteja.",
|
|
78
|
+
license_invalid_project_banner_unnamed: "Esta chave de licença não está associada a este projeto. As funcionalidades PRO ficam em pausa até que esteja.",
|
|
79
|
+
license_over_quota_banner: "A licença deste projeto cobre {{licensed}} projetos em produção e este não é um deles. As funcionalidades PRO, como o editor de esquemas, a importação/exportação e o histórico, estão em pausa; os seus dados e coleções continuam a funcionar.",
|
|
80
|
+
license_over_quota_banner_one: "A licença deste projeto cobre {{licensed}} projeto em produção e é outro. As funcionalidades PRO, como o editor de esquemas, a importação/exportação e o histórico, estão em pausa; os seus dados e coleções continuam a funcionar.",
|
|
81
|
+
license_get_license: "Obter uma licença",
|
|
82
|
+
license_update_license: "Atualizar a sua licença",
|
|
83
|
+
license_add_project_to_license: "Adicioná-lo à sua licença",
|
|
84
|
+
pro_suggestion_user_management: "{{users}} pessoas usam este CMS. O FireCMS PRO acrescenta a gestão de utilizadores, com funções e permissões por coleção, grátis durante 30 dias em produção.",
|
|
85
|
+
pro_suggestion_user_management_uncounted: "O FireCMS PRO acrescenta a gestão de utilizadores, com funções e permissões por coleção, grátis durante 30 dias em produção.",
|
|
86
|
+
pro_suggestion_entity_history: "O FireCMS PRO guarda o histórico de cada alteração ao seu conteúdo e de quem a fez, e permite revertê-la. Grátis durante 30 dias em produção.",
|
|
87
|
+
pro_suggestion_learn_more: "Como adicioná-lo",
|
|
88
|
+
pro_features_paused: "Funcionalidades PRO em pausa",
|
|
89
|
+
user_management_paused_description: "A gestão de utilizadores e funções faz parte do FireCMS PRO. Os seus utilizadores e funções atuais continuam a decidir quem pode iniciar sessão e o que pode fazer, e poderá voltar a editá-los assim que este projeto tiver uma licença.",
|
|
75
90
|
column_cannot_be_edited: "Esta coluna não pode ser editada diretamente",
|
|
76
91
|
close: "Fechar",
|
|
77
92
|
unsaved_local_changes: "Alterações locais não guardadas",
|
|
@@ -395,6 +410,9 @@ export const pt: FireCMSTranslations = {
|
|
|
395
410
|
large_number_of_documents: "Esta coleção tem um grande número de documentos ({{count}}).",
|
|
396
411
|
include_undefined_values: "Incluir valores indefinidos",
|
|
397
412
|
export_apply_filter_sort: "Exportar apenas os resultados que correspondem ao filtro/ordenação atual",
|
|
413
|
+
export_all_entities: "Todas as entidades",
|
|
414
|
+
export_selected_entities: "Entidades selecionadas ({{count}})",
|
|
415
|
+
export_error: "Não foi possível exportar os dados: {{message}}",
|
|
398
416
|
submit: "Submeter",
|
|
399
417
|
|
|
400
418
|
no_filterable_properties: "Não há propriedades filtráveis disponíveis",
|
|
@@ -444,6 +462,7 @@ export const pt: FireCMSTranslations = {
|
|
|
444
462
|
roles_menu: "Funções",
|
|
445
463
|
project_settings: "Definições do projeto",
|
|
446
464
|
firestore_manager: "Gerenciador do Firestore",
|
|
465
|
+
datatalk: "DataTalk",
|
|
447
466
|
manage_your_firestore_data: "Gerencie os seus dados do Firestore",
|
|
448
467
|
|
|
449
468
|
// ─── FireCMS Cloud Login ──────────────────────────────────────
|
|
@@ -460,6 +479,7 @@ export const pt: FireCMSTranslations = {
|
|
|
460
479
|
not_the_admin_panel: "não no painel de administração.",
|
|
461
480
|
join_our_newsletter: "Subscreva a nossa newsletter. Sem spam, apenas atualizações importantes!",
|
|
462
481
|
by_signing_in_you_agree_to_our: "Ao iniciar sessão, concorda com os nossos",
|
|
482
|
+
please_accept_the_terms_to_continue: "Aceite os termos e condições para continuar",
|
|
463
483
|
terms_and_conditions: "Termos e Condições",
|
|
464
484
|
and_our: "e a nossa",
|
|
465
485
|
privacy_policy: "Política de privacidade",
|
|
@@ -502,6 +522,7 @@ export const pt: FireCMSTranslations = {
|
|
|
502
522
|
licensed_projects_lowercase: "projetos licenciados",
|
|
503
523
|
manage: "Gerir",
|
|
504
524
|
update_payment_method: "Atualizar método de pagamento",
|
|
525
|
+
stripe_portal_error: "Não foi possível abrir o Stripe: {{message}}",
|
|
505
526
|
your_firecms_cloud_projects: "Os seus projetos FireCMS Cloud",
|
|
506
527
|
status_active: "Ativo",
|
|
507
528
|
status_trialing: "Em avaliação",
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
3
|
import { format } from "date-fns";
|
|
4
|
-
import * as locales from "date-fns/locale";
|
|
5
4
|
import { useCustomizationController } from "../../hooks";
|
|
6
|
-
import { defaultDateFormat } from "../../util";
|
|
5
|
+
import { defaultDateFormat, useDateFnsLocale } from "../../util";
|
|
7
6
|
|
|
8
7
|
export interface DatePreviewProps {
|
|
9
8
|
date: Date;
|
|
@@ -28,8 +27,7 @@ export function DatePreview({
|
|
|
28
27
|
}: DatePreviewProps): React.ReactElement {
|
|
29
28
|
|
|
30
29
|
const customizationController = useCustomizationController();
|
|
31
|
-
|
|
32
|
-
const dateUtilsLocale = customizationController?.locale ? locales[customizationController?.locale] : undefined;
|
|
30
|
+
const dateUtilsLocale = useDateFnsLocale(customizationController?.locale);
|
|
33
31
|
|
|
34
32
|
if (!date) {
|
|
35
33
|
return <></>;
|
package/src/types/analytics.ts
CHANGED
package/src/types/firecms.tsx
CHANGED
|
@@ -70,10 +70,28 @@ export type FireCMSProps<USER extends User> = {
|
|
|
70
70
|
}) => React.ReactNode;
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
|
-
*
|
|
73
|
+
* Your FireCMS PRO license key. It is checked against
|
|
74
|
+
* `https://api.firecms.co/access_log` when a user signs in.
|
|
74
75
|
*/
|
|
75
76
|
apiKey?: string;
|
|
76
77
|
|
|
78
|
+
/**
|
|
79
|
+
* On sign-in FireCMS sends one request to `https://api.firecms.co/access_log`
|
|
80
|
+
* with the user's ID token (which carries the Firebase project id, the uid
|
|
81
|
+
* and the email), the user's email, the datasource key and the keys of the
|
|
82
|
+
* mounted plugins; the browser adds the page's referrer. It is how the
|
|
83
|
+
* FireCMS PRO license and trial are checked. No database credentials or
|
|
84
|
+
* content are sent.
|
|
85
|
+
*
|
|
86
|
+
* Set to `false` to skip that request. This only takes effect when the
|
|
87
|
+
* app has no `apiKey` and mounts no PRO plugin (collection editor, user
|
|
88
|
+
* management, import/export, entity history, data enhancement, DataTalk):
|
|
89
|
+
* otherwise the request is the license check and is always sent.
|
|
90
|
+
*
|
|
91
|
+
* Defaults to `true`.
|
|
92
|
+
*/
|
|
93
|
+
telemetry?: boolean;
|
|
94
|
+
|
|
77
95
|
/**
|
|
78
96
|
* Record of custom form fields to be used in the CMS.
|
|
79
97
|
* You can use the key to reference the custom field in
|
|
@@ -11,6 +11,7 @@ import { DialogsController } from "./dialogs_controller";
|
|
|
11
11
|
import { CustomizationController } from "./customization_controller";
|
|
12
12
|
import { AnalyticsController } from "./analytics_controller";
|
|
13
13
|
import { InternalUserManagement } from "./internal_user_management";
|
|
14
|
+
import { AccessResponse } from "./license";
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Context that includes the internal controllers and contexts used by the app.
|
|
@@ -97,4 +98,12 @@ export type FireCMSContext<USER extends User = User, AuthControllerType extends
|
|
|
97
98
|
*/
|
|
98
99
|
userManagement: InternalUserManagement<USER>
|
|
99
100
|
|
|
101
|
+
/**
|
|
102
|
+
* FireCMS license status of this project, `null` until the license check
|
|
103
|
+
* answers or when it is not sent. PRO plugins are paused while `blocked`
|
|
104
|
+
* is true.
|
|
105
|
+
* @see useLicenseStatus
|
|
106
|
+
*/
|
|
107
|
+
licenseStatus?: AccessResponse | null;
|
|
108
|
+
|
|
100
109
|
};
|
package/src/types/index.ts
CHANGED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the FireCMS license check says about this project.
|
|
3
|
+
*
|
|
4
|
+
* - `not_required`: no PRO plugin is mounted.
|
|
5
|
+
* - `whitelisted`: the project is exempt from licensing.
|
|
6
|
+
* - `licensed`: a license covers this project.
|
|
7
|
+
* - `trial`: PRO plugins run on the free trial; see `daysLeft` and `trialEndsAt`.
|
|
8
|
+
* - `expired`: the trial ended without a license. PRO plugins are paused.
|
|
9
|
+
* - `invalid_project`: a license key was presented, but this project is not
|
|
10
|
+
* linked to that license. PRO plugins are paused.
|
|
11
|
+
* - `over_quota`: the license links more projects than it pays for, and this
|
|
12
|
+
* is not one of the projects it covers in production. PRO plugins are
|
|
13
|
+
* paused.
|
|
14
|
+
*
|
|
15
|
+
* @group Models
|
|
16
|
+
*/
|
|
17
|
+
export type LicenseState =
|
|
18
|
+
| "not_required"
|
|
19
|
+
| "whitelisted"
|
|
20
|
+
| "licensed"
|
|
21
|
+
| "trial"
|
|
22
|
+
| "expired"
|
|
23
|
+
| "invalid_project"
|
|
24
|
+
| "over_quota";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Response of the FireCMS license check (`POST https://api.firecms.co/access_log`).
|
|
28
|
+
*
|
|
29
|
+
* Servers older than the PRO relaunch send only `blocked` and `message`, so
|
|
30
|
+
* treat a missing `licenseState` as unknown. `blocked` is honoured either way.
|
|
31
|
+
*
|
|
32
|
+
* @group Models
|
|
33
|
+
*/
|
|
34
|
+
export type AccessResponse = {
|
|
35
|
+
/**
|
|
36
|
+
* True when the PRO plugins must be paused. The core CMS is never blocked.
|
|
37
|
+
*/
|
|
38
|
+
blocked?: boolean;
|
|
39
|
+
licenseState?: LicenseState;
|
|
40
|
+
/**
|
|
41
|
+
* Number of projects the license pays for. Present with `licensed` and `over_quota`.
|
|
42
|
+
*/
|
|
43
|
+
licensedProjects?: number;
|
|
44
|
+
/**
|
|
45
|
+
* Number of projects linked to the license.
|
|
46
|
+
*/
|
|
47
|
+
linkedProjects?: number;
|
|
48
|
+
projectId?: string;
|
|
49
|
+
licenseId?: string;
|
|
50
|
+
/**
|
|
51
|
+
* ISO date the trial ends or ended. Present with `trial` and `expired`.
|
|
52
|
+
*/
|
|
53
|
+
trialEndsAt?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Whole days left in the trial, present with `trial`.
|
|
56
|
+
*/
|
|
57
|
+
daysLeft?: number;
|
|
58
|
+
/**
|
|
59
|
+
* Where to get or update a license for this project.
|
|
60
|
+
*/
|
|
61
|
+
subscribeUrl?: string;
|
|
62
|
+
/**
|
|
63
|
+
* A PRO plugin the server suggests for this project. Only read with
|
|
64
|
+
* `not_required`, and only shown when the app mounts no PRO plugin: the
|
|
65
|
+
* server also answers `not_required` to localhost and FireCMS Cloud,
|
|
66
|
+
* whatever they mount.
|
|
67
|
+
*/
|
|
68
|
+
suggestion?: ProSuggestion;
|
|
69
|
+
message?: string;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* A FireCMS PRO plugin the license check suggests to a project that runs
|
|
74
|
+
* none, such as user management for a CMS that several people sign in to.
|
|
75
|
+
* The server decides which projects get one; the CMS shows it as a note the
|
|
76
|
+
* user can dismiss for good.
|
|
77
|
+
*
|
|
78
|
+
* @group Models
|
|
79
|
+
*/
|
|
80
|
+
export type ProSuggestion = {
|
|
81
|
+
/**
|
|
82
|
+
* Key of the suggested plugin. Keys this version of FireCMS has no copy
|
|
83
|
+
* for are ignored, so the server can add new ones safely.
|
|
84
|
+
*/
|
|
85
|
+
plugin: "user_management" | "entity_history";
|
|
86
|
+
/**
|
|
87
|
+
* How many people use this CMS, when the server counted them.
|
|
88
|
+
*/
|
|
89
|
+
users?: number;
|
|
90
|
+
};
|
package/src/types/plugins.tsx
CHANGED
|
@@ -15,6 +15,9 @@ import { InternalUserManagement } from "./internal_user_management";
|
|
|
15
15
|
* NOTE: This is a work in progress and the API is not stable yet.
|
|
16
16
|
* @group Core
|
|
17
17
|
*/
|
|
18
|
+
/** The strings a plugin contributes for one locale. */
|
|
19
|
+
export type PluginTranslations = Record<string, string>;
|
|
20
|
+
|
|
18
21
|
export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollection = EntityCollection, COL_ACTIONS_PROPS = any, COL_ACTIONS_START__PROPS = any> = {
|
|
19
22
|
|
|
20
23
|
/**
|
|
@@ -33,8 +36,14 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollec
|
|
|
33
36
|
* locales, specific for this plugin.
|
|
34
37
|
* Keys can be existing `FireCMSTranslations` keys, or new keys if using
|
|
35
38
|
* module augmentation.
|
|
39
|
+
*
|
|
40
|
+
* A value may be the strings themselves, or a function returning a promise
|
|
41
|
+
* of them. Use the function form for locales you ship in the plugin bundle:
|
|
42
|
+
* only the active language is ever read, so importing all of them statically
|
|
43
|
+
* puts every language into the bundle of every app that mounts the plugin.
|
|
44
|
+
* Both forms are supported; a plain record keeps working unchanged.
|
|
36
45
|
*/
|
|
37
|
-
i18n?: Record<string,
|
|
46
|
+
i18n?: Record<string, PluginTranslations | (() => Promise<PluginTranslations>)>;
|
|
38
47
|
|
|
39
48
|
/**
|
|
40
49
|
* You can use this prop to add higher order components to the CMS.
|
|
@@ -66,8 +66,40 @@ export interface FireCMSTranslations {
|
|
|
66
66
|
select_from: string;
|
|
67
67
|
done: string;
|
|
68
68
|
log_out: string;
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
/** License banner during the PRO trial. `{{days}}` is the number of days left; plural form. */
|
|
70
|
+
license_trial_banner: string;
|
|
71
|
+
/** `license_trial_banner` when one day is left (i18next `_one` plural form). */
|
|
72
|
+
license_trial_banner_one: string;
|
|
73
|
+
/** License banner once the trial has ended. `{{date}}` is the day it ended. */
|
|
74
|
+
license_expired_banner: string;
|
|
75
|
+
/** `license_expired_banner` when the end date is not known. */
|
|
76
|
+
license_expired_banner_undated: string;
|
|
77
|
+
/** License banner when the license key is not linked to this project. `{{projectId}}` is the Firebase project id. */
|
|
78
|
+
license_invalid_project_banner: string;
|
|
79
|
+
/** `license_invalid_project_banner` when the project id is not known. */
|
|
80
|
+
license_invalid_project_banner_unnamed: string;
|
|
81
|
+
/** License banner when more projects are linked than the license covers. `{{licensed}}` covered, `{{actual}}` linked; plural form. */
|
|
82
|
+
license_over_quota_banner: string;
|
|
83
|
+
/** `license_over_quota_banner` when the license covers one project (i18next `_one` plural form). */
|
|
84
|
+
license_over_quota_banner_one: string;
|
|
85
|
+
/** Link in the license banner to buy a license. */
|
|
86
|
+
license_get_license: string;
|
|
87
|
+
/** Link in the over-quota banner to the license settings. */
|
|
88
|
+
license_update_license: string;
|
|
89
|
+
/** Link in the invalid-project banner to link this project to the license. */
|
|
90
|
+
license_add_project_to_license: string;
|
|
91
|
+
/** Suggestion of the PRO user management plugin to a project without it. `{{users}}` is how many people use the CMS, always 2 or more. */
|
|
92
|
+
pro_suggestion_user_management: string;
|
|
93
|
+
/** `pro_suggestion_user_management` when the number of people is not known. */
|
|
94
|
+
pro_suggestion_user_management_uncounted: string;
|
|
95
|
+
/** Suggestion of the PRO entity history plugin to a project without it. */
|
|
96
|
+
pro_suggestion_entity_history: string;
|
|
97
|
+
/** Link in a PRO suggestion to the plugin's documentation. */
|
|
98
|
+
pro_suggestion_learn_more: string;
|
|
99
|
+
/** Title of the notice a PRO view shows while PRO features are paused. */
|
|
100
|
+
pro_features_paused: string;
|
|
101
|
+
/** Users and Roles views while PRO features are paused. */
|
|
102
|
+
user_management_paused_description: string;
|
|
71
103
|
column_cannot_be_edited: string;
|
|
72
104
|
close: string;
|
|
73
105
|
unsaved_local_changes: string;
|
|
@@ -421,6 +453,12 @@ export interface FireCMSTranslations {
|
|
|
421
453
|
include_undefined_values: string;
|
|
422
454
|
/** Toggle in the export dialog, only shown when a filter or sort is active */
|
|
423
455
|
export_apply_filter_sort: string;
|
|
456
|
+
/** Choice in the export dialog, only shown when entities are selected */
|
|
457
|
+
export_all_entities: string;
|
|
458
|
+
/** Same choice; `{{count}}` is the number of selected entities */
|
|
459
|
+
export_selected_entities: string;
|
|
460
|
+
/** Shown in the export dialog when the export fails; `{{message}}` is the error's message */
|
|
461
|
+
export_error: string;
|
|
424
462
|
submit: string;
|
|
425
463
|
|
|
426
464
|
no_filterable_properties: string;
|
|
@@ -470,6 +508,8 @@ export interface FireCMSTranslations {
|
|
|
470
508
|
roles_menu: string;
|
|
471
509
|
project_settings: string;
|
|
472
510
|
firestore_manager: string;
|
|
511
|
+
/** The DataTalk product name, keyed so a locale can transliterate it. */
|
|
512
|
+
datatalk: string;
|
|
473
513
|
manage_your_firestore_data: string;
|
|
474
514
|
|
|
475
515
|
// ─── FireCMS Cloud Login ──────────────────────────────────────
|
|
@@ -486,6 +526,7 @@ export interface FireCMSTranslations {
|
|
|
486
526
|
not_the_admin_panel: string;
|
|
487
527
|
join_our_newsletter: string;
|
|
488
528
|
by_signing_in_you_agree_to_our: string;
|
|
529
|
+
please_accept_the_terms_to_continue: string;
|
|
489
530
|
terms_and_conditions: string;
|
|
490
531
|
and_our: string;
|
|
491
532
|
privacy_policy: string;
|
|
@@ -528,6 +569,8 @@ export interface FireCMSTranslations {
|
|
|
528
569
|
licensed_projects_lowercase: string;
|
|
529
570
|
manage: string;
|
|
530
571
|
update_payment_method: string;
|
|
572
|
+
/** Snackbar when a Stripe billing portal link can't be created. `{{message}}` is the reason. */
|
|
573
|
+
stripe_portal_error: string;
|
|
531
574
|
your_firecms_cloud_projects: string;
|
|
532
575
|
status_active: string;
|
|
533
576
|
status_trialing: string;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { useEffect, useReducer } from "react";
|
|
2
|
+
import type { Locale as DateFnsLocale } from "date-fns";
|
|
3
|
+
import { Locale } from "../types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* On-demand loading of date-fns locales.
|
|
7
|
+
*
|
|
8
|
+
* `import * as locales from "date-fns/locale"` pulls in every locale date-fns
|
|
9
|
+
* ships — 625KB of parsed JavaScript, loaded on every single page view, to
|
|
10
|
+
* support a `locale` setting that is unset for almost every project. Worse, it
|
|
11
|
+
* sat on the critical path: `@firecms/core` imported it statically, so the
|
|
12
|
+
* browser could not render anything until it had come down.
|
|
13
|
+
*
|
|
14
|
+
* Each locale now has its own dynamic import, so exactly one small chunk is
|
|
15
|
+
* fetched, and only when a project actually configures a locale. Projects that
|
|
16
|
+
* do not configure one (the default) pay nothing at all.
|
|
17
|
+
*
|
|
18
|
+
* The map is written out rather than built from a template literal because Vite
|
|
19
|
+
* and webpack both need the specifier to be statically analysable to emit the
|
|
20
|
+
* chunks.
|
|
21
|
+
*/
|
|
22
|
+
const loaders: Partial<Record<Locale, () => Promise<DateFnsLocale>>> = {
|
|
23
|
+
af: () => import("date-fns/locale/af").then(m => m.af),
|
|
24
|
+
ar: () => import("date-fns/locale/ar").then(m => m.ar),
|
|
25
|
+
arDZ: () => import("date-fns/locale/ar-DZ").then(m => m.arDZ),
|
|
26
|
+
arMA: () => import("date-fns/locale/ar-MA").then(m => m.arMA),
|
|
27
|
+
arSA: () => import("date-fns/locale/ar-SA").then(m => m.arSA),
|
|
28
|
+
az: () => import("date-fns/locale/az").then(m => m.az),
|
|
29
|
+
be: () => import("date-fns/locale/be").then(m => m.be),
|
|
30
|
+
bg: () => import("date-fns/locale/bg").then(m => m.bg),
|
|
31
|
+
bn: () => import("date-fns/locale/bn").then(m => m.bn),
|
|
32
|
+
ca: () => import("date-fns/locale/ca").then(m => m.ca),
|
|
33
|
+
cs: () => import("date-fns/locale/cs").then(m => m.cs),
|
|
34
|
+
cy: () => import("date-fns/locale/cy").then(m => m.cy),
|
|
35
|
+
da: () => import("date-fns/locale/da").then(m => m.da),
|
|
36
|
+
de: () => import("date-fns/locale/de").then(m => m.de),
|
|
37
|
+
el: () => import("date-fns/locale/el").then(m => m.el),
|
|
38
|
+
enAU: () => import("date-fns/locale/en-AU").then(m => m.enAU),
|
|
39
|
+
enCA: () => import("date-fns/locale/en-CA").then(m => m.enCA),
|
|
40
|
+
enGB: () => import("date-fns/locale/en-GB").then(m => m.enGB),
|
|
41
|
+
enIN: () => import("date-fns/locale/en-IN").then(m => m.enIN),
|
|
42
|
+
enNZ: () => import("date-fns/locale/en-NZ").then(m => m.enNZ),
|
|
43
|
+
enUS: () => import("date-fns/locale/en-US").then(m => m.enUS),
|
|
44
|
+
eo: () => import("date-fns/locale/eo").then(m => m.eo),
|
|
45
|
+
es: () => import("date-fns/locale/es").then(m => m.es),
|
|
46
|
+
et: () => import("date-fns/locale/et").then(m => m.et),
|
|
47
|
+
eu: () => import("date-fns/locale/eu").then(m => m.eu),
|
|
48
|
+
faIR: () => import("date-fns/locale/fa-IR").then(m => m.faIR),
|
|
49
|
+
fi: () => import("date-fns/locale/fi").then(m => m.fi),
|
|
50
|
+
fr: () => import("date-fns/locale/fr").then(m => m.fr),
|
|
51
|
+
frCA: () => import("date-fns/locale/fr-CA").then(m => m.frCA),
|
|
52
|
+
frCH: () => import("date-fns/locale/fr-CH").then(m => m.frCH),
|
|
53
|
+
gd: () => import("date-fns/locale/gd").then(m => m.gd),
|
|
54
|
+
gl: () => import("date-fns/locale/gl").then(m => m.gl),
|
|
55
|
+
gu: () => import("date-fns/locale/gu").then(m => m.gu),
|
|
56
|
+
he: () => import("date-fns/locale/he").then(m => m.he),
|
|
57
|
+
hi: () => import("date-fns/locale/hi").then(m => m.hi),
|
|
58
|
+
hr: () => import("date-fns/locale/hr").then(m => m.hr),
|
|
59
|
+
hu: () => import("date-fns/locale/hu").then(m => m.hu),
|
|
60
|
+
hy: () => import("date-fns/locale/hy").then(m => m.hy),
|
|
61
|
+
id: () => import("date-fns/locale/id").then(m => m.id),
|
|
62
|
+
is: () => import("date-fns/locale/is").then(m => m.is),
|
|
63
|
+
it: () => import("date-fns/locale/it").then(m => m.it),
|
|
64
|
+
ja: () => import("date-fns/locale/ja").then(m => m.ja),
|
|
65
|
+
ka: () => import("date-fns/locale/ka").then(m => m.ka),
|
|
66
|
+
kk: () => import("date-fns/locale/kk").then(m => m.kk),
|
|
67
|
+
kn: () => import("date-fns/locale/kn").then(m => m.kn),
|
|
68
|
+
ko: () => import("date-fns/locale/ko").then(m => m.ko),
|
|
69
|
+
lb: () => import("date-fns/locale/lb").then(m => m.lb),
|
|
70
|
+
lt: () => import("date-fns/locale/lt").then(m => m.lt),
|
|
71
|
+
lv: () => import("date-fns/locale/lv").then(m => m.lv),
|
|
72
|
+
mk: () => import("date-fns/locale/mk").then(m => m.mk),
|
|
73
|
+
ms: () => import("date-fns/locale/ms").then(m => m.ms),
|
|
74
|
+
mt: () => import("date-fns/locale/mt").then(m => m.mt),
|
|
75
|
+
nb: () => import("date-fns/locale/nb").then(m => m.nb),
|
|
76
|
+
nl: () => import("date-fns/locale/nl").then(m => m.nl),
|
|
77
|
+
nlBE: () => import("date-fns/locale/nl-BE").then(m => m.nlBE),
|
|
78
|
+
nn: () => import("date-fns/locale/nn").then(m => m.nn),
|
|
79
|
+
pl: () => import("date-fns/locale/pl").then(m => m.pl),
|
|
80
|
+
pt: () => import("date-fns/locale/pt").then(m => m.pt),
|
|
81
|
+
ptBR: () => import("date-fns/locale/pt-BR").then(m => m.ptBR),
|
|
82
|
+
ro: () => import("date-fns/locale/ro").then(m => m.ro),
|
|
83
|
+
ru: () => import("date-fns/locale/ru").then(m => m.ru),
|
|
84
|
+
sk: () => import("date-fns/locale/sk").then(m => m.sk),
|
|
85
|
+
sl: () => import("date-fns/locale/sl").then(m => m.sl),
|
|
86
|
+
sr: () => import("date-fns/locale/sr").then(m => m.sr),
|
|
87
|
+
srLatn: () => import("date-fns/locale/sr-Latn").then(m => m.srLatn),
|
|
88
|
+
sv: () => import("date-fns/locale/sv").then(m => m.sv),
|
|
89
|
+
ta: () => import("date-fns/locale/ta").then(m => m.ta),
|
|
90
|
+
te: () => import("date-fns/locale/te").then(m => m.te),
|
|
91
|
+
th: () => import("date-fns/locale/th").then(m => m.th),
|
|
92
|
+
tr: () => import("date-fns/locale/tr").then(m => m.tr),
|
|
93
|
+
ug: () => import("date-fns/locale/ug").then(m => m.ug),
|
|
94
|
+
uk: () => import("date-fns/locale/uk").then(m => m.uk),
|
|
95
|
+
uz: () => import("date-fns/locale/uz").then(m => m.uz),
|
|
96
|
+
vi: () => import("date-fns/locale/vi").then(m => m.vi),
|
|
97
|
+
zhCN: () => import("date-fns/locale/zh-CN").then(m => m.zhCN),
|
|
98
|
+
zhTW: () => import("date-fns/locale/zh-TW").then(m => m.zhTW),
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const cache = new Map<Locale, DateFnsLocale>();
|
|
102
|
+
const inFlight = new Map<Locale, Promise<DateFnsLocale | undefined>>();
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Load a date-fns locale, resolving from cache when it is already in memory.
|
|
106
|
+
* Concurrent callers for the same locale share one request.
|
|
107
|
+
*/
|
|
108
|
+
export function loadDateFnsLocale(locale: Locale): Promise<DateFnsLocale | undefined> {
|
|
109
|
+
const cached = cache.get(locale);
|
|
110
|
+
if (cached) {
|
|
111
|
+
return Promise.resolve(cached);
|
|
112
|
+
}
|
|
113
|
+
const pending = inFlight.get(locale);
|
|
114
|
+
if (pending) {
|
|
115
|
+
return pending;
|
|
116
|
+
}
|
|
117
|
+
const loader = loaders[locale];
|
|
118
|
+
if (!loader) {
|
|
119
|
+
// An unknown key behaves as it did when the whole barrel was imported:
|
|
120
|
+
// the lookup missed and date-fns fell back to its built-in English.
|
|
121
|
+
return Promise.resolve(undefined);
|
|
122
|
+
}
|
|
123
|
+
const promise = loader()
|
|
124
|
+
.then((loaded) => {
|
|
125
|
+
cache.set(locale, loaded);
|
|
126
|
+
return loaded;
|
|
127
|
+
})
|
|
128
|
+
.catch(() => undefined)
|
|
129
|
+
.finally(() => {
|
|
130
|
+
inFlight.delete(locale);
|
|
131
|
+
});
|
|
132
|
+
inFlight.set(locale, promise);
|
|
133
|
+
return promise;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** The locale if it is already loaded, otherwise undefined. Never suspends. */
|
|
137
|
+
export function getLoadedDateFnsLocale(locale?: Locale): DateFnsLocale | undefined {
|
|
138
|
+
return locale ? cache.get(locale) : undefined;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* The date-fns locale for `locale`, loading it in the background on first use.
|
|
143
|
+
*
|
|
144
|
+
* Returns undefined until the chunk arrives, which formats the first paint with
|
|
145
|
+
* date-fns' built-in English and then re-renders. That is a change only for
|
|
146
|
+
* projects that set a locale, and only for the few hundred milliseconds before
|
|
147
|
+
* the chunk lands — in exchange for every project no longer waiting on 625KB.
|
|
148
|
+
*/
|
|
149
|
+
export function useDateFnsLocale(locale?: Locale): DateFnsLocale | undefined {
|
|
150
|
+
const [, forceUpdate] = useReducer((count: number) => count + 1, 0);
|
|
151
|
+
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (!locale || cache.has(locale)) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
let active = true;
|
|
157
|
+
loadDateFnsLocale(locale).then((loaded) => {
|
|
158
|
+
if (active && loaded) {
|
|
159
|
+
forceUpdate();
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
return () => {
|
|
163
|
+
active = false;
|
|
164
|
+
};
|
|
165
|
+
}, [locale]);
|
|
166
|
+
|
|
167
|
+
return locale ? cache.get(locale) : undefined;
|
|
168
|
+
}
|