resolve-accept-language 1.1.56 → 2.0.1
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/README.md +33 -30
- package/lib/locale-list.d.ts +2 -2
- package/lib/locale.d.ts +3 -2
- package/lib/lookup-list.d.ts +16 -17
- package/lib/lookup-list.js +53 -40
- package/lib/resolve-accept-language.d.ts +21 -35
- package/lib/resolve-accept-language.js +54 -84
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# resolve-accept-language
|
|
2
2
|
|
|
3
|
-
[](https://opensource.org/licenses/MIT)
|
|
4
|
-
[](https://www.npmjs.com/package/resolve-accept-language)
|
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://www.npmjs.com/package/resolve-accept-language)
|
|
5
5
|

|
|
6
|
-

|
|
7
7
|
[](https://snyk.io/test/github/Avansai/resolve-accept-language?targetFile=package.json)
|
|
8
8
|
|
|
9
|
-
Resolve the
|
|
9
|
+
Resolve the best locale based on the value of an `Accept-Language` HTTP header.
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
@@ -21,8 +21,20 @@ Code example:
|
|
|
21
21
|
```ts
|
|
22
22
|
import resolveAcceptLanguage from 'resolve-accept-language'
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* The API is well documented from within your IDE using TSDoc. The arguments are as follows:
|
|
26
|
+
*
|
|
27
|
+
* 1) The HTTP accept-language header.
|
|
28
|
+
* 2) The available locales (they must contain the default locale).
|
|
29
|
+
* 3) The default locale.
|
|
30
|
+
*/
|
|
24
31
|
console.log(
|
|
25
|
-
resolveAcceptLanguage(
|
|
32
|
+
resolveAcceptLanguage(
|
|
33
|
+
'fr-CA;q=0.01,en-CA;q=0.1,en-US;q=0.001',
|
|
34
|
+
// The `as const` is optional for TypeScript but gives better typing.
|
|
35
|
+
['en-US', 'fr-CA'] as const,
|
|
36
|
+
'en-US'
|
|
37
|
+
)
|
|
26
38
|
)
|
|
27
39
|
```
|
|
28
40
|
|
|
@@ -37,33 +49,24 @@ fr-CA
|
|
|
37
49
|
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
50
|
|
|
39
51
|
```ts
|
|
40
|
-
import { ResolveAcceptLanguage } from 'resolve-accept-language'
|
|
52
|
+
import { MATCH_TYPES, ResolveAcceptLanguage } from 'resolve-accept-language'
|
|
41
53
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
'fr-CA',
|
|
50
|
-
])
|
|
51
|
-
|
|
52
|
-
if (resolveAcceptLanguage.hasMatch()) {
|
|
53
|
-
const locale = resolveAcceptLanguage.getBestMatch() as string
|
|
54
|
-
console.log(`A locale was matched: ${locale}`)
|
|
55
|
-
|
|
56
|
-
if (resolveAcceptLanguage.bestMatchIsLocaleBased()) {
|
|
57
|
-
console.log('The match is locale-based')
|
|
58
|
-
} else if (resolveAcceptLanguage.bestMatchIsLanguageBased()) {
|
|
59
|
-
console.log('The match is language-based')
|
|
60
|
-
} else if (resolveAcceptLanguage.bestMatchIsRelatedLocaleBased()) {
|
|
61
|
-
console.log('The match is related-locale-based')
|
|
62
|
-
}
|
|
63
|
-
}
|
|
54
|
+
const resolveAcceptLanguage = new ResolveAcceptLanguage(
|
|
55
|
+
'fr-CA;q=0.01,en-CA;q=0.1,en-US;q=0.001' as const,
|
|
56
|
+
['en-US', 'fr-CA'],
|
|
57
|
+
'fr-CA'
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
console.log(`A locale was matched: ${resolveAcceptLanguage.getMatch()}`)
|
|
64
61
|
|
|
65
|
-
if (resolveAcceptLanguage.
|
|
66
|
-
console.log('
|
|
62
|
+
if (resolveAcceptLanguage.getMatchType() === MATCH_TYPES.localeBased) {
|
|
63
|
+
console.log('The match is locale-based')
|
|
64
|
+
} else if (resolveAcceptLanguage.getMatchType() === MATCH_TYPES.languageBased) {
|
|
65
|
+
console.log('The match is language-based')
|
|
66
|
+
} else if (resolveAcceptLanguage.getMatchType() === MATCH_TYPES.relatedLocaleBased) {
|
|
67
|
+
console.log('The match is related-locale-based')
|
|
68
|
+
} else if (resolveAcceptLanguage.getMatchType() === MATCH_TYPES.defaultLocale) {
|
|
69
|
+
console.log('The match is the default locale')
|
|
67
70
|
}
|
|
68
71
|
```
|
|
69
72
|
|
package/lib/locale-list.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Locale from './locale';
|
|
2
|
-
export default class LocaleList {
|
|
2
|
+
export default class LocaleList<TLocales extends readonly string[]> {
|
|
3
3
|
/** A set of ISO 3166-1 alpha-2 country codes. */
|
|
4
4
|
readonly countries: Set<string>;
|
|
5
5
|
/** A set of ISO 639-1 alpha-2 language codes. */
|
|
@@ -15,5 +15,5 @@ export default class LocaleList {
|
|
|
15
15
|
*
|
|
16
16
|
* @throws Will throw an error if one of the locale's format is invalid.
|
|
17
17
|
*/
|
|
18
|
-
constructor(locales: string[]);
|
|
18
|
+
constructor(locales: TLocales extends string[] ? TLocales[number][] : TLocales);
|
|
19
19
|
}
|
package/lib/locale.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { NormalizeLocale } from './resolve-accept-language';
|
|
1
2
|
/** Class to manage a locale identifier using the BCP 47 `language`-`country` format. */
|
|
2
|
-
export default class Locale {
|
|
3
|
+
export default class Locale<TLocale extends string = string> {
|
|
3
4
|
/** The ISO 3166-1 alpha-2 country code. */
|
|
4
5
|
readonly countryCode: string;
|
|
5
6
|
/** The locale identifier using the BCP 47 `language`-`country` case-normalized format. */
|
|
6
|
-
readonly identifier:
|
|
7
|
+
readonly identifier: NormalizeLocale<TLocale>;
|
|
7
8
|
/** The ISO 639-1 alpha-2 language code. */
|
|
8
9
|
readonly languageCode: string;
|
|
9
10
|
/**
|
package/lib/lookup-list.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { NormalizeLocale } from './resolve-accept-language';
|
|
1
2
|
/** Lookup list used to match the preferred locale based on the value of an `Accept-Language` HTTP header. */
|
|
2
|
-
export default class LookupList {
|
|
3
|
+
export default class LookupList<TLocales extends readonly string[]> {
|
|
3
4
|
/** The list of locales used to get the match during the lookup. */
|
|
4
5
|
private localeList;
|
|
5
6
|
/**
|
|
@@ -19,27 +20,25 @@ export default class LookupList {
|
|
|
19
20
|
* @param locales - An array of locale identifiers. The order will be used for matching where the first identifier will be more
|
|
20
21
|
* likely to be matched than the last identifier.
|
|
21
22
|
*/
|
|
22
|
-
constructor(acceptLanguageHeader: string, locales: string[]);
|
|
23
|
+
constructor(acceptLanguageHeader: string, locales: TLocales extends string[] ? TLocales[number][] : TLocales, defaultLocale: TLocales[number]);
|
|
23
24
|
/**
|
|
24
|
-
* Get the top
|
|
25
|
+
* Get the top locale-based match if available.
|
|
25
26
|
*
|
|
26
|
-
* @
|
|
27
|
-
*
|
|
28
|
-
* @returns The top locale with the specified language.
|
|
27
|
+
* @returns The top locale-based match or undefined when there is no match.
|
|
29
28
|
*/
|
|
30
|
-
|
|
29
|
+
getLocaleBasedMatch(): NormalizeLocale<TLocales[number]> | undefined;
|
|
31
30
|
/**
|
|
32
|
-
* Get the
|
|
31
|
+
* Get the language-based match if available.
|
|
33
32
|
*
|
|
34
|
-
* @returns The
|
|
33
|
+
* @returns The language-based match or undefined when there is no match.
|
|
35
34
|
*/
|
|
36
|
-
|
|
35
|
+
getLanguageBasedMatch(): NormalizeLocale<TLocales[number]> | undefined;
|
|
37
36
|
/**
|
|
38
|
-
* Get the
|
|
37
|
+
* Get the related-locale-based match if available.
|
|
39
38
|
*
|
|
40
|
-
* @returns The
|
|
39
|
+
* @returns The related-locale-based match or undefined when there is no match.
|
|
41
40
|
*/
|
|
42
|
-
|
|
41
|
+
getRelatedLocaleBasedMatch(): NormalizeLocale<TLocales[number]> | undefined;
|
|
43
42
|
/**
|
|
44
43
|
* Add a language in the data object matching its quality.
|
|
45
44
|
*
|
|
@@ -70,11 +69,11 @@ export default class LookupList {
|
|
|
70
69
|
*/
|
|
71
70
|
private getDirective;
|
|
72
71
|
/**
|
|
73
|
-
* Get
|
|
72
|
+
* Get a match from a data object.
|
|
74
73
|
*
|
|
75
|
-
* @param
|
|
74
|
+
* @param dataObject - A data object.
|
|
76
75
|
*
|
|
77
|
-
* @returns
|
|
76
|
+
* @returns A match or undefined when there is no match.
|
|
78
77
|
*/
|
|
79
|
-
private
|
|
78
|
+
private getMatch;
|
|
80
79
|
}
|
package/lib/lookup-list.js
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
3
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
4
|
+
if (ar || !(i in from)) {
|
|
5
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
6
|
+
ar[i] = from[i];
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
10
|
+
};
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
var locale_1 = require("./locale");
|
|
3
13
|
var locale_list_1 = require("./locale-list");
|
|
4
14
|
/** Lookup list used to match the preferred locale based on the value of an `Accept-Language` HTTP header. */
|
|
5
15
|
var LookupList = /** @class */ (function () {
|
|
@@ -10,7 +20,8 @@ var LookupList = /** @class */ (function () {
|
|
|
10
20
|
* @param locales - An array of locale identifiers. The order will be used for matching where the first identifier will be more
|
|
11
21
|
* likely to be matched than the last identifier.
|
|
12
22
|
*/
|
|
13
|
-
function LookupList(acceptLanguageHeader, locales) {
|
|
23
|
+
function LookupList(acceptLanguageHeader, locales, defaultLocale) {
|
|
24
|
+
var _this = this;
|
|
14
25
|
/**
|
|
15
26
|
* Data object where the properties are quality (in string format) and their values a set containing locale
|
|
16
27
|
* identifiers using the `language`-`country` format and ISO 639-1 alpha-2 language code.
|
|
@@ -21,16 +32,16 @@ var LookupList = /** @class */ (function () {
|
|
|
21
32
|
* language code.
|
|
22
33
|
*/
|
|
23
34
|
this.relatedLocaleLanguagesByQuality = {};
|
|
24
|
-
|
|
25
|
-
|
|
35
|
+
// Put the default locale first so that it will be more likely to be matched.
|
|
36
|
+
this.localeList = new locale_list_1.default(__spreadArray([
|
|
37
|
+
defaultLocale
|
|
38
|
+
], locales.filter(function (locale) { return locale !== defaultLocale; }), true));
|
|
39
|
+
var directives = acceptLanguageHeader
|
|
26
40
|
.split(',')
|
|
27
|
-
.map(function (directiveString) { return directiveString.trim(); })
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
var directive =
|
|
31
|
-
if (directive === undefined) {
|
|
32
|
-
continue; // No match for this directive.
|
|
33
|
-
}
|
|
41
|
+
.map(function (directiveString) { return _this.getDirective(directiveString.trim()); })
|
|
42
|
+
.filter(function (directive) { return directive !== undefined; });
|
|
43
|
+
for (var _i = 0, directives_1 = directives; _i < directives_1.length; _i++) {
|
|
44
|
+
var directive = directives_1[_i];
|
|
34
45
|
var locale = directive.locale, languageCode = directive.languageCode, quality = directive.quality;
|
|
35
46
|
// If the language is not supported, skip to the next match.
|
|
36
47
|
if (!this.localeList.languages.has(languageCode)) {
|
|
@@ -51,40 +62,39 @@ var LookupList = /** @class */ (function () {
|
|
|
51
62
|
}
|
|
52
63
|
}
|
|
53
64
|
/**
|
|
54
|
-
* Get the top
|
|
65
|
+
* Get the top locale-based match if available.
|
|
55
66
|
*
|
|
56
|
-
* @
|
|
57
|
-
*
|
|
58
|
-
* @returns The top locale with the specified language.
|
|
67
|
+
* @returns The top locale-based match or undefined when there is no match.
|
|
59
68
|
*/
|
|
60
|
-
LookupList.prototype.
|
|
61
|
-
var
|
|
62
|
-
return
|
|
69
|
+
LookupList.prototype.getLocaleBasedMatch = function () {
|
|
70
|
+
var match = this.getMatch(this.localesAndLanguagesByQuality);
|
|
71
|
+
return match && locale_1.default.isLocale(match)
|
|
72
|
+
? match
|
|
73
|
+
: undefined;
|
|
63
74
|
};
|
|
64
75
|
/**
|
|
65
|
-
* Get the
|
|
76
|
+
* Get the language-based match if available.
|
|
66
77
|
*
|
|
67
|
-
* @returns The
|
|
78
|
+
* @returns The language-based match or undefined when there is no match.
|
|
68
79
|
*/
|
|
69
|
-
LookupList.prototype.
|
|
70
|
-
var
|
|
71
|
-
|
|
72
|
-
return
|
|
73
|
-
|
|
74
|
-
|
|
80
|
+
LookupList.prototype.getLanguageBasedMatch = function () {
|
|
81
|
+
var match = this.getMatch(this.localesAndLanguagesByQuality);
|
|
82
|
+
return match && !locale_1.default.isLocale(match)
|
|
83
|
+
? this.localeList.objects.find(function (locale) { return locale.languageCode === match; })
|
|
84
|
+
.identifier
|
|
85
|
+
: undefined;
|
|
75
86
|
};
|
|
76
87
|
/**
|
|
77
|
-
* Get the
|
|
88
|
+
* Get the related-locale-based match if available.
|
|
78
89
|
*
|
|
79
|
-
* @returns The
|
|
90
|
+
* @returns The related-locale-based match or undefined when there is no match.
|
|
80
91
|
*/
|
|
81
|
-
LookupList.prototype.
|
|
82
|
-
var
|
|
83
|
-
|
|
84
|
-
return
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return this.getTopByLanguage(topRelatedLocaleLanguage);
|
|
92
|
+
LookupList.prototype.getRelatedLocaleBasedMatch = function () {
|
|
93
|
+
var match = this.getMatch(this.relatedLocaleLanguagesByQuality);
|
|
94
|
+
return match
|
|
95
|
+
? this.localeList.objects.find(function (locale) { return locale.languageCode === match; })
|
|
96
|
+
.identifier
|
|
97
|
+
: undefined;
|
|
88
98
|
};
|
|
89
99
|
/**
|
|
90
100
|
* Add a language in the data object matching its quality.
|
|
@@ -135,7 +145,7 @@ var LookupList = /** @class */ (function () {
|
|
|
135
145
|
* browsers today (also those options seem unpractical):
|
|
136
146
|
*
|
|
137
147
|
* - The wildcard character "*", as per RFC 2616 (section 14.4), should match any unmatched language tag.
|
|
138
|
-
* - Language tags that starts with a wildcard (e.g
|
|
148
|
+
* - Language tags that starts with a wildcard (e.g., "*-CA") should match the first supported locale of a country.
|
|
139
149
|
* - A quality value equivalent to "0", as per RFC 2616 (section 3.9), should be considered as "not acceptable".
|
|
140
150
|
*/
|
|
141
151
|
var directiveMatch = directiveString.match(/^((?<matchedLanguageCode>([a-z]{2}))(-(?<matchedCountryCode>[a-z]{2}))?)(;q=(?<matchedQuality>(1(\.0{0,3})?)|(0(\.\d{0,3})?)))?$/i);
|
|
@@ -150,14 +160,17 @@ var LookupList = /** @class */ (function () {
|
|
|
150
160
|
return { languageCode: languageCode, locale: locale, quality: quality };
|
|
151
161
|
};
|
|
152
162
|
/**
|
|
153
|
-
* Get
|
|
163
|
+
* Get a match from a data object.
|
|
154
164
|
*
|
|
155
|
-
* @param
|
|
165
|
+
* @param dataObject - A data object.
|
|
156
166
|
*
|
|
157
|
-
* @returns
|
|
167
|
+
* @returns A match or undefined when there is no match.
|
|
158
168
|
*/
|
|
159
|
-
LookupList.prototype.
|
|
160
|
-
|
|
169
|
+
LookupList.prototype.getMatch = function (dataObject) {
|
|
170
|
+
var dataObjectEntries = Object.entries(dataObject);
|
|
171
|
+
return dataObjectEntries.length === 0
|
|
172
|
+
? undefined
|
|
173
|
+
: dataObjectEntries.sort().reverse()[0][1].values().next().value;
|
|
161
174
|
};
|
|
162
175
|
return LookupList;
|
|
163
176
|
}());
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
+
/** The type matches. */
|
|
2
|
+
export type MatchType = 'localeBased' | 'languageBased' | 'relatedLocaleBased' | 'defaultLocale';
|
|
3
|
+
/** Match type enumeration. */
|
|
4
|
+
export declare const MATCH_TYPES: {
|
|
5
|
+
readonly [K in MatchType]: K;
|
|
6
|
+
};
|
|
7
|
+
/** Type to normalize the locale format. */
|
|
8
|
+
export type NormalizeLocale<Remainder extends string> = Remainder extends `${infer LanguageCode}-${infer CountryCode}` ? `${Lowercase<LanguageCode>}-${Uppercase<CountryCode>}` : Remainder;
|
|
1
9
|
/** Resolve the preferred locale from an HTTP `Accept-Language` header. */
|
|
2
|
-
export declare class ResolveAcceptLanguage {
|
|
3
|
-
/** The
|
|
4
|
-
private
|
|
10
|
+
export declare class ResolveAcceptLanguage<TLocales extends readonly string[] = string[]> {
|
|
11
|
+
/** The default locale. */
|
|
12
|
+
private defaultLocale;
|
|
5
13
|
/** The locale-based match, if applicable. */
|
|
6
14
|
private localeBasedMatch;
|
|
15
|
+
/** The language-based match, if applicable. */
|
|
16
|
+
private languageBasedMatch;
|
|
7
17
|
/** The related-locale-based match, if applicable. */
|
|
8
18
|
private relatedLocaleBasedMatch;
|
|
9
19
|
/**
|
|
@@ -15,43 +25,19 @@ export declare class ResolveAcceptLanguage {
|
|
|
15
25
|
* @param locales - An array of locale identifiers. The order will be used for matching where the first identifier will be more
|
|
16
26
|
* likely to be matched than the last identifier.
|
|
17
27
|
*/
|
|
18
|
-
constructor(acceptLanguageHeader: string, locales: string[]);
|
|
19
|
-
/**
|
|
20
|
-
* Is the best match language-based?
|
|
21
|
-
*
|
|
22
|
-
* @returns True if the best match language-based, otherwise false.
|
|
23
|
-
*/
|
|
24
|
-
bestMatchIsLanguageBased(): boolean;
|
|
25
|
-
/**
|
|
26
|
-
* Is the best match locale-based?
|
|
27
|
-
*
|
|
28
|
-
* @returns True if the best match locale-based, otherwise false.
|
|
29
|
-
*/
|
|
30
|
-
bestMatchIsLocaleBased(): boolean;
|
|
31
|
-
/**
|
|
32
|
-
* Is the best match related-locale-based?
|
|
33
|
-
*
|
|
34
|
-
* @returns True if the best match related-locale-based, otherwise false.
|
|
35
|
-
*/
|
|
36
|
-
bestMatchIsRelatedLocaleBased(): boolean;
|
|
37
|
-
/**
|
|
38
|
-
* Get the locale which was the best match.
|
|
39
|
-
*
|
|
40
|
-
* @returns The locale which was the best match.
|
|
41
|
-
*/
|
|
42
|
-
getBestMatch(): string | undefined;
|
|
28
|
+
constructor(acceptLanguageHeader: string, locales: TLocales extends string[] ? TLocales[number][] : TLocales, defaultLocale: TLocales[number]);
|
|
43
29
|
/**
|
|
44
|
-
*
|
|
30
|
+
* Get the type of match.
|
|
45
31
|
*
|
|
46
|
-
* @returns
|
|
32
|
+
* @returns The type of match.
|
|
47
33
|
*/
|
|
48
|
-
|
|
34
|
+
getMatchType(): MatchType;
|
|
49
35
|
/**
|
|
50
|
-
*
|
|
36
|
+
* Get the matching locale.
|
|
51
37
|
*
|
|
52
|
-
* @returns
|
|
38
|
+
* @returns The matching locale.
|
|
53
39
|
*/
|
|
54
|
-
|
|
40
|
+
getMatch(): NormalizeLocale<TLocales[number]>;
|
|
55
41
|
}
|
|
56
42
|
/**
|
|
57
43
|
* Resolve the preferred locale from an HTTP `Accept-Language` header.
|
|
@@ -73,5 +59,5 @@ export declare class ResolveAcceptLanguage {
|
|
|
73
59
|
* 'en-US'
|
|
74
60
|
* )
|
|
75
61
|
*/
|
|
76
|
-
declare const resolveAcceptLanguage: <TLocales extends readonly string[]>(acceptLanguageHeader: string, locales: TLocales extends string[] ? TLocales[number][] : TLocales, defaultLocale: TLocales[number]) => TLocales[number]
|
|
62
|
+
declare const resolveAcceptLanguage: <TLocales extends readonly string[]>(acceptLanguageHeader: string, locales: TLocales extends string[] ? TLocales[number][] : TLocales, defaultLocale: TLocales[number]) => NormalizeLocale<TLocales[number]>;
|
|
77
63
|
export default resolveAcceptLanguage;
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
3
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
4
|
-
if (ar || !(i in from)) {
|
|
5
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
6
|
-
ar[i] = from[i];
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.ResolveAcceptLanguage = void 0;
|
|
3
|
+
exports.ResolveAcceptLanguage = exports.MATCH_TYPES = void 0;
|
|
13
4
|
var locale_1 = require("./locale");
|
|
14
5
|
var lookup_list_1 = require("./lookup-list");
|
|
6
|
+
/** Match type enumeration. */
|
|
7
|
+
exports.MATCH_TYPES = {
|
|
8
|
+
localeBased: 'localeBased',
|
|
9
|
+
languageBased: 'languageBased',
|
|
10
|
+
relatedLocaleBased: 'relatedLocaleBased',
|
|
11
|
+
defaultLocale: 'defaultLocale',
|
|
12
|
+
};
|
|
15
13
|
/** Resolve the preferred locale from an HTTP `Accept-Language` header. */
|
|
16
14
|
var ResolveAcceptLanguage = /** @class */ (function () {
|
|
17
15
|
/**
|
|
@@ -23,69 +21,61 @@ var ResolveAcceptLanguage = /** @class */ (function () {
|
|
|
23
21
|
* @param locales - An array of locale identifiers. The order will be used for matching where the first identifier will be more
|
|
24
22
|
* likely to be matched than the last identifier.
|
|
25
23
|
*/
|
|
26
|
-
function ResolveAcceptLanguage(acceptLanguageHeader, locales) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
if (locale_1.default.isLocale(topLocaleOrLanguage)) {
|
|
34
|
-
this.localeBasedMatch = topLocaleOrLanguage;
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
this.languageBasedMatch = lookupList.getTopByLanguage(topLocaleOrLanguage);
|
|
24
|
+
function ResolveAcceptLanguage(acceptLanguageHeader, locales, defaultLocale) {
|
|
25
|
+
// Check if the locales are valid.
|
|
26
|
+
locales.forEach(function (locale) {
|
|
27
|
+
if (!locale_1.default.isLocale(locale, false)) {
|
|
28
|
+
throw new Error("invalid locale identifier '".concat(locale, "'"));
|
|
38
29
|
}
|
|
30
|
+
});
|
|
31
|
+
// Check if the default locale is valid.
|
|
32
|
+
if (!locale_1.default.isLocale(defaultLocale, false)) {
|
|
33
|
+
throw new Error("invalid default locale identifier '".concat(defaultLocale, "'"));
|
|
34
|
+
}
|
|
35
|
+
// Check if the default locale is included in the locales.
|
|
36
|
+
if (!locales.some(function (locale) { return locale.toLowerCase() === defaultLocale.toLowerCase(); })) {
|
|
37
|
+
throw new Error('the default locale must be included in the locales');
|
|
38
|
+
}
|
|
39
|
+
this.defaultLocale = new locale_1.default(defaultLocale).identifier;
|
|
40
|
+
var lookupList = new lookup_list_1.default(acceptLanguageHeader, locales, defaultLocale);
|
|
41
|
+
// Check if the match if locale based.
|
|
42
|
+
this.localeBasedMatch = lookupList.getLocaleBasedMatch();
|
|
43
|
+
if (this.localeBasedMatch) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
// Check if the match is language based.
|
|
47
|
+
this.languageBasedMatch = lookupList.getLanguageBasedMatch();
|
|
48
|
+
if (this.languageBasedMatch) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// Check if the match is related-locale based.
|
|
52
|
+
this.relatedLocaleBasedMatch = lookupList.getRelatedLocaleBasedMatch();
|
|
53
|
+
if (this.relatedLocaleBasedMatch) {
|
|
54
|
+
return;
|
|
39
55
|
}
|
|
40
56
|
}
|
|
41
57
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* @returns True if the best match language-based, otherwise false.
|
|
45
|
-
*/
|
|
46
|
-
ResolveAcceptLanguage.prototype.bestMatchIsLanguageBased = function () {
|
|
47
|
-
return this.languageBasedMatch !== undefined;
|
|
48
|
-
};
|
|
49
|
-
/**
|
|
50
|
-
* Is the best match locale-based?
|
|
58
|
+
* Get the type of match.
|
|
51
59
|
*
|
|
52
|
-
* @returns
|
|
60
|
+
* @returns The type of match.
|
|
53
61
|
*/
|
|
54
|
-
ResolveAcceptLanguage.prototype.
|
|
55
|
-
return this.localeBasedMatch
|
|
62
|
+
ResolveAcceptLanguage.prototype.getMatchType = function () {
|
|
63
|
+
return this.localeBasedMatch
|
|
64
|
+
? exports.MATCH_TYPES.localeBased
|
|
65
|
+
: this.languageBasedMatch
|
|
66
|
+
? exports.MATCH_TYPES.languageBased
|
|
67
|
+
: this.relatedLocaleBasedMatch
|
|
68
|
+
? exports.MATCH_TYPES.relatedLocaleBased
|
|
69
|
+
: exports.MATCH_TYPES.defaultLocale;
|
|
56
70
|
};
|
|
57
71
|
/**
|
|
58
|
-
*
|
|
72
|
+
* Get the matching locale.
|
|
59
73
|
*
|
|
60
|
-
* @returns
|
|
74
|
+
* @returns The matching locale.
|
|
61
75
|
*/
|
|
62
|
-
ResolveAcceptLanguage.prototype.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Get the locale which was the best match.
|
|
67
|
-
*
|
|
68
|
-
* @returns The locale which was the best match.
|
|
69
|
-
*/
|
|
70
|
-
ResolveAcceptLanguage.prototype.getBestMatch = function () {
|
|
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 ? false : true;
|
|
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();
|
|
76
|
+
ResolveAcceptLanguage.prototype.getMatch = function () {
|
|
77
|
+
var _a, _b, _c;
|
|
78
|
+
return ((_c = (_b = (_a = this.localeBasedMatch) !== null && _a !== void 0 ? _a : this.languageBasedMatch) !== null && _b !== void 0 ? _b : this.relatedLocaleBasedMatch) !== null && _c !== void 0 ? _c : this.defaultLocale);
|
|
89
79
|
};
|
|
90
80
|
return ResolveAcceptLanguage;
|
|
91
81
|
}());
|
|
@@ -111,26 +101,6 @@ exports.ResolveAcceptLanguage = ResolveAcceptLanguage;
|
|
|
111
101
|
* )
|
|
112
102
|
*/
|
|
113
103
|
var resolveAcceptLanguage = function (acceptLanguageHeader, locales, defaultLocale) {
|
|
114
|
-
|
|
115
|
-
locales.forEach(function (locale) {
|
|
116
|
-
if (!locale_1.default.isLocale(locale, false)) {
|
|
117
|
-
throw new Error("invalid locale identifier '".concat(locale, "'"));
|
|
118
|
-
}
|
|
119
|
-
if (locale.toLowerCase() === defaultLocale.toLocaleLowerCase()) {
|
|
120
|
-
localesIncludeDefault = true;
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
if (!locale_1.default.isLocale(defaultLocale, false)) {
|
|
124
|
-
throw new Error("invalid default locale identifier '".concat(defaultLocale, "'"));
|
|
125
|
-
}
|
|
126
|
-
if (!localesIncludeDefault) {
|
|
127
|
-
throw new Error('the default locale must be included in the locales');
|
|
128
|
-
}
|
|
129
|
-
var rankedLocales = __spreadArray([defaultLocale], locales.filter(function (locale) { return locale !== defaultLocale; }), true);
|
|
130
|
-
var resolveAcceptLanguage = new ResolveAcceptLanguage(acceptLanguageHeader, rankedLocales);
|
|
131
|
-
if (resolveAcceptLanguage.hasMatch()) {
|
|
132
|
-
return resolveAcceptLanguage.getBestMatch();
|
|
133
|
-
}
|
|
134
|
-
return new locale_1.default(defaultLocale).identifier;
|
|
104
|
+
return new ResolveAcceptLanguage(acceptLanguageHeader, locales, defaultLocale).getMatch();
|
|
135
105
|
};
|
|
136
106
|
exports.default = resolveAcceptLanguage;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "resolve-accept-language",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Resolve the preferred locale based on the value of an `Accept-Language` HTTP header.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accept-language",
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@release-it/conventional-changelog": "5.1.1",
|
|
41
41
|
"@types/jest": "29.5.1",
|
|
42
|
-
"@typescript-eslint/eslint-plugin": "5.59.
|
|
43
|
-
"@typescript-eslint/parser": "5.59.
|
|
42
|
+
"@typescript-eslint/eslint-plugin": "5.59.6",
|
|
43
|
+
"@typescript-eslint/parser": "5.59.6",
|
|
44
44
|
"dotenv-cli": "7.2.1",
|
|
45
|
-
"eslint": "8.
|
|
45
|
+
"eslint": "8.41.0",
|
|
46
46
|
"eslint-config-prettier": "8.8.0",
|
|
47
47
|
"eslint-import-resolver-node": "0.3.7",
|
|
48
48
|
"eslint-import-resolver-typescript": "3.5.5",
|