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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. package/.server/server/forms/register-as-a-unicorn-breeder.yaml +0 -14
  2. package/.server/server/forms/simple-form.yaml +106 -3
  3. package/.server/server/plugins/engine/components/AutocompleteField.d.ts +11 -11
  4. package/.server/server/plugins/engine/components/AutocompleteField.js +2 -2
  5. package/.server/server/plugins/engine/components/AutocompleteField.js.map +1 -1
  6. package/.server/server/plugins/engine/components/CheckboxesField.d.ts +3 -2
  7. package/.server/server/plugins/engine/components/CheckboxesField.js +4 -9
  8. package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -1
  9. package/.server/server/plugins/engine/components/ComponentCollection.d.ts +8 -7
  10. package/.server/server/plugins/engine/components/ComponentCollection.js +106 -51
  11. package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
  12. package/.server/server/plugins/engine/components/DatePartsField.d.ts +8 -6
  13. package/.server/server/plugins/engine/components/DatePartsField.js +27 -9
  14. package/.server/server/plugins/engine/components/DatePartsField.js.map +1 -1
  15. package/.server/server/plugins/engine/components/DeclarationField.d.ts +13 -11
  16. package/.server/server/plugins/engine/components/DeclarationField.js +31 -9
  17. package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -1
  18. package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +6 -5
  19. package/.server/server/plugins/engine/components/EastingNorthingField.js +42 -22
  20. package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -1
  21. package/.server/server/plugins/engine/components/EmailAddressField.d.ts +11 -14
  22. package/.server/server/plugins/engine/components/EmailAddressField.js +2 -2
  23. package/.server/server/plugins/engine/components/EmailAddressField.js.map +1 -1
  24. package/.server/server/plugins/engine/components/FileUploadField.d.ts +14 -12
  25. package/.server/server/plugins/engine/components/FileUploadField.js +22 -12
  26. package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
  27. package/.server/server/plugins/engine/components/FormComponent.d.ts +21 -12
  28. package/.server/server/plugins/engine/components/FormComponent.js +33 -14
  29. package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
  30. package/.server/server/plugins/engine/components/GeospatialField.d.ts +14 -12
  31. package/.server/server/plugins/engine/components/GeospatialField.js +19 -13
  32. package/.server/server/plugins/engine/components/GeospatialField.js.map +1 -1
  33. package/.server/server/plugins/engine/components/LatLongField.d.ts +6 -5
  34. package/.server/server/plugins/engine/components/LatLongField.js +32 -20
  35. package/.server/server/plugins/engine/components/LatLongField.js.map +1 -1
  36. package/.server/server/plugins/engine/components/ListFormComponent.d.ts +7 -6
  37. package/.server/server/plugins/engine/components/ListFormComponent.js +19 -7
  38. package/.server/server/plugins/engine/components/ListFormComponent.js.map +1 -1
  39. package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +17 -16
  40. package/.server/server/plugins/engine/components/LocationFieldBase.js +2 -2
  41. package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -1
  42. package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +3 -3
  43. package/.server/server/plugins/engine/components/LocationFieldHelpers.js +2 -2
  44. package/.server/server/plugins/engine/components/LocationFieldHelpers.js.map +1 -1
  45. package/.server/server/plugins/engine/components/Markdown.d.ts +8 -7
  46. package/.server/server/plugins/engine/components/Markdown.js +5 -2
  47. package/.server/server/plugins/engine/components/Markdown.js.map +1 -1
  48. package/.server/server/plugins/engine/components/MonthYearField.d.ts +9 -7
  49. package/.server/server/plugins/engine/components/MonthYearField.js +26 -8
  50. package/.server/server/plugins/engine/components/MonthYearField.js.map +1 -1
  51. package/.server/server/plugins/engine/components/MultilineTextField.d.ts +10 -9
  52. package/.server/server/plugins/engine/components/MultilineTextField.js +2 -2
  53. package/.server/server/plugins/engine/components/MultilineTextField.js.map +1 -1
  54. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +2 -1
  55. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js +14 -6
  56. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js.map +1 -1
  57. package/.server/server/plugins/engine/components/NumberField.d.ts +10 -9
  58. package/.server/server/plugins/engine/components/NumberField.js +2 -2
  59. package/.server/server/plugins/engine/components/NumberField.js.map +1 -1
  60. package/.server/server/plugins/engine/components/OsGridRefField.d.ts +2 -1
  61. package/.server/server/plugins/engine/components/OsGridRefField.js +14 -6
  62. package/.server/server/plugins/engine/components/OsGridRefField.js.map +1 -1
  63. package/.server/server/plugins/engine/components/PaymentField.d.ts +12 -10
  64. package/.server/server/plugins/engine/components/PaymentField.js +21 -8
  65. package/.server/server/plugins/engine/components/PaymentField.js.map +1 -1
  66. package/.server/server/plugins/engine/components/SelectField.d.ts +11 -11
  67. package/.server/server/plugins/engine/components/SelectField.js +2 -2
  68. package/.server/server/plugins/engine/components/SelectField.js.map +1 -1
  69. package/.server/server/plugins/engine/components/SelectionControlField.d.ts +4 -4
  70. package/.server/server/plugins/engine/components/SelectionControlField.js +2 -2
  71. package/.server/server/plugins/engine/components/SelectionControlField.js.map +1 -1
  72. package/.server/server/plugins/engine/components/TelephoneNumberField.d.ts +10 -9
  73. package/.server/server/plugins/engine/components/TelephoneNumberField.js +2 -2
  74. package/.server/server/plugins/engine/components/TelephoneNumberField.js.map +1 -1
  75. package/.server/server/plugins/engine/components/UkAddressField.d.ts +12 -10
  76. package/.server/server/plugins/engine/components/UkAddressField.js +29 -17
  77. package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
  78. package/.server/server/plugins/engine/components/YesNoField.d.ts +3 -0
  79. package/.server/server/plugins/engine/components/YesNoField.js +9 -0
  80. package/.server/server/plugins/engine/components/YesNoField.js.map +1 -1
  81. package/.server/server/plugins/engine/components/helpers/components.d.ts +3 -2
  82. package/.server/server/plugins/engine/components/helpers/components.js +11 -8
  83. package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
  84. package/.server/server/plugins/engine/components/types.d.ts +8 -1
  85. package/.server/server/plugins/engine/components/types.js.map +1 -1
  86. package/.server/server/plugins/engine/configureEnginePlugin.js +8 -1
  87. package/.server/server/plugins/engine/configureEnginePlugin.js.map +1 -1
  88. package/.server/server/plugins/engine/form-context.d.ts +1 -0
  89. package/.server/server/plugins/engine/form-context.js +4 -2
  90. package/.server/server/plugins/engine/form-context.js.map +1 -1
  91. package/.server/server/plugins/engine/helpers.d.ts +1 -1
  92. package/.server/server/plugins/engine/helpers.js +8 -13
  93. package/.server/server/plugins/engine/helpers.js.map +1 -1
  94. package/.server/server/plugins/engine/i18n/buildValidationMessages.d.ts +39 -0
  95. package/.server/server/plugins/engine/i18n/buildValidationMessages.js +50 -0
  96. package/.server/server/plugins/engine/i18n/buildValidationMessages.js.map +1 -0
  97. package/.server/server/plugins/engine/i18n/createFormTranslator.d.ts +5 -0
  98. package/.server/server/plugins/engine/i18n/createFormTranslator.js +18 -0
  99. package/.server/server/plugins/engine/i18n/createFormTranslator.js.map +1 -0
  100. package/.server/server/plugins/engine/i18n/createTranslator.d.ts +9 -0
  101. package/.server/server/plugins/engine/i18n/createTranslator.js +51 -0
  102. package/.server/server/plugins/engine/i18n/createTranslator.js.map +1 -0
  103. package/.server/server/plugins/engine/i18n/extractBaseTranslations.d.ts +5 -0
  104. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js +57 -0
  105. package/.server/server/plugins/engine/i18n/extractBaseTranslations.js.map +1 -0
  106. package/.server/server/plugins/engine/i18n/index.d.ts +18 -0
  107. package/.server/server/plugins/engine/i18n/index.js +71 -0
  108. package/.server/server/plugins/engine/i18n/index.js.map +1 -0
  109. package/.server/server/plugins/engine/i18n/translations/cy.json +271 -0
  110. package/.server/server/plugins/engine/i18n/translations/en-GB.json +271 -0
  111. package/.server/server/plugins/engine/i18n/types.d.ts +41 -0
  112. package/.server/server/plugins/engine/i18n/types.js +2 -0
  113. package/.server/server/plugins/engine/i18n/types.js.map +1 -0
  114. package/.server/server/plugins/engine/index.js +3 -2
  115. package/.server/server/plugins/engine/index.js.map +1 -1
  116. package/.server/server/plugins/engine/models/FormModel.d.ts +9 -1
  117. package/.server/server/plugins/engine/models/FormModel.js +44 -18
  118. package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
  119. package/.server/server/plugins/engine/models/SummaryViewModel.d.ts +5 -2
  120. package/.server/server/plugins/engine/models/SummaryViewModel.js +44 -18
  121. package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
  122. package/.server/server/plugins/engine/options.js +2 -1
  123. package/.server/server/plugins/engine/options.js.map +1 -1
  124. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +4 -0
  125. package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
  126. package/.server/server/plugins/engine/outputFormatters/human/v1.js +2 -1
  127. package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
  128. package/.server/server/plugins/engine/outputFormatters/machine/v1.js +7 -6
  129. package/.server/server/plugins/engine/outputFormatters/machine/v1.js.map +1 -1
  130. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.d.ts +2 -1
  131. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +6 -3
  132. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
  133. package/.server/server/plugins/engine/pageControllers/PageController.d.ts +3 -1
  134. package/.server/server/plugins/engine/pageControllers/PageController.js +11 -1
  135. package/.server/server/plugins/engine/pageControllers/PageController.js.map +1 -1
  136. package/.server/server/plugins/engine/pageControllers/QuestionPageController.d.ts +4 -2
  137. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +52 -21
  138. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
  139. package/.server/server/plugins/engine/pageControllers/RepeatPageController.d.ts +3 -2
  140. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js +63 -26
  141. package/.server/server/plugins/engine/pageControllers/RepeatPageController.js.map +1 -1
  142. package/.server/server/plugins/engine/pageControllers/StartPageController.d.ts +3 -1
  143. package/.server/server/plugins/engine/pageControllers/StartPageController.js +2 -2
  144. package/.server/server/plugins/engine/pageControllers/StartPageController.js.map +1 -1
  145. package/.server/server/plugins/engine/pageControllers/StatusPageController.js +12 -2
  146. package/.server/server/plugins/engine/pageControllers/StatusPageController.js.map +1 -1
  147. package/.server/server/plugins/engine/pageControllers/SummaryPageController.d.ts +4 -3
  148. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +44 -28
  149. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
  150. package/.server/server/plugins/engine/pageControllers/__stubs__/translator.d.ts +2 -0
  151. package/.server/server/plugins/engine/pageControllers/__stubs__/translator.js +24 -0
  152. package/.server/server/plugins/engine/pageControllers/__stubs__/translator.js.map +1 -0
  153. package/.server/server/plugins/engine/pageControllers/errors.d.ts +1 -1
  154. package/.server/server/plugins/engine/pageControllers/errors.js +3 -2
  155. package/.server/server/plugins/engine/pageControllers/errors.js.map +1 -1
  156. package/.server/server/plugins/engine/pageControllers/helpers/submission.d.ts +3 -2
  157. package/.server/server/plugins/engine/pageControllers/helpers/submission.js +4 -4
  158. package/.server/server/plugins/engine/pageControllers/helpers/submission.js.map +1 -1
  159. package/.server/server/plugins/engine/pageControllers/validationOptions.d.ts +7 -3
  160. package/.server/server/plugins/engine/pageControllers/validationOptions.js +34 -33
  161. package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
  162. package/.server/server/plugins/engine/plugin.js +2 -0
  163. package/.server/server/plugins/engine/plugin.js.map +1 -1
  164. package/.server/server/plugins/engine/routes/index.js +4 -1
  165. package/.server/server/plugins/engine/routes/index.js.map +1 -1
  166. package/.server/server/plugins/engine/routes/questions.js +5 -2
  167. package/.server/server/plugins/engine/routes/questions.js.map +1 -1
  168. package/.server/server/plugins/engine/types/index.d.ts +1 -0
  169. package/.server/server/plugins/engine/types/index.js.map +1 -1
  170. package/.server/server/plugins/engine/types/schema.js +1 -0
  171. package/.server/server/plugins/engine/types/schema.js.map +1 -1
  172. package/.server/server/plugins/engine/types.d.ts +12 -1
  173. package/.server/server/plugins/engine/types.js.map +1 -1
  174. package/.server/server/plugins/engine/views/components/_location-field-base.html +1 -1
  175. package/.server/server/plugins/engine/views/components/fileuploadfield.html +3 -3
  176. package/.server/server/plugins/engine/views/components/nationalgridfieldnumberfield.html +1 -1
  177. package/.server/server/plugins/engine/views/components/osgridreffield.html +1 -1
  178. package/.server/server/plugins/engine/views/components/paymentfield.html +8 -8
  179. package/.server/server/plugins/engine/views/components/ukaddressfield.html +4 -4
  180. package/.server/server/plugins/engine/views/confirmation.html +4 -4
  181. package/.server/server/plugins/engine/views/exit.html +4 -4
  182. package/.server/server/plugins/engine/views/file-upload.html +3 -3
  183. package/.server/server/plugins/engine/views/index.html +3 -3
  184. package/.server/server/plugins/engine/views/item-delete.html +1 -1
  185. package/.server/server/plugins/engine/views/partials/form.html +3 -3
  186. package/.server/server/plugins/engine/views/partials/preview-banner.html +4 -4
  187. package/.server/server/plugins/engine/views/partials/warn-missing-notification-email.html +4 -5
  188. package/.server/server/plugins/engine/views/repeat-list-summary.html +4 -4
  189. package/.server/server/plugins/engine/views/summary.html +14 -7
  190. package/.server/server/plugins/nunjucks/enviroment.test.js +10 -0
  191. package/.server/server/plugins/nunjucks/enviroment.test.js.map +1 -1
  192. package/.server/server/plugins/nunjucks/environment.d.ts +8 -0
  193. package/.server/server/plugins/nunjucks/environment.js +13 -0
  194. package/.server/server/plugins/nunjucks/environment.js.map +1 -1
  195. package/.server/server/plugins/nunjucks/filters/answer.js +9 -1
  196. package/.server/server/plugins/nunjucks/filters/answer.js.map +1 -1
  197. package/.server/server/plugins/nunjucks/filters/answer.test.js +13 -2
  198. package/.server/server/plugins/nunjucks/filters/answer.test.js.map +1 -1
  199. package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
  200. package/.server/server/plugins/postcode-lookup/models/index.d.ts +24 -19
  201. package/.server/server/plugins/postcode-lookup/models/index.js +83 -76
  202. package/.server/server/plugins/postcode-lookup/models/index.js.map +1 -1
  203. package/.server/server/plugins/postcode-lookup/routes/index.js +7 -13
  204. package/.server/server/plugins/postcode-lookup/routes/index.js.map +1 -1
  205. package/.server/server/plugins/postcode-lookup/types.d.ts +1 -0
  206. package/.server/server/plugins/postcode-lookup/types.js +1 -0
  207. package/.server/server/plugins/postcode-lookup/types.js.map +1 -1
  208. package/.server/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  209. package/.server/server/types.d.ts +2 -1
  210. package/.server/server/types.js.map +1 -1
  211. package/.server/server/utils/utils.d.ts +5 -0
  212. package/.server/server/utils/utils.js +16 -0
  213. package/.server/server/utils/utils.js.map +1 -1
  214. package/.server/typings/hapi/index.d.js.map +1 -1
  215. package/package.json +3 -2
  216. package/src/server/forms/register-as-a-unicorn-breeder.yaml +0 -14
  217. package/src/server/forms/simple-form.yaml +106 -3
  218. package/src/server/plugins/engine/components/AutocompleteField.ts +3 -6
  219. package/src/server/plugins/engine/components/CheckboxesField.ts +12 -11
  220. package/src/server/plugins/engine/components/ComponentCollection.ts +143 -61
  221. package/src/server/plugins/engine/components/DatePartsField.ts +33 -11
  222. package/src/server/plugins/engine/components/DeclarationField.ts +37 -14
  223. package/src/server/plugins/engine/components/EastingNorthingField.ts +83 -22
  224. package/src/server/plugins/engine/components/EmailAddressField.ts +4 -7
  225. package/src/server/plugins/engine/components/FileUploadField.ts +28 -22
  226. package/src/server/plugins/engine/components/FormComponent.ts +49 -12
  227. package/src/server/plugins/engine/components/GeospatialField.ts +36 -21
  228. package/src/server/plugins/engine/components/LatLongField.ts +52 -21
  229. package/src/server/plugins/engine/components/ListFormComponent.ts +26 -10
  230. package/src/server/plugins/engine/components/LocationFieldBase.ts +5 -8
  231. package/src/server/plugins/engine/components/LocationFieldHelpers.ts +3 -3
  232. package/src/server/plugins/engine/components/Markdown.ts +7 -3
  233. package/src/server/plugins/engine/components/MonthYearField.ts +32 -10
  234. package/src/server/plugins/engine/components/MultilineTextField.ts +5 -8
  235. package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +25 -11
  236. package/src/server/plugins/engine/components/NumberField.ts +3 -4
  237. package/src/server/plugins/engine/components/OsGridRefField.ts +25 -9
  238. package/src/server/plugins/engine/components/PaymentField.ts +22 -12
  239. package/src/server/plugins/engine/components/SelectField.ts +3 -6
  240. package/src/server/plugins/engine/components/SelectionControlField.ts +7 -8
  241. package/src/server/plugins/engine/components/TelephoneNumberField.ts +4 -7
  242. package/src/server/plugins/engine/components/UkAddressField.ts +33 -18
  243. package/src/server/plugins/engine/components/YesNoField.ts +10 -0
  244. package/src/server/plugins/engine/components/helpers/components.ts +13 -6
  245. package/src/server/plugins/engine/components/types.ts +9 -0
  246. package/src/server/plugins/engine/configureEnginePlugin.ts +12 -1
  247. package/src/server/plugins/engine/form-context.ts +8 -2
  248. package/src/server/plugins/engine/helpers.ts +10 -18
  249. package/src/server/plugins/engine/i18n/buildValidationMessages.ts +69 -0
  250. package/src/server/plugins/engine/i18n/createFormTranslator.ts +33 -0
  251. package/src/server/plugins/engine/i18n/createTranslator.ts +61 -0
  252. package/src/server/plugins/engine/i18n/extractBaseTranslations.ts +61 -0
  253. package/src/server/plugins/engine/i18n/index.ts +80 -0
  254. package/src/server/plugins/engine/i18n/translations/cy.json +271 -0
  255. package/src/server/plugins/engine/i18n/translations/en-GB.json +271 -0
  256. package/src/server/plugins/engine/i18n/types.ts +62 -0
  257. package/src/server/plugins/engine/index.ts +4 -2
  258. package/src/server/plugins/engine/models/FormModel.ts +59 -23
  259. package/src/server/plugins/engine/models/SummaryViewModel.ts +68 -25
  260. package/src/server/plugins/engine/options.js +2 -1
  261. package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +5 -0
  262. package/src/server/plugins/engine/outputFormatters/human/v1.ts +2 -3
  263. package/src/server/plugins/engine/outputFormatters/machine/v1.ts +9 -8
  264. package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +7 -3
  265. package/src/server/plugins/engine/pageControllers/PageController.ts +12 -1
  266. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +53 -21
  267. package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +66 -29
  268. package/src/server/plugins/engine/pageControllers/StartPageController.ts +7 -2
  269. package/src/server/plugins/engine/pageControllers/StatusPageController.ts +10 -2
  270. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +48 -22
  271. package/src/server/plugins/engine/pageControllers/__stubs__/translator.ts +28 -0
  272. package/src/server/plugins/engine/pageControllers/errors.ts +4 -2
  273. package/src/server/plugins/engine/pageControllers/helpers/submission.ts +11 -4
  274. package/src/server/plugins/engine/pageControllers/validationOptions.ts +43 -53
  275. package/src/server/plugins/engine/plugin.ts +2 -0
  276. package/src/server/plugins/engine/routes/index.ts +9 -1
  277. package/src/server/plugins/engine/routes/questions.ts +5 -1
  278. package/src/server/plugins/engine/types/index.ts +5 -0
  279. package/src/server/plugins/engine/types/schema.ts +1 -0
  280. package/src/server/plugins/engine/types.ts +10 -0
  281. package/src/server/plugins/engine/views/components/_location-field-base.html +1 -1
  282. package/src/server/plugins/engine/views/components/fileuploadfield.html +3 -3
  283. package/src/server/plugins/engine/views/components/nationalgridfieldnumberfield.html +1 -1
  284. package/src/server/plugins/engine/views/components/osgridreffield.html +1 -1
  285. package/src/server/plugins/engine/views/components/paymentfield.html +8 -8
  286. package/src/server/plugins/engine/views/components/ukaddressfield.html +4 -4
  287. package/src/server/plugins/engine/views/confirmation.html +4 -4
  288. package/src/server/plugins/engine/views/exit.html +4 -4
  289. package/src/server/plugins/engine/views/file-upload.html +3 -3
  290. package/src/server/plugins/engine/views/index.html +3 -3
  291. package/src/server/plugins/engine/views/item-delete.html +1 -1
  292. package/src/server/plugins/engine/views/partials/form.html +3 -3
  293. package/src/server/plugins/engine/views/partials/preview-banner.html +4 -4
  294. package/src/server/plugins/engine/views/partials/warn-missing-notification-email.html +4 -5
  295. package/src/server/plugins/engine/views/repeat-list-summary.html +4 -4
  296. package/src/server/plugins/engine/views/summary.html +14 -7
  297. package/src/server/plugins/nunjucks/environment.js +14 -0
  298. package/src/server/plugins/nunjucks/filters/answer.js +12 -1
  299. package/src/server/plugins/postcode-lookup/models/index.js +144 -87
  300. package/src/server/plugins/postcode-lookup/routes/index.js +13 -16
  301. package/src/server/plugins/postcode-lookup/types.js +1 -0
  302. package/src/server/plugins/postcode-lookup/views/postcode-lookup-details.html +3 -3
  303. package/src/server/types.ts +2 -0
  304. package/src/server/utils/utils.js +14 -0
  305. package/src/typings/hapi/index.d.ts +1 -0
  306. package/.server/server/plugins/engine/components/constants.d.ts +0 -1
  307. package/.server/server/plugins/engine/components/constants.js +0 -2
  308. package/.server/server/plugins/engine/components/constants.js.map +0 -1
  309. package/src/server/plugins/engine/components/constants.ts +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":["FileStatus","UploadStatus"],"sources":["../../../../src/server/plugins/engine/types.ts"],"sourcesContent":["import {\n type ComponentDef,\n type Event,\n type FormVersionMetadata,\n type Item,\n type List,\n type Page,\n type PaymentFieldComponent,\n type UkAddressFieldComponent\n} from '@defra/forms-model'\nimport {\n type PluginProperties,\n type Request,\n type ResponseObject\n} from '@hapi/hapi'\nimport { type JoiExpression, type ValidationErrorItem } from 'joi'\n\nimport { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { type UkAddressState } from '~/src/server/plugins/engine/components/UkAddressField.js'\nimport { type Component } from '~/src/server/plugins/engine/components/helpers/components.js'\nimport {\n type FileUploadField,\n type PaymentField\n} from '~/src/server/plugins/engine/components/index.js'\nimport {\n type BackLink,\n type ComponentText,\n type ComponentViewModel,\n type DatePartsState,\n type EastingNorthingState,\n type LatLongState,\n type MonthYearState\n} from '~/src/server/plugins/engine/components/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type DetailItemField } from '~/src/server/plugins/engine/models/types.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport { type QuestionPageController } from '~/src/server/plugins/engine/pageControllers/index.js'\nimport {\n type FileStatus,\n type FormAdapterSubmissionSchemaVersion,\n type UploadStatus\n} from '~/src/server/plugins/engine/types/enums.js'\nimport { type ViewContext } from '~/src/server/plugins/nunjucks/types.js'\nimport {\n type FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormResponseToolkit,\n type FormStatus\n} from '~/src/server/routes/types.js'\nimport { type CacheService } from '~/src/server/services/cacheService.js'\nimport { type RequestOptions } from '~/src/server/services/httpService.js'\nimport { type Services } from '~/src/server/types.js'\n\nexport type AnyFormRequest = FormRequest | FormRequestPayload\nexport type AnyRequest = Request | AnyFormRequest\n\nexport interface CacheRequest {\n yar: { id: string | undefined }\n params: { slug?: string; state?: string }\n}\n\n/**\n * Form submission state stores the following in Redis:\n * Props containing user's submitted values as `{ [inputId]: value }` or as `{ [sectionName]: { [inputName]: value } }`\n * a) . e.g:\n * ```ts\n * {\n * _C9PRHmsgt: 'Ben',\n * WfLk9McjzX: 'Music',\n * IK7jkUFCBL: 'Royal Academy of Music'\n * }\n * ```\n *\n * b)\n * ```ts\n * {\n * checkBeforeYouStart: { ukPassport: true },\n * applicantDetails: {\n * numberOfApplicants: 1,\n * phoneNumber: '77777777',\n * emailAddress: 'aaa@aaa.com'\n * },\n * applicantOneDetails: {\n * firstName: 'a',\n * middleName: 'a',\n * lastName: 'a',\n * address: { addressLine1: 'a', addressLine2: 'a', town: 'a', postcode: 'a' }\n * }\n * }\n * ```\n */\n\n/**\n * Form submission state\n */\nexport type FormSubmissionState = {\n upload?: Record<string, TempFileState>\n} & FormState\n\nexport interface FormSubmissionError extends Pick<\n ValidationErrorItem,\n 'context' | 'path'\n> {\n href: string // e.g: '#dateField__day'\n name: string // e.g: 'dateField__day'\n text: string // e.g: 'Date field must be a real date'\n}\n\nexport interface FormConfirmationState {\n confirmed?: true\n formId?: string\n referenceNumber?: string\n}\n\nexport interface FormPayloadParams {\n action?: FormAction\n confirm?: true\n crumb?: string\n itemId?: string\n}\n\n/**\n * Form POST for question pages\n * (after Joi has converted value types)\n */\nexport type FormPayload = FormPayloadParams & Partial<Record<string, FormValue>>\n\nexport type FormValue =\n | Item['value']\n | Item['value'][]\n | UploadState\n | RepeatListState\n | GeospatialState\n | undefined\n\nexport type FormState = Partial<Record<string, FormStateValue>>\nexport type FormStateValue = Exclude<FormValue, undefined> | null\n\nexport interface FormValidationResult<\n ValueType extends FormPayload | FormSubmissionState\n> {\n value: ValueType\n errors: FormSubmissionError[] | undefined\n}\n\nexport interface FormContext {\n /**\n * Evaluation form state only (filtered by visited paths),\n * with values formatted for condition evaluation using\n * {@link FormComponent.getContextValueFromState}\n */\n evaluationState: FormState\n\n /**\n * Relevant form state only (filtered by visited paths)\n */\n relevantState: FormState\n\n /**\n * Relevant pages only (filtered by visited paths)\n */\n relevantPages: PageControllerClass[]\n\n /**\n * Form submission payload (single page)\n */\n payload: FormPayload\n\n /**\n * Form submission state (entire form)\n */\n state: FormSubmissionState\n\n /**\n * Validation errors (entire form)\n */\n errors?: FormSubmissionError[]\n\n /**\n * Visited paths evaluated from form state\n */\n paths: string[]\n\n /**\n * Preview URL direct access is allowed\n */\n isForceAccess: boolean\n\n /**\n * Miscellaneous extra data from event responses\n */\n data: object\n\n pageDefMap: Map<string, Page>\n listDefMap: Map<string, List>\n componentDefMap: Map<string, ComponentDef>\n pageMap: Map<string, PageControllerClass>\n componentMap: Map<string, Component>\n referenceNumber: string\n}\n\nexport type FormContextRequest = (\n | {\n method: 'get'\n payload?: undefined\n }\n | {\n method: 'post'\n payload: FormPayload\n }\n | {\n method: FormRequest['method']\n payload?: object | undefined\n }\n) &\n Pick<\n FormRequest,\n 'app' | 'method' | 'params' | 'path' | 'query' | 'url' | 'server'\n >\n\nexport interface UploadInitiateResponse {\n uploadId: string\n uploadUrl: string\n statusUrl: string\n}\n\nexport {\n FileStatus,\n UploadStatus\n} from '~/src/server/plugins/engine/types/enums.js'\n\nexport type UploadState = FileState[]\n\nexport type FileUpload = {\n fileId: string\n filename: string\n contentLength: number\n} & (\n | {\n fileStatus: FileStatus.complete | FileStatus.rejected | FileStatus.pending\n errorMessage?: string\n }\n | {\n fileStatus: FileStatus.complete\n errorMessage?: undefined\n }\n)\n\nexport interface FileUploadMetadata {\n retrievalKey: string\n}\n\nexport type UploadStatusResponse =\n | {\n uploadStatus: UploadStatus.initiated\n metadata: FileUploadMetadata\n form: { file?: undefined }\n }\n | {\n uploadStatus: UploadStatus.pending | UploadStatus.ready\n metadata: FileUploadMetadata\n form: { file: FileUpload }\n numberOfRejectedFiles?: number\n }\n | {\n uploadStatus: UploadStatus.ready\n metadata: FileUploadMetadata\n form: { file: FileUpload }\n numberOfRejectedFiles: 0\n }\n\nexport type UploadStatusFileResponse = Exclude<\n UploadStatusResponse,\n { uploadStatus: UploadStatus.initiated }\n>\n\nexport interface FileState {\n uploadId: string\n status: UploadStatusFileResponse\n}\n\nexport interface TempFileState {\n upload?: UploadInitiateResponse\n files: UploadState\n}\n\nexport interface RepeatItemState extends FormPayload {\n itemId: string\n}\n\nexport type RepeatListState = RepeatItemState[]\n\n/**\n * A longitude/latitude coordinate pair in WGS84 format\n * Format: [longitude, latitude]\n */\nexport type Coordinates = [longitude: number, latitude: number]\n\n/**\n * GeoJSON Point geometry\n */\nexport interface PointGeometry {\n type: 'Point'\n coordinates: Coordinates\n}\n\n/**\n * GeoJSON LineString geometry\n */\nexport interface LineStringGeometry {\n type: 'LineString'\n coordinates: Coordinates[]\n}\n\n/**\n * GeoJSON Polygon geometry\n */\nexport interface PolygonGeometry {\n type: 'Polygon'\n coordinates: Coordinates[][]\n}\n\n/**\n * Supported geometry types\n */\nexport type Geometry = PointGeometry | LineStringGeometry | PolygonGeometry\n\n/**\n * Feature metadata\n */\nexport interface FeatureProperties {\n /**\n * Human-readable description of the feature\n */\n description: string\n /**\n * The OS grid reference of the first coordinate of the feature\n */\n coordinateGridReference?: string\n /**\n * The OS grid reference of the centroid of the feature\n */\n centroidGridReference?: string\n}\n\n/**\n * A single GeoJSON Feature\n */\nexport interface Feature {\n id: string\n type: 'Feature'\n properties: FeatureProperties\n geometry: Geometry\n}\n\n/**\n * A GeoJSON FeatureCollection\n */\nexport type FeatureCollection = Feature[]\n\nexport type GeospatialState = FeatureCollection\n\nexport interface CheckAnswers {\n title?: ComponentText\n summaryList: SummaryList\n}\n\nexport interface SummaryList {\n classes?: string\n rows: SummaryListRow[]\n}\n\nexport interface SummaryListRow {\n key: ComponentText\n value: ComponentText\n actions?: { items: SummaryListAction[] }\n}\n\nexport type SummaryListAction = ComponentText & {\n href: string\n visuallyHiddenText: string\n}\n\nexport interface PageViewModelBase extends Partial<ViewContext> {\n page: PageController\n name?: string\n pageTitle: string\n sectionTitle?: string\n showTitle: boolean\n isStartPage: boolean\n backLink?: BackLink\n feedbackLink?: string\n serviceUrl: string\n phaseTag?: string\n}\n\nexport interface ItemDeletePageViewModel extends PageViewModelBase {\n context: FormContext\n itemTitle: string\n confirmation?: ComponentText\n buttonConfirm: ComponentText\n buttonCancel: ComponentText\n}\n\nexport interface FormPageViewModel extends PageViewModelBase {\n components: ComponentViewModel[]\n context: FormContext\n errors?: FormSubmissionError[]\n hasMissingNotificationEmail?: boolean\n allowSaveAndExit: boolean\n showSubmitButton?: boolean\n showPaymentExpiredNotification?: boolean\n}\n\nexport interface RepeaterSummaryPageViewModel extends PageViewModelBase {\n context: FormContext\n errors?: FormSubmissionError[]\n checkAnswers: CheckAnswers[]\n repeatTitle: string\n allowSaveAndExit: boolean\n}\n\nexport interface FeaturedFormPageViewModel extends FormPageViewModel {\n formAction?: string\n formComponent: ComponentViewModel\n componentsBefore: ComponentViewModel[]\n uploadId: string | undefined\n proxyUrl: string | null\n}\n\nexport type PageViewModel =\n | PageViewModelBase\n | ItemDeletePageViewModel\n | FormPageViewModel\n | RepeaterSummaryPageViewModel\n | FeaturedFormPageViewModel\n\nexport type GlobalFunction = (value: unknown) => unknown\nexport type FilterFunction = (value: unknown) => unknown\nexport interface ErrorMessageTemplate {\n type: string\n template: JoiExpression\n}\n\nexport interface ErrorMessageTemplateList {\n baseErrors: ErrorMessageTemplate[]\n advancedSettingsErrors: ErrorMessageTemplate[]\n}\n\nexport type PreparePageEventRequestOptions = (\n options: RequestOptions,\n event: Event,\n page: PageControllerClass,\n context: FormContext\n) => void\n\nexport type OnRequestCallback = (\n request: AnyFormRequest,\n h: FormResponseToolkit,\n context: FormContext\n) =>\n | ResponseObject\n | FormResponseToolkit['continue']\n | Promise<ResponseObject | FormResponseToolkit['continue']>\n\nexport type SaveAndExitHandler = (\n request: FormRequestPayload,\n h: FormResponseToolkit,\n context: FormContext\n) => ResponseObject\n\nexport interface ExternalArgs {\n component: ComponentDef\n controller: QuestionPageController\n sourceUrl: string\n actionArgs?: Record<string, string>\n isLive: boolean\n isPreview: boolean\n}\n\nexport interface PostcodeLookupExternalArgs extends ExternalArgs {\n component: UkAddressFieldComponent\n actionArgs: { step: string }\n}\n\nexport interface PaymentExternalArgs extends ExternalArgs {\n component: PaymentFieldComponent\n}\n\nexport interface ExternalStateAppendage {\n component: string\n data: FormStateValue | FormState\n}\n\nexport interface PluginOptions {\n model?: FormModel\n services?: Services\n controllers?: Record<string, typeof PageController>\n cache?: CacheService | string\n globals?: Record<string, GlobalFunction>\n filters?: Record<string, FilterFunction>\n saveAndExit?: SaveAndExitHandler\n pluginPath?: string\n nunjucks: {\n baseLayoutPath: string\n paths: string[]\n }\n viewContext: PluginProperties['forms-engine-plugin']['viewContext']\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n onRequest?: OnRequestCallback\n baseUrl: string // base URL of the application, protocol and hostname e.g. \"https://myapp.com\"\n ordnanceSurveyApiKey?: string\n ordnanceSurveyApiSecret?: string\n}\n\nexport interface FormAdapterSubmissionMessageMeta {\n schemaVersion: FormAdapterSubmissionSchemaVersion\n timestamp: Date\n referenceNumber: string\n formName: string\n formId: string\n formSlug: string\n status: FormStatus\n isPreview: boolean\n notificationEmail: string\n versionMetadata?: FormVersionMetadata\n custom?: Record<string, unknown>\n}\n\nexport type FormAdapterSubmissionMessageMetaSerialised = Omit<\n FormAdapterSubmissionMessageMeta,\n 'schemaVersion' | 'timestamp' | 'status'\n> & {\n schemaVersion: number\n status: string\n timestamp: string\n}\nexport interface FormAdapterFile {\n fileName: string\n fileId: string\n userDownloadLink: string\n}\n\nexport interface FormAdapterPayment {\n paymentId: string\n reference: string\n amount: number\n description: string\n createdAt: string\n}\n\nexport interface FormAdapterSubmissionMessageResult {\n files: {\n main: string\n repeaters: Record<string, string>\n }\n}\n\n/**\n * A detail item specifically for files\n */\nexport type FileUploadFieldDetailitem = Omit<DetailItemField, 'field'> & {\n field: FileUploadField\n}\n\n/**\n * A detail item specifically for payments\n */\nexport type PaymentFieldDetailItem = Omit<DetailItemField, 'field'> & {\n field: PaymentField\n}\nexport type RichFormValue =\n | FormValue\n | FormPayload\n | DatePartsState\n | MonthYearState\n | UkAddressState\n | EastingNorthingState\n | LatLongState\n | GeospatialState\n\nexport interface FormAdapterSubmissionMessageData {\n main: Record<string, RichFormValue | null>\n repeaters: Record<string, Record<string, RichFormValue>[]>\n files: Record<string, FormAdapterFile[]>\n payment?: FormAdapterPayment\n}\n\nexport interface FormAdapterSubmissionMessagePayload {\n meta: FormAdapterSubmissionMessageMeta\n data: FormAdapterSubmissionMessageData\n result: FormAdapterSubmissionMessageResult\n}\n\nexport interface FormAdapterSubmissionMessage extends FormAdapterSubmissionMessagePayload {\n messageId: string\n recordCreatedAt: Date\n}\n\nexport interface FormAdapterSubmissionService {\n handleFormSubmission: (\n submissionMessage: FormAdapterSubmissionMessage\n ) => unknown\n}\n"],"mappings":"AA+DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AA2BA;AACA;AACA;AACA;;AAsGA,SACEA,UAAU,EACVC,YAAY;;AAgEd;AACA;AACA;AACA;;AAGA;AACA;AACA;;AAMA;AACA;AACA;;AAMA;AACA;AACA;;AAMA;AACA;AACA;;AAGA;AACA;AACA;;AAgBA;AACA;AACA;;AAQA;AACA;AACA;;AAyMA;AACA;AACA;;AAKA;AACA;AACA","ignoreList":[]}
1
+ {"version":3,"file":"types.js","names":["FileStatus","UploadStatus"],"sources":["../../../../src/server/plugins/engine/types.ts"],"sourcesContent":["import {\n type ComponentDef,\n type Event,\n type FormVersionMetadata,\n type Item,\n type List,\n type Page,\n type PaymentFieldComponent,\n type UkAddressFieldComponent\n} from '@defra/forms-model'\nimport {\n type PluginProperties,\n type Request,\n type RequestQuery,\n type ResponseObject\n} from '@hapi/hapi'\nimport { type Yar } from '@hapi/yar'\nimport { type JoiExpression, type ValidationErrorItem } from 'joi'\n\nimport { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { type UkAddressState } from '~/src/server/plugins/engine/components/UkAddressField.js'\nimport { type Component } from '~/src/server/plugins/engine/components/helpers/components.js'\nimport {\n type FileUploadField,\n type PaymentField\n} from '~/src/server/plugins/engine/components/index.js'\nimport {\n type BackLink,\n type ComponentText,\n type ComponentViewModel,\n type DatePartsState,\n type EastingNorthingState,\n type LatLongState,\n type MonthYearState\n} from '~/src/server/plugins/engine/components/types.js'\nimport { type Translator } from '~/src/server/plugins/engine/i18n/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type DetailItemField } from '~/src/server/plugins/engine/models/types.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport { type QuestionPageController } from '~/src/server/plugins/engine/pageControllers/index.js'\nimport {\n type FileStatus,\n type FormAdapterSubmissionSchemaVersion,\n type UploadStatus\n} from '~/src/server/plugins/engine/types/enums.js'\nimport { type ViewContext } from '~/src/server/plugins/nunjucks/types.js'\nimport {\n type FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormResponseToolkit,\n type FormStatus\n} from '~/src/server/routes/types.js'\nimport { type CacheService } from '~/src/server/services/cacheService.js'\nimport { type RequestOptions } from '~/src/server/services/httpService.js'\nimport { type Services } from '~/src/server/types.js'\n\nexport type AnyFormRequest = FormRequest | FormRequestPayload\nexport type AnyRequest = Request | AnyFormRequest\n\nexport interface CacheRequest {\n yar: { id: string | undefined }\n params: { slug?: string; state?: string }\n}\n\n/**\n * Form submission state stores the following in Redis:\n * Props containing user's submitted values as `{ [inputId]: value }` or as `{ [sectionName]: { [inputName]: value } }`\n * a) . e.g:\n * ```ts\n * {\n * _C9PRHmsgt: 'Ben',\n * WfLk9McjzX: 'Music',\n * IK7jkUFCBL: 'Royal Academy of Music'\n * }\n * ```\n *\n * b)\n * ```ts\n * {\n * checkBeforeYouStart: { ukPassport: true },\n * applicantDetails: {\n * numberOfApplicants: 1,\n * phoneNumber: '77777777',\n * emailAddress: 'aaa@aaa.com'\n * },\n * applicantOneDetails: {\n * firstName: 'a',\n * middleName: 'a',\n * lastName: 'a',\n * address: { addressLine1: 'a', addressLine2: 'a', town: 'a', postcode: 'a' }\n * }\n * }\n * ```\n */\n\n/**\n * Form submission state\n */\nexport type FormSubmissionState = {\n upload?: Record<string, TempFileState>\n} & FormState\n\nexport interface FormSubmissionError extends Pick<\n ValidationErrorItem,\n 'context' | 'path'\n> {\n href: string // e.g: '#dateField__day'\n name: string // e.g: 'dateField__day'\n text: string // e.g: 'Date field must be a real date'\n}\n\nexport interface FormConfirmationState {\n confirmed?: true\n formId?: string\n referenceNumber?: string\n}\n\nexport interface FormPayloadParams {\n action?: FormAction\n confirm?: true\n crumb?: string\n itemId?: string\n}\n\n/**\n * Form POST for question pages\n * (after Joi has converted value types)\n */\nexport type FormPayload = FormPayloadParams & Partial<Record<string, FormValue>>\n\nexport type FormValue =\n | Item['value']\n | Item['value'][]\n | UploadState\n | RepeatListState\n | GeospatialState\n | undefined\n\nexport type FormState = Partial<Record<string, FormStateValue>>\nexport type FormStateValue = Exclude<FormValue, undefined> | null\n\nexport interface FormValidationResult<\n ValueType extends FormPayload | FormSubmissionState\n> {\n value: ValueType\n errors: FormSubmissionError[] | undefined\n}\n\nexport interface FormContext {\n /**\n * Evaluation form state only (filtered by visited paths),\n * with values formatted for condition evaluation using\n * {@link FormComponent.getContextValueFromState}\n */\n evaluationState: FormState\n\n /**\n * Relevant form state only (filtered by visited paths)\n */\n relevantState: FormState\n\n /**\n * Relevant pages only (filtered by visited paths)\n */\n relevantPages: PageControllerClass[]\n\n /**\n * Form submission payload (single page)\n */\n payload: FormPayload\n\n /**\n * Form submission state (entire form)\n */\n state: FormSubmissionState\n\n /**\n * Validation errors (entire form)\n */\n errors?: FormSubmissionError[]\n\n /**\n * Visited paths evaluated from form state\n */\n paths: string[]\n\n /**\n * Preview URL direct access is allowed\n */\n isForceAccess: boolean\n\n /**\n * Miscellaneous extra data from event responses\n */\n data: object\n\n pageDefMap: Map<string, Page>\n listDefMap: Map<string, List>\n componentDefMap: Map<string, ComponentDef>\n pageMap: Map<string, PageControllerClass>\n componentMap: Map<string, Component>\n referenceNumber: string\n languages: { name: string; code: string }[]\n translator: Translator | undefined\n}\n\nexport type FormContextRequest = (\n | {\n method: 'get'\n payload?: undefined\n }\n | {\n method: 'post'\n payload: FormPayload\n }\n | {\n method: FormRequest['method']\n payload?: object | undefined\n }\n) &\n Pick<\n FormRequest,\n 'app' | 'method' | 'params' | 'path' | 'query' | 'url' | 'server'\n >\n\nexport interface UploadInitiateResponse {\n uploadId: string\n uploadUrl: string\n statusUrl: string\n}\n\nexport {\n FileStatus,\n UploadStatus\n} from '~/src/server/plugins/engine/types/enums.js'\n\nexport type UploadState = FileState[]\n\nexport type FileUpload = {\n fileId: string\n filename: string\n contentLength: number\n} & (\n | {\n fileStatus: FileStatus.complete | FileStatus.rejected | FileStatus.pending\n errorMessage?: string\n }\n | {\n fileStatus: FileStatus.complete\n errorMessage?: undefined\n }\n)\n\nexport interface FileUploadMetadata {\n retrievalKey: string\n}\n\nexport type UploadStatusResponse =\n | {\n uploadStatus: UploadStatus.initiated\n metadata: FileUploadMetadata\n form: { file?: undefined }\n }\n | {\n uploadStatus: UploadStatus.pending | UploadStatus.ready\n metadata: FileUploadMetadata\n form: { file: FileUpload }\n numberOfRejectedFiles?: number\n }\n | {\n uploadStatus: UploadStatus.ready\n metadata: FileUploadMetadata\n form: { file: FileUpload }\n numberOfRejectedFiles: 0\n }\n\nexport type UploadStatusFileResponse = Exclude<\n UploadStatusResponse,\n { uploadStatus: UploadStatus.initiated }\n>\n\nexport interface FileState {\n uploadId: string\n status: UploadStatusFileResponse\n}\n\nexport interface TempFileState {\n upload?: UploadInitiateResponse\n files: UploadState\n}\n\nexport interface RepeatItemState extends FormPayload {\n itemId: string\n}\n\nexport type RepeatListState = RepeatItemState[]\n\n/**\n * A longitude/latitude coordinate pair in WGS84 format\n * Format: [longitude, latitude]\n */\nexport type Coordinates = [longitude: number, latitude: number]\n\n/**\n * GeoJSON Point geometry\n */\nexport interface PointGeometry {\n type: 'Point'\n coordinates: Coordinates\n}\n\n/**\n * GeoJSON LineString geometry\n */\nexport interface LineStringGeometry {\n type: 'LineString'\n coordinates: Coordinates[]\n}\n\n/**\n * GeoJSON Polygon geometry\n */\nexport interface PolygonGeometry {\n type: 'Polygon'\n coordinates: Coordinates[][]\n}\n\n/**\n * Supported geometry types\n */\nexport type Geometry = PointGeometry | LineStringGeometry | PolygonGeometry\n\n/**\n * Feature metadata\n */\nexport interface FeatureProperties {\n /**\n * Human-readable description of the feature\n */\n description: string\n /**\n * The OS grid reference of the first coordinate of the feature\n */\n coordinateGridReference?: string\n /**\n * The OS grid reference of the centroid of the feature\n */\n centroidGridReference?: string\n}\n\n/**\n * A single GeoJSON Feature\n */\nexport interface Feature {\n id: string\n type: 'Feature'\n properties: FeatureProperties\n geometry: Geometry\n}\n\n/**\n * A GeoJSON FeatureCollection\n */\nexport type FeatureCollection = Feature[]\n\nexport type GeospatialState = FeatureCollection\n\nexport interface CheckAnswers {\n title?: ComponentText\n summaryList: SummaryList\n}\n\nexport interface SummaryList {\n classes?: string\n rows: SummaryListRow[]\n}\n\nexport interface SummaryListRow {\n key: ComponentText\n value: ComponentText\n actions?: { items: SummaryListAction[] }\n}\n\nexport type SummaryListAction = ComponentText & {\n href: string\n visuallyHiddenText: string\n}\n\nexport interface PageViewModelBase extends Partial<ViewContext> {\n page: PageController\n name?: string\n pageTitle: string\n sectionTitle?: string\n showTitle: boolean\n isStartPage: boolean\n backLink?: BackLink\n feedbackLink?: string\n serviceUrl: string\n phaseTag?: string\n t?: (key: string, opts?: Record<string, unknown>) => string\n}\n\nexport interface ItemDeletePageViewModel extends PageViewModelBase {\n context: FormContext\n itemTitle: string\n confirmation?: ComponentText\n buttonConfirm: ComponentText\n buttonCancel: ComponentText\n}\n\nexport interface FormPageViewModel extends PageViewModelBase {\n components: ComponentViewModel[]\n context: FormContext\n errors?: FormSubmissionError[]\n hasMissingNotificationEmail?: boolean\n allowSaveAndExit: boolean\n showSubmitButton?: boolean\n showPaymentExpiredNotification?: boolean\n}\n\nexport interface RepeaterSummaryPageViewModel extends PageViewModelBase {\n context: FormContext\n errors?: FormSubmissionError[]\n checkAnswers: CheckAnswers[]\n repeatTitle: string\n allowSaveAndExit: boolean\n}\n\nexport interface FeaturedFormPageViewModel extends FormPageViewModel {\n formAction?: string\n formComponent: ComponentViewModel\n componentsBefore: ComponentViewModel[]\n uploadId: string | undefined\n proxyUrl: string | null\n}\n\nexport type PageViewModel =\n | PageViewModelBase\n | ItemDeletePageViewModel\n | FormPageViewModel\n | RepeaterSummaryPageViewModel\n | FeaturedFormPageViewModel\n\nexport type GlobalFunction = (value: unknown) => unknown\nexport type FilterFunction = (value: unknown) => unknown\nexport interface ErrorMessageTemplate {\n type: string\n template: JoiExpression\n}\n\nexport interface ErrorMessageTemplateList {\n baseErrors: ErrorMessageTemplate[]\n advancedSettingsErrors: ErrorMessageTemplate[]\n}\n\nexport type PreparePageEventRequestOptions = (\n options: RequestOptions,\n event: Event,\n page: PageControllerClass,\n context: FormContext\n) => void\n\nexport type OnRequestCallback = (\n request: AnyFormRequest,\n h: FormResponseToolkit,\n context: FormContext\n) =>\n | ResponseObject\n | FormResponseToolkit['continue']\n | Promise<ResponseObject | FormResponseToolkit['continue']>\n\nexport type SaveAndExitHandler = (\n request: FormRequestPayload,\n h: FormResponseToolkit,\n context: FormContext\n) => ResponseObject\n\nexport type GetLanguageHandler = (query?: RequestQuery, yar?: Yar) => string\n\nexport interface ExternalArgs {\n component: ComponentDef\n controller: QuestionPageController\n sourceUrl: string\n actionArgs?: Record<string, string>\n isLive: boolean\n isPreview: boolean\n}\n\nexport interface PostcodeLookupExternalArgs extends ExternalArgs {\n component: UkAddressFieldComponent\n actionArgs: { step: string }\n}\n\nexport interface PaymentExternalArgs extends ExternalArgs {\n component: PaymentFieldComponent\n}\n\nexport interface ExternalStateAppendage {\n component: string\n data: FormStateValue | FormState\n}\n\nexport interface PluginOptions {\n model?: FormModel\n services?: Services\n controllers?: Record<string, typeof PageController>\n cache?: CacheService | string\n globals?: Record<string, GlobalFunction>\n filters?: Record<string, FilterFunction>\n saveAndExit?: SaveAndExitHandler\n pluginPath?: string\n nunjucks: {\n baseLayoutPath: string\n paths: string[]\n }\n viewContext: PluginProperties['forms-engine-plugin']['viewContext']\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n onRequest?: OnRequestCallback\n getLanguage?: GetLanguageHandler\n baseUrl: string // base URL of the application, protocol and hostname e.g. \"https://myapp.com\"\n ordnanceSurveyApiKey?: string\n ordnanceSurveyApiSecret?: string\n}\n\nexport interface FormAdapterSubmissionMessageMeta {\n schemaVersion: FormAdapterSubmissionSchemaVersion\n timestamp: Date\n referenceNumber: string\n formName: string\n formId: string\n formSlug: string\n status: FormStatus\n isPreview: boolean\n notificationEmail: string\n versionMetadata?: FormVersionMetadata\n language?: string\n custom?: Record<string, unknown>\n}\n\nexport type FormAdapterSubmissionMessageMetaSerialised = Omit<\n FormAdapterSubmissionMessageMeta,\n 'schemaVersion' | 'timestamp' | 'status'\n> & {\n schemaVersion: number\n status: string\n timestamp: string\n}\nexport interface FormAdapterFile {\n fileName: string\n fileId: string\n userDownloadLink: string\n}\n\nexport interface FormAdapterPayment {\n paymentId: string\n reference: string\n amount: number\n description: string\n createdAt: string\n}\n\nexport interface FormAdapterSubmissionMessageResult {\n files: {\n main: string\n repeaters: Record<string, string>\n }\n}\n\n/**\n * A detail item specifically for files\n */\nexport type FileUploadFieldDetailitem = Omit<DetailItemField, 'field'> & {\n field: FileUploadField\n}\n\n/**\n * A detail item specifically for payments\n */\nexport type PaymentFieldDetailItem = Omit<DetailItemField, 'field'> & {\n field: PaymentField\n}\nexport type RichFormValue =\n | FormValue\n | FormPayload\n | DatePartsState\n | MonthYearState\n | UkAddressState\n | EastingNorthingState\n | LatLongState\n | GeospatialState\n\nexport interface FormAdapterSubmissionMessageData {\n main: Record<string, RichFormValue | null>\n repeaters: Record<string, Record<string, RichFormValue>[]>\n files: Record<string, FormAdapterFile[]>\n payment?: FormAdapterPayment\n}\n\nexport interface FormAdapterSubmissionMessagePayload {\n meta: FormAdapterSubmissionMessageMeta\n data: FormAdapterSubmissionMessageData\n result: FormAdapterSubmissionMessageResult\n}\n\nexport interface FormAdapterSubmissionMessage extends FormAdapterSubmissionMessagePayload {\n messageId: string\n recordCreatedAt: Date\n}\n\nexport interface FormAdapterSubmissionService {\n handleFormSubmission: (\n submissionMessage: FormAdapterSubmissionMessage\n ) => unknown\n}\n"],"mappings":"AAkEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AA2BA;AACA;AACA;AACA;;AAwGA,SACEA,UAAU,EACVC,YAAY;;AAgEd;AACA;AACA;AACA;;AAGA;AACA;AACA;;AAMA;AACA;AACA;;AAMA;AACA;AACA;;AAMA;AACA;AACA;;AAGA;AACA;AACA;;AAgBA;AACA;AACA;;AAQA;AACA;AACA;;AA8MA;AACA;AACA;;AAKA;AACA;AACA","ignoreList":[]}
@@ -61,7 +61,7 @@
61
61
  {% set detailsHtml %}
62
62
  {% if component.model.instructionText %}
63
63
  {{ govukDetails({
64
- summaryText: "How to find location details",
64
+ summaryText: t('components.locationFieldBase.howToFind'),
65
65
  html: component.model.instructionText | markdown | safe,
66
66
  classes: "govuk-!-margin-top-3"
67
67
  }) }}
@@ -4,9 +4,9 @@
4
4
  {% set upload = component.model.upload %}
5
5
 
6
6
  <div id="uploadedFilesContainer">
7
- <h2 class="govuk-heading-m">Uploaded files</h2>
7
+ <h2 class="govuk-heading-m">{{ t('components.fileUploadField.uploadedFilesHeading') }}</h2>
8
8
  {% if upload.count %}
9
- <p class="govuk-body" role="alert">{{upload.count}} file{{ "s" if upload.count > 1}} uploaded</p>
9
+ <p class="govuk-body" role="alert">{{ t('components.fileUploadField.filesCount', { count: upload.count }) }}</p>
10
10
  <p class="govuk-body">
11
11
  </p>
12
12
 
@@ -14,7 +14,7 @@
14
14
  {{ govukSummaryList(upload.summaryList) }}
15
15
  {% endif %}
16
16
  {% else %}
17
- <p class="govuk-body">{{upload.count}} files uploaded</p>
17
+ <p class="govuk-body">{{ t('components.fileUploadField.filesCount', { count: upload.count }) }}</p>
18
18
  {% endif %}
19
19
  </div>
20
20
  {% endmacro %}
@@ -8,7 +8,7 @@
8
8
 
9
9
  {% if component.model.instructionText %}
10
10
  {{ govukDetails({
11
- summaryText: "How to find location details",
11
+ summaryText: t('components.nationalGridField.howToFind'),
12
12
  html: component.model.instructionText | markdown | safe,
13
13
  classes: "govuk-!-margin-top-3"
14
14
  }) }}
@@ -10,7 +10,7 @@
10
10
 
11
11
  {% if component.model.instructionText %}
12
12
  {{ govukDetails({
13
- summaryText: "How to find location details",
13
+ summaryText: t('components.osGridRefField.howToFind'),
14
14
  html: component.model.instructionText | markdown | safe,
15
15
  classes: "govuk-!-margin-top-3"
16
16
  }) }}
@@ -11,27 +11,27 @@
11
11
  <div class="app-payment-field">
12
12
  {% if isPreAuthorised %}
13
13
  {# Payment already pre-authorised - show confirmation message #}
14
- <h2 class="govuk-heading-m">You have already authorised a payment for this form</h2>
14
+ <h2 class="govuk-heading-m">{{ t('components.paymentField.preAuthorisedTitle') }}</h2>
15
15
 
16
- <p class="govuk-body">Continue to submit the form. You will not be charged twice.</p>
16
+ <p class="govuk-body">{{ t('components.paymentField.preAuthorisedBody') }}</p>
17
17
  {% else %}
18
18
  {# No pre-authorisation - show payment form #}
19
- <h2 class="govuk-heading-m">{{ model.label.text if model.label and model.label.text else "Payment details required" }}</h2>
19
+ <h2 class="govuk-heading-m">{{ model.label.text if model.label and model.label.text else t('components.paymentField.detailsRequired') }}</h2>
20
20
 
21
21
  <p class="govuk-body">{{ description }}</p>
22
22
 
23
23
  {{ govukWarningText({
24
- text: "You may see a pending transaction in your bank account but you will only be charged when you submit the form.",
25
- iconFallbackText: "Warning"
24
+ text: t('components.paymentField.pendingTransaction'),
25
+ iconFallbackText: t('common.warningIconFallback')
26
26
  }) }}
27
27
 
28
- <p class="govuk-body">You can submit the form after you have added your payment details.</p>
28
+ <p class="govuk-body">{{ t('components.paymentField.canSubmitAfterPayment') }}</p>
29
29
 
30
- <p class="govuk-body govuk-!-margin-bottom-1">Total amount:</p>
30
+ <p class="govuk-body govuk-!-margin-bottom-1">{{ t('components.paymentField.totalAmountLabel') }}</p>
31
31
  <p class="govuk-heading-l govuk-!-margin-bottom-4 govuk-!-padding-top-0">{{ amount }}</p>
32
32
 
33
33
  {{ govukButton({
34
- text: "Add payment details",
34
+ text: t('components.paymentField.addPaymentDetails'),
35
35
  attributes: {
36
36
  name: "action",
37
37
  value: "external-" + model.name
@@ -37,13 +37,13 @@
37
37
 
38
38
  {% if value %}
39
39
  {% set insetHtml %}
40
- <strong>Selected address:</strong>
40
+ <strong>{{ t('components.addressField.selectedAddress') }}</strong>
41
41
  <br><br>
42
42
  {{ value }}
43
43
  <br><br>
44
44
  <p class="govuk-body">
45
45
  <button class="govuk-link govuk-button--link govuk-!-margin-right-1" name="action"
46
- value="external-{{component.model.name}}">Use a different address</button>
46
+ value="external-{{component.model.name}}">{{ t('components.addressField.useDifferentAddress') }}</button>
47
47
  </p>
48
48
  {% endset %}
49
49
 
@@ -54,14 +54,14 @@
54
54
  {% else %}
55
55
  <div class="govuk-button-group govuk-!-margin-bottom-0">
56
56
  {{ govukButton({
57
- text: "Find an address",
57
+ text: t('components.addressField.findAddress'),
58
58
  attributes: {
59
59
  name: "action",
60
60
  value: "external-" + component.model.name
61
61
  },
62
62
  classes: "govuk-button--secondary govuk-!-margin-right-1 govuk-!-margin-bottom-0"
63
63
  }) }}
64
- <p class="govuk-body govuk-!-margin-bottom-0">or <button class="govuk-link govuk-button--link govuk-!-margin-right-1 govuk-!-margin-bottom-0" name="action" value="external-{{component.model.name}}--step:manual">enter address manually</button></p>
64
+ <p class="govuk-body govuk-!-margin-bottom-0">or <button class="govuk-link govuk-button--link govuk-!-margin-right-1 govuk-!-margin-bottom-0" name="action" value="external-{{component.model.name}}--step:manual">{{ t('components.addressField.enterManually') }}</button></p>
65
65
  </div>
66
66
  {# Include a line break if this is the last component #}
67
67
  {% if components[components.length - 1] == component %}
@@ -8,16 +8,16 @@
8
8
  <div class="govuk-grid-row">
9
9
  <div class="govuk-grid-column-two-thirds">
10
10
  {{ govukPanel({
11
- titleText: pageTitle,
12
- html: "Your reference number<br><strong>" + referenceNumber + "</strong>" if showReferenceNumber
11
+ titleText: t('pages.confirmation.formSubmitted'),
12
+ html: t('pages.confirmation.referenceNumber') + "<br><strong>" + referenceNumber + "</strong>" if showReferenceNumber
13
13
  }) }}
14
- <h2 class="govuk-heading-m">What happens next</h2>
14
+ <h2 class="govuk-heading-m">{{ t('pages.confirmation.whatHappensNext') }}</h2>
15
15
  <div class="app-prose-scope">
16
16
  {{ submissionGuidance | markdown(3) | safe }}
17
17
  </div>
18
18
  {% if feedbackLink %}
19
19
  <p class="govuk-body">
20
- <a href="{{ feedbackLink }}" class="govuk-link govuk-link--no-visited-state">What do you think of this service?</a> (takes 30 seconds)
20
+ <a href="{{ feedbackLink }}" class="govuk-link govuk-link--no-visited-state">{{ t('pages.confirmation.feedbackLink') }}</a>
21
21
  </p>
22
22
  {% endif %}
23
23
  </div>
@@ -9,17 +9,17 @@
9
9
  <div class="govuk-grid-row">
10
10
  <div class="govuk-grid-column-two-thirds">
11
11
  {{ govukPanel({
12
- titleText: pageTitle or "Your progress has been saved"
12
+ titleText: pageTitle or t('pages.exit.defaultTitle')
13
13
  }) }}
14
14
 
15
- <h2 class="govuk-heading-m">What happens next</h2>
15
+ <h2 class="govuk-heading-m">{{ t('pages.exit.whatHappensNext') }}</h2>
16
16
  <div class="app-prose-scope">
17
- <p class="govuk-body">Your form progress has been saved. You can return to complete your application at any time using the link provided.</p>
17
+ <p class="govuk-body">{{ t('pages.exit.body') }}</p>
18
18
 
19
19
  {% if returnUrl %}
20
20
  <p class="govuk-body">
21
21
  {{ govukButton({
22
- text: "Return to application",
22
+ text: t('pages.exit.returnToApplication'),
23
23
  href: returnUrl,
24
24
  classes: "govuk-button--secondary"
25
25
  }) }}
@@ -14,15 +14,15 @@
14
14
 
15
15
  {% if formAction %}
16
16
  {{ govukButton({
17
- text: "Upload file",
17
+ text: t('pages.fileUpload.upload'),
18
18
  classes: "govuk-button--secondary upload-file-button",
19
19
  preventDoubleClick: true,
20
20
  disabled: context.isForceAccess
21
21
  }) }}
22
22
  {% else %}
23
23
  {{ govukWarningText({
24
- text: "You have reached the maximum number of files. Please remove a file to upload more.",
25
- iconFallbackText: "Warning"
24
+ text: t('pages.fileUpload.maxFilesReached'),
25
+ iconFallbackText: t('common.warningIconFallback')
26
26
  }) }}
27
27
  {% endif %}
28
28
  </form>
@@ -13,14 +13,14 @@
13
13
 
14
14
  {% if showPaymentExpiredNotification %}
15
15
  {{ govukNotificationBanner({
16
- titleText: "Important",
17
- html: '<h3 class="govuk-notification-banner__heading">Your payment has been cancelled</h3><p class="govuk-body">Your payment details were deleted because the form was inactive for 5 days.</p><p class="govuk-body">Add your payment details again.</p>'
16
+ titleText: t('pages.question.paymentCancelledBannerTitle'),
17
+ html: '<h3 class="govuk-notification-banner__heading">' + t('pages.question.paymentCancelledTitle') + '</h3><p class="govuk-body">' + t('pages.question.paymentCancelledBody') + '</p><p class="govuk-body">' + t('pages.question.paymentCancelledAction') + '</p>'
18
18
  }) }}
19
19
  {% endif %}
20
20
 
21
21
  {% if errors | length and not showPaymentExpiredNotification %}
22
22
  {{ govukErrorSummary({
23
- titleText: "There is a problem",
23
+ titleText: t('errors.title'),
24
24
  errorList: checkErrorTemplates(errors)
25
25
  }) }}
26
26
  {% endif %}
@@ -13,7 +13,7 @@
13
13
 
14
14
  {% if errors %}
15
15
  {{ govukErrorSummary({
16
- titleText: "There is a problem",
16
+ titleText: t('errors.title'),
17
17
  errorList: errors
18
18
  }) }}
19
19
  {% endif %}
@@ -20,11 +20,11 @@
20
20
  {{ componentList(components) }}
21
21
 
22
22
  {% if isStartPage %}
23
- {% set buttonText = "Start now" %}
23
+ {% set buttonText = t('pages.question.startNow') %}
24
24
  {% elif submitButtonText %}
25
25
  {% set buttonText = submitButtonText %}
26
26
  {% else %}
27
- {% set buttonText = "Continue" %}
27
+ {% set buttonText = t('common.continue') %}
28
28
  {% endif %}
29
29
 
30
30
  <div class="govuk-button-group">
@@ -38,7 +38,7 @@
38
38
 
39
39
  {% if allowSaveAndExit %}
40
40
  {{ govukButton({
41
- text: "Save and exit",
41
+ text: t('common.saveAndExit'),
42
42
  classes: "govuk-button--secondary",
43
43
  name: "action",
44
44
  value: "save-and-exit",
@@ -9,23 +9,23 @@
9
9
  {%- endmacro -%}
10
10
 
11
11
  {% call govukNotificationBanner() %}
12
+ {% set previewModeTranslated = t('common.' + previewMode) %}
12
13
  {% if not context.isForceAccess %}
13
14
  <p class="govuk-notification-banner__heading govuk-!-margin-bottom-0">
14
- This is a preview of a {{ previewMode }} form. Do not enter personal information.
15
+ {{ t('pages.preview.bannerForce', { previewMode: previewModeTranslated }) }}
15
16
  </p>
16
17
 
17
18
  {{ _closeLink() }}
18
19
  {% else %}
19
20
  <p class="govuk-notification-banner__heading govuk-!-margin-bottom-0">
20
- This is a preview of a {{ previewMode }} form page you are editing.
21
+ {{ t('pages.preview.bannerText', { previewMode: previewModeTranslated }) }}
21
22
  </p>
22
23
 
23
24
  {{ _closeLink() }}
24
25
 
25
26
  {% if hasPreviousPages %}
26
27
  <p class="govuk-body govuk-!-margin-top-2">
27
- It depends on answers from earlier pages in the form. In the live
28
- version, users will need to complete those questions first.
28
+ {{ t('pages.preview.previousPages') }}
29
29
  </p>
30
30
  {% endif %}
31
31
  {% endif %}
@@ -1,10 +1,9 @@
1
1
  {% from "govuk/components/warning-text/macro.njk" import govukWarningText %}
2
2
 
3
- {% set html %}
4
- If you want to receive a test email, <a target="_blank" rel="noopener noreferrer" class="govuk-link" href="{{ config.designerUrl }}/library/{{ slug }}/edit/notification-email">enter the email address (opens in new tab)</a> you want form submissions to go to.
5
- {% endset %}
3
+ {% set linkText %}{{ t('pages.preview.warnMissingNotificationEmail.linkText') }}{% endset %}
4
+ {% set linkHtml %}<a target="_blank" rel="noopener noreferrer" class="govuk-link" href="{{ config.designerUrl }}/library/{{ slug }}/edit/notification-email">{{ linkText }}</a>{% endset %}
6
5
 
7
6
  {{ govukWarningText({
8
- html: html,
9
- iconFallbackText: "Warning"
7
+ html: t('pages.preview.warnMissingNotificationEmail.body', { link: linkHtml }),
8
+ iconFallbackText: t('common.warningIconFallback')
10
9
  }) }}
@@ -13,7 +13,7 @@
13
13
 
14
14
  {% if errors %}
15
15
  {{ govukErrorSummary({
16
- titleText: "There is a problem",
16
+ titleText: t('errors.title'),
17
17
  errorList: errors
18
18
  }) }}
19
19
  {% endif %}
@@ -29,14 +29,14 @@
29
29
 
30
30
  <div class="govuk-button-group">
31
31
  {{ govukButton({
32
- text: "Continue",
32
+ text: t('pages.repeater.continue'),
33
33
  name: "action",
34
34
  value: "continue",
35
35
  preventDoubleClick: true
36
36
  }) }}
37
37
 
38
38
  {{ govukButton({
39
- text: "Add another",
39
+ text: t('pages.repeater.addAnother'),
40
40
  name: "action",
41
41
  value: "add-another",
42
42
  classes: "govuk-button--secondary",
@@ -45,7 +45,7 @@
45
45
 
46
46
  {% if allowSaveAndExit %}
47
47
  {{ govukButton({
48
- text: "Save and exit",
48
+ text: t('pages.repeater.saveAndExit'),
49
49
  classes: "govuk-button--secondary",
50
50
  name: "action",
51
51
  value: "save-and-exit",
@@ -17,14 +17,14 @@
17
17
  {% if paymentState and paymentState.preAuth and paymentState.preAuth.status == 'success' %}
18
18
  {{ govukNotificationBanner({
19
19
  type: "success",
20
- titleText: "Success",
21
- html: "<h3 class=\"govuk-notification-banner__heading\">We have your payment details</h3><p class=\"govuk-body\">Your payment is on hold. We will charge you when you submit the form.</p>"
20
+ titleText: t('pages.summary.paymentSuccessBannerTitle'),
21
+ html: "<h3 class=\"govuk-notification-banner__heading\">" + t('pages.summary.paymentSuccessTitle') + "</h3><p class=\"govuk-body\">" + t('pages.summary.paymentSuccessBody') + "</p>"
22
22
  }) }}
23
23
  {% endif %}
24
24
 
25
25
  {% if errors %}
26
26
  {{ govukErrorSummary({
27
- titleText: "There is a problem",
27
+ titleText: t('errors.title'),
28
28
  errorList: checkErrorTemplates(errors)
29
29
  }) }}
30
30
  {% endif %}
@@ -65,7 +65,7 @@
65
65
  {{ componentList(components) }}
66
66
 
67
67
  {% if declaration %}
68
- <h2 class="govuk-heading-m" id="declaration">Declaration</h2>
68
+ <h2 class="govuk-heading-m" id="declaration">{{ t('pages.summary.declaration') }}</h2>
69
69
  <div class="govuk-body">
70
70
  {{ declaration | safe }}
71
71
  </div>
@@ -75,12 +75,19 @@
75
75
  {% set isDeclaration = declaration or components | length %}
76
76
  {% set paymentPending = paymentRequired and not paymentState %}
77
77
 
78
+ {% set submitButtonText = t('pages.summary.submit') %}
79
+ {% if paymentPending %}
80
+ {% set submitButtonText = t('pages.summary.payAndSubmit') %}
81
+ {% endif %}
82
+ {% if isDeclaration %}
83
+ {% set submitButtonText = t('pages.summary.acceptAndSubmit') %}
84
+ {% endif %}
85
+
78
86
  {# The prevent-multiple-clicks CSS class wires up to debounce-click.js to disable the button for 10s.
79
87
  For those with JS enabled, it will help prevent multiple submissions when a large form is taking a while to submit.
80
88
  When a better fix is implemented, this class can be removed and preventDoubleClick should be set back to true. #}
81
89
  {{ govukButton({
82
- text: "Pay and submit" if paymentPending else ("Accept and submit" if isDeclaration else "Submit"),
83
- classes: "prevent-multiple-clicks",
90
+ text: submitButtonText,
84
91
  name: "action",
85
92
  value: "send",
86
93
  preventDoubleClick: false
@@ -88,7 +95,7 @@
88
95
 
89
96
  {% if allowSaveAndExit %}
90
97
  {{ govukButton({
91
- text: "Save and exit",
98
+ text: t('pages.summary.saveAndExit'),
92
99
  classes: "govuk-button--secondary",
93
100
  name: "action",
94
101
  value: "save-and-exit",
@@ -1,6 +1,16 @@
1
1
  import * as helpers from "../engine/helpers.js";
2
2
  import { environment } from "./environment.js";
3
3
  describe('Nunjucks environment', () => {
4
+ describe('t global function', () => {
5
+ it('has t as a global function', () => {
6
+ const globals = /** @type {any} */environment.globals;
7
+ expect(typeof globals.t).toBe('function');
8
+ });
9
+ it('t global returns the English string for a known key', () => {
10
+ const globals = /** @type {any} */environment.globals;
11
+ expect(globals.t('errors.title')).toBe('There is a problem');
12
+ });
13
+ });
4
14
  describe('checkErrorTemplates function', () => {
5
15
  /** @type {Function} */
6
16
  let checkErrorTemplates;
@@ -1 +1 @@
1
- {"version":3,"file":"enviroment.test.js","names":["helpers","environment","describe","checkErrorTemplates","beforeEach","getGlobal","jest","spyOn","mockImplementation","text","afterEach","restoreAllMocks","test","nunjucksCtx","ctx","errors","result","call","expect","toBe","evaluateTemplate","not","toHaveBeenCalled","formContext","someData","context","toHaveBeenCalledTimes","toHaveBeenCalledWith","toEqual","checkComponentTemplates","component","type","isFormComponent","model","content","nonStringContent","some","label","evaluateFunc","template"],"sources":["../../../../src/server/plugins/nunjucks/enviroment.test.js"],"sourcesContent":["import * as helpers from '~/src/server/plugins/engine/helpers.js'\nimport { environment } from '~/src/server/plugins/nunjucks/environment.js'\n\ndescribe('Nunjucks environment', () => {\n describe('checkErrorTemplates function', () => {\n /** @type {Function} */\n let checkErrorTemplates\n\n beforeEach(() => {\n checkErrorTemplates = environment.getGlobal('checkErrorTemplates')\n\n jest\n .spyOn(helpers, 'evaluateTemplate')\n .mockImplementation((text) => `evaluated-${text}`)\n })\n\n afterEach(() => {\n jest.restoreAllMocks()\n })\n\n test('returns errors unchanged when context is not present', () => {\n const nunjucksCtx = {\n ctx: {}\n }\n\n const errors = [{ text: 'Error 1' }, { text: 'Error 2' }]\n\n const result = checkErrorTemplates.call(nunjucksCtx, errors)\n\n expect(result).toBe(errors)\n expect(helpers.evaluateTemplate).not.toHaveBeenCalled()\n })\n\n test('evaluates error texts when context is present', () => {\n const formContext = { someData: 'some-text' }\n const nunjucksCtx = {\n ctx: { context: formContext }\n }\n\n const errors = [{ text: 'Error 1' }, { text: 'Error 2' }]\n\n const result = checkErrorTemplates.call(nunjucksCtx, errors)\n\n expect(helpers.evaluateTemplate).toHaveBeenCalledTimes(2)\n expect(helpers.evaluateTemplate).toHaveBeenCalledWith(\n 'Error 1',\n formContext\n )\n expect(helpers.evaluateTemplate).toHaveBeenCalledWith(\n 'Error 2',\n formContext\n )\n\n expect(result).toEqual([\n { text: 'evaluated-Error 1' },\n { text: 'evaluated-Error 2' }\n ])\n })\n })\n\n describe('checkComponentTemplates function', () => {\n /** @type {Function} */\n let checkComponentTemplates\n\n beforeEach(() => {\n checkComponentTemplates = environment.getGlobal('checkComponentTemplates')\n\n jest\n .spyOn(helpers, 'evaluateTemplate')\n .mockImplementation((text) => `evaluated-${text}`)\n })\n\n afterEach(() => {\n jest.restoreAllMocks()\n })\n\n test('evaluates string content for Html components', () => {\n const formContext = { someData: 'some-text' }\n const nunjucksCtx = {\n ctx: { context: formContext }\n }\n\n const component = {\n type: 'Html',\n isFormComponent: false,\n model: {\n content: 'Some {{ context.someData }} content'\n }\n }\n\n const result = /** @type {{ model: { content: string } }} */ (\n checkComponentTemplates.call(nunjucksCtx, component)\n )\n\n expect(helpers.evaluateTemplate).toHaveBeenCalledWith(\n 'Some {{ context.someData }} content',\n formContext\n )\n expect(result.model.content).toBe(\n 'evaluated-Some {{ context.someData }} content'\n )\n })\n\n test('does not evaluate non-string content for Html components', () => {\n const formContext = { someData: 'some-text' }\n const nunjucksCtx = {\n ctx: { context: formContext }\n }\n\n const nonStringContent = { some: 'object' }\n const component = {\n type: 'Html',\n isFormComponent: false,\n model: {\n content: nonStringContent\n }\n }\n\n const result = /** @type {{ model: { content: string } }} */ (\n checkComponentTemplates.call(nunjucksCtx, component)\n )\n\n expect(helpers.evaluateTemplate).not.toHaveBeenCalled()\n\n expect(result.model.content).toBe(nonStringContent)\n })\n\n test('evaluates label text for form components', () => {\n const formContext = { someData: 'some-text' }\n const nunjucksCtx = {\n ctx: { context: formContext }\n }\n\n const component = {\n isFormComponent: true,\n model: {\n label: {\n text: 'Label with {{ context.someData }}'\n }\n }\n }\n\n const result = /** @type {{ model: { label?: { text: string } } }} */ (\n checkComponentTemplates.call(nunjucksCtx, component)\n )\n\n expect(helpers.evaluateTemplate).toHaveBeenCalledWith(\n 'Label with {{ context.someData }}',\n formContext\n )\n\n expect(result.model.label?.text).toBe(\n 'evaluated-Label with {{ context.someData }}'\n )\n })\n })\n\n describe('evaluate function', () => {\n /** @type {Function} */\n let evaluateFunc\n\n beforeEach(() => {\n evaluateFunc = environment.getGlobal('evaluate')\n\n jest\n .spyOn(helpers, 'evaluateTemplate')\n .mockImplementation((text) => `evaluated-${text}`)\n })\n\n afterEach(() => {\n jest.restoreAllMocks()\n })\n\n test('evaluates template when context is present', () => {\n const formContext = { someData: 'some-text' }\n const nunjucksCtx = {\n ctx: { context: formContext }\n }\n\n const template = 'Template with {{ context.someData }}'\n const result = evaluateFunc.call(nunjucksCtx, template)\n\n expect(helpers.evaluateTemplate).toHaveBeenCalledWith(\n template,\n formContext\n )\n expect(result).toBe('evaluated-Template with {{ context.someData }}')\n })\n\n test('returns template unchanged when context is not present', () => {\n const nunjucksCtx = {\n ctx: {}\n }\n\n const template = 'Template with {{ context.someData }}'\n const result = evaluateFunc.call(nunjucksCtx, template)\n\n expect(helpers.evaluateTemplate).not.toHaveBeenCalled()\n\n expect(result).toBe(template)\n })\n })\n})\n\n/*\n * @import { ComponentViewModel } from '~/src/server/plugins/engine/components/types.js'\n */\n"],"mappings":"AAAA,OAAO,KAAKA,OAAO;AACnB,SAASC,WAAW;AAEpBC,QAAQ,CAAC,sBAAsB,EAAE,MAAM;EACrCA,QAAQ,CAAC,8BAA8B,EAAE,MAAM;IAC7C;IACA,IAAIC,mBAAmB;IAEvBC,UAAU,CAAC,MAAM;MACfD,mBAAmB,GAAGF,WAAW,CAACI,SAAS,CAAC,qBAAqB,CAAC;MAElEC,IAAI,CACDC,KAAK,CAACP,OAAO,EAAE,kBAAkB,CAAC,CAClCQ,kBAAkB,CAAEC,IAAI,IAAK,aAAaA,IAAI,EAAE,CAAC;IACtD,CAAC,CAAC;IAEFC,SAAS,CAAC,MAAM;MACdJ,IAAI,CAACK,eAAe,CAAC,CAAC;IACxB,CAAC,CAAC;IAEFC,IAAI,CAAC,sDAAsD,EAAE,MAAM;MACjE,MAAMC,WAAW,GAAG;QAClBC,GAAG,EAAE,CAAC;MACR,CAAC;MAED,MAAMC,MAAM,GAAG,CAAC;QAAEN,IAAI,EAAE;MAAU,CAAC,EAAE;QAAEA,IAAI,EAAE;MAAU,CAAC,CAAC;MAEzD,MAAMO,MAAM,GAAGb,mBAAmB,CAACc,IAAI,CAACJ,WAAW,EAAEE,MAAM,CAAC;MAE5DG,MAAM,CAACF,MAAM,CAAC,CAACG,IAAI,CAACJ,MAAM,CAAC;MAC3BG,MAAM,CAAClB,OAAO,CAACoB,gBAAgB,CAAC,CAACC,GAAG,CAACC,gBAAgB,CAAC,CAAC;IACzD,CAAC,CAAC;IAEFV,IAAI,CAAC,+CAA+C,EAAE,MAAM;MAC1D,MAAMW,WAAW,GAAG;QAAEC,QAAQ,EAAE;MAAY,CAAC;MAC7C,MAAMX,WAAW,GAAG;QAClBC,GAAG,EAAE;UAAEW,OAAO,EAAEF;QAAY;MAC9B,CAAC;MAED,MAAMR,MAAM,GAAG,CAAC;QAAEN,IAAI,EAAE;MAAU,CAAC,EAAE;QAAEA,IAAI,EAAE;MAAU,CAAC,CAAC;MAEzD,MAAMO,MAAM,GAAGb,mBAAmB,CAACc,IAAI,CAACJ,WAAW,EAAEE,MAAM,CAAC;MAE5DG,MAAM,CAAClB,OAAO,CAACoB,gBAAgB,CAAC,CAACM,qBAAqB,CAAC,CAAC,CAAC;MACzDR,MAAM,CAAClB,OAAO,CAACoB,gBAAgB,CAAC,CAACO,oBAAoB,CACnD,SAAS,EACTJ,WACF,CAAC;MACDL,MAAM,CAAClB,OAAO,CAACoB,gBAAgB,CAAC,CAACO,oBAAoB,CACnD,SAAS,EACTJ,WACF,CAAC;MAEDL,MAAM,CAACF,MAAM,CAAC,CAACY,OAAO,CAAC,CACrB;QAAEnB,IAAI,EAAE;MAAoB,CAAC,EAC7B;QAAEA,IAAI,EAAE;MAAoB,CAAC,CAC9B,CAAC;IACJ,CAAC,CAAC;EACJ,CAAC,CAAC;EAEFP,QAAQ,CAAC,kCAAkC,EAAE,MAAM;IACjD;IACA,IAAI2B,uBAAuB;IAE3BzB,UAAU,CAAC,MAAM;MACfyB,uBAAuB,GAAG5B,WAAW,CAACI,SAAS,CAAC,yBAAyB,CAAC;MAE1EC,IAAI,CACDC,KAAK,CAACP,OAAO,EAAE,kBAAkB,CAAC,CAClCQ,kBAAkB,CAAEC,IAAI,IAAK,aAAaA,IAAI,EAAE,CAAC;IACtD,CAAC,CAAC;IAEFC,SAAS,CAAC,MAAM;MACdJ,IAAI,CAACK,eAAe,CAAC,CAAC;IACxB,CAAC,CAAC;IAEFC,IAAI,CAAC,8CAA8C,EAAE,MAAM;MACzD,MAAMW,WAAW,GAAG;QAAEC,QAAQ,EAAE;MAAY,CAAC;MAC7C,MAAMX,WAAW,GAAG;QAClBC,GAAG,EAAE;UAAEW,OAAO,EAAEF;QAAY;MAC9B,CAAC;MAED,MAAMO,SAAS,GAAG;QAChBC,IAAI,EAAE,MAAM;QACZC,eAAe,EAAE,KAAK;QACtBC,KAAK,EAAE;UACLC,OAAO,EAAE;QACX;MACF,CAAC;MAED,MAAMlB,MAAM,GAAG;MACba,uBAAuB,CAACZ,IAAI,CAACJ,WAAW,EAAEiB,SAAS,CACpD;MAEDZ,MAAM,CAAClB,OAAO,CAACoB,gBAAgB,CAAC,CAACO,oBAAoB,CACnD,qCAAqC,EACrCJ,WACF,CAAC;MACDL,MAAM,CAACF,MAAM,CAACiB,KAAK,CAACC,OAAO,CAAC,CAACf,IAAI,CAC/B,+CACF,CAAC;IACH,CAAC,CAAC;IAEFP,IAAI,CAAC,0DAA0D,EAAE,MAAM;MACrE,MAAMW,WAAW,GAAG;QAAEC,QAAQ,EAAE;MAAY,CAAC;MAC7C,MAAMX,WAAW,GAAG;QAClBC,GAAG,EAAE;UAAEW,OAAO,EAAEF;QAAY;MAC9B,CAAC;MAED,MAAMY,gBAAgB,GAAG;QAAEC,IAAI,EAAE;MAAS,CAAC;MAC3C,MAAMN,SAAS,GAAG;QAChBC,IAAI,EAAE,MAAM;QACZC,eAAe,EAAE,KAAK;QACtBC,KAAK,EAAE;UACLC,OAAO,EAAEC;QACX;MACF,CAAC;MAED,MAAMnB,MAAM,GAAG;MACba,uBAAuB,CAACZ,IAAI,CAACJ,WAAW,EAAEiB,SAAS,CACpD;MAEDZ,MAAM,CAAClB,OAAO,CAACoB,gBAAgB,CAAC,CAACC,GAAG,CAACC,gBAAgB,CAAC,CAAC;MAEvDJ,MAAM,CAACF,MAAM,CAACiB,KAAK,CAACC,OAAO,CAAC,CAACf,IAAI,CAACgB,gBAAgB,CAAC;IACrD,CAAC,CAAC;IAEFvB,IAAI,CAAC,0CAA0C,EAAE,MAAM;MACrD,MAAMW,WAAW,GAAG;QAAEC,QAAQ,EAAE;MAAY,CAAC;MAC7C,MAAMX,WAAW,GAAG;QAClBC,GAAG,EAAE;UAAEW,OAAO,EAAEF;QAAY;MAC9B,CAAC;MAED,MAAMO,SAAS,GAAG;QAChBE,eAAe,EAAE,IAAI;QACrBC,KAAK,EAAE;UACLI,KAAK,EAAE;YACL5B,IAAI,EAAE;UACR;QACF;MACF,CAAC;MAED,MAAMO,MAAM,GAAG;MACba,uBAAuB,CAACZ,IAAI,CAACJ,WAAW,EAAEiB,SAAS,CACpD;MAEDZ,MAAM,CAAClB,OAAO,CAACoB,gBAAgB,CAAC,CAACO,oBAAoB,CACnD,mCAAmC,EACnCJ,WACF,CAAC;MAEDL,MAAM,CAACF,MAAM,CAACiB,KAAK,CAACI,KAAK,EAAE5B,IAAI,CAAC,CAACU,IAAI,CACnC,6CACF,CAAC;IACH,CAAC,CAAC;EACJ,CAAC,CAAC;EAEFjB,QAAQ,CAAC,mBAAmB,EAAE,MAAM;IAClC;IACA,IAAIoC,YAAY;IAEhBlC,UAAU,CAAC,MAAM;MACfkC,YAAY,GAAGrC,WAAW,CAACI,SAAS,CAAC,UAAU,CAAC;MAEhDC,IAAI,CACDC,KAAK,CAACP,OAAO,EAAE,kBAAkB,CAAC,CAClCQ,kBAAkB,CAAEC,IAAI,IAAK,aAAaA,IAAI,EAAE,CAAC;IACtD,CAAC,CAAC;IAEFC,SAAS,CAAC,MAAM;MACdJ,IAAI,CAACK,eAAe,CAAC,CAAC;IACxB,CAAC,CAAC;IAEFC,IAAI,CAAC,4CAA4C,EAAE,MAAM;MACvD,MAAMW,WAAW,GAAG;QAAEC,QAAQ,EAAE;MAAY,CAAC;MAC7C,MAAMX,WAAW,GAAG;QAClBC,GAAG,EAAE;UAAEW,OAAO,EAAEF;QAAY;MAC9B,CAAC;MAED,MAAMgB,QAAQ,GAAG,sCAAsC;MACvD,MAAMvB,MAAM,GAAGsB,YAAY,CAACrB,IAAI,CAACJ,WAAW,EAAE0B,QAAQ,CAAC;MAEvDrB,MAAM,CAAClB,OAAO,CAACoB,gBAAgB,CAAC,CAACO,oBAAoB,CACnDY,QAAQ,EACRhB,WACF,CAAC;MACDL,MAAM,CAACF,MAAM,CAAC,CAACG,IAAI,CAAC,gDAAgD,CAAC;IACvE,CAAC,CAAC;IAEFP,IAAI,CAAC,wDAAwD,EAAE,MAAM;MACnE,MAAMC,WAAW,GAAG;QAClBC,GAAG,EAAE,CAAC;MACR,CAAC;MAED,MAAMyB,QAAQ,GAAG,sCAAsC;MACvD,MAAMvB,MAAM,GAAGsB,YAAY,CAACrB,IAAI,CAACJ,WAAW,EAAE0B,QAAQ,CAAC;MAEvDrB,MAAM,CAAClB,OAAO,CAACoB,gBAAgB,CAAC,CAACC,GAAG,CAACC,gBAAgB,CAAC,CAAC;MAEvDJ,MAAM,CAACF,MAAM,CAAC,CAACG,IAAI,CAACoB,QAAQ,CAAC;IAC/B,CAAC,CAAC;EACJ,CAAC,CAAC;AACJ,CAAC,CAAC;;AAEF;AACA;AACA","ignoreList":[]}
1
+ {"version":3,"file":"enviroment.test.js","names":["helpers","environment","describe","it","globals","expect","t","toBe","checkErrorTemplates","beforeEach","getGlobal","jest","spyOn","mockImplementation","text","afterEach","restoreAllMocks","test","nunjucksCtx","ctx","errors","result","call","evaluateTemplate","not","toHaveBeenCalled","formContext","someData","context","toHaveBeenCalledTimes","toHaveBeenCalledWith","toEqual","checkComponentTemplates","component","type","isFormComponent","model","content","nonStringContent","some","label","evaluateFunc","template"],"sources":["../../../../src/server/plugins/nunjucks/enviroment.test.js"],"sourcesContent":["import * as helpers from '~/src/server/plugins/engine/helpers.js'\nimport { environment } from '~/src/server/plugins/nunjucks/environment.js'\n\ndescribe('Nunjucks environment', () => {\n describe('t global function', () => {\n it('has t as a global function', () => {\n const globals = /** @type {any} */ (environment).globals\n expect(typeof globals.t).toBe('function')\n })\n\n it('t global returns the English string for a known key', () => {\n const globals = /** @type {any} */ (environment).globals\n expect(globals.t('errors.title')).toBe('There is a problem')\n })\n })\n\n describe('checkErrorTemplates function', () => {\n /** @type {Function} */\n let checkErrorTemplates\n\n beforeEach(() => {\n checkErrorTemplates = environment.getGlobal('checkErrorTemplates')\n\n jest\n .spyOn(helpers, 'evaluateTemplate')\n .mockImplementation((text) => `evaluated-${text}`)\n })\n\n afterEach(() => {\n jest.restoreAllMocks()\n })\n\n test('returns errors unchanged when context is not present', () => {\n const nunjucksCtx = {\n ctx: {}\n }\n\n const errors = [{ text: 'Error 1' }, { text: 'Error 2' }]\n\n const result = checkErrorTemplates.call(nunjucksCtx, errors)\n\n expect(result).toBe(errors)\n expect(helpers.evaluateTemplate).not.toHaveBeenCalled()\n })\n\n test('evaluates error texts when context is present', () => {\n const formContext = { someData: 'some-text' }\n const nunjucksCtx = {\n ctx: { context: formContext }\n }\n\n const errors = [{ text: 'Error 1' }, { text: 'Error 2' }]\n\n const result = checkErrorTemplates.call(nunjucksCtx, errors)\n\n expect(helpers.evaluateTemplate).toHaveBeenCalledTimes(2)\n expect(helpers.evaluateTemplate).toHaveBeenCalledWith(\n 'Error 1',\n formContext\n )\n expect(helpers.evaluateTemplate).toHaveBeenCalledWith(\n 'Error 2',\n formContext\n )\n\n expect(result).toEqual([\n { text: 'evaluated-Error 1' },\n { text: 'evaluated-Error 2' }\n ])\n })\n })\n\n describe('checkComponentTemplates function', () => {\n /** @type {Function} */\n let checkComponentTemplates\n\n beforeEach(() => {\n checkComponentTemplates = environment.getGlobal('checkComponentTemplates')\n\n jest\n .spyOn(helpers, 'evaluateTemplate')\n .mockImplementation((text) => `evaluated-${text}`)\n })\n\n afterEach(() => {\n jest.restoreAllMocks()\n })\n\n test('evaluates string content for Html components', () => {\n const formContext = { someData: 'some-text' }\n const nunjucksCtx = {\n ctx: { context: formContext }\n }\n\n const component = {\n type: 'Html',\n isFormComponent: false,\n model: {\n content: 'Some {{ context.someData }} content'\n }\n }\n\n const result = /** @type {{ model: { content: string } }} */ (\n checkComponentTemplates.call(nunjucksCtx, component)\n )\n\n expect(helpers.evaluateTemplate).toHaveBeenCalledWith(\n 'Some {{ context.someData }} content',\n formContext\n )\n expect(result.model.content).toBe(\n 'evaluated-Some {{ context.someData }} content'\n )\n })\n\n test('does not evaluate non-string content for Html components', () => {\n const formContext = { someData: 'some-text' }\n const nunjucksCtx = {\n ctx: { context: formContext }\n }\n\n const nonStringContent = { some: 'object' }\n const component = {\n type: 'Html',\n isFormComponent: false,\n model: {\n content: nonStringContent\n }\n }\n\n const result = /** @type {{ model: { content: string } }} */ (\n checkComponentTemplates.call(nunjucksCtx, component)\n )\n\n expect(helpers.evaluateTemplate).not.toHaveBeenCalled()\n\n expect(result.model.content).toBe(nonStringContent)\n })\n\n test('evaluates label text for form components', () => {\n const formContext = { someData: 'some-text' }\n const nunjucksCtx = {\n ctx: { context: formContext }\n }\n\n const component = {\n isFormComponent: true,\n model: {\n label: {\n text: 'Label with {{ context.someData }}'\n }\n }\n }\n\n const result = /** @type {{ model: { label?: { text: string } } }} */ (\n checkComponentTemplates.call(nunjucksCtx, component)\n )\n\n expect(helpers.evaluateTemplate).toHaveBeenCalledWith(\n 'Label with {{ context.someData }}',\n formContext\n )\n\n expect(result.model.label?.text).toBe(\n 'evaluated-Label with {{ context.someData }}'\n )\n })\n })\n\n describe('evaluate function', () => {\n /** @type {Function} */\n let evaluateFunc\n\n beforeEach(() => {\n evaluateFunc = environment.getGlobal('evaluate')\n\n jest\n .spyOn(helpers, 'evaluateTemplate')\n .mockImplementation((text) => `evaluated-${text}`)\n })\n\n afterEach(() => {\n jest.restoreAllMocks()\n })\n\n test('evaluates template when context is present', () => {\n const formContext = { someData: 'some-text' }\n const nunjucksCtx = {\n ctx: { context: formContext }\n }\n\n const template = 'Template with {{ context.someData }}'\n const result = evaluateFunc.call(nunjucksCtx, template)\n\n expect(helpers.evaluateTemplate).toHaveBeenCalledWith(\n template,\n formContext\n )\n expect(result).toBe('evaluated-Template with {{ context.someData }}')\n })\n\n test('returns template unchanged when context is not present', () => {\n const nunjucksCtx = {\n ctx: {}\n }\n\n const template = 'Template with {{ context.someData }}'\n const result = evaluateFunc.call(nunjucksCtx, template)\n\n expect(helpers.evaluateTemplate).not.toHaveBeenCalled()\n\n expect(result).toBe(template)\n })\n })\n})\n\n/*\n * @import { ComponentViewModel } from '~/src/server/plugins/engine/components/types.js'\n */\n"],"mappings":"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","ignoreList":[]}
@@ -14,6 +14,14 @@ export function checkComponentTemplates(this: NunjucksContext, component: Compon
14
14
  */
15
15
  export function evaluate(this: NunjucksContext, template: string): string;
16
16
  export function govukRebrand(): boolean;
17
+ /**
18
+ * Global t() function — en-GB fallback for templates not wired to a specific language.
19
+ * Per-request page controllers override this by passing t in their view model.
20
+ * @param {string} key
21
+ * @param {Record<string, unknown>} [opts]
22
+ * @returns {string}
23
+ */
24
+ export function tGlobal(key: string, opts?: Record<string, unknown>): string;
17
25
  export const paths: string[];
18
26
  export const environment: nunjucks.Environment;
19
27
  import type { FormSubmissionError } from '../../../server/plugins/engine/types.js';
@@ -4,6 +4,7 @@ import nunjucks from 'nunjucks';
4
4
  import resolvePkg from 'resolve';
5
5
  import { config } from "../../../config/index.js";
6
6
  import { evaluateTemplate } from "../engine/helpers.js";
7
+ import { t as i18nT } from "../engine/i18n/index.js";
7
8
  import * as filters from "./filters/index.js";
8
9
  const govukFrontendPath = dirname(resolvePkg.sync('govuk-frontend/package.json'));
9
10
  export const paths = [join(config.get('appDir'), 'plugins/engine/views'), join(config.get('appDir'), 'views')];
@@ -91,6 +92,18 @@ export function govukRebrand() {
91
92
  }
92
93
  environment.addGlobal('govukRebrand', govukRebrand());
93
94
 
95
+ /**
96
+ * Global t() function — en-GB fallback for templates not wired to a specific language.
97
+ * Per-request page controllers override this by passing t in their view model.
98
+ * @param {string} key
99
+ * @param {Record<string, unknown>} [opts]
100
+ * @returns {string}
101
+ */
102
+ export function tGlobal(key, opts) {
103
+ return i18nT(key, 'en-GB', opts);
104
+ }
105
+ environment.addGlobal('t', tGlobal);
106
+
94
107
  /**
95
108
  * @import { NunjucksContext } from '../../../server/plugins/nunjucks/types.js'
96
109
  * @import { FormSubmissionError } from '../../../server/plugins/engine/types.js'