Skip to content

feat/df-1065: Welsh translation for plugin#436

Open
jbarnsley10 wants to merge 87 commits into
mainfrom
feature/i18n-linting
Open

feat/df-1065: Welsh translation for plugin#436
jbarnsley10 wants to merge 87 commits into
mainfrom
feature/i18n-linting

Conversation

@jbarnsley10

@jbarnsley10 jbarnsley10 commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Proposed change

Welsh translation for plugin

Jira ticket: DF-1065

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Misc. (documentation, build updates, etc)

Checklist

  • You have executed this code locally and it performs as expected.
  • You have added tests to verify your code works.
  • You have added code comments and JSDoc, where appropriate.
  • There is no commented-out code.
  • You have added developer docs in README.md and docs/* (where appropriate, e.g. new features).
  • The tests are passing (npm run test).
  • The linting checks are passing (npm run lint).
  • The code has been formatted (npm run format).

Adds buildValidationMessages(t) — a factory that accepts a language-bound
translation function and returns a set of Joi message templates (JoiExpressions
for lowerFirst-containing strings, plain template strings for the rest).

Also adds require('@defra/forms-model') to jest.setup.cjs to align Joi's
internal Symbol state across the babel-jest ESM/CJS module boundary; without
this, JoiExpression objects fail Template.isTemplate() checks inside Joi's
.messages() method when resetModules: true clears the registry between tests.
…key, lang)

Remove the lang parameter from getValidationConfig/getErrorTemplates in
NationalGridFieldNumberField and OsGridRefField; fix LocationFieldBase
constructor call that was passing model.language as an argument.
Static getAllPossibleErrors() now constructs the result directly using
the module-level t() at en-GB, matching the pattern used by
EastingNorthingField.
…l.language)

Remove free t() import from all five page controllers; replace every
t(key, lang/this.model.language, opts) call with this.model.t(key, opts).
Includes getBackLink lang var removal and all RepeatPageController
list-summary translation calls.
The two inline controller.model mocks in the dispatcher error tests
were missing the t() method after PaymentField.ts was updated to call
model.t() instead of the free t(key, lang) function.
Adds x-pirate locale (arrr), registers it in i18next, and wires up
simple-form-pirate.yaml in localFormsService. Visit /simple-form-pirate
to experience the high seas.
Apply pirate flavour to every remaining bland key — date field labels,
lat/long errors, address fields, button labels, repeater actions, and
payment strings. Comedy matters everywhere.
alexluckett and others added 29 commits April 27, 2026 22:40
…hrough all getViewModel, getViewErrors, getDisplayStringFromState

- Translator required (not union) in FormComponent.getViewModel and all subclass overrides
- isForceAccess boolean param replaces FormQuery in ComponentCollection.getViewModel and FileUploadField
- ComponentCollection.getViewErrors passes translator to field.getViewErrors
- QuestionPageController passes translator to collection.getViewErrors calls
- getDisplayStringFromFormValue/getDisplayStringFromState accept optional Translator
- GeospatialField and DeclarationField use translator.t when provided, tPlugin fallback otherwise
- getAnswer() and ItemField() accept optional Translator, thread from SummaryViewModel
- FileUploadField.onSubmit and routes/questions.ts handleHttpEvent use per-request language from getPluginOptions
- FormModel.fieldStateIsInvalid uses form default language as fallback when no translator
Translate all plugin UI strings into Welsh. Register cy locale in both
the global i18next instance and createFormI18nInstance so per-request
translators resolve Welsh strings when language is set to 'cy'.
…on time

ComponentCollection.validate now rebuilds the Joi schema with the translated
shortDescription (or title) as the field label when a Translator is provided.
This ensures #label in validation message templates like 'Nodwch {{lowerFirst(#label)}}'
resolves to the translated value (e.g. 'eich enw olaf') rather than the
construction-time English value ('your last name').
… ItemField rows

ItemField now uses tContent to resolve translated shortDescription (row key) and
title (Change link visuallyHiddenText) for each field. Builds a lookup object with
the English values so the GUID-based translation lookup fires correctly.
ItemRepeat now accepts and passes translator, and uses t('pages.repeater.pageTitle')
for the repeater value string instead of a hardcoded English template.
…jucks global

getLanguage now reads from yar session (set on first ?language= query param)
so language preference persists across redirects. Registers t as a nunjucks
global so templates can call t() directly.
…FromFormValue

Uses t('components.fileUploadField.filesCount', { count }) for the check-your-answers
display string instead of the hardcoded English "Uploaded N file(s)". Falls back to
the English template when no translator is provided (e.g. email formatting).
…ionField default label

ComponentCollection.validate now processes composite field sub-fields:
- Translates sub-field labels via t(subField.title) so key constants like
  'components.addressField.line1' resolve to e.g. "Llinell cyfeiriad 1" (#label)
- Calls field.getValidationMessagesOverride(translator) to apply per-request
  Joi message overrides that replace schema-level English .messages() calls

DatePartsField and MonthYearField implement getValidationMessagesOverride to
return Welsh objectMissing/dateFormat expressions, fixing date validation errors.

DeclarationField no longer resolves the default checkbox label at construction
time via tPlugin('en-GB'). It stores undefined and lets getViewModel resolve
t('components.declarationField.defaultLabel') at render time.
…rs in correct language

UkAddressField.dispatcher now resolves the per-request language via getPluginOptions
and includes it in the initial session data. The postcode lookup models already
read session.initial.language — it was simply never being set.
…ection titles

YesNo list items now store i18n key constants ('components.yesNoField.yes') instead
of construction-time English strings. ListFormComponent.getViewModel and
getDisplayStringFromFormValue resolve them via tContent/tPlugin at render time.
getAnswerMarkdown also resolves item text via translator.

DeclarationField.getValidationMessagesOverride returns Welsh declarationRequired
expression; ComponentCollection.validate now also applies message overrides for
non-composite fields (same pattern as composite sub-fields).

SummaryViewModel.summaryDetails resolves section titles via tContent.

stubTranslator.tContent now resolves raw values via resolveKey('en-GB') so i18n
key constants (e.g. 'components.yesNoField.yes') return 'Yes' in tests.
…ate YesNo validation

resolveContent now calls t(raw) as fallback when a GUID entity has no form
translation, so plugin key constants like 'components.yesNoField.yes' stored
as list item text are resolved to 'Ie'/'Na' etc. rather than returned verbatim.

YesNoField.getValidationMessagesOverride applies the per-request Welsh
selectYesNoRequired template at validation time, replacing the English message
baked into the schema at construction time.
…introduce RenderContext for components

Move the getLanguage/createTranslator boilerplate into a protected
PageController.getTranslator(request) helper so new page controllers
inherit it without any i18n knowledge.

Replace the four-positional-param getViewModel signature on all form
components with a single RenderContext object { payload, errors,
translator, isForceAccess? } so future context additions (permissions,
feature flags, etc.) don't require touching every component signature.
…iminate fallback patterns

translator is now required on getDisplayStringFromState, getDisplayStringFromFormValue,
getViewErrors, getAnswer, and getAnswerMarkdown. All callers either thread a per-request
translator or construct one via model.createTranslator() which defaults to en-GB.

Removes all translator?.t ?? tPlugin() fallback patterns — English now lives only in
en-GB.json. GeospatialField, FileUploadField, UkAddressField, CheckboxesField,
DeclarationField, and ListFormComponent cleaned up accordingly. getErrors retains
optional translator since it is called from validation paths without a request context.
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
1 New Major Issues (required ≤ 0)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants