@kopynator/cli 1.0.9 → 1.0.11
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/dist/index.js +136 -20
- package/package.json +1 -1
- package/src/commands/init.ts +36 -17
- package/src/commands/sync.ts +157 -4
package/dist/index.js
CHANGED
|
@@ -98,17 +98,29 @@ async function initCommand() {
|
|
|
98
98
|
console.log(import_chalk.default.green(`
|
|
99
99
|
\u2705 Setting up for ${answers.framework}...`));
|
|
100
100
|
if (answers.framework === "Angular") {
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
const appConfigPath = import_path.default.join(process.cwd(), "src/app/app.config.ts");
|
|
102
|
+
const appModulePath = import_path.default.join(process.cwd(), "src/app/app.module.ts");
|
|
103
|
+
let targetPath = null;
|
|
104
|
+
let isModule = false;
|
|
105
|
+
if (import_fs.default.existsSync(appConfigPath)) {
|
|
106
|
+
targetPath = appConfigPath;
|
|
107
|
+
isModule = false;
|
|
108
|
+
console.log(import_chalk.default.blue("\u2139\uFE0F Detected Angular standalone project (app.config.ts)"));
|
|
109
|
+
} else if (import_fs.default.existsSync(appModulePath)) {
|
|
110
|
+
targetPath = appModulePath;
|
|
111
|
+
isModule = true;
|
|
112
|
+
console.log(import_chalk.default.blue("\u2139\uFE0F Detected Angular NgModule project (app.module.ts)"));
|
|
113
|
+
}
|
|
114
|
+
if (targetPath) {
|
|
115
|
+
let fileContent = import_fs.default.readFileSync(targetPath, "utf-8");
|
|
116
|
+
const hasImport = fileContent.includes("@kopynator/angular");
|
|
106
117
|
if (!hasImport) {
|
|
107
|
-
|
|
108
|
-
` +
|
|
118
|
+
fileContent = `import { provideKopynator } from '@kopynator/angular';
|
|
119
|
+
` + fileContent;
|
|
109
120
|
}
|
|
110
|
-
if (
|
|
111
|
-
console.log(import_chalk.default.yellow("\u26A0\uFE0F provideKopynator is already present
|
|
121
|
+
if (fileContent.includes("provideKopynator(")) {
|
|
122
|
+
console.log(import_chalk.default.yellow("\u26A0\uFE0F provideKopynator is already present. Skipping injection."));
|
|
123
|
+
return;
|
|
112
124
|
} else {
|
|
113
125
|
const providerString = `
|
|
114
126
|
provideKopynator({
|
|
@@ -117,21 +129,21 @@ async function initCommand() {
|
|
|
117
129
|
mode: 'local',
|
|
118
130
|
languages: ${JSON.stringify(answers.languages)},
|
|
119
131
|
}),`;
|
|
120
|
-
const providersRegex = /(providers:\s*\[)/;
|
|
121
|
-
if (providersRegex.test(
|
|
122
|
-
|
|
123
|
-
import_fs.default.writeFileSync(
|
|
124
|
-
console.log(import_chalk.default.green(
|
|
132
|
+
const providersRegex = isModule ? /(providers:\s*\[)/ : /(providers:\s*\[)/;
|
|
133
|
+
if (providersRegex.test(fileContent)) {
|
|
134
|
+
fileContent = fileContent.replace(providersRegex, `$1${providerString}`);
|
|
135
|
+
import_fs.default.writeFileSync(targetPath, fileContent);
|
|
136
|
+
console.log(import_chalk.default.green(`\u2705 Successfully injected configuration into ${isModule ? "app.module.ts" : "app.config.ts"}`));
|
|
125
137
|
console.log(import_chalk.default.yellow("\nNext steps:"));
|
|
126
138
|
console.log("1. Get your API Key from https://www.kopynator.com");
|
|
127
|
-
console.log(
|
|
139
|
+
console.log(`2. Update the apiKey in ${isModule ? "src/app/app.module.ts" : "src/app/app.config.ts"}`);
|
|
128
140
|
return;
|
|
129
141
|
} else {
|
|
130
|
-
console.log(import_chalk.default.yellow(
|
|
142
|
+
console.log(import_chalk.default.yellow(`\u26A0\uFE0F Could not find "providers: []" array. Falling back to config file.`));
|
|
131
143
|
}
|
|
132
144
|
}
|
|
133
145
|
} else {
|
|
134
|
-
console.log(import_chalk.default.yellow("\u26A0\uFE0F Could not find
|
|
146
|
+
console.log(import_chalk.default.yellow("\u26A0\uFE0F Could not find app.config.ts or app.module.ts. Falling back to config file."));
|
|
135
147
|
}
|
|
136
148
|
}
|
|
137
149
|
const configContent = {
|
|
@@ -190,11 +202,115 @@ async function checkCommand() {
|
|
|
190
202
|
|
|
191
203
|
// src/commands/sync.ts
|
|
192
204
|
var import_chalk3 = __toESM(require("chalk"));
|
|
205
|
+
var import_fs3 = __toESM(require("fs"));
|
|
206
|
+
var import_path3 = __toESM(require("path"));
|
|
207
|
+
function detectFramework() {
|
|
208
|
+
const angularJson = import_path3.default.join(process.cwd(), "angular.json");
|
|
209
|
+
const packageJson = import_path3.default.join(process.cwd(), "package.json");
|
|
210
|
+
if (import_fs3.default.existsSync(angularJson)) {
|
|
211
|
+
return "Angular";
|
|
212
|
+
}
|
|
213
|
+
if (import_fs3.default.existsSync(packageJson)) {
|
|
214
|
+
try {
|
|
215
|
+
const pkg = JSON.parse(import_fs3.default.readFileSync(packageJson, "utf-8"));
|
|
216
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
217
|
+
if (deps["@angular/core"]) return "Angular";
|
|
218
|
+
if (deps["react"]) return "React";
|
|
219
|
+
if (deps["vue"]) return "Vue";
|
|
220
|
+
} catch (e) {
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return "Other";
|
|
224
|
+
}
|
|
225
|
+
function getTranslationDir(framework) {
|
|
226
|
+
switch (framework) {
|
|
227
|
+
case "Angular":
|
|
228
|
+
return import_path3.default.join(process.cwd(), "src/assets/i18n");
|
|
229
|
+
case "React":
|
|
230
|
+
return import_path3.default.join(process.cwd(), "public/locales");
|
|
231
|
+
case "Vue":
|
|
232
|
+
return import_path3.default.join(process.cwd(), "public/locales");
|
|
233
|
+
default:
|
|
234
|
+
return import_path3.default.join(process.cwd(), "locales");
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function extractApiKey() {
|
|
238
|
+
const appConfigPath = import_path3.default.join(process.cwd(), "src/app/app.config.ts");
|
|
239
|
+
const appModulePath = import_path3.default.join(process.cwd(), "src/app/app.module.ts");
|
|
240
|
+
const jsonConfigPath = import_path3.default.join(process.cwd(), "kopynator.config.json");
|
|
241
|
+
if (import_fs3.default.existsSync(appConfigPath)) {
|
|
242
|
+
const content = import_fs3.default.readFileSync(appConfigPath, "utf-8");
|
|
243
|
+
const apiKeyMatch = content.match(/apiKey:\s*['"]([^'"]+)['"]/);
|
|
244
|
+
if (apiKeyMatch) {
|
|
245
|
+
console.log(import_chalk3.default.blue("\u2139\uFE0F Found API key in app.config.ts"));
|
|
246
|
+
return { apiKey: apiKeyMatch[1] };
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (import_fs3.default.existsSync(appModulePath)) {
|
|
250
|
+
const content = import_fs3.default.readFileSync(appModulePath, "utf-8");
|
|
251
|
+
const apiKeyMatch = content.match(/apiKey:\s*['"]([^'"]+)['"]/);
|
|
252
|
+
if (apiKeyMatch) {
|
|
253
|
+
console.log(import_chalk3.default.blue("\u2139\uFE0F Found API key in app.module.ts"));
|
|
254
|
+
return { apiKey: apiKeyMatch[1] };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (import_fs3.default.existsSync(jsonConfigPath)) {
|
|
258
|
+
try {
|
|
259
|
+
const config = JSON.parse(import_fs3.default.readFileSync(jsonConfigPath, "utf-8"));
|
|
260
|
+
if (config.apiKey) {
|
|
261
|
+
console.log(import_chalk3.default.blue("\u2139\uFE0F Found API key in kopynator.config.json"));
|
|
262
|
+
return { apiKey: config.apiKey, baseUrl: config.baseUrl };
|
|
263
|
+
}
|
|
264
|
+
} catch (e) {
|
|
265
|
+
console.log(import_chalk3.default.red("\u274C Error parsing kopynator.config.json"));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
193
270
|
async function syncCommand() {
|
|
194
271
|
console.log(import_chalk3.default.bold.blue("\n\u2601\uFE0F Syncing with Kopynator Cloud...\n"));
|
|
195
|
-
|
|
196
|
-
console.log(import_chalk3.default.
|
|
197
|
-
|
|
272
|
+
const framework = detectFramework();
|
|
273
|
+
console.log(import_chalk3.default.blue(`\u2139\uFE0F Detected ${framework} project`));
|
|
274
|
+
const config = extractApiKey();
|
|
275
|
+
if (!config) {
|
|
276
|
+
console.log(import_chalk3.default.red("\u274C Could not find API key in any config file."));
|
|
277
|
+
console.log(import_chalk3.default.yellow("Run `npx kopynator init` first or configure your API key manually."));
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
const baseUrl = config.baseUrl || "http://localhost:7300/api/tokens";
|
|
281
|
+
const token = config.apiKey;
|
|
282
|
+
try {
|
|
283
|
+
console.log(import_chalk3.default.blue("\u{1F4E1} Fetching available languages..."));
|
|
284
|
+
const languagesUrl = `${baseUrl}/languages?token=${token}`;
|
|
285
|
+
const languagesResponse = await fetch(languagesUrl);
|
|
286
|
+
if (!languagesResponse.ok) {
|
|
287
|
+
console.log(import_chalk3.default.red(`\u274C Failed to fetch languages: ${languagesResponse.status} ${languagesResponse.statusText}`));
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const languages = await languagesResponse.json();
|
|
291
|
+
console.log(import_chalk3.default.green(`\u2705 Found ${languages.length} language(s): ${languages.join(", ")}`));
|
|
292
|
+
const i18nDir = getTranslationDir(framework);
|
|
293
|
+
if (!import_fs3.default.existsSync(i18nDir)) {
|
|
294
|
+
import_fs3.default.mkdirSync(i18nDir, { recursive: true });
|
|
295
|
+
console.log(import_chalk3.default.blue(`\u{1F4C1} Created directory: ${i18nDir}`));
|
|
296
|
+
}
|
|
297
|
+
for (const locale of languages) {
|
|
298
|
+
console.log(import_chalk3.default.blue(`\u2B07\uFE0F Downloading ${locale}...`));
|
|
299
|
+
const fetchUrl = `${baseUrl}/fetch?token=${token}&langs=${locale}&nested=false&includeLangKey=false&pretty=true&indent=2`;
|
|
300
|
+
const translationResponse = await fetch(fetchUrl);
|
|
301
|
+
if (!translationResponse.ok) {
|
|
302
|
+
console.log(import_chalk3.default.yellow(`\u26A0\uFE0F Failed to fetch ${locale}: ${translationResponse.status}`));
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
const translationData = await translationResponse.json();
|
|
306
|
+
const outputPath = import_path3.default.join(i18nDir, `${locale}.json`);
|
|
307
|
+
import_fs3.default.writeFileSync(outputPath, JSON.stringify(translationData, null, 2));
|
|
308
|
+
console.log(import_chalk3.default.green(`\u2705 Saved ${locale}.json`));
|
|
309
|
+
}
|
|
310
|
+
console.log(import_chalk3.default.bold.green("\n\u{1F389} Sync completed successfully!\n"));
|
|
311
|
+
} catch (error) {
|
|
312
|
+
console.log(import_chalk3.default.red(`\u274C Sync failed: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
313
|
+
}
|
|
198
314
|
}
|
|
199
315
|
|
|
200
316
|
// src/index.ts
|
package/package.json
CHANGED
package/src/commands/init.ts
CHANGED
|
@@ -71,22 +71,37 @@ export async function initCommand() {
|
|
|
71
71
|
console.log(chalk.green(`\n✅ Setting up for ${answers.framework}...`));
|
|
72
72
|
|
|
73
73
|
if (answers.framework === 'Angular') {
|
|
74
|
-
|
|
74
|
+
// Try app.config.ts first (Angular 17+ standalone)
|
|
75
|
+
const appConfigPath = path.join(process.cwd(), 'src/app/app.config.ts');
|
|
76
|
+
const appModulePath = path.join(process.cwd(), 'src/app/app.module.ts');
|
|
75
77
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
78
|
+
let targetPath: string | null = null;
|
|
79
|
+
let isModule = false;
|
|
80
|
+
|
|
81
|
+
if (fs.existsSync(appConfigPath)) {
|
|
82
|
+
targetPath = appConfigPath;
|
|
83
|
+
isModule = false;
|
|
84
|
+
console.log(chalk.blue('ℹ️ Detected Angular standalone project (app.config.ts)'));
|
|
85
|
+
} else if (fs.existsSync(appModulePath)) {
|
|
86
|
+
targetPath = appModulePath;
|
|
87
|
+
isModule = true;
|
|
88
|
+
console.log(chalk.blue('ℹ️ Detected Angular NgModule project (app.module.ts)'));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (targetPath) {
|
|
92
|
+
let fileContent = fs.readFileSync(targetPath, 'utf-8');
|
|
79
93
|
|
|
80
94
|
// 1. Add Import if missing
|
|
81
|
-
const hasImport =
|
|
95
|
+
const hasImport = fileContent.includes('@kopynator/angular');
|
|
82
96
|
if (!hasImport) {
|
|
83
|
-
|
|
97
|
+
fileContent = `import { provideKopynator } from '@kopynator/angular';\n` + fileContent;
|
|
84
98
|
}
|
|
85
99
|
|
|
86
100
|
// 2. Add Provider
|
|
87
|
-
// Check for the *usage* of the provider
|
|
88
|
-
if (
|
|
89
|
-
console.log(chalk.yellow('⚠️ provideKopynator is already present
|
|
101
|
+
// Check for the *usage* of the provider
|
|
102
|
+
if (fileContent.includes('provideKopynator(')) {
|
|
103
|
+
console.log(chalk.yellow('⚠️ provideKopynator is already present. Skipping injection.'));
|
|
104
|
+
return; // Exit successfully, assuming manual config is sufficient
|
|
90
105
|
} else {
|
|
91
106
|
const providerString = `
|
|
92
107
|
provideKopynator({
|
|
@@ -96,21 +111,25 @@ export async function initCommand() {
|
|
|
96
111
|
languages: ${JSON.stringify(answers.languages)},
|
|
97
112
|
}),`;
|
|
98
113
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
114
|
+
// Different regex for NgModule vs standalone config
|
|
115
|
+
const providersRegex = isModule
|
|
116
|
+
? /(providers:\s*\[)/ // NgModule: providers: [ in @NgModule decorator
|
|
117
|
+
: /(providers:\s*\[)/; // Standalone: providers: [ in ApplicationConfig
|
|
118
|
+
|
|
119
|
+
if (providersRegex.test(fileContent)) {
|
|
120
|
+
fileContent = fileContent.replace(providersRegex, `$1${providerString}`);
|
|
121
|
+
fs.writeFileSync(targetPath, fileContent);
|
|
122
|
+
console.log(chalk.green(`✅ Successfully injected configuration into ${isModule ? 'app.module.ts' : 'app.config.ts'}`));
|
|
104
123
|
console.log(chalk.yellow('\nNext steps:'));
|
|
105
124
|
console.log('1. Get your API Key from https://www.kopynator.com');
|
|
106
|
-
console.log(
|
|
125
|
+
console.log(`2. Update the apiKey in ${isModule ? 'src/app/app.module.ts' : 'src/app/app.config.ts'}`);
|
|
107
126
|
return; // Exit successfully without creating json
|
|
108
127
|
} else {
|
|
109
|
-
console.log(chalk.yellow(
|
|
128
|
+
console.log(chalk.yellow(`⚠️ Could not find "providers: []" array. Falling back to config file.`));
|
|
110
129
|
}
|
|
111
130
|
}
|
|
112
131
|
} else {
|
|
113
|
-
console.log(chalk.yellow('⚠️ Could not find
|
|
132
|
+
console.log(chalk.yellow('⚠️ Could not find app.config.ts or app.module.ts. Falling back to config file.'));
|
|
114
133
|
}
|
|
115
134
|
}
|
|
116
135
|
|
package/src/commands/sync.ts
CHANGED
|
@@ -1,10 +1,163 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
interface KopyConfig {
|
|
6
|
+
apiKey: string;
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Detect the framework being used in the current project
|
|
12
|
+
*/
|
|
13
|
+
function detectFramework(): 'Angular' | 'React' | 'Vue' | 'Other' {
|
|
14
|
+
const angularJson = path.join(process.cwd(), 'angular.json');
|
|
15
|
+
const packageJson = path.join(process.cwd(), 'package.json');
|
|
16
|
+
|
|
17
|
+
// Check for Angular
|
|
18
|
+
if (fs.existsSync(angularJson)) {
|
|
19
|
+
return 'Angular';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Check package.json for React/Vue
|
|
23
|
+
if (fs.existsSync(packageJson)) {
|
|
24
|
+
try {
|
|
25
|
+
const pkg = JSON.parse(fs.readFileSync(packageJson, 'utf-8'));
|
|
26
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
27
|
+
|
|
28
|
+
if (deps['@angular/core']) return 'Angular';
|
|
29
|
+
if (deps['react']) return 'React';
|
|
30
|
+
if (deps['vue']) return 'Vue';
|
|
31
|
+
} catch (e) {
|
|
32
|
+
// Ignore parse errors
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return 'Other';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get the translation directory path based on framework
|
|
41
|
+
*/
|
|
42
|
+
function getTranslationDir(framework: string): string {
|
|
43
|
+
switch (framework) {
|
|
44
|
+
case 'Angular':
|
|
45
|
+
return path.join(process.cwd(), 'src/assets/i18n');
|
|
46
|
+
case 'React':
|
|
47
|
+
// Common React patterns, can be customized later
|
|
48
|
+
return path.join(process.cwd(), 'public/locales');
|
|
49
|
+
case 'Vue':
|
|
50
|
+
// Common Vue patterns, can be customized later
|
|
51
|
+
return path.join(process.cwd(), 'public/locales');
|
|
52
|
+
default:
|
|
53
|
+
// Default fallback
|
|
54
|
+
return path.join(process.cwd(), 'locales');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Extract API key from Angular config files or JSON config
|
|
60
|
+
* Tries: app.config.ts -> app.module.ts -> kopynator.config.json
|
|
61
|
+
*/
|
|
62
|
+
function extractApiKey(): KopyConfig | null {
|
|
63
|
+
const appConfigPath = path.join(process.cwd(), 'src/app/app.config.ts');
|
|
64
|
+
const appModulePath = path.join(process.cwd(), 'src/app/app.module.ts');
|
|
65
|
+
const jsonConfigPath = path.join(process.cwd(), 'kopynator.config.json');
|
|
66
|
+
|
|
67
|
+
// Try app.config.ts
|
|
68
|
+
if (fs.existsSync(appConfigPath)) {
|
|
69
|
+
const content = fs.readFileSync(appConfigPath, 'utf-8');
|
|
70
|
+
const apiKeyMatch = content.match(/apiKey:\s*['"]([^'"]+)['"]/);
|
|
71
|
+
if (apiKeyMatch) {
|
|
72
|
+
console.log(chalk.blue('ℹ️ Found API key in app.config.ts'));
|
|
73
|
+
return { apiKey: apiKeyMatch[1] };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Try app.module.ts
|
|
78
|
+
if (fs.existsSync(appModulePath)) {
|
|
79
|
+
const content = fs.readFileSync(appModulePath, 'utf-8');
|
|
80
|
+
const apiKeyMatch = content.match(/apiKey:\s*['"]([^'"]+)['"]/);
|
|
81
|
+
if (apiKeyMatch) {
|
|
82
|
+
console.log(chalk.blue('ℹ️ Found API key in app.module.ts'));
|
|
83
|
+
return { apiKey: apiKeyMatch[1] };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Try kopynator.config.json
|
|
88
|
+
if (fs.existsSync(jsonConfigPath)) {
|
|
89
|
+
try {
|
|
90
|
+
const config = JSON.parse(fs.readFileSync(jsonConfigPath, 'utf-8'));
|
|
91
|
+
if (config.apiKey) {
|
|
92
|
+
console.log(chalk.blue('ℹ️ Found API key in kopynator.config.json'));
|
|
93
|
+
return { apiKey: config.apiKey, baseUrl: config.baseUrl };
|
|
94
|
+
}
|
|
95
|
+
} catch (e) {
|
|
96
|
+
console.log(chalk.red('❌ Error parsing kopynator.config.json'));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
2
102
|
|
|
3
103
|
export async function syncCommand() {
|
|
4
104
|
console.log(chalk.bold.blue('\n☁️ Syncing with Kopynator Cloud...\n'));
|
|
5
105
|
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
console.log(chalk.
|
|
9
|
-
|
|
106
|
+
// Detect framework
|
|
107
|
+
const framework = detectFramework();
|
|
108
|
+
console.log(chalk.blue(`ℹ️ Detected ${framework} project`));
|
|
109
|
+
|
|
110
|
+
// Extract API key
|
|
111
|
+
const config = extractApiKey();
|
|
112
|
+
if (!config) {
|
|
113
|
+
console.log(chalk.red('❌ Could not find API key in any config file.'));
|
|
114
|
+
console.log(chalk.yellow('Run `npx kopynator init` first or configure your API key manually.'));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const baseUrl = config.baseUrl || 'http://localhost:7300/api/tokens';
|
|
119
|
+
const token = config.apiKey;
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
// 1. Fetch available languages
|
|
123
|
+
console.log(chalk.blue('📡 Fetching available languages...'));
|
|
124
|
+
const languagesUrl = `${baseUrl}/languages?token=${token}`;
|
|
125
|
+
const languagesResponse = await fetch(languagesUrl);
|
|
126
|
+
|
|
127
|
+
if (!languagesResponse.ok) {
|
|
128
|
+
console.log(chalk.red(`❌ Failed to fetch languages: ${languagesResponse.status} ${languagesResponse.statusText}`));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const languages = await languagesResponse.json() as string[];
|
|
133
|
+
console.log(chalk.green(`✅ Found ${languages.length} language(s): ${languages.join(', ')}`));
|
|
134
|
+
|
|
135
|
+
// 2. Get translation directory based on framework
|
|
136
|
+
const i18nDir = getTranslationDir(framework);
|
|
137
|
+
if (!fs.existsSync(i18nDir)) {
|
|
138
|
+
fs.mkdirSync(i18nDir, { recursive: true });
|
|
139
|
+
console.log(chalk.blue(`📁 Created directory: ${i18nDir}`));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 3. Download translations for each language
|
|
143
|
+
for (const locale of languages) {
|
|
144
|
+
console.log(chalk.blue(`⬇️ Downloading ${locale}...`));
|
|
145
|
+
const fetchUrl = `${baseUrl}/fetch?token=${token}&langs=${locale}&nested=false&includeLangKey=false&pretty=true&indent=2`;
|
|
146
|
+
const translationResponse = await fetch(fetchUrl);
|
|
147
|
+
|
|
148
|
+
if (!translationResponse.ok) {
|
|
149
|
+
console.log(chalk.yellow(`⚠️ Failed to fetch ${locale}: ${translationResponse.status}`));
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const translationData = await translationResponse.json();
|
|
154
|
+
const outputPath = path.join(i18nDir, `${locale}.json`);
|
|
155
|
+
fs.writeFileSync(outputPath, JSON.stringify(translationData, null, 2));
|
|
156
|
+
console.log(chalk.green(`✅ Saved ${locale}.json`));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
console.log(chalk.bold.green('\n🎉 Sync completed successfully!\n'));
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.log(chalk.red(`❌ Sync failed: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
162
|
+
}
|
|
10
163
|
}
|