@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
@@ -9,6 +9,8 @@ import {
9
9
  FormComponent,
10
10
  isUploadState
11
11
  } from './FormComponent.js'
12
+ import { type RenderContext } from './types.js'
13
+ import { type Translator } from '../i18n/types.js'
12
14
  import { InvalidComponentStateError } from '../pageControllers/errors.js'
13
15
  import { messageTemplate } from '../pageControllers/validationOptions.js'
14
16
  import {
@@ -19,10 +21,8 @@ import {
19
21
  type FileUpload,
20
22
  type FileUploadMetadata,
21
23
  type FormContext,
22
- type FormPayload,
23
24
  type FormState,
24
25
  type FormStateValue,
25
- type FormSubmissionError,
26
26
  type FormSubmissionState,
27
27
  type SummaryList,
28
28
  type SummaryListAction,
@@ -32,10 +32,8 @@ import {
32
32
  type UploadStatusResponse
33
33
  } from '../types.js'
34
34
  import { render } from '../../nunjucks/index.js'
35
- import {
36
- type FormQuery,
37
- type FormRequestPayload
38
- } from '../../../routes/types.js'
35
+ import { type FormRequestPayload } from '../../../routes/types.js'
36
+ import { resolveLanguage } from '../../../utils/utils.js'
39
37
 
40
38
  export const uploadIdSchema = joi.string().uuid().required()
41
39
 
@@ -163,19 +161,26 @@ export class FileUploadField extends FormComponent {
163
161
  return this.isValue(value) ? value : undefined
164
162
  }
165
163
 
166
- getDisplayStringFromFormValue(files: FileState[] | undefined): string {
164
+ getDisplayStringFromFormValue(
165
+ files: FileState[] | undefined,
166
+ translator: Translator
167
+ ): string {
167
168
  if (!files?.length) {
168
169
  return ''
169
170
  }
170
171
 
171
- const unit = files.length === 1 ? 'file' : 'files'
172
- return `Uploaded ${files.length} ${unit}`
172
+ return translator.t('components.fileUploadField.filesCount', {
173
+ count: files.length
174
+ })
173
175
  }
174
176
 
175
- getDisplayStringFromState(state: FormSubmissionState) {
177
+ getDisplayStringFromState(
178
+ state: FormSubmissionState,
179
+ translator: Translator
180
+ ) {
176
181
  const files = this.getFormValueFromState(state)
177
182
 
178
- return this.getDisplayStringFromFormValue(files)
183
+ return this.getDisplayStringFromFormValue(files, translator)
179
184
  }
180
185
 
181
186
  getContextValueFromFormValue(
@@ -189,17 +194,12 @@ export class FileUploadField extends FormComponent {
189
194
  return this.getContextValueFromFormValue(files)
190
195
  }
191
196
 
192
- getViewModel(
193
- payload: FormPayload,
194
- errors?: FormSubmissionError[],
195
- query: FormQuery = {}
196
- ) {
197
+ getViewModel(context: RenderContext) {
198
+ const { errors, isForceAccess = false } = context
199
+ const { t } = context.translator
197
200
  const { options, page, schema } = this
198
201
 
199
- // Allow preview URL direct access
200
- const isForceAccess = 'force' in query
201
-
202
- const viewModel = super.getViewModel(payload, errors)
202
+ const viewModel = super.getViewModel(context)
203
203
  const { attributes, id, value } = viewModel
204
204
 
205
205
  const files = this.getFormValue(value) ?? []
@@ -213,7 +213,10 @@ export class FileUploadField extends FormComponent {
213
213
  const { form } = status
214
214
  const { file } = form
215
215
 
216
- const tag = { classes: 'govuk-tag--green', text: 'Uploaded' }
216
+ const tag = {
217
+ classes: 'govuk-tag--green',
218
+ text: t('components.fileUploadField.uploaded')
219
+ }
217
220
 
218
221
  const valueHtml = render
219
222
  .view('components/fileuploadfield-value.html', {
@@ -309,6 +312,9 @@ export class FileUploadField extends FormComponent {
309
312
  metadata: FormMetadata,
310
313
  context: FormContext
311
314
  ) {
315
+ const language = resolveLanguage(request)
316
+ const { t } = this.model.createTranslator(language)
317
+
312
318
  const notificationEmail = metadata.notificationEmail
313
319
 
314
320
  if (!notificationEmail) {
@@ -347,7 +353,7 @@ export class FileUploadField extends FormComponent {
347
353
  // Scenarios: file missing from S3, invalid retrieval key (timing problem), etc.
348
354
  throw new InvalidComponentStateError(
349
355
  this,
350
- 'There was a problem with your uploaded files. Re-upload them before submitting the form again.'
356
+ t('components.fileUploadField.uploadFailed')
351
357
  )
352
358
  }
353
359
 
@@ -1,11 +1,14 @@
1
1
  import {
2
+ type ComponentDef,
2
3
  type FormComponentsDef,
3
4
  type FormMetadata,
4
5
  type Item
5
6
  } from '@defra/forms-model'
7
+ import { type LanguageMessages } from 'joi'
6
8
 
7
9
  import { ComponentBase } from './ComponentBase.js'
8
- import { optionalText } from './constants.js'
10
+ import { type RenderContext } from './types.js'
11
+ import { type Translator } from '../i18n/types.js'
9
12
  import {
10
13
  type FormContext,
11
14
  type FormRequestPayload
@@ -115,7 +118,10 @@ export class FormComponent extends ComponentBase {
115
118
  }
116
119
  }
117
120
 
118
- getErrors(errors?: FormSubmissionError[]): FormSubmissionError[] | undefined {
121
+ getErrors(
122
+ _translator: Translator,
123
+ errors?: FormSubmissionError[]
124
+ ): FormSubmissionError[] | undefined {
119
125
  const { name } = this
120
126
 
121
127
  // Filter component and child errors only
@@ -134,34 +140,59 @@ export class FormComponent extends ComponentBase {
134
140
  }
135
141
 
136
142
  getFirstError(
143
+ translator: Translator,
137
144
  errors?: FormSubmissionError[]
138
145
  ): FormSubmissionError | undefined {
139
- return this.getErrors(errors)?.[0]
146
+ return this.getErrors(translator, errors)?.[0]
140
147
  }
141
148
 
142
149
  getViewErrors(
150
+ translator: Translator,
143
151
  errors?: FormSubmissionError[]
144
152
  ): FormSubmissionError[] | undefined {
145
- const firstError = this.getFirstError(errors)
153
+ const firstError = this.getFirstError(translator, errors)
146
154
  return firstError && [firstError]
147
155
  }
148
156
 
149
- getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {
157
+ /**
158
+ * Override in composite fields to return translated Joi message overrides for
159
+ * their sub-fields, applied at validation time so schema-level English messages
160
+ * are replaced with the correct language. Return null to skip message patching.
161
+ */
162
+ getValidationMessagesOverride(
163
+ _translator: Translator
164
+ ): LanguageMessages | null {
165
+ return null
166
+ }
167
+
168
+ getViewModel({
169
+ payload,
170
+ errors,
171
+ translator,
172
+ isForceAccess: _isForceAccess = false
173
+ }: RenderContext) {
150
174
  const { hint, name, options = {}, title, viewModel } = this
151
175
 
176
+ const { t, tComponent } = translator
177
+
152
178
  const isRequired = !('required' in options) || options.required !== false
153
179
  const hideOptional = 'optionalText' in options && options.optionalText
154
- const label = `${title}${!isRequired && !hideOptional ? optionalText : ''}`
180
+
181
+ const resolvedTitle =
182
+ tComponent(this as unknown as ComponentDef, 'title') || title
183
+ const optionalTag =
184
+ !isRequired && !hideOptional ? ` ${t('common.optional')}` : ''
185
+ const label = `${resolvedTitle}${optionalTag}`
155
186
 
156
187
  if (hint) {
157
188
  viewModel.hint = {
158
- text: hint
189
+ text: tComponent(this as unknown as ComponentDef, 'hint') || hint
159
190
  }
160
191
  }
161
192
 
162
193
  // Filter component errors only
163
- const componentErrors = this.getErrors(errors)
164
- const componentError = this.getFirstError(componentErrors)
194
+ const componentErrors = this.getErrors(translator, errors)
195
+ const componentError = this.getFirstError(translator, componentErrors)
165
196
 
166
197
  if (componentErrors) {
167
198
  viewModel.errors = componentErrors
@@ -184,15 +215,21 @@ export class FormComponent extends ComponentBase {
184
215
  }
185
216
  }
186
217
 
187
- getDisplayStringFromFormValue(value: FormValue | FormPayload): string {
218
+ getDisplayStringFromFormValue(
219
+ value: FormValue | FormPayload,
220
+ _translator: Translator
221
+ ): string {
188
222
  // Map selected values to text
189
223
  // eslint-disable-next-line @typescript-eslint/no-base-to-string
190
224
  return this.isValue(value) ? value.toString() : ''
191
225
  }
192
226
 
193
- getDisplayStringFromState(state: FormSubmissionState): string {
227
+ getDisplayStringFromState(
228
+ state: FormSubmissionState,
229
+ translator: Translator
230
+ ): string {
194
231
  const value = this.getFormValueFromState(state)
195
- return this.getDisplayStringFromFormValue(value)
232
+ return this.getDisplayStringFromFormValue(value, translator)
196
233
  }
197
234
 
198
235
  getContextValueFromFormValue(
@@ -6,11 +6,13 @@ import {
6
6
  FormComponent,
7
7
  isGeospatialState
8
8
  } from './FormComponent.js'
9
+ import { getMapLayers } from './LocationFieldHelpers.js'
9
10
  import { getGeospatialSchema } from './helpers/geospatial.js'
11
+ import { type RenderContext } from './types.js'
12
+ import { type Translator } from '../i18n/types.js'
10
13
  import { messageTemplate } from '../pageControllers/validationOptions.js'
11
14
  import {
12
15
  type ErrorMessageTemplateList,
13
- type FormPayload,
14
16
  type FormState,
15
17
  type FormStateValue,
16
18
  type FormSubmissionError,
@@ -31,13 +33,11 @@ export class GeospatialField extends FormComponent {
31
33
 
32
34
  const { options } = def
33
35
 
34
- const formSchema = getGeospatialSchema(def)
35
- .label(this.label)
36
- .messages({
37
- 'array.min': messageTemplate.featuresMin as string,
38
- 'array.max': messageTemplate.featuresMax as string,
39
- 'array.length': messageTemplate.featuresLength as string
40
- })
36
+ const formSchema = getGeospatialSchema(def).label(this.label).messages({
37
+ 'array.min': messageTemplate.featuresMin,
38
+ 'array.max': messageTemplate.featuresMax,
39
+ 'array.length': messageTemplate.featuresLength
40
+ })
41
41
 
42
42
  this.formSchema = formSchema
43
43
  this.stateSchema = formSchema.default(null)
@@ -58,20 +58,26 @@ export class GeospatialField extends FormComponent {
58
58
  return this.isValue(value) ? value : undefined
59
59
  }
60
60
 
61
- getDisplayStringFromFormValue(features: GeospatialState | undefined): string {
61
+ getDisplayStringFromFormValue(
62
+ features: GeospatialState | undefined,
63
+ translator: Translator
64
+ ): string {
62
65
  if (!features?.length) {
63
66
  return ''
64
67
  }
65
68
 
66
- const unit = features.length === 1 ? 'location' : 'locations'
67
-
68
- return `Added ${features.length} ${unit}`
69
+ return translator.t('components.geospatialField.added', {
70
+ count: features.length
71
+ })
69
72
  }
70
73
 
71
- getDisplayStringFromState(state: FormSubmissionState) {
74
+ getDisplayStringFromState(
75
+ state: FormSubmissionState,
76
+ translator: Translator
77
+ ) {
72
78
  const features = this.getFormValueFromState(state)
73
79
 
74
- return this.getDisplayStringFromFormValue(features)
80
+ return this.getDisplayStringFromFormValue(features, translator)
75
81
  }
76
82
 
77
83
  getContextValueFromFormValue(
@@ -86,8 +92,8 @@ export class GeospatialField extends FormComponent {
86
92
  return this.getContextValueFromFormValue(features)
87
93
  }
88
94
 
89
- getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {
90
- const viewModel = super.getViewModel(payload, errors)
95
+ getViewModel(context: RenderContext) {
96
+ const viewModel = super.getViewModel(context)
91
97
  const value =
92
98
  typeof viewModel.value === 'string'
93
99
  ? viewModel.value
@@ -97,20 +103,30 @@ export class GeospatialField extends FormComponent {
97
103
  ...viewModel,
98
104
  country: this.options.countries?.at(0),
99
105
  geometryTypes: this.options.geometryTypes,
106
+ mapLayers: getMapLayers(this),
100
107
  value
101
108
  }
102
109
  }
103
110
 
104
- getErrors(errors?: FormSubmissionError[]): FormSubmissionError[] | undefined {
105
- const fieldErrors = super.getErrors(errors)
111
+ getErrors(
112
+ translator: Translator,
113
+ errors?: FormSubmissionError[]
114
+ ): FormSubmissionError[] | undefined {
115
+ const fieldErrors = super.getErrors(translator, errors)
106
116
 
107
117
  fieldErrors?.forEach((err) => {
108
118
  if (err.name === 'description') {
109
119
  err.href = `#description_${err.path[1]}`
110
- err.text = `Enter description for location ${Number(err.path[1]) + 1}`
120
+ err.text = translator.t(
121
+ 'components.geospatialField.validation.descriptionRequired',
122
+ { count: Number(err.path[1]) + 1 }
123
+ )
111
124
  } else if (typeof err.name === 'number' && err.context?.country) {
112
125
  err.href = `#description_${err.path[1]}`
113
- err.text = `Location ${Number(err.path[1]) + 1} must be in ${err.context.country}`
126
+ err.text = translator.t(
127
+ 'components.geospatialField.validation.wrongCountry',
128
+ { count: Number(err.path[1]) + 1, country: err.context.country }
129
+ )
114
130
  }
115
131
  })
116
132
 
@@ -118,9 +134,10 @@ export class GeospatialField extends FormComponent {
118
134
  }
119
135
 
120
136
  getViewErrors(
137
+ translator: Translator,
121
138
  errors?: FormSubmissionError[]
122
139
  ): FormSubmissionError[] | undefined {
123
- return this.getErrors(errors)
140
+ return this.getErrors(translator, errors)
124
141
  }
125
142
 
126
143
  isValue(value?: FormStateValue | FormState): value is GeospatialState {
@@ -13,7 +13,12 @@ import {
13
13
  } from './LocationFieldHelpers.js'
14
14
  import { NumberField } from './NumberField.js'
15
15
  import { createLowerFirstExpression } from './helpers/index.js'
16
- import { type LatLongState } from './types.js'
16
+ import {
17
+ type LatLongState,
18
+ type RenderContext
19
+ } from './types.js'
20
+ import { t as tPlugin } from '../i18n/index.js'
21
+ import { type Translator } from '../i18n/types.js'
17
22
  import { messageTemplate } from '../pageControllers/validationOptions.js'
18
23
  import {
19
24
  type ErrorMessageTemplateList,
@@ -51,31 +56,50 @@ export class LatLongField extends FormComponent {
51
56
  const longitudeMin = schema?.longitude?.min ?? -13.687
52
57
  const longitudeMax = schema?.longitude?.max ?? 1.767
53
58
 
54
- const latitudeRequired = 'Enter latitude'
55
- const longitudeRequired = 'Enter longitude'
59
+ const fieldLabel = lowerFirst(this.label)
56
60
 
57
61
  const customValidationMessages: LanguageMessages =
58
62
  convertToLanguageMessages({
59
- 'number.precision':
60
- '{{#label}} must have no more than 7 decimal places',
61
- 'number.unsafe': '{{#label}} must be a valid number'
63
+ 'number.precision': tPlugin(
64
+ 'components.latLongField.precision',
65
+ 'en-GB'
66
+ ),
67
+ 'number.unsafe': tPlugin('components.latLongField.notANumber', 'en-GB')
62
68
  })
63
69
 
64
- const latitudeRangeMessage = `Latitude for ${lowerFirst(this.label)} must be between ${latitudeMin} and ${latitudeMax}`
65
- const longitudeRangeMessage = `Longitude for ${lowerFirst(this.label)} must be between ${longitudeMin} and ${longitudeMax}`
70
+ const latitudeRangeMessage = tPlugin(
71
+ 'components.latLongField.latitudeRange',
72
+ 'en-GB',
73
+ { fieldLabel, min: latitudeMin, max: latitudeMax }
74
+ )
75
+ const longitudeRangeMessage = tPlugin(
76
+ 'components.latLongField.longitudeRange',
77
+ 'en-GB',
78
+ { fieldLabel, min: longitudeMin, max: longitudeMax }
79
+ )
66
80
 
67
81
  const latitudeMessages: LanguageMessages = convertToLanguageMessages({
68
82
  ...customValidationMessages,
69
- 'any.required': latitudeRequired,
70
- 'number.base': `Enter a valid latitude for ${lowerFirst(this.label)} like 51.519450`,
83
+ 'any.required': tPlugin(
84
+ 'components.latLongField.latitudeRequired',
85
+ 'en-GB'
86
+ ),
87
+ 'number.base': tPlugin('components.latLongField.latitudeBase', 'en-GB', {
88
+ fieldLabel
89
+ }),
71
90
  'number.min': latitudeRangeMessage,
72
91
  'number.max': latitudeRangeMessage
73
92
  })
74
93
 
75
94
  const longitudeMessages: LanguageMessages = convertToLanguageMessages({
76
95
  ...customValidationMessages,
77
- 'any.required': longitudeRequired,
78
- 'number.base': `Enter a valid longitude for ${lowerFirst(this.label)} like -0.127758`,
96
+ 'any.required': tPlugin(
97
+ 'components.latLongField.longitudeRequired',
98
+ 'en-GB'
99
+ ),
100
+ 'number.base': tPlugin('components.latLongField.longitudeBase', 'en-GB', {
101
+ fieldLabel
102
+ }),
79
103
  'number.min': longitudeRangeMessage,
80
104
  'number.max': longitudeRangeMessage
81
105
  })
@@ -85,7 +109,7 @@ export class LatLongField extends FormComponent {
85
109
  {
86
110
  type: ComponentType.NumberField,
87
111
  name: `${name}__latitude`,
88
- title: 'Latitude',
112
+ title: 'components.latLongField.latitude',
89
113
  schema: {
90
114
  min: latitudeMin,
91
115
  max: latitudeMax,
@@ -102,7 +126,7 @@ export class LatLongField extends FormComponent {
102
126
  {
103
127
  type: ComponentType.NumberField,
104
128
  name: `${name}__longitude`,
105
- title: 'Longitude',
129
+ title: 'components.latLongField.longitude',
106
130
  schema: {
107
131
  min: longitudeMin,
108
132
  max: longitudeMax,
@@ -133,7 +157,10 @@ export class LatLongField extends FormComponent {
133
157
  return LatLongField.isLatLong(value) ? value : undefined
134
158
  }
135
159
 
136
- getDisplayStringFromFormValue(value: LatLongState | undefined): string {
160
+ getDisplayStringFromFormValue(
161
+ value: LatLongState | undefined,
162
+ _translator: Translator
163
+ ): string {
137
164
  if (!value) {
138
165
  return ''
139
166
  }
@@ -142,10 +169,13 @@ export class LatLongField extends FormComponent {
142
169
  return `${value.latitude}, ${value.longitude}`
143
170
  }
144
171
 
145
- getDisplayStringFromState(state: FormSubmissionState) {
172
+ getDisplayStringFromState(
173
+ state: FormSubmissionState,
174
+ translator: Translator
175
+ ) {
146
176
  const value = this.getFormValueFromState(state)
147
177
 
148
- return this.getDisplayStringFromFormValue(value)
178
+ return this.getDisplayStringFromFormValue(value, translator)
149
179
  }
150
180
 
151
181
  getContextValueFromFormValue(value: LatLongState | undefined): string | null {
@@ -163,15 +193,16 @@ export class LatLongField extends FormComponent {
163
193
  return this.getContextValueFromFormValue(value)
164
194
  }
165
195
 
166
- getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {
167
- const viewModel = super.getViewModel(payload, errors)
168
- return getLocationFieldViewModel(this, viewModel, payload, errors)
196
+ getViewModel(context: RenderContext) {
197
+ const viewModel = super.getViewModel(context)
198
+ return getLocationFieldViewModel(this, viewModel, context)
169
199
  }
170
200
 
171
201
  getViewErrors(
202
+ translator: Translator,
172
203
  errors?: FormSubmissionError[]
173
204
  ): FormSubmissionError[] | undefined {
174
- const allErrors = this.getErrors(errors)
205
+ const allErrors = this.getErrors(translator, errors)
175
206
  return deduplicateErrorsByHref(allErrors)
176
207
  }
177
208
 
@@ -13,12 +13,14 @@ import joi, {
13
13
  } from 'joi'
14
14
 
15
15
  import { FormComponent } from './FormComponent.js'
16
- import { type ListItem } from './types.js'
16
+ import {
17
+ type ListItem,
18
+ type RenderContext
19
+ } from './types.js'
20
+ import { type Translator } from '../i18n/types.js'
17
21
  import { messageTemplate } from '../pageControllers/validationOptions.js'
18
22
  import {
19
23
  type ErrorMessageTemplateList,
20
- type FormPayload,
21
- type FormSubmissionError,
22
24
  type FormSubmissionState
23
25
  } from '../types.js'
24
26
 
@@ -100,7 +102,8 @@ export class ListFormComponent extends FormComponent {
100
102
  }
101
103
 
102
104
  getDisplayStringFromFormValue(
103
- value: string | number | boolean | Item['value'][] | undefined
105
+ value: string | number | boolean | Item['value'][] | undefined,
106
+ translator: Translator
104
107
  ): string {
105
108
  const { items } = this
106
109
 
@@ -108,29 +111,42 @@ export class ListFormComponent extends FormComponent {
108
111
 
109
112
  return items
110
113
  .filter((item) => values.includes(item.value))
111
- .map((item) => item.text)
114
+ .map((item) => translator.tListItem(item, 'text') || item.text)
112
115
  .join(', ')
113
116
  }
114
117
 
115
- getDisplayStringFromState(state: FormSubmissionState) {
118
+ getDisplayStringFromState(
119
+ state: FormSubmissionState,
120
+ translator: Translator
121
+ ) {
116
122
  // Allow for array values via subclass
117
123
  const value = this.getFormValueFromState(state)
118
124
 
119
- return this.getDisplayStringFromFormValue(value)
125
+ return this.getDisplayStringFromFormValue(value, translator)
120
126
  }
121
127
 
122
- getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {
128
+ getViewModel(context: RenderContext) {
123
129
  const { items: listItems } = this
124
130
 
125
- const viewModel = super.getViewModel(payload, errors)
131
+ const viewModel = super.getViewModel(context)
126
132
  const { value } = viewModel
127
133
 
128
134
  // Support multiple values for checkboxes
129
135
  const values = this.isValue(value) ? [value].flat() : []
130
136
 
137
+ const { tListItem } = context.translator
138
+
131
139
  const items = listItems.map((item) => {
132
140
  const selected = values.includes(item.value)
133
- const itemModel: ListItem = { ...item, selected }
141
+ const resolvedText = tListItem(item, 'text') || item.text
142
+ const resolvedHint = tListItem(item, 'hint') || item.hint?.text
143
+ const hintAttr = resolvedHint ? { hint: { text: resolvedHint } } : {}
144
+ const itemModel: ListItem = {
145
+ ...item,
146
+ text: resolvedText,
147
+ selected,
148
+ ...hintAttr
149
+ }
134
150
 
135
151
  if ('id' in itemModel) {
136
152
  delete itemModel.id
@@ -10,13 +10,12 @@ import {
10
10
  isFormValue
11
11
  } from './FormComponent.js'
12
12
  import { addClassOptionIfNone } from './helpers/index.js'
13
+ import { type RenderContext } from './types.js'
13
14
  import { messageTemplate } from '../pageControllers/validationOptions.js'
14
15
  import {
15
16
  type ErrorMessageTemplateList,
16
- type FormPayload,
17
17
  type FormState,
18
18
  type FormStateValue,
19
- type FormSubmissionError,
20
19
  type FormSubmissionState
21
20
  } from '../types.js'
22
21
  import { convertToLanguageMessages } from '../../../utils/type-utils.js'
@@ -63,8 +62,7 @@ export abstract class LocationFieldBase extends FormComponent {
63
62
  addClassOptionIfNone(locationOptions, 'govuk-input--width-10')
64
63
 
65
64
  const config = this.getValidationConfig()
66
- const requiredMessage =
67
- config.requiredMessage ?? (messageTemplate.required as string)
65
+ const requiredMessage = config.requiredMessage ?? messageTemplate.required
68
66
 
69
67
  const messages = convertToLanguageMessages({
70
68
  'any.required': requiredMessage,
@@ -120,8 +118,8 @@ export abstract class LocationFieldBase extends FormComponent {
120
118
  return LocationFieldBase.isText(value)
121
119
  }
122
120
 
123
- getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {
124
- const viewModel = super.getViewModel(payload, errors)
121
+ getViewModel(context: RenderContext) {
122
+ const viewModel = super.getViewModel(context)
125
123
 
126
124
  if (this.instructionText) {
127
125
  return {
@@ -140,8 +138,7 @@ export abstract class LocationFieldBase extends FormComponent {
140
138
  baseErrors: [
141
139
  {
142
140
  type: 'required',
143
- template:
144
- config.requiredMessage ?? (messageTemplate.required as string)
141
+ template: config.requiredMessage ?? messageTemplate.required
145
142
  },
146
143
  ...this.getErrorTemplates()
147
144
  ],
@@ -2,10 +2,13 @@ import { type Context, type CustomValidator } from 'joi'
2
2
 
3
3
  import { type EastingNorthingField } from './EastingNorthingField.js'
4
4
  import { isFormValue } from './FormComponent.js'
5
+ import { type GeospatialField } from './GeospatialField.js'
5
6
  import { type LatLongField } from './LatLongField.js'
7
+ import { type OsGridRefField } from './OsGridRefField.js'
6
8
  import {
7
9
  type DateInputItem,
8
10
  type Label,
11
+ type RenderContext,
9
12
  type ViewModel
10
13
  } from './types.js'
11
14
  import {
@@ -86,6 +89,23 @@ export function deduplicateErrorsByHref(
86
89
  )
87
90
  }
88
91
 
92
+ export function getMapLayers(
93
+ component:
94
+ | GeospatialField
95
+ | OsGridRefField
96
+ | LatLongField
97
+ | EastingNorthingField
98
+ ) {
99
+ const { mapLayers } = component.options
100
+ const layers = []
101
+
102
+ if (mapLayers?.sssi) {
103
+ layers.push('sssi')
104
+ }
105
+
106
+ return layers.join(',')
107
+ }
108
+
89
109
  export function getLocationFieldViewModel(
90
110
  component: LocationField,
91
111
  viewModel: ViewModel & {
@@ -94,13 +114,12 @@ export function getLocationFieldViewModel(
94
114
  name: string
95
115
  value: FormValue
96
116
  },
97
- payload: FormPayload,
98
- errors?: FormSubmissionError[]
117
+ context: RenderContext
99
118
  ) {
100
119
  const { collection } = component
101
120
  const { fieldset: existingFieldset, label } = viewModel
102
121
 
103
- const subViewModels = collection.getViewModel(payload, errors)
122
+ const subViewModels = collection.getViewModel(context)
104
123
 
105
124
  const fieldErrors: string[] = []
106
125
  subViewModels.forEach(({ model }) => {
@@ -167,7 +186,8 @@ export function getLocationFieldViewModel(
167
186
  const result = {
168
187
  ...viewModel,
169
188
  fieldset,
170
- items
189
+ items,
190
+ mapLayers: getMapLayers(component)
171
191
  }
172
192
 
173
193
  if (component.options.instructionText) {