@defra/forms-engine-plugin 4.23.0 → 5.0.0-alpha

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 (309) hide show
  1. package/.server/server/forms/register-as-a-unicorn-breeder.yaml +0 -14
  2. package/.server/server/forms/simple-form.yaml +106 -3
  3. package/.server/server/plugins/engine/components/AutocompleteField.d.ts +11 -11
  4. package/.server/server/plugins/engine/components/AutocompleteField.js +2 -2
  5. package/.server/server/plugins/engine/components/AutocompleteField.js.map +1 -1
  6. package/.server/server/plugins/engine/components/CheckboxesField.d.ts +3 -2
  7. package/.server/server/plugins/engine/components/CheckboxesField.js +4 -9
  8. package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -1
  9. package/.server/server/plugins/engine/components/ComponentCollection.d.ts +8 -7
  10. package/.server/server/plugins/engine/components/ComponentCollection.js +106 -51
  11. package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
  12. package/.server/server/plugins/engine/components/DatePartsField.d.ts +8 -6
  13. package/.server/server/plugins/engine/components/DatePartsField.js +27 -9
  14. package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -1
  15. package/.server/server/plugins/engine/components/DeclarationField.d.ts +13 -11
  16. package/.server/server/plugins/engine/components/DeclarationField.js +31 -9
  17. package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -1
  18. package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +6 -5
  19. package/.server/server/plugins/engine/components/EastingNorthingField.js +42 -22
  20. package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -1
  21. package/.server/server/plugins/engine/components/EmailAddressField.d.ts +11 -14
  22. package/.server/server/plugins/engine/components/EmailAddressField.js +2 -2
  23. package/.server/server/plugins/engine/components/EmailAddressField.js.map +1 -1
  24. package/.server/server/plugins/engine/components/FileUploadField.d.ts +14 -12
  25. package/.server/server/plugins/engine/components/FileUploadField.js +22 -12
  26. package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
  27. package/.server/server/plugins/engine/components/FormComponent.d.ts +21 -12
  28. package/.server/server/plugins/engine/components/FormComponent.js +33 -14
  29. package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
  30. package/.server/server/plugins/engine/components/GeospatialField.d.ts +14 -12
  31. package/.server/server/plugins/engine/components/GeospatialField.js +19 -13
  32. package/.server/server/plugins/engine/components/GeospatialField.js.map +1 -1
  33. package/.server/server/plugins/engine/components/LatLongField.d.ts +6 -5
  34. package/.server/server/plugins/engine/components/LatLongField.js +32 -20
  35. package/.server/server/plugins/engine/components/LatLongField.js.map +1 -1
  36. package/.server/server/plugins/engine/components/ListFormComponent.d.ts +7 -6
  37. package/.server/server/plugins/engine/components/ListFormComponent.js +19 -7
  38. package/.server/server/plugins/engine/components/ListFormComponent.js.map +1 -1
  39. package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +17 -16
  40. package/.server/server/plugins/engine/components/LocationFieldBase.js +2 -2
  41. package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -1
  42. package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +3 -3
  43. package/.server/server/plugins/engine/components/LocationFieldHelpers.js +2 -2
  44. package/.server/server/plugins/engine/components/LocationFieldHelpers.js.map +1 -1
  45. package/.server/server/plugins/engine/components/Markdown.d.ts +8 -7
  46. package/.server/server/plugins/engine/components/Markdown.js +5 -2
  47. package/.server/server/plugins/engine/components/Markdown.js.map +1 -1
  48. package/.server/server/plugins/engine/components/MonthYearField.d.ts +9 -7
  49. package/.server/server/plugins/engine/components/MonthYearField.js +26 -8
  50. package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -1
  51. package/.server/server/plugins/engine/components/MultilineTextField.d.ts +10 -9
  52. package/.server/server/plugins/engine/components/MultilineTextField.js +2 -2
  53. package/.server/server/plugins/engine/components/MultilineTextField.js.map +1 -1
  54. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +2 -1
  55. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js +14 -6
  56. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js.map +1 -1
  57. package/.server/server/plugins/engine/components/NumberField.d.ts +10 -9
  58. package/.server/server/plugins/engine/components/NumberField.js +2 -2
  59. package/.server/server/plugins/engine/components/NumberField.js.map +1 -1
  60. package/.server/server/plugins/engine/components/OsGridRefField.d.ts +2 -1
  61. package/.server/server/plugins/engine/components/OsGridRefField.js +14 -6
  62. package/.server/server/plugins/engine/components/OsGridRefField.js.map +1 -1
  63. package/.server/server/plugins/engine/components/PaymentField.d.ts +12 -10
  64. package/.server/server/plugins/engine/components/PaymentField.js +21 -8
  65. package/.server/server/plugins/engine/components/PaymentField.js.map +1 -1
  66. package/.server/server/plugins/engine/components/SelectField.d.ts +11 -11
  67. package/.server/server/plugins/engine/components/SelectField.js +2 -2
  68. package/.server/server/plugins/engine/components/SelectField.js.map +1 -1
  69. package/.server/server/plugins/engine/components/SelectionControlField.d.ts +4 -4
  70. package/.server/server/plugins/engine/components/SelectionControlField.js +2 -2
  71. package/.server/server/plugins/engine/components/SelectionControlField.js.map +1 -1
  72. package/.server/server/plugins/engine/components/TelephoneNumberField.d.ts +10 -9
  73. package/.server/server/plugins/engine/components/TelephoneNumberField.js +2 -2
  74. package/.server/server/plugins/engine/components/TelephoneNumberField.js.map +1 -1
  75. package/.server/server/plugins/engine/components/UkAddressField.d.ts +12 -10
  76. package/.server/server/plugins/engine/components/UkAddressField.js +29 -17
  77. package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
  78. package/.server/server/plugins/engine/components/YesNoField.d.ts +3 -0
  79. package/.server/server/plugins/engine/components/YesNoField.js +9 -0
  80. package/.server/server/plugins/engine/components/YesNoField.js.map +1 -1
  81. package/.server/server/plugins/engine/components/helpers/components.d.ts +3 -2
  82. package/.server/server/plugins/engine/components/helpers/components.js +11 -8
  83. package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
  84. package/.server/server/plugins/engine/components/types.d.ts +8 -1
  85. package/.server/server/plugins/engine/components/types.js.map +1 -1
  86. package/.server/server/plugins/engine/configureEnginePlugin.js +8 -1
  87. package/.server/server/plugins/engine/configureEnginePlugin.js.map +1 -1
  88. package/.server/server/plugins/engine/form-context.d.ts +1 -0
  89. package/.server/server/plugins/engine/form-context.js +4 -2
  90. package/.server/server/plugins/engine/form-context.js.map +1 -1
  91. package/.server/server/plugins/engine/helpers.d.ts +1 -1
  92. package/.server/server/plugins/engine/helpers.js +8 -13
  93. package/.server/server/plugins/engine/helpers.js.map +1 -1
  94. package/.server/server/plugins/engine/i18n/buildValidationMessages.d.ts +39 -0
  95. package/.server/server/plugins/engine/i18n/buildValidationMessages.js +50 -0
  96. package/.server/server/plugins/engine/i18n/buildValidationMessages.js.map +1 -0
  97. package/.server/server/plugins/engine/i18n/createFormTranslator.d.ts +5 -0
  98. package/.server/server/plugins/engine/i18n/createFormTranslator.js +18 -0
  99. package/.server/server/plugins/engine/i18n/createFormTranslator.js.map +1 -0
  100. package/.server/server/plugins/engine/i18n/createTranslator.d.ts +9 -0
  101. package/.server/server/plugins/engine/i18n/createTranslator.js +51 -0
  102. package/.server/server/plugins/engine/i18n/createTranslator.js.map +1 -0
  103. package/.server/server/plugins/engine/i18n/extractBaseTranslations.d.ts +5 -0
  104. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js +57 -0
  105. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js.map +1 -0
  106. package/.server/server/plugins/engine/i18n/index.d.ts +18 -0
  107. package/.server/server/plugins/engine/i18n/index.js +71 -0
  108. package/.server/server/plugins/engine/i18n/index.js.map +1 -0
  109. package/.server/server/plugins/engine/i18n/translations/cy.json +271 -0
  110. package/.server/server/plugins/engine/i18n/translations/en-GB.json +271 -0
  111. package/.server/server/plugins/engine/i18n/types.d.ts +41 -0
  112. package/.server/server/plugins/engine/i18n/types.js +2 -0
  113. package/.server/server/plugins/engine/i18n/types.js.map +1 -0
  114. package/.server/server/plugins/engine/index.js +3 -2
  115. package/.server/server/plugins/engine/index.js.map +1 -1
  116. package/.server/server/plugins/engine/models/FormModel.d.ts +9 -1
  117. package/.server/server/plugins/engine/models/FormModel.js +44 -18
  118. package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
  119. package/.server/server/plugins/engine/models/SummaryViewModel.d.ts +5 -2
  120. package/.server/server/plugins/engine/models/SummaryViewModel.js +44 -18
  121. package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
  122. package/.server/server/plugins/engine/options.js +2 -1
  123. package/.server/server/plugins/engine/options.js.map +1 -1
  124. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +4 -0
  125. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
  126. package/.server/server/plugins/engine/outputFormatters/human/v1.js +2 -1
  127. package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
  128. package/.server/server/plugins/engine/outputFormatters/machine/v1.js +7 -6
  129. package/.server/server/plugins/engine/outputFormatters/machine/v1.js.map +1 -1
  130. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.d.ts +2 -1
  131. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +6 -3
  132. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
  133. package/.server/server/plugins/engine/pageControllers/PageController.d.ts +3 -1
  134. package/.server/server/plugins/engine/pageControllers/PageController.js +11 -1
  135. package/.server/server/plugins/engine/pageControllers/PageController.js.map +1 -1
  136. package/.server/server/plugins/engine/pageControllers/QuestionPageController.d.ts +4 -2
  137. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +52 -21
  138. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
  139. package/.server/server/plugins/engine/pageControllers/RepeatPageController.d.ts +3 -2
  140. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js +63 -26
  141. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js.map +1 -1
  142. package/.server/server/plugins/engine/pageControllers/StartPageController.d.ts +3 -1
  143. package/.server/server/plugins/engine/pageControllers/StartPageController.js +2 -2
  144. package/.server/server/plugins/engine/pageControllers/StartPageController.js.map +1 -1
  145. package/.server/server/plugins/engine/pageControllers/StatusPageController.js +12 -2
  146. package/.server/server/plugins/engine/pageControllers/StatusPageController.js.map +1 -1
  147. package/.server/server/plugins/engine/pageControllers/SummaryPageController.d.ts +4 -3
  148. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +44 -28
  149. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
  150. package/.server/server/plugins/engine/pageControllers/__stubs__/translator.d.ts +2 -0
  151. package/.server/server/plugins/engine/pageControllers/__stubs__/translator.js +24 -0
  152. package/.server/server/plugins/engine/pageControllers/__stubs__/translator.js.map +1 -0
  153. package/.server/server/plugins/engine/pageControllers/errors.d.ts +1 -1
  154. package/.server/server/plugins/engine/pageControllers/errors.js +3 -2
  155. package/.server/server/plugins/engine/pageControllers/errors.js.map +1 -1
  156. package/.server/server/plugins/engine/pageControllers/helpers/submission.d.ts +3 -2
  157. package/.server/server/plugins/engine/pageControllers/helpers/submission.js +4 -4
  158. package/.server/server/plugins/engine/pageControllers/helpers/submission.js.map +1 -1
  159. package/.server/server/plugins/engine/pageControllers/validationOptions.d.ts +7 -3
  160. package/.server/server/plugins/engine/pageControllers/validationOptions.js +34 -33
  161. package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
  162. package/.server/server/plugins/engine/plugin.js +2 -0
  163. package/.server/server/plugins/engine/plugin.js.map +1 -1
  164. package/.server/server/plugins/engine/routes/index.js +4 -1
  165. package/.server/server/plugins/engine/routes/index.js.map +1 -1
  166. package/.server/server/plugins/engine/routes/questions.js +5 -2
  167. package/.server/server/plugins/engine/routes/questions.js.map +1 -1
  168. package/.server/server/plugins/engine/types/index.d.ts +1 -0
  169. package/.server/server/plugins/engine/types/index.js.map +1 -1
  170. package/.server/server/plugins/engine/types/schema.js +1 -0
  171. package/.server/server/plugins/engine/types/schema.js.map +1 -1
  172. package/.server/server/plugins/engine/types.d.ts +12 -1
  173. package/.server/server/plugins/engine/types.js.map +1 -1
  174. package/.server/server/plugins/engine/views/components/_location-field-base.html +1 -1
  175. package/.server/server/plugins/engine/views/components/fileuploadfield.html +3 -3
  176. package/.server/server/plugins/engine/views/components/nationalgridfieldnumberfield.html +1 -1
  177. package/.server/server/plugins/engine/views/components/osgridreffield.html +1 -1
  178. package/.server/server/plugins/engine/views/components/paymentfield.html +8 -8
  179. package/.server/server/plugins/engine/views/components/ukaddressfield.html +4 -4
  180. package/.server/server/plugins/engine/views/confirmation.html +4 -4
  181. package/.server/server/plugins/engine/views/exit.html +4 -4
  182. package/.server/server/plugins/engine/views/file-upload.html +3 -3
  183. package/.server/server/plugins/engine/views/index.html +3 -3
  184. package/.server/server/plugins/engine/views/item-delete.html +1 -1
  185. package/.server/server/plugins/engine/views/partials/form.html +3 -3
  186. package/.server/server/plugins/engine/views/partials/preview-banner.html +4 -4
  187. package/.server/server/plugins/engine/views/partials/warn-missing-notification-email.html +4 -5
  188. package/.server/server/plugins/engine/views/repeat-list-summary.html +4 -4
  189. package/.server/server/plugins/engine/views/summary.html +14 -7
  190. package/.server/server/plugins/nunjucks/enviroment.test.js +10 -0
  191. package/.server/server/plugins/nunjucks/enviroment.test.js.map +1 -1
  192. package/.server/server/plugins/nunjucks/environment.d.ts +8 -0
  193. package/.server/server/plugins/nunjucks/environment.js +13 -0
  194. package/.server/server/plugins/nunjucks/environment.js.map +1 -1
  195. package/.server/server/plugins/nunjucks/filters/answer.js +9 -1
  196. package/.server/server/plugins/nunjucks/filters/answer.js.map +1 -1
  197. package/.server/server/plugins/nunjucks/filters/answer.test.js +13 -2
  198. package/.server/server/plugins/nunjucks/filters/answer.test.js.map +1 -1
  199. package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
  200. package/.server/server/plugins/postcode-lookup/models/index.d.ts +24 -19
  201. package/.server/server/plugins/postcode-lookup/models/index.js +83 -76
  202. package/.server/server/plugins/postcode-lookup/models/index.js.map +1 -1
  203. package/.server/server/plugins/postcode-lookup/routes/index.js +7 -13
  204. package/.server/server/plugins/postcode-lookup/routes/index.js.map +1 -1
  205. package/.server/server/plugins/postcode-lookup/types.d.ts +1 -0
  206. package/.server/server/plugins/postcode-lookup/types.js +1 -0
  207. package/.server/server/plugins/postcode-lookup/types.js.map +1 -1
  208. package/.server/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  209. package/.server/server/types.d.ts +2 -1
  210. package/.server/server/types.js.map +1 -1
  211. package/.server/server/utils/utils.d.ts +5 -0
  212. package/.server/server/utils/utils.js +16 -0
  213. package/.server/server/utils/utils.js.map +1 -1
  214. package/.server/typings/hapi/index.d.js.map +1 -1
  215. package/package.json +3 -2
  216. package/src/server/forms/register-as-a-unicorn-breeder.yaml +0 -14
  217. package/src/server/forms/simple-form.yaml +106 -3
  218. package/src/server/plugins/engine/components/AutocompleteField.ts +3 -6
  219. package/src/server/plugins/engine/components/CheckboxesField.ts +12 -11
  220. package/src/server/plugins/engine/components/ComponentCollection.ts +143 -61
  221. package/src/server/plugins/engine/components/DatePartsField.ts +33 -11
  222. package/src/server/plugins/engine/components/DeclarationField.ts +37 -14
  223. package/src/server/plugins/engine/components/EastingNorthingField.ts +83 -22
  224. package/src/server/plugins/engine/components/EmailAddressField.ts +4 -7
  225. package/src/server/plugins/engine/components/FileUploadField.ts +28 -22
  226. package/src/server/plugins/engine/components/FormComponent.ts +49 -12
  227. package/src/server/plugins/engine/components/GeospatialField.ts +36 -21
  228. package/src/server/plugins/engine/components/LatLongField.ts +52 -21
  229. package/src/server/plugins/engine/components/ListFormComponent.ts +26 -10
  230. package/src/server/plugins/engine/components/LocationFieldBase.ts +5 -8
  231. package/src/server/plugins/engine/components/LocationFieldHelpers.ts +3 -3
  232. package/src/server/plugins/engine/components/Markdown.ts +7 -3
  233. package/src/server/plugins/engine/components/MonthYearField.ts +32 -10
  234. package/src/server/plugins/engine/components/MultilineTextField.ts +5 -8
  235. package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +25 -11
  236. package/src/server/plugins/engine/components/NumberField.ts +3 -4
  237. package/src/server/plugins/engine/components/OsGridRefField.ts +25 -9
  238. package/src/server/plugins/engine/components/PaymentField.ts +22 -12
  239. package/src/server/plugins/engine/components/SelectField.ts +3 -6
  240. package/src/server/plugins/engine/components/SelectionControlField.ts +7 -8
  241. package/src/server/plugins/engine/components/TelephoneNumberField.ts +4 -7
  242. package/src/server/plugins/engine/components/UkAddressField.ts +33 -18
  243. package/src/server/plugins/engine/components/YesNoField.ts +10 -0
  244. package/src/server/plugins/engine/components/helpers/components.ts +13 -6
  245. package/src/server/plugins/engine/components/types.ts +9 -0
  246. package/src/server/plugins/engine/configureEnginePlugin.ts +12 -1
  247. package/src/server/plugins/engine/form-context.ts +8 -2
  248. package/src/server/plugins/engine/helpers.ts +10 -18
  249. package/src/server/plugins/engine/i18n/buildValidationMessages.ts +69 -0
  250. package/src/server/plugins/engine/i18n/createFormTranslator.ts +33 -0
  251. package/src/server/plugins/engine/i18n/createTranslator.ts +61 -0
  252. package/src/server/plugins/engine/i18n/extractBaseTranslations.ts +61 -0
  253. package/src/server/plugins/engine/i18n/index.ts +80 -0
  254. package/src/server/plugins/engine/i18n/translations/cy.json +271 -0
  255. package/src/server/plugins/engine/i18n/translations/en-GB.json +271 -0
  256. package/src/server/plugins/engine/i18n/types.ts +62 -0
  257. package/src/server/plugins/engine/index.ts +4 -2
  258. package/src/server/plugins/engine/models/FormModel.ts +59 -23
  259. package/src/server/plugins/engine/models/SummaryViewModel.ts +68 -25
  260. package/src/server/plugins/engine/options.js +2 -1
  261. package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +5 -0
  262. package/src/server/plugins/engine/outputFormatters/human/v1.ts +2 -3
  263. package/src/server/plugins/engine/outputFormatters/machine/v1.ts +9 -8
  264. package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +7 -3
  265. package/src/server/plugins/engine/pageControllers/PageController.ts +12 -1
  266. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +53 -21
  267. package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +66 -29
  268. package/src/server/plugins/engine/pageControllers/StartPageController.ts +7 -2
  269. package/src/server/plugins/engine/pageControllers/StatusPageController.ts +10 -2
  270. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +48 -22
  271. package/src/server/plugins/engine/pageControllers/__stubs__/translator.ts +28 -0
  272. package/src/server/plugins/engine/pageControllers/errors.ts +4 -2
  273. package/src/server/plugins/engine/pageControllers/helpers/submission.ts +11 -4
  274. package/src/server/plugins/engine/pageControllers/validationOptions.ts +43 -53
  275. package/src/server/plugins/engine/plugin.ts +2 -0
  276. package/src/server/plugins/engine/routes/index.ts +9 -1
  277. package/src/server/plugins/engine/routes/questions.ts +5 -1
  278. package/src/server/plugins/engine/types/index.ts +5 -0
  279. package/src/server/plugins/engine/types/schema.ts +1 -0
  280. package/src/server/plugins/engine/types.ts +10 -0
  281. package/src/server/plugins/engine/views/components/_location-field-base.html +1 -1
  282. package/src/server/plugins/engine/views/components/fileuploadfield.html +3 -3
  283. package/src/server/plugins/engine/views/components/nationalgridfieldnumberfield.html +1 -1
  284. package/src/server/plugins/engine/views/components/osgridreffield.html +1 -1
  285. package/src/server/plugins/engine/views/components/paymentfield.html +8 -8
  286. package/src/server/plugins/engine/views/components/ukaddressfield.html +4 -4
  287. package/src/server/plugins/engine/views/confirmation.html +4 -4
  288. package/src/server/plugins/engine/views/exit.html +4 -4
  289. package/src/server/plugins/engine/views/file-upload.html +3 -3
  290. package/src/server/plugins/engine/views/index.html +3 -3
  291. package/src/server/plugins/engine/views/item-delete.html +1 -1
  292. package/src/server/plugins/engine/views/partials/form.html +3 -3
  293. package/src/server/plugins/engine/views/partials/preview-banner.html +4 -4
  294. package/src/server/plugins/engine/views/partials/warn-missing-notification-email.html +4 -5
  295. package/src/server/plugins/engine/views/repeat-list-summary.html +4 -4
  296. package/src/server/plugins/engine/views/summary.html +14 -7
  297. package/src/server/plugins/nunjucks/environment.js +14 -0
  298. package/src/server/plugins/nunjucks/filters/answer.js +12 -1
  299. package/src/server/plugins/postcode-lookup/models/index.js +144 -87
  300. package/src/server/plugins/postcode-lookup/routes/index.js +13 -16
  301. package/src/server/plugins/postcode-lookup/types.js +1 -0
  302. package/src/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  303. package/src/server/types.ts +2 -0
  304. package/src/server/utils/utils.js +14 -0
  305. package/src/typings/hapi/index.d.ts +1 -0
  306. package/.server/server/plugins/engine/components/constants.d.ts +0 -1
  307. package/.server/server/plugins/engine/components/constants.js +0 -2
  308. package/.server/server/plugins/engine/components/constants.js.map +0 -1
  309. 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,62 @@
1
+ import {
2
+ type ComponentDef,
3
+ type Item,
4
+ type Page,
5
+ type Section
6
+ } from '@defra/forms-model'
7
+
8
+ /**
9
+ * Structure of the `translations` block in a form definition.
10
+ * Also used to derive the valid property keys for the typed tX functions.
11
+ */
12
+ export type FormDefinitionTranslations = Record<
13
+ string,
14
+ {
15
+ pages: Record<string, Partial<{ title: string; repeatTitle: string }>>
16
+ // ComponentDef is a discriminated union; Pick across the full union is not feasible.
17
+ // The four keys below are the complete set of translatable component properties.
18
+ components: Record<
19
+ string,
20
+ Partial<{
21
+ title: string
22
+ hint: string
23
+ content: string
24
+ shortDescription: string
25
+ }>
26
+ >
27
+ sections: Record<string, Partial<Pick<Section, 'title'>>>
28
+ listItems: Record<string, Partial<Pick<Item, 'text' | 'hint'>>>
29
+ form: Record<string, string>
30
+ }
31
+ >
32
+
33
+ type EntityTranslations = FormDefinitionTranslations[string]
34
+
35
+ /**
36
+ * Scoped translator returned by model.createTranslator(language).
37
+ * t — plugin namespace (UI strings, buttons, errors, sub-field labels)
38
+ * tForm — form namespace: form attributes, currently only form name
39
+ * tPage — form namespace: page titles
40
+ * tComponent — form namespace: component titles, hints, shortDescriptions
41
+ * tSection — form namespace: section titles
42
+ * tListItem — form namespace: list item text
43
+ * language - current language
44
+ */
45
+ export interface Translator {
46
+ t: (key: string, opts?: Record<string, unknown>) => string
47
+ tForm: (prop: string) => string
48
+ tPage: (page: Page, prop: keyof EntityTranslations['pages'][string]) => string
49
+ tComponent: (
50
+ component: ComponentDef,
51
+ prop: keyof EntityTranslations['components'][string]
52
+ ) => string
53
+ tSection: (
54
+ section: Section,
55
+ prop: keyof EntityTranslations['sections'][string]
56
+ ) => string
57
+ tListItem: (
58
+ item: Item,
59
+ prop: keyof EntityTranslations['listItems'][string]
60
+ ) => string
61
+ language: string
62
+ }
@@ -8,7 +8,8 @@ import {
8
8
  checkComponentTemplates,
9
9
  checkErrorTemplates,
10
10
  evaluate,
11
- govukRebrand
11
+ govukRebrand,
12
+ tGlobal
12
13
  } from '../nunjucks/environment.js'
13
14
  import * as filters from '../nunjucks/filters/index.js'
14
15
 
@@ -26,7 +27,8 @@ const globals = {
26
27
  checkComponentTemplates,
27
28
  checkErrorTemplates,
28
29
  evaluate,
29
- govukRebrand
30
+ govukRebrand,
31
+ t: tGlobal
30
32
  }
31
33
 
32
34
  export const VIEW_PATH = 'src/server/plugins/engine/views'
@@ -27,6 +27,7 @@ import {
27
27
  } from '@defra/forms-model'
28
28
  import { add, format } from 'date-fns'
29
29
  import { Parser, type Value } from 'expr-eval-fork'
30
+ import { type i18n } from 'i18next'
30
31
  import joi from 'joi'
31
32
 
32
33
  import { logger } from '../../../common/helpers/logging/logger.js'
@@ -40,9 +41,13 @@ import { todayAsDateOnly } from '../date-helper.js'
40
41
  import {
41
42
  findPage,
42
43
  getError,
43
- getPage,
44
- setPageTitles
44
+ getPage
45
45
  } from '../helpers.js'
46
+ import { loadFormTranslations } from '../i18n/createFormTranslator.js'
47
+ import { createTranslator } from '../i18n/createTranslator.js'
48
+ import { extractBaseTranslations } from '../i18n/extractBaseTranslations.js'
49
+ import { createFormI18nInstance } from '../i18n/index.js'
50
+ import { type Translator } from '../i18n/types.js'
46
51
  import { type ExecutableCondition } from './types.js'
47
52
  import { type PageController } from '../pageControllers/PageController.js'
48
53
  import {
@@ -81,6 +86,7 @@ export class FormModel {
81
86
  conditions: Partial<Record<string, ExecutableCondition>>
82
87
  pages: PageControllerClass[]
83
88
  services: Services
89
+ private readonly i18nInstance: i18n
84
90
 
85
91
  controllers?: Record<string, typeof PageController>
86
92
  pageDefMap: Map<string, Page>
@@ -123,7 +129,12 @@ export class FormModel {
123
129
  // by joi so as not to change the source data.
124
130
  def = structuredClone(result.value)
125
131
 
126
- // Add default lists
132
+ const baseTranslations = extractBaseTranslations(def)
133
+ this.i18nInstance = createFormI18nInstance(baseTranslations)
134
+ loadFormTranslations(def, this.i18nInstance)
135
+
136
+ // Add default lists. Yes/No text stored as i18n key constants so they
137
+ // resolve to the user's language at render time via the translator.
127
138
  def.lists.push({
128
139
  id: def.schema === SchemaVersion.V1 ? yesNoListName : yesNoListId,
129
140
  name: '__yesNo',
@@ -132,20 +143,17 @@ export class FormModel {
132
143
  items: [
133
144
  {
134
145
  id: '02900d42-83d1-4c72-a719-c4e8228952fa',
135
- text: 'Yes',
146
+ text: 'components.yesNoField.yes',
136
147
  value: true
137
148
  },
138
149
  {
139
150
  id: 'f39000eb-c51b-4019-8f82-bbda0423f04d',
140
- text: 'No',
151
+ text: 'components.yesNoField.no',
141
152
  value: false
142
153
  }
143
154
  ]
144
155
  })
145
156
 
146
- // Fix up page titles
147
- setPageTitles(def)
148
-
149
157
  this.engine = def.engine
150
158
  this.schemaVersion = def.schema ?? SchemaVersion.V1
151
159
  this.def = def
@@ -213,7 +221,7 @@ export class FormModel {
213
221
  ) {
214
222
  this.pages.push(
215
223
  createPage(this, {
216
- title: 'Form submitted',
224
+ title: 'pages.confirmation.formSubmitted',
217
225
  path: ControllerPath.Status,
218
226
  controller: ControllerType.Status
219
227
  })
@@ -231,6 +239,11 @@ export class FormModel {
231
239
  )
232
240
  }
233
241
 
242
+ /** Returns a scoped translator pair for the given language. */
243
+ createTranslator(language = 'en-GB'): Translator {
244
+ return createTranslator(this.i18nInstance, language)
245
+ }
246
+
234
247
  /**
235
248
  * build the entire model schema from individual pages/sections and filter out answers
236
249
  * for pages which are no longer accessible due to an answer that has been changed
@@ -337,7 +350,8 @@ export class FormModel {
337
350
  getFormContext(
338
351
  request: FormContextRequest,
339
352
  state: FormSubmissionState,
340
- errors?: FormSubmissionError[]
353
+ errors?: FormSubmissionError[],
354
+ translator?: Translator
341
355
  ): FormContext {
342
356
  const { query } = request
343
357
 
@@ -365,11 +379,13 @@ export class FormModel {
365
379
  componentDefMap: this.componentDefMap,
366
380
  pageMap: this.pageMap,
367
381
  componentMap: this.componentMap,
368
- referenceNumber: getReferenceNumber(state)
382
+ referenceNumber: getReferenceNumber(state),
383
+ languages: getAvailableLanguages(this.def),
384
+ translator
369
385
  }
370
386
 
371
387
  // Validate current page
372
- context = validateFormPayload(request, page, context)
388
+ context = validateFormPayload(request, page, context, translator)
373
389
 
374
390
  // Find start page
375
391
  let nextPage = findPage(this, startPath)
@@ -387,7 +403,7 @@ export class FormModel {
387
403
 
388
404
  // Stop at current page
389
405
  if (
390
- this.pageStateIsInvalid(context, nextPage) ||
406
+ this.pageStateIsInvalid(context, nextPage, translator) ||
391
407
  nextPage.path === currentPath
392
408
  ) {
393
409
  break
@@ -448,7 +464,11 @@ export class FormModel {
448
464
  }
449
465
  }
450
466
 
451
- private pageStateIsInvalid(context: FormContext, page: PageControllerClass) {
467
+ private pageStateIsInvalid(
468
+ context: FormContext,
469
+ page: PageControllerClass,
470
+ translator?: Translator
471
+ ) {
452
472
  // Get any list-bound fields on the page
453
473
  const listFields = page.collection.fields.filter(hasListFormField)
454
474
 
@@ -464,7 +484,7 @@ export class FormModel {
464
484
  list.items.filter((item) => item.condition).length > 0
465
485
 
466
486
  if (hasOptionalItems) {
467
- return this.fieldStateIsInvalid(context, field, list)
487
+ return this.fieldStateIsInvalid(context, field, list, translator)
468
488
  }
469
489
  }
470
490
  }
@@ -473,7 +493,8 @@ export class FormModel {
473
493
  private fieldStateIsInvalid(
474
494
  context: FormContext,
475
495
  field: ListFormComponent,
476
- list: List
496
+ list: List,
497
+ translator?: Translator
477
498
  ) {
478
499
  const { evaluationState, state } = context
479
500
 
@@ -503,8 +524,9 @@ export class FormModel {
503
524
  if (isInvalid) {
504
525
  context.errors ??= []
505
526
 
506
- const text =
507
- 'Options are different because you changed a previous answer'
527
+ const text = (translator ?? this.createTranslator('en-GB')).t(
528
+ 'errors.optionsMismatch'
529
+ )
508
530
 
509
531
  context.errors.push({
510
532
  text,
@@ -571,7 +593,8 @@ export class FormModel {
571
593
  function validateFormPayload(
572
594
  request: FormContextRequest,
573
595
  page: PageControllerClass,
574
- context: FormContext
596
+ context: FormContext,
597
+ translator?: Translator
575
598
  ): FormContext {
576
599
  const { collection } = page
577
600
  const { payload, state } = context
@@ -601,10 +624,10 @@ function validateFormPayload(
601
624
  }
602
625
  })
603
626
 
604
- const { value, errors } = collection.validate({
605
- ...payload,
606
- ...update
607
- })
627
+ const { value, errors } = collection.validate(
628
+ { ...payload, ...update },
629
+ translator
630
+ )
608
631
 
609
632
  // Add sanitised payload (ready to save)
610
633
  const formState = page.getStateFromValidForm(request, state, value)
@@ -656,3 +679,16 @@ function getReferenceNumber(state: FormSubmissionState): string {
656
679
 
657
680
  return state.$$__referenceNumber
658
681
  }
682
+
683
+ export function getAvailableLanguages(
684
+ def: FormDefinition
685
+ ): { name: string; code: string }[] {
686
+ // @ts-expect-error - dynamic property
687
+ if (def.metadata?.translations?.cy) {
688
+ return [
689
+ { name: 'English', code: 'en-GB' },
690
+ { name: 'Cymraeg', code: 'cy' }
691
+ ]
692
+ }
693
+ return []
694
+ }