@saidksi/localizer-cli 0.1.1
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/LICENSE +21 -0
- package/README.md +99 -0
- package/dist/bin/localize.d.ts +3 -0
- package/dist/bin/localize.d.ts.map +1 -0
- package/dist/bin/localize.js +7 -0
- package/dist/bin/localize.js.map +1 -0
- package/dist/commands/add-lang.d.ts +3 -0
- package/dist/commands/add-lang.d.ts.map +1 -0
- package/dist/commands/add-lang.js +103 -0
- package/dist/commands/add-lang.js.map +1 -0
- package/dist/commands/audit.d.ts +3 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +174 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/diff.d.ts +3 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +76 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +427 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/rewrite.d.ts +3 -0
- package/dist/commands/rewrite.d.ts.map +1 -0
- package/dist/commands/rewrite.js +140 -0
- package/dist/commands/rewrite.js.map +1 -0
- package/dist/commands/run.d.ts +3 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +324 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/scan.d.ts +3 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +121 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +128 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/translate.d.ts +3 -0
- package/dist/commands/translate.d.ts.map +1 -0
- package/dist/commands/translate.js +233 -0
- package/dist/commands/translate.js.map +1 -0
- package/dist/commands/validate.d.ts +3 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +121 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/config.d.ts +30 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +94 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/diff.d.ts +10 -0
- package/dist/utils/diff.d.ts.map +1 -0
- package/dist/utils/diff.js +31 -0
- package/dist/utils/diff.js.map +1 -0
- package/dist/utils/json.d.ts +3 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +15 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/logger.d.ts +28 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +48 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/prompt.d.ts +18 -0
- package/dist/utils/prompt.d.ts.map +1 -0
- package/dist/utils/prompt.js +65 -0
- package/dist/utils/prompt.js.map +1 -0
- package/dist/utils/reporter.d.ts +17 -0
- package/dist/utils/reporter.d.ts.map +1 -0
- package/dist/utils/reporter.js +87 -0
- package/dist/utils/reporter.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { readFile, readdir, access } from "fs/promises";
|
|
3
|
+
import { join, resolve } from "path";
|
|
4
|
+
import ora from "ora";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import { scanDirectory, validateApiKey } from "@saidksi/localizer-core";
|
|
7
|
+
import { logger } from "../utils/logger.js";
|
|
8
|
+
import { saveApiKey, writeProjectConfig } from "../utils/config.js";
|
|
9
|
+
import { promptConfirm, promptSelect, promptMultiselect, promptInput, promptSecret, } from "../utils/prompt.js";
|
|
10
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
11
|
+
const COMMON_LANGUAGES = [
|
|
12
|
+
{ name: "Arabic (ar)", value: "ar" },
|
|
13
|
+
{ name: "Chinese Simplified (zh)", value: "zh" },
|
|
14
|
+
{ name: "Czech (cs)", value: "cs" },
|
|
15
|
+
{ name: "Danish (da)", value: "da" },
|
|
16
|
+
{ name: "Dutch (nl)", value: "nl" },
|
|
17
|
+
{ name: "English (en)", value: "en" },
|
|
18
|
+
{ name: "Finnish (fi)", value: "fi" },
|
|
19
|
+
{ name: "French (fr)", value: "fr" },
|
|
20
|
+
{ name: "German (de)", value: "de" },
|
|
21
|
+
{ name: "Greek (el)", value: "el" },
|
|
22
|
+
{ name: "Hebrew (he)", value: "he" },
|
|
23
|
+
{ name: "Hindi (hi)", value: "hi" },
|
|
24
|
+
{ name: "Hungarian (hu)", value: "hu" },
|
|
25
|
+
{ name: "Indonesian (id)", value: "id" },
|
|
26
|
+
{ name: "Italian (it)", value: "it" },
|
|
27
|
+
{ name: "Japanese (ja)", value: "ja" },
|
|
28
|
+
{ name: "Korean (ko)", value: "ko" },
|
|
29
|
+
{ name: "Norwegian (nb)", value: "nb" },
|
|
30
|
+
{ name: "Polish (pl)", value: "pl" },
|
|
31
|
+
{ name: "Portuguese (pt)", value: "pt" },
|
|
32
|
+
{ name: "Romanian (ro)", value: "ro" },
|
|
33
|
+
{ name: "Russian (ru)", value: "ru" },
|
|
34
|
+
{ name: "Spanish (es)", value: "es" },
|
|
35
|
+
{ name: "Swedish (sv)", value: "sv" },
|
|
36
|
+
{ name: "Thai (th)", value: "th" },
|
|
37
|
+
{ name: "Turkish (tr)", value: "tr" },
|
|
38
|
+
{ name: "Ukrainian (uk)", value: "uk" },
|
|
39
|
+
{ name: "Vietnamese (vi)", value: "vi" },
|
|
40
|
+
];
|
|
41
|
+
const ANTHROPIC_MODELS = [
|
|
42
|
+
{ name: "Claude Sonnet 4.6 (recommended)", value: "claude-sonnet-4-6" },
|
|
43
|
+
{ name: "Claude Opus 4.6 (most capable)", value: "claude-opus-4-6" },
|
|
44
|
+
{ name: "Claude Haiku 4.5 (fastest)", value: "claude-haiku-4-5" },
|
|
45
|
+
];
|
|
46
|
+
const OPENAI_MODELS = [
|
|
47
|
+
{ name: "GPT-4o (recommended)", value: "gpt-4o" },
|
|
48
|
+
{ name: "GPT-4 Turbo", value: "gpt-4-turbo" },
|
|
49
|
+
{ name: "GPT-3.5 Turbo", value: "gpt-3.5-turbo" },
|
|
50
|
+
];
|
|
51
|
+
const PRESETS = {
|
|
52
|
+
nextjs: {
|
|
53
|
+
include: ["./app", "./src"],
|
|
54
|
+
exclude: ["node_modules", "dist", ".next", "**/*.test.*", "**/*.stories.*"],
|
|
55
|
+
i18nLibrary: "next-intl",
|
|
56
|
+
keyStyle: "dot.notation",
|
|
57
|
+
aiProvider: "anthropic",
|
|
58
|
+
aiModel: "claude-sonnet-4-6",
|
|
59
|
+
messagesDir: "./messages",
|
|
60
|
+
},
|
|
61
|
+
expo: {
|
|
62
|
+
include: ["./src", "./app"],
|
|
63
|
+
exclude: ["node_modules", "dist", "**/*.test.*"],
|
|
64
|
+
i18nLibrary: "react-i18next",
|
|
65
|
+
keyStyle: "dot.notation",
|
|
66
|
+
aiProvider: "anthropic",
|
|
67
|
+
aiModel: "claude-sonnet-4-6",
|
|
68
|
+
messagesDir: "./messages",
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
72
|
+
async function detectFramework(cwd) {
|
|
73
|
+
try {
|
|
74
|
+
const raw = await readFile(join(cwd, "package.json"), "utf-8");
|
|
75
|
+
const pkg = JSON.parse(raw);
|
|
76
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
77
|
+
if (deps["next"])
|
|
78
|
+
return "Next.js";
|
|
79
|
+
if (deps["expo"])
|
|
80
|
+
return "Expo";
|
|
81
|
+
if (deps["vue"])
|
|
82
|
+
return "Vue";
|
|
83
|
+
if (deps["svelte"])
|
|
84
|
+
return "Svelte";
|
|
85
|
+
if (deps["react"])
|
|
86
|
+
return "React";
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async function detectI18nLibrary(cwd) {
|
|
94
|
+
try {
|
|
95
|
+
const raw = await readFile(join(cwd, "package.json"), "utf-8");
|
|
96
|
+
const pkg = JSON.parse(raw);
|
|
97
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
98
|
+
if (deps["next-intl"])
|
|
99
|
+
return "next-intl";
|
|
100
|
+
if (deps["react-intl"])
|
|
101
|
+
return "react-intl";
|
|
102
|
+
if (deps["react-i18next"])
|
|
103
|
+
return "react-i18next";
|
|
104
|
+
if (deps["vue-i18n"])
|
|
105
|
+
return "vue-i18n";
|
|
106
|
+
if (deps["i18next"])
|
|
107
|
+
return "i18next";
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function detectExistingLanguages(messagesDir) {
|
|
115
|
+
try {
|
|
116
|
+
const entries = await readdir(messagesDir, { withFileTypes: true });
|
|
117
|
+
return entries
|
|
118
|
+
.filter((e) => e.isDirectory())
|
|
119
|
+
.map((e) => e.name)
|
|
120
|
+
.filter((n) => /^[a-z]{2}(-[A-Z]{2})?$/.test(n));
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async function fileExists(filePath) {
|
|
127
|
+
try {
|
|
128
|
+
await access(filePath);
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function smartDefaultIncludes(framework) {
|
|
136
|
+
if (framework === "Next.js")
|
|
137
|
+
return ["./app", "./src"];
|
|
138
|
+
if (framework === "Expo")
|
|
139
|
+
return ["./src", "./app"];
|
|
140
|
+
return ["./src"];
|
|
141
|
+
}
|
|
142
|
+
function smartDefaultLibrary(framework) {
|
|
143
|
+
if (framework === "Next.js")
|
|
144
|
+
return "next-intl";
|
|
145
|
+
if (framework === "Vue")
|
|
146
|
+
return "vue-i18n";
|
|
147
|
+
return "react-i18next";
|
|
148
|
+
}
|
|
149
|
+
async function runWizard(cwd, options) {
|
|
150
|
+
logger.blank();
|
|
151
|
+
logger.raw(chalk.bold(" localize init"));
|
|
152
|
+
logger.blank();
|
|
153
|
+
// ── Step 1: Detect framework and i18n library
|
|
154
|
+
const framework = await detectFramework(cwd);
|
|
155
|
+
if (framework) {
|
|
156
|
+
logger.info(`Detected framework: ${chalk.cyan(framework)}`);
|
|
157
|
+
}
|
|
158
|
+
const detectedI18nLibrary = await detectI18nLibrary(cwd);
|
|
159
|
+
if (detectedI18nLibrary) {
|
|
160
|
+
logger.info(`Detected i18n library: ${chalk.cyan(detectedI18nLibrary)}`);
|
|
161
|
+
}
|
|
162
|
+
// ── Step 2: Check existing config
|
|
163
|
+
const configPath = resolve(cwd, ".localize", "config.json");
|
|
164
|
+
const configExists = await fileExists(configPath);
|
|
165
|
+
if (configExists && !options.reset) {
|
|
166
|
+
const choice = await promptSelect("A .localize/config.json already exists. What would you like to do?", [
|
|
167
|
+
{ name: "Overwrite it", value: "overwrite" },
|
|
168
|
+
{ name: "Abort", value: "abort" },
|
|
169
|
+
]);
|
|
170
|
+
if (choice === "abort") {
|
|
171
|
+
logger.warn("Aborted.");
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// ── Apply preset (skips most wizard steps)
|
|
176
|
+
if (options.preset) {
|
|
177
|
+
const preset = PRESETS[options.preset];
|
|
178
|
+
if (!preset)
|
|
179
|
+
logger.fatal(`Unknown preset "${options.preset}". Available: nextjs, expo`);
|
|
180
|
+
await runPresetFlow(cwd, preset, framework, detectedI18nLibrary);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
// ── Step 3: Check existing messages directory
|
|
184
|
+
const defaultMessagesDir = "./messages";
|
|
185
|
+
const messagesAbsolute = resolve(cwd, defaultMessagesDir);
|
|
186
|
+
const existingLanguages = await detectExistingLanguages(messagesAbsolute);
|
|
187
|
+
const hasExistingTranslations = existingLanguages.length > 0;
|
|
188
|
+
let defaultLanguage;
|
|
189
|
+
let targetLanguages;
|
|
190
|
+
if (hasExistingTranslations) {
|
|
191
|
+
// ── Branch A: existing translations found
|
|
192
|
+
logger.info(`Found existing languages: ${chalk.cyan(existingLanguages.join(", "))}`);
|
|
193
|
+
defaultLanguage = await promptSelect("Which is your default (source) language?", existingLanguages.map((l) => ({
|
|
194
|
+
name: COMMON_LANGUAGES.find((c) => c.value === l)?.name ?? l,
|
|
195
|
+
value: l,
|
|
196
|
+
})));
|
|
197
|
+
const addMore = await promptConfirm("Add more target languages (can add more later)?", false);
|
|
198
|
+
if (addMore) {
|
|
199
|
+
const extra = await promptMultiselect("Select additional target languages:", COMMON_LANGUAGES.filter((l) => !existingLanguages.includes(l.value)));
|
|
200
|
+
targetLanguages = [...existingLanguages.filter((l) => l !== defaultLanguage), ...extra];
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
targetLanguages = existingLanguages.filter((l) => l !== defaultLanguage);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
// ── Branch B: no existing translations
|
|
208
|
+
defaultLanguage = await promptSelect("Default (source) language:", COMMON_LANGUAGES);
|
|
209
|
+
targetLanguages = await promptMultiselect("Target languages to translate into:", COMMON_LANGUAGES.filter((l) => l.value !== defaultLanguage));
|
|
210
|
+
if (targetLanguages.length === 0) {
|
|
211
|
+
logger.warn("No target languages selected. You can add them later with `localize add-lang`.");
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// ── Step 5: Directories to include
|
|
215
|
+
const defaultIncludes = smartDefaultIncludes(framework).join(", ");
|
|
216
|
+
const includeRaw = await promptInput("Directories to scan (comma-separated):", defaultIncludes);
|
|
217
|
+
const include = includeRaw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
218
|
+
// ── Step 6: Directories to exclude
|
|
219
|
+
const excludeRaw = await promptInput("Patterns to exclude (comma-separated):", "node_modules, dist, .next, **/*.test.*, **/*.stories.*");
|
|
220
|
+
const exclude = excludeRaw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
221
|
+
// ── Step 7: AI provider + model
|
|
222
|
+
const aiProvider = await promptSelect("AI provider:", [
|
|
223
|
+
{ name: "Anthropic (Claude)", value: "anthropic" },
|
|
224
|
+
{ name: "OpenAI (GPT)", value: "openai" },
|
|
225
|
+
]);
|
|
226
|
+
const modelChoices = aiProvider === "anthropic" ? ANTHROPIC_MODELS : OPENAI_MODELS;
|
|
227
|
+
const aiModel = await promptSelect("Model:", modelChoices);
|
|
228
|
+
// ── Step 8: Key style
|
|
229
|
+
const keyStyle = await promptSelect("Key naming style:", [
|
|
230
|
+
{ name: "dot.notation (auth.sign_in_button)", value: "dot.notation" },
|
|
231
|
+
{ name: "snake_case (auth_sign_in_button)", value: "snake_case" },
|
|
232
|
+
]);
|
|
233
|
+
// ── Step 9: i18n library
|
|
234
|
+
let i18nLibrary;
|
|
235
|
+
if (detectedI18nLibrary) {
|
|
236
|
+
// Auto-use detected library (skip prompt)
|
|
237
|
+
i18nLibrary = detectedI18nLibrary;
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
// Prompt if not detected
|
|
241
|
+
const defaultLibrary = smartDefaultLibrary(framework);
|
|
242
|
+
const i18nLibraryChoices = [
|
|
243
|
+
{ name: "react-i18next", value: "react-i18next" },
|
|
244
|
+
{ name: "next-intl", value: "next-intl" },
|
|
245
|
+
{ name: "react-intl", value: "react-intl" },
|
|
246
|
+
{ name: "vue-i18n", value: "vue-i18n" },
|
|
247
|
+
{ name: "i18next", value: "i18next" },
|
|
248
|
+
];
|
|
249
|
+
i18nLibrary = await promptSelect("i18n library:", i18nLibraryChoices.map((c) => ({
|
|
250
|
+
...c,
|
|
251
|
+
name: c.value === defaultLibrary ? `${c.name} (recommended for ${framework ?? "this project"})` : c.name,
|
|
252
|
+
})));
|
|
253
|
+
}
|
|
254
|
+
// ── Step 10: Strict mode
|
|
255
|
+
const strictMode = await promptConfirm("Enable strict mode? (validate exits with code 1 on any missing key)", false);
|
|
256
|
+
// ── Step 11: API key
|
|
257
|
+
const envVar = aiProvider === "anthropic" ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
|
|
258
|
+
const envKey = process.env[envVar];
|
|
259
|
+
let apiKey = envKey ?? null;
|
|
260
|
+
if (envKey) {
|
|
261
|
+
logger.success(`Found ${envVar} in environment.`);
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
const enterKey = await promptConfirm(`No ${envVar} found. Enter your ${aiProvider} API key now?`, true);
|
|
265
|
+
if (enterKey) {
|
|
266
|
+
apiKey = await promptSecret(`${aiProvider} API key:`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// ── Step 12: Validate API key
|
|
270
|
+
if (apiKey) {
|
|
271
|
+
const spinner = ora("Validating API key...").start();
|
|
272
|
+
const valid = await validateApiKey(aiProvider, aiModel, apiKey);
|
|
273
|
+
if (valid) {
|
|
274
|
+
spinner.succeed("API key is valid.");
|
|
275
|
+
if (!envKey) {
|
|
276
|
+
const save = await promptConfirm("Save key to .localize/.keys for future use?", true);
|
|
277
|
+
if (save) {
|
|
278
|
+
await saveApiKey(aiProvider, apiKey);
|
|
279
|
+
logger.success("Key saved to .localize/.keys");
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
spinner.fail("API key validation failed.");
|
|
285
|
+
const proceed = await promptConfirm("Continue anyway?", false);
|
|
286
|
+
if (!proceed)
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// ── Step 13: Build config + confirm
|
|
291
|
+
const config = {
|
|
292
|
+
defaultLanguage,
|
|
293
|
+
languages: targetLanguages,
|
|
294
|
+
messagesDir: defaultMessagesDir,
|
|
295
|
+
include,
|
|
296
|
+
exclude,
|
|
297
|
+
aiProvider,
|
|
298
|
+
aiModel,
|
|
299
|
+
keyStyle,
|
|
300
|
+
i18nLibrary,
|
|
301
|
+
overwriteExisting: false,
|
|
302
|
+
strictMode,
|
|
303
|
+
glossary: {},
|
|
304
|
+
};
|
|
305
|
+
logger.blank();
|
|
306
|
+
logger.header(" Config summary:");
|
|
307
|
+
logger.raw(chalk.dim(JSON.stringify(config, null, 2).replace(/^/gm, " ")));
|
|
308
|
+
logger.blank();
|
|
309
|
+
const write = await promptConfirm("Write this config?", true);
|
|
310
|
+
if (!write) {
|
|
311
|
+
logger.warn("Aborted — nothing written.");
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
await writeProjectConfig(config, cwd);
|
|
315
|
+
logger.success(`Wrote .localize/config.json`);
|
|
316
|
+
// ── Step 14: Gitignore — ensure .localize/ itself is NOT gitignored
|
|
317
|
+
// (config.json is committed; only .keys and cache.json are gitignored via .localize/.gitignore)
|
|
318
|
+
logger.dim("Created .localize/.gitignore (ignores .keys and cache.json)");
|
|
319
|
+
// ── Step 14: Fast pre-scan estimate
|
|
320
|
+
await runPreScanEstimate(cwd, config);
|
|
321
|
+
// ── Step 15: What's next
|
|
322
|
+
printWhatsNext(config);
|
|
323
|
+
}
|
|
324
|
+
// ─── Preset flow (abbreviated wizard) ────────────────────────────────────────
|
|
325
|
+
async function runPresetFlow(cwd, preset, framework, detectedI18nLibrary) {
|
|
326
|
+
logger.info(`Applying preset defaults for ${chalk.cyan(framework ?? "this project")}`);
|
|
327
|
+
const defaultLanguage = await promptSelect("Default (source) language:", COMMON_LANGUAGES);
|
|
328
|
+
const targetLanguages = await promptMultiselect("Target languages:", COMMON_LANGUAGES.filter((l) => l.value !== defaultLanguage));
|
|
329
|
+
const aiProvider = (preset.aiProvider ?? "anthropic");
|
|
330
|
+
const aiModel = preset.aiModel ?? "claude-sonnet-4-6";
|
|
331
|
+
const envVar = aiProvider === "anthropic" ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
|
|
332
|
+
const envKey = process.env[envVar];
|
|
333
|
+
let apiKey = envKey ?? null;
|
|
334
|
+
if (!envKey) {
|
|
335
|
+
const enter = await promptConfirm(`Enter ${aiProvider} API key?`, true);
|
|
336
|
+
if (enter) {
|
|
337
|
+
apiKey = await promptSecret(`${aiProvider} API key:`);
|
|
338
|
+
if (apiKey) {
|
|
339
|
+
const spinner = ora("Validating API key...").start();
|
|
340
|
+
const valid = await validateApiKey(aiProvider, aiModel, apiKey);
|
|
341
|
+
valid ? spinner.succeed("Valid.") : spinner.fail("Invalid key.");
|
|
342
|
+
if (valid) {
|
|
343
|
+
await saveApiKey(aiProvider, apiKey);
|
|
344
|
+
logger.success("Key saved to .localize/.keys");
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
const config = {
|
|
350
|
+
defaultLanguage,
|
|
351
|
+
languages: targetLanguages,
|
|
352
|
+
messagesDir: preset.messagesDir ?? "./messages",
|
|
353
|
+
include: preset.include ?? ["./src"],
|
|
354
|
+
exclude: preset.exclude ?? ["node_modules", "dist"],
|
|
355
|
+
aiProvider,
|
|
356
|
+
aiModel,
|
|
357
|
+
keyStyle: (preset.keyStyle ?? "dot.notation"),
|
|
358
|
+
i18nLibrary: detectedI18nLibrary ?? (preset.i18nLibrary ?? "react-i18next"),
|
|
359
|
+
overwriteExisting: false,
|
|
360
|
+
strictMode: false,
|
|
361
|
+
glossary: {},
|
|
362
|
+
};
|
|
363
|
+
const write = await promptConfirm("Write config?", true);
|
|
364
|
+
if (!write) {
|
|
365
|
+
logger.warn("Aborted.");
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
await writeProjectConfig(config, cwd);
|
|
369
|
+
logger.success("Wrote .localize/config.json");
|
|
370
|
+
await runPreScanEstimate(cwd, config);
|
|
371
|
+
printWhatsNext(config);
|
|
372
|
+
}
|
|
373
|
+
// ─── Pre-scan estimate ────────────────────────────────────────────────────────
|
|
374
|
+
async function runPreScanEstimate(cwd, config) {
|
|
375
|
+
logger.blank();
|
|
376
|
+
const spinner = ora("Running fast pre-scan to estimate work...").start();
|
|
377
|
+
try {
|
|
378
|
+
const results = await Promise.all(config.include.map((dir) => scanDirectory(resolve(cwd, dir), config).catch(() => [])));
|
|
379
|
+
const allResults = results.flat();
|
|
380
|
+
const unique = new Set(allResults.map((r) => r.value)).size;
|
|
381
|
+
const estimatedCost = (unique * 0.001).toFixed(3);
|
|
382
|
+
spinner.succeed(`Pre-scan complete.`);
|
|
383
|
+
logger.dim(`Found ~${allResults.length} strings (${unique} unique) across ${config.include.join(", ")}`);
|
|
384
|
+
logger.dim(`Estimated AI cost for first full run: ~$${estimatedCost}`);
|
|
385
|
+
}
|
|
386
|
+
catch {
|
|
387
|
+
spinner.warn("Pre-scan skipped — source directories not found yet.");
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
// ─── What's next panel ────────────────────────────────────────────────────────
|
|
391
|
+
function printWhatsNext(config) {
|
|
392
|
+
logger.blank();
|
|
393
|
+
logger.raw(chalk.bold(" What's next:"));
|
|
394
|
+
logger.blank();
|
|
395
|
+
logger.raw(` ${chalk.dim("# See all untranslated strings across your app")}`);
|
|
396
|
+
logger.raw(` ${chalk.cyan("localize audit")}`);
|
|
397
|
+
logger.blank();
|
|
398
|
+
logger.raw(` ${chalk.dim("# Localize a single file (scan → translate → rewrite → validate)")}`);
|
|
399
|
+
logger.raw(` ${chalk.cyan("localize run --file ./src/pages/Login.tsx")}`);
|
|
400
|
+
logger.blank();
|
|
401
|
+
if (config.languages.length > 0) {
|
|
402
|
+
logger.raw(` ${chalk.dim("# Check key coverage across all languages")}`);
|
|
403
|
+
logger.raw(` ${chalk.cyan("localize validate")}`);
|
|
404
|
+
logger.blank();
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
// ─── Command export ───────────────────────────────────────────────────────────
|
|
408
|
+
export const initCommand = new Command("init")
|
|
409
|
+
.description("Interactive setup wizard — creates .localize.config.json")
|
|
410
|
+
.option("--reset", "Wipe existing config and start fresh")
|
|
411
|
+
.option("--preset <name>", "Skip wizard, apply preset defaults (nextjs | expo)")
|
|
412
|
+
.action(async (options) => {
|
|
413
|
+
try {
|
|
414
|
+
await runWizard(process.cwd(), options);
|
|
415
|
+
}
|
|
416
|
+
catch (err) {
|
|
417
|
+
// Gracefully handle Ctrl+C during prompts
|
|
418
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
419
|
+
if (msg.includes("User force closed") || msg.includes("ExitPromptError")) {
|
|
420
|
+
logger.blank();
|
|
421
|
+
logger.warn("Init cancelled.");
|
|
422
|
+
process.exit(0);
|
|
423
|
+
}
|
|
424
|
+
logger.fatal(msg);
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rewrite.d.ts","sourceRoot":"","sources":["../../src/commands/rewrite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8KpC,eAAO,MAAM,cAAc,SAYvB,CAAC"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { resolve, relative } from "path";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import ora from "ora";
|
|
5
|
+
import { scanFile, scanDirectory, rewriteFile, applyRewrite, groupResultsByFile, resolveKeysFromMessages, } from "@saidksi/localizer-core";
|
|
6
|
+
import { logger } from "../utils/logger.js";
|
|
7
|
+
import { loadConfig } from "../utils/config.js";
|
|
8
|
+
import { promptApplyChanges } from "../utils/prompt.js";
|
|
9
|
+
import { printDiff } from "../utils/diff.js";
|
|
10
|
+
// ─── Per-file rewrite flow ────────────────────────────────────────────────────
|
|
11
|
+
/**
|
|
12
|
+
* Rewrite a single file:
|
|
13
|
+
* 1. Show diff
|
|
14
|
+
* 2. Ask for confirmation (unless --yes or --dry-run)
|
|
15
|
+
* 3. Write to disk on confirmation
|
|
16
|
+
*
|
|
17
|
+
* Returns the RewriteResult (applied: true if written).
|
|
18
|
+
*/
|
|
19
|
+
async function processOneFile(filePath, results, options, config) {
|
|
20
|
+
const cwd = process.cwd();
|
|
21
|
+
const relPath = relative(cwd, filePath);
|
|
22
|
+
const rewrite = await rewriteFile(filePath, results, config);
|
|
23
|
+
if (rewrite.changesCount === 0) {
|
|
24
|
+
logger.dim(`${relPath} — no changes (all strings already translated or keys unresolved)`);
|
|
25
|
+
return rewrite;
|
|
26
|
+
}
|
|
27
|
+
// Show file header + diff
|
|
28
|
+
logger.blank();
|
|
29
|
+
logger.raw(` ${chalk.bold(chalk.cyan(relPath))} ` +
|
|
30
|
+
chalk.dim(`(${rewrite.changesCount} change${rewrite.changesCount !== 1 ? "s" : ""})`));
|
|
31
|
+
logger.blank();
|
|
32
|
+
printDiff(rewrite.diff);
|
|
33
|
+
logger.blank();
|
|
34
|
+
if (options.dryRun) {
|
|
35
|
+
logger.dim(" Dry run — skipping write.");
|
|
36
|
+
return rewrite;
|
|
37
|
+
}
|
|
38
|
+
if (options.yes) {
|
|
39
|
+
const applied = await applyRewrite(rewrite);
|
|
40
|
+
logger.success(`Applied changes to ${relPath}`);
|
|
41
|
+
return applied;
|
|
42
|
+
}
|
|
43
|
+
const confirmed = await promptApplyChanges(relPath);
|
|
44
|
+
if (confirmed) {
|
|
45
|
+
const applied = await applyRewrite(rewrite);
|
|
46
|
+
logger.success(`Applied changes to ${relPath}`);
|
|
47
|
+
return applied;
|
|
48
|
+
}
|
|
49
|
+
logger.warn(`Skipped ${relPath}`);
|
|
50
|
+
return rewrite;
|
|
51
|
+
}
|
|
52
|
+
async function runRewrite(options) {
|
|
53
|
+
const cwd = process.cwd();
|
|
54
|
+
const config = await loadConfig(cwd).catch((err) => logger.fatal(err instanceof Error ? err.message : String(err)));
|
|
55
|
+
// ── Step 1: Scan
|
|
56
|
+
const scanSpinner = ora("Scanning...").start();
|
|
57
|
+
let rawResults = [];
|
|
58
|
+
try {
|
|
59
|
+
if (options.file) {
|
|
60
|
+
rawResults = await scanFile(resolve(cwd, options.file), config);
|
|
61
|
+
}
|
|
62
|
+
else if (options.dir) {
|
|
63
|
+
rawResults = await scanDirectory(resolve(cwd, options.dir), config);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
const all = await Promise.all(config.include.map((d) => scanDirectory(resolve(cwd, d), config).catch(() => [])));
|
|
67
|
+
rawResults = all.flat();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
scanSpinner.fail("Scan failed.");
|
|
72
|
+
logger.fatal(err instanceof Error ? err.message : String(err));
|
|
73
|
+
}
|
|
74
|
+
scanSpinner.succeed(`Scanned ${new Set(rawResults.map((r) => r.file)).size} file(s).`);
|
|
75
|
+
// ── Step 2: Resolve keys from messages JSON
|
|
76
|
+
// (populated in memory when called from `run`; recovered from disk when standalone)
|
|
77
|
+
const resolveSpinner = ora("Resolving keys from messages JSON...").start();
|
|
78
|
+
const results = await resolveKeysFromMessages(rawResults, config);
|
|
79
|
+
const resolvable = results.filter((r) => r.resolvedKey !== null && !r.alreadyTranslated);
|
|
80
|
+
resolveSpinner.succeed(`${resolvable.length} string${resolvable.length !== 1 ? "s" : ""} ready to rewrite` +
|
|
81
|
+
(results.length - resolvable.length > 0
|
|
82
|
+
? chalk.dim(` (${results.length - resolvable.length} skipped — no key found, run translate first)`)
|
|
83
|
+
: ""));
|
|
84
|
+
if (resolvable.length === 0) {
|
|
85
|
+
logger.blank();
|
|
86
|
+
logger.info("Nothing to rewrite. Run `localize translate` first to generate keys.");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
// ── Step 3: Process file by file
|
|
90
|
+
const byFile = groupResultsByFile(resolvable);
|
|
91
|
+
const fileList = [...byFile.keys()];
|
|
92
|
+
logger.blank();
|
|
93
|
+
if (!options.yes && !options.dryRun) {
|
|
94
|
+
logger.raw(chalk.dim(` Processing ${fileList.length} file${fileList.length !== 1 ? "s" : ""} — you will be asked to confirm each diff.\n`));
|
|
95
|
+
}
|
|
96
|
+
let applied = 0;
|
|
97
|
+
let skipped = 0;
|
|
98
|
+
let totalChanges = 0;
|
|
99
|
+
for (const [filePath, fileResults] of byFile) {
|
|
100
|
+
const rewriteResult = await processOneFile(filePath, fileResults, options, config);
|
|
101
|
+
if (rewriteResult.applied) {
|
|
102
|
+
applied++;
|
|
103
|
+
totalChanges += rewriteResult.changesCount;
|
|
104
|
+
}
|
|
105
|
+
else if (rewriteResult.changesCount > 0) {
|
|
106
|
+
skipped++;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// ── Summary
|
|
110
|
+
logger.blank();
|
|
111
|
+
if (options.dryRun) {
|
|
112
|
+
logger.raw(chalk.bold(" Dry run summary:"));
|
|
113
|
+
logger.dim(` ${fileList.length} file${fileList.length !== 1 ? "s" : ""} would be rewritten.`);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
logger.raw(chalk.bold(" Rewrite summary:"));
|
|
117
|
+
if (applied > 0) {
|
|
118
|
+
logger.success(`${applied} file${applied !== 1 ? "s" : ""} rewritten (${totalChanges} string${totalChanges !== 1 ? "s" : ""} replaced).`);
|
|
119
|
+
}
|
|
120
|
+
if (skipped > 0) {
|
|
121
|
+
logger.warn(`${skipped} file${skipped !== 1 ? "s" : ""} skipped.`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
logger.blank();
|
|
125
|
+
}
|
|
126
|
+
export const rewriteCommand = new Command("rewrite")
|
|
127
|
+
.description("Replace hardcoded strings with t() calls (shows diff, confirms per file)")
|
|
128
|
+
.option("--file <file>", "Scope to a single file")
|
|
129
|
+
.option("--dir <dir>", "Scope to a directory")
|
|
130
|
+
.option("--dry-run", "Preview diffs only, no writes")
|
|
131
|
+
.option("--yes", "Apply all changes without per-file confirmation")
|
|
132
|
+
.action(async (options) => {
|
|
133
|
+
try {
|
|
134
|
+
await runRewrite(options);
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
logger.fatal(err instanceof Error ? err.message : String(err));
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
//# sourceMappingURL=rewrite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rewrite.js","sourceRoot":"","sources":["../../src/commands/rewrite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgZpC,eAAO,MAAM,UAAU,SAmBnB,CAAC"}
|