Skip to content
Merged
216 changes: 169 additions & 47 deletions src/client/javascripts/geospatial-map.js

Large diffs are not rendered by default.

52 changes: 50 additions & 2 deletions src/client/javascripts/location-map.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
// @ts-expect-error - no types
import createDatasetsPlugin from '@defra/interactive-map/plugins/datasets'

import {
DEFAULT_LANG,
ENGLISH_LANG,
WELSH_LANG
} from '~/src/client/javascripts/map-constants.js'
import {
EVENTS,
centerMap,
Expand All @@ -14,9 +19,30 @@ import {
osGridRefToLatLong
} from '~/src/client/javascripts/map.js'
import sssiDataset from '~/src/client/javascripts/sssi-dataset.js'
import cy from '~/src/server/plugins/engine/i18n/translations/cy.json' with { type: 'json' }
import enGB from '~/src/server/plugins/engine/i18n/translations/en-GB.json' with { type: 'json' }

const englishTranslations = enGB.components.locationFieldBase.map
const welshTranslations = cy.components.locationFieldBase.map

const LOCATION_FIELD_SELECTOR = 'input.govuk-input'

/**
* @type {Record<LanguageCode, LocationLanguageTexts>}
*/
export const languageTexts = {
[ENGLISH_LANG]: englishTranslations,
[WELSH_LANG]: welshTranslations
}

/**
* Get the map texts for the given language code
* @param {LanguageCode} lang - the lanugae code
*/
export function getTexts(lang = DEFAULT_LANG) {
return languageTexts[lang]
}

/**
* Gets initial map config for a location field
* @param {HTMLDivElement} locationField - the location field element
Expand Down Expand Up @@ -437,6 +463,11 @@ export function processLocation(config, location, index) {
initConfig.plugins = [createDatasetsPlugin({ datasets })]
}

const lang = /** @type {LanguageCode} */ (
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
location.dataset.lang || DEFAULT_LANG
)

const { map, interactPlugin } = createMap(mapId, initConfig, config)

map.on(
Expand All @@ -461,11 +492,13 @@ export function processLocation(config, location, index) {
throw new Error('Not implemented')
}

const texts = getTexts(lang)

// Add info panel
map.addPanel('info', {
focus: false,
showLabel: true,
label: 'How to use the map',
label: texts.helpPanel.label,
mobile: {
slot: 'drawer',
open: true,
Expand All @@ -484,7 +517,7 @@ export function processLocation(config, location, index) {
dismissible: true,
modal: false
},
html: '<ul><li>Search for a place or postcode</li><li>Use the + and - icons to zoom in and out</li><li>Use a mouse or keyboard to centre the point at the location</li><li>Click to add the location to the map</li></ul>'
html: `<ul><li>${texts.helpPanel.point1}</li><li>${texts.helpPanel.point2}</li><li>${texts.helpPanel.point3}</li><li>${texts.helpPanel.point4}</li></ul>`
})

// Enable the interact plugin
Expand All @@ -494,5 +527,20 @@ export function processLocation(config, location, index) {
}

/**
* @typedef {object} LocationPanelTexts
* @property {string} label - the label for the info panel
* @property {string} point1 - the text for bullet point 1 in the info panel
* @property {string} point2 - the text for bullet point 2 in the info panel
* @property {string} point3 - the text for bullet point 3 in the info panel
* @property {string} point4 - the text for bullet point 4 in the info panel
*/

/**
* @typedef {object} LocationLanguageTexts
* @property {LocationPanelTexts} helpPanel - texts for the info panel
*/

/**
* @import { LanguageCode } from '~/src/client/javascripts/map.js'
* @import { InteractiveMap, InteractiveMapInitConfig, MapCenter, MapLibreMap, MapsEnvironmentConfig } from '~/src/client/javascripts/map.js'
*/
3 changes: 3 additions & 0 deletions src/client/javascripts/map-constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const ENGLISH_LANG = 'en-GB'
export const WELSH_LANG = 'cy'
export const DEFAULT_LANG = ENGLISH_LANG
5 changes: 5 additions & 0 deletions src/client/javascripts/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -460,3 +460,8 @@ export function getMapCountryLayers(apiPath, country) {
/**
* @import { Feature } from '~/src/server/plugins/engine/types.js'
*/

/**
* Supported language codes
* @typedef {('en-GB'|'cy')} LanguageCode
*/
1 change: 1 addition & 0 deletions src/server/plugins/engine/components/GeospatialField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export class GeospatialField extends FormComponent {

return {
...viewModel,
lang: context.translator.language,
country: this.options.countries?.at(0),
geometryTypes: this.options.geometryTypes,
mapLayers: getMapLayers(this),
Expand Down
4 changes: 4 additions & 0 deletions src/server/plugins/engine/components/LocationFieldBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ export abstract class LocationFieldBase extends FormComponent {
getViewModel(context: RenderContext) {
const viewModel = super.getViewModel(context)

Object.assign(viewModel, {
lang: context.translator.language
})

if (this.instructionText) {
const { tComponent } = context.translator
return {
Expand Down
3 changes: 2 additions & 1 deletion src/server/plugins/engine/components/LocationFieldHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ export function getLocationFieldViewModel(
country:
component instanceof EastingNorthingField
? component.options.countries?.at(0)
: undefined
: undefined,
lang: context.translator.language
}

if (component.options.instructionText) {
Expand Down
52 changes: 51 additions & 1 deletion src/server/plugins/engine/i18n/translations/cy.json
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,16 @@
},

"locationFieldBase": {
"howToFind": "Sut i ddod o hyd i fanylion lleoliad"
"howToFind": "Sut i ddod o hyd i fanylion lleoliad",
"map": {
"helpPanel": {
"label": "Sut i ddefnyddio'r map hwn",
"point1": "Chwilio am sir, lle neu god post",
"point2": "Defnyddiwch yr eiconau + a - i chwyddo i mewn ac allan",
"point3": "Defnyddiwch lyfliwr neu allweddlon i ganolbwyntio'r pwynt yn y lleoliad",
"point4": "Cliciwch i ychwanegu'r lleoliad i'r map"
}
}
},

"yesNoField": {
Expand All @@ -350,6 +359,47 @@
"added_few": "Ychwanegwyd [[count]] lleoliad",
"added_many": "Ychwanegwyd [[count]] o leoliadau",
"added_other": "Ychwanegwyd [[count]] lleoliad",
"map": {
"helpPanel": {
"label": "Sut i ddefnyddio'r map hwn",
"ledeIntro": "Gallwch ychwanegu",
"ledeOutro": "i'r map.",
"lineText": "llinell",
"shapeText": "siâp",
"lineOrShapeText": "llinell neu siâp",
"typesPhrasePoint": "pwyntiau",
"typesPhraseLine": "lliniau",
"typesPhraseShape": "siâpiau",
"typesPhraseOr": "neu",
"point1": "Chwilio am sir, lle neu god post",
"point2": "Defnyddiwch yr eiconau + a - i chwyddo i mewn ac allan",
"point3": "Cliciwch ddwywaith, neu dewiswch 'Wedi gorffen', pan fyddwch wedi",
"point4": "Rhowch enw i'r lleoliad"
},
"typeDescriptions": {
"point": "Pwynt",
"line": "Llinell",
"polygon": "Siâp"
},
"buttons": {
"point": "Ychwanegu pwynt",
"line": "Ychwanegu llinell",
"polygon": "Ychwanegu siâp"
},
"itemLabel1": "Lleoliad",
"itemLabel2": "disgrifiad",
"itemUpdateLink": "Diweddaru",
"itemDeleteLink": "Dileu",
"itemFocusLink": "Dangos",
"itemVisuallyHidden": "lleoliad",
"details": {
"summary": "Cyfesurynnau",
"type": "Math",
"centroidGridReference": "Canol cyfeirnod grid",
"firstPointGridReference": "Cyfeirnod grid y pwynt cyntaf",
"detailedCoordinates": "Cyfesurynnau manwl"
}
},
"validation": {
"descriptionRequired": "Rhowch ddisgrifiad ar gyfer lleoliad [[count]]",
"wrongCountry": "Rhaid i leoliad [[count]] fod y tu mewn i [[country]]"
Expand Down
52 changes: 51 additions & 1 deletion src/server/plugins/engine/i18n/translations/en-GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,16 @@
},

"locationFieldBase": {
"howToFind": "How to find location details"
"howToFind": "How to find location details",
"map": {
"helpPanel": {
"label": "How to use this map",
"point1": "Search for a place or postcode",
"point2": "Use the + and - icons to zoom in and out",
"point3": "Use a mouse or keyboard to centre the point at the location",
"point4": "Click to add the location to the map"
}
}
},

"yesNoField": {
Expand All @@ -289,6 +298,47 @@
"geospatialField": {
"added_one": "Added [[count]] location",
"added_other": "Added [[count]] locations",
"map": {
"helpPanel": {
"label": "How to use this map",
"ledeIntro": "You can add",
"ledeOutro": "to the map.",
"lineText": "a line",
"shapeText": "a shape",
"lineOrShapeText": "a line or shape",
"typesPhrasePoint": "points",
"typesPhraseLine": "lines",
"typesPhraseShape": "shapes",
"typesPhraseOr": "or",
"point1": "Search for a county, place or postcode",
"point2": "Use the + and - icons to zoom in and out",
"point3": "Double‑click, or select 'Done', when you have finished drawing",
"point4": "Give the location a name"
},
"typeDescriptions": {
"point": "Point",
"line": "Line",
"polygon": "Shape"
},
"buttons": {
"point": "Add point",
"line": "Add line",
"polygon": "Add shape"
},
"itemLabel1": "Location",
"itemLabel2": "description",
"itemUpdateLink": "Update",
"itemDeleteLink": "Delete",
"itemFocusLink": "Show",
"itemVisuallyHidden": "location",
"details": {
"summary": "Coordinates",
"type": "Type",
"centroidGridReference": "Centre grid reference",
"firstPointGridReference": "First point grid reference",
"detailedCoordinates": "Detailed coordinates"
}
},
"validation": {
"descriptionRequired": "Enter description for location [[count]]",
"wrongCountry": "Location [[count]] must be within [[country]]"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
<div id="{{component.model.name}}" class="govuk-form-group app-location-field {{ "govuk-form-group--error" if hasErrors }}"
data-locationtype="{{component.type | lower}}"
data-country="{{component.model.country}}"
data-lang="{{component.model.lang}}"
data-maplayers="{{component.model.mapLayers}}">
{{ govukFieldset({
legend: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

{% macro GeospatialField(component) %}
<div class="app-geospatial-field"
data-lang="{{component.model.lang}}"
data-country="{{component.model.country}}"
data-geometryTypes="{{component.model.geometryTypes}}"
data-maplayers="{{component.model.mapLayers}}">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

{% macro OsGridRefField(component) %}
{% set hasErrors = component.model.errorMessage %}
<div class="govuk-form-group app-location-field {{ "govuk-form-group--error" if hasErrors }}" data-locationtype="{{component.type | lower}}">
<div class="govuk-form-group app-location-field {{ "govuk-form-group--error" if hasErrors }}"
data-locationtype="{{component.type | lower}}"
data-lang="{{component.model.lang}}">
<div class="app-location-field-inputs">
{{ TextField(component) }}
</div>
Expand Down
31 changes: 31 additions & 0 deletions test/client/javascripts/geospatial-map-i18n.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { getTexts } from '~/src/client/javascripts/geospatial-map.js'
import {
ENGLISH_LANG,
WELSH_LANG
} from '~/src/client/javascripts/map-constants.js'
import cy from '~/src/server/plugins/engine/i18n/translations/cy.json' with { type: 'json' }
import enGB from '~/src/server/plugins/engine/i18n/translations/en-GB.json' with { type: 'json' }

describe('geospatial map translations', () => {
it('uses the shared server translation values for the English map UI', () => {
const texts = getTexts(ENGLISH_LANG)

expect(texts.helpPanel.label).toBe(
enGB.components.geospatialField.map.helpPanel.label
)
expect(texts.buttons.point).toBe(
enGB.components.geospatialField.map.buttons.point
)
})

it('uses the shared server translation values for the Welsh map UI', () => {
const texts = getTexts(WELSH_LANG)

expect(texts.helpPanel.label).toBe(
cy.components.geospatialField.map.helpPanel.label
)
expect(texts.buttons.point).toBe(
cy.components.geospatialField.map.buttons.point
)
})
})
17 changes: 10 additions & 7 deletions test/client/javascripts/map.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import {
createFeatureHTML,
createFeaturesHTML,
getHelpPanelHtml,
getTexts,
getUIManager
} from '~/src/client/javascripts/geospatial-map.js'
import { ENGLISH_LANG } from '~/src/client/javascripts/map-constants.js'
import {
formSubmitFactory,
getCentroidGridRef,
Expand Down Expand Up @@ -310,38 +312,39 @@ describe('Maps Client JS', () => {
})

describe('getHelpPanelHtml', () => {
const texts = getTexts(ENGLISH_LANG)
it('should handle only point', () => {
expect(getHelpPanelHtml(true, false, false)).toBe(
expect(getHelpPanelHtml(texts.helpPanel, true, false, false)).toBe(
'<p class="govuk-body-s govuk-!-margin-bottom-2">You can add points to the map.</p><ul class="govuk-list govuk-list--number govuk-body-s"><li>Search for a county, place or postcode</li><li>Use the + and - icons to zoom in and out</li><li>Give the location a name</li></ul>'
)
})
it('should handle only line', () => {
expect(getHelpPanelHtml(false, true, false)).toBe(
expect(getHelpPanelHtml(texts.helpPanel, false, true, false)).toBe(
'<p class="govuk-body-s govuk-!-margin-bottom-2">You can add lines to the map.</p><ul class="govuk-list govuk-list--number govuk-body-s"><li>Search for a county, place or postcode</li><li>Use the + and - icons to zoom in and out</li><li>Double‑click, or select \'Done\', when you have finished drawing a line</li><li>Give the location a name</li></ul>'
)
})
it('should handle only shape', () => {
expect(getHelpPanelHtml(false, false, true)).toBe(
expect(getHelpPanelHtml(texts.helpPanel, false, false, true)).toBe(
'<p class="govuk-body-s govuk-!-margin-bottom-2">You can add shapes to the map.</p><ul class="govuk-list govuk-list--number govuk-body-s"><li>Search for a county, place or postcode</li><li>Use the + and - icons to zoom in and out</li><li>Double‑click, or select \'Done\', when you have finished drawing a shape</li><li>Give the location a name</li></ul>'
)
})
it('should handle point and line', () => {
expect(getHelpPanelHtml(true, true, false)).toBe(
expect(getHelpPanelHtml(texts.helpPanel, true, true, false)).toBe(
'<p class="govuk-body-s govuk-!-margin-bottom-2">You can add points or lines to the map.</p><ul class="govuk-list govuk-list--number govuk-body-s"><li>Search for a county, place or postcode</li><li>Use the + and - icons to zoom in and out</li><li>Double‑click, or select \'Done\', when you have finished drawing a line</li><li>Give the location a name</li></ul>'
)
})
it('should handle point and shape', () => {
expect(getHelpPanelHtml(true, false, true)).toBe(
expect(getHelpPanelHtml(texts.helpPanel, true, false, true)).toBe(
'<p class="govuk-body-s govuk-!-margin-bottom-2">You can add points or shapes to the map.</p><ul class="govuk-list govuk-list--number govuk-body-s"><li>Search for a county, place or postcode</li><li>Use the + and - icons to zoom in and out</li><li>Double‑click, or select \'Done\', when you have finished drawing a shape</li><li>Give the location a name</li></ul>'
)
})
it('should handle line and shape', () => {
expect(getHelpPanelHtml(false, true, true)).toBe(
expect(getHelpPanelHtml(texts.helpPanel, false, true, true)).toBe(
'<p class="govuk-body-s govuk-!-margin-bottom-2">You can add lines or shapes to the map.</p><ul class="govuk-list govuk-list--number govuk-body-s"><li>Search for a county, place or postcode</li><li>Use the + and - icons to zoom in and out</li><li>Double‑click, or select \'Done\', when you have finished drawing a line or shape</li><li>Give the location a name</li></ul>'
)
})
it('should handle point, line and shape', () => {
expect(getHelpPanelHtml(true, true, true)).toBe(
expect(getHelpPanelHtml(texts.helpPanel, true, true, true)).toBe(
'<p class="govuk-body-s govuk-!-margin-bottom-2">You can add points, lines or shapes to the map.</p><ul class="govuk-list govuk-list--number govuk-body-s"><li>Search for a county, place or postcode</li><li>Use the + and - icons to zoom in and out</li><li>Double‑click, or select \'Done\', when you have finished drawing a line or shape</li><li>Give the location a name</li></ul>'
)
})
Expand Down
Loading