govuk_tech_docs 3.2.1 → 3.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/publish.yaml +1 -1
- data/CHANGELOG.md +26 -7
- data/README.md +2 -2
- data/lib/assets/javascripts/_modules/search.js +2 -2
- data/lib/govuk_tech_docs/contribution_banner.rb +1 -1
- data/lib/govuk_tech_docs/version.rb +1 -1
- data/lib/source/layouts/core.erb +1 -1
- data/node_modules/govuk-frontend/govuk/all.js +1548 -311
- data/node_modules/govuk-frontend/govuk/common/closest-attribute-value.js +70 -0
- data/node_modules/govuk-frontend/govuk/common/index.js +172 -0
- data/node_modules/govuk-frontend/govuk/common/normalise-dataset.js +373 -0
- data/node_modules/govuk-frontend/govuk/common.js +138 -3
- data/node_modules/govuk-frontend/govuk/components/_all.scss +1 -0
- data/node_modules/govuk-frontend/govuk/components/accordion/_index.scss +5 -6
- data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js +754 -36
- data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_index.scss +0 -2
- data/node_modules/govuk-frontend/govuk/components/button/_index.scss +29 -21
- data/node_modules/govuk-frontend/govuk/components/button/button.js +365 -107
- data/node_modules/govuk-frontend/govuk/components/character-count/_index.scss +9 -0
- data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +1092 -109
- data/node_modules/govuk-frontend/govuk/components/checkboxes/_index.scss +3 -2
- data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js +30 -2
- data/node_modules/govuk-frontend/govuk/components/details/details.js +51 -33
- data/node_modules/govuk-frontend/govuk/components/error-summary/error-summary.js +289 -6
- data/node_modules/govuk-frontend/govuk/components/footer/_index.scss +13 -23
- data/node_modules/govuk-frontend/govuk/components/header/_index.scss +30 -24
- data/node_modules/govuk-frontend/govuk/components/header/header.js +59 -11
- data/node_modules/govuk-frontend/govuk/components/input/_index.scss +13 -23
- data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js +252 -2
- data/node_modules/govuk-frontend/govuk/components/pagination/_index.scss +247 -0
- data/node_modules/govuk-frontend/govuk/components/pagination/_pagination.scss +2 -0
- data/node_modules/govuk-frontend/govuk/components/panel/_index.scss +1 -1
- data/node_modules/govuk-frontend/govuk/components/radios/_index.scss +5 -12
- data/node_modules/govuk-frontend/govuk/components/radios/radios.js +30 -2
- data/node_modules/govuk-frontend/govuk/components/select/_index.scss +11 -0
- data/node_modules/govuk-frontend/govuk/components/skip-link/_index.scss +1 -3
- data/node_modules/govuk-frontend/govuk/components/skip-link/skip-link.js +10 -4
- data/node_modules/govuk-frontend/govuk/components/summary-list/_index.scss +45 -13
- data/node_modules/govuk-frontend/govuk/components/table/_index.scss +1 -1
- data/node_modules/govuk-frontend/govuk/components/tabs/tabs.js +28 -0
- data/node_modules/govuk-frontend/govuk/core/_section-break.scss +1 -1
- data/node_modules/govuk-frontend/govuk/helpers/_colour.scss +5 -5
- data/node_modules/govuk-frontend/govuk/helpers/_focused.scss +5 -0
- data/node_modules/govuk-frontend/govuk/helpers/_links.scss +13 -11
- data/node_modules/govuk-frontend/govuk/helpers/_media-queries.scss +2 -2
- data/node_modules/govuk-frontend/govuk/helpers/_shape-arrow.scss +1 -1
- data/node_modules/govuk-frontend/govuk/helpers/_spacing.scss +3 -3
- data/node_modules/govuk-frontend/govuk/helpers/_typography.scss +16 -9
- data/node_modules/govuk-frontend/govuk/i18n.js +390 -0
- data/node_modules/govuk-frontend/govuk/objects/_button-group.scss +10 -26
- data/node_modules/govuk-frontend/govuk/objects/_template.scss +1 -1
- data/node_modules/govuk-frontend/govuk/objects/_width-container.scss +0 -4
- data/node_modules/govuk-frontend/govuk/overrides/_spacing.scss +56 -12
- data/node_modules/govuk-frontend/govuk/settings/_all.scss +1 -0
- data/node_modules/govuk-frontend/govuk/settings/_colours-palette.scss +12 -0
- data/node_modules/govuk-frontend/govuk/settings/_compatibility.scss +26 -0
- data/node_modules/govuk-frontend/govuk/settings/_spacing.scss +4 -8
- data/node_modules/govuk-frontend/govuk/settings/_typography-font.scss +23 -0
- data/node_modules/govuk-frontend/govuk/settings/_typography-responsive.scss +12 -0
- data/node_modules/govuk-frontend/govuk/settings/_warnings.scss +53 -0
- data/node_modules/govuk-frontend/govuk/tools/_compatibility.scss +20 -6
- data/node_modules/govuk-frontend/govuk/tools/_exports.scss +1 -1
- data/node_modules/govuk-frontend/govuk/tools/_font-url.scss +1 -1
- data/node_modules/govuk-frontend/govuk/tools/_image-url.scss +1 -1
- data/node_modules/govuk-frontend/govuk/tools/_px-to-em.scss +2 -2
- data/node_modules/govuk-frontend/govuk/tools/_px-to-rem.scss +1 -1
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Date/now.js +21 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/dataset.js +300 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/String/prototype/trim.js +21 -0
- data/node_modules/govuk-frontend/govuk-prototype-kit/init.js +7 -0
- data/node_modules/govuk-frontend/govuk-prototype-kit/init.scss +12 -0
- data/package-lock.json +12 -12
- data/package.json +1 -1
- metadata +14 -2
@@ -30,12 +30,12 @@
|
|
30
30
|
@mixin govuk-link-decoration {
|
31
31
|
text-decoration: underline;
|
32
32
|
|
33
|
-
@if
|
34
|
-
@if
|
33
|
+
@if $govuk-new-link-styles {
|
34
|
+
@if $govuk-link-underline-thickness {
|
35
35
|
text-decoration-thickness: $govuk-link-underline-thickness;
|
36
36
|
}
|
37
37
|
|
38
|
-
@if
|
38
|
+
@if $govuk-link-underline-offset {
|
39
39
|
text-underline-offset: $govuk-link-underline-offset;
|
40
40
|
}
|
41
41
|
}
|
@@ -50,7 +50,7 @@
|
|
50
50
|
/// @access public
|
51
51
|
|
52
52
|
@mixin govuk-link-hover-decoration {
|
53
|
-
@if
|
53
|
+
@if $govuk-new-link-styles and $govuk-link-hover-underline-thickness {
|
54
54
|
text-decoration-thickness: $govuk-link-hover-underline-thickness;
|
55
55
|
// Disable ink skipping on underlines on hover. Browsers haven't
|
56
56
|
// standardised on this part of the spec yet, so set both properties
|
@@ -104,7 +104,7 @@
|
|
104
104
|
// we need to override the text colour for that combination of selectors so
|
105
105
|
// so that unvisited links styled as buttons do not end up with dark blue
|
106
106
|
// text when focussed.
|
107
|
-
@include
|
107
|
+
@include _govuk-compatibility(govuk_template) {
|
108
108
|
&:link:focus {
|
109
109
|
color: $govuk-focus-text-colour;
|
110
110
|
}
|
@@ -152,7 +152,7 @@
|
|
152
152
|
// we need to override the text colour for that combination of selectors so
|
153
153
|
// so that unvisited links styled as buttons do not end up with dark blue
|
154
154
|
// text when focussed.
|
155
|
-
@include
|
155
|
+
@include _govuk-compatibility(govuk_template) {
|
156
156
|
&:link:focus {
|
157
157
|
color: $govuk-focus-text-colour;
|
158
158
|
}
|
@@ -200,7 +200,7 @@
|
|
200
200
|
// we need to override the text colour for that combination of selectors so
|
201
201
|
// so that unvisited links styled as buttons do not end up with dark blue
|
202
202
|
// text when focussed.
|
203
|
-
@include
|
203
|
+
@include _govuk-compatibility(govuk_template) {
|
204
204
|
&:link:focus {
|
205
205
|
color: $govuk-focus-text-colour;
|
206
206
|
}
|
@@ -243,7 +243,7 @@
|
|
243
243
|
// alphagov/govuk_template includes a specific a:link:focus selector designed
|
244
244
|
// to make unvisited links a slightly darker blue when focussed, so we need to
|
245
245
|
// override the text colour for that combination of selectors.
|
246
|
-
@include
|
246
|
+
@include _govuk-compatibility(govuk_template) {
|
247
247
|
&:link:focus {
|
248
248
|
@include govuk-text-colour;
|
249
249
|
}
|
@@ -275,7 +275,9 @@
|
|
275
275
|
// Force a colour change on hover to work around a bug in Safari
|
276
276
|
// https://bugs.webkit.org/show_bug.cgi?id=224483
|
277
277
|
&:hover {
|
278
|
-
|
278
|
+
@if type-of($govuk-text-colour) == color {
|
279
|
+
color: rgba($govuk-text-colour, .99);
|
280
|
+
}
|
279
281
|
}
|
280
282
|
|
281
283
|
&:active,
|
@@ -286,7 +288,7 @@
|
|
286
288
|
// alphagov/govuk_template includes a specific a:link:focus selector designed
|
287
289
|
// to make unvisited links a slightly darker blue when focussed, so we need to
|
288
290
|
// override the text colour for that combination of selectors.
|
289
|
-
@include
|
291
|
+
@include _govuk-compatibility(govuk_template) {
|
290
292
|
&:link:focus {
|
291
293
|
@include govuk-text-colour;
|
292
294
|
}
|
@@ -329,7 +331,7 @@
|
|
329
331
|
// alphagov/govuk_template includes a specific a:link:focus selector designed
|
330
332
|
// to make unvisited links a slightly darker blue when focussed, so we need to
|
331
333
|
// override the text colour for that combination of selectors.
|
332
|
-
@include
|
334
|
+
@include _govuk-compatibility(govuk_template) {
|
333
335
|
&:link:focus {
|
334
336
|
color: $govuk-focus-text-colour;
|
335
337
|
}
|
@@ -12,7 +12,7 @@ $mq-static-breakpoint: if(variable-exists(govuk-ie8-breakpoint), $govuk-ie8-brea
|
|
12
12
|
|
13
13
|
$mq-show-breakpoints: ();
|
14
14
|
|
15
|
-
@if
|
15
|
+
@if variable-exists(govuk-show-breakpoints) and $govuk-show-breakpoints {
|
16
16
|
$mq-show-breakpoints: map-keys($govuk-breakpoints);
|
17
17
|
}
|
18
18
|
|
@@ -20,7 +20,7 @@ $mq-show-breakpoints: ();
|
|
20
20
|
// 'rasterize' any media queries.
|
21
21
|
|
22
22
|
$mq-responsive: true;
|
23
|
-
@if
|
23
|
+
@if variable-exists(govuk-is-ie8) and $govuk-is-ie8 {
|
24
24
|
$mq-responsive: false;
|
25
25
|
}
|
26
26
|
|
@@ -39,7 +39,7 @@
|
|
39
39
|
}
|
40
40
|
|
41
41
|
$is-negative: false;
|
42
|
-
@if
|
42
|
+
@if $spacing-point < 0 {
|
43
43
|
$is-negative: true;
|
44
44
|
$spacing-point: abs($spacing-point);
|
45
45
|
}
|
@@ -94,12 +94,12 @@
|
|
94
94
|
// Loop through each breakpoint in the map
|
95
95
|
@each $breakpoint, $breakpoint-value in $scale-map {
|
96
96
|
|
97
|
-
@if
|
97
|
+
@if $adjustment {
|
98
98
|
$breakpoint-value: $breakpoint-value + $adjustment;
|
99
99
|
}
|
100
100
|
|
101
101
|
// The 'null' breakpoint is for mobile.
|
102
|
-
@if $breakpoint
|
102
|
+
@if not $breakpoint {
|
103
103
|
|
104
104
|
@if $direction == all {
|
105
105
|
#{$property}: $breakpoint-value if($important, !important, null);
|
@@ -23,7 +23,7 @@
|
|
23
23
|
// We do not need to include the GDS Transport font-face declarations if
|
24
24
|
// alphagov/govuk_template is being used since nta will already be included by
|
25
25
|
// default.
|
26
|
-
@if
|
26
|
+
@if $govuk-include-default-font-face {
|
27
27
|
@include _govuk-font-face-gds-transport;
|
28
28
|
}
|
29
29
|
|
@@ -86,12 +86,13 @@
|
|
86
86
|
|
87
87
|
/// Responsive typography helper
|
88
88
|
///
|
89
|
-
/// Takes a 'font map' as an argument
|
90
|
-
///
|
89
|
+
/// Takes a point from the responsive 'font map' as an argument (the size as it
|
90
|
+
/// would appear on tablet and above), and uses it to create font-size and
|
91
|
+
/// line-height declarations for different breakpoints, and print.
|
91
92
|
///
|
92
93
|
/// Example font map:
|
93
94
|
///
|
94
|
-
///
|
95
|
+
/// 19: (
|
95
96
|
/// null: (
|
96
97
|
/// font-size: 16px,
|
97
98
|
/// line-height: 20px
|
@@ -106,12 +107,15 @@
|
|
106
107
|
/// )
|
107
108
|
/// );
|
108
109
|
///
|
109
|
-
/// @param {
|
110
|
+
/// @param {Number} $size - Point from the spacing scale (the size as it would
|
111
|
+
/// appear on tablet and above)
|
110
112
|
/// @param {Number} $override-line-height [false] - Non responsive custom line
|
111
113
|
/// height. Omit to use the line height from the font map.
|
112
114
|
/// @param {Boolean} $important [false] - Whether to mark declarations as
|
113
115
|
/// `!important`.
|
114
116
|
///
|
117
|
+
/// @throw if `$size` is not a valid point from the spacing scale
|
118
|
+
///
|
115
119
|
/// @access public
|
116
120
|
|
117
121
|
@mixin govuk-typography-responsive($size, $override-line-height: false, $important: false) {
|
@@ -142,7 +146,7 @@
|
|
142
146
|
$font-size-rem: $font-size-rem if($important, !important, null);
|
143
147
|
$line-height: $line-height if($important, !important, null);
|
144
148
|
|
145
|
-
@if $breakpoint
|
149
|
+
@if not $breakpoint {
|
146
150
|
font-size: $font-size;
|
147
151
|
@if $govuk-typography-use-rem {
|
148
152
|
font-size: $font-size-rem;
|
@@ -167,11 +171,14 @@
|
|
167
171
|
|
168
172
|
/// Font helper
|
169
173
|
///
|
170
|
-
/// @param {Number} $size
|
171
|
-
///
|
174
|
+
/// @param {Number | Boolean} $size Point from the spacing scale (the size as it
|
175
|
+
/// would appear on tablet and above). Use `false` to avoid setting a size.
|
172
176
|
/// @param {String} $weight [regular] - Weight: `bold` or `regular`
|
173
177
|
/// @param {Boolean} $tabular [false] - Whether to use tabular numbers or not
|
174
|
-
/// @param {Number} $line-height [false] - Line-height, if overriding the
|
178
|
+
/// @param {Number} $line-height [false] - Line-height, if overriding the
|
179
|
+
/// default
|
180
|
+
///
|
181
|
+
/// @throw if `$size` is not a valid point from the spacing scale (or false)
|
175
182
|
///
|
176
183
|
/// @access public
|
177
184
|
|
@@ -0,0 +1,390 @@
|
|
1
|
+
(function (global, factory) {
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
3
|
+
typeof define === 'function' && define.amd ? define('GOVUKFrontend', ['exports'], factory) :
|
4
|
+
(factory((global.GOVUKFrontend = {})));
|
5
|
+
}(this, (function (exports) { 'use strict';
|
6
|
+
|
7
|
+
/**
|
8
|
+
* Internal support for selecting messages to render, with placeholder
|
9
|
+
* interpolation and locale-aware number formatting and pluralisation
|
10
|
+
*
|
11
|
+
* @class
|
12
|
+
* @private
|
13
|
+
* @param {TranslationsFlattened} translations - Key-value pairs of the translation strings to use.
|
14
|
+
* @param {object} [config] - Configuration options for the function.
|
15
|
+
* @param {string} config.locale - An overriding locale for the PluralRules functionality.
|
16
|
+
*/
|
17
|
+
function I18n (translations, config) {
|
18
|
+
// Make list of translations available throughout function
|
19
|
+
this.translations = translations || {};
|
20
|
+
|
21
|
+
// The locale to use for PluralRules and NumberFormat
|
22
|
+
this.locale = (config && config.locale) || document.documentElement.lang || 'en';
|
23
|
+
}
|
24
|
+
|
25
|
+
/**
|
26
|
+
* The most used function - takes the key for a given piece of UI text and
|
27
|
+
* returns the appropriate string.
|
28
|
+
*
|
29
|
+
* @param {string} lookupKey - The lookup key of the string to use.
|
30
|
+
* @param {object} options - Any options passed with the translation string, e.g: for string interpolation.
|
31
|
+
* @returns {string} The appropriate translation string.
|
32
|
+
*/
|
33
|
+
I18n.prototype.t = function (lookupKey, options) {
|
34
|
+
if (!lookupKey) {
|
35
|
+
// Print a console error if no lookup key has been provided
|
36
|
+
throw new Error('i18n: lookup key missing')
|
37
|
+
}
|
38
|
+
|
39
|
+
// If the `count` option is set, determine which plural suffix is needed and
|
40
|
+
// change the lookupKey to match. We check to see if it's undefined instead of
|
41
|
+
// falsy, as this could legitimately be 0.
|
42
|
+
if (options && typeof options.count !== 'undefined') {
|
43
|
+
// Get the plural suffix
|
44
|
+
lookupKey = lookupKey + '.' + this.getPluralSuffix(lookupKey, options.count);
|
45
|
+
}
|
46
|
+
|
47
|
+
if (lookupKey in this.translations) {
|
48
|
+
// Fetch the translation string for that lookup key
|
49
|
+
var translationString = this.translations[lookupKey];
|
50
|
+
|
51
|
+
// Check for ${} placeholders in the translation string
|
52
|
+
if (translationString.match(/%{(.\S+)}/)) {
|
53
|
+
if (!options) {
|
54
|
+
throw new Error('i18n: cannot replace placeholders in string if no option data provided')
|
55
|
+
}
|
56
|
+
|
57
|
+
return this.replacePlaceholders(translationString, options)
|
58
|
+
} else {
|
59
|
+
return translationString
|
60
|
+
}
|
61
|
+
} else {
|
62
|
+
// If the key wasn't found in our translations object,
|
63
|
+
// return the lookup key itself as the fallback
|
64
|
+
return lookupKey
|
65
|
+
}
|
66
|
+
};
|
67
|
+
|
68
|
+
/**
|
69
|
+
* Takes a translation string with placeholders, and replaces the placeholders
|
70
|
+
* with the provided data
|
71
|
+
*
|
72
|
+
* @param {string} translationString - The translation string
|
73
|
+
* @param {object} options - Any options passed with the translation string, e.g: for string interpolation.
|
74
|
+
* @returns {string} The translation string to output, with ${} placeholders replaced
|
75
|
+
*/
|
76
|
+
I18n.prototype.replacePlaceholders = function (translationString, options) {
|
77
|
+
var formatter;
|
78
|
+
|
79
|
+
if (this.hasIntlNumberFormatSupport()) {
|
80
|
+
formatter = new Intl.NumberFormat(this.locale);
|
81
|
+
}
|
82
|
+
|
83
|
+
return translationString.replace(/%{(.\S+)}/g, function (placeholderWithBraces, placeholderKey) {
|
84
|
+
if (Object.prototype.hasOwnProperty.call(options, placeholderKey)) {
|
85
|
+
var placeholderValue = options[placeholderKey];
|
86
|
+
|
87
|
+
// If a user has passed `false` as the value for the placeholder
|
88
|
+
// treat it as though the value should not be displayed
|
89
|
+
if (placeholderValue === false) {
|
90
|
+
return ''
|
91
|
+
}
|
92
|
+
|
93
|
+
// If the placeholder's value is a number, localise the number formatting
|
94
|
+
if (typeof placeholderValue === 'number' && formatter) {
|
95
|
+
return formatter.format(placeholderValue)
|
96
|
+
}
|
97
|
+
|
98
|
+
return placeholderValue
|
99
|
+
} else {
|
100
|
+
throw new Error('i18n: no data found to replace ' + placeholderWithBraces + ' placeholder in string')
|
101
|
+
}
|
102
|
+
})
|
103
|
+
};
|
104
|
+
|
105
|
+
/**
|
106
|
+
* Check to see if the browser supports Intl and Intl.PluralRules.
|
107
|
+
*
|
108
|
+
* It requires all conditions to be met in order to be supported:
|
109
|
+
* - The browser supports the Intl class (true in IE11)
|
110
|
+
* - The implementation of Intl supports PluralRules (NOT true in IE11)
|
111
|
+
* - The browser/OS has plural rules for the current locale (browser dependent)
|
112
|
+
*
|
113
|
+
* @returns {boolean} Returns true if all conditions are met. Returns false otherwise.
|
114
|
+
*/
|
115
|
+
I18n.prototype.hasIntlPluralRulesSupport = function () {
|
116
|
+
return Boolean(window.Intl && ('PluralRules' in window.Intl && Intl.PluralRules.supportedLocalesOf(this.locale).length))
|
117
|
+
};
|
118
|
+
|
119
|
+
/**
|
120
|
+
* Check to see if the browser supports Intl and Intl.NumberFormat.
|
121
|
+
*
|
122
|
+
* It requires all conditions to be met in order to be supported:
|
123
|
+
* - The browser supports the Intl class (true in IE11)
|
124
|
+
* - The implementation of Intl supports NumberFormat (also true in IE11)
|
125
|
+
* - The browser/OS has number formatting rules for the current locale (browser dependent)
|
126
|
+
*
|
127
|
+
* @returns {boolean} Returns true if all conditions are met. Returns false otherwise.
|
128
|
+
*/
|
129
|
+
I18n.prototype.hasIntlNumberFormatSupport = function () {
|
130
|
+
return Boolean(window.Intl && ('NumberFormat' in window.Intl && Intl.NumberFormat.supportedLocalesOf(this.locale).length))
|
131
|
+
};
|
132
|
+
|
133
|
+
/**
|
134
|
+
* Get the appropriate suffix for the plural form.
|
135
|
+
*
|
136
|
+
* Uses Intl.PluralRules (or our own fallback implementation) to get the
|
137
|
+
* 'preferred' form to use for the given count.
|
138
|
+
*
|
139
|
+
* Checks that a translation has been provided for that plural form – if it
|
140
|
+
* hasn't, it'll fall back to the 'other' plural form (unless that doesn't exist
|
141
|
+
* either, in which case an error will be thrown)
|
142
|
+
*
|
143
|
+
* @param {string} lookupKey - The lookup key of the string to use.
|
144
|
+
* @param {number} count - Number used to determine which pluralisation to use.
|
145
|
+
* @returns {PluralRule} The suffix associated with the correct pluralisation for this locale.
|
146
|
+
*/
|
147
|
+
I18n.prototype.getPluralSuffix = function (lookupKey, count) {
|
148
|
+
// Validate that the number is actually a number.
|
149
|
+
//
|
150
|
+
// Number(count) will turn anything that can't be converted to a Number type
|
151
|
+
// into 'NaN'. isFinite filters out NaN, as it isn't a finite number.
|
152
|
+
count = Number(count);
|
153
|
+
if (!isFinite(count)) { return 'other' }
|
154
|
+
|
155
|
+
var preferredForm;
|
156
|
+
|
157
|
+
// Check to verify that all the requirements for Intl.PluralRules are met.
|
158
|
+
// If so, we can use that instead of our custom implementation. Otherwise,
|
159
|
+
// use the hardcoded fallback.
|
160
|
+
if (this.hasIntlPluralRulesSupport()) {
|
161
|
+
preferredForm = new Intl.PluralRules(this.locale).select(count);
|
162
|
+
} else {
|
163
|
+
preferredForm = this.selectPluralFormUsingFallbackRules(count);
|
164
|
+
}
|
165
|
+
|
166
|
+
// Use the correct plural form if provided
|
167
|
+
if (lookupKey + '.' + preferredForm in this.translations) {
|
168
|
+
return preferredForm
|
169
|
+
// Fall back to `other` if the plural form is missing, but log a warning
|
170
|
+
// to the console
|
171
|
+
} else if (lookupKey + '.other' in this.translations) {
|
172
|
+
if (console && 'warn' in console) {
|
173
|
+
console.warn('i18n: Missing plural form ".' + preferredForm + '" for "' +
|
174
|
+
this.locale + '" locale. Falling back to ".other".');
|
175
|
+
}
|
176
|
+
|
177
|
+
return 'other'
|
178
|
+
// If the required `other` plural form is missing, all we can do is error
|
179
|
+
} else {
|
180
|
+
throw new Error(
|
181
|
+
'i18n: Plural form ".other" is required for "' + this.locale + '" locale'
|
182
|
+
)
|
183
|
+
}
|
184
|
+
};
|
185
|
+
|
186
|
+
/**
|
187
|
+
* Get the plural form using our fallback implementation
|
188
|
+
*
|
189
|
+
* This is split out into a separate function to make it easier to test the
|
190
|
+
* fallback behaviour in an environment where Intl.PluralRules exists.
|
191
|
+
*
|
192
|
+
* @param {number} count - Number used to determine which pluralisation to use.
|
193
|
+
* @returns {PluralRule} The pluralisation form for count in this locale.
|
194
|
+
*/
|
195
|
+
I18n.prototype.selectPluralFormUsingFallbackRules = function (count) {
|
196
|
+
// Currently our custom code can only handle positive integers, so let's
|
197
|
+
// make sure our number is one of those.
|
198
|
+
count = Math.abs(Math.floor(count));
|
199
|
+
|
200
|
+
var ruleset = this.getPluralRulesForLocale();
|
201
|
+
|
202
|
+
if (ruleset) {
|
203
|
+
return I18n.pluralRules[ruleset](count)
|
204
|
+
}
|
205
|
+
|
206
|
+
return 'other'
|
207
|
+
};
|
208
|
+
|
209
|
+
/**
|
210
|
+
* Work out which pluralisation rules to use for the current locale
|
211
|
+
*
|
212
|
+
* The locale may include a regional indicator (such as en-GB), but we don't
|
213
|
+
* usually care about this part, as pluralisation rules are usually the same
|
214
|
+
* regardless of region. There are exceptions, however, (e.g. Portuguese) so
|
215
|
+
* this searches by both the full and shortened locale codes, just to be sure.
|
216
|
+
*
|
217
|
+
* @returns {PluralRuleName | undefined} The name of the pluralisation rule to use (a key for one
|
218
|
+
* of the functions in this.pluralRules)
|
219
|
+
*/
|
220
|
+
I18n.prototype.getPluralRulesForLocale = function () {
|
221
|
+
var locale = this.locale;
|
222
|
+
var localeShort = locale.split('-')[0];
|
223
|
+
|
224
|
+
// Look through the plural rules map to find which `pluralRule` is
|
225
|
+
// appropriate for our current `locale`.
|
226
|
+
for (var pluralRule in I18n.pluralRulesMap) {
|
227
|
+
if (Object.prototype.hasOwnProperty.call(I18n.pluralRulesMap, pluralRule)) {
|
228
|
+
var languages = I18n.pluralRulesMap[pluralRule];
|
229
|
+
for (var i = 0; i < languages.length; i++) {
|
230
|
+
if (languages[i] === locale || languages[i] === localeShort) {
|
231
|
+
return pluralRule
|
232
|
+
}
|
233
|
+
}
|
234
|
+
}
|
235
|
+
}
|
236
|
+
};
|
237
|
+
|
238
|
+
/**
|
239
|
+
* Map of plural rules to languages where those rules apply.
|
240
|
+
*
|
241
|
+
* Note: These groups are named for the most dominant or recognisable language
|
242
|
+
* that uses each system. The groupings do not imply that the languages are
|
243
|
+
* related to one another. Many languages have evolved the same systems
|
244
|
+
* independently of one another.
|
245
|
+
*
|
246
|
+
* Code to support more languages can be found in the i18n spike:
|
247
|
+
* {@link https://github.com/alphagov/govuk-frontend/blob/spike-i18n-support/src/govuk/i18n.mjs}
|
248
|
+
*
|
249
|
+
* Languages currently supported:
|
250
|
+
*
|
251
|
+
* Arabic: Arabic (ar)
|
252
|
+
* Chinese: Burmese (my), Chinese (zh), Indonesian (id), Japanese (ja),
|
253
|
+
* Javanese (jv), Korean (ko), Malay (ms), Thai (th), Vietnamese (vi)
|
254
|
+
* French: Armenian (hy), Bangla (bn), French (fr), Gujarati (gu), Hindi (hi),
|
255
|
+
* Persian Farsi (fa), Punjabi (pa), Zulu (zu)
|
256
|
+
* German: Afrikaans (af), Albanian (sq), Azerbaijani (az), Basque (eu),
|
257
|
+
* Bulgarian (bg), Catalan (ca), Danish (da), Dutch (nl), English (en),
|
258
|
+
* Estonian (et), Finnish (fi), Georgian (ka), German (de), Greek (el),
|
259
|
+
* Hungarian (hu), Luxembourgish (lb), Norwegian (no), Somali (so),
|
260
|
+
* Swahili (sw), Swedish (sv), Tamil (ta), Telugu (te), Turkish (tr),
|
261
|
+
* Urdu (ur)
|
262
|
+
* Irish: Irish Gaelic (ga)
|
263
|
+
* Russian: Russian (ru), Ukrainian (uk)
|
264
|
+
* Scottish: Scottish Gaelic (gd)
|
265
|
+
* Spanish: European Portuguese (pt-PT), Italian (it), Spanish (es)
|
266
|
+
* Welsh: Welsh (cy)
|
267
|
+
*
|
268
|
+
* @type {Object<PluralRuleName, string[]>}
|
269
|
+
*/
|
270
|
+
I18n.pluralRulesMap = {
|
271
|
+
arabic: ['ar'],
|
272
|
+
chinese: ['my', 'zh', 'id', 'ja', 'jv', 'ko', 'ms', 'th', 'vi'],
|
273
|
+
french: ['hy', 'bn', 'fr', 'gu', 'hi', 'fa', 'pa', 'zu'],
|
274
|
+
german: [
|
275
|
+
'af', 'sq', 'az', 'eu', 'bg', 'ca', 'da', 'nl', 'en', 'et', 'fi', 'ka',
|
276
|
+
'de', 'el', 'hu', 'lb', 'no', 'so', 'sw', 'sv', 'ta', 'te', 'tr', 'ur'
|
277
|
+
],
|
278
|
+
irish: ['ga'],
|
279
|
+
russian: ['ru', 'uk'],
|
280
|
+
scottish: ['gd'],
|
281
|
+
spanish: ['pt-PT', 'it', 'es'],
|
282
|
+
welsh: ['cy']
|
283
|
+
};
|
284
|
+
|
285
|
+
/**
|
286
|
+
* Different pluralisation rule sets
|
287
|
+
*
|
288
|
+
* Returns the appropriate suffix for the plural form associated with `n`.
|
289
|
+
* Possible suffixes: 'zero', 'one', 'two', 'few', 'many', 'other' (the actual
|
290
|
+
* meaning of each differs per locale). 'other' should always exist, even in
|
291
|
+
* languages without plurals, such as Chinese.
|
292
|
+
* {@link https://cldr.unicode.org/index/cldr-spec/plural-rules}
|
293
|
+
*
|
294
|
+
* The count must be a positive integer. Negative numbers and decimals aren't accounted for
|
295
|
+
*
|
296
|
+
* @type {Object<string, function(number): PluralRule>}
|
297
|
+
*/
|
298
|
+
I18n.pluralRules = {
|
299
|
+
arabic: function (n) {
|
300
|
+
if (n === 0) { return 'zero' }
|
301
|
+
if (n === 1) { return 'one' }
|
302
|
+
if (n === 2) { return 'two' }
|
303
|
+
if (n % 100 >= 3 && n % 100 <= 10) { return 'few' }
|
304
|
+
if (n % 100 >= 11 && n % 100 <= 99) { return 'many' }
|
305
|
+
return 'other'
|
306
|
+
},
|
307
|
+
chinese: function () {
|
308
|
+
return 'other'
|
309
|
+
},
|
310
|
+
french: function (n) {
|
311
|
+
return n === 0 || n === 1 ? 'one' : 'other'
|
312
|
+
},
|
313
|
+
german: function (n) {
|
314
|
+
return n === 1 ? 'one' : 'other'
|
315
|
+
},
|
316
|
+
irish: function (n) {
|
317
|
+
if (n === 1) { return 'one' }
|
318
|
+
if (n === 2) { return 'two' }
|
319
|
+
if (n >= 3 && n <= 6) { return 'few' }
|
320
|
+
if (n >= 7 && n <= 10) { return 'many' }
|
321
|
+
return 'other'
|
322
|
+
},
|
323
|
+
russian: function (n) {
|
324
|
+
var lastTwo = n % 100;
|
325
|
+
var last = lastTwo % 10;
|
326
|
+
if (last === 1 && lastTwo !== 11) { return 'one' }
|
327
|
+
if (last >= 2 && last <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) { return 'few' }
|
328
|
+
if (last === 0 || (last >= 5 && last <= 9) || (lastTwo >= 11 && lastTwo <= 14)) { return 'many' }
|
329
|
+
// Note: The 'other' suffix is only used by decimal numbers in Russian.
|
330
|
+
// We don't anticipate it being used, but it's here for consistency.
|
331
|
+
return 'other'
|
332
|
+
},
|
333
|
+
scottish: function (n) {
|
334
|
+
if (n === 1 || n === 11) { return 'one' }
|
335
|
+
if (n === 2 || n === 12) { return 'two' }
|
336
|
+
if ((n >= 3 && n <= 10) || (n >= 13 && n <= 19)) { return 'few' }
|
337
|
+
return 'other'
|
338
|
+
},
|
339
|
+
spanish: function (n) {
|
340
|
+
if (n === 1) { return 'one' }
|
341
|
+
if (n % 1000000 === 0 && n !== 0) { return 'many' }
|
342
|
+
return 'other'
|
343
|
+
},
|
344
|
+
welsh: function (n) {
|
345
|
+
if (n === 0) { return 'zero' }
|
346
|
+
if (n === 1) { return 'one' }
|
347
|
+
if (n === 2) { return 'two' }
|
348
|
+
if (n === 3) { return 'few' }
|
349
|
+
if (n === 6) { return 'many' }
|
350
|
+
return 'other'
|
351
|
+
}
|
352
|
+
};
|
353
|
+
|
354
|
+
/**
|
355
|
+
* Supported languages for plural rules
|
356
|
+
*
|
357
|
+
* @typedef {'arabic' | 'chinese' | 'french' | 'german' | 'irish' | 'russian' | 'scottish' | 'spanish' | 'welsh'} PluralRuleName
|
358
|
+
*/
|
359
|
+
|
360
|
+
/**
|
361
|
+
* Plural rule category mnemonic tags
|
362
|
+
*
|
363
|
+
* @typedef {'zero' | 'one' | 'two' | 'few' | 'many' | 'other'} PluralRule
|
364
|
+
*/
|
365
|
+
|
366
|
+
/**
|
367
|
+
* Translated message by plural rule they correspond to.
|
368
|
+
*
|
369
|
+
* Allows to group pluralised messages under a single key when passing
|
370
|
+
* translations to a component's constructor
|
371
|
+
*
|
372
|
+
* @typedef {object} TranslationPluralForms
|
373
|
+
* @property {string} [other] - General plural form
|
374
|
+
* @property {string} [zero] - Plural form used with 0
|
375
|
+
* @property {string} [one] - Plural form used with 1
|
376
|
+
* @property {string} [two] - Plural form used with 2
|
377
|
+
* @property {string} [few] - Plural form used for a few
|
378
|
+
* @property {string} [many] - Plural form used for many
|
379
|
+
*/
|
380
|
+
|
381
|
+
/**
|
382
|
+
* Translated messages (flattened)
|
383
|
+
*
|
384
|
+
* @private
|
385
|
+
* @typedef {Object<string, string> | {}} TranslationsFlattened
|
386
|
+
*/
|
387
|
+
|
388
|
+
exports.I18n = I18n;
|
389
|
+
|
390
|
+
})));
|
@@ -29,19 +29,12 @@
|
|
29
29
|
// margins, but unfortunately the support isn't there (yet) and @supports
|
30
30
|
// doesn't play nicely with it
|
31
31
|
// (https://github.com/w3c/csswg-drafts/issues/3559)
|
32
|
-
display: -webkit-box;
|
33
|
-
display: -webkit-flex;
|
34
32
|
display: -ms-flexbox;
|
35
33
|
display: flex;
|
36
|
-
-
|
37
|
-
|
38
|
-
-
|
39
|
-
-
|
40
|
-
flex-direction: column;
|
41
|
-
-webkit-box-align: center;
|
42
|
-
-webkit-align-items: center;
|
43
|
-
-ms-flex-align: center;
|
44
|
-
align-items: center;
|
34
|
+
-ms-flex-direction: column;
|
35
|
+
flex-direction: column;
|
36
|
+
-ms-flex-align: center;
|
37
|
+
align-items: center;
|
45
38
|
|
46
39
|
// Give links within the button group the same font-size and line-height
|
47
40
|
// as buttons.
|
@@ -71,22 +64,13 @@
|
|
71
64
|
// Cancel out the column gap for the last item in each row
|
72
65
|
margin-right: ($horizontal-gap * -1);
|
73
66
|
|
74
|
-
-
|
67
|
+
-ms-flex-direction: row;
|
75
68
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
-
|
81
|
-
|
82
|
-
flex-direction: row;
|
83
|
-
-webkit-flex-wrap: wrap;
|
84
|
-
-ms-flex-wrap: wrap;
|
85
|
-
flex-wrap: wrap;
|
86
|
-
-webkit-box-align: baseline;
|
87
|
-
-webkit-align-items: baseline;
|
88
|
-
-ms-flex-align: baseline;
|
89
|
-
align-items: baseline;
|
69
|
+
flex-direction: row;
|
70
|
+
-ms-flex-wrap: wrap;
|
71
|
+
flex-wrap: wrap;
|
72
|
+
-ms-flex-align: baseline;
|
73
|
+
align-items: baseline;
|
90
74
|
|
91
75
|
.govuk-button,
|
92
76
|
.govuk-link {
|
@@ -11,7 +11,7 @@
|
|
11
11
|
// Prevent automatic text sizing, as we already cater for small devices and
|
12
12
|
// would like the browser to stay on 100% text zoom by default.
|
13
13
|
-webkit-text-size-adjust: 100%;
|
14
|
-
|
14
|
+
-moz-text-size-adjust: 100%;
|
15
15
|
text-size-adjust: 100%;
|
16
16
|
|
17
17
|
// Force the scrollbar to always display in IE, to prevent horizontal page
|
@@ -28,9 +28,7 @@
|
|
28
28
|
|
29
29
|
// Respect 'display cutout' safe area (avoids notches and rounded corners)
|
30
30
|
@supports (margin: unquote("max(calc(0px))")) {
|
31
|
-
$gutter-safe-area-right: -webkit-calc(#{$govuk-gutter-half} + env(safe-area-inset-right));
|
32
31
|
$gutter-safe-area-right: calc(#{$govuk-gutter-half} + env(safe-area-inset-right));
|
33
|
-
$gutter-safe-area-left: -webkit-calc(#{$govuk-gutter-half} + env(safe-area-inset-left));
|
34
32
|
$gutter-safe-area-left: calc(#{$govuk-gutter-half} + env(safe-area-inset-left));
|
35
33
|
|
36
34
|
// Use max() to pick largest margin, default or with safe area
|
@@ -46,9 +44,7 @@
|
|
46
44
|
|
47
45
|
// Respect 'display cutout' safe area (avoids notches and rounded corners)
|
48
46
|
@supports (margin: unquote("max(calc(0px))")) {
|
49
|
-
$gutter-safe-area-right: -webkit-calc(#{$govuk-gutter-half} + env(safe-area-inset-right));
|
50
47
|
$gutter-safe-area-right: calc(#{$govuk-gutter-half} + env(safe-area-inset-right));
|
51
|
-
$gutter-safe-area-left: -webkit-calc(#{$govuk-gutter-half} + env(safe-area-inset-left));
|
52
48
|
$gutter-safe-area-left: calc(#{$govuk-gutter-half} + env(safe-area-inset-left));
|
53
49
|
|
54
50
|
// Use max() to pick largest margin, default or with safe area
|