Skip to content

Commit 6f78e74

Browse files
feat(langneg): Order Accept-Language header tags by q values (#262)
Co-authored-by: Eemeli Aro <eemeli@mozilla.com>
1 parent efe272d commit 6f78e74

File tree

2 files changed

+47
-4
lines changed

2 files changed

+47
-4
lines changed
Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
1-
export function acceptedLanguages(str: string = ""): Array<string> {
2-
if (typeof str !== "string") {
1+
const entryRegexp =
2+
// locale ; q = qval
3+
/(?:^|,)([^,;]+)(?:;\s*[qQ]\s*=([^,;]+))?/g;
4+
5+
export function acceptedLanguages(acceptLanguageHeader = ""): string[] {
6+
if (typeof acceptLanguageHeader !== "string") {
37
throw new TypeError("Argument must be a string");
48
}
5-
const tokens = str.split(",").map(t => t.trim());
6-
return tokens.filter(t => t !== "").map(t => t.split(";")[0]);
9+
10+
const langsWithQ: Array<{ lang: string; q: number; index: number }> = [];
11+
for (const token of acceptLanguageHeader.matchAll(entryRegexp)) {
12+
const q = token[2] ? parseFloat(token[2]) || 0 : 1;
13+
langsWithQ.push({ lang: token[1].trim(), q, index: token.index });
14+
}
15+
16+
// order by q descending, keeping the header order for equal weights
17+
langsWithQ.sort((a, b) => (a.q === b.q ? a.index - b.index : b.q - a.q));
18+
19+
return langsWithQ.map(val => val.lang);
720
}

fluent-langneg/test/headers_test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,36 @@ suite("parse headers", () => {
1818
);
1919
});
2020

21+
test("with out of order quality values", () => {
22+
assert.deepStrictEqual(
23+
acceptedLanguages("en;q=0.8, fr;q=0.9, de;q=0.7, *;q=0.5, fr-CH"),
24+
["fr-CH", "fr", "en", "de", "*"]
25+
);
26+
});
27+
28+
test("with equal q values", () => {
29+
assert.deepStrictEqual(
30+
acceptedLanguages("en;q=0.1, fr;q=0.1, de;q=0.1, *;q=0.1"),
31+
["en", "fr", "de", "*"]
32+
);
33+
});
34+
35+
test("with duff q values", () => {
36+
assert.deepStrictEqual(
37+
acceptedLanguages(
38+
"en;q=no, fr;z=0.9, de;q=0.7;q=9, *;q=0.5, fr-CH;q=a=0.1"
39+
),
40+
["fr", "de", "*", "en", "fr-CH"]
41+
);
42+
});
43+
44+
test("with empty entries", () => {
45+
assert.deepStrictEqual(
46+
acceptedLanguages("en;q=0.8,,, fr;q=0.9,, de;q=0.7, *;q=0.5, fr-CH"),
47+
["fr-CH", "fr", "en", "de", "*"]
48+
);
49+
});
50+
2151
test("edge cases", () => {
2252
const args = [null, NaN, Infinity, [], {}];
2353

0 commit comments

Comments
 (0)