Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DO NOT MERGE] Internationalisation support #2614

Closed
wants to merge 34 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9eddfab
Allow localisation of copyright and content licence
querkmachine May 27, 2022
1a29a44
Add parameters to hide the OGL and Crown Copyright graphics
querkmachine May 30, 2022
33d788b
Add parameter to localise mobile menu toggle button
querkmachine May 30, 2022
cc88f85
Enable custom limit hint text on character count
querkmachine May 30, 2022
1cb8938
i18n support prototype
querkmachine Apr 28, 2022
45aaa93
Add pluralisation support for fallback phrases
querkmachine May 11, 2022
e62bf24
Export I18n function
querkmachine May 11, 2022
9f1b448
Fix some last-minute refactoring removing something it shouldn't
querkmachine May 11, 2022
139e0fd
Tidy up documentation
querkmachine May 11, 2022
db3f03e
Changes for IE9–11 support
querkmachine May 23, 2022
eed52b5
Polyfill Object.keys for IE8
querkmachine May 23, 2022
4c174a2
Polyfill Array.prototype.indexOf for IE8
querkmachine May 23, 2022
044ac8b
Don't run flatten method if no translations are passed in
querkmachine May 24, 2022
cbbd1d8
Rename i18n function to I18n
querkmachine May 25, 2022
044a311
Refactor I18n to use a singleton pattern
querkmachine May 25, 2022
c84e74a
Document getInstance function
querkmachine May 25, 2022
f8a4c9f
Add error checking for an invalid lookup key
querkmachine May 26, 2022
b50767f
Validate that count option is a number we can use
querkmachine May 26, 2022
e9bb7e0
Remove separator configuration option
querkmachine May 26, 2022
6e49322
Add check for if a string contains placeholders
querkmachine May 26, 2022
49f5605
Remove debug code
querkmachine May 26, 2022
c869791
Amend tests for I18n support
querkmachine May 31, 2022
a56fd78
Make I18n a private function
querkmachine Jun 6, 2022
d2dee7c
Remove demo configuration
querkmachine Jun 7, 2022
bae8012
Add localised components full-page example
querkmachine Jun 8, 2022
3127cf3
Add localisation tests
querkmachine Jun 8, 2022
220a5d7
Update character count fallback text test
querkmachine Jun 8, 2022
7478719
Add code to progressively enhance to Intl.PluralRules
querkmachine Jun 9, 2022
64977b3
Remove duplicated localisation example
querkmachine Jun 13, 2022
1bfc346
Add localised number formatting for 'count'
querkmachine Jun 13, 2022
9e2f3f1
Spike component-level approach to i18n initialisation
querkmachine Jun 20, 2022
39d2e7c
Fix tests
querkmachine Jun 20, 2022
ba97460
Swap out Object.assign polyfill
querkmachine Jun 21, 2022
0697445
Rename new .js files to .mjs
querkmachine Jun 23, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 212 additions & 0 deletions app/views/full-page-examples/localisation/index.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
---
scenario: >-
Examples of various components translated into Welsh.
---

{# Example content derived from: https://www.gov.uk/adnewyddu-trwydded-yrru #}
{% extends "full-page-example.njk" %}

{% from "skip-link/macro.njk" import govukSkipLink %}
{% from "footer/macro.njk" import govukFooter %}
{% from "breadcrumbs/macro.njk" import govukBreadcrumbs %}
{% from "button/macro.njk" import govukButton %}
{% from "accordion/macro.njk" import govukAccordion %}
{% from "character-count/macro.njk" import govukCharacterCount %}

{% set pageTitle = "Adnewyddu eich trwydded yrru" %}
{% block pageTitle %}{{ pageTitle }} - GOV.UK{% endblock %}

{% set htmlLang = "cy" %}

{% block skipLink %}
{{ govukSkipLink({
href: '#main-content',
text: "Symud i'r prif gynnwys"
}) }}
{% endblock %}

{% block beforeContent %}
{{ govukBreadcrumbs({
items: [
{
text: "Hafan",
href: "#/"
},
{
text: "Gyrru a chludiant",
href: "#/browse/driving"
},
{
text: "Trwyddedau gyrru",
href: "#/browse/driving/driving-licences"
}
]
}) }}
{% endblock %}

{% block content %}
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<h1 class="govuk-heading-xl">{{ pageTitle }}</h1>

<p class="govuk-body">Bydd arnoch angen pasbort y DU dilys i adnewyddu eich trwydded ar-lein gyda DVLA.</p>

<h2 class="govuk-heading-m" id="adnewyddu-ar-lein">Adnewyddu ar-lein</h2>

<p class="govuk-body">Bydd eich trwydded newydd yn ddilys o’r dyddiad y mae’ch cais yn cael ei gymeradwyo, nid o ddyddiad dod i ben eich trwydded gyfredol.</p>

{{ govukButton({
text: "Dechrau nawr",
href: "#",
classes: "govuk-!-margin-top-2 govuk-!-margin-bottom-8",
isStartButton: true
}) }}

{{ govukCharacterCount({
label: { text: "Enw(au) cyntaf" },
hint: { text: "Rhowch eich enw cyntaf ac unrhyw enwau canol." },
limitHint: "Ysgrifennwch hyd at %{count} o nodau",
id: "character-count",
maxlength: 20,
value: 'A1234567890'
}) }}

{% set moreInformationHTML %}
<p class="govuk-body">Mae’n rhaid ichi adnewyddu trwydded cerdyn-llun bob 10 mlynedd - byddwch yn derbyn nodyn atgoffa cyn bod eich trwydded gyfredol yn dod i ben.</p>

<h2 class="govuk-heading-m">Beth sydd arnoch angen</h2>

<p class="govuk-body">I adnewyddu ar-lein, mae arnoch angen y canlynol:</p>

<ul class="govuk-list govuk-list--bullet">
<li>pasbort y DU dilys</li>
<li>bod yn breswylydd ym Mhrydain Fawr - mae gwasanaeth gwahanol i gael yng <a class="govuk-link" rel="external" href="https://www.nidirect.gov.uk/articles/renew-your-driving-licence">Ngogledd Iwerddon</a>
</li>
<li>talu £14 gyda cherdyn debyd neu gredyd Mastercard, Visa, Electron neu Delta (nid oes ffi os ydych dros 70 neu os oes gennych drwydded cyfnod byr am resymau meddygol)</li>
<li>cyfeiriadau lle rydych wedi byw dros y 3 blynedd diwethaf</li>
<li>eich trwydded yrru gyfredol (os nad oes gennych eich trwydded mae’n rhaid ichi roi’r rheswm yn eich cais)</li>
<li>eich rhif Yswiriant Gwladol (os ydych yn ei wybod)</li>
<li>peidio â bod wedi eich gwahardd rhag gyrru</li>
</ul>

<h2 class="govuk-heading-m">Data personol</h2>

<p class="govuk-body">Bydd DVLA yn anfon ebost cadarnhau atoch unwaith eich bod wedi gwneud cais. Efallai y gofynnir ichi gymryd rhan mewn ymchwil drwy e-bost, ond gallwch optio allan.</p>
{% endset %}

{% set otherWaysToApplyHTML %}
<h2 class="govuk-heading-m">Gwneud cais mewn Swyddfa’r Post</h2>

<p class="govuk-body">Byddwch yn cael llythyr atgoffa yn y post. Gallwch gymryd hwn i <a class="govuk-link" rel="external" href="http://www.postoffice.co.uk/branch-finder">Swyddfa’r Post</a> sy’n delio ag adnewyddu trwyddedau cerdyn-llun DVLA.</p>

<p>Bydd hefyd angen ichi gymryd:</p>

<ul class="govuk-list govuk-list--bullet">
<li>eich trwydded yrru cerdyn-llun os ydyw gennych</li>
<li>y ffi o £21.50</li>
</ul>

<p class="govuk-body">Os nad oes gennych lythyr atgoffa, bydd arnoch angen eich trwydded yrru cerdyn-llun i wneud cais mewn Swyddfa’r Post.</p>

<div role="note" class="govuk-inset-text">
<p class="govuk-body">Ni allwch wneud cais mewn Swyddfa’r Post os yw’ch enw wedi newid. Bydd angen ichi wneud cais drwy’r post.</p>
</div>

<h2 class="govuk-heading-m" id="gwneud-cais-drwyr-post">Gwneud cais drwy’r post</h2>

<div role="note" class="govuk-inset-text">
<p class="govuk-body">Mae’n cymryd yn hirach na’r arfer i brosesu ceisiadau a anfonir trwy’r post oherwydd coronafeirws (COVID-19).</p>
</div>

<p class="govuk-body">Gallwch gael ‘pecyn D1W’ o ffurflenni o <a class="govuk-link" rel="external" href="http://www.postoffice.co.uk/branch-finder">Swyddfa’r Post</a> sy’n delio ag adnewyddu trwyddedau cerdyn-llun neu dreth cerbyd DVLA.</p>

<p class="govuk-body">Mae angen ichi gynnwys y pethau canlynol gyda’ch ffurflenni wedi’u cwblhau:</p>

<ul class="govuk-list govuk-list--bullet">
<li>
<a class="govuk-link" href="/photos-for-passports">ffotograff math pasbort</a> diweddar (peidiwch â llofnodi cefn y llun)</li>
<li>eich trwydded cerdyn-llun gyfredol os ydyw gennych</li>
<li>siec neu archeb bost am £17, yn daladwy i DVLA (nid oes ffi yn daladwy os oes gennych drwydded yrru cyfnod byr am resymau meddygol neu os ydych yn 70 oed neu’n hŷn)</li>
</ul>

<p class="govuk-body">Mae hefyd angen ichi gynnwys <a class="govuk-link" href="/driving-licence-application-identity-documents">dogfennau adnabod</a> os ydych wedi newid eich enw.</p>

<p class="govuk-body">Anfonwch y cais i:</p>

<p class="govuk-body">DVLA
<br>Abertawe
<br>SA99 1DH
<br>
</p>

<h2 class="govuk-heading-m" id="ar-l-ichi-wneud-cais-mewn-swyddfar-post-neu-drwyr-post">Ar ôl ichi wneud cais mewn Swyddfa’r Post neu drwy’r post</h2>

<p class="govuk-body">Gallwch barhau i yrru tra rydych yn aros am eich trwydded newydd gyrraedd.</p>

{% endset %}

{{ govukAccordion({
id: "accordion-default",
items: [
{
heading: { text: "Rhagor o wybodaeth" },
content: {
html: moreInformationHTML
}
},
{
heading: { text: "Ffyrdd eraill o wneud cais" },
content: {
html: otherWaysToApplyHTML
}
}
]
}) }}
</div>


</div>
{% endblock %}

{% block footer %}
{{ govukFooter({
contentLicence: 'Mae’r holl gynnwys ar gael dan <a class="govuk-footer__link" href="https://www.nationalarchives.gov.uk/doc/open-government-licence-cymraeg/version/3/" rel="license">Drwydded y Llywodraeth Agored v3.0</a>, ac eithrio lle nodir yn wahanol',
copyright: '© Hawlfraint y Goron'
}) }}
{% endblock %}

{% block bodyEnd %}
<script src="/public/all.js"></script>
<script>window.GOVUKFrontend.initAll({
accordion: {
i18n: {
locale: "cy",
translations: {
show_all_sections: "Show ALL THE THINGS!!!",
hide_all_sections: "Cuddiwch bob adran",
show_this_section: "Dangoswch yr adran hon",
hide_this_section: "Cuddio'r adran hon"
}
}
},
character_count: {
i18n: {
locale: "cy",
translations: {
characters_over_limit_zero: "Rydych chi %{count} llythyrau drosodd",
characters_over_limit_one: "Rydych chi %{count} llythyr drosodd",
characters_over_limit_two: "Rydych chi %{count} lythyren drosodd",
characters_over_limit_few: "Rydych chi %{count} llythyren drosodd",
characters_over_limit_many: "Rydych chi %{count} llythyren drosodd",
characters_over_limit_other: "Rydych chi %{count} o lythyrau drosodd",
characters_under_limit_zero: "Mae gennych %{count} llythyren ar ôl",
characters_under_limit_one: "Mae gennych %{count} llythyr ar ôl",
characters_under_limit_two: "Mae gennych %{count} lythyren ar ôl",
characters_under_limit_few: "Mae gennych %{count} llythyren ar ôl",
characters_under_limit_many: "Mae gennych %{count} llythyr ar ôl",
characters_under_limit_other: "Mae gennych %{count} llythyren ar ôl"
}
}
}
})</script>
{% endblock %}
4 changes: 2 additions & 2 deletions src/govuk/all.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function initAll (options) {

var $accordions = scope.querySelectorAll('[data-module="govuk-accordion"]')
nodeListForEach($accordions, function ($accordion) {
new Accordion($accordion).init()
new Accordion($accordion, options.accordion || {}).init()
})

var $details = scope.querySelectorAll('[data-module="govuk-details"]')
Expand All @@ -36,7 +36,7 @@ function initAll (options) {

var $characterCounts = scope.querySelectorAll('[data-module="govuk-character-count"]')
nodeListForEach($characterCounts, function ($characterCount) {
new CharacterCount($characterCount).init()
new CharacterCount($characterCount, options.character_count || {}).init()
})

var $checkboxes = scope.querySelectorAll('[data-module="govuk-checkboxes"]')
Expand Down
32 changes: 23 additions & 9 deletions src/govuk/components/accordion/accordion.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,28 @@

*/

import I18n from '../../i18n.mjs'
import { nodeListForEach } from '../../common.mjs'
import '../../vendor/polyfills/Function/prototype/bind.mjs'
import '../../vendor/polyfills/Element/prototype/classList.mjs'
import '../../vendor/polyfills/Object/assign.mjs'

function Accordion ($module) {
function Accordion ($module, options) {
this.$module = $module

var defaultOptions = {
i18n: {
translations: {
show_this_section: 'Show<span class="govuk-visually-hidden"> this section</span>',
hide_this_section: 'Hide<span class="govuk-visually-hidden"> this section</span>',
show_all_sections: 'Show all sections',
hide_all_sections: 'Hide all sections'
}
}
}
this.options = Object.assign({}, defaultOptions, options)
this.i18n = new I18n(this.options.i18n)

this.moduleId = $module.getAttribute('id')
this.$sections = $module.querySelectorAll('.govuk-accordion__section')
this.$showAllButton = ''
Expand Down Expand Up @@ -233,15 +249,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('hide_this_section')
: this.i18n.t('show_this_section')

$showHideText.innerHTML = $newButtonText
$showHideText.appendChild($visuallyHiddenText)
$button.setAttribute('aria-expanded', expanded)

// Swap icon, change class
Expand Down Expand Up @@ -278,7 +290,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('hide_all_sections')
: this.i18n.t('show_all_sections')
this.$showAllButton.setAttribute('aria-expanded', expanded)
$showAllText.innerHTML = newButtonText

Expand Down
50 changes: 38 additions & 12 deletions src/govuk/components/character-count/character-count.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,30 @@
import I18n from '../../i18n.mjs'
import '../../vendor/polyfills/Function/prototype/bind.mjs'
import '../../vendor/polyfills/Event.mjs' // addEventListener and event.target normaliziation
import '../../vendor/polyfills/Element/prototype/classList.mjs'
import '../../vendor/polyfills/Object/assign.mjs'

function CharacterCount ($module) {
function CharacterCount ($module, options) {
this.$module = $module
this.options = options || {}

var defaultOptions = {
i18n: {
translations: {
characters_under_limit_one: 'You have %{count} character remaining',
characters_under_limit_other: 'You have %{count} characters remaining',
characters_over_limit_one: 'You have %{count} character too many',
characters_over_limit_other: 'You have %{count} characters too many',
words_under_limit_one: 'You have %{count} word remaining',
words_under_limit_other: 'You have %{count} words remaining',
words_over_limit_one: 'You have %{count} word too many',
words_over_limit_other: 'You have %{count} words too many'
}
}
}
this.options = Object.assign({}, defaultOptions, options)
this.i18n = new I18n(this.options.i18n)

this.$textarea = $module.querySelector('.govuk-js-character-count')
this.$visibleCountMessage = null
this.$screenReaderCountMessage = null
Expand Down Expand Up @@ -192,18 +213,23 @@ CharacterCount.prototype.formattedUpdateMessage = function () {
var options = this.options
var remainingNumber = this.maxLength - this.count($textarea.value)

var charVerb = 'remaining'
var charNoun = 'character'
var displayNumber = remainingNumber
if (options.maxwords) {
charNoun = 'word'
if (options.maxwords && remainingNumber < 0) {
return this.i18n.t('words_over_limit', {
count: Math.abs(remainingNumber)
})
} else if (options.maxwords) {
return this.i18n.t('words_under_limit', {
count: remainingNumber
})
} else if (remainingNumber < 0) {
return this.i18n.t('characters_over_limit', {
count: Math.abs(remainingNumber)
})
} else {
return this.i18n.t('characters_under_limit', {
count: remainingNumber
})
}
charNoun = charNoun + ((remainingNumber === -1 || remainingNumber === 1) ? '' : 's')

charVerb = (remainingNumber < 0) ? 'too many' : 'remaining'
displayNumber = Math.abs(remainingNumber)

return 'You have ' + displayNumber + ' ' + charNoun + ' ' + charVerb
}

// Checks whether the value is over the configured threshold for the input.
Expand Down
4 changes: 2 additions & 2 deletions src/govuk/components/character-count/character-count.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ describe('Character count', () => {

it('shows the static message', async () => {
await goToExample()
const message = await page.$eval('.govuk-character-count__message', el => el.innerHTML.trim())
const messageClasses = await page.$eval('.govuk-character-count__message', el => el.className)

expect(message).toEqual('You can enter up to 10 characters')
expect(messageClasses).not.toContain('govuk-visually-hidden')
})
})

Expand Down
Loading