gtx-cli 2.1.5-alpha.5 → 2.1.5-alpha.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.
Files changed (59) hide show
  1. package/dist/api/checkFileTranslations.d.ts +1 -4
  2. package/dist/api/checkFileTranslations.js +32 -35
  3. package/dist/api/downloadFileBatch.d.ts +1 -0
  4. package/dist/api/sendFiles.d.ts +2 -13
  5. package/dist/api/sendFiles.js +15 -8
  6. package/dist/cli/base.d.ts +5 -17
  7. package/dist/cli/base.js +57 -75
  8. package/dist/cli/commands/stage.d.ts +5 -0
  9. package/dist/cli/commands/stage.js +100 -0
  10. package/dist/cli/commands/translate.d.ts +6 -0
  11. package/dist/cli/commands/translate.js +58 -0
  12. package/dist/cli/flags.d.ts +3 -0
  13. package/dist/cli/flags.js +37 -0
  14. package/dist/cli/next.js +0 -1
  15. package/dist/cli/react.d.ts +2 -5
  16. package/dist/cli/react.js +13 -153
  17. package/dist/config/generateSettings.js +11 -6
  18. package/dist/console/index.d.ts +1 -0
  19. package/dist/console/index.js +1 -0
  20. package/dist/console/logging.d.ts +1 -0
  21. package/dist/console/logging.js +3 -0
  22. package/dist/formats/files/fileMapping.d.ts +2 -1
  23. package/dist/formats/files/fileMapping.js +6 -0
  24. package/dist/formats/files/translate.d.ts +4 -13
  25. package/dist/formats/files/translate.js +30 -142
  26. package/dist/formats/files/upload.js +1 -75
  27. package/dist/formats/gt/save.d.ts +1 -2
  28. package/dist/formats/gt/save.js +2 -5
  29. package/dist/fs/config/setupConfig.d.ts +1 -0
  30. package/dist/fs/config/setupConfig.js +1 -0
  31. package/dist/fs/config/updateConfig.d.ts +1 -2
  32. package/dist/fs/config/updateConfig.js +1 -1
  33. package/dist/fs/config/updateVersions.d.ts +10 -0
  34. package/dist/fs/config/updateVersions.js +30 -0
  35. package/dist/fs/copyFile.d.ts +1 -2
  36. package/dist/translation/parse.d.ts +2 -2
  37. package/dist/translation/parse.js +4 -6
  38. package/dist/translation/stage.d.ts +2 -5
  39. package/dist/translation/stage.js +13 -55
  40. package/dist/types/files.d.ts +1 -0
  41. package/dist/types/files.js +1 -0
  42. package/dist/types/index.d.ts +27 -3
  43. package/dist/utils/flattenJsonFiles.d.ts +2 -2
  44. package/dist/utils/hash.d.ts +6 -0
  45. package/dist/utils/hash.js +11 -0
  46. package/dist/utils/localizeStaticImports.d.ts +2 -2
  47. package/dist/utils/localizeStaticUrls.d.ts +2 -2
  48. package/dist/utils/localizeStaticUrls.js +13 -15
  49. package/package.json +2 -2
  50. package/dist/api/downloadFile.d.ts +0 -9
  51. package/dist/api/downloadFile.js +0 -74
  52. package/dist/api/fetchTranslations.d.ts +0 -7
  53. package/dist/api/fetchTranslations.js +0 -18
  54. package/dist/api/sendUpdates.d.ts +0 -19
  55. package/dist/api/sendUpdates.js +0 -48
  56. package/dist/api/waitForUpdates.d.ts +0 -9
  57. package/dist/api/waitForUpdates.js +0 -89
  58. package/dist/translation/translate.d.ts +0 -2
  59. package/dist/translation/translate.js +0 -18
@@ -1,9 +1,6 @@
1
1
  import { noSupportedFormatError, noDefaultLocaleError, noApiKeyError, noProjectIdError, devApiKeyError, } from '../../console/index.js';
2
- import { logErrorAndExit, createSpinner, logError, } from '../../console/logging.js';
2
+ import { logErrorAndExit, logError } from '../../console/logging.js';
3
3
  import { getRelative, readFile } from '../../fs/findFilepath.js';
4
- import chalk from 'chalk';
5
- import { downloadFile } from '../../api/downloadFile.js';
6
- import { downloadFileBatch } from '../../api/downloadFileBatch.js';
7
4
  import { SUPPORTED_FILE_EXTENSIONS } from './supportedFiles.js';
8
5
  import sanitizeFileContent from '../../utils/sanitizeFileContent.js';
9
6
  import { parseJson } from '../json/parseJson.js';
@@ -139,74 +136,3 @@ export async function upload(filePaths, placeholderPaths, transformPaths, dataFo
139
136
  logErrorAndExit(`Error uploading files: ${error}`);
140
137
  }
141
138
  }
142
- /**
143
- * Processes translations that were already completed and returned with the initial API response
144
- * @returns Set of downloaded file+locale combinations
145
- */
146
- async function processInitialTranslations(translations = [], fileMapping, options) {
147
- const downloadStatus = {
148
- downloaded: new Set(),
149
- failed: new Set(),
150
- };
151
- if (!translations || translations.length === 0) {
152
- return downloadStatus;
153
- }
154
- // Filter for ready translations
155
- const readyTranslations = translations.filter((translation) => translation.isReady && translation.fileName);
156
- if (readyTranslations.length > 0) {
157
- const spinner = createSpinner('dots');
158
- spinner.start('Downloading translations...');
159
- // Prepare batch download data
160
- const batchFiles = readyTranslations
161
- .map((translation) => {
162
- const { locale, fileName, id } = translation;
163
- const outputPath = fileMapping[locale][fileName];
164
- if (!outputPath) {
165
- return null;
166
- }
167
- return {
168
- translationId: id,
169
- outputPath,
170
- inputPath: fileName,
171
- fileLocale: `${fileName}:${locale}`,
172
- locale,
173
- };
174
- })
175
- .filter(Boolean);
176
- if (batchFiles.length === 0 || batchFiles[0] === null) {
177
- return downloadStatus;
178
- }
179
- // Use batch download if there are multiple files
180
- if (batchFiles.length > 1) {
181
- const batchResult = await downloadFileBatch(batchFiles.map(({ translationId, outputPath, inputPath, locale }) => ({
182
- translationId,
183
- outputPath,
184
- inputPath,
185
- locale,
186
- })), options);
187
- // Process results
188
- batchFiles.forEach((file) => {
189
- const { translationId, fileLocale } = file;
190
- if (batchResult.successful.includes(translationId)) {
191
- downloadStatus.downloaded.add(fileLocale);
192
- }
193
- else if (batchResult.failed.includes(translationId)) {
194
- downloadStatus.failed.add(fileLocale);
195
- }
196
- });
197
- }
198
- else if (batchFiles.length === 1) {
199
- // For a single file, use the original downloadFile method
200
- const file = batchFiles[0];
201
- const result = await downloadFile(file.translationId, file.outputPath, file.inputPath, file.locale, options);
202
- if (result) {
203
- downloadStatus.downloaded.add(file.fileLocale);
204
- }
205
- else {
206
- downloadStatus.failed.add(file.fileLocale);
207
- }
208
- }
209
- spinner.stop(chalk.green('Downloaded cached translations'));
210
- }
211
- return downloadStatus;
212
- }
@@ -1,10 +1,9 @@
1
1
  import { RetrievedTranslations } from 'generaltranslation/types';
2
2
  import { ResolvedFiles } from '../../types/index.js';
3
- import { DataFormat } from '../../types/data.js';
4
3
  /**
5
4
  * Saves translations to a local directory
6
5
  * @param translations - The translations to save
7
6
  * @param translationsDir - The directory to save the translations to
8
7
  * @param fileType - The file type to save the translations as (file extension)
9
8
  */
10
- export declare function saveTranslations(translations: RetrievedTranslations, placeholderPaths: ResolvedFiles, dataFormat: DataFormat): Promise<void>;
9
+ export declare function saveTranslations(translations: RetrievedTranslations, placeholderPaths: ResolvedFiles): Promise<void>;
@@ -9,7 +9,7 @@ import { resolveLocaleFiles } from '../../fs/config/parseFilesConfig.js';
9
9
  * @param translationsDir - The directory to save the translations to
10
10
  * @param fileType - The file type to save the translations as (file extension)
11
11
  */
12
- export async function saveTranslations(translations, placeholderPaths, dataFormat) {
12
+ export async function saveTranslations(translations, placeholderPaths) {
13
13
  for (const translation of translations) {
14
14
  const locale = translation.locale;
15
15
  const translationFiles = resolveLocaleFiles(placeholderPaths, locale);
@@ -21,9 +21,6 @@ export async function saveTranslations(translations, placeholderPaths, dataForma
21
21
  const translationData = translation.translation;
22
22
  // Ensure directory exists
23
23
  await fs.promises.mkdir(path.dirname(filepath), { recursive: true });
24
- // Handle different file types
25
- if (dataFormat === 'JSX') {
26
- await fs.promises.writeFile(filepath, JSON.stringify(translationData, null, 2));
27
- }
24
+ await fs.promises.writeFile(filepath, JSON.stringify(translationData, null, 2));
28
25
  }
29
26
  }
@@ -13,4 +13,5 @@ export declare function createOrUpdateConfig(configFilepath: string, options: {
13
13
  files?: FilesOptions;
14
14
  framework?: SupportedFrameworks;
15
15
  baseUrl?: string;
16
+ publish?: boolean;
16
17
  }): Promise<string>;
@@ -17,6 +17,7 @@ export async function createOrUpdateConfig(configFilepath, options) {
17
17
  ...(options.files && { files: options.files }),
18
18
  ...(options.framework && { framework: options.framework }),
19
19
  ...(options.baseUrl && { baseUrl: options.baseUrl }),
20
+ ...(options.publish && { publish: options.publish }),
20
21
  };
21
22
  try {
22
23
  // if file exists
@@ -2,10 +2,9 @@
2
2
  * Update the config file version id, locales, and projectId (if necessary)
3
3
  * @param {Record<string, any>} configObject - The config object to write if the file does not exist.
4
4
  */
5
- export default function updateConfig({ configFilepath, projectId, _versionId, locales, stageTranslations, }: {
5
+ export default function updateConfig({ configFilepath, projectId, _versionId, stageTranslations, }: {
6
6
  configFilepath: string;
7
7
  projectId?: string;
8
8
  _versionId?: string;
9
- locales?: string[];
10
9
  stageTranslations?: boolean;
11
10
  }): Promise<void>;
@@ -5,7 +5,7 @@ import { logError } from '../../console/logging.js';
5
5
  * Update the config file version id, locales, and projectId (if necessary)
6
6
  * @param {Record<string, any>} configObject - The config object to write if the file does not exist.
7
7
  */
8
- export default async function updateConfig({ configFilepath, projectId, _versionId, locales, stageTranslations, }) {
8
+ export default async function updateConfig({ configFilepath, projectId, _versionId, stageTranslations, }) {
9
9
  // Filter out empty string values from the config object
10
10
  const newContent = {
11
11
  ...(projectId && { projectId }),
@@ -0,0 +1,10 @@
1
+ type StagedVersionData = Record<string, {
2
+ fileName: string;
3
+ versionId: string;
4
+ }>;
5
+ export declare function updateVersions({ configDirectory, versionData, }: {
6
+ configDirectory: string;
7
+ versionData: StagedVersionData;
8
+ }): Promise<void>;
9
+ export declare function getStagedVersions(configDirectory: string): Promise<StagedVersionData>;
10
+ export {};
@@ -0,0 +1,30 @@
1
+ import fs from 'node:fs';
2
+ import { displayUpdatedVersionsFile } from '../../console/logging.js';
3
+ import { logError } from '../../console/logging.js';
4
+ import path from 'node:path';
5
+ const STAGED_VERSIONS_FILE = 'staged-versions.json';
6
+ // Update the versions.json file with the new version ids
7
+ // of the translations that were sent to the API
8
+ export async function updateVersions({ configDirectory, versionData, }) {
9
+ const versionFilepath = path.join(configDirectory, STAGED_VERSIONS_FILE);
10
+ try {
11
+ fs.mkdirSync(configDirectory, { recursive: true });
12
+ fs.writeFileSync(versionFilepath, JSON.stringify(versionData, null, 2));
13
+ // show update in console
14
+ displayUpdatedVersionsFile(versionFilepath);
15
+ }
16
+ catch (error) {
17
+ logError(`An error occurred while updating ${versionFilepath}: ${error}`);
18
+ }
19
+ }
20
+ export async function getStagedVersions(configDirectory) {
21
+ try {
22
+ const versionFilepath = path.join(configDirectory, STAGED_VERSIONS_FILE);
23
+ const versionData = JSON.parse(fs.readFileSync(versionFilepath, 'utf8'));
24
+ return versionData;
25
+ }
26
+ catch (error) {
27
+ logError(`An error occurred while getting staged versions: ${error}`);
28
+ return {};
29
+ }
30
+ }
@@ -1,8 +1,7 @@
1
1
  import { Settings } from '../types/index.js';
2
- import { TranslateOptions } from '../cli/base.js';
3
2
  /**
4
3
  * Copy a file to target locale without translation
5
4
  *
6
5
  * This is a naive approach, does not allow for wild cards
7
6
  */
8
- export default function copyFile(settings: Settings & TranslateOptions): Promise<void>;
7
+ export default function copyFile(settings: Settings): Promise<void>;
@@ -1,4 +1,4 @@
1
- import { Options, GenerateSourceOptions, Updates } from '../types/index.js';
1
+ import { Updates, TranslateFlags } from '../types/index.js';
2
2
  /**
3
3
  * Searches for gt-react or gt-next dictionary files and creates updates for them,
4
4
  * as well as inline updates for <T> tags and useGT()/getGT() calls
@@ -8,7 +8,7 @@ import { Options, GenerateSourceOptions, Updates } from '../types/index.js';
8
8
  * @param pkg - The package name
9
9
  * @returns An object containing the updates and errors
10
10
  */
11
- export declare function createUpdates(options: Options | GenerateSourceOptions, sourceDictionary: string | undefined, pkg: 'gt-react' | 'gt-next', validate: boolean): Promise<{
11
+ export declare function createUpdates(options: TranslateFlags, sourceDictionary: string | undefined, pkg: 'gt-react' | 'gt-next', validate: boolean): Promise<{
12
12
  updates: Updates;
13
13
  errors: string[];
14
14
  warnings: string[];
@@ -48,12 +48,10 @@ export async function createUpdates(options, sourceDictionary, pkg, validate) {
48
48
  }
49
49
  }
50
50
  // Scan through project for <T> tags
51
- if (options.inline) {
52
- const { updates: newUpdates, errors: newErrors, warnings: newWarnings, } = await createInlineUpdates(pkg, validate, options.src);
53
- errors = [...errors, ...newErrors];
54
- warnings = [...warnings, ...newWarnings];
55
- updates = [...updates, ...newUpdates];
56
- }
51
+ const { updates: newUpdates, errors: newErrors, warnings: newWarnings, } = await createInlineUpdates(pkg, validate, options.src);
52
+ errors = [...errors, ...newErrors];
53
+ warnings = [...warnings, ...newWarnings];
54
+ updates = [...updates, ...newUpdates];
57
55
  // Metadata addition and validation
58
56
  const idHashMap = new Map();
59
57
  const duplicateIds = new Set();
@@ -1,5 +1,2 @@
1
- import { Options, Settings } from '../types/index.js';
2
- export declare function stageProject(settings: Options & Settings, pkg: 'gt-react' | 'gt-next'): Promise<{
3
- versionId: string;
4
- locales: string[];
5
- } | null>;
1
+ import { Settings, TranslateFlags, Updates } from '../types/index.js';
2
+ export declare function aggregateReactTranslations(options: TranslateFlags, settings: Settings, library: 'gt-react' | 'gt-next'): Promise<Updates>;
@@ -1,14 +1,11 @@
1
- import { devApiKeyError } from '../console/index.js';
2
1
  import { logErrorAndExit } from '../console/logging.js';
3
2
  import chalk from 'chalk';
4
3
  import findFilepath from '../fs/findFilepath.js';
5
- import { logSuccess, logWarning, logError } from '../console/logging.js';
4
+ import { logWarning, logError } from '../console/logging.js';
6
5
  import { createUpdates } from './parse.js';
7
- import { noLocalesError, noDefaultLocaleError, noProjectIdError, noApiKeyError, } from '../console/index.js';
8
- import { sendUpdates } from '../api/sendUpdates.js';
9
- export async function stageProject(settings, pkg) {
10
- if (!settings.dictionary) {
11
- settings.dictionary = findFilepath([
6
+ export async function aggregateReactTranslations(options, settings, library) {
7
+ if (!options.dictionary) {
8
+ options.dictionary = findFilepath([
12
9
  './dictionary.js',
13
10
  './src/dictionary.js',
14
11
  './dictionary.json',
@@ -17,29 +14,16 @@ export async function stageProject(settings, pkg) {
17
14
  './src/dictionary.ts',
18
15
  ]);
19
16
  }
20
- // Separate defaultLocale from locales
21
- settings.locales = settings.locales.filter((locale) => locale !== settings.defaultLocale);
22
- // validate timeout
23
- const timeout = parseInt(settings.timeout);
24
- if (isNaN(timeout) || timeout < 0) {
25
- logErrorAndExit(`Invalid timeout: ${settings.timeout}. Must be a positive integer.`);
26
- }
27
- settings.timeout = timeout.toString();
28
17
  // ---- CREATING UPDATES ---- //
29
- const { updates, errors, warnings } = await createUpdates(settings, settings.dictionary, pkg, false);
18
+ const { updates, errors, warnings } = await createUpdates(options, options.dictionary, library, false);
30
19
  if (warnings.length > 0) {
31
- if (settings.suppressWarnings) {
32
- logWarning(chalk.yellow(`CLI tool encountered ${warnings.length} warnings while scanning for translatable content. ${chalk.gray('To view these warnings, re-run without the --suppress-warnings flag')}`));
33
- }
34
- else {
35
- logWarning(chalk.yellow(`CLI tool encountered ${warnings.length} warnings while scanning for translatable content. ${chalk.gray('To suppress these warnings, re-run with --suppress-warnings')}\n` +
36
- warnings
37
- .map((warning) => chalk.yellow('• Warning: ') + chalk.white(warning))
38
- .join('\n')));
39
- }
20
+ logWarning(chalk.yellow(`CLI tool encountered ${warnings.length} warnings while scanning for translatable content.\n` +
21
+ warnings
22
+ .map((warning) => chalk.yellow('• Warning: ') + chalk.white(warning))
23
+ .join('\n')));
40
24
  }
41
25
  if (errors.length > 0) {
42
- if (settings.ignoreErrors) {
26
+ if (options.ignoreErrors) {
43
27
  logWarning(chalk.yellow(`Warning: CLI tool encountered ${errors.length} syntax errors while scanning for translatable content. These components will not be translated.\n` +
44
28
  errors
45
29
  .map((error) => chalk.yellow('• ') + chalk.white(error) + '\n')
@@ -52,35 +36,9 @@ export async function stageProject(settings, pkg) {
52
36
  .join('')));
53
37
  }
54
38
  }
55
- if (settings.dryRun) {
56
- logSuccess('Dry run: No translations were sent to General Translation.');
57
- return null;
58
- }
59
39
  if (updates.length == 0) {
60
- logError(chalk.red(`No in-line content or dictionaries were found for ${chalk.green(pkg)}. Are you sure you're running this command in the right directory?`));
61
- return null;
62
- }
63
- // Send updates to General Translation API
64
- if (!settings.locales) {
65
- logErrorAndExit(noLocalesError);
66
- }
67
- if (!settings.defaultLocale) {
68
- logErrorAndExit(noDefaultLocaleError);
69
- }
70
- if (!settings.apiKey) {
71
- logErrorAndExit(noApiKeyError);
72
- }
73
- if (settings.apiKey.startsWith('gtx-dev-')) {
74
- logErrorAndExit(devApiKeyError);
75
- }
76
- if (!settings.projectId) {
77
- logErrorAndExit(noProjectIdError);
40
+ logError(chalk.red(`No in-line content or dictionaries were found for ${chalk.green(library)}. Are you sure you're running this command in the right directory?`));
41
+ return updates;
78
42
  }
79
- const updateResponse = await sendUpdates(updates, {
80
- ...settings,
81
- timeout: settings.timeout,
82
- dataFormat: 'JSX',
83
- }, pkg);
84
- const { versionId, locales } = updateResponse;
85
- return { versionId, locales };
43
+ return updates;
86
44
  }
@@ -0,0 +1 @@
1
+ export type FileMapping = Record<string, Record<string, string>>;
@@ -0,0 +1 @@
1
+ export {};
@@ -15,13 +15,35 @@ export type Options = {
15
15
  ignoreErrors: boolean;
16
16
  suppressWarnings: boolean;
17
17
  dryRun: boolean;
18
- timeout: string;
18
+ timeout: number;
19
19
  stageTranslations?: boolean;
20
20
  experimentalLocalizeStaticUrls?: boolean;
21
21
  experimentalHideDefaultLocale?: boolean;
22
22
  experimentalFlattenJsonFiles?: boolean;
23
23
  experimentalLocalizeStaticImports?: boolean;
24
24
  };
25
+ export type TranslateFlags = {
26
+ config?: string;
27
+ apiKey?: string;
28
+ projectId?: string;
29
+ versionId?: string;
30
+ jsconfig?: string;
31
+ dictionary?: string;
32
+ defaultLocale?: string;
33
+ locales?: string[];
34
+ ignoreErrors?: boolean;
35
+ src?: string[];
36
+ timeout: number;
37
+ dryRun: boolean;
38
+ stageTranslations?: boolean;
39
+ publish?: boolean;
40
+ experimentalLocalizeStaticUrls?: boolean;
41
+ experimentalHideDefaultLocale?: boolean;
42
+ experimentalFlattenJsonFiles?: boolean;
43
+ experimentalLocalizeStaticImports?: boolean;
44
+ excludeStaticUrls?: string[];
45
+ excludeStaticImports?: string[];
46
+ };
25
47
  export type WrapOptions = {
26
48
  src?: string[];
27
49
  config: string;
@@ -80,10 +102,11 @@ export type FilesOptions = {
80
102
  };
81
103
  export type Settings = {
82
104
  config: string;
105
+ configDirectory: string;
83
106
  baseUrl: string;
84
107
  dashboardUrl: string;
85
- apiKey: string;
86
- projectId: string;
108
+ apiKey?: string;
109
+ projectId?: string;
87
110
  defaultLocale: string;
88
111
  locales: string[];
89
112
  files: {
@@ -92,6 +115,7 @@ export type Settings = {
92
115
  transformPaths: TransformFiles;
93
116
  } | undefined;
94
117
  stageTranslations: boolean;
118
+ publish: boolean;
95
119
  _versionId?: string;
96
120
  version?: string;
97
121
  description?: string;
@@ -1,2 +1,2 @@
1
- import { Settings, Options } from '../types/index.js';
2
- export default function flattenJsonFiles(settings: Omit<Settings & Options, 'ignoreErrors' | 'suppressWarnings' | 'timeout'>): Promise<void>;
1
+ import { Settings } from '../types/index.js';
2
+ export default function flattenJsonFiles(settings: Settings): Promise<void>;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Hashes a string using SHA-256 algorithm.
3
+ * @param {string} string - The string to be hashed.
4
+ * @returns {string} The hashed string.
5
+ */
6
+ export declare function hashStringSync(string: string): string;
@@ -0,0 +1,11 @@
1
+ import crypto from 'crypto';
2
+ /**
3
+ * Hashes a string using SHA-256 algorithm.
4
+ * @param {string} string - The string to be hashed.
5
+ * @returns {string} The hashed string.
6
+ */
7
+ export function hashStringSync(string) {
8
+ const hash = crypto.createHash('sha256');
9
+ hash.update(string);
10
+ return hash.digest('hex');
11
+ }
@@ -1,4 +1,4 @@
1
- import { Options, Settings } from '../types/index.js';
1
+ import { Settings } from '../types/index.js';
2
2
  /**
3
3
  * Localizes static imports in content files.
4
4
  * Currently only supported for md and mdx files. (/docs/ -> /[locale]/docs/)
@@ -12,4 +12,4 @@ import { Options, Settings } from '../types/index.js';
12
12
  * - Support more file types
13
13
  * - Support more complex paths
14
14
  */
15
- export default function localizeStaticImports(settings: Omit<Settings & Options, 'ignoreErrors' | 'suppressWarnings' | 'timeout'>): Promise<void>;
15
+ export default function localizeStaticImports(settings: Settings): Promise<void>;
@@ -1,4 +1,4 @@
1
- import { Options, Settings } from '../types/index.js';
1
+ import { Settings } from '../types/index.js';
2
2
  /**
3
3
  * Localizes static urls in content files.
4
4
  * Currently only supported for md and mdx files. (/docs/ -> /[locale]/docs/)
@@ -12,7 +12,7 @@ import { Options, 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: Omit<Settings & Options, 'ignoreErrors' | 'suppressWarnings' | 'timeout'>, targetLocales?: string[]): Promise<void>;
15
+ export default function localizeStaticUrls(settings: Settings, targetLocales?: string[]): Promise<void>;
16
16
  /**
17
17
  * Main URL transformation function that delegates to specific scenarios
18
18
  */
@@ -7,7 +7,6 @@ import remarkMdx from 'remark-mdx';
7
7
  import remarkFrontmatter from 'remark-frontmatter';
8
8
  import remarkStringify from 'remark-stringify';
9
9
  import { visit } from 'unist-util-visit';
10
- import { logMessage } from '../console/logging.js';
11
10
  const { isMatch } = micromatch;
12
11
  /**
13
12
  * Localizes static urls in content files.
@@ -22,8 +21,7 @@ const { isMatch } = micromatch;
22
21
  * - Support more file types
23
22
  * - Support more complex paths
24
23
  */
25
- export default async function localizeStaticUrls(settings, targetLocales // Optional filter for specific locales
26
- ) {
24
+ export default async function localizeStaticUrls(settings, targetLocales) {
27
25
  if (!settings.files ||
28
26
  (Object.keys(settings.files.placeholderPaths).length === 1 &&
29
27
  settings.files.placeholderPaths.gt)) {
@@ -54,10 +52,12 @@ export default async function localizeStaticUrls(settings, targetLocales // Opti
54
52
  // Get file content
55
53
  const fileContent = await fs.promises.readFile(filePath, 'utf8');
56
54
  // Localize the file using default locale
57
- const localizedFile = localizeStaticUrlsForFile(fileContent, settings.defaultLocale, settings.defaultLocale, // Process as default locale
58
- settings.experimentalHideDefaultLocale || false, settings.options?.docsUrlPattern, settings.options?.excludeStaticUrls, settings.options?.baseDomain);
59
- // Write the localized file back to the same path
60
- await fs.promises.writeFile(filePath, localizedFile);
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
+ }
61
61
  }));
62
62
  processPromises.push(defaultPromise);
63
63
  }
@@ -73,9 +73,11 @@ export default async function localizeStaticUrls(settings, targetLocales // Opti
73
73
  // Get file content
74
74
  const fileContent = await fs.promises.readFile(filePath, 'utf8');
75
75
  // Localize the file (handles both URLs and hrefs in single AST pass)
76
- const localizedFile = localizeStaticUrlsForFile(fileContent, settings.defaultLocale, locale, settings.experimentalHideDefaultLocale || false, settings.options?.docsUrlPattern, settings.options?.excludeStaticUrls, settings.options?.baseDomain);
77
- // Write the localized file to the target path
78
- await fs.promises.writeFile(filePath, localizedFile);
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
+ }
79
81
  }));
80
82
  });
81
83
  processPromises.push(...mappingPromises);
@@ -245,10 +247,7 @@ function transformMdxUrls(mdxContent, defaultLocale, targetLocale, hideDefaultLo
245
247
  // Skip absolute URLs (http://, https://, //, etc.)
246
248
  if (baseDomain && shouldProcessAbsoluteUrl(originalUrl, baseDomain)) {
247
249
  // Get everything after the base domain
248
- logMessage(`originalUrl: ${originalUrl}`);
249
- logMessage(`baseDomain: ${baseDomain}`);
250
250
  const afterDomain = originalUrl.substring(baseDomain.length);
251
- logMessage(`afterDomain: ${afterDomain}`);
252
251
  const transformedPath = transformUrlPath(afterDomain, patternHead, targetLocale, defaultLocale, hideDefaultLocale);
253
252
  return transformedPath ? baseDomain + transformedPath : null;
254
253
  }
@@ -390,8 +389,7 @@ function transformMdxUrls(mdxContent, defaultLocale, targetLocale, hideDefaultLo
390
389
  function localizeStaticUrlsForFile(file, defaultLocale, targetLocale, hideDefaultLocale, pattern = '/[locale]', // eg /docs/[locale] or /[locale]
391
390
  exclude = [], baseDomain) {
392
391
  // Use AST-based transformation for MDX files
393
- const result = transformMdxUrls(file, defaultLocale, targetLocale, hideDefaultLocale, pattern, exclude, baseDomain || '');
394
- return result.content;
392
+ return transformMdxUrls(file, defaultLocale, targetLocale, hideDefaultLocale, pattern, exclude, baseDomain || '');
395
393
  }
396
394
  function cleanPath(path) {
397
395
  let cleanedPath = path.startsWith('/') ? path.slice(1) : path;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtx-cli",
3
- "version": "2.1.5-alpha.5",
3
+ "version": "2.1.5-alpha.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.0",
90
+ "generaltranslation": "^7.4.1-alpha.2",
91
91
  "json-pointer": "^0.6.2",
92
92
  "jsonpath-plus": "^10.3.0",
93
93
  "jsonpointer": "^5.0.1",
@@ -1,9 +0,0 @@
1
- import { Settings } from '../types/index.js';
2
- /**
3
- * Downloads a file from the API and saves it to a local directory
4
- * @param translationId - The ID of the translation to download
5
- * @param outputPath - The path to save the file to
6
- * @param maxRetries - The maximum number of retries to attempt
7
- * @param retryDelay - The delay between retries in milliseconds
8
- */
9
- export declare function downloadFile(translationId: string, outputPath: string, inputPath: string, locale: string, options: Settings, maxRetries?: number, retryDelay?: number): Promise<boolean>;
@@ -1,74 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
- import { logError } from '../console/logging.js';
4
- import { gt } from '../utils/gt.js';
5
- import { validateJsonSchema } from '../formats/json/utils.js';
6
- import { mergeJson } from '../formats/json/mergeJson.js';
7
- import { TextDecoder } from 'node:util';
8
- import mergeYaml from '../formats/yaml/mergeYaml.js';
9
- import { validateYamlSchema } from '../formats/yaml/utils.js';
10
- /**
11
- * Downloads a file from the API and saves it to a local directory
12
- * @param translationId - The ID of the translation to download
13
- * @param outputPath - The path to save the file to
14
- * @param maxRetries - The maximum number of retries to attempt
15
- * @param retryDelay - The delay between retries in milliseconds
16
- */
17
- export async function downloadFile(translationId, outputPath, inputPath, locale, options, maxRetries = 3, retryDelay = 1000) {
18
- let retries = 0;
19
- while (retries <= maxRetries) {
20
- try {
21
- // Get the file data as an ArrayBuffer
22
- const fileData = await gt.downloadFile(translationId);
23
- // Ensure the directory exists
24
- const dir = path.dirname(outputPath);
25
- if (!fs.existsSync(dir)) {
26
- fs.mkdirSync(dir, { recursive: true });
27
- }
28
- let data = new TextDecoder().decode(fileData);
29
- if (options.options?.jsonSchema && locale) {
30
- const jsonSchema = validateJsonSchema(options.options, inputPath);
31
- if (jsonSchema) {
32
- const originalContent = fs.readFileSync(inputPath, 'utf8');
33
- if (originalContent) {
34
- data = mergeJson(originalContent, inputPath, options.options, [
35
- {
36
- translatedContent: data,
37
- targetLocale: locale,
38
- },
39
- ], options.defaultLocale)[0];
40
- }
41
- }
42
- }
43
- if (options.options?.yamlSchema && locale) {
44
- const yamlSchema = validateYamlSchema(options.options, inputPath);
45
- if (yamlSchema) {
46
- const originalContent = fs.readFileSync(inputPath, 'utf8');
47
- if (originalContent) {
48
- data = mergeYaml(originalContent, inputPath, options.options, [
49
- {
50
- translatedContent: data,
51
- targetLocale: locale,
52
- },
53
- ])[0];
54
- }
55
- }
56
- }
57
- // Write the file to disk
58
- await fs.promises.writeFile(outputPath, data);
59
- return true;
60
- }
61
- catch (error) {
62
- // If we've retried too many times, log an error and return false
63
- if (retries >= maxRetries) {
64
- logError(`Error downloading file ${outputPath} after ${maxRetries + 1} attempts: ` +
65
- error);
66
- return false;
67
- }
68
- // Increment retry counter and wait before next attempt
69
- retries++;
70
- await new Promise((resolve) => setTimeout(resolve, retryDelay));
71
- }
72
- }
73
- return false;
74
- }