Skip to content

Commit ab8c0c5

Browse files
Merge pull request #14300 from mozilla/train-243-uplift-4
Train 243.4 uplift
2 parents 93a0798 + 7372fd4 commit ab8c0c5

File tree

5 files changed

+142
-127
lines changed

5 files changed

+142
-127
lines changed

packages/fxa-auth-server/test/local/l10n/index.ts

-77
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,6 @@ describe('Localizer', () => {
2828
}, 'Invalid ftl translations basePath');
2929
});
3030

31-
it('produces the current locales', async () => {
32-
const { currentLocales } = await localizer.getLocalizerDeps(
33-
'de-CH,it;q=0.8,en-US;q=0.5,en;q=0.3'
34-
);
35-
36-
assert.deepEqual(currentLocales, ['de', 'it', 'en-US', 'en']);
37-
});
38-
3931
it('selects the proper locale', async () => {
4032
const { selectedLocale } = await localizer.setupLocalizer(
4133
'de-DE,en-US;q=0.7,en;q=0.3'
@@ -85,75 +77,6 @@ describe('Localizer', () => {
8577
});
8678
});
8779

88-
describe('language negotiation', () => {
89-
it('handles empty case', () => {
90-
const result = parseAcceptLanguage('');
91-
92-
assert.deepEqual(result, ['en']);
93-
});
94-
95-
it('ignores unknown language', () => {
96-
const result = parseAcceptLanguage('zy');
97-
assert.deepEqual(result, ['en']);
98-
});
99-
100-
it('handles en case', () => {
101-
const result = parseAcceptLanguage('en');
102-
103-
// Note: We are using the 'filtering' mode for negotiate languages so all are going to be provided
104-
assert.deepEqual(result, ['en']);
105-
});
106-
107-
it('handles en-* case', () => {
108-
const result = parseAcceptLanguage('en-US');
109-
110-
// Note: We are using the 'filtering' mode for negotiate languages so all are english dialects are going to be provided
111-
assert.deepEqual(result, ['en-US', 'en']);
112-
});
113-
114-
it('handles alias to en-GB', () => {
115-
const result = parseAcceptLanguage('en-NZ');
116-
117-
assert.deepEqual(result, ['en-GB', 'en']);
118-
});
119-
120-
it('always has default language, en, present', () => {
121-
const result = parseAcceptLanguage('de');
122-
123-
assert.deepEqual(result, ['de', 'en']);
124-
});
125-
126-
it('is falls back to root language if dialect is missing', () => {
127-
const result = parseAcceptLanguage('fr-FR');
128-
129-
assert.deepEqual(result, ['fr', 'en']);
130-
});
131-
132-
it('resolves dialects', () => {
133-
const result = parseAcceptLanguage('es-MX');
134-
135-
assert.deepEqual(result, ['es-MX', 'en']);
136-
});
137-
138-
it('handles multiple languages', () => {
139-
const result = parseAcceptLanguage('ja, de-CH, en-US, en');
140-
141-
assert.deepEqual(result, ['ja', 'de', 'en-US', 'en']);
142-
});
143-
144-
it('handles multiple languages with en-GB alias', () => {
145-
const result = parseAcceptLanguage('en-NZ, en-GB, en-MY');
146-
147-
assert.deepEqual(result, ['en-GB', 'en']);
148-
});
149-
150-
it('handles Chinese dialects properly', () => {
151-
const result = parseAcceptLanguage('zh-CN, zh-TW, zh-HK, zh');
152-
153-
assert.deepEqual(result, ['zh-CN', 'zh-TW', 'en']);
154-
});
155-
});
156-
15780
describe('localizeStrings', () => {
15881
const localizer = new Localizer(new LocalizerBindings());
15982

packages/fxa-auth-server/test/local/server.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ describe('lib/server', () => {
234234
assert.equal(args[0], 'server.onRequest');
235235
assert.ok(args[1]);
236236
assert.equal(args[1].path, '/account/create');
237-
assert.equal(args[1].app.locale, 'en-GB');
237+
assert.equal(args[1].app.locale, 'fr');
238238
});
239239

240240
it('called log.summary correctly', () => {
@@ -283,8 +283,8 @@ describe('lib/server', () => {
283283

284284
it('parsed locale correctly', () => {
285285
// Note that fr-CH would be the correct language, but it is not in the list of supported
286-
// languages. This means that en-GB has the highest q-value and should be selected.
287-
assert.equal(request.app.locale, 'en-GB');
286+
// languages so it defaults to fr.
287+
assert.equal(request.app.locale, 'fr');
288288
});
289289

290290
it('parsed user agent correctly', () => {
@@ -336,7 +336,7 @@ describe('lib/server', () => {
336336
return instance
337337
.inject({
338338
headers: {
339-
'accept-language': 'fr-CH, fr;q=0.9, en-GB, en;q=0.5',
339+
'accept-language': 'fr-CH, en-GB, en;q=0.5',
340340
'user-agent': 'Firefox-Android-FxAccounts/34.0a1 (Nightly)',
341341
'x-forwarded-for': ' 194.12.187.0 , 194.12.187.1 ',
342342
},
@@ -379,14 +379,14 @@ describe('lib/server', () => {
379379
it('second request has its own accept-language', () => {
380380
assert.equal(
381381
secondRequest.app.acceptLanguage,
382-
'fr-CH, fr;q=0.9, en-GB, en;q=0.5'
382+
'fr-CH, en-GB, en;q=0.5'
383383
);
384384
});
385385

386386
it('second request has its own locale', () => {
387387
// Note that fr-CH would be the correct language, but it is not in the list of supported
388-
// languages. This means that en-GB has the highest q-value and should be selected.
389-
assert.equal(secondRequest.app.locale, 'en-GB');
388+
// languages so it defaults to fr.
389+
assert.equal(secondRequest.app.locale, 'fr');
390390
});
391391

392392
it('second request has its own user agent info', () => {

packages/fxa-shared/l10n/parseAcceptLanguage.ts

+5-12
Original file line numberDiff line numberDiff line change
@@ -51,24 +51,17 @@ export function parseAcceptLanguage(
5151
}
5252
}
5353

54-
/*
55-
* We use the 'matching' strategy because the default strategy, 'filtering', will load all
56-
* English locales with dialects included, e.g. `en-CA`, even when the user prefers 'en' or
57-
* 'en-US', which would then be shown instead of the English (US) fallback text.
58-
*/
54+
// Order of locales represents priority and should correspond to q-values.
55+
const sortedQValues = Object.entries(qValues).sort((a, b) => b[1] - a[1]);
56+
const parsedLocalesByQValue = sortedQValues.map((qValue) => qValue[0]);
57+
5958
const currentLocales = negotiateLanguages(
60-
[...Object.keys(qValues)],
59+
parsedLocalesByQValue,
6160
[...supportedLanguages],
6261
{
6362
defaultLocale: 'en',
64-
strategy: 'matching',
6563
}
6664
);
6765

68-
// Order of locales represents priority and should correspond to q-values.
69-
currentLocales.sort(
70-
(a, b) => qValues[b.toLocaleLowerCase()] - qValues[a.toLocaleLowerCase()]
71-
);
72-
7366
return currentLocales;
7467
}

packages/fxa-shared/test/l10n/determineLocale.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ describe('l10n/determineLocale:', () => {
4747
expect(determineLocale('en-US;q=.1, es-MX; q=.8')).to.eq('es-MX');
4848
});
4949

50-
it('falls back to supported locale', () => {
51-
// This is an intersting case. en-GB has an implicit q=1, fr has q=0.9, and fr-CH is thrown
52-
// out because it is not supported. Therefore, en-GB ends up having the highest q value and
50+
it('falls back to supported locale with unsupported locale', () => {
51+
// en-GB has an implicit q=1, fr has q=0.9, and xyz is thrown out because it is
52+
// not supported. Therefore, en-GB ends up having the highest q value and
5353
// should be the expected result.
54-
expect(determineLocale('fr-CH, fr;q=0.9, en-GB, en;q=0.5')).to.eq('en-GB');
54+
expect(determineLocale('xyz, fr;q=0.9, en-GB, en;q=0.5')).to.eq('en-GB');
5555
});
5656

5757
it('handles q-values out of range', () => {

packages/fxa-shared/test/l10n/parseAcceptLanguage.ts

+126-27
Original file line numberDiff line numberDiff line change
@@ -7,48 +7,147 @@ import { parseAcceptLanguage } from '../../l10n/parseAcceptLanguage';
77

88
describe('l10n/parseAcceptLanguage:', () => {
99
it('returns default', () => {
10-
expect(parseAcceptLanguage('en')).to.deep.equal(['en']);
11-
});
12-
13-
it('handles unknown', () => {
14-
expect(parseAcceptLanguage('xyz')).to.deep.equal(['en']);
15-
});
16-
17-
it('parses single', () => {
18-
expect(parseAcceptLanguage('en')).to.deep.equal(['en']);
10+
expect(parseAcceptLanguage('en')).to.deep.equal([
11+
'en',
12+
'en-US',
13+
'en-GB',
14+
'en-CA',
15+
]);
1916
});
2017

21-
it('always contains default language (en)', () => {
22-
expect(parseAcceptLanguage('es')).to.deep.equal(['es', 'en']);
18+
it('handles empty case', () => {
19+
expect(parseAcceptLanguage('')).to.deep.equal(['en']);
2320
});
2421

25-
it('handles region', () => {
26-
expect(parseAcceptLanguage('es-MX')).to.deep.equal(['es-MX', 'en']);
22+
it('handles unknown', () => {
23+
expect(parseAcceptLanguage('xyz')).to.deep.equal(['en']);
2724
});
2825

29-
it('handles region with incorrect case', () => {
30-
expect(parseAcceptLanguage('es-mx, ru')).to.deep.equal([
31-
'es-MX',
32-
'ru',
33-
'en',
34-
]);
26+
it('parses single and always contains default language (en)', () => {
27+
expect(parseAcceptLanguage('it')).to.deep.equal(['it', 'en']);
3528
});
3629

37-
it('parses several', () => {
30+
it('parses several with expected output', () => {
3831
expect(parseAcceptLanguage('en, de, es, ru')).to.deep.equal([
3932
'en',
33+
'en-US',
34+
'en-GB',
35+
'en-CA',
4036
'de',
4137
'es',
38+
'es-ES',
39+
'es-AR',
40+
'es-CL',
41+
'es-MX',
4242
'ru',
4343
]);
4444
});
4545

46-
it('it applies qvalue', () => {
47-
expect(parseAcceptLanguage('en, de;q=0.1, es, ru;q=0.3')).to.deep.equal([
48-
'en',
49-
'es',
50-
'ru',
51-
'de',
52-
]);
46+
describe('qvalue', () => {
47+
it('applies correctly with an implicit and explicit value', () => {
48+
expect(parseAcceptLanguage('ru;q=0.3, it')).to.deep.equal([
49+
'it',
50+
'ru',
51+
'en',
52+
]);
53+
});
54+
55+
it('applies correctly with multiple explicit and implicit values', () => {
56+
expect(
57+
parseAcceptLanguage('de, it;q=0.8, en;q=0.5, es;q=1.0')
58+
).to.deep.equal([
59+
'de',
60+
'es',
61+
'es-ES',
62+
'es-AR',
63+
'es-CL',
64+
'es-MX',
65+
'it',
66+
'en',
67+
'en-US',
68+
'en-GB',
69+
'en-CA',
70+
]);
71+
});
72+
73+
it('applies correctly with dialects', () => {
74+
expect(parseAcceptLanguage('de-DE, en-US;q=0.7, en;q=0.3')).to.deep.equal(
75+
['de', 'en-US', 'en', 'en-GB', 'en-CA']
76+
);
77+
});
78+
});
79+
80+
describe('dialect (region) options', () => {
81+
it('handles en-*', () => {
82+
expect(parseAcceptLanguage('en-CA')).to.deep.equal([
83+
'en-CA',
84+
'en',
85+
'en-US',
86+
'en-GB',
87+
]);
88+
});
89+
90+
it('includes all options and always contains default language (en)', () => {
91+
expect(parseAcceptLanguage('es')).to.deep.equal([
92+
'es',
93+
'es-ES',
94+
'es-AR',
95+
'es-CL',
96+
'es-MX',
97+
'en',
98+
]);
99+
});
100+
101+
it('handles region with incorrect case', () => {
102+
expect(parseAcceptLanguage('es-mx, ru')).to.deep.equal([
103+
'es-MX',
104+
'es',
105+
'es-ES',
106+
'es-AR',
107+
'es-CL',
108+
'ru',
109+
'en',
110+
]);
111+
});
112+
113+
it('gives "en" higher priority than second locale when first locale is en-*', () => {
114+
expect(parseAcceptLanguage('en-US, de')).to.deep.equal([
115+
'en-US',
116+
'en',
117+
'en-GB',
118+
'en-CA',
119+
'de',
120+
]);
121+
});
122+
123+
it('handles alias to en-GB', () => {
124+
expect(parseAcceptLanguage('en-NZ')).to.deep.equal([
125+
'en-GB',
126+
'en',
127+
'en-US',
128+
'en-CA',
129+
]);
130+
});
131+
132+
it('handles multiple languages with en-GB alias', () => {
133+
expect(parseAcceptLanguage('en-NZ, en-GB, en-MY')).to.deep.equal([
134+
'en-GB',
135+
'en',
136+
'en-US',
137+
'en-CA',
138+
]);
139+
});
140+
141+
it('falls back to root language if dialect is missing', () => {
142+
expect(parseAcceptLanguage('fr-FR')).to.deep.equal(['fr', 'en']);
143+
});
144+
145+
it('handles Chinese dialects properly', () => {
146+
expect(parseAcceptLanguage('zh-CN, zh-TW, zh-HK, zh')).to.deep.equal([
147+
'zh-CN',
148+
'zh-TW',
149+
'en',
150+
]);
151+
});
53152
});
54153
});

0 commit comments

Comments
 (0)