From 68568a2ab61c5d21d41df1593d24e7e27381fd41 Mon Sep 17 00:00:00 2001 From: Kimberly Grey Date: Fri, 26 Aug 2022 16:11:27 +0100 Subject: [PATCH] Add i18n lookup function --- src/govuk/components/accordion/accordion.mjs | 25 ++++++++---- src/govuk/i18n.mjs | 33 +++++++++++++++ src/govuk/i18n.unit.test.mjs | 42 ++++++++++++++++++++ 3 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 src/govuk/i18n.mjs create mode 100644 src/govuk/i18n.unit.test.mjs diff --git a/src/govuk/components/accordion/accordion.mjs b/src/govuk/components/accordion/accordion.mjs index 897e7524a7..e63b659150 100644 --- a/src/govuk/components/accordion/accordion.mjs +++ b/src/govuk/components/accordion/accordion.mjs @@ -16,6 +16,7 @@ */ import { nodeListForEach } from '../../common.mjs' +import I18n from '../../i18n.mjs' import '../../vendor/polyfills/Function/prototype/bind.mjs' import '../../vendor/polyfills/Element/prototype/classList.mjs' @@ -25,6 +26,16 @@ function Accordion ($module) { this.$showAllButton = '' this.browserSupportsSessionStorage = helper.checkForSessionStorage() + var defaultConfig = { + i18n: { + hideAllSections: 'Hide all sections', + hideSection: 'Hide this section', + showAllSections: 'Show all sections', + showSection: 'Show this section' + } + } + this.i18n = new I18n(defaultConfig.i18n) + this.controlsClass = 'govuk-accordion__controls' this.showAllClass = 'govuk-accordion__show-all' this.showAllTextClass = 'govuk-accordion__show-all-text' @@ -232,15 +243,11 @@ Accordion.prototype.setExpanded = function (expanded, $section) { var $icon = $section.querySelector('.' + this.upChevronIconClass) var $showHideText = $section.querySelector('.' + this.sectionShowHideTextClass) var $button = $section.querySelector('.' + this.sectionButtonClass) - var newButtonText = expanded ? 'Hide' : 'Show' - - // Build additional copy of "this section" for assistive technology and place inside toggle link - var $visuallyHiddenText = document.createElement('span') - $visuallyHiddenText.classList.add('govuk-visually-hidden') - $visuallyHiddenText.innerHTML = ' this section' + var newButtonText = expanded + ? this.i18n.t('hideSection') + : this.i18n.t('showSection') $showHideText.innerHTML = newButtonText - $showHideText.appendChild($visuallyHiddenText) $button.setAttribute('aria-expanded', expanded) // Swap icon, change class @@ -277,7 +284,9 @@ Accordion.prototype.checkIfAllSectionsOpen = function () { Accordion.prototype.updateShowAllButton = function (expanded) { var $showAllIcon = this.$showAllButton.querySelector('.' + this.upChevronIconClass) var $showAllText = this.$showAllButton.querySelector('.' + this.showAllTextClass) - var newButtonText = expanded ? 'Hide all sections' : 'Show all sections' + var newButtonText = expanded + ? this.i18n.t('hideAllSections') + : this.i18n.t('showAllSections') this.$showAllButton.setAttribute('aria-expanded', expanded) $showAllText.innerHTML = newButtonText diff --git a/src/govuk/i18n.mjs b/src/govuk/i18n.mjs new file mode 100644 index 0000000000..18231287c2 --- /dev/null +++ b/src/govuk/i18n.mjs @@ -0,0 +1,33 @@ +/** + * i18n support initialisation function + * + * @constructor + * @param {Object} translations - Key-value pairs of the translation + strings to use. + */ +function I18n (translations) { + // Make list of translations available throughout function + this.translations = translations || {} +} + +/** + * The most used function - takes the key for a given piece of UI text and + * returns the appropriate string. + * + * @param {String} lookupKey - The lookup key of the string to use. + * @returns {String} - The appropriate translation string. + */ +I18n.prototype.t = function (lookupKey) { + if (!lookupKey) { + // Print a console error if no lookup key has been provided + throw new Error('i18n lookup key missing.') + } else if (lookupKey in this.translations) { + // Return the translation string if it exists in the object + return this.translations[lookupKey] + } else { + // Otherwise, return the lookup key itself as the fallback + return lookupKey + } +} + +export default I18n diff --git a/src/govuk/i18n.unit.test.mjs b/src/govuk/i18n.unit.test.mjs new file mode 100644 index 0000000000..0d4100ff0c --- /dev/null +++ b/src/govuk/i18n.unit.test.mjs @@ -0,0 +1,42 @@ +/** + * @jest-environment jsdom + */ +/* eslint-env jest */ + +import I18n from './i18n.mjs' + +describe('I18n', () => { + describe('retrieving translations', () => { + let config = {} + + beforeEach(() => { + config = { + textString: 'Hello world', + htmlString: 'Hello world' + } + }) + + test('returns the text for a given lookup key', () => { + const i18n = new I18n(config) + const returnString = i18n.t('textString') + expect(returnString).toBe('Hello world') + }) + + test('returns the HTML for a given lookup key', () => { + const i18n = new I18n(config) + const returnString = i18n.t('htmlString') + expect(returnString).toBe('Hello world') + }) + + test('returns the lookup key if no translation is defined', () => { + const i18n = new I18n(config) + const returnString = i18n.t('missingString') + expect(returnString).toBe('missingString') + }) + + test('throws an error if no lookup key is provided', () => { + const i18n = new I18n(config) + expect(() => i18n.t()).toThrow('i18n lookup key missing.') + }) + }) +})