@the-i18n-kit/cli 6.0.0 → 8.0.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.
- package/README.md +7 -57
- package/dist/bin.js +1 -1
- package/dist/{_shared-CkMAydRl.js → cli-BTMcWXGs.js} +157 -27
- package/dist/cli-BTMcWXGs.js.map +1 -0
- package/dist/config/framework/stubs/{next-intl-routing-lExp4Q3r.d.ts → next-intl-routing-i6Mlxwdt.d.ts} +1 -1
- package/dist/config/framework/stubs/{next-intl-routing-lExp4Q3r.d.ts.map → next-intl-routing-i6Mlxwdt.d.ts.map} +1 -1
- package/dist/{define-config-BeHvSYBP.d.ts → define-config-BpdVaEVR.d.ts} +1 -1
- package/dist/{define-config-DW-rgsU6.d.ts → define-config-ZRZw5PWy.d.ts} +40 -6
- package/dist/define-config-ZRZw5PWy.d.ts.map +1 -0
- package/dist/define-config.d.ts +1 -1
- package/dist/descriptors-Bo5UM031.js +1242 -0
- package/dist/descriptors-Bo5UM031.js.map +1 -0
- package/dist/detector-B4z_RZde.js +2189 -0
- package/dist/detector-B4z_RZde.js.map +1 -0
- package/dist/detector-DTfFbwSU.js +5 -0
- package/dist/{index-w-EQZEZF.d.ts → index-CWFWYHf5.d.ts} +728 -268
- package/dist/index-CWFWYHf5.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +8 -4
- package/dist/json-writer-D0b6vEax.js +2 -0
- package/dist/json-writer-ek8yEI5R.js +342 -0
- package/dist/json-writer-ek8yEI5R.js.map +1 -0
- package/dist/operations-CKHEmLNJ.js +8 -0
- package/dist/{operations-PfRSTepi.js → operations-Daf2Ommm.js} +1655 -3298
- package/dist/operations-Daf2Ommm.js.map +1 -0
- package/dist/php-reader-BGx6Ii2d.js +2 -0
- package/dist/{php-reader-3Fgw80zK.js → php-reader-DRpcRVzv.js} +6 -3
- package/dist/{php-reader-3Fgw80zK.js.map → php-reader-DRpcRVzv.js.map} +1 -1
- package/dist/{providers-CAsU_aV1.js → project-config-eLR0J377.js} +24 -209
- package/dist/project-config-eLR0J377.js.map +1 -0
- package/dist/providers-BbVPelvp.js +406 -0
- package/dist/providers-BbVPelvp.js.map +1 -0
- package/dist/report-By1-5JtO.js +37 -0
- package/dist/report-By1-5JtO.js.map +1 -0
- package/dist/report-CHZgH9Wy.js +2 -0
- package/package.json +4 -16
- package/dist/_shared-CkMAydRl.js.map +0 -1
- package/dist/add-BBoVUNEq.js +0 -40
- package/dist/add-BBoVUNEq.js.map +0 -1
- package/dist/check-IosaN_EM.js +0 -41
- package/dist/check-IosaN_EM.js.map +0 -1
- package/dist/cli-CnZNGUGu.js +0 -70
- package/dist/cli-CnZNGUGu.js.map +0 -1
- package/dist/config/framework/stubs/unplugin-vue-i18n-mH7YdYqA.d.ts +0 -25
- package/dist/config/framework/stubs/unplugin-vue-i18n-mH7YdYqA.d.ts.map +0 -1
- package/dist/config/framework/stubs/unplugin-vue-i18n.js +0 -26
- package/dist/config/framework/stubs/unplugin-vue-i18n.js.map +0 -1
- package/dist/define-config-DW-rgsU6.d.ts.map +0 -1
- package/dist/detect-3jjcQJs1.js +0 -17
- package/dist/detect-3jjcQJs1.js.map +0 -1
- package/dist/empty-D3La0enO.js +0 -36
- package/dist/empty-D3La0enO.js.map +0 -1
- package/dist/find-duplicates-BlQoJDgu.js +0 -42
- package/dist/find-duplicates-BlQoJDgu.js.map +0 -1
- package/dist/get-Cr5O5zJX.js +0 -41
- package/dist/get-Cr5O5zJX.js.map +0 -1
- package/dist/index-w-EQZEZF.d.ts.map +0 -1
- package/dist/init-BRBMkcI0.js +0 -33
- package/dist/init-BRBMkcI0.js.map +0 -1
- package/dist/list-dirs-BMuByyuX.js +0 -17
- package/dist/list-dirs-BMuByyuX.js.map +0 -1
- package/dist/missing-CBOk4ZgD.js +0 -51
- package/dist/missing-CBOk4ZgD.js.map +0 -1
- package/dist/move-DOdPKnOV.js +0 -50
- package/dist/move-DOdPKnOV.js.map +0 -1
- package/dist/operations-PfRSTepi.js.map +0 -1
- package/dist/php-reader-CpnaPSpZ.js +0 -2
- package/dist/providers-CAsU_aV1.js.map +0 -1
- package/dist/remove-CVBjJV9h.js +0 -41
- package/dist/remove-CVBjJV9h.js.map +0 -1
- package/dist/remove-orphans-BaKEISxA.js +0 -57
- package/dist/remove-orphans-BaKEISxA.js.map +0 -1
- package/dist/rename-CN2ajUeb.js +0 -45
- package/dist/rename-CN2ajUeb.js.map +0 -1
- package/dist/scaffold-CUKUFuEy.js +0 -39
- package/dist/scaffold-CUKUFuEy.js.map +0 -1
- package/dist/scan-Bhv0Nmy3.js +0 -31
- package/dist/scan-Bhv0Nmy3.js.map +0 -1
- package/dist/search-CrkLgz3m.js +0 -49
- package/dist/search-CrkLgz3m.js.map +0 -1
- package/dist/status-DprS-qDC.js +0 -45
- package/dist/status-DprS-qDC.js.map +0 -1
- package/dist/translate-Cs6EdbzA.js +0 -92
- package/dist/translate-Cs6EdbzA.js.map +0 -1
- package/dist/translate-key-BBZpYQjL.js +0 -73
- package/dist/translate-key-BBZpYQjL.js.map +0 -1
- package/dist/update-BQuGxSSy.js +0 -40
- package/dist/update-BQuGxSSy.js.map +0 -1
- package/dist/write-B8z6I5Vf.js +0 -47
- package/dist/write-B8z6I5Vf.js.map +0 -1
- /package/dist/{bin-g05vSfAz.d.ts → bin-NyzIHE2F.d.ts} +0 -0
|
@@ -1,7 +1,127 @@
|
|
|
1
|
-
import { a as LocaleDir, i as LocaleDefinition, n as defineI18nKitConfig, o as ProjectConfig, r as I18nConfig,
|
|
1
|
+
import { a as LocaleDir, i as LocaleDefinition, n as defineI18nKitConfig, o as ProjectConfig, r as I18nConfig, t as I18nKitConfig } from "./define-config-ZRZw5PWy.js";
|
|
2
2
|
|
|
3
|
-
//#region src/
|
|
3
|
+
//#region src/config/layer-graph.d.ts
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Queryable view over the layer topology a resolved {@link I18nConfig}
|
|
7
|
+
* already carries: which locale dirs are canonical (alias-free), which
|
|
8
|
+
* layer owns an aliased dir, and which apps consume which layers.
|
|
9
|
+
*
|
|
10
|
+
* This is a pure derivation — no filesystem access, no config-shape
|
|
11
|
+
* changes. Cross-layer tooling (duplicate detection, scope-aware orphan
|
|
12
|
+
* scanning) builds on these queries instead of name-matching heuristics.
|
|
13
|
+
*
|
|
14
|
+
* ## Degenerate-case semantics
|
|
15
|
+
*
|
|
16
|
+
* These are load-bearing for consumers (scope-aware scanning must never
|
|
17
|
+
* wrongly narrow its scan scope):
|
|
18
|
+
*
|
|
19
|
+
* - **No app info** (`config.apps` empty or absent, e.g. hand-built
|
|
20
|
+
* configs): consumption edges are unknowable. `appsUsingLayer` and
|
|
21
|
+
* `layersOfApp` return `[]`, and `sharedLayers` conservatively contains
|
|
22
|
+
* *every* canonical layer — with no ownership information, every
|
|
23
|
+
* layer's keys must be treated as globally visible.
|
|
24
|
+
* - **Single-app config** (generic/Laravel/React adapters, or a Nuxt
|
|
25
|
+
* project with one app): the strict definition applies, so
|
|
26
|
+
* `sharedLayers` is empty (no layer is consumed by more than one app)
|
|
27
|
+
* and `appsUsingLayer` returns that one app for the layers it consumes.
|
|
28
|
+
* Per-layer scope then equals the whole project, which is correct.
|
|
29
|
+
* - **Canonical layer consumed by no app** (in a multi-app config):
|
|
30
|
+
* `appsUsingLayer` returns `[]` and the layer is not in `sharedLayers`.
|
|
31
|
+
* Callers should treat such layers conservatively (global scope).
|
|
32
|
+
*/
|
|
33
|
+
interface LayerGraph {
|
|
34
|
+
/**
|
|
35
|
+
* Alias-free locale dirs, in `config.localeDirs` order. Aliased entries
|
|
36
|
+
* (e.g. `app-outlook` pointing at `app-shop`'s dir) are excluded.
|
|
37
|
+
*/
|
|
38
|
+
canonicalLayers: LocaleDir[];
|
|
39
|
+
/**
|
|
40
|
+
* Resolve a layer name to the canonical layer that owns its locale dir.
|
|
41
|
+
* Follows chained `aliasOf` links (an alias may point at a layer that
|
|
42
|
+
* was itself demoted to an alias). Identity for canonical names and for
|
|
43
|
+
* names unknown to `localeDirs` (e.g. layers without locale dirs).
|
|
44
|
+
*/
|
|
45
|
+
ownerOf: (layer: string) => string;
|
|
46
|
+
/**
|
|
47
|
+
* Names of apps whose consumed layers include the given layer. The
|
|
48
|
+
* queried name and each app's layer list are alias-resolved via
|
|
49
|
+
* {@link ownerOf} first, so querying an alias name yields the owner's
|
|
50
|
+
* consumers. Returns `[]` when no app info exists.
|
|
51
|
+
*/
|
|
52
|
+
appsUsingLayer: (layer: string) => string[];
|
|
53
|
+
/**
|
|
54
|
+
* Canonical layers consumed by more than one app — e.g. a shared root
|
|
55
|
+
* layer in a multi-app monorepo, identified purely from consumption
|
|
56
|
+
* edges (no name matching). When no app info exists, contains every
|
|
57
|
+
* canonical layer (see degenerate-case semantics above).
|
|
58
|
+
*/
|
|
59
|
+
sharedLayers: LocaleDir[];
|
|
60
|
+
/**
|
|
61
|
+
* Canonical layers the given app consumes (alias entries in the app's
|
|
62
|
+
* layer list resolve to their owners; layers without locale dirs are
|
|
63
|
+
* omitted). Returns `[]` for unknown apps or when no app info exists.
|
|
64
|
+
*/
|
|
65
|
+
layersOfApp: (app: string) => LocaleDir[];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Build a {@link LayerGraph} from a resolved config's `localeDirs`
|
|
69
|
+
* (with their `aliasOf` markers) and `apps` (app → consumed-layers edges).
|
|
70
|
+
*/
|
|
71
|
+
declare function buildLayerGraph(config: I18nConfig): LayerGraph;
|
|
72
|
+
/**
|
|
73
|
+
* The graph as plain data, for surfaces that can only carry JSON.
|
|
74
|
+
*
|
|
75
|
+
* {@link LayerGraph} is function-valued, so it cannot be serialised directly.
|
|
76
|
+
* This answers the question an agent actually has — *which layer does this key
|
|
77
|
+
* belong in* — which the flat layer list `discover` returned could not: a key
|
|
78
|
+
* used by more than one app belongs in a layer those apps share, and `shared`
|
|
79
|
+
* names those layers outright (#342).
|
|
80
|
+
*
|
|
81
|
+
* The degenerate cases documented on {@link LayerGraph} survive the flattening,
|
|
82
|
+
* because they are what keeps a consumer from wrongly narrowing scope:
|
|
83
|
+
* a config with no app info reports *every* canonical layer as shared, and a
|
|
84
|
+
* layer no app consumes appears in `consumers` with an empty array rather than
|
|
85
|
+
* being left out. Absent and "none" must not look alike here.
|
|
86
|
+
*/
|
|
87
|
+
interface SerializedLayerGraph {
|
|
88
|
+
/** Alias-free layer names, in `config.localeDirs` order. */
|
|
89
|
+
canonical: string[];
|
|
90
|
+
/** Canonical layers consumed by more than one app — where shared keys belong. */
|
|
91
|
+
shared: string[];
|
|
92
|
+
/** Alias layer name → the canonical layer whose locale dir it points at. */
|
|
93
|
+
aliases: Record<string, string>;
|
|
94
|
+
/** Canonical layer name → the apps consuming it. Every canonical layer is a key. */
|
|
95
|
+
consumers: Record<string, string[]>;
|
|
96
|
+
}
|
|
97
|
+
/** Flatten {@link buildLayerGraph}'s view of `config` into plain JSON. */
|
|
98
|
+
declare function serializeLayerGraph(config: I18nConfig): SerializedLayerGraph;
|
|
99
|
+
//# sourceMappingURL=layer-graph.d.ts.map
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/core/types.d.ts
|
|
102
|
+
/**
|
|
103
|
+
* The whole resolved project in one answer: the config, the locale dirs behind
|
|
104
|
+
* it, the topology those dirs form, and which locales are maintained by hand.
|
|
105
|
+
*
|
|
106
|
+
* A superset of `I18nConfig` rather than a wrapper around it, because every
|
|
107
|
+
* caller of the old three-call sequence merged the parts anyway and a nested
|
|
108
|
+
* `config` key would break each of them for nothing.
|
|
109
|
+
*/
|
|
110
|
+
interface DescribeProjectResult extends I18nConfig {
|
|
111
|
+
/**
|
|
112
|
+
* Canonical codes of the locales the translate operations leave alone. The
|
|
113
|
+
* raw refs stay visible under `projectConfig.protectedLocales`.
|
|
114
|
+
*/
|
|
115
|
+
protectedLocales: string[];
|
|
116
|
+
/** One entry per locale directory, with file counts and key namespaces. */
|
|
117
|
+
layers: LocaleDirInfo[];
|
|
118
|
+
/**
|
|
119
|
+
* Which layers are shared, which apps consume which layer, and what each
|
|
120
|
+
* alias points at — the topology behind the flat `layers` list, and what
|
|
121
|
+
* answers where a new key belongs.
|
|
122
|
+
*/
|
|
123
|
+
layerGraph: SerializedLayerGraph;
|
|
124
|
+
}
|
|
5
125
|
interface LocaleDirInfo {
|
|
6
126
|
layer: string;
|
|
7
127
|
path: string;
|
|
@@ -62,27 +182,6 @@ interface MutationResult {
|
|
|
62
182
|
/** Present only when a ref matched several locales and precedence picked one. */
|
|
63
183
|
ambiguousLocales?: LocaleRefAmbiguity[];
|
|
64
184
|
}
|
|
65
|
-
interface AddTranslationsResult {
|
|
66
|
-
/** Present when dryRun=true */
|
|
67
|
-
dryRun?: boolean;
|
|
68
|
-
wouldAdd?: MutationPreview[];
|
|
69
|
-
/** Present when dryRun=false */
|
|
70
|
-
added?: string[];
|
|
71
|
-
skipped: string[];
|
|
72
|
-
filesWritten?: number;
|
|
73
|
-
warnings?: string[];
|
|
74
|
-
/** Present only when a locale ref resolved to nothing — see UnresolvedLocaleRef. */
|
|
75
|
-
unresolvedLocales?: UnresolvedLocaleRef[];
|
|
76
|
-
/** Present only when a locale ref matched several locales. */
|
|
77
|
-
ambiguousLocales?: LocaleRefAmbiguity[];
|
|
78
|
-
placeholderValidation?: PlaceholderValidationResult;
|
|
79
|
-
summary?: {
|
|
80
|
-
keysToAdd: number;
|
|
81
|
-
keysSkipped: number;
|
|
82
|
-
message: string;
|
|
83
|
-
};
|
|
84
|
-
skippedKeys?: string[];
|
|
85
|
-
}
|
|
86
185
|
interface WriteTranslationsResult {
|
|
87
186
|
/** Present when dryRun=true */
|
|
88
187
|
dryRun?: boolean;
|
|
@@ -104,26 +203,6 @@ interface WriteTranslationsResult {
|
|
|
104
203
|
};
|
|
105
204
|
skippedKeys?: string[];
|
|
106
205
|
}
|
|
107
|
-
interface UpdateTranslationsResult {
|
|
108
|
-
/** Present when dryRun=true */
|
|
109
|
-
dryRun?: boolean;
|
|
110
|
-
wouldUpdate?: MutationPreview[];
|
|
111
|
-
/** Present when dryRun=false */
|
|
112
|
-
updated?: string[];
|
|
113
|
-
skipped: string[];
|
|
114
|
-
filesWritten?: number;
|
|
115
|
-
/** Present only when a locale ref resolved to nothing — see UnresolvedLocaleRef. */
|
|
116
|
-
unresolvedLocales?: UnresolvedLocaleRef[];
|
|
117
|
-
/** Present only when a locale ref matched several locales. */
|
|
118
|
-
ambiguousLocales?: LocaleRefAmbiguity[];
|
|
119
|
-
placeholderValidation?: PlaceholderValidationResult;
|
|
120
|
-
summary?: {
|
|
121
|
-
keysToUpdate: number;
|
|
122
|
-
keysSkipped: number;
|
|
123
|
-
message: string;
|
|
124
|
-
};
|
|
125
|
-
skippedKeys?: string[];
|
|
126
|
-
}
|
|
127
206
|
/**
|
|
128
207
|
* The config `init` emits. Only fields the matched adapter cannot derive:
|
|
129
208
|
* writing a copy of what the framework already states creates a second source
|
|
@@ -173,16 +252,13 @@ interface InitProjectConfigResult {
|
|
|
173
252
|
overwritten: boolean;
|
|
174
253
|
}
|
|
175
254
|
interface MissingTranslationsResult {
|
|
176
|
-
|
|
177
|
-
missing?: Record<string, Record<string, string[]>>;
|
|
255
|
+
missing: Record<string, Record<string, string[]>>;
|
|
178
256
|
summary: {
|
|
179
257
|
referenceLocale: string | LocaleRefInfo;
|
|
180
258
|
targetLocales: Array<string | LocaleRefInfo>;
|
|
181
259
|
layersScanned: string[];
|
|
182
260
|
totalMissingKeys: number;
|
|
183
261
|
};
|
|
184
|
-
/** Present when reportOutput is configured */
|
|
185
|
-
reportFile?: string;
|
|
186
262
|
}
|
|
187
263
|
interface LocaleStatus extends LocaleRefInfo {
|
|
188
264
|
total: number;
|
|
@@ -203,10 +279,21 @@ interface LayerStatus {
|
|
|
203
279
|
missing: number;
|
|
204
280
|
empty: number;
|
|
205
281
|
completion: number;
|
|
282
|
+
/**
|
|
283
|
+
* Apps whose declared layers include this one. Empty means either no app
|
|
284
|
+
* information exists (hand-built configs) or nothing consumes the layer.
|
|
285
|
+
*/
|
|
286
|
+
consumedBy: string[];
|
|
206
287
|
}
|
|
207
288
|
interface TranslationStatusSummary {
|
|
208
289
|
referenceLocale: LocaleRefInfo;
|
|
209
290
|
layersScanned: string[];
|
|
291
|
+
/**
|
|
292
|
+
* Scanned layers no app consumes — keys nothing can render. Stays empty
|
|
293
|
+
* unless the project declares more than one app, since a single-app project
|
|
294
|
+
* has no consumption edges worth reporting on.
|
|
295
|
+
*/
|
|
296
|
+
unconsumedLayers: string[];
|
|
210
297
|
localesChecked: number;
|
|
211
298
|
protectedLocales: string[];
|
|
212
299
|
totalKeys: number;
|
|
@@ -217,31 +304,76 @@ interface TranslationStatusSummary {
|
|
|
217
304
|
completionPercent: number;
|
|
218
305
|
}
|
|
219
306
|
interface TranslationStatusResult {
|
|
220
|
-
locales
|
|
221
|
-
layers
|
|
307
|
+
locales: LocaleStatus[];
|
|
308
|
+
layers: LayerStatus[];
|
|
309
|
+
/**
|
|
310
|
+
* Locale → layer → the keys `summary.emptyKeys` counts: empty in that target
|
|
311
|
+
* locale while the reference locale has a value. Present only when the caller
|
|
312
|
+
* asked to list them. Added to the result rather than replacing it, so asking
|
|
313
|
+
* which keys are empty still answers the coverage question that prompted it.
|
|
314
|
+
*/
|
|
315
|
+
empty?: Record<string, Record<string, string[]>>;
|
|
316
|
+
/**
|
|
317
|
+
* Layer → keys whose value is empty in the reference locale itself. Nothing
|
|
318
|
+
* to translate from, so excluded from every count; listed so a deliberate
|
|
319
|
+
* blank and a forgotten one can be told apart. Present only with `empty`,
|
|
320
|
+
* and only when there are any.
|
|
321
|
+
*/
|
|
322
|
+
emptyInReference?: Record<string, string[]>;
|
|
222
323
|
summary: TranslationStatusSummary;
|
|
223
|
-
/** Present when the full breakdown went to a file instead. */
|
|
224
|
-
reportFile?: string;
|
|
225
324
|
}
|
|
226
325
|
interface EmptyTranslationsResult {
|
|
227
|
-
|
|
228
|
-
emptyKeys?: Record<string, Record<string, string[]>>;
|
|
326
|
+
emptyKeys: Record<string, Record<string, string[]>>;
|
|
229
327
|
summary: {
|
|
230
328
|
totalEmpty: number;
|
|
231
329
|
localesChecked: string[];
|
|
232
330
|
layersChecked: string[];
|
|
233
331
|
};
|
|
234
|
-
/** Present when reportOutput is configured */
|
|
235
|
-
reportFile?: string;
|
|
236
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* One key in one locale of one layer — the detail rows, returned when the
|
|
335
|
+
* caller asks for them.
|
|
336
|
+
*/
|
|
237
337
|
interface SearchMatch {
|
|
238
338
|
layer: string;
|
|
239
339
|
locale: string;
|
|
240
340
|
key: string;
|
|
241
341
|
value: unknown;
|
|
242
342
|
}
|
|
343
|
+
/**
|
|
344
|
+
* One key, however many layers and locales define it — the row a search
|
|
345
|
+
* returns by default.
|
|
346
|
+
*
|
|
347
|
+
* A key that exists in seven layers and thirty locales used to come back as
|
|
348
|
+
* dozens of near-identical rows, which an agent pays for and then has to group
|
|
349
|
+
* itself before it can answer the question it asked: does a translation for
|
|
350
|
+
* this text already exist, and where. Grouped here instead, because `layers`
|
|
351
|
+
* is the answer to the second half — one layer means reuse it, several mean
|
|
352
|
+
* the key is already duplicated.
|
|
353
|
+
*/
|
|
354
|
+
interface SearchKeyMatch {
|
|
355
|
+
key: string;
|
|
356
|
+
/** Every searched layer that defines the key, in layer order. */
|
|
357
|
+
layers: string[];
|
|
358
|
+
/** What `locale` holds for the key. */
|
|
359
|
+
value: unknown;
|
|
360
|
+
/**
|
|
361
|
+
* Which locale `value` was read from: the reference locale where it defines
|
|
362
|
+
* the key, otherwise the first searched locale that does.
|
|
363
|
+
*/
|
|
364
|
+
locale: string;
|
|
365
|
+
/** How many of the searched locales define the key. */
|
|
366
|
+
localeCount: number;
|
|
367
|
+
}
|
|
368
|
+
/** How `query` is compared against a key path or a value. */
|
|
369
|
+
type SearchMatchMode = 'contains' | 'exact' | 'fuzzy';
|
|
243
370
|
interface SearchTranslationsResult {
|
|
244
|
-
|
|
371
|
+
/**
|
|
372
|
+
* One row per key by default; one row per key and locale when the caller
|
|
373
|
+
* passed `includeLocales`.
|
|
374
|
+
*/
|
|
375
|
+
matches: SearchKeyMatch[] | SearchMatch[];
|
|
376
|
+
/** How many rows `matches` holds, whichever shape it is in. */
|
|
245
377
|
totalMatches: number;
|
|
246
378
|
}
|
|
247
379
|
interface RemoveTranslationsPreview {
|
|
@@ -297,6 +429,12 @@ interface MoveTranslationKeyPlanEntry {
|
|
|
297
429
|
*/
|
|
298
430
|
action: 'move' | 'deduplicate';
|
|
299
431
|
}
|
|
432
|
+
/**
|
|
433
|
+
* What a move returns: a rename result when the key stayed in its layer, a move
|
|
434
|
+
* result when it changed layers. A union rather than one merged shape, so
|
|
435
|
+
* neither half carries fields that can never be set for the other.
|
|
436
|
+
*/
|
|
437
|
+
type MoveTranslationKeyOutcome = MoveTranslationKeyResult | RenameTranslationKeyResult;
|
|
300
438
|
interface MoveTranslationKeyResult {
|
|
301
439
|
/** Present when dryRun=true */
|
|
302
440
|
dryRun?: boolean;
|
|
@@ -326,6 +464,29 @@ type TranslateMode = 'provider' | 'agent' | 'dry-run';
|
|
|
326
464
|
type TranslateFailReason = 'provider-error' | 'omitted-by-model' | 'placeholder-mismatch' | 'plural-mismatch' | 'write-error' | 'truncated';
|
|
327
465
|
/** Why a key or locale was intentionally not attempted. */
|
|
328
466
|
type TranslateSkipReason = 'no-provider' | 'already-translated' | 'protected-locale';
|
|
467
|
+
/** What translate_missing accepts. `layer` omitted means every layer at once. */
|
|
468
|
+
interface TranslateMissingOptions {
|
|
469
|
+
layer?: string;
|
|
470
|
+
referenceLocale?: string;
|
|
471
|
+
targetLocales?: string[];
|
|
472
|
+
locales?: string[];
|
|
473
|
+
keys?: string[];
|
|
474
|
+
batchSize?: number;
|
|
475
|
+
dryRun?: boolean;
|
|
476
|
+
compact?: boolean;
|
|
477
|
+
projectDir?: string;
|
|
478
|
+
/**
|
|
479
|
+
* Also re-translate keys whose target was written from source text that has
|
|
480
|
+
* changed since (translation memory only). Off by default: without it the
|
|
481
|
+
* operation still never touches an existing value, it only reports the stale
|
|
482
|
+
* ones in `stale`.
|
|
483
|
+
*/
|
|
484
|
+
overwriteStale?: boolean;
|
|
485
|
+
translateFn?: TranslateFn;
|
|
486
|
+
progressFn?: ProgressFn;
|
|
487
|
+
/** Called once after the pre-scan with the computed total number of progress steps. */
|
|
488
|
+
onProgressTotal?: (total: number) => void;
|
|
489
|
+
}
|
|
329
490
|
interface TranslateMissingLocaleResult {
|
|
330
491
|
mode: TranslateMode;
|
|
331
492
|
/** Number of missing keys found for this locale. Always equals
|
|
@@ -342,6 +503,14 @@ interface TranslateMissingLocaleResult {
|
|
|
342
503
|
key: string;
|
|
343
504
|
reason: TranslateSkipReason;
|
|
344
505
|
}>;
|
|
506
|
+
/**
|
|
507
|
+
* Translation-memory only: keys whose target value was written from source
|
|
508
|
+
* text that has changed since, and which this run left untouched. A bucket of
|
|
509
|
+
* its own, not part of `missing` — these keys are translated, just outdated —
|
|
510
|
+
* so the invariant above still holds. Re-translating them needs
|
|
511
|
+
* `overwriteStale`, which counts them into `missing` instead.
|
|
512
|
+
*/
|
|
513
|
+
stale?: string[];
|
|
345
514
|
batches?: number;
|
|
346
515
|
model?: string;
|
|
347
516
|
writeError?: string;
|
|
@@ -356,6 +525,7 @@ interface TranslateMissingCompactEntry {
|
|
|
356
525
|
failed: number;
|
|
357
526
|
skipped: number;
|
|
358
527
|
wouldTranslate?: number;
|
|
528
|
+
stale?: number;
|
|
359
529
|
batches?: number;
|
|
360
530
|
model?: string;
|
|
361
531
|
writeError?: string;
|
|
@@ -372,6 +542,8 @@ interface TranslateMissingResult {
|
|
|
372
542
|
totalFailed: number;
|
|
373
543
|
totalSkipped: number;
|
|
374
544
|
totalWouldTranslate?: number;
|
|
545
|
+
/** Translation-memory only: stale keys left untouched, across all locales. */
|
|
546
|
+
staleCount?: number;
|
|
375
547
|
layer: string;
|
|
376
548
|
referenceLocale: string | LocaleRefInfo;
|
|
377
549
|
targetLocales: Array<string | LocaleRefInfo>;
|
|
@@ -393,6 +565,8 @@ interface TranslateAllLayersSummary {
|
|
|
393
565
|
totalFailed: number;
|
|
394
566
|
totalSkipped: number;
|
|
395
567
|
totalWouldTranslate?: number;
|
|
568
|
+
/** Translation-memory only: stale keys left untouched, across all layers and locales. */
|
|
569
|
+
staleCount?: number;
|
|
396
570
|
/** Layer names that were translated. */
|
|
397
571
|
layers: string[];
|
|
398
572
|
byLayer: TranslateLayerTotals[];
|
|
@@ -425,6 +599,18 @@ interface TranslateKeyLocaleIssue {
|
|
|
425
599
|
reason: TranslateFailReason | 'read-error';
|
|
426
600
|
detail?: string;
|
|
427
601
|
}
|
|
602
|
+
/**
|
|
603
|
+
* One locale translate_key deliberately left alone. `reason` is a closed set;
|
|
604
|
+
* `stale` refines 'already-translated' rather than extending it, so a caller
|
|
605
|
+
* can tell an existing translation that still matches its source from one the
|
|
606
|
+
* source has since outgrown.
|
|
607
|
+
*/
|
|
608
|
+
interface TranslateKeySkip {
|
|
609
|
+
locale: string;
|
|
610
|
+
reason: TranslateSkipReason;
|
|
611
|
+
/** Translation-memory only: whether the existing value is out of date. */
|
|
612
|
+
stale?: boolean;
|
|
613
|
+
}
|
|
428
614
|
interface TranslateKeyResult {
|
|
429
615
|
key: string;
|
|
430
616
|
sourceLocale: LocaleRefInfo;
|
|
@@ -433,10 +619,7 @@ interface TranslateKeyResult {
|
|
|
433
619
|
translated: string[];
|
|
434
620
|
/** Dry-run only: locales that would be translated. */
|
|
435
621
|
wouldTranslate?: string[];
|
|
436
|
-
skipped:
|
|
437
|
-
locale: string;
|
|
438
|
-
reason: TranslateSkipReason;
|
|
439
|
-
}>;
|
|
622
|
+
skipped: TranslateKeySkip[];
|
|
440
623
|
failed: TranslateKeyLocaleIssue[];
|
|
441
624
|
filesWritten: number;
|
|
442
625
|
dryRun: boolean;
|
|
@@ -468,9 +651,22 @@ interface UnresolvedKeyWarningRef {
|
|
|
468
651
|
callee: string;
|
|
469
652
|
suggestedIgnorePattern?: string;
|
|
470
653
|
}
|
|
654
|
+
/**
|
|
655
|
+
* One `declaredNamespaces` entry with the keys it answers for.
|
|
656
|
+
*
|
|
657
|
+
* `matchedKeys` is what makes a declaration auditable in both directions: the
|
|
658
|
+
* keys a reader would otherwise see in the orphan list, and — when it is empty
|
|
659
|
+
* — a declaration whose namespace no longer exists.
|
|
660
|
+
*/
|
|
661
|
+
interface DeclaredNamespaceRef {
|
|
662
|
+
pattern: string;
|
|
663
|
+
/** What keeps these keys alive, as declared in the config. */
|
|
664
|
+
reason: string;
|
|
665
|
+
/** Keys of the checked layers this pattern covers. Empty means the declaration is stale. */
|
|
666
|
+
matchedKeys: string[];
|
|
667
|
+
}
|
|
471
668
|
interface FindOrphanKeysResult {
|
|
472
|
-
|
|
473
|
-
orphanKeys?: Record<string, string[]>;
|
|
669
|
+
orphanKeys: Record<string, string[]>;
|
|
474
670
|
uncertainKeys?: Record<string, string[]>;
|
|
475
671
|
/**
|
|
476
672
|
* Keys kept alive solely by the bare-candidate net — nothing a frontend
|
|
@@ -483,6 +679,9 @@ interface FindOrphanKeysResult {
|
|
|
483
679
|
/** Keys used only from apps that do not consume the owning layer. */
|
|
484
680
|
misplacedUsages?: MisplacedUsageRef[];
|
|
485
681
|
misplacedUsageNote?: string;
|
|
682
|
+
/** Every declared namespace with the keys it covers. Present when any is declared. */
|
|
683
|
+
declaredNamespaces?: DeclaredNamespaceRef[];
|
|
684
|
+
declaredNamespaceNote?: string;
|
|
486
685
|
summary: {
|
|
487
686
|
totalKeys: number;
|
|
488
687
|
orphanCount: number;
|
|
@@ -491,6 +690,8 @@ interface FindOrphanKeysResult {
|
|
|
491
690
|
misplacedCount?: number;
|
|
492
691
|
dynamicMatchedCount?: number;
|
|
493
692
|
ignoredCount?: number;
|
|
693
|
+
/** Keys withheld from the orphan list by a declared namespace. */
|
|
694
|
+
declaredCount?: number;
|
|
494
695
|
usedCount?: number;
|
|
495
696
|
filesScanned: number;
|
|
496
697
|
/** Files a syntax frontend declined; pattern matching read them instead. */
|
|
@@ -504,13 +705,10 @@ interface FindOrphanKeysResult {
|
|
|
504
705
|
dynamicKeyWarning?: string;
|
|
505
706
|
dynamicKeys?: DynamicKeyRef[];
|
|
506
707
|
unresolvedKeyWarnings?: UnresolvedKeyWarningRef[];
|
|
507
|
-
/** Present when reportOutput is configured */
|
|
508
|
-
reportFile?: string;
|
|
509
708
|
}
|
|
510
709
|
/** Where each requested key is referenced in source. */
|
|
511
710
|
interface CodeUsageResult {
|
|
512
|
-
|
|
513
|
-
usages?: Record<string, CodeUsageRef[]>;
|
|
711
|
+
usages: Record<string, CodeUsageRef[]>;
|
|
514
712
|
/** Requested keys with no reference anywhere in the scanned source. */
|
|
515
713
|
notFoundInCode?: string[];
|
|
516
714
|
/** Dynamic expressions that could reach the requested keys. */
|
|
@@ -524,8 +722,6 @@ interface CodeUsageResult {
|
|
|
524
722
|
dirsScanned?: string[];
|
|
525
723
|
message?: string;
|
|
526
724
|
};
|
|
527
|
-
/** Present when the full report went to a file instead. */
|
|
528
|
-
reportFile?: string;
|
|
529
725
|
}
|
|
530
726
|
interface CodeUsageRef {
|
|
531
727
|
file: string;
|
|
@@ -544,8 +740,6 @@ interface ScanCodeUsageResult {
|
|
|
544
740
|
};
|
|
545
741
|
notFoundInCode?: string[];
|
|
546
742
|
dynamicKeys?: DynamicKeyRef[];
|
|
547
|
-
/** Present when reportOutput is configured */
|
|
548
|
-
reportFile?: string;
|
|
549
743
|
}
|
|
550
744
|
interface RemoveOrphanKeysResult {
|
|
551
745
|
orphanKeys?: Record<string, string[]>;
|
|
@@ -553,6 +747,9 @@ interface RemoveOrphanKeysResult {
|
|
|
553
747
|
uncertainKeys?: Record<string, string[]>;
|
|
554
748
|
misplacedUsages?: MisplacedUsageRef[];
|
|
555
749
|
misplacedUsageNote?: string;
|
|
750
|
+
/** Every declared namespace with the keys it covers — the keys this run will not delete. */
|
|
751
|
+
declaredNamespaces?: DeclaredNamespaceRef[];
|
|
752
|
+
declaredNamespaceNote?: string;
|
|
556
753
|
summary: {
|
|
557
754
|
dryRun?: boolean;
|
|
558
755
|
totalKeys: number;
|
|
@@ -562,6 +759,8 @@ interface RemoveOrphanKeysResult {
|
|
|
562
759
|
misplacedCount?: number;
|
|
563
760
|
dynamicMatchedCount?: number;
|
|
564
761
|
ignoredCount?: number;
|
|
762
|
+
/** Keys withheld from the orphan list by a declared namespace. */
|
|
763
|
+
declaredCount?: number;
|
|
565
764
|
usedCount?: number;
|
|
566
765
|
remainingCount?: number;
|
|
567
766
|
filesScanned?: number;
|
|
@@ -575,8 +774,6 @@ interface RemoveOrphanKeysResult {
|
|
|
575
774
|
dynamicKeyWarning?: string;
|
|
576
775
|
dynamicKeys?: DynamicKeyRef[];
|
|
577
776
|
unresolvedKeyWarnings?: UnresolvedKeyWarningRef[];
|
|
578
|
-
/** Present when reportOutput is configured */
|
|
579
|
-
reportFile?: string;
|
|
580
777
|
}
|
|
581
778
|
interface ScaffoldLocaleFileInfo {
|
|
582
779
|
locale: string;
|
|
@@ -625,7 +822,7 @@ declare function findLocaleImpl(config: I18nConfig, localeRef: string): LocaleDe
|
|
|
625
822
|
* project default. Throws LOCALE_NOT_FOUND listing the available codes.
|
|
626
823
|
*/
|
|
627
824
|
//#endregion
|
|
628
|
-
//#region src/core/
|
|
825
|
+
//#region src/core/translate/targets.d.ts
|
|
629
826
|
/**
|
|
630
827
|
* Resolve the config's `protectedLocales` entries (any locale ref: code,
|
|
631
828
|
* language tag, or file name) against the known locales. Entries that do not
|
|
@@ -633,6 +830,15 @@ declare function findLocaleImpl(config: I18nConfig, localeRef: string): LocaleDe
|
|
|
633
830
|
* definitions, deduplicated by canonical code.
|
|
634
831
|
*/
|
|
635
832
|
declare function resolveProtectedLocales(config: I18nConfig): LocaleDefinition[];
|
|
833
|
+
/**
|
|
834
|
+
* Resolve translate_missing target locales. Protected locales are excluded
|
|
835
|
+
* from the DEFAULT target set (returned separately so the caller can report
|
|
836
|
+
* them as skipped); naming one explicitly in targetLocales overrides the
|
|
837
|
+
* protection with a warning.
|
|
838
|
+
*/
|
|
839
|
+
|
|
840
|
+
//#endregion
|
|
841
|
+
//#region src/core/translate/run.d.ts
|
|
636
842
|
/**
|
|
637
843
|
* Find keys missing in target locales and translate them.
|
|
638
844
|
*
|
|
@@ -642,21 +848,7 @@ declare function resolveProtectedLocales(config: I18nConfig): LocaleDefinition[]
|
|
|
642
848
|
* When `layer` is omitted, every canonical locale-backed layer is translated
|
|
643
849
|
* in one run and the results are aggregated (see translateMissingAllLayers).
|
|
644
850
|
*/
|
|
645
|
-
declare function translateMissing(opts:
|
|
646
|
-
layer?: string;
|
|
647
|
-
referenceLocale?: string;
|
|
648
|
-
targetLocales?: string[];
|
|
649
|
-
locales?: string[];
|
|
650
|
-
keys?: string[];
|
|
651
|
-
batchSize?: number;
|
|
652
|
-
dryRun?: boolean;
|
|
653
|
-
compact?: boolean;
|
|
654
|
-
projectDir?: string;
|
|
655
|
-
translateFn?: TranslateFn;
|
|
656
|
-
progressFn?: ProgressFn;
|
|
657
|
-
/** Called once after the pre-scan with the computed total number of progress steps. */
|
|
658
|
-
onProgressTotal?: (total: number) => void;
|
|
659
|
-
}): Promise<TranslateMissingOutcome>;
|
|
851
|
+
declare function translateMissing(opts: TranslateMissingOptions): Promise<TranslateMissingOutcome>;
|
|
660
852
|
/**
|
|
661
853
|
* Translate one key from a source locale into target locales. Unlike
|
|
662
854
|
* translate_missing, this can overwrite stale existing target values.
|
|
@@ -673,9 +865,23 @@ declare function translateKey(opts: {
|
|
|
673
865
|
projectDir?: string;
|
|
674
866
|
translateFn?: TranslateFn;
|
|
675
867
|
}): Promise<TranslateKeyResult>;
|
|
676
|
-
//# sourceMappingURL=
|
|
868
|
+
//# sourceMappingURL=run.d.ts.map
|
|
677
869
|
//#endregion
|
|
678
870
|
//#region src/core/ops-read.d.ts
|
|
871
|
+
/**
|
|
872
|
+
* Everything a caller needs to know about a project before touching it:
|
|
873
|
+
* resolved config, locale directories, the layer topology, and which locales
|
|
874
|
+
* are hand-maintained.
|
|
875
|
+
*
|
|
876
|
+
* This composition used to live in the MCP `discover` handler, so the terminal
|
|
877
|
+
* had no way to ask the question its own docs told people to ask — and the two
|
|
878
|
+
* surfaces would have had to be kept in step by hand once one of them grew a
|
|
879
|
+
* field. Callers add whatever is theirs alone (the MCP server adds the
|
|
880
|
+
* translation backend it resolved at startup); the project half is here.
|
|
881
|
+
*/
|
|
882
|
+
declare function describeProject(opts?: {
|
|
883
|
+
projectDir?: string;
|
|
884
|
+
}): Promise<DescribeProjectResult>;
|
|
679
885
|
/**
|
|
680
886
|
* Detect the i18n configuration from the project, always bypassing the
|
|
681
887
|
* config cache (clears it first).
|
|
@@ -704,7 +910,6 @@ declare function getMissingTranslations(opts: {
|
|
|
704
910
|
targetLocales?: string[];
|
|
705
911
|
locales?: string[];
|
|
706
912
|
projectDir?: string;
|
|
707
|
-
outputFile?: string;
|
|
708
913
|
}): Promise<MissingTranslationsResult>;
|
|
709
914
|
/**
|
|
710
915
|
* Find translation keys that have empty string values in locale files.
|
|
@@ -713,27 +918,30 @@ declare function findEmptyTranslations(opts: {
|
|
|
713
918
|
layer?: string;
|
|
714
919
|
locale?: string;
|
|
715
920
|
projectDir?: string;
|
|
716
|
-
outputFile?: string;
|
|
717
921
|
}): Promise<EmptyTranslationsResult>;
|
|
718
922
|
/**
|
|
719
|
-
*
|
|
923
|
+
* The scan behind {@link findEmptyTranslations}, against a config the caller
|
|
924
|
+
* already has.
|
|
925
|
+
*
|
|
926
|
+
* Separate so `getTranslationStatus` can embed the listing under its own
|
|
927
|
+
* `--list-empty` flag without detecting the project a second time.
|
|
928
|
+
*/
|
|
929
|
+
|
|
930
|
+
/**
|
|
931
|
+
* Search translation files by key path or value.
|
|
932
|
+
*
|
|
933
|
+
* Returns one row per key. The detail rows — one per key and locale — are what
|
|
934
|
+
* `includeLocales` asks for.
|
|
720
935
|
*/
|
|
721
936
|
declare function searchTranslations(opts: {
|
|
722
937
|
query: string;
|
|
723
938
|
searchIn?: 'keys' | 'values' | 'both';
|
|
939
|
+
matchMode?: SearchMatchMode;
|
|
940
|
+
includeLocales?: boolean;
|
|
724
941
|
layer?: string;
|
|
725
942
|
locale?: string;
|
|
726
943
|
projectDir?: string;
|
|
727
|
-
|
|
728
|
-
}): Promise<{
|
|
729
|
-
matches: SearchMatch[];
|
|
730
|
-
totalMatches: number;
|
|
731
|
-
} | {
|
|
732
|
-
reportFile: string;
|
|
733
|
-
summary: {
|
|
734
|
-
totalMatches: number;
|
|
735
|
-
};
|
|
736
|
-
}>;
|
|
944
|
+
}): Promise<SearchTranslationsResult>;
|
|
737
945
|
interface NamespaceNode {
|
|
738
946
|
keyCount: number;
|
|
739
947
|
children?: Record<string, NamespaceNode>;
|
|
@@ -770,28 +978,6 @@ declare function writeTranslations(opts: {
|
|
|
770
978
|
dryRun?: boolean;
|
|
771
979
|
projectDir?: string;
|
|
772
980
|
}): Promise<WriteTranslationsResult>;
|
|
773
|
-
/**
|
|
774
|
-
* Add new translation keys to the specified layer.
|
|
775
|
-
*
|
|
776
|
-
* @deprecated Use writeTranslations with mode: 'add' instead.
|
|
777
|
-
*/
|
|
778
|
-
declare function addTranslations(opts: {
|
|
779
|
-
layer: string;
|
|
780
|
-
translations: Record<string, Record<string, string>>;
|
|
781
|
-
dryRun?: boolean;
|
|
782
|
-
projectDir?: string;
|
|
783
|
-
}): Promise<AddTranslationsResult>;
|
|
784
|
-
/**
|
|
785
|
-
* Update existing translation keys in the specified layer.
|
|
786
|
-
*
|
|
787
|
-
* @deprecated Use writeTranslations with mode: 'update' instead.
|
|
788
|
-
*/
|
|
789
|
-
declare function updateTranslations(opts: {
|
|
790
|
-
layer: string;
|
|
791
|
-
translations: Record<string, Record<string, string>>;
|
|
792
|
-
dryRun?: boolean;
|
|
793
|
-
projectDir?: string;
|
|
794
|
-
}): Promise<UpdateTranslationsResult>;
|
|
795
981
|
/**
|
|
796
982
|
* Remove one or more translation keys from ALL locale files in the specified layer.
|
|
797
983
|
*/
|
|
@@ -802,7 +988,12 @@ declare function removeTranslations(opts: {
|
|
|
802
988
|
projectDir?: string;
|
|
803
989
|
}): Promise<RemoveTranslationsResult>;
|
|
804
990
|
/**
|
|
805
|
-
* Rename
|
|
991
|
+
* Rename a translation key across ALL locale files in one layer.
|
|
992
|
+
*
|
|
993
|
+
* Reachable on both surfaces through {@link moveTranslationKey}, which routes a
|
|
994
|
+
* same-layer request here. Kept exported because renaming within a layer is a
|
|
995
|
+
* complete operation on its own, and a programmatic caller that means exactly
|
|
996
|
+
* that should not have to express it as a move to nowhere.
|
|
806
997
|
*/
|
|
807
998
|
declare function renameTranslationKey(opts: {
|
|
808
999
|
layer: string;
|
|
@@ -821,7 +1012,13 @@ declare function scaffoldLocaleFiles(opts: {
|
|
|
821
1012
|
projectDir?: string;
|
|
822
1013
|
}): Promise<ScaffoldLocaleResult>;
|
|
823
1014
|
/**
|
|
824
|
-
* Move a key
|
|
1015
|
+
* Move a key: to another layer, to another key path, or both.
|
|
1016
|
+
*
|
|
1017
|
+
* One entry point rather than two, because the caller's intent is "this key
|
|
1018
|
+
* belongs somewhere else" and whether that somewhere else is a different layer
|
|
1019
|
+
* is a detail of the project's shape, not a different operation. Omitting
|
|
1020
|
+
* `toLayer` (or naming the layer the key already lives in) is a rename within
|
|
1021
|
+
* the layer and routes to {@link renameTranslationKey}.
|
|
825
1022
|
*
|
|
826
1023
|
* Promoting an app-layer key to the shared layer once a second app needs it is
|
|
827
1024
|
* a first-class operation in a layered monorepo, and composing it out of
|
|
@@ -842,13 +1039,15 @@ declare function scaffoldLocaleFiles(opts: {
|
|
|
842
1039
|
* silently.
|
|
843
1040
|
*/
|
|
844
1041
|
declare function moveTranslationKey(opts: {
|
|
845
|
-
|
|
846
|
-
|
|
1042
|
+
/** Layer the key lives in today. */
|
|
1043
|
+
layer: string;
|
|
847
1044
|
key: string;
|
|
1045
|
+
/** Layer to move it to. Omitted, or equal to `layer`, means a rename in place. */
|
|
1046
|
+
toLayer?: string;
|
|
848
1047
|
newKey?: string;
|
|
849
1048
|
dryRun?: boolean;
|
|
850
1049
|
projectDir?: string;
|
|
851
|
-
}): Promise<
|
|
1050
|
+
}): Promise<MoveTranslationKeyOutcome>;
|
|
852
1051
|
//# sourceMappingURL=ops-write.d.ts.map
|
|
853
1052
|
//#endregion
|
|
854
1053
|
//#region src/core/ops-status.d.ts
|
|
@@ -863,8 +1062,13 @@ declare function moveTranslationKey(opts: {
|
|
|
863
1062
|
declare function getTranslationStatus(opts: {
|
|
864
1063
|
layer?: string;
|
|
865
1064
|
referenceLocale?: string;
|
|
1065
|
+
/**
|
|
1066
|
+
* Also list the keys behind `summary.emptyKeys`, under `empty`. Off by
|
|
1067
|
+
* default: the count is what a health check reads, and the list grows with
|
|
1068
|
+
* the project.
|
|
1069
|
+
*/
|
|
1070
|
+
listEmpty?: boolean;
|
|
866
1071
|
projectDir?: string;
|
|
867
|
-
outputFile?: string;
|
|
868
1072
|
}): Promise<TranslationStatusResult>;
|
|
869
1073
|
//# sourceMappingURL=ops-status.d.ts.map
|
|
870
1074
|
//#endregion
|
|
@@ -909,13 +1113,9 @@ type CallArgument = /** A literal: `t('common.save')`. */
|
|
|
909
1113
|
kind: 'unknown';
|
|
910
1114
|
};
|
|
911
1115
|
/** Everything one file yields. Unchanged from what the scanner already consumes. */
|
|
912
|
-
|
|
913
|
-
usages: KeyUsage[];
|
|
914
|
-
dynamicKeys: DynamicKeyUsage[];
|
|
915
|
-
bareStringCandidates: Set<string>;
|
|
916
|
-
}
|
|
1116
|
+
|
|
917
1117
|
interface LanguageFrontend {
|
|
918
|
-
/**
|
|
1118
|
+
/** Names the frontend in diagnostics, so a decline says which one declined. */
|
|
919
1119
|
readonly name: string;
|
|
920
1120
|
/** Whether this frontend reads that file. */
|
|
921
1121
|
handles(filePath: string): boolean;
|
|
@@ -950,17 +1150,13 @@ interface ScanPatternSet {
|
|
|
950
1150
|
* producing `${_}.header`-class candidates that suppress every key ending
|
|
951
1151
|
* in those segments. Language-neutral shapes (dotted literals,
|
|
952
1152
|
* trailing-dot prefixes) always run.
|
|
1153
|
+
*
|
|
1154
|
+
* Two-valued only because the two supported languages need two shape sets.
|
|
1155
|
+
* A third frontend makes this a language identifier rather than a family
|
|
1156
|
+
* flag — widen it then, and key it on the language the scanner is reading.
|
|
953
1157
|
*/
|
|
954
1158
|
bareShapes?: 'js' | 'php';
|
|
955
1159
|
}
|
|
956
|
-
declare const VUE_NUXT_PATTERNS: ScanPatternSet;
|
|
957
|
-
/**
|
|
958
|
-
* Maps locale file format to the appropriate scan pattern set.
|
|
959
|
-
* 'php-array' → Laravel (PHP translation helpers in Blade/PHP files).
|
|
960
|
-
* 'json' / undefined → Vue/Nuxt ($t / t calls in Vue/TS/JS files).
|
|
961
|
-
*/
|
|
962
|
-
declare function getPatternSet(format?: LocaleFileFormat): ScanPatternSet;
|
|
963
|
-
//# sourceMappingURL=patterns.d.ts.map
|
|
964
1160
|
//#endregion
|
|
965
1161
|
//#region src/scanner/code-scanner.d.ts
|
|
966
1162
|
interface KeyUsage {
|
|
@@ -1005,7 +1201,18 @@ interface ScanResult {
|
|
|
1005
1201
|
* frontend reports call sites, the rules decide what they mean.
|
|
1006
1202
|
*/
|
|
1007
1203
|
|
|
1008
|
-
|
|
1204
|
+
/** What a caller can hand a scan beyond its inputs. */
|
|
1205
|
+
interface ScanSourceFilesHooks {
|
|
1206
|
+
/** Files to read, relative to `rootDir` — a {@link globSourceFiles} result, reused instead of walking the tree twice. */
|
|
1207
|
+
files?: string[];
|
|
1208
|
+
/**
|
|
1209
|
+
* Called once per file, right after it was read. `done` counts completions,
|
|
1210
|
+
* so it fires in completion order while the scan result itself stays in
|
|
1211
|
+
* input order — a counter is all that depends on the timing.
|
|
1212
|
+
*/
|
|
1213
|
+
onFile?: (done: number, total: number, file: string) => void;
|
|
1214
|
+
}
|
|
1215
|
+
declare function scanSourceFiles(rootDir: string, excludeDirs?: string[], patterns?: ScanPatternSet, frontends?: LanguageFrontend[], hooks?: ScanSourceFilesHooks): Promise<ScanResult>;
|
|
1009
1216
|
//#endregion
|
|
1010
1217
|
//#region src/core/ops-orphans.d.ts
|
|
1011
1218
|
/**
|
|
@@ -1024,7 +1231,10 @@ declare function findOrphanKeys(opts: {
|
|
|
1024
1231
|
scanDirs?: string[];
|
|
1025
1232
|
excludeDirs?: string[];
|
|
1026
1233
|
projectDir?: string;
|
|
1027
|
-
|
|
1234
|
+
/** Scanning every source file of every app takes seconds — a caller that asked for progress hears about each stride of files. */
|
|
1235
|
+
progressFn?: ProgressFn;
|
|
1236
|
+
/** Called once with the number of progress steps, before the first `progressFn` call. */
|
|
1237
|
+
onProgressTotal?: (total: number) => void;
|
|
1028
1238
|
}): Promise<FindOrphanKeysResult>;
|
|
1029
1239
|
/**
|
|
1030
1240
|
* Scan Vue/TS source files to find where translation keys are referenced.
|
|
@@ -1034,7 +1244,6 @@ declare function scanCodeUsage(opts: {
|
|
|
1034
1244
|
scanDirs?: string[];
|
|
1035
1245
|
excludeDirs?: string[];
|
|
1036
1246
|
projectDir?: string;
|
|
1037
|
-
outputFile?: string;
|
|
1038
1247
|
}): Promise<CodeUsageResult>;
|
|
1039
1248
|
/**
|
|
1040
1249
|
* Find translation keys not referenced in source code and remove them.
|
|
@@ -1047,9 +1256,10 @@ declare function removeOrphanKeys(opts: {
|
|
|
1047
1256
|
excludeDirs?: string[];
|
|
1048
1257
|
dryRun?: boolean;
|
|
1049
1258
|
projectDir?: string;
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1259
|
+
/** Same scan as {@link findOrphanKeys}, same reporting. */
|
|
1260
|
+
progressFn?: ProgressFn;
|
|
1261
|
+
/** Called once with the number of progress steps, before the first `progressFn` call. */
|
|
1262
|
+
onProgressTotal?: (total: number) => void;
|
|
1053
1263
|
}): Promise<RemoveOrphanKeysResult>;
|
|
1054
1264
|
//# sourceMappingURL=ops-orphans.d.ts.map
|
|
1055
1265
|
//#endregion
|
|
@@ -1114,7 +1324,6 @@ interface FindDuplicateKeysResult {
|
|
|
1114
1324
|
declare function findDuplicateKeys(opts?: {
|
|
1115
1325
|
locale?: string;
|
|
1116
1326
|
projectDir?: string;
|
|
1117
|
-
outputFile?: string;
|
|
1118
1327
|
/**
|
|
1119
1328
|
* Also group keys by the value they carry. Off by default: it reads every
|
|
1120
1329
|
* canonical layer rather than only the paired ones, and the existing result
|
|
@@ -1123,10 +1332,7 @@ declare function findDuplicateKeys(opts?: {
|
|
|
1123
1332
|
byValue?: boolean;
|
|
1124
1333
|
/** Shortest value worth grouping. Below it, repetition is usually legitimate. */
|
|
1125
1334
|
minValueLength?: number;
|
|
1126
|
-
}): Promise<FindDuplicateKeysResult
|
|
1127
|
-
reportFile: string;
|
|
1128
|
-
summary: FindDuplicateKeysSummary;
|
|
1129
|
-
}>;
|
|
1335
|
+
}): Promise<FindDuplicateKeysResult>;
|
|
1130
1336
|
//# sourceMappingURL=ops-duplicates.d.ts.map
|
|
1131
1337
|
//#endregion
|
|
1132
1338
|
//#region src/core/ops-check.d.ts
|
|
@@ -1155,13 +1361,31 @@ interface UncertainKeyFinding extends UndefinedKeyFinding {
|
|
|
1155
1361
|
/** Why this is not a hard finding. */
|
|
1156
1362
|
reason: string;
|
|
1157
1363
|
}
|
|
1364
|
+
/** The locale file `write` extracted the undefined keys into. */
|
|
1365
|
+
interface ExtractedUndefinedKeys {
|
|
1366
|
+
layer: string;
|
|
1367
|
+
/** The project's default locale — the source every other locale is filled from. */
|
|
1368
|
+
locale: string;
|
|
1369
|
+
/** The keys that reached the file, in alphabetical order. */
|
|
1370
|
+
keys: string[];
|
|
1371
|
+
}
|
|
1158
1372
|
interface CheckUndefinedKeysSummary {
|
|
1159
1373
|
/** Distinct statically referenced keys across all scan units. */
|
|
1160
1374
|
usedKeysChecked: number;
|
|
1375
|
+
/**
|
|
1376
|
+
* Keys that render raw at runtime, which is what the gate reads. After a
|
|
1377
|
+
* `write` run this counts the ones still undefined: an extracted key now has
|
|
1378
|
+
* a definition — an empty one — so it resolves, and `status` reports it as an
|
|
1379
|
+
* empty translation instead.
|
|
1380
|
+
*/
|
|
1161
1381
|
undefinedCount: number;
|
|
1382
|
+
/** Keys extracted into a locale file. Present only alongside `written`. */
|
|
1383
|
+
writtenCount?: number;
|
|
1162
1384
|
uncertainCount: number;
|
|
1163
1385
|
/** Unresolvable keys excluded by orphanScan ignorePatterns. */
|
|
1164
1386
|
ignoredCount: number;
|
|
1387
|
+
/** Unresolvable keys covered by a declaredNamespaces entry — defined by contract, never written. */
|
|
1388
|
+
declaredCount: number;
|
|
1165
1389
|
filesScanned: number;
|
|
1166
1390
|
/** Files a syntax frontend declined; pattern matching read them instead. */
|
|
1167
1391
|
filesDeclined: number;
|
|
@@ -1171,9 +1395,19 @@ interface CheckUndefinedKeysSummary {
|
|
|
1171
1395
|
message: string;
|
|
1172
1396
|
}
|
|
1173
1397
|
interface CheckUndefinedKeysResult {
|
|
1398
|
+
/**
|
|
1399
|
+
* The findings as the scan made them. A `write` run leaves them in place —
|
|
1400
|
+
* what was extracted is named in `written`, and the summary counts what is
|
|
1401
|
+
* left — because the call sites are what a reader has to visit either way.
|
|
1402
|
+
*/
|
|
1174
1403
|
undefinedKeys: UndefinedKeyFinding[];
|
|
1175
1404
|
uncertainKeys: UncertainKeyFinding[];
|
|
1176
1405
|
limitation: string;
|
|
1406
|
+
/**
|
|
1407
|
+
* Present only when `write` was asked for and the scan found something to
|
|
1408
|
+
* write. A clean scan reports nothing here, having written nothing.
|
|
1409
|
+
*/
|
|
1410
|
+
written?: ExtractedUndefinedKeys;
|
|
1177
1411
|
summary: CheckUndefinedKeysSummary;
|
|
1178
1412
|
}
|
|
1179
1413
|
/**
|
|
@@ -1186,6 +1420,9 @@ interface CheckUndefinedKeysResult {
|
|
|
1186
1420
|
* scopeByLayer — a unit resolves exactly the layers it vouches for). The
|
|
1187
1421
|
* graph's degenerate semantics carry over: with no app info every layer is
|
|
1188
1422
|
* resolvable everywhere, so only keys defined in NO layer are flagged.
|
|
1423
|
+
*
|
|
1424
|
+
* With `write`, the findings are also extracted into a locale file as empty
|
|
1425
|
+
* translations, which is what turns a report into the first half of the fix.
|
|
1189
1426
|
*/
|
|
1190
1427
|
declare function checkUndefinedKeys(opts?: {
|
|
1191
1428
|
locale?: string;
|
|
@@ -1195,128 +1432,368 @@ declare function checkUndefinedKeys(opts?: {
|
|
|
1195
1432
|
*/
|
|
1196
1433
|
scanDirs?: string[];
|
|
1197
1434
|
excludeDirs?: string[];
|
|
1435
|
+
/** Extract the undefined keys into a locale file. See extractUndefinedKeys. */
|
|
1436
|
+
write?: boolean;
|
|
1437
|
+
/** The layer to extract into, where the findings alone do not decide. */
|
|
1438
|
+
layer?: string;
|
|
1198
1439
|
projectDir?: string;
|
|
1199
|
-
|
|
1200
|
-
/** Also write the findings as a GitLab Code Quality JSON array to this path. */
|
|
1201
|
-
codequalityOutput?: string;
|
|
1202
|
-
}): Promise<CheckUndefinedKeysResult | {
|
|
1203
|
-
reportFile: string;
|
|
1204
|
-
summary: CheckUndefinedKeysSummary;
|
|
1205
|
-
}>;
|
|
1440
|
+
}): Promise<CheckUndefinedKeysResult>;
|
|
1206
1441
|
//# sourceMappingURL=ops-check.d.ts.map
|
|
1207
1442
|
//#endregion
|
|
1208
|
-
//#region src/
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1443
|
+
//#region src/core/codequality.d.ts
|
|
1444
|
+
interface CodeQualityIssue {
|
|
1445
|
+
description: string;
|
|
1446
|
+
check_name: string;
|
|
1447
|
+
fingerprint: string;
|
|
1448
|
+
severity: 'info' | 'minor' | 'major' | 'critical' | 'blocker';
|
|
1449
|
+
location: {
|
|
1450
|
+
path: string;
|
|
1451
|
+
lines: {
|
|
1452
|
+
begin: number;
|
|
1453
|
+
};
|
|
1454
|
+
};
|
|
1455
|
+
}
|
|
1456
|
+
/**
|
|
1457
|
+
* `check` findings → one issue per usage location. Uncertain findings are
|
|
1458
|
+
* not mapped: the widget has no "maybe" state, and a hard-looking finding
|
|
1459
|
+
* for an unverifiable key would train consumers to ignore the report.
|
|
1460
|
+
*/
|
|
1214
1461
|
//#endregion
|
|
1215
|
-
//#region src/
|
|
1462
|
+
//#region src/surface/types.d.ts
|
|
1463
|
+
/** Which surface is invoking an operation. They differ only in the prose they own. */
|
|
1464
|
+
type Surface = 'cli' | 'mcp';
|
|
1216
1465
|
/**
|
|
1217
|
-
*
|
|
1218
|
-
* already carries: which locale dirs are canonical (alias-free), which
|
|
1219
|
-
* layer owns an aliased dir, and which apps consume which layers.
|
|
1466
|
+
* What a parameter carries.
|
|
1220
1467
|
*
|
|
1221
|
-
*
|
|
1222
|
-
*
|
|
1223
|
-
*
|
|
1468
|
+
* `string[]` is a list on both surfaces: MCP passes a JSON array, the CLI a
|
|
1469
|
+
* comma-separated string it splits. `record` is the one nested shape on the
|
|
1470
|
+
* surface — the key → locale → value map `write` takes — so the builders state
|
|
1471
|
+
* its inner levels once instead of every spec carrying a schema.
|
|
1472
|
+
*/
|
|
1473
|
+
type ParamType = 'string' | 'boolean' | 'number' | 'string[]' | 'record';
|
|
1474
|
+
/** The value shape of a `record` parameter: dot-path key → locale ref → string. */
|
|
1475
|
+
type TranslationsRecord = Record<string, Record<string, string>>;
|
|
1476
|
+
interface CliParamOptions {
|
|
1477
|
+
/**
|
|
1478
|
+
* Additional spellings citty accepts for this flag. Single characters render
|
|
1479
|
+
* as `-d`; longer ones are the flag's previous name, kept working after the
|
|
1480
|
+
* descriptor took the name the MCP tool used.
|
|
1481
|
+
*/
|
|
1482
|
+
alias?: string | readonly string[];
|
|
1483
|
+
/** Not exposed as a flag. Every use of this states why in a comment. */
|
|
1484
|
+
hidden?: boolean;
|
|
1485
|
+
}
|
|
1486
|
+
interface McpParamOptions {
|
|
1487
|
+
/** Not part of the tool's input schema. Every use of this states why in a comment. */
|
|
1488
|
+
hidden?: boolean;
|
|
1489
|
+
}
|
|
1490
|
+
/** One parameter of an operation, as both surfaces expose it. */
|
|
1491
|
+
interface ParamSpec {
|
|
1492
|
+
type: ParamType;
|
|
1493
|
+
/**
|
|
1494
|
+
* The one description. It reaches `--help`, the generated CLI page and the
|
|
1495
|
+
* JSON Schema an MCP host hands its model, so it is written for a reader who
|
|
1496
|
+
* knows neither surface: no `--flag` spellings, no "this tool".
|
|
1497
|
+
*/
|
|
1498
|
+
description: string;
|
|
1499
|
+
required?: boolean;
|
|
1500
|
+
/**
|
|
1501
|
+
* Applied by the CLI so `--help` can state it. Deliberately not put into the
|
|
1502
|
+
* JSON Schema: the operations already apply their own defaults, and a schema
|
|
1503
|
+
* default would make a host send a value the caller never chose.
|
|
1504
|
+
*/
|
|
1505
|
+
default?: unknown;
|
|
1506
|
+
/** The accepted values. The CLI validates against them and MCP emits an enum. */
|
|
1507
|
+
enum?: readonly string[];
|
|
1508
|
+
/** Numbers only: reject a fractional value. */
|
|
1509
|
+
integer?: boolean;
|
|
1510
|
+
/** Numbers only: reject anything below this. */
|
|
1511
|
+
min?: number;
|
|
1512
|
+
/** `string[]` parameters that also accept the literal "all". */
|
|
1513
|
+
allowAll?: boolean;
|
|
1514
|
+
cli?: CliParamOptions;
|
|
1515
|
+
mcp?: McpParamOptions;
|
|
1516
|
+
}
|
|
1517
|
+
type Params = Record<string, ParamSpec>;
|
|
1518
|
+
/**
|
|
1519
|
+
* A CI gate a command evaluates. `counter` is the field of `result.summary`
|
|
1520
|
+
* carrying the observed value.
|
|
1224
1521
|
*
|
|
1225
|
-
*
|
|
1522
|
+
* The two shapes are a union rather than one type with optional halves so the
|
|
1523
|
+
* invariants hold at compile time: a flagged gate always has a flag to read
|
|
1524
|
+
* its name and threshold from, and a flagless one always carries both itself.
|
|
1525
|
+
* Stated as options, `{ counter, threshold }` type-checks and then has no name
|
|
1526
|
+
* to report the gate under.
|
|
1527
|
+
*/
|
|
1528
|
+
type GateSpec = FlaggedGateSpec | AlwaysOnGateSpec;
|
|
1529
|
+
interface GateSpecBase {
|
|
1530
|
+
counter: string;
|
|
1531
|
+
/** 'above' trips when observed > threshold (default); 'below' when observed < threshold. */
|
|
1532
|
+
direction?: 'above' | 'below';
|
|
1533
|
+
}
|
|
1534
|
+
/**
|
|
1535
|
+
* Requested by a flag, and evaluated only when that flag is passed. Omitting
|
|
1536
|
+
* `threshold` takes it from the flag's own value, so a boolean flag pairs with
|
|
1537
|
+
* `threshold: 0` and a numeric one (`--failUnder 90`) omits it.
|
|
1538
|
+
*/
|
|
1539
|
+
interface FlaggedGateSpec extends GateSpecBase {
|
|
1540
|
+
flag: string;
|
|
1541
|
+
name?: never;
|
|
1542
|
+
threshold?: number;
|
|
1543
|
+
}
|
|
1544
|
+
/**
|
|
1545
|
+
* Always evaluated, for findings that are a defect rather than a threshold — a
|
|
1546
|
+
* key that renders raw in production is not something you opt into caring
|
|
1547
|
+
* about. It still reports as a gate: the run succeeded, and what it found is
|
|
1548
|
+
* what you are being told about.
|
|
1549
|
+
*/
|
|
1550
|
+
interface AlwaysOnGateSpec extends GateSpecBase {
|
|
1551
|
+
flag?: never;
|
|
1552
|
+
name: string;
|
|
1553
|
+
threshold: number;
|
|
1554
|
+
}
|
|
1555
|
+
/**
|
|
1556
|
+
* What the surface hands a report builder beyond the result: the project the
|
|
1557
|
+
* operation ran against and the arguments it ran with.
|
|
1558
|
+
*/
|
|
1559
|
+
interface ReportContext<A = Record<string, unknown>> {
|
|
1560
|
+
projectDir: string;
|
|
1561
|
+
/** The project's resolved i18n configuration, as the operation itself read it. */
|
|
1562
|
+
config: I18nConfig;
|
|
1563
|
+
/** The operation's arguments, as the surface resolved them. */
|
|
1564
|
+
args: A;
|
|
1565
|
+
}
|
|
1566
|
+
/**
|
|
1567
|
+
* How a result too large to hand back is diverted to a file.
|
|
1226
1568
|
*
|
|
1227
|
-
*
|
|
1228
|
-
*
|
|
1569
|
+
* An operation always returns its whole result. Whether that result is written
|
|
1570
|
+
* to disk and replaced by a compact stand-in is the surface's decision — it is
|
|
1571
|
+
* the surface that owns `outputFile`, the configured report directory and the
|
|
1572
|
+
* name the file is written under — so the operations know nothing about any of
|
|
1573
|
+
* it, and a descriptor declaring this is what gives an operation the parameters
|
|
1574
|
+
* that request it.
|
|
1575
|
+
*/
|
|
1576
|
+
interface ReportSpec<R = unknown, A = Record<string, unknown>> {
|
|
1577
|
+
/**
|
|
1578
|
+
* The file's base name under the configured report directory, and the tool
|
|
1579
|
+
* name recorded inside the report. A function where one operation answers
|
|
1580
|
+
* different questions and writes each under its own name — pipelines archive
|
|
1581
|
+
* these paths, so they are part of the contract.
|
|
1582
|
+
*/
|
|
1583
|
+
name: string | ((args: A) => string);
|
|
1584
|
+
/** The compact stand-in returned once the full result is on disk. */
|
|
1585
|
+
summary: (result: R) => unknown;
|
|
1586
|
+
/**
|
|
1587
|
+
* The `outputFile` parameter as this operation offers it. Declared here and
|
|
1588
|
+
* nowhere else, so an operation cannot advertise the parameter without the
|
|
1589
|
+
* plumbing behind it, nor grow the plumbing without the parameter.
|
|
1590
|
+
*/
|
|
1591
|
+
outputFile: {
|
|
1592
|
+
/** The example path its description carries. */
|
|
1593
|
+
example: string;
|
|
1594
|
+
cli?: CliParamOptions;
|
|
1595
|
+
mcp?: McpParamOptions;
|
|
1596
|
+
};
|
|
1597
|
+
/** The same findings, as a GitLab Code Quality report the pipeline collects. */
|
|
1598
|
+
codequality?: {
|
|
1599
|
+
/** What the findings are called in the parameter's description. */
|
|
1600
|
+
findings: string;
|
|
1601
|
+
/**
|
|
1602
|
+
* Returning undefined writes nothing, which is not the same as writing an
|
|
1603
|
+
* empty array: the empty array is the baseline the merge-request widget
|
|
1604
|
+
* diffs against, so it is only right for a run that looked for these
|
|
1605
|
+
* findings and found none.
|
|
1606
|
+
*/
|
|
1607
|
+
issues: (result: R, ctx: ReportContext<A>) => CodeQualityIssue[] | undefined;
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
/**
|
|
1611
|
+
* A report spec with its result type erased, as the runner sees it.
|
|
1229
1612
|
*
|
|
1230
|
-
*
|
|
1231
|
-
*
|
|
1232
|
-
*
|
|
1233
|
-
* *every* canonical layer — with no ownership information, every
|
|
1234
|
-
* layer's keys must be treated as globally visible.
|
|
1235
|
-
* - **Single-app config** (generic/Laravel/Vue/React adapters, or a Nuxt
|
|
1236
|
-
* project with one app): the strict definition applies, so
|
|
1237
|
-
* `sharedLayers` is empty (no layer is consumed by more than one app)
|
|
1238
|
-
* and `appsUsingLayer` returns that one app for the layers it consumes.
|
|
1239
|
-
* Per-layer scope then equals the whole project, which is correct.
|
|
1240
|
-
* - **Canonical layer consumed by no app** (in a multi-app config):
|
|
1241
|
-
* `appsUsingLayer` returns `[]` and the layer is not in `sharedLayers`.
|
|
1242
|
-
* Callers should treat such layers conservatively (global scope).
|
|
1613
|
+
* `any` rather than `unknown`: the runner holds a result whose type it cannot
|
|
1614
|
+
* know, while every declaration site is checked against its own operation's
|
|
1615
|
+
* result type.
|
|
1243
1616
|
*/
|
|
1244
|
-
|
|
1617
|
+
type AnyReportSpec = ReportSpec<any>;
|
|
1618
|
+
/** How the MCP server advertises an operation as a tool. */
|
|
1619
|
+
interface McpToolSpec {
|
|
1620
|
+
name: string;
|
|
1621
|
+
/** The display title a host shows. */
|
|
1622
|
+
title: string;
|
|
1623
|
+
/** Behaviour hints a host reads. Only the translating tools declare any. */
|
|
1624
|
+
annotations?: {
|
|
1625
|
+
title?: string;
|
|
1626
|
+
readOnlyHint?: boolean;
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1629
|
+
/** How the CLI exposes an operation as a command. */
|
|
1630
|
+
interface CliCommandSpec {
|
|
1631
|
+
name: string;
|
|
1632
|
+
}
|
|
1633
|
+
/**
|
|
1634
|
+
* What a surface hands an operation beyond its parameters.
|
|
1635
|
+
*
|
|
1636
|
+
* `surface` exists because the guidance an agent-mode result carries is the
|
|
1637
|
+
* caller's, not the operation's: a terminal is told to pass `--provider`, a
|
|
1638
|
+
* host is told to translate the fallback contexts inline. Keeping both strings
|
|
1639
|
+
* in one place is the point — they used to sit in two files and say different
|
|
1640
|
+
* things about the same state.
|
|
1641
|
+
*/
|
|
1642
|
+
interface OperationContext {
|
|
1643
|
+
surface: Surface;
|
|
1644
|
+
/** Provider-backed translation, when the surface resolved one. */
|
|
1645
|
+
translateFn?: TranslateFn;
|
|
1245
1646
|
/**
|
|
1246
|
-
*
|
|
1247
|
-
*
|
|
1647
|
+
* Progress reporting, when the caller asked for it. Only MCP does — a
|
|
1648
|
+
* terminal is left with its exit code. The operations that take long enough
|
|
1649
|
+
* to report call it (translating, orphan scans); the rest never do.
|
|
1248
1650
|
*/
|
|
1249
|
-
|
|
1651
|
+
progressFn?: ProgressFn;
|
|
1250
1652
|
/**
|
|
1251
|
-
*
|
|
1252
|
-
*
|
|
1253
|
-
*
|
|
1254
|
-
* names unknown to `localeDirs` (e.g. layers without locale dirs).
|
|
1653
|
+
* The number of steps the operation is about to report, counted in whatever
|
|
1654
|
+
* unit it reports in. Called once, before the first `progressFn` call, so a
|
|
1655
|
+
* notification never goes out against an unknown total.
|
|
1255
1656
|
*/
|
|
1256
|
-
|
|
1657
|
+
onProgressTotal?: (total: number) => void;
|
|
1658
|
+
}
|
|
1659
|
+
/**
|
|
1660
|
+
* The value of one parameter as the operation receives it: already split,
|
|
1661
|
+
* parsed and validated by whichever surface took it.
|
|
1662
|
+
*/
|
|
1663
|
+
type ParamValue<S extends ParamSpec> = S extends {
|
|
1664
|
+
type: 'boolean';
|
|
1665
|
+
} ? boolean : S extends {
|
|
1666
|
+
type: 'number';
|
|
1667
|
+
} ? number : S extends {
|
|
1668
|
+
type: 'record';
|
|
1669
|
+
} ? TranslationsRecord : S extends {
|
|
1670
|
+
type: 'string[]';
|
|
1671
|
+
allowAll: true;
|
|
1672
|
+
} ? string[] | 'all' : S extends {
|
|
1673
|
+
type: 'string[]';
|
|
1674
|
+
} ? string[] : S extends {
|
|
1675
|
+
type: 'string';
|
|
1676
|
+
enum: readonly (infer E extends string)[];
|
|
1677
|
+
} ? E : S extends {
|
|
1678
|
+
type: 'string';
|
|
1679
|
+
} ? string : never;
|
|
1680
|
+
type RequiredParamNames<P extends Params> = { [K in keyof P]-?: P[K] extends {
|
|
1681
|
+
required: true;
|
|
1682
|
+
} ? K : never }[keyof P];
|
|
1683
|
+
/**
|
|
1684
|
+
* The arguments an operation's `run` receives. Required parameters are present,
|
|
1685
|
+
* the rest are optional, and `projectDir` is always available because both
|
|
1686
|
+
* surfaces resolve it themselves (the CLI from `--projectDir`, the server from
|
|
1687
|
+
* I18N_PROJECT_DIR) rather than making every operation declare it.
|
|
1688
|
+
*/
|
|
1689
|
+
type OperationArgs<P extends Params = Params> = { [K in RequiredParamNames<P> & keyof P]: ParamValue<P[K]> } & { [K in Exclude<keyof P, RequiredParamNames<P>>]?: ParamValue<P[K]> } & {
|
|
1690
|
+
projectDir?: string;
|
|
1691
|
+
};
|
|
1692
|
+
/** One operation, as both surfaces read it. */
|
|
1693
|
+
interface OperationDescriptor<P extends Params = Params> {
|
|
1694
|
+
/** Stable identifier, independent of what either surface calls it. */
|
|
1695
|
+
id: string;
|
|
1696
|
+
/** Null for an operation the CLI does not expose. */
|
|
1697
|
+
cli: CliCommandSpec | null;
|
|
1698
|
+
/** Null for an operation the MCP server does not advertise. */
|
|
1699
|
+
mcp: McpToolSpec | null;
|
|
1700
|
+
/** One sentence, on both surfaces. */
|
|
1701
|
+
description: string;
|
|
1257
1702
|
/**
|
|
1258
|
-
*
|
|
1259
|
-
*
|
|
1260
|
-
*
|
|
1261
|
-
*
|
|
1703
|
+
* Further prose for a model deciding whether to call the tool: when to reach
|
|
1704
|
+
* for it, what the result carries, what it will not do. MCP only — a `--help`
|
|
1705
|
+
* line has to stay a line, and the generated CLI page says the same things in
|
|
1706
|
+
* its flag table.
|
|
1262
1707
|
*/
|
|
1263
|
-
|
|
1708
|
+
longDescription?: string;
|
|
1709
|
+
params: P;
|
|
1710
|
+
/** CI gates the CLI evaluates. Exit codes are a CLI notion, so MCP ignores these. */
|
|
1711
|
+
gates?: GateSpec[];
|
|
1264
1712
|
/**
|
|
1265
|
-
*
|
|
1266
|
-
*
|
|
1267
|
-
*
|
|
1268
|
-
*
|
|
1713
|
+
* The operation translates, so the surface has to hand it a backend: the CLI
|
|
1714
|
+
* resolves one from the provider flags, the server from its startup
|
|
1715
|
+
* environment. Without one the operation returns contexts to translate by
|
|
1716
|
+
* hand rather than failing.
|
|
1269
1717
|
*/
|
|
1270
|
-
|
|
1718
|
+
usesTranslateFn?: boolean;
|
|
1271
1719
|
/**
|
|
1272
|
-
*
|
|
1273
|
-
*
|
|
1274
|
-
*
|
|
1720
|
+
* The result is large enough to be worth writing to a file instead of
|
|
1721
|
+
* returning. Declaring this is what adds the parameters that request it and
|
|
1722
|
+
* what makes the configured report directory apply to the operation.
|
|
1723
|
+
*
|
|
1724
|
+
* The result type stays open: a `run` whose parameters are contextually typed
|
|
1725
|
+
* is not an inference site, so nothing here can see the operation's own
|
|
1726
|
+
* result type. Declaration sites annotate it on the builder instead, which is
|
|
1727
|
+
* what type-checks them.
|
|
1275
1728
|
*/
|
|
1276
|
-
|
|
1729
|
+
report?: ReportSpec<any, OperationArgs<P>>;
|
|
1730
|
+
/**
|
|
1731
|
+
* Declared as a method so the table can hold descriptors with different
|
|
1732
|
+
* parameter maps: method parameters are compared bivariantly, which is what
|
|
1733
|
+
* lets `run` be typed against each operation's own arguments and still be
|
|
1734
|
+
* callable through the erased element type below.
|
|
1735
|
+
*/
|
|
1736
|
+
run(args: OperationArgs<P>, ctx: OperationContext): Promise<unknown>;
|
|
1277
1737
|
}
|
|
1278
1738
|
/**
|
|
1279
|
-
*
|
|
1280
|
-
*
|
|
1739
|
+
* A descriptor as the registrars see it, with `run` erased to plain arguments.
|
|
1740
|
+
* They build those arguments from a schema at runtime and cannot know the
|
|
1741
|
+
* per-operation type, so the erasure happens once, in `defineOperation`,
|
|
1742
|
+
* instead of at every call site.
|
|
1281
1743
|
*/
|
|
1282
|
-
|
|
1744
|
+
type AnyOperationDescriptor = Omit<OperationDescriptor<Params>, 'run' | 'params' | 'report'> & {
|
|
1745
|
+
params: Params;
|
|
1746
|
+
report?: AnyReportSpec;
|
|
1747
|
+
run(args: Record<string, unknown>, ctx: OperationContext): Promise<unknown>;
|
|
1748
|
+
};
|
|
1283
1749
|
/**
|
|
1284
|
-
*
|
|
1750
|
+
* Declare one operation. The `const` type parameter is what keeps `required:
|
|
1751
|
+
* true` and `enum: [...]` literal, so `run` receives `layer: string` rather
|
|
1752
|
+
* than `string | undefined` for a parameter the surface guarantees.
|
|
1285
1753
|
*
|
|
1286
|
-
*
|
|
1287
|
-
*
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1754
|
+
* An operation that declares a `report` gains the parameters that request one
|
|
1755
|
+
* here, so the two cannot drift apart.
|
|
1756
|
+
*/
|
|
1757
|
+
//#endregion
|
|
1758
|
+
//#region src/surface/descriptors.d.ts
|
|
1759
|
+
/**
|
|
1760
|
+
* Registry order: it is the order `the-i18n-cli --help` lists commands in and
|
|
1761
|
+
* the order both generated reference overviews are written in.
|
|
1762
|
+
*/
|
|
1763
|
+
declare const descriptors: readonly AnyOperationDescriptor[];
|
|
1764
|
+
/** The descriptors a surface exposes, in registry order. */
|
|
1765
|
+
declare function descriptorsFor(surface: 'cli' | 'mcp'): AnyOperationDescriptor[];
|
|
1766
|
+
/** The parameter names a surface exposes for one operation, in declaration order. */
|
|
1767
|
+
declare function visibleParams(descriptor: AnyOperationDescriptor, surface: 'cli' | 'mcp'): string[];
|
|
1768
|
+
//# sourceMappingURL=descriptors.d.ts.map
|
|
1769
|
+
|
|
1770
|
+
//#endregion
|
|
1771
|
+
//#region src/surface/report.d.ts
|
|
1772
|
+
/**
|
|
1773
|
+
* Write the result where the caller asked for it, and hand back the compact
|
|
1774
|
+
* stand-in — or hand back the result untouched when nothing asked for a file.
|
|
1291
1775
|
*
|
|
1292
|
-
*
|
|
1293
|
-
*
|
|
1294
|
-
* a config with no app info reports *every* canonical layer as shared, and a
|
|
1295
|
-
* layer no app consumes appears in `consumers` with an empty array rather than
|
|
1296
|
-
* being left out. Absent and "none" must not look alike here.
|
|
1776
|
+
* Called with the arguments the operation ran with, which is what lets an
|
|
1777
|
+
* operation answering several questions write each under its own report name.
|
|
1297
1778
|
*/
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
consumers: Record<string, string[]>;
|
|
1307
|
-
}
|
|
1308
|
-
/** Flatten {@link buildLayerGraph}'s view of `config` into plain JSON. */
|
|
1309
|
-
declare function serializeLayerGraph(config: I18nConfig): SerializedLayerGraph;
|
|
1310
|
-
//# sourceMappingURL=layer-graph.d.ts.map
|
|
1779
|
+
declare function divertToReport(result: unknown, descriptor: AnyOperationDescriptor, args: Record<string, unknown>): Promise<unknown>;
|
|
1780
|
+
//# sourceMappingURL=report.d.ts.map
|
|
1781
|
+
//#endregion
|
|
1782
|
+
//#region src/config/cache.d.ts
|
|
1783
|
+
/** The most recently resolved config, or null when nothing has been resolved. */
|
|
1784
|
+
declare function getCachedConfig(): I18nConfig | null;
|
|
1785
|
+
declare function clearConfigCache(): void;
|
|
1786
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
1311
1787
|
//#endregion
|
|
1312
|
-
//#region src/
|
|
1313
|
-
declare function
|
|
1314
|
-
//# sourceMappingURL=
|
|
1788
|
+
//#region src/config/detector.d.ts
|
|
1789
|
+
declare function detectI18nConfig(projectDir: string): Promise<I18nConfig>;
|
|
1790
|
+
//# sourceMappingURL=detector.d.ts.map
|
|
1315
1791
|
|
|
1316
1792
|
//#endregion
|
|
1317
1793
|
//#region src/scanner/frontends/patterns.d.ts
|
|
1318
1794
|
/**
|
|
1319
|
-
*
|
|
1795
|
+
* Pattern matching as a language frontend, reached only for a file a syntax
|
|
1796
|
+
* frontend declined.
|
|
1320
1797
|
*
|
|
1321
1798
|
* Regexes frame text and report call sites; what a site means is decided once,
|
|
1322
1799
|
* in the rules, the same as for every other frontend. Binding is always
|
|
@@ -1339,24 +1816,6 @@ declare function createPhpFrontend(): LanguageFrontend;
|
|
|
1339
1816
|
* a key's fate must not depend on which file type referenced it (#332).
|
|
1340
1817
|
*/
|
|
1341
1818
|
|
|
1342
|
-
//#endregion
|
|
1343
|
-
//#region src/scanner/frontends/php/blade.d.ts
|
|
1344
|
-
/**
|
|
1345
|
-
* Blade, by lifting (#404, #332).
|
|
1346
|
-
*
|
|
1347
|
-
* No maintained Blade AST parser exists, and none is needed: every construct
|
|
1348
|
-
* that can carry a translation key wraps a PHP expression. The lexical pass
|
|
1349
|
-
* here finds those wrappers — echoes, `@lang`/`@choice`, `@php` blocks, raw
|
|
1350
|
-
* PHP tags — and hands the expression inside to the same parser and the same
|
|
1351
|
-
* site collection plain PHP uses. The regex frames text; it never decides
|
|
1352
|
-
* what a key is.
|
|
1353
|
-
*
|
|
1354
|
-
* A lifted chunk the parser cannot read declines the whole file to the
|
|
1355
|
-
* pattern fallback: partially-read templates would silently drop keys.
|
|
1356
|
-
*/
|
|
1357
|
-
declare function createBladeFrontend(): LanguageFrontend;
|
|
1358
|
-
//# sourceMappingURL=blade.d.ts.map
|
|
1359
|
-
|
|
1360
1819
|
//#endregion
|
|
1361
1820
|
//#region src/io/locale-data.d.ts
|
|
1362
1821
|
declare function readLocaleData(config: I18nConfig, layer: string, locale: LocaleDefinition): Promise<Record<string, unknown>>;
|
|
@@ -1400,7 +1859,7 @@ declare class TranslateProviderError extends Error {
|
|
|
1400
1859
|
constructor(message: string, kind: TranslateProviderErrorKind, status?: number);
|
|
1401
1860
|
}
|
|
1402
1861
|
/**
|
|
1403
|
-
* Classify
|
|
1862
|
+
* Classify a provider error into a TranslateProviderError:
|
|
1404
1863
|
* 401/403 → auth, 429 → rate-limit, anything else → provider.
|
|
1405
1864
|
* Already-classified errors pass through unchanged.
|
|
1406
1865
|
*/
|
|
@@ -1432,8 +1891,9 @@ declare function resolveProviderBaseUrl(sources: {
|
|
|
1432
1891
|
config?: string;
|
|
1433
1892
|
}): string | undefined;
|
|
1434
1893
|
/**
|
|
1435
|
-
* Create a TranslateFn from an LLM provider config.
|
|
1436
|
-
*
|
|
1894
|
+
* Create a TranslateFn from an LLM provider config. Every provider is called
|
|
1895
|
+
* over plain HTTP, so nothing beyond the CLI has to be installed.
|
|
1896
|
+
* Throws if the API key is missing.
|
|
1437
1897
|
*/
|
|
1438
1898
|
declare function createTranslateFn(config: LlmProviderConfig): Promise<TranslateFn>;
|
|
1439
1899
|
//# sourceMappingURL=providers.d.ts.map
|
|
@@ -1455,5 +1915,5 @@ declare function loadProjectConfig(projectDir: string): Promise<ProjectConfig |
|
|
|
1455
1915
|
//# sourceMappingURL=project-config.d.ts.map
|
|
1456
1916
|
|
|
1457
1917
|
//#endregion
|
|
1458
|
-
export {
|
|
1459
|
-
//# sourceMappingURL=index-
|
|
1918
|
+
export { type AnyOperationDescriptor, type AnyReportSpec, BASE_URL_ENV, type CheckUndefinedKeysResult, type CheckUndefinedKeysSummary, CodeUsageRef, CodeUsageResult, DeclaredNamespaceRef, DescribeProjectResult, type DuplicateKeyCollision, DynamicKeyRef, EmptyTranslationsResult, type FindDuplicateKeysResult, type FindDuplicateKeysSummary, FindOrphanKeysResult, GeneratedProjectConfig, type I18nConfig, type I18nKitConfig, InitProjectConfigResult, type KeyUsageLocation, LARAVEL_PATTERNS, type LanguageFrontend, type LayerGraph, LayerStatus, type LlmProvider, type LlmProviderConfig, type LocaleDefinition, type LocaleDir, LocaleDirInfo, type LocaleRefAmbiguity, LocaleRefInfo, LocaleStatus, MisplacedUsageRef, MissingTranslationsResult, MoveTranslationKeyOutcome, MoveTranslationKeyPlanEntry, MoveTranslationKeyResult, MutationPreview, MutationResult, type OperationContext, type OperationDescriptor, type ParamSpec, type ParamType, type Params, PlaceholderValidationIssue, PlaceholderValidationResult, ProgressFn, type ProjectConfig, RemoveOrphanKeysResult, RemoveTranslationsPreview, RemoveTranslationsResult, RenameTranslationKeyPreview, RenameTranslationKeyResult, type ReportContext, type ReportSpec, ScaffoldLocaleFileInfo, ScaffoldLocaleResult, ScanCodeUsageResult, type ScanResult, SearchKeyMatch, SearchMatch, SearchMatchMode, SearchTranslationsResult, type SerializedLayerGraph, type Surface, ToolError, TranslateAllLayersResult, TranslateAllLayersSummary, TranslateFailReason, TranslateFn, TranslateKeyLocaleIssue, TranslateKeyResult, TranslateKeySkip, TranslateLayerTotals, TranslateMissingCompactEntry, TranslateMissingLocaleResult, TranslateMissingOptions, TranslateMissingOutcome, TranslateMissingResult, TranslateMode, TranslateProviderError, type TranslateProviderErrorKind, TranslateRequest, TranslateResponse, TranslateSkipReason, TranslationStatusResult, TranslationStatusSummary, type TranslationsRecord, type UncertainKeyFinding, type UndefinedKeyFinding, UnresolvedKeyWarningRef, UnresolvedLocaleRef, WriteTranslationsResult, buildLayerGraph, checkUndefinedKeys, classifyProviderError, clearConfigCache, createPatternsFrontend, createPhpFrontend, createTranslateFn, defineI18nKitConfig, describeProject, descriptors, descriptorsFor, detectConfig, detectI18nConfig, divertToReport, findDuplicateKeys, findEmptyTranslations, findLocaleImpl, findOrphanKeys, getCachedConfig, getMissingTranslations, getTranslationStatus, getTranslations, listLocaleDirs, listNamespaces, loadProjectConfig, moveTranslationKey, readLocaleData, removeOrphanKeys, removeTranslations, renameTranslationKey, resolveProtectedLocales, resolveProviderBaseUrl, scaffoldLocaleFiles, scanCodeUsage, scanSourceFiles, searchTranslations, serializeLayerGraph, toErrorMessage, translateKey, translateMissing, visibleParams, writeTranslations };
|
|
1919
|
+
//# sourceMappingURL=index-CWFWYHf5.d.ts.map
|