@defra/forms-engine-plugin 5.0.0-alpha → 5.0.0-alpha.10

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 (303) hide show
  1. package/.public/assets-manifest.json +3 -5
  2. package/.public/javascripts/application.min.js +1 -1
  3. package/.public/javascripts/application.min.js.map +1 -1
  4. package/.public/javascripts/im-core.min.js +2 -0
  5. package/.public/javascripts/im-core.min.js.map +1 -0
  6. package/.public/javascripts/shared.min.js +1 -1
  7. package/.public/javascripts/shared.min.js.map +1 -1
  8. package/.public/javascripts/vendor/@defra.min.js +1 -1
  9. package/.public/javascripts/vendor/@defra.min.js.map +1 -1
  10. package/.public/stylesheets/application.min.css +1 -1
  11. package/.public/stylesheets/application.min.css.map +1 -1
  12. package/.server/client/javascripts/file-upload.js +5 -3
  13. package/.server/client/javascripts/file-upload.js.map +1 -1
  14. package/.server/client/javascripts/geospatial-map.js +36 -29
  15. package/.server/client/javascripts/geospatial-map.js.map +1 -1
  16. package/.server/client/javascripts/location-map.js +16 -1
  17. package/.server/client/javascripts/location-map.js.map +1 -1
  18. package/.server/client/javascripts/map.d.ts +6 -0
  19. package/.server/client/javascripts/map.js +10 -0
  20. package/.server/client/javascripts/map.js.map +1 -1
  21. package/.server/client/javascripts/maps.d.ts +5 -0
  22. package/.server/client/javascripts/maps.js +6 -0
  23. package/.server/client/javascripts/maps.js.map +1 -0
  24. package/.server/client/javascripts/shared.d.ts +1 -3
  25. package/.server/client/javascripts/shared.js +1 -3
  26. package/.server/client/javascripts/shared.js.map +1 -1
  27. package/.server/client/javascripts/sssi-dataset.d.ts +32 -0
  28. package/.server/client/javascripts/sssi-dataset.js +99 -0
  29. package/.server/client/javascripts/sssi-dataset.js.map +1 -0
  30. package/.server/client/stylesheets/maps.scss +4 -0
  31. package/.server/client/stylesheets/shared.scss +1 -7
  32. package/.server/server/constants.d.ts +2 -0
  33. package/.server/server/constants.js +2 -0
  34. package/.server/server/constants.js.map +1 -1
  35. package/.server/server/plugins/engine/components/AutocompleteField.d.ts +9 -3
  36. package/.server/server/plugins/engine/components/AutocompleteField.js +12 -0
  37. package/.server/server/plugins/engine/components/AutocompleteField.js.map +1 -1
  38. package/.server/server/plugins/engine/components/CheckboxesField.d.ts +4 -1
  39. package/.server/server/plugins/engine/components/CheckboxesField.js +13 -0
  40. package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -1
  41. package/.server/server/plugins/engine/components/ComponentBase.d.ts +1 -0
  42. package/.server/server/plugins/engine/components/ComponentBase.js +2 -0
  43. package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -1
  44. package/.server/server/plugins/engine/components/ComponentCollection.js +11 -6
  45. package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
  46. package/.server/server/plugins/engine/components/DatePartsField.d.ts +6 -3
  47. package/.server/server/plugins/engine/components/DatePartsField.js +12 -7
  48. package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -1
  49. package/.server/server/plugins/engine/components/DeclarationField.d.ts +5 -2
  50. package/.server/server/plugins/engine/components/DeclarationField.js +6 -4
  51. package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -1
  52. package/.server/server/plugins/engine/components/Details.d.ts +1 -0
  53. package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +28 -2
  54. package/.server/server/plugins/engine/components/EastingNorthingField.js +93 -54
  55. package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -1
  56. package/.server/server/plugins/engine/components/EmailAddressField.d.ts +4 -1
  57. package/.server/server/plugins/engine/components/EmailAddressField.js +2 -1
  58. package/.server/server/plugins/engine/components/EmailAddressField.js.map +1 -1
  59. package/.server/server/plugins/engine/components/FileUploadField.d.ts +12 -0
  60. package/.server/server/plugins/engine/components/FileUploadField.js +20 -2
  61. package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
  62. package/.server/server/plugins/engine/components/FormComponent.d.ts +5 -1
  63. package/.server/server/plugins/engine/components/FormComponent.js +5 -2
  64. package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
  65. package/.server/server/plugins/engine/components/GeospatialField.d.ts +2 -0
  66. package/.server/server/plugins/engine/components/GeospatialField.js +3 -1
  67. package/.server/server/plugins/engine/components/GeospatialField.js.map +1 -1
  68. package/.server/server/plugins/engine/components/Html.d.ts +1 -0
  69. package/.server/server/plugins/engine/components/InsetText.d.ts +1 -0
  70. package/.server/server/plugins/engine/components/LatLongField.d.ts +28 -2
  71. package/.server/server/plugins/engine/components/LatLongField.js +85 -48
  72. package/.server/server/plugins/engine/components/LatLongField.js.map +1 -1
  73. package/.server/server/plugins/engine/components/List.d.ts +1 -0
  74. package/.server/server/plugins/engine/components/ListFormComponent.d.ts +1 -0
  75. package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +8 -2
  76. package/.server/server/plugins/engine/components/LocationFieldBase.js +18 -5
  77. package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -1
  78. package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +10 -2
  79. package/.server/server/plugins/engine/components/LocationFieldHelpers.js +22 -12
  80. package/.server/server/plugins/engine/components/LocationFieldHelpers.js.map +1 -1
  81. package/.server/server/plugins/engine/components/Markdown.d.ts +1 -0
  82. package/.server/server/plugins/engine/components/Markdown.js +1 -1
  83. package/.server/server/plugins/engine/components/Markdown.js.map +1 -1
  84. package/.server/server/plugins/engine/components/MonthYearField.d.ts +5 -2
  85. package/.server/server/plugins/engine/components/MonthYearField.js +13 -9
  86. package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -1
  87. package/.server/server/plugins/engine/components/MultilineTextField.d.ts +1 -0
  88. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +2 -1
  89. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js +4 -3
  90. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js.map +1 -1
  91. package/.server/server/plugins/engine/components/NotificationBanner.d.ts +1 -0
  92. package/.server/server/plugins/engine/components/NumberField.d.ts +5 -0
  93. package/.server/server/plugins/engine/components/NumberField.js +16 -0
  94. package/.server/server/plugins/engine/components/NumberField.js.map +1 -1
  95. package/.server/server/plugins/engine/components/OsGridRefField.d.ts +2 -1
  96. package/.server/server/plugins/engine/components/OsGridRefField.js +4 -3
  97. package/.server/server/plugins/engine/components/OsGridRefField.js.map +1 -1
  98. package/.server/server/plugins/engine/components/PaymentField.d.ts +3 -0
  99. package/.server/server/plugins/engine/components/PaymentField.js +17 -6
  100. package/.server/server/plugins/engine/components/PaymentField.js.map +1 -1
  101. package/.server/server/plugins/engine/components/SelectField.d.ts +1 -0
  102. package/.server/server/plugins/engine/components/SelectionControlField.d.ts +1 -0
  103. package/.server/server/plugins/engine/components/TelephoneNumberField.d.ts +1 -0
  104. package/.server/server/plugins/engine/components/UkAddressField.d.ts +1 -0
  105. package/.server/server/plugins/engine/components/UkAddressField.js +23 -8
  106. package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
  107. package/.server/server/plugins/engine/components/YesNoField.d.ts +5 -2
  108. package/.server/server/plugins/engine/components/YesNoField.js +17 -8
  109. package/.server/server/plugins/engine/components/YesNoField.js.map +1 -1
  110. package/.server/server/plugins/engine/components/helpers/components.js +1 -2
  111. package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
  112. package/.server/server/plugins/engine/components/helpers/index.d.ts +7 -0
  113. package/.server/server/plugins/engine/components/helpers/index.js +13 -1
  114. package/.server/server/plugins/engine/components/helpers/index.js.map +1 -1
  115. package/.server/server/plugins/engine/components/types.d.ts +1 -0
  116. package/.server/server/plugins/engine/components/types.js.map +1 -1
  117. package/.server/server/plugins/engine/helpers.d.ts +22 -2
  118. package/.server/server/plugins/engine/helpers.js +44 -5
  119. package/.server/server/plugins/engine/helpers.js.map +1 -1
  120. package/.server/server/plugins/engine/i18n/buildValidationMessages.d.ts +3 -0
  121. package/.server/server/plugins/engine/i18n/buildValidationMessages.js +10 -7
  122. package/.server/server/plugins/engine/i18n/buildValidationMessages.js.map +1 -1
  123. package/.server/server/plugins/engine/i18n/createFormTranslator.d.ts +4 -4
  124. package/.server/server/plugins/engine/i18n/createFormTranslator.js +33 -4
  125. package/.server/server/plugins/engine/i18n/createFormTranslator.js.map +1 -1
  126. package/.server/server/plugins/engine/i18n/extractBaseTranslations.d.ts +1 -1
  127. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js +9 -0
  128. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js.map +1 -1
  129. package/.server/server/plugins/engine/i18n/form.d.ts +13 -0
  130. package/.server/server/plugins/engine/i18n/form.js +35 -0
  131. package/.server/server/plugins/engine/i18n/form.js.map +1 -0
  132. package/.server/server/plugins/engine/i18n/languages.d.ts +10 -0
  133. package/.server/server/plugins/engine/i18n/languages.js +19 -0
  134. package/.server/server/plugins/engine/i18n/languages.js.map +1 -0
  135. package/.server/server/plugins/engine/i18n/translations/cy.json +73 -6
  136. package/.server/server/plugins/engine/i18n/translations/en-GB.json +43 -4
  137. package/.server/server/plugins/engine/i18n/types.d.ts +2 -0
  138. package/.server/server/plugins/engine/i18n/types.js.map +1 -1
  139. package/.server/server/plugins/engine/index.d.ts +4 -0
  140. package/.server/server/plugins/engine/index.js +4 -0
  141. package/.server/server/plugins/engine/index.js.map +1 -1
  142. package/.server/server/plugins/engine/models/FormModel.d.ts +0 -4
  143. package/.server/server/plugins/engine/models/FormModel.js +9 -15
  144. package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
  145. package/.server/server/plugins/engine/models/SummaryViewModel.js +9 -4
  146. package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
  147. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +3 -5
  148. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
  149. package/.server/server/plugins/engine/outputFormatters/human/v1.js +2 -1
  150. package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
  151. package/.server/server/plugins/engine/outputFormatters/machine/v2.d.ts +2 -0
  152. package/.server/server/plugins/engine/outputFormatters/machine/v2.js +2 -0
  153. package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -1
  154. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.d.ts +1 -1
  155. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +22 -9
  156. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
  157. package/.server/server/plugins/engine/pageControllers/QuestionPageController.d.ts +1 -1
  158. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +7 -3
  159. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
  160. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js +3 -4
  161. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js.map +1 -1
  162. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +10 -4
  163. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
  164. package/.server/server/plugins/engine/pageControllers/helpers/submission.d.ts +1 -1
  165. package/.server/server/plugins/engine/pageControllers/helpers/submission.js +3 -3
  166. package/.server/server/plugins/engine/pageControllers/helpers/submission.js.map +1 -1
  167. package/.server/server/plugins/engine/pageControllers/validationOptions.js +23 -2
  168. package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
  169. package/.server/server/plugins/engine/types/schema.js +1 -0
  170. package/.server/server/plugins/engine/types/schema.js.map +1 -1
  171. package/.server/server/plugins/engine/types.d.ts +1 -0
  172. package/.server/server/plugins/engine/types.js.map +1 -1
  173. package/.server/server/plugins/engine/views/components/_location-field-base.html +3 -1
  174. package/.server/server/plugins/engine/views/components/fileuploadfield.html +1 -1
  175. package/.server/server/plugins/engine/views/components/geospatialfield.html +4 -1
  176. package/.server/server/plugins/engine/views/components/multilinetextfield.html +12 -1
  177. package/.server/server/plugins/engine/views/components/paymentfield.html +1 -1
  178. package/.server/server/plugins/engine/views/components/ukaddressfield.html +1 -1
  179. package/.server/server/plugins/engine/views/partials/preview-banner.html +3 -1
  180. package/.server/server/plugins/map/routes/index.js +1 -1
  181. package/.server/server/plugins/map/routes/index.js.map +1 -1
  182. package/.server/server/plugins/map/types.d.ts +1 -25
  183. package/.server/server/plugins/map/types.js +1 -16
  184. package/.server/server/plugins/map/types.js.map +1 -1
  185. package/.server/server/plugins/nunjucks/filters/applyUrlParam.d.ts +9 -0
  186. package/.server/server/plugins/nunjucks/filters/applyUrlParam.js +17 -0
  187. package/.server/server/plugins/nunjucks/filters/applyUrlParam.js.map +1 -0
  188. package/.server/server/plugins/nunjucks/filters/applyUrlParam.test.js +17 -0
  189. package/.server/server/plugins/nunjucks/filters/applyUrlParam.test.js.map +1 -0
  190. package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
  191. package/.server/server/plugins/nunjucks/filters/index.d.ts +1 -0
  192. package/.server/server/plugins/nunjucks/filters/index.js +1 -0
  193. package/.server/server/plugins/nunjucks/filters/index.js.map +1 -1
  194. package/.server/server/plugins/payment/helper.d.ts +11 -1
  195. package/.server/server/plugins/payment/helper.js +18 -2
  196. package/.server/server/plugins/payment/helper.js.map +1 -1
  197. package/.server/server/plugins/payment/helper.test.js +2 -1
  198. package/.server/server/plugins/payment/helper.test.js.map +1 -1
  199. package/.server/server/plugins/payment/service.d.ts +2 -1
  200. package/.server/server/plugins/payment/service.js +5 -2
  201. package/.server/server/plugins/payment/service.js.map +1 -1
  202. package/.server/server/plugins/payment/service.test.js +7 -3
  203. package/.server/server/plugins/payment/service.test.js.map +1 -1
  204. package/.server/server/plugins/payment/types.d.ts +4 -0
  205. package/.server/server/plugins/payment/types.js +1 -0
  206. package/.server/server/plugins/payment/types.js.map +1 -1
  207. package/.server/server/plugins/postcode-lookup/models/index.d.ts +249 -3
  208. package/.server/server/plugins/postcode-lookup/models/index.js +87 -33
  209. package/.server/server/plugins/postcode-lookup/models/index.js.map +1 -1
  210. package/.server/server/plugins/postcode-lookup/routes/index.d.ts +15 -1
  211. package/.server/server/plugins/postcode-lookup/routes/index.js +47 -15
  212. package/.server/server/plugins/postcode-lookup/routes/index.js.map +1 -1
  213. package/.server/server/plugins/postcode-lookup/routes/index.test.js +84 -0
  214. package/.server/server/plugins/postcode-lookup/routes/index.test.js.map +1 -0
  215. package/.server/server/plugins/postcode-lookup/types.d.ts +12 -0
  216. package/.server/server/plugins/postcode-lookup/types.js +6 -1
  217. package/.server/server/plugins/postcode-lookup/types.js.map +1 -1
  218. package/.server/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  219. package/.server/server/utils/type-utils.d.ts +1 -2
  220. package/.server/server/utils/type-utils.js +0 -3
  221. package/.server/server/utils/type-utils.js.map +1 -1
  222. package/package.json +9 -3
  223. package/src/client/javascripts/file-upload.js +10 -3
  224. package/src/client/javascripts/geospatial-map.js +38 -32
  225. package/src/client/javascripts/location-map.js +17 -0
  226. package/src/client/javascripts/map.js +10 -0
  227. package/src/client/javascripts/maps.js +5 -0
  228. package/src/client/javascripts/shared.js +1 -3
  229. package/src/client/javascripts/sssi-dataset.js +104 -0
  230. package/src/client/stylesheets/maps.scss +4 -0
  231. package/src/client/stylesheets/shared.scss +1 -7
  232. package/src/server/constants.js +2 -0
  233. package/src/server/plugins/engine/components/AutocompleteField.ts +13 -0
  234. package/src/server/plugins/engine/components/CheckboxesField.ts +13 -1
  235. package/src/server/plugins/engine/components/ComponentBase.ts +2 -0
  236. package/src/server/plugins/engine/components/ComponentCollection.ts +16 -11
  237. package/src/server/plugins/engine/components/DatePartsField.ts +20 -9
  238. package/src/server/plugins/engine/components/DeclarationField.ts +7 -6
  239. package/src/server/plugins/engine/components/EastingNorthingField.ts +154 -89
  240. package/src/server/plugins/engine/components/EmailAddressField.ts +2 -1
  241. package/src/server/plugins/engine/components/FileUploadField.ts +21 -2
  242. package/src/server/plugins/engine/components/FormComponent.ts +6 -5
  243. package/src/server/plugins/engine/components/GeospatialField.ts +8 -1
  244. package/src/server/plugins/engine/components/LatLongField.ts +128 -58
  245. package/src/server/plugins/engine/components/LocationFieldBase.ts +23 -6
  246. package/src/server/plugins/engine/components/LocationFieldHelpers.ts +35 -12
  247. package/src/server/plugins/engine/components/Markdown.ts +2 -3
  248. package/src/server/plugins/engine/components/MonthYearField.ts +20 -15
  249. package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +9 -3
  250. package/src/server/plugins/engine/components/NumberField.ts +21 -1
  251. package/src/server/plugins/engine/components/OsGridRefField.ts +9 -3
  252. package/src/server/plugins/engine/components/PaymentField.ts +15 -5
  253. package/src/server/plugins/engine/components/UkAddressField.ts +30 -7
  254. package/src/server/plugins/engine/components/YesNoField.ts +17 -9
  255. package/src/server/plugins/engine/components/helpers/components.ts +1 -2
  256. package/src/server/plugins/engine/components/helpers/index.ts +19 -0
  257. package/src/server/plugins/engine/components/types.ts +1 -0
  258. package/src/server/plugins/engine/helpers.ts +52 -5
  259. package/src/server/plugins/engine/i18n/buildValidationMessages.ts +10 -7
  260. package/src/server/plugins/engine/i18n/createFormTranslator.ts +62 -11
  261. package/src/server/plugins/engine/i18n/extractBaseTranslations.ts +7 -1
  262. package/src/server/plugins/engine/i18n/form.ts +54 -0
  263. package/src/server/plugins/engine/i18n/languages.ts +19 -0
  264. package/src/server/plugins/engine/i18n/translations/cy.json +73 -6
  265. package/src/server/plugins/engine/i18n/translations/en-GB.json +43 -4
  266. package/src/server/plugins/engine/i18n/types.ts +2 -0
  267. package/src/server/plugins/engine/index.ts +7 -0
  268. package/src/server/plugins/engine/models/FormModel.ts +9 -15
  269. package/src/server/plugins/engine/models/SummaryViewModel.ts +6 -5
  270. package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +3 -6
  271. package/src/server/plugins/engine/outputFormatters/human/v1.ts +2 -1
  272. package/src/server/plugins/engine/outputFormatters/machine/v2.ts +3 -0
  273. package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +18 -8
  274. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +10 -5
  275. package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +2 -2
  276. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +15 -4
  277. package/src/server/plugins/engine/pageControllers/helpers/submission.ts +6 -3
  278. package/src/server/plugins/engine/pageControllers/validationOptions.ts +27 -2
  279. package/src/server/plugins/engine/types/schema.ts +1 -0
  280. package/src/server/plugins/engine/types.ts +1 -0
  281. package/src/server/plugins/engine/views/components/_location-field-base.html +3 -1
  282. package/src/server/plugins/engine/views/components/fileuploadfield.html +1 -1
  283. package/src/server/plugins/engine/views/components/geospatialfield.html +4 -1
  284. package/src/server/plugins/engine/views/components/multilinetextfield.html +12 -1
  285. package/src/server/plugins/engine/views/components/paymentfield.html +1 -1
  286. package/src/server/plugins/engine/views/components/ukaddressfield.html +1 -1
  287. package/src/server/plugins/engine/views/partials/preview-banner.html +3 -1
  288. package/src/server/plugins/map/routes/index.js +1 -1
  289. package/src/server/plugins/map/types.js +1 -16
  290. package/src/server/plugins/nunjucks/filters/applyUrlParam.js +17 -0
  291. package/src/server/plugins/nunjucks/filters/index.js +1 -0
  292. package/src/server/plugins/payment/helper.js +22 -2
  293. package/src/server/plugins/payment/service.js +6 -2
  294. package/src/server/plugins/payment/types.js +1 -0
  295. package/src/server/plugins/postcode-lookup/models/index.js +75 -43
  296. package/src/server/plugins/postcode-lookup/routes/index.js +73 -16
  297. package/src/server/plugins/postcode-lookup/types.js +6 -1
  298. package/src/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  299. package/src/server/utils/type-utils.ts +1 -11
  300. package/.public/javascripts/im-search-plugin.min.js +0 -2
  301. package/.public/javascripts/im-search-plugin.min.js.map +0 -1
  302. package/.public/javascripts/vendor/preact.min.js +0 -2
  303. package/.public/javascripts/vendor/preact.min.js.map +0 -1
@@ -45,6 +45,7 @@ export class PaymentField extends FormComponent {
45
45
  declare options: PaymentFieldComponent['options']
46
46
  declare formSchema: ObjectSchema
47
47
  declare stateSchema: ObjectSchema
48
+ declare def: PaymentFieldComponent
48
49
  isAppendageStateSingleObject = true
49
50
 
50
51
  constructor(
@@ -54,6 +55,7 @@ export class PaymentField extends FormComponent {
54
55
  super(def, props)
55
56
 
56
57
  this.options = def.options
58
+ this.def = def
57
59
 
58
60
  const paymentStateSchema = joi
59
61
  .object({
@@ -61,6 +63,7 @@ export class PaymentField extends FormComponent {
61
63
  reference: joi.string().required(),
62
64
  amount: joi.number().required(),
63
65
  description: joi.string().required(),
66
+ descriptionInEng: joi.string().optional(),
64
67
  uuid: joi.string().uuid().required(),
65
68
  formId: joi.string().required(),
66
69
  isLivePayment: joi.boolean().required(),
@@ -110,6 +113,8 @@ export class PaymentField extends FormComponent {
110
113
  getViewModel(context: RenderContext) {
111
114
  const { payload } = context
112
115
  const viewModel = super.getViewModel(context)
116
+ const { translator } = context
117
+ const { tComponent } = translator
113
118
 
114
119
  // Payload is pre-populated from state if a payment has already been made
115
120
  const paymentState = this.isPaymentState(payload[this.name] as unknown)
@@ -124,7 +129,8 @@ export class PaymentField extends FormComponent {
124
129
  return {
125
130
  ...viewModel,
126
131
  amount: formatCurrency(amount),
127
- description: this.options.description,
132
+ description:
133
+ tComponent(this.def, 'paymentDescription') || this.options.description,
128
134
  paymentState
129
135
  }
130
136
  }
@@ -234,8 +240,9 @@ export class PaymentField extends FormComponent {
234
240
  ): Promise<unknown> {
235
241
  const { options, name: componentName } = args.component
236
242
  const { model } = args.controller
237
- const language = resolveLanguage(request)
238
- const { t } = model.createTranslator(language)
243
+ const { language, t, tComponent } = model.createTranslator(
244
+ resolveLanguage(request)
245
+ )
239
246
  const state = await args.controller.getState(request)
240
247
  const { baseUrl } = getPluginOptions(request.server)
241
248
  const summaryUrl = `${baseUrl}/${model.basePath}/summary`
@@ -267,7 +274,8 @@ export class PaymentField extends FormComponent {
267
274
  return h.redirect(summaryUrl).code(StatusCodes.SEE_OTHER)
268
275
  }
269
276
 
270
- const description = options.description
277
+ const description =
278
+ tComponent(args.component, 'paymentDescription') || options.description
271
279
 
272
280
  const slug = `/${model.basePath}`
273
281
 
@@ -287,7 +295,7 @@ export class PaymentField extends FormComponent {
287
295
  payCallbackUrl,
288
296
  reference,
289
297
  isLivePayment,
290
- { formId, slug },
298
+ { formId, slug, language },
291
299
  prefilledEmail
292
300
  )
293
301
 
@@ -308,6 +316,7 @@ export class PaymentField extends FormComponent {
308
316
  reference,
309
317
  amount: resolvedAmount,
310
318
  description,
319
+ descriptionInEng: options.description,
311
320
  paymentId: payment.paymentId,
312
321
  componentName,
313
322
  returnUrl: summaryUrl,
@@ -444,6 +453,7 @@ export interface PaymentSessionData {
444
453
  reference: string
445
454
  amount: number
446
455
  description: string
456
+ descriptionInEng?: string
447
457
  paymentId: string
448
458
  componentName: string
449
459
  returnUrl: string
@@ -1,4 +1,9 @@
1
- import { ComponentType, type UkAddressFieldComponent } from '@defra/forms-model'
1
+ import {
2
+ ComponentType,
3
+ FormStatus,
4
+ type FormMetadata,
5
+ type UkAddressFieldComponent
6
+ } from '@defra/forms-model'
2
7
  import { type ObjectSchema } from 'joi'
3
8
  import lowerFirst from 'lodash/lowerFirst.js'
4
9
 
@@ -9,6 +14,8 @@ import {
9
14
  } from './FormComponent.js'
10
15
  import { TextField } from './TextField.js'
11
16
  import { type RenderContext } from './types.js'
17
+ import { getCachedPluginTranslator } from '../i18n/form.js'
18
+ import { getAvailableLanguages } from '../i18n/languages.js'
12
19
  import { type Translator } from '../i18n/types.js'
13
20
  import {
14
21
  type FormRequestPayload,
@@ -207,7 +214,7 @@ export class UkAddressField extends FormComponent {
207
214
 
208
215
  /**
209
216
  * For screen readers, only hide legend visually. This can be overridden
210
- * by single component {@link QuestionPageController | `showTitle` handling}
217
+ * by single component (see QuestionPageController and showTitle handling)
211
218
  */
212
219
  classes: options.hideTitle
213
220
  ? 'govuk-visually-hidden'
@@ -290,7 +297,6 @@ export class UkAddressField extends FormComponent {
290
297
  )
291
298
  }
292
299
 
293
- // eslint-disable-next-line @typescript-eslint/require-await
294
300
  static async dispatcher(
295
301
  request: FormRequestPayload,
296
302
  h: FormResponseToolkit,
@@ -299,14 +305,31 @@ export class UkAddressField extends FormComponent {
299
305
  const { controller, component } = args
300
306
  const language = resolveLanguage(request)
301
307
 
308
+ const availableLanguages = getAvailableLanguages(controller.model.def)
309
+ const languages = availableLanguages.length
310
+ ? { languages: availableLanguages }
311
+ : {}
312
+
313
+ const translator = await getCachedPluginTranslator(
314
+ request,
315
+ { id: controller.model.formId } as unknown as FormMetadata,
316
+ args.isLive ? FormStatus.Live : FormStatus.Draft,
317
+ language
318
+ )
319
+ const { tComponent, tForm } = translator
320
+
302
321
  return dispatch(request, h, {
303
- formName: controller.model.name,
322
+ formName: tForm('title'),
323
+ formId: controller.model.formId,
324
+ formStatus: args.isLive ? FormStatus.Live : FormStatus.Draft,
325
+ componentId: component.id ?? 'unknown',
304
326
  componentName: component.name,
305
- componentHint: component.hint,
306
- componentTitle: component.title || controller.title,
327
+ componentHint: tComponent(component, 'hint'),
328
+ componentTitle: tComponent(component, 'title') || controller.title,
307
329
  step: args.actionArgs.step,
308
330
  sourceUrl: args.sourceUrl,
309
- language
331
+ language,
332
+ ...languages
310
333
  })
311
334
  }
312
335
  }
@@ -4,7 +4,6 @@ import {
4
4
  yesNoListName,
5
5
  type YesNoFieldComponent
6
6
  } from '@defra/forms-model'
7
- import { type LanguageMessages } from 'joi'
8
7
 
9
8
  import { SelectionControlField } from './SelectionControlField.js'
10
9
  import { addClassOptionIfNone } from './helpers/index.js'
@@ -12,7 +11,6 @@ import { buildValidationMessages } from '../i18n/buildValidationMessages.js'
12
11
  import { type Translator } from '../i18n/types.js'
13
12
  import { messageTemplate } from '../pageControllers/validationOptions.js'
14
13
  import { type ErrorMessageTemplateList } from '../types.js'
15
- import { convertToLanguageMessages } from '../../../utils/type-utils.js'
16
14
 
17
15
  /**
18
16
  * @description
@@ -45,21 +43,31 @@ export class YesNoField extends SelectionControlField {
45
43
  formSchema = formSchema.optional()
46
44
  }
47
45
 
48
- formSchema = formSchema.messages(
49
- convertToLanguageMessages({
46
+ if (options.customValidationMessage) {
47
+ const message = options.customValidationMessage
48
+
49
+ formSchema = formSchema.messages({
50
+ 'any.required': message
51
+ })
52
+ } else if (options.customValidationMessages) {
53
+ formSchema = formSchema.messages(options.customValidationMessages)
54
+ } else {
55
+ formSchema = formSchema.messages({
50
56
  'any.required': messageTemplate.selectYesNoRequired
51
57
  })
52
- )
58
+ }
53
59
 
54
60
  this.formSchema = formSchema
55
61
  this.options = options
56
62
  }
57
63
 
58
- getValidationMessagesOverride(translator: Translator): LanguageMessages {
64
+ getValidationMessagesOverride(translator: Translator) {
59
65
  const { selectYesNoRequired } = buildValidationMessages(translator.t)
60
- return convertToLanguageMessages({
61
- 'any.required': selectYesNoRequired
62
- })
66
+ return {
67
+ [this.name]: {
68
+ 'any.required': selectYesNoRequired
69
+ }
70
+ }
63
71
  }
64
72
 
65
73
  /**
@@ -347,8 +347,7 @@ export function getAnswerMarkdown(
347
347
  field instanceof Components.EastingNorthingField ||
348
348
  field instanceof Components.LatLongField
349
349
  ) {
350
- const contextValue = field.getContextValueFromState(state)
351
- answerEscaped = contextValue ? `${contextValue}\n` : ''
350
+ answerEscaped = answer ? `${answer}\n` : ''
352
351
  } else if (field instanceof Components.GeospatialField) {
353
352
  const features = field.getFormValueFromState(state)
354
353
  const value = field.getDisplayStringFromFormValue(features, translator)
@@ -2,6 +2,8 @@ import { type ComponentDef } from '@defra/forms-model'
2
2
  import joi, { type JoiExpression, type ReferenceOptions } from 'joi'
3
3
  import lowerFirst from 'lodash/lowerFirst.js'
4
4
 
5
+ import { type Translator } from '../../i18n/types.js'
6
+
5
7
  /**
6
8
  * Prevent Markdown formatting
7
9
  * @see {@link https://pandoc.org/chunkedhtml-demo/8.11-backslash-escapes.html}
@@ -66,3 +68,20 @@ export const lowerFirstExpressionOptions = {
66
68
  */
67
69
  export const createLowerFirstExpression = (template: string): JoiExpression =>
68
70
  joi.expression(template, lowerFirstExpressionOptions) as JoiExpression
71
+
72
+ /**
73
+ * Translate a component label, in precedence order of errorDescription, then shortDesciption, then title
74
+ * @param {ComponentDef} component
75
+ * @param {Translator} translator
76
+ */
77
+ export function getTranslatedLabel(
78
+ component: ComponentDef,
79
+ translator: Translator
80
+ ) {
81
+ const { tComponent } = translator
82
+ const translatedLabel =
83
+ tComponent(component, 'errorDescription') ||
84
+ tComponent(component, 'shortDescription') ||
85
+ tComponent(component, 'title')
86
+ return translatedLabel
87
+ }
@@ -124,6 +124,7 @@ export interface ViewModel extends Record<string, unknown> {
124
124
  upload?: {
125
125
  count: number
126
126
  summaryList: SummaryList
127
+ uploadingLabel?: string
127
128
  }
128
129
  }
129
130
 
@@ -8,13 +8,14 @@ import {
8
8
  } from '@defra/forms-model'
9
9
  import Boom from '@hapi/boom'
10
10
  import { type ResponseToolkit, type Server } from '@hapi/hapi'
11
- import { format, parseISO } from 'date-fns'
11
+ import { format, parseISO, type Locale } from 'date-fns'
12
+ import { cy, enGB } from 'date-fns/locale'
12
13
  import { StatusCodes } from 'http-status-codes'
13
14
  import { type Schema, type ValidationErrorItem } from 'joi'
14
15
  import { Liquid } from 'liquidjs'
15
16
 
16
17
  import { logger } from '../../common/helpers/logging/logger.js'
17
- import { FORM_VERSION_METADATA_KEY } from '../../constants.js'
18
+ import { CY, EN_GB, FORM_VERSION_METADATA_KEY } from '../../constants.js'
18
19
  import {
19
20
  getAnswer,
20
21
  type Field
@@ -300,19 +301,24 @@ export function checkEmailAddressForLiveFormSubmission(
300
301
 
301
302
  /**
302
303
  * Parses the errors from {@link Schema.validate} so they can be rendered by govuk-frontend templates
304
+ * @param language - the target language for translations
303
305
  * @param [details] - provided by {@link Schema.validate}
304
306
  */
305
307
  export function getErrors(
308
+ language: string | undefined,
306
309
  details?: ValidationErrorItem[]
307
310
  ): FormSubmissionError[] | undefined {
308
311
  if (!details?.length) {
309
312
  return
310
313
  }
311
314
 
312
- return details.map(getError)
315
+ return details.map((detail) => getError(language, detail))
313
316
  }
314
317
 
315
- export function getError(detail: ValidationErrorItem): FormSubmissionError {
318
+ export function getError(
319
+ language: string | undefined,
320
+ detail: ValidationErrorItem
321
+ ): FormSubmissionError {
316
322
  const { context, message, path } = detail
317
323
 
318
324
  const name = context?.key ?? ''
@@ -320,7 +326,10 @@ export function getError(detail: ValidationErrorItem): FormSubmissionError {
320
326
 
321
327
  const text = message.replace(
322
328
  /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/,
323
- (text) => format(parseISO(text), 'd MMMM yyyy')
329
+ (text) =>
330
+ format(parseISO(text), 'd MMMM yyyy', {
331
+ locale: toLanguageLocale(language)
332
+ })
324
333
  )
325
334
 
326
335
  return {
@@ -410,3 +419,41 @@ export function getFormVersion(
410
419
  | FormVersionMetadata
411
420
  | undefined
412
421
  }
422
+
423
+ const payLanguageCodes = {
424
+ [EN_GB]: 'en',
425
+ [CY]: 'cy'
426
+ } as Record<string, string>
427
+
428
+ const languageLocales = {
429
+ [EN_GB]: enGB,
430
+ [CY]: cy
431
+ } as Record<string, Locale>
432
+
433
+ const defaultLanguageCode = 'en'
434
+ const defaultLanguageLocale = enGB
435
+
436
+ /**
437
+ * Converts a BCP 47 language tag to the ISO 639-1 code GOV.UK Pay accepts.
438
+ * Defaults to English if the language is not supported.
439
+ * @param { string | undefined } language - BCP 47 language code
440
+ * @returns {string} language code required by GOV.UK Pay
441
+ */
442
+ export function toPayLanguageCode(language: string | undefined): string {
443
+ return payLanguageCodes[language ?? 'unknown'] ?? defaultLanguageCode
444
+ }
445
+
446
+ /**
447
+ * Converts a BCP 47 language tag to the date-fns Locale (for date formatting).
448
+ * Defaults to English if the language is not supported.
449
+ * @param { string | undefined } language - BCP 47 language code
450
+ * @returns {Locale} language locale
451
+ */
452
+ export function toLanguageLocale(language: string | undefined): Locale {
453
+ return languageLocales[language ?? 'unknown'] ?? defaultLanguageLocale
454
+ }
455
+
456
+ /**
457
+ * @import { FormsService } from '../../types.js'
458
+ * @import { Locale } from 'date-fns/locale'
459
+ */
@@ -56,13 +56,16 @@ export function buildValidationMessages(t: (key: string) => string) {
56
56
  dateMin: t('components.dateField.validation.dateMin'),
57
57
  dateMax: t('components.dateField.validation.dateMax'),
58
58
 
59
- unicode: 'validation.unicode',
60
- arrayMin: 'validation.array.min',
61
- arrayMax: 'validation.array.max',
62
- arrayLength: 'validation.array.length',
63
- featuresMin: 'validation.features.min',
64
- featuresMax: 'validation.features.max',
65
- featuresLength: 'validation.features.length'
59
+ unicode: t('validation.unicode'),
60
+ arrayMin: t('validation.arrayMin'),
61
+ arrayMax: t('validation.arrayMax'),
62
+ arrayLength: t('validation.arrayLength'),
63
+ featuresMin: t('validation.featuresMin'),
64
+ featuresMax: t('validation.featuresMax'),
65
+ featuresLength: t('validation.featuresLength'),
66
+ filesMin: t('validation.filesMin'),
67
+ filesMax: t('validation.filesMax'),
68
+ filesLength: t('validation.filesLength')
66
69
  }
67
70
  }
68
71
 
@@ -1,26 +1,40 @@
1
- import { type FormDefinition } from '@defra/forms-model'
1
+ import {
2
+ yesNoListNoItemId,
3
+ yesNoListYesItemId,
4
+ type FormDefinition,
5
+ type FormMetadata
6
+ } from '@defra/forms-model'
2
7
  import { type i18n } from 'i18next'
3
8
 
9
+ import { CY } from '../../../constants.js'
4
10
  import { createTranslator } from './createTranslator.js'
5
11
  import { extractBaseTranslations } from './extractBaseTranslations.js'
6
12
  import { createFormI18nInstance } from './index.js'
7
- import {
8
- type FormDefinitionTranslations,
9
- type Translator
10
- } from './types.js'
13
+ import { type FormDefinitionTranslations } from './types.js'
11
14
 
12
15
  export function createFormTranslator(
13
- def: FormDefinition,
16
+ metadata: FormMetadata,
17
+ definition: FormDefinition | undefined,
14
18
  language: string
15
- ): Translator {
16
- const baseTranslations = extractBaseTranslations(def)
19
+ ) {
20
+ const baseTranslations = extractBaseTranslations(definition)
17
21
  const i18nInstance = createFormI18nInstance(baseTranslations)
18
- loadFormTranslations(def, i18nInstance)
22
+ loadFormTranslations(definition, i18nInstance)
23
+ extractMetadataBaseTranslations(metadata, i18nInstance)
24
+
25
+ const translator = createTranslator(i18nInstance, language)
19
26
 
20
- return createTranslator(i18nInstance, language)
27
+ return translator
21
28
  }
22
29
 
23
- export function loadFormTranslations(def: FormDefinition, i18nInstance: i18n) {
30
+ export function loadFormTranslations(
31
+ def: FormDefinition | undefined,
32
+ i18nInstance: i18n
33
+ ) {
34
+ if (!def) {
35
+ return
36
+ }
37
+
24
38
  const formTranslations = def.metadata?.translations as
25
39
  | FormDefinitionTranslations
26
40
  | undefined
@@ -28,6 +42,43 @@ export function loadFormTranslations(def: FormDefinition, i18nInstance: i18n) {
28
42
  if (formTranslations) {
29
43
  for (const [lng, resources] of Object.entries(formTranslations)) {
30
44
  i18nInstance.addResourceBundle(lng, 'form', resources, true, true)
45
+
46
+ // Temporary workaround - until we develop a better solution
47
+ if (lng === CY) {
48
+ i18nInstance.addResource(
49
+ lng,
50
+ 'form',
51
+ `listItems.${yesNoListYesItemId}.text`,
52
+ 'Ie'
53
+ )
54
+ i18nInstance.addResource(
55
+ lng,
56
+ 'form',
57
+ `listItems.${yesNoListNoItemId}.text`,
58
+ 'Nage'
59
+ )
60
+ }
61
+ }
62
+ }
63
+ }
64
+
65
+ export function extractMetadataBaseTranslations(
66
+ metadata: FormMetadata | undefined,
67
+ i18nInstance: i18n
68
+ ) {
69
+ if (metadata) {
70
+ const translations = {
71
+ 'form.title': metadata.title,
72
+ 'form.contact.email.address': metadata.contact?.email?.address ?? '',
73
+ 'form.contact.email.responseTime':
74
+ metadata.contact?.email?.responseTime ?? '',
75
+ 'form.contact.online.url': metadata.contact?.online?.url ?? '',
76
+ 'form.contact.online.text': metadata.contact?.online?.text ?? '',
77
+ 'form.contact.phone': metadata.contact?.phone ?? '',
78
+ 'form.submissionGuidance': metadata.submissionGuidance ?? '',
79
+ 'form.privacyNoticeText': metadata.privacyNoticeText ?? '',
80
+ 'form.privacyNoticeUrl': metadata.privacyNoticeUrl ?? ''
31
81
  }
82
+ i18nInstance.addResourceBundle('en-GB', 'form', translations, true, true)
32
83
  }
33
84
  }
@@ -7,13 +7,19 @@ import { type FormDefinitionTranslations } from './types.js'
7
7
 
8
8
  type BaseTranslations = FormDefinitionTranslations[string]
9
9
 
10
- export function extractBaseTranslations(def: FormDefinition): BaseTranslations {
10
+ export function extractBaseTranslations(
11
+ def: FormDefinition | undefined
12
+ ): BaseTranslations {
11
13
  const pages: BaseTranslations['pages'] = {}
12
14
  const components: BaseTranslations['components'] = {}
13
15
  const sections: BaseTranslations['sections'] = {}
14
16
  const listItems: BaseTranslations['listItems'] = {}
15
17
  const form: BaseTranslations['form'] = {}
16
18
 
19
+ if (!def) {
20
+ return { pages, components, sections, listItems, form }
21
+ }
22
+
17
23
  for (const page of def.pages) {
18
24
  if (page.id && page.title) {
19
25
  pages[page.id] = { title: page.title }
@@ -0,0 +1,54 @@
1
+ import { type FormMetadata, type FormStatus } from '@defra/forms-model'
2
+ import Boom from '@hapi/boom'
3
+ import { LRUCache } from 'lru-cache'
4
+
5
+ import { getPluginOptions } from '../helpers.js'
6
+ import { createFormTranslator } from './createFormTranslator.js'
7
+ import { type Translator } from './types.js'
8
+ import { type AnyFormRequest } from '../types.js'
9
+
10
+ const cache = new LRUCache({
11
+ max: 100,
12
+ ttl: 1000 * 60 * 15 // 15 minutes
13
+ })
14
+
15
+ /**
16
+ * Get translator for plugin, for the current form's metadata (as well as the plugin-specific boilerplate).
17
+ * This is an async call so we can read the form definition inside this call.
18
+ * See docs/features/multi-language.md for the language and translation flow overview.
19
+ * @param {AnyFormRequest} request
20
+ * @param {FormMetadata} metadata - the metadata of the form
21
+ * @param {FormStatus} status - the form status to use when retrieving the definition
22
+ * @param {string} language - the language to use for the translator
23
+ */
24
+ export async function getCachedPluginTranslator(
25
+ request: AnyFormRequest,
26
+ metadata: FormMetadata,
27
+ status: FormStatus,
28
+ language: string
29
+ ) {
30
+ const key = `${metadata.id}-${status}-${language}-plugin-meta`
31
+
32
+ if (cache.has(key)) {
33
+ return cache.get(key) as unknown as Translator
34
+ }
35
+
36
+ const { services } = getPluginOptions(request.server)
37
+
38
+ const definition = await services?.formsService.getFormDefinition(
39
+ metadata.id,
40
+ status
41
+ )
42
+
43
+ if (!definition) {
44
+ throw Boom.notFound(
45
+ `FormDefinition not found for form ${metadata.id} and status ${status}`
46
+ )
47
+ }
48
+
49
+ const translator = createFormTranslator(metadata, definition, language)
50
+
51
+ cache.set(key, translator)
52
+
53
+ return translator
54
+ }
@@ -0,0 +1,19 @@
1
+ import { type FormDefinition } from '@defra/forms-model'
2
+
3
+ /**
4
+ * Return a list of available languages.
5
+ * Empty array if only English, or an array of English and Welsh if translations have been defined.
6
+ * @param {FormDefinition} def
7
+ */
8
+ export function getAvailableLanguages(
9
+ def: FormDefinition
10
+ ): { name: string; code: string }[] {
11
+ // @ts-expect-error - dynamic property
12
+ if (def.metadata?.translations?.cy) {
13
+ return [
14
+ { name: 'English', code: 'en-GB' },
15
+ { name: 'Cymraeg', code: 'cy' }
16
+ ]
17
+ }
18
+ return []
19
+ }