lighthouse 13.6.0-dev.20261027 → 13.6.0-dev.20261029

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.
@@ -349,6 +349,11 @@ async function mergePlugins(config, configDir, flags) {
349
349
  const flagPlugins = flags?.plugins || [];
350
350
  const pluginNames = new Set([...configPlugins, ...flagPlugins]);
351
351
 
352
+ const configLocales = config.locales;
353
+ if (configLocales) {
354
+ delete config.locales;
355
+ }
356
+
352
357
  for (const pluginName of pluginNames) {
353
358
  validation.assertValidPluginName(config, pluginName);
354
359
 
@@ -362,6 +367,10 @@ async function mergePlugins(config, configDir, flags) {
362
367
  config = mergeConfigFragment(config, pluginJson);
363
368
  }
364
369
 
370
+ if (configLocales) {
371
+ config.locales = mergeConfigFragment(config.locales, configLocales);
372
+ }
373
+
365
374
  return config;
366
375
  }
367
376
 
@@ -34,6 +34,13 @@ declare class ConfigPlugin {
34
34
  * @return {Record<string, LH.Config.GroupJson>|undefined}
35
35
  */
36
36
  static _parseGroups(groupsJson: unknown, pluginName: string): Record<string, LH.Config.GroupJson> | undefined;
37
+ /**
38
+ * Extract and validate locales JSON added by the plugin.
39
+ * @param {unknown} localesJson
40
+ * @param {string} pluginName
41
+ * @return {NonNullable<LH.Config['locales']>|undefined}
42
+ */
43
+ static _parseLocales(localesJson: unknown, pluginName: string): NonNullable<LH.Config["locales"]> | undefined;
37
44
  /**
38
45
  * Extracts and validates a config from the provided plugin input, throwing
39
46
  * if it deviates from the expected object shape.
@@ -215,6 +215,53 @@ class ConfigPlugin {
215
215
  return parsedGroupsJson;
216
216
  }
217
217
 
218
+ /**
219
+ * Extract and validate locales JSON added by the plugin.
220
+ * @param {unknown} localesJson
221
+ * @param {string} pluginName
222
+ * @return {NonNullable<LH.Config['locales']>|undefined}
223
+ */
224
+ static _parseLocales(localesJson, pluginName) {
225
+ if (localesJson === undefined) {
226
+ return undefined;
227
+ }
228
+
229
+ if (!isObjectOfUnknownProperties(localesJson)) {
230
+ throw new Error(`${pluginName} locales json is not defined as an object.`);
231
+ }
232
+
233
+ /** @type {NonNullable<LH.Config['locales']>} */
234
+ const parsedLocalesJson = {};
235
+ for (const [locale, localeMessagesJson] of Object.entries(localesJson)) {
236
+ if (!isObjectOfUnknownProperties(localeMessagesJson)) {
237
+ throw new Error(`${pluginName} has a locale (${locale}) not defined as an object.`);
238
+ }
239
+
240
+ /** @type {Record<string, {message: string}>} */
241
+ const parsedMessages = {};
242
+ for (const [icuMessageId, messageEntry] of Object.entries(localeMessagesJson)) {
243
+ if (!isObjectOfUnknownProperties(messageEntry)) {
244
+ throw new Error(
245
+ `${pluginName} has a locale message (${icuMessageId}) not defined as an object.`
246
+ );
247
+ }
248
+
249
+ const {message, ...invalidRest} = messageEntry;
250
+ assertNoExcessProperties(invalidRest, pluginName, 'locale message');
251
+
252
+ if (typeof message !== 'string') {
253
+ throw new Error(`${pluginName} has an invalid locale message (${icuMessageId}).`);
254
+ }
255
+
256
+ parsedMessages[icuMessageId] = {message};
257
+ }
258
+
259
+ parsedLocalesJson[/** @type {LH.Locale} */ (locale)] = parsedMessages;
260
+ }
261
+
262
+ return parsedLocalesJson;
263
+ }
264
+
218
265
  /**
219
266
  * Extracts and validates a config from the provided plugin input, throwing
220
267
  * if it deviates from the expected object shape.
@@ -233,6 +280,7 @@ class ConfigPlugin {
233
280
  audits: pluginAuditsJson,
234
281
  category: pluginCategoryJson,
235
282
  groups: pluginGroupsJson,
283
+ locales: pluginLocalesJson,
236
284
  ...invalidRest
237
285
  } = pluginJson;
238
286
 
@@ -244,6 +292,7 @@ class ConfigPlugin {
244
292
  [pluginName]: ConfigPlugin._parseCategory(pluginCategoryJson, pluginName),
245
293
  },
246
294
  groups: ConfigPlugin._parseGroups(pluginGroupsJson, pluginName),
295
+ locales: ConfigPlugin._parseLocales(pluginLocalesJson, pluginName),
247
296
  };
248
297
  }
249
298
  }
@@ -163,6 +163,7 @@ async function resolveArtifactsToDefns(artifacts, configDir) {
163
163
  id: artifactJson.id,
164
164
  gatherer,
165
165
  dependencies: resolveArtifactDependencies(artifactJson, gatherer, artifactDefnsBySymbol),
166
+ alwaysGather: artifactJson.alwaysGather,
166
167
  };
167
168
 
168
169
  const symbol = artifact.gatherer.instance.meta.symbol;
@@ -229,6 +230,14 @@ async function initializeConfig(gatherMode, config, flags = {}) {
229
230
  configWorkingCopy = resolveExtensions(configWorkingCopy);
230
231
  configWorkingCopy = await mergePlugins(configWorkingCopy, configDir, flags);
231
232
 
233
+ if (configWorkingCopy.locales) {
234
+ for (const [locale, lhlMessages] of Object.entries(configWorkingCopy.locales)) {
235
+ if (lhlMessages) {
236
+ format.registerLocaleData(/** @type {LH.Locale} */ (locale), lhlMessages);
237
+ }
238
+ }
239
+ }
240
+
232
241
  const settings = resolveSettings(configWorkingCopy.settings || {}, flags);
233
242
  overrideSettingsForGatherMode(settings, gatherMode);
234
243
  overrideThrottlingWindows(settings);
@@ -69,6 +69,7 @@ function filterArtifactsByAvailableAudits(artifacts, audits) {
69
69
  /** @type {Set<string>} */
70
70
  const artifactIdsToKeep = new Set([
71
71
  ...filterResistantArtifactIds,
72
+ ...artifacts.filter(artifact => artifact.alwaysGather).map(artifact => artifact.id),
72
73
  ...audits.flatMap(audit => audit.implementation.meta.requiredArtifacts),
73
74
  ]);
74
75
 
package/core/index.d.ts CHANGED
@@ -68,6 +68,8 @@ export function auditFlowArtifacts(flowArtifacts: LH.UserFlow.FlowArtifacts, con
68
68
  }>;
69
69
  export function getAuditList(): string[];
70
70
  export const traceCategories: string[];
71
+ import * as i18n from './lib/i18n/i18n.js';
71
72
  import * as LH from '../types/lh.js';
72
73
  import { UserFlow } from './user-flow.js';
74
+ export { i18n };
73
75
  //# sourceMappingURL=index.d.ts.map
package/core/index.js CHANGED
@@ -11,6 +11,7 @@ import {ReportGenerator} from '../report/generator/report-generator.js';
11
11
  import {startTimespanGather} from './gather/timespan-runner.js';
12
12
  import {snapshotGather} from './gather/snapshot-runner.js';
13
13
  import {navigationGather} from './gather/navigation-runner.js';
14
+ import * as i18n from './lib/i18n/i18n.js';
14
15
  import * as LH from '../types/lh.js';
15
16
 
16
17
  /*
@@ -131,4 +132,5 @@ export {
131
132
  auditFlowArtifacts,
132
133
  getAuditList,
133
134
  traceCategories,
135
+ i18n,
134
136
  };
@@ -77,4 +77,6 @@ export function createIcuMessageFn(filename: string, fileStrings?: Record<string
77
77
  * @return {value is string|LH.IcuMessage}
78
78
  */
79
79
  export function isStringOrIcuMessage(value: unknown): value is string | LH.IcuMessage;
80
+ import { registerLocaleData } from '../../../shared/localization/format.js';
81
+ export { registerLocaleData };
80
82
  //# sourceMappingURL=i18n.d.ts.map
@@ -9,9 +9,14 @@ import url from 'url';
9
9
 
10
10
  import log from 'lighthouse-logger';
11
11
 
12
- import {getAvailableLocales} from '../../../shared/localization/format.js';
12
+ import {
13
+ getAvailableLocales,
14
+ isIcuMessage,
15
+ formatMessage,
16
+ registerLocaleData,
17
+ DEFAULT_LOCALE,
18
+ } from '../../../shared/localization/format.js';
13
19
  import {LH_ROOT} from '../../../shared/root.js';
14
- import {isIcuMessage, formatMessage, DEFAULT_LOCALE} from '../../../shared/localization/format.js';
15
20
 
16
21
  const UIStrings = {
17
22
  /** Used to show the duration in milliseconds that something lasted. The `{timeInMs}` placeholder will be replaced with the time duration, shown in milliseconds (e.g. 63 ms) */
@@ -232,4 +237,5 @@ export {
232
237
  lookupLocale,
233
238
  createIcuMessageFn,
234
239
  isStringOrIcuMessage,
240
+ registerLocaleData,
235
241
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lighthouse",
3
3
  "type": "module",
4
- "version": "13.6.0-dev.20261027",
4
+ "version": "13.6.0-dev.20261029",
5
5
  "description": "Automated auditing, performance metrics, and best practices for the web.",
6
6
  "main": "./core/index.js",
7
7
  "bin": {
@@ -466,7 +466,10 @@ function getAvailableLocales() {
466
466
  * @param {import('./locales').LhlMessages} lhlMessages
467
467
  */
468
468
  function registerLocaleData(locale, lhlMessages) {
469
- LOCALE_MESSAGES[locale] = lhlMessages;
469
+ LOCALE_MESSAGES[locale] = {
470
+ ...LOCALE_MESSAGES[locale],
471
+ ...lhlMessages,
472
+ };
470
473
  }
471
474
 
472
475
  /**
@@ -3791,6 +3791,9 @@
3791
3791
  "treemap/app/src/util.js | coverageColumnName": {
3792
3792
  "message": "Coverage"
3793
3793
  },
3794
+ "treemap/app/src/util.js | duplicateModuleHiddenCopiesLabel": {
3795
+ "message": "Copies outside this view: {count}"
3796
+ },
3794
3797
  "treemap/app/src/util.js | duplicateModulesLabel": {
3795
3798
  "message": "Duplicate modules"
3796
3799
  },
@@ -3791,6 +3791,9 @@
3791
3791
  "treemap/app/src/util.js | coverageColumnName": {
3792
3792
  "message": "Ĉóv̂ér̂áĝé"
3793
3793
  },
3794
+ "treemap/app/src/util.js | duplicateModuleHiddenCopiesLabel": {
3795
+ "message": "Ĉóp̂íêś ôút̂śîd́ê t́ĥíŝ v́îéŵ: {count}"
3796
+ },
3794
3797
  "treemap/app/src/util.js | duplicateModulesLabel": {
3795
3798
  "message": "D̂úp̂ĺîćât́ê ḿôd́ûĺêś"
3796
3799
  },
package/types/config.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import {Audit} from '../core/audits/audit.js';
9
- import {SharedFlagsSettings, ConfigSettings} from './lhr/settings.js';
9
+ import {SharedFlagsSettings, ConfigSettings, Locale} from './lhr/settings.js';
10
10
  import Gatherer from './gatherer.js';
11
11
  import {IcuMessage} from './lhr/i18n.js';
12
12
  import Result from './lhr/lhr.js';
@@ -26,6 +26,7 @@ interface Config {
26
26
  categories?: Record<string, Config.CategoryJson> | null;
27
27
  groups?: Record<string, Config.GroupJson> | null;
28
28
  plugins?: Array<string>;
29
+ locales?: Partial<Record<Locale, Record<string, {message: string}>>> | null;
29
30
  }
30
31
 
31
32
  declare namespace Config {
@@ -43,6 +44,7 @@ declare namespace Config {
43
44
  interface ArtifactJson {
44
45
  id: string;
45
46
  gatherer: GathererJson;
47
+ alwaysGather?: boolean;
46
48
  }
47
49
 
48
50
  type GathererJson = {
@@ -94,6 +96,7 @@ declare namespace Config {
94
96
  dependencies?: TDependencies extends Gatherer.DefaultDependenciesKey ?
95
97
  undefined :
96
98
  Record<Exclude<TDependencies, Gatherer.DefaultDependenciesKey>, {id: string}>;
99
+ alwaysGather?: boolean;
97
100
  }
98
101
 
99
102
  type ArtifactDefnExpander<TDependencies extends Gatherer.DependencyKey> =
@@ -136,6 +139,8 @@ declare namespace Config {
136
139
  category: Config.Category;
137
140
  /** Optionally provide more groups in addition to those specified by the base config. */
138
141
  groups?: Record<string, Config.GroupJson>;
142
+ /** Optionally provide locale messages for translating plugin strings. */
143
+ locales?: Partial<Record<Locale, Record<string, {message: string}>>>;
139
144
  }
140
145
 
141
146
  type Merge = {