@defra/forms-engine-plugin 5.0.0-alpha.1 → 5.0.0-alpha.11

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 (301) hide show
  1. package/.public/javascripts/application.min.js +1 -1
  2. package/.public/javascripts/application.min.js.LICENSE.txt +7 -0
  3. package/.public/javascripts/application.min.js.map +1 -1
  4. package/.public/javascripts/shared.min.js +1 -1
  5. package/.public/javascripts/shared.min.js.LICENSE.txt +7 -0
  6. package/.public/javascripts/shared.min.js.map +1 -1
  7. package/.public/stylesheets/application.min.css.map +1 -1
  8. package/.server/client/javascripts/file-upload.js +6 -3
  9. package/.server/client/javascripts/file-upload.js.map +1 -1
  10. package/.server/client/javascripts/geospatial-map.js +10 -31
  11. package/.server/client/javascripts/geospatial-map.js.map +1 -1
  12. package/.server/client/javascripts/govuk.js +2 -1
  13. package/.server/client/javascripts/govuk.js.map +1 -1
  14. package/.server/client/javascripts/location-map.js +11 -2
  15. package/.server/client/javascripts/location-map.js.map +1 -1
  16. package/.server/client/javascripts/map.d.ts +6 -0
  17. package/.server/client/javascripts/map.js +37 -0
  18. package/.server/client/javascripts/map.js.map +1 -1
  19. package/.server/client/javascripts/maps.d.ts +5 -0
  20. package/.server/client/javascripts/maps.js +6 -0
  21. package/.server/client/javascripts/maps.js.map +1 -0
  22. package/.server/client/javascripts/shared.d.ts +1 -3
  23. package/.server/client/javascripts/shared.js +1 -3
  24. package/.server/client/javascripts/shared.js.map +1 -1
  25. package/.server/client/javascripts/sssi-dataset.d.ts +18 -20
  26. package/.server/client/javascripts/sssi-dataset.js +37 -39
  27. package/.server/client/javascripts/sssi-dataset.js.map +1 -1
  28. package/.server/client/stylesheets/maps.scss +4 -0
  29. package/.server/client/stylesheets/shared.scss +1 -5
  30. package/.server/server/constants.d.ts +2 -0
  31. package/.server/server/constants.js +2 -0
  32. package/.server/server/constants.js.map +1 -1
  33. package/.server/server/plugins/engine/components/AutocompleteField.d.ts +9 -3
  34. package/.server/server/plugins/engine/components/AutocompleteField.js +12 -0
  35. package/.server/server/plugins/engine/components/AutocompleteField.js.map +1 -1
  36. package/.server/server/plugins/engine/components/CheckboxesField.d.ts +4 -1
  37. package/.server/server/plugins/engine/components/CheckboxesField.js +13 -0
  38. package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -1
  39. package/.server/server/plugins/engine/components/ComponentBase.d.ts +1 -0
  40. package/.server/server/plugins/engine/components/ComponentBase.js +2 -0
  41. package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -1
  42. package/.server/server/plugins/engine/components/ComponentCollection.js +11 -6
  43. package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
  44. package/.server/server/plugins/engine/components/DatePartsField.d.ts +6 -3
  45. package/.server/server/plugins/engine/components/DatePartsField.js +12 -7
  46. package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -1
  47. package/.server/server/plugins/engine/components/DeclarationField.d.ts +5 -2
  48. package/.server/server/plugins/engine/components/DeclarationField.js +6 -4
  49. package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -1
  50. package/.server/server/plugins/engine/components/Details.d.ts +1 -0
  51. package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +29 -2
  52. package/.server/server/plugins/engine/components/EastingNorthingField.js +110 -54
  53. package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -1
  54. package/.server/server/plugins/engine/components/EmailAddressField.d.ts +4 -1
  55. package/.server/server/plugins/engine/components/EmailAddressField.js +2 -1
  56. package/.server/server/plugins/engine/components/EmailAddressField.js.map +1 -1
  57. package/.server/server/plugins/engine/components/FileUploadField.d.ts +12 -0
  58. package/.server/server/plugins/engine/components/FileUploadField.js +23 -3
  59. package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
  60. package/.server/server/plugins/engine/components/FormComponent.d.ts +5 -1
  61. package/.server/server/plugins/engine/components/FormComponent.js +5 -2
  62. package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
  63. package/.server/server/plugins/engine/components/GeospatialField.d.ts +1 -0
  64. package/.server/server/plugins/engine/components/GeospatialField.js +1 -1
  65. package/.server/server/plugins/engine/components/GeospatialField.js.map +1 -1
  66. package/.server/server/plugins/engine/components/Html.d.ts +1 -0
  67. package/.server/server/plugins/engine/components/InsetText.d.ts +1 -0
  68. package/.server/server/plugins/engine/components/LatLongField.d.ts +28 -2
  69. package/.server/server/plugins/engine/components/LatLongField.js +85 -48
  70. package/.server/server/plugins/engine/components/LatLongField.js.map +1 -1
  71. package/.server/server/plugins/engine/components/List.d.ts +1 -0
  72. package/.server/server/plugins/engine/components/ListFormComponent.d.ts +1 -0
  73. package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +8 -2
  74. package/.server/server/plugins/engine/components/LocationFieldBase.js +18 -5
  75. package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -1
  76. package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +8 -3
  77. package/.server/server/plugins/engine/components/LocationFieldHelpers.js +13 -12
  78. package/.server/server/plugins/engine/components/LocationFieldHelpers.js.map +1 -1
  79. package/.server/server/plugins/engine/components/Markdown.d.ts +1 -0
  80. package/.server/server/plugins/engine/components/Markdown.js +1 -1
  81. package/.server/server/plugins/engine/components/Markdown.js.map +1 -1
  82. package/.server/server/plugins/engine/components/MonthYearField.d.ts +5 -2
  83. package/.server/server/plugins/engine/components/MonthYearField.js +13 -9
  84. package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -1
  85. package/.server/server/plugins/engine/components/MultilineTextField.d.ts +1 -0
  86. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +2 -1
  87. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js +4 -3
  88. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js.map +1 -1
  89. package/.server/server/plugins/engine/components/NotificationBanner.d.ts +1 -0
  90. package/.server/server/plugins/engine/components/NumberField.d.ts +5 -0
  91. package/.server/server/plugins/engine/components/NumberField.js +16 -0
  92. package/.server/server/plugins/engine/components/NumberField.js.map +1 -1
  93. package/.server/server/plugins/engine/components/OsGridRefField.d.ts +2 -1
  94. package/.server/server/plugins/engine/components/OsGridRefField.js +4 -3
  95. package/.server/server/plugins/engine/components/OsGridRefField.js.map +1 -1
  96. package/.server/server/plugins/engine/components/PaymentField.d.ts +3 -0
  97. package/.server/server/plugins/engine/components/PaymentField.js +17 -6
  98. package/.server/server/plugins/engine/components/PaymentField.js.map +1 -1
  99. package/.server/server/plugins/engine/components/SelectField.d.ts +1 -0
  100. package/.server/server/plugins/engine/components/SelectionControlField.d.ts +1 -0
  101. package/.server/server/plugins/engine/components/TelephoneNumberField.d.ts +1 -0
  102. package/.server/server/plugins/engine/components/UkAddressField.d.ts +1 -0
  103. package/.server/server/plugins/engine/components/UkAddressField.js +23 -8
  104. package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
  105. package/.server/server/plugins/engine/components/YesNoField.d.ts +5 -2
  106. package/.server/server/plugins/engine/components/YesNoField.js +17 -8
  107. package/.server/server/plugins/engine/components/YesNoField.js.map +1 -1
  108. package/.server/server/plugins/engine/components/helpers/components.js +1 -2
  109. package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
  110. package/.server/server/plugins/engine/components/helpers/geospatial.d.ts +3 -1
  111. package/.server/server/plugins/engine/components/helpers/geospatial.js +32 -0
  112. package/.server/server/plugins/engine/components/helpers/geospatial.js.map +1 -1
  113. package/.server/server/plugins/engine/components/helpers/index.d.ts +7 -0
  114. package/.server/server/plugins/engine/components/helpers/index.js +13 -1
  115. package/.server/server/plugins/engine/components/helpers/index.js.map +1 -1
  116. package/.server/server/plugins/engine/components/types.d.ts +1 -0
  117. package/.server/server/plugins/engine/components/types.js.map +1 -1
  118. package/.server/server/plugins/engine/helpers.d.ts +22 -2
  119. package/.server/server/plugins/engine/helpers.js +44 -5
  120. package/.server/server/plugins/engine/helpers.js.map +1 -1
  121. package/.server/server/plugins/engine/i18n/buildValidationMessages.d.ts +3 -0
  122. package/.server/server/plugins/engine/i18n/buildValidationMessages.js +10 -7
  123. package/.server/server/plugins/engine/i18n/buildValidationMessages.js.map +1 -1
  124. package/.server/server/plugins/engine/i18n/createFormTranslator.d.ts +4 -4
  125. package/.server/server/plugins/engine/i18n/createFormTranslator.js +33 -4
  126. package/.server/server/plugins/engine/i18n/createFormTranslator.js.map +1 -1
  127. package/.server/server/plugins/engine/i18n/extractBaseTranslations.d.ts +1 -1
  128. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js +9 -0
  129. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js.map +1 -1
  130. package/.server/server/plugins/engine/i18n/form.d.ts +13 -0
  131. package/.server/server/plugins/engine/i18n/form.js +35 -0
  132. package/.server/server/plugins/engine/i18n/form.js.map +1 -0
  133. package/.server/server/plugins/engine/i18n/languages.d.ts +10 -0
  134. package/.server/server/plugins/engine/i18n/languages.js +19 -0
  135. package/.server/server/plugins/engine/i18n/languages.js.map +1 -0
  136. package/.server/server/plugins/engine/i18n/translations/cy.json +85 -8
  137. package/.server/server/plugins/engine/i18n/translations/en-GB.json +55 -6
  138. package/.server/server/plugins/engine/i18n/types.d.ts +2 -0
  139. package/.server/server/plugins/engine/i18n/types.js.map +1 -1
  140. package/.server/server/plugins/engine/index.d.ts +4 -0
  141. package/.server/server/plugins/engine/index.js +4 -0
  142. package/.server/server/plugins/engine/index.js.map +1 -1
  143. package/.server/server/plugins/engine/models/FormModel.d.ts +0 -4
  144. package/.server/server/plugins/engine/models/FormModel.js +9 -15
  145. package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
  146. package/.server/server/plugins/engine/models/SummaryViewModel.js +9 -4
  147. package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
  148. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +3 -5
  149. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
  150. package/.server/server/plugins/engine/outputFormatters/human/v1.js +2 -1
  151. package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
  152. package/.server/server/plugins/engine/outputFormatters/machine/v2.d.ts +2 -0
  153. package/.server/server/plugins/engine/outputFormatters/machine/v2.js +2 -0
  154. package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -1
  155. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.d.ts +7 -1
  156. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +56 -10
  157. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
  158. package/.server/server/plugins/engine/pageControllers/QuestionPageController.d.ts +1 -1
  159. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +7 -3
  160. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
  161. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js +3 -4
  162. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js.map +1 -1
  163. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +10 -4
  164. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
  165. package/.server/server/plugins/engine/pageControllers/helpers/submission.d.ts +1 -1
  166. package/.server/server/plugins/engine/pageControllers/helpers/submission.js +3 -3
  167. package/.server/server/plugins/engine/pageControllers/helpers/submission.js.map +1 -1
  168. package/.server/server/plugins/engine/pageControllers/validationOptions.js +23 -2
  169. package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
  170. package/.server/server/plugins/engine/types/schema.js +1 -0
  171. package/.server/server/plugins/engine/types/schema.js.map +1 -1
  172. package/.server/server/plugins/engine/types.d.ts +5 -0
  173. package/.server/server/plugins/engine/types.js.map +1 -1
  174. package/.server/server/plugins/engine/views/components/_location-field-base.html +2 -1
  175. package/.server/server/plugins/engine/views/components/fileuploadfield.html +1 -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/file-upload.html +1 -1
  180. package/.server/server/plugins/engine/views/partials/preview-banner.html +3 -1
  181. package/.server/server/plugins/nunjucks/filters/applyUrlParam.d.ts +9 -0
  182. package/.server/server/plugins/nunjucks/filters/applyUrlParam.js +17 -0
  183. package/.server/server/plugins/nunjucks/filters/applyUrlParam.js.map +1 -0
  184. package/.server/server/plugins/nunjucks/filters/applyUrlParam.test.js +17 -0
  185. package/.server/server/plugins/nunjucks/filters/applyUrlParam.test.js.map +1 -0
  186. package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
  187. package/.server/server/plugins/nunjucks/filters/index.d.ts +1 -0
  188. package/.server/server/plugins/nunjucks/filters/index.js +1 -0
  189. package/.server/server/plugins/nunjucks/filters/index.js.map +1 -1
  190. package/.server/server/plugins/payment/helper.d.ts +11 -1
  191. package/.server/server/plugins/payment/helper.js +18 -2
  192. package/.server/server/plugins/payment/helper.js.map +1 -1
  193. package/.server/server/plugins/payment/helper.test.js +2 -1
  194. package/.server/server/plugins/payment/helper.test.js.map +1 -1
  195. package/.server/server/plugins/payment/service.d.ts +2 -1
  196. package/.server/server/plugins/payment/service.js +5 -2
  197. package/.server/server/plugins/payment/service.js.map +1 -1
  198. package/.server/server/plugins/payment/service.test.js +7 -3
  199. package/.server/server/plugins/payment/service.test.js.map +1 -1
  200. package/.server/server/plugins/payment/types.d.ts +4 -0
  201. package/.server/server/plugins/payment/types.js +1 -0
  202. package/.server/server/plugins/payment/types.js.map +1 -1
  203. package/.server/server/plugins/postcode-lookup/models/index.d.ts +249 -3
  204. package/.server/server/plugins/postcode-lookup/models/index.js +87 -33
  205. package/.server/server/plugins/postcode-lookup/models/index.js.map +1 -1
  206. package/.server/server/plugins/postcode-lookup/routes/index.d.ts +15 -1
  207. package/.server/server/plugins/postcode-lookup/routes/index.js +47 -15
  208. package/.server/server/plugins/postcode-lookup/routes/index.js.map +1 -1
  209. package/.server/server/plugins/postcode-lookup/routes/index.test.js +84 -0
  210. package/.server/server/plugins/postcode-lookup/routes/index.test.js.map +1 -0
  211. package/.server/server/plugins/postcode-lookup/types.d.ts +12 -0
  212. package/.server/server/plugins/postcode-lookup/types.js +6 -1
  213. package/.server/server/plugins/postcode-lookup/types.js.map +1 -1
  214. package/.server/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  215. package/.server/server/utils/type-utils.d.ts +1 -2
  216. package/.server/server/utils/type-utils.js +0 -3
  217. package/.server/server/utils/type-utils.js.map +1 -1
  218. package/.server/server/utils/utils.d.ts +6 -0
  219. package/.server/server/utils/utils.js +18 -1
  220. package/.server/server/utils/utils.js.map +1 -1
  221. package/.server/server/utils/utils.test.js +21 -1
  222. package/.server/server/utils/utils.test.js.map +1 -1
  223. package/package.json +9 -2
  224. package/src/client/javascripts/file-upload.js +11 -3
  225. package/src/client/javascripts/geospatial-map.js +7 -34
  226. package/src/client/javascripts/govuk.js +2 -0
  227. package/src/client/javascripts/location-map.js +9 -1
  228. package/src/client/javascripts/map.js +42 -0
  229. package/src/client/javascripts/maps.js +5 -0
  230. package/src/client/javascripts/shared.js +1 -3
  231. package/src/client/javascripts/sssi-dataset.js +39 -41
  232. package/src/client/stylesheets/maps.scss +4 -0
  233. package/src/client/stylesheets/shared.scss +1 -5
  234. package/src/server/constants.js +2 -0
  235. package/src/server/plugins/engine/components/AutocompleteField.ts +13 -0
  236. package/src/server/plugins/engine/components/CheckboxesField.ts +13 -1
  237. package/src/server/plugins/engine/components/ComponentBase.ts +2 -0
  238. package/src/server/plugins/engine/components/ComponentCollection.ts +16 -11
  239. package/src/server/plugins/engine/components/DatePartsField.ts +20 -9
  240. package/src/server/plugins/engine/components/DeclarationField.ts +7 -6
  241. package/src/server/plugins/engine/components/EastingNorthingField.ts +185 -89
  242. package/src/server/plugins/engine/components/EmailAddressField.ts +2 -1
  243. package/src/server/plugins/engine/components/FileUploadField.ts +24 -3
  244. package/src/server/plugins/engine/components/FormComponent.ts +6 -5
  245. package/src/server/plugins/engine/components/GeospatialField.ts +6 -1
  246. package/src/server/plugins/engine/components/LatLongField.ts +128 -58
  247. package/src/server/plugins/engine/components/LocationFieldBase.ts +23 -6
  248. package/src/server/plugins/engine/components/LocationFieldHelpers.ts +20 -13
  249. package/src/server/plugins/engine/components/Markdown.ts +2 -3
  250. package/src/server/plugins/engine/components/MonthYearField.ts +20 -15
  251. package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +9 -3
  252. package/src/server/plugins/engine/components/NumberField.ts +21 -1
  253. package/src/server/plugins/engine/components/OsGridRefField.ts +9 -3
  254. package/src/server/plugins/engine/components/PaymentField.ts +15 -5
  255. package/src/server/plugins/engine/components/UkAddressField.ts +30 -7
  256. package/src/server/plugins/engine/components/YesNoField.ts +17 -9
  257. package/src/server/plugins/engine/components/helpers/components.ts +1 -2
  258. package/src/server/plugins/engine/components/helpers/geospatial.ts +53 -0
  259. package/src/server/plugins/engine/components/helpers/index.ts +19 -0
  260. package/src/server/plugins/engine/components/types.ts +1 -0
  261. package/src/server/plugins/engine/helpers.ts +52 -5
  262. package/src/server/plugins/engine/i18n/buildValidationMessages.ts +10 -7
  263. package/src/server/plugins/engine/i18n/createFormTranslator.ts +62 -11
  264. package/src/server/plugins/engine/i18n/extractBaseTranslations.ts +7 -1
  265. package/src/server/plugins/engine/i18n/form.ts +54 -0
  266. package/src/server/plugins/engine/i18n/languages.ts +19 -0
  267. package/src/server/plugins/engine/i18n/translations/cy.json +85 -8
  268. package/src/server/plugins/engine/i18n/translations/en-GB.json +55 -6
  269. package/src/server/plugins/engine/i18n/types.ts +2 -0
  270. package/src/server/plugins/engine/index.ts +7 -0
  271. package/src/server/plugins/engine/models/FormModel.ts +9 -15
  272. package/src/server/plugins/engine/models/SummaryViewModel.ts +6 -5
  273. package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +3 -6
  274. package/src/server/plugins/engine/outputFormatters/human/v1.ts +2 -1
  275. package/src/server/plugins/engine/outputFormatters/machine/v2.ts +3 -0
  276. package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +60 -9
  277. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +10 -5
  278. package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +2 -2
  279. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +15 -4
  280. package/src/server/plugins/engine/pageControllers/helpers/submission.ts +6 -3
  281. package/src/server/plugins/engine/pageControllers/validationOptions.ts +27 -2
  282. package/src/server/plugins/engine/types/schema.ts +1 -0
  283. package/src/server/plugins/engine/types.ts +5 -0
  284. package/src/server/plugins/engine/views/components/_location-field-base.html +2 -1
  285. package/src/server/plugins/engine/views/components/fileuploadfield.html +1 -1
  286. package/src/server/plugins/engine/views/components/multilinetextfield.html +12 -1
  287. package/src/server/plugins/engine/views/components/paymentfield.html +1 -1
  288. package/src/server/plugins/engine/views/components/ukaddressfield.html +1 -1
  289. package/src/server/plugins/engine/views/file-upload.html +1 -1
  290. package/src/server/plugins/engine/views/partials/preview-banner.html +3 -1
  291. package/src/server/plugins/nunjucks/filters/applyUrlParam.js +17 -0
  292. package/src/server/plugins/nunjucks/filters/index.js +1 -0
  293. package/src/server/plugins/payment/helper.js +22 -2
  294. package/src/server/plugins/payment/service.js +6 -2
  295. package/src/server/plugins/payment/types.js +1 -0
  296. package/src/server/plugins/postcode-lookup/models/index.js +75 -43
  297. package/src/server/plugins/postcode-lookup/routes/index.js +73 -16
  298. package/src/server/plugins/postcode-lookup/types.js +6 -1
  299. package/src/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  300. package/src/server/utils/type-utils.ts +1 -11
  301. package/src/server/utils/utils.js +19 -1
@@ -14,7 +14,17 @@
14
14
  "numberInteger": "Rhaid i {{#label}} fod yn rhif cyfan",
15
15
  "numberMin": "Rhaid i {{#label}} fod yn {{#limit}} neu uwch",
16
16
  "numberMax": "Rhaid i {{#label}} fod yn {{#limit}} neu is",
17
- "maxWords": "Rhaid i {{#label}} fod yn {{#limit}} o eiriau neu lai"
17
+ "maxWords": "Rhaid i {{#label}} fod yn {{#limit}} o eiriau neu lai",
18
+ "unicode": "Mae {{#label}} yn cynnwys nodau annilys, er enghraifft, dashes hirion",
19
+ "arrayMin": "Dewiswch o leiaf {{#limit}} o opsiynau o'r rhestr",
20
+ "arrayMax": "Dim ond {{#limit}} y gellir eu dewis o'r rhestr",
21
+ "arrayLength": "Dewiswch ddim ond {{#limit}} o opsiynau o'r rhestr",
22
+ "featuresMin": "Diffiniwch o leiaf {{#limit}} nodwedd",
23
+ "featuresMax": "Dim ond {{#limit}} nodwedd y gellir eu diffinio",
24
+ "featuresLength": "Diffiniwch nodweddion {{#limit}} yn union",
25
+ "filesMin": "Rhaid i chi uwchlwytho {{#limit}} o ffeiliau neu fwy",
26
+ "filesMax": "Dim ond {{#limit}} o ffeiliau neu lai y gallwch eu huwchlwytho",
27
+ "filesLength": "Rhaid i chi uwchlwytho'n union {{#limit}} o ffeiliau"
18
28
  },
19
29
 
20
30
  "errors": {
@@ -29,7 +39,14 @@
29
39
  "continue": "Parhau",
30
40
  "saveAndExit": "Cadw a gadael",
31
41
  "draft": "ddrafft",
32
- "live": "fyw"
42
+ "live": "fyw",
43
+ "or": "neu",
44
+ "and": "a",
45
+ "england": "Lloegr",
46
+ "wales": "Cymru",
47
+ "northernIreland": "Gogledd Iwerddon",
48
+ "scotland": "Yr Alban",
49
+ "sendFeedback": "Anfon adborth"
33
50
  },
34
51
 
35
52
  "pages": {
@@ -60,6 +77,12 @@
60
77
  "totalAmount": "Cyfanswm",
61
78
  "reference": "Cyfeirnod",
62
79
  "dateOfPayment": "Dyddiad talu",
80
+ "fileUpload_zero": "Ni uwchlwythwyd unrhyw ffeiliau",
81
+ "fileUpload_one": "Uwchlwythwyd [[count]] ffeil",
82
+ "fileUpload_two": "Uwchlwythwyd dwy feil",
83
+ "fileUpload_few": "Uwchlwythwyd [[count]] ffeil",
84
+ "fileUpload_many": "Uwchlwythwyd [[count]] o ffeiliau",
85
+ "fileUpload_other": "Uwchlwythwyd [[count]] ffeil",
63
86
  "submissionFailed": "Roedd problem ac ni chyflwynwyd eich ffurflen. Ceisiwch gyflwyno'r ffurflen eto",
64
87
  "submissionFailedContactSuffix": " neu gallwch [[contactUsLink]] a dyfynnu'ch cyfeirnod i drefnu ad-daliad",
65
88
  "contactUsLinkText": "cysylltu â ni (yn agor mewn tab newydd)",
@@ -79,17 +102,40 @@
79
102
  "change": "Newid",
80
103
  "notProvided": "Heb ei ddarparu",
81
104
  "visuallyHiddenItem": "eitem [[index]]",
105
+ "pageTitle_zero": "Nid ydych wedi ychwanegu unrhyw atebion",
82
106
  "pageTitle_one": "Rydych wedi ychwanegu [[count]] ateb",
107
+ "pageTitle_two": "Rydych wedi ychwanegu dau ateb",
108
+ "pageTitle_few": "Rydych wedi ychwanegu [[count]] ateb",
109
+ "pageTitle_many": "Rydych wedi ychwanegu [[count]] o atebion",
83
110
  "pageTitle_other": "Rydych wedi ychwanegu [[count]] ateb",
111
+ "tooMany_zero": "Ni allwch ychwanegu unrhyw atebion",
84
112
  "tooMany_one": "Dim ond hyd at [[count]] ateb y gallwch ei ychwanegu",
113
+ "tooMany_two": "Dim ond hyd at ddau gateb y gallwch eu hychwanegu",
114
+ "tooMany_few": "Dim ond hyd at [[count]] ateb y gallwch eu hychwanegu",
115
+ "tooMany_many": "Dim ond hyd at [[count]] o atebion y gallwch eu hychwanegu",
85
116
  "tooMany_other": "Dim ond hyd at [[count]] ateb y gallwch eu hychwanegu",
117
+ "tooFew_zero": "Rhaid i chi ychwanegu atebion",
86
118
  "tooFew_one": "Rhaid i chi ychwanegu o leiaf [[count]] ateb",
119
+ "tooFew_two": "Rhaid i chi ychwanegu o leiaf ddau gateb",
120
+ "tooFew_few": "Rhaid i chi ychwanegu o leiaf [[count]] ateb",
121
+ "tooFew_many": "Rhaid i chi ychwanegu o leiaf [[count]] o atebion",
87
122
  "tooFew_other": "Rhaid i chi ychwanegu o leiaf [[count]] ateb"
88
123
  },
89
124
 
90
125
  "fileUpload": {
91
126
  "upload": "Uwchlwytho ffeil",
92
- "maxFilesReached": "Rydych wedi cyrraedd nifer uchaf y ffeiliau. Tynnwch ffeil i uwchlwytho rhagor."
127
+ "maxFilesReached": "Rydych wedi cyrraedd nifer uchaf y ffeiliau. Tynnwch ffeil i uwchlwytho rhagor.",
128
+ "remove": "Tynnu",
129
+ "removeFileTitle": "Ydych chi'n siŵr eich bod chi eisiau dileu'r ffeil hon?",
130
+ "removeFileBody": "Ni allwch adfer ffeiliau a dynnwyd.",
131
+ "removeFileButton": "Dileu ffeil",
132
+ "cancel": "Canslo",
133
+ "FILE_VIRUS": "Mae'r ffeil a ddewiswyd yn cynnwys firws",
134
+ "FILE_EMPTY": "Mae'r ffeil a ddewiswyd yn wag",
135
+ "FILE_TOO_LARGE": "Rhaid i'r ffeil a ddewiswyd fod yn llai na [[maxFileSizeFormatted]]",
136
+ "FILE_INVALID_TYPE": "Rhaid i'r ffeil a ddewiswyd fod yn [[fileExtensions]]",
137
+ "FILE_UPLOAD_FAILED": "Ni ellid uwchlwytho'r ffeil a ddewiswyd - rhowch gynnig arall arni",
138
+ "FILE_ERROR_UNKNOWN": "Gwall anhysbys"
93
139
  },
94
140
 
95
141
  "exit": {
@@ -111,6 +157,7 @@
111
157
  "body": "Os hoffech dderbyn e-bost prawf, [[link]] yr hoffech i gyflwyniadau ffurflen fynd iddo.",
112
158
  "linkText": "nodwch y cyfeiriad e-bost (yn agor mewn tab newydd)"
113
159
  },
160
+ "bannerTitle": "Pwysig",
114
161
  "bannerForce": "Rhagolwg o ffurflen [[previewMode]] yw hon. Peidiwch â rhoi gwybodaeth bersonol.",
115
162
  "bannerText": "Dyma ragolwg o dudalen ffurflen [[previewMode]] rydych chi'n ei golygu.",
116
163
  "previousPages": "Mae'n dibynnu ar atebion o dudalennau cynharach yn y ffurflen. Yn y fersiwn fyw, bydd angen i ddefnyddwyr gwblhau'r cwestiynau hynny yn gyntaf."
@@ -134,7 +181,11 @@
134
181
  "findAnAddressInstead": "dod o hyd i gyfeiriad yn lle hynny",
135
182
  "noAddressFoundTitle": "Ni chanfuwyd cyfeiriad",
136
183
  "noAddressFoundBody": "Ni allem ddod o hyd i gyfeiriad cyfatebol",
184
+ "addressFound_zero": "Ni chanfuwyd unrhyw gyfeiriadau ar gyfer",
137
185
  "addressFound_one": "Canfuwyd [[count]] cyfeiriad ar gyfer",
186
+ "addressFound_two": "Canfuwyd dau gyfeiriad ar gyfer",
187
+ "addressFound_few": "Canfuwyd [[count]] chyfeiriad ar gyfer",
188
+ "addressFound_many": "Canfuwyd [[count]] o gyfeiriadau ar gyfer",
138
189
  "addressFound_other": "Canfuwyd [[count]] cyfeiriad ar gyfer",
139
190
  "validation": {
140
191
  "invalidPostcode": "Nodwch god post dilys neu nodwch gyfeiriad â llaw",
@@ -199,7 +250,8 @@
199
250
  "eastingDigits": "Rhaid i {{#label}} ar gyfer [[fieldLabel]] fod rhwng 1 a 6 digid",
200
251
  "northingDigits": "Rhaid i {{#label}} ar gyfer [[fieldLabel]] fod rhwng 1 a 7 digid",
201
252
  "eastingRange": "Rhaid i {{#label}} ar gyfer [[fieldLabel]] fod rhwng [[min]] a [[max]]",
202
- "northingRange": "Rhaid i {{#label}} ar gyfer [[fieldLabel]] fod rhwng [[min]] a [[max]]"
253
+ "northingRange": "Rhaid i {{#label}} ar gyfer [[fieldLabel]] fod rhwng [[min]] a [[max]]",
254
+ "wrongCountry": "Rhaid i leoliad fod y tu mewn i [[country]]"
203
255
  },
204
256
 
205
257
  "nationalGridField": {
@@ -220,9 +272,9 @@
220
272
 
221
273
  "yesNoField": {
222
274
  "yes": "Ie",
223
- "no": "Na",
275
+ "no": "Nage",
224
276
  "validation": {
225
- "selectYesNoRequired": "{{#label}} - dewiswch ie neu na"
277
+ "selectYesNoRequired": "{{#label}} - dewiswch ie neu nage"
226
278
  }
227
279
  },
228
280
 
@@ -236,7 +288,11 @@
236
288
  },
237
289
 
238
290
  "geospatialField": {
291
+ "added_zero": "Ni ychwanegwyd unrhyw leoliadau",
239
292
  "added_one": "Ychwanegwyd [[count]] lleoliad",
293
+ "added_two": "Ychwanegwyd dau leoliad",
294
+ "added_few": "Ychwanegwyd [[count]] lleoliad",
295
+ "added_many": "Ychwanegwyd [[count]] o leoliadau",
240
296
  "added_other": "Ychwanegwyd [[count]] lleoliad",
241
297
  "validation": {
242
298
  "descriptionRequired": "Rhowch ddisgrifiad ar gyfer lleoliad [[count]]",
@@ -245,7 +301,7 @@
245
301
  },
246
302
 
247
303
  "paymentField": {
248
- "detailsRequired": "Angen manylion talu",
304
+ "detailsRequired": "Angen talu",
249
305
  "pendingTransaction": "Mae'n bosibl y gwelwch drafodiad ar y gweill yn eich cyfrif banc ond dim ond pan fyddwch yn cyflwyno'r ffurflen y codir tâl arnoch.",
250
306
  "addPaymentDetails": "Ychwanegu manylion talu",
251
307
  "cannotTakePayment": "Mae problem ac ni allwn dderbyn taliad. Cysylltwch â ni (manylion yn nhroedyn y ffurflen hon) neu cadwch eich cynnydd a dychwelyd at y ffurflen yn ddiweddarach.",
@@ -261,11 +317,32 @@
261
317
  },
262
318
 
263
319
  "fileUploadField": {
320
+ "uploading": "Yn uwchlwytho…",
264
321
  "uploaded": "Wedi'i uwchlwytho",
265
322
  "uploadFailed": "Roedd problem gyda'ch ffeiliau a uwchlwythwyd. Uwchlwythwch nhw eto cyn cyflwyno'r ffurflen.",
266
323
  "uploadedFilesHeading": "Ffeiliau a uwchlwythwyd",
324
+ "filesCount_zero": "Uwchlwythwyd [[count]] o ffeiliau",
267
325
  "filesCount_one": "Uwchlwythwyd [[count]] ffeil",
268
- "filesCount_other": "Uwchlwythwyd [[count]] ffeil"
326
+ "filesCount_two": "Uwchlwythwyd [[count]] ffeil",
327
+ "filesCount_few": "Uwchlwythwyd [[count]] ffeil",
328
+ "filesCount_many": "Uwchlwythwyd [[count]] o ffeiliau",
329
+ "filesCount_other": "Uwchlwythwyd [[count]] ffeil",
330
+ "chooseFile": "Dewiswch ffeil",
331
+ "dropFile": "neu ollwng ffeil",
332
+ "noFileChosen": "Dim ffeil wedi'i dewis"
333
+ },
334
+
335
+ "characterCount": {
336
+ "_comment": "Note the use of %{count} instead of [[count]]. This is because we are passing to the govuk template, not passing to Joi",
337
+ "underLimit": {
338
+ "one": "Mae gennych %{count} nod ar ôl",
339
+ "other": "Mae gennych %{count} nod ar ôl"
340
+ },
341
+ "atLimit": "Mae gennych 0 nod ar ôl",
342
+ "overLimit": {
343
+ "one": "Mae gennych %{count} nod yn ormod",
344
+ "other": "Mae gennych %{count} nod yn ormod"
345
+ }
269
346
  }
270
347
  }
271
348
  }
@@ -14,7 +14,17 @@
14
14
  "numberInteger": "{{#label}} must be a whole number",
15
15
  "numberMin": "{{#label}} must be {{#limit}} or higher",
16
16
  "numberMax": "{{#label}} must be {{#limit}} or lower",
17
- "maxWords": "{{#label}} must be {{#limit}} words or fewer"
17
+ "maxWords": "{{#label}} must be {{#limit}} words or fewer",
18
+ "unicode": "{{#label}} includes invalid characters, for example, long dashes",
19
+ "arrayMin": "Select at least {{#limit}} options from the list",
20
+ "arrayMax": "Only {{#limit}} can be selected from the list",
21
+ "arrayLength": "Select only {{#limit}} options from the list",
22
+ "featuresMin": "Define at least {{#limit}} features",
23
+ "featuresMax": "Only {{#limit}} features can be defined",
24
+ "featuresLength": "Define exactly {{#limit}} features",
25
+ "filesMin": "You must upload {{#limit}} files or more",
26
+ "filesMax": "You can only upload {{#limit}} files or less",
27
+ "filesLength": "You must upload exactly {{#limit}} files"
18
28
  },
19
29
 
20
30
  "errors": {
@@ -29,7 +39,14 @@
29
39
  "continue": "Continue",
30
40
  "saveAndExit": "Save and exit",
31
41
  "draft": "draft",
32
- "live": "live"
42
+ "live": "live",
43
+ "or": "or",
44
+ "and": "and",
45
+ "england": "England",
46
+ "wales": "Wales",
47
+ "northernIreland": "Northern Ireland",
48
+ "scotland": "Scotland",
49
+ "sendFeedback": "Send feedback"
33
50
  },
34
51
 
35
52
  "pages": {
@@ -60,6 +77,8 @@
60
77
  "totalAmount": "Total amount",
61
78
  "reference": "Reference",
62
79
  "dateOfPayment": "Date of payment",
80
+ "fileUpload_one": "Uploaded [[count]] file",
81
+ "fileUpload_other": "Uploaded [[count]] files",
63
82
  "submissionFailed": "There was a problem and your form was not submitted. Try submitting the form again",
64
83
  "submissionFailedContactSuffix": " or you can [[contactUsLink]] and quote your reference number to arrange a refund",
65
84
  "contactUsLinkText": "contact us (opens in new tab)",
@@ -89,7 +108,18 @@
89
108
 
90
109
  "fileUpload": {
91
110
  "upload": "Upload file",
92
- "maxFilesReached": "You have reached the maximum number of files. Please remove a file to upload more."
111
+ "maxFilesReached": "You have reached the maximum number of files. Please remove a file to upload more.",
112
+ "remove": "Remove",
113
+ "removeFileTitle": "Are you sure you want to remove this file?",
114
+ "removeFileBody": "You cannot recover removed files.",
115
+ "removeFileButton": "Remove file",
116
+ "cancel": "Cancel",
117
+ "FILE_VIRUS": "The selected file contains a virus",
118
+ "FILE_EMPTY": "The selected file is empty",
119
+ "FILE_TOO_LARGE": "The selected file must be smaller than [[maxFileSizeFormatted]]",
120
+ "FILE_INVALID_TYPE": "The selected file must be a [[fileExtensions]]",
121
+ "FILE_UPLOAD_FAILED": "The selected file could not be uploaded - try again",
122
+ "FILE_ERROR_UNKNOWN": "Unknown error"
93
123
  },
94
124
 
95
125
  "exit": {
@@ -111,6 +141,7 @@
111
141
  "body": "If you want to receive a test email, [[link]] you want form submissions to go to.",
112
142
  "linkText": "enter the email address (opens in new tab)"
113
143
  },
144
+ "bannerTitle": "Important",
114
145
  "bannerForce": "This is a preview of a [[previewMode]] form. Do not enter personal information.",
115
146
  "bannerText": "This is a preview of a [[previewMode]] form page you are editing.",
116
147
  "previousPages": "It depends on answers from earlier pages in the form. In the live version, users will need to complete those questions first."
@@ -199,7 +230,8 @@
199
230
  "eastingDigits": "{{#label}} for [[fieldLabel]] must be between 1 and 6 digits",
200
231
  "northingDigits": "{{#label}} for [[fieldLabel]] must be between 1 and 7 digits",
201
232
  "eastingRange": "{{#label}} for [[fieldLabel]] must be between [[min]] and [[max]]",
202
- "northingRange": "{{#label}} for [[fieldLabel]] must be between [[min]] and [[max]]"
233
+ "northingRange": "{{#label}} for [[fieldLabel]] must be between [[min]] and [[max]]",
234
+ "wrongCountry": "Location must be within [[country]]"
203
235
  },
204
236
 
205
237
  "nationalGridField": {
@@ -245,7 +277,7 @@
245
277
  },
246
278
 
247
279
  "paymentField": {
248
- "detailsRequired": "Payment details required",
280
+ "detailsRequired": "Payment required",
249
281
  "pendingTransaction": "You may see a pending transaction in your bank account but you will only be charged when you submit the form.",
250
282
  "addPaymentDetails": "Add payment details",
251
283
  "cannotTakePayment": "There is a problem and we cannot take a payment. Contact us (details in the footer of this form) or save your progress and return to the form later.",
@@ -261,11 +293,28 @@
261
293
  },
262
294
 
263
295
  "fileUploadField": {
296
+ "uploading": "Uploading…",
264
297
  "uploaded": "Uploaded",
265
298
  "uploadFailed": "There was a problem with your uploaded files. Re-upload them before submitting the form again.",
266
299
  "uploadedFilesHeading": "Uploaded files",
267
300
  "filesCount_one": "[[count]] file uploaded",
268
- "filesCount_other": "[[count]] files uploaded"
301
+ "filesCount_other": "[[count]] files uploaded",
302
+ "chooseFile": "Choose file",
303
+ "dropFile": "or drop file",
304
+ "noFileChosen": "No file chosen"
305
+ },
306
+
307
+ "characterCount": {
308
+ "_comment": "Note the use of %{count} instead of [[count]]. This is because we are passing to the govuk template, not passing to Joi",
309
+ "underLimit": {
310
+ "one": "You have %{count} character remaining",
311
+ "other": "You have %{count} characters remaining"
312
+ },
313
+ "atLimit": "You have 0 characters remaining",
314
+ "overLimit": {
315
+ "one": "You have %{count} character too many",
316
+ "other": "You have %{count} characters too many"
317
+ }
269
318
  }
270
319
  }
271
320
  }
@@ -22,6 +22,8 @@ export type FormDefinitionTranslations = Record<
22
22
  hint: string
23
23
  content: string
24
24
  shortDescription: string
25
+ errorDescription: string
26
+ paymentDescription: string
25
27
  }>
26
28
  >
27
29
  sections: Record<string, Partial<Pick<Section, 'title'>>>
@@ -22,6 +22,13 @@ export {
22
22
  resolveFormModel
23
23
  } from './form-context.js'
24
24
  export * from './form-availability.js'
25
+ export { getAvailableLanguages } from './i18n/languages.js'
26
+ export {
27
+ extractMetadataBaseTranslations,
28
+ loadFormTranslations
29
+ } from './i18n/createFormTranslator.js'
30
+ export { extractBaseTranslations } from './i18n/extractBaseTranslations.js'
31
+ export { applyUrlParam } from '../nunjucks/filters/applyUrlParam.js'
25
32
 
26
33
  const globals = {
27
34
  checkComponentTemplates,
@@ -31,6 +31,7 @@ import { type i18n } from 'i18next'
31
31
  import joi from 'joi'
32
32
 
33
33
  import { logger } from '../../../common/helpers/logging/logger.js'
34
+ import { EN_GB } from '../../../constants.js'
34
35
  import { type ListFormComponent } from '../components/ListFormComponent.js'
35
36
  import {} from '../components/YesNoField.js'
36
37
  import {
@@ -47,6 +48,7 @@ import { loadFormTranslations } from '../i18n/createFormTranslator.js'
47
48
  import { createTranslator } from '../i18n/createTranslator.js'
48
49
  import { extractBaseTranslations } from '../i18n/extractBaseTranslations.js'
49
50
  import { createFormI18nInstance } from '../i18n/index.js'
51
+ import { getAvailableLanguages } from '../i18n/languages.js'
50
52
  import { type Translator } from '../i18n/types.js'
51
53
  import { type ExecutableCondition } from './types.js'
52
54
  import { type PageController } from '../pageControllers/PageController.js'
@@ -240,7 +242,12 @@ export class FormModel {
240
242
  }
241
243
 
242
244
  /** Returns a scoped translator pair for the given language. */
243
- createTranslator(language = 'en-GB'): Translator {
245
+ createTranslator(language = EN_GB): Translator {
246
+ // @ts-expect-error - dynamic language lookup
247
+ if (!this.def.metadata?.translations?.[language]) {
248
+ // If not translations defined in the FormDefinition, always default to English
249
+ language = EN_GB
250
+ }
244
251
  return createTranslator(this.i18nInstance, language)
245
252
  }
246
253
 
@@ -662,7 +669,7 @@ function validateFormState(
662
669
 
663
670
  // Add relevant state errors
664
671
  if (error) {
665
- const errorsState = error.details.map(getError)
672
+ const errorsState = error.details.map((item) => getError(EN_GB, item))
666
673
  return { ...context, errors: errors.concat(errorsState) }
667
674
  }
668
675
 
@@ -679,16 +686,3 @@ function getReferenceNumber(state: FormSubmissionState): string {
679
686
 
680
687
  return state.$$__referenceNumber
681
688
  }
682
-
683
- export function getAvailableLanguages(
684
- def: FormDefinition
685
- ): { name: string; code: string }[] {
686
- // @ts-expect-error - dynamic property
687
- if (def.metadata?.translations?.cy) {
688
- return [
689
- { name: 'English', code: 'en-GB' },
690
- { name: 'Cymraeg', code: 'cy' }
691
- ]
692
- }
693
- return []
694
- }
@@ -4,6 +4,7 @@ import {
4
4
  type Section
5
5
  } from '@defra/forms-model'
6
6
 
7
+ import { EN_GB } from '../../../constants.js'
7
8
  import { PaymentField } from '../components/PaymentField.js'
8
9
  import { type PaymentState } from '../components/PaymentField.types.js'
9
10
  import {
@@ -96,7 +97,7 @@ export class SummaryViewModel {
96
97
  .validate(this.context.relevantState, { ...opts, stripUnknown: true })
97
98
 
98
99
  // Format errors
99
- this.errors = result.error?.details.map(getError)
100
+ this.errors = result.error?.details.map((item) => getError(EN_GB, item))
100
101
  this.details = this.summaryDetails(request, sections, translator)
101
102
 
102
103
  // Format check answers
@@ -212,12 +213,12 @@ function ItemRepeat(
212
213
  translator: Translator
213
214
  ): DetailItemRepeat {
214
215
  const { collection, repeat } = page
215
- const { name, title } = repeat.options
216
-
216
+ const { name } = repeat.options
217
+ const { t, tPage } = translator
218
+ const title = tPage(page.pageDef, 'repeatTitle') || repeat.options.title
217
219
  const values = page.getListFromState(state)
218
220
  const count = values.length
219
- const value =
220
- count === 0 ? '' : translator.t('pages.repeater.pageTitle', { count })
221
+ const value = count === 0 ? '' : t('pages.repeater.pageTitle', { count })
221
222
 
222
223
  return {
223
224
  name,
@@ -3,6 +3,7 @@ import {
3
3
  type SubmitResponsePayload
4
4
  } from '@defra/forms-model'
5
5
 
6
+ import { EN_GB } from '../../../../constants.js'
6
7
  import {
7
8
  getFormVersion,
8
9
  type checkFormStatus
@@ -42,18 +43,14 @@ export function format(
42
43
  formSlug: formMetadata?.slug ?? '',
43
44
  status: formStatus.state,
44
45
  isPreview: formStatus.isPreview,
45
- notificationEmail: formMetadata?.notificationEmail ?? ''
46
+ notificationEmail: formMetadata?.notificationEmail ?? '',
47
+ language: context.translator?.language ?? EN_GB
46
48
  }
47
49
 
48
50
  if (versionMetadata) {
49
51
  meta.versionMetadata = versionMetadata
50
52
  }
51
53
 
52
- const definitionLanguage = model.def.metadata?.language
53
- if (typeof definitionLanguage === 'string') {
54
- meta.language = definitionLanguage
55
- }
56
-
57
54
  const main = Object.fromEntries(
58
55
  Object.entries(v2Main).map(([key, value]) => {
59
56
  if (value === undefined) {
@@ -5,6 +5,7 @@ import {
5
5
  import { addDays, format as dateFormat } from 'date-fns'
6
6
 
7
7
  import { config } from '../../../../../config/index.js'
8
+ import { EN_GB } from '../../../../constants.js'
8
9
  import { getAnswer } from '../../components/helpers/components.js'
9
10
  import { escapeMarkdown } from '../../components/helpers/index.js'
10
11
  import { PaymentField } from '../../components/index.js'
@@ -116,7 +117,7 @@ function appendPaymentSection(paymentItems: DetailItem[], lines: string[]) {
116
117
 
117
118
  const formattedAmount = formatCurrency(paymentState.amount)
118
119
  const dateOfPayment = paymentState.preAuth?.createdAt
119
- ? formatPaymentDate(paymentState.preAuth.createdAt)
120
+ ? formatPaymentDate(paymentState.preAuth.createdAt, EN_GB)
120
121
  : ''
121
122
 
122
123
  lines.push(
@@ -28,6 +28,7 @@ interface PaymentOutput {
28
28
  reference: string
29
29
  amount: number
30
30
  description: string
31
+ descriptionInEng?: string
31
32
  createdAt: string
32
33
  }
33
34
 
@@ -93,6 +94,7 @@ export function format(
93
94
  * reference: 'REF-123',
94
95
  * amount: 10.00,
95
96
  * description: 'Application fee',
97
+ * descriptionInEng: 'Applicaiton fee',
96
98
  * createdAt: '2025-01-23T10:30:00.000Z'
97
99
  * }
98
100
  * }
@@ -204,6 +206,7 @@ function extractPayment(
204
206
  reference: paymentState.reference,
205
207
  amount: paymentState.amount,
206
208
  description: paymentState.description,
209
+ descriptionInEng: item.field.def.options.description,
207
210
  createdAt: paymentState.preAuth?.createdAt ?? ''
208
211
  }
209
212
  }
@@ -42,6 +42,7 @@ import {
42
42
  type FormRequestPayload,
43
43
  type FormResponseToolkit
44
44
  } from '../../../routes/types.js'
45
+ import { joinWithOr } from '../../../utils/utils.js'
45
46
 
46
47
  const MAX_UPLOADS = 25
47
48
  const CDP_UPLOAD_TIMEOUT_MS = 60000 // 1 minute
@@ -188,17 +189,19 @@ export class FileUploadPageController extends QuestionPageController {
188
189
 
189
190
  const { filename } = fileToRemove.status.form.file
190
191
 
191
- const { t } = this.getTranslator(request)
192
+ const translator = this.getTranslator(request)
193
+ const { t } = translator
192
194
 
193
195
  return h.view(this.fileDeleteViewName, {
194
196
  ...viewModel,
195
197
  context,
196
198
  backLink: this.getBackLink(request, context, t),
197
- pageTitle: `Are you sure you want to remove this file?`,
199
+ pageTitle: t('pages.fileUpload.removeFileTitle'),
198
200
  itemTitle: filename,
199
- confirmation: { text: 'You cannot recover removed files.' },
200
- buttonConfirm: { text: 'Remove file' },
201
- buttonCancel: { text: 'Cancel' }
201
+ confirmation: { text: t('pages.fileUpload.removeFileBody') },
202
+ buttonConfirm: { text: t('pages.fileUpload.removeFileButton') },
203
+ buttonCancel: { text: t('pages.fileUpload.cancel') },
204
+ t
202
205
  } satisfies ItemDeletePageViewModel)
203
206
  }
204
207
  }
@@ -224,7 +227,7 @@ export class FileUploadPageController extends QuestionPageController {
224
227
  }
225
228
  }
226
229
 
227
- getErrors(details?: ValidationErrorItem[]) {
230
+ getErrors(details?: ValidationErrorItem[], language?: string) {
228
231
  const { fileUpload } = this
229
232
 
230
233
  if (details) {
@@ -237,7 +240,7 @@ export class FileUploadPageController extends QuestionPageController {
237
240
  if (!isUploadError || isUploadRootError) {
238
241
  // The error is for the root of the upload or another
239
242
  // field on the page so defer to the getError helper
240
- errors.push(getError(error))
243
+ errors.push(getError(language, error))
241
244
  } else {
242
245
  const { context, path, type } = error
243
246
 
@@ -266,6 +269,7 @@ export class FileUploadPageController extends QuestionPageController {
266
269
  ): FeaturedFormPageViewModel {
267
270
  const { fileUpload } = this
268
271
  const { state } = context
272
+ const { t } = translator
269
273
 
270
274
  const upload = this.getUploadFromState(state)
271
275
 
@@ -277,6 +281,19 @@ export class FileUploadPageController extends QuestionPageController {
277
281
  ({ model }) => model.id === fileUpload.name
278
282
  )
279
283
 
284
+ formComponent.model.upload = {
285
+ count: formComponent.model.upload?.count ?? 0,
286
+ summaryList: formComponent.model.upload?.summaryList ?? { rows: [] },
287
+ uploadingLabel: t('components.fileUploadField.uploading')
288
+ }
289
+ formComponent.model = {
290
+ ...formComponent.model,
291
+ javascript: true,
292
+ chooseFilesButtonText: t('components.fileUploadField.chooseFile'),
293
+ dropInstructionText: t('components.fileUploadField.dropFile'),
294
+ noFileChosenText: t('components.fileUploadField.noFileChosen')
295
+ }
296
+
280
297
  const index = components.indexOf(formComponent)
281
298
 
282
299
  const proxyUrl = getProxyUrlForLocalDevelopment(upload?.uploadUrl)
@@ -290,7 +307,8 @@ export class FileUploadPageController extends QuestionPageController {
290
307
  // Split out components before/after
291
308
  componentsBefore: components.slice(0, index),
292
309
  components: components.slice(index),
293
- proxyUrl
310
+ proxyUrl,
311
+ t
294
312
  }
295
313
  }
296
314
 
@@ -441,6 +459,9 @@ export class FileUploadPageController extends QuestionPageController {
441
459
 
442
460
  const allErrors: FormSubmissionError[] = []
443
461
 
462
+ const translator = this.getTranslator(request)
463
+ const { t } = translator
464
+
444
465
  for (const file of uploadedFiles) {
445
466
  if (file.fileStatus === FileStatus.complete) {
446
467
  const perFileState: FileState = {
@@ -455,7 +476,14 @@ export class FileUploadPageController extends QuestionPageController {
455
476
  // Collect the error for rejected/pending files.
456
477
  const { fileUpload } = this
457
478
  const name = fileUpload.name
458
- const text = file.errorMessage ?? 'Unknown error'
479
+ const errorParams = this.expandErrorParams(
480
+ file.errorParams,
481
+ t('common.or')
482
+ )
483
+ const text = t(
484
+ `pages.fileUpload.${file.errorCode ?? 'FILE_ERROR_UNKNOWN'}`,
485
+ errorParams
486
+ )
459
487
  allErrors.push({ path: [name], href: `#${name}`, name, text })
460
488
  }
461
489
  }
@@ -472,6 +500,29 @@ export class FileUploadPageController extends QuestionPageController {
472
500
  }
473
501
  }
474
502
 
503
+ /**
504
+ * Process the error parameters so any arrays get expanded (joined), ready to be passed into the error message
505
+ * @param errorParams - received from the file upload (may be a number, a string, or a string array)
506
+ * @param finalSeparator - 'or' in English, and 'neu' in Welsh
507
+ */
508
+ private expandErrorParams(
509
+ errorParams: Record<string, number | string | string[]> | undefined,
510
+ finalSeparator: string
511
+ ) {
512
+ if (!errorParams) {
513
+ return {}
514
+ }
515
+ const expanded = {} as Record<string, number | string>
516
+ for (const [key, value] of Object.entries(errorParams)) {
517
+ if (Array.isArray(value)) {
518
+ expanded[key] = joinWithOr(value, finalSeparator)
519
+ } else {
520
+ expanded[key] = value
521
+ }
522
+ }
523
+ return expanded
524
+ }
525
+
475
526
  /**
476
527
  * Checks the payload for a file getting removed
477
528
  * and removes it from the upload files if found
@@ -174,9 +174,14 @@ export class QuestionPageController extends PageController {
174
174
  if (!pageTitle) {
175
175
  pageTitle = labelOrLegend.text
176
176
  }
177
- labelOrLegend.text = isOptional
178
- ? `${pageTitle} ${t('common.optional')}`
179
- : pageTitle
177
+
178
+ // The question text may have already appended 'optional' in the relevant language
179
+ const optionalWord = t('common.optional')
180
+ const optionalAlreadyAppended = pageTitle.endsWith(` ${optionalWord}`)
181
+ labelOrLegend.text =
182
+ isOptional && !optionalAlreadyAppended
183
+ ? `${pageTitle} ${optionalWord}`
184
+ : pageTitle
180
185
  }
181
186
 
182
187
  // Fallback if still no pageTitle set
@@ -359,8 +364,8 @@ export class QuestionPageController extends PageController {
359
364
  return this.collection.getStateFromValidForm(payload)
360
365
  }
361
366
 
362
- getErrors(details?: ValidationErrorItem[]) {
363
- return getErrors(details)
367
+ getErrors(details?: ValidationErrorItem[], language?: string) {
368
+ return getErrors(language, details)
364
369
  }
365
370
 
366
371
  async getState(request: AnyFormRequest) {