govuk_publishing_components 34.7.0 → 34.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/govuk_publishing_components/presenters/related_navigation_helper.rb +0 -7
- data/lib/govuk_publishing_components/version.rb +1 -1
- data/node_modules/govuk-frontend/govuk/all.js +4029 -3792
- data/node_modules/govuk-frontend/govuk/all.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/common/closest-attribute-value.js +52 -51
- data/node_modules/govuk-frontend/govuk/common/closest-attribute-value.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/common/index.js +153 -145
- data/node_modules/govuk-frontend/govuk/common/index.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/common/normalise-dataset.js +324 -321
- data/node_modules/govuk-frontend/govuk/common/normalise-dataset.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/common.js +154 -146
- data/node_modules/govuk-frontend/govuk/common.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/_all.scss +1 -1
- data/node_modules/govuk-frontend/govuk/components/accordion/_index.scss +23 -4
- data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js +2059 -1654
- data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/accordion/fixtures.json +11 -11
- data/node_modules/govuk-frontend/govuk/components/accordion/template.njk +1 -1
- data/node_modules/govuk-frontend/govuk/components/back-link/_index.scss +19 -19
- data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_index.scss +21 -10
- data/node_modules/govuk-frontend/govuk/components/button/button.js +927 -917
- data/node_modules/govuk-frontend/govuk/components/button/button.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +2050 -2040
- data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js +1155 -1147
- data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/cookie-banner/fixtures.json +23 -23
- data/node_modules/govuk-frontend/govuk/components/cookie-banner/template.njk +1 -1
- data/node_modules/govuk-frontend/govuk/components/details/details.js +800 -799
- data/node_modules/govuk-frontend/govuk/components/details/details.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/error-summary/error-summary.js +1058 -1045
- data/node_modules/govuk-frontend/govuk/components/error-summary/error-summary.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/header/_index.scss +6 -0
- data/node_modules/govuk-frontend/govuk/components/header/header.js +646 -998
- data/node_modules/govuk-frontend/govuk/components/header/header.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js +760 -752
- data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/pagination/fixtures.json +61 -0
- data/node_modules/govuk-frontend/govuk/components/pagination/template.njk +1 -1
- data/node_modules/govuk-frontend/govuk/components/phase-banner/macro-options.json +1 -1
- data/node_modules/govuk-frontend/govuk/components/radios/radios.js +1110 -1107
- data/node_modules/govuk-frontend/govuk/components/radios/radios.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/skip-link/skip-link.js +1017 -1014
- data/node_modules/govuk-frontend/govuk/components/skip-link/skip-link.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/summary-list/_index.scss +107 -0
- data/node_modules/govuk-frontend/govuk/components/summary-list/fixtures.json +318 -23
- data/node_modules/govuk-frontend/govuk/components/summary-list/macro-options.json +110 -0
- data/node_modules/govuk-frontend/govuk/components/summary-list/template.njk +72 -28
- data/node_modules/govuk-frontend/govuk/components/tabs/tabs.js +1392 -1264
- data/node_modules/govuk-frontend/govuk/components/tabs/tabs.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/i18n.js +363 -364
- data/node_modules/govuk-frontend/govuk/i18n.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/settings/_measurements.scss +5 -5
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/DOMTokenList.js +242 -241
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/DOMTokenList.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Date/now.js +13 -12
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Date/now.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Document.js +17 -16
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Document.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/classList.js +547 -546
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/classList.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/closest.js +37 -36
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/closest.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/dataset.js +251 -250
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/dataset.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/matches.js +21 -20
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/matches.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/nextElementSibling.js +198 -197
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/nextElementSibling.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/previousElementSibling.js +198 -197
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/previousElementSibling.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element.js +106 -105
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Event.js +400 -399
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Event.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Function/prototype/bind.js +239 -238
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Function/prototype/bind.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Object/defineProperty.js +72 -71
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Object/defineProperty.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/String/prototype/trim.js +14 -13
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/String/prototype/trim.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Window.js +17 -16
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Window.js.map +1 -0
- data/node_modules/govuk-frontend/govuk-esm/all.mjs +2 -2
- data/node_modules/govuk-frontend/govuk-esm/common/index.mjs +17 -10
- data/node_modules/govuk-frontend/govuk-esm/common/normalise-dataset.mjs +3 -1
- data/node_modules/govuk-frontend/govuk-esm/components/accordion/accordion.mjs +135 -52
- data/node_modules/govuk-frontend/govuk-esm/components/button/button.mjs +11 -9
- data/node_modules/govuk-frontend/govuk-esm/components/character-count/character-count.mjs +10 -7
- data/node_modules/govuk-frontend/govuk-esm/components/checkboxes/checkboxes.mjs +24 -18
- data/node_modules/govuk-frontend/govuk-esm/components/details/details.mjs +23 -16
- data/node_modules/govuk-frontend/govuk-esm/components/error-summary/error-summary.mjs +15 -11
- data/node_modules/govuk-frontend/govuk-esm/components/header/header.mjs +3 -2
- data/node_modules/govuk-frontend/govuk-esm/components/notification-banner/notification-banner.mjs +3 -4
- data/node_modules/govuk-frontend/govuk-esm/components/radios/radios.mjs +10 -9
- data/node_modules/govuk-frontend/govuk-esm/components/skip-link/skip-link.mjs +5 -3
- data/node_modules/govuk-frontend/govuk-esm/components/tabs/tabs.mjs +165 -38
- data/node_modules/govuk-frontend/govuk-esm/i18n.mjs +9 -11
- data/node_modules/govuk-frontend/package.json +1 -1
- metadata +34 -2
@@ -1,390 +1,389 @@
|
|
1
1
|
(function (global, factory) {
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
3
|
+
typeof define === 'function' && define.amd ? define('GOVUKFrontend', ['exports'], factory) :
|
4
|
+
(factory((global.GOVUKFrontend = {})));
|
5
5
|
}(this, (function (exports) { 'use strict';
|
6
6
|
|
7
|
-
/**
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
function I18n (translations, config) {
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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')
|
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 {Object<string, unknown>} 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';
|
37
23
|
}
|
38
24
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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<string, unknown>} [options] - Any options passed with the translation string, e.g: for string interpolation.
|
31
|
+
* @returns {string} The appropriate translation string.
|
32
|
+
* @throws {Error} Lookup key required
|
33
|
+
* @throws {Error} Options required for `${}` placeholders
|
34
|
+
*/
|
35
|
+
I18n.prototype.t = function (lookupKey, options) {
|
36
|
+
if (!lookupKey) {
|
37
|
+
// Print a console error if no lookup key has been provided
|
38
|
+
throw new Error('i18n: lookup key missing')
|
39
|
+
}
|
46
40
|
|
47
|
-
|
48
|
-
//
|
49
|
-
|
41
|
+
// If the `count` option is set, determine which plural suffix is needed and
|
42
|
+
// change the lookupKey to match. We check to see if it's undefined instead of
|
43
|
+
// falsy, as this could legitimately be 0.
|
44
|
+
if (options && typeof options.count !== 'undefined') {
|
45
|
+
// Get the plural suffix
|
46
|
+
lookupKey = lookupKey + '.' + this.getPluralSuffix(lookupKey, options.count);
|
47
|
+
}
|
50
48
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
throw new Error('i18n: cannot replace placeholders in string if no option data provided')
|
55
|
-
}
|
49
|
+
if (lookupKey in this.translations) {
|
50
|
+
// Fetch the translation string for that lookup key
|
51
|
+
var translationString = this.translations[lookupKey];
|
56
52
|
|
57
|
-
|
53
|
+
// Check for ${} placeholders in the translation string
|
54
|
+
if (translationString.match(/%{(.\S+)}/)) {
|
55
|
+
if (!options) {
|
56
|
+
throw new Error('i18n: cannot replace placeholders in string if no option data provided')
|
57
|
+
}
|
58
|
+
|
59
|
+
return this.replacePlaceholders(translationString, options)
|
60
|
+
} else {
|
61
|
+
return translationString
|
62
|
+
}
|
58
63
|
} else {
|
59
|
-
|
64
|
+
// If the key wasn't found in our translations object,
|
65
|
+
// return the lookup key itself as the fallback
|
66
|
+
return lookupKey
|
60
67
|
}
|
61
|
-
}
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
68
|
+
};
|
69
|
+
|
70
|
+
/**
|
71
|
+
* Takes a translation string with placeholders, and replaces the placeholders
|
72
|
+
* with the provided data
|
73
|
+
*
|
74
|
+
* @param {string} translationString - The translation string
|
75
|
+
* @param {Object<string, unknown>} options - Any options passed with the translation string, e.g: for string interpolation.
|
76
|
+
* @returns {string} The translation string to output, with ${} placeholders replaced
|
77
|
+
*/
|
78
|
+
I18n.prototype.replacePlaceholders = function (translationString, options) {
|
79
|
+
var formatter;
|
80
|
+
|
81
|
+
if (this.hasIntlNumberFormatSupport()) {
|
82
|
+
formatter = new Intl.NumberFormat(this.locale);
|
83
|
+
}
|
84
|
+
|
85
|
+
return translationString.replace(/%{(.\S+)}/g, function (placeholderWithBraces, placeholderKey) {
|
86
|
+
if (Object.prototype.hasOwnProperty.call(options, placeholderKey)) {
|
87
|
+
var placeholderValue = options[placeholderKey];
|
88
|
+
|
89
|
+
// If a user has passed `false` as the value for the placeholder
|
90
|
+
// treat it as though the value should not be displayed
|
91
|
+
if (placeholderValue === false) {
|
92
|
+
return ''
|
93
|
+
}
|
82
94
|
|
83
|
-
|
84
|
-
|
85
|
-
|
95
|
+
// If the placeholder's value is a number, localise the number formatting
|
96
|
+
if (typeof placeholderValue === 'number' && formatter) {
|
97
|
+
return formatter.format(placeholderValue)
|
98
|
+
}
|
86
99
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
return ''
|
100
|
+
return placeholderValue
|
101
|
+
} else {
|
102
|
+
throw new Error('i18n: no data found to replace ' + placeholderWithBraces + ' placeholder in string')
|
91
103
|
}
|
104
|
+
})
|
105
|
+
};
|
106
|
+
|
107
|
+
/**
|
108
|
+
* Check to see if the browser supports Intl and Intl.PluralRules.
|
109
|
+
*
|
110
|
+
* It requires all conditions to be met in order to be supported:
|
111
|
+
* - The browser supports the Intl class (true in IE11)
|
112
|
+
* - The implementation of Intl supports PluralRules (NOT true in IE11)
|
113
|
+
* - The browser/OS has plural rules for the current locale (browser dependent)
|
114
|
+
*
|
115
|
+
* @returns {boolean} Returns true if all conditions are met. Returns false otherwise.
|
116
|
+
*/
|
117
|
+
I18n.prototype.hasIntlPluralRulesSupport = function () {
|
118
|
+
return Boolean(window.Intl && ('PluralRules' in window.Intl && Intl.PluralRules.supportedLocalesOf(this.locale).length))
|
119
|
+
};
|
120
|
+
|
121
|
+
/**
|
122
|
+
* Check to see if the browser supports Intl and Intl.NumberFormat.
|
123
|
+
*
|
124
|
+
* It requires all conditions to be met in order to be supported:
|
125
|
+
* - The browser supports the Intl class (true in IE11)
|
126
|
+
* - The implementation of Intl supports NumberFormat (also true in IE11)
|
127
|
+
* - The browser/OS has number formatting rules for the current locale (browser dependent)
|
128
|
+
*
|
129
|
+
* @returns {boolean} Returns true if all conditions are met. Returns false otherwise.
|
130
|
+
*/
|
131
|
+
I18n.prototype.hasIntlNumberFormatSupport = function () {
|
132
|
+
return Boolean(window.Intl && ('NumberFormat' in window.Intl && Intl.NumberFormat.supportedLocalesOf(this.locale).length))
|
133
|
+
};
|
134
|
+
|
135
|
+
/**
|
136
|
+
* Get the appropriate suffix for the plural form.
|
137
|
+
*
|
138
|
+
* Uses Intl.PluralRules (or our own fallback implementation) to get the
|
139
|
+
* 'preferred' form to use for the given count.
|
140
|
+
*
|
141
|
+
* Checks that a translation has been provided for that plural form – if it
|
142
|
+
* hasn't, it'll fall back to the 'other' plural form (unless that doesn't exist
|
143
|
+
* either, in which case an error will be thrown)
|
144
|
+
*
|
145
|
+
* @param {string} lookupKey - The lookup key of the string to use.
|
146
|
+
* @param {number} count - Number used to determine which pluralisation to use.
|
147
|
+
* @returns {PluralRule} The suffix associated with the correct pluralisation for this locale.
|
148
|
+
* @throws {Error} Plural form `.other` required when preferred plural form is missing
|
149
|
+
*/
|
150
|
+
I18n.prototype.getPluralSuffix = function (lookupKey, count) {
|
151
|
+
// Validate that the number is actually a number.
|
152
|
+
//
|
153
|
+
// Number(count) will turn anything that can't be converted to a Number type
|
154
|
+
// into 'NaN'. isFinite filters out NaN, as it isn't a finite number.
|
155
|
+
count = Number(count);
|
156
|
+
if (!isFinite(count)) { return 'other' }
|
157
|
+
|
158
|
+
var preferredForm;
|
159
|
+
|
160
|
+
// Check to verify that all the requirements for Intl.PluralRules are met.
|
161
|
+
// If so, we can use that instead of our custom implementation. Otherwise,
|
162
|
+
// use the hardcoded fallback.
|
163
|
+
if (this.hasIntlPluralRulesSupport()) {
|
164
|
+
preferredForm = new Intl.PluralRules(this.locale).select(count);
|
165
|
+
} else {
|
166
|
+
preferredForm = this.selectPluralFormUsingFallbackRules(count);
|
167
|
+
}
|
92
168
|
|
93
|
-
|
94
|
-
|
95
|
-
|
169
|
+
// Use the correct plural form if provided
|
170
|
+
if (lookupKey + '.' + preferredForm in this.translations) {
|
171
|
+
return preferredForm
|
172
|
+
// Fall back to `other` if the plural form is missing, but log a warning
|
173
|
+
// to the console
|
174
|
+
} else if (lookupKey + '.other' in this.translations) {
|
175
|
+
if (console && 'warn' in console) {
|
176
|
+
console.warn('i18n: Missing plural form ".' + preferredForm + '" for "' +
|
177
|
+
this.locale + '" locale. Falling back to ".other".');
|
96
178
|
}
|
97
179
|
|
98
|
-
return
|
180
|
+
return 'other'
|
181
|
+
// If the required `other` plural form is missing, all we can do is error
|
99
182
|
} else {
|
100
|
-
throw new Error(
|
183
|
+
throw new Error(
|
184
|
+
'i18n: Plural form ".other" is required for "' + this.locale + '" locale'
|
185
|
+
)
|
101
186
|
}
|
102
|
-
}
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
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".');
|
187
|
+
};
|
188
|
+
|
189
|
+
/**
|
190
|
+
* Get the plural form using our fallback implementation
|
191
|
+
*
|
192
|
+
* This is split out into a separate function to make it easier to test the
|
193
|
+
* fallback behaviour in an environment where Intl.PluralRules exists.
|
194
|
+
*
|
195
|
+
* @param {number} count - Number used to determine which pluralisation to use.
|
196
|
+
* @returns {PluralRule} The pluralisation form for count in this locale.
|
197
|
+
*/
|
198
|
+
I18n.prototype.selectPluralFormUsingFallbackRules = function (count) {
|
199
|
+
// Currently our custom code can only handle positive integers, so let's
|
200
|
+
// make sure our number is one of those.
|
201
|
+
count = Math.abs(Math.floor(count));
|
202
|
+
|
203
|
+
var ruleset = this.getPluralRulesForLocale();
|
204
|
+
|
205
|
+
if (ruleset) {
|
206
|
+
return I18n.pluralRules[ruleset](count)
|
175
207
|
}
|
176
208
|
|
177
209
|
return 'other'
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
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
|
210
|
+
};
|
211
|
+
|
212
|
+
/**
|
213
|
+
* Work out which pluralisation rules to use for the current locale
|
214
|
+
*
|
215
|
+
* The locale may include a regional indicator (such as en-GB), but we don't
|
216
|
+
* usually care about this part, as pluralisation rules are usually the same
|
217
|
+
* regardless of region. There are exceptions, however, (e.g. Portuguese) so
|
218
|
+
* this searches by both the full and shortened locale codes, just to be sure.
|
219
|
+
*
|
220
|
+
* @returns {PluralRuleName | undefined} The name of the pluralisation rule to use (a key for one
|
221
|
+
* of the functions in this.pluralRules)
|
222
|
+
*/
|
223
|
+
I18n.prototype.getPluralRulesForLocale = function () {
|
224
|
+
var locale = this.locale;
|
225
|
+
var localeShort = locale.split('-')[0];
|
226
|
+
|
227
|
+
// Look through the plural rules map to find which `pluralRule` is
|
228
|
+
// appropriate for our current `locale`.
|
229
|
+
for (var pluralRule in I18n.pluralRulesMap) {
|
230
|
+
if (Object.prototype.hasOwnProperty.call(I18n.pluralRulesMap, pluralRule)) {
|
231
|
+
var languages = I18n.pluralRulesMap[pluralRule];
|
232
|
+
for (var i = 0; i < languages.length; i++) {
|
233
|
+
if (languages[i] === locale || languages[i] === localeShort) {
|
234
|
+
return pluralRule
|
235
|
+
}
|
232
236
|
}
|
233
237
|
}
|
234
238
|
}
|
235
|
-
}
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
*
|
384
|
-
* @private
|
385
|
-
* @typedef {Object<string, string> | {}} TranslationsFlattened
|
386
|
-
*/
|
387
|
-
|
388
|
-
exports.I18n = I18n;
|
239
|
+
};
|
240
|
+
|
241
|
+
/**
|
242
|
+
* Map of plural rules to languages where those rules apply.
|
243
|
+
*
|
244
|
+
* Note: These groups are named for the most dominant or recognisable language
|
245
|
+
* that uses each system. The groupings do not imply that the languages are
|
246
|
+
* related to one another. Many languages have evolved the same systems
|
247
|
+
* independently of one another.
|
248
|
+
*
|
249
|
+
* Code to support more languages can be found in the i18n spike:
|
250
|
+
* {@link https://github.com/alphagov/govuk-frontend/blob/spike-i18n-support/src/govuk/i18n.mjs}
|
251
|
+
*
|
252
|
+
* Languages currently supported:
|
253
|
+
*
|
254
|
+
* Arabic: Arabic (ar)
|
255
|
+
* Chinese: Burmese (my), Chinese (zh), Indonesian (id), Japanese (ja),
|
256
|
+
* Javanese (jv), Korean (ko), Malay (ms), Thai (th), Vietnamese (vi)
|
257
|
+
* French: Armenian (hy), Bangla (bn), French (fr), Gujarati (gu), Hindi (hi),
|
258
|
+
* Persian Farsi (fa), Punjabi (pa), Zulu (zu)
|
259
|
+
* German: Afrikaans (af), Albanian (sq), Azerbaijani (az), Basque (eu),
|
260
|
+
* Bulgarian (bg), Catalan (ca), Danish (da), Dutch (nl), English (en),
|
261
|
+
* Estonian (et), Finnish (fi), Georgian (ka), German (de), Greek (el),
|
262
|
+
* Hungarian (hu), Luxembourgish (lb), Norwegian (no), Somali (so),
|
263
|
+
* Swahili (sw), Swedish (sv), Tamil (ta), Telugu (te), Turkish (tr),
|
264
|
+
* Urdu (ur)
|
265
|
+
* Irish: Irish Gaelic (ga)
|
266
|
+
* Russian: Russian (ru), Ukrainian (uk)
|
267
|
+
* Scottish: Scottish Gaelic (gd)
|
268
|
+
* Spanish: European Portuguese (pt-PT), Italian (it), Spanish (es)
|
269
|
+
* Welsh: Welsh (cy)
|
270
|
+
*
|
271
|
+
* @type {Object<PluralRuleName, string[]>}
|
272
|
+
*/
|
273
|
+
I18n.pluralRulesMap = {
|
274
|
+
arabic: ['ar'],
|
275
|
+
chinese: ['my', 'zh', 'id', 'ja', 'jv', 'ko', 'ms', 'th', 'vi'],
|
276
|
+
french: ['hy', 'bn', 'fr', 'gu', 'hi', 'fa', 'pa', 'zu'],
|
277
|
+
german: [
|
278
|
+
'af', 'sq', 'az', 'eu', 'bg', 'ca', 'da', 'nl', 'en', 'et', 'fi', 'ka',
|
279
|
+
'de', 'el', 'hu', 'lb', 'no', 'so', 'sw', 'sv', 'ta', 'te', 'tr', 'ur'
|
280
|
+
],
|
281
|
+
irish: ['ga'],
|
282
|
+
russian: ['ru', 'uk'],
|
283
|
+
scottish: ['gd'],
|
284
|
+
spanish: ['pt-PT', 'it', 'es'],
|
285
|
+
welsh: ['cy']
|
286
|
+
};
|
287
|
+
|
288
|
+
/**
|
289
|
+
* Different pluralisation rule sets
|
290
|
+
*
|
291
|
+
* Returns the appropriate suffix for the plural form associated with `n`.
|
292
|
+
* Possible suffixes: 'zero', 'one', 'two', 'few', 'many', 'other' (the actual
|
293
|
+
* meaning of each differs per locale). 'other' should always exist, even in
|
294
|
+
* languages without plurals, such as Chinese.
|
295
|
+
* {@link https://cldr.unicode.org/index/cldr-spec/plural-rules}
|
296
|
+
*
|
297
|
+
* The count must be a positive integer. Negative numbers and decimals aren't accounted for
|
298
|
+
*
|
299
|
+
* @type {Object<string, function(number): PluralRule>}
|
300
|
+
*/
|
301
|
+
I18n.pluralRules = {
|
302
|
+
/* eslint-disable jsdoc/require-jsdoc */
|
303
|
+
arabic: function (n) {
|
304
|
+
if (n === 0) { return 'zero' }
|
305
|
+
if (n === 1) { return 'one' }
|
306
|
+
if (n === 2) { return 'two' }
|
307
|
+
if (n % 100 >= 3 && n % 100 <= 10) { return 'few' }
|
308
|
+
if (n % 100 >= 11 && n % 100 <= 99) { return 'many' }
|
309
|
+
return 'other'
|
310
|
+
},
|
311
|
+
chinese: function () {
|
312
|
+
return 'other'
|
313
|
+
},
|
314
|
+
french: function (n) {
|
315
|
+
return n === 0 || n === 1 ? 'one' : 'other'
|
316
|
+
},
|
317
|
+
german: function (n) {
|
318
|
+
return n === 1 ? 'one' : 'other'
|
319
|
+
},
|
320
|
+
irish: function (n) {
|
321
|
+
if (n === 1) { return 'one' }
|
322
|
+
if (n === 2) { return 'two' }
|
323
|
+
if (n >= 3 && n <= 6) { return 'few' }
|
324
|
+
if (n >= 7 && n <= 10) { return 'many' }
|
325
|
+
return 'other'
|
326
|
+
},
|
327
|
+
russian: function (n) {
|
328
|
+
var lastTwo = n % 100;
|
329
|
+
var last = lastTwo % 10;
|
330
|
+
if (last === 1 && lastTwo !== 11) { return 'one' }
|
331
|
+
if (last >= 2 && last <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) { return 'few' }
|
332
|
+
if (last === 0 || (last >= 5 && last <= 9) || (lastTwo >= 11 && lastTwo <= 14)) { return 'many' }
|
333
|
+
// Note: The 'other' suffix is only used by decimal numbers in Russian.
|
334
|
+
// We don't anticipate it being used, but it's here for consistency.
|
335
|
+
return 'other'
|
336
|
+
},
|
337
|
+
scottish: function (n) {
|
338
|
+
if (n === 1 || n === 11) { return 'one' }
|
339
|
+
if (n === 2 || n === 12) { return 'two' }
|
340
|
+
if ((n >= 3 && n <= 10) || (n >= 13 && n <= 19)) { return 'few' }
|
341
|
+
return 'other'
|
342
|
+
},
|
343
|
+
spanish: function (n) {
|
344
|
+
if (n === 1) { return 'one' }
|
345
|
+
if (n % 1000000 === 0 && n !== 0) { return 'many' }
|
346
|
+
return 'other'
|
347
|
+
},
|
348
|
+
welsh: function (n) {
|
349
|
+
if (n === 0) { return 'zero' }
|
350
|
+
if (n === 1) { return 'one' }
|
351
|
+
if (n === 2) { return 'two' }
|
352
|
+
if (n === 3) { return 'few' }
|
353
|
+
if (n === 6) { return 'many' }
|
354
|
+
return 'other'
|
355
|
+
}
|
356
|
+
/* eslint-enable jsdoc/require-jsdoc */
|
357
|
+
};
|
358
|
+
|
359
|
+
/**
|
360
|
+
* Supported languages for plural rules
|
361
|
+
*
|
362
|
+
* @typedef {'arabic' | 'chinese' | 'french' | 'german' | 'irish' | 'russian' | 'scottish' | 'spanish' | 'welsh'} PluralRuleName
|
363
|
+
*/
|
364
|
+
|
365
|
+
/**
|
366
|
+
* Plural rule category mnemonic tags
|
367
|
+
*
|
368
|
+
* @typedef {'zero' | 'one' | 'two' | 'few' | 'many' | 'other'} PluralRule
|
369
|
+
*/
|
370
|
+
|
371
|
+
/**
|
372
|
+
* Translated message by plural rule they correspond to.
|
373
|
+
*
|
374
|
+
* Allows to group pluralised messages under a single key when passing
|
375
|
+
* translations to a component's constructor
|
376
|
+
*
|
377
|
+
* @typedef {object} TranslationPluralForms
|
378
|
+
* @property {string} [other] - General plural form
|
379
|
+
* @property {string} [zero] - Plural form used with 0
|
380
|
+
* @property {string} [one] - Plural form used with 1
|
381
|
+
* @property {string} [two] - Plural form used with 2
|
382
|
+
* @property {string} [few] - Plural form used for a few
|
383
|
+
* @property {string} [many] - Plural form used for many
|
384
|
+
*/
|
385
|
+
|
386
|
+
exports.I18n = I18n;
|
389
387
|
|
390
388
|
})));
|
389
|
+
//# sourceMappingURL=i18n.js.map
|