@better-translate/cli 2.0.0 → 3.0.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/README.md CHANGED
@@ -2,4 +2,101 @@
2
2
 
3
3
  `@better-translate/cli` extracts marked source strings into your source locale file, generates translated message files, and localizes markdown. Use it when you want Better Translate to create or update locale files for you.
4
4
 
5
+ Install the CLI and the provider package you want to use in your own project:
6
+
7
+ ```sh
8
+ npm install -D @better-translate/cli @ai-sdk/openai
9
+ # or: npm install -D @better-translate/cli @ai-sdk/anthropic
10
+ # or: npm install -D @better-translate/cli @ai-sdk/moonshotai
11
+ ```
12
+
13
+ Then configure the CLI with a real AI SDK language model. The flow is the same for any provider package:
14
+
15
+ ```ts
16
+ import { openai } from "@ai-sdk/openai";
17
+ import { defineConfig } from "@better-translate/cli/config";
18
+
19
+ export default defineConfig({
20
+ sourceLocale: "en",
21
+ locales: ["es", "fr"],
22
+ model: openai("gpt-5"),
23
+ messages: {
24
+ entry: "./src/messages/en.json",
25
+ },
26
+ });
27
+ ```
28
+
29
+ ```ts
30
+ import { anthropic } from "@ai-sdk/anthropic";
31
+ import { defineConfig } from "@better-translate/cli/config";
32
+
33
+ export default defineConfig({
34
+ sourceLocale: "en",
35
+ locales: ["es", "fr"],
36
+ model: anthropic("claude-sonnet-4-5"),
37
+ messages: {
38
+ entry: "./src/messages/en.json",
39
+ },
40
+ });
41
+ ```
42
+
43
+ ```ts
44
+ import { moonshotai } from "@ai-sdk/moonshotai";
45
+ import { defineConfig } from "@better-translate/cli/config";
46
+
47
+ export default defineConfig({
48
+ sourceLocale: "en",
49
+ locales: ["es", "fr"],
50
+ model: moonshotai("kimi-k2-0905-preview"),
51
+ messages: {
52
+ entry: "./src/messages/en.json",
53
+ },
54
+ });
55
+ ```
56
+
57
+ If you need provider-specific settings, create the model in your app first and pass it through. Credentials and provider configuration stay entirely in the provider package setup:
58
+
59
+ ```ts
60
+ import { createOpenAI } from "@ai-sdk/openai";
61
+ import { defineConfig } from "@better-translate/cli/config";
62
+
63
+ const model = createOpenAI({
64
+ apiKey: process.env.OPENAI_API_KEY,
65
+ baseURL: process.env.OPENAI_BASE_URL,
66
+ })("gpt-5");
67
+
68
+ export default defineConfig({
69
+ sourceLocale: "en",
70
+ locales: ["es", "fr"],
71
+ model,
72
+ messages: {
73
+ entry: "./src/messages/en.json",
74
+ },
75
+ });
76
+ ```
77
+
5
78
  Full docs: [better-translate-placeholder.com/en/docs/cli](https://better-translate-placeholder.com/en/docs/cli)
79
+
80
+ ## Commands
81
+
82
+ Extract new source keys:
83
+
84
+ ```sh
85
+ npx bt extract
86
+ ```
87
+
88
+ Generate translated locale files:
89
+
90
+ ```sh
91
+ npx bt generate
92
+ ```
93
+
94
+ When markdown generation is enabled and `bt generate` would create or overwrite translated `.md` or `.mdx` files, the CLI asks for confirmation before it makes changes.
95
+
96
+ Use `--yes` or `-y` to skip that confirmation, especially in CI or other non-interactive environments:
97
+
98
+ ```sh
99
+ npx bt generate --yes
100
+ ```
101
+
102
+ In non-interactive environments, markdown generation requires `--yes` when translated markdown files would be written.
@@ -0,0 +1,94 @@
1
+ // src/ai-sdk-generator.ts
2
+ function validateGeneratedValue(value, request) {
3
+ if (!request.validate) {
4
+ return value;
5
+ }
6
+ return request.validate(value);
7
+ }
8
+ function createOutputValidator(request) {
9
+ return {
10
+ validate(value) {
11
+ try {
12
+ return {
13
+ success: true,
14
+ value: validateGeneratedValue(value, request)
15
+ };
16
+ } catch (error) {
17
+ return {
18
+ error: error instanceof Error ? error : new Error(String(error)),
19
+ success: false
20
+ };
21
+ }
22
+ }
23
+ };
24
+ }
25
+ function isSchemaTooLargeError(error) {
26
+ const message = error instanceof Error ? error.message : String(error);
27
+ const normalizedMessage = message.toLowerCase();
28
+ return normalizedMessage.includes("compiled grammar is too large") || normalizedMessage.includes("reduce the number of strict tools") || normalizedMessage.includes("tool schemas exceed") || normalizedMessage.includes("tool schema size") || normalizedMessage.includes("exceeds maximum schema size") || normalizedMessage.includes("too many tools");
29
+ }
30
+ function extractJsonPayload(text) {
31
+ const trimmed = text.trim();
32
+ const fencedMatch = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
33
+ if (fencedMatch?.[1]) {
34
+ return fencedMatch[1].trim();
35
+ }
36
+ const firstBrace = trimmed.indexOf("{");
37
+ const lastBrace = trimmed.lastIndexOf("}");
38
+ if (firstBrace >= 0 && lastBrace > firstBrace) {
39
+ return trimmed.slice(firstBrace, lastBrace + 1);
40
+ }
41
+ return trimmed;
42
+ }
43
+ function parseJsonText(text, request) {
44
+ if (!request.validate) {
45
+ throw new Error(
46
+ `Fallback JSON parsing failed for "${request.sourcePath}": no validator provided`
47
+ );
48
+ }
49
+ const payload = extractJsonPayload(text);
50
+ try {
51
+ return validateGeneratedValue(JSON.parse(payload), request);
52
+ } catch (error) {
53
+ const reason = error instanceof Error ? error.message : String(error);
54
+ throw new Error(
55
+ `Fallback JSON parsing failed for "${request.sourcePath}": ${reason}`
56
+ );
57
+ }
58
+ }
59
+ async function generateWithAiSdk(model, request) {
60
+ const { Output, generateText, jsonSchema } = await import("ai");
61
+ const baseInput = {
62
+ model,
63
+ prompt: request.prompt,
64
+ system: request.system,
65
+ temperature: 0
66
+ };
67
+ try {
68
+ const result = await generateText({
69
+ ...baseInput,
70
+ experimental_output: Output.object({
71
+ schema: jsonSchema(request.schema, createOutputValidator(request))
72
+ })
73
+ });
74
+ return result.experimental_output;
75
+ } catch (error) {
76
+ if (!isSchemaTooLargeError(error)) {
77
+ throw error;
78
+ }
79
+ }
80
+ const fallbackResult = await generateText({
81
+ ...baseInput,
82
+ prompt: [
83
+ request.prompt,
84
+ "",
85
+ "Return only a valid JSON object that matches the required shape exactly.",
86
+ "Do not wrap the JSON in markdown fences."
87
+ ].join("\n"),
88
+ system: `${request.system} Return only valid JSON.`
89
+ });
90
+ return parseJsonText(fallbackResult.text, request);
91
+ }
92
+ export {
93
+ generateWithAiSdk
94
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"ai-sdk-generator.d.ts","sourceRoot":"","sources":["../src/ai-sdk-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAE9D,wBAAsB,iBAAiB,CAAC,OAAO,EAC7C,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,2BAA2B,CAAC,OAAO,CAAC,GAC5C,OAAO,CAAC,OAAO,CAAC,CAkClB"}
1
+ {"version":3,"file":"ai-sdk-generator.d.ts","sourceRoot":"","sources":["../src/ai-sdk-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAiG9D,wBAAsB,iBAAiB,CAAC,OAAO,EAC7C,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,2BAA2B,CAAC,OAAO,CAAC,GAC5C,OAAO,CAAC,OAAO,CAAC,CAoClB"}
package/dist/bin.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  extractProject,
4
4
  generateProject
5
- } from "./chunk-NRZIFUEW.js";
5
+ } from "./chunk-RBZAR5EL.js";
6
6
 
7
7
  // src/cli.ts
8
8
  import pc2 from "picocolors";
@@ -70,7 +70,7 @@ ${pc.magenta("\u25C6")} locale: ${pc.bold(localeMatch[1])}`);
70
70
  spinner.stopAndPersist({ symbol: "\u25CC", text: pc.dim(message) });
71
71
  return;
72
72
  }
73
- if (message.startsWith("Using AI Gateway model:") || message.startsWith("Using built-in OpenAI provider model:") || message.startsWith("Source locale:") || message.startsWith("Target locales:")) {
73
+ if (message.startsWith("Using AI Gateway model:") || message.startsWith("Using configured provider model:") || message.startsWith("Source locale:") || message.startsWith("Target locales:")) {
74
74
  spinner.stop();
75
75
  console.log(pc.dim(message));
76
76
  return;
@@ -137,19 +137,24 @@ function usage() {
137
137
  return [
138
138
  "Usage:",
139
139
  " bt extract [--config ./better-translate.config.ts] [--dry-run] [--max-length 40]",
140
- " bt generate [--config ./better-translate.config.ts] [--dry-run]"
140
+ " bt generate [--config ./better-translate.config.ts] [--dry-run] [--yes|-y]"
141
141
  ].join("\n");
142
142
  }
143
143
  function parseCommonArgs(argv) {
144
144
  let configPath;
145
145
  let dryRun = false;
146
146
  let maxLength;
147
+ let yes = false;
147
148
  for (let index = 0; index < argv.length; index += 1) {
148
149
  const arg = argv[index];
149
150
  if (arg === "--dry-run") {
150
151
  dryRun = true;
151
152
  continue;
152
153
  }
154
+ if (arg === "--yes" || arg === "-y") {
155
+ yes = true;
156
+ continue;
157
+ }
153
158
  if (arg === "--config" || arg === "-c") {
154
159
  const value = argv[index + 1];
155
160
  if (!value) {
@@ -180,12 +185,15 @@ function parseCommonArgs(argv) {
180
185
  return {
181
186
  configPath,
182
187
  dryRun,
183
- maxLength
188
+ maxLength,
189
+ yes
184
190
  };
185
191
  }
186
192
  async function runCli(argv = process.argv.slice(2), options = {}) {
187
193
  const stderr = options.stderr ?? console.error;
188
194
  const stdout = options.stdout ?? console.log;
195
+ const extractProjectImpl = options.extractProjectImpl ?? extractProject;
196
+ const generateProjectImpl = options.generateProjectImpl ?? generateProject;
189
197
  const [command, ...args] = argv;
190
198
  if (!command || command === "--help" || command === "-h") {
191
199
  stdout(usage());
@@ -200,12 +208,17 @@ ${usage()}`);
200
208
  const parsed = parseCommonArgs(args);
201
209
  if (command === "generate" && parsed.maxLength !== void 0) {
202
210
  stderr(`--max-length is not valid for "generate".
211
+ ${usage()}`);
212
+ return 1;
213
+ }
214
+ if (command === "extract" && parsed.yes) {
215
+ stderr(`--yes is not valid for "extract".
203
216
  ${usage()}`);
204
217
  return 1;
205
218
  }
206
219
  console.log(pc2.bold("\n better-translate\n"));
207
220
  if (command === "extract") {
208
- await extractProject({
221
+ await extractProjectImpl({
209
222
  configPath: parsed.configPath,
210
223
  cwd: options.cwd,
211
224
  dryRun: parsed.dryRun,
@@ -213,11 +226,12 @@ ${usage()}`);
213
226
  maxLength: parsed.maxLength
214
227
  });
215
228
  } else {
216
- await generateProject({
229
+ await generateProjectImpl({
217
230
  configPath: parsed.configPath,
218
231
  cwd: options.cwd,
219
232
  dryRun: parsed.dryRun,
220
- logger: createSpinnerLogger()
233
+ logger: createSpinnerLogger(),
234
+ yes: parsed.yes
221
235
  });
222
236
  }
223
237
  return 0;
@@ -179,33 +179,32 @@ function toJavaScriptIdentifier(value) {
179
179
 
180
180
  // src/config-loader.ts
181
181
  var DEFAULT_CONFIG_FILE = "better-translate.config.ts";
182
- function resolveProviderModelSpec(model) {
182
+ function resolveCliLanguageModel(model) {
183
183
  assert(
184
184
  isRecord(model),
185
- 'Config requires model to be a non-empty string or openai("model-id", { apiKey }).'
185
+ "Config requires model to be a non-empty string or an AI SDK language model instance."
186
186
  );
187
187
  assert(
188
- model.kind === "provider-model",
189
- 'Config requires model to be a non-empty string or openai("model-id", { apiKey }).'
188
+ model.specificationVersion === "v3",
189
+ "Config requires model to be a non-empty string or an AI SDK language model instance."
190
190
  );
191
191
  assert(
192
- model.provider === "openai",
193
- 'Only openai("model-id", { apiKey }) is supported for built-in provider mode right now.'
192
+ typeof model.provider === "string" && model.provider.trim().length > 0,
193
+ "AI SDK language model instances require a non-empty provider string."
194
194
  );
195
195
  assert(
196
196
  typeof model.modelId === "string" && model.modelId.trim().length > 0,
197
- 'openai("model-id", { apiKey }) requires a non-empty model id.'
197
+ "AI SDK language model instances require a non-empty modelId string."
198
198
  );
199
199
  assert(
200
- typeof model.apiKey === "string" && model.apiKey.trim().length > 0,
201
- 'openai("model-id", { apiKey }) requires a non-empty apiKey string.'
200
+ typeof model.doGenerate === "function",
201
+ "AI SDK language model instances must provide a doGenerate function."
202
202
  );
203
- return {
204
- apiKey: model.apiKey.trim(),
205
- kind: "provider-model",
206
- modelId: model.modelId.trim(),
207
- provider: "openai"
208
- };
203
+ assert(
204
+ typeof model.doStream === "function",
205
+ "AI SDK language model instances must provide a doStream function."
206
+ );
207
+ return model;
209
208
  }
210
209
  function resolveConfig(rawConfig, configDirectory) {
211
210
  assert(
@@ -271,7 +270,7 @@ function resolveConfig(rawConfig, configDirectory) {
271
270
  if (typeof model === "string") {
272
271
  assert(
273
272
  model.trim().length > 0,
274
- 'Config requires a non-empty model string, for example "openai/gpt-4.1".'
273
+ 'Config requires a non-empty model string, for example "provider/model-id".'
275
274
  );
276
275
  assert(
277
276
  isRecord(gateway),
@@ -291,9 +290,9 @@ function resolveConfig(rawConfig, configDirectory) {
291
290
  }
292
291
  assert(
293
292
  gateway === void 0,
294
- "Config must not include gateway when model is created with openai(...)."
293
+ "Config must not include gateway when model is an AI SDK language model instance."
295
294
  );
296
- const resolvedModel = resolveProviderModelSpec(model);
295
+ const resolvedModel = resolveCliLanguageModel(model);
297
296
  return {
298
297
  ...resolvedBase,
299
298
  model: resolvedModel
@@ -932,12 +931,85 @@ async function extractProject(options = {}) {
932
931
  }
933
932
 
934
933
  // src/generate.ts
935
- import { mkdir, writeFile as writeFile3 } from "fs/promises";
936
- import path7 from "path";
934
+ import { access, mkdir, writeFile as writeFile3 } from "fs/promises";
935
+ import path8 from "path";
936
+
937
+ // src/confirm.ts
938
+ import path6 from "path";
939
+ import readline from "readline";
940
+ var MAX_PREVIEW_WRITES = 5;
941
+ function pluralize(count, singular, plural) {
942
+ return `${count} ${count === 1 ? singular : plural}`;
943
+ }
944
+ function formatSummary(request) {
945
+ const parts = [];
946
+ if (request.createCount > 0) {
947
+ parts.push(`create ${pluralize(request.createCount, "new file", "new files")}`);
948
+ }
949
+ if (request.overwriteCount > 0) {
950
+ parts.push(
951
+ `overwrite ${pluralize(request.overwriteCount, "existing file", "existing files")}`
952
+ );
953
+ }
954
+ if (parts.length === 0) {
955
+ return "write translated markdown files";
956
+ }
957
+ if (parts.length === 1) {
958
+ return parts[0] ?? "write translated markdown files";
959
+ }
960
+ return `${parts[0]} and ${parts[1]}`;
961
+ }
962
+ function formatTargetPath(targetPath, projectCwd) {
963
+ const relativePath = path6.relative(projectCwd, targetPath);
964
+ if (relativePath.length > 0 && !relativePath.startsWith("..") && !path6.isAbsolute(relativePath)) {
965
+ return relativePath;
966
+ }
967
+ return targetPath;
968
+ }
969
+ async function confirmMarkdownWrites(request) {
970
+ if (request.writes.length === 0) {
971
+ return true;
972
+ }
973
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
974
+ throw new Error(
975
+ "Markdown translation would create or overwrite translated .md/.mdx files in a non-interactive environment. Re-run with --yes to continue."
976
+ );
977
+ }
978
+ const locales = Array.from(new Set(request.writes.map((write) => write.locale))).sort().join(", ");
979
+ const projectCwd = request.projectCwd ?? process.cwd();
980
+ const previewWrites = request.writes.slice(0, MAX_PREVIEW_WRITES);
981
+ const remainingCount = request.writes.length - previewWrites.length;
982
+ const preview = previewWrites.map(
983
+ (write) => ` - ${write.action}: ${formatTargetPath(write.targetPath, projectCwd)}`
984
+ ).join("\n");
985
+ const prompt = [
986
+ "",
987
+ `This run will ${formatSummary(request)} as translated markdown files (.md/.mdx).`,
988
+ `Target locales: ${locales}`,
989
+ "Planned markdown writes:",
990
+ preview,
991
+ remainingCount > 0 ? ` - ...and ${remainingCount} more planned write${remainingCount === 1 ? "" : "s"}` : "",
992
+ "",
993
+ "Continue? [y/N] "
994
+ ].filter(Boolean).join("\n");
995
+ const rl = readline.createInterface({
996
+ input: process.stdin,
997
+ output: process.stdout
998
+ });
999
+ try {
1000
+ const answer = await new Promise((resolve) => {
1001
+ rl.question(prompt, resolve);
1002
+ });
1003
+ const normalized = answer.trim().toLowerCase();
1004
+ return normalized === "y" || normalized === "yes";
1005
+ } finally {
1006
+ rl.close();
1007
+ }
1008
+ }
937
1009
 
938
1010
  // src/markdown.ts
939
1011
  import { readdir as readdir2, readFile as readFile4 } from "fs/promises";
940
- import path6 from "path";
1012
+ import path7 from "path";
941
1013
  import matter from "gray-matter";
942
1014
  async function walkDirectory(directory) {
943
1015
  const entries = await readdir2(directory, {
@@ -945,7 +1017,7 @@ async function walkDirectory(directory) {
945
1017
  });
946
1018
  const files = await Promise.all(
947
1019
  entries.map(async (entry) => {
948
- const entryPath = path6.join(directory, entry.name);
1020
+ const entryPath = path7.join(directory, entry.name);
949
1021
  if (entry.isDirectory()) {
950
1022
  return walkDirectory(entryPath);
951
1023
  }
@@ -1035,7 +1107,7 @@ async function loadMarkdownDocument(rootDir, sourcePath) {
1035
1107
  const parsed = matter(sourceText);
1036
1108
  const frontmatter = isRecord(parsed.data) ? parsed.data : {};
1037
1109
  const frontmatterStrings = extractFrontmatterStrings(frontmatter);
1038
- const relativePath = path6.relative(rootDir, sourcePath).split(path6.sep).join("/");
1110
+ const relativePath = path7.relative(rootDir, sourcePath).split(path7.sep).join("/");
1039
1111
  return {
1040
1112
  body: parsed.content,
1041
1113
  frontmatter,
@@ -1047,15 +1119,15 @@ async function loadMarkdownDocument(rootDir, sourcePath) {
1047
1119
  };
1048
1120
  }
1049
1121
  function deriveTargetMarkdownRoot(rootDir, sourceLocale, targetLocale) {
1050
- const basename = path6.basename(rootDir);
1122
+ const basename = path7.basename(rootDir);
1051
1123
  assert(
1052
1124
  basename === sourceLocale,
1053
1125
  `markdown.rootDir must end with the source locale "${sourceLocale}" so the CLI can mirror sibling locale folders.`
1054
1126
  );
1055
- return path6.join(path6.dirname(rootDir), targetLocale);
1127
+ return path7.join(path7.dirname(rootDir), targetLocale);
1056
1128
  }
1057
1129
  function deriveTargetMarkdownPath(rootDir, sourceLocale, targetLocale, relativePath) {
1058
- return path6.join(
1130
+ return path7.join(
1059
1131
  deriveTargetMarkdownRoot(rootDir, sourceLocale, targetLocale),
1060
1132
  relativePath
1061
1133
  );
@@ -1151,6 +1223,46 @@ function createConsoleLogger() {
1151
1223
  function describeError(error) {
1152
1224
  return error instanceof Error ? error.message : String(error);
1153
1225
  }
1226
+ async function pathExists(filePath) {
1227
+ try {
1228
+ await access(filePath);
1229
+ return true;
1230
+ } catch (error) {
1231
+ if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
1232
+ return false;
1233
+ }
1234
+ throw error;
1235
+ }
1236
+ }
1237
+ function toMarkdownRelativePath(rootDir, sourcePath) {
1238
+ return path8.relative(rootDir, sourcePath).split(path8.sep).join("/");
1239
+ }
1240
+ async function createMarkdownWriteConfirmationRequest(options) {
1241
+ const writes = await Promise.all(
1242
+ options.locales.flatMap(
1243
+ (locale) => options.sourcePaths.map(async (sourcePath) => {
1244
+ const targetPath = deriveTargetMarkdownPath(
1245
+ options.markdownRootDir,
1246
+ options.sourceLocale,
1247
+ locale,
1248
+ toMarkdownRelativePath(options.markdownRootDir, sourcePath)
1249
+ );
1250
+ return {
1251
+ action: await pathExists(targetPath) ? "overwrite" : "create",
1252
+ locale,
1253
+ sourcePath,
1254
+ targetPath
1255
+ };
1256
+ })
1257
+ )
1258
+ );
1259
+ return {
1260
+ createCount: writes.filter((write) => write.action === "create").length,
1261
+ overwriteCount: writes.filter((write) => write.action === "overwrite").length,
1262
+ projectCwd: options.projectCwd,
1263
+ writes
1264
+ };
1265
+ }
1154
1266
  async function persistWrite(write, options) {
1155
1267
  if (options.dryRun) {
1156
1268
  options.logger.info(
@@ -1158,7 +1270,7 @@ async function persistWrite(write, options) {
1158
1270
  );
1159
1271
  return;
1160
1272
  }
1161
- await mkdir(path7.dirname(write.targetPath), {
1273
+ await mkdir(path8.dirname(write.targetPath), {
1162
1274
  recursive: true
1163
1275
  });
1164
1276
  await writeFile3(write.targetPath, write.content, "utf8");
@@ -1174,7 +1286,7 @@ function prepareGatewayEnvironment(apiKey) {
1174
1286
  process.env.AI_GATEWAY_API_KEY = apiKey;
1175
1287
  }
1176
1288
  async function createDefaultGenerator(model) {
1177
- const { generateWithAiSdk } = await import("./ai-sdk-generator-WPQCTPGA.js");
1289
+ const { generateWithAiSdk } = await import("./ai-sdk-generator-QEGOC4LN.js");
1178
1290
  return async (request) => generateWithAiSdk(model, request);
1179
1291
  }
1180
1292
  async function resolveRuntimeModel(config) {
@@ -1185,13 +1297,9 @@ async function resolveRuntimeModel(config) {
1185
1297
  model: config.model
1186
1298
  };
1187
1299
  }
1188
- const { createOpenAI } = await import("@ai-sdk/openai");
1189
- const provider = createOpenAI({
1190
- apiKey: config.model.apiKey
1191
- });
1192
1300
  return {
1193
- description: `Using built-in OpenAI provider model: ${config.model.modelId}`,
1194
- model: provider(config.model.modelId)
1301
+ description: `Using configured provider model: ${config.model.provider}/${config.model.modelId}`,
1302
+ model: config.model
1195
1303
  };
1196
1304
  }
1197
1305
  function validateMarkdownTranslation(frontmatterStrings, value) {
@@ -1248,6 +1356,19 @@ async function generateProject(options = {}) {
1248
1356
  } else {
1249
1357
  logger.info("Markdown generation disabled.");
1250
1358
  }
1359
+ if (config.markdown && markdownSources.length > 0 && !options.dryRun && !options.yes) {
1360
+ const confirmationRequest = await createMarkdownWriteConfirmationRequest({
1361
+ locales: config.locales,
1362
+ markdownRootDir: config.markdown.rootDir,
1363
+ projectCwd: cwd,
1364
+ sourceLocale: config.sourceLocale,
1365
+ sourcePaths: markdownSources
1366
+ });
1367
+ const confirmed = await (options.confirmMarkdownWrites ?? confirmMarkdownWrites)(confirmationRequest);
1368
+ if (!confirmed) {
1369
+ throw new Error("Markdown translation cancelled. No files were written.");
1370
+ }
1371
+ }
1251
1372
  for (const locale of config.locales) {
1252
1373
  logger.info(`Starting locale "${locale}"...`);
1253
1374
  const messagePrompt = createMessagesPrompt({
@@ -0,0 +1,8 @@
1
+ // src/define-config.ts
2
+ function defineConfig(config) {
3
+ return config;
4
+ }
5
+
6
+ export {
7
+ defineConfig
8
+ };
package/dist/cli.d.ts CHANGED
@@ -1,5 +1,9 @@
1
+ import { extractProject } from "./extract.js";
2
+ import { generateProject } from "./generate.js";
1
3
  export declare function runCli(argv?: string[], options?: {
2
4
  cwd?: string;
5
+ extractProjectImpl?: typeof extractProject;
6
+ generateProjectImpl?: typeof generateProject;
3
7
  stderr?: (message: string) => void;
4
8
  stdout?: (message: string) => void;
5
9
  }): Promise<number>;
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AA2EA,wBAAsB,MAAM,CAC1B,IAAI,WAAwB,EAC5B,OAAO,GAAE;IACP,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B,GACL,OAAO,CAAC,MAAM,CAAC,CAmDjB"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAgFhD,wBAAsB,MAAM,CAC1B,IAAI,WAAwB,EAC5B,OAAO,GAAE;IACP,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kBAAkB,CAAC,EAAE,OAAO,cAAc,CAAC;IAC3C,mBAAmB,CAAC,EAAE,OAAO,eAAe,CAAC;IAC7C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B,GACL,OAAO,CAAC,MAAM,CAAC,CA2DjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../src/config-loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,8BAA8B,EAG/B,MAAM,YAAY,CAAC;AAuJpB,wBAAsB,aAAa,CACjC,OAAO,GAAE;IACP,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;CACT,GACL,OAAO,CAAC,8BAA8B,CAAC,CAyBzC"}
1
+ {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../src/config-loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,8BAA8B,EAE/B,MAAM,YAAY,CAAC;AAsJpB,wBAAsB,aAAa,CACjC,OAAO,GAAE;IACP,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;CACT,GACL,OAAO,CAAC,8BAA8B,CAAC,CAyBzC"}
package/dist/config.d.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  export { defineConfig } from "./define-config.js";
2
- export { openai } from "./provider-models.js";
3
- export type { BetterTranslateCliConfig, MarkdownExtension, OpenAIProviderModelSpec, } from "./types.js";
2
+ export type { BetterTranslateCliConfig, BetterTranslateCliDirectModelConfig, CliLanguageModel, MarkdownExtension, } from "./types.js";
4
3
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,YAAY,EACV,wBAAwB,EACxB,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,YAAY,EACV,wBAAwB,EACxB,mCAAmC,EACnC,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
package/dist/config.js CHANGED
@@ -1,8 +1,6 @@
1
1
  import {
2
- defineConfig,
3
- openai
4
- } from "./chunk-WMIZO3GE.js";
2
+ defineConfig
3
+ } from "./chunk-VYOBAIBH.js";
5
4
  export {
6
- defineConfig,
7
- openai
5
+ defineConfig
8
6
  };
@@ -0,0 +1,3 @@
1
+ import type { MarkdownWriteConfirmationRequest } from "./types.js";
2
+ export declare function confirmMarkdownWrites(request: MarkdownWriteConfirmationRequest): Promise<boolean>;
3
+ //# sourceMappingURL=confirm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm.d.ts","sourceRoot":"","sources":["../src/confirm.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,YAAY,CAAC;AA8CnE,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,gCAAgC,GACxC,OAAO,CAAC,OAAO,CAAC,CAqDlB"}
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAGV,sBAAsB,EACtB,qBAAqB,EAGtB,MAAM,YAAY,CAAC;AAgHpB,wBAAsB,eAAe,CACnC,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,qBAAqB,CAAC,CA6KhC"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAGV,sBAAsB,EACtB,qBAAqB,EAKtB,MAAM,YAAY,CAAC;AAqKpB,wBAAsB,eAAe,CACnC,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,qBAAqB,CAAC,CAoMhC"}
package/dist/index.d.ts CHANGED
@@ -2,6 +2,5 @@ export { loadCliConfig } from "./config-loader.js";
2
2
  export { defineConfig } from "./define-config.js";
3
3
  export { extractProject } from "./extract.js";
4
4
  export { generateProject } from "./generate.js";
5
- export { openai } from "./provider-models.js";
6
- export type { BetterTranslateCliConfig, BetterTranslateCliGatewayConfig, BetterTranslateCliOpenAIConfig, CliLogger, ExtractProjectOptions, ExtractProjectResult, CliWriteOperation, GenerateProjectOptions, GenerateProjectResult, LoadedBetterTranslateCliConfig, MarkdownExtension, OpenAIProviderModelSpec, ResolvedBetterTranslateCliConfig, ResolvedBetterTranslateCliGatewayConfig, ResolvedBetterTranslateCliOpenAIConfig, StructuredGenerationRequest, StructuredGenerator, } from "./types.js";
5
+ export type { BetterTranslateCliConfig, BetterTranslateCliDirectModelConfig, BetterTranslateCliGatewayConfig, CliLanguageModel, CliLogger, ExtractProjectOptions, ExtractProjectResult, CliWriteOperation, GenerateProjectOptions, GenerateProjectResult, LoadedBetterTranslateCliConfig, MarkdownWriteConfirmationEntry, MarkdownWriteConfirmationRequest, MarkdownExtension, ResolvedBetterTranslateCliConfig, ResolvedBetterTranslateCliDirectModelConfig, ResolvedBetterTranslateCliGatewayConfig, StructuredGenerationRequest, StructuredGenerator, } from "./types.js";
7
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,YAAY,EACV,wBAAwB,EACxB,+BAA+B,EAC/B,8BAA8B,EAC9B,SAAS,EACT,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,EACtB,qBAAqB,EACrB,8BAA8B,EAC9B,iBAAiB,EACjB,uBAAuB,EACvB,gCAAgC,EAChC,uCAAuC,EACvC,sCAAsC,EACtC,2BAA2B,EAC3B,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,YAAY,EACV,wBAAwB,EACxB,mCAAmC,EACnC,+BAA+B,EAC/B,gBAAgB,EAChB,SAAS,EACT,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,EACtB,qBAAqB,EACrB,8BAA8B,EAC9B,8BAA8B,EAC9B,gCAAgC,EAChC,iBAAiB,EACjB,gCAAgC,EAChC,2CAA2C,EAC3C,uCAAuC,EACvC,2BAA2B,EAC3B,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -2,15 +2,13 @@ import {
2
2
  extractProject,
3
3
  generateProject,
4
4
  loadCliConfig
5
- } from "./chunk-NRZIFUEW.js";
5
+ } from "./chunk-RBZAR5EL.js";
6
6
  import {
7
- defineConfig,
8
- openai
9
- } from "./chunk-WMIZO3GE.js";
7
+ defineConfig
8
+ } from "./chunk-VYOBAIBH.js";
10
9
  export {
11
10
  defineConfig,
12
11
  extractProject,
13
12
  generateProject,
14
- loadCliConfig,
15
- openai
13
+ loadCliConfig
16
14
  };
package/dist/types.d.ts CHANGED
@@ -1,4 +1,6 @@
1
+ import type { LanguageModelV3 } from "@ai-sdk/provider";
1
2
  export type MarkdownExtension = ".md" | ".mdx";
3
+ export type CliLanguageModel = LanguageModelV3;
2
4
  interface BetterTranslateCliConfigBase {
3
5
  locales: string[];
4
6
  markdown?: {
@@ -10,23 +12,17 @@ interface BetterTranslateCliConfigBase {
10
12
  };
11
13
  sourceLocale: string;
12
14
  }
13
- export interface OpenAIProviderModelSpec {
14
- apiKey: string;
15
- kind: "provider-model";
16
- modelId: string;
17
- provider: "openai";
18
- }
19
15
  export interface BetterTranslateCliGatewayConfig extends BetterTranslateCliConfigBase {
20
16
  gateway: {
21
17
  apiKey: string;
22
18
  };
23
19
  model: string;
24
20
  }
25
- export interface BetterTranslateCliOpenAIConfig extends BetterTranslateCliConfigBase {
21
+ export interface BetterTranslateCliDirectModelConfig extends BetterTranslateCliConfigBase {
26
22
  gateway?: never;
27
- model: OpenAIProviderModelSpec;
23
+ model: CliLanguageModel;
28
24
  }
29
- export type BetterTranslateCliConfig = BetterTranslateCliGatewayConfig | BetterTranslateCliOpenAIConfig;
25
+ export type BetterTranslateCliConfig = BetterTranslateCliGatewayConfig | BetterTranslateCliDirectModelConfig;
30
26
  interface ResolvedBetterTranslateCliConfigBase {
31
27
  locales: readonly string[];
32
28
  markdown?: {
@@ -44,10 +40,10 @@ export interface ResolvedBetterTranslateCliGatewayConfig extends ResolvedBetterT
44
40
  };
45
41
  model: string;
46
42
  }
47
- export interface ResolvedBetterTranslateCliOpenAIConfig extends ResolvedBetterTranslateCliConfigBase {
48
- model: OpenAIProviderModelSpec;
43
+ export interface ResolvedBetterTranslateCliDirectModelConfig extends ResolvedBetterTranslateCliConfigBase {
44
+ model: CliLanguageModel;
49
45
  }
50
- export type ResolvedBetterTranslateCliConfig = ResolvedBetterTranslateCliGatewayConfig | ResolvedBetterTranslateCliOpenAIConfig;
46
+ export type ResolvedBetterTranslateCliConfig = ResolvedBetterTranslateCliGatewayConfig | ResolvedBetterTranslateCliDirectModelConfig;
51
47
  export interface LoadedBetterTranslateCliConfig {
52
48
  config: ResolvedBetterTranslateCliConfig;
53
49
  directory: string;
@@ -60,6 +56,18 @@ export interface CliWriteOperation {
60
56
  sourcePath: string;
61
57
  targetPath: string;
62
58
  }
59
+ export interface MarkdownWriteConfirmationEntry {
60
+ action: "create" | "overwrite";
61
+ locale: string;
62
+ sourcePath: string;
63
+ targetPath: string;
64
+ }
65
+ export interface MarkdownWriteConfirmationRequest {
66
+ createCount: number;
67
+ overwriteCount: number;
68
+ projectCwd?: string;
69
+ writes: readonly MarkdownWriteConfirmationEntry[];
70
+ }
63
71
  export interface CliLogger {
64
72
  error(message: string): void;
65
73
  info(message: string): void;
@@ -76,10 +84,12 @@ export interface StructuredGenerationRequest<TOutput> {
76
84
  export type StructuredGenerator = <TOutput>(request: StructuredGenerationRequest<TOutput>) => Promise<TOutput>;
77
85
  export interface GenerateProjectOptions {
78
86
  configPath?: string;
87
+ confirmMarkdownWrites?: (request: MarkdownWriteConfirmationRequest) => Promise<boolean>;
79
88
  cwd?: string;
80
89
  dryRun?: boolean;
81
90
  generator?: StructuredGenerator;
82
91
  logger?: CliLogger;
92
+ yes?: boolean;
83
93
  }
84
94
  export interface GenerateProjectResult {
85
95
  dryRun: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-translate/cli",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "AI-powered translation generation CLI for Better Translate.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -45,9 +45,9 @@
45
45
  "url": "https://github.com/jralvarenga/better-translate/issues"
46
46
  },
47
47
  "dependencies": {
48
- "@ai-sdk/openai": "^3.0.41",
48
+ "@ai-sdk/provider": "^3.0.8",
49
+ "@better-translate/core": "^2.1.0",
49
50
  "ai": "^6.0.116",
50
- "@better-translate/core": "^2.0.0",
51
51
  "dotenv": "^17.2.3",
52
52
  "gray-matter": "^4.0.3",
53
53
  "ora": "^8.2.0",
@@ -1,37 +0,0 @@
1
- // src/ai-sdk-generator.ts
2
- async function generateWithAiSdk(model, request) {
3
- const { Output, generateText, jsonSchema } = await import("ai");
4
- const result = await generateText({
5
- experimental_output: Output.object({
6
- schema: jsonSchema(request.schema, {
7
- validate(value) {
8
- if (!request.validate) {
9
- return {
10
- success: true,
11
- value
12
- };
13
- }
14
- try {
15
- return {
16
- success: true,
17
- value: request.validate(value)
18
- };
19
- } catch (error) {
20
- return {
21
- error: error instanceof Error ? error : new Error(String(error)),
22
- success: false
23
- };
24
- }
25
- }
26
- })
27
- }),
28
- model,
29
- prompt: request.prompt,
30
- system: request.system,
31
- temperature: 0
32
- });
33
- return result.experimental_output;
34
- }
35
- export {
36
- generateWithAiSdk
37
- };
@@ -1,19 +0,0 @@
1
- // src/define-config.ts
2
- function defineConfig(config) {
3
- return config;
4
- }
5
-
6
- // src/provider-models.ts
7
- function openai(modelId, options) {
8
- return {
9
- apiKey: options.apiKey,
10
- kind: "provider-model",
11
- modelId,
12
- provider: "openai"
13
- };
14
- }
15
-
16
- export {
17
- defineConfig,
18
- openai
19
- };
@@ -1,5 +0,0 @@
1
- import type { OpenAIProviderModelSpec } from "./types.js";
2
- export declare function openai(modelId: string, options: {
3
- apiKey: string;
4
- }): OpenAIProviderModelSpec;
5
- //# sourceMappingURL=provider-models.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"provider-models.d.ts","sourceRoot":"","sources":["../src/provider-models.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D,wBAAgB,MAAM,CACpB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;IACP,MAAM,EAAE,MAAM,CAAC;CAChB,GACA,uBAAuB,CAOzB"}