gtx-cli 2.3.6-alpha.3 → 2.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/api/checkFileTranslations.js +18 -0
- package/dist/cli/flags.js +2 -1
- package/dist/config/generateSettings.js +4 -0
- package/dist/fs/clearLocaleFolders.d.ts +8 -0
- package/dist/fs/clearLocaleFolders.js +126 -0
- package/dist/types/index.d.ts +2 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# gtx-cli
|
|
2
2
|
|
|
3
|
+
## 2.3.7
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#710](https://github.com/generaltranslation/gt/pull/710) [`8325bae`](https://github.com/generaltranslation/gt/commit/8325bae9a8661a0b269131ac6dadefab327c5b2c) Thanks [@SamEggert](https://github.com/SamEggert)! - add clearLocaleFolders option
|
|
8
|
+
|
|
9
|
+
## 2.3.6
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#698](https://github.com/generaltranslation/gt/pull/698) [`9eefc14`](https://github.com/generaltranslation/gt/commit/9eefc14577013fcfa699344c4a950c12d3b3350b) Thanks [@brian-lou](https://github.com/brian-lou)! - Switch monorepo package manager to pnpm (no new features or bugs fixed). Please report issues to https://github.com/generaltranslation/gt
|
|
14
|
+
|
|
15
|
+
- Updated dependencies [[`9eefc14`](https://github.com/generaltranslation/gt/commit/9eefc14577013fcfa699344c4a950c12d3b3350b)]:
|
|
16
|
+
- gt-remark@1.0.2
|
|
17
|
+
- generaltranslation@7.6.4
|
|
18
|
+
|
|
3
19
|
## 2.3.5
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
|
@@ -4,6 +4,8 @@ import { getLocaleProperties } from 'generaltranslation';
|
|
|
4
4
|
import { downloadFileBatch } from './downloadFileBatch.js';
|
|
5
5
|
import { gt } from '../utils/gt.js';
|
|
6
6
|
import { TEMPLATE_FILE_NAME } from '../cli/commands/stage.js';
|
|
7
|
+
import { clearLocaleFolders } from '../fs/clearLocaleFolders.js';
|
|
8
|
+
import path from 'node:path';
|
|
7
9
|
/**
|
|
8
10
|
* Checks the status of translations for a given version ID
|
|
9
11
|
* @param apiKey - The API key for the General Translation API
|
|
@@ -24,6 +26,22 @@ export async function checkFileTranslations(data, locales, timeoutDuration, reso
|
|
|
24
26
|
spinner.start(spinnerMessage);
|
|
25
27
|
// Initialize the query data
|
|
26
28
|
const fileQueryData = prepareFileQueryData(data, locales);
|
|
29
|
+
// Clear translated files before any downloads (if enabled)
|
|
30
|
+
if (options.options?.experimentalClearLocaleFolders === true &&
|
|
31
|
+
fileQueryData.length > 0) {
|
|
32
|
+
const translatedFiles = new Set(fileQueryData
|
|
33
|
+
.map((file) => {
|
|
34
|
+
const outputPath = resolveOutputPath(file.fileName, file.locale);
|
|
35
|
+
// Only clear if the output path is different from the source (i.e., there's a transform)
|
|
36
|
+
return outputPath !== null && outputPath !== file.fileName
|
|
37
|
+
? outputPath
|
|
38
|
+
: null;
|
|
39
|
+
})
|
|
40
|
+
.filter((path) => path !== null));
|
|
41
|
+
// Derive cwd from config path
|
|
42
|
+
const cwd = path.dirname(options.config);
|
|
43
|
+
await clearLocaleFolders(translatedFiles, locales, options.options?.clearLocaleFoldersExclude, cwd);
|
|
44
|
+
}
|
|
27
45
|
const downloadStatus = {
|
|
28
46
|
downloaded: new Set(),
|
|
29
47
|
failed: new Set(),
|
package/dist/cli/flags.js
CHANGED
|
@@ -24,7 +24,8 @@ export function attachTranslateFlags(command) {
|
|
|
24
24
|
.option('--experimental-hide-default-locale', 'When localizing static locales, hide the default locale from the path', false)
|
|
25
25
|
.option('--experimental-flatten-json-files', 'Triggering this will flatten the json files into a single file. This is useful for projects that have a lot of json files.', false)
|
|
26
26
|
.option('--experimental-localize-static-imports', 'Triggering this will run a script after the cli tool that localizes all static imports in content files. Currently only supported for md and mdx files.', false)
|
|
27
|
-
.option('--force', 'Force a retranslation, invalidating all existing cached translations if they exist.', false)
|
|
27
|
+
.option('--force', 'Force a retranslation, invalidating all existing cached translations if they exist.', false)
|
|
28
|
+
.option('--experimental-clear-locale-folders', 'Clear locale folders before downloading new translations', false);
|
|
28
29
|
return command;
|
|
29
30
|
}
|
|
30
31
|
export function attachAdditionalReactTranslateFlags(command) {
|
|
@@ -126,6 +126,10 @@ export async function generateSettings(options, cwd = process.cwd()) {
|
|
|
126
126
|
options.experimentalHideDefaultLocale,
|
|
127
127
|
experimentalFlattenJsonFiles: gtConfig.options?.experimentalFlattenJsonFiles ||
|
|
128
128
|
options.experimentalFlattenJsonFiles,
|
|
129
|
+
experimentalClearLocaleFolders: gtConfig.options?.experimentalClearLocaleFolders ||
|
|
130
|
+
options.experimentalClearLocaleFolders,
|
|
131
|
+
clearLocaleFoldersExclude: gtConfig.options?.clearLocaleFoldersExclude ||
|
|
132
|
+
options.clearLocaleFoldersExclude,
|
|
129
133
|
};
|
|
130
134
|
// Add additional options if provided
|
|
131
135
|
if (mergedOptions.options) {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clears translated files before writing new translations
|
|
3
|
+
* @param filePaths - Set of translated file paths to clear
|
|
4
|
+
* @param locales - Array of locale codes to match against
|
|
5
|
+
* @param excludePatterns - Optional array of glob patterns to exclude from clearing (supports [locale] and [locales])
|
|
6
|
+
* @param cwd - Current working directory for resolving relative exclude patterns (defaults to process.cwd())
|
|
7
|
+
*/
|
|
8
|
+
export declare function clearLocaleFolders(filePaths: Set<string>, locales: string[], excludePatterns?: string[], cwd?: string): Promise<void>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { logSuccess, logWarning } from '../console/logging.js';
|
|
4
|
+
import fg from 'fast-glob';
|
|
5
|
+
import micromatch from 'micromatch';
|
|
6
|
+
/**
|
|
7
|
+
* Extracts locale directories from translated file paths.
|
|
8
|
+
* Groups files by their immediate parent containing a locale code.
|
|
9
|
+
* For example: "snippets/es/api-test/file.mdx" -> "snippets/es"
|
|
10
|
+
*/
|
|
11
|
+
function extractLocaleDirectories(filePaths, locales) {
|
|
12
|
+
const localeDirs = new Set();
|
|
13
|
+
const localeSet = new Set(locales);
|
|
14
|
+
for (const filePath of filePaths) {
|
|
15
|
+
const parts = filePath.split(path.sep);
|
|
16
|
+
// Find directory segments that match the provided locales
|
|
17
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
18
|
+
const segment = parts[i];
|
|
19
|
+
if (localeSet.has(segment)) {
|
|
20
|
+
// Found a locale directory, capture up to and including this segment
|
|
21
|
+
const localeDir = parts.slice(0, i + 1).join(path.sep);
|
|
22
|
+
localeDirs.add(localeDir);
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return localeDirs;
|
|
28
|
+
}
|
|
29
|
+
async function getAllFiles(dirPath) {
|
|
30
|
+
return await fg(path.join(dirPath, '**/*'), {
|
|
31
|
+
absolute: true,
|
|
32
|
+
onlyFiles: true,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
async function getFilesToDelete(dirPath, excludePatterns, currentLocale, cwd) {
|
|
36
|
+
const allFiles = await getAllFiles(dirPath);
|
|
37
|
+
const absoluteCwd = path.resolve(cwd);
|
|
38
|
+
const expandedExcludePatterns = excludePatterns.map((p) => {
|
|
39
|
+
const resolvedPattern = path.isAbsolute(p) ? p : path.join(absoluteCwd, p);
|
|
40
|
+
return resolvedPattern
|
|
41
|
+
.replace(/\[locale\]/g, currentLocale)
|
|
42
|
+
.replace(/\[locales\]/g, currentLocale);
|
|
43
|
+
});
|
|
44
|
+
const filesToKeep = micromatch(allFiles, expandedExcludePatterns, {
|
|
45
|
+
dot: true,
|
|
46
|
+
});
|
|
47
|
+
const filesToKeepSet = new Set(filesToKeep);
|
|
48
|
+
return allFiles.filter((file) => !filesToKeepSet.has(file));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Clears translated files before writing new translations
|
|
52
|
+
* @param filePaths - Set of translated file paths to clear
|
|
53
|
+
* @param locales - Array of locale codes to match against
|
|
54
|
+
* @param excludePatterns - Optional array of glob patterns to exclude from clearing (supports [locale] and [locales])
|
|
55
|
+
* @param cwd - Current working directory for resolving relative exclude patterns (defaults to process.cwd())
|
|
56
|
+
*/
|
|
57
|
+
export async function clearLocaleFolders(filePaths, locales, excludePatterns, cwd = process.cwd()) {
|
|
58
|
+
// Extract locale directories
|
|
59
|
+
const localeDirs = extractLocaleDirectories(filePaths, locales);
|
|
60
|
+
for (const dir of localeDirs) {
|
|
61
|
+
try {
|
|
62
|
+
await fs.stat(dir);
|
|
63
|
+
// Extract locale from directory path
|
|
64
|
+
const dirParts = dir.split(path.sep);
|
|
65
|
+
const locale = locales.find((loc) => dirParts.includes(loc));
|
|
66
|
+
if (!locale) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (!excludePatterns?.length) {
|
|
70
|
+
await fs.rm(dir, { recursive: true, force: true });
|
|
71
|
+
logSuccess(`Cleared locale directory: ${dir}`);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const filesToDelete = await getFilesToDelete(dir, excludePatterns, locale, cwd);
|
|
75
|
+
// Get all files for count comparison
|
|
76
|
+
const allFiles = await getAllFiles(dir);
|
|
77
|
+
for (const file of filesToDelete) {
|
|
78
|
+
try {
|
|
79
|
+
await fs.unlink(file);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (error.code !== 'ENOENT') {
|
|
83
|
+
logWarning(`Failed to delete file ${file}: ${error}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Clean up empty directories
|
|
88
|
+
await cleanupEmptyDirs(dir);
|
|
89
|
+
const excludedCount = allFiles.length - filesToDelete.length;
|
|
90
|
+
if (excludedCount > 0) {
|
|
91
|
+
logSuccess(`Cleared locale directory: ${dir} (excluded ${excludedCount} file${excludedCount > 1 ? 's' : ''})`);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
logSuccess(`Cleared locale directory: ${dir}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
if (error.code !== 'ENOENT') {
|
|
99
|
+
logWarning(`Failed to clear locale directory ${dir}: ${error}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Recursively removes empty directories
|
|
106
|
+
* @param dirPath - The directory to clean up
|
|
107
|
+
*/
|
|
108
|
+
async function cleanupEmptyDirs(dirPath) {
|
|
109
|
+
try {
|
|
110
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
111
|
+
// Recursively clean subdirectories first
|
|
112
|
+
for (const entry of entries) {
|
|
113
|
+
if (entry.isDirectory()) {
|
|
114
|
+
await cleanupEmptyDirs(path.join(dirPath, entry.name));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Check if directory is now empty
|
|
118
|
+
const remainingEntries = await fs.readdir(dirPath);
|
|
119
|
+
if (remainingEntries.length === 0) {
|
|
120
|
+
await fs.rmdir(dirPath);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
// Ignore errors - directory might not exist or might not be empty
|
|
125
|
+
}
|
|
126
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -143,6 +143,8 @@ export type AdditionalOptions = {
|
|
|
143
143
|
excludeStaticImports?: string[];
|
|
144
144
|
docsHideDefaultLocaleImport?: boolean;
|
|
145
145
|
copyFiles?: string[];
|
|
146
|
+
experimentalClearLocaleFolders?: boolean;
|
|
147
|
+
clearLocaleFoldersExclude?: string[];
|
|
146
148
|
experimentalLocalizeStaticImports?: boolean;
|
|
147
149
|
experimentalLocalizeStaticUrls?: boolean;
|
|
148
150
|
experimentalAddHeaderAnchorIds?: 'mintlify';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gtx-cli",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.7",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"bin": "dist/main.js",
|
|
6
6
|
"files": [
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"unified": "^11.0.5",
|
|
92
92
|
"unist-util-visit": "^5.0.0",
|
|
93
93
|
"yaml": "^2.8.0",
|
|
94
|
-
"generaltranslation": "7.6.4
|
|
94
|
+
"generaltranslation": "7.6.4"
|
|
95
95
|
},
|
|
96
96
|
"devDependencies": {
|
|
97
97
|
"@babel/types": "^7.28.4",
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
},
|
|
117
117
|
"scripts": {
|
|
118
118
|
"build": "tsc",
|
|
119
|
-
"build:clean": "
|
|
119
|
+
"build:clean": "sh ../../scripts/clean.sh && pnpm run build",
|
|
120
120
|
"build:release": "pnpm run build:clean",
|
|
121
121
|
"lint": "eslint \"src/**/*.{js,ts}\" \"./**/__tests__/**/*.{js,ts}\"",
|
|
122
122
|
"lint:fix": "eslint \"src/**/*.{js,ts}\" \"./**/__tests__/**/*.{js,ts}\" --fix",
|