@defra/forms-engine-plugin 4.23.0 → 5.0.0-alpha.1
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/.public/assets-manifest.json +3 -5
- package/.public/javascripts/im-core.min.js +2 -0
- package/.public/javascripts/im-core.min.js.map +1 -0
- package/.public/javascripts/shared.min.js +1 -1
- package/.public/javascripts/shared.min.js.map +1 -1
- package/.public/javascripts/vendor/@defra.min.js +1 -1
- package/.public/javascripts/vendor/@defra.min.js.map +1 -1
- package/.public/stylesheets/application.min.css +1 -1
- package/.public/stylesheets/application.min.css.map +1 -1
- package/.server/client/javascripts/geospatial-map.js +8 -6
- package/.server/client/javascripts/geospatial-map.js.map +1 -1
- package/.server/client/javascripts/location-map.js +8 -1
- package/.server/client/javascripts/location-map.js.map +1 -1
- package/.server/client/javascripts/map.d.ts +6 -0
- package/.server/client/javascripts/map.js +10 -0
- package/.server/client/javascripts/map.js.map +1 -1
- package/.server/client/javascripts/sssi-dataset.d.ts +34 -0
- package/.server/client/javascripts/sssi-dataset.js +101 -0
- package/.server/client/javascripts/sssi-dataset.js.map +1 -0
- package/.server/client/stylesheets/shared.scss +0 -2
- package/.server/server/forms/register-as-a-unicorn-breeder.yaml +0 -14
- package/.server/server/forms/simple-form.yaml +106 -3
- package/.server/server/plugins/engine/components/AutocompleteField.d.ts +11 -11
- package/.server/server/plugins/engine/components/AutocompleteField.js +2 -2
- package/.server/server/plugins/engine/components/AutocompleteField.js.map +1 -1
- package/.server/server/plugins/engine/components/CheckboxesField.d.ts +3 -2
- package/.server/server/plugins/engine/components/CheckboxesField.js +4 -9
- package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -1
- package/.server/server/plugins/engine/components/ComponentCollection.d.ts +8 -7
- package/.server/server/plugins/engine/components/ComponentCollection.js +106 -51
- package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
- package/.server/server/plugins/engine/components/DatePartsField.d.ts +8 -6
- package/.server/server/plugins/engine/components/DatePartsField.js +27 -9
- package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -1
- package/.server/server/plugins/engine/components/DeclarationField.d.ts +13 -11
- package/.server/server/plugins/engine/components/DeclarationField.js +31 -9
- package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -1
- package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +8 -5
- package/.server/server/plugins/engine/components/EastingNorthingField.js +42 -22
- package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -1
- package/.server/server/plugins/engine/components/EmailAddressField.d.ts +11 -14
- package/.server/server/plugins/engine/components/EmailAddressField.js +2 -2
- package/.server/server/plugins/engine/components/EmailAddressField.js.map +1 -1
- package/.server/server/plugins/engine/components/FileUploadField.d.ts +14 -12
- package/.server/server/plugins/engine/components/FileUploadField.js +22 -12
- package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
- package/.server/server/plugins/engine/components/FormComponent.d.ts +21 -12
- package/.server/server/plugins/engine/components/FormComponent.js +33 -14
- package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
- package/.server/server/plugins/engine/components/GeospatialField.d.ts +15 -12
- package/.server/server/plugins/engine/components/GeospatialField.js +21 -13
- package/.server/server/plugins/engine/components/GeospatialField.js.map +1 -1
- package/.server/server/plugins/engine/components/LatLongField.d.ts +8 -5
- package/.server/server/plugins/engine/components/LatLongField.js +32 -20
- package/.server/server/plugins/engine/components/LatLongField.js.map +1 -1
- package/.server/server/plugins/engine/components/ListFormComponent.d.ts +7 -6
- package/.server/server/plugins/engine/components/ListFormComponent.js +19 -7
- package/.server/server/plugins/engine/components/ListFormComponent.js.map +1 -1
- package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +17 -16
- package/.server/server/plugins/engine/components/LocationFieldBase.js +2 -2
- package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -1
- package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +8 -3
- package/.server/server/plugins/engine/components/LocationFieldHelpers.js +14 -3
- package/.server/server/plugins/engine/components/LocationFieldHelpers.js.map +1 -1
- package/.server/server/plugins/engine/components/Markdown.d.ts +8 -7
- package/.server/server/plugins/engine/components/Markdown.js +5 -2
- package/.server/server/plugins/engine/components/Markdown.js.map +1 -1
- package/.server/server/plugins/engine/components/MonthYearField.d.ts +9 -7
- package/.server/server/plugins/engine/components/MonthYearField.js +26 -8
- package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -1
- package/.server/server/plugins/engine/components/MultilineTextField.d.ts +10 -9
- package/.server/server/plugins/engine/components/MultilineTextField.js +2 -2
- package/.server/server/plugins/engine/components/MultilineTextField.js.map +1 -1
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +2 -1
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js +14 -6
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js.map +1 -1
- package/.server/server/plugins/engine/components/NumberField.d.ts +10 -9
- package/.server/server/plugins/engine/components/NumberField.js +2 -2
- package/.server/server/plugins/engine/components/NumberField.js.map +1 -1
- package/.server/server/plugins/engine/components/OsGridRefField.d.ts +2 -1
- package/.server/server/plugins/engine/components/OsGridRefField.js +14 -6
- package/.server/server/plugins/engine/components/OsGridRefField.js.map +1 -1
- package/.server/server/plugins/engine/components/PaymentField.d.ts +12 -10
- package/.server/server/plugins/engine/components/PaymentField.js +21 -8
- package/.server/server/plugins/engine/components/PaymentField.js.map +1 -1
- package/.server/server/plugins/engine/components/SelectField.d.ts +11 -11
- package/.server/server/plugins/engine/components/SelectField.js +2 -2
- package/.server/server/plugins/engine/components/SelectField.js.map +1 -1
- package/.server/server/plugins/engine/components/SelectionControlField.d.ts +4 -4
- package/.server/server/plugins/engine/components/SelectionControlField.js +2 -2
- package/.server/server/plugins/engine/components/SelectionControlField.js.map +1 -1
- package/.server/server/plugins/engine/components/TelephoneNumberField.d.ts +10 -9
- package/.server/server/plugins/engine/components/TelephoneNumberField.js +2 -2
- package/.server/server/plugins/engine/components/TelephoneNumberField.js.map +1 -1
- package/.server/server/plugins/engine/components/UkAddressField.d.ts +12 -10
- package/.server/server/plugins/engine/components/UkAddressField.js +29 -17
- package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
- package/.server/server/plugins/engine/components/YesNoField.d.ts +3 -0
- package/.server/server/plugins/engine/components/YesNoField.js +9 -0
- package/.server/server/plugins/engine/components/YesNoField.js.map +1 -1
- package/.server/server/plugins/engine/components/helpers/components.d.ts +3 -2
- package/.server/server/plugins/engine/components/helpers/components.js +11 -8
- package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
- package/.server/server/plugins/engine/components/types.d.ts +8 -1
- package/.server/server/plugins/engine/components/types.js.map +1 -1
- package/.server/server/plugins/engine/configureEnginePlugin.js +8 -1
- package/.server/server/plugins/engine/configureEnginePlugin.js.map +1 -1
- package/.server/server/plugins/engine/form-context.d.ts +1 -0
- package/.server/server/plugins/engine/form-context.js +4 -2
- package/.server/server/plugins/engine/form-context.js.map +1 -1
- package/.server/server/plugins/engine/helpers.d.ts +1 -1
- package/.server/server/plugins/engine/helpers.js +8 -13
- package/.server/server/plugins/engine/helpers.js.map +1 -1
- package/.server/server/plugins/engine/i18n/buildValidationMessages.d.ts +39 -0
- package/.server/server/plugins/engine/i18n/buildValidationMessages.js +50 -0
- package/.server/server/plugins/engine/i18n/buildValidationMessages.js.map +1 -0
- package/.server/server/plugins/engine/i18n/createFormTranslator.d.ts +5 -0
- package/.server/server/plugins/engine/i18n/createFormTranslator.js +18 -0
- package/.server/server/plugins/engine/i18n/createFormTranslator.js.map +1 -0
- package/.server/server/plugins/engine/i18n/createTranslator.d.ts +9 -0
- package/.server/server/plugins/engine/i18n/createTranslator.js +51 -0
- package/.server/server/plugins/engine/i18n/createTranslator.js.map +1 -0
- package/.server/server/plugins/engine/i18n/extractBaseTranslations.d.ts +5 -0
- package/.server/server/plugins/engine/i18n/extractBaseTranslations.js +57 -0
- package/.server/server/plugins/engine/i18n/extractBaseTranslations.js.map +1 -0
- package/.server/server/plugins/engine/i18n/index.d.ts +18 -0
- package/.server/server/plugins/engine/i18n/index.js +71 -0
- package/.server/server/plugins/engine/i18n/index.js.map +1 -0
- package/.server/server/plugins/engine/i18n/translations/cy.json +271 -0
- package/.server/server/plugins/engine/i18n/translations/en-GB.json +271 -0
- package/.server/server/plugins/engine/i18n/types.d.ts +41 -0
- package/.server/server/plugins/engine/i18n/types.js +2 -0
- package/.server/server/plugins/engine/i18n/types.js.map +1 -0
- package/.server/server/plugins/engine/index.js +3 -2
- package/.server/server/plugins/engine/index.js.map +1 -1
- package/.server/server/plugins/engine/models/FormModel.d.ts +9 -1
- package/.server/server/plugins/engine/models/FormModel.js +44 -18
- package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
- package/.server/server/plugins/engine/models/SummaryViewModel.d.ts +5 -2
- package/.server/server/plugins/engine/models/SummaryViewModel.js +44 -18
- package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
- package/.server/server/plugins/engine/options.js +2 -1
- package/.server/server/plugins/engine/options.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +4 -0
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/human/v1.js +2 -1
- package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/machine/v1.js +7 -6
- package/.server/server/plugins/engine/outputFormatters/machine/v1.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.d.ts +2 -1
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +6 -3
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/PageController.d.ts +3 -1
- package/.server/server/plugins/engine/pageControllers/PageController.js +11 -1
- package/.server/server/plugins/engine/pageControllers/PageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.d.ts +4 -2
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +52 -21
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/RepeatPageController.d.ts +3 -2
- package/.server/server/plugins/engine/pageControllers/RepeatPageController.js +63 -26
- package/.server/server/plugins/engine/pageControllers/RepeatPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/StartPageController.d.ts +3 -1
- package/.server/server/plugins/engine/pageControllers/StartPageController.js +2 -2
- package/.server/server/plugins/engine/pageControllers/StartPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/StatusPageController.js +12 -2
- package/.server/server/plugins/engine/pageControllers/StatusPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.d.ts +4 -3
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +44 -28
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/__stubs__/translator.d.ts +2 -0
- package/.server/server/plugins/engine/pageControllers/__stubs__/translator.js +24 -0
- package/.server/server/plugins/engine/pageControllers/__stubs__/translator.js.map +1 -0
- package/.server/server/plugins/engine/pageControllers/errors.d.ts +1 -1
- package/.server/server/plugins/engine/pageControllers/errors.js +3 -2
- package/.server/server/plugins/engine/pageControllers/errors.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/helpers/submission.d.ts +3 -2
- package/.server/server/plugins/engine/pageControllers/helpers/submission.js +4 -4
- package/.server/server/plugins/engine/pageControllers/helpers/submission.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/validationOptions.d.ts +7 -3
- package/.server/server/plugins/engine/pageControllers/validationOptions.js +34 -33
- package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
- package/.server/server/plugins/engine/plugin.js +2 -0
- package/.server/server/plugins/engine/plugin.js.map +1 -1
- package/.server/server/plugins/engine/routes/index.js +4 -1
- package/.server/server/plugins/engine/routes/index.js.map +1 -1
- package/.server/server/plugins/engine/routes/questions.js +5 -2
- package/.server/server/plugins/engine/routes/questions.js.map +1 -1
- package/.server/server/plugins/engine/types/index.d.ts +1 -0
- package/.server/server/plugins/engine/types/index.js.map +1 -1
- package/.server/server/plugins/engine/types/schema.js +1 -0
- package/.server/server/plugins/engine/types/schema.js.map +1 -1
- package/.server/server/plugins/engine/types.d.ts +12 -1
- package/.server/server/plugins/engine/types.js.map +1 -1
- package/.server/server/plugins/engine/views/components/_location-field-base.html +4 -2
- package/.server/server/plugins/engine/views/components/fileuploadfield.html +3 -3
- package/.server/server/plugins/engine/views/components/geospatialfield.html +4 -1
- package/.server/server/plugins/engine/views/components/nationalgridfieldnumberfield.html +1 -1
- package/.server/server/plugins/engine/views/components/osgridreffield.html +1 -1
- package/.server/server/plugins/engine/views/components/paymentfield.html +8 -8
- package/.server/server/plugins/engine/views/components/ukaddressfield.html +4 -4
- package/.server/server/plugins/engine/views/confirmation.html +4 -4
- package/.server/server/plugins/engine/views/exit.html +4 -4
- package/.server/server/plugins/engine/views/file-upload.html +3 -3
- package/.server/server/plugins/engine/views/index.html +3 -3
- package/.server/server/plugins/engine/views/item-delete.html +1 -1
- package/.server/server/plugins/engine/views/partials/form.html +3 -3
- package/.server/server/plugins/engine/views/partials/preview-banner.html +4 -4
- package/.server/server/plugins/engine/views/partials/warn-missing-notification-email.html +4 -5
- package/.server/server/plugins/engine/views/repeat-list-summary.html +4 -4
- package/.server/server/plugins/engine/views/summary.html +14 -7
- package/.server/server/plugins/map/routes/index.js +1 -1
- package/.server/server/plugins/map/routes/index.js.map +1 -1
- package/.server/server/plugins/map/types.d.ts +1 -25
- package/.server/server/plugins/map/types.js +1 -16
- package/.server/server/plugins/map/types.js.map +1 -1
- package/.server/server/plugins/nunjucks/enviroment.test.js +10 -0
- package/.server/server/plugins/nunjucks/enviroment.test.js.map +1 -1
- package/.server/server/plugins/nunjucks/environment.d.ts +8 -0
- package/.server/server/plugins/nunjucks/environment.js +13 -0
- package/.server/server/plugins/nunjucks/environment.js.map +1 -1
- package/.server/server/plugins/nunjucks/filters/answer.js +9 -1
- package/.server/server/plugins/nunjucks/filters/answer.js.map +1 -1
- package/.server/server/plugins/nunjucks/filters/answer.test.js +13 -2
- package/.server/server/plugins/nunjucks/filters/answer.test.js.map +1 -1
- package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
- package/.server/server/plugins/postcode-lookup/models/index.d.ts +24 -19
- package/.server/server/plugins/postcode-lookup/models/index.js +83 -76
- package/.server/server/plugins/postcode-lookup/models/index.js.map +1 -1
- package/.server/server/plugins/postcode-lookup/routes/index.js +7 -13
- package/.server/server/plugins/postcode-lookup/routes/index.js.map +1 -1
- package/.server/server/plugins/postcode-lookup/types.d.ts +1 -0
- package/.server/server/plugins/postcode-lookup/types.js +1 -0
- package/.server/server/plugins/postcode-lookup/types.js.map +1 -1
- package/.server/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
- package/.server/server/types.d.ts +2 -1
- package/.server/server/types.js.map +1 -1
- package/.server/server/utils/utils.d.ts +5 -0
- package/.server/server/utils/utils.js +16 -0
- package/.server/server/utils/utils.js.map +1 -1
- package/.server/typings/hapi/index.d.js.map +1 -1
- package/package.json +5 -4
- package/src/client/javascripts/geospatial-map.js +10 -6
- package/src/client/javascripts/location-map.js +11 -0
- package/src/client/javascripts/map.js +10 -0
- package/src/client/javascripts/sssi-dataset.js +106 -0
- package/src/client/stylesheets/shared.scss +0 -2
- package/src/server/forms/register-as-a-unicorn-breeder.yaml +0 -14
- package/src/server/forms/simple-form.yaml +106 -3
- package/src/server/plugins/engine/components/AutocompleteField.ts +3 -6
- package/src/server/plugins/engine/components/CheckboxesField.ts +12 -11
- package/src/server/plugins/engine/components/ComponentCollection.ts +143 -61
- package/src/server/plugins/engine/components/DatePartsField.ts +33 -11
- package/src/server/plugins/engine/components/DeclarationField.ts +37 -14
- package/src/server/plugins/engine/components/EastingNorthingField.ts +83 -22
- package/src/server/plugins/engine/components/EmailAddressField.ts +4 -7
- package/src/server/plugins/engine/components/FileUploadField.ts +28 -22
- package/src/server/plugins/engine/components/FormComponent.ts +49 -12
- package/src/server/plugins/engine/components/GeospatialField.ts +38 -21
- package/src/server/plugins/engine/components/LatLongField.ts +52 -21
- package/src/server/plugins/engine/components/ListFormComponent.ts +26 -10
- package/src/server/plugins/engine/components/LocationFieldBase.ts +5 -8
- package/src/server/plugins/engine/components/LocationFieldHelpers.ts +24 -4
- package/src/server/plugins/engine/components/Markdown.ts +7 -3
- package/src/server/plugins/engine/components/MonthYearField.ts +32 -10
- package/src/server/plugins/engine/components/MultilineTextField.ts +5 -8
- package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +25 -11
- package/src/server/plugins/engine/components/NumberField.ts +3 -4
- package/src/server/plugins/engine/components/OsGridRefField.ts +25 -9
- package/src/server/plugins/engine/components/PaymentField.ts +22 -12
- package/src/server/plugins/engine/components/SelectField.ts +3 -6
- package/src/server/plugins/engine/components/SelectionControlField.ts +7 -8
- package/src/server/plugins/engine/components/TelephoneNumberField.ts +4 -7
- package/src/server/plugins/engine/components/UkAddressField.ts +33 -18
- package/src/server/plugins/engine/components/YesNoField.ts +10 -0
- package/src/server/plugins/engine/components/helpers/components.ts +13 -6
- package/src/server/plugins/engine/components/types.ts +9 -0
- package/src/server/plugins/engine/configureEnginePlugin.ts +12 -1
- package/src/server/plugins/engine/form-context.ts +8 -2
- package/src/server/plugins/engine/helpers.ts +10 -18
- package/src/server/plugins/engine/i18n/buildValidationMessages.ts +69 -0
- package/src/server/plugins/engine/i18n/createFormTranslator.ts +33 -0
- package/src/server/plugins/engine/i18n/createTranslator.ts +61 -0
- package/src/server/plugins/engine/i18n/extractBaseTranslations.ts +61 -0
- package/src/server/plugins/engine/i18n/index.ts +80 -0
- package/src/server/plugins/engine/i18n/translations/cy.json +271 -0
- package/src/server/plugins/engine/i18n/translations/en-GB.json +271 -0
- package/src/server/plugins/engine/i18n/types.ts +62 -0
- package/src/server/plugins/engine/index.ts +4 -2
- package/src/server/plugins/engine/models/FormModel.ts +59 -23
- package/src/server/plugins/engine/models/SummaryViewModel.ts +68 -25
- package/src/server/plugins/engine/options.js +2 -1
- package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +5 -0
- package/src/server/plugins/engine/outputFormatters/human/v1.ts +2 -3
- package/src/server/plugins/engine/outputFormatters/machine/v1.ts +9 -8
- package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +7 -3
- package/src/server/plugins/engine/pageControllers/PageController.ts +12 -1
- package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +53 -21
- package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +66 -29
- package/src/server/plugins/engine/pageControllers/StartPageController.ts +7 -2
- package/src/server/plugins/engine/pageControllers/StatusPageController.ts +10 -2
- package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +48 -22
- package/src/server/plugins/engine/pageControllers/__stubs__/translator.ts +28 -0
- package/src/server/plugins/engine/pageControllers/errors.ts +4 -2
- package/src/server/plugins/engine/pageControllers/helpers/submission.ts +11 -4
- package/src/server/plugins/engine/pageControllers/validationOptions.ts +43 -53
- package/src/server/plugins/engine/plugin.ts +2 -0
- package/src/server/plugins/engine/routes/index.ts +9 -1
- package/src/server/plugins/engine/routes/questions.ts +5 -1
- package/src/server/plugins/engine/types/index.ts +5 -0
- package/src/server/plugins/engine/types/schema.ts +1 -0
- package/src/server/plugins/engine/types.ts +10 -0
- package/src/server/plugins/engine/views/components/_location-field-base.html +4 -2
- package/src/server/plugins/engine/views/components/fileuploadfield.html +3 -3
- package/src/server/plugins/engine/views/components/geospatialfield.html +4 -1
- package/src/server/plugins/engine/views/components/nationalgridfieldnumberfield.html +1 -1
- package/src/server/plugins/engine/views/components/osgridreffield.html +1 -1
- package/src/server/plugins/engine/views/components/paymentfield.html +8 -8
- package/src/server/plugins/engine/views/components/ukaddressfield.html +4 -4
- package/src/server/plugins/engine/views/confirmation.html +4 -4
- package/src/server/plugins/engine/views/exit.html +4 -4
- package/src/server/plugins/engine/views/file-upload.html +3 -3
- package/src/server/plugins/engine/views/index.html +3 -3
- package/src/server/plugins/engine/views/item-delete.html +1 -1
- package/src/server/plugins/engine/views/partials/form.html +3 -3
- package/src/server/plugins/engine/views/partials/preview-banner.html +4 -4
- package/src/server/plugins/engine/views/partials/warn-missing-notification-email.html +4 -5
- package/src/server/plugins/engine/views/repeat-list-summary.html +4 -4
- package/src/server/plugins/engine/views/summary.html +14 -7
- package/src/server/plugins/map/routes/index.js +1 -1
- package/src/server/plugins/map/types.js +1 -16
- package/src/server/plugins/nunjucks/environment.js +14 -0
- package/src/server/plugins/nunjucks/filters/answer.js +12 -1
- package/src/server/plugins/postcode-lookup/models/index.js +144 -87
- package/src/server/plugins/postcode-lookup/routes/index.js +13 -16
- package/src/server/plugins/postcode-lookup/types.js +1 -0
- package/src/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
- package/src/server/types.ts +2 -0
- package/src/server/utils/utils.js +14 -0
- package/src/typings/hapi/index.d.ts +1 -0
- package/.public/javascripts/im-search-plugin.min.js +0 -2
- package/.public/javascripts/im-search-plugin.min.js.map +0 -1
- package/.public/javascripts/vendor/preact.min.js +0 -2
- package/.public/javascripts/vendor/preact.min.js.map +0 -1
- package/.server/server/plugins/engine/components/constants.d.ts +0 -1
- package/.server/server/plugins/engine/components/constants.js +0 -2
- package/.server/server/plugins/engine/components/constants.js.map +0 -1
- package/src/server/plugins/engine/components/constants.ts +0 -1
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
isFormState
|
|
9
9
|
} from './FormComponent.js'
|
|
10
10
|
import { TextField } from './TextField.js'
|
|
11
|
-
import { type
|
|
11
|
+
import { type RenderContext } from './types.js'
|
|
12
|
+
import { type Translator } from '../i18n/types.js'
|
|
12
13
|
import {
|
|
13
14
|
type FormRequestPayload,
|
|
14
15
|
type FormResponseToolkit
|
|
@@ -23,6 +24,7 @@ import {
|
|
|
23
24
|
type PostcodeLookupExternalArgs
|
|
24
25
|
} from '../types.js'
|
|
25
26
|
import { dispatch } from '../../postcode-lookup/routes/index.js'
|
|
27
|
+
import { resolveLanguage } from '../../../utils/utils.js'
|
|
26
28
|
|
|
27
29
|
export class UkAddressField extends FormComponent {
|
|
28
30
|
declare options: UkAddressFieldComponent['options']
|
|
@@ -41,13 +43,12 @@ export class UkAddressField extends FormComponent {
|
|
|
41
43
|
const isRequired = options.required !== false
|
|
42
44
|
const hideOptional = !!options.optionalText
|
|
43
45
|
const hideTitle = !!options.hideTitle
|
|
44
|
-
|
|
45
46
|
this.collection = new ComponentCollection(
|
|
46
47
|
[
|
|
47
48
|
{
|
|
48
49
|
type: ComponentType.TextField,
|
|
49
50
|
name: `${name}__uprn`,
|
|
50
|
-
title: '
|
|
51
|
+
title: 'components.addressField.uprn',
|
|
51
52
|
schema: {},
|
|
52
53
|
options: {
|
|
53
54
|
required: false,
|
|
@@ -57,7 +58,7 @@ export class UkAddressField extends FormComponent {
|
|
|
57
58
|
{
|
|
58
59
|
type: ComponentType.TextField,
|
|
59
60
|
name: `${name}__addressLine1`,
|
|
60
|
-
title: '
|
|
61
|
+
title: 'components.addressField.line1',
|
|
61
62
|
schema: { max: 100 },
|
|
62
63
|
options: {
|
|
63
64
|
autocomplete: 'address-line1',
|
|
@@ -68,7 +69,7 @@ export class UkAddressField extends FormComponent {
|
|
|
68
69
|
{
|
|
69
70
|
type: ComponentType.TextField,
|
|
70
71
|
name: `${name}__addressLine2`,
|
|
71
|
-
title: '
|
|
72
|
+
title: 'components.addressField.line2',
|
|
72
73
|
schema: { max: 100 },
|
|
73
74
|
options: {
|
|
74
75
|
autocomplete: 'address-line2',
|
|
@@ -79,7 +80,7 @@ export class UkAddressField extends FormComponent {
|
|
|
79
80
|
{
|
|
80
81
|
type: ComponentType.TextField,
|
|
81
82
|
name: `${name}__town`,
|
|
82
|
-
title: '
|
|
83
|
+
title: 'components.addressField.town',
|
|
83
84
|
schema: { max: 100 },
|
|
84
85
|
options: {
|
|
85
86
|
autocomplete: 'address-level2',
|
|
@@ -91,7 +92,7 @@ export class UkAddressField extends FormComponent {
|
|
|
91
92
|
{
|
|
92
93
|
type: ComponentType.TextField,
|
|
93
94
|
name: `${name}__county`,
|
|
94
|
-
title: '
|
|
95
|
+
title: 'components.addressField.county',
|
|
95
96
|
schema: { max: 100 },
|
|
96
97
|
options: {
|
|
97
98
|
autocomplete: 'address-level1',
|
|
@@ -102,7 +103,7 @@ export class UkAddressField extends FormComponent {
|
|
|
102
103
|
{
|
|
103
104
|
type: ComponentType.TextField,
|
|
104
105
|
name: `${name}__postcode`,
|
|
105
|
-
title: '
|
|
106
|
+
title: 'components.addressField.postcode',
|
|
106
107
|
schema: {
|
|
107
108
|
regex: '^[a-zA-Z]{1,2}\\d[a-zA-Z\\d]?\\s?\\d[a-zA-Z]{2}$'
|
|
108
109
|
},
|
|
@@ -143,23 +144,32 @@ export class UkAddressField extends FormComponent {
|
|
|
143
144
|
return this.getContextValueFromFormValue(value)
|
|
144
145
|
}
|
|
145
146
|
|
|
146
|
-
getDisplayStringFromFormValue(
|
|
147
|
+
getDisplayStringFromFormValue(
|
|
148
|
+
value: UkAddressState | undefined,
|
|
149
|
+
_translator: Translator
|
|
150
|
+
): string {
|
|
147
151
|
return this.getContextValueFromFormValue(value)?.join(', ') ?? ''
|
|
148
152
|
}
|
|
149
153
|
|
|
150
|
-
getDisplayStringFromState(
|
|
154
|
+
getDisplayStringFromState(
|
|
155
|
+
state: FormSubmissionState,
|
|
156
|
+
translator: Translator
|
|
157
|
+
) {
|
|
151
158
|
const value = this.getFormValueFromState(state)
|
|
152
159
|
|
|
153
|
-
return this.getDisplayStringFromFormValue(value)
|
|
160
|
+
return this.getDisplayStringFromFormValue(value, translator)
|
|
154
161
|
}
|
|
155
162
|
|
|
156
163
|
/**
|
|
157
164
|
* Returns one error per child field
|
|
158
165
|
*/
|
|
159
166
|
getViewErrors(
|
|
167
|
+
translator: Translator,
|
|
160
168
|
errors?: FormSubmissionError[]
|
|
161
169
|
): FormSubmissionError[] | undefined {
|
|
162
|
-
const
|
|
170
|
+
const { t } = translator
|
|
171
|
+
|
|
172
|
+
const uniqueErrors = this.getErrors(translator, errors)?.filter(
|
|
163
173
|
(error, index, self) =>
|
|
164
174
|
index === self.findIndex((err) => err.name === error.name)
|
|
165
175
|
)
|
|
@@ -174,7 +184,9 @@ export class UkAddressField extends FormComponent {
|
|
|
174
184
|
name,
|
|
175
185
|
path: [name],
|
|
176
186
|
href: `#${name}`,
|
|
177
|
-
text:
|
|
187
|
+
text: t('components.addressField.enterAddress', {
|
|
188
|
+
shortDescription: lowerFirst(label)
|
|
189
|
+
})
|
|
178
190
|
}
|
|
179
191
|
]
|
|
180
192
|
}
|
|
@@ -182,10 +194,11 @@ export class UkAddressField extends FormComponent {
|
|
|
182
194
|
return uniqueErrors
|
|
183
195
|
}
|
|
184
196
|
|
|
185
|
-
getViewModel(
|
|
197
|
+
getViewModel(context: RenderContext) {
|
|
198
|
+
const { payload, translator } = context
|
|
186
199
|
const { collection, name, options } = this
|
|
187
200
|
|
|
188
|
-
const viewModel = super.getViewModel(
|
|
201
|
+
const viewModel = super.getViewModel(context)
|
|
189
202
|
let { fieldset, hint, label } = viewModel
|
|
190
203
|
|
|
191
204
|
fieldset ??= {
|
|
@@ -209,7 +222,7 @@ export class UkAddressField extends FormComponent {
|
|
|
209
222
|
}
|
|
210
223
|
}
|
|
211
224
|
|
|
212
|
-
const components = collection.getViewModel(
|
|
225
|
+
const components = collection.getViewModel(context)
|
|
213
226
|
|
|
214
227
|
// Hide UPRN
|
|
215
228
|
const uprn = components.at(0)
|
|
@@ -224,7 +237,7 @@ export class UkAddressField extends FormComponent {
|
|
|
224
237
|
const usePostcodeLookup = this.shouldUsePostcodeLookup()
|
|
225
238
|
|
|
226
239
|
const value = usePostcodeLookup
|
|
227
|
-
? this.getDisplayStringFromState(payload)
|
|
240
|
+
? this.getDisplayStringFromState(payload, translator)
|
|
228
241
|
: undefined
|
|
229
242
|
|
|
230
243
|
return {
|
|
@@ -284,6 +297,7 @@ export class UkAddressField extends FormComponent {
|
|
|
284
297
|
args: PostcodeLookupExternalArgs
|
|
285
298
|
) {
|
|
286
299
|
const { controller, component } = args
|
|
300
|
+
const language = resolveLanguage(request)
|
|
287
301
|
|
|
288
302
|
return dispatch(request, h, {
|
|
289
303
|
formName: controller.model.name,
|
|
@@ -291,7 +305,8 @@ export class UkAddressField extends FormComponent {
|
|
|
291
305
|
componentHint: component.hint,
|
|
292
306
|
componentTitle: component.title || controller.title,
|
|
293
307
|
step: args.actionArgs.step,
|
|
294
|
-
sourceUrl: args.sourceUrl
|
|
308
|
+
sourceUrl: args.sourceUrl,
|
|
309
|
+
language
|
|
295
310
|
})
|
|
296
311
|
}
|
|
297
312
|
}
|
|
@@ -4,9 +4,12 @@ import {
|
|
|
4
4
|
yesNoListName,
|
|
5
5
|
type YesNoFieldComponent
|
|
6
6
|
} from '@defra/forms-model'
|
|
7
|
+
import { type LanguageMessages } from 'joi'
|
|
7
8
|
|
|
8
9
|
import { SelectionControlField } from './SelectionControlField.js'
|
|
9
10
|
import { addClassOptionIfNone } from './helpers/index.js'
|
|
11
|
+
import { buildValidationMessages } from '../i18n/buildValidationMessages.js'
|
|
12
|
+
import { type Translator } from '../i18n/types.js'
|
|
10
13
|
import { messageTemplate } from '../pageControllers/validationOptions.js'
|
|
11
14
|
import { type ErrorMessageTemplateList } from '../types.js'
|
|
12
15
|
import { convertToLanguageMessages } from '../../../utils/type-utils.js'
|
|
@@ -52,6 +55,13 @@ export class YesNoField extends SelectionControlField {
|
|
|
52
55
|
this.options = options
|
|
53
56
|
}
|
|
54
57
|
|
|
58
|
+
getValidationMessagesOverride(translator: Translator): LanguageMessages {
|
|
59
|
+
const { selectYesNoRequired } = buildValidationMessages(translator.t)
|
|
60
|
+
return convertToLanguageMessages({
|
|
61
|
+
'any.required': selectYesNoRequired
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
55
65
|
/**
|
|
56
66
|
* For error preview page that shows all possible errors on a component
|
|
57
67
|
*/
|
|
@@ -6,6 +6,7 @@ import { ListFormComponent } from '../ListFormComponent.js'
|
|
|
6
6
|
import { escapeMarkdown } from './index.js'
|
|
7
7
|
import * as Components from '../index.js'
|
|
8
8
|
import { markdown } from '../markdownParser.js'
|
|
9
|
+
import { type Translator } from '../../i18n/types.js'
|
|
9
10
|
import { type FormState } from '../../types.js'
|
|
10
11
|
|
|
11
12
|
// All component instances
|
|
@@ -221,6 +222,7 @@ export function createComponent(
|
|
|
221
222
|
export function getAnswer(
|
|
222
223
|
field: Field,
|
|
223
224
|
state: FormState,
|
|
225
|
+
translator: Translator,
|
|
224
226
|
options: {
|
|
225
227
|
format:
|
|
226
228
|
| 'data' // Submission data
|
|
@@ -230,7 +232,7 @@ export function getAnswer(
|
|
|
230
232
|
) {
|
|
231
233
|
// Use escaped display text for GOV.UK Notify emails
|
|
232
234
|
if (options.format === 'email') {
|
|
233
|
-
return getAnswerMarkdown(field, state, { format: 'email' })
|
|
235
|
+
return getAnswerMarkdown(field, state, translator, { format: 'email' })
|
|
234
236
|
}
|
|
235
237
|
|
|
236
238
|
// Use context value for submission data
|
|
@@ -248,12 +250,15 @@ export function getAnswer(
|
|
|
248
250
|
field instanceof Components.LatLongField
|
|
249
251
|
) {
|
|
250
252
|
return markdown
|
|
251
|
-
.parse(
|
|
253
|
+
.parse(
|
|
254
|
+
getAnswerMarkdown(field, state, translator, { format: 'summary' }),
|
|
255
|
+
{ async: false }
|
|
256
|
+
)
|
|
252
257
|
.trim()
|
|
253
258
|
}
|
|
254
259
|
|
|
255
260
|
// Use display text for check answers summary (single line)
|
|
256
|
-
return field.getDisplayStringFromState(state)
|
|
261
|
+
return field.getDisplayStringFromState(state, translator)
|
|
257
262
|
}
|
|
258
263
|
|
|
259
264
|
/**
|
|
@@ -262,13 +267,14 @@ export function getAnswer(
|
|
|
262
267
|
export function getAnswerMarkdown(
|
|
263
268
|
field: Field,
|
|
264
269
|
state: FormState,
|
|
270
|
+
translator: Translator,
|
|
265
271
|
options: {
|
|
266
272
|
format:
|
|
267
273
|
| 'email' // GOV.UK Notify emails
|
|
268
274
|
| 'summary' // Check answers summary
|
|
269
275
|
} = { format: 'summary' }
|
|
270
276
|
) {
|
|
271
|
-
const answer = field.getDisplayStringFromState(state)
|
|
277
|
+
const answer = field.getDisplayStringFromState(state, translator)
|
|
272
278
|
|
|
273
279
|
// Use escaped display text
|
|
274
280
|
let answerEscaped = `${escapeMarkdown(answer)}\n`
|
|
@@ -305,7 +311,8 @@ export function getAnswerMarkdown(
|
|
|
305
311
|
// Append bullet points
|
|
306
312
|
answerEscaped += items
|
|
307
313
|
.map((item) => {
|
|
308
|
-
const
|
|
314
|
+
const resolvedText = translator.tListItem(item, 'text') || item.text
|
|
315
|
+
const label = escapeMarkdown(resolvedText)
|
|
309
316
|
const value = escapeMarkdown(`(${item.value})`)
|
|
310
317
|
|
|
311
318
|
let line = label
|
|
@@ -344,7 +351,7 @@ export function getAnswerMarkdown(
|
|
|
344
351
|
answerEscaped = contextValue ? `${contextValue}\n` : ''
|
|
345
352
|
} else if (field instanceof Components.GeospatialField) {
|
|
346
353
|
const features = field.getFormValueFromState(state)
|
|
347
|
-
const value = field.getDisplayStringFromFormValue(features)
|
|
354
|
+
const value = field.getDisplayStringFromFormValue(features, translator)
|
|
348
355
|
|
|
349
356
|
answerEscaped = value ? `${value}\n` : ''
|
|
350
357
|
}
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { type ComponentType, type Item } from '@defra/forms-model'
|
|
2
2
|
|
|
3
|
+
import { type Translator } from '../i18n/types.js'
|
|
3
4
|
import {
|
|
5
|
+
type FormPayload,
|
|
4
6
|
type FormSubmissionError,
|
|
5
7
|
type FormValue,
|
|
6
8
|
type SummaryList
|
|
7
9
|
} from '../types.js'
|
|
8
10
|
|
|
11
|
+
export interface RenderContext {
|
|
12
|
+
payload: FormPayload
|
|
13
|
+
errors: FormSubmissionError[] | undefined
|
|
14
|
+
translator: Translator
|
|
15
|
+
isForceAccess?: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
9
18
|
export type ComponentText = {
|
|
10
19
|
classes?: string
|
|
11
20
|
attributes?: string | Record<string, string>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { join, parse } from 'node:path'
|
|
2
2
|
|
|
3
3
|
import { type FormDefinition } from '@defra/forms-model'
|
|
4
|
+
import { type RequestQuery } from '@hapi/hapi'
|
|
5
|
+
import { type Yar } from '@hapi/yar'
|
|
4
6
|
|
|
5
7
|
import { FORM_PREFIX } from '../../constants.js'
|
|
6
8
|
import { FormModel } from './models/FormModel.js'
|
|
@@ -67,7 +69,16 @@ export const configureEnginePlugin = async (
|
|
|
67
69
|
baseUrl: 'http://localhost:3009', // always runs locally
|
|
68
70
|
saveAndExit,
|
|
69
71
|
ordnanceSurveyApiKey,
|
|
70
|
-
ordnanceSurveyApiSecret
|
|
72
|
+
ordnanceSurveyApiSecret,
|
|
73
|
+
getLanguage: (query: RequestQuery = {}, yar?: Yar) => {
|
|
74
|
+
const defaultLang = 'en-GB'
|
|
75
|
+
|
|
76
|
+
if (yar && 'language' in query) {
|
|
77
|
+
yar.set('language', query.language)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return yar?.get('language') ?? defaultLang
|
|
81
|
+
}
|
|
71
82
|
}
|
|
72
83
|
}
|
|
73
84
|
}
|
|
@@ -13,6 +13,7 @@ import { type PageController } from './pageControllers/PageController.js'
|
|
|
13
13
|
import { TerminalPageController } from './pageControllers/index.js'
|
|
14
14
|
import * as defaultServices from './services/index.js'
|
|
15
15
|
import {
|
|
16
|
+
type AnyFormRequest,
|
|
16
17
|
type AnyRequest,
|
|
17
18
|
type FormContext,
|
|
18
19
|
type FormContextRequest,
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
} from './types.js'
|
|
22
23
|
import { FormStatus } from '../../routes/types.js'
|
|
23
24
|
import { type Services } from '../../types.js'
|
|
25
|
+
import { resolveLanguage } from '../../utils/utils.js'
|
|
24
26
|
|
|
25
27
|
type JourneyState = FormStatus | 'preview'
|
|
26
28
|
|
|
@@ -36,6 +38,7 @@ export interface FormModelOptions {
|
|
|
36
38
|
|
|
37
39
|
export interface FormContextOptions extends FormModelOptions {
|
|
38
40
|
errors?: FormSubmissionError[]
|
|
41
|
+
language?: string
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
type SummaryRequest = FormContextRequest & {
|
|
@@ -119,10 +122,14 @@ export async function getFormContext(
|
|
|
119
122
|
$$__referenceNumber: cachedState.$$__referenceNumber
|
|
120
123
|
} as unknown as FormSubmissionState
|
|
121
124
|
|
|
125
|
+
const language = resolveLanguage(summaryRequest as unknown as AnyFormRequest)
|
|
126
|
+
const translator = formModel.createTranslator(language)
|
|
127
|
+
|
|
122
128
|
return formModel.getFormContext(
|
|
123
129
|
summaryRequest,
|
|
124
130
|
formState,
|
|
125
|
-
options.errors ?? []
|
|
131
|
+
options.errors ?? [],
|
|
132
|
+
translator
|
|
126
133
|
)
|
|
127
134
|
}
|
|
128
135
|
|
|
@@ -148,7 +155,6 @@ export async function resolveFormModel(
|
|
|
148
155
|
}
|
|
149
156
|
|
|
150
157
|
// The models cache is created lazily per server instance
|
|
151
|
-
|
|
152
158
|
server.app.models ??= new Map<string, { model: FormModel; updatedAt: Date }>()
|
|
153
159
|
|
|
154
160
|
const cache = server.app.models
|
|
@@ -2,8 +2,6 @@ import {
|
|
|
2
2
|
ControllerPath,
|
|
3
3
|
Engine,
|
|
4
4
|
getErrorMessage,
|
|
5
|
-
hasComponents,
|
|
6
|
-
isFormType,
|
|
7
5
|
type ComponentDef,
|
|
8
6
|
type FormDefinition,
|
|
9
7
|
type Page
|
|
@@ -109,7 +107,16 @@ engine.registerFilter('answer', function (name: string) {
|
|
|
109
107
|
return
|
|
110
108
|
}
|
|
111
109
|
|
|
112
|
-
const
|
|
110
|
+
const field = component as Field
|
|
111
|
+
const { translator } = globals.context
|
|
112
|
+
const answer = getAnswer(
|
|
113
|
+
field,
|
|
114
|
+
globals.context.relevantState,
|
|
115
|
+
translator ?? field.model.createTranslator(),
|
|
116
|
+
{
|
|
117
|
+
format: 'summary'
|
|
118
|
+
}
|
|
119
|
+
)
|
|
113
120
|
|
|
114
121
|
return answer
|
|
115
122
|
})
|
|
@@ -403,18 +410,3 @@ export function getFormVersion(
|
|
|
403
410
|
| FormVersionMetadata
|
|
404
411
|
| undefined
|
|
405
412
|
}
|
|
406
|
-
|
|
407
|
-
export function setPageTitles(def: FormDefinition) {
|
|
408
|
-
def.pages.forEach((page) => {
|
|
409
|
-
if (!page.title) {
|
|
410
|
-
if (hasComponents(page)) {
|
|
411
|
-
// Set the page title from the first form component
|
|
412
|
-
const firstFormComponent = page.components.find((component) =>
|
|
413
|
-
isFormType(component.type)
|
|
414
|
-
)
|
|
415
|
-
|
|
416
|
-
page.title = firstFormComponent?.title ?? ''
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
})
|
|
420
|
-
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import joi, { type JoiExpression, type ReferenceOptions } from 'joi'
|
|
2
|
+
|
|
3
|
+
import { lowerFirstPreserveProperNouns } from '../components/helpers/index.js'
|
|
4
|
+
|
|
5
|
+
const opts = {
|
|
6
|
+
functions: {
|
|
7
|
+
lowerFirst: lowerFirstPreserveProperNouns
|
|
8
|
+
}
|
|
9
|
+
} as ReferenceOptions
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Builds a set of translated Joi message templates for a given language.
|
|
13
|
+
* Called once per FormModel at construction time.
|
|
14
|
+
*
|
|
15
|
+
* Strings containing {{lowerFirst(#label)}} must be wrapped in joi.expression()
|
|
16
|
+
* because Joi cannot resolve custom functions from a plain string.
|
|
17
|
+
* Plain strings with only built-in tokens ({{#label}}, {{#limit}}) work without wrapping.
|
|
18
|
+
*/
|
|
19
|
+
export function buildValidationMessages(t: (key: string) => string) {
|
|
20
|
+
return {
|
|
21
|
+
// Expressions — contain lowerFirst custom function
|
|
22
|
+
required: joi.expression(t('validation.required'), opts) as JoiExpression,
|
|
23
|
+
selectRequired: joi.expression(
|
|
24
|
+
t('validation.selectRequired'),
|
|
25
|
+
opts
|
|
26
|
+
) as JoiExpression,
|
|
27
|
+
pattern: joi.expression(t('validation.pattern'), opts) as JoiExpression,
|
|
28
|
+
format: joi.expression(t('validation.format'), opts) as JoiExpression,
|
|
29
|
+
declarationRequired: joi.expression(
|
|
30
|
+
t('components.declarationField.validation.declarationRequired'),
|
|
31
|
+
opts
|
|
32
|
+
) as JoiExpression,
|
|
33
|
+
objectRequired: joi.expression(
|
|
34
|
+
t('validation.objectRequired'),
|
|
35
|
+
opts
|
|
36
|
+
) as JoiExpression,
|
|
37
|
+
objectMissing: joi.expression(
|
|
38
|
+
t('validation.objectMissing'),
|
|
39
|
+
opts
|
|
40
|
+
) as JoiExpression,
|
|
41
|
+
|
|
42
|
+
// Plain Joi template strings — no lowerFirst
|
|
43
|
+
selectYesNoRequired: t(
|
|
44
|
+
'components.yesNoField.validation.selectYesNoRequired'
|
|
45
|
+
),
|
|
46
|
+
max: t('validation.max'),
|
|
47
|
+
min: t('validation.min'),
|
|
48
|
+
minMax: t('validation.minMax'),
|
|
49
|
+
number: t('validation.number'),
|
|
50
|
+
numberPrecision: t('validation.numberPrecision'),
|
|
51
|
+
numberInteger: t('validation.numberInteger'),
|
|
52
|
+
numberMin: t('validation.numberMin'),
|
|
53
|
+
numberMax: t('validation.numberMax'),
|
|
54
|
+
maxWords: t('validation.maxWords'),
|
|
55
|
+
dateFormat: t('components.dateField.validation.dateFormat'),
|
|
56
|
+
dateMin: t('components.dateField.validation.dateMin'),
|
|
57
|
+
dateMax: t('components.dateField.validation.dateMax'),
|
|
58
|
+
|
|
59
|
+
unicode: 'validation.unicode',
|
|
60
|
+
arrayMin: 'validation.array.min',
|
|
61
|
+
arrayMax: 'validation.array.max',
|
|
62
|
+
arrayLength: 'validation.array.length',
|
|
63
|
+
featuresMin: 'validation.features.min',
|
|
64
|
+
featuresMax: 'validation.features.max',
|
|
65
|
+
featuresLength: 'validation.features.length'
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export type ValidationMessages = ReturnType<typeof buildValidationMessages>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type FormDefinition } from '@defra/forms-model'
|
|
2
|
+
import { type i18n } from 'i18next'
|
|
3
|
+
|
|
4
|
+
import { createTranslator } from './createTranslator.js'
|
|
5
|
+
import { extractBaseTranslations } from './extractBaseTranslations.js'
|
|
6
|
+
import { createFormI18nInstance } from './index.js'
|
|
7
|
+
import {
|
|
8
|
+
type FormDefinitionTranslations,
|
|
9
|
+
type Translator
|
|
10
|
+
} from './types.js'
|
|
11
|
+
|
|
12
|
+
export function createFormTranslator(
|
|
13
|
+
def: FormDefinition,
|
|
14
|
+
language: string
|
|
15
|
+
): Translator {
|
|
16
|
+
const baseTranslations = extractBaseTranslations(def)
|
|
17
|
+
const i18nInstance = createFormI18nInstance(baseTranslations)
|
|
18
|
+
loadFormTranslations(def, i18nInstance)
|
|
19
|
+
|
|
20
|
+
return createTranslator(i18nInstance, language)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function loadFormTranslations(def: FormDefinition, i18nInstance: i18n) {
|
|
24
|
+
const formTranslations = def.metadata?.translations as
|
|
25
|
+
| FormDefinitionTranslations
|
|
26
|
+
| undefined
|
|
27
|
+
|
|
28
|
+
if (formTranslations) {
|
|
29
|
+
for (const [lng, resources] of Object.entries(formTranslations)) {
|
|
30
|
+
i18nInstance.addResourceBundle(lng, 'form', resources, true, true)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type i18n } from 'i18next'
|
|
2
|
+
|
|
3
|
+
import { type Translator } from './types.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a translator for the specified language, decorated with utility functions
|
|
7
|
+
* for translating specific parts of the form definition.
|
|
8
|
+
* @param i18nInstance - instance of i18next which gets created on startup (reads the boilerplate files en-GB.json and cy.json)
|
|
9
|
+
* @param language - requested language
|
|
10
|
+
*/
|
|
11
|
+
export function createTranslator(
|
|
12
|
+
i18nInstance: i18n,
|
|
13
|
+
language = 'en-GB'
|
|
14
|
+
): Translator {
|
|
15
|
+
const t = (key: string, opts?: Record<string, unknown>): string =>
|
|
16
|
+
i18nInstance.t(key, { lng: language, ns: 'plugin', ...opts })
|
|
17
|
+
|
|
18
|
+
const resolveContent = (
|
|
19
|
+
entity: { id?: string },
|
|
20
|
+
entityType: string,
|
|
21
|
+
prop: string
|
|
22
|
+
): string => {
|
|
23
|
+
if (!entity.id) {
|
|
24
|
+
const raw = (entity as Record<string, unknown>)[prop]
|
|
25
|
+
if (typeof raw !== 'string') return ''
|
|
26
|
+
// t() resolves i18next key constants (sub-field labels); returns raw string unchanged if not a key
|
|
27
|
+
return t(raw)
|
|
28
|
+
}
|
|
29
|
+
const key = `${entityType}.${entity.id}.${prop}`
|
|
30
|
+
const result = i18nInstance.t(key, {
|
|
31
|
+
lng: language,
|
|
32
|
+
ns: 'form'
|
|
33
|
+
})
|
|
34
|
+
if (result === key) {
|
|
35
|
+
// No form translation found — fall through to t(raw) so plugin i18n
|
|
36
|
+
// key constants (e.g. 'components.yesNoField.yes') are still resolved.
|
|
37
|
+
const raw = (entity as Record<string, unknown>)[prop]
|
|
38
|
+
if (typeof raw !== 'string') return ''
|
|
39
|
+
return t(raw)
|
|
40
|
+
}
|
|
41
|
+
return result
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const resolveFormContent = (prop: string) => {
|
|
45
|
+
const key = `form.${prop}`
|
|
46
|
+
return i18nInstance.t(key, { lng: language, ns: 'form' })
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
t,
|
|
51
|
+
tForm: (prop) => resolveFormContent(prop),
|
|
52
|
+
tPage: (entity, prop) => resolveContent(entity, 'pages', prop as string),
|
|
53
|
+
tComponent: (entity, prop) =>
|
|
54
|
+
resolveContent(entity, 'components', prop as string),
|
|
55
|
+
tSection: (entity, prop) =>
|
|
56
|
+
resolveContent(entity, 'sections', prop as string),
|
|
57
|
+
tListItem: (entity, prop) =>
|
|
58
|
+
resolveContent(entity, 'listItems', prop as string),
|
|
59
|
+
language
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import {
|
|
2
|
+
hasComponentsEvenIfNoNext,
|
|
3
|
+
type FormDefinition
|
|
4
|
+
} from '@defra/forms-model'
|
|
5
|
+
|
|
6
|
+
import { type FormDefinitionTranslations } from './types.js'
|
|
7
|
+
|
|
8
|
+
type BaseTranslations = FormDefinitionTranslations[string]
|
|
9
|
+
|
|
10
|
+
export function extractBaseTranslations(def: FormDefinition): BaseTranslations {
|
|
11
|
+
const pages: BaseTranslations['pages'] = {}
|
|
12
|
+
const components: BaseTranslations['components'] = {}
|
|
13
|
+
const sections: BaseTranslations['sections'] = {}
|
|
14
|
+
const listItems: BaseTranslations['listItems'] = {}
|
|
15
|
+
const form: BaseTranslations['form'] = {}
|
|
16
|
+
|
|
17
|
+
for (const page of def.pages) {
|
|
18
|
+
if (page.id && page.title) {
|
|
19
|
+
pages[page.id] = { title: page.title }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (hasComponentsEvenIfNoNext(page)) {
|
|
23
|
+
for (const component of page.components) {
|
|
24
|
+
if (!component.id) continue
|
|
25
|
+
|
|
26
|
+
const entry: BaseTranslations['components'][string] = {}
|
|
27
|
+
|
|
28
|
+
if (component.title) entry.title = component.title
|
|
29
|
+
if ('hint' in component && component.hint) entry.hint = component.hint
|
|
30
|
+
if ('content' in component && component.content) {
|
|
31
|
+
entry.content = component.content
|
|
32
|
+
}
|
|
33
|
+
if ('shortDescription' in component && component.shortDescription) {
|
|
34
|
+
entry.shortDescription = component.shortDescription
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (Object.keys(entry).length) {
|
|
38
|
+
components[component.id] = entry
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
for (const section of def.sections) {
|
|
45
|
+
if (section.id && section.title) {
|
|
46
|
+
sections[section.id] = { title: section.title }
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
for (const list of def.lists) {
|
|
51
|
+
for (const item of list.items) {
|
|
52
|
+
if (item.id && item.text) {
|
|
53
|
+
listItems[item.id] = { text: item.text }
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
form.title = def.name ?? ''
|
|
59
|
+
|
|
60
|
+
return { pages, components, sections, listItems, form }
|
|
61
|
+
}
|