gtx-cli 2.3.6-alpha.2 → 2.3.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 (192) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/api/checkFileTranslations.d.ts +23 -0
  3. package/dist/api/checkFileTranslations.js +236 -0
  4. package/dist/api/downloadFileBatch.d.ts +20 -0
  5. package/dist/api/downloadFileBatch.js +113 -0
  6. package/dist/api/sendFiles.d.ts +17 -0
  7. package/dist/api/sendFiles.js +115 -0
  8. package/dist/api/uploadFiles.d.ts +27 -0
  9. package/dist/api/uploadFiles.js +40 -0
  10. package/dist/cli/base.d.ts +32 -0
  11. package/dist/cli/base.js +335 -0
  12. package/dist/cli/commands/stage.d.ts +5 -0
  13. package/dist/cli/commands/stage.js +100 -0
  14. package/dist/cli/commands/translate.d.ts +6 -0
  15. package/dist/cli/commands/translate.js +63 -0
  16. package/dist/cli/flags.d.ts +3 -0
  17. package/dist/cli/flags.js +38 -0
  18. package/dist/cli/next.d.ts +11 -0
  19. package/dist/cli/next.js +20 -0
  20. package/dist/cli/react.d.ts +18 -0
  21. package/dist/cli/react.js +175 -0
  22. package/dist/config/generateSettings.d.ts +9 -0
  23. package/dist/config/generateSettings.js +176 -0
  24. package/dist/config/optionPresets.d.ts +2 -0
  25. package/dist/config/optionPresets.js +56 -0
  26. package/dist/config/resolveConfig.d.ts +4 -0
  27. package/dist/config/resolveConfig.js +19 -0
  28. package/dist/config/utils.d.ts +2 -0
  29. package/dist/config/utils.js +4 -0
  30. package/dist/config/validateSettings.d.ts +3 -0
  31. package/dist/config/validateSettings.js +32 -0
  32. package/dist/console/colors.d.ts +5 -0
  33. package/dist/console/colors.js +16 -0
  34. package/dist/console/index.d.ts +21 -0
  35. package/dist/console/index.js +24 -0
  36. package/dist/console/logging.d.ts +53 -0
  37. package/dist/console/logging.js +185 -0
  38. package/dist/formats/files/fileMapping.d.ts +11 -0
  39. package/dist/formats/files/fileMapping.js +82 -0
  40. package/dist/formats/files/save.d.ts +5 -0
  41. package/dist/formats/files/save.js +17 -0
  42. package/dist/formats/files/supportedFiles.d.ts +10 -0
  43. package/dist/formats/files/supportedFiles.js +18 -0
  44. package/dist/formats/files/translate.d.ts +4 -0
  45. package/dist/formats/files/translate.js +119 -0
  46. package/dist/formats/files/upload.d.ts +13 -0
  47. package/dist/formats/files/upload.js +136 -0
  48. package/dist/formats/gt/save.d.ts +9 -0
  49. package/dist/formats/gt/save.js +26 -0
  50. package/dist/formats/json/flattenJson.d.ts +14 -0
  51. package/dist/formats/json/flattenJson.js +64 -0
  52. package/dist/formats/json/mergeJson.d.ts +13 -0
  53. package/dist/formats/json/mergeJson.js +257 -0
  54. package/dist/formats/json/parseJson.d.ts +2 -0
  55. package/dist/formats/json/parseJson.js +108 -0
  56. package/dist/formats/json/utils.d.ts +47 -0
  57. package/dist/formats/json/utils.js +149 -0
  58. package/dist/formats/utils.d.ts +2 -0
  59. package/dist/formats/utils.js +24 -0
  60. package/dist/formats/yaml/mergeYaml.d.ts +5 -0
  61. package/dist/formats/yaml/mergeYaml.js +55 -0
  62. package/dist/formats/yaml/parseYaml.d.ts +5 -0
  63. package/dist/formats/yaml/parseYaml.js +23 -0
  64. package/dist/formats/yaml/utils.d.ts +2 -0
  65. package/dist/formats/yaml/utils.js +22 -0
  66. package/dist/fs/config/loadConfig.d.ts +1 -0
  67. package/dist/fs/config/loadConfig.js +9 -0
  68. package/dist/fs/config/parseFilesConfig.d.ts +27 -0
  69. package/dist/fs/config/parseFilesConfig.js +129 -0
  70. package/dist/fs/config/setupConfig.d.ts +17 -0
  71. package/dist/fs/config/setupConfig.js +50 -0
  72. package/dist/fs/config/updateConfig.d.ts +10 -0
  73. package/dist/fs/config/updateConfig.js +36 -0
  74. package/dist/fs/config/updateVersions.d.ts +10 -0
  75. package/dist/fs/config/updateVersions.js +30 -0
  76. package/dist/fs/copyFile.d.ts +7 -0
  77. package/dist/fs/copyFile.js +39 -0
  78. package/dist/fs/createLoadTranslationsFile.d.ts +1 -0
  79. package/dist/fs/createLoadTranslationsFile.js +36 -0
  80. package/dist/fs/determineFramework.d.ts +5 -0
  81. package/dist/fs/determineFramework.js +46 -0
  82. package/dist/fs/findFilepath.d.ts +36 -0
  83. package/dist/fs/findFilepath.js +89 -0
  84. package/dist/fs/getPackageResource.d.ts +1 -0
  85. package/dist/fs/getPackageResource.js +6 -0
  86. package/dist/fs/index.d.ts +1 -0
  87. package/dist/fs/index.js +1 -0
  88. package/dist/fs/loadJSON.d.ts +6 -0
  89. package/dist/fs/loadJSON.js +17 -0
  90. package/dist/fs/matchFiles.d.ts +1 -0
  91. package/dist/fs/matchFiles.js +8 -0
  92. package/dist/fs/saveJSON.d.ts +1 -0
  93. package/dist/fs/saveJSON.js +7 -0
  94. package/dist/fs/utils.d.ts +1 -0
  95. package/dist/fs/utils.js +16 -0
  96. package/dist/hooks/postProcess.d.ts +4 -0
  97. package/dist/hooks/postProcess.js +110 -0
  98. package/dist/index.d.ts +4 -0
  99. package/dist/index.js +20 -0
  100. package/dist/main.d.ts +2 -0
  101. package/dist/main.js +9 -0
  102. package/dist/next/config/parseNextConfig.d.ts +10 -0
  103. package/dist/next/config/parseNextConfig.js +53 -0
  104. package/dist/next/jsx/utils.d.ts +7 -0
  105. package/dist/next/jsx/utils.js +42 -0
  106. package/dist/next/parse/handleInitGT.d.ts +7 -0
  107. package/dist/next/parse/handleInitGT.js +208 -0
  108. package/dist/next/parse/wrapContent.d.ts +11 -0
  109. package/dist/next/parse/wrapContent.js +163 -0
  110. package/dist/react/config/createESBuildConfig.d.ts +2 -0
  111. package/dist/react/config/createESBuildConfig.js +119 -0
  112. package/dist/react/data-_gt/addGTIdentifierToSyntaxTree.d.ts +8 -0
  113. package/dist/react/data-_gt/addGTIdentifierToSyntaxTree.js +111 -0
  114. package/dist/react/jsx/evaluateJsx.d.ts +17 -0
  115. package/dist/react/jsx/evaluateJsx.js +85 -0
  116. package/dist/react/jsx/trimJsxStringChildren.d.ts +7 -0
  117. package/dist/react/jsx/trimJsxStringChildren.js +95 -0
  118. package/dist/react/jsx/utils/constants.d.ts +10 -0
  119. package/dist/react/jsx/utils/constants.js +31 -0
  120. package/dist/react/jsx/utils/parseAst.d.ts +30 -0
  121. package/dist/react/jsx/utils/parseAst.js +277 -0
  122. package/dist/react/jsx/utils/parseJsx.d.ts +21 -0
  123. package/dist/react/jsx/utils/parseJsx.js +244 -0
  124. package/dist/react/jsx/utils/parseStringFunction.d.ts +16 -0
  125. package/dist/react/jsx/utils/parseStringFunction.js +411 -0
  126. package/dist/react/jsx/utils/validateStringFunction.d.ts +7 -0
  127. package/dist/react/jsx/utils/validateStringFunction.js +31 -0
  128. package/dist/react/jsx/wrapJsx.d.ts +51 -0
  129. package/dist/react/jsx/wrapJsx.js +387 -0
  130. package/dist/react/parse/createDictionaryUpdates.d.ts +3 -0
  131. package/dist/react/parse/createDictionaryUpdates.js +169 -0
  132. package/dist/react/parse/createInlineUpdates.d.ts +6 -0
  133. package/dist/react/parse/createInlineUpdates.js +122 -0
  134. package/dist/react/parse/wrapContent.d.ts +11 -0
  135. package/dist/react/parse/wrapContent.js +162 -0
  136. package/dist/react/utils/flattenDictionary.d.ts +20 -0
  137. package/dist/react/utils/flattenDictionary.js +75 -0
  138. package/dist/react/utils/getEntryAndMetadata.d.ts +5 -0
  139. package/dist/react/utils/getEntryAndMetadata.js +11 -0
  140. package/dist/react/utils/getVariableName.d.ts +25 -0
  141. package/dist/react/utils/getVariableName.js +37 -0
  142. package/dist/setup/userInput.d.ts +4 -0
  143. package/dist/setup/userInput.js +29 -0
  144. package/dist/setup/wizard.d.ts +2 -0
  145. package/dist/setup/wizard.js +127 -0
  146. package/dist/translation/parse.d.ts +15 -0
  147. package/dist/translation/parse.js +76 -0
  148. package/dist/translation/stage.d.ts +2 -0
  149. package/dist/translation/stage.js +44 -0
  150. package/dist/translation/validate.d.ts +2 -0
  151. package/dist/translation/validate.js +50 -0
  152. package/dist/types/data/json.d.ts +6 -0
  153. package/dist/types/data/json.js +1 -0
  154. package/dist/types/data.d.ts +30 -0
  155. package/dist/types/data.js +1 -0
  156. package/dist/types/files.d.ts +1 -0
  157. package/dist/types/files.js +1 -0
  158. package/dist/types/index.d.ts +173 -0
  159. package/dist/types/index.js +1 -0
  160. package/dist/utils/addExplicitAnchorIds.d.ts +24 -0
  161. package/dist/utils/addExplicitAnchorIds.js +260 -0
  162. package/dist/utils/constants.d.ts +2 -0
  163. package/dist/utils/constants.js +2 -0
  164. package/dist/utils/credentials.d.ts +12 -0
  165. package/dist/utils/credentials.js +119 -0
  166. package/dist/utils/flattenJsonFiles.d.ts +2 -0
  167. package/dist/utils/flattenJsonFiles.js +36 -0
  168. package/dist/utils/gt.d.ts +2 -0
  169. package/dist/utils/gt.js +2 -0
  170. package/dist/utils/hash.d.ts +6 -0
  171. package/dist/utils/hash.js +11 -0
  172. package/dist/utils/headers.d.ts +1 -0
  173. package/dist/utils/headers.js +14 -0
  174. package/dist/utils/installPackage.d.ts +3 -0
  175. package/dist/utils/installPackage.js +77 -0
  176. package/dist/utils/localizeStaticImports.d.ts +15 -0
  177. package/dist/utils/localizeStaticImports.js +341 -0
  178. package/dist/utils/localizeStaticUrls.d.ts +19 -0
  179. package/dist/utils/localizeStaticUrls.js +432 -0
  180. package/dist/utils/packageInfo.d.ts +3 -0
  181. package/dist/utils/packageInfo.js +17 -0
  182. package/dist/utils/packageJson.d.ts +6 -0
  183. package/dist/utils/packageJson.js +76 -0
  184. package/dist/utils/packageManager.d.ts +28 -0
  185. package/dist/utils/packageManager.js +269 -0
  186. package/dist/utils/processAnchorIds.d.ts +6 -0
  187. package/dist/utils/processAnchorIds.js +47 -0
  188. package/dist/utils/sanitizeFileContent.d.ts +6 -0
  189. package/dist/utils/sanitizeFileContent.js +29 -0
  190. package/dist/utils/validateMdx.d.ts +10 -0
  191. package/dist/utils/validateMdx.js +25 -0
  192. package/package.json +3 -3
@@ -0,0 +1,185 @@
1
+ import { log, spinner, intro, outro, text, select, confirm, isCancel, cancel, multiselect, } from '@clack/prompts';
2
+ import chalk from 'chalk';
3
+ import { getCLIVersion } from '../utils/packageJson.js';
4
+ // Basic logging functions
5
+ export function logInfo(message) {
6
+ log.info(message);
7
+ }
8
+ export function logWarning(message) {
9
+ log.warn(message);
10
+ }
11
+ export function logError(message) {
12
+ log.error(message);
13
+ }
14
+ export function logSuccess(message) {
15
+ log.success(message);
16
+ }
17
+ export function logStep(message) {
18
+ log.step(message);
19
+ }
20
+ export function logMessage(message) {
21
+ log.message(message, { symbol: chalk.cyan('~') });
22
+ }
23
+ export function logErrorAndExit(message) {
24
+ log.error(message);
25
+ exit(1);
26
+ }
27
+ export function exit(code) {
28
+ process.exit(code);
29
+ }
30
+ // Clack prompts
31
+ export function startCommand(message) {
32
+ intro(chalk.cyan(message));
33
+ }
34
+ export function endCommand(message) {
35
+ outro(chalk.cyan(message));
36
+ }
37
+ // GT specific logging
38
+ export function displayHeader(introString) {
39
+ displayAsciiTitle();
40
+ displayInitializingText();
41
+ if (introString) {
42
+ startCommand(introString);
43
+ }
44
+ }
45
+ function displayAsciiTitle() {
46
+ console.log(chalk.cyan(`\n ,ad8888ba, 888888888888
47
+ d8"' \`"8b 88
48
+ d8' 88
49
+ 88 88
50
+ 88 88888 88
51
+ Y8, 88 88
52
+ Y8a. .a88 88
53
+ \`"Y88888P" 88 `));
54
+ }
55
+ function displayInitializingText() {
56
+ const version = getCLIVersion();
57
+ console.log(`\n${chalk.bold.blue('General Translation, Inc.')}
58
+ ${chalk.dim('https://generaltranslation.com/docs')}
59
+ ${chalk.dim(`CLI Version: ${version}\n`)}`);
60
+ }
61
+ export function displayProjectId(projectId) {
62
+ logMessage(chalk.dim(`Project ID: ${chalk.bold(projectId)}`));
63
+ }
64
+ export function displayResolvedPaths(resolvedPaths) {
65
+ const paths = resolvedPaths.map(([key, resolvedPath]) => {
66
+ return chalk.dim(`'${chalk.white(key)}' → '${chalk.green(resolvedPath)}'`);
67
+ });
68
+ log.step(`Resolved path aliases:\n${paths.join('\n')}`);
69
+ }
70
+ export function displayCreatedConfigFile(configFilepath) {
71
+ log.step(`Created config file ${chalk.cyan(configFilepath)}`);
72
+ }
73
+ export function displayUpdatedConfigFile(configFilepath) {
74
+ log.success(`Updated config file ${chalk.cyan(configFilepath)}`);
75
+ }
76
+ export function displayUpdatedVersionsFile(versionFilepath) {
77
+ log.success(`Updated versions file ${chalk.cyan(versionFilepath)}`);
78
+ }
79
+ // Spinner functionality
80
+ export function createSpinner(indicator = 'timer') {
81
+ return spinner({ indicator });
82
+ }
83
+ // Spinner functionality
84
+ export async function createOraSpinner(indicator = 'circleHalves') {
85
+ const ora = await import('ora');
86
+ return ora.default({ spinner: indicator });
87
+ }
88
+ // Input prompts
89
+ export async function promptText({ message, defaultValue, validate, }) {
90
+ const result = await text({
91
+ message,
92
+ placeholder: defaultValue,
93
+ validate: validate
94
+ ? (value) => {
95
+ const validation = validate(value || '');
96
+ return validation === true ? undefined : validation.toString();
97
+ }
98
+ : undefined,
99
+ });
100
+ if (isCancel(result)) {
101
+ cancel('Operation cancelled');
102
+ process.exit(0);
103
+ }
104
+ return result;
105
+ }
106
+ export async function promptSelect({ message, options, defaultValue, }) {
107
+ // Convert options to the format expected by clack
108
+ const clackOptions = options.map((opt) => ({
109
+ value: opt.value,
110
+ label: opt.label,
111
+ hint: opt.hint,
112
+ }));
113
+ const result = await select({
114
+ message,
115
+ options: clackOptions,
116
+ initialValue: defaultValue,
117
+ });
118
+ if (isCancel(result)) {
119
+ cancel('Operation cancelled');
120
+ process.exit(0);
121
+ }
122
+ return result;
123
+ }
124
+ export async function promptMultiSelect({ message, options, required = true, }) {
125
+ // Convert options to the format expected by clack
126
+ const clackOptions = options.map((opt) => ({
127
+ value: opt.value,
128
+ label: opt.label,
129
+ hint: opt.hint,
130
+ }));
131
+ const result = await multiselect({
132
+ message,
133
+ options: clackOptions,
134
+ required,
135
+ });
136
+ if (isCancel(result)) {
137
+ cancel('Operation cancelled');
138
+ process.exit(0);
139
+ }
140
+ return result;
141
+ }
142
+ export async function promptConfirm({ message, defaultValue = true, cancelMessage = 'Operation cancelled', }) {
143
+ const result = await confirm({
144
+ message,
145
+ initialValue: defaultValue,
146
+ });
147
+ if (isCancel(result)) {
148
+ cancel(cancelMessage);
149
+ process.exit(0);
150
+ }
151
+ return result;
152
+ }
153
+ // Warning display functions
154
+ export function warnApiKeyInConfig(optionsFilepath) {
155
+ log.warn(`Found ${chalk.cyan('apiKey')} in "${chalk.green(optionsFilepath)}". ` +
156
+ chalk.white('Your API key is exposed! Please remove it from the file and include it as an environment variable.'));
157
+ }
158
+ export function warnVariableProp(file, attrName, value) {
159
+ log.warn(`Found ${chalk.green('<T>')} component in ${chalk.cyan(file)} with variable ${attrName}: "${chalk.white(value)}". ` +
160
+ `Change "${attrName}" to ensure this content is translated.`);
161
+ }
162
+ export function warnNoId(file) {
163
+ log.warn(`Found ${chalk.green('<T>')} component in ${chalk.cyan(file)} with no id. ` +
164
+ chalk.white('Add an id to ensure the content is translated.'));
165
+ }
166
+ export function warnHasUnwrappedExpression(file, id, unwrappedExpressions) {
167
+ log.warn(`${chalk.green('<T>')} with id "${id}" in ${chalk.cyan(file)} has children: ${unwrappedExpressions.join(', ')} that could change at runtime. ` +
168
+ chalk.white('Use a variable component like ') +
169
+ chalk.green('<Var>') +
170
+ chalk.white(' (') +
171
+ chalk.blue('https://generaltranslation.com/docs') +
172
+ chalk.white(') to translate this properly.'));
173
+ }
174
+ export function warnNonStaticExpression(file, attrName, value) {
175
+ log.warn(`Found non-static expression in ${chalk.cyan(file)} for attribute ${attrName}: "${chalk.white(value)}". ` +
176
+ `Change "${attrName}" to ensure this content is translated.`);
177
+ }
178
+ export function warnTemplateLiteral(file, value) {
179
+ log.warn(`Found template literal with quasis (${value}) in ${chalk.cyan(file)}. ` +
180
+ chalk.white('Change the template literal to a string to ensure this content is translated.'));
181
+ }
182
+ export function warnTernary(file) {
183
+ log.warn(`Found ternary expression in ${chalk.cyan(file)}. ` +
184
+ chalk.white('A Branch component may be more appropriate here.'));
185
+ }
@@ -0,0 +1,11 @@
1
+ import { ResolvedFiles, TransformFiles } from '../../types/index.js';
2
+ import { FileMapping } from '../../types/files.js';
3
+ /**
4
+ * Creates a mapping between source files and their translated counterparts for each locale
5
+ * @param filePaths - Resolved file paths for different file types
6
+ * @param placeholderPaths - Placeholder paths for translated files
7
+ * @param transformPaths - Transform paths for file naming
8
+ * @param locales - List of locales to create a mapping for
9
+ * @returns A mapping between source files and their translated counterparts for each locale, in the form of relative paths
10
+ */
11
+ export declare function createFileMapping(filePaths: ResolvedFiles, placeholderPaths: ResolvedFiles, transformPaths: TransformFiles, targetLocales: string[], defaultLocale: string): FileMapping;
@@ -0,0 +1,82 @@
1
+ import { SUPPORTED_FILE_EXTENSIONS } from '../files/supportedFiles.js';
2
+ import { resolveLocaleFiles } from '../../fs/config/parseFilesConfig.js';
3
+ import path from 'node:path';
4
+ import { getRelative } from '../../fs/findFilepath.js';
5
+ import { getLocaleProperties } from 'generaltranslation';
6
+ import { replaceLocalePlaceholders } from '../utils.js';
7
+ import { TEMPLATE_FILE_NAME } from '../../cli/commands/stage.js';
8
+ /**
9
+ * Creates a mapping between source files and their translated counterparts for each locale
10
+ * @param filePaths - Resolved file paths for different file types
11
+ * @param placeholderPaths - Placeholder paths for translated files
12
+ * @param transformPaths - Transform paths for file naming
13
+ * @param locales - List of locales to create a mapping for
14
+ * @returns A mapping between source files and their translated counterparts for each locale, in the form of relative paths
15
+ */
16
+ export function createFileMapping(filePaths, placeholderPaths, transformPaths, targetLocales, defaultLocale) {
17
+ const fileMapping = {};
18
+ for (const locale of targetLocales) {
19
+ const translatedPaths = resolveLocaleFiles(placeholderPaths, locale);
20
+ const localeMapping = {};
21
+ // Process each file type
22
+ // Start with GTJSON Template files
23
+ if (translatedPaths.gt) {
24
+ const filepath = translatedPaths.gt;
25
+ localeMapping[TEMPLATE_FILE_NAME] = filepath;
26
+ }
27
+ for (const typeIndex of SUPPORTED_FILE_EXTENSIONS) {
28
+ if (!filePaths[typeIndex] || !translatedPaths[typeIndex])
29
+ continue;
30
+ const sourcePaths = filePaths[typeIndex];
31
+ let translatedFiles = translatedPaths[typeIndex];
32
+ if (!translatedFiles)
33
+ continue;
34
+ const transformPath = transformPaths[typeIndex];
35
+ if (transformPath) {
36
+ if (typeof transformPath === 'string') {
37
+ translatedFiles = translatedFiles.map((filePath) => {
38
+ const directory = path.dirname(filePath);
39
+ const fileName = path.basename(filePath);
40
+ const baseName = fileName.split('.')[0];
41
+ const transformedFileName = transformPath
42
+ .replace('*', baseName)
43
+ .replace('[locale]', locale);
44
+ return path.join(directory, transformedFileName);
45
+ });
46
+ }
47
+ else {
48
+ // transformPath is an object
49
+ const targetLocaleProperties = getLocaleProperties(locale);
50
+ const defaultLocaleProperties = getLocaleProperties(defaultLocale);
51
+ if (!transformPath.replace ||
52
+ typeof transformPath.replace !== 'string') {
53
+ continue;
54
+ }
55
+ // Replace all locale property placeholders
56
+ const replaceString = replaceLocalePlaceholders(transformPath.replace, targetLocaleProperties);
57
+ translatedFiles = translatedFiles.map((filePath) => {
58
+ let relativePath = getRelative(filePath);
59
+ if (transformPath.match &&
60
+ typeof transformPath.match === 'string') {
61
+ // Replace locale placeholders in the match string using defaultLocale properties
62
+ let matchString = transformPath.match;
63
+ matchString = replaceLocalePlaceholders(matchString, defaultLocaleProperties);
64
+ relativePath = relativePath.replace(new RegExp(matchString, 'g'), replaceString);
65
+ }
66
+ else {
67
+ relativePath = replaceString;
68
+ }
69
+ return path.resolve(relativePath);
70
+ });
71
+ }
72
+ }
73
+ for (let i = 0; i < sourcePaths.length; i++) {
74
+ const sourceFile = getRelative(sourcePaths[i]);
75
+ const translatedFile = getRelative(translatedFiles[i]);
76
+ localeMapping[sourceFile] = translatedFile;
77
+ }
78
+ }
79
+ fileMapping[locale] = localeMapping;
80
+ }
81
+ return fileMapping;
82
+ }
@@ -0,0 +1,5 @@
1
+ import { DataFormat } from '../../types/data.js';
2
+ /**
3
+ * Saves translated MDX/MD file content to the appropriate location
4
+ */
5
+ export declare function saveTranslatedFile(translatedContent: string, outputDir: string, fileName: string, dataFormat: DataFormat, locales: string[]): Promise<void>;
@@ -0,0 +1,17 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'node:path';
3
+ import { logSuccess } from '../../console/logging.js';
4
+ /**
5
+ * Saves translated MDX/MD file content to the appropriate location
6
+ */
7
+ export async function saveTranslatedFile(translatedContent, outputDir, fileName, dataFormat, locales) {
8
+ // Create locale-specific directories if they don't exist
9
+ for (const locale of locales) {
10
+ const localeDir = path.join(outputDir, locale);
11
+ await fs.mkdir(localeDir, { recursive: true });
12
+ // Save the translated file with the appropriate extension
13
+ const outputPath = path.join(localeDir, fileName);
14
+ await fs.writeFile(outputPath, translatedContent);
15
+ logSuccess(`Saved translated ${dataFormat} file to: ${outputPath}`);
16
+ }
17
+ }
@@ -0,0 +1,10 @@
1
+ export declare const SUPPORTED_FILE_EXTENSIONS: readonly ["json", "mdx", "md", "ts", "js", "yaml", "html"];
2
+ export declare const FILE_EXT_TO_EXT_LABEL: {
3
+ json: string;
4
+ mdx: string;
5
+ md: string;
6
+ ts: string;
7
+ js: string;
8
+ yaml: string;
9
+ html: string;
10
+ };
@@ -0,0 +1,18 @@
1
+ export const SUPPORTED_FILE_EXTENSIONS = [
2
+ 'json',
3
+ 'mdx',
4
+ 'md',
5
+ 'ts',
6
+ 'js',
7
+ 'yaml',
8
+ 'html',
9
+ ];
10
+ export const FILE_EXT_TO_EXT_LABEL = {
11
+ json: 'JSON',
12
+ mdx: 'MDX',
13
+ md: 'Markdown',
14
+ ts: 'TypeScript',
15
+ js: 'JavaScript',
16
+ yaml: 'YAML',
17
+ html: 'HTML',
18
+ };
@@ -0,0 +1,4 @@
1
+ import { Settings } from '../../types/index.js';
2
+ import { FileToTranslate } from '../../types/data.js';
3
+ export declare const SUPPORTED_DATA_FORMATS: string[];
4
+ export declare function aggregateFiles(settings: Settings): Promise<FileToTranslate[]>;
@@ -0,0 +1,119 @@
1
+ import { logError, logWarning } from '../../console/logging.js';
2
+ import { getRelative, readFile } from '../../fs/findFilepath.js';
3
+ import { SUPPORTED_FILE_EXTENSIONS } from './supportedFiles.js';
4
+ import sanitizeFileContent from '../../utils/sanitizeFileContent.js';
5
+ import { parseJson } from '../json/parseJson.js';
6
+ import parseYaml from '../yaml/parseYaml.js';
7
+ import { determineLibrary } from '../../fs/determineFramework.js';
8
+ import { isValidMdx } from '../../utils/validateMdx.js';
9
+ export const SUPPORTED_DATA_FORMATS = ['JSX', 'ICU', 'I18NEXT'];
10
+ export async function aggregateFiles(settings) {
11
+ // Aggregate all files to translate
12
+ const allFiles = [];
13
+ if (!settings.files ||
14
+ (Object.keys(settings.files.placeholderPaths).length === 1 &&
15
+ settings.files.placeholderPaths.gt)) {
16
+ return allFiles;
17
+ }
18
+ const { resolvedPaths: filePaths } = settings.files;
19
+ // Process JSON files
20
+ if (filePaths.json) {
21
+ const { library, additionalModules } = determineLibrary();
22
+ // Determine dataFormat for JSONs
23
+ let dataFormat;
24
+ if (library === 'next-intl') {
25
+ dataFormat = 'ICU';
26
+ }
27
+ else if (library === 'i18next') {
28
+ if (additionalModules.includes('i18next-icu')) {
29
+ dataFormat = 'ICU';
30
+ }
31
+ else {
32
+ dataFormat = 'I18NEXT';
33
+ }
34
+ }
35
+ else {
36
+ dataFormat = 'JSX';
37
+ }
38
+ const jsonFiles = filePaths.json
39
+ .map((filePath) => {
40
+ const content = readFile(filePath);
41
+ const relativePath = getRelative(filePath);
42
+ const parsedJson = parseJson(content, filePath, settings.options || {}, settings.defaultLocale);
43
+ return {
44
+ content: parsedJson,
45
+ fileName: relativePath,
46
+ fileFormat: 'JSON',
47
+ dataFormat,
48
+ };
49
+ })
50
+ .filter((file) => {
51
+ if (!file || typeof file.content !== 'string' || !file.content.trim()) {
52
+ logWarning(`Skipping ${file?.fileName ?? 'unknown'}: JSON file is empty`);
53
+ return false;
54
+ }
55
+ return true;
56
+ });
57
+ allFiles.push(...jsonFiles);
58
+ }
59
+ // Process YAML files
60
+ if (filePaths.yaml) {
61
+ const yamlFiles = filePaths.yaml
62
+ .map((filePath) => {
63
+ const content = readFile(filePath);
64
+ const relativePath = getRelative(filePath);
65
+ const { content: parsedYaml, fileFormat } = parseYaml(content, filePath, settings.options || {});
66
+ return {
67
+ content: parsedYaml,
68
+ fileName: relativePath,
69
+ fileFormat,
70
+ };
71
+ })
72
+ .filter((file) => {
73
+ if (!file || typeof file.content !== 'string' || !file.content.trim()) {
74
+ logWarning(`Skipping ${file?.fileName ?? 'unknown'}: YAML file is empty`);
75
+ return false;
76
+ }
77
+ return true;
78
+ });
79
+ allFiles.push(...yamlFiles);
80
+ }
81
+ for (const fileType of SUPPORTED_FILE_EXTENSIONS) {
82
+ if (fileType === 'json' || fileType === 'yaml')
83
+ continue;
84
+ if (filePaths[fileType]) {
85
+ const files = filePaths[fileType]
86
+ .map((filePath) => {
87
+ const content = readFile(filePath);
88
+ const relativePath = getRelative(filePath);
89
+ if (fileType === 'mdx') {
90
+ const validation = isValidMdx(content, filePath);
91
+ if (!validation.isValid) {
92
+ logWarning(`Skipping ${relativePath}: MDX file is not AST parsable${validation.error ? `: ${validation.error}` : ''}`);
93
+ return null;
94
+ }
95
+ }
96
+ const sanitizedContent = sanitizeFileContent(content);
97
+ return {
98
+ content: sanitizedContent,
99
+ fileName: relativePath,
100
+ fileFormat: fileType.toUpperCase(),
101
+ };
102
+ })
103
+ .filter((file) => {
104
+ if (!file ||
105
+ typeof file.content !== 'string' ||
106
+ !file.content.trim()) {
107
+ logWarning(`Skipping ${file?.fileName ?? 'unknown'}: File is empty after sanitization`);
108
+ return false;
109
+ }
110
+ return true;
111
+ });
112
+ allFiles.push(...files);
113
+ }
114
+ }
115
+ if (allFiles.length === 0) {
116
+ logError('No files to translate were found. Please check your configuration and try again.');
117
+ }
118
+ return allFiles;
119
+ }
@@ -0,0 +1,13 @@
1
+ import { ResolvedFiles, Settings, TransformFiles } from '../../types/index.js';
2
+ import { DataFormat } from '../../types/data.js';
3
+ import { UploadOptions } from '../../cli/base.js';
4
+ /**
5
+ * Sends multiple files to the API for translation
6
+ * @param filePaths - Resolved file paths for different file types
7
+ * @param placeholderPaths - Placeholder paths for translated files
8
+ * @param transformPaths - Transform paths for file naming
9
+ * @param dataFormat - Format of the data within the files
10
+ * @param options - Translation options including API settings
11
+ * @returns Promise that resolves when translation is complete
12
+ */
13
+ export declare function upload(filePaths: ResolvedFiles, placeholderPaths: ResolvedFiles, transformPaths: TransformFiles, dataFormat: DataFormat | undefined, options: Settings & UploadOptions): Promise<void>;
@@ -0,0 +1,136 @@
1
+ import { noSupportedFormatError, noDefaultLocaleError, noApiKeyError, noProjectIdError, devApiKeyError, } from '../../console/index.js';
2
+ import { logErrorAndExit, logError } from '../../console/logging.js';
3
+ import { getRelative, readFile } from '../../fs/findFilepath.js';
4
+ import { SUPPORTED_FILE_EXTENSIONS } from './supportedFiles.js';
5
+ import sanitizeFileContent from '../../utils/sanitizeFileContent.js';
6
+ import { parseJson } from '../json/parseJson.js';
7
+ import { uploadFiles } from '../../api/uploadFiles.js';
8
+ import { existsSync, readFileSync } from 'node:fs';
9
+ import { createFileMapping } from './fileMapping.js';
10
+ import parseYaml from '../yaml/parseYaml.js';
11
+ const SUPPORTED_DATA_FORMATS = ['JSX', 'ICU', 'I18NEXT'];
12
+ /**
13
+ * Sends multiple files to the API for translation
14
+ * @param filePaths - Resolved file paths for different file types
15
+ * @param placeholderPaths - Placeholder paths for translated files
16
+ * @param transformPaths - Transform paths for file naming
17
+ * @param dataFormat - Format of the data within the files
18
+ * @param options - Translation options including API settings
19
+ * @returns Promise that resolves when translation is complete
20
+ */
21
+ export async function upload(filePaths, placeholderPaths, transformPaths, dataFormat = 'JSX', options) {
22
+ // Collect all files to translate
23
+ const allFiles = [];
24
+ const additionalOptions = options.options || {};
25
+ // Process JSON files
26
+ if (filePaths.json) {
27
+ if (!SUPPORTED_DATA_FORMATS.includes(dataFormat)) {
28
+ logErrorAndExit(noSupportedFormatError);
29
+ }
30
+ const jsonFiles = filePaths.json.map((filePath) => {
31
+ const content = readFile(filePath);
32
+ const parsedJson = parseJson(content, filePath, additionalOptions, options.defaultLocale);
33
+ const relativePath = getRelative(filePath);
34
+ return {
35
+ content: parsedJson,
36
+ fileName: relativePath,
37
+ fileFormat: 'JSON',
38
+ dataFormat,
39
+ locale: options.defaultLocale,
40
+ };
41
+ });
42
+ allFiles.push(...jsonFiles);
43
+ }
44
+ // Process YAML files
45
+ if (filePaths.yaml) {
46
+ if (!SUPPORTED_DATA_FORMATS.includes(dataFormat)) {
47
+ logErrorAndExit(noSupportedFormatError);
48
+ }
49
+ const yamlFiles = filePaths.yaml.map((filePath) => {
50
+ const content = readFile(filePath);
51
+ const { content: parsedYaml, fileFormat } = parseYaml(content, filePath, additionalOptions);
52
+ const relativePath = getRelative(filePath);
53
+ return {
54
+ content: parsedYaml,
55
+ fileName: relativePath,
56
+ fileFormat,
57
+ dataFormat,
58
+ locale: options.defaultLocale,
59
+ };
60
+ });
61
+ allFiles.push(...yamlFiles);
62
+ }
63
+ for (const fileType of SUPPORTED_FILE_EXTENSIONS) {
64
+ if (fileType === 'json' || fileType === 'yaml')
65
+ continue;
66
+ if (filePaths[fileType]) {
67
+ const files = filePaths[fileType].map((filePath) => {
68
+ const content = readFile(filePath);
69
+ const sanitizedContent = sanitizeFileContent(content);
70
+ const relativePath = getRelative(filePath);
71
+ return {
72
+ content: sanitizedContent,
73
+ fileName: relativePath,
74
+ fileFormat: fileType.toUpperCase(),
75
+ dataFormat,
76
+ locale: options.defaultLocale,
77
+ };
78
+ });
79
+ allFiles.push(...files);
80
+ }
81
+ }
82
+ if (allFiles.length === 0) {
83
+ logError('No files to upload were found. Please check your configuration and try again.');
84
+ return;
85
+ }
86
+ if (!options.defaultLocale) {
87
+ logErrorAndExit(noDefaultLocaleError);
88
+ }
89
+ if (!options.apiKey) {
90
+ logErrorAndExit(noApiKeyError);
91
+ }
92
+ if (options.apiKey.startsWith('gtx-dev-')) {
93
+ logErrorAndExit(devApiKeyError);
94
+ }
95
+ if (!options.projectId) {
96
+ logErrorAndExit(noProjectIdError);
97
+ }
98
+ const locales = options.locales || [];
99
+ // Create file mapping for all file types
100
+ const fileMapping = createFileMapping(filePaths, placeholderPaths, transformPaths, locales, options.defaultLocale);
101
+ // construct object
102
+ const uploadData = allFiles.map((file) => {
103
+ const sourceFile = {
104
+ content: file.content,
105
+ fileName: file.fileName,
106
+ fileFormat: file.fileFormat,
107
+ dataFormat: file.dataFormat,
108
+ locale: file.locale,
109
+ };
110
+ const translations = [];
111
+ for (const locale of locales) {
112
+ const translatedFileName = fileMapping[locale][file.fileName];
113
+ if (translatedFileName && existsSync(translatedFileName)) {
114
+ const translatedContent = readFileSync(translatedFileName, 'utf8');
115
+ translations.push({
116
+ content: translatedContent,
117
+ fileName: translatedFileName,
118
+ fileFormat: file.fileFormat,
119
+ dataFormat: file.dataFormat,
120
+ locale,
121
+ });
122
+ }
123
+ }
124
+ return {
125
+ source: sourceFile,
126
+ translations,
127
+ };
128
+ });
129
+ try {
130
+ // Send all files in a single API call
131
+ await uploadFiles(uploadData, options);
132
+ }
133
+ catch (error) {
134
+ logErrorAndExit(`Error uploading files: ${error}`);
135
+ }
136
+ }
@@ -0,0 +1,9 @@
1
+ import { RetrievedTranslations } from 'generaltranslation/types';
2
+ import { ResolvedFiles } from '../../types/index.js';
3
+ /**
4
+ * Saves translations to a local directory
5
+ * @param translations - The translations to save
6
+ * @param translationsDir - The directory to save the translations to
7
+ * @param fileType - The file type to save the translations as (file extension)
8
+ */
9
+ export declare function saveTranslations(translations: RetrievedTranslations, placeholderPaths: ResolvedFiles): Promise<void>;
@@ -0,0 +1,26 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { logError } from '../../console/logging.js';
4
+ import { noFilesError } from '../../console/index.js';
5
+ import { resolveLocaleFiles } from '../../fs/config/parseFilesConfig.js';
6
+ /**
7
+ * Saves translations to a local directory
8
+ * @param translations - The translations to save
9
+ * @param translationsDir - The directory to save the translations to
10
+ * @param fileType - The file type to save the translations as (file extension)
11
+ */
12
+ export async function saveTranslations(translations, placeholderPaths) {
13
+ for (const translation of translations) {
14
+ const locale = translation.locale;
15
+ const translationFiles = resolveLocaleFiles(placeholderPaths, locale);
16
+ if (!translationFiles.gt) {
17
+ logError(noFilesError);
18
+ process.exit(1);
19
+ }
20
+ const filepath = translationFiles.gt;
21
+ const translationData = translation.translation;
22
+ // Ensure directory exists
23
+ await fs.promises.mkdir(path.dirname(filepath), { recursive: true });
24
+ await fs.promises.writeFile(filepath, JSON.stringify(translationData, null, 2));
25
+ }
26
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Flattens a JSON object according to a list of JSON paths.
3
+ * @param json - The JSON object to flatten
4
+ * @param jsonPaths - The list of JSON paths to flatten
5
+ * @returns A mapping of json pointers to their values
6
+ */
7
+ export declare function flattenJson(json: any, jsonPaths: string[]): Record<string, any>;
8
+ /**
9
+ * Flattens a JSON object according to a list of JSON paths, only including strings
10
+ * @param json - The JSON object to flatten
11
+ * @param jsonPaths - The list of JSON paths to flatten
12
+ * @returns A mapping of json pointers to their values
13
+ */
14
+ export declare function flattenJsonWithStringFilter(json: any, jsonPaths: string[]): Record<string, any>;