@transi-store/cli 1.5.2 → 1.6.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/CHANGELOG.md +6 -0
- package/dist/cli.js +180 -26
- package/dist/fetchForConfig.d.ts +4 -0
- package/dist/fetchForConfig.d.ts.map +1 -0
- package/dist/fetchTranslations.d.ts +10 -2
- package/dist/fetchTranslations.d.ts.map +1 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,29 @@ import path from "node:path";
|
|
|
5
5
|
import { pathToFileURL } from "node:url";
|
|
6
6
|
import z from "zod";
|
|
7
7
|
import { simpleGit } from "simple-git";
|
|
8
|
+
//#region \0rolldown/runtime.js
|
|
9
|
+
var __create = Object.create;
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
14
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
15
|
+
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
16
|
+
var __copyProps = (to, from, except, desc) => {
|
|
17
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
18
|
+
key = keys[i];
|
|
19
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
20
|
+
get: ((k) => from[k]).bind(null, key),
|
|
21
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
27
|
+
value: mod,
|
|
28
|
+
enumerable: true
|
|
29
|
+
}) : target, mod));
|
|
30
|
+
//#endregion
|
|
8
31
|
//#region ../common/dist/import-strategy.js
|
|
9
32
|
var ImportStrategy;
|
|
10
33
|
(function(ImportStrategy) {
|
|
@@ -38,7 +61,57 @@ const schema = z.object({
|
|
|
38
61
|
});
|
|
39
62
|
//#endregion
|
|
40
63
|
//#region src/fetchTranslations.ts
|
|
41
|
-
|
|
64
|
+
var import_picocolors_browser = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
65
|
+
var x = String;
|
|
66
|
+
var create = function() {
|
|
67
|
+
return {
|
|
68
|
+
isColorSupported: false,
|
|
69
|
+
reset: x,
|
|
70
|
+
bold: x,
|
|
71
|
+
dim: x,
|
|
72
|
+
italic: x,
|
|
73
|
+
underline: x,
|
|
74
|
+
inverse: x,
|
|
75
|
+
hidden: x,
|
|
76
|
+
strikethrough: x,
|
|
77
|
+
black: x,
|
|
78
|
+
red: x,
|
|
79
|
+
green: x,
|
|
80
|
+
yellow: x,
|
|
81
|
+
blue: x,
|
|
82
|
+
magenta: x,
|
|
83
|
+
cyan: x,
|
|
84
|
+
white: x,
|
|
85
|
+
gray: x,
|
|
86
|
+
bgBlack: x,
|
|
87
|
+
bgRed: x,
|
|
88
|
+
bgGreen: x,
|
|
89
|
+
bgYellow: x,
|
|
90
|
+
bgBlue: x,
|
|
91
|
+
bgMagenta: x,
|
|
92
|
+
bgCyan: x,
|
|
93
|
+
bgWhite: x,
|
|
94
|
+
blackBright: x,
|
|
95
|
+
redBright: x,
|
|
96
|
+
greenBright: x,
|
|
97
|
+
yellowBright: x,
|
|
98
|
+
blueBright: x,
|
|
99
|
+
magentaBright: x,
|
|
100
|
+
cyanBright: x,
|
|
101
|
+
whiteBright: x,
|
|
102
|
+
bgBlackBright: x,
|
|
103
|
+
bgRedBright: x,
|
|
104
|
+
bgGreenBright: x,
|
|
105
|
+
bgYellowBright: x,
|
|
106
|
+
bgBlueBright: x,
|
|
107
|
+
bgMagentaBright: x,
|
|
108
|
+
bgCyanBright: x,
|
|
109
|
+
bgWhiteBright: x
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
module.exports = create();
|
|
113
|
+
module.exports.createColors = create;
|
|
114
|
+
})))(), 1);
|
|
42
115
|
async function fetchTranslations({ domainRoot, apiKey, org, project, format, locale, output, branch }) {
|
|
43
116
|
const params = new URLSearchParams({
|
|
44
117
|
format,
|
|
@@ -50,54 +123,135 @@ async function fetchTranslations({ domainRoot, apiKey, org, project, format, loc
|
|
|
50
123
|
const content = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
|
|
51
124
|
if (!content.ok) {
|
|
52
125
|
const errorData = await content.text();
|
|
53
|
-
|
|
54
|
-
|
|
126
|
+
return {
|
|
127
|
+
success: false,
|
|
128
|
+
error: `${content.status} ${content.statusText} — ${errorData.trim()}`,
|
|
129
|
+
output
|
|
130
|
+
};
|
|
55
131
|
}
|
|
56
132
|
const data = await content.json();
|
|
57
|
-
if (!content.ok) {
|
|
58
|
-
console.error(`Failed to fetch translations: ${content.status} ${content.statusText}\n`, data.error);
|
|
59
|
-
process.exit(1);
|
|
60
|
-
}
|
|
61
133
|
const dir = path.dirname(output);
|
|
62
134
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
63
135
|
fs.writeFileSync(output, `${JSON.stringify(data, null, 2)}\n`, "utf-8");
|
|
64
|
-
|
|
136
|
+
return {
|
|
137
|
+
success: true,
|
|
138
|
+
output
|
|
139
|
+
};
|
|
65
140
|
} catch (error) {
|
|
66
|
-
|
|
141
|
+
return {
|
|
142
|
+
success: false,
|
|
143
|
+
error: error instanceof Error ? error.message : String(error),
|
|
144
|
+
output
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//#endregion
|
|
149
|
+
//#region src/fetchForConfig.ts
|
|
150
|
+
async function fetchTranslationsAndPrint(config) {
|
|
151
|
+
const result = await fetchTranslations(config);
|
|
152
|
+
if (result.success) console.log(`${import_picocolors_browser.default.green("✓")} ${import_picocolors_browser.default.bold(`${config.project} / ${config.locale}`)} ${import_picocolors_browser.default.dim("→")} ${result.output}`);
|
|
153
|
+
else {
|
|
154
|
+
console.error(`${import_picocolors_browser.default.red("✗")} ${import_picocolors_browser.default.bold(`${config.project} / ${config.locale}`)} — ${import_picocolors_browser.default.red(result.error)}`);
|
|
67
155
|
process.exit(1);
|
|
68
156
|
}
|
|
69
157
|
}
|
|
158
|
+
function renderProgressBar(completed, total) {
|
|
159
|
+
const barWidth = 28;
|
|
160
|
+
const filled = total === 0 ? barWidth : Math.round(completed / total * barWidth);
|
|
161
|
+
return ` [${import_picocolors_browser.default.green("█".repeat(filled)) + import_picocolors_browser.default.dim("░".repeat(barWidth - filled))}] ${import_picocolors_browser.default.bold(String(completed))}${import_picocolors_browser.default.dim(`/${total}`)}`;
|
|
162
|
+
}
|
|
70
163
|
async function fetchForConfig(configPath, apiKey, branch) {
|
|
71
164
|
const cwd = process.cwd();
|
|
72
165
|
const fullPath = path.resolve(cwd, configPath);
|
|
73
166
|
if (!fs.existsSync(fullPath)) {
|
|
74
|
-
console.error(`Config file not found: ${configPath}`);
|
|
167
|
+
console.error(import_picocolors_browser.default.red(`Config file not found: ${configPath}`));
|
|
75
168
|
process.exit(1);
|
|
76
169
|
}
|
|
77
170
|
const config = (await import(pathToFileURL(fullPath).href, { with: { type: "json" } })).default;
|
|
78
171
|
const result = schema.safeParse(config);
|
|
79
172
|
if (!result.success) {
|
|
80
173
|
const pretty = z.prettifyError(result.error);
|
|
81
|
-
console.error("Config validation error:", pretty);
|
|
174
|
+
console.error(import_picocolors_browser.default.red("Config validation error:"), pretty);
|
|
82
175
|
process.exit(1);
|
|
83
176
|
}
|
|
84
177
|
const domainRoot = result.data.domainRoot ?? "https://transi-store.com";
|
|
85
|
-
console.log(
|
|
178
|
+
console.log();
|
|
179
|
+
console.log(import_picocolors_browser.default.bold(import_picocolors_browser.default.cyan("↓ Downloading translations")));
|
|
180
|
+
console.log(import_picocolors_browser.default.dim(` Domain : ${domainRoot}`));
|
|
181
|
+
console.log(import_picocolors_browser.default.dim(` Org : ${result.data.org}`));
|
|
182
|
+
console.log(import_picocolors_browser.default.dim(` Branch : ${branch ?? import_picocolors_browser.default.italic("(main)")}`));
|
|
183
|
+
console.log();
|
|
86
184
|
const tasks = [];
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
185
|
+
const projectOrder = [];
|
|
186
|
+
const localesByProject = /* @__PURE__ */ new Map();
|
|
187
|
+
for (const configItem of result.data.projects) {
|
|
188
|
+
if (!localesByProject.has(configItem.project)) {
|
|
189
|
+
projectOrder.push(configItem.project);
|
|
190
|
+
localesByProject.set(configItem.project, []);
|
|
191
|
+
}
|
|
192
|
+
for (const locale of configItem.langs) {
|
|
193
|
+
localesByProject.get(configItem.project).push(locale);
|
|
194
|
+
tasks.push({
|
|
195
|
+
domainRoot,
|
|
196
|
+
apiKey,
|
|
197
|
+
org: result.data.org,
|
|
198
|
+
project: configItem.project,
|
|
199
|
+
format: configItem.format,
|
|
200
|
+
locale,
|
|
201
|
+
output: configItem.output.replace("<lang>", locale).replace("<project>", configItem.project).replace("<format>", configItem.format),
|
|
202
|
+
branch
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const total = tasks.length;
|
|
207
|
+
let completed = 0;
|
|
208
|
+
const isTTY = process.stdout.isTTY ?? false;
|
|
209
|
+
const resultsMap = /* @__PURE__ */ new Map();
|
|
210
|
+
for (const project of projectOrder) resultsMap.set(project, /* @__PURE__ */ new Map());
|
|
211
|
+
if (isTTY) process.stdout.write(renderProgressBar(0, total) + "\r");
|
|
212
|
+
for (let i = 0; i < tasks.length; i += 5) await Promise.all(tasks.slice(i, i + 5).map(async (task) => {
|
|
213
|
+
const fetchResult = await fetchTranslations(task);
|
|
214
|
+
completed++;
|
|
215
|
+
resultsMap.get(task.project).set(task.locale, fetchResult);
|
|
216
|
+
if (isTTY) process.stdout.write(renderProgressBar(completed, total) + "\r");
|
|
217
|
+
else {
|
|
218
|
+
const counter = import_picocolors_browser.default.dim(`[${completed}/${total}]`);
|
|
219
|
+
if (fetchResult.success) console.log(` ${counter} ${import_picocolors_browser.default.green("✓")} ${import_picocolors_browser.default.bold(`${task.project} / ${task.locale}`)}`);
|
|
220
|
+
else console.log(` ${counter} ${import_picocolors_browser.default.red("✗")} ${import_picocolors_browser.default.bold(`${task.project} / ${task.locale}`)} — ${import_picocolors_browser.default.red(fetchResult.error)}`);
|
|
221
|
+
}
|
|
222
|
+
}));
|
|
223
|
+
if (isTTY) process.stdout.write("\r\x1B[K");
|
|
224
|
+
const projectNameLen = Math.max(...projectOrder.map((p) => p.length));
|
|
225
|
+
const failures = [];
|
|
226
|
+
for (const project of projectOrder) {
|
|
227
|
+
const localeResults = resultsMap.get(project);
|
|
228
|
+
const name = import_picocolors_browser.default.bold(project.padEnd(projectNameLen + 2));
|
|
229
|
+
const statuses = [];
|
|
230
|
+
for (const locale of localesByProject.get(project)) {
|
|
231
|
+
const res = localeResults.get(locale);
|
|
232
|
+
if (!res) continue;
|
|
233
|
+
if (res.success) statuses.push(import_picocolors_browser.default.green(`✓ ${locale}`));
|
|
234
|
+
else {
|
|
235
|
+
statuses.push(import_picocolors_browser.default.red(`✗ ${locale}`));
|
|
236
|
+
failures.push({
|
|
237
|
+
label: `${project} / ${locale}`,
|
|
238
|
+
error: res.error
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
console.log(` ${name}${statuses.join(import_picocolors_browser.default.dim(" "))}`);
|
|
243
|
+
}
|
|
244
|
+
console.log();
|
|
245
|
+
const succeeded = total - failures.length;
|
|
246
|
+
if (failures.length === 0) console.log(import_picocolors_browser.default.green(import_picocolors_browser.default.bold(`✓ All ${total} translation${total > 1 ? "s" : ""} downloaded successfully`)));
|
|
247
|
+
else {
|
|
248
|
+
if (succeeded > 0) console.log(import_picocolors_browser.default.green(`✓ ${succeeded} translation${succeeded > 1 ? "s" : ""} downloaded`));
|
|
249
|
+
console.log(import_picocolors_browser.default.red(import_picocolors_browser.default.bold(`✗ ${failures.length} failed:`)));
|
|
250
|
+
for (const failure of failures) console.log(import_picocolors_browser.default.red(` · ${failure.label}: ${failure.error}`));
|
|
251
|
+
console.log();
|
|
252
|
+
process.exit(1);
|
|
99
253
|
}
|
|
100
|
-
|
|
254
|
+
console.log();
|
|
101
255
|
}
|
|
102
256
|
//#endregion
|
|
103
257
|
//#region src/git.ts
|
|
@@ -245,7 +399,7 @@ async function uploadForConfig(configPath, apiKey, strategy, branch) {
|
|
|
245
399
|
const program = new Command();
|
|
246
400
|
const apiKeyOption = new Option("-k, --api-key <apiKey>", "API key for authentication").env("TRANSI_STORE_API_KEY").makeOptionMandatory();
|
|
247
401
|
program.command("download").description("Download translations for a project").addOption(apiKeyOption).requiredOption("-d, --domain-root <domainRoot>", "Root domain to download translations from (default is https://transi-store.com)", DEFAULT_DOMAIN_ROOT).requiredOption("-o, --org <org>", "Organization slug").requiredOption("-p, --project <project>", "Project slug").requiredOption("-l, --locale <locale>", "Locale to export").requiredOption("-O, --output <output>", "Output file path").option("-f, --format <format>", "Export format (json, csv, etc.)", "json").option("-b, --branch <branch>", `Branch slug (exports main + branch keys). Use "${ALL_BRANCHES_VALUE}" to export all branches`).action((options) => {
|
|
248
|
-
|
|
402
|
+
fetchTranslationsAndPrint(options);
|
|
249
403
|
});
|
|
250
404
|
program.command("upload").description("Upload translations for a project").addOption(apiKeyOption).requiredOption("-d, --domain-root <domainRoot>", "Root domain to upload translations to (default is https://transi-store.com)", DEFAULT_DOMAIN_ROOT).requiredOption("-o, --org <org>", "Organization slug").requiredOption("-p, --project <project>", "Project slug").requiredOption("-l, --locale <locale>", "Target locale").requiredOption("-I, --input <input>", "Input file path (JSON or XLIFF)").option("-s, --strategy <strategy>", `Import strategy: '${ImportStrategy.OVERWRITE}' or '${ImportStrategy.SKIP}' existing translations`, ImportStrategy.SKIP).option("-f, --format <format>", "File format (json or xliff). Auto-detected from extension if omitted").option("-b, --branch <branch>", "Branch slug (new keys will be created on this branch)").action((options) => {
|
|
251
405
|
const strategy = options.strategy;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type Config } from "./fetchTranslations.ts";
|
|
2
|
+
export declare function fetchTranslationsAndPrint(config: Config): Promise<void>;
|
|
3
|
+
export declare function fetchForConfig(configPath: string, apiKey: string, branch?: string): Promise<void>;
|
|
4
|
+
//# sourceMappingURL=fetchForConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetchForConfig.d.ts","sourceRoot":"","sources":["../src/fetchForConfig.ts"],"names":[],"mappings":"AAOA,OAAO,EAGL,KAAK,MAAM,EAEZ,MAAM,wBAAwB,CAAC;AAEhC,wBAAsB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAY7E;AAWD,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CA2Jf"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare const CONCURRENCY_CALLS = 5;
|
|
1
2
|
export type Config = {
|
|
2
3
|
domainRoot: string;
|
|
3
4
|
org: string;
|
|
@@ -8,6 +9,13 @@ export type Config = {
|
|
|
8
9
|
output: string;
|
|
9
10
|
branch?: string | undefined;
|
|
10
11
|
};
|
|
11
|
-
export
|
|
12
|
-
|
|
12
|
+
export type FetchResult = {
|
|
13
|
+
success: true;
|
|
14
|
+
output: string;
|
|
15
|
+
} | {
|
|
16
|
+
success: false;
|
|
17
|
+
error: string;
|
|
18
|
+
output: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function fetchTranslations({ domainRoot, apiKey, org, project, format, locale, output, branch, }: Config): Promise<FetchResult>;
|
|
13
21
|
//# sourceMappingURL=fetchTranslations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetchTranslations.d.ts","sourceRoot":"","sources":["../src/fetchTranslations.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fetchTranslations.d.ts","sourceRoot":"","sources":["../src/fetchTranslations.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,MAAM,MAAM,MAAM,GAAG;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,WAAW,GACnB;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD,wBAAsB,iBAAiB,CAAC,EACtC,UAAU,EACV,MAAM,EACN,GAAG,EACH,OAAO,EACP,MAAM,EACN,MAAM,EACN,MAAM,EACN,MAAM,GACP,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAwC/B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@transi-store/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/cli.js",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@commander-js/extra-typings": "^14.0.0",
|
|
14
14
|
"commander": "^14.0.3",
|
|
15
|
+
"picocolors": "^1.1.1",
|
|
15
16
|
"simple-git": "^3.33.0",
|
|
16
17
|
"zod": "^4.3.6"
|
|
17
18
|
},
|