ai-l10n-sdk 1.4.1 → 1.5.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 CHANGED
@@ -5,6 +5,13 @@ All notable changes to the SDK package will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.5.0] - 2026-04-16
9
+
10
+ ### Changed
11
+ - Updated to use `ai-l10n-core@1.5.0` — all API methods now return `ApiResponse<T>` and never throw
12
+ - `TranslationOutput.remainingBalance` is now sourced from `TranslationResponse.currentBalance` (unchanged behavior for consumers)
13
+ - Error results from `translate()` (previously thrown or null-returned) are now uniformly surfaced as failed `TranslationOutput` entries with the error `message` from `TranslationResponse`
14
+
8
15
  ## [1.4.0] - 2026-04-02
9
16
 
10
17
  ### Added
@@ -41,7 +41,7 @@ const ai_l10n_core_1 = require("ai-l10n-core");
41
41
  class ApiKeyManager {
42
42
  constructor(logger = new ai_l10n_core_1.ConsoleLogger()) {
43
43
  this.logger = logger;
44
- this.noApiKeyMessage = "ℹ️ API Key not found. Please provide it via:\n" +
44
+ this.noApiKeyMessage = "ℹ️ API Key not found. Please provide it via:\n" +
45
45
  "1. Configuration option (apiKey)\n" +
46
46
  "2. Environment variable (L10N_API_KEY)\n" +
47
47
  "3. Run 'ai-l10n config --api-key YOUR_KEY' to save it\n" +
package/dist/index.js CHANGED
@@ -69,7 +69,7 @@ class AiTranslator {
69
69
  const fileExtension = path.extname(sourceFilePath);
70
70
  const format = fileExtension.slice(1);
71
71
  if (verbose) {
72
- console.log(`📂 Source file: ${sourceFilePath}`);
72
+ this.logger.logInfo(`📂 Source file: ${sourceFilePath}`);
73
73
  }
74
74
  // Ensure API key is available
75
75
  const apiKey = await this.apiKeyManager.ensureApiKey(config.apiKey);
@@ -82,7 +82,7 @@ class AiTranslator {
82
82
  if (targetLanguages.length === 0) {
83
83
  throw new Error("No target languages found. Please specify targetLanguages in config or ensure your project has the proper structure (e.g., folders named with language codes or files named with language codes).");
84
84
  }
85
- console.log(`✨ Auto-detected target languages from project structure: ${targetLanguages.join(", ")}`);
85
+ this.logger.logInfo(`✨ Auto-detected target languages from project structure: ${targetLanguages.join(", ")}`);
86
86
  }
87
87
  // Validate language codes
88
88
  for (const lang of targetLanguages) {
@@ -91,7 +91,7 @@ class AiTranslator {
91
91
  }
92
92
  }
93
93
  if (verbose) {
94
- console.log(`🎯 Target languages: ${targetLanguages.join(", ")}`);
94
+ this.logger.logInfo(`🎯 Target languages: ${targetLanguages.join(", ")}`);
95
95
  }
96
96
  // Prepare configuration
97
97
  const useContractions = config.useContractions ?? true;
@@ -101,7 +101,7 @@ class AiTranslator {
101
101
  const saveFilteredStrings = config.saveFilteredStrings ?? true;
102
102
  const translateOnlyNewStrings = config.translateOnlyNewStrings ?? false;
103
103
  if (verbose) {
104
- console.log(`Configuration:
104
+ this.logger.logInfo(`Configuration:
105
105
  - Use contractions: ${useContractions}
106
106
  - Use shortening: ${useShortening}
107
107
  - Generate plural forms: ${generatePluralForms}
@@ -114,17 +114,16 @@ class AiTranslator {
114
114
  const translationPromises = targetLanguages.map(async (targetLanguage, i) => {
115
115
  const targetFilePath = this.i18nProjectManager.generateTargetFilePath(sourceFilePath, targetLanguage);
116
116
  try {
117
- console.log(`\n🌐 Translating (${i + 1}/${totalLanguages}) to ${targetLanguage}...`);
117
+ this.logger.logInfo(`\n🌐 Translating (${i + 1}/${totalLanguages}) to ${targetLanguage}...`);
118
118
  const result = await this.performTranslation(apiKey, sourceFilePath, targetLanguage, targetFilePath, translateOnlyNewStrings, useContractions, useShortening, generatePluralForms, translateMetadata, saveFilteredStrings, format, verbose);
119
119
  return result;
120
120
  }
121
121
  catch (error) {
122
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
123
- console.error(`❌ Translation to ${targetLanguage} failed: ${errorMessage}`);
122
+ this.logger.showAndLogError(`Translation to ${targetLanguage} failed`, error);
124
123
  return {
125
124
  success: false,
126
125
  language: targetLanguage,
127
- error: errorMessage,
126
+ error: error instanceof Error ? error.message : "Unknown error",
128
127
  };
129
128
  }
130
129
  });
@@ -143,19 +142,19 @@ class AiTranslator {
143
142
  }
144
143
  // Summary
145
144
  const successCount = results.filter((r) => r.success).length;
146
- console.log(`\n${"=".repeat(50)}`);
147
- console.log(`📊 Translation Summary`);
148
- console.log(`${"=".repeat(50)}`);
149
- console.log(`✅ Successful: ${successCount}/${targetLanguages.length}`);
150
- console.log(`📝 Total characters used: ${totalCharsUsed.toLocaleString()}`);
145
+ this.logger.logInfo(`\n${"=".repeat(50)}`);
146
+ this.logger.logInfo(`📊 Translation Summary`);
147
+ this.logger.logInfo(`${"=".repeat(50)}`);
148
+ this.logger.logInfo(`✅ Successful: ${successCount}/${targetLanguages.length}`);
149
+ this.logger.logInfo(`📝 Total characters used: ${totalCharsUsed.toLocaleString()}`);
151
150
  if (remainingBalance !== undefined && remainingBalance !== null) {
152
- console.log(`💰 Remaining balance: ${remainingBalance.toLocaleString()} characters`);
151
+ this.logger.logInfo(`💰 Remaining balance: ${remainingBalance.toLocaleString()} characters`);
153
152
  }
154
153
  if (successCount < targetLanguages.length) {
155
154
  const failedLanguages = results
156
155
  .filter((r) => !r.success)
157
156
  .map((r) => r.language);
158
- console.log(`❌ Failed: ${failedLanguages.join(", ")}`);
157
+ this.logger.logWarning(`Failed: ${failedLanguages.join(", ")}`);
159
158
  }
160
159
  return {
161
160
  success: successCount > 0,
@@ -165,8 +164,7 @@ class AiTranslator {
165
164
  };
166
165
  }
167
166
  catch (error) {
168
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
169
- console.error(`❌ Translation failed: ${errorMessage}`);
167
+ this.logger.showAndLogError("Translation failed", error);
170
168
  return {
171
169
  success: false,
172
170
  results: [],
@@ -182,7 +180,7 @@ class AiTranslator {
182
180
  if (translateOnlyNewStrings && fs.existsSync(targetFilePath)) {
183
181
  targetStrings = fs.readFileSync(targetFilePath, "utf8");
184
182
  if (verbose) {
185
- console.log(` 📄 Updating existing file: ${targetFilePath}`);
183
+ this.logger.logInfo(` 📄 Updating existing file: ${targetFilePath}`);
186
184
  }
187
185
  }
188
186
  // Normalize language code for API
@@ -196,21 +194,21 @@ class AiTranslator {
196
194
  generatePluralForms,
197
195
  translateMetadata,
198
196
  client: ai_l10n_core_1.CONFIG.CLIENT,
199
- returnTranslationsAsString: true,
200
197
  translateOnlyNewStrings,
201
198
  targetStrings,
202
199
  schema: format === "arb" ? ai_l10n_core_1.FileSchema.ARBFlutter : null,
203
200
  format,
204
201
  };
205
202
  // Call translation service
206
- const result = await this.translationService.translate(request, apiKey);
207
- if (!result) {
203
+ const response = await this.translationService.translate(request, apiKey);
204
+ if (!response.success) {
208
205
  return {
209
206
  success: false,
210
207
  language: targetLanguage,
211
- error: "Translation service returned no result",
208
+ error: response.message ?? "Translation service returned no result",
212
209
  };
213
210
  }
211
+ const result = response.data;
214
212
  if (!result.translations) {
215
213
  return {
216
214
  success: false,
@@ -230,14 +228,14 @@ class AiTranslator {
230
228
  this.handleFilteredStrings(result, outputPath, saveFilteredStrings);
231
229
  }
232
230
  const charsUsed = result.usage.charsUsed || 0;
233
- console.log(` ✅ Saved to: ${outputPath}`);
234
- console.log(` 📊 Characters used: ${charsUsed.toLocaleString()}`);
231
+ this.logger.logInfo(` ✅ Saved to: ${outputPath}`);
232
+ this.logger.logInfo(` 📊 Characters used: ${charsUsed.toLocaleString()}`);
235
233
  return {
236
234
  success: true,
237
235
  language: targetLanguage,
238
236
  outputPath,
239
237
  charsUsed,
240
- remainingBalance: result.remainingBalance,
238
+ remainingBalance: response.currentBalance,
241
239
  };
242
240
  }
243
241
  handleFilteredStrings(result, targetFilePath, saveFilteredStrings) {
@@ -252,9 +250,9 @@ class AiTranslator {
252
250
  return;
253
251
  }
254
252
  const filteredStringsContent = result.filteredStrings ?? "";
255
- console.warn(` ⚠️ Some string(s) were excluded due to ${reasonMessage}`);
253
+ this.logger.logWarning(`Some strings were excluded due to ${reasonMessage}`);
256
254
  if (result.finishReason === ai_l10n_core_1.FinishReason.contentFilter) {
257
- console.warn(` ℹ️ View content policy at: ${ai_l10n_core_1.URLS.CONTENT_POLICY}`);
255
+ this.logger.logInfo(` ℹ️ View content policy at: ${ai_l10n_core_1.URLS.CONTENT_POLICY}`);
258
256
  }
259
257
  if (saveFilteredStrings) {
260
258
  const ext = path.extname(targetFilePath);
@@ -262,10 +260,10 @@ class AiTranslator {
262
260
  const dir = path.dirname(targetFilePath);
263
261
  const filteredPath = path.join(dir, `${base}.filtered${ext}`);
264
262
  fs.writeFileSync(filteredPath, filteredStringsContent, "utf8");
265
- console.log(` 📝 Filtered strings saved to: ${filteredPath}`);
263
+ this.logger.logInfo(` 📝 Filtered strings saved to: ${filteredPath}`);
266
264
  }
267
265
  else {
268
- console.log(` 📝 Filtered strings:\n${filteredStringsContent}`);
266
+ this.logger.logInfo(` 📝 Filtered strings:\n${filteredStringsContent}`);
269
267
  }
270
268
  }
271
269
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-l10n-sdk",
3
- "version": "1.4.1",
3
+ "version": "1.5.0",
4
4
  "description": "Lightweight SDK for AI-powered localization automation - programmatic API (no CLI)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -46,7 +46,7 @@
46
46
  "node": ">=14.0.0"
47
47
  },
48
48
  "dependencies": {
49
- "ai-l10n-core": "^1.4.1"
49
+ "ai-l10n-core": "^1.5.0"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/mocha": "^10.0.10",