gt 2.14.33 → 2.14.34
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/CHANGELOG.md +12 -0
- package/dist/cli/inline.js +1 -1
- package/dist/formats/files/collectFiles.js +1 -1
- package/dist/formats/json/extractJson.js +4 -2
- package/dist/formats/json/flattenJson.d.ts +3 -2
- package/dist/formats/json/flattenJson.js +3 -15
- package/dist/formats/json/jsonPath.d.ts +8 -0
- package/dist/formats/json/jsonPath.js +19 -0
- package/dist/formats/json/jsonPointer.d.ts +4 -0
- package/dist/formats/json/jsonPointer.js +20 -0
- package/dist/formats/json/mergeJson.d.ts +2 -1
- package/dist/formats/json/mergeJson.js +23 -32
- package/dist/formats/json/parseJson.js +5 -13
- package/dist/formats/json/transformJson.d.ts +3 -2
- package/dist/formats/json/transformJson.js +7 -31
- package/dist/formats/json/utils.d.ts +14 -10
- package/dist/formats/json/utils.js +13 -13
- package/dist/fs/copyFile.d.ts +4 -2
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/translation/parse.js +27 -8
- package/dist/types/data/json.d.ts +1 -2
- package/dist/types/index.d.ts +4 -0
- package/dist/utils/addExplicitAnchorIds.d.ts +6 -1
- package/dist/utils/localizeRelativeAssets.d.ts +3 -2
- package/dist/utils/localizeRelativeAssets.js +16 -15
- package/dist/utils/localizeStaticImports.d.ts +3 -2
- package/dist/utils/localizeStaticImports.js +1 -1
- package/dist/utils/localizeStaticUrls.d.ts +3 -2
- package/dist/utils/localizeStaticUrls.js +1 -1
- package/dist/utils/sharedStaticAssets.js +20 -21
- package/dist/workflows/steps/BranchStep.d.ts +6 -3
- package/dist/workflows/steps/UploadSourcesStep.d.ts +6 -3
- package/package.json +12 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# gtx-cli
|
|
2
2
|
|
|
3
|
+
## 2.14.34
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1385](https://github.com/generaltranslation/gt/pull/1385) [`bcb2b91`](https://github.com/generaltranslation/gt/commit/bcb2b91581d1edb134a451f9713c3a899e32282a) Thanks [@bgub](https://github.com/bgub)! - Warn when duplicate source update IDs include hashless entries.
|
|
8
|
+
|
|
9
|
+
- [#1379](https://github.com/generaltranslation/gt/pull/1379) [`e88fd39`](https://github.com/generaltranslation/gt/commit/e88fd399683868d5af1fe2b0ba2974fe5b17d7a7) Thanks [@bgub](https://github.com/bgub)! - Tighten public and API metadata types, and handle metadata entries without hashes in the CLI.
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [[`e88fd39`](https://github.com/generaltranslation/gt/commit/e88fd399683868d5af1fe2b0ba2974fe5b17d7a7), [`95f852a`](https://github.com/generaltranslation/gt/commit/95f852ae086ac79d2c446f4d3072d8fd18688796)]:
|
|
12
|
+
- generaltranslation@8.2.13
|
|
13
|
+
- @generaltranslation/python-extractor@0.2.19
|
|
14
|
+
|
|
3
15
|
## 2.14.33
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/cli/inline.js
CHANGED
|
@@ -80,7 +80,8 @@ export function extractJson(localContent, inputPath, options, targetLocale, defa
|
|
|
80
80
|
const extractedValues = flattenJsonWithStringFilter(sourceItem, sourceObjectOptions.include);
|
|
81
81
|
// Use default locale key
|
|
82
82
|
const outputKey = i < defaultKeys.length ? defaultKeys[i] : targetEntries[i][0];
|
|
83
|
-
compositeResult[sourceObjectPointer][outputKey] =
|
|
83
|
+
compositeResult[sourceObjectPointer][outputKey] =
|
|
84
|
+
extractedValues;
|
|
84
85
|
}
|
|
85
86
|
}
|
|
86
87
|
else {
|
|
@@ -89,8 +90,9 @@ export function extractJson(localContent, inputPath, options, targetLocale, defa
|
|
|
89
90
|
logger.warn(`Source object value is not an object at path: ${sourceObjectPointer}`);
|
|
90
91
|
continue;
|
|
91
92
|
}
|
|
93
|
+
const sourceObjectRecord = sourceObjectValue;
|
|
92
94
|
// Find the matching item for the target locale
|
|
93
|
-
const matchingTargetItem = findMatchingItemObject(canonicalTargetLocale, sourceObjectPointer, sourceObjectOptions,
|
|
95
|
+
const matchingTargetItem = findMatchingItemObject(canonicalTargetLocale, sourceObjectPointer, sourceObjectOptions, sourceObjectRecord);
|
|
94
96
|
if (!matchingTargetItem.sourceItem) {
|
|
95
97
|
logger.warn(`No matching item found for locale ${targetLocale} at path: ${sourceObjectPointer}`);
|
|
96
98
|
continue;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
import type { JSONValue } from '../../types/data/json.js';
|
|
1
2
|
/**
|
|
2
3
|
* Flattens a JSON object according to a list of JSON paths.
|
|
3
4
|
* @param json - The JSON object to flatten
|
|
4
5
|
* @param jsonPaths - The list of JSON paths to flatten
|
|
5
6
|
* @returns A mapping of json pointers to their values
|
|
6
7
|
*/
|
|
7
|
-
export declare function flattenJson(json:
|
|
8
|
+
export declare function flattenJson(json: unknown, jsonPaths: string[]): Record<string, JSONValue>;
|
|
8
9
|
/**
|
|
9
10
|
* Flattens a JSON object according to a list of JSON paths, only including strings
|
|
10
11
|
* @param json - The JSON object to flatten
|
|
11
12
|
* @param jsonPaths - The list of JSON paths to flatten
|
|
12
13
|
* @returns A mapping of json pointers to their values
|
|
13
14
|
*/
|
|
14
|
-
export declare function flattenJsonWithStringFilter(json:
|
|
15
|
+
export declare function flattenJsonWithStringFilter(json: unknown, jsonPaths: string[]): Record<string, string>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { JSONPath } from 'jsonpath-plus';
|
|
2
1
|
import { logger } from '../../console/logger.js';
|
|
2
|
+
import { getJSONPathMatches } from './jsonPath.js';
|
|
3
3
|
/**
|
|
4
4
|
* Flattens a JSON object according to a list of JSON paths.
|
|
5
5
|
* @param json - The JSON object to flatten
|
|
@@ -10,13 +10,7 @@ export function flattenJson(json, jsonPaths) {
|
|
|
10
10
|
const extractedJson = {};
|
|
11
11
|
for (const jsonPath of jsonPaths) {
|
|
12
12
|
try {
|
|
13
|
-
const results =
|
|
14
|
-
json,
|
|
15
|
-
path: jsonPath,
|
|
16
|
-
resultType: 'all',
|
|
17
|
-
flatten: true,
|
|
18
|
-
wrap: true,
|
|
19
|
-
});
|
|
13
|
+
const results = getJSONPathMatches(json, jsonPath);
|
|
20
14
|
if (!results || results.length === 0) {
|
|
21
15
|
continue;
|
|
22
16
|
}
|
|
@@ -40,13 +34,7 @@ export function flattenJsonWithStringFilter(json, jsonPaths) {
|
|
|
40
34
|
const extractedJson = {};
|
|
41
35
|
for (const jsonPath of jsonPaths) {
|
|
42
36
|
try {
|
|
43
|
-
const results =
|
|
44
|
-
json,
|
|
45
|
-
path: jsonPath,
|
|
46
|
-
resultType: 'all',
|
|
47
|
-
flatten: true,
|
|
48
|
-
wrap: true,
|
|
49
|
-
});
|
|
37
|
+
const results = getJSONPathMatches(json, jsonPath);
|
|
50
38
|
if (!results || results.length === 0) {
|
|
51
39
|
continue;
|
|
52
40
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { JSONValue } from '../../types/data/json.js';
|
|
2
|
+
export type JSONPathMatch = {
|
|
3
|
+
pointer: string;
|
|
4
|
+
value: JSONValue;
|
|
5
|
+
parentProperty: string | number | null;
|
|
6
|
+
};
|
|
7
|
+
export declare function getJSONPathMatches(json: JSONValue, path: string): JSONPathMatch[] | undefined;
|
|
8
|
+
export declare function getJSONPathValues(json: JSONValue, path: string): JSONValue[] | undefined;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { JSONPath } from 'jsonpath-plus';
|
|
2
|
+
const jsonPathOptions = (json, path) => ({
|
|
3
|
+
json,
|
|
4
|
+
path,
|
|
5
|
+
flatten: true,
|
|
6
|
+
wrap: true,
|
|
7
|
+
});
|
|
8
|
+
export function getJSONPathMatches(json, path) {
|
|
9
|
+
return JSONPath({
|
|
10
|
+
...jsonPathOptions(json, path),
|
|
11
|
+
resultType: 'all',
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export function getJSONPathValues(json, path) {
|
|
15
|
+
return JSONPath({
|
|
16
|
+
...jsonPathOptions(json, path),
|
|
17
|
+
resultType: 'value',
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { JSONValue } from '../../types/data/json.js';
|
|
2
|
+
export declare function getJSONPointerValue(json: JSONValue, pointer: string): JSONValue;
|
|
3
|
+
export declare function setJSONPointerValue(json: JSONValue, pointer: string, value: JSONValue): void;
|
|
4
|
+
export declare function deleteJSONPointerValue(json: JSONValue, pointer: string): void;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import JSONPointer from 'jsonpointer';
|
|
2
|
+
export function getJSONPointerValue(json, pointer) {
|
|
3
|
+
return JSONPointer.get(json, pointer);
|
|
4
|
+
}
|
|
5
|
+
export function setJSONPointerValue(json, pointer, value) {
|
|
6
|
+
JSONPointer.set(json, pointer, value);
|
|
7
|
+
}
|
|
8
|
+
export function deleteJSONPointerValue(json, pointer) {
|
|
9
|
+
const lastSlash = pointer.lastIndexOf('/');
|
|
10
|
+
if (lastSlash < 0)
|
|
11
|
+
return;
|
|
12
|
+
const parentPointer = pointer.substring(0, lastSlash) || '';
|
|
13
|
+
const leafKey = pointer.substring(lastSlash + 1);
|
|
14
|
+
const parent = parentPointer
|
|
15
|
+
? getJSONPointerValue(json, parentPointer)
|
|
16
|
+
: json;
|
|
17
|
+
if (parent && typeof parent === 'object' && leafKey in parent) {
|
|
18
|
+
delete parent[leafKey];
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AdditionalOptions, SourceObjectOptions } from '../../types/index.js';
|
|
2
|
+
import type { JSONValue } from '../../types/data/json.js';
|
|
2
3
|
export declare function mergeJson(originalContent: string, inputPath: string, options: AdditionalOptions, targets: {
|
|
3
4
|
translatedContent: string;
|
|
4
5
|
targetLocale: string;
|
|
@@ -10,4 +11,4 @@ export declare function mergeJson(originalContent: string, inputPath: string, op
|
|
|
10
11
|
* @param targetLocale - The target locale
|
|
11
12
|
* @param defaultLocale - The default locale
|
|
12
13
|
*/
|
|
13
|
-
export declare function applyTransformations(sourceItem:
|
|
14
|
+
export declare function applyTransformations(sourceItem: JSONValue, transform: SourceObjectOptions['transform'], targetLocale: string, defaultLocale: string): void;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import JSONPointer from 'jsonpointer';
|
|
2
1
|
import { exitSync } from '../../console/logging.js';
|
|
3
2
|
import { logger } from '../../console/logger.js';
|
|
4
3
|
import { findMatchingItemArray, findMatchingItemObject, generateSourceObjectPointers, getIdentifyingLocaleProperty, getSourceObjectOptionsArray, validateJsonSchema, } from './utils.js';
|
|
5
|
-
import { JSONPath } from 'jsonpath-plus';
|
|
6
4
|
import { getLocaleProperties } from 'generaltranslation';
|
|
7
5
|
import { replaceLocalePlaceholders } from '../utils.js';
|
|
8
6
|
import { gt } from '../../utils/gt.js';
|
|
9
7
|
import { applyStructuralTransforms, unapplyStructuralTransforms, } from './transformJson.js';
|
|
8
|
+
import { getJSONPathMatches, getJSONPathValues } from './jsonPath.js';
|
|
9
|
+
import { getJSONPointerValue, setJSONPointerValue } from './jsonPointer.js';
|
|
10
10
|
export function mergeJson(originalContent, inputPath, options, targets, defaultLocale, localeOrder = []) {
|
|
11
11
|
const jsonSchema = validateJsonSchema(options, inputPath);
|
|
12
12
|
if (!jsonSchema) {
|
|
@@ -39,10 +39,10 @@ export function mergeJson(originalContent, inputPath, options, targets, defaultL
|
|
|
39
39
|
const translatedJson = JSON.parse(target.translatedContent);
|
|
40
40
|
for (const [jsonPointer, translatedValue] of Object.entries(translatedJson)) {
|
|
41
41
|
try {
|
|
42
|
-
const value =
|
|
42
|
+
const value = getJSONPointerValue(mergedJson, jsonPointer);
|
|
43
43
|
if (!value)
|
|
44
44
|
continue;
|
|
45
|
-
|
|
45
|
+
setJSONPointerValue(mergedJson, jsonPointer, translatedValue);
|
|
46
46
|
}
|
|
47
47
|
catch {
|
|
48
48
|
/* empty */
|
|
@@ -146,18 +146,18 @@ export function mergeJson(originalContent, inputPath, options, targets, defaultL
|
|
|
146
146
|
const { identifyingLocaleProperty: targetLocaleKeyProperty } = getSourceObjectOptionsArray(useCanonicalLocaleKeys
|
|
147
147
|
? gt.resolveCanonicalLocale(target.targetLocale)
|
|
148
148
|
: target.targetLocale, sourceObjectPointer, sourceObjectOptions);
|
|
149
|
-
|
|
150
|
-
for (const [translatedKeyJsonPointer, translatedValue,] of Object.entries(targetItem || {})) {
|
|
149
|
+
setJSONPointerValue(mutatedSourceItem, defaultLocaleKeyPointer, targetLocaleKeyProperty);
|
|
150
|
+
for (const [translatedKeyJsonPointer, translatedValue,] of Object.entries((targetItem || {}))) {
|
|
151
151
|
const valueToSet = useCanonicalLocaleKeys &&
|
|
152
152
|
defaultLocaleKeyPointer &&
|
|
153
153
|
translatedKeyJsonPointer === defaultLocaleKeyPointer
|
|
154
154
|
? targetLocaleKeyProperty
|
|
155
155
|
: translatedValue;
|
|
156
156
|
try {
|
|
157
|
-
const value =
|
|
157
|
+
const value = getJSONPointerValue(mutatedSourceItem, translatedKeyJsonPointer);
|
|
158
158
|
if (!value)
|
|
159
159
|
continue;
|
|
160
|
-
|
|
160
|
+
setJSONPointerValue(mutatedSourceItem, translatedKeyJsonPointer, valueToSet);
|
|
161
161
|
}
|
|
162
162
|
catch {
|
|
163
163
|
/* empty */
|
|
@@ -176,7 +176,7 @@ export function mergeJson(originalContent, inputPath, options, targets, defaultL
|
|
|
176
176
|
const filteredSourceObjectValue = sourceObjectValue.filter((_, index) => !indiciesToRemove.has(index));
|
|
177
177
|
// 10. Add all items to the original JSON
|
|
178
178
|
filteredSourceObjectValue.push(...itemsToAdd);
|
|
179
|
-
|
|
179
|
+
setJSONPointerValue(mergedJson, sourceObjectPointer, sortByLocaleOrder(filteredSourceObjectValue, sourceObjectOptions, canonicalLocaleOrder, sourceObjectPointer, canonicalDefaultLocale));
|
|
180
180
|
}
|
|
181
181
|
else {
|
|
182
182
|
// Validate type
|
|
@@ -184,8 +184,9 @@ export function mergeJson(originalContent, inputPath, options, targets, defaultL
|
|
|
184
184
|
logger.error(`Source object value is not an object at path: ${sourceObjectPointer}`);
|
|
185
185
|
return exitSync(1);
|
|
186
186
|
}
|
|
187
|
+
const sourceObjectRecord = sourceObjectValue;
|
|
187
188
|
// Validate localeProperty
|
|
188
|
-
const matchingDefaultLocaleItem = findMatchingItemObject(canonicalDefaultLocale, sourceObjectPointer, sourceObjectOptions,
|
|
189
|
+
const matchingDefaultLocaleItem = findMatchingItemObject(canonicalDefaultLocale, sourceObjectPointer, sourceObjectOptions, sourceObjectRecord);
|
|
189
190
|
// Validate source item exists
|
|
190
191
|
if (!matchingDefaultLocaleItem.sourceItem) {
|
|
191
192
|
logger.error(`Source item not found at path: ${sourceObjectPointer}. You must specify a source item where its key matches the default locale`);
|
|
@@ -209,12 +210,12 @@ export function mergeJson(originalContent, inputPath, options, targets, defaultL
|
|
|
209
210
|
// 2. Find the source item for the target locale
|
|
210
211
|
const matchingTargetItem = findMatchingItemObject(useCanonicalLocaleKeys
|
|
211
212
|
? gt.resolveCanonicalLocale(target.targetLocale)
|
|
212
|
-
: target.targetLocale, sourceObjectPointer, sourceObjectOptions,
|
|
213
|
+
: target.targetLocale, sourceObjectPointer, sourceObjectOptions, sourceObjectRecord);
|
|
213
214
|
const mutateSourceItemKey = matchingTargetItem.keyParentProperty;
|
|
214
215
|
// If the source item is a string, use the translated string directly
|
|
215
216
|
if (typeof defaultLocaleSourceItem === 'string') {
|
|
216
217
|
if (typeof targetItems === 'string') {
|
|
217
|
-
|
|
218
|
+
sourceObjectRecord[mutateSourceItemKey] = targetItems;
|
|
218
219
|
}
|
|
219
220
|
// If no translation found, leave the locale slot unchanged
|
|
220
221
|
continue;
|
|
@@ -224,7 +225,9 @@ export function mergeJson(originalContent, inputPath, options, targets, defaultL
|
|
|
224
225
|
const mutateSourceItem = structuredClone(defaultLocaleSourceItem);
|
|
225
226
|
// 3. Merge the target items with the source item (if there are transformations to perform)
|
|
226
227
|
const mergedItems = {
|
|
227
|
-
...(sourceObjectOptions.transform
|
|
228
|
+
...(sourceObjectOptions.transform
|
|
229
|
+
? defaultLocaleSourceItem
|
|
230
|
+
: {}),
|
|
228
231
|
...targetItems,
|
|
229
232
|
};
|
|
230
233
|
// 4. Validate that the mergedItems is not empty
|
|
@@ -235,10 +238,10 @@ export function mergeJson(originalContent, inputPath, options, targets, defaultL
|
|
|
235
238
|
// 5. Override the source item with the translated values
|
|
236
239
|
for (const [translatedKeyJsonPointer, translatedValue,] of Object.entries(mergedItems || {})) {
|
|
237
240
|
try {
|
|
238
|
-
const value =
|
|
241
|
+
const value = getJSONPointerValue(mutateSourceItem, translatedKeyJsonPointer);
|
|
239
242
|
if (!value)
|
|
240
243
|
continue;
|
|
241
|
-
|
|
244
|
+
setJSONPointerValue(mutateSourceItem, translatedKeyJsonPointer, translatedValue);
|
|
242
245
|
}
|
|
243
246
|
catch {
|
|
244
247
|
/* empty */
|
|
@@ -247,9 +250,9 @@ export function mergeJson(originalContent, inputPath, options, targets, defaultL
|
|
|
247
250
|
// 6. Apply additional mutations to the sourceItem
|
|
248
251
|
applyTransformations(mutateSourceItem, sourceObjectOptions.transform, target.targetLocale, defaultLocale);
|
|
249
252
|
// 7. Merge the source item with the original JSON
|
|
250
|
-
|
|
253
|
+
sourceObjectRecord[mutateSourceItemKey] = mutateSourceItem;
|
|
251
254
|
}
|
|
252
|
-
|
|
255
|
+
setJSONPointerValue(mergedJson, sourceObjectPointer, sourceObjectValue);
|
|
253
256
|
}
|
|
254
257
|
}
|
|
255
258
|
if (jsonSchema.structuralTransform && jsonSchema.composite) {
|
|
@@ -265,13 +268,7 @@ function sortByLocaleOrder(items, sourceObjectOptions, localeOrder, sourceObject
|
|
|
265
268
|
const itemsWithLocale = items.map((item) => {
|
|
266
269
|
let localeValue;
|
|
267
270
|
try {
|
|
268
|
-
const values =
|
|
269
|
-
json: item,
|
|
270
|
-
path: sourceObjectOptions.key,
|
|
271
|
-
resultType: 'value',
|
|
272
|
-
flatten: true,
|
|
273
|
-
wrap: true,
|
|
274
|
-
});
|
|
271
|
+
const values = getJSONPathValues(item, sourceObjectOptions.key);
|
|
275
272
|
const value = values?.[0];
|
|
276
273
|
if (typeof value === 'string') {
|
|
277
274
|
localeValue = value;
|
|
@@ -350,13 +347,7 @@ export function applyTransformations(sourceItem, transform, targetLocale, defaul
|
|
|
350
347
|
typeof transformOptions.replace !== 'string') {
|
|
351
348
|
continue;
|
|
352
349
|
}
|
|
353
|
-
const results =
|
|
354
|
-
json: sourceItem,
|
|
355
|
-
path: transformPath,
|
|
356
|
-
resultType: 'all',
|
|
357
|
-
flatten: true,
|
|
358
|
-
wrap: true,
|
|
359
|
-
});
|
|
350
|
+
const results = getJSONPathMatches(sourceItem, transformPath);
|
|
360
351
|
if (!results || results.length === 0) {
|
|
361
352
|
continue;
|
|
362
353
|
}
|
|
@@ -379,7 +370,7 @@ export function applyTransformations(sourceItem, transform, targetLocale, defaul
|
|
|
379
370
|
result.value = replaceString;
|
|
380
371
|
}
|
|
381
372
|
// Update the actual sourceItem using JSONPointer
|
|
382
|
-
|
|
373
|
+
setJSONPointerValue(sourceItem, result.pointer, result.value);
|
|
383
374
|
});
|
|
384
375
|
}
|
|
385
376
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { flattenJson, flattenJsonWithStringFilter } from './flattenJson.js';
|
|
2
|
-
import { JSONPath } from 'jsonpath-plus';
|
|
3
2
|
import { exitSync } from '../../console/logging.js';
|
|
4
3
|
import { logger } from '../../console/logger.js';
|
|
5
4
|
import { findMatchingItemArray, findMatchingItemObject, generateSourceObjectPointers, validateJsonSchema, } from './utils.js';
|
|
6
5
|
import { applyStructuralTransforms } from './transformJson.js';
|
|
6
|
+
import { getJSONPathMatches } from './jsonPath.js';
|
|
7
7
|
// Parse a JSON file according to a JSON schema
|
|
8
8
|
export function parseJson(content, filePath, options, defaultLocale, filterStrings = true) {
|
|
9
9
|
const jsonSchema = validateJsonSchema(options, filePath);
|
|
@@ -63,13 +63,7 @@ export function parseJson(content, filePath, options, defaultLocale, filterStrin
|
|
|
63
63
|
const matchingItemsToTranslate = [];
|
|
64
64
|
for (const include of sourceObjectOptions.include) {
|
|
65
65
|
try {
|
|
66
|
-
const matchingItems =
|
|
67
|
-
json: sourceItem,
|
|
68
|
-
path: include,
|
|
69
|
-
resultType: 'all',
|
|
70
|
-
flatten: true,
|
|
71
|
-
wrap: true,
|
|
72
|
-
});
|
|
66
|
+
const matchingItems = getJSONPathMatches(sourceItem, include);
|
|
73
67
|
if (matchingItems) {
|
|
74
68
|
matchingItemsToTranslate.push(...matchingItems);
|
|
75
69
|
}
|
|
@@ -81,10 +75,7 @@ export function parseJson(content, filePath, options, defaultLocale, filterStrin
|
|
|
81
75
|
// Filter out the key pointer
|
|
82
76
|
sourceItemsToTranslate[arrayPointer] = Object.fromEntries(matchingItemsToTranslate
|
|
83
77
|
.filter((item) => item.pointer !== keyPointer)
|
|
84
|
-
.map((item) => [
|
|
85
|
-
item.pointer,
|
|
86
|
-
item.value,
|
|
87
|
-
]));
|
|
78
|
+
.map((item) => [item.pointer, item.value]));
|
|
88
79
|
}
|
|
89
80
|
// Add the items to translate to the result
|
|
90
81
|
sourceObjectsToTranslate[sourceObjectPointer] = sourceItemsToTranslate;
|
|
@@ -96,8 +87,9 @@ export function parseJson(content, filePath, options, defaultLocale, filterStrin
|
|
|
96
87
|
logger.error(`Source object value is not an object at path: ${sourceObjectPointer}`);
|
|
97
88
|
return exitSync(1);
|
|
98
89
|
}
|
|
90
|
+
const sourceObjectRecord = sourceObjectValue;
|
|
99
91
|
// Validate localeProperty
|
|
100
|
-
const matchingItem = findMatchingItemObject(defaultLocale, sourceObjectPointer, sourceObjectOptions,
|
|
92
|
+
const matchingItem = findMatchingItemObject(defaultLocale, sourceObjectPointer, sourceObjectOptions, sourceObjectRecord);
|
|
101
93
|
// Validate source item exists
|
|
102
94
|
if (!matchingItem.sourceItem) {
|
|
103
95
|
logger.error(`Source item not found at path: ${sourceObjectPointer}. You must specify a source item where its key matches the default locale`);
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { StructuralTransform, SourceObjectOptions } from '../../types/index.js';
|
|
2
|
+
import type { JSONValue } from '../../types/data/json.js';
|
|
2
3
|
/**
|
|
3
4
|
* Apply structural transforms: copy values from sourcePointer to destinationPointer
|
|
4
5
|
* for each entry resolved by the composite config's parent paths.
|
|
5
6
|
* Mutates json in-place.
|
|
6
7
|
*/
|
|
7
|
-
export declare function applyStructuralTransforms(json:
|
|
8
|
+
export declare function applyStructuralTransforms(json: JSONValue, transforms: StructuralTransform[], compositeConfig: Record<string, SourceObjectOptions>): JSONValue;
|
|
8
9
|
/**
|
|
9
10
|
* Unapply structural transforms: delete the value at destinationPointer
|
|
10
11
|
* for each entry resolved by the composite config's parent paths.
|
|
11
12
|
* Leaves sourcePointer untouched. Mutates json in-place.
|
|
12
13
|
*/
|
|
13
|
-
export declare function unapplyStructuralTransforms(json:
|
|
14
|
+
export declare function unapplyStructuralTransforms(json: JSONValue, transforms: StructuralTransform[], compositeConfig: Record<string, SourceObjectOptions>): JSONValue;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import { getJSONPathMatches } from './jsonPath.js';
|
|
2
|
+
import { deleteJSONPointerValue, getJSONPointerValue, setJSONPointerValue, } from './jsonPointer.js';
|
|
3
3
|
/**
|
|
4
4
|
* Derive entry parent paths from composite sourceObjectPaths by trimming the last segment.
|
|
5
5
|
* e.g., "$.*.translations" → "$.*"
|
|
@@ -22,13 +22,7 @@ function deriveEntryPaths(compositeConfig) {
|
|
|
22
22
|
export function applyStructuralTransforms(json, transforms, compositeConfig) {
|
|
23
23
|
const entryPaths = deriveEntryPaths(compositeConfig);
|
|
24
24
|
for (const entryPath of entryPaths) {
|
|
25
|
-
const entries =
|
|
26
|
-
json,
|
|
27
|
-
path: entryPath,
|
|
28
|
-
resultType: 'all',
|
|
29
|
-
flatten: true,
|
|
30
|
-
wrap: true,
|
|
31
|
-
});
|
|
25
|
+
const entries = getJSONPathMatches(json, entryPath);
|
|
32
26
|
if (!entries)
|
|
33
27
|
continue;
|
|
34
28
|
for (const entry of entries) {
|
|
@@ -36,9 +30,9 @@ export function applyStructuralTransforms(json, transforms, compositeConfig) {
|
|
|
36
30
|
if (typeof entryObj !== 'object' || entryObj === null)
|
|
37
31
|
continue;
|
|
38
32
|
for (const transform of transforms) {
|
|
39
|
-
const sourceValue =
|
|
33
|
+
const sourceValue = getJSONPointerValue(entryObj, transform.sourcePointer);
|
|
40
34
|
if (sourceValue !== undefined) {
|
|
41
|
-
|
|
35
|
+
setJSONPointerValue(entryObj, transform.destinationPointer, sourceValue);
|
|
42
36
|
}
|
|
43
37
|
}
|
|
44
38
|
}
|
|
@@ -53,13 +47,7 @@ export function applyStructuralTransforms(json, transforms, compositeConfig) {
|
|
|
53
47
|
export function unapplyStructuralTransforms(json, transforms, compositeConfig) {
|
|
54
48
|
const entryPaths = deriveEntryPaths(compositeConfig);
|
|
55
49
|
for (const entryPath of entryPaths) {
|
|
56
|
-
const entries =
|
|
57
|
-
json,
|
|
58
|
-
path: entryPath,
|
|
59
|
-
resultType: 'all',
|
|
60
|
-
flatten: true,
|
|
61
|
-
wrap: true,
|
|
62
|
-
});
|
|
50
|
+
const entries = getJSONPathMatches(json, entryPath);
|
|
63
51
|
if (!entries)
|
|
64
52
|
continue;
|
|
65
53
|
for (const entry of entries) {
|
|
@@ -67,20 +55,8 @@ export function unapplyStructuralTransforms(json, transforms, compositeConfig) {
|
|
|
67
55
|
if (typeof entryObj !== 'object' || entryObj === null)
|
|
68
56
|
continue;
|
|
69
57
|
for (const transform of transforms) {
|
|
70
|
-
// Navigate to parent of destinationPointer and delete the leaf key
|
|
71
|
-
const pointer = transform.destinationPointer;
|
|
72
|
-
const lastSlash = pointer.lastIndexOf('/');
|
|
73
|
-
if (lastSlash < 0)
|
|
74
|
-
continue;
|
|
75
|
-
const parentPointer = pointer.substring(0, lastSlash) || '';
|
|
76
|
-
const leafKey = pointer.substring(lastSlash + 1);
|
|
77
58
|
try {
|
|
78
|
-
|
|
79
|
-
? JSONPointer.get(entryObj, parentPointer)
|
|
80
|
-
: entryObj;
|
|
81
|
-
if (parent && typeof parent === 'object' && leafKey in parent) {
|
|
82
|
-
delete parent[leafKey];
|
|
83
|
-
}
|
|
59
|
+
deleteJSONPointerValue(entryObj, transform.destinationPointer);
|
|
84
60
|
}
|
|
85
61
|
catch {
|
|
86
62
|
/* entry may not have the destination path */
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { AdditionalOptions, JsonSchema, SourceObjectOptions } from '../../types/index.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import type { JSONObject, JSONValue } from '../../types/data/json.js';
|
|
3
|
+
type MatchingArrayItem = {
|
|
4
|
+
sourceItem: JSONValue;
|
|
5
|
+
keyParentProperty: string | number;
|
|
5
6
|
keyPointer: string;
|
|
6
7
|
index: number;
|
|
8
|
+
};
|
|
9
|
+
type SourceObjectPointerMap = Record<string, {
|
|
10
|
+
sourceObjectValue: JSONValue;
|
|
11
|
+
sourceObjectOptions: SourceObjectOptions;
|
|
7
12
|
}>;
|
|
8
|
-
export declare function
|
|
9
|
-
|
|
13
|
+
export declare function findMatchingItemArray(locale: string, sourceObjectOptions: SourceObjectOptions, sourceObjectPointer: string, sourceObjectValue: JSONValue[]): Record<string, MatchingArrayItem>;
|
|
14
|
+
export declare function findMatchingItemObject(locale: string, sourceObjectPointer: string, sourceObjectOptions: SourceObjectOptions, sourceObjectValue: JSONObject): {
|
|
15
|
+
sourceItem: JSONValue | undefined;
|
|
10
16
|
keyParentProperty: string;
|
|
11
17
|
};
|
|
12
18
|
/**
|
|
@@ -40,10 +46,7 @@ export declare function getSourceObjectOptionsObject(defaultLocale: string, sour
|
|
|
40
46
|
*/
|
|
41
47
|
export declare function generateSourceObjectPointers(jsonSchema: {
|
|
42
48
|
[sourceObjectPath: string]: SourceObjectOptions;
|
|
43
|
-
}, originalJson:
|
|
44
|
-
sourceObjectValue: any;
|
|
45
|
-
sourceObjectOptions: SourceObjectOptions;
|
|
46
|
-
}>;
|
|
49
|
+
}, originalJson: JSONValue): SourceObjectPointerMap;
|
|
47
50
|
/**
|
|
48
51
|
* Validate the json schema for composite or include schemas
|
|
49
52
|
* @param options - Additional options containing jsonSchema config
|
|
@@ -56,4 +59,5 @@ export declare function validateJsonSchema(options: AdditionalOptions, filePath:
|
|
|
56
59
|
* Detect unsupported fields (e.g. $ref) in Mintlify docs.json files.
|
|
57
60
|
* Logs a warning listing the fields found.
|
|
58
61
|
*/
|
|
59
|
-
export declare function detectMintlifyUnsupportedFields(json:
|
|
62
|
+
export declare function detectMintlifyUnsupportedFields(json: JSONValue, filePath: string): void;
|
|
63
|
+
export {};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { getLocaleProperties } from 'generaltranslation';
|
|
2
2
|
import { exitSync } from '../../console/logging.js';
|
|
3
3
|
import { logger } from '../../console/logger.js';
|
|
4
|
-
import { JSONPath } from 'jsonpath-plus';
|
|
5
4
|
import { flattenJson } from './flattenJson.js';
|
|
6
5
|
import chalk from 'chalk';
|
|
7
6
|
import path from 'node:path';
|
|
8
7
|
import micromatch from 'micromatch';
|
|
8
|
+
import { getJSONPathMatches } from './jsonPath.js';
|
|
9
9
|
const { isMatch } = micromatch;
|
|
10
10
|
// Find the matching source item in an array
|
|
11
11
|
// where the key matches the identifying locale property
|
|
@@ -16,13 +16,7 @@ export function findMatchingItemArray(locale, sourceObjectOptions, sourceObjectP
|
|
|
16
16
|
const matchingItems = {};
|
|
17
17
|
for (const [index, item] of sourceObjectValue.entries()) {
|
|
18
18
|
// Get the key candidates
|
|
19
|
-
const keyCandidates =
|
|
20
|
-
json: item,
|
|
21
|
-
path: localeKeyJsonPath,
|
|
22
|
-
resultType: 'all',
|
|
23
|
-
flatten: true,
|
|
24
|
-
wrap: true,
|
|
25
|
-
});
|
|
19
|
+
const keyCandidates = getJSONPathMatches(item, localeKeyJsonPath);
|
|
26
20
|
if (!keyCandidates) {
|
|
27
21
|
logger.error(`Source item at path: ${sourceObjectPointer} does not have a key value at path: ${localeKeyJsonPath}`);
|
|
28
22
|
return exitSync(1);
|
|
@@ -40,10 +34,15 @@ export function findMatchingItemArray(locale, sourceObjectOptions, sourceObjectP
|
|
|
40
34
|
// Validate the key is the identifying locale property
|
|
41
35
|
continue;
|
|
42
36
|
}
|
|
37
|
+
const keyParentProperty = keyCandidates[0].parentProperty;
|
|
38
|
+
if (keyParentProperty === null) {
|
|
39
|
+
logger.error(`Source item at path: ${sourceObjectPointer} has a root-level key match with path: ${localeKeyJsonPath}`);
|
|
40
|
+
return exitSync(1);
|
|
41
|
+
}
|
|
43
42
|
// Map the index to the source item
|
|
44
43
|
matchingItems[`/${index}`] = {
|
|
45
44
|
sourceItem: item,
|
|
46
|
-
keyParentProperty
|
|
45
|
+
keyParentProperty,
|
|
47
46
|
keyPointer: keyCandidates[0].pointer,
|
|
48
47
|
index,
|
|
49
48
|
};
|
|
@@ -174,15 +173,16 @@ function findMintlifyUnsupportedFields(value, fieldNames, pointer = '') {
|
|
|
174
173
|
return results;
|
|
175
174
|
}
|
|
176
175
|
// Check if this object contains an unsupported field
|
|
176
|
+
const objectValue = value;
|
|
177
177
|
for (const field of fieldNames) {
|
|
178
|
-
if (typeof
|
|
179
|
-
return [{ pointer, field, fieldValue:
|
|
178
|
+
if (typeof objectValue[field] === 'string') {
|
|
179
|
+
return [{ pointer, field, fieldValue: objectValue[field] }];
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
182
|
// Recurse into child properties
|
|
183
183
|
const results = [];
|
|
184
|
-
for (const key of Object.keys(
|
|
185
|
-
results.push(...findMintlifyUnsupportedFields(
|
|
184
|
+
for (const key of Object.keys(objectValue)) {
|
|
185
|
+
results.push(...findMintlifyUnsupportedFields(objectValue[key], fieldNames, `${pointer}/${key}`));
|
|
186
186
|
}
|
|
187
187
|
return results;
|
|
188
188
|
}
|
package/dist/fs/copyFile.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { Settings } from '../types/index.js';
|
|
1
|
+
import type { Settings } from '../types/index.js';
|
|
2
|
+
type CopyFileSettings = Pick<Settings, 'defaultLocale' | 'locales' | 'options'>;
|
|
2
3
|
/**
|
|
3
4
|
* Copy a file to target locale without translation
|
|
4
5
|
*
|
|
5
6
|
* This is a naive approach, does not allow for wild cards
|
|
6
7
|
*/
|
|
7
|
-
export default function copyFile(settings:
|
|
8
|
+
export default function copyFile(settings: CopyFileSettings): Promise<void>;
|
|
9
|
+
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "2.14.
|
|
1
|
+
export declare const PACKAGE_VERSION = "2.14.34";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// This file is auto-generated. Do not edit manually.
|
|
2
|
-
export const PACKAGE_VERSION = '2.14.
|
|
2
|
+
export const PACKAGE_VERSION = '2.14.34';
|
|
@@ -59,23 +59,42 @@ export async function createUpdates(options, src, sourceDictionary, pkg, validat
|
|
|
59
59
|
updates = [...updates, ...newUpdates];
|
|
60
60
|
// Metadata addition and validation
|
|
61
61
|
const idHashMap = new Map();
|
|
62
|
+
const hashlessIds = new Set();
|
|
63
|
+
const warnedHashlessDuplicateIds = new Set();
|
|
62
64
|
const duplicateIds = new Set();
|
|
65
|
+
const warnHashlessDuplicateId = (id) => {
|
|
66
|
+
if (warnedHashlessDuplicateIds.has(id))
|
|
67
|
+
return;
|
|
68
|
+
warnings.push(`Duplicate id ${chalk.blue(id)} includes at least one entry without a hash. Hashless duplicate IDs cannot be compared, and later entries may overwrite earlier entries.`);
|
|
69
|
+
warnedHashlessDuplicateIds.add(id);
|
|
70
|
+
};
|
|
63
71
|
updates = updates.map((update) => {
|
|
64
|
-
|
|
72
|
+
const { id, hash } = update.metadata;
|
|
73
|
+
if (!id)
|
|
65
74
|
return update;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
75
|
+
if (!hash) {
|
|
76
|
+
if (hashlessIds.has(id) || idHashMap.has(id)) {
|
|
77
|
+
warnHashlessDuplicateId(id);
|
|
78
|
+
}
|
|
79
|
+
hashlessIds.add(id);
|
|
80
|
+
return update;
|
|
81
|
+
}
|
|
82
|
+
if (hashlessIds.has(id)) {
|
|
83
|
+
warnHashlessDuplicateId(id);
|
|
84
|
+
}
|
|
85
|
+
const existingHash = idHashMap.get(id);
|
|
86
|
+
if (existingHash !== undefined) {
|
|
87
|
+
if (existingHash !== hash) {
|
|
88
|
+
errors.push(`Hashes don't match on two components with the same id: ${chalk.blue(id)}. Check your ${chalk.green('<T>')} tags and dictionary entries and make sure you're not accidentally duplicating IDs.`);
|
|
89
|
+
duplicateIds.add(id);
|
|
71
90
|
}
|
|
72
91
|
}
|
|
73
92
|
else {
|
|
74
|
-
idHashMap.set(
|
|
93
|
+
idHashMap.set(id, hash);
|
|
75
94
|
}
|
|
76
95
|
return update;
|
|
77
96
|
});
|
|
78
97
|
// Filter out updates with duplicate IDs
|
|
79
|
-
updates = updates.filter((update) => !duplicateIds.has(update.metadata.id));
|
|
98
|
+
updates = updates.filter((update) => !update.metadata.id || !duplicateIds.has(update.metadata.id));
|
|
80
99
|
return { updates, errors, warnings };
|
|
81
100
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
type JSONValue = string | number | boolean | null | JSONObject | JSONArray;
|
|
1
|
+
export type JSONValue = string | number | boolean | null | JSONObject | JSONArray;
|
|
2
2
|
export type JSONObject = {
|
|
3
3
|
[key: string]: JSONValue;
|
|
4
4
|
};
|
|
5
5
|
export type JSONArray = JSONValue[];
|
|
6
|
-
export {};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -206,6 +206,10 @@ export type Settings = {
|
|
|
206
206
|
branchOptions: BranchOptions;
|
|
207
207
|
sharedStaticAssets?: SharedStaticAssetsConfig;
|
|
208
208
|
};
|
|
209
|
+
export type StaticLocalizationFiles = Pick<Settings['files'], 'placeholderPaths' | 'resolvedPaths'> & Partial<Pick<Settings['files'], 'transformPaths' | 'transformFormats'>>;
|
|
210
|
+
export type StaticLocalizationSettings = Pick<Settings, 'defaultLocale' | 'locales' | 'options'> & {
|
|
211
|
+
files?: StaticLocalizationFiles | null;
|
|
212
|
+
};
|
|
209
213
|
export type BranchOptions = {
|
|
210
214
|
currentBranch?: string;
|
|
211
215
|
autoDetectBranches?: boolean;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import type { AdditionalOptions } from '../types/index.js';
|
|
2
|
+
type AnchorIdSettings = {
|
|
3
|
+
options?: Pick<AdditionalOptions, 'experimentalAddHeaderAnchorIds'>;
|
|
4
|
+
};
|
|
1
5
|
/**
|
|
2
6
|
* Represents a heading with its position and metadata
|
|
3
7
|
*/
|
|
@@ -14,7 +18,7 @@ export declare function extractHeadingInfo(mdxContent: string): HeadingInfo[];
|
|
|
14
18
|
/**
|
|
15
19
|
* Applies anchor IDs to translated content based on source heading mapping
|
|
16
20
|
*/
|
|
17
|
-
export declare function addExplicitAnchorIds(translatedContent: string, sourceHeadingMap: HeadingInfo[], settings?:
|
|
21
|
+
export declare function addExplicitAnchorIds(translatedContent: string, sourceHeadingMap: HeadingInfo[], settings?: AnchorIdSettings, sourcePath?: string, translatedPath?: string, fileTypeHint?: 'md' | 'mdx'): {
|
|
18
22
|
content: string;
|
|
19
23
|
hasChanges: boolean;
|
|
20
24
|
addedIds: Array<{
|
|
@@ -22,3 +26,4 @@ export declare function addExplicitAnchorIds(translatedContent: string, sourceHe
|
|
|
22
26
|
id: string;
|
|
23
27
|
}>;
|
|
24
28
|
};
|
|
29
|
+
export {};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { StaticLocalizationSettings } from '../types/index.js';
|
|
2
2
|
type RewriteResult = {
|
|
3
3
|
content: string;
|
|
4
4
|
hasChanges: boolean;
|
|
5
5
|
};
|
|
6
|
+
export type RelativeAssetSettings = StaticLocalizationSettings;
|
|
6
7
|
export declare function localizeRelativeAssetsForContent(content: string, sourcePath: string, targetPath: string, cwd: string): RewriteResult;
|
|
7
|
-
export default function localizeRelativeAssets(settings:
|
|
8
|
+
export default function localizeRelativeAssets(settings: RelativeAssetSettings, targetLocales?: string[], includeFiles?: Set<string>): Promise<void>;
|
|
8
9
|
export {};
|
|
@@ -81,24 +81,25 @@ export function localizeRelativeAssetsForContent(content, sourcePath, targetPath
|
|
|
81
81
|
return newPath + suffix;
|
|
82
82
|
};
|
|
83
83
|
visit(ast, (node) => {
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
const assetNode = node;
|
|
85
|
+
if (assetNode.type === 'image' && typeof assetNode.url === 'string') {
|
|
86
|
+
const newUrl = maybeRewrite(assetNode.url);
|
|
86
87
|
if (newUrl)
|
|
87
|
-
|
|
88
|
+
assetNode.url = newUrl;
|
|
88
89
|
return;
|
|
89
90
|
}
|
|
90
|
-
if ((
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
Array.isArray(
|
|
94
|
-
for (const attr of
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
typeof
|
|
99
|
-
const newUrl = maybeRewrite(
|
|
91
|
+
if ((assetNode.type === 'mdxJsxFlowElement' ||
|
|
92
|
+
assetNode.type === 'mdxJsxTextElement') &&
|
|
93
|
+
assetNode.name === 'img' &&
|
|
94
|
+
Array.isArray(assetNode.attributes)) {
|
|
95
|
+
for (const attr of assetNode.attributes) {
|
|
96
|
+
const attribute = attr;
|
|
97
|
+
if (attribute.type === 'mdxJsxAttribute' &&
|
|
98
|
+
attribute.name === 'src' &&
|
|
99
|
+
typeof attribute.value === 'string') {
|
|
100
|
+
const newUrl = maybeRewrite(attribute.value);
|
|
100
101
|
if (newUrl)
|
|
101
|
-
|
|
102
|
+
attribute.value = newUrl;
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
105
|
}
|
|
@@ -136,7 +137,7 @@ export default async function localizeRelativeAssets(settings, targetLocales, in
|
|
|
136
137
|
}
|
|
137
138
|
const { resolvedPaths: sourceFiles } = settings.files;
|
|
138
139
|
const locales = targetLocales || settings.locales;
|
|
139
|
-
const fileMapping = createFileMapping(sourceFiles, settings.files.placeholderPaths, settings.files.transformPaths, settings.files.transformFormats, settings.locales, settings.defaultLocale);
|
|
140
|
+
const fileMapping = createFileMapping(sourceFiles, settings.files.placeholderPaths, settings.files.transformPaths ?? {}, settings.files.transformFormats ?? {}, settings.locales, settings.defaultLocale);
|
|
140
141
|
const cwd = process.cwd();
|
|
141
142
|
const processPromises = Object.entries(fileMapping)
|
|
142
143
|
.filter(([locale]) => locales.includes(locale))
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { StaticLocalizationSettings } from '../types/index.js';
|
|
2
|
+
export type StaticImportSettings = StaticLocalizationSettings;
|
|
2
3
|
/**
|
|
3
4
|
* Localizes static imports in content files.
|
|
4
5
|
* Currently only supported for md and mdx files. (/docs/ -> /[locale]/docs/)
|
|
@@ -12,4 +13,4 @@ import { Settings } from '../types/index.js';
|
|
|
12
13
|
* - Support more file types
|
|
13
14
|
* - Support more complex paths
|
|
14
15
|
*/
|
|
15
|
-
export default function localizeStaticImports(settings:
|
|
16
|
+
export default function localizeStaticImports(settings: StaticImportSettings, includeFiles?: Set<string>): Promise<void>;
|
|
@@ -28,7 +28,7 @@ export default async function localizeStaticImports(settings, includeFiles) {
|
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
30
|
const { resolvedPaths: sourceFiles } = settings.files;
|
|
31
|
-
const fileMapping = createFileMapping(sourceFiles, settings.files.placeholderPaths, settings.files.transformPaths, settings.files.transformFormats, settings.locales, settings.defaultLocale);
|
|
31
|
+
const fileMapping = createFileMapping(sourceFiles, settings.files.placeholderPaths, settings.files.transformPaths ?? {}, settings.files.transformFormats ?? {}, settings.locales, settings.defaultLocale);
|
|
32
32
|
// Process all file types at once with a single call
|
|
33
33
|
const processPromises = [];
|
|
34
34
|
// First, process default locale files (from source files)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { StaticLocalizationSettings } from '../types/index.js';
|
|
2
|
+
export type StaticUrlSettings = StaticLocalizationSettings;
|
|
2
3
|
/**
|
|
3
4
|
* Localizes static urls in content files.
|
|
4
5
|
* Currently only supported for md and mdx files. (/docs/ -> /[locale]/docs/)
|
|
@@ -12,7 +13,7 @@ import { Settings } from '../types/index.js';
|
|
|
12
13
|
* - Support more file types
|
|
13
14
|
* - Support more complex paths
|
|
14
15
|
*/
|
|
15
|
-
export default function localizeStaticUrls(settings:
|
|
16
|
+
export default function localizeStaticUrls(settings: StaticUrlSettings, targetLocales?: string[], includeFiles?: Set<string>): Promise<void>;
|
|
16
17
|
/**
|
|
17
18
|
* Main URL transformation function that delegates to specific scenarios
|
|
18
19
|
*/
|
|
@@ -31,7 +31,7 @@ export default async function localizeStaticUrls(settings, targetLocales, includ
|
|
|
31
31
|
const { resolvedPaths: sourceFiles } = settings.files;
|
|
32
32
|
// Use filtered locales if provided, otherwise use all locales
|
|
33
33
|
const locales = targetLocales || settings.locales;
|
|
34
|
-
const fileMapping = createFileMapping(sourceFiles, settings.files.placeholderPaths, settings.files.transformPaths, settings.files.transformFormats, settings.locales, // Always use all locales for mapping, filter later
|
|
34
|
+
const fileMapping = createFileMapping(sourceFiles, settings.files.placeholderPaths, settings.files.transformPaths ?? {}, settings.files.transformFormats ?? {}, settings.locales, // Always use all locales for mapping, filter later
|
|
35
35
|
settings.defaultLocale);
|
|
36
36
|
// Process all file types at once with a single call
|
|
37
37
|
const processPromises = [];
|
|
@@ -38,11 +38,9 @@ async function moveFile(src, dest) {
|
|
|
38
38
|
await fs.promises.rename(src, dest);
|
|
39
39
|
}
|
|
40
40
|
catch (err) {
|
|
41
|
+
const code = err?.code;
|
|
41
42
|
// Fallback to copy+unlink for cross-device or existing files
|
|
42
|
-
if (
|
|
43
|
-
(err.code === 'EXDEV' ||
|
|
44
|
-
err.code === 'EEXIST' ||
|
|
45
|
-
err.code === 'ENOTEMPTY')) {
|
|
43
|
+
if (code === 'EXDEV' || code === 'EEXIST' || code === 'ENOTEMPTY') {
|
|
46
44
|
const data = await fs.promises.readFile(src);
|
|
47
45
|
await ensureDir(path.dirname(dest));
|
|
48
46
|
await fs.promises.writeFile(dest, data);
|
|
@@ -53,7 +51,7 @@ async function moveFile(src, dest) {
|
|
|
53
51
|
// Ignore cleanup errors for source files that were already moved.
|
|
54
52
|
}
|
|
55
53
|
}
|
|
56
|
-
else if (
|
|
54
|
+
else if (code === 'ENOENT') {
|
|
57
55
|
// already moved or missing; ignore
|
|
58
56
|
return;
|
|
59
57
|
}
|
|
@@ -148,32 +146,33 @@ function rewriteMdxContent(content, filePath, pathMap) {
|
|
|
148
146
|
return null;
|
|
149
147
|
};
|
|
150
148
|
visit(ast, (node) => {
|
|
149
|
+
const assetNode = node;
|
|
151
150
|
// Markdown image: 
|
|
152
|
-
if (
|
|
153
|
-
const newUrl = maybeRewrite(
|
|
151
|
+
if (assetNode.type === 'image' && typeof assetNode.url === 'string') {
|
|
152
|
+
const newUrl = maybeRewrite(assetNode.url);
|
|
154
153
|
if (newUrl)
|
|
155
|
-
|
|
154
|
+
assetNode.url = newUrl;
|
|
156
155
|
return;
|
|
157
156
|
}
|
|
158
157
|
// Markdown link: [text](url) — useful for PDFs and other downloadable assets
|
|
159
|
-
if (
|
|
160
|
-
const newUrl = maybeRewrite(
|
|
158
|
+
if (assetNode.type === 'link' && typeof assetNode.url === 'string') {
|
|
159
|
+
const newUrl = maybeRewrite(assetNode.url);
|
|
161
160
|
if (newUrl)
|
|
162
|
-
|
|
161
|
+
assetNode.url = newUrl;
|
|
163
162
|
return;
|
|
164
163
|
}
|
|
165
164
|
// MDX <img src="..." />
|
|
166
|
-
if ((
|
|
167
|
-
|
|
168
|
-
Array.isArray(
|
|
169
|
-
for (const attr of
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
(
|
|
173
|
-
typeof
|
|
174
|
-
const newUrl = maybeRewrite(
|
|
165
|
+
if ((assetNode.type === 'mdxJsxFlowElement' ||
|
|
166
|
+
assetNode.type === 'mdxJsxTextElement') &&
|
|
167
|
+
Array.isArray(assetNode.attributes)) {
|
|
168
|
+
for (const attr of assetNode.attributes) {
|
|
169
|
+
const attribute = attr;
|
|
170
|
+
if (attribute.type === 'mdxJsxAttribute' &&
|
|
171
|
+
(attribute.name === 'src' || attribute.name === 'href') &&
|
|
172
|
+
typeof attribute.value === 'string') {
|
|
173
|
+
const newUrl = maybeRewrite(attribute.value);
|
|
175
174
|
if (newUrl)
|
|
176
|
-
|
|
175
|
+
attribute.value = newUrl;
|
|
177
176
|
}
|
|
178
177
|
}
|
|
179
178
|
}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { WorkflowStep } from './WorkflowStep.js';
|
|
2
|
-
import { GT } from 'generaltranslation';
|
|
3
|
-
import { Settings } from '../../types/index.js';
|
|
2
|
+
import type { GT } from 'generaltranslation';
|
|
3
|
+
import type { Settings } from '../../types/index.js';
|
|
4
4
|
import { BranchData } from '../../types/branch.js';
|
|
5
|
+
type BranchStepClient = Pick<GT, 'queryBranchData' | 'createBranch'>;
|
|
6
|
+
type BranchStepSettings = Pick<Settings, 'branchOptions'>;
|
|
5
7
|
export declare class BranchStep extends WorkflowStep<null, BranchData | null> {
|
|
6
8
|
private spinner;
|
|
7
9
|
private branchData;
|
|
8
10
|
private settings;
|
|
9
11
|
private gt;
|
|
10
|
-
constructor(gt:
|
|
12
|
+
constructor(gt: BranchStepClient, settings: BranchStepSettings);
|
|
11
13
|
run(): Promise<BranchData | null>;
|
|
12
14
|
wait(): Promise<void>;
|
|
13
15
|
}
|
|
16
|
+
export {};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { FileToUpload } from 'generaltranslation/types';
|
|
2
2
|
import { WorkflowStep } from './WorkflowStep.js';
|
|
3
|
-
import { GT } from 'generaltranslation';
|
|
4
|
-
import { Settings } from '../../types/index.js';
|
|
3
|
+
import type { GT } from 'generaltranslation';
|
|
4
|
+
import type { Settings } from '../../types/index.js';
|
|
5
5
|
import { BranchData } from '../../types/branch.js';
|
|
6
6
|
import type { FileReference } from 'generaltranslation/types';
|
|
7
|
+
type UploadSourcesClient = Pick<GT, 'queryFileData' | 'getOrphanedFiles' | 'processFileMoves' | 'uploadSourceFiles'>;
|
|
8
|
+
type UploadSourcesSettings = Pick<Settings, 'defaultLocale' | 'modelProvider'>;
|
|
7
9
|
export declare class UploadSourcesStep extends WorkflowStep<{
|
|
8
10
|
files: FileToUpload[];
|
|
9
11
|
branchData: BranchData;
|
|
@@ -12,7 +14,7 @@ export declare class UploadSourcesStep extends WorkflowStep<{
|
|
|
12
14
|
private settings;
|
|
13
15
|
private spinner;
|
|
14
16
|
private result;
|
|
15
|
-
constructor(gt:
|
|
17
|
+
constructor(gt: UploadSourcesClient, settings: UploadSourcesSettings);
|
|
16
18
|
/**
|
|
17
19
|
* Detects file moves by comparing local files against orphaned files.
|
|
18
20
|
* A move is detected when a local file has the same versionId (content hash)
|
|
@@ -25,3 +27,4 @@ export declare class UploadSourcesStep extends WorkflowStep<{
|
|
|
25
27
|
}): Promise<FileReference[]>;
|
|
26
28
|
wait(): Promise<void>;
|
|
27
29
|
}
|
|
30
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gt",
|
|
3
|
-
"version": "2.14.
|
|
3
|
+
"version": "2.14.34",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"bin": "bin/main.js",
|
|
6
6
|
"files": [
|
|
@@ -111,8 +111,8 @@
|
|
|
111
111
|
"unified": "^11.0.5",
|
|
112
112
|
"unist-util-visit": "^5.0.0",
|
|
113
113
|
"yaml": "^2.8.0",
|
|
114
|
-
"@generaltranslation/python-extractor": "0.2.
|
|
115
|
-
"generaltranslation": "8.2.
|
|
114
|
+
"@generaltranslation/python-extractor": "0.2.19",
|
|
115
|
+
"generaltranslation": "8.2.13",
|
|
116
116
|
"gt-remark": "1.0.7"
|
|
117
117
|
},
|
|
118
118
|
"devDependencies": {
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
"@types/mdast": "^4.0.0",
|
|
124
124
|
"@types/micromatch": "^4.0.9",
|
|
125
125
|
"@types/mock-require": "^2.0.3",
|
|
126
|
-
"@types/node": "^22.5
|
|
126
|
+
"@types/node": "^22.13.5",
|
|
127
127
|
"@types/react": "^18.3.4",
|
|
128
128
|
"@types/resolve": "^1.20.2",
|
|
129
129
|
"eslint": "^9.20.0",
|
|
@@ -133,14 +133,15 @@
|
|
|
133
133
|
"prettier": "^3.4.2",
|
|
134
134
|
"ts-node": "^10.9.2",
|
|
135
135
|
"tslib": "^2.8.1",
|
|
136
|
-
"typescript": "^5.
|
|
137
|
-
"vitest": "^2.
|
|
136
|
+
"typescript": "^5.9.2",
|
|
137
|
+
"vitest": "^3.2.4"
|
|
138
138
|
},
|
|
139
139
|
"scripts": {
|
|
140
|
-
"
|
|
140
|
+
"generate-version": "node scripts/generate-version.js",
|
|
141
|
+
"build": "pnpm run generate-version && tsc && rm -rf dist/setup/instructions && cp -r src/setup/instructions dist/setup/instructions",
|
|
141
142
|
"build:clean": "sh ../../scripts/clean.sh && pnpm bin:restore && rm -rf binaries && pnpm run build",
|
|
142
143
|
"build:release": "pnpm run build:clean",
|
|
143
|
-
"build:bin": "
|
|
144
|
+
"build:bin": "pnpm run generate-version && tsc && rm -rf dist/setup/instructions && cp -r src/setup/instructions dist/setup/instructions && sh scripts/build-exe.sh all",
|
|
144
145
|
"build:bin:clean": "sh ../../scripts/clean.sh && rm -rf binaries && pnpm run build:bin",
|
|
145
146
|
"build:bin:release": "pnpm run build:bin:clean && pnpm run build:bin",
|
|
146
147
|
"build:bin:darwin-x64": "sh scripts/build-exe.sh darwin-x64",
|
|
@@ -148,8 +149,8 @@
|
|
|
148
149
|
"build:bin:linux-x64": "sh scripts/build-exe.sh linux-x64",
|
|
149
150
|
"build:bin:linux-arm64": "sh scripts/build-exe.sh linux-arm64",
|
|
150
151
|
"build:bin:windows-x64": "sh scripts/build-exe.sh windows-x64",
|
|
151
|
-
"test": "vitest run --config=./vitest.config.ts",
|
|
152
|
-
"test:watch": "vitest --config=./vitest.config.ts",
|
|
152
|
+
"test": "pnpm run generate-version && vitest run --config=./vitest.config.ts",
|
|
153
|
+
"test:watch": "pnpm run generate-version && vitest --config=./vitest.config.ts",
|
|
153
154
|
"release": "pnpm run release:normal && pnpm run release:bin",
|
|
154
155
|
"release:normal": "pnpm run build:clean && pnpm publish",
|
|
155
156
|
"release:bin": "pnpm run bin:prep && pnpm run build:bin:clean && pnpm publish --tag bin --no-git-checks && pnpm run bin:restore && pnpm run build:clean",
|
|
@@ -158,6 +159,6 @@
|
|
|
158
159
|
"release:latest": "pnpm run build:clean && pnpm publish --tag latest",
|
|
159
160
|
"bin:restore": "node scripts/restore-package-json.js",
|
|
160
161
|
"bin:prep": "node scripts/prepare-binary-release.js",
|
|
161
|
-
"typecheck": "tsc --noEmit"
|
|
162
|
+
"typecheck": "pnpm run generate-version && tsc --noEmit"
|
|
162
163
|
}
|
|
163
164
|
}
|