resolve-accept-language 1.1.12 → 1.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +10 -10
- package/lib/locale-list.d.ts +6 -6
- package/lib/locale-list.js +6 -6
- package/lib/locale.d.ts +16 -16
- package/lib/locale.js +10 -10
- package/lib/lookup-list.d.ts +28 -28
- package/lib/lookup-list.js +64 -64
- package/lib/resolve-accept-language.d.ts +17 -17
- package/lib/resolve-accept-language.js +22 -35
- package/package.json +62 -54
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2021 Avansai
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Avansai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -19,11 +19,11 @@ npm install resolve-accept-language
|
|
|
19
19
|
Code example:
|
|
20
20
|
|
|
21
21
|
```ts
|
|
22
|
-
import resolveAcceptLanguage from 'resolve-accept-language'
|
|
22
|
+
import resolveAcceptLanguage from 'resolve-accept-language'
|
|
23
23
|
|
|
24
24
|
console.log(
|
|
25
25
|
resolveAcceptLanguage('fr-CA;q=0.01,en-CA;q=0.1,en-US;q=0.001', ['en-US', 'fr-CA'], 'en-US')
|
|
26
|
-
)
|
|
26
|
+
)
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
Output:
|
|
@@ -37,7 +37,7 @@ fr-CA
|
|
|
37
37
|
You may want to control exactly the behavior depending on the type of match. For example, you could want to display a language picker on your home page if the match is not satisfactory. In those cases, you will need to use the `ResolveAcceptLanguage` class instead. It offers more visibility into the selection process while matching a locale:
|
|
38
38
|
|
|
39
39
|
```ts
|
|
40
|
-
import { ResolveAcceptLanguage } from 'resolve-accept-language'
|
|
40
|
+
import { ResolveAcceptLanguage } from 'resolve-accept-language'
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* If you are planning to have a "default locale", make sure to add it first in the provided locale list.
|
|
@@ -47,23 +47,23 @@ import { ResolveAcceptLanguage } from 'resolve-accept-language';
|
|
|
47
47
|
const resolveAcceptLanguage = new ResolveAcceptLanguage('fr-CA;q=0.01,en-CA;q=0.1,en-US;q=0.001', [
|
|
48
48
|
'en-US',
|
|
49
49
|
'fr-CA',
|
|
50
|
-
])
|
|
50
|
+
])
|
|
51
51
|
|
|
52
52
|
if (resolveAcceptLanguage.hasMatch()) {
|
|
53
|
-
const locale = resolveAcceptLanguage.getBestMatch() as string
|
|
54
|
-
console.log(`A locale was matched: ${locale}`)
|
|
53
|
+
const locale = resolveAcceptLanguage.getBestMatch() as string
|
|
54
|
+
console.log(`A locale was matched: ${locale}`)
|
|
55
55
|
|
|
56
56
|
if (resolveAcceptLanguage.bestMatchIsLocaleBased()) {
|
|
57
|
-
console.log('The match is locale-based')
|
|
57
|
+
console.log('The match is locale-based')
|
|
58
58
|
} else if (resolveAcceptLanguage.bestMatchIsLanguageBased()) {
|
|
59
|
-
console.log('The match is language-based')
|
|
59
|
+
console.log('The match is language-based')
|
|
60
60
|
} else if (resolveAcceptLanguage.bestMatchIsRelatedLocaleBased()) {
|
|
61
|
-
console.log('The match is related-locale-based')
|
|
61
|
+
console.log('The match is related-locale-based')
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
if (resolveAcceptLanguage.hasNoMatch()) {
|
|
66
|
-
console.log('No match found :(')
|
|
66
|
+
console.log('No match found :(')
|
|
67
67
|
}
|
|
68
68
|
```
|
|
69
69
|
|
package/lib/locale-list.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import Locale from './locale';
|
|
2
2
|
export default class LocaleList {
|
|
3
|
-
/** A list of locale objects. */
|
|
4
|
-
readonly objects: Locale[];
|
|
5
|
-
/** A set of locale identifiers using the BCP 47 `language`-`country` case-normalized format. */
|
|
6
|
-
readonly locales: Set<string>;
|
|
7
|
-
/** A set of ISO 639-1 alpha-2 language codes. */
|
|
8
|
-
readonly languages: Set<string>;
|
|
9
3
|
/** A set of ISO 3166-1 alpha-2 country codes. */
|
|
10
4
|
readonly countries: Set<string>;
|
|
5
|
+
/** A set of ISO 639-1 alpha-2 language codes. */
|
|
6
|
+
readonly languages: Set<string>;
|
|
7
|
+
/** A set of locale identifiers using the BCP 47 `language`-`country` case-normalized format. */
|
|
8
|
+
readonly locales: Set<string>;
|
|
9
|
+
/** A list of locale objects. */
|
|
10
|
+
readonly objects: Locale[];
|
|
11
11
|
/**
|
|
12
12
|
* Create a list of locale identifiers.
|
|
13
13
|
*
|
package/lib/locale-list.js
CHANGED
|
@@ -11,14 +11,14 @@ var LocaleList = /** @class */ (function () {
|
|
|
11
11
|
*/
|
|
12
12
|
function LocaleList(locales) {
|
|
13
13
|
var _this = this;
|
|
14
|
-
/** A list of locale objects. */
|
|
15
|
-
this.objects = [];
|
|
16
|
-
/** A set of locale identifiers using the BCP 47 `language`-`country` case-normalized format. */
|
|
17
|
-
this.locales = new Set();
|
|
18
|
-
/** A set of ISO 639-1 alpha-2 language codes. */
|
|
19
|
-
this.languages = new Set();
|
|
20
14
|
/** A set of ISO 3166-1 alpha-2 country codes. */
|
|
21
15
|
this.countries = new Set();
|
|
16
|
+
/** A set of ISO 639-1 alpha-2 language codes. */
|
|
17
|
+
this.languages = new Set();
|
|
18
|
+
/** A set of locale identifiers using the BCP 47 `language`-`country` case-normalized format. */
|
|
19
|
+
this.locales = new Set();
|
|
20
|
+
/** A list of locale objects. */
|
|
21
|
+
this.objects = [];
|
|
22
22
|
locales.forEach(function (locale) {
|
|
23
23
|
var localeObject = new locale_1.default(locale);
|
|
24
24
|
if (!_this.locales.has(localeObject.identifier)) {
|
package/lib/locale.d.ts
CHANGED
|
@@ -1,25 +1,19 @@
|
|
|
1
1
|
/** Class to manage a locale identifier using the BCP 47 `language`-`country` format. */
|
|
2
2
|
export default class Locale {
|
|
3
|
+
/** The ISO 3166-1 alpha-2 country code. */
|
|
4
|
+
readonly countryCode: string;
|
|
3
5
|
/** The locale identifier using the BCP 47 `language`-`country` case-normalized format. */
|
|
4
6
|
readonly identifier: string;
|
|
5
7
|
/** The ISO 639-1 alpha-2 language code. */
|
|
6
8
|
readonly languageCode: string;
|
|
7
|
-
/** The ISO 3166-1 alpha-2 country code. */
|
|
8
|
-
readonly countryCode: string;
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Create a new `Locale` object.
|
|
11
11
|
*
|
|
12
|
-
* @param identifier - A
|
|
13
|
-
* @param caseNormalized - Should we verify if the identifier is using the case-normalized format?
|
|
14
|
-
*/
|
|
15
|
-
static isLocale(identifier: string, caseNormalized?: boolean): boolean;
|
|
16
|
-
/**
|
|
17
|
-
* Is a given string an ISO 639-1 alpha-2 language code.
|
|
12
|
+
* @param identifier - A locale identifier using the BCP 47 `language`-`country` format (case insensitive).
|
|
18
13
|
*
|
|
19
|
-
* @
|
|
20
|
-
* @param caseNormalized - Should we verify if the identifier is using the case-normalized format?
|
|
14
|
+
* @throws An error if the `identifier` format is invalid.
|
|
21
15
|
*/
|
|
22
|
-
|
|
16
|
+
constructor(identifier: string);
|
|
23
17
|
/**
|
|
24
18
|
* Is a given string an ISO 3166-1 alpha-2 country code.
|
|
25
19
|
*
|
|
@@ -28,11 +22,17 @@ export default class Locale {
|
|
|
28
22
|
*/
|
|
29
23
|
static isCountryCode(countryCode: string, caseNormalized?: boolean): boolean;
|
|
30
24
|
/**
|
|
31
|
-
*
|
|
25
|
+
* Is a given string an ISO 639-1 alpha-2 language code.
|
|
32
26
|
*
|
|
33
|
-
* @param
|
|
27
|
+
* @param languageCode - An ISO 639-1 alpha-2 language code.
|
|
28
|
+
* @param caseNormalized - Should we verify if the identifier is using the case-normalized format?
|
|
29
|
+
*/
|
|
30
|
+
static isLanguageCode(languageCode: string, caseNormalized?: boolean): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Is a given string a locale identifier following the BCP 47 `language`-`country` format.
|
|
34
33
|
*
|
|
35
|
-
* @
|
|
34
|
+
* @param identifier - A potential locale identify to verify.
|
|
35
|
+
* @param caseNormalized - Should we verify if the identifier is using the case-normalized format?
|
|
36
36
|
*/
|
|
37
|
-
|
|
37
|
+
static isLocale(identifier: string, caseNormalized?: boolean): boolean;
|
|
38
38
|
}
|
package/lib/locale.js
CHANGED
|
@@ -19,15 +19,15 @@ var Locale = /** @class */ (function () {
|
|
|
19
19
|
this.identifier = "".concat(this.languageCode, "-").concat(this.countryCode);
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
|
-
* Is a given string
|
|
22
|
+
* Is a given string an ISO 3166-1 alpha-2 country code.
|
|
23
23
|
*
|
|
24
|
-
* @param
|
|
24
|
+
* @param countryCode - An ISO 3166-1 alpha-2 country code.
|
|
25
25
|
* @param caseNormalized - Should we verify if the identifier is using the case-normalized format?
|
|
26
26
|
*/
|
|
27
|
-
Locale.
|
|
27
|
+
Locale.isCountryCode = function (countryCode, caseNormalized) {
|
|
28
28
|
if (caseNormalized === void 0) { caseNormalized = true; }
|
|
29
|
-
var regExp = new RegExp(/^[
|
|
30
|
-
return regExp.test(
|
|
29
|
+
var regExp = new RegExp(/^[A-Z]{2}$/, caseNormalized ? undefined : 'i');
|
|
30
|
+
return regExp.test(countryCode);
|
|
31
31
|
};
|
|
32
32
|
/**
|
|
33
33
|
* Is a given string an ISO 639-1 alpha-2 language code.
|
|
@@ -41,15 +41,15 @@ var Locale = /** @class */ (function () {
|
|
|
41
41
|
return regExp.test(languageCode);
|
|
42
42
|
};
|
|
43
43
|
/**
|
|
44
|
-
* Is a given string
|
|
44
|
+
* Is a given string a locale identifier following the BCP 47 `language`-`country` format.
|
|
45
45
|
*
|
|
46
|
-
* @param
|
|
46
|
+
* @param identifier - A potential locale identify to verify.
|
|
47
47
|
* @param caseNormalized - Should we verify if the identifier is using the case-normalized format?
|
|
48
48
|
*/
|
|
49
|
-
Locale.
|
|
49
|
+
Locale.isLocale = function (identifier, caseNormalized) {
|
|
50
50
|
if (caseNormalized === void 0) { caseNormalized = true; }
|
|
51
|
-
var regExp = new RegExp(/^[A-Z]{2}$/, caseNormalized ? undefined : 'i');
|
|
52
|
-
return regExp.test(
|
|
51
|
+
var regExp = new RegExp(/^[a-z]{2}-[A-Z]{2}$/, caseNormalized ? undefined : 'i');
|
|
52
|
+
return regExp.test(identifier);
|
|
53
53
|
};
|
|
54
54
|
return Locale;
|
|
55
55
|
}());
|
package/lib/lookup-list.d.ts
CHANGED
|
@@ -17,20 +17,25 @@ export default class LookupList {
|
|
|
17
17
|
*/
|
|
18
18
|
constructor(acceptLanguageHeader: string, locales: string[]);
|
|
19
19
|
/**
|
|
20
|
-
* Get
|
|
20
|
+
* Get the top (highest-ranked) locale by language.
|
|
21
21
|
*
|
|
22
|
-
* @param
|
|
22
|
+
* @param languageCode - An ISO 639-1 alpha-2 language code.
|
|
23
23
|
*
|
|
24
|
-
* @returns
|
|
24
|
+
* @returns The top locale with the specified language.
|
|
25
25
|
*/
|
|
26
|
-
|
|
26
|
+
getTopByLanguage(languageCode: string): string | undefined;
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
28
|
+
* Get the top (highest-ranked) locale or language.
|
|
29
29
|
*
|
|
30
|
-
* @
|
|
31
|
-
* @param identifier - A locale identifier using the BCP 47 `language`-`country` case-normalized format.
|
|
30
|
+
* @returns The top match, which can either be a locale or a language.
|
|
32
31
|
*/
|
|
33
|
-
|
|
32
|
+
getTopLocaleOrLanguage(): string | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Get the top (highest-ranked) related locale.
|
|
35
|
+
*
|
|
36
|
+
* @returns The top related locale.
|
|
37
|
+
*/
|
|
38
|
+
getTopRelatedLocale(): string | undefined;
|
|
34
39
|
/**
|
|
35
40
|
* Add a language in the data object matching its quality.
|
|
36
41
|
*
|
|
@@ -38,6 +43,13 @@ export default class LookupList {
|
|
|
38
43
|
* @param languageCode - An ISO 639-1 alpha-2 language code.
|
|
39
44
|
*/
|
|
40
45
|
private addLanguage;
|
|
46
|
+
/**
|
|
47
|
+
* Add a locale in the data object matching its quality.
|
|
48
|
+
*
|
|
49
|
+
* @param quality - The HTTP header's quality factor associated with a locale.
|
|
50
|
+
* @param identifier - A locale identifier using the BCP 47 `language`-`country` case-normalized format.
|
|
51
|
+
*/
|
|
52
|
+
private addLocale;
|
|
41
53
|
/**
|
|
42
54
|
* Add a related locale's language in the data object matching its quality.
|
|
43
55
|
*
|
|
@@ -46,31 +58,19 @@ export default class LookupList {
|
|
|
46
58
|
*/
|
|
47
59
|
private addRelatedLocaleLanguage;
|
|
48
60
|
/**
|
|
49
|
-
* Get
|
|
50
|
-
*
|
|
51
|
-
* @param dataObjectEntries - The object entries of a dataset object.
|
|
61
|
+
* Get a directive object from a directive string.
|
|
52
62
|
*
|
|
53
|
-
* @
|
|
54
|
-
*/
|
|
55
|
-
private getTop;
|
|
56
|
-
/**
|
|
57
|
-
* Get the top (highest-ranked) locale or language.
|
|
63
|
+
* @param directiveString - The string representing a directive, extracted from the HTTP header.
|
|
58
64
|
*
|
|
59
|
-
* @returns
|
|
65
|
+
* @returns A `Directive` object or `undefined` if the string's format is invalid.
|
|
60
66
|
*/
|
|
61
|
-
|
|
67
|
+
private getDirective;
|
|
62
68
|
/**
|
|
63
|
-
* Get the top (highest-ranked)
|
|
64
|
-
*
|
|
65
|
-
* @param languageCode - An ISO 639-1 alpha-2 language code.
|
|
69
|
+
* Get the top (highest-ranked) entry from a dataset object entries.
|
|
66
70
|
*
|
|
67
|
-
* @
|
|
68
|
-
*/
|
|
69
|
-
getTopByLanguage(languageCode: string): string | undefined;
|
|
70
|
-
/**
|
|
71
|
-
* Get the top (highest-ranked) related locale.
|
|
71
|
+
* @param dataObjectEntries - The object entries of a dataset object.
|
|
72
72
|
*
|
|
73
|
-
* @returns The top
|
|
73
|
+
* @returns The top entry from a dataset object entries.
|
|
74
74
|
*/
|
|
75
|
-
|
|
75
|
+
private getTop;
|
|
76
76
|
}
|
package/lib/lookup-list.js
CHANGED
|
@@ -46,42 +46,40 @@ var LookupList = /** @class */ (function () {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
/**
|
|
49
|
-
* Get
|
|
49
|
+
* Get the top (highest-ranked) locale by language.
|
|
50
50
|
*
|
|
51
|
-
* @param
|
|
51
|
+
* @param languageCode - An ISO 639-1 alpha-2 language code.
|
|
52
52
|
*
|
|
53
|
-
* @returns
|
|
53
|
+
* @returns The top locale with the specified language.
|
|
54
54
|
*/
|
|
55
|
-
LookupList.prototype.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
* browsers today (also those options seem unpractical):
|
|
59
|
-
*
|
|
60
|
-
* - The wildcard character "*", as per RFC 2616 (section 14.4), should match any unmatched language tag.
|
|
61
|
-
* - Language tags that starts with a wildcard (e.g. "*-CA") should match the first supported locale of a country.
|
|
62
|
-
* - A quality value equivalent to "0", as per RFC 2616 (section 3.9), should be considered as "not acceptable".
|
|
63
|
-
*/
|
|
64
|
-
var directiveMatch = directiveString.match(/^((?<matchedLanguageCode>([A-Z]{2}))(-(?<matchedCountryCode>[A-Z]{2}))?)(;q=(?<matchedQuality>1|0.(\d*[1-9]\d*){1,3}))?$/i);
|
|
65
|
-
if (!(directiveMatch === null || directiveMatch === void 0 ? void 0 : directiveMatch.groups))
|
|
66
|
-
return undefined; // No regular expression match.
|
|
67
|
-
var _a = directiveMatch.groups, matchedLanguageCode = _a.matchedLanguageCode, matchedCountryCode = _a.matchedCountryCode, matchedQuality = _a.matchedQuality;
|
|
68
|
-
var languageCode = matchedLanguageCode.toLowerCase();
|
|
69
|
-
var countryCode = matchedCountryCode ? matchedCountryCode.toUpperCase() : undefined;
|
|
70
|
-
var quality = matchedQuality === undefined ? '1' : parseFloat(matchedQuality).toString(); // Remove trailing zeros.
|
|
71
|
-
var locale = countryCode ? "".concat(languageCode, "-").concat(countryCode) : undefined;
|
|
72
|
-
return { locale: locale, languageCode: languageCode, quality: quality };
|
|
55
|
+
LookupList.prototype.getTopByLanguage = function (languageCode) {
|
|
56
|
+
var _a;
|
|
57
|
+
return (_a = this.localeList.objects.find(function (locale) { return locale.languageCode === languageCode; })) === null || _a === void 0 ? void 0 : _a.identifier;
|
|
73
58
|
};
|
|
74
59
|
/**
|
|
75
|
-
*
|
|
60
|
+
* Get the top (highest-ranked) locale or language.
|
|
76
61
|
*
|
|
77
|
-
* @
|
|
78
|
-
* @param identifier - A locale identifier using the BCP 47 `language`-`country` case-normalized format.
|
|
62
|
+
* @returns The top match, which can either be a locale or a language.
|
|
79
63
|
*/
|
|
80
|
-
LookupList.prototype.
|
|
81
|
-
|
|
82
|
-
|
|
64
|
+
LookupList.prototype.getTopLocaleOrLanguage = function () {
|
|
65
|
+
var localesAndLanguagesByQuality = Object.entries(this.localesAndLanguagesByQuality);
|
|
66
|
+
if (localesAndLanguagesByQuality.length === 0) {
|
|
67
|
+
return undefined;
|
|
83
68
|
}
|
|
84
|
-
this.localesAndLanguagesByQuality
|
|
69
|
+
return this.getTop(localesAndLanguagesByQuality);
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Get the top (highest-ranked) related locale.
|
|
73
|
+
*
|
|
74
|
+
* @returns The top related locale.
|
|
75
|
+
*/
|
|
76
|
+
LookupList.prototype.getTopRelatedLocale = function () {
|
|
77
|
+
var relatedLocaleLanguagesByQuality = Object.entries(this.relatedLocaleLanguagesByQuality);
|
|
78
|
+
if (relatedLocaleLanguagesByQuality.length === 0) {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
var topRelatedLocaleLanguage = this.getTop(relatedLocaleLanguagesByQuality);
|
|
82
|
+
return this.getTopByLanguage(topRelatedLocaleLanguage);
|
|
85
83
|
};
|
|
86
84
|
/**
|
|
87
85
|
* Add a language in the data object matching its quality.
|
|
@@ -95,6 +93,18 @@ var LookupList = /** @class */ (function () {
|
|
|
95
93
|
}
|
|
96
94
|
this.localesAndLanguagesByQuality[quality].add(languageCode);
|
|
97
95
|
};
|
|
96
|
+
/**
|
|
97
|
+
* Add a locale in the data object matching its quality.
|
|
98
|
+
*
|
|
99
|
+
* @param quality - The HTTP header's quality factor associated with a locale.
|
|
100
|
+
* @param identifier - A locale identifier using the BCP 47 `language`-`country` case-normalized format.
|
|
101
|
+
*/
|
|
102
|
+
LookupList.prototype.addLocale = function (quality, identifier) {
|
|
103
|
+
if (!this.localesAndLanguagesByQuality[quality]) {
|
|
104
|
+
this.localesAndLanguagesByQuality[quality] = new Set();
|
|
105
|
+
}
|
|
106
|
+
this.localesAndLanguagesByQuality[quality].add(identifier);
|
|
107
|
+
};
|
|
98
108
|
/**
|
|
99
109
|
* Add a related locale's language in the data object matching its quality.
|
|
100
110
|
*
|
|
@@ -108,50 +118,40 @@ var LookupList = /** @class */ (function () {
|
|
|
108
118
|
this.relatedLocaleLanguagesByQuality[quality].add(languageCode);
|
|
109
119
|
};
|
|
110
120
|
/**
|
|
111
|
-
* Get
|
|
112
|
-
*
|
|
113
|
-
* @param dataObjectEntries - The object entries of a dataset object.
|
|
121
|
+
* Get a directive object from a directive string.
|
|
114
122
|
*
|
|
115
|
-
* @
|
|
116
|
-
*/
|
|
117
|
-
LookupList.prototype.getTop = function (dataObjectEntries) {
|
|
118
|
-
return dataObjectEntries.sort().reverse()[0][1].values().next().value;
|
|
119
|
-
};
|
|
120
|
-
/**
|
|
121
|
-
* Get the top (highest-ranked) locale or language.
|
|
123
|
+
* @param directiveString - The string representing a directive, extracted from the HTTP header.
|
|
122
124
|
*
|
|
123
|
-
* @returns
|
|
125
|
+
* @returns A `Directive` object or `undefined` if the string's format is invalid.
|
|
124
126
|
*/
|
|
125
|
-
LookupList.prototype.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
LookupList.prototype.getDirective = function (directiveString) {
|
|
128
|
+
/**
|
|
129
|
+
* The regular expression is excluding certain directives due to the inability to configure those options in modern
|
|
130
|
+
* browsers today (also those options seem unpractical):
|
|
131
|
+
*
|
|
132
|
+
* - The wildcard character "*", as per RFC 2616 (section 14.4), should match any unmatched language tag.
|
|
133
|
+
* - Language tags that starts with a wildcard (e.g. "*-CA") should match the first supported locale of a country.
|
|
134
|
+
* - A quality value equivalent to "0", as per RFC 2616 (section 3.9), should be considered as "not acceptable".
|
|
135
|
+
*/
|
|
136
|
+
var directiveMatch = directiveString.match(/^((?<matchedLanguageCode>([a-z]{2}))(-(?<matchedCountryCode>[a-z]{2}))?)(;q=(?<matchedQuality>1|0.(\d*[1-9]\d*){1,3}))?$/i);
|
|
137
|
+
if (!(directiveMatch === null || directiveMatch === void 0 ? void 0 : directiveMatch.groups))
|
|
138
|
+
return undefined; // No regular expression match.
|
|
139
|
+
var _a = directiveMatch.groups, matchedLanguageCode = _a.matchedLanguageCode, matchedCountryCode = _a.matchedCountryCode, matchedQuality = _a.matchedQuality;
|
|
140
|
+
var languageCode = matchedLanguageCode.toLowerCase();
|
|
141
|
+
var countryCode = matchedCountryCode ? matchedCountryCode.toUpperCase() : undefined;
|
|
142
|
+
var quality = matchedQuality === undefined ? '1' : Number.parseFloat(matchedQuality).toString(); // Remove trailing zeros.
|
|
143
|
+
var locale = countryCode ? "".concat(languageCode, "-").concat(countryCode) : undefined;
|
|
144
|
+
return { languageCode: languageCode, locale: locale, quality: quality };
|
|
131
145
|
};
|
|
132
146
|
/**
|
|
133
|
-
* Get the top (highest-ranked)
|
|
134
|
-
*
|
|
135
|
-
* @param languageCode - An ISO 639-1 alpha-2 language code.
|
|
147
|
+
* Get the top (highest-ranked) entry from a dataset object entries.
|
|
136
148
|
*
|
|
137
|
-
* @
|
|
138
|
-
*/
|
|
139
|
-
LookupList.prototype.getTopByLanguage = function (languageCode) {
|
|
140
|
-
var _a;
|
|
141
|
-
return (_a = this.localeList.objects.find(function (locale) { return locale.languageCode === languageCode; })) === null || _a === void 0 ? void 0 : _a.identifier;
|
|
142
|
-
};
|
|
143
|
-
/**
|
|
144
|
-
* Get the top (highest-ranked) related locale.
|
|
149
|
+
* @param dataObjectEntries - The object entries of a dataset object.
|
|
145
150
|
*
|
|
146
|
-
* @returns The top
|
|
151
|
+
* @returns The top entry from a dataset object entries.
|
|
147
152
|
*/
|
|
148
|
-
LookupList.prototype.
|
|
149
|
-
|
|
150
|
-
if (!relatedLocaleLanguagesByQuality.length) {
|
|
151
|
-
return undefined;
|
|
152
|
-
}
|
|
153
|
-
var topRelatedLocaleLanguage = this.getTop(relatedLocaleLanguagesByQuality);
|
|
154
|
-
return this.getTopByLanguage(topRelatedLocaleLanguage);
|
|
153
|
+
LookupList.prototype.getTop = function (dataObjectEntries) {
|
|
154
|
+
return dataObjectEntries.sort().reverse()[0][1].values().next().value;
|
|
155
155
|
};
|
|
156
156
|
return LookupList;
|
|
157
157
|
}());
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/** Resolve the preferred locale from an HTTP `Accept-Language` header. */
|
|
2
2
|
export declare class ResolveAcceptLanguage {
|
|
3
|
-
/** The locale-based match, if applicable. */
|
|
4
|
-
private localeBasedMatch;
|
|
5
3
|
/** The language-based match, if applicable. */
|
|
6
4
|
private languageBasedMatch;
|
|
5
|
+
/** The locale-based match, if applicable. */
|
|
6
|
+
private localeBasedMatch;
|
|
7
7
|
/** The related-locale-based match, if applicable. */
|
|
8
8
|
private relatedLocaleBasedMatch;
|
|
9
9
|
/**
|
|
@@ -17,29 +17,17 @@ export declare class ResolveAcceptLanguage {
|
|
|
17
17
|
*/
|
|
18
18
|
constructor(acceptLanguageHeader: string, locales: string[]);
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* @returns True when a match is found, otherwise false.
|
|
23
|
-
*/
|
|
24
|
-
hasMatch(): boolean;
|
|
25
|
-
/**
|
|
26
|
-
* Did the resolution of the preferred locale find no match?
|
|
20
|
+
* Is the best match language-based?
|
|
27
21
|
*
|
|
28
|
-
* @returns True
|
|
22
|
+
* @returns True if the best match language-based, otherwise false.
|
|
29
23
|
*/
|
|
30
|
-
|
|
24
|
+
bestMatchIsLanguageBased(): boolean;
|
|
31
25
|
/**
|
|
32
26
|
* Is the best match locale-based?
|
|
33
27
|
*
|
|
34
28
|
* @returns True if the best match locale-based, otherwise false.
|
|
35
29
|
*/
|
|
36
30
|
bestMatchIsLocaleBased(): boolean;
|
|
37
|
-
/**
|
|
38
|
-
* Is the best match language-based?
|
|
39
|
-
*
|
|
40
|
-
* @returns True if the best match language-based, otherwise false.
|
|
41
|
-
*/
|
|
42
|
-
bestMatchIsLanguageBased(): boolean;
|
|
43
31
|
/**
|
|
44
32
|
* Is the best match related-locale-based?
|
|
45
33
|
*
|
|
@@ -52,6 +40,18 @@ export declare class ResolveAcceptLanguage {
|
|
|
52
40
|
* @returns The locale which was the best match.
|
|
53
41
|
*/
|
|
54
42
|
getBestMatch(): string | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Was a match found when resolving the preferred locale?
|
|
45
|
+
*
|
|
46
|
+
* @returns True when a match is found, otherwise false.
|
|
47
|
+
*/
|
|
48
|
+
hasMatch(): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Did the resolution of the preferred locale find no match?
|
|
51
|
+
*
|
|
52
|
+
* @returns True when there is no match, otherwise false.
|
|
53
|
+
*/
|
|
54
|
+
hasNoMatch(): boolean;
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
57
57
|
* Resolve the preferred locale from an HTTP `Accept-Language` header.
|
|
@@ -39,25 +39,12 @@ var ResolveAcceptLanguage = /** @class */ (function () {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* @returns True when a match is found, otherwise false.
|
|
45
|
-
*/
|
|
46
|
-
ResolveAcceptLanguage.prototype.hasMatch = function () {
|
|
47
|
-
if (this.localeBasedMatch !== undefined ||
|
|
48
|
-
this.languageBasedMatch !== undefined ||
|
|
49
|
-
this.relatedLocaleBasedMatch !== undefined) {
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
return false;
|
|
53
|
-
};
|
|
54
|
-
/**
|
|
55
|
-
* Did the resolution of the preferred locale find no match?
|
|
42
|
+
* Is the best match language-based?
|
|
56
43
|
*
|
|
57
|
-
* @returns True
|
|
44
|
+
* @returns True if the best match language-based, otherwise false.
|
|
58
45
|
*/
|
|
59
|
-
ResolveAcceptLanguage.prototype.
|
|
60
|
-
return
|
|
46
|
+
ResolveAcceptLanguage.prototype.bestMatchIsLanguageBased = function () {
|
|
47
|
+
return this.languageBasedMatch !== undefined;
|
|
61
48
|
};
|
|
62
49
|
/**
|
|
63
50
|
* Is the best match locale-based?
|
|
@@ -67,14 +54,6 @@ var ResolveAcceptLanguage = /** @class */ (function () {
|
|
|
67
54
|
ResolveAcceptLanguage.prototype.bestMatchIsLocaleBased = function () {
|
|
68
55
|
return this.localeBasedMatch !== undefined;
|
|
69
56
|
};
|
|
70
|
-
/**
|
|
71
|
-
* Is the best match language-based?
|
|
72
|
-
*
|
|
73
|
-
* @returns True if the best match language-based, otherwise false.
|
|
74
|
-
*/
|
|
75
|
-
ResolveAcceptLanguage.prototype.bestMatchIsLanguageBased = function () {
|
|
76
|
-
return this.languageBasedMatch !== undefined;
|
|
77
|
-
};
|
|
78
57
|
/**
|
|
79
58
|
* Is the best match related-locale-based?
|
|
80
59
|
*
|
|
@@ -89,16 +68,24 @@ var ResolveAcceptLanguage = /** @class */ (function () {
|
|
|
89
68
|
* @returns The locale which was the best match.
|
|
90
69
|
*/
|
|
91
70
|
ResolveAcceptLanguage.prototype.getBestMatch = function () {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return undefined;
|
|
71
|
+
var _a, _b;
|
|
72
|
+
return (_b = (_a = this.localeBasedMatch) !== null && _a !== void 0 ? _a : this.languageBasedMatch) !== null && _b !== void 0 ? _b : this.relatedLocaleBasedMatch;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Was a match found when resolving the preferred locale?
|
|
76
|
+
*
|
|
77
|
+
* @returns True when a match is found, otherwise false.
|
|
78
|
+
*/
|
|
79
|
+
ResolveAcceptLanguage.prototype.hasMatch = function () {
|
|
80
|
+
return this.getBestMatch() !== undefined ? true : false;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Did the resolution of the preferred locale find no match?
|
|
84
|
+
*
|
|
85
|
+
* @returns True when there is no match, otherwise false.
|
|
86
|
+
*/
|
|
87
|
+
ResolveAcceptLanguage.prototype.hasNoMatch = function () {
|
|
88
|
+
return !this.hasMatch();
|
|
102
89
|
};
|
|
103
90
|
return ResolveAcceptLanguage;
|
|
104
91
|
}());
|
package/package.json
CHANGED
|
@@ -1,54 +1,62 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "resolve-accept-language",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "Resolve the preferred locale based on the value of an `Accept-Language` HTTP header.",
|
|
5
|
-
"author": "Avansai (https://avansai.com)",
|
|
6
|
-
"repository": {
|
|
7
|
-
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/Avansai/resolve-accept-language.git"
|
|
9
|
-
},
|
|
10
|
-
"main": "lib/resolve-accept-language.js",
|
|
11
|
-
"types": "lib/resolve-accept-language.d.ts",
|
|
12
|
-
"scripts": {
|
|
13
|
-
"build": "rm -Rf ./lib && tsc && npm
|
|
14
|
-
"
|
|
15
|
-
"lint": "eslint . --
|
|
16
|
-
"
|
|
17
|
-
"prettier
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"@
|
|
41
|
-
"@
|
|
42
|
-
"@typescript-eslint/
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"eslint
|
|
46
|
-
"eslint-
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "resolve-accept-language",
|
|
3
|
+
"version": "1.1.15",
|
|
4
|
+
"description": "Resolve the preferred locale based on the value of an `Accept-Language` HTTP header.",
|
|
5
|
+
"author": "Avansai (https://avansai.com)",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/Avansai/resolve-accept-language.git"
|
|
9
|
+
},
|
|
10
|
+
"main": "lib/resolve-accept-language.js",
|
|
11
|
+
"types": "lib/resolve-accept-language.d.ts",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "npm run prettier && npm run lint-fix && rm -Rf ./lib && tsc && npm test",
|
|
14
|
+
"lint-fix": "eslint --ext .js --ext .jsx --ext .ts --ext .tsx --fix .",
|
|
15
|
+
"lint-check": "eslint --ext .js --ext .jsx --ext .ts --ext .tsx .",
|
|
16
|
+
"lint-print-config": "eslint --print-config ./eslintrc.yaml",
|
|
17
|
+
"prettier": "prettier --write .",
|
|
18
|
+
"test": "jest --coverage",
|
|
19
|
+
"release": "dotenv -- release-it --only-version"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"files": [
|
|
23
|
+
"lib"
|
|
24
|
+
],
|
|
25
|
+
"keywords": [
|
|
26
|
+
"accept-language",
|
|
27
|
+
"RFC 4647",
|
|
28
|
+
"locale",
|
|
29
|
+
"language tags",
|
|
30
|
+
"RFC 4646",
|
|
31
|
+
"BCP 47",
|
|
32
|
+
"RFC 2616",
|
|
33
|
+
"resolve",
|
|
34
|
+
"detect",
|
|
35
|
+
"intl",
|
|
36
|
+
"i18n",
|
|
37
|
+
"internationalization"
|
|
38
|
+
],
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@release-it/conventional-changelog": "^5.0.0",
|
|
41
|
+
"@types/jest": "^28.1.6",
|
|
42
|
+
"@typescript-eslint/eslint-plugin": "^5.33.0",
|
|
43
|
+
"@typescript-eslint/parser": "^5.33.0",
|
|
44
|
+
"dotenv-cli": "^6.0.0",
|
|
45
|
+
"eslint": "^8.21.0",
|
|
46
|
+
"eslint-config-prettier": "^8.5.0",
|
|
47
|
+
"eslint-import-resolver-node": "^0.3.6",
|
|
48
|
+
"eslint-import-resolver-typescript": "^3.4.0",
|
|
49
|
+
"eslint-plugin-import": "^2.26.0",
|
|
50
|
+
"eslint-plugin-jest": "^26.8.2",
|
|
51
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
52
|
+
"eslint-plugin-unicorn": "^43.0.2",
|
|
53
|
+
"jest": "^28.1.3",
|
|
54
|
+
"prettier": "^2.7.1",
|
|
55
|
+
"prettier-plugin-organize-imports": "^3.0.3",
|
|
56
|
+
"prettier-plugin-sh": "^0.12.8",
|
|
57
|
+
"release-it": "^15.3.0",
|
|
58
|
+
"ts-jest": "^28.0.7",
|
|
59
|
+
"ts-node": "^10.9.1",
|
|
60
|
+
"typescript": "^4.7.4"
|
|
61
|
+
}
|
|
62
|
+
}
|