gtx-cli 2.1.15 → 2.1.17
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
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# gtx-cli
|
|
2
2
|
|
|
3
|
+
## 2.1.17
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#635](https://github.com/generaltranslation/gt/pull/635) [`10aa051`](https://github.com/generaltranslation/gt/commit/10aa051592cea43f772615da200c8615d4dd1a78) Thanks [@brian-lou](https://github.com/brian-lou)! - Create dictionary with uuid to reduce flakiness
|
|
8
|
+
|
|
9
|
+
## 2.1.16
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#630](https://github.com/generaltranslation/gt/pull/630) [`1f0dc1b`](https://github.com/generaltranslation/gt/commit/1f0dc1b17f22737263938998f5c516e0aa136b1a) Thanks [@fernando-aviles](https://github.com/fernando-aviles)! - Adding localization of import paths to MDX files
|
|
14
|
+
|
|
3
15
|
## 2.1.15
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -7,6 +7,7 @@ import flattenJsonFiles from '../../utils/flattenJsonFiles.js';
|
|
|
7
7
|
import localizeStaticUrls from '../../utils/localizeStaticUrls.js';
|
|
8
8
|
import processAnchorIds from '../../utils/processAnchorIds.js';
|
|
9
9
|
import { noFilesError, noVersionIdError } from '../../console/index.js';
|
|
10
|
+
import localizeStaticImports from '../../utils/localizeStaticImports.js';
|
|
10
11
|
// Downloads translations that were completed
|
|
11
12
|
export async function handleTranslate(options, settings, filesTranslationResponse) {
|
|
12
13
|
if (filesTranslationResponse && settings.files) {
|
|
@@ -46,6 +47,10 @@ export async function postProcessTranslations(settings) {
|
|
|
46
47
|
// Uses inline {#id} format by default, or div wrapping if experimentalAddHeaderAnchorIds is 'mintlify'
|
|
47
48
|
await processAnchorIds(settings);
|
|
48
49
|
}
|
|
50
|
+
// Localize static imports (import Snippet from /snippets/file.mdx -> import Snippet from /snippets/[locale]/file.mdx)
|
|
51
|
+
if (settings.options?.experimentalLocalizeStaticImports) {
|
|
52
|
+
await localizeStaticImports(settings);
|
|
53
|
+
}
|
|
49
54
|
// Flatten json files into a single file
|
|
50
55
|
if (settings.options?.experimentalFlattenJsonFiles) {
|
|
51
56
|
await flattenJsonFiles(settings);
|
|
@@ -7,6 +7,7 @@ import loadJSON from '../../fs/loadJSON.js';
|
|
|
7
7
|
import { hashSource } from 'generaltranslation/id';
|
|
8
8
|
import getEntryAndMetadata from '../utils/getEntryAndMetadata.js';
|
|
9
9
|
import { logError } from '../../console/logging.js';
|
|
10
|
+
import { randomUUID } from 'node:crypto';
|
|
10
11
|
export async function createDictionaryUpdates(dictionaryPath, esbuildConfig) {
|
|
11
12
|
let dictionary;
|
|
12
13
|
// ---- HANDLE JSON STRING DICTIONARY ----- //
|
|
@@ -21,7 +22,7 @@ export async function createDictionaryUpdates(dictionaryPath, esbuildConfig) {
|
|
|
21
22
|
write: false,
|
|
22
23
|
});
|
|
23
24
|
const bundledCode = result.outputFiles[0].text;
|
|
24
|
-
const tempFilePath = path.join(os.tmpdir(),
|
|
25
|
+
const tempFilePath = path.join(os.tmpdir(), `bundled-dictionary-${randomUUID()}.js`);
|
|
25
26
|
await fs.promises.writeFile(tempFilePath, bundledCode);
|
|
26
27
|
// Load the module using dynamic import
|
|
27
28
|
let dictionaryModule;
|
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
2
3
|
import { createFileMapping } from '../formats/files/fileMapping.js';
|
|
3
4
|
import micromatch from 'micromatch';
|
|
4
5
|
import { unified } from 'unified';
|
|
5
6
|
import remarkParse from 'remark-parse';
|
|
6
7
|
import remarkMdx from 'remark-mdx';
|
|
7
8
|
import remarkFrontmatter from 'remark-frontmatter';
|
|
8
|
-
import remarkStringify from 'remark-stringify';
|
|
9
9
|
import { visit } from 'unist-util-visit';
|
|
10
10
|
const { isMatch } = micromatch;
|
|
11
|
+
/**
|
|
12
|
+
* Checks if a file exists at the given path
|
|
13
|
+
*/
|
|
14
|
+
function fileExists(filePath) {
|
|
15
|
+
try {
|
|
16
|
+
return fs.existsSync(filePath);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
11
22
|
/**
|
|
12
23
|
* Localizes static imports in content files.
|
|
13
24
|
* Currently only supported for md and mdx files. (/docs/ -> /[locale]/docs/)
|
|
@@ -48,7 +59,7 @@ export default async function localizeStaticImports(settings) {
|
|
|
48
59
|
const fileContent = await fs.promises.readFile(filePath, 'utf8');
|
|
49
60
|
// Localize the file using default locale
|
|
50
61
|
const localizedFile = localizeStaticImportsForFile(fileContent, settings.defaultLocale, settings.defaultLocale, // Process as default locale
|
|
51
|
-
settings.options?.docsHideDefaultLocaleImport || false, settings.options?.docsImportPattern, settings.options?.excludeStaticImports, filePath
|
|
62
|
+
settings.options?.docsHideDefaultLocaleImport || false, settings.options?.docsImportPattern, settings.options?.excludeStaticImports, filePath);
|
|
52
63
|
// Write the localized file back to the same path
|
|
53
64
|
await fs.promises.writeFile(filePath, localizedFile);
|
|
54
65
|
}));
|
|
@@ -64,7 +75,7 @@ export default async function localizeStaticImports(settings) {
|
|
|
64
75
|
// Get file content
|
|
65
76
|
const fileContent = await fs.promises.readFile(filePath, 'utf8');
|
|
66
77
|
// Localize the file
|
|
67
|
-
const localizedFile = localizeStaticImportsForFile(fileContent, settings.defaultLocale, locale, settings.options?.docsHideDefaultLocaleImport || false, settings.options?.docsImportPattern, settings.options?.excludeStaticImports, filePath
|
|
78
|
+
const localizedFile = localizeStaticImportsForFile(fileContent, settings.defaultLocale, locale, settings.options?.docsHideDefaultLocaleImport || false, settings.options?.docsImportPattern, settings.options?.excludeStaticImports, filePath);
|
|
68
79
|
// Write the localized file to the target path
|
|
69
80
|
await fs.promises.writeFile(filePath, localizedFile);
|
|
70
81
|
}));
|
|
@@ -175,23 +186,45 @@ function transformNonDefaultLocaleImportPath(fullPath, patternHead, targetLocale
|
|
|
175
186
|
/**
|
|
176
187
|
* Main import path transformation function that delegates to specific scenarios
|
|
177
188
|
*/
|
|
178
|
-
function transformImportPath(fullPath, patternHead, targetLocale, defaultLocale, hideDefaultLocale)
|
|
189
|
+
function transformImportPath(fullPath, patternHead, targetLocale, defaultLocale, hideDefaultLocale, currentFilePath, projectRoot = process.cwd() // fallback if not provided
|
|
190
|
+
) {
|
|
191
|
+
let newPath;
|
|
179
192
|
if (targetLocale === defaultLocale) {
|
|
180
|
-
|
|
193
|
+
newPath = transformDefaultLocaleImportPath(fullPath, patternHead, defaultLocale, hideDefaultLocale);
|
|
181
194
|
}
|
|
182
195
|
else if (hideDefaultLocale) {
|
|
183
|
-
|
|
196
|
+
newPath = transformNonDefaultLocaleImportPathWithHidden(fullPath, patternHead, targetLocale, defaultLocale);
|
|
184
197
|
}
|
|
185
198
|
else {
|
|
186
|
-
|
|
199
|
+
newPath = transformNonDefaultLocaleImportPath(fullPath, patternHead, targetLocale, defaultLocale);
|
|
187
200
|
}
|
|
201
|
+
if (!newPath)
|
|
202
|
+
return null;
|
|
203
|
+
if (currentFilePath) {
|
|
204
|
+
let resolvedPath;
|
|
205
|
+
if (newPath.startsWith('/')) {
|
|
206
|
+
// Interpret as project-root relative
|
|
207
|
+
resolvedPath = path.join(projectRoot, newPath.replace(/^\//, ''));
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
// Relative to current file
|
|
211
|
+
const currentDir = path.dirname(currentFilePath);
|
|
212
|
+
resolvedPath = path.resolve(currentDir, newPath);
|
|
213
|
+
}
|
|
214
|
+
const pathExists = fileExists(resolvedPath);
|
|
215
|
+
if (!pathExists) {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return newPath;
|
|
188
220
|
}
|
|
189
221
|
/**
|
|
190
222
|
* AST-based transformation for MDX files using remark-mdx
|
|
191
223
|
*/
|
|
192
|
-
function transformMdxImports(mdxContent, defaultLocale, targetLocale, hideDefaultLocale, pattern = '/[locale]', exclude = []) {
|
|
224
|
+
function transformMdxImports(mdxContent, defaultLocale, targetLocale, hideDefaultLocale, pattern = '/[locale]', exclude = [], currentFilePath) {
|
|
193
225
|
const transformedImports = [];
|
|
194
|
-
|
|
226
|
+
// Don't auto-prefix relative patterns that start with . or ..
|
|
227
|
+
if (!pattern.startsWith('/') && !pattern.startsWith('.')) {
|
|
195
228
|
pattern = '/' + pattern;
|
|
196
229
|
}
|
|
197
230
|
const patternHead = pattern.split('[locale]')[0];
|
|
@@ -239,23 +272,23 @@ function transformMdxImports(mdxContent, defaultLocale, targetLocale, hideDefaul
|
|
|
239
272
|
transformedImports: [],
|
|
240
273
|
};
|
|
241
274
|
}
|
|
242
|
-
|
|
275
|
+
let content = mdxContent;
|
|
276
|
+
// Visit only mdxjsEsm nodes (import/export statements) to collect replacements
|
|
243
277
|
visit(processedAst, 'mdxjsEsm', (node) => {
|
|
244
278
|
if (node.value && node.value.includes(patternHead.replace(/\/$/, ''))) {
|
|
245
|
-
// Find
|
|
279
|
+
// Find import lines that need transformation
|
|
246
280
|
const lines = node.value.split('\n');
|
|
247
|
-
|
|
281
|
+
lines.forEach((line) => {
|
|
248
282
|
// Only process import lines that match our pattern
|
|
249
283
|
if (!line.trim().startsWith('import ')) {
|
|
250
|
-
return
|
|
284
|
+
return;
|
|
251
285
|
}
|
|
252
286
|
// Check if this line should be processed
|
|
253
287
|
if (!shouldProcessImportPath(line, patternHead, targetLocale, defaultLocale)) {
|
|
254
|
-
return
|
|
288
|
+
return;
|
|
255
289
|
}
|
|
256
290
|
// Extract the path from the import statement
|
|
257
291
|
const quotes = ['"', "'", '`'];
|
|
258
|
-
let transformedLine = line;
|
|
259
292
|
for (const quote of quotes) {
|
|
260
293
|
// Try both with and without trailing slash
|
|
261
294
|
let startPattern = `${quote}${patternHead}`;
|
|
@@ -274,7 +307,7 @@ function transformMdxImports(mdxContent, defaultLocale, targetLocale, hideDefaul
|
|
|
274
307
|
continue;
|
|
275
308
|
const fullPath = line.slice(pathStart, pathEnd);
|
|
276
309
|
// Transform the import path
|
|
277
|
-
const newPath = transformImportPath(fullPath, patternHead, targetLocale, defaultLocale, hideDefaultLocale);
|
|
310
|
+
const newPath = transformImportPath(fullPath, patternHead, targetLocale, defaultLocale, hideDefaultLocale, currentFilePath);
|
|
278
311
|
if (!newPath) {
|
|
279
312
|
continue; // No transformation needed
|
|
280
313
|
}
|
|
@@ -282,43 +315,15 @@ function transformMdxImports(mdxContent, defaultLocale, targetLocale, hideDefaul
|
|
|
282
315
|
if (isImportPathExcluded(fullPath, exclude, defaultLocale)) {
|
|
283
316
|
continue;
|
|
284
317
|
}
|
|
285
|
-
// Apply the transformation
|
|
318
|
+
// Apply the transformation to the original content
|
|
319
|
+
// Simply replace the import path with the new path
|
|
320
|
+
content = content.replace(`${quote}${fullPath}${quote}`, `${quote}${newPath}${quote}`);
|
|
286
321
|
transformedImports.push({ originalPath: fullPath, newPath });
|
|
287
|
-
transformedLine =
|
|
288
|
-
line.slice(0, pathStart) + newPath + line.slice(pathEnd);
|
|
289
322
|
break;
|
|
290
323
|
}
|
|
291
|
-
return transformedLine;
|
|
292
324
|
});
|
|
293
|
-
node.value = transformedLines.join('\n');
|
|
294
325
|
}
|
|
295
326
|
});
|
|
296
|
-
// Convert the modified AST back to MDX string
|
|
297
|
-
let content;
|
|
298
|
-
try {
|
|
299
|
-
const stringifyProcessor = unified()
|
|
300
|
-
.use(remarkStringify)
|
|
301
|
-
.use(remarkFrontmatter, ['yaml', 'toml'])
|
|
302
|
-
.use(remarkMdx);
|
|
303
|
-
content = stringifyProcessor.stringify(processedAst);
|
|
304
|
-
}
|
|
305
|
-
catch (error) {
|
|
306
|
-
console.warn(`Failed to stringify MDX content: ${error instanceof Error ? error.message : String(error)}`);
|
|
307
|
-
console.warn('Returning original content unchanged due to stringify error.');
|
|
308
|
-
return {
|
|
309
|
-
content: mdxContent,
|
|
310
|
-
hasChanges: false,
|
|
311
|
-
transformedImports: [],
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
// Handle newline formatting to match original input
|
|
315
|
-
if (content.endsWith('\n') && !mdxContent.endsWith('\n')) {
|
|
316
|
-
content = content.slice(0, -1);
|
|
317
|
-
}
|
|
318
|
-
// Preserve leading newlines from original content
|
|
319
|
-
if (mdxContent.startsWith('\n') && !content.startsWith('\n')) {
|
|
320
|
-
content = '\n' + content;
|
|
321
|
-
}
|
|
322
327
|
return {
|
|
323
328
|
content,
|
|
324
329
|
hasChanges: transformedImports.length > 0,
|
|
@@ -329,12 +334,12 @@ function transformMdxImports(mdxContent, defaultLocale, targetLocale, hideDefaul
|
|
|
329
334
|
* AST-based transformation for MDX files only
|
|
330
335
|
*/
|
|
331
336
|
function localizeStaticImportsForFile(file, defaultLocale, targetLocale, hideDefaultLocale, pattern = '/[locale]', // eg /docs/[locale] or /[locale]
|
|
332
|
-
exclude = [],
|
|
337
|
+
exclude = [], currentFilePath) {
|
|
333
338
|
// Skip .md files entirely - they cannot have imports
|
|
334
|
-
if (
|
|
339
|
+
if (currentFilePath && currentFilePath.endsWith('.md')) {
|
|
335
340
|
return file;
|
|
336
341
|
}
|
|
337
342
|
// For MDX files, use AST-based transformation
|
|
338
|
-
const result = transformMdxImports(file, defaultLocale, targetLocale, hideDefaultLocale, pattern, exclude);
|
|
343
|
+
const result = transformMdxImports(file, defaultLocale, targetLocale, hideDefaultLocale, pattern, exclude, currentFilePath);
|
|
339
344
|
return result.content;
|
|
340
345
|
}
|