@defra/forms-engine-plugin 5.0.0-alpha.1 → 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 (278) hide show
  1. package/.public/javascripts/application.min.js +1 -1
  2. package/.public/javascripts/application.min.js.map +1 -1
  3. package/.public/javascripts/shared.min.js +1 -1
  4. package/.public/javascripts/shared.min.js.map +1 -1
  5. package/.public/stylesheets/application.min.css.map +1 -1
  6. package/.server/client/javascripts/file-upload.js +5 -3
  7. package/.server/client/javascripts/file-upload.js.map +1 -1
  8. package/.server/client/javascripts/geospatial-map.js +31 -26
  9. package/.server/client/javascripts/geospatial-map.js.map +1 -1
  10. package/.server/client/javascripts/location-map.js +9 -1
  11. package/.server/client/javascripts/location-map.js.map +1 -1
  12. package/.server/client/javascripts/maps.d.ts +5 -0
  13. package/.server/client/javascripts/maps.js +6 -0
  14. package/.server/client/javascripts/maps.js.map +1 -0
  15. package/.server/client/javascripts/shared.d.ts +1 -3
  16. package/.server/client/javascripts/shared.js +1 -3
  17. package/.server/client/javascripts/shared.js.map +1 -1
  18. package/.server/client/javascripts/sssi-dataset.d.ts +18 -20
  19. package/.server/client/javascripts/sssi-dataset.js +37 -39
  20. package/.server/client/javascripts/sssi-dataset.js.map +1 -1
  21. package/.server/client/stylesheets/maps.scss +4 -0
  22. package/.server/client/stylesheets/shared.scss +1 -5
  23. package/.server/server/constants.d.ts +2 -0
  24. package/.server/server/constants.js +2 -0
  25. package/.server/server/constants.js.map +1 -1
  26. package/.server/server/plugins/engine/components/AutocompleteField.d.ts +9 -3
  27. package/.server/server/plugins/engine/components/AutocompleteField.js +12 -0
  28. package/.server/server/plugins/engine/components/AutocompleteField.js.map +1 -1
  29. package/.server/server/plugins/engine/components/CheckboxesField.d.ts +4 -1
  30. package/.server/server/plugins/engine/components/CheckboxesField.js +13 -0
  31. package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -1
  32. package/.server/server/plugins/engine/components/ComponentBase.d.ts +1 -0
  33. package/.server/server/plugins/engine/components/ComponentBase.js +2 -0
  34. package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -1
  35. package/.server/server/plugins/engine/components/ComponentCollection.js +11 -6
  36. package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
  37. package/.server/server/plugins/engine/components/DatePartsField.d.ts +6 -3
  38. package/.server/server/plugins/engine/components/DatePartsField.js +12 -7
  39. package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -1
  40. package/.server/server/plugins/engine/components/DeclarationField.d.ts +5 -2
  41. package/.server/server/plugins/engine/components/DeclarationField.js +6 -4
  42. package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -1
  43. package/.server/server/plugins/engine/components/Details.d.ts +1 -0
  44. package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +26 -2
  45. package/.server/server/plugins/engine/components/EastingNorthingField.js +93 -54
  46. package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -1
  47. package/.server/server/plugins/engine/components/EmailAddressField.d.ts +4 -1
  48. package/.server/server/plugins/engine/components/EmailAddressField.js +2 -1
  49. package/.server/server/plugins/engine/components/EmailAddressField.js.map +1 -1
  50. package/.server/server/plugins/engine/components/FileUploadField.d.ts +12 -0
  51. package/.server/server/plugins/engine/components/FileUploadField.js +20 -2
  52. package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
  53. package/.server/server/plugins/engine/components/FormComponent.d.ts +5 -1
  54. package/.server/server/plugins/engine/components/FormComponent.js +5 -2
  55. package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
  56. package/.server/server/plugins/engine/components/GeospatialField.d.ts +1 -0
  57. package/.server/server/plugins/engine/components/GeospatialField.js +1 -1
  58. package/.server/server/plugins/engine/components/GeospatialField.js.map +1 -1
  59. package/.server/server/plugins/engine/components/Html.d.ts +1 -0
  60. package/.server/server/plugins/engine/components/InsetText.d.ts +1 -0
  61. package/.server/server/plugins/engine/components/LatLongField.d.ts +26 -2
  62. package/.server/server/plugins/engine/components/LatLongField.js +85 -48
  63. package/.server/server/plugins/engine/components/LatLongField.js.map +1 -1
  64. package/.server/server/plugins/engine/components/List.d.ts +1 -0
  65. package/.server/server/plugins/engine/components/ListFormComponent.d.ts +1 -0
  66. package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +8 -2
  67. package/.server/server/plugins/engine/components/LocationFieldBase.js +18 -5
  68. package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -1
  69. package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +5 -2
  70. package/.server/server/plugins/engine/components/LocationFieldHelpers.js +10 -11
  71. package/.server/server/plugins/engine/components/LocationFieldHelpers.js.map +1 -1
  72. package/.server/server/plugins/engine/components/Markdown.d.ts +1 -0
  73. package/.server/server/plugins/engine/components/Markdown.js +1 -1
  74. package/.server/server/plugins/engine/components/Markdown.js.map +1 -1
  75. package/.server/server/plugins/engine/components/MonthYearField.d.ts +5 -2
  76. package/.server/server/plugins/engine/components/MonthYearField.js +13 -9
  77. package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -1
  78. package/.server/server/plugins/engine/components/MultilineTextField.d.ts +1 -0
  79. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +2 -1
  80. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js +4 -3
  81. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js.map +1 -1
  82. package/.server/server/plugins/engine/components/NotificationBanner.d.ts +1 -0
  83. package/.server/server/plugins/engine/components/NumberField.d.ts +5 -0
  84. package/.server/server/plugins/engine/components/NumberField.js +16 -0
  85. package/.server/server/plugins/engine/components/NumberField.js.map +1 -1
  86. package/.server/server/plugins/engine/components/OsGridRefField.d.ts +2 -1
  87. package/.server/server/plugins/engine/components/OsGridRefField.js +4 -3
  88. package/.server/server/plugins/engine/components/OsGridRefField.js.map +1 -1
  89. package/.server/server/plugins/engine/components/PaymentField.d.ts +3 -0
  90. package/.server/server/plugins/engine/components/PaymentField.js +17 -6
  91. package/.server/server/plugins/engine/components/PaymentField.js.map +1 -1
  92. package/.server/server/plugins/engine/components/SelectField.d.ts +1 -0
  93. package/.server/server/plugins/engine/components/SelectionControlField.d.ts +1 -0
  94. package/.server/server/plugins/engine/components/TelephoneNumberField.d.ts +1 -0
  95. package/.server/server/plugins/engine/components/UkAddressField.d.ts +1 -0
  96. package/.server/server/plugins/engine/components/UkAddressField.js +23 -8
  97. package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
  98. package/.server/server/plugins/engine/components/YesNoField.d.ts +5 -2
  99. package/.server/server/plugins/engine/components/YesNoField.js +17 -8
  100. package/.server/server/plugins/engine/components/YesNoField.js.map +1 -1
  101. package/.server/server/plugins/engine/components/helpers/components.js +1 -2
  102. package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
  103. package/.server/server/plugins/engine/components/helpers/index.d.ts +7 -0
  104. package/.server/server/plugins/engine/components/helpers/index.js +13 -1
  105. package/.server/server/plugins/engine/components/helpers/index.js.map +1 -1
  106. package/.server/server/plugins/engine/components/types.d.ts +1 -0
  107. package/.server/server/plugins/engine/components/types.js.map +1 -1
  108. package/.server/server/plugins/engine/helpers.d.ts +22 -2
  109. package/.server/server/plugins/engine/helpers.js +44 -5
  110. package/.server/server/plugins/engine/helpers.js.map +1 -1
  111. package/.server/server/plugins/engine/i18n/buildValidationMessages.d.ts +3 -0
  112. package/.server/server/plugins/engine/i18n/buildValidationMessages.js +10 -7
  113. package/.server/server/plugins/engine/i18n/buildValidationMessages.js.map +1 -1
  114. package/.server/server/plugins/engine/i18n/createFormTranslator.d.ts +4 -4
  115. package/.server/server/plugins/engine/i18n/createFormTranslator.js +33 -4
  116. package/.server/server/plugins/engine/i18n/createFormTranslator.js.map +1 -1
  117. package/.server/server/plugins/engine/i18n/extractBaseTranslations.d.ts +1 -1
  118. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js +9 -0
  119. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js.map +1 -1
  120. package/.server/server/plugins/engine/i18n/form.d.ts +13 -0
  121. package/.server/server/plugins/engine/i18n/form.js +35 -0
  122. package/.server/server/plugins/engine/i18n/form.js.map +1 -0
  123. package/.server/server/plugins/engine/i18n/languages.d.ts +10 -0
  124. package/.server/server/plugins/engine/i18n/languages.js +19 -0
  125. package/.server/server/plugins/engine/i18n/languages.js.map +1 -0
  126. package/.server/server/plugins/engine/i18n/translations/cy.json +73 -6
  127. package/.server/server/plugins/engine/i18n/translations/en-GB.json +43 -4
  128. package/.server/server/plugins/engine/i18n/types.d.ts +2 -0
  129. package/.server/server/plugins/engine/i18n/types.js.map +1 -1
  130. package/.server/server/plugins/engine/index.d.ts +4 -0
  131. package/.server/server/plugins/engine/index.js +4 -0
  132. package/.server/server/plugins/engine/index.js.map +1 -1
  133. package/.server/server/plugins/engine/models/FormModel.d.ts +0 -4
  134. package/.server/server/plugins/engine/models/FormModel.js +9 -15
  135. package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
  136. package/.server/server/plugins/engine/models/SummaryViewModel.js +9 -4
  137. package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
  138. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +3 -5
  139. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
  140. package/.server/server/plugins/engine/outputFormatters/human/v1.js +2 -1
  141. package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
  142. package/.server/server/plugins/engine/outputFormatters/machine/v2.d.ts +2 -0
  143. package/.server/server/plugins/engine/outputFormatters/machine/v2.js +2 -0
  144. package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -1
  145. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.d.ts +1 -1
  146. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +22 -9
  147. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
  148. package/.server/server/plugins/engine/pageControllers/QuestionPageController.d.ts +1 -1
  149. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +7 -3
  150. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
  151. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js +3 -4
  152. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js.map +1 -1
  153. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +10 -4
  154. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
  155. package/.server/server/plugins/engine/pageControllers/helpers/submission.d.ts +1 -1
  156. package/.server/server/plugins/engine/pageControllers/helpers/submission.js +3 -3
  157. package/.server/server/plugins/engine/pageControllers/helpers/submission.js.map +1 -1
  158. package/.server/server/plugins/engine/pageControllers/validationOptions.js +23 -2
  159. package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
  160. package/.server/server/plugins/engine/types/schema.js +1 -0
  161. package/.server/server/plugins/engine/types/schema.js.map +1 -1
  162. package/.server/server/plugins/engine/types.d.ts +1 -0
  163. package/.server/server/plugins/engine/types.js.map +1 -1
  164. package/.server/server/plugins/engine/views/components/fileuploadfield.html +1 -1
  165. package/.server/server/plugins/engine/views/components/multilinetextfield.html +12 -1
  166. package/.server/server/plugins/engine/views/components/paymentfield.html +1 -1
  167. package/.server/server/plugins/engine/views/components/ukaddressfield.html +1 -1
  168. package/.server/server/plugins/engine/views/partials/preview-banner.html +3 -1
  169. package/.server/server/plugins/nunjucks/filters/applyUrlParam.d.ts +9 -0
  170. package/.server/server/plugins/nunjucks/filters/applyUrlParam.js +17 -0
  171. package/.server/server/plugins/nunjucks/filters/applyUrlParam.js.map +1 -0
  172. package/.server/server/plugins/nunjucks/filters/applyUrlParam.test.js +17 -0
  173. package/.server/server/plugins/nunjucks/filters/applyUrlParam.test.js.map +1 -0
  174. package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
  175. package/.server/server/plugins/nunjucks/filters/index.d.ts +1 -0
  176. package/.server/server/plugins/nunjucks/filters/index.js +1 -0
  177. package/.server/server/plugins/nunjucks/filters/index.js.map +1 -1
  178. package/.server/server/plugins/payment/helper.d.ts +11 -1
  179. package/.server/server/plugins/payment/helper.js +18 -2
  180. package/.server/server/plugins/payment/helper.js.map +1 -1
  181. package/.server/server/plugins/payment/helper.test.js +2 -1
  182. package/.server/server/plugins/payment/helper.test.js.map +1 -1
  183. package/.server/server/plugins/payment/service.d.ts +2 -1
  184. package/.server/server/plugins/payment/service.js +5 -2
  185. package/.server/server/plugins/payment/service.js.map +1 -1
  186. package/.server/server/plugins/payment/service.test.js +7 -3
  187. package/.server/server/plugins/payment/service.test.js.map +1 -1
  188. package/.server/server/plugins/payment/types.d.ts +4 -0
  189. package/.server/server/plugins/payment/types.js +1 -0
  190. package/.server/server/plugins/payment/types.js.map +1 -1
  191. package/.server/server/plugins/postcode-lookup/models/index.d.ts +249 -3
  192. package/.server/server/plugins/postcode-lookup/models/index.js +87 -33
  193. package/.server/server/plugins/postcode-lookup/models/index.js.map +1 -1
  194. package/.server/server/plugins/postcode-lookup/routes/index.d.ts +15 -1
  195. package/.server/server/plugins/postcode-lookup/routes/index.js +47 -15
  196. package/.server/server/plugins/postcode-lookup/routes/index.js.map +1 -1
  197. package/.server/server/plugins/postcode-lookup/routes/index.test.js +84 -0
  198. package/.server/server/plugins/postcode-lookup/routes/index.test.js.map +1 -0
  199. package/.server/server/plugins/postcode-lookup/types.d.ts +12 -0
  200. package/.server/server/plugins/postcode-lookup/types.js +6 -1
  201. package/.server/server/plugins/postcode-lookup/types.js.map +1 -1
  202. package/.server/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  203. package/.server/server/utils/type-utils.d.ts +1 -2
  204. package/.server/server/utils/type-utils.js +0 -3
  205. package/.server/server/utils/type-utils.js.map +1 -1
  206. package/package.json +8 -2
  207. package/src/client/javascripts/file-upload.js +10 -3
  208. package/src/client/javascripts/geospatial-map.js +32 -30
  209. package/src/client/javascripts/location-map.js +7 -1
  210. package/src/client/javascripts/maps.js +5 -0
  211. package/src/client/javascripts/shared.js +1 -3
  212. package/src/client/javascripts/sssi-dataset.js +39 -41
  213. package/src/client/stylesheets/maps.scss +4 -0
  214. package/src/client/stylesheets/shared.scss +1 -5
  215. package/src/server/constants.js +2 -0
  216. package/src/server/plugins/engine/components/AutocompleteField.ts +13 -0
  217. package/src/server/plugins/engine/components/CheckboxesField.ts +13 -1
  218. package/src/server/plugins/engine/components/ComponentBase.ts +2 -0
  219. package/src/server/plugins/engine/components/ComponentCollection.ts +16 -11
  220. package/src/server/plugins/engine/components/DatePartsField.ts +20 -9
  221. package/src/server/plugins/engine/components/DeclarationField.ts +7 -6
  222. package/src/server/plugins/engine/components/EastingNorthingField.ts +154 -89
  223. package/src/server/plugins/engine/components/EmailAddressField.ts +2 -1
  224. package/src/server/plugins/engine/components/FileUploadField.ts +21 -2
  225. package/src/server/plugins/engine/components/FormComponent.ts +6 -5
  226. package/src/server/plugins/engine/components/GeospatialField.ts +6 -1
  227. package/src/server/plugins/engine/components/LatLongField.ts +128 -58
  228. package/src/server/plugins/engine/components/LocationFieldBase.ts +23 -6
  229. package/src/server/plugins/engine/components/LocationFieldHelpers.ts +14 -11
  230. package/src/server/plugins/engine/components/Markdown.ts +2 -3
  231. package/src/server/plugins/engine/components/MonthYearField.ts +20 -15
  232. package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +9 -3
  233. package/src/server/plugins/engine/components/NumberField.ts +21 -1
  234. package/src/server/plugins/engine/components/OsGridRefField.ts +9 -3
  235. package/src/server/plugins/engine/components/PaymentField.ts +15 -5
  236. package/src/server/plugins/engine/components/UkAddressField.ts +30 -7
  237. package/src/server/plugins/engine/components/YesNoField.ts +17 -9
  238. package/src/server/plugins/engine/components/helpers/components.ts +1 -2
  239. package/src/server/plugins/engine/components/helpers/index.ts +19 -0
  240. package/src/server/plugins/engine/components/types.ts +1 -0
  241. package/src/server/plugins/engine/helpers.ts +52 -5
  242. package/src/server/plugins/engine/i18n/buildValidationMessages.ts +10 -7
  243. package/src/server/plugins/engine/i18n/createFormTranslator.ts +62 -11
  244. package/src/server/plugins/engine/i18n/extractBaseTranslations.ts +7 -1
  245. package/src/server/plugins/engine/i18n/form.ts +54 -0
  246. package/src/server/plugins/engine/i18n/languages.ts +19 -0
  247. package/src/server/plugins/engine/i18n/translations/cy.json +73 -6
  248. package/src/server/plugins/engine/i18n/translations/en-GB.json +43 -4
  249. package/src/server/plugins/engine/i18n/types.ts +2 -0
  250. package/src/server/plugins/engine/index.ts +7 -0
  251. package/src/server/plugins/engine/models/FormModel.ts +9 -15
  252. package/src/server/plugins/engine/models/SummaryViewModel.ts +6 -5
  253. package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +3 -6
  254. package/src/server/plugins/engine/outputFormatters/human/v1.ts +2 -1
  255. package/src/server/plugins/engine/outputFormatters/machine/v2.ts +3 -0
  256. package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +18 -8
  257. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +10 -5
  258. package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +2 -2
  259. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +15 -4
  260. package/src/server/plugins/engine/pageControllers/helpers/submission.ts +6 -3
  261. package/src/server/plugins/engine/pageControllers/validationOptions.ts +27 -2
  262. package/src/server/plugins/engine/types/schema.ts +1 -0
  263. package/src/server/plugins/engine/types.ts +1 -0
  264. package/src/server/plugins/engine/views/components/fileuploadfield.html +1 -1
  265. package/src/server/plugins/engine/views/components/multilinetextfield.html +12 -1
  266. package/src/server/plugins/engine/views/components/paymentfield.html +1 -1
  267. package/src/server/plugins/engine/views/components/ukaddressfield.html +1 -1
  268. package/src/server/plugins/engine/views/partials/preview-banner.html +3 -1
  269. package/src/server/plugins/nunjucks/filters/applyUrlParam.js +17 -0
  270. package/src/server/plugins/nunjucks/filters/index.js +1 -0
  271. package/src/server/plugins/payment/helper.js +22 -2
  272. package/src/server/plugins/payment/service.js +6 -2
  273. package/src/server/plugins/payment/types.js +1 -0
  274. package/src/server/plugins/postcode-lookup/models/index.js +75 -43
  275. package/src/server/plugins/postcode-lookup/routes/index.js +73 -16
  276. package/src/server/plugins/postcode-lookup/types.js +6 -1
  277. package/src/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  278. package/src/server/utils/type-utils.ts +1 -11
@@ -11,14 +11,15 @@ import {
11
11
  } from './FormComponent.js'
12
12
  import { addClassOptionIfNone } from './helpers/index.js'
13
13
  import { type RenderContext } from './types.js'
14
+ import { buildValidationMessages } from '../i18n/buildValidationMessages.js'
14
15
  import { messageTemplate } from '../pageControllers/validationOptions.js'
16
+ import { type Translator } from '../types/index.js'
15
17
  import {
16
18
  type ErrorMessageTemplateList,
17
19
  type FormState,
18
20
  type FormStateValue,
19
21
  type FormSubmissionState
20
22
  } from '../types.js'
21
- import { convertToLanguageMessages } from '../../../utils/type-utils.js'
22
23
 
23
24
  interface LocationFieldOptions {
24
25
  instructionText?: string
@@ -43,7 +44,9 @@ export abstract class LocationFieldBase extends FormComponent {
43
44
  declare stateSchema: StringSchema
44
45
  instructionText?: string
45
46
 
46
- protected abstract getValidationConfig(): ValidationConfig
47
+ protected abstract getValidationConfig(
48
+ translator: Translator | undefined
49
+ ): ValidationConfig
47
50
  protected abstract getErrorTemplates(): {
48
51
  type: string
49
52
  template: JoiExpression
@@ -61,14 +64,14 @@ export abstract class LocationFieldBase extends FormComponent {
61
64
 
62
65
  addClassOptionIfNone(locationOptions, 'govuk-input--width-10')
63
66
 
64
- const config = this.getValidationConfig()
67
+ const config = this.getValidationConfig(undefined)
65
68
  const requiredMessage = config.requiredMessage ?? messageTemplate.required
66
69
 
67
- const messages = convertToLanguageMessages({
70
+ const messages = {
68
71
  'any.required': requiredMessage,
69
72
  'string.empty': requiredMessage,
70
73
  'string.pattern.base': config.patternErrorMessage
71
- })
74
+ } as LanguageMessages
72
75
 
73
76
  let formSchema = joi
74
77
  .string()
@@ -131,8 +134,22 @@ export abstract class LocationFieldBase extends FormComponent {
131
134
  return viewModel
132
135
  }
133
136
 
137
+ getValidationMessagesOverride(translator: Translator) {
138
+ const { t } = translator
139
+ const config = this.getValidationConfig(translator)
140
+ return {
141
+ [this.name]: {
142
+ 'any.required':
143
+ config.requiredMessage ?? buildValidationMessages(t).objectRequired,
144
+ 'string.empty':
145
+ config.requiredMessage ?? buildValidationMessages(t).objectRequired,
146
+ 'string.pattern.base': config.patternErrorMessage
147
+ } as LanguageMessages
148
+ }
149
+ }
150
+
134
151
  getAllPossibleErrors(): ErrorMessageTemplateList {
135
- const config = this.getValidationConfig()
152
+ const config = this.getValidationConfig(undefined)
136
153
 
137
154
  return {
138
155
  baseErrors: [
@@ -11,6 +11,7 @@ import {
11
11
  type RenderContext,
12
12
  type ViewModel
13
13
  } from './types.js'
14
+ import { type Translator } from '../i18n/types.js'
14
15
  import {
15
16
  type FormPayload,
16
17
  type FormSubmissionError,
@@ -29,25 +30,25 @@ export type LocationField =
29
30
  * - "latitude must be..." -> "latitude must be..."
30
31
  */
31
32
  function lowercaseMessageStart(message: string): string {
32
- if (message.startsWith('Enter ')) {
33
- return 'enter' + message.slice(5)
34
- }
35
-
36
- // Lowercase first character for any other message
33
+ // Lowercase first character for a message
37
34
  return message.charAt(0).toLowerCase() + message.slice(1)
38
35
  }
39
36
 
40
- export function joinWithAnd(items: string[]): string {
37
+ export function joinWithAnd(items: string[], translator: Translator): string {
38
+ const { t } = translator
41
39
  if (items.length === 2) {
42
- return `${items[0]} and ${items[1]}`
40
+ return `${items[0]} ${t('common.and')} ${items[1]}`
43
41
  }
44
42
 
45
43
  const leading = items.slice(0, -1).join(', ')
46
44
  const last = items[items.length - 1]
47
- return `${leading} and ${last}`
45
+ return `${leading} ${t('common.and')} ${last}`
48
46
  }
49
47
 
50
- export function formatErrorList(messages: string[]): string {
48
+ export function formatErrorList(
49
+ messages: string[],
50
+ translator: Translator
51
+ ): string {
51
52
  if (!messages.length) {
52
53
  return ''
53
54
  }
@@ -60,7 +61,7 @@ export function formatErrorList(messages: string[]): string {
60
61
  index === 0 ? msg : lowercaseMessageStart(msg)
61
62
  )
62
63
 
63
- return joinWithAnd(formattedMessages)
64
+ return joinWithAnd(formattedMessages, translator)
64
65
  }
65
66
 
66
67
  export function mergeCssClasses(...classNames: (string | undefined)[]) {
@@ -172,7 +173,9 @@ export function getLocationFieldViewModel(
172
173
  if (hasFieldErrors) {
173
174
  viewModel.errorMessage = {
174
175
  text:
175
- fieldErrors.length === 1 ? fieldErrors[0] : formatErrorList(fieldErrors)
176
+ fieldErrors.length === 1
177
+ ? fieldErrors[0]
178
+ : formatErrorList(fieldErrors, context.translator)
176
179
  }
177
180
  }
178
181
 
@@ -1,4 +1,4 @@
1
- import { type ComponentDef, type MarkdownComponent } from '@defra/forms-model'
1
+ import { type MarkdownComponent } from '@defra/forms-model'
2
2
 
3
3
  import { ComponentBase } from './ComponentBase.js'
4
4
  import { type RenderContext } from './types.js'
@@ -28,8 +28,7 @@ export class Markdown extends ComponentBase {
28
28
 
29
29
  return {
30
30
  ...viewModel,
31
- content:
32
- tComponent(this as unknown as ComponentDef, 'content') || content,
31
+ content: tComponent(this.def, 'content') || content,
33
32
  headerStartLevel: this.headerStartLevel
34
33
  }
35
34
  }
@@ -30,7 +30,7 @@ import {
30
30
  type FormStateValue,
31
31
  type FormSubmissionState
32
32
  } from '../types.js'
33
- import { convertToLanguageMessages } from '../../../utils/type-utils.js'
33
+ import { formatDateForLanguage } from '../../payment/helper.js'
34
34
 
35
35
  export class MonthYearField extends FormComponent {
36
36
  declare options: MonthYearFieldComponent['options']
@@ -48,16 +48,15 @@ export class MonthYearField extends FormComponent {
48
48
 
49
49
  const isRequired = options.required !== false
50
50
 
51
- const customValidationMessages: LanguageMessages =
52
- convertToLanguageMessages({
53
- 'any.required': messageTemplate.objectMissing,
54
- 'number.base': messageTemplate.objectMissing,
55
- 'number.precision': messageTemplate.dateFormat,
56
- 'number.integer': messageTemplate.dateFormat,
57
- 'number.unsafe': messageTemplate.dateFormat,
58
- 'number.min': messageTemplate.dateFormat,
59
- 'number.max': messageTemplate.dateFormat
60
- })
51
+ const customValidationMessages = {
52
+ 'any.required': messageTemplate.objectMissing,
53
+ 'number.base': messageTemplate.objectMissing,
54
+ 'number.precision': messageTemplate.dateFormat,
55
+ 'number.integer': messageTemplate.dateFormat,
56
+ 'number.unsafe': messageTemplate.dateFormat,
57
+ 'number.min': messageTemplate.dateFormat,
58
+ 'number.max': messageTemplate.dateFormat
59
+ } as LanguageMessages
61
60
 
62
61
  this.collection = new ComponentCollection(
63
62
  [
@@ -105,16 +104,18 @@ export class MonthYearField extends FormComponent {
105
104
 
106
105
  getDisplayStringFromFormValue(
107
106
  value: MonthYearState | undefined,
108
- _translator: Translator
107
+ translator: Translator
109
108
  ): string {
110
109
  if (!value) {
111
110
  return ''
112
111
  }
113
112
 
114
113
  const date = new Date()
114
+ // Force to first day of month in case current date was say 31st and specified month has fewer than 31 days
115
+ date.setDate(1)
115
116
  date.setMonth(value.month - 1)
116
117
 
117
- const monthString = date.toLocaleString('default', { month: 'long' })
118
+ const monthString = formatDateForLanguage(date, 'LLLL', translator.language)
118
119
  return `${monthString} ${value.year}`
119
120
  }
120
121
 
@@ -155,7 +156,7 @@ export class MonthYearField extends FormComponent {
155
156
 
156
157
  getValidationMessagesOverride(translator: Translator) {
157
158
  const { t } = translator
158
- return convertToLanguageMessages({
159
+ const messages = {
159
160
  'any.required': buildValidationMessages(t).objectMissing,
160
161
  'number.base': buildValidationMessages(t).objectMissing,
161
162
  'number.precision': buildValidationMessages(t).dateFormat,
@@ -163,7 +164,11 @@ export class MonthYearField extends FormComponent {
163
164
  'number.unsafe': buildValidationMessages(t).dateFormat,
164
165
  'number.min': buildValidationMessages(t).dateFormat,
165
166
  'number.max': buildValidationMessages(t).dateFormat
166
- })
167
+ } as LanguageMessages
168
+ return {
169
+ [`${this.name}__month`]: messages,
170
+ [`${this.name}__year`]: messages
171
+ }
167
172
  }
168
173
 
169
174
  getViewModel(context: RenderContext) {
@@ -1,14 +1,16 @@
1
1
  import { type NationalGridFieldNumberFieldComponent } from '@defra/forms-model'
2
2
 
3
+ import { EN_GB } from '../../../constants.js'
3
4
  import { LocationFieldBase } from './LocationFieldBase.js'
4
5
  import { createLowerFirstExpression } from './helpers/index.js'
5
6
  import { t } from '../i18n/index.js'
7
+ import { type Translator } from '../i18n/types.js'
6
8
  import { type ErrorMessageTemplateList } from '../types.js'
7
9
 
8
10
  export class NationalGridFieldNumberField extends LocationFieldBase {
9
11
  declare options: NationalGridFieldNumberFieldComponent['options']
10
12
 
11
- protected getValidationConfig() {
13
+ protected getValidationConfig(translator: Translator | undefined) {
12
14
  // Regex for OS national grid field references (NGFR)
13
15
  // Validates specific valid OS grid letter combinations with:
14
16
  // - 2 letters & 8 digits in 2 blocks of 4 e.g. ST 6789 6789
@@ -18,10 +20,14 @@ export class NationalGridFieldNumberField extends LocationFieldBase {
18
20
  return {
19
21
  pattern,
20
22
  patternErrorMessage: createLowerFirstExpression(
21
- t('components.nationalGridField.pattern', 'en-GB')
23
+ translator
24
+ ? translator.t('components.nationalGridField.pattern')
25
+ : t('components.nationalGridField.pattern', EN_GB)
22
26
  ),
23
27
  requiredMessage: createLowerFirstExpression(
24
- t('components.nationalGridField.required', 'en-GB')
28
+ translator
29
+ ? translator.t('components.nationalGridField.required')
30
+ : t('components.nationalGridField.required', EN_GB)
25
31
  )
26
32
  }
27
33
  }
@@ -1,12 +1,18 @@
1
1
  import { type NumberFieldComponent } from '@defra/forms-model'
2
- import joi, { type CustomValidator, type NumberSchema } from 'joi'
2
+ import joi, {
3
+ type CustomValidator,
4
+ type LanguageMessages,
5
+ type NumberSchema
6
+ } from 'joi'
3
7
 
4
8
  import {
5
9
  FormComponent,
6
10
  isFormValue
7
11
  } from './FormComponent.js'
8
12
  import { type RenderContext } from './types.js'
13
+ import { buildValidationMessages } from '../i18n/buildValidationMessages.js'
9
14
  import { messageTemplate } from '../pageControllers/validationOptions.js'
15
+ import { type Translator } from '../types/index.js'
10
16
  import {
11
17
  type ErrorMessageTemplateList,
12
18
  type FormState,
@@ -130,6 +136,20 @@ export class NumberField extends FormComponent {
130
136
  return NumberField.isNumber(value)
131
137
  }
132
138
 
139
+ getValidationMessagesOverride(translator: Translator) {
140
+ const { t } = translator
141
+ return {
142
+ [this.name]: {
143
+ 'any.required': buildValidationMessages(t).objectRequired,
144
+ 'number.base': buildValidationMessages(t).objectMissing,
145
+ 'number.precision': buildValidationMessages(t).numberPrecision,
146
+ 'number.integer': buildValidationMessages(t).numberInteger,
147
+ 'number.min': buildValidationMessages(t).numberMin,
148
+ 'number.max': buildValidationMessages(t).numberMax
149
+ } as LanguageMessages
150
+ }
151
+ }
152
+
133
153
  /**
134
154
  * For error preview page that shows all possible errors on a component
135
155
  */
@@ -1,14 +1,16 @@
1
1
  import { type OsGridRefFieldComponent } from '@defra/forms-model'
2
2
 
3
+ import { EN_GB } from '../../../constants.js'
3
4
  import { LocationFieldBase } from './LocationFieldBase.js'
4
5
  import { createLowerFirstExpression } from './helpers/index.js'
5
6
  import { t } from '../i18n/index.js'
7
+ import { type Translator } from '../types/index.js'
6
8
  import { type ErrorMessageTemplateList } from '../types.js'
7
9
 
8
10
  export class OsGridRefField extends LocationFieldBase {
9
11
  declare options: OsGridRefFieldComponent['options']
10
12
 
11
- protected getValidationConfig() {
13
+ protected getValidationConfig(translator: Translator | undefined) {
12
14
  // Regex for OS national grid references (NGR)
13
15
  // Validates specific valid OS grid letter combinations with:
14
16
  // - 2 letters & 6 digits in 2 blocks of 3 e.g. ST 678 678
@@ -21,10 +23,14 @@ export class OsGridRefField extends LocationFieldBase {
21
23
  return {
22
24
  pattern,
23
25
  patternErrorMessage: createLowerFirstExpression(
24
- t('components.osGridRefField.pattern', 'en-GB')
26
+ translator
27
+ ? translator.t('components.osGridRefField.pattern')
28
+ : t('components.osGridRefField.pattern', EN_GB)
25
29
  ),
26
30
  requiredMessage: createLowerFirstExpression(
27
- t('components.osGridRefField.required', 'en-GB')
31
+ translator
32
+ ? translator.t('components.osGridRefField.required')
33
+ : t('components.osGridRefField.required', EN_GB)
28
34
  )
29
35
  }
30
36
  }
@@ -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