resolve-accept-language 2.2.0 → 3.1.0

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 CHANGED
@@ -9,6 +9,8 @@ Resolve the best locale based on the value of an `Accept-Language` HTTP header.
9
9
 
10
10
  ## Usage
11
11
 
12
+ > ⚠ In March 2024, version 3 of this package was released, which includes breaking changes. Please refer to the [upgrade guide](./V2-TO-V3-UPGRADE-GUIDE.md) before upgrading.
13
+
12
14
  Add the package as a dependency:
13
15
 
14
16
  ```
@@ -18,7 +20,7 @@ npm install resolve-accept-language
18
20
  Code example:
19
21
 
20
22
  ```ts
21
- import resolveAcceptLanguage from 'resolve-accept-language'
23
+ import { resolveAcceptLanguage } from 'resolve-accept-language'
22
24
 
23
25
  /**
24
26
  * The API is well documented from within your IDE using TSDoc. The arguments are as follows:
@@ -45,44 +47,78 @@ fr-CA
45
47
 
46
48
  ## Advanced use cases
47
49
 
48
- 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:
50
+ ### Match types
51
+
52
+ You may want to control exactly the behavior depending on the type of match. For example, you might 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 `{ returnMatchType: true }` option. It offers more visibility into the selection process while matching a locale:
49
53
 
50
54
  ```ts
51
- import { MATCH_TYPES, ResolveAcceptLanguage } from 'resolve-accept-language'
55
+ import { MATCH_TYPES, resolveAcceptLanguage } from 'resolve-accept-language'
52
56
 
53
- const resolveAcceptLanguage = new ResolveAcceptLanguage(
57
+ const { match, matchType } = resolveAcceptLanguage(
54
58
  'fr-CA;q=0.01,en-CA;q=0.1,en-US;q=0.001' as const,
55
59
  ['en-US', 'fr-CA'],
56
- 'fr-CA'
60
+ 'fr-CA',
61
+ { returnMatchType: true }
57
62
  )
58
63
 
59
- console.log(`A locale was matched: ${resolveAcceptLanguage.getMatch()}`)
64
+ console.log(`A locale was matched: ${match}`)
60
65
 
61
- if (resolveAcceptLanguage.getMatchType() === MATCH_TYPES.localeBased) {
66
+ if (matchType === MATCH_TYPES.locale) {
62
67
  console.log('The match is locale-based')
63
- } else if (resolveAcceptLanguage.getMatchType() === MATCH_TYPES.languageBased) {
68
+ } else if (matchType === MATCH_TYPES.languageSpecificLocale) {
69
+ console.log('The match is language specific locale-based')
70
+ } else if (matchType === MATCH_TYPES.language) {
64
71
  console.log('The match is language-based')
65
- } else if (resolveAcceptLanguage.getMatchType() === MATCH_TYPES.relatedLocaleBased) {
72
+ } else if (matchType === MATCH_TYPES.relatedLocale) {
66
73
  console.log('The match is related-locale-based')
67
- } else if (resolveAcceptLanguage.getMatchType() === MATCH_TYPES.defaultLocale) {
74
+ } else if (matchType === MATCH_TYPES.languageCountry) {
75
+ console.log('The match is language country-based')
76
+ } else if (matchType === MATCH_TYPES.defaultLocale) {
68
77
  console.log('The match is the default locale')
69
78
  }
70
79
  ```
71
80
 
81
+ ### Country match
82
+
83
+ There may be cases where it is preferred to perform a "country match" before falling back to the default locale match. For example:
84
+
85
+ ```ts
86
+ console.log(
87
+ resolveAcceptLanguage('af-ZA', ['en-US', 'zu-ZA'] as const, 'en-US', {
88
+ returnMatchType: true,
89
+ matchCountry: true,
90
+ })
91
+ )
92
+ ```
93
+
94
+ Output:
95
+
96
+ ```json
97
+ { "match": "zu-ZA", "matchType": "country" }
98
+ ```
99
+
100
+ In this case, the header prefers `af-ZA`, which shares the same country as `zu-ZA`. Instead of falling back to the default `en-US`, `zu-ZA` is matched.
101
+
102
+ This behavior is not set by default because, in most cases, the quality of the default locale is better than the translations. Performing a country match could potentially lower the quality of the selection. However, there may be cases where this is not true, which is why the `matchCountry` option exists.
103
+
72
104
  ## How does the resolver work?
73
105
 
74
106
  As per RFC 4647, this package uses the "lookup" matching scheme. This means that it will always produce exactly one match for a given request.
75
107
 
76
- The matching strategy will use the following logic:
108
+ The matching strategy follows these steps, in order:
109
+
110
+ 1. Start with the default locale, as it's considered the highest quality content available.
111
+ 2. Extract all locales and languages from the HTTP header, sorted by quality factor and position in the header. Each of these elements is referred to as a "directive".
112
+ 3. Perform matching in several stages:
113
+ 1. **Locale Match**: Look for an exact locale match in the directives.
114
+ 2. **Language-Specific Locale Match**: If no locale match is found, look for a locale that matches the language of the directive.
115
+ 3. **Language Match**: If no language-specific locale match is found, look for a locale that matches the language.
116
+ 4. **Related-Locale Match**: If no language match is found, look for a locale that matches the language in the next round of directives.
117
+ 5. **Language Country Match**: If no related-locale match is found, look for a locale that matches the default locale's language but in a country from a locale specified in a directive.
118
+ 6. **Country Match**: If the option is enabled and no language country match is found, look for a locale that matches the country in the next round of directives.
119
+ 7. **Default Locale Match**: If all else fails, fall back to the default locale.
77
120
 
78
- 1. The default locale (when provided) will always be put as the first locale being evaluated since it is considered the highest quality content available. Otherwise, the locales will be evaluated in the order provided, where the first is the highest quality and the last the lowest.
79
- 2. All locales and languages are extracted from the HTTP header and sorted by quality factor. Locales and languages that are in the HTTP header but not in scope are discarded.
80
- 3. Three different matching patterns (based on the HTTP header's quality factor and order of the provided locales):
81
- 1. If there were any matches, get the highest-ranked (quality factor) locale or language code:
82
- 1. **Locale-based match**: Is the highest-ranked a locale? If yes, this is the best match.
83
- 2. **Language-based match**: Otherwise, find the first locale that matches the highest-ranked language.
84
- 2. **Related-locale-based match**: If there is no match, find the first locale with a language that matches the highest-ranked language of locales that were not in scope. This is a bit of a "fuzzy match", but the presumption is that it's better to show content in a language that can be understood even if the country is wrong.
85
- 4. When using `resolveAcceptLanguage` return the default locale as a last resort option.
121
+ Each stage only happens if the previous stage didn't find a match. This ensures the best possible match is found according to the given criteria.
86
122
 
87
123
  ## Why another `Accept-Language` package?
88
124
 
@@ -0,0 +1,29 @@
1
+ /** An object representing an HTTP `Accept-Language` header directive. */
2
+ type Directive = {
3
+ /** The ISO 639-1 alpha-2 language code. */
4
+ languageCode: string;
5
+ /** The ISO 3166-1 alpha-2 country code. */
6
+ countryCode?: string;
7
+ /** The locale identifier using the BCP 47 `language`-`country` in case-normalized format. */
8
+ locale?: string;
9
+ /** The quality factor (default is 1; values can range from 0 to 1 with up to 3 decimals). */
10
+ quality: number;
11
+ };
12
+ /** A directive object including the position in its HTTP header. */
13
+ type IndexedDirective = Directive & {
14
+ /** This is the position of the directive in the HTTP header. */
15
+ headerPosition: number;
16
+ };
17
+ /** A directive object including the position in its HTTP header and the locale. */
18
+ export type IndexedDirectiveWithLocale = IndexedDirective & {
19
+ locale: string;
20
+ };
21
+ /**
22
+ * Get a list of directives from an HTTP `Accept-Language` header.
23
+ *
24
+ * @param acceptLanguageHeader - The value of an HTTP request `Accept-Language` header (also known as a "language priority list").
25
+ *
26
+ * @returns A list of `IndexedDirective` objects sorted by quality and header position.
27
+ */
28
+ export declare const getDirectives: (acceptLanguageHeader: string) => IndexedDirective[];
29
+ export {};
@@ -0,0 +1 @@
1
+ "use strict";var __assign=this&&this.__assign||function(){return __assign=Object.assign||function(e){for(var r,t=1,a=arguments.length;t<a;t++)for(var i in r=arguments[t])Object.prototype.hasOwnProperty.call(r,i)&&(e[i]=r[i]);return e},__assign.apply(this,arguments)},__read=this&&this.__read||function(e,r){var t="function"==typeof Symbol&&e[Symbol.iterator];if(!t)return e;var a,i,o=t.call(e),n=[];try{for(;(void 0===r||r-- >0)&&!(a=o.next()).done;)n.push(a.value)}catch(e){i={error:e}}finally{try{a&&!a.done&&(t=o.return)&&t.call(o)}finally{if(i)throw i.error}}return n},__spreadArray=this&&this.__spreadArray||function(e,r,t){if(t||2===arguments.length)for(var a,i=0,o=r.length;i<o;i++)!a&&i in r||(a||(a=Array.prototype.slice.call(r,0,i)),a[i]=r[i]);return e.concat(a||Array.prototype.slice.call(r))};Object.defineProperty(exports,"__esModule",{value:!0}),exports.getDirectives=void 0;var getDirective=function(e){var r=e.match(/^((?<matchedLanguageCode>([a-z]{2}))(-(?<matchedCountryCode>[a-z]{2}|419))?)(;q=(?<matchedQuality>(1(\.0{0,3})?)|(0(\.\d{0,3})?)))?$/i);if(null==r?void 0:r.groups){var t=r.groups,a=t.matchedLanguageCode,i=t.matchedCountryCode,o=t.matchedQuality,n=a.toLowerCase(),s=i?i.toUpperCase():void 0;if("419"!==s||"es"===n){var c=void 0===o?1:Number.parseFloat(o);return{languageCode:n,countryCode:s,locale:s?"".concat(n,"-").concat(s):void 0,quality:c}}}},getDirectives=function(e){var r=[],t=0;e.split(",").forEach((function(e){var a=getDirective(e.trim());a&&(r.some((function(e){return e.languageCode===a.languageCode&&e.locale===a.locale}))||(r.push(__assign(__assign({},a),{headerPosition:t})),t++))}));var a=r.findIndex((function(e){return"es-419"===e.locale}));if(a>=0){var i=r[a],o=["es-AR","es-CL","es-CO","es-CR","es-HN","es-MX","es-PE","es-US","es-UY","es-VE"].map((function(e){return __assign(__assign({},i),{locale:e})}));r.splice.apply(r,__spreadArray([a,1],__read(o),!1))}return r.sort((function(e,r){var t=r.quality-e.quality;return t||e.headerPosition-r.headerPosition}))};exports.getDirectives=getDirectives;
@@ -0,0 +1,44 @@
1
+ /** The type of matches. */
2
+ export type MatchType = 'locale' | 'languageSpecificLocale' | 'language' | 'relatedLocale' | 'languageCountry' | 'country' | 'defaultLocale';
3
+ /** The type of matches 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;
9
+ /** Additional options to apply. */
10
+ type Options<WithMatchType extends boolean | undefined> = {
11
+ /** Should the match type be returned? */
12
+ returnMatchType?: WithMatchType;
13
+ /** Should the country of the locale be used for matching? */
14
+ matchCountry?: boolean;
15
+ };
16
+ type Result<Locales extends string[], WithMatchType extends boolean | undefined> = WithMatchType extends true ? {
17
+ /** The best locale match. */
18
+ match: NormalizeLocale<Locales[number]>;
19
+ /** The type of match. */
20
+ matchType: MatchType;
21
+ } : NormalizeLocale<Locales[number]>;
22
+ /**
23
+ * Resolve the preferred locale from an HTTP `Accept-Language` header.
24
+ *
25
+ * All locale identifiers provided as parameters must following the BCP 47 `language`-`country` (case insensitive).
26
+ *
27
+ * @param acceptLanguageHeader - The value of an HTTP request `Accept-Language` header (also known as a "language priority list").
28
+ * @param locales - An array of locale identifiers that must include the default locale. The order will be used for matching where
29
+ * the first identifier will be more likely to be matched than the last identifier.
30
+ * @param defaultLocale - The default locale identifier when no match is found.
31
+ * @param options - Additional options to apply.
32
+ *
33
+ * @returns Either the best locale match or a match object, depending on options.
34
+ *
35
+ * @example
36
+ * // returns 'fr-CA'
37
+ * resolveAcceptLanguage(
38
+ * 'fr-CA;q=0.01,en-CA;q=0.1,en-US;q=0.001',
39
+ * ['en-US', 'fr-CA'],
40
+ * 'en-US'
41
+ * )
42
+ */
43
+ export declare const resolveAcceptLanguage: <Locales extends string[], WithMatchType extends boolean | undefined = undefined>(acceptLanguageHeader: string, locales: Locales, defaultLocale: Locales[number], options?: Options<WithMatchType> | undefined) => Result<Locales, WithMatchType>;
44
+ export {};
@@ -0,0 +1 @@
1
+ "use strict";var __read=this&&this.__read||function(e,r){var a="function"==typeof Symbol&&e[Symbol.iterator];if(!a)return e;var t,o,n=a.call(e),l=[];try{for(;(void 0===r||r-- >0)&&!(t=n.next()).done;)l.push(t.value)}catch(e){o={error:e}}finally{try{t&&!t.done&&(a=n.return)&&a.call(n)}finally{if(o)throw o.error}}return l},__spreadArray=this&&this.__spreadArray||function(e,r,a){if(a||2===arguments.length)for(var t,o=0,n=r.length;o<n;o++)!t&&o in r||(t||(t=Array.prototype.slice.call(r,0,o)),t[o]=r[o]);return e.concat(t||Array.prototype.slice.call(r))},__values=this&&this.__values||function(e){var r="function"==typeof Symbol&&Symbol.iterator,a=r&&e[r],t=0;if(a)return a.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&t>=e.length&&(e=void 0),{value:e&&e[t++],done:!e}}};throw new TypeError(r?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(exports,"__esModule",{value:!0}),exports.resolveAcceptLanguage=exports.MATCH_TYPES=void 0;var directives_1=require("./directives"),locales_1=require("./locales");exports.MATCH_TYPES={locale:"locale",languageSpecificLocale:"languageSpecificLocale",language:"language",relatedLocale:"relatedLocale",languageCountry:"languageCountry",country:"country",defaultLocale:"defaultLocale"};var resolveAcceptLanguage=function(e,r,a,t){if(r.forEach((function(e){if(!(0,locales_1.isLocale)(e,!1))throw new Error("Invalid locale identifier '".concat(e,"'. A valid locale should follow the BCP 47 'language-country' format."))})),!(0,locales_1.isLocale)(a,!1))throw new Error("Invalid default locale identifier '".concat(a,"'. A valid locale should follow the BCP 47 'language-country' format."));if(!r.some((function(e){return e.toLowerCase()===a.toLowerCase()})))throw new Error("The default locale '".concat(a,"' must be included in the locales array because it is used as a fallback when no match is found."));var o=new locales_1.Locale(a),n=new Set(__spreadArray([o.identifier],__read(r.map((function(e){return new locales_1.Locale(e).identifier}))),!1)),l=function(){var r,a,l,c,i,u,f,d,s=new locales_1.LocaleList(n),v=(0,directives_1.getDirectives)(e),y=v.filter((function(e){return s.languages.has(e.languageCode)})),g=function(e){var r=e.locale,a=e.languageCode;if(void 0!==r)return s.locales.has(r)?{value:{match:r,matchType:exports.MATCH_TYPES.locale}}:"continue";var t=v.find((function(e){return e.languageCode===a&&void 0!==e.locale&&s.locales.has(e.locale)}));if(t)return{value:{match:t.locale,matchType:exports.MATCH_TYPES.languageSpecificLocale}};var o=s.objects.find((function(e){return e.languageCode===a}));return o?{value:{match:o.identifier,matchType:exports.MATCH_TYPES.language}}:void 0};try{for(var h=__values(y),p=h.next();!p.done;p=h.next()){var _=g(P=p.value);if("object"==typeof _)return _.value}}catch(e){r={error:e}}finally{try{p&&!p.done&&(a=h.return)&&a.call(h)}finally{if(r)throw r.error}}var C=function(e){var r=s.objects.find((function(r){return r.languageCode===e.languageCode}));if(r)return{value:{match:r.identifier,matchType:exports.MATCH_TYPES.relatedLocale}}};try{for(var m=__values(y),T=m.next();!T.done;T=m.next()){var w=C(P=T.value);if("object"==typeof w)return w.value}}catch(e){l={error:e}}finally{try{T&&!T.done&&(c=m.return)&&c.call(m)}finally{if(l)throw l.error}}var x=s.objects.filter((function(e){return e.languageCode===o.languageCode&&e.identifier!==o.identifier})).map((function(e){return e.countryCode}));if(x.length>0)try{for(var L=__values(v),A=L.next();!A.done;A=L.next()){if(void 0!==(P=A.value).locale&&void 0!==P.countryCode&&x.includes(P.countryCode))return{match:"".concat(o.languageCode,"-").concat(P.countryCode),matchType:exports.MATCH_TYPES.languageCountry}}}catch(e){i={error:e}}finally{try{A&&!A.done&&(u=L.return)&&u.call(L)}finally{if(i)throw i.error}}if(null==t?void 0:t.matchCountry){var b=function(e){var r=s.objects.find((function(r){return r.countryCode===e.countryCode}));if(r)return{value:{match:r.identifier,matchType:exports.MATCH_TYPES.country}}};try{for(var S=__values(v),E=S.next();!E.done;E=S.next()){var P,M=b(P=E.value);if("object"==typeof M)return M.value}}catch(e){f={error:e}}finally{try{E&&!E.done&&(d=S.return)&&d.call(S)}finally{if(f)throw f.error}}}return{match:o.identifier,matchType:exports.MATCH_TYPES.defaultLocale}}();return(null==t?void 0:t.returnMatchType)?l:l.match};exports.resolveAcceptLanguage=resolveAcceptLanguage;
@@ -0,0 +1,42 @@
1
+ /** Class to manage a locale identifier using the BCP 47 `language`-`country` format. */
2
+ export declare class Locale {
3
+ /** The ISO 639-1 alpha-2 language code. */
4
+ readonly languageCode: string;
5
+ /** The ISO 3166-1 alpha-2 country code. */
6
+ readonly countryCode: string;
7
+ /** The locale identifier using the BCP 47 `language`-`country` case-normalized format. */
8
+ readonly identifier: string;
9
+ /**
10
+ * Create a new `Locale` object.
11
+ *
12
+ * @param identifier - A locale identifier using the BCP 47 `language`-`country` format (case insensitive).
13
+ *
14
+ * @throws An error if the `identifier` format is invalid.
15
+ */
16
+ constructor(identifier: string);
17
+ }
18
+ export declare class LocaleList {
19
+ /** A set of ISO 639-1 alpha-2 language codes. */
20
+ readonly languages: Set<string>;
21
+ /** A set of ISO 3166-1 alpha-2 country codes. */
22
+ readonly countries: Set<string>;
23
+ /** A set of locale identifiers using the BCP 47 `language`-`country` case-normalized format. */
24
+ readonly locales: Set<string>;
25
+ /** A list of locale objects. */
26
+ readonly objects: Locale[];
27
+ /**
28
+ * Create a list of locale identifiers.
29
+ *
30
+ * @param locales - An set of unique locale identifiers using the BCP 47 `language`-`country` format (case insensitive).
31
+ *
32
+ * @throws Will throw an error if one of the locale's format is invalid.
33
+ */
34
+ constructor(locales: Set<string>);
35
+ }
36
+ /**
37
+ * Is a given string a locale identifier following the BCP 47 `language`-`country` format.
38
+ *
39
+ * @param identifier - A potential locale identify to verify.
40
+ * @param caseNormalized - Should we verify if the identifier is using the case-normalized format?
41
+ */
42
+ export declare const isLocale: (identifier: string, caseNormalized?: boolean) => boolean;
@@ -0,0 +1 @@
1
+ "use strict";var __read=this&&this.__read||function(e,o){var t="function"==typeof Symbol&&e[Symbol.iterator];if(!t)return e;var a,r,i=t.call(e),s=[];try{for(;(void 0===o||o-- >0)&&!(a=i.next()).done;)s.push(a.value)}catch(e){r={error:e}}finally{try{a&&!a.done&&(t=i.return)&&t.call(i)}finally{if(r)throw r.error}}return s};Object.defineProperty(exports,"__esModule",{value:!0}),exports.isLocale=exports.LocaleList=exports.Locale=void 0;var Locale=function(e){if(!(0,exports.isLocale)(e,!1))throw new Error("invalid locale identifier '".concat(e,"'"));var o=__read(e.split("-"),2),t=o[0],a=o[1];this.languageCode=t.toLowerCase(),this.countryCode=a.toUpperCase(),this.identifier="".concat(this.languageCode,"-").concat(this.countryCode)};exports.Locale=Locale;var LocaleList=function(e){var o=this;this.languages=new Set,this.countries=new Set,this.locales=new Set,this.objects=[],e.forEach((function(e){var t=new Locale(e);o.objects.push(t),o.locales.add(t.identifier),o.languages.add(t.languageCode),o.countries.add(t.countryCode)}))};exports.LocaleList=LocaleList;var isLocale=function(e,o){return void 0===o&&(o=!0),new RegExp(/^[a-z]{2}-[A-Z]{2}$/,o?void 0:"i").test(e)};exports.isLocale=isLocale;
@@ -0,0 +1,29 @@
1
+ /** An object representing an HTTP `Accept-Language` header directive. */
2
+ type Directive = {
3
+ /** The ISO 639-1 alpha-2 language code. */
4
+ languageCode: string;
5
+ /** The ISO 3166-1 alpha-2 country code. */
6
+ countryCode?: string;
7
+ /** The locale identifier using the BCP 47 `language`-`country` in case-normalized format. */
8
+ locale?: string;
9
+ /** The quality factor (default is 1; values can range from 0 to 1 with up to 3 decimals). */
10
+ quality: number;
11
+ };
12
+ /** A directive object including the position in its HTTP header. */
13
+ type IndexedDirective = Directive & {
14
+ /** This is the position of the directive in the HTTP header. */
15
+ headerPosition: number;
16
+ };
17
+ /** A directive object including the position in its HTTP header and the locale. */
18
+ export type IndexedDirectiveWithLocale = IndexedDirective & {
19
+ locale: string;
20
+ };
21
+ /**
22
+ * Get a list of directives from an HTTP `Accept-Language` header.
23
+ *
24
+ * @param acceptLanguageHeader - The value of an HTTP request `Accept-Language` header (also known as a "language priority list").
25
+ *
26
+ * @returns A list of `IndexedDirective` objects sorted by quality and header position.
27
+ */
28
+ export declare const getDirectives: (acceptLanguageHeader: string) => IndexedDirective[];
29
+ export {};
@@ -0,0 +1 @@
1
+ var __assign=this&&this.__assign||function(){return __assign=Object.assign||function(e){for(var r,a=1,t=arguments.length;a<t;a++)for(var n in r=arguments[a])Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n]);return e},__assign.apply(this,arguments)},__read=this&&this.__read||function(e,r){var a="function"==typeof Symbol&&e[Symbol.iterator];if(!a)return e;var t,n,o=a.call(e),i=[];try{for(;(void 0===r||r-- >0)&&!(t=o.next()).done;)i.push(t.value)}catch(e){n={error:e}}finally{try{t&&!t.done&&(a=o.return)&&a.call(o)}finally{if(n)throw n.error}}return i},__spreadArray=this&&this.__spreadArray||function(e,r,a){if(a||2===arguments.length)for(var t,n=0,o=r.length;n<o;n++)!t&&n in r||(t||(t=Array.prototype.slice.call(r,0,n)),t[n]=r[n]);return e.concat(t||Array.prototype.slice.call(r))},getDirective=function(e){var r=e.match(/^((?<matchedLanguageCode>([a-z]{2}))(-(?<matchedCountryCode>[a-z]{2}|419))?)(;q=(?<matchedQuality>(1(\.0{0,3})?)|(0(\.\d{0,3})?)))?$/i);if(null==r?void 0:r.groups){var a=r.groups,t=a.matchedLanguageCode,n=a.matchedCountryCode,o=a.matchedQuality,i=t.toLowerCase(),s=n?n.toUpperCase():void 0;if("419"!==s||"es"===i){var c=void 0===o?1:Number.parseFloat(o);return{languageCode:i,countryCode:s,locale:s?"".concat(i,"-").concat(s):void 0,quality:c}}}};export var getDirectives=function(e){var r=[],a=0;e.split(",").forEach((function(e){var t=getDirective(e.trim());t&&(r.some((function(e){return e.languageCode===t.languageCode&&e.locale===t.locale}))||(r.push(__assign(__assign({},t),{headerPosition:a})),a++))}));var t=r.findIndex((function(e){return"es-419"===e.locale}));if(t>=0){var n=r[t],o=["es-AR","es-CL","es-CO","es-CR","es-HN","es-MX","es-PE","es-US","es-UY","es-VE"].map((function(e){return __assign(__assign({},n),{locale:e})}));r.splice.apply(r,__spreadArray([t,1],__read(o),!1))}return r.sort((function(e,r){var a=r.quality-e.quality;return a||e.headerPosition-r.headerPosition}))};
@@ -0,0 +1,44 @@
1
+ /** The type of matches. */
2
+ export type MatchType = 'locale' | 'languageSpecificLocale' | 'language' | 'relatedLocale' | 'languageCountry' | 'country' | 'defaultLocale';
3
+ /** The type of matches 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;
9
+ /** Additional options to apply. */
10
+ type Options<WithMatchType extends boolean | undefined> = {
11
+ /** Should the match type be returned? */
12
+ returnMatchType?: WithMatchType;
13
+ /** Should the country of the locale be used for matching? */
14
+ matchCountry?: boolean;
15
+ };
16
+ type Result<Locales extends string[], WithMatchType extends boolean | undefined> = WithMatchType extends true ? {
17
+ /** The best locale match. */
18
+ match: NormalizeLocale<Locales[number]>;
19
+ /** The type of match. */
20
+ matchType: MatchType;
21
+ } : NormalizeLocale<Locales[number]>;
22
+ /**
23
+ * Resolve the preferred locale from an HTTP `Accept-Language` header.
24
+ *
25
+ * All locale identifiers provided as parameters must following the BCP 47 `language`-`country` (case insensitive).
26
+ *
27
+ * @param acceptLanguageHeader - The value of an HTTP request `Accept-Language` header (also known as a "language priority list").
28
+ * @param locales - An array of locale identifiers that must include the default locale. The order will be used for matching where
29
+ * the first identifier will be more likely to be matched than the last identifier.
30
+ * @param defaultLocale - The default locale identifier when no match is found.
31
+ * @param options - Additional options to apply.
32
+ *
33
+ * @returns Either the best locale match or a match object, depending on options.
34
+ *
35
+ * @example
36
+ * // returns 'fr-CA'
37
+ * resolveAcceptLanguage(
38
+ * 'fr-CA;q=0.01,en-CA;q=0.1,en-US;q=0.001',
39
+ * ['en-US', 'fr-CA'],
40
+ * 'en-US'
41
+ * )
42
+ */
43
+ export declare const resolveAcceptLanguage: <Locales extends string[], WithMatchType extends boolean | undefined = undefined>(acceptLanguageHeader: string, locales: Locales, defaultLocale: Locales[number], options?: Options<WithMatchType> | undefined) => Result<Locales, WithMatchType>;
44
+ export {};
@@ -0,0 +1 @@
1
+ var __read=this&&this.__read||function(e,r){var a="function"==typeof Symbol&&e[Symbol.iterator];if(!a)return e;var t,n,o=a.call(e),l=[];try{for(;(void 0===r||r-- >0)&&!(t=o.next()).done;)l.push(t.value)}catch(e){n={error:e}}finally{try{t&&!t.done&&(a=o.return)&&a.call(o)}finally{if(n)throw n.error}}return l},__spreadArray=this&&this.__spreadArray||function(e,r,a){if(a||2===arguments.length)for(var t,n=0,o=r.length;n<o;n++)!t&&n in r||(t||(t=Array.prototype.slice.call(r,0,n)),t[n]=r[n]);return e.concat(t||Array.prototype.slice.call(r))},__values=this&&this.__values||function(e){var r="function"==typeof Symbol&&Symbol.iterator,a=r&&e[r],t=0;if(a)return a.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&t>=e.length&&(e=void 0),{value:e&&e[t++],done:!e}}};throw new TypeError(r?"Object is not iterable.":"Symbol.iterator is not defined.")};import{getDirectives}from"./directives.js";import{Locale,LocaleList,isLocale}from"./locales.js";export var MATCH_TYPES={locale:"locale",languageSpecificLocale:"languageSpecificLocale",language:"language",relatedLocale:"relatedLocale",languageCountry:"languageCountry",country:"country",defaultLocale:"defaultLocale"};export var resolveAcceptLanguage=function(e,r,a,t){if(r.forEach((function(e){if(!isLocale(e,!1))throw new Error("Invalid locale identifier '".concat(e,"'. A valid locale should follow the BCP 47 'language-country' format."))})),!isLocale(a,!1))throw new Error("Invalid default locale identifier '".concat(a,"'. A valid locale should follow the BCP 47 'language-country' format."));if(!r.some((function(e){return e.toLowerCase()===a.toLowerCase()})))throw new Error("The default locale '".concat(a,"' must be included in the locales array because it is used as a fallback when no match is found."));var n=new Locale(a),o=new Set(__spreadArray([n.identifier],__read(r.map((function(e){return new Locale(e).identifier}))),!1)),l=function(){var r,a,l,i,c,u,f,d,y=new LocaleList(o),v=getDirectives(e),h=v.filter((function(e){return y.languages.has(e.languageCode)})),s=function(e){var r=e.locale,a=e.languageCode;if(void 0!==r)return y.locales.has(r)?{value:{match:r,matchType:MATCH_TYPES.locale}}:"continue";var t=v.find((function(e){return e.languageCode===a&&void 0!==e.locale&&y.locales.has(e.locale)}));if(t)return{value:{match:t.locale,matchType:MATCH_TYPES.languageSpecificLocale}};var n=y.objects.find((function(e){return e.languageCode===a}));return n?{value:{match:n.identifier,matchType:MATCH_TYPES.language}}:void 0};try{for(var g=__values(h),m=g.next();!m.done;m=g.next()){var p=s(j=m.value);if("object"==typeof p)return p.value}}catch(e){r={error:e}}finally{try{m&&!m.done&&(a=g.return)&&a.call(g)}finally{if(r)throw r.error}}var _=function(e){var r=y.objects.find((function(r){return r.languageCode===e.languageCode}));if(r)return{value:{match:r.identifier,matchType:MATCH_TYPES.relatedLocale}}};try{for(var C=__values(h),T=C.next();!T.done;T=C.next()){var w=_(j=T.value);if("object"==typeof w)return w.value}}catch(e){l={error:e}}finally{try{T&&!T.done&&(i=C.return)&&i.call(C)}finally{if(l)throw l.error}}var L=y.objects.filter((function(e){return e.languageCode===n.languageCode&&e.identifier!==n.identifier})).map((function(e){return e.countryCode}));if(L.length>0)try{for(var b=__values(v),S=b.next();!S.done;S=b.next()){if(void 0!==(j=S.value).locale&&void 0!==j.countryCode&&L.includes(j.countryCode))return{match:"".concat(n.languageCode,"-").concat(j.countryCode),matchType:MATCH_TYPES.languageCountry}}}catch(e){c={error:e}}finally{try{S&&!S.done&&(u=b.return)&&u.call(b)}finally{if(c)throw c.error}}if(null==t?void 0:t.matchCountry){var A=function(e){var r=y.objects.find((function(r){return r.countryCode===e.countryCode}));if(r)return{value:{match:r.identifier,matchType:MATCH_TYPES.country}}};try{for(var E=__values(v),x=E.next();!x.done;x=E.next()){var j,P=A(j=x.value);if("object"==typeof P)return P.value}}catch(e){f={error:e}}finally{try{x&&!x.done&&(d=E.return)&&d.call(E)}finally{if(f)throw f.error}}}return{match:n.identifier,matchType:MATCH_TYPES.defaultLocale}}();return(null==t?void 0:t.returnMatchType)?l:l.match};
@@ -0,0 +1,42 @@
1
+ /** Class to manage a locale identifier using the BCP 47 `language`-`country` format. */
2
+ export declare class Locale {
3
+ /** The ISO 639-1 alpha-2 language code. */
4
+ readonly languageCode: string;
5
+ /** The ISO 3166-1 alpha-2 country code. */
6
+ readonly countryCode: string;
7
+ /** The locale identifier using the BCP 47 `language`-`country` case-normalized format. */
8
+ readonly identifier: string;
9
+ /**
10
+ * Create a new `Locale` object.
11
+ *
12
+ * @param identifier - A locale identifier using the BCP 47 `language`-`country` format (case insensitive).
13
+ *
14
+ * @throws An error if the `identifier` format is invalid.
15
+ */
16
+ constructor(identifier: string);
17
+ }
18
+ export declare class LocaleList {
19
+ /** A set of ISO 639-1 alpha-2 language codes. */
20
+ readonly languages: Set<string>;
21
+ /** A set of ISO 3166-1 alpha-2 country codes. */
22
+ readonly countries: Set<string>;
23
+ /** A set of locale identifiers using the BCP 47 `language`-`country` case-normalized format. */
24
+ readonly locales: Set<string>;
25
+ /** A list of locale objects. */
26
+ readonly objects: Locale[];
27
+ /**
28
+ * Create a list of locale identifiers.
29
+ *
30
+ * @param locales - An set of unique locale identifiers using the BCP 47 `language`-`country` format (case insensitive).
31
+ *
32
+ * @throws Will throw an error if one of the locale's format is invalid.
33
+ */
34
+ constructor(locales: Set<string>);
35
+ }
36
+ /**
37
+ * Is a given string a locale identifier following the BCP 47 `language`-`country` format.
38
+ *
39
+ * @param identifier - A potential locale identify to verify.
40
+ * @param caseNormalized - Should we verify if the identifier is using the case-normalized format?
41
+ */
42
+ export declare const isLocale: (identifier: string, caseNormalized?: boolean) => boolean;
@@ -0,0 +1 @@
1
+ var __read=this&&this.__read||function(e,t){var o="function"==typeof Symbol&&e[Symbol.iterator];if(!o)return e;var a,r,i=o.call(e),n=[];try{for(;(void 0===t||t-- >0)&&!(a=i.next()).done;)n.push(a.value)}catch(e){r={error:e}}finally{try{a&&!a.done&&(o=i.return)&&o.call(i)}finally{if(r)throw r.error}}return n},Locale=function(e){if(!isLocale(e,!1))throw new Error("invalid locale identifier '".concat(e,"'"));var t=__read(e.split("-"),2),o=t[0],a=t[1];this.languageCode=o.toLowerCase(),this.countryCode=a.toUpperCase(),this.identifier="".concat(this.languageCode,"-").concat(this.countryCode)};export{Locale};var LocaleList=function(e){var t=this;this.languages=new Set,this.countries=new Set,this.locales=new Set,this.objects=[],e.forEach((function(e){var o=new Locale(e);t.objects.push(o),t.locales.add(o.identifier),t.languages.add(o.languageCode),t.countries.add(o.countryCode)}))};export{LocaleList};export var isLocale=function(e,t){return void 0===t&&(t=!0),new RegExp(/^[a-z]{2}-[A-Z]{2}$/,t?void 0:"i").test(e)};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "resolve-accept-language",
3
- "version": "2.2.0",
3
+ "version": "3.1.0",
4
4
  "description": "Resolve the preferred locale based on the value of an `Accept-Language` HTTP header.",
5
5
  "keywords": [
6
6
  "accept-language",
@@ -26,18 +26,18 @@
26
26
  "exports": {
27
27
  ".": {
28
28
  "import": {
29
- "types": "./lib/esm/resolve-accept-language.d.ts",
30
- "default": "./lib/esm/resolve-accept-language.js"
29
+ "types": "./lib/esm/index.d.ts",
30
+ "default": "./lib/esm/index.js"
31
31
  },
32
32
  "require": {
33
- "types": "./lib/cjs/resolve-accept-language.d.ts",
34
- "default": "./lib/cjs/resolve-accept-language.js"
33
+ "types": "./lib/cjs/index.d.ts",
34
+ "default": "./lib/cjs/index.js"
35
35
  }
36
36
  }
37
37
  },
38
- "main": "lib/cjs/resolve-accept-language.js",
39
- "module": "lib/esm/resolve-accept-language.js",
40
- "types": "lib/esm/resolve-accept-language.d.ts",
38
+ "main": "lib/cjs/index.js",
39
+ "module": "lib/esm/index.js",
40
+ "types": "lib/esm/index.d.ts",
41
41
  "files": [
42
42
  "lib"
43
43
  ],
@@ -54,8 +54,8 @@
54
54
  "@release-it/conventional-changelog": "8.0.1",
55
55
  "@types/jest": "29.5.12",
56
56
  "@types/node": "^20.11.24",
57
- "@typescript-eslint/eslint-plugin": "7.1.0",
58
- "@typescript-eslint/parser": "7.1.0",
57
+ "@typescript-eslint/eslint-plugin": "7.1.1",
58
+ "@typescript-eslint/parser": "7.1.1",
59
59
  "depcheck": "^1.4.7",
60
60
  "dotenv-cli": "7.3.0",
61
61
  "eslint": "8.57.0",
@@ -1,19 +0,0 @@
1
- import Locale from './locale';
2
- export default class LocaleList<TLocales extends readonly string[]> {
3
- /** A set of ISO 3166-1 alpha-2 country codes. */
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
- /**
12
- * Create a list of locale identifiers.
13
- *
14
- * @param locales - An array of locale identifiers using the BCP 47 `language`-`country` format.
15
- *
16
- * @throws Will throw an error if one of the locale's format is invalid.
17
- */
18
- constructor(locales: TLocales extends string[] ? TLocales[number][] : TLocales);
19
- }
@@ -1 +0,0 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var locale_1=require("./locale"),LocaleList=function(e){var t=this;this.countries=new Set,this.languages=new Set,this.locales=new Set,this.objects=[],e.forEach((function(e){var a=new locale_1.default(e);t.locales.has(a.identifier)||(t.objects.push(a),t.locales.add(a.identifier),t.languages.add(a.languageCode),t.countries.add(a.countryCode))}))};exports.default=LocaleList;
@@ -1,39 +0,0 @@
1
- import { NormalizeLocale } from './resolve-accept-language';
2
- /** Class to manage a locale identifier using the BCP 47 `language`-`country` format. */
3
- export default class Locale<TLocale extends string = string> {
4
- /** The ISO 3166-1 alpha-2 country code. */
5
- readonly countryCode: string;
6
- /** The locale identifier using the BCP 47 `language`-`country` case-normalized format. */
7
- readonly identifier: NormalizeLocale<TLocale>;
8
- /** The ISO 639-1 alpha-2 language code. */
9
- readonly languageCode: string;
10
- /**
11
- * Create a new `Locale` object.
12
- *
13
- * @param identifier - A locale identifier using the BCP 47 `language`-`country` format (case insensitive).
14
- *
15
- * @throws An error if the `identifier` format is invalid.
16
- */
17
- constructor(identifier: string);
18
- /**
19
- * Is a given string an ISO 3166-1 alpha-2 country code.
20
- *
21
- * @param countryCode - An ISO 3166-1 alpha-2 country code.
22
- * @param caseNormalized - Should we verify if the identifier is using the case-normalized format?
23
- */
24
- static isCountryCode(countryCode: string, caseNormalized?: boolean): boolean;
25
- /**
26
- * Is a given string an ISO 639-1 alpha-2 language code.
27
- *
28
- * @param languageCode - An ISO 639-1 alpha-2 language code.
29
- * @param caseNormalized - Should we verify if the identifier is using the case-normalized format?
30
- */
31
- static isLanguageCode(languageCode: string, caseNormalized?: boolean): boolean;
32
- /**
33
- * Is a given string a locale identifier following the BCP 47 `language`-`country` format.
34
- *
35
- * @param identifier - A potential locale identify to verify.
36
- * @param caseNormalized - Should we verify if the identifier is using the case-normalized format?
37
- */
38
- static isLocale(identifier: string, caseNormalized?: boolean): boolean;
39
- }
package/lib/cjs/locale.js DELETED
@@ -1 +0,0 @@
1
- "use strict";var __read=this&&this.__read||function(e,t){var o="function"==typeof Symbol&&e[Symbol.iterator];if(!o)return e;var r,i,n=o.call(e),a=[];try{for(;(void 0===t||t-- >0)&&!(r=n.next()).done;)a.push(r.value)}catch(e){i={error:e}}finally{try{r&&!r.done&&(o=n.return)&&o.call(n)}finally{if(i)throw i.error}}return a};Object.defineProperty(exports,"__esModule",{value:!0});var Locale=function(){function e(t){if(!e.isLocale(t,!1))throw new Error("invalid locale identifier '".concat(t,"'"));var o=__read(t.split("-"),2),r=o[0],i=o[1];this.languageCode=r.toLowerCase(),this.countryCode=i.toUpperCase(),this.identifier="".concat(this.languageCode,"-").concat(this.countryCode)}return e.isCountryCode=function(e,t){return void 0===t&&(t=!0),new RegExp(/^[A-Z]{2}$/,t?void 0:"i").test(e)},e.isLanguageCode=function(e,t){return void 0===t&&(t=!0),new RegExp(/^[a-z]{2}$/,t?void 0:"i").test(e)},e.isLocale=function(e,t){return void 0===t&&(t=!0),new RegExp(/^[a-z]{2}-[A-Z]{2}$/,t?void 0:"i").test(e)},e}();exports.default=Locale;
@@ -1,79 +0,0 @@
1
- import { NormalizeLocale } from './resolve-accept-language';
2
- /** Lookup list used to match the preferred locale based on the value of an `Accept-Language` HTTP header. */
3
- export default class LookupList<TLocales extends readonly string[]> {
4
- /** The list of locales used to get the match during the lookup. */
5
- private localeList;
6
- /**
7
- * Data object where the properties are quality (in string format) and their values a set containing locale
8
- * identifiers using the `language`-`country` format and ISO 639-1 alpha-2 language code.
9
- */
10
- private localesAndLanguagesByQuality;
11
- /**
12
- * Data object where the properties are quality (in string format) and their value a set of ISO 639-1 alpha-2
13
- * language code.
14
- */
15
- private relatedLocaleLanguagesByQuality;
16
- /**
17
- * Create a new `LookupList` object.
18
- *
19
- * @param acceptLanguageHeader - The value of an HTTP request `Accept-Language` header (also known as a "language priority list").
20
- * @param locales - An array of locale identifiers. The order will be used for matching where the first identifier will be more
21
- * likely to be matched than the last identifier.
22
- */
23
- constructor(acceptLanguageHeader: string, locales: TLocales extends string[] ? TLocales[number][] : TLocales, defaultLocale: TLocales[number]);
24
- /**
25
- * Get the top locale-based match if available.
26
- *
27
- * @returns The top locale-based match or undefined when there is no match.
28
- */
29
- getLocaleBasedMatch(): NormalizeLocale<TLocales[number]> | undefined;
30
- /**
31
- * Get the language-based match if available.
32
- *
33
- * @returns The language-based match or undefined when there is no match.
34
- */
35
- getLanguageBasedMatch(): NormalizeLocale<TLocales[number]> | undefined;
36
- /**
37
- * Get the related-locale-based match if available.
38
- *
39
- * @returns The related-locale-based match or undefined when there is no match.
40
- */
41
- getRelatedLocaleBasedMatch(): NormalizeLocale<TLocales[number]> | undefined;
42
- /**
43
- * Add a language in the data object matching its quality.
44
- *
45
- * @param quality - The HTTP header's quality factor associated with a language.
46
- * @param languageCode - An ISO 639-1 alpha-2 language code.
47
- */
48
- private addLanguage;
49
- /**
50
- * Add a locale in the data object matching its quality.
51
- *
52
- * @param quality - The HTTP header's quality factor associated with a locale.
53
- * @param identifier - A locale identifier using the BCP 47 `language`-`country` case-normalized format.
54
- */
55
- private addLocale;
56
- /**
57
- * Add a related locale's language in the data object matching its quality.
58
- *
59
- * @param quality - The HTTP header's quality factor associated with a related locale's language.
60
- * @param languageCode - An ISO 639-1 alpha-2 language code.
61
- */
62
- private addRelatedLocaleLanguage;
63
- /**
64
- * Get a directive object from a directive string.
65
- *
66
- * @param directiveString - The string representing a directive, extracted from the HTTP header.
67
- *
68
- * @returns A `Directive` object or `undefined` if the string's format is invalid.
69
- */
70
- private getDirective;
71
- /**
72
- * Get a match from a data object.
73
- *
74
- * @param dataObject - A data object.
75
- *
76
- * @returns A match or undefined when there is no match.
77
- */
78
- private getMatch;
79
- }
@@ -1 +0,0 @@
1
- "use strict";var __read=this&&this.__read||function(e,t){var a="function"==typeof Symbol&&e[Symbol.iterator];if(!a)return e;var l,o,r=a.call(e),i=[];try{for(;(void 0===t||t-- >0)&&!(l=r.next()).done;)i.push(l.value)}catch(e){o={error:e}}finally{try{l&&!l.done&&(a=r.return)&&a.call(r)}finally{if(o)throw o.error}}return i},__spreadArray=this&&this.__spreadArray||function(e,t,a){if(a||2===arguments.length)for(var l,o=0,r=t.length;o<r;o++)!l&&o in t||(l||(l=Array.prototype.slice.call(t,0,o)),l[o]=t[o]);return e.concat(l||Array.prototype.slice.call(t))},__values=this&&this.__values||function(e){var t="function"==typeof Symbol&&Symbol.iterator,a=t&&e[t],l=0;if(a)return a.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&l>=e.length&&(e=void 0),{value:e&&e[l++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(exports,"__esModule",{value:!0});var locale_1=require("./locale"),locale_list_1=require("./locale-list"),LookupList=function(){function e(e,t,a){var l,o,r=this;this.localesAndLanguagesByQuality={},this.relatedLocaleLanguagesByQuality={},this.localeList=new locale_list_1.default(__spreadArray([a],__read(t.filter((function(e){return e!==a}))),!1));var i=e.split(",").map((function(e){return r.getDirective(e.trim())})).filter((function(e){return void 0!==e})),n=i.findIndex((function(e){return"es-419"===e.locale}));if(n>=0){var s=i[n];i.splice(n,1);["es-AR","es-CL","es-CO","es-CR","es-HN","es-MX","es-PE","es-US","es-UY","es-VE"].forEach((function(e){i.push({languageCode:"es",locale:e,quality:s.quality})}))}try{for(var u=__values(i),c=u.next();!c.done;c=u.next()){var d=c.value,g=d.locale,y=d.languageCode,h=d.quality;this.localeList.languages.has(y)&&(g?this.localeList.locales.has(g)||!this.localeList.languages.has(y)?this.addLocale(h,g):this.addRelatedLocaleLanguage(h,y):this.addLanguage(h,y))}}catch(e){l={error:e}}finally{try{c&&!c.done&&(o=u.return)&&o.call(u)}finally{if(l)throw l.error}}}return e.prototype.getLocaleBasedMatch=function(){var e=this.getMatch(this.localesAndLanguagesByQuality);return e&&locale_1.default.isLocale(e)?e:void 0},e.prototype.getLanguageBasedMatch=function(){var e=this.getMatch(this.localesAndLanguagesByQuality);return e&&!locale_1.default.isLocale(e)?this.localeList.objects.find((function(t){return t.languageCode===e})).identifier:void 0},e.prototype.getRelatedLocaleBasedMatch=function(){var e=this.getMatch(this.relatedLocaleLanguagesByQuality);return e?this.localeList.objects.find((function(t){return t.languageCode===e})).identifier:void 0},e.prototype.addLanguage=function(e,t){this.localesAndLanguagesByQuality[e]||(this.localesAndLanguagesByQuality[e]=new Set),this.localesAndLanguagesByQuality[e].add(t)},e.prototype.addLocale=function(e,t){this.localesAndLanguagesByQuality[e]||(this.localesAndLanguagesByQuality[e]=new Set),this.localesAndLanguagesByQuality[e].add(t)},e.prototype.addRelatedLocaleLanguage=function(e,t){this.relatedLocaleLanguagesByQuality[e]||(this.relatedLocaleLanguagesByQuality[e]=new Set),this.relatedLocaleLanguagesByQuality[e].add(t)},e.prototype.getDirective=function(e){var t=e.match(/^((?<matchedLanguageCode>([a-z]{2}))(-(?<matchedCountryCode>[a-z]{2}|419))?)(;q=(?<matchedQuality>(1(\.0{0,3})?)|(0(\.\d{0,3})?)))?$/i);if(null==t?void 0:t.groups){var a=t.groups,l=a.matchedLanguageCode,o=a.matchedCountryCode,r=a.matchedQuality,i=l.toLowerCase(),n=o?o.toUpperCase():void 0;if("419"!==n||"es"===i){var s=void 0===r?"1":Number.parseFloat(r).toString();return{languageCode:i,locale:n?"".concat(i,"-").concat(n):void 0,quality:s}}}},e.prototype.getMatch=function(e){var t=Object.entries(e);return 0===t.length?void 0:t.sort().reverse()[0][1].values().next().value},e}();exports.default=LookupList;
@@ -1,63 +0,0 @@
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;
9
- /** Resolve the preferred locale from an HTTP `Accept-Language` header. */
10
- export declare class ResolveAcceptLanguage<TLocales extends readonly string[] = string[]> {
11
- /** The default locale. */
12
- private defaultLocale;
13
- /** The locale-based match, if applicable. */
14
- private localeBasedMatch;
15
- /** The language-based match, if applicable. */
16
- private languageBasedMatch;
17
- /** The related-locale-based match, if applicable. */
18
- private relatedLocaleBasedMatch;
19
- /**
20
- * Create a new `ResolveAcceptLanguage` object.
21
- *
22
- * All locale identifiers provided as parameters must following the BCP 47 `language`-`country` (case insensitive).
23
- *
24
- * @param acceptLanguageHeader - The value of an HTTP request `Accept-Language` header (also known as a "language priority list").
25
- * @param locales - An array of locale identifiers. The order will be used for matching where the first identifier will be more
26
- * likely to be matched than the last identifier.
27
- */
28
- constructor(acceptLanguageHeader: string, locales: TLocales extends string[] ? TLocales[number][] : TLocales, defaultLocale: TLocales[number]);
29
- /**
30
- * Get the type of match.
31
- *
32
- * @returns The type of match.
33
- */
34
- getMatchType(): MatchType;
35
- /**
36
- * Get the matching locale.
37
- *
38
- * @returns The matching locale.
39
- */
40
- getMatch(): NormalizeLocale<TLocales[number]>;
41
- }
42
- /**
43
- * Resolve the preferred locale from an HTTP `Accept-Language` header.
44
- *
45
- * All locale identifiers provided as parameters must following the BCP 47 `language`-`country` (case insensitive).
46
- *
47
- * @param acceptLanguageHeader - The value of an HTTP request `Accept-Language` header (also known as a "language priority list").
48
- * @param locales - An array of locale identifiers that must include the default locale. The order will be used for matching where
49
- * the first identifier will be more likely to be matched than the last identifier.
50
- * @param defaultLocale - The default locale identifier when no match is found.
51
- *
52
- * @returns The locale identifier which was the best match, in case-normalized format.
53
- *
54
- * @example
55
- * // returns 'fr-CA'
56
- * resolveAcceptLanguage(
57
- * 'fr-CA;q=0.01,en-CA;q=0.1,en-US;q=0.001',
58
- * ['en-US', 'fr-CA'],
59
- * 'en-US'
60
- * )
61
- */
62
- declare const resolveAcceptLanguage: <TLocales extends readonly string[]>(acceptLanguageHeader: string, locales: TLocales extends string[] ? TLocales[number][] : TLocales, defaultLocale: TLocales[number]) => NormalizeLocale<TLocales[number]>;
63
- export default resolveAcceptLanguage;
@@ -1 +0,0 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ResolveAcceptLanguage=exports.MATCH_TYPES=void 0;var locale_1=require("./locale"),lookup_list_1=require("./lookup-list");exports.MATCH_TYPES={localeBased:"localeBased",languageBased:"languageBased",relatedLocaleBased:"relatedLocaleBased",defaultLocale:"defaultLocale"};var ResolveAcceptLanguage=function(){function e(e,a,t){if(a.forEach((function(e){if(!locale_1.default.isLocale(e,!1))throw new Error("invalid locale identifier '".concat(e,"'"))})),!locale_1.default.isLocale(t,!1))throw new Error("invalid default locale identifier '".concat(t,"'"));if(!a.some((function(e){return e.toLowerCase()===t.toLowerCase()})))throw new Error("the default locale must be included in the locales");this.defaultLocale=new locale_1.default(t).identifier;var l=new lookup_list_1.default(e,a,t);this.localeBasedMatch=l.getLocaleBasedMatch(),this.localeBasedMatch||(this.languageBasedMatch=l.getLanguageBasedMatch(),this.languageBasedMatch||(this.relatedLocaleBasedMatch=l.getRelatedLocaleBasedMatch(),this.relatedLocaleBasedMatch))}return e.prototype.getMatchType=function(){return this.localeBasedMatch?exports.MATCH_TYPES.localeBased:this.languageBasedMatch?exports.MATCH_TYPES.languageBased:this.relatedLocaleBasedMatch?exports.MATCH_TYPES.relatedLocaleBased:exports.MATCH_TYPES.defaultLocale},e.prototype.getMatch=function(){var e,a,t;return null!==(t=null!==(a=null!==(e=this.localeBasedMatch)&&void 0!==e?e:this.languageBasedMatch)&&void 0!==a?a:this.relatedLocaleBasedMatch)&&void 0!==t?t:this.defaultLocale},e}();exports.ResolveAcceptLanguage=ResolveAcceptLanguage;var resolveAcceptLanguage=function(e,a,t){return new ResolveAcceptLanguage(e,a,t).getMatch()};exports.default=resolveAcceptLanguage;
@@ -1,19 +0,0 @@
1
- import Locale from './locale.js';
2
- export default class LocaleList<TLocales extends readonly string[]> {
3
- /** A set of ISO 3166-1 alpha-2 country codes. */
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
- /**
12
- * Create a list of locale identifiers.
13
- *
14
- * @param locales - An array of locale identifiers using the BCP 47 `language`-`country` format.
15
- *
16
- * @throws Will throw an error if one of the locale's format is invalid.
17
- */
18
- constructor(locales: TLocales extends string[] ? TLocales[number][] : TLocales);
19
- }
@@ -1 +0,0 @@
1
- import Locale from"./locale.js";var LocaleList=function(e){var a=this;this.countries=new Set,this.languages=new Set,this.locales=new Set,this.objects=[],e.forEach((function(e){var t=new Locale(e);a.locales.has(t.identifier)||(a.objects.push(t),a.locales.add(t.identifier),a.languages.add(t.languageCode),a.countries.add(t.countryCode))}))};export default LocaleList;
@@ -1,39 +0,0 @@
1
- import { NormalizeLocale } from './resolve-accept-language.js';
2
- /** Class to manage a locale identifier using the BCP 47 `language`-`country` format. */
3
- export default class Locale<TLocale extends string = string> {
4
- /** The ISO 3166-1 alpha-2 country code. */
5
- readonly countryCode: string;
6
- /** The locale identifier using the BCP 47 `language`-`country` case-normalized format. */
7
- readonly identifier: NormalizeLocale<TLocale>;
8
- /** The ISO 639-1 alpha-2 language code. */
9
- readonly languageCode: string;
10
- /**
11
- * Create a new `Locale` object.
12
- *
13
- * @param identifier - A locale identifier using the BCP 47 `language`-`country` format (case insensitive).
14
- *
15
- * @throws An error if the `identifier` format is invalid.
16
- */
17
- constructor(identifier: string);
18
- /**
19
- * Is a given string an ISO 3166-1 alpha-2 country code.
20
- *
21
- * @param countryCode - An ISO 3166-1 alpha-2 country code.
22
- * @param caseNormalized - Should we verify if the identifier is using the case-normalized format?
23
- */
24
- static isCountryCode(countryCode: string, caseNormalized?: boolean): boolean;
25
- /**
26
- * Is a given string an ISO 639-1 alpha-2 language code.
27
- *
28
- * @param languageCode - An ISO 639-1 alpha-2 language code.
29
- * @param caseNormalized - Should we verify if the identifier is using the case-normalized format?
30
- */
31
- static isLanguageCode(languageCode: string, caseNormalized?: boolean): boolean;
32
- /**
33
- * Is a given string a locale identifier following the BCP 47 `language`-`country` format.
34
- *
35
- * @param identifier - A potential locale identify to verify.
36
- * @param caseNormalized - Should we verify if the identifier is using the case-normalized format?
37
- */
38
- static isLocale(identifier: string, caseNormalized?: boolean): boolean;
39
- }
package/lib/esm/locale.js DELETED
@@ -1 +0,0 @@
1
- var __read=this&&this.__read||function(e,t){var o="function"==typeof Symbol&&e[Symbol.iterator];if(!o)return e;var r,i,n=o.call(e),a=[];try{for(;(void 0===t||t-- >0)&&!(r=n.next()).done;)a.push(r.value)}catch(e){i={error:e}}finally{try{r&&!r.done&&(o=n.return)&&o.call(n)}finally{if(i)throw i.error}}return a},Locale=function(){function e(t){if(!e.isLocale(t,!1))throw new Error("invalid locale identifier '".concat(t,"'"));var o=__read(t.split("-"),2),r=o[0],i=o[1];this.languageCode=r.toLowerCase(),this.countryCode=i.toUpperCase(),this.identifier="".concat(this.languageCode,"-").concat(this.countryCode)}return e.isCountryCode=function(e,t){return void 0===t&&(t=!0),new RegExp(/^[A-Z]{2}$/,t?void 0:"i").test(e)},e.isLanguageCode=function(e,t){return void 0===t&&(t=!0),new RegExp(/^[a-z]{2}$/,t?void 0:"i").test(e)},e.isLocale=function(e,t){return void 0===t&&(t=!0),new RegExp(/^[a-z]{2}-[A-Z]{2}$/,t?void 0:"i").test(e)},e}();export default Locale;
@@ -1,79 +0,0 @@
1
- import { NormalizeLocale } from './resolve-accept-language.js';
2
- /** Lookup list used to match the preferred locale based on the value of an `Accept-Language` HTTP header. */
3
- export default class LookupList<TLocales extends readonly string[]> {
4
- /** The list of locales used to get the match during the lookup. */
5
- private localeList;
6
- /**
7
- * Data object where the properties are quality (in string format) and their values a set containing locale
8
- * identifiers using the `language`-`country` format and ISO 639-1 alpha-2 language code.
9
- */
10
- private localesAndLanguagesByQuality;
11
- /**
12
- * Data object where the properties are quality (in string format) and their value a set of ISO 639-1 alpha-2
13
- * language code.
14
- */
15
- private relatedLocaleLanguagesByQuality;
16
- /**
17
- * Create a new `LookupList` object.
18
- *
19
- * @param acceptLanguageHeader - The value of an HTTP request `Accept-Language` header (also known as a "language priority list").
20
- * @param locales - An array of locale identifiers. The order will be used for matching where the first identifier will be more
21
- * likely to be matched than the last identifier.
22
- */
23
- constructor(acceptLanguageHeader: string, locales: TLocales extends string[] ? TLocales[number][] : TLocales, defaultLocale: TLocales[number]);
24
- /**
25
- * Get the top locale-based match if available.
26
- *
27
- * @returns The top locale-based match or undefined when there is no match.
28
- */
29
- getLocaleBasedMatch(): NormalizeLocale<TLocales[number]> | undefined;
30
- /**
31
- * Get the language-based match if available.
32
- *
33
- * @returns The language-based match or undefined when there is no match.
34
- */
35
- getLanguageBasedMatch(): NormalizeLocale<TLocales[number]> | undefined;
36
- /**
37
- * Get the related-locale-based match if available.
38
- *
39
- * @returns The related-locale-based match or undefined when there is no match.
40
- */
41
- getRelatedLocaleBasedMatch(): NormalizeLocale<TLocales[number]> | undefined;
42
- /**
43
- * Add a language in the data object matching its quality.
44
- *
45
- * @param quality - The HTTP header's quality factor associated with a language.
46
- * @param languageCode - An ISO 639-1 alpha-2 language code.
47
- */
48
- private addLanguage;
49
- /**
50
- * Add a locale in the data object matching its quality.
51
- *
52
- * @param quality - The HTTP header's quality factor associated with a locale.
53
- * @param identifier - A locale identifier using the BCP 47 `language`-`country` case-normalized format.
54
- */
55
- private addLocale;
56
- /**
57
- * Add a related locale's language in the data object matching its quality.
58
- *
59
- * @param quality - The HTTP header's quality factor associated with a related locale's language.
60
- * @param languageCode - An ISO 639-1 alpha-2 language code.
61
- */
62
- private addRelatedLocaleLanguage;
63
- /**
64
- * Get a directive object from a directive string.
65
- *
66
- * @param directiveString - The string representing a directive, extracted from the HTTP header.
67
- *
68
- * @returns A `Directive` object or `undefined` if the string's format is invalid.
69
- */
70
- private getDirective;
71
- /**
72
- * Get a match from a data object.
73
- *
74
- * @param dataObject - A data object.
75
- *
76
- * @returns A match or undefined when there is no match.
77
- */
78
- private getMatch;
79
- }
@@ -1 +0,0 @@
1
- var __read=this&&this.__read||function(e,t){var a="function"==typeof Symbol&&e[Symbol.iterator];if(!a)return e;var o,r,l=a.call(e),i=[];try{for(;(void 0===t||t-- >0)&&!(o=l.next()).done;)i.push(o.value)}catch(e){r={error:e}}finally{try{o&&!o.done&&(a=l.return)&&a.call(l)}finally{if(r)throw r.error}}return i},__spreadArray=this&&this.__spreadArray||function(e,t,a){if(a||2===arguments.length)for(var o,r=0,l=t.length;r<l;r++)!o&&r in t||(o||(o=Array.prototype.slice.call(t,0,r)),o[r]=t[r]);return e.concat(o||Array.prototype.slice.call(t))},__values=this&&this.__values||function(e){var t="function"==typeof Symbol&&Symbol.iterator,a=t&&e[t],o=0;if(a)return a.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&o>=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")};import Locale from"./locale.js";import LocaleList from"./locale-list.js";var LookupList=function(){function e(e,t,a){var o,r,l=this;this.localesAndLanguagesByQuality={},this.relatedLocaleLanguagesByQuality={},this.localeList=new LocaleList(__spreadArray([a],__read(t.filter((function(e){return e!==a}))),!1));var i=e.split(",").map((function(e){return l.getDirective(e.trim())})).filter((function(e){return void 0!==e})),n=i.findIndex((function(e){return"es-419"===e.locale}));if(n>=0){var s=i[n];i.splice(n,1);["es-AR","es-CL","es-CO","es-CR","es-HN","es-MX","es-PE","es-US","es-UY","es-VE"].forEach((function(e){i.push({languageCode:"es",locale:e,quality:s.quality})}))}try{for(var u=__values(i),c=u.next();!c.done;c=u.next()){var d=c.value,g=d.locale,y=d.languageCode,h=d.quality;this.localeList.languages.has(y)&&(g?this.localeList.locales.has(g)||!this.localeList.languages.has(y)?this.addLocale(h,g):this.addRelatedLocaleLanguage(h,y):this.addLanguage(h,y))}}catch(e){o={error:e}}finally{try{c&&!c.done&&(r=u.return)&&r.call(u)}finally{if(o)throw o.error}}}return e.prototype.getLocaleBasedMatch=function(){var e=this.getMatch(this.localesAndLanguagesByQuality);return e&&Locale.isLocale(e)?e:void 0},e.prototype.getLanguageBasedMatch=function(){var e=this.getMatch(this.localesAndLanguagesByQuality);return e&&!Locale.isLocale(e)?this.localeList.objects.find((function(t){return t.languageCode===e})).identifier:void 0},e.prototype.getRelatedLocaleBasedMatch=function(){var e=this.getMatch(this.relatedLocaleLanguagesByQuality);return e?this.localeList.objects.find((function(t){return t.languageCode===e})).identifier:void 0},e.prototype.addLanguage=function(e,t){this.localesAndLanguagesByQuality[e]||(this.localesAndLanguagesByQuality[e]=new Set),this.localesAndLanguagesByQuality[e].add(t)},e.prototype.addLocale=function(e,t){this.localesAndLanguagesByQuality[e]||(this.localesAndLanguagesByQuality[e]=new Set),this.localesAndLanguagesByQuality[e].add(t)},e.prototype.addRelatedLocaleLanguage=function(e,t){this.relatedLocaleLanguagesByQuality[e]||(this.relatedLocaleLanguagesByQuality[e]=new Set),this.relatedLocaleLanguagesByQuality[e].add(t)},e.prototype.getDirective=function(e){var t=e.match(/^((?<matchedLanguageCode>([a-z]{2}))(-(?<matchedCountryCode>[a-z]{2}|419))?)(;q=(?<matchedQuality>(1(\.0{0,3})?)|(0(\.\d{0,3})?)))?$/i);if(null==t?void 0:t.groups){var a=t.groups,o=a.matchedLanguageCode,r=a.matchedCountryCode,l=a.matchedQuality,i=o.toLowerCase(),n=r?r.toUpperCase():void 0;if("419"!==n||"es"===i){var s=void 0===l?"1":Number.parseFloat(l).toString();return{languageCode:i,locale:n?"".concat(i,"-").concat(n):void 0,quality:s}}}},e.prototype.getMatch=function(e){var t=Object.entries(e);return 0===t.length?void 0:t.sort().reverse()[0][1].values().next().value},e}();export default LookupList;
@@ -1,63 +0,0 @@
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;
9
- /** Resolve the preferred locale from an HTTP `Accept-Language` header. */
10
- export declare class ResolveAcceptLanguage<TLocales extends readonly string[] = string[]> {
11
- /** The default locale. */
12
- private defaultLocale;
13
- /** The locale-based match, if applicable. */
14
- private localeBasedMatch;
15
- /** The language-based match, if applicable. */
16
- private languageBasedMatch;
17
- /** The related-locale-based match, if applicable. */
18
- private relatedLocaleBasedMatch;
19
- /**
20
- * Create a new `ResolveAcceptLanguage` object.
21
- *
22
- * All locale identifiers provided as parameters must following the BCP 47 `language`-`country` (case insensitive).
23
- *
24
- * @param acceptLanguageHeader - The value of an HTTP request `Accept-Language` header (also known as a "language priority list").
25
- * @param locales - An array of locale identifiers. The order will be used for matching where the first identifier will be more
26
- * likely to be matched than the last identifier.
27
- */
28
- constructor(acceptLanguageHeader: string, locales: TLocales extends string[] ? TLocales[number][] : TLocales, defaultLocale: TLocales[number]);
29
- /**
30
- * Get the type of match.
31
- *
32
- * @returns The type of match.
33
- */
34
- getMatchType(): MatchType;
35
- /**
36
- * Get the matching locale.
37
- *
38
- * @returns The matching locale.
39
- */
40
- getMatch(): NormalizeLocale<TLocales[number]>;
41
- }
42
- /**
43
- * Resolve the preferred locale from an HTTP `Accept-Language` header.
44
- *
45
- * All locale identifiers provided as parameters must following the BCP 47 `language`-`country` (case insensitive).
46
- *
47
- * @param acceptLanguageHeader - The value of an HTTP request `Accept-Language` header (also known as a "language priority list").
48
- * @param locales - An array of locale identifiers that must include the default locale. The order will be used for matching where
49
- * the first identifier will be more likely to be matched than the last identifier.
50
- * @param defaultLocale - The default locale identifier when no match is found.
51
- *
52
- * @returns The locale identifier which was the best match, in case-normalized format.
53
- *
54
- * @example
55
- * // returns 'fr-CA'
56
- * resolveAcceptLanguage(
57
- * 'fr-CA;q=0.01,en-CA;q=0.1,en-US;q=0.001',
58
- * ['en-US', 'fr-CA'],
59
- * 'en-US'
60
- * )
61
- */
62
- declare const resolveAcceptLanguage: <TLocales extends readonly string[]>(acceptLanguageHeader: string, locales: TLocales extends string[] ? TLocales[number][] : TLocales, defaultLocale: TLocales[number]) => NormalizeLocale<TLocales[number]>;
63
- export default resolveAcceptLanguage;
@@ -1 +0,0 @@
1
- import Locale from"./locale.js";import LookupList from"./lookup-list.js";export var MATCH_TYPES={localeBased:"localeBased",languageBased:"languageBased",relatedLocaleBased:"relatedLocaleBased",defaultLocale:"defaultLocale"};var ResolveAcceptLanguage=function(){function e(e,a,t){if(a.forEach((function(e){if(!Locale.isLocale(e,!1))throw new Error("invalid locale identifier '".concat(e,"'"))})),!Locale.isLocale(t,!1))throw new Error("invalid default locale identifier '".concat(t,"'"));if(!a.some((function(e){return e.toLowerCase()===t.toLowerCase()})))throw new Error("the default locale must be included in the locales");this.defaultLocale=new Locale(t).identifier;var l=new LookupList(e,a,t);this.localeBasedMatch=l.getLocaleBasedMatch(),this.localeBasedMatch||(this.languageBasedMatch=l.getLanguageBasedMatch(),this.languageBasedMatch||(this.relatedLocaleBasedMatch=l.getRelatedLocaleBasedMatch(),this.relatedLocaleBasedMatch))}return e.prototype.getMatchType=function(){return this.localeBasedMatch?MATCH_TYPES.localeBased:this.languageBasedMatch?MATCH_TYPES.languageBased:this.relatedLocaleBasedMatch?MATCH_TYPES.relatedLocaleBased:MATCH_TYPES.defaultLocale},e.prototype.getMatch=function(){var e,a,t;return null!==(t=null!==(a=null!==(e=this.localeBasedMatch)&&void 0!==e?e:this.languageBasedMatch)&&void 0!==a?a:this.relatedLocaleBasedMatch)&&void 0!==t?t:this.defaultLocale},e}();export{ResolveAcceptLanguage};var resolveAcceptLanguage=function(e,a,t){return new ResolveAcceptLanguage(e,a,t).getMatch()};export default resolveAcceptLanguage;