@kopynator/cli 1.0.14 ā 1.2.0
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 +118 -5
- package/package.json +2 -1
- package/src/commands/init.ts +125 -2
- package/src/commands/sync.ts +10 -3
- package/src/index.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -34,12 +34,53 @@ var import_fs = __toESM(require("fs"));
|
|
|
34
34
|
var import_path = __toESM(require("path"));
|
|
35
35
|
async function initCommand() {
|
|
36
36
|
console.log(import_chalk.default.bold.blue("\n\u{1F680} Initializing Kopynator...\n"));
|
|
37
|
+
let detectedFramework = null;
|
|
38
|
+
let isReactNative = false;
|
|
39
|
+
let isIonic = false;
|
|
40
|
+
let ionicFramework = null;
|
|
41
|
+
const packageJsonPath = import_path.default.join(process.cwd(), "package.json");
|
|
42
|
+
if (import_fs.default.existsSync(packageJsonPath)) {
|
|
43
|
+
try {
|
|
44
|
+
const packageJson = JSON.parse(import_fs.default.readFileSync(packageJsonPath, "utf-8"));
|
|
45
|
+
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
46
|
+
if (deps["react-native"]) {
|
|
47
|
+
isReactNative = true;
|
|
48
|
+
detectedFramework = "React Native";
|
|
49
|
+
console.log(import_chalk.default.cyan("\u{1F4F1} Detected React Native project!"));
|
|
50
|
+
} else if (deps["@ionic/angular"] || deps["@ionic/react"] || deps["@ionic/vue"] || deps["@capacitor/core"]) {
|
|
51
|
+
isIonic = true;
|
|
52
|
+
if (deps["@ionic/angular"] || deps["@angular/core"]) {
|
|
53
|
+
ionicFramework = "Angular";
|
|
54
|
+
detectedFramework = "Ionic (Angular)";
|
|
55
|
+
} else if (deps["@ionic/react"] || deps["react"]) {
|
|
56
|
+
ionicFramework = "React";
|
|
57
|
+
detectedFramework = "Ionic (React)";
|
|
58
|
+
} else if (deps["@ionic/vue"] || deps["vue"]) {
|
|
59
|
+
ionicFramework = "Vue";
|
|
60
|
+
detectedFramework = "Ionic (Vue)";
|
|
61
|
+
}
|
|
62
|
+
console.log(import_chalk.default.magenta(`\u{1F50C} Detected ${detectedFramework} project!`));
|
|
63
|
+
} else if (deps["@angular/core"]) {
|
|
64
|
+
detectedFramework = "Angular";
|
|
65
|
+
console.log(import_chalk.default.red("\u{1F170}\uFE0F Detected Angular project!"));
|
|
66
|
+
} else if (deps["react"] && !deps["react-native"]) {
|
|
67
|
+
detectedFramework = "React";
|
|
68
|
+
console.log(import_chalk.default.blue("\u269B\uFE0F Detected React project!"));
|
|
69
|
+
} else if (deps["vue"]) {
|
|
70
|
+
detectedFramework = "Vue";
|
|
71
|
+
console.log(import_chalk.default.green("\u{1F7E2} Detected Vue project!"));
|
|
72
|
+
}
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.log(import_chalk.default.yellow("\u26A0\uFE0F Could not read package.json"));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
37
77
|
const answers = await import_inquirer.default.prompt([
|
|
38
78
|
{
|
|
39
79
|
type: "list",
|
|
40
80
|
name: "framework",
|
|
41
|
-
message: "What framework are you using?",
|
|
42
|
-
choices: ["Angular", "React", "Vue", "Other"]
|
|
81
|
+
message: detectedFramework ? `Detected ${detectedFramework}. Is this correct?` : "What framework are you using?",
|
|
82
|
+
choices: detectedFramework ? [detectedFramework, "Other"] : ["Angular", "React", "Vue", "React Native", "Ionic", "Other"],
|
|
83
|
+
default: detectedFramework || "React"
|
|
43
84
|
},
|
|
44
85
|
{
|
|
45
86
|
type: "input",
|
|
@@ -146,6 +187,70 @@ async function initCommand() {
|
|
|
146
187
|
console.log(import_chalk.default.yellow("\u26A0\uFE0F Could not find app.config.ts or app.module.ts. Falling back to config file."));
|
|
147
188
|
}
|
|
148
189
|
}
|
|
190
|
+
if (isReactNative || answers.framework === "React Native") {
|
|
191
|
+
console.log(import_chalk.default.green("\n\u2705 React Native Setup"));
|
|
192
|
+
console.log(import_chalk.default.cyan("\nInstall the package:"));
|
|
193
|
+
console.log(import_chalk.default.white(" npm install @kopynator/react"));
|
|
194
|
+
console.log(import_chalk.default.cyan("\nWrap your App.tsx:"));
|
|
195
|
+
console.log(import_chalk.default.gray(`
|
|
196
|
+
import { KopyProvider } from '@kopynator/react';
|
|
197
|
+
|
|
198
|
+
export default function App() {
|
|
199
|
+
return (
|
|
200
|
+
<KopyProvider config={{ apiKey: 'YOUR_API_KEY', languages: ${JSON.stringify(answers.languages)} }}>
|
|
201
|
+
<YourApp />
|
|
202
|
+
</KopyProvider>
|
|
203
|
+
);
|
|
204
|
+
}`));
|
|
205
|
+
console.log(import_chalk.default.yellow("\n\u{1F4CC} Get your API Key from: https://www.kopynator.com"));
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (isIonic) {
|
|
209
|
+
console.log(import_chalk.default.green(`
|
|
210
|
+
\u2705 Ionic (${ionicFramework}) Setup`));
|
|
211
|
+
console.log(import_chalk.default.magenta("\n\u2139\uFE0F Ionic/Capacitor apps use the standard web framework packages."));
|
|
212
|
+
if (ionicFramework === "Angular") {
|
|
213
|
+
console.log(import_chalk.default.cyan("\nInstall the package:"));
|
|
214
|
+
console.log(import_chalk.default.white(" npm install @kopynator/angular"));
|
|
215
|
+
console.log(import_chalk.default.cyan("\nAdd to your app.config.ts or app.module.ts:"));
|
|
216
|
+
console.log(import_chalk.default.gray(`
|
|
217
|
+
import { provideKopynator } from '@kopynator/angular';
|
|
218
|
+
|
|
219
|
+
providers: [
|
|
220
|
+
provideKopynator({
|
|
221
|
+
apiKey: 'YOUR_API_KEY',
|
|
222
|
+
mode: 'hybrid',
|
|
223
|
+
languages: ${JSON.stringify(answers.languages)}
|
|
224
|
+
})
|
|
225
|
+
]`));
|
|
226
|
+
} else if (ionicFramework === "React") {
|
|
227
|
+
console.log(import_chalk.default.cyan("\nInstall the package:"));
|
|
228
|
+
console.log(import_chalk.default.white(" npm install @kopynator/react"));
|
|
229
|
+
console.log(import_chalk.default.cyan("\nWrap your App:"));
|
|
230
|
+
console.log(import_chalk.default.gray(`
|
|
231
|
+
import { KopyProvider } from '@kopynator/react';
|
|
232
|
+
|
|
233
|
+
<KopyProvider config={{ apiKey: 'YOUR_API_KEY', languages: ${JSON.stringify(answers.languages)} }}>
|
|
234
|
+
<IonApp>...</IonApp>
|
|
235
|
+
</KopyProvider>`));
|
|
236
|
+
} else if (ionicFramework === "Vue") {
|
|
237
|
+
console.log(import_chalk.default.cyan("\nInstall the package:"));
|
|
238
|
+
console.log(import_chalk.default.white(" npm install @kopynator/vue"));
|
|
239
|
+
console.log(import_chalk.default.cyan("\nAdd to your main.ts:"));
|
|
240
|
+
console.log(import_chalk.default.gray(`
|
|
241
|
+
import { createKopy } from '@kopynator/vue';
|
|
242
|
+
|
|
243
|
+
const kopy = createKopy({
|
|
244
|
+
apiKey: 'YOUR_API_KEY',
|
|
245
|
+
defaultLocale: '${answers.defaultLocale}'
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
app.use(kopy);`));
|
|
249
|
+
}
|
|
250
|
+
console.log(import_chalk.default.yellow("\n\u{1F4CC} Get your API Key from: https://www.kopynator.com"));
|
|
251
|
+
console.log(import_chalk.default.green("\n\u{1F4A1} Pro Tip: Your translations will work seamlessly across iOS, Android, and web!"));
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
149
254
|
const configContent = {
|
|
150
255
|
apiKey: "YOUR_API_KEY_HERE",
|
|
151
256
|
defaultLocale: answers.defaultLocale,
|
|
@@ -339,7 +444,11 @@ async function syncCommand() {
|
|
|
339
444
|
try {
|
|
340
445
|
spinner.text = "\u{1F4E1} Fetching available languages...";
|
|
341
446
|
const languagesUrl = `${baseUrl}/languages?token=${token}`;
|
|
342
|
-
const languagesResponse = await fetch(languagesUrl
|
|
447
|
+
const languagesResponse = await fetch(languagesUrl, {
|
|
448
|
+
headers: {
|
|
449
|
+
"x-kopynator-version": "1.1.0"
|
|
450
|
+
}
|
|
451
|
+
});
|
|
343
452
|
if (!languagesResponse.ok) {
|
|
344
453
|
spinner.fail(`Failed to fetch languages: ${languagesResponse.status} ${languagesResponse.statusText}`);
|
|
345
454
|
return;
|
|
@@ -355,7 +464,11 @@ async function syncCommand() {
|
|
|
355
464
|
const downloadSpinner = (0, import_ora.default)(`\u2B07\uFE0F Downloading ${locale}...`).start();
|
|
356
465
|
const fetchUrl = `${baseUrl}/fetch?token=${token}&langs=${locale}&nested=${syncConfig.nested}&includeLangKey=${syncConfig.includeLangKey}&pretty=${syncConfig.pretty}&indent=${syncConfig.indent}`;
|
|
357
466
|
try {
|
|
358
|
-
const translationResponse = await fetch(fetchUrl
|
|
467
|
+
const translationResponse = await fetch(fetchUrl, {
|
|
468
|
+
headers: {
|
|
469
|
+
"x-kopynator-version": "1.1.0"
|
|
470
|
+
}
|
|
471
|
+
});
|
|
359
472
|
if (!translationResponse.ok) {
|
|
360
473
|
downloadSpinner.warn(`Failed to fetch ${locale}: ${translationResponse.status}`);
|
|
361
474
|
continue;
|
|
@@ -383,7 +496,7 @@ async function syncCommand() {
|
|
|
383
496
|
|
|
384
497
|
// src/index.ts
|
|
385
498
|
var program = new import_commander.Command();
|
|
386
|
-
program.name("kopynator").description("Kopynator CLI - Manage your i18n workflow").version("1.
|
|
499
|
+
program.name("kopynator").description("Kopynator CLI - Manage your i18n workflow").version("1.2.0");
|
|
387
500
|
program.command("init").description("Initialize Kopynator in your project").action(initCommand);
|
|
388
501
|
program.command("check").description("Validate your local JSON translation files").action(checkCommand);
|
|
389
502
|
program.command("sync").description("Sync your translations with the Kopynator Cloud").action(syncCommand);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kopynator/cli",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "CLI tool for Kopynator - The i18n management solution",
|
|
5
5
|
"bin": {
|
|
6
6
|
"kopynator": "dist/index.js"
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"author": "Carlos Florio",
|
|
23
23
|
"license": "ISC",
|
|
24
24
|
"dependencies": {
|
|
25
|
+
"@kopynator/core": "^1.0.1",
|
|
25
26
|
"chalk": "^4.1.2",
|
|
26
27
|
"commander": "^11.1.0",
|
|
27
28
|
"inquirer": "^8.2.6",
|
package/src/commands/init.ts
CHANGED
|
@@ -6,12 +6,66 @@ import path from 'path';
|
|
|
6
6
|
export async function initCommand() {
|
|
7
7
|
console.log(chalk.bold.blue('\nš Initializing Kopynator...\n'));
|
|
8
8
|
|
|
9
|
+
// Auto-detect framework from package.json
|
|
10
|
+
let detectedFramework: string | null = null;
|
|
11
|
+
let isReactNative = false;
|
|
12
|
+
let isIonic = false;
|
|
13
|
+
let ionicFramework: string | null = null;
|
|
14
|
+
|
|
15
|
+
const packageJsonPath = path.join(process.cwd(), 'package.json');
|
|
16
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
17
|
+
try {
|
|
18
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
19
|
+
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
20
|
+
|
|
21
|
+
// Check for React Native
|
|
22
|
+
if (deps['react-native']) {
|
|
23
|
+
isReactNative = true;
|
|
24
|
+
detectedFramework = 'React Native';
|
|
25
|
+
console.log(chalk.cyan('š± Detected React Native project!'));
|
|
26
|
+
}
|
|
27
|
+
// Check for Ionic/Capacitor
|
|
28
|
+
else if (deps['@ionic/angular'] || deps['@ionic/react'] || deps['@ionic/vue'] || deps['@capacitor/core']) {
|
|
29
|
+
isIonic = true;
|
|
30
|
+
if (deps['@ionic/angular'] || deps['@angular/core']) {
|
|
31
|
+
ionicFramework = 'Angular';
|
|
32
|
+
detectedFramework = 'Ionic (Angular)';
|
|
33
|
+
} else if (deps['@ionic/react'] || deps['react']) {
|
|
34
|
+
ionicFramework = 'React';
|
|
35
|
+
detectedFramework = 'Ionic (React)';
|
|
36
|
+
} else if (deps['@ionic/vue'] || deps['vue']) {
|
|
37
|
+
ionicFramework = 'Vue';
|
|
38
|
+
detectedFramework = 'Ionic (Vue)';
|
|
39
|
+
}
|
|
40
|
+
console.log(chalk.magenta(`š Detected ${detectedFramework} project!`));
|
|
41
|
+
}
|
|
42
|
+
// Check for standard frameworks
|
|
43
|
+
else if (deps['@angular/core']) {
|
|
44
|
+
detectedFramework = 'Angular';
|
|
45
|
+
console.log(chalk.red('š
°ļø Detected Angular project!'));
|
|
46
|
+
} else if (deps['react'] && !deps['react-native']) {
|
|
47
|
+
detectedFramework = 'React';
|
|
48
|
+
console.log(chalk.blue('āļø Detected React project!'));
|
|
49
|
+
} else if (deps['vue']) {
|
|
50
|
+
detectedFramework = 'Vue';
|
|
51
|
+
console.log(chalk.green('š¢ Detected Vue project!'));
|
|
52
|
+
}
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.log(chalk.yellow('ā ļø Could not read package.json'));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
9
58
|
const answers = await inquirer.prompt([
|
|
10
59
|
{
|
|
11
60
|
type: 'list',
|
|
12
61
|
name: 'framework',
|
|
13
|
-
message:
|
|
14
|
-
|
|
62
|
+
message: detectedFramework
|
|
63
|
+
? `Detected ${detectedFramework}. Is this correct?`
|
|
64
|
+
: 'What framework are you using?',
|
|
65
|
+
choices: detectedFramework
|
|
66
|
+
? [detectedFramework, 'Other']
|
|
67
|
+
: ['Angular', 'React', 'Vue', 'React Native', 'Ionic', 'Other'],
|
|
68
|
+
default: detectedFramework || 'React'
|
|
15
69
|
},
|
|
16
70
|
{
|
|
17
71
|
type: 'input',
|
|
@@ -133,6 +187,75 @@ export async function initCommand() {
|
|
|
133
187
|
}
|
|
134
188
|
}
|
|
135
189
|
|
|
190
|
+
// React Native specific instructions
|
|
191
|
+
if (isReactNative || answers.framework === 'React Native') {
|
|
192
|
+
console.log(chalk.green('\nā
React Native Setup'));
|
|
193
|
+
console.log(chalk.cyan('\nInstall the package:'));
|
|
194
|
+
console.log(chalk.white(' npm install @kopynator/react'));
|
|
195
|
+
console.log(chalk.cyan('\nWrap your App.tsx:'));
|
|
196
|
+
console.log(chalk.gray(`
|
|
197
|
+
import { KopyProvider } from '@kopynator/react';
|
|
198
|
+
|
|
199
|
+
export default function App() {
|
|
200
|
+
return (
|
|
201
|
+
<KopyProvider config={{ apiKey: 'YOUR_API_KEY', languages: ${JSON.stringify(answers.languages)} }}>
|
|
202
|
+
<YourApp />
|
|
203
|
+
</KopyProvider>
|
|
204
|
+
);
|
|
205
|
+
}`));
|
|
206
|
+
console.log(chalk.yellow('\nš Get your API Key from: https://www.kopynator.com'));
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Ionic/Capacitor specific instructions
|
|
211
|
+
if (isIonic) {
|
|
212
|
+
console.log(chalk.green(`\nā
Ionic (${ionicFramework}) Setup`));
|
|
213
|
+
console.log(chalk.magenta('\nā¹ļø Ionic/Capacitor apps use the standard web framework packages.'));
|
|
214
|
+
|
|
215
|
+
if (ionicFramework === 'Angular') {
|
|
216
|
+
console.log(chalk.cyan('\nInstall the package:'));
|
|
217
|
+
console.log(chalk.white(' npm install @kopynator/angular'));
|
|
218
|
+
console.log(chalk.cyan('\nAdd to your app.config.ts or app.module.ts:'));
|
|
219
|
+
console.log(chalk.gray(`
|
|
220
|
+
import { provideKopynator } from '@kopynator/angular';
|
|
221
|
+
|
|
222
|
+
providers: [
|
|
223
|
+
provideKopynator({
|
|
224
|
+
apiKey: 'YOUR_API_KEY',
|
|
225
|
+
mode: 'hybrid',
|
|
226
|
+
languages: ${JSON.stringify(answers.languages)}
|
|
227
|
+
})
|
|
228
|
+
]`));
|
|
229
|
+
} else if (ionicFramework === 'React') {
|
|
230
|
+
console.log(chalk.cyan('\nInstall the package:'));
|
|
231
|
+
console.log(chalk.white(' npm install @kopynator/react'));
|
|
232
|
+
console.log(chalk.cyan('\nWrap your App:'));
|
|
233
|
+
console.log(chalk.gray(`
|
|
234
|
+
import { KopyProvider } from '@kopynator/react';
|
|
235
|
+
|
|
236
|
+
<KopyProvider config={{ apiKey: 'YOUR_API_KEY', languages: ${JSON.stringify(answers.languages)} }}>
|
|
237
|
+
<IonApp>...</IonApp>
|
|
238
|
+
</KopyProvider>`));
|
|
239
|
+
} else if (ionicFramework === 'Vue') {
|
|
240
|
+
console.log(chalk.cyan('\nInstall the package:'));
|
|
241
|
+
console.log(chalk.white(' npm install @kopynator/vue'));
|
|
242
|
+
console.log(chalk.cyan('\nAdd to your main.ts:'));
|
|
243
|
+
console.log(chalk.gray(`
|
|
244
|
+
import { createKopy } from '@kopynator/vue';
|
|
245
|
+
|
|
246
|
+
const kopy = createKopy({
|
|
247
|
+
apiKey: 'YOUR_API_KEY',
|
|
248
|
+
defaultLocale: '${answers.defaultLocale}'
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
app.use(kopy);`));
|
|
252
|
+
}
|
|
253
|
+
console.log(chalk.yellow('\nš Get your API Key from: https://www.kopynator.com'));
|
|
254
|
+
console.log(chalk.green('\nš” Pro Tip: Your translations will work seamlessly across iOS, Android, and web!'));
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
|
|
136
259
|
// Fallback: Creates a basic config file
|
|
137
260
|
const configContent = {
|
|
138
261
|
apiKey: "YOUR_API_KEY_HERE",
|
package/src/commands/sync.ts
CHANGED
|
@@ -202,8 +202,11 @@ export async function syncCommand() {
|
|
|
202
202
|
// 1. Fetch available languages
|
|
203
203
|
spinner.text = 'š” Fetching available languages...';
|
|
204
204
|
const languagesUrl = `${baseUrl}/languages?token=${token}`;
|
|
205
|
-
const languagesResponse = await fetch(languagesUrl
|
|
206
|
-
|
|
205
|
+
const languagesResponse = await fetch(languagesUrl, {
|
|
206
|
+
headers: {
|
|
207
|
+
'x-kopynator-version': '1.1.0'
|
|
208
|
+
}
|
|
209
|
+
});
|
|
207
210
|
if (!languagesResponse.ok) {
|
|
208
211
|
spinner.fail(`Failed to fetch languages: ${languagesResponse.status} ${languagesResponse.statusText}`);
|
|
209
212
|
return;
|
|
@@ -225,7 +228,11 @@ export async function syncCommand() {
|
|
|
225
228
|
const fetchUrl = `${baseUrl}/fetch?token=${token}&langs=${locale}&nested=${syncConfig.nested}&includeLangKey=${syncConfig.includeLangKey}&pretty=${syncConfig.pretty}&indent=${syncConfig.indent}`;
|
|
226
229
|
|
|
227
230
|
try {
|
|
228
|
-
const translationResponse = await fetch(fetchUrl
|
|
231
|
+
const translationResponse = await fetch(fetchUrl, {
|
|
232
|
+
headers: {
|
|
233
|
+
'x-kopynator-version': '1.1.0'
|
|
234
|
+
}
|
|
235
|
+
});
|
|
229
236
|
|
|
230
237
|
if (!translationResponse.ok) {
|
|
231
238
|
downloadSpinner.warn(`Failed to fetch ${locale}: ${translationResponse.status}`);
|