gtx-cli 2.1.5-alpha.6 → 2.1.6

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,20 @@
1
1
  # gtx-cli
2
2
 
3
+ ## 2.1.6
4
+
5
+ ### Patch Changes
6
+
7
+ - [#584](https://github.com/generaltranslation/gt/pull/584) [`fd3d958`](https://github.com/generaltranslation/gt/commit/fd3d958dab3d14a7f1f9b49c5c49fba191077a57) Thanks [@brian-lou](https://github.com/brian-lou)! - Fix version
8
+
9
+ ## 2.1.5
10
+
11
+ ### Patch Changes
12
+
13
+ - [#580](https://github.com/generaltranslation/gt/pull/580) [`9b05fda`](https://github.com/generaltranslation/gt/commit/9b05fda9959f9e24491c02f357bc2a2c49ba0276) Thanks [@brian-lou](https://github.com/brian-lou)! - Update API schema, combine files and JSX translation endpoints
14
+
15
+ - Updated dependencies [[`9b05fda`](https://github.com/generaltranslation/gt/commit/9b05fda9959f9e24491c02f357bc2a2c49ba0276)]:
16
+ - generaltranslation@7.4.1
17
+
3
18
  ## 2.1.5
4
19
 
5
20
  ### Patch Changes
package/dist/cli/base.js CHANGED
@@ -17,7 +17,6 @@ import { upload } from '../formats/files/upload.js';
17
17
  import { attachTranslateFlags } from './flags.js';
18
18
  import { handleStage } from './commands/stage.js';
19
19
  import { handleDownload, handleTranslate, postProcessTranslations, } from './commands/translate.js';
20
- import localizeStaticUrls from '../utils/localizeStaticUrls.js';
21
20
  import updateConfig from '../fs/config/updateConfig.js';
22
21
  export class BaseCLI {
23
22
  library;
@@ -79,19 +78,11 @@ export class BaseCLI {
79
78
  const settings = await generateSettings(initOptions);
80
79
  if (!settings.stageTranslations) {
81
80
  const results = await handleStage(initOptions, settings, this.library, false);
82
- // Process default locale static URLs first, before translations
83
- if (settings.options?.experimentalLocalizeStaticUrls) {
84
- await localizeStaticUrls(settings, [settings.defaultLocale]);
85
- }
86
81
  if (results) {
87
82
  await handleTranslate(initOptions, settings, results);
88
83
  }
89
84
  }
90
85
  else {
91
- // Process default locale static URLs first, before downloading translations
92
- if (settings.options?.experimentalLocalizeStaticUrls) {
93
- await localizeStaticUrls(settings, [settings.defaultLocale]);
94
- }
95
86
  await handleDownload(initOptions, settings);
96
87
  }
97
88
  await postProcessTranslations(settings);
@@ -35,13 +35,9 @@ export async function handleDownload(options, settings) {
35
35
  await checkFileTranslations(stagedVersionData, settings.locales, options.timeout, (sourcePath, locale) => fileMapping[locale][sourcePath] ?? null, settings);
36
36
  }
37
37
  export async function postProcessTranslations(settings) {
38
- // Localize static urls (/docs -> /[locale]/docs) for non-default locales only
39
- // Default locale is processed earlier in the flow in base.ts
38
+ // Localize static urls (/docs -> /[locale]/docs)
40
39
  if (settings.options?.experimentalLocalizeStaticUrls) {
41
- const nonDefaultLocales = settings.locales.filter(locale => locale !== settings.defaultLocale);
42
- if (nonDefaultLocales.length > 0) {
43
- await localizeStaticUrls(settings, nonDefaultLocales);
44
- }
40
+ await localizeStaticUrls(settings);
45
41
  }
46
42
  // Localize static imports (/docs -> /[locale]/docs)
47
43
  if (settings.options?.experimentalLocalizeStaticImports) {
@@ -141,7 +141,6 @@ export type AdditionalOptions = {
141
141
  experimentalLocalizeStaticUrls?: boolean;
142
142
  experimentalHideDefaultLocale?: boolean;
143
143
  experimentalFlattenJsonFiles?: boolean;
144
- baseDomain?: string;
145
144
  };
146
145
  export type JsonSchema = {
147
146
  preset?: 'mintlify';
@@ -12,8 +12,4 @@ import { Settings } from '../types/index.js';
12
12
  * - Support more file types
13
13
  * - Support more complex paths
14
14
  */
15
- export default function localizeStaticUrls(settings: Settings, targetLocales?: string[]): Promise<void>;
16
- /**
17
- * Main URL transformation function that delegates to specific scenarios
18
- */
19
- export declare function transformUrlPath(originalUrl: string, patternHead: string, targetLocale: string, defaultLocale: string, hideDefaultLocale: boolean): string | null;
15
+ export default function localizeStaticUrls(settings: Settings): Promise<void>;
@@ -21,24 +21,19 @@ const { isMatch } = micromatch;
21
21
  * - Support more file types
22
22
  * - Support more complex paths
23
23
  */
24
- export default async function localizeStaticUrls(settings, targetLocales) {
24
+ export default async function localizeStaticUrls(settings) {
25
25
  if (!settings.files ||
26
26
  (Object.keys(settings.files.placeholderPaths).length === 1 &&
27
27
  settings.files.placeholderPaths.gt)) {
28
28
  return;
29
29
  }
30
30
  const { resolvedPaths: sourceFiles } = settings.files;
31
- // Use filtered locales if provided, otherwise use all locales
32
- const locales = targetLocales || settings.locales;
33
- const fileMapping = createFileMapping(sourceFiles, settings.files.placeholderPaths, settings.files.transformPaths, settings.locales, // Always use all locales for mapping, filter later
34
- settings.defaultLocale);
31
+ const fileMapping = createFileMapping(sourceFiles, settings.files.placeholderPaths, settings.files.transformPaths, settings.locales, settings.defaultLocale);
35
32
  // Process all file types at once with a single call
36
33
  const processPromises = [];
37
34
  // First, process default locale files (from source files)
38
35
  // This is needed because they might not be in the fileMapping if they're not being translated
39
- // Only process default locale if it's in the target locales filter
40
- if (!fileMapping[settings.defaultLocale] &&
41
- locales.includes(settings.defaultLocale)) {
36
+ if (!fileMapping[settings.defaultLocale]) {
42
37
  const defaultLocaleFiles = [];
43
38
  // Collect all .md and .mdx files from sourceFiles
44
39
  if (sourceFiles.md) {
@@ -52,20 +47,16 @@ export default async function localizeStaticUrls(settings, targetLocales) {
52
47
  // Get file content
53
48
  const fileContent = await fs.promises.readFile(filePath, 'utf8');
54
49
  // Localize the file using default locale
55
- const result = localizeStaticUrlsForFile(fileContent, settings.defaultLocale, settings.defaultLocale, // Process as default locale
56
- settings.options?.experimentalHideDefaultLocale || false, settings.options?.docsUrlPattern, settings.options?.excludeStaticUrls, settings.options?.baseDomain);
57
- // Only write the file if there were changes
58
- if (result.hasChanges) {
59
- await fs.promises.writeFile(filePath, result.content);
60
- }
50
+ const localizedFile = localizeStaticUrlsForFile(fileContent, settings.defaultLocale, settings.defaultLocale, // Process as default locale
51
+ settings.options?.experimentalHideDefaultLocale || false, settings.options?.docsUrlPattern, settings.options?.excludeStaticUrls);
52
+ // Write the localized file back to the same path
53
+ await fs.promises.writeFile(filePath, localizedFile);
61
54
  }));
62
55
  processPromises.push(defaultPromise);
63
56
  }
64
57
  }
65
58
  // Then process all other locales from fileMapping
66
- const mappingPromises = Object.entries(fileMapping)
67
- .filter(([locale, filesMap]) => locales.includes(locale)) // Filter by target locales
68
- .map(async ([locale, filesMap]) => {
59
+ const mappingPromises = Object.entries(fileMapping).map(async ([locale, filesMap]) => {
69
60
  // Get all files that are md or mdx
70
61
  const targetFiles = Object.values(filesMap).filter((path) => path.endsWith('.md') || path.endsWith('.mdx'));
71
62
  // Replace the placeholder path with the target path
@@ -73,11 +64,9 @@ export default async function localizeStaticUrls(settings, targetLocales) {
73
64
  // Get file content
74
65
  const fileContent = await fs.promises.readFile(filePath, 'utf8');
75
66
  // Localize the file (handles both URLs and hrefs in single AST pass)
76
- const result = localizeStaticUrlsForFile(fileContent, settings.defaultLocale, locale, settings.options?.experimentalHideDefaultLocale || false, settings.options?.docsUrlPattern, settings.options?.excludeStaticUrls, settings.options?.baseDomain);
77
- // Only write the file if there were changes
78
- if (result.hasChanges) {
79
- await fs.promises.writeFile(filePath, result.content);
80
- }
67
+ const localizedFile = localizeStaticUrlsForFile(fileContent, settings.defaultLocale, locale, settings.options?.experimentalHideDefaultLocale || false, settings.options?.docsUrlPattern, settings.options?.excludeStaticUrls);
68
+ // Write the localized file to the target path
69
+ await fs.promises.writeFile(filePath, localizedFile);
81
70
  }));
82
71
  });
83
72
  processPromises.push(...mappingPromises);
@@ -86,28 +75,21 @@ export default async function localizeStaticUrls(settings, targetLocales) {
86
75
  /**
87
76
  * Determines if a URL should be processed based on pattern matching
88
77
  */
89
- function shouldProcessUrl(originalUrl, patternHead, targetLocale, defaultLocale, baseDomain) {
90
- const patternWithoutSlash = patternHead.replace(/\/$/, '');
91
- // Handle absolute URLs with baseDomain
92
- let urlToCheck = originalUrl;
93
- if (baseDomain && originalUrl.startsWith(baseDomain)) {
94
- urlToCheck = originalUrl.substring(baseDomain.length);
78
+ function shouldProcessUrl(originalUrl, patternHead, targetLocale, defaultLocale) {
79
+ // Skip absolute URLs (http://, https://, //, etc.)
80
+ if (originalUrl.includes(':')) {
81
+ return false;
95
82
  }
83
+ const patternWithoutSlash = patternHead.replace(/\/$/, '');
96
84
  if (targetLocale === defaultLocale) {
97
85
  // For default locale processing, check if URL contains the pattern
98
- return urlToCheck.includes(patternWithoutSlash);
86
+ return originalUrl.includes(patternWithoutSlash);
99
87
  }
100
88
  else {
101
89
  // For non-default locales, check if URL starts with pattern
102
- return urlToCheck.startsWith(patternWithoutSlash);
90
+ return originalUrl.startsWith(patternWithoutSlash);
103
91
  }
104
92
  }
105
- /**
106
- * Determines if a URL should be processed based on the base domain
107
- */
108
- function shouldProcessAbsoluteUrl(originalUrl, baseDomain) {
109
- return originalUrl.startsWith(baseDomain);
110
- }
111
93
  /**
112
94
  * Checks if a URL should be excluded based on exclusion patterns
113
95
  */
@@ -116,79 +98,102 @@ function isUrlExcluded(originalUrl, exclude, defaultLocale) {
116
98
  return excludePatterns.some((pattern) => isMatch(originalUrl, pattern));
117
99
  }
118
100
  /**
119
- * Main URL transformation function that delegates to specific scenarios
101
+ * Transforms URL for default locale processing
120
102
  */
121
- export function transformUrlPath(originalUrl, patternHead, targetLocale, defaultLocale, hideDefaultLocale) {
122
- const originalPathArray = originalUrl
123
- .split('/')
124
- .filter((path) => path !== '');
125
- const patternHeadArray = patternHead.split('/').filter((path) => path !== '');
126
- // check if the pattern head matches the original path
127
- if (!checkIfPathMatchesPattern(originalPathArray, patternHeadArray)) {
103
+ function transformDefaultLocaleUrl(originalUrl, patternHead, defaultLocale, hideDefaultLocale) {
104
+ if (hideDefaultLocale) {
105
+ // Remove locale from URLs that have it: '/docs/en/file' -> '/docs/file'
106
+ if (originalUrl.includes(`/${defaultLocale}/`)) {
107
+ return originalUrl.replace(`/${defaultLocale}/`, '/');
108
+ }
109
+ else if (originalUrl.endsWith(`/${defaultLocale}`)) {
110
+ return originalUrl.replace(`/${defaultLocale}`, '');
111
+ }
112
+ return null; // URL doesn't have default locale
113
+ }
114
+ else {
115
+ // Add locale to URLs that don't have it: '/docs/file' -> '/docs/en/file'
116
+ if (originalUrl.includes(`/${defaultLocale}/`) ||
117
+ originalUrl.endsWith(`/${defaultLocale}`)) {
118
+ return null; // Already has default locale
119
+ }
120
+ if (originalUrl.startsWith(patternHead)) {
121
+ const pathAfterHead = originalUrl.slice(patternHead.length);
122
+ if (pathAfterHead) {
123
+ return `${patternHead}${defaultLocale}/${pathAfterHead}`;
124
+ }
125
+ else {
126
+ return `${patternHead.replace(/\/$/, '')}/${defaultLocale}`;
127
+ }
128
+ }
129
+ return null; // URL doesn't match pattern
130
+ }
131
+ }
132
+ /**
133
+ * Transforms URL for non-default locale processing with hideDefaultLocale=true
134
+ */
135
+ function transformNonDefaultLocaleUrlWithHidden(originalUrl, patternHead, targetLocale, defaultLocale) {
136
+ // Check if already localized
137
+ if (originalUrl.startsWith(`${patternHead}${targetLocale}/`) ||
138
+ originalUrl === `${patternHead}${targetLocale}`) {
128
139
  return null;
129
140
  }
130
- if (patternHeadArray.length > originalPathArray.length) {
131
- return null; // Pattern is longer than the URL path
141
+ // Replace default locale with target locale
142
+ const expectedPathWithDefaultLocale = `${patternHead}${defaultLocale}`;
143
+ if (originalUrl.startsWith(`${expectedPathWithDefaultLocale}/`) ||
144
+ originalUrl === expectedPathWithDefaultLocale) {
145
+ return originalUrl.replace(`${patternHead}${defaultLocale}`, `${patternHead}${targetLocale}`);
132
146
  }
133
- let result = null;
134
- if (targetLocale === defaultLocale) {
135
- if (hideDefaultLocale) {
136
- // check if default locale is already present
137
- if (originalPathArray?.[patternHeadArray.length] !== defaultLocale) {
138
- return null;
139
- }
140
- // remove default locale
141
- const newPathArray = [
142
- ...originalPathArray.slice(0, patternHeadArray.length),
143
- ...originalPathArray.slice(patternHeadArray.length + 1),
144
- ];
145
- result = newPathArray.join('/');
147
+ // Handle exact pattern match
148
+ if (originalUrl === patternHead.replace(/\/$/, '')) {
149
+ return `${patternHead.replace(/\/$/, '')}/${targetLocale}`;
150
+ }
151
+ // Add target locale to URL without any locale
152
+ const pathAfterHead = originalUrl.slice(originalUrl.startsWith(patternHead) ? patternHead.length : 0);
153
+ return pathAfterHead
154
+ ? `${patternHead}${targetLocale}/${pathAfterHead}`
155
+ : `${patternHead}${targetLocale}`;
156
+ }
157
+ /**
158
+ * Transforms URL for non-default locale processing with hideDefaultLocale=false
159
+ */
160
+ function transformNonDefaultLocaleUrl(originalUrl, patternHead, targetLocale, defaultLocale) {
161
+ const expectedPathWithLocale = `${patternHead}${defaultLocale}`;
162
+ if (originalUrl.startsWith(`${expectedPathWithLocale}/`) ||
163
+ originalUrl === expectedPathWithLocale) {
164
+ // Replace existing default locale with target locale
165
+ return originalUrl.replace(`${patternHead}${defaultLocale}`, `${patternHead}${targetLocale}`);
166
+ }
167
+ else if (originalUrl.startsWith(patternHead)) {
168
+ // Add target locale to URL that doesn't have any locale
169
+ const pathAfterHead = originalUrl.slice(patternHead.length);
170
+ if (pathAfterHead) {
171
+ return `${patternHead}${targetLocale}/${pathAfterHead}`;
146
172
  }
147
173
  else {
148
- // check if default locale is already present
149
- if (originalPathArray?.[patternHeadArray.length] === defaultLocale) {
150
- return null;
151
- }
152
- // insert default locale
153
- const newPathArray = [
154
- ...originalPathArray.slice(0, patternHeadArray.length),
155
- defaultLocale,
156
- ...originalPathArray.slice(patternHeadArray.length),
157
- ];
158
- result = newPathArray.join('/');
174
+ return `${patternHead.replace(/\/$/, '')}/${targetLocale}`;
159
175
  }
160
176
  }
177
+ return null; // URL doesn't match pattern
178
+ }
179
+ /**
180
+ * Main URL transformation function that delegates to specific scenarios
181
+ */
182
+ function transformUrlPath(originalUrl, patternHead, targetLocale, defaultLocale, hideDefaultLocale) {
183
+ if (targetLocale === defaultLocale) {
184
+ return transformDefaultLocaleUrl(originalUrl, patternHead, defaultLocale, hideDefaultLocale);
185
+ }
161
186
  else if (hideDefaultLocale) {
162
- const newPathArray = [
163
- ...originalPathArray.slice(0, patternHeadArray.length),
164
- targetLocale,
165
- ...originalPathArray.slice(patternHeadArray.length),
166
- ];
167
- result = newPathArray.join('/');
187
+ return transformNonDefaultLocaleUrlWithHidden(originalUrl, patternHead, targetLocale, defaultLocale);
168
188
  }
169
189
  else {
170
- // check default locale
171
- if (originalPathArray?.[patternHeadArray.length] !== defaultLocale) {
172
- return null;
173
- }
174
- // replace default locale with target locale
175
- const newPathArray = [...originalPathArray];
176
- newPathArray[patternHeadArray.length] = targetLocale;
177
- result = newPathArray.join('/');
178
- }
179
- // check for leading and trailing slashes
180
- if (originalUrl.startsWith('/')) {
181
- result = '/' + result;
190
+ return transformNonDefaultLocaleUrl(originalUrl, patternHead, targetLocale, defaultLocale);
182
191
  }
183
- if (originalUrl.endsWith('/')) {
184
- result = result + '/';
185
- }
186
- return result;
187
192
  }
188
193
  /**
189
194
  * AST-based transformation for MDX files using remark-mdx
190
195
  */
191
- function transformMdxUrls(mdxContent, defaultLocale, targetLocale, hideDefaultLocale, pattern = '/[locale]', exclude = [], baseDomain) {
196
+ function transformMdxUrls(mdxContent, defaultLocale, targetLocale, hideDefaultLocale, pattern = '/[locale]', exclude = []) {
192
197
  const transformedUrls = [];
193
198
  if (!pattern.startsWith('/')) {
194
199
  pattern = '/' + pattern;
@@ -241,18 +246,7 @@ function transformMdxUrls(mdxContent, defaultLocale, targetLocale, hideDefaultLo
241
246
  // Helper function to transform URL based on pattern
242
247
  const transformUrl = (originalUrl, linkType) => {
243
248
  // Check if URL should be processed
244
- if (!shouldProcessUrl(originalUrl, patternHead, targetLocale, defaultLocale, baseDomain)) {
245
- return null;
246
- }
247
- // Skip absolute URLs (http://, https://, //, etc.)
248
- if (baseDomain && shouldProcessAbsoluteUrl(originalUrl, baseDomain)) {
249
- // Get everything after the base domain
250
- const afterDomain = originalUrl.substring(baseDomain.length);
251
- const transformedPath = transformUrlPath(afterDomain, patternHead, targetLocale, defaultLocale, hideDefaultLocale);
252
- return transformedPath ? baseDomain + transformedPath : null;
253
- }
254
- // Exclude colon-prefixed URLs (http://, https://, //, etc.)
255
- if (originalUrl.split('?')[0].includes(':')) {
249
+ if (!shouldProcessUrl(originalUrl, patternHead, targetLocale, defaultLocale)) {
256
250
  return null;
257
251
  }
258
252
  // Transform the URL based on locale and configuration
@@ -387,23 +381,8 @@ function transformMdxUrls(mdxContent, defaultLocale, targetLocale, hideDefaultLo
387
381
  }
388
382
  // AST-based transformation for MDX files using remark
389
383
  function localizeStaticUrlsForFile(file, defaultLocale, targetLocale, hideDefaultLocale, pattern = '/[locale]', // eg /docs/[locale] or /[locale]
390
- exclude = [], baseDomain) {
384
+ exclude = []) {
391
385
  // Use AST-based transformation for MDX files
392
- return transformMdxUrls(file, defaultLocale, targetLocale, hideDefaultLocale, pattern, exclude, baseDomain || '');
393
- }
394
- function cleanPath(path) {
395
- let cleanedPath = path.startsWith('/') ? path.slice(1) : path;
396
- cleanedPath = cleanedPath.endsWith('/')
397
- ? cleanedPath.slice(0, -1)
398
- : cleanedPath;
399
- return cleanedPath;
400
- }
401
- function checkIfPathMatchesPattern(originalUrlArray, patternHeadArray) {
402
- // check if the pattern head matches the original path
403
- for (let i = 0; i < patternHeadArray.length; i++) {
404
- if (patternHeadArray[i] !== originalUrlArray?.[i]) {
405
- return false;
406
- }
407
- }
408
- return true;
386
+ const result = transformMdxUrls(file, defaultLocale, targetLocale, hideDefaultLocale, pattern, exclude);
387
+ return result.content;
409
388
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtx-cli",
3
- "version": "2.1.5-alpha.6",
3
+ "version": "2.1.6",
4
4
  "main": "dist/index.js",
5
5
  "bin": "dist/main.js",
6
6
  "files": [
@@ -87,7 +87,7 @@
87
87
  "esbuild": "^0.25.4",
88
88
  "fast-glob": "^3.3.3",
89
89
  "form-data": "^4.0.4",
90
- "generaltranslation": "^7.4.1-alpha.2",
90
+ "generaltranslation": "^7.4.1",
91
91
  "json-pointer": "^0.6.2",
92
92
  "jsonpath-plus": "^10.3.0",
93
93
  "jsonpointer": "^5.0.1",