@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.
Files changed (347) hide show
  1. package/.public/assets-manifest.json +3 -5
  2. package/.public/javascripts/im-core.min.js +2 -0
  3. package/.public/javascripts/im-core.min.js.map +1 -0
  4. package/.public/javascripts/shared.min.js +1 -1
  5. package/.public/javascripts/shared.min.js.map +1 -1
  6. package/.public/javascripts/vendor/@defra.min.js +1 -1
  7. package/.public/javascripts/vendor/@defra.min.js.map +1 -1
  8. package/.public/stylesheets/application.min.css +1 -1
  9. package/.public/stylesheets/application.min.css.map +1 -1
  10. package/.server/client/javascripts/geospatial-map.js +8 -6
  11. package/.server/client/javascripts/geospatial-map.js.map +1 -1
  12. package/.server/client/javascripts/location-map.js +8 -1
  13. package/.server/client/javascripts/location-map.js.map +1 -1
  14. package/.server/client/javascripts/map.d.ts +6 -0
  15. package/.server/client/javascripts/map.js +10 -0
  16. package/.server/client/javascripts/map.js.map +1 -1
  17. package/.server/client/javascripts/sssi-dataset.d.ts +34 -0
  18. package/.server/client/javascripts/sssi-dataset.js +101 -0
  19. package/.server/client/javascripts/sssi-dataset.js.map +1 -0
  20. package/.server/client/stylesheets/shared.scss +0 -2
  21. package/.server/server/forms/register-as-a-unicorn-breeder.yaml +0 -14
  22. package/.server/server/forms/simple-form.yaml +106 -3
  23. package/.server/server/plugins/engine/components/AutocompleteField.d.ts +11 -11
  24. package/.server/server/plugins/engine/components/AutocompleteField.js +2 -2
  25. package/.server/server/plugins/engine/components/AutocompleteField.js.map +1 -1
  26. package/.server/server/plugins/engine/components/CheckboxesField.d.ts +3 -2
  27. package/.server/server/plugins/engine/components/CheckboxesField.js +4 -9
  28. package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -1
  29. package/.server/server/plugins/engine/components/ComponentCollection.d.ts +8 -7
  30. package/.server/server/plugins/engine/components/ComponentCollection.js +106 -51
  31. package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
  32. package/.server/server/plugins/engine/components/DatePartsField.d.ts +8 -6
  33. package/.server/server/plugins/engine/components/DatePartsField.js +27 -9
  34. package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -1
  35. package/.server/server/plugins/engine/components/DeclarationField.d.ts +13 -11
  36. package/.server/server/plugins/engine/components/DeclarationField.js +31 -9
  37. package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -1
  38. package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +8 -5
  39. package/.server/server/plugins/engine/components/EastingNorthingField.js +42 -22
  40. package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -1
  41. package/.server/server/plugins/engine/components/EmailAddressField.d.ts +11 -14
  42. package/.server/server/plugins/engine/components/EmailAddressField.js +2 -2
  43. package/.server/server/plugins/engine/components/EmailAddressField.js.map +1 -1
  44. package/.server/server/plugins/engine/components/FileUploadField.d.ts +14 -12
  45. package/.server/server/plugins/engine/components/FileUploadField.js +22 -12
  46. package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
  47. package/.server/server/plugins/engine/components/FormComponent.d.ts +21 -12
  48. package/.server/server/plugins/engine/components/FormComponent.js +33 -14
  49. package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
  50. package/.server/server/plugins/engine/components/GeospatialField.d.ts +15 -12
  51. package/.server/server/plugins/engine/components/GeospatialField.js +21 -13
  52. package/.server/server/plugins/engine/components/GeospatialField.js.map +1 -1
  53. package/.server/server/plugins/engine/components/LatLongField.d.ts +8 -5
  54. package/.server/server/plugins/engine/components/LatLongField.js +32 -20
  55. package/.server/server/plugins/engine/components/LatLongField.js.map +1 -1
  56. package/.server/server/plugins/engine/components/ListFormComponent.d.ts +7 -6
  57. package/.server/server/plugins/engine/components/ListFormComponent.js +19 -7
  58. package/.server/server/plugins/engine/components/ListFormComponent.js.map +1 -1
  59. package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +17 -16
  60. package/.server/server/plugins/engine/components/LocationFieldBase.js +2 -2
  61. package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -1
  62. package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +8 -3
  63. package/.server/server/plugins/engine/components/LocationFieldHelpers.js +14 -3
  64. package/.server/server/plugins/engine/components/LocationFieldHelpers.js.map +1 -1
  65. package/.server/server/plugins/engine/components/Markdown.d.ts +8 -7
  66. package/.server/server/plugins/engine/components/Markdown.js +5 -2
  67. package/.server/server/plugins/engine/components/Markdown.js.map +1 -1
  68. package/.server/server/plugins/engine/components/MonthYearField.d.ts +9 -7
  69. package/.server/server/plugins/engine/components/MonthYearField.js +26 -8
  70. package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -1
  71. package/.server/server/plugins/engine/components/MultilineTextField.d.ts +10 -9
  72. package/.server/server/plugins/engine/components/MultilineTextField.js +2 -2
  73. package/.server/server/plugins/engine/components/MultilineTextField.js.map +1 -1
  74. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +2 -1
  75. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js +14 -6
  76. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js.map +1 -1
  77. package/.server/server/plugins/engine/components/NumberField.d.ts +10 -9
  78. package/.server/server/plugins/engine/components/NumberField.js +2 -2
  79. package/.server/server/plugins/engine/components/NumberField.js.map +1 -1
  80. package/.server/server/plugins/engine/components/OsGridRefField.d.ts +2 -1
  81. package/.server/server/plugins/engine/components/OsGridRefField.js +14 -6
  82. package/.server/server/plugins/engine/components/OsGridRefField.js.map +1 -1
  83. package/.server/server/plugins/engine/components/PaymentField.d.ts +12 -10
  84. package/.server/server/plugins/engine/components/PaymentField.js +21 -8
  85. package/.server/server/plugins/engine/components/PaymentField.js.map +1 -1
  86. package/.server/server/plugins/engine/components/SelectField.d.ts +11 -11
  87. package/.server/server/plugins/engine/components/SelectField.js +2 -2
  88. package/.server/server/plugins/engine/components/SelectField.js.map +1 -1
  89. package/.server/server/plugins/engine/components/SelectionControlField.d.ts +4 -4
  90. package/.server/server/plugins/engine/components/SelectionControlField.js +2 -2
  91. package/.server/server/plugins/engine/components/SelectionControlField.js.map +1 -1
  92. package/.server/server/plugins/engine/components/TelephoneNumberField.d.ts +10 -9
  93. package/.server/server/plugins/engine/components/TelephoneNumberField.js +2 -2
  94. package/.server/server/plugins/engine/components/TelephoneNumberField.js.map +1 -1
  95. package/.server/server/plugins/engine/components/UkAddressField.d.ts +12 -10
  96. package/.server/server/plugins/engine/components/UkAddressField.js +29 -17
  97. package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
  98. package/.server/server/plugins/engine/components/YesNoField.d.ts +3 -0
  99. package/.server/server/plugins/engine/components/YesNoField.js +9 -0
  100. package/.server/server/plugins/engine/components/YesNoField.js.map +1 -1
  101. package/.server/server/plugins/engine/components/helpers/components.d.ts +3 -2
  102. package/.server/server/plugins/engine/components/helpers/components.js +11 -8
  103. package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
  104. package/.server/server/plugins/engine/components/types.d.ts +8 -1
  105. package/.server/server/plugins/engine/components/types.js.map +1 -1
  106. package/.server/server/plugins/engine/configureEnginePlugin.js +8 -1
  107. package/.server/server/plugins/engine/configureEnginePlugin.js.map +1 -1
  108. package/.server/server/plugins/engine/form-context.d.ts +1 -0
  109. package/.server/server/plugins/engine/form-context.js +4 -2
  110. package/.server/server/plugins/engine/form-context.js.map +1 -1
  111. package/.server/server/plugins/engine/helpers.d.ts +1 -1
  112. package/.server/server/plugins/engine/helpers.js +8 -13
  113. package/.server/server/plugins/engine/helpers.js.map +1 -1
  114. package/.server/server/plugins/engine/i18n/buildValidationMessages.d.ts +39 -0
  115. package/.server/server/plugins/engine/i18n/buildValidationMessages.js +50 -0
  116. package/.server/server/plugins/engine/i18n/buildValidationMessages.js.map +1 -0
  117. package/.server/server/plugins/engine/i18n/createFormTranslator.d.ts +5 -0
  118. package/.server/server/plugins/engine/i18n/createFormTranslator.js +18 -0
  119. package/.server/server/plugins/engine/i18n/createFormTranslator.js.map +1 -0
  120. package/.server/server/plugins/engine/i18n/createTranslator.d.ts +9 -0
  121. package/.server/server/plugins/engine/i18n/createTranslator.js +51 -0
  122. package/.server/server/plugins/engine/i18n/createTranslator.js.map +1 -0
  123. package/.server/server/plugins/engine/i18n/extractBaseTranslations.d.ts +5 -0
  124. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js +57 -0
  125. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js.map +1 -0
  126. package/.server/server/plugins/engine/i18n/index.d.ts +18 -0
  127. package/.server/server/plugins/engine/i18n/index.js +71 -0
  128. package/.server/server/plugins/engine/i18n/index.js.map +1 -0
  129. package/.server/server/plugins/engine/i18n/translations/cy.json +271 -0
  130. package/.server/server/plugins/engine/i18n/translations/en-GB.json +271 -0
  131. package/.server/server/plugins/engine/i18n/types.d.ts +41 -0
  132. package/.server/server/plugins/engine/i18n/types.js +2 -0
  133. package/.server/server/plugins/engine/i18n/types.js.map +1 -0
  134. package/.server/server/plugins/engine/index.js +3 -2
  135. package/.server/server/plugins/engine/index.js.map +1 -1
  136. package/.server/server/plugins/engine/models/FormModel.d.ts +9 -1
  137. package/.server/server/plugins/engine/models/FormModel.js +44 -18
  138. package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
  139. package/.server/server/plugins/engine/models/SummaryViewModel.d.ts +5 -2
  140. package/.server/server/plugins/engine/models/SummaryViewModel.js +44 -18
  141. package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
  142. package/.server/server/plugins/engine/options.js +2 -1
  143. package/.server/server/plugins/engine/options.js.map +1 -1
  144. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +4 -0
  145. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
  146. package/.server/server/plugins/engine/outputFormatters/human/v1.js +2 -1
  147. package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
  148. package/.server/server/plugins/engine/outputFormatters/machine/v1.js +7 -6
  149. package/.server/server/plugins/engine/outputFormatters/machine/v1.js.map +1 -1
  150. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.d.ts +2 -1
  151. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +6 -3
  152. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
  153. package/.server/server/plugins/engine/pageControllers/PageController.d.ts +3 -1
  154. package/.server/server/plugins/engine/pageControllers/PageController.js +11 -1
  155. package/.server/server/plugins/engine/pageControllers/PageController.js.map +1 -1
  156. package/.server/server/plugins/engine/pageControllers/QuestionPageController.d.ts +4 -2
  157. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +52 -21
  158. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
  159. package/.server/server/plugins/engine/pageControllers/RepeatPageController.d.ts +3 -2
  160. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js +63 -26
  161. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js.map +1 -1
  162. package/.server/server/plugins/engine/pageControllers/StartPageController.d.ts +3 -1
  163. package/.server/server/plugins/engine/pageControllers/StartPageController.js +2 -2
  164. package/.server/server/plugins/engine/pageControllers/StartPageController.js.map +1 -1
  165. package/.server/server/plugins/engine/pageControllers/StatusPageController.js +12 -2
  166. package/.server/server/plugins/engine/pageControllers/StatusPageController.js.map +1 -1
  167. package/.server/server/plugins/engine/pageControllers/SummaryPageController.d.ts +4 -3
  168. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +44 -28
  169. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
  170. package/.server/server/plugins/engine/pageControllers/__stubs__/translator.d.ts +2 -0
  171. package/.server/server/plugins/engine/pageControllers/__stubs__/translator.js +24 -0
  172. package/.server/server/plugins/engine/pageControllers/__stubs__/translator.js.map +1 -0
  173. package/.server/server/plugins/engine/pageControllers/errors.d.ts +1 -1
  174. package/.server/server/plugins/engine/pageControllers/errors.js +3 -2
  175. package/.server/server/plugins/engine/pageControllers/errors.js.map +1 -1
  176. package/.server/server/plugins/engine/pageControllers/helpers/submission.d.ts +3 -2
  177. package/.server/server/plugins/engine/pageControllers/helpers/submission.js +4 -4
  178. package/.server/server/plugins/engine/pageControllers/helpers/submission.js.map +1 -1
  179. package/.server/server/plugins/engine/pageControllers/validationOptions.d.ts +7 -3
  180. package/.server/server/plugins/engine/pageControllers/validationOptions.js +34 -33
  181. package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
  182. package/.server/server/plugins/engine/plugin.js +2 -0
  183. package/.server/server/plugins/engine/plugin.js.map +1 -1
  184. package/.server/server/plugins/engine/routes/index.js +4 -1
  185. package/.server/server/plugins/engine/routes/index.js.map +1 -1
  186. package/.server/server/plugins/engine/routes/questions.js +5 -2
  187. package/.server/server/plugins/engine/routes/questions.js.map +1 -1
  188. package/.server/server/plugins/engine/types/index.d.ts +1 -0
  189. package/.server/server/plugins/engine/types/index.js.map +1 -1
  190. package/.server/server/plugins/engine/types/schema.js +1 -0
  191. package/.server/server/plugins/engine/types/schema.js.map +1 -1
  192. package/.server/server/plugins/engine/types.d.ts +12 -1
  193. package/.server/server/plugins/engine/types.js.map +1 -1
  194. package/.server/server/plugins/engine/views/components/_location-field-base.html +4 -2
  195. package/.server/server/plugins/engine/views/components/fileuploadfield.html +3 -3
  196. package/.server/server/plugins/engine/views/components/geospatialfield.html +4 -1
  197. package/.server/server/plugins/engine/views/components/nationalgridfieldnumberfield.html +1 -1
  198. package/.server/server/plugins/engine/views/components/osgridreffield.html +1 -1
  199. package/.server/server/plugins/engine/views/components/paymentfield.html +8 -8
  200. package/.server/server/plugins/engine/views/components/ukaddressfield.html +4 -4
  201. package/.server/server/plugins/engine/views/confirmation.html +4 -4
  202. package/.server/server/plugins/engine/views/exit.html +4 -4
  203. package/.server/server/plugins/engine/views/file-upload.html +3 -3
  204. package/.server/server/plugins/engine/views/index.html +3 -3
  205. package/.server/server/plugins/engine/views/item-delete.html +1 -1
  206. package/.server/server/plugins/engine/views/partials/form.html +3 -3
  207. package/.server/server/plugins/engine/views/partials/preview-banner.html +4 -4
  208. package/.server/server/plugins/engine/views/partials/warn-missing-notification-email.html +4 -5
  209. package/.server/server/plugins/engine/views/repeat-list-summary.html +4 -4
  210. package/.server/server/plugins/engine/views/summary.html +14 -7
  211. package/.server/server/plugins/map/routes/index.js +1 -1
  212. package/.server/server/plugins/map/routes/index.js.map +1 -1
  213. package/.server/server/plugins/map/types.d.ts +1 -25
  214. package/.server/server/plugins/map/types.js +1 -16
  215. package/.server/server/plugins/map/types.js.map +1 -1
  216. package/.server/server/plugins/nunjucks/enviroment.test.js +10 -0
  217. package/.server/server/plugins/nunjucks/enviroment.test.js.map +1 -1
  218. package/.server/server/plugins/nunjucks/environment.d.ts +8 -0
  219. package/.server/server/plugins/nunjucks/environment.js +13 -0
  220. package/.server/server/plugins/nunjucks/environment.js.map +1 -1
  221. package/.server/server/plugins/nunjucks/filters/answer.js +9 -1
  222. package/.server/server/plugins/nunjucks/filters/answer.js.map +1 -1
  223. package/.server/server/plugins/nunjucks/filters/answer.test.js +13 -2
  224. package/.server/server/plugins/nunjucks/filters/answer.test.js.map +1 -1
  225. package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
  226. package/.server/server/plugins/postcode-lookup/models/index.d.ts +24 -19
  227. package/.server/server/plugins/postcode-lookup/models/index.js +83 -76
  228. package/.server/server/plugins/postcode-lookup/models/index.js.map +1 -1
  229. package/.server/server/plugins/postcode-lookup/routes/index.js +7 -13
  230. package/.server/server/plugins/postcode-lookup/routes/index.js.map +1 -1
  231. package/.server/server/plugins/postcode-lookup/types.d.ts +1 -0
  232. package/.server/server/plugins/postcode-lookup/types.js +1 -0
  233. package/.server/server/plugins/postcode-lookup/types.js.map +1 -1
  234. package/.server/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  235. package/.server/server/types.d.ts +2 -1
  236. package/.server/server/types.js.map +1 -1
  237. package/.server/server/utils/utils.d.ts +5 -0
  238. package/.server/server/utils/utils.js +16 -0
  239. package/.server/server/utils/utils.js.map +1 -1
  240. package/.server/typings/hapi/index.d.js.map +1 -1
  241. package/package.json +5 -4
  242. package/src/client/javascripts/geospatial-map.js +10 -6
  243. package/src/client/javascripts/location-map.js +11 -0
  244. package/src/client/javascripts/map.js +10 -0
  245. package/src/client/javascripts/sssi-dataset.js +106 -0
  246. package/src/client/stylesheets/shared.scss +0 -2
  247. package/src/server/forms/register-as-a-unicorn-breeder.yaml +0 -14
  248. package/src/server/forms/simple-form.yaml +106 -3
  249. package/src/server/plugins/engine/components/AutocompleteField.ts +3 -6
  250. package/src/server/plugins/engine/components/CheckboxesField.ts +12 -11
  251. package/src/server/plugins/engine/components/ComponentCollection.ts +143 -61
  252. package/src/server/plugins/engine/components/DatePartsField.ts +33 -11
  253. package/src/server/plugins/engine/components/DeclarationField.ts +37 -14
  254. package/src/server/plugins/engine/components/EastingNorthingField.ts +83 -22
  255. package/src/server/plugins/engine/components/EmailAddressField.ts +4 -7
  256. package/src/server/plugins/engine/components/FileUploadField.ts +28 -22
  257. package/src/server/plugins/engine/components/FormComponent.ts +49 -12
  258. package/src/server/plugins/engine/components/GeospatialField.ts +38 -21
  259. package/src/server/plugins/engine/components/LatLongField.ts +52 -21
  260. package/src/server/plugins/engine/components/ListFormComponent.ts +26 -10
  261. package/src/server/plugins/engine/components/LocationFieldBase.ts +5 -8
  262. package/src/server/plugins/engine/components/LocationFieldHelpers.ts +24 -4
  263. package/src/server/plugins/engine/components/Markdown.ts +7 -3
  264. package/src/server/plugins/engine/components/MonthYearField.ts +32 -10
  265. package/src/server/plugins/engine/components/MultilineTextField.ts +5 -8
  266. package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +25 -11
  267. package/src/server/plugins/engine/components/NumberField.ts +3 -4
  268. package/src/server/plugins/engine/components/OsGridRefField.ts +25 -9
  269. package/src/server/plugins/engine/components/PaymentField.ts +22 -12
  270. package/src/server/plugins/engine/components/SelectField.ts +3 -6
  271. package/src/server/plugins/engine/components/SelectionControlField.ts +7 -8
  272. package/src/server/plugins/engine/components/TelephoneNumberField.ts +4 -7
  273. package/src/server/plugins/engine/components/UkAddressField.ts +33 -18
  274. package/src/server/plugins/engine/components/YesNoField.ts +10 -0
  275. package/src/server/plugins/engine/components/helpers/components.ts +13 -6
  276. package/src/server/plugins/engine/components/types.ts +9 -0
  277. package/src/server/plugins/engine/configureEnginePlugin.ts +12 -1
  278. package/src/server/plugins/engine/form-context.ts +8 -2
  279. package/src/server/plugins/engine/helpers.ts +10 -18
  280. package/src/server/plugins/engine/i18n/buildValidationMessages.ts +69 -0
  281. package/src/server/plugins/engine/i18n/createFormTranslator.ts +33 -0
  282. package/src/server/plugins/engine/i18n/createTranslator.ts +61 -0
  283. package/src/server/plugins/engine/i18n/extractBaseTranslations.ts +61 -0
  284. package/src/server/plugins/engine/i18n/index.ts +80 -0
  285. package/src/server/plugins/engine/i18n/translations/cy.json +271 -0
  286. package/src/server/plugins/engine/i18n/translations/en-GB.json +271 -0
  287. package/src/server/plugins/engine/i18n/types.ts +62 -0
  288. package/src/server/plugins/engine/index.ts +4 -2
  289. package/src/server/plugins/engine/models/FormModel.ts +59 -23
  290. package/src/server/plugins/engine/models/SummaryViewModel.ts +68 -25
  291. package/src/server/plugins/engine/options.js +2 -1
  292. package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +5 -0
  293. package/src/server/plugins/engine/outputFormatters/human/v1.ts +2 -3
  294. package/src/server/plugins/engine/outputFormatters/machine/v1.ts +9 -8
  295. package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +7 -3
  296. package/src/server/plugins/engine/pageControllers/PageController.ts +12 -1
  297. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +53 -21
  298. package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +66 -29
  299. package/src/server/plugins/engine/pageControllers/StartPageController.ts +7 -2
  300. package/src/server/plugins/engine/pageControllers/StatusPageController.ts +10 -2
  301. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +48 -22
  302. package/src/server/plugins/engine/pageControllers/__stubs__/translator.ts +28 -0
  303. package/src/server/plugins/engine/pageControllers/errors.ts +4 -2
  304. package/src/server/plugins/engine/pageControllers/helpers/submission.ts +11 -4
  305. package/src/server/plugins/engine/pageControllers/validationOptions.ts +43 -53
  306. package/src/server/plugins/engine/plugin.ts +2 -0
  307. package/src/server/plugins/engine/routes/index.ts +9 -1
  308. package/src/server/plugins/engine/routes/questions.ts +5 -1
  309. package/src/server/plugins/engine/types/index.ts +5 -0
  310. package/src/server/plugins/engine/types/schema.ts +1 -0
  311. package/src/server/plugins/engine/types.ts +10 -0
  312. package/src/server/plugins/engine/views/components/_location-field-base.html +4 -2
  313. package/src/server/plugins/engine/views/components/fileuploadfield.html +3 -3
  314. package/src/server/plugins/engine/views/components/geospatialfield.html +4 -1
  315. package/src/server/plugins/engine/views/components/nationalgridfieldnumberfield.html +1 -1
  316. package/src/server/plugins/engine/views/components/osgridreffield.html +1 -1
  317. package/src/server/plugins/engine/views/components/paymentfield.html +8 -8
  318. package/src/server/plugins/engine/views/components/ukaddressfield.html +4 -4
  319. package/src/server/plugins/engine/views/confirmation.html +4 -4
  320. package/src/server/plugins/engine/views/exit.html +4 -4
  321. package/src/server/plugins/engine/views/file-upload.html +3 -3
  322. package/src/server/plugins/engine/views/index.html +3 -3
  323. package/src/server/plugins/engine/views/item-delete.html +1 -1
  324. package/src/server/plugins/engine/views/partials/form.html +3 -3
  325. package/src/server/plugins/engine/views/partials/preview-banner.html +4 -4
  326. package/src/server/plugins/engine/views/partials/warn-missing-notification-email.html +4 -5
  327. package/src/server/plugins/engine/views/repeat-list-summary.html +4 -4
  328. package/src/server/plugins/engine/views/summary.html +14 -7
  329. package/src/server/plugins/map/routes/index.js +1 -1
  330. package/src/server/plugins/map/types.js +1 -16
  331. package/src/server/plugins/nunjucks/environment.js +14 -0
  332. package/src/server/plugins/nunjucks/filters/answer.js +12 -1
  333. package/src/server/plugins/postcode-lookup/models/index.js +144 -87
  334. package/src/server/plugins/postcode-lookup/routes/index.js +13 -16
  335. package/src/server/plugins/postcode-lookup/types.js +1 -0
  336. package/src/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  337. package/src/server/types.ts +2 -0
  338. package/src/server/utils/utils.js +14 -0
  339. package/src/typings/hapi/index.d.ts +1 -0
  340. package/.public/javascripts/im-search-plugin.min.js +0 -2
  341. package/.public/javascripts/im-search-plugin.min.js.map +0 -1
  342. package/.public/javascripts/vendor/preact.min.js +0 -2
  343. package/.public/javascripts/vendor/preact.min.js.map +0 -1
  344. package/.server/server/plugins/engine/components/constants.d.ts +0 -1
  345. package/.server/server/plugins/engine/components/constants.js +0 -2
  346. package/.server/server/plugins/engine/components/constants.js.map +0 -1
  347. package/src/server/plugins/engine/components/constants.ts +0 -1
@@ -0,0 +1,271 @@
1
+ {
2
+ "validation": {
3
+ "required": "Enter {{lowerFirst(#label)}}",
4
+ "selectRequired": "Select {{lowerFirst(#label)}}",
5
+ "pattern": "Enter a valid {{lowerFirst(#label)}}",
6
+ "format": "Enter {{lowerFirst(#label)}} in the correct format",
7
+ "objectRequired": "Enter {{#label}}",
8
+ "objectMissing": "{{#title}} must include a {{lowerFirst(#label)}}",
9
+ "max": "{{#label}} must be {{#limit}} characters or less",
10
+ "min": "{{#label}} must be {{#limit}} characters or more",
11
+ "minMax": "{{#label}} must be between {{#min}} and {{#max}} characters",
12
+ "number": "{{#label}} must be a number",
13
+ "numberPrecision": "{{#label}} must have {{#limit}} or fewer decimal places",
14
+ "numberInteger": "{{#label}} must be a whole number",
15
+ "numberMin": "{{#label}} must be {{#limit}} or higher",
16
+ "numberMax": "{{#label}} must be {{#limit}} or lower",
17
+ "maxWords": "{{#label}} must be {{#limit}} words or fewer"
18
+ },
19
+
20
+ "errors": {
21
+ "title": "There is a problem",
22
+ "optionsMismatch": "Options are different because you changed a previous answer"
23
+ },
24
+
25
+ "common": {
26
+ "optional": "(optional)",
27
+ "warningIconFallback": "Warning",
28
+ "back": "Back",
29
+ "continue": "Continue",
30
+ "saveAndExit": "Save and exit",
31
+ "draft": "draft",
32
+ "live": "live"
33
+ },
34
+
35
+ "pages": {
36
+ "question": {
37
+ "paymentCancelledBannerTitle": "Important",
38
+ "paymentCancelledTitle": "Your payment has been cancelled",
39
+ "paymentCancelledBody": "Your payment details were deleted because the form was inactive for 5 days.",
40
+ "paymentCancelledAction": "Add your payment details again.",
41
+ "backToAddAnother": "Go back to add another",
42
+ "backToCheckAnswers": "Go back to check answers",
43
+ "startNow": "Start now"
44
+ },
45
+
46
+ "summary": {
47
+ "title": "Check your answers before sending your form",
48
+ "change": "Change",
49
+ "notProvided": "Not provided",
50
+ "declaration": "Declaration",
51
+ "acceptAndSubmit": "Accept and submit",
52
+ "payAndSubmit": "Pay and submit",
53
+ "submit": "Submit",
54
+ "saveAndExit": "Save and exit",
55
+ "paymentSuccessBannerTitle": "Success",
56
+ "paymentSuccessTitle": "We have your payment details",
57
+ "paymentSuccessBody": "Your payment is on hold. We will charge you when you submit the form.",
58
+ "paymentDetailsTitle": "Payment details",
59
+ "paymentFor": "Payment for",
60
+ "totalAmount": "Total amount",
61
+ "reference": "Reference",
62
+ "dateOfPayment": "Date of payment",
63
+ "submissionFailed": "There was a problem and your form was not submitted. Try submitting the form again",
64
+ "submissionFailedContactSuffix": " or you can [[contactUsLink]] and quote your reference number to arrange a refund",
65
+ "contactUsLinkText": "contact us (opens in new tab)",
66
+ "confirmationEmail": "Confirmation email (optional)",
67
+ "confirmationEmailHint": "Enter your email address to receive a confirmation email and a copy of your answers"
68
+ },
69
+
70
+ "repeater": {
71
+ "removeAnswer": "Are you sure you want to remove this answer?",
72
+ "remove": "Remove",
73
+ "cancel": "Cancel",
74
+ "lastItemCannotBeRemoved": "Last list item cannot be removed",
75
+ "itemToRemoveNotFound": "List item to remove not found",
76
+ "continue": "Continue",
77
+ "addAnother": "Add another",
78
+ "saveAndExit": "Save and exit",
79
+ "change": "Change",
80
+ "notProvided": "Not provided",
81
+ "visuallyHiddenItem": "item [[index]]",
82
+ "pageTitle_one": "You have added [[count]] answer",
83
+ "pageTitle_other": "You have added [[count]] answers",
84
+ "tooMany_one": "You can only add up to [[count]] answer",
85
+ "tooMany_other": "You can only add up to [[count]] answers",
86
+ "tooFew_one": "You must add at least [[count]] answer",
87
+ "tooFew_other": "You must add at least [[count]] answers"
88
+ },
89
+
90
+ "fileUpload": {
91
+ "upload": "Upload file",
92
+ "maxFilesReached": "You have reached the maximum number of files. Please remove a file to upload more."
93
+ },
94
+
95
+ "exit": {
96
+ "defaultTitle": "Your progress has been saved",
97
+ "whatHappensNext": "What happens next",
98
+ "body": "Your form progress has been saved. You can return to complete your application at any time using the link provided.",
99
+ "returnToApplication": "Return to application"
100
+ },
101
+
102
+ "confirmation": {
103
+ "formSubmitted": "Form submitted",
104
+ "whatHappensNext": "What happens next",
105
+ "referenceNumber": "Your reference number",
106
+ "feedbackLink": "What do you think of this service? (takes 30 seconds)"
107
+ },
108
+
109
+ "preview": {
110
+ "warnMissingNotificationEmail": {
111
+ "body": "If you want to receive a test email, [[link]] you want form submissions to go to.",
112
+ "linkText": "enter the email address (opens in new tab)"
113
+ },
114
+ "bannerForce": "This is a preview of a [[previewMode]] form. Do not enter personal information.",
115
+ "bannerText": "This is a preview of a [[previewMode]] form page you are editing.",
116
+ "previousPages": "It depends on answers from earlier pages in the form. In the live version, users will need to complete those questions first."
117
+ }
118
+ },
119
+
120
+ "postcodeLookup": {
121
+ "postcodeLabel": "Postcode",
122
+ "postcodeHint": "For example, AA3 1AB",
123
+ "buildingNameLabel": "Building name or number (optional)",
124
+ "buildingNameHint": "For example, 15 or Prospect Cottage",
125
+ "selectAddress": "Select an address",
126
+ "addressLine1Label": "Address line 1",
127
+ "addressLine2Label": "Address line 2 (optional)",
128
+ "townLabel": "Town or city",
129
+ "countyLabel": "County (optional)",
130
+ "findAddress": "Find address",
131
+ "enterManually": "enter address manually",
132
+ "searchAgain": "Search again",
133
+ "useThisAddress": "Use this address",
134
+ "findAnAddressInstead": "find an address instead",
135
+ "noAddressFoundTitle": "No address found",
136
+ "noAddressFoundBody": "We could not find an address that matches",
137
+ "addressFound_one": "[[count]] address found for",
138
+ "addressFound_other": "[[count]] addresses found for",
139
+ "validation": {
140
+ "invalidPostcode": "Enter a valid postcode or enter an address manually",
141
+ "requiredPostcode": "Enter a postcode",
142
+ "selectAddress": "Select an address",
143
+ "requiredAddressLine1": "Enter address line 1",
144
+ "requiredTown": "Enter town or city",
145
+ "invalidManualPostcode": "Enter a valid postcode",
146
+ "requiredManualPostcode": "Enter postcode"
147
+ }
148
+ },
149
+
150
+ "components": {
151
+ "dateField": {
152
+ "day": "Day",
153
+ "month": "Month",
154
+ "year": "Year",
155
+ "validation": {
156
+ "dateFormat": "{{#title}} must be a real date",
157
+ "dateMin": "{{#title}} must be the same as or after {{#limit}}",
158
+ "dateMax": "{{#title}} must be the same as or before {{#limit}}"
159
+ }
160
+ },
161
+
162
+ "monthYearField": {
163
+ "month": "Month",
164
+ "year": "Year"
165
+ },
166
+
167
+ "addressField": {
168
+ "uprn": "UPRN",
169
+ "line1": "Address line 1",
170
+ "line2": "Address line 2",
171
+ "town": "Town or city",
172
+ "county": "County",
173
+ "postcode": "Postcode",
174
+ "enterAddress": "Enter [[shortDescription]]",
175
+ "findAddress": "Find an address",
176
+ "selectedAddress": "Selected address:",
177
+ "useDifferentAddress": "Use a different address",
178
+ "enterManually": "enter address manually"
179
+ },
180
+
181
+ "latLongField": {
182
+ "latitude": "Latitude",
183
+ "longitude": "Longitude",
184
+ "latitudeRequired": "Enter latitude",
185
+ "longitudeRequired": "Enter longitude",
186
+ "precision": "{{#label}} must have no more than 7 decimal places",
187
+ "notANumber": "{{#label}} must be a valid number",
188
+ "latitudeBase": "Enter a valid latitude for [[fieldLabel]] like 51.519450",
189
+ "longitudeBase": "Enter a valid longitude for [[fieldLabel]] like -0.127758",
190
+ "latitudeRange": "Latitude for [[fieldLabel]] must be between [[min]] and [[max]]",
191
+ "longitudeRange": "Longitude for [[fieldLabel]] must be between [[min]] and [[max]]"
192
+ },
193
+
194
+ "eastingNorthingField": {
195
+ "easting": "Easting",
196
+ "northing": "Northing",
197
+ "eastingRequired": "Enter easting",
198
+ "northingRequired": "Enter northing",
199
+ "eastingDigits": "{{#label}} for [[fieldLabel]] must be between 1 and 6 digits",
200
+ "northingDigits": "{{#label}} for [[fieldLabel]] must be between 1 and 7 digits",
201
+ "eastingRange": "{{#label}} for [[fieldLabel]] must be between [[min]] and [[max]]",
202
+ "northingRange": "{{#label}} for [[fieldLabel]] must be between [[min]] and [[max]]"
203
+ },
204
+
205
+ "nationalGridField": {
206
+ "required": "Enter {{lowerFirst(#title)}}",
207
+ "pattern": "Enter a valid National Grid field number for {{lowerFirst(#title)}} like NG 1234 5678",
208
+ "howToFind": "How to find location details"
209
+ },
210
+
211
+ "osGridRefField": {
212
+ "required": "Enter {{lowerFirst(#title)}}",
213
+ "pattern": "Enter a valid OS grid reference for {{lowerFirst(#title)}} like TQ123456",
214
+ "howToFind": "How to find location details"
215
+ },
216
+
217
+ "locationFieldBase": {
218
+ "howToFind": "How to find location details"
219
+ },
220
+
221
+ "yesNoField": {
222
+ "yes": "Yes",
223
+ "no": "No",
224
+ "validation": {
225
+ "selectYesNoRequired": "{{#label}} - select yes or no"
226
+ }
227
+ },
228
+
229
+ "declarationField": {
230
+ "defaultLabel": "I understand and agree",
231
+ "defaultConfirmationLabel": "I confirm that I understand and accept this declaration",
232
+ "notProvided": "Not provided",
233
+ "validation": {
234
+ "declarationRequired": "You must confirm you understand and agree with the {{lowerFirst(#label)}} to continue"
235
+ }
236
+ },
237
+
238
+ "geospatialField": {
239
+ "added_one": "Added [[count]] location",
240
+ "added_other": "Added [[count]] locations",
241
+ "validation": {
242
+ "descriptionRequired": "Enter description for location [[count]]",
243
+ "wrongCountry": "Location [[count]] must be within [[country]]"
244
+ }
245
+ },
246
+
247
+ "paymentField": {
248
+ "detailsRequired": "Payment details required",
249
+ "pendingTransaction": "You may see a pending transaction in your bank account but you will only be charged when you submit the form.",
250
+ "addPaymentDetails": "Add payment details",
251
+ "cannotTakePayment": "There is a problem and we cannot take a payment. Contact us (details in the footer of this form) or save your progress and return to the form later.",
252
+ "testApiKey": "Add a valid test API key before you can preview the payment journey.",
253
+ "completePayment": "Complete the payment to continue",
254
+ "paymentExpired": "Your payment authorisation has expired. Please add your payment details again.",
255
+ "submissionFailed": "There was a problem and your form was not submitted. Try submitting the form again.",
256
+ "canSubmitAfterPayment": "You can submit the form after you have added your payment details.",
257
+ "preAuthorisedTitle": "You have already authorised a payment for this form",
258
+ "preAuthorisedBody": "Continue to submit the form. You will not be charged twice.",
259
+ "totalAmountLabel": "Total amount:",
260
+ "paymentAmountMismatch": "The pre-authorised payment amount is somehow different from that requested. Try adding payment details again."
261
+ },
262
+
263
+ "fileUploadField": {
264
+ "uploaded": "Uploaded",
265
+ "uploadFailed": "There was a problem with your uploaded files. Re-upload them before submitting the form again.",
266
+ "uploadedFilesHeading": "Uploaded files",
267
+ "filesCount_one": "[[count]] file uploaded",
268
+ "filesCount_other": "[[count]] files uploaded"
269
+ }
270
+ }
271
+ }
@@ -0,0 +1,41 @@
1
+ import { type ComponentDef, type Item, type Page, type Section } from '@defra/forms-model';
2
+ /**
3
+ * Structure of the `translations` block in a form definition.
4
+ * Also used to derive the valid property keys for the typed tX functions.
5
+ */
6
+ export type FormDefinitionTranslations = Record<string, {
7
+ pages: Record<string, Partial<{
8
+ title: string;
9
+ repeatTitle: string;
10
+ }>>;
11
+ components: Record<string, Partial<{
12
+ title: string;
13
+ hint: string;
14
+ content: string;
15
+ shortDescription: string;
16
+ }>>;
17
+ sections: Record<string, Partial<Pick<Section, 'title'>>>;
18
+ listItems: Record<string, Partial<Pick<Item, 'text' | 'hint'>>>;
19
+ form: Record<string, string>;
20
+ }>;
21
+ type EntityTranslations = FormDefinitionTranslations[string];
22
+ /**
23
+ * Scoped translator returned by model.createTranslator(language).
24
+ * t — plugin namespace (UI strings, buttons, errors, sub-field labels)
25
+ * tForm — form namespace: form attributes, currently only form name
26
+ * tPage — form namespace: page titles
27
+ * tComponent — form namespace: component titles, hints, shortDescriptions
28
+ * tSection — form namespace: section titles
29
+ * tListItem — form namespace: list item text
30
+ * language - current language
31
+ */
32
+ export interface Translator {
33
+ t: (key: string, opts?: Record<string, unknown>) => string;
34
+ tForm: (prop: string) => string;
35
+ tPage: (page: Page, prop: keyof EntityTranslations['pages'][string]) => string;
36
+ tComponent: (component: ComponentDef, prop: keyof EntityTranslations['components'][string]) => string;
37
+ tSection: (section: Section, prop: keyof EntityTranslations['sections'][string]) => string;
38
+ tListItem: (item: Item, prop: keyof EntityTranslations['listItems'][string]) => string;
39
+ language: string;
40
+ }
41
+ export {};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../../../src/server/plugins/engine/i18n/types.ts"],"sourcesContent":["import {\n type ComponentDef,\n type Item,\n type Page,\n type Section\n} from '@defra/forms-model'\n\n/**\n * Structure of the `translations` block in a form definition.\n * Also used to derive the valid property keys for the typed tX functions.\n */\nexport type FormDefinitionTranslations = Record<\n string,\n {\n pages: Record<string, Partial<{ title: string; repeatTitle: string }>>\n // ComponentDef is a discriminated union; Pick across the full union is not feasible.\n // The four keys below are the complete set of translatable component properties.\n components: Record<\n string,\n Partial<{\n title: string\n hint: string\n content: string\n shortDescription: string\n }>\n >\n sections: Record<string, Partial<Pick<Section, 'title'>>>\n listItems: Record<string, Partial<Pick<Item, 'text' | 'hint'>>>\n form: Record<string, string>\n }\n>\n\ntype EntityTranslations = FormDefinitionTranslations[string]\n\n/**\n * Scoped translator returned by model.createTranslator(language).\n * t — plugin namespace (UI strings, buttons, errors, sub-field labels)\n * tForm — form namespace: form attributes, currently only form name\n * tPage — form namespace: page titles\n * tComponent — form namespace: component titles, hints, shortDescriptions\n * tSection — form namespace: section titles\n * tListItem — form namespace: list item text\n * language - current language\n */\nexport interface Translator {\n t: (key: string, opts?: Record<string, unknown>) => string\n tForm: (prop: string) => string\n tPage: (page: Page, prop: keyof EntityTranslations['pages'][string]) => string\n tComponent: (\n component: ComponentDef,\n prop: keyof EntityTranslations['components'][string]\n ) => string\n tSection: (\n section: Section,\n prop: keyof EntityTranslations['sections'][string]\n ) => string\n tListItem: (\n item: Item,\n prop: keyof EntityTranslations['listItems'][string]\n ) => string\n language: string\n}\n"],"mappings":"","ignoreList":[]}
@@ -1,7 +1,7 @@
1
1
  import { markdownToHtml } from '@defra/forms-model';
2
2
  import { engine } from "./helpers.js";
3
3
  import { plugin } from "./plugin.js";
4
- import { checkComponentTemplates, checkErrorTemplates, evaluate, govukRebrand } from "../nunjucks/environment.js";
4
+ import { checkComponentTemplates, checkErrorTemplates, evaluate, govukRebrand, tGlobal } from "../nunjucks/environment.js";
5
5
  import * as filters from "../nunjucks/filters/index.js";
6
6
  export { getPageHref } from "./helpers.js";
7
7
  export { context } from "../nunjucks/context.js";
@@ -11,7 +11,8 @@ const globals = {
11
11
  checkComponentTemplates,
12
12
  checkErrorTemplates,
13
13
  evaluate,
14
- govukRebrand
14
+ govukRebrand,
15
+ t: tGlobal
15
16
  };
16
17
  export const VIEW_PATH = 'src/server/plugins/engine/views';
17
18
  export const PLUGIN_PATH = 'node_modules/@defra/forms-engine-plugin';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["markdownToHtml","engine","plugin","checkComponentTemplates","checkErrorTemplates","evaluate","govukRebrand","filters","getPageHref","context","getFirstJourneyPage","getFormContext","getFormModel","resolveFormModel","globals","VIEW_PATH","PLUGIN_PATH","STATE_NOT_YET_VALIDATED","CURRENT_PAGE_PATH_KEY","MAGIC_LINK_GROUP_ID","prepareNunjucksEnvironment","env","pluginOptions","name","nunjucksFilter","Object","entries","addFilter","text","startingHeaderLevel","baseUrl","nunjucksGlobal","addGlobal","filter","registerFilter","forEach","fn"],"sources":["../../../../src/server/plugins/engine/index.ts"],"sourcesContent":["import { markdownToHtml } from '@defra/forms-model'\nimport { type Environment } from 'nunjucks'\n\nimport { engine } from '~/src/server/plugins/engine/helpers.js'\nimport { plugin } from '~/src/server/plugins/engine/plugin.js'\nimport { type PluginOptions } from '~/src/server/plugins/engine/types.js'\nimport {\n checkComponentTemplates,\n checkErrorTemplates,\n evaluate,\n govukRebrand\n} from '~/src/server/plugins/nunjucks/environment.js'\nimport * as filters from '~/src/server/plugins/nunjucks/filters/index.js'\n\nexport { getPageHref } from '~/src/server/plugins/engine/helpers.js'\nexport { context } from '~/src/server/plugins/nunjucks/context.js'\nexport {\n getFirstJourneyPage,\n getFormContext,\n getFormModel,\n resolveFormModel\n} from '~/src/server/plugins/engine/form-context.js'\nexport * from '~/src/server/plugins/engine/form-availability.js'\n\nconst globals = {\n checkComponentTemplates,\n checkErrorTemplates,\n evaluate,\n govukRebrand\n}\n\nexport const VIEW_PATH = 'src/server/plugins/engine/views'\nexport const PLUGIN_PATH = 'node_modules/@defra/forms-engine-plugin'\n\nexport const STATE_NOT_YET_VALIDATED = '__stateNotYetValidated'\nexport const CURRENT_PAGE_PATH_KEY = '__currentPagePath'\nexport const MAGIC_LINK_GROUP_ID = '__magicLinkGroupId'\n\nexport const prepareNunjucksEnvironment = function (\n env: Environment,\n pluginOptions: PluginOptions\n) {\n for (const [name, nunjucksFilter] of Object.entries(filters)) {\n env.addFilter(name, nunjucksFilter)\n }\n\n env.addFilter('markdown', (text: string, startingHeaderLevel?: number) =>\n markdownToHtml(text, {\n baseUrl: pluginOptions.baseUrl,\n startingHeaderLevel\n })\n )\n\n for (const [name, nunjucksGlobal] of Object.entries(globals)) {\n env.addGlobal(name, nunjucksGlobal)\n }\n\n // Apply any additional filters to both the liquid and nunjucks engines\n if (pluginOptions.filters) {\n for (const [name, filter] of Object.entries(pluginOptions.filters)) {\n env.addFilter(name, filter)\n engine.registerFilter(name, filter)\n }\n }\n\n // Apply any additional globals to nunjucks engines\n if (pluginOptions.globals) {\n Object.entries(pluginOptions.globals).forEach(([name, fn]) => {\n env.addGlobal(name, fn)\n })\n }\n}\n\nexport default plugin\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,oBAAoB;AAGnD,SAASC,MAAM;AACf,SAASC,MAAM;AAEf,SACEC,uBAAuB,EACvBC,mBAAmB,EACnBC,QAAQ,EACRC,YAAY;AAEd,OAAO,KAAKC,OAAO;AAEnB,SAASC,WAAW;AACpB,SAASC,OAAO;AAChB,SACEC,mBAAmB,EACnBC,cAAc,EACdC,YAAY,EACZC,gBAAgB;AAElB;AAEA,MAAMC,OAAO,GAAG;EACdX,uBAAuB;EACvBC,mBAAmB;EACnBC,QAAQ;EACRC;AACF,CAAC;AAED,OAAO,MAAMS,SAAS,GAAG,iCAAiC;AAC1D,OAAO,MAAMC,WAAW,GAAG,yCAAyC;AAEpE,OAAO,MAAMC,uBAAuB,GAAG,wBAAwB;AAC/D,OAAO,MAAMC,qBAAqB,GAAG,mBAAmB;AACxD,OAAO,MAAMC,mBAAmB,GAAG,oBAAoB;AAEvD,OAAO,MAAMC,0BAA0B,GAAG,SAAAA,CACxCC,GAAgB,EAChBC,aAA4B,EAC5B;EACA,KAAK,MAAM,CAACC,IAAI,EAAEC,cAAc,CAAC,IAAIC,MAAM,CAACC,OAAO,CAACnB,OAAO,CAAC,EAAE;IAC5Dc,GAAG,CAACM,SAAS,CAACJ,IAAI,EAAEC,cAAc,CAAC;EACrC;EAEAH,GAAG,CAACM,SAAS,CAAC,UAAU,EAAE,CAACC,IAAY,EAAEC,mBAA4B,KACnE7B,cAAc,CAAC4B,IAAI,EAAE;IACnBE,OAAO,EAAER,aAAa,CAACQ,OAAO;IAC9BD;EACF,CAAC,CACH,CAAC;EAED,KAAK,MAAM,CAACN,IAAI,EAAEQ,cAAc,CAAC,IAAIN,MAAM,CAACC,OAAO,CAACZ,OAAO,CAAC,EAAE;IAC5DO,GAAG,CAACW,SAAS,CAACT,IAAI,EAAEQ,cAAc,CAAC;EACrC;;EAEA;EACA,IAAIT,aAAa,CAACf,OAAO,EAAE;IACzB,KAAK,MAAM,CAACgB,IAAI,EAAEU,MAAM,CAAC,IAAIR,MAAM,CAACC,OAAO,CAACJ,aAAa,CAACf,OAAO,CAAC,EAAE;MAClEc,GAAG,CAACM,SAAS,CAACJ,IAAI,EAAEU,MAAM,CAAC;MAC3BhC,MAAM,CAACiC,cAAc,CAACX,IAAI,EAAEU,MAAM,CAAC;IACrC;EACF;;EAEA;EACA,IAAIX,aAAa,CAACR,OAAO,EAAE;IACzBW,MAAM,CAACC,OAAO,CAACJ,aAAa,CAACR,OAAO,CAAC,CAACqB,OAAO,CAAC,CAAC,CAACZ,IAAI,EAAEa,EAAE,CAAC,KAAK;MAC5Df,GAAG,CAACW,SAAS,CAACT,IAAI,EAAEa,EAAE,CAAC;IACzB,CAAC,CAAC;EACJ;AACF,CAAC;AAED,eAAelC,MAAM","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["markdownToHtml","engine","plugin","checkComponentTemplates","checkErrorTemplates","evaluate","govukRebrand","tGlobal","filters","getPageHref","context","getFirstJourneyPage","getFormContext","getFormModel","resolveFormModel","globals","t","VIEW_PATH","PLUGIN_PATH","STATE_NOT_YET_VALIDATED","CURRENT_PAGE_PATH_KEY","MAGIC_LINK_GROUP_ID","prepareNunjucksEnvironment","env","pluginOptions","name","nunjucksFilter","Object","entries","addFilter","text","startingHeaderLevel","baseUrl","nunjucksGlobal","addGlobal","filter","registerFilter","forEach","fn"],"sources":["../../../../src/server/plugins/engine/index.ts"],"sourcesContent":["import { markdownToHtml } from '@defra/forms-model'\nimport { type Environment } from 'nunjucks'\n\nimport { engine } from '~/src/server/plugins/engine/helpers.js'\nimport { plugin } from '~/src/server/plugins/engine/plugin.js'\nimport { type PluginOptions } from '~/src/server/plugins/engine/types.js'\nimport {\n checkComponentTemplates,\n checkErrorTemplates,\n evaluate,\n govukRebrand,\n tGlobal\n} from '~/src/server/plugins/nunjucks/environment.js'\nimport * as filters from '~/src/server/plugins/nunjucks/filters/index.js'\n\nexport { getPageHref } from '~/src/server/plugins/engine/helpers.js'\nexport { context } from '~/src/server/plugins/nunjucks/context.js'\nexport {\n getFirstJourneyPage,\n getFormContext,\n getFormModel,\n resolveFormModel\n} from '~/src/server/plugins/engine/form-context.js'\nexport * from '~/src/server/plugins/engine/form-availability.js'\n\nconst globals = {\n checkComponentTemplates,\n checkErrorTemplates,\n evaluate,\n govukRebrand,\n t: tGlobal\n}\n\nexport const VIEW_PATH = 'src/server/plugins/engine/views'\nexport const PLUGIN_PATH = 'node_modules/@defra/forms-engine-plugin'\n\nexport const STATE_NOT_YET_VALIDATED = '__stateNotYetValidated'\nexport const CURRENT_PAGE_PATH_KEY = '__currentPagePath'\nexport const MAGIC_LINK_GROUP_ID = '__magicLinkGroupId'\n\nexport const prepareNunjucksEnvironment = function (\n env: Environment,\n pluginOptions: PluginOptions\n) {\n for (const [name, nunjucksFilter] of Object.entries(filters)) {\n env.addFilter(name, nunjucksFilter)\n }\n\n env.addFilter('markdown', (text: string, startingHeaderLevel?: number) =>\n markdownToHtml(text, {\n baseUrl: pluginOptions.baseUrl,\n startingHeaderLevel\n })\n )\n\n for (const [name, nunjucksGlobal] of Object.entries(globals)) {\n env.addGlobal(name, nunjucksGlobal)\n }\n\n // Apply any additional filters to both the liquid and nunjucks engines\n if (pluginOptions.filters) {\n for (const [name, filter] of Object.entries(pluginOptions.filters)) {\n env.addFilter(name, filter)\n engine.registerFilter(name, filter)\n }\n }\n\n // Apply any additional globals to nunjucks engines\n if (pluginOptions.globals) {\n Object.entries(pluginOptions.globals).forEach(([name, fn]) => {\n env.addGlobal(name, fn)\n })\n }\n}\n\nexport default plugin\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,oBAAoB;AAGnD,SAASC,MAAM;AACf,SAASC,MAAM;AAEf,SACEC,uBAAuB,EACvBC,mBAAmB,EACnBC,QAAQ,EACRC,YAAY,EACZC,OAAO;AAET,OAAO,KAAKC,OAAO;AAEnB,SAASC,WAAW;AACpB,SAASC,OAAO;AAChB,SACEC,mBAAmB,EACnBC,cAAc,EACdC,YAAY,EACZC,gBAAgB;AAElB;AAEA,MAAMC,OAAO,GAAG;EACdZ,uBAAuB;EACvBC,mBAAmB;EACnBC,QAAQ;EACRC,YAAY;EACZU,CAAC,EAAET;AACL,CAAC;AAED,OAAO,MAAMU,SAAS,GAAG,iCAAiC;AAC1D,OAAO,MAAMC,WAAW,GAAG,yCAAyC;AAEpE,OAAO,MAAMC,uBAAuB,GAAG,wBAAwB;AAC/D,OAAO,MAAMC,qBAAqB,GAAG,mBAAmB;AACxD,OAAO,MAAMC,mBAAmB,GAAG,oBAAoB;AAEvD,OAAO,MAAMC,0BAA0B,GAAG,SAAAA,CACxCC,GAAgB,EAChBC,aAA4B,EAC5B;EACA,KAAK,MAAM,CAACC,IAAI,EAAEC,cAAc,CAAC,IAAIC,MAAM,CAACC,OAAO,CAACpB,OAAO,CAAC,EAAE;IAC5De,GAAG,CAACM,SAAS,CAACJ,IAAI,EAAEC,cAAc,CAAC;EACrC;EAEAH,GAAG,CAACM,SAAS,CAAC,UAAU,EAAE,CAACC,IAAY,EAAEC,mBAA4B,KACnE/B,cAAc,CAAC8B,IAAI,EAAE;IACnBE,OAAO,EAAER,aAAa,CAACQ,OAAO;IAC9BD;EACF,CAAC,CACH,CAAC;EAED,KAAK,MAAM,CAACN,IAAI,EAAEQ,cAAc,CAAC,IAAIN,MAAM,CAACC,OAAO,CAACb,OAAO,CAAC,EAAE;IAC5DQ,GAAG,CAACW,SAAS,CAACT,IAAI,EAAEQ,cAAc,CAAC;EACrC;;EAEA;EACA,IAAIT,aAAa,CAAChB,OAAO,EAAE;IACzB,KAAK,MAAM,CAACiB,IAAI,EAAEU,MAAM,CAAC,IAAIR,MAAM,CAACC,OAAO,CAACJ,aAAa,CAAChB,OAAO,CAAC,EAAE;MAClEe,GAAG,CAACM,SAAS,CAACJ,IAAI,EAAEU,MAAM,CAAC;MAC3BlC,MAAM,CAACmC,cAAc,CAACX,IAAI,EAAEU,MAAM,CAAC;IACrC;EACF;;EAEA;EACA,IAAIX,aAAa,CAACT,OAAO,EAAE;IACzBY,MAAM,CAACC,OAAO,CAACJ,aAAa,CAACT,OAAO,CAAC,CAACsB,OAAO,CAAC,CAAC,CAACZ,IAAI,EAAEa,EAAE,CAAC,KAAK;MAC5Df,GAAG,CAACW,SAAS,CAACT,IAAI,EAAEa,EAAE,CAAC;IACzB,CAAC,CAAC;EACJ;AACF,CAAC;AAED,eAAepC,MAAM","ignoreList":[]}
@@ -2,6 +2,7 @@ import { SchemaVersion, type ComponentDef, type ConditionWrapper, type Condition
2
2
  import { Parser, type Value } from 'expr-eval-fork';
3
3
  import joi from 'joi';
4
4
  import { type Component } from '../../../../server/plugins/engine/components/helpers/components.js';
5
+ import { type Translator } from '../../../../server/plugins/engine/i18n/types.js';
5
6
  import { type ExecutableCondition } from '../../../../server/plugins/engine/models/types.js';
6
7
  import { type PageController } from '../../../../server/plugins/engine/pageControllers/PageController.js';
7
8
  import { type PageControllerClass } from '../../../../server/plugins/engine/pageControllers/helpers/pages.js';
@@ -23,6 +24,7 @@ export declare class FormModel {
23
24
  conditions: Partial<Record<string, ExecutableCondition>>;
24
25
  pages: PageControllerClass[];
25
26
  services: Services;
27
+ private readonly i18nInstance;
26
28
  controllers?: Record<string, typeof PageController>;
27
29
  pageDefMap: Map<string, Page>;
28
30
  listDefMap: Map<string, List>;
@@ -36,6 +38,8 @@ export declare class FormModel {
36
38
  ordnanceSurveyApiKey?: string;
37
39
  formId?: string;
38
40
  }, services?: Services, controllers?: Record<string, typeof PageController>);
41
+ /** Returns a scoped translator pair for the given language. */
42
+ createTranslator(language?: string): Translator;
39
43
  /**
40
44
  * build the entire model schema from individual pages/sections and filter out answers
41
45
  * for pages which are no longer accessible due to an answer that has been changed
@@ -53,7 +57,7 @@ export declare class FormModel {
53
57
  /**
54
58
  * Form context for the current page
55
59
  */
56
- getFormContext(request: FormContextRequest, state: FormSubmissionState, errors?: FormSubmissionError[]): FormContext;
60
+ getFormContext(request: FormContextRequest, state: FormSubmissionState, errors?: FormSubmissionError[], translator?: Translator): FormContext;
57
61
  private initialiseContext;
58
62
  private assignEvaluationState;
59
63
  private assignRelevantState;
@@ -73,3 +77,7 @@ export declare class FormModel {
73
77
  */
74
78
  moreThanOnePaymentQuestion(): boolean;
75
79
  }
80
+ export declare function getAvailableLanguages(def: FormDefinition): {
81
+ name: string;
82
+ code: string;
83
+ }[];
@@ -6,7 +6,11 @@ import { logger } from "../../../common/helpers/logging/logger.js";
6
6
  import "../components/YesNoField.js";
7
7
  import { hasListFormField } from "../components/helpers/components.js";
8
8
  import { todayAsDateOnly } from "../date-helper.js";
9
- import { findPage, getError, getPage, setPageTitles } from "../helpers.js";
9
+ import { findPage, getError, getPage } from "../helpers.js";
10
+ import { loadFormTranslations } from "../i18n/createFormTranslator.js";
11
+ import { createTranslator } from "../i18n/createTranslator.js";
12
+ import { extractBaseTranslations } from "../i18n/extractBaseTranslations.js";
13
+ import { createFormI18nInstance } from "../i18n/index.js";
10
14
  import { createPage } from "../pageControllers/helpers/pages.js";
11
15
  import { validationOptions as opts } from "../pageControllers/validationOptions.js";
12
16
  import * as defaultServices from "../services/index.js";
@@ -29,6 +33,7 @@ export class FormModel {
29
33
  conditions;
30
34
  pages;
31
35
  services;
36
+ i18nInstance;
32
37
  controllers;
33
38
  pageDefMap;
34
39
  listDefMap;
@@ -53,8 +58,12 @@ export class FormModel {
53
58
  // Make a clone of the shallow copy returned
54
59
  // by joi so as not to change the source data.
55
60
  def = structuredClone(result.value);
61
+ const baseTranslations = extractBaseTranslations(def);
62
+ this.i18nInstance = createFormI18nInstance(baseTranslations);
63
+ loadFormTranslations(def, this.i18nInstance);
56
64
 
57
- // Add default lists
65
+ // Add default lists. Yes/No text stored as i18n key constants so they
66
+ // resolve to the user's language at render time via the translator.
58
67
  def.lists.push({
59
68
  id: def.schema === SchemaVersion.V1 ? yesNoListName : yesNoListId,
60
69
  name: '__yesNo',
@@ -62,17 +71,14 @@ export class FormModel {
62
71
  type: 'boolean',
63
72
  items: [{
64
73
  id: '02900d42-83d1-4c72-a719-c4e8228952fa',
65
- text: 'Yes',
74
+ text: 'components.yesNoField.yes',
66
75
  value: true
67
76
  }, {
68
77
  id: 'f39000eb-c51b-4019-8f82-bbda0423f04d',
69
- text: 'No',
78
+ text: 'components.yesNoField.no',
70
79
  value: false
71
80
  }]
72
81
  });
73
-
74
- // Fix up page titles
75
- setPageTitles(def);
76
82
  this.engine = def.engine;
77
83
  this.schemaVersion = def.schema ?? SchemaVersion.V1;
78
84
  this.def = def;
@@ -113,7 +119,7 @@ export class FormModel {
113
119
  // Check for user-provided status page (optional)
114
120
  controller === ControllerType.Status)) {
115
121
  this.pages.push(createPage(this, {
116
- title: 'Form submitted',
122
+ title: 'pages.confirmation.formSubmitted',
117
123
  path: ControllerPath.Status,
118
124
  controller: ControllerType.Status
119
125
  }));
@@ -122,6 +128,11 @@ export class FormModel {
122
128
  this.componentMap = new Map(this.pages.flatMap(page => page.collection.components.map(component => [component.name, component])));
123
129
  }
124
130
 
131
+ /** Returns a scoped translator pair for the given language. */
132
+ createTranslator(language = 'en-GB') {
133
+ return createTranslator(this.i18nInstance, language);
134
+ }
135
+
125
136
  /**
126
137
  * build the entire model schema from individual pages/sections and filter out answers
127
138
  * for pages which are no longer accessible due to an answer that has been changed
@@ -207,7 +218,7 @@ export class FormModel {
207
218
  /**
208
219
  * Form context for the current page
209
220
  */
210
- getFormContext(request, state, errors) {
221
+ getFormContext(request, state, errors, translator) {
211
222
  const {
212
223
  query
213
224
  } = request;
@@ -234,11 +245,13 @@ export class FormModel {
234
245
  componentDefMap: this.componentDefMap,
235
246
  pageMap: this.pageMap,
236
247
  componentMap: this.componentMap,
237
- referenceNumber: getReferenceNumber(state)
248
+ referenceNumber: getReferenceNumber(state),
249
+ languages: getAvailableLanguages(this.def),
250
+ translator
238
251
  };
239
252
 
240
253
  // Validate current page
241
- context = validateFormPayload(request, page, context);
254
+ context = validateFormPayload(request, page, context, translator);
242
255
 
243
256
  // Find start page
244
257
  let nextPage = findPage(this, startPath);
@@ -252,7 +265,7 @@ export class FormModel {
252
265
  this.assignRelevantState(context, nextPage);
253
266
 
254
267
  // Stop at current page
255
- if (this.pageStateIsInvalid(context, nextPage) || nextPage.path === currentPath) {
268
+ if (this.pageStateIsInvalid(context, nextPage, translator) || nextPage.path === currentPath) {
256
269
  break;
257
270
  }
258
271
 
@@ -301,7 +314,7 @@ export class FormModel {
301
314
  }
302
315
  }
303
316
  }
304
- pageStateIsInvalid(context, page) {
317
+ pageStateIsInvalid(context, page, translator) {
305
318
  // Get any list-bound fields on the page
306
319
  const listFields = page.collection.fields.filter(hasListFormField);
307
320
 
@@ -315,12 +328,12 @@ export class FormModel {
315
328
  if (list !== undefined && field.type !== ComponentType.YesNoField) {
316
329
  const hasOptionalItems = list.items.filter(item => item.condition).length > 0;
317
330
  if (hasOptionalItems) {
318
- return this.fieldStateIsInvalid(context, field, list);
331
+ return this.fieldStateIsInvalid(context, field, list, translator);
319
332
  }
320
333
  }
321
334
  }
322
335
  }
323
- fieldStateIsInvalid(context, field, list) {
336
+ fieldStateIsInvalid(context, field, list, translator) {
324
337
  const {
325
338
  evaluationState,
326
339
  state
@@ -342,7 +355,7 @@ export class FormModel {
342
355
  }
343
356
  if (isInvalid) {
344
357
  context.errors ??= [];
345
- const text = 'Options are different because you changed a previous answer';
358
+ const text = (translator ?? this.createTranslator('en-GB')).t('errors.optionsMismatch');
346
359
  context.errors.push({
347
360
  text,
348
361
  name: field.name,
@@ -399,7 +412,7 @@ export class FormModel {
399
412
  /**
400
413
  * Validate current page only
401
414
  */
402
- function validateFormPayload(request, page, context) {
415
+ function validateFormPayload(request, page, context, translator) {
403
416
  const {
404
417
  collection
405
418
  } = page;
@@ -433,7 +446,7 @@ function validateFormPayload(request, page, context) {
433
446
  } = collection.validate({
434
447
  ...payload,
435
448
  ...update
436
- });
449
+ }, translator);
437
450
 
438
451
  // Add sanitised payload (ready to save)
439
452
  const formState = page.getStateFromValidForm(request, state, value);
@@ -482,4 +495,17 @@ function getReferenceNumber(state) {
482
495
  }
483
496
  return state.$$__referenceNumber;
484
497
  }
498
+ export function getAvailableLanguages(def) {
499
+ // @ts-expect-error - dynamic property
500
+ if (def.metadata?.translations?.cy) {
501
+ return [{
502
+ name: 'English',
503
+ code: 'en-GB'
504
+ }, {
505
+ name: 'Cymraeg',
506
+ code: 'cy'
507
+ }];
508
+ }
509
+ return [];
510
+ }
485
511
  //# sourceMappingURL=FormModel.js.map