Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make acceptedLanguages order the header by q values descending #262

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
26 changes: 22 additions & 4 deletions fluent-langneg/src/accepted_languages.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
export default function acceptedLanguages(string = "") {
if (typeof string !== "string") {
function parseAcceptLanguageEntry(entry) {
const langWithQ = entry.split(";").map(u => u.trim());
let q = 1.0;
if (langWithQ.length > 1) {
const qVal = langWithQ[1].split("=").map(u => u.trim());
if (qVal.length === 2 && qVal[0].toLowerCase() === "q") {
const qn = Number(qVal[1]);
q = isNaN(qn) ? 0.0 : qn;
}
}
return { lang: langWithQ[0], q };
}

export default function acceptedLanguages(acceptLanguageHeader = "") {
if (typeof acceptLanguageHeader !== "string") {
throw new TypeError("Argument must be a string");
}
const tokens = string.split(",").map(t => t.trim());
return tokens.filter(t => t !== "").map(t => t.split(";")[0]);
const tokens = acceptLanguageHeader.split(",").map(t => t.trim())
.filter(t => t !== "");
const langsWithQ = Array.from(tokens.map(parseAcceptLanguageEntry).entries());
// order by q descending, keeping the header order for equal weights
langsWithQ.sort(([aidx, aval], [bidx, bval]) =>
aval.q === bval.q ? aidx - bidx : bval.q - aval.q);
return langsWithQ.map(([, val]) => val.lang);
}
53 changes: 53 additions & 0 deletions fluent-langneg/test/headers_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import assert from 'assert';
import acceptedLanguages from '../src/accepted_languages';

suite('parse headers', () => {
test('without an argument', () => {
assert.deepStrictEqual(
acceptedLanguages(), []
);
});

test('without quality values', () => {
assert.deepStrictEqual(
acceptedLanguages('en-US, fr, pl'), [
Expand Down Expand Up @@ -29,6 +35,53 @@ suite('parse headers', () => {
);
});

test('with out of order quality values', () => {
assert.deepStrictEqual(
acceptedLanguages('en;q=0.8, fr;q=0.9, de;q=0.7, *;q=0.5, fr-CH'), [
'fr-CH',
'fr',
'en',
'de',
'*'
]
);
});

test('with equal q values', () => {
assert.deepStrictEqual(
acceptedLanguages('en;q=0.1, fr;q=0.1, de;q=0.1, *;q=0.1'), [
'en',
'fr',
'de',
'*'
]
);
});

test('with duff q values', () => {
assert.deepStrictEqual(
acceptedLanguages('en;q=no, fr;z=0.9, de;q=0.7;q=9, *;q=0.5, fr-CH;q=a=0.1'), [
'fr',
'fr-CH',
'de',
'*',
'en'
]
);
});

test('with empty entries', () => {
assert.deepStrictEqual(
acceptedLanguages('en;q=0.8,,, fr;q=0.9,, de;q=0.7, *;q=0.5, fr-CH'), [
'fr-CH',
'fr',
'en',
'de',
'*'
]
);
});

test('edge cases', () => {
const args = [
null,
Expand Down