UNPKG

2.35 kBJavaScriptView Raw
1'use strict';
2
3// Load modules
4
5const Hoek = require('hoek');
6
7
8// Declare internals
9
10const internals = {};
11
12
13// https://tools.ietf.org/html/rfc7231#section-5.3.5
14// Accept-Language: da, en-gb;q=0.8, en;q=0.7
15
16
17exports.language = function (header, preferences) {
18
19 Hoek.assert(!preferences || Array.isArray(preferences), 'Preferences must be an array');
20 const languages = exports.languages(header);
21
22 if (languages.length === 0) {
23 languages.push('');
24 }
25
26 // No preferences. Take the first charset.
27
28 if (!preferences || preferences.length === 0) {
29 return languages[0];
30 }
31
32 // If languages includes * return first preference
33
34 if (languages.indexOf('*') !== -1) {
35 return preferences[0];
36 }
37
38 // Try to find the first match in the array of preferences
39
40 preferences = preferences.map((str) => str.toLowerCase());
41
42 for (let i = 0; i < languages.length; ++i) {
43 if (preferences.indexOf(languages[i].toLowerCase()) !== -1) {
44 return languages[i];
45 }
46 }
47
48 return '';
49};
50
51
52exports.languages = function (header) {
53
54 if (header === undefined || typeof header !== 'string') {
55 return [];
56 }
57
58 return header
59 .split(',')
60 .map(internals.getParts)
61 .filter(internals.removeUnwanted)
62 .sort(internals.compareByWeight)
63 .map(internals.partToLanguage);
64};
65
66
67internals.getParts = function (item) {
68
69 const result = {
70 weight: 1,
71 language: ''
72 };
73
74 const match = item.match(internals.partsRegex);
75 if (!match) {
76 return result;
77 }
78
79 result.language = match[1];
80 if (match[2] && internals.isNumber(match[2])) {
81 const weight = parseFloat(match[2]);
82 if (weight === 0 || (weight >= 0.001 && weight <= 1)) {
83 result.weight = weight;
84 }
85 }
86
87 return result;
88};
89
90
91// 1: token 2: qvalue
92internals.partsRegex = /\s*([^;]+)(?:\s*;\s*[qQ]\=([01](?:\.\d*)?))?\s*/;
93
94
95internals.removeUnwanted = function (item) {
96
97 return item.weight !== 0 && item.language !== '';
98};
99
100
101internals.compareByWeight = function (a, b) {
102
103 return b.weight - a.weight;
104};
105
106
107internals.partToLanguage = function (item) {
108
109 return item.language;
110};
111
112
113internals.isNumber = function (n) {
114
115 return !isNaN(parseFloat(n));
116};