@x18n/core 0.1.6 → 0.1.7

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 CHANGED
@@ -248,235 +248,6 @@ interface ReviewFilter {
248
248
  readonly open?: boolean | undefined;
249
249
  }
250
250
  //#endregion
251
- //#region src/types/model.d.ts
252
- /** A locale code exactly as written in paths and files: `en`, `zh_CN`, `pt-BR`. Never normalized. */
253
- type LocaleCode = string;
254
- /** Canonical key string: `ns:a.b.c`, or `a.b.c` without namespace. */
255
- type KeyString = string;
256
- /** Resource id: the resource path, plus `#<block index>` for embedded resources. */
257
- type ResourceId = string;
258
- type MessageLeaf = string | number | boolean | null;
259
- interface MessageTree {
260
- readonly [segment: string]: MessageLeaf | MessageTree;
261
- }
262
- /** UTF-16 offsets, the same as JS strings. */
263
- interface TextRange {
264
- readonly start: number;
265
- readonly end: number;
266
- }
267
- interface TextEdit {
268
- readonly range: TextRange;
269
- readonly text: string;
270
- }
271
- /** Ranges of a key and its value (or object) in the resource text. */
272
- interface NodeRange {
273
- readonly key: TextRange;
274
- readonly value: TextRange;
275
- }
276
- interface KeyId {
277
- readonly namespace: string | undefined;
278
- readonly path: readonly string[];
279
- }
280
- /** Display data from a lenient parse of a code. Never changes the code itself. */
281
- interface LocaleInfo {
282
- readonly code: LocaleCode;
283
- readonly language: string | undefined;
284
- readonly region: string | undefined;
285
- readonly displayName: string | undefined;
286
- readonly flag: string | undefined;
287
- /** The plural categories a message may have. */
288
- readonly pluralCategories: readonly Intl.LDMLPluralRule[];
289
- /** Categories of ordinal numbers (1st, 2nd), which differ from the cardinal ones. */
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[];
294
- }
295
- /** Embedded resource inside a file, for example a Vue `<i18n>` block. */
296
- interface ResourceBlock {
297
- readonly index: number;
298
- /** Range of the block content in the file. */
299
- readonly range: TextRange;
300
- readonly lang: string | undefined;
301
- }
302
- interface Resource {
303
- readonly id: ResourceId;
304
- /** Posix path relative to the project root. */
305
- readonly path: string;
306
- readonly locale: LocaleCode;
307
- readonly namespace: string | undefined;
308
- readonly format: string;
309
- readonly block: ResourceBlock | undefined;
310
- /** True for read-only formats and for resources loaded with `execute: true`. */
311
- readonly readonly: boolean;
312
- /** Id of the locale finder that found the resource. */
313
- readonly finder: string;
314
- }
315
- /** One stored value of one key in one locale. */
316
- interface Message {
317
- readonly key: KeyString;
318
- readonly locale: LocaleCode;
319
- readonly value: MessageLeaf;
320
- readonly resource: ResourceId;
321
- /** Property path as stored in the resource (`['a.b']` in a flat file, `['a', 'b']` nested). */
322
- readonly storedPath: readonly string[];
323
- /** Ranges in the resource file text (block offsets already added). */
324
- readonly range: NodeRange | undefined;
325
- }
326
- type UsageKind = "call" | "selector" | "accessor" | "constant" | "marker";
327
- interface Usage {
328
- /** Undefined when the key is fully dynamic. */
329
- readonly key: KeyString | undefined;
330
- /** The key text as written in code. */
331
- readonly raw: string;
332
- readonly path: string;
333
- /** Range of the key text only (inside the quotes): the range rename rewrites. */
334
- readonly range: TextRange;
335
- /** Range of the whole call that holds the key (`t('a', { n })`), when the scanner knows it. */
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;
341
- readonly scanner: string;
342
- readonly kind: UsageKind;
343
- /** `t(`pages.${id}.title`)` gives 'prefix' with key `pages`. */
344
- readonly dynamic: false | "prefix" | "unknown";
345
- readonly locale: LocaleCode | undefined;
346
- /** Namespace that came from a scope or a factory, not from the raw text. */
347
- readonly scopeNamespace: string | undefined;
348
- /** Key prefix that came from a scope or factory (`keyPrefix`), not from the raw text. */
349
- readonly scopePrefix: string | undefined;
350
- }
351
- type Severity = "error" | "warning" | "info" | "hint";
352
- type EditOp = {
353
- readonly type: "set";
354
- readonly key: KeyString;
355
- readonly locale: LocaleCode;
356
- readonly value: MessageLeaf;
357
- } | {
358
- readonly type: "rename";
359
- readonly from: KeyString;
360
- readonly to: KeyString;
361
- readonly usages?: boolean;
362
- } | {
363
- readonly type: "rename-prefix";
364
- readonly from: KeyString;
365
- readonly to: KeyString;
366
- readonly usages?: boolean;
367
- } | {
368
- readonly type: "delete";
369
- readonly key: KeyString;
370
- readonly locales?: "all" | readonly LocaleCode[];
371
- } | {
372
- readonly type: "extract";
373
- readonly items: readonly ExtractItem[];
374
- } | {
375
- readonly type: "format";
376
- readonly paths?: readonly string[];
377
- } | {
378
- readonly type: "review";
379
- readonly key: KeyString;
380
- readonly locale: LocaleCode;
381
- readonly review: ReviewType;
382
- readonly text?: string | undefined;
383
- /** The proposed value, required for `suggestion`. */
384
- readonly suggestion?: string | undefined;
385
- readonly author?: ReviewAuthor | undefined;
386
- readonly id?: string | undefined;
387
- readonly time?: string | undefined;
388
- } | {
389
- readonly type: "resolve-review";
390
- readonly id: string;
391
- } | {
392
- readonly type: "apply-suggestion";
393
- readonly id: string;
394
- } | {
395
- readonly type: "mark-fresh";
396
- readonly key: KeyString;
397
- readonly locales?: readonly LocaleCode[] | undefined;
398
- };
399
- interface ExtractItem {
400
- readonly path: string;
401
- /** Range of the hard string in the source file, quotes included. */
402
- readonly range: TextRange;
403
- readonly key: KeyString;
404
- readonly value: string;
405
- /** Replacement text for the range. */
406
- readonly replacement: string;
407
- /** Lines to add once per file when missing, for example an import. */
408
- readonly imports?: readonly string[];
409
- }
410
- interface Fix {
411
- readonly title: string;
412
- readonly ops: readonly EditOp[];
413
- }
414
- interface Location {
415
- readonly path: string;
416
- readonly range: TextRange;
417
- }
418
- interface Diagnostic {
419
- /** Check id, for example 'missing-translation'. */
420
- readonly code: string;
421
- readonly severity: Severity;
422
- readonly message: string;
423
- readonly key: KeyString | undefined;
424
- readonly locale: LocaleCode | undefined;
425
- readonly location: Location | undefined;
426
- readonly fixes: readonly Fix[];
427
- }
428
- interface Placeholder {
429
- readonly syntax: string;
430
- /** Text as written, for example `{name}`. */
431
- readonly text: string;
432
- /** Name used for comparison across locales, for example `name`. */
433
- readonly name: string;
434
- readonly range: TextRange;
435
- }
436
- type JsonPrimitive = string | number | boolean | null;
437
- type JsonValue = JsonPrimitive | readonly JsonValue[] | JsonObject;
438
- interface JsonObject {
439
- readonly [key: string]: JsonValue;
440
- }
441
- //#endregion
442
- //#region src/contracts.d.ts
443
- /** Version of every JSON contract (CLI `--json`, LSP `x18n/*`, RPC, MCP). Bumped on breaking changes to any shape. */
444
- export declare const contractVersion = 2;
445
- interface WireRange {
446
- /** 1-based. */
447
- readonly line: number;
448
- /** 1-based, UTF-16 code units. */
449
- readonly column: number;
450
- readonly endLine: number;
451
- readonly endColumn: number;
452
- /** 0-based UTF-16 offsets. */
453
- readonly start: number;
454
- readonly end: number;
455
- }
456
- interface WireDiagnostic {
457
- readonly project: string;
458
- readonly code: string;
459
- readonly severity: Severity;
460
- readonly message: string;
461
- readonly key: KeyString | undefined;
462
- readonly locale: LocaleCode | undefined;
463
- /** Path relative to the project root. */
464
- readonly file: string | undefined;
465
- readonly range: WireRange | undefined;
466
- readonly fixes: readonly Fix[];
467
- }
468
- interface Envelope<T> {
469
- readonly x18n: number;
470
- readonly command: string;
471
- readonly data: T;
472
- readonly diagnostics: readonly WireDiagnostic[];
473
- readonly errors: readonly ErrorInfo[];
474
- }
475
- /** Line and column form of an offset range in a text. */
476
- export declare function toWireRange(text: string | undefined, start: number, end: number): WireRange;
477
- export declare function toWireDiagnostic(project: string, diagnostic: Diagnostic, text: (path: string) => string | undefined): WireDiagnostic;
478
- export declare function envelope<T>(command: string, data: T, diagnostics?: readonly WireDiagnostic[], errors?: readonly ErrorInfo[]): Envelope<T>;
479
- //#endregion
480
251
  //#region src/types/host.d.ts
481
252
  interface Disposable {
482
253
  readonly dispose: () => void;
@@ -543,6 +314,8 @@ interface ResourceCandidate {
543
314
  readonly format?: string | undefined;
544
315
  readonly block?: ResourceBlock | undefined;
545
316
  readonly readonly?: boolean | undefined;
317
+ /** Key separator of the resource, over the config's (from `ResourceSpec.keySeparator`). */
318
+ readonly keySeparator?: KeySeparator | undefined;
546
319
  }
547
320
  interface FinderContext {
548
321
  readonly host: Host;
@@ -574,6 +347,8 @@ interface ParseResult {
574
347
  readonly tree: MessageTree;
575
348
  /** Ranges of keys and values (leaves and objects), keyed by `pathId(storedPath)`. */
576
349
  readonly ranges?: ReadonlyMap<string, NodeRange> | undefined;
350
+ /** What the file says about a message for translators (a note or comment next to it), keyed by `pathId(storedPath)`. */
351
+ readonly descriptions?: ReadonlyMap<string, string> | undefined;
577
352
  }
578
353
  type MessageOp = {
579
354
  readonly type: "set";
@@ -635,6 +410,8 @@ interface UsageCandidate {
635
410
  readonly params?: readonly string[] | undefined;
636
411
  /** The default value the call writes in code. */
637
412
  readonly defaultValue?: string | undefined;
413
+ /** A description of the message written next to the key in code. */
414
+ readonly description?: string | undefined;
638
415
  readonly kind: UsageKind;
639
416
  readonly dynamic: false | "prefix" | "unknown";
640
417
  readonly namespace?: string | undefined;
@@ -648,6 +425,10 @@ interface Scope {
648
425
  readonly keyPrefix?: string | undefined;
649
426
  /** The key prefix applies only to keys it defines; others resolve without it, as page messages that extend global ones. */
650
427
  readonly optionalPrefix?: boolean | undefined;
428
+ /** With `optionalPrefix`: more prefixes to try after `keyPrefix`, in order. */
429
+ readonly otherPrefixes?: readonly string[] | undefined;
430
+ /** With `optionalPrefix`: a prefixed key counts in the fallback namespaces too. */
431
+ readonly prefixInFallback?: boolean | undefined;
651
432
  }
652
433
  interface HardString {
653
434
  readonly text: string;
@@ -843,6 +624,8 @@ interface ResourceTransform {
843
624
  readonly read: (tree: MessageTree, ctx: ResourceTransformContext) => MessageTree;
844
625
  /** The path in the file of a key path of the transformed tree. */
845
626
  readonly toStored: (path: readonly string[], ctx: ResourceTransformContext) => string[];
627
+ /** Descriptions that the stored tree holds beside the messages, such as `{ "name": { "message": "...", "description": "..." } }`, keyed by `pathId(storedPath)`. */
628
+ readonly describe?: ((tree: MessageTree, ctx: ResourceTransformContext) => ReadonlyMap<string, string>) | undefined;
846
629
  }
847
630
  interface PromptDraft {
848
631
  readonly rules: string[];
@@ -951,6 +734,8 @@ interface CallSpec {
951
734
  readonly params?: ParamsSource | undefined;
952
735
  /** Where a default value written in code comes from; the first string found wins. For factories, that of the returned functions. */
953
736
  readonly defaultValue?: readonly ArgSource[] | undefined;
737
+ /** With a key read from a property: the property beside it that describes the message for translators, such as `'description'` for `{ id, description }`. */
738
+ readonly description?: string | undefined;
954
739
  /** The callee is a factory that returns the translate function, for example `useI18n()` returning `{ t }`. */
955
740
  readonly factory?: boolean | undefined;
956
741
  /** For factories: the names of the returned translate functions. Default `['t']`. */
@@ -974,7 +759,14 @@ interface ResourceSpec {
974
759
  readonly locale?: string | undefined;
975
760
  /** Run matching JS/TS files in Node instead of reading them statically. Makes them read-only. */
976
761
  readonly execute?: boolean | undefined;
762
+ /** Key separator of matching files, over `keySeparator`. `false` for files keyed by whole sentences (Laravel `lang/{locale}.json`). */
763
+ readonly keySeparator?: string | false | undefined;
977
764
  }
765
+ /**
766
+ * What splits a key into a path: `.` by default (`a.b` is `{ a: { b } }` in a nested file).
767
+ * `false` makes keys literal, so `Welcome back.` or `Note: x` is one key (i18next `keySeparator: false`, gettext, Laravel JSON).
768
+ */
769
+ type KeySeparator = string | false;
978
770
  type CheckLevel = Severity | "off";
979
771
  type CheckSetting = CheckLevel | readonly [CheckLevel, JsonObject];
980
772
  interface GlossaryEntry {
@@ -987,6 +779,7 @@ interface GlossaryEntry {
987
779
  readonly doNotTranslate?: boolean | undefined;
988
780
  }
989
781
  interface ExtractTemplate {
782
+ /** Replacement code with `{key}`, `{attr}`, `{args}`, `{text}`, `{source}` and `{parts}` tokens. `{key}` and `{text}` are escaped for the quotes around them. */
990
783
  readonly template: string;
991
784
  /** Hard-string kinds the template applies to, for example `jsx-text`. */
992
785
  readonly kinds?: readonly string[] | undefined;
@@ -1036,8 +829,8 @@ interface WriteOptions {
1036
829
  readonly keepFilled?: boolean | undefined;
1037
830
  }
1038
831
  interface NamespaceOptions {
1039
- /** Separator between namespace and key in code. `.` merges the namespace into the key path. Default `.`. */
1040
- readonly separator?: string | undefined;
832
+ /** Separator between namespace and key in code. `.` merges the namespace into the key path. `false` keeps namespaces out of keys in code (i18next `nsSeparator: false`), so a key may hold `:`. Default `.`. */
833
+ readonly separator?: string | false | undefined;
1041
834
  /** Namespace of keys written without one. */
1042
835
  readonly default?: string | undefined;
1043
836
  /** Namespaces searched in order when a key written without a namespace is not in its own (i18next `fallbackNS`). */
@@ -1083,6 +876,8 @@ interface SerializableConfig {
1083
876
  readonly [extension: string]: string;
1084
877
  } | undefined;
1085
878
  readonly keyStyle?: "auto" | "nested" | "flat" | undefined;
879
+ /** What splits a key into a path: `a.b` is `{ a: { b } }` in a nested file. `false` makes keys literal, so `Welcome back.` or `Note: x` is one key and a new key is one property (i18next `keySeparator: false`, gettext). A resource pattern can set its own. */
880
+ readonly keySeparator?: string | false | undefined;
1086
881
  readonly namespace?: NamespaceOptions | undefined;
1087
882
  readonly usage?: UsageOptions | undefined;
1088
883
  readonly write?: WriteOptions | undefined;
@@ -1144,8 +939,9 @@ interface ResolvedConfig {
1144
939
  readonly [extension: string]: string;
1145
940
  };
1146
941
  readonly keyStyle: "auto" | "nested" | "flat";
942
+ readonly keySeparator: KeySeparator;
1147
943
  readonly namespace: {
1148
- readonly separator: string;
944
+ readonly separator: string | false;
1149
945
  readonly default: string | undefined;
1150
946
  readonly fallback: readonly string[];
1151
947
  readonly byFile: {
@@ -1189,6 +985,241 @@ interface ResolvedConfig {
1189
985
  /** A mutable view of the config that `config` hooks change. */
1190
986
  type ConfigDraft = { -readonly [K in keyof Omit<ResolvedConfig, "origins" | "name">]: ResolvedConfig[K]; };
1191
987
  //#endregion
988
+ //#region src/types/model.d.ts
989
+ /** A locale code exactly as written in paths and files: `en`, `zh_CN`, `pt-BR`. Never normalized. */
990
+ type LocaleCode = string;
991
+ /** Canonical key string: `ns:a.b.c`, or `a.b.c` without namespace. */
992
+ type KeyString = string;
993
+ /** Resource id: the resource path, plus `#<block index>` for embedded resources. */
994
+ type ResourceId = string;
995
+ type MessageLeaf = string | number | boolean | null;
996
+ interface MessageTree {
997
+ readonly [segment: string]: MessageLeaf | MessageTree;
998
+ }
999
+ /** UTF-16 offsets, the same as JS strings. */
1000
+ interface TextRange {
1001
+ readonly start: number;
1002
+ readonly end: number;
1003
+ }
1004
+ interface TextEdit {
1005
+ readonly range: TextRange;
1006
+ readonly text: string;
1007
+ }
1008
+ /** Ranges of a key and its value (or object) in the resource text. */
1009
+ interface NodeRange {
1010
+ readonly key: TextRange;
1011
+ readonly value: TextRange;
1012
+ }
1013
+ interface KeyId {
1014
+ readonly namespace: string | undefined;
1015
+ readonly path: readonly string[];
1016
+ }
1017
+ /** Display data from a lenient parse of a code. Never changes the code itself. */
1018
+ interface LocaleInfo {
1019
+ readonly code: LocaleCode;
1020
+ readonly language: string | undefined;
1021
+ readonly region: string | undefined;
1022
+ readonly displayName: string | undefined;
1023
+ readonly flag: string | undefined;
1024
+ /** The plural categories a message may have. */
1025
+ readonly pluralCategories: readonly Intl.LDMLPluralRule[];
1026
+ /** Categories of ordinal numbers (1st, 2nd), which differ from the cardinal ones. */
1027
+ readonly ordinalCategories: readonly Intl.LDMLPluralRule[];
1028
+ /** The plural categories a message must have: those whole numbers select. French may leave out `many`, from 1,000,000 only. */
1029
+ readonly requiredPluralCategories: readonly Intl.LDMLPluralRule[];
1030
+ readonly requiredOrdinalCategories: readonly Intl.LDMLPluralRule[];
1031
+ }
1032
+ /** Embedded resource inside a file, for example a Vue `<i18n>` block. */
1033
+ interface ResourceBlock {
1034
+ readonly index: number;
1035
+ /** Range of the block content in the file. */
1036
+ readonly range: TextRange;
1037
+ readonly lang: string | undefined;
1038
+ }
1039
+ interface Resource {
1040
+ readonly id: ResourceId;
1041
+ /** Posix path relative to the project root. */
1042
+ readonly path: string;
1043
+ readonly locale: LocaleCode;
1044
+ readonly namespace: string | undefined;
1045
+ readonly format: string;
1046
+ readonly block: ResourceBlock | undefined;
1047
+ /** True for read-only formats and for resources loaded with `execute: true`. */
1048
+ readonly readonly: boolean;
1049
+ /** Id of the locale finder that found the resource. */
1050
+ readonly finder: string;
1051
+ /** Key separator of the resource when it differs from the config's `keySeparator` (from its resource spec). */
1052
+ readonly keySeparator?: KeySeparator | undefined;
1053
+ }
1054
+ /** One stored value of one key in one locale. */
1055
+ interface Message {
1056
+ readonly key: KeyString;
1057
+ readonly locale: LocaleCode;
1058
+ readonly value: MessageLeaf;
1059
+ readonly resource: ResourceId;
1060
+ /** Property path as stored in the resource (`['a.b']` in a flat file, `['a', 'b']` nested). */
1061
+ readonly storedPath: readonly string[];
1062
+ /** Ranges in the resource file text (block offsets already added). */
1063
+ readonly range: NodeRange | undefined;
1064
+ /** What the resource says about the message for translators, such as a note or a comment beside it. */
1065
+ readonly description?: string | undefined;
1066
+ }
1067
+ type UsageKind = "call" | "selector" | "accessor" | "constant" | "marker";
1068
+ interface Usage {
1069
+ /** Undefined when the key is fully dynamic. */
1070
+ readonly key: KeyString | undefined;
1071
+ /** The key text as written in code. */
1072
+ readonly raw: string;
1073
+ readonly path: string;
1074
+ /** Range of the key text only (inside the quotes): the range rename rewrites. */
1075
+ readonly range: TextRange;
1076
+ /** Range of the whole call that holds the key (`t('a', { n })`), when the scanner knows it. */
1077
+ readonly expression: TextRange | undefined;
1078
+ /** 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. */
1079
+ readonly params?: readonly string[] | undefined;
1080
+ /** The default value written in code (`t('a', 'Default')`), when the scanner knows it. */
1081
+ readonly defaultValue?: string | undefined;
1082
+ /** A description of the message written next to the key in code (`CallSpec.description`), when the scanner knows it. */
1083
+ readonly description?: string | undefined;
1084
+ readonly scanner: string;
1085
+ readonly kind: UsageKind;
1086
+ /** `t(`pages.${id}.title`)` gives 'prefix' with key `pages`. */
1087
+ readonly dynamic: false | "prefix" | "unknown";
1088
+ readonly locale: LocaleCode | undefined;
1089
+ /** Namespace that came from a scope or a factory, not from the raw text. */
1090
+ readonly scopeNamespace: string | undefined;
1091
+ /** Key prefix that came from a scope or factory (`keyPrefix`), not from the raw text. */
1092
+ readonly scopePrefix: string | undefined;
1093
+ }
1094
+ type Severity = "error" | "warning" | "info" | "hint";
1095
+ type EditOp = {
1096
+ readonly type: "set";
1097
+ readonly key: KeyString;
1098
+ readonly locale: LocaleCode;
1099
+ readonly value: MessageLeaf;
1100
+ } | {
1101
+ readonly type: "rename";
1102
+ readonly from: KeyString;
1103
+ readonly to: KeyString;
1104
+ readonly usages?: boolean;
1105
+ } | {
1106
+ readonly type: "rename-prefix";
1107
+ readonly from: KeyString;
1108
+ readonly to: KeyString;
1109
+ readonly usages?: boolean;
1110
+ } | {
1111
+ readonly type: "delete";
1112
+ readonly key: KeyString;
1113
+ readonly locales?: "all" | readonly LocaleCode[];
1114
+ } | {
1115
+ readonly type: "extract";
1116
+ readonly items: readonly ExtractItem[];
1117
+ } | {
1118
+ readonly type: "format";
1119
+ readonly paths?: readonly string[];
1120
+ } | {
1121
+ readonly type: "review";
1122
+ readonly key: KeyString;
1123
+ readonly locale: LocaleCode;
1124
+ readonly review: ReviewType;
1125
+ readonly text?: string | undefined;
1126
+ /** The proposed value, required for `suggestion`. */
1127
+ readonly suggestion?: string | undefined;
1128
+ readonly author?: ReviewAuthor | undefined;
1129
+ readonly id?: string | undefined;
1130
+ readonly time?: string | undefined;
1131
+ } | {
1132
+ readonly type: "resolve-review";
1133
+ readonly id: string;
1134
+ } | {
1135
+ readonly type: "apply-suggestion";
1136
+ readonly id: string;
1137
+ } | {
1138
+ readonly type: "mark-fresh";
1139
+ readonly key: KeyString;
1140
+ readonly locales?: readonly LocaleCode[] | undefined;
1141
+ };
1142
+ interface ExtractItem {
1143
+ readonly path: string;
1144
+ /** Range of the hard string in the source file, quotes included. */
1145
+ readonly range: TextRange;
1146
+ readonly key: KeyString;
1147
+ readonly value: string;
1148
+ /** Replacement text for the range. */
1149
+ readonly replacement: string;
1150
+ /** Lines to add once per file when missing, for example an import. */
1151
+ readonly imports?: readonly string[];
1152
+ }
1153
+ interface Fix {
1154
+ readonly title: string;
1155
+ readonly ops: readonly EditOp[];
1156
+ }
1157
+ interface Location {
1158
+ readonly path: string;
1159
+ readonly range: TextRange;
1160
+ }
1161
+ interface Diagnostic {
1162
+ /** Check id, for example 'missing-translation'. */
1163
+ readonly code: string;
1164
+ readonly severity: Severity;
1165
+ readonly message: string;
1166
+ readonly key: KeyString | undefined;
1167
+ readonly locale: LocaleCode | undefined;
1168
+ readonly location: Location | undefined;
1169
+ readonly fixes: readonly Fix[];
1170
+ }
1171
+ interface Placeholder {
1172
+ readonly syntax: string;
1173
+ /** Text as written, for example `{name}`. */
1174
+ readonly text: string;
1175
+ /** Name used for comparison across locales, for example `name`. */
1176
+ readonly name: string;
1177
+ readonly range: TextRange;
1178
+ }
1179
+ type JsonPrimitive = string | number | boolean | null;
1180
+ type JsonValue = JsonPrimitive | readonly JsonValue[] | JsonObject;
1181
+ interface JsonObject {
1182
+ readonly [key: string]: JsonValue;
1183
+ }
1184
+ //#endregion
1185
+ //#region src/contracts.d.ts
1186
+ /** Version of every JSON contract (CLI `--json`, LSP `x18n/*`, RPC, MCP). Bumped on breaking changes to any shape. */
1187
+ export declare const contractVersion = 2;
1188
+ interface WireRange {
1189
+ /** 1-based. */
1190
+ readonly line: number;
1191
+ /** 1-based, UTF-16 code units. */
1192
+ readonly column: number;
1193
+ readonly endLine: number;
1194
+ readonly endColumn: number;
1195
+ /** 0-based UTF-16 offsets. */
1196
+ readonly start: number;
1197
+ readonly end: number;
1198
+ }
1199
+ interface WireDiagnostic {
1200
+ readonly project: string;
1201
+ readonly code: string;
1202
+ readonly severity: Severity;
1203
+ readonly message: string;
1204
+ readonly key: KeyString | undefined;
1205
+ readonly locale: LocaleCode | undefined;
1206
+ /** Path relative to the project root. */
1207
+ readonly file: string | undefined;
1208
+ readonly range: WireRange | undefined;
1209
+ readonly fixes: readonly Fix[];
1210
+ }
1211
+ interface Envelope<T> {
1212
+ readonly x18n: number;
1213
+ readonly command: string;
1214
+ readonly data: T;
1215
+ readonly diagnostics: readonly WireDiagnostic[];
1216
+ readonly errors: readonly ErrorInfo[];
1217
+ }
1218
+ /** Line and column form of an offset range in a text. */
1219
+ export declare function toWireRange(text: string | undefined, start: number, end: number): WireRange;
1220
+ export declare function toWireDiagnostic(project: string, diagnostic: Diagnostic, text: (path: string) => string | undefined): WireDiagnostic;
1221
+ export declare function envelope<T>(command: string, data: T, diagnostics?: readonly WireDiagnostic[], errors?: readonly ErrorInfo[]): Envelope<T>;
1222
+ //#endregion
1192
1223
  //#region src/define.d.ts
1193
1224
  export declare function definePlugin<const T extends Plugin>(plugin: T): T;
1194
1225
  export declare function definePlugin<O, const T extends Plugin>(factory: (options: O) => T): (options: O) => T;
@@ -1200,12 +1231,15 @@ export declare function defineConfig(config: UserConfig & { readonly [K in keyof
1200
1231
  export declare function fuzzyScore(query: string, text: string): number;
1201
1232
  //#endregion
1202
1233
  //#region src/keys.d.ts
1203
- /** Canonical string form of a key: `ns:a.b.c`, or `a.b.c` without namespace. */
1204
- export declare function joinKey(namespace: string | undefined, path: readonly string[]): KeyString;
1205
- /** Splits a key string. `namespaced` is false for projects without namespaces, where `:` is part of the key. */
1206
- export declare function splitKey(key: KeyString, namespaced?: boolean): KeyId;
1207
- /** True when `key` is `prefix` itself or lies under it (`a.b` is under `a`). */
1208
- export declare function isKeyUnder(key: KeyString, prefix: KeyString): boolean;
1234
+ /** Canonical string form of a key: `ns:a.b.c`, or `a.b.c` without namespace. `separator` joins the path (`.` by default). */
1235
+ export declare function joinKey(namespace: string | undefined, path: readonly string[], separator?: KeySeparator): KeyString;
1236
+ /**
1237
+ * Splits a key string. `namespaced` is false for projects without namespaces, where `:` is part of the key.
1238
+ * The namespace ends at the first `:`, so the rest of the key may hold more. With `separator: false` the path is one literal segment.
1239
+ */
1240
+ export declare function splitKey(key: KeyString, namespaced?: boolean, separator?: KeySeparator): KeyId;
1241
+ /** True when `key` is `prefix` itself or lies under it (`a.b` is under `a`). A literal key (`separator: false`) has nothing under it but in its namespace. */
1242
+ export declare function isKeyUnder(key: KeyString, prefix: KeyString, separator?: KeySeparator): boolean;
1209
1243
  /** Replaces the `from` prefix of `key` with `to`. */
1210
1244
  export declare function replaceKeyPrefix(key: KeyString, from: KeyString, to: KeyString): KeyString;
1211
1245
  /**
@@ -1213,8 +1247,8 @@ export declare function replaceKeyPrefix(key: KeyString, from: KeyString, to: Ke
1213
1247
  * `{a,b}` alternates, `[...]` is a character class.
1214
1248
  */
1215
1249
  export declare function globToRegExp(glob: string, separator?: string): RegExp;
1216
- /** Matcher over key globs: `*` stays inside a segment, `**` spans segments. */
1217
- export declare function keyMatcher(globs: readonly string[]): (key: KeyString) => boolean;
1250
+ /** Matcher over key globs: `*` stays inside a segment, `**` spans segments. With literal keys (`separator: false`) `*` spans the whole key. */
1251
+ export declare function keyMatcher(globs: readonly string[], separator?: KeySeparator): (key: KeyString) => boolean;
1218
1252
  /** Matcher over posix file paths. */
1219
1253
  export declare function pathMatcher(globs: readonly string[]): (path: string) => boolean;
1220
1254
  //#endregion
@@ -1236,6 +1270,8 @@ interface LibraryOptions {
1236
1270
  /** Default resource patterns (i18n-ally `preferredLocalePaths` + `pathMatcher`). */
1237
1271
  readonly resources?: readonly ResourceSpec[];
1238
1272
  readonly keyStyle?: "nested" | "flat";
1273
+ /** The library's key separator; `false` for literal keys (gettext). The user's `keySeparator` wins. */
1274
+ readonly keySeparator?: KeySeparator;
1239
1275
  readonly templates?: readonly ExtractTemplate[];
1240
1276
  readonly finders?: readonly LocaleFinder[];
1241
1277
  readonly normalizeKey?: Plugin["normalizeKey"];
@@ -1342,6 +1378,15 @@ interface PromptOptions {
1342
1378
  readonly stale?: boolean | undefined;
1343
1379
  /** Translate prompts: add translations that checks report in the target locale, all of them (`true`) or of these check ids. */
1344
1380
  readonly check?: boolean | readonly string[] | undefined;
1381
+ /**
1382
+ * Values of related locales to show next to each message: `true` (default) picks them (see `relatedLocales`),
1383
+ * a list names them in order, `false` leaves them out.
1384
+ */
1385
+ readonly related?: boolean | readonly LocaleCode[] | undefined;
1386
+ }
1387
+ interface RelatedValue {
1388
+ readonly locale: LocaleCode;
1389
+ readonly value: string;
1345
1390
  }
1346
1391
  interface PromptIssue {
1347
1392
  /** Check id, for example `identical-to-source`. */
@@ -1357,6 +1402,10 @@ interface PromptItem {
1357
1402
  readonly key: KeyString;
1358
1403
  readonly source: string;
1359
1404
  readonly placeholders: readonly string[];
1405
+ /** What the resources or the code say about the message for translators, when they say something. */
1406
+ readonly description?: string | undefined;
1407
+ /** Values of the message in related locales, such as `pt` when translating to `pt-BR`, nearest first. */
1408
+ readonly related?: readonly RelatedValue[] | undefined;
1360
1409
  /** The current value in the target locale, when there is one. */
1361
1410
  readonly existing: string | undefined;
1362
1411
  /** For a stale translation: the source value when the translation last changed, when known. */
@@ -1390,6 +1439,12 @@ interface PromptData {
1390
1439
  readonly items: readonly PromptItem[];
1391
1440
  readonly instructions: readonly string[];
1392
1441
  }
1442
+ /**
1443
+ * The locales whose values help translate to `to`, nearest first: the fallback chain of `to`, then the other locales of
1444
+ * the same language, those that share more subtags with `to` first, then the shorter codes (`pt` and `pt-PT` for `pt-BR`,
1445
+ * `pt-BR` for `pt`). The source locale and `to` itself are never related.
1446
+ */
1447
+ export declare function relatedLocales(to: LocaleCode, locales: readonly LocaleCode[], sourceLocale: LocaleCode, fallbacks: Readonly<Record<LocaleCode, LocaleCode>>): LocaleCode[];
1393
1448
  /** Plain markdown, with no provider-specific syntax. */
1394
1449
  export declare function renderPrompt(data: PromptData): string;
1395
1450
  //#endregion
@@ -1505,6 +1560,35 @@ interface Analysis {
1505
1560
  /** Usages whose key is not defined in the source locale. */
1506
1561
  readonly undefinedUsages: readonly Usage[];
1507
1562
  }
1563
+ /** Which unused keys `planUnused` deletes. */
1564
+ interface UnusedQuery {
1565
+ /** Key glob: `*` inside a segment, `**` across segments. */
1566
+ readonly glob?: string | undefined;
1567
+ readonly namespace?: string | undefined;
1568
+ }
1569
+ /** An unused key the plan deletes, with the messages it removes. */
1570
+ interface UnusedKeyDeletion {
1571
+ readonly key: KeyString;
1572
+ /** One entry per message, in locale order. */
1573
+ readonly messages: readonly {
1574
+ readonly locale: LocaleCode;
1575
+ readonly path: string;
1576
+ }[];
1577
+ }
1578
+ /** An unused key left alone because fully dynamic usages in a scope (`keyPrefix`, namespace) may reach it. */
1579
+ interface KeptUnusedKey {
1580
+ readonly key: KeyString;
1581
+ readonly usages: readonly Usage[];
1582
+ }
1583
+ /** The bulk delete of unused keys, as data: review it (dry run), then pass `plan` to `apply`. */
1584
+ interface UnusedDeletion {
1585
+ /** Deletes `keys` in every locale, in place. Its warnings list the fully dynamic usages that may reach any key. */
1586
+ readonly plan: Plan;
1587
+ /** Sorted by key. */
1588
+ readonly keys: readonly UnusedKeyDeletion[];
1589
+ /** Sorted by key. */
1590
+ readonly kept: readonly KeptUnusedKey[];
1591
+ }
1508
1592
  interface ProjectExplanation {
1509
1593
  readonly name: string;
1510
1594
  readonly root: string;
@@ -1648,6 +1732,8 @@ interface Project {
1648
1732
  /** True when the path is a resource file or a scanned source file. */
1649
1733
  readonly owns: (path: string) => boolean;
1650
1734
  readonly plan: (ops: readonly EditOp[]) => Plan;
1735
+ /** Plans the deletion of the unused keys (`analyze().unused`), minus `ignoreKeys` and keys a scoped fully dynamic usage may reach. */
1736
+ readonly planUnused: (query?: UnusedQuery) => UnusedDeletion;
1651
1737
  readonly apply: (plan: Plan, options?: {
1652
1738
  readonly answers?: Answers | undefined;
1653
1739
  }) => Promise<ApplyResult>;
@@ -1714,6 +1800,7 @@ interface PluginFile {
1714
1800
  readonly resources?: readonly ResourceSpec[] | undefined;
1715
1801
  readonly namespace?: NamespaceOptions | undefined;
1716
1802
  readonly keyStyle?: "auto" | "nested" | "flat" | undefined;
1803
+ readonly keySeparator?: KeySeparator | undefined;
1717
1804
  } | undefined;
1718
1805
  readonly scanners?: {
1719
1806
  readonly calls?: readonly CallSpec[] | undefined;
@@ -1789,4 +1876,4 @@ export declare function rangeContains(range: TextRange, offset: number): boolean
1789
1876
  /** Fast non-cryptographic string hash (cyrb53), as hex. */
1790
1877
  export declare function hashText(text: string): string;
1791
1878
  //#endregion
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 };
1879
+ 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, KeptUnusedKey, KeyContext, KeyId, KeyInfo, KeyQuery, KeySeparator, 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, RelatedValue, 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, UnusedDeletion, UnusedKeyDeletion, UnusedQuery, Usage, UsageCandidate, UsageContext, UsageKind, UsageMatch, UsageOptions, UsageQuery, UserConfig, WireDiagnostic, WireRange, WriteOptions, X18nError };