@x18n/core 0.1.3 → 0.1.5
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.
- package/dist/index.d.mts +42 -1
- package/dist/index.mjs +53 -10
- package/package.json +1 -1
- package/schema/config.json +46 -0
- package/schema/plugin.json +46 -0
package/dist/index.d.mts
CHANGED
|
@@ -284,9 +284,13 @@ interface LocaleInfo {
|
|
|
284
284
|
readonly region: string | undefined;
|
|
285
285
|
readonly displayName: string | undefined;
|
|
286
286
|
readonly flag: string | undefined;
|
|
287
|
+
/** The plural categories a message may have. */
|
|
287
288
|
readonly pluralCategories: readonly Intl.LDMLPluralRule[];
|
|
288
289
|
/** Categories of ordinal numbers (1st, 2nd), which differ from the cardinal ones. */
|
|
289
290
|
readonly ordinalCategories: readonly Intl.LDMLPluralRule[];
|
|
291
|
+
/** The plural categories a message must have: those whole numbers select. French may leave out `many`, from 1,000,000 only. */
|
|
292
|
+
readonly requiredPluralCategories: readonly Intl.LDMLPluralRule[];
|
|
293
|
+
readonly requiredOrdinalCategories: readonly Intl.LDMLPluralRule[];
|
|
290
294
|
}
|
|
291
295
|
/** Embedded resource inside a file, for example a Vue `<i18n>` block. */
|
|
292
296
|
interface ResourceBlock {
|
|
@@ -330,6 +334,10 @@ interface Usage {
|
|
|
330
334
|
readonly range: TextRange;
|
|
331
335
|
/** Range of the whole call that holds the key (`t('a', { n })`), when the scanner knows it. */
|
|
332
336
|
readonly expression: TextRange | undefined;
|
|
337
|
+
/** Names of the params the call passes (`t('a', { n })` gives `['n']`); undefined when the scanner cannot tell, as with a spread or a variable. */
|
|
338
|
+
readonly params?: readonly string[] | undefined;
|
|
339
|
+
/** The default value written in code (`t('a', 'Default')`), when the scanner knows it. */
|
|
340
|
+
readonly defaultValue?: string | undefined;
|
|
333
341
|
readonly scanner: string;
|
|
334
342
|
readonly kind: UsageKind;
|
|
335
343
|
/** `t(`pages.${id}.title`)` gives 'prefix' with key `pages`. */
|
|
@@ -623,6 +631,10 @@ interface UsageCandidate {
|
|
|
623
631
|
readonly range: TextRange;
|
|
624
632
|
/** Range of the whole call that holds the key, when the scanner knows it. */
|
|
625
633
|
readonly expression?: TextRange | undefined;
|
|
634
|
+
/** Names of the params the call passes, when they are all static. */
|
|
635
|
+
readonly params?: readonly string[] | undefined;
|
|
636
|
+
/** The default value the call writes in code. */
|
|
637
|
+
readonly defaultValue?: string | undefined;
|
|
626
638
|
readonly kind: UsageKind;
|
|
627
639
|
readonly dynamic: false | "prefix" | "unknown";
|
|
628
640
|
readonly namespace?: string | undefined;
|
|
@@ -782,10 +794,19 @@ interface ReportInput {
|
|
|
782
794
|
readonly coverage: readonly LocaleCoverage[];
|
|
783
795
|
readonly summary: ReportSummary;
|
|
784
796
|
}
|
|
797
|
+
/** What a check baseline left out (`x18n check --baseline`). */
|
|
798
|
+
interface BaselineSummary {
|
|
799
|
+
/** Known diagnostics that the baseline left out of the report. */
|
|
800
|
+
readonly suppressed: number;
|
|
801
|
+
/** Baseline entries that no longer occur, to drop with `--update-baseline`. */
|
|
802
|
+
readonly fixed: number;
|
|
803
|
+
}
|
|
785
804
|
interface ReporterContext {
|
|
786
805
|
/** Turns a project path into the path to print (relative to the cwd). */
|
|
787
806
|
readonly displayPath: (path: string, project: string) => string;
|
|
788
807
|
readonly color: boolean;
|
|
808
|
+
/** Set when a baseline applies; the inputs then hold only new diagnostics. */
|
|
809
|
+
readonly baseline?: BaselineSummary | undefined;
|
|
789
810
|
}
|
|
790
811
|
interface Reporter {
|
|
791
812
|
readonly id: string;
|
|
@@ -907,6 +928,13 @@ interface ArgSource {
|
|
|
907
928
|
readonly arg: number;
|
|
908
929
|
readonly property?: string | undefined;
|
|
909
930
|
}
|
|
931
|
+
/** Where the params of a call are: the static keys of an object literal argument. */
|
|
932
|
+
interface ParamsSource {
|
|
933
|
+
/** Arguments that may hold the params object, in order; string arguments are skipped (`t(key, 'Default', { n })`). */
|
|
934
|
+
readonly arg: number | readonly number[];
|
|
935
|
+
/** Option names the library reads itself, which a message need not use (`ns`, `defaultValue`). */
|
|
936
|
+
readonly options?: readonly string[] | undefined;
|
|
937
|
+
}
|
|
910
938
|
/** Data that drives the AST scanners: which calls are translate calls and where the key is. */
|
|
911
939
|
interface CallSpec {
|
|
912
940
|
/** Function or member path: 't', '$t', 'i18n.t', 'intl.formatMessage'. */
|
|
@@ -919,6 +947,10 @@ interface CallSpec {
|
|
|
919
947
|
readonly namespace?: ArgSource | string | undefined;
|
|
920
948
|
/** Where a key prefix comes from (`keyPrefix` option, or next-intl `useTranslations('a.b')`). */
|
|
921
949
|
readonly keyPrefix?: ArgSource | undefined;
|
|
950
|
+
/** Where the params passed to the message are. For factories, those of the returned functions. */
|
|
951
|
+
readonly params?: ParamsSource | undefined;
|
|
952
|
+
/** Where a default value written in code comes from; the first string found wins. For factories, that of the returned functions. */
|
|
953
|
+
readonly defaultValue?: readonly ArgSource[] | undefined;
|
|
922
954
|
/** The callee is a factory that returns the translate function, for example `useI18n()` returning `{ t }`. */
|
|
923
955
|
readonly factory?: boolean | undefined;
|
|
924
956
|
/** For factories: the names of the returned translate functions. Default `['t']`. */
|
|
@@ -1308,6 +1340,13 @@ interface PromptOptions {
|
|
|
1308
1340
|
readonly context?: boolean | undefined;
|
|
1309
1341
|
/** Translate prompts: add stale translations (load history first). */
|
|
1310
1342
|
readonly stale?: boolean | undefined;
|
|
1343
|
+
/** Translate prompts: add translations that checks report in the target locale, all of them (`true`) or of these check ids. */
|
|
1344
|
+
readonly check?: boolean | readonly string[] | undefined;
|
|
1345
|
+
}
|
|
1346
|
+
interface PromptIssue {
|
|
1347
|
+
/** Check id, for example `identical-to-source`. */
|
|
1348
|
+
readonly code: string;
|
|
1349
|
+
readonly message: string;
|
|
1311
1350
|
}
|
|
1312
1351
|
interface UsageContext {
|
|
1313
1352
|
readonly path: string;
|
|
@@ -1322,6 +1361,8 @@ interface PromptItem {
|
|
|
1322
1361
|
readonly existing: string | undefined;
|
|
1323
1362
|
/** For a stale translation: the source value when the translation last changed, when known. */
|
|
1324
1363
|
readonly previousSource?: string | undefined;
|
|
1364
|
+
/** With `check`: what the checks report for the current value. */
|
|
1365
|
+
readonly issues?: readonly PromptIssue[] | undefined;
|
|
1325
1366
|
readonly context: readonly UsageContext[];
|
|
1326
1367
|
}
|
|
1327
1368
|
interface PromptData {
|
|
@@ -1748,4 +1789,4 @@ export declare function rangeContains(range: TextRange, offset: number): boolean
|
|
|
1748
1789
|
/** Fast non-cryptographic string hash (cyrb53), as hex. */
|
|
1749
1790
|
export declare function hashText(text: string): string;
|
|
1750
1791
|
//#endregion
|
|
1751
|
-
export type { Analysis, Answers, ApplyResult, ArgSource, Builtins, CacheStore, CallSpec, CapabilityConflict, Check, CheckContext, CheckIds, CheckLevel, CheckSetting, ConfigContext, ConfigDraft, ConfigOrigin, CreateProjectOptions, Decision, DecisionOption, DetectContext, Diagnostic, DiagnosticInput, Disposable, EditOp, Envelope, ErrorCode, ErrorInfo, ExtractItem, ExtractOptions, ExtractTemplate, Extractor, FileChange, FileEvent, FileScan, FinderContext, Fix, Format, FormatContext, FormatEntry, GlobOptions, GlossaryEntry, HardString, HistoryConfigs, HistoryContext, HistoryOptions, HistoryProvider, HistorySettings, Host, JsonObject, JsonPrimitive, JsonValue, KeyContext, KeyId, KeyInfo, KeyQuery, KeyString, KeyTarget, LazyFormat, LazyScanner, LibraryOptions, LineIndex, LinePosition, LocaleCode, LocaleCoverage, LocaleFinder, LocaleInfo, Location, Logger, ManifestReader, MemoryHost, Message, MessageChange, MessageHistory, MessageLeaf, MessageOp, MessageTree, NamespaceFromPath, NamespaceOptions, NodeRange, OverlayHost, ParseResult, Placeholder, PlaceholderComparer, PlaceholderProblem, PlaceholderSyntax, Plan, Plugin, PluginConfigs, PluginFile, PluginLoader, PluginOption, PluginRegistry, PluginSpecifier, PluralForm, Preset, PresetDetection, PresetEntry, PresetExplanation, PresetFactory, PresetLoader, PresetOption, Project, ProjectChange, ProjectExplanation, PromptContext, PromptData, PromptDraft, PromptItem, PromptOptions, RegexScannerSpec, ReportInput, ReportSummary, Reporter, ReporterContext, ReporterLoader, ResolveConfigOptions, ResolvedConfig, Resource, ResourceBlock, ResourceCandidate, ResourceId, ResourceNode, ResourceSpec, ResourceTransform, ResourceTransformContext, ReviewAuthor, ReviewComment, ReviewData, ReviewFile, ReviewFilter, ReviewOptions, ReviewState, ReviewStore, ReviewThread, ReviewType, ScanContext, ScanResult, Scanner, ScannerEntry, SchemaIssue, Scope, SearchMatch, SearchOptions, SerializableConfig, Setup, Severity, SourceFile, TextEdit, TextRange, ThreadComment, TreeLeaf, Usage, UsageCandidate, UsageContext, UsageKind, UsageMatch, UsageOptions, UsageQuery, UserConfig, WireDiagnostic, WireRange, WriteOptions, X18nError };
|
|
1792
|
+
export type { Analysis, Answers, ApplyResult, ArgSource, BaselineSummary, Builtins, CacheStore, CallSpec, CapabilityConflict, Check, CheckContext, CheckIds, CheckLevel, CheckSetting, ConfigContext, ConfigDraft, ConfigOrigin, CreateProjectOptions, Decision, DecisionOption, DetectContext, Diagnostic, DiagnosticInput, Disposable, EditOp, Envelope, ErrorCode, ErrorInfo, ExtractItem, ExtractOptions, ExtractTemplate, Extractor, FileChange, FileEvent, FileScan, FinderContext, Fix, Format, FormatContext, FormatEntry, GlobOptions, GlossaryEntry, HardString, HistoryConfigs, HistoryContext, HistoryOptions, HistoryProvider, HistorySettings, Host, JsonObject, JsonPrimitive, JsonValue, KeyContext, KeyId, KeyInfo, KeyQuery, KeyString, KeyTarget, LazyFormat, LazyScanner, LibraryOptions, LineIndex, LinePosition, LocaleCode, LocaleCoverage, LocaleFinder, LocaleInfo, Location, Logger, ManifestReader, MemoryHost, Message, MessageChange, MessageHistory, MessageLeaf, MessageOp, MessageTree, NamespaceFromPath, NamespaceOptions, NodeRange, OverlayHost, ParamsSource, ParseResult, Placeholder, PlaceholderComparer, PlaceholderProblem, PlaceholderSyntax, Plan, Plugin, PluginConfigs, PluginFile, PluginLoader, PluginOption, PluginRegistry, PluginSpecifier, PluralForm, Preset, PresetDetection, PresetEntry, PresetExplanation, PresetFactory, PresetLoader, PresetOption, Project, ProjectChange, ProjectExplanation, PromptContext, PromptData, PromptDraft, PromptIssue, PromptItem, PromptOptions, RegexScannerSpec, ReportInput, ReportSummary, Reporter, ReporterContext, ReporterLoader, ResolveConfigOptions, ResolvedConfig, Resource, ResourceBlock, ResourceCandidate, ResourceId, ResourceNode, ResourceSpec, ResourceTransform, ResourceTransformContext, ReviewAuthor, ReviewComment, ReviewData, ReviewFile, ReviewFilter, ReviewOptions, ReviewState, ReviewStore, ReviewThread, ReviewType, ScanContext, ScanResult, Scanner, ScannerEntry, SchemaIssue, Scope, SearchMatch, SearchOptions, SerializableConfig, Setup, Severity, SourceFile, TextEdit, TextRange, ThreadComment, TreeLeaf, Usage, UsageCandidate, UsageContext, UsageKind, UsageMatch, UsageOptions, UsageQuery, UserConfig, WireDiagnostic, WireRange, WriteOptions, X18nError };
|
package/dist/index.mjs
CHANGED
|
@@ -492,6 +492,14 @@ function parseLocaleInfo(code) {
|
|
|
492
492
|
const found = language ? safe(() => new Intl.PluralRules(tag, { type }).resolvedOptions().pluralCategories) : void 0;
|
|
493
493
|
return found ? pluralOrder.filter((category) => found.includes(category)) : ["other"];
|
|
494
494
|
};
|
|
495
|
+
const required = (type) => {
|
|
496
|
+
const found = /* @__PURE__ */ new Set(["other"]);
|
|
497
|
+
if (language && safe(() => Intl.PluralRules.supportedLocalesOf([tag]).length > 0)) {
|
|
498
|
+
const rules = new Intl.PluralRules(tag, { type });
|
|
499
|
+
for (let n = 0; n < 2e3; n++) found.add(rules.select(n));
|
|
500
|
+
}
|
|
501
|
+
return pluralOrder.filter((category) => found.has(category));
|
|
502
|
+
};
|
|
495
503
|
const flagRegion = region ?? (language === "zh" && script === "Hant" ? "TW" : language ? defaultRegions[language] : void 0);
|
|
496
504
|
return {
|
|
497
505
|
code,
|
|
@@ -500,7 +508,9 @@ function parseLocaleInfo(code) {
|
|
|
500
508
|
displayName,
|
|
501
509
|
flag: flagRegion ? flagOf(flagRegion) : void 0,
|
|
502
510
|
pluralCategories: categories("cardinal"),
|
|
503
|
-
ordinalCategories: categories("ordinal")
|
|
511
|
+
ordinalCategories: categories("ordinal"),
|
|
512
|
+
requiredPluralCategories: required("cardinal"),
|
|
513
|
+
requiredOrdinalCategories: required("ordinal")
|
|
504
514
|
};
|
|
505
515
|
}
|
|
506
516
|
/** Codes that differ only in spelling (`zh_CN` and `zh-cn`), the same after a lenient normalization. */
|
|
@@ -776,6 +786,10 @@ const argSource = v.strictObject({
|
|
|
776
786
|
arg: v.number(),
|
|
777
787
|
property: v.optional(v.string())
|
|
778
788
|
});
|
|
789
|
+
const paramsSource = v.strictObject({
|
|
790
|
+
arg: v.union([v.number(), v.array(v.number())]),
|
|
791
|
+
options: v.optional(strings)
|
|
792
|
+
});
|
|
779
793
|
const callSpec = v.strictObject({
|
|
780
794
|
callee: v.union([v.string(), strings]),
|
|
781
795
|
kind: v.optional(v.picklist([
|
|
@@ -786,6 +800,8 @@ const callSpec = v.strictObject({
|
|
|
786
800
|
key: v.optional(v.union([v.number(), argSource])),
|
|
787
801
|
namespace: v.optional(v.union([argSource, v.string()])),
|
|
788
802
|
keyPrefix: v.optional(argSource),
|
|
803
|
+
params: v.optional(paramsSource),
|
|
804
|
+
defaultValue: v.optional(v.array(argSource)),
|
|
789
805
|
factory: v.optional(v.boolean()),
|
|
790
806
|
returns: v.optional(strings),
|
|
791
807
|
types: v.optional(strings)
|
|
@@ -1167,6 +1183,8 @@ function createUsageResolver(config, namespaced, normalizers) {
|
|
|
1167
1183
|
path,
|
|
1168
1184
|
range: candidate.range,
|
|
1169
1185
|
expression: candidate.expression,
|
|
1186
|
+
...candidate.params ? { params: candidate.params } : {},
|
|
1187
|
+
...candidate.defaultValue === void 0 ? {} : { defaultValue: candidate.defaultValue },
|
|
1170
1188
|
scanner,
|
|
1171
1189
|
kind: candidate.kind,
|
|
1172
1190
|
dynamic: candidate.dynamic,
|
|
@@ -1202,8 +1220,12 @@ function suppressedRanges(text) {
|
|
|
1202
1220
|
}
|
|
1203
1221
|
return ranges;
|
|
1204
1222
|
}
|
|
1205
|
-
/** The plural categories of a locale's language: Japanese has only `other`. */
|
|
1206
|
-
function categoriesOf(info, type) {
|
|
1223
|
+
/** The plural categories of a locale's language: Japanese has only `other`. `required` keeps those whole numbers select. */
|
|
1224
|
+
function categoriesOf(info, type, required = false) {
|
|
1225
|
+
if (required) {
|
|
1226
|
+
const allowed = categoriesOf(info, type);
|
|
1227
|
+
return (type === "ordinal" ? info.requiredOrdinalCategories : info.requiredPluralCategories).filter((category) => category === "other" || allowed.includes(category));
|
|
1228
|
+
}
|
|
1207
1229
|
return type === "ordinal" ? info.ordinalCategories : info.pluralCategories;
|
|
1208
1230
|
}
|
|
1209
1231
|
const tokens = /(\{key\}|\{plural\}|\{ordinal\}|\*)/;
|
|
@@ -1282,7 +1304,7 @@ function levelOf(setting) {
|
|
|
1282
1304
|
}
|
|
1283
1305
|
/**
|
|
1284
1306
|
* The keys a locale needs: the reference keys, with plural forms swapped for the categories of the locale's
|
|
1285
|
-
* language. Forms the language lacks (`item_zero` in English) count only where they exist.
|
|
1307
|
+
* language. Forms the language lacks or may leave out (`item_zero` in English, `item_many` in French) count only where they exist.
|
|
1286
1308
|
*/
|
|
1287
1309
|
function expectedKeys(state, options, reference, locale) {
|
|
1288
1310
|
const info = options.localeInfo(locale);
|
|
@@ -1290,7 +1312,7 @@ function expectedKeys(state, options, reference, locale) {
|
|
|
1290
1312
|
for (const key of reference) {
|
|
1291
1313
|
const form = options.formOf(key);
|
|
1292
1314
|
if (!form || state.messages.get(key)?.has(locale)) keys.add(key);
|
|
1293
|
-
form && categoriesOf(info, form.type).forEach((category) => keys.add(form.keyOf(category)));
|
|
1315
|
+
form && categoriesOf(info, form.type, true).forEach((category) => keys.add(form.keyOf(category)));
|
|
1294
1316
|
}
|
|
1295
1317
|
return [...keys].sort();
|
|
1296
1318
|
}
|
|
@@ -2416,13 +2438,28 @@ function contextOf(project, key) {
|
|
|
2416
2438
|
}];
|
|
2417
2439
|
});
|
|
2418
2440
|
}
|
|
2441
|
+
/** The diagnostics of checks (all, or these ids) on values the locale has, by key. */
|
|
2442
|
+
function reportedValues(project, diagnostics, to, check) {
|
|
2443
|
+
const codes = check === true ? void 0 : new Set(check);
|
|
2444
|
+
const reported = /* @__PURE__ */ new Map();
|
|
2445
|
+
for (const diagnostic of diagnostics) {
|
|
2446
|
+
if (diagnostic.key === void 0 || diagnostic.locale !== to || codes && !codes.has(diagnostic.code)) continue;
|
|
2447
|
+
if (!text(project.message(diagnostic.key, to)?.value)) continue;
|
|
2448
|
+
const found = reported.get(diagnostic.key) ?? [];
|
|
2449
|
+
reported.set(diagnostic.key, found);
|
|
2450
|
+
found.push(diagnostic);
|
|
2451
|
+
}
|
|
2452
|
+
return reported;
|
|
2453
|
+
}
|
|
2419
2454
|
/** Builds the parts of a translate or review prompt from project state. */
|
|
2420
2455
|
function buildPrompt(project, kind, to, options, extra) {
|
|
2421
2456
|
const from = project.sourceLocale;
|
|
2422
2457
|
const match = typeof options.keys === "string" ? keyMatcher([options.keys]) : void 0;
|
|
2423
2458
|
const list = Array.isArray(options.keys) ? new Set(options.keys) : void 0;
|
|
2424
|
-
const
|
|
2459
|
+
const analysis = project.analyze();
|
|
2460
|
+
const outdated = new Set(analysis.coverage.find((c) => c.locale === to)?.outdated);
|
|
2425
2461
|
const stale = (key) => outdated.has(key);
|
|
2462
|
+
const reported = kind === "translate" && options.check ? reportedValues(project, analysis.diagnostics, to, options.check) : /* @__PURE__ */ new Map();
|
|
2426
2463
|
const candidates = project.keys({ namespace: options.namespace }).filter((key) => {
|
|
2427
2464
|
if (match && !match(key)) return false;
|
|
2428
2465
|
if (list && !list.has(key)) return false;
|
|
@@ -2430,7 +2467,7 @@ function buildPrompt(project, kind, to, options, extra) {
|
|
|
2430
2467
|
if (source === void 0 || source === "") return false;
|
|
2431
2468
|
const target = text(project.message(key, to)?.value);
|
|
2432
2469
|
if (kind === "review") return target !== void 0 && target !== "";
|
|
2433
|
-
return list !== void 0 || target === void 0 || target === "" || options.stale === true && stale(key);
|
|
2470
|
+
return list !== void 0 || target === void 0 || target === "" || options.stale === true && stale(key) || reported.has(key);
|
|
2434
2471
|
});
|
|
2435
2472
|
const start = Number(options.cursor ?? 0) || 0;
|
|
2436
2473
|
const limit = options.limit ?? 50;
|
|
@@ -2444,6 +2481,7 @@ function buildPrompt(project, kind, to, options, extra) {
|
|
|
2444
2481
|
};
|
|
2445
2482
|
if (syntaxes.length > 0) draft.rules.push(`Keep every placeholder exactly as written (${syntaxes.map((s) => `\`${s.example ?? s.id}\``).join(", ")}); do not translate their names.`);
|
|
2446
2483
|
draft.rules.push("Keep markup tags and their attributes as they are.", "Match the tone and wording of the existing messages in the target locale.", "Do not translate glossary terms marked \"do not translate\".");
|
|
2484
|
+
if (reported.size > 0) draft.rules.push(`A message with a reported problem has a current ${to} value: fix the problem. When the current value is right as it is, such as a word that is the same in both languages, leave the key out of the results.`);
|
|
2447
2485
|
if (info.pluralCategories.length > 1) draft.notes.push(`${to} uses the plural categories ${info.pluralCategories.join(", ")}.`);
|
|
2448
2486
|
for (const hook of extra.hooks) hook(draft, {
|
|
2449
2487
|
sourceLocale: from,
|
|
@@ -2453,7 +2491,7 @@ function buildPrompt(project, kind, to, options, extra) {
|
|
|
2453
2491
|
const examples = kind === "translate" ? project.keys().flatMap((key) => {
|
|
2454
2492
|
const source = text(project.message(key, from)?.value);
|
|
2455
2493
|
const target = text(project.message(key, to)?.value);
|
|
2456
|
-
return source && target && !candidates.includes(key) ? [{
|
|
2494
|
+
return source && target && target !== source && !candidates.includes(key) ? [{
|
|
2457
2495
|
key,
|
|
2458
2496
|
source,
|
|
2459
2497
|
target
|
|
@@ -2469,6 +2507,10 @@ function buildPrompt(project, kind, to, options, extra) {
|
|
|
2469
2507
|
placeholders: [...new Set(syntaxes.flatMap((s) => s.find(source)).map((p) => p.text))],
|
|
2470
2508
|
existing: text(project.message(key, to)?.value) || void 0,
|
|
2471
2509
|
previousSource: previous === source ? void 0 : previous,
|
|
2510
|
+
issues: reported.get(key)?.map((d) => ({
|
|
2511
|
+
code: d.code,
|
|
2512
|
+
message: d.message
|
|
2513
|
+
})),
|
|
2472
2514
|
context: options.context === false ? [] : contextOf(project, key)
|
|
2473
2515
|
};
|
|
2474
2516
|
});
|
|
@@ -2513,6 +2555,7 @@ function renderItem(item, to) {
|
|
|
2513
2555
|
if (item.placeholders.length) out.push(`- Placeholders: ${item.placeholders.map((p) => `\`${p}\``).join(", ")}`);
|
|
2514
2556
|
if (item.previousSource !== void 0) out.push(`- Source when ${to} last changed: ${JSON.stringify(item.previousSource)}`);
|
|
2515
2557
|
if (item.existing !== void 0) out.push(`- Current ${to}: ${JSON.stringify(item.existing)}`);
|
|
2558
|
+
for (const issue of item.issues ?? []) out.push(`- Reported: ${issue.message} (\`${issue.code}\`)`);
|
|
2516
2559
|
for (const context of item.context) out.push(`- Used in \`${context.path}:${context.line}\`:`, "", " ```", ...context.snippet.split("\n").map((line) => ` ${line}`), " ```");
|
|
2517
2560
|
out.push("");
|
|
2518
2561
|
return out;
|
|
@@ -2605,10 +2648,10 @@ function createProject(options) {
|
|
|
2605
2648
|
}
|
|
2606
2649
|
return info;
|
|
2607
2650
|
}
|
|
2608
|
-
/** Whether `locale` needs `key`: not a plural form of a category its language lacks. */
|
|
2651
|
+
/** Whether `locale` needs `key`: not a plural form of a category its language lacks or may leave out. */
|
|
2609
2652
|
function needs(key, locale) {
|
|
2610
2653
|
const form = formOf(key);
|
|
2611
|
-
return !form || categoriesOf(localeInfo(locale), form.type).includes(form.category);
|
|
2654
|
+
return !form || categoriesOf(localeInfo(locale), form.type, true).includes(form.category);
|
|
2612
2655
|
}
|
|
2613
2656
|
const reviewStore = config.review.enabled ? registry.reviewStores.at(-1) : void 0;
|
|
2614
2657
|
async function loadReviews() {
|
package/package.json
CHANGED
package/schema/config.json
CHANGED
|
@@ -272,6 +272,52 @@
|
|
|
272
272
|
],
|
|
273
273
|
"additionalProperties": false
|
|
274
274
|
},
|
|
275
|
+
"params": {
|
|
276
|
+
"type": "object",
|
|
277
|
+
"properties": {
|
|
278
|
+
"arg": {
|
|
279
|
+
"anyOf": [
|
|
280
|
+
{
|
|
281
|
+
"type": "number"
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
"type": "array",
|
|
285
|
+
"items": {
|
|
286
|
+
"type": "number"
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
]
|
|
290
|
+
},
|
|
291
|
+
"options": {
|
|
292
|
+
"type": "array",
|
|
293
|
+
"items": {
|
|
294
|
+
"type": "string"
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
"required": [
|
|
299
|
+
"arg"
|
|
300
|
+
],
|
|
301
|
+
"additionalProperties": false
|
|
302
|
+
},
|
|
303
|
+
"defaultValue": {
|
|
304
|
+
"type": "array",
|
|
305
|
+
"items": {
|
|
306
|
+
"type": "object",
|
|
307
|
+
"properties": {
|
|
308
|
+
"arg": {
|
|
309
|
+
"type": "number"
|
|
310
|
+
},
|
|
311
|
+
"property": {
|
|
312
|
+
"type": "string"
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
"required": [
|
|
316
|
+
"arg"
|
|
317
|
+
],
|
|
318
|
+
"additionalProperties": false
|
|
319
|
+
}
|
|
320
|
+
},
|
|
275
321
|
"factory": {
|
|
276
322
|
"type": "boolean"
|
|
277
323
|
},
|
package/schema/plugin.json
CHANGED
|
@@ -217,6 +217,52 @@
|
|
|
217
217
|
],
|
|
218
218
|
"additionalProperties": false
|
|
219
219
|
},
|
|
220
|
+
"params": {
|
|
221
|
+
"type": "object",
|
|
222
|
+
"properties": {
|
|
223
|
+
"arg": {
|
|
224
|
+
"anyOf": [
|
|
225
|
+
{
|
|
226
|
+
"type": "number"
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"type": "array",
|
|
230
|
+
"items": {
|
|
231
|
+
"type": "number"
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
]
|
|
235
|
+
},
|
|
236
|
+
"options": {
|
|
237
|
+
"type": "array",
|
|
238
|
+
"items": {
|
|
239
|
+
"type": "string"
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
"required": [
|
|
244
|
+
"arg"
|
|
245
|
+
],
|
|
246
|
+
"additionalProperties": false
|
|
247
|
+
},
|
|
248
|
+
"defaultValue": {
|
|
249
|
+
"type": "array",
|
|
250
|
+
"items": {
|
|
251
|
+
"type": "object",
|
|
252
|
+
"properties": {
|
|
253
|
+
"arg": {
|
|
254
|
+
"type": "number"
|
|
255
|
+
},
|
|
256
|
+
"property": {
|
|
257
|
+
"type": "string"
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
"required": [
|
|
261
|
+
"arg"
|
|
262
|
+
],
|
|
263
|
+
"additionalProperties": false
|
|
264
|
+
}
|
|
265
|
+
},
|
|
220
266
|
"factory": {
|
|
221
267
|
"type": "boolean"
|
|
222
268
|
},
|