lighthouse 8.6.0-dev.20211021 → 8.6.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.
Files changed (115) hide show
  1. package/dist/report/flow.js +13 -30
  2. package/dist/report/standalone.js +17 -17
  3. package/flow-report/assets/styles.css +30 -51
  4. package/flow-report/src/common.tsx +1 -1
  5. package/flow-report/src/header.tsx +2 -2
  6. package/flow-report/src/help-dialog.tsx +3 -3
  7. package/flow-report/src/i18n/i18n.tsx +13 -50
  8. package/flow-report/src/i18n/ui-strings.js +0 -48
  9. package/flow-report/src/icons.tsx +0 -7
  10. package/flow-report/src/sidebar/sidebar.tsx +6 -8
  11. package/flow-report/src/summary/category.tsx +18 -17
  12. package/flow-report/src/summary/summary.tsx +10 -10
  13. package/flow-report/src/topbar.tsx +5 -9
  14. package/flow-report/src/util.ts +5 -0
  15. package/flow-report/src/wrappers/category-score.tsx +3 -0
  16. package/flow-report/test/common-test.tsx +1 -1
  17. package/flow-report/test/summary/category-test.tsx +5 -9
  18. package/flow-report/test/summary/summary-test.tsx +1 -1
  19. package/flow-report/test/topbar-test.tsx +0 -1
  20. package/flow-report/tsconfig.json +0 -1
  21. package/jest.config.js +0 -1
  22. package/lighthouse-cli/test/smokehouse/lighthouse-runners/cli.js +1 -1
  23. package/lighthouse-core/audits/accessibility/axe-audit.js +1 -7
  24. package/lighthouse-core/audits/redirects-http.js +59 -0
  25. package/lighthouse-core/config/config-helpers.js +0 -1
  26. package/lighthouse-core/config/default-config.js +11 -0
  27. package/lighthouse-core/fraggle-rock/config/config.js +1 -1
  28. package/lighthouse-core/gather/gatherers/accessibility.js +0 -27
  29. package/lighthouse-core/gather/gatherers/http-redirect.js +46 -0
  30. package/lighthouse-core/lib/asset-saver.js +3 -3
  31. package/lighthouse-core/lib/i18n/i18n.js +8 -19
  32. package/lighthouse-core/lib/i18n/locales/en-US.ctc.json +6699 -0
  33. package/lighthouse-core/lib/i18n/locales/en-XL.ctc.json +6672 -0
  34. package/lighthouse-core/util-commonjs.js +37 -25
  35. package/package.json +4 -8
  36. package/readme.md +3 -3
  37. package/report/assets/styles.css +28 -157
  38. package/report/assets/templates.html +47 -2
  39. package/report/clients/psi.js +158 -0
  40. package/report/renderer/category-renderer.js +1 -30
  41. package/report/renderer/components.js +34 -16
  42. package/report/renderer/performance-category-renderer.js +10 -5
  43. package/report/renderer/report-renderer.js +33 -56
  44. package/report/renderer/util.js +37 -25
  45. package/report/test/clients/psi-test.js +143 -0
  46. package/report/test/renderer/category-renderer-test.js +1 -5
  47. package/report/test/renderer/i18n-test.js +7 -0
  48. package/report/test/renderer/performance-category-renderer-test.js +1 -1
  49. package/report/test/renderer/pwa-category-renderer-test.js +2 -2
  50. package/report/test/renderer/report-renderer-axe-test.js +10 -5
  51. package/report/test/renderer/report-renderer-test.js +11 -9
  52. package/report/test-assets/faux-psi-template.html +4 -1
  53. package/report/test-assets/faux-psi.js +16 -39
  54. package/shared/localization/format.js +17 -50
  55. package/shared/localization/locales/ar-XB.json +24 -0
  56. package/shared/localization/locales/ar.json +24 -0
  57. package/shared/localization/locales/bg.json +24 -0
  58. package/shared/localization/locales/ca.json +24 -0
  59. package/shared/localization/locales/cs.json +24 -0
  60. package/shared/localization/locales/da.json +24 -0
  61. package/shared/localization/locales/de.json +24 -0
  62. package/shared/localization/locales/el.json +24 -0
  63. package/shared/localization/locales/en-GB.json +24 -0
  64. package/shared/localization/locales/en-US.ctc.json +6877 -0
  65. package/shared/localization/locales/en-US.json +23 -26
  66. package/shared/localization/locales/en-XA.json +24 -0
  67. package/shared/localization/locales/en-XL.ctc.json +6852 -0
  68. package/shared/localization/locales/en-XL.json +23 -26
  69. package/shared/localization/locales/es-419.json +24 -0
  70. package/shared/localization/locales/es.json +24 -0
  71. package/shared/localization/locales/fi.json +24 -0
  72. package/shared/localization/locales/fil.json +24 -0
  73. package/shared/localization/locales/fr.json +24 -0
  74. package/shared/localization/locales/he.json +24 -0
  75. package/shared/localization/locales/hi.json +24 -0
  76. package/shared/localization/locales/hr.json +24 -0
  77. package/shared/localization/locales/hu.json +24 -0
  78. package/shared/localization/locales/id.json +24 -0
  79. package/shared/localization/locales/it.json +24 -0
  80. package/shared/localization/locales/ja.json +24 -0
  81. package/shared/localization/locales/ko.json +24 -0
  82. package/shared/localization/locales/lt.json +24 -0
  83. package/shared/localization/locales/lv.json +24 -0
  84. package/shared/localization/locales/nl.json +24 -0
  85. package/shared/localization/locales/no.json +24 -0
  86. package/shared/localization/locales/pl.json +24 -0
  87. package/shared/localization/locales/pt-PT.json +24 -0
  88. package/shared/localization/locales/pt.json +24 -0
  89. package/shared/localization/locales/ro.json +24 -0
  90. package/shared/localization/locales/ru.json +24 -0
  91. package/shared/localization/locales/sk.json +24 -0
  92. package/shared/localization/locales/sl.json +24 -0
  93. package/shared/localization/locales/sr-Latn.json +24 -0
  94. package/shared/localization/locales/sr.json +24 -0
  95. package/shared/localization/locales/sv.json +24 -0
  96. package/shared/localization/locales/ta.json +24 -0
  97. package/shared/localization/locales/te.json +24 -0
  98. package/shared/localization/locales/th.json +24 -0
  99. package/shared/localization/locales/tr.json +24 -0
  100. package/shared/localization/locales/uk.json +24 -0
  101. package/shared/localization/locales/vi.json +24 -0
  102. package/shared/localization/locales/zh-HK.json +24 -0
  103. package/shared/localization/locales/zh-TW.json +24 -0
  104. package/shared/localization/locales/zh.json +24 -0
  105. package/shared/localization/locales.js +0 -6
  106. package/shared/test/localization/format-test.js +9 -45
  107. package/shared/test/localization/swap-locale-test.js +12 -0
  108. package/third-party/download-content-shell/download-content-shell.js +2 -2
  109. package/third-party/download-content-shell/utils.js +24 -0
  110. package/tsconfig.json +1 -0
  111. package/types/artifacts.d.ts +3 -1
  112. package/types/enquirer.d.ts +1 -3
  113. package/types/node.d.ts +5 -5
  114. package/flow-report/test/wrappers/category-score-test.tsx +0 -87
  115. package/report/test/clients/bundle-test.js +0 -62
@@ -7,7 +7,6 @@
7
7
  .flow-vars {
8
8
  --app-font-size: 12px;
9
9
  --base-spacing: 16px;
10
- --bold-weight: 500;
11
10
  --category-summary-font-size: 18px;
12
11
  --double-base-spacing: calc(var(--base-spacing) * 2);
13
12
  --gather-mode-icon-size: 16px;
@@ -24,12 +23,10 @@
24
23
  --sidebar-selected-bg-color: #DDEEFF;
25
24
  --sidebar-summary-font-size: 14px;
26
25
  --sidebar-title-font-size: 16px;
27
- --sidebar-width: 320px;
28
- --summary-flow-step-link-font-size: 14px;
29
- --summary-navigation-header-font-size: 12px;
30
- --summary-header-margin: 52px;
31
- --summary-subtitle-font-size: 12px;
32
- --summary-title-font-size: 20px;
26
+ --sidebar-max-width: 400px;
27
+ --summary-flow-step-label-font-size: 16px;
28
+ --summary-subtitle-font-size: 16px;
29
+ --summary-title-font-size: 32px;
33
30
  --summary-tooltip-box-shadow-color: rgba(0, 0, 0, 0.25);
34
31
  --topbar-button-font-size: 14px;
35
32
  --topbar-button-size: 45px;
@@ -117,18 +114,10 @@
117
114
 
118
115
  .Topbar__title {
119
116
  font-size: var(--topbar-title-font-size);
120
- font-weight: var(--bold-weight);
117
+ font-weight: bold;
121
118
  margin-right: var(--double-base-spacing);
122
119
  }
123
120
 
124
- .Topbar__help-label {
125
- display: flex;
126
- align-items: center;
127
- }
128
- .Topbar__help-label > :first-child {
129
- margin-right: var(--half-base-spacing);
130
- }
131
-
132
121
  .Content {
133
122
  grid-area: content;
134
123
  overflow-y: auto;
@@ -159,19 +148,19 @@
159
148
  .Sidebar {
160
149
  grid-area: sidebar;
161
150
  border-right: 1px solid var(--separator-color);
162
- width: var(--sidebar-width);
151
+ width: min-content;
152
+ max-width: var(--sidebar-max-width);
163
153
  overflow-x: hidden;
164
154
  overflow-y: auto;
165
155
  }
166
156
  .Sidebar a {
167
- color: var(--color-gray-700);
157
+ color: var(--color-gray-800);
168
158
  text-decoration: none;
169
159
  }
170
160
 
171
161
  .Sidebar--current {
172
162
  background-color: var(--sidebar-selected-bg-color);
173
163
  color: var(--color-blue-A700) !important;
174
- font-weight: var(--bold-weight);
175
164
  }
176
165
 
177
166
  .SidebarHeader {
@@ -179,7 +168,7 @@
179
168
  }
180
169
  .SidebarHeader__title {
181
170
  font-size: var(--sidebar-title-font-size);
182
- font-weight: var(--bold-weight);
171
+ font-weight: bold;
183
172
  width: max-content;
184
173
  }
185
174
  .SidebarHeader__date {
@@ -191,7 +180,6 @@
191
180
  margin: var(--base-spacing);
192
181
  padding: var(--half-base-spacing);
193
182
  background-color: var(--color-gray-50);
194
- color: var(--color-gray-700);
195
183
  border-radius: 3px;
196
184
  }
197
185
 
@@ -270,23 +258,21 @@
270
258
  }
271
259
 
272
260
  .SummaryHeader {
273
- margin: var(--summary-header-margin) 0px;
261
+ margin: calc(var(--base-spacing) * 3) 0px;
262
+ width: 100%;
274
263
  }
275
264
 
276
265
  .SummaryHeader__title {
266
+ margin: var(--base-spacing) 0;
277
267
  font-size: var(--summary-title-font-size);
278
- font-weight: var(--bold-weight);
279
- line-height: 28px;
280
- margin: 0 0 calc(0.25 * var(--base-spacing));
281
268
  }
282
269
 
283
270
  .SummaryHeader__subtitle {
284
271
  font-size: var(--summary-subtitle-font-size);
285
- line-height: 16px;
286
272
  }
287
273
 
288
274
  .SummarySectionHeader {
289
- margin-top: var(--base-spacing);
275
+ margin-top: var(--double-base-spacing);
290
276
  }
291
277
 
292
278
  .SummarySectionHeader__content {
@@ -295,15 +281,15 @@
295
281
  }
296
282
 
297
283
  .SummaryFlow {
284
+ width: 100%;
298
285
  display: grid;
299
- max-width: var(--report-width);
300
286
  grid-auto-rows: min-content;
301
- grid-template-columns: min-content min-content minmax(var(--min-text-width), max-content) 1fr 1fr 1fr 1fr;
287
+ grid-template-columns: min-content min-content minmax(var(--min-text-width), 4fr) 1fr 1fr 1fr 1fr;
302
288
  align-items: center;
303
289
  margin: var(--base-spacing) 0px;
304
- --gauge-circle-size: 48px;
305
290
  }
306
291
  .SummaryFlow .lh-fraction__content {
292
+ padding: 0px;
307
293
  min-width: unset;
308
294
  }
309
295
 
@@ -335,7 +321,7 @@
335
321
  grid-column: 2;
336
322
  }
337
323
  .SummaryFlowStep .FlowStepThumbnail {
338
- margin: var(--half-base-spacing);
324
+ margin: var(--base-spacing) var(--half-base-spacing);
339
325
  }
340
326
 
341
327
  .FlowStepThumbnail {
@@ -343,10 +329,7 @@
343
329
  justify-self: center;
344
330
  object-fit: cover;
345
331
  object-position: top left;
346
- border: 1px solid var(--color-gray-700);
347
- border-radius: 3px;
348
- padding: 2px;
349
- box-sizing: content-box !important;
332
+ border: 1px solid var(--color-gray);
350
333
  }
351
334
 
352
335
  .SummaryFlowStep__label {
@@ -358,13 +341,11 @@
358
341
  }
359
342
 
360
343
  .SummaryFlowStep__mode {
361
- color: var(--color-blue-A700);
362
- font-weight: var(--bold-weight);
344
+ color: var(--color-gray-700);
363
345
  }
364
346
 
365
347
  .SummaryFlowStep__link {
366
- font-size: var(--summary-flow-step-link-font-size);
367
- line-height: 20px;
348
+ font-size: var(--summary-flow-step-label-font-size);
368
349
  color: var(--color-gray-800);
369
350
  text-decoration: underline;
370
351
  width: 100%;
@@ -373,6 +354,7 @@
373
354
 
374
355
  .SummaryCategory__content {
375
356
  position: relative;
357
+ margin: var(--half-base-spacing);
376
358
  }
377
359
  .SummaryCategory__content:hover,
378
360
  .SummaryCategory__content:focus-within {
@@ -399,12 +381,12 @@
399
381
  }
400
382
 
401
383
  .SummaryTooltip__title {
402
- font-weight: var(--bold-weight);
384
+ font-weight: bold;
403
385
  margin-bottom: var(--half-base-spacing);
404
386
  }
405
387
 
406
388
  .SummaryTooltip__category {
407
- font-weight: var(--bold-weight);
389
+ font-weight: bold;
408
390
  display: flex;
409
391
  margin-top: var(--half-base-spacing);
410
392
  }
@@ -425,8 +407,7 @@
425
407
  }
426
408
 
427
409
  .SummaryNavigationHeader {
428
- font-size: var(--summary-navigation-header-font-size);
429
- line-height: 16px;
410
+ font-size: var(--summary-flow-step-label-font-size);
430
411
  display: contents;
431
412
  }
432
413
 
@@ -549,7 +530,6 @@
549
530
  .Header__prev-title {
550
531
  grid-area: prev-title;
551
532
  text-align: left;
552
- justify-self: start;
553
533
  }
554
534
 
555
535
  .Header__next-title {
@@ -564,17 +544,16 @@
564
544
  align-self: start;
565
545
  overflow-x: hidden;
566
546
  text-overflow: ellipsis;
567
- max-width: 100%;
547
+ width: 100%;
568
548
  }
569
549
 
570
550
  .Header__current-title {
571
551
  grid-area: current-title;
572
552
  text-align: center;
573
553
  font-size: var(--header-current-title-font-size);
574
- font-weight: var(--bold-weight);
554
+ font-weight: bold;
575
555
  overflow-x: hidden;
576
556
  text-overflow: ellipsis;
577
- margin: 0px var(--half-base-spacing);
578
557
  }
579
558
 
580
559
  .Header__current-description {
@@ -604,7 +583,7 @@
604
583
  align-items: center;
605
584
 
606
585
  font-size: var(--dialog-title-font-size);
607
- font-weight: var(--bold-weight);
586
+ font-weight: bold;
608
587
 
609
588
  margin-bottom: calc(var(--base-spacing) * 2);
610
589
  }
@@ -630,12 +609,12 @@
630
609
 
631
610
  .HelpDialogColumn__header-title {
632
611
  font-size: var(--category-summary-font-size);
633
- font-weight: var(--bold-weight);
612
+ font-weight: bold;
634
613
  }
635
614
 
636
615
  .HelpDialogColumn__legend-label {
637
616
  color: var(--color-blue-A700);
638
- font-weight: var(--bold-weight);
617
+ font-weight: bold;
639
618
  }
640
619
 
641
620
  .HelpDialogColumn ul {
@@ -644,7 +623,7 @@
644
623
 
645
624
  .HelpDialogColumn__use-cases p,
646
625
  .HelpDialogColumn__categories p {
647
- font-weight: var(--bold-weight);
626
+ font-weight: bold;
648
627
  color: var(--color-gray-700);
649
628
  }
650
629
 
@@ -10,7 +10,7 @@ import {useEffect, useState} from 'preact/hooks';
10
10
  import {NavigationIcon, SnapshotIcon, TimespanIcon} from './icons';
11
11
  import {getFilmstripFrames, getScreenDimensions, getScreenshot} from './util';
12
12
 
13
- const ANIMATION_FRAME_DURATION_MS = 500;
13
+ const ANIMATION_FRAME_DURATION_MS = 250;
14
14
 
15
15
  export const Separator: FunctionComponent = () => {
16
16
  return <div className="Separator" role="separator"></div>;
@@ -8,7 +8,7 @@ import {FunctionComponent} from 'preact';
8
8
 
9
9
  import {Util} from '../../report/renderer/util';
10
10
  import {FlowStepIcon, FlowStepThumbnail} from './common';
11
- import {useLocalizedStrings} from './i18n/i18n';
11
+ import {useUIStrings} from './i18n/i18n';
12
12
  import {getModeDescription, useFlowResult} from './util';
13
13
 
14
14
  const SIDE_THUMBNAIL_HEIGHT = 80;
@@ -39,7 +39,7 @@ export const Header: FunctionComponent<{currentLhr: LH.FlowResult.LhrRef}> =
39
39
  const prevStep = flowResult.steps[index - 1];
40
40
  const nextStep = flowResult.steps[index + 1];
41
41
 
42
- const strings = useLocalizedStrings();
42
+ const strings = useUIStrings();
43
43
  const modeDescription = getModeDescription(step.lhr.gatherMode, strings);
44
44
 
45
45
  return (
@@ -6,7 +6,7 @@
6
6
 
7
7
  import {FunctionComponent, JSX} from 'preact';
8
8
 
9
- import {useLocalizedStrings} from './i18n/i18n';
9
+ import {useUIStrings} from './i18n/i18n';
10
10
  import {CloseIcon, NavigationIcon, SnapshotIcon, TimespanIcon} from './icons';
11
11
 
12
12
  const HelpDialogColumn: FunctionComponent<{
@@ -18,7 +18,7 @@ const HelpDialogColumn: FunctionComponent<{
18
18
  useCases: string[];
19
19
  availableCategories: string[];
20
20
  }> = (props) => {
21
- const strings = useLocalizedStrings();
21
+ const strings = useUIStrings();
22
22
 
23
23
  return (
24
24
  <div className="HelpDialogColumn">
@@ -56,7 +56,7 @@ const HelpDialogColumn: FunctionComponent<{
56
56
  export const HelpDialog: FunctionComponent<{onClose: () => void}> = ({
57
57
  onClose,
58
58
  }) => {
59
- const strings = useLocalizedStrings();
59
+ const strings = useUIStrings();
60
60
 
61
61
  return (
62
62
  <div className="HelpDialog">
@@ -7,69 +7,32 @@
7
7
  import {createContext, FunctionComponent} from 'preact';
8
8
  import {useContext, useMemo} from 'preact/hooks';
9
9
 
10
- import {formatMessage} from '../../../shared/localization/format';
11
10
  import {I18n} from '../../../report/renderer/i18n';
12
11
  import {UIStrings} from './ui-strings';
13
- import {useFlowResult} from '../util';
12
+ import {useLocale} from '../util';
14
13
  import strings from './localized-strings';
15
- import {Util} from '../../../report/renderer/util';
16
14
 
17
- const I18nContext = createContext(new I18n('en-US', {...Util.UIStrings, ...UIStrings}));
18
-
19
- function useLhrLocale() {
20
- const flowResult = useFlowResult();
21
- const firstLhr = flowResult.steps[0].lhr;
22
- const locale = firstLhr.configSettings.locale;
23
-
24
- if (flowResult.steps.some(step => step.lhr.configSettings.locale !== locale)) {
25
- console.warn('LHRs have inconsistent locales');
26
- }
27
-
28
- return {
29
- locale,
30
- lhrStrings: firstLhr.i18n.rendererFormattedStrings,
31
- };
32
- }
15
+ const I18nContext = createContext<I18n<typeof UIStrings>|undefined>(undefined);
33
16
 
34
17
  export function useI18n() {
35
- return useContext(I18nContext);
18
+ const i18n = useContext(I18nContext);
19
+ if (!i18n) throw Error('i18n was not initialized');
20
+ return i18n;
36
21
  }
37
22
 
38
- export function useLocalizedStrings() {
23
+ export function useUIStrings() {
39
24
  const i18n = useI18n();
40
25
  return i18n.strings;
41
26
  }
42
27
 
43
- export function useStringFormatter() {
44
- const {locale} = useLhrLocale();
45
- return (str: string, values?: Record<string, string|number>) => {
46
- return formatMessage(str, values, locale);
47
- };
48
- }
49
-
50
28
  export const I18nProvider: FunctionComponent = ({children}) => {
51
- const {locale, lhrStrings} = useLhrLocale();
52
-
53
- const i18n = useMemo(() => {
54
- const i18n = new I18n(locale, {
55
- // Set any missing lhr strings to default (english) values.
56
- ...Util.UIStrings,
57
- // Preload with strings from the first lhr.
58
- // Used for legacy report components imported into the flow report.
59
- ...lhrStrings,
60
- // Set any missing flow strings to default (english) values.
61
- ...UIStrings,
62
- // `strings` is generated in build/build-report.js
63
- ...strings[locale],
64
- });
65
-
66
- // Initialize renderer util i18n for strings rendered in wrapped components.
67
- // TODO: Don't attach global i18n to `Util`.
68
- // @ts-ignore TS reports as read-only.
69
- Util.i18n = i18n;
70
-
71
- return i18n;
72
- }, [locale, lhrStrings]);
29
+ const locale = useLocale();
30
+ const i18n = useMemo(() => new I18n(locale, {
31
+ // Set missing renderer strings to default (english) values.
32
+ ...UIStrings,
33
+ // `strings` is generated in build/build-report.js
34
+ ...strings[locale],
35
+ }), [locale]);
73
36
 
74
37
  return (
75
38
  <I18nContext.Provider value={i18n}>
@@ -57,30 +57,6 @@ export const UIStrings = {
57
57
  ratingFail: 'Poor',
58
58
  /** Rating indicating that a report category rating could not be calculated because of an error. */
59
59
  ratingError: 'Error',
60
- /**
61
- * @description Label indicating the number of Lighthouse reports that evaluate a web page as it loads.
62
- * @example {2} numNavigation
63
- */
64
- navigationReportCount: `{numNavigation, plural,
65
- =1 {{numNavigation} navigation report}
66
- other {{numNavigation} navigation reports}
67
- }`,
68
- /**
69
- * @description Label indicating the number of Lighthouse reports that evaluate a web page over a period of time.
70
- * @example {2} numTimespan
71
- */
72
- timespanReportCount: `{numTimespan, plural,
73
- =1 {{numTimespan} timespan report}
74
- other {{numTimespan} timespan reports}
75
- }`,
76
- /**
77
- * @description Label indicating the number of Lighthouse reports that evaluate a web page at a single point in time.
78
- * @example {2} numSnapshot
79
- */
80
- snapshotReportCount: `{numSnapshot, plural,
81
- =1 {{numSnapshot} snapshot report}
82
- other {{numSnapshot} snapshot reports}
83
- }`,
84
60
  /** Label for a button that saves a Lighthouse report to disk. */
85
61
  save: 'Save',
86
62
  /** Label for a button that toggles the help modal with explanations on how to interpret the Lighthouse flow report. */
@@ -107,28 +83,4 @@ export const UIStrings = {
107
83
  helpUseCaseSnapshot1: 'Find accessibility issues in single page applications or complex forms.',
108
84
  /** Example use case for how Lighthouse can be applied in practice. Appears in a list with other examples. */
109
85
  helpUseCaseSnapshot2: 'Evaluate best practices of menus and UI elements hidden behind interaction.',
110
- /**
111
- * @description Label indicating the number of Lighthouse audits that passed.
112
- * @example {2} numPassed
113
- */
114
- passedAuditCount: `{numPassed, plural,
115
- =1 {{numPassed} audit passed}
116
- other {{numPassed} audits passed}
117
- }`,
118
- /**
119
- * @description Label indicating the number of Lighthouse audits that are possible to pass for a page.
120
- * @example {2} numPassableAudits
121
- */
122
- passableAuditCount: `{numPassableAudits, plural,
123
- =1 {{numPassableAudits} passable audit}
124
- other {{numPassableAudits} passable audits}
125
- }`,
126
- /**
127
- * @description Label indicating the number of Lighthouse audits that are informative.
128
- * @example {2} numInformative
129
- */
130
- informativeAuditCount: `{numInformative, plural,
131
- =1 {{numInformative} informative audit}
132
- other {{numInformative} informative audits}
133
- }`,
134
86
  };
@@ -122,10 +122,3 @@ export const HamburgerIcon: FunctionComponent = () => {
122
122
  );
123
123
  };
124
124
 
125
- export const InfoIcon: FunctionComponent = () => {
126
- return (
127
- <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
128
- <path fill-rule="evenodd" clip-rule="evenodd" d="M13 7C13 10.3137 10.3137 13 7 13C3.68629 13 1 10.3137 1 7C1 3.68629 3.68629 1 7 1C10.3137 1 13 3.68629 13 7ZM14 7C14 10.866 10.866 14 7 14C3.13401 14 0 10.866 0 7C0 3.13401 3.13401 0 7 0C10.866 0 14 3.13401 14 7ZM7.66658 11H6.33325V9.66667H7.66658V11ZM4.33325 5.66667C4.33325 4.19333 5.52659 3 6.99992 3C8.47325 3 9.66658 4.19333 9.66658 5.66667C9.66658 6.52194 9.1399 6.98221 8.62709 7.43036C8.1406 7.85551 7.66658 8.26975 7.66658 9H6.33325C6.33325 7.78582 6.96133 7.30439 7.51355 6.88112C7.94674 6.54907 8.33325 6.25281 8.33325 5.66667C8.33325 4.93333 7.73325 4.33333 6.99992 4.33333C6.26658 4.33333 5.66658 4.93333 5.66658 5.66667H4.33325Z" fill="currentColor"/>
129
- </svg>
130
- );
131
- };
@@ -7,14 +7,14 @@
7
7
  import {FunctionComponent} from 'preact';
8
8
 
9
9
  import {Separator} from '../common';
10
- import {useI18n, useLocalizedStrings} from '../i18n/i18n';
10
+ import {useI18n, useUIStrings} from '../i18n/i18n';
11
11
  import {CpuIcon, EnvIcon, SummaryIcon} from '../icons';
12
12
  import {classNames, useCurrentLhr, useFlowResult} from '../util';
13
13
  import {SidebarFlow} from './flow';
14
14
 
15
15
  export const SidebarSummary: FunctionComponent = () => {
16
16
  const currentLhr = useCurrentLhr();
17
- const strings = useLocalizedStrings();
17
+ const strings = useUIStrings();
18
18
 
19
19
  const url = new URL(location.href);
20
20
  url.hash = '#';
@@ -33,21 +33,19 @@ export const SidebarSummary: FunctionComponent = () => {
33
33
  };
34
34
 
35
35
  const SidebarRuntimeSettings: FunctionComponent<{settings: LH.ConfigSettings}> = ({settings}) => {
36
- const strings = useLocalizedStrings();
36
+ const strings = useUIStrings();
37
37
 
38
38
  return (
39
39
  <div className="SidebarRuntimeSettings">
40
- <div className="SidebarRuntimeSettings__item" title={strings.runtimeSettingsDevice}>
40
+ <div className="SidebarRuntimeSettings__item">
41
41
  <div className="SidebarRuntimeSettings__item--icon">
42
42
  <EnvIcon/>
43
43
  </div>
44
44
  {
45
- settings.formFactor === 'desktop' ?
46
- strings.runtimeDesktopEmulation :
47
- strings.runtimeMobileEmulation
45
+ settings.formFactor === 'desktop' ? strings.desktop : strings.mobile
48
46
  }
49
47
  </div>
50
- <div className="SidebarRuntimeSettings__item" title={strings.runtimeSettingsCPUThrottling}>
48
+ <div className="SidebarRuntimeSettings__item">
51
49
  <div className="SidebarRuntimeSettings__item--icon">
52
50
  <CpuIcon/>
53
51
  </div>
@@ -9,7 +9,7 @@ import {FunctionComponent} from 'preact';
9
9
  import {Util} from '../../../report/renderer/util';
10
10
  import {Separator} from '../common';
11
11
  import {CategoryScore} from '../wrappers/category-score';
12
- import {useI18n, useStringFormatter, useLocalizedStrings} from '../i18n/i18n';
12
+ import {useUIStrings} from '../i18n/i18n';
13
13
 
14
14
  import type {UIStringsType} from '../i18n/ui-strings';
15
15
 
@@ -34,8 +34,7 @@ export const SummaryTooltip: FunctionComponent<{
34
34
  category: LH.ReportResult.Category,
35
35
  gatherMode: LH.Result.GatherMode
36
36
  }> = ({category, gatherMode}) => {
37
- const strings = useLocalizedStrings();
38
- const str_ = useStringFormatter();
37
+ const strings = useUIStrings();
39
38
  const {
40
39
  numPassed,
41
40
  numPassableAudits,
@@ -43,12 +42,10 @@ export const SummaryTooltip: FunctionComponent<{
43
42
  totalWeight,
44
43
  } = Util.calculateCategoryFraction(category);
45
44
 
46
- const i18n = useI18n();
47
45
  const displayAsFraction = Util.shouldDisplayAsFraction(gatherMode);
48
- const score = displayAsFraction ?
49
- numPassed / numPassableAudits :
50
- category.score;
51
- const rating = score === null ? 'error' : Util.calculateRating(score);
46
+ const rating = displayAsFraction ?
47
+ Util.calculateRating(numPassed / numPassableAudits) :
48
+ Util.calculateRating(category.score);
52
49
 
53
50
  return (
54
51
  <div className="SummaryTooltip">
@@ -63,23 +60,27 @@ export const SummaryTooltip: FunctionComponent<{
63
60
  <div className={`SummaryTooltip__rating SummaryTooltip__rating--${rating}`}>
64
61
  <span>{getCategoryRating(rating, strings)}</span>
65
62
  {
66
- !displayAsFraction && category.score !== null && <>
63
+ !displayAsFraction && category.score && <>
67
64
  <span> · </span>
68
- <span>{i18n.formatNumber(category.score * 100)}</span>
65
+ <span>{category.score * 100}</span>
69
66
  </>
70
67
  }
71
68
  </div>
72
69
  }
73
70
  </div>
74
71
  <div className="SummaryTooltip__fraction">
75
- <span>{str_(strings.passedAuditCount, {numPassed})}</span>
76
- <span> / </span>
77
- <span>{str_(strings.passableAuditCount, {numPassableAudits})}</span>
72
+ {
73
+ // TODO(FLOW-I18N): Placeholder format.
74
+ `${numPassed} audits passed / ${numPassableAudits} passable audits`
75
+ }
78
76
  </div>
79
- {numInformative !== 0 &&
80
- <div className="SummaryTooltip__informative">
81
- {str_(strings.informativeAuditCount, {numInformative})}
82
- </div>
77
+ {
78
+ // TODO(FLOW-I18N): Placeholder format.
79
+ numInformative ?
80
+ <div className="SummaryTooltip__informative">
81
+ {`${numInformative} informative audits`}
82
+ </div> :
83
+ null
83
84
  }
84
85
  </div>
85
86
  );
@@ -11,13 +11,13 @@ import {FlowSegment, FlowStepThumbnail, Separator} from '../common';
11
11
  import {getModeDescription, useFlowResult} from '../util';
12
12
  import {Util} from '../../../report/renderer/util';
13
13
  import {SummaryCategory} from './category';
14
- import {useStringFormatter, useLocalizedStrings} from '../i18n/i18n';
14
+ import {useUIStrings} from '../i18n/i18n';
15
15
 
16
16
  const DISPLAYED_CATEGORIES = ['performance', 'accessibility', 'best-practices', 'seo'];
17
- const THUMBNAIL_WIDTH = 40;
17
+ const THUMBNAIL_WIDTH = 50;
18
18
 
19
19
  const SummaryNavigationHeader: FunctionComponent<{lhr: LH.Result}> = ({lhr}) => {
20
- const strings = useLocalizedStrings();
20
+ const strings = useUIStrings();
21
21
 
22
22
  return (
23
23
  <div className="SummaryNavigationHeader" data-testid="SummaryNavigationHeader">
@@ -50,7 +50,7 @@ export const SummaryFlowStep: FunctionComponent<{
50
50
  hashIndex: number,
51
51
  }> = ({lhr, label, hashIndex}) => {
52
52
  const reportResult = useMemo(() => Util.prepareReportResult(lhr), [lhr]);
53
- const strings = useLocalizedStrings();
53
+ const strings = useUIStrings();
54
54
  const modeDescription = getModeDescription(lhr.gatherMode, strings);
55
55
 
56
56
  return (
@@ -107,8 +107,7 @@ const SummaryFlow: FunctionComponent = () => {
107
107
 
108
108
  export const SummaryHeader: FunctionComponent = () => {
109
109
  const flowResult = useFlowResult();
110
- const strings = useLocalizedStrings();
111
- const str_ = useStringFormatter();
110
+ const strings = useUIStrings();
112
111
 
113
112
  let numNavigation = 0;
114
113
  let numTimespan = 0;
@@ -127,10 +126,11 @@ export const SummaryHeader: FunctionComponent = () => {
127
126
  }
128
127
  }
129
128
 
129
+ // TODO(FLOW-I18N): Placeholder format.
130
130
  const subtitleCounts = [];
131
- if (numNavigation) subtitleCounts.push(str_(strings.navigationReportCount, {numNavigation}));
132
- if (numTimespan) subtitleCounts.push(str_(strings.timespanReportCount, {numTimespan}));
133
- if (numSnapshot) subtitleCounts.push(str_(strings.snapshotReportCount, {numSnapshot}));
131
+ if (numNavigation) subtitleCounts.push(`${numNavigation} navigation reports`);
132
+ if (numTimespan) subtitleCounts.push(`${numTimespan} timespan reports`);
133
+ if (numSnapshot) subtitleCounts.push(`${numSnapshot} snapshot reports`);
134
134
  const subtitle = subtitleCounts.join(' · ');
135
135
 
136
136
  return (
@@ -151,7 +151,7 @@ const SummarySectionHeader: FunctionComponent = ({children}) => {
151
151
  };
152
152
 
153
153
  export const Summary: FunctionComponent = () => {
154
- const strings = useLocalizedStrings();
154
+ const strings = useUIStrings();
155
155
 
156
156
  return (
157
157
  <div className="Summary" data-testid="Summary">
@@ -9,8 +9,8 @@ import {useState} from 'preact/hooks';
9
9
 
10
10
  import {HelpDialog} from './help-dialog';
11
11
  import {getFilenamePrefix} from '../../report/generator/file-namer';
12
- import {useLocalizedStrings} from './i18n/i18n';
13
- import {HamburgerIcon, InfoIcon} from './icons';
12
+ import {useUIStrings} from './i18n/i18n';
13
+ import {HamburgerIcon} from './icons';
14
14
  import {useFlowResult} from './util';
15
15
  import {useReportRenderer} from './wrappers/report-renderer';
16
16
 
@@ -79,7 +79,7 @@ export const Topbar: FunctionComponent<{onMenuClick: JSX.MouseEventHandler<HTMLB
79
79
  ({onMenuClick}) => {
80
80
  const flowResult = useFlowResult();
81
81
  const {dom} = useReportRenderer();
82
- const strings = useLocalizedStrings();
82
+ const strings = useUIStrings();
83
83
  const [showHelpDialog, setShowHelpDialog] = useState(false);
84
84
 
85
85
  return (
@@ -98,12 +98,8 @@ export const Topbar: FunctionComponent<{onMenuClick: JSX.MouseEventHandler<HTMLB
98
98
  <div style={{flexGrow: 1}} />
99
99
  <TopbarButton
100
100
  onClick={() => setShowHelpDialog(previous => !previous)}
101
- label="Button that toggles the help dialog"
102
- >
103
- <div className="Topbar__help-label">
104
- <InfoIcon/>
105
- {strings.helpLabel}
106
- </div>
101
+ label="Button that toggles the help dialog">
102
+ {strings.helpLabel}
107
103
  </TopbarButton>
108
104
  {showHelpDialog ?
109
105
  <HelpDialog onClose={() => setShowHelpDialog(false)} /> :