@form-engine-ts/translator-google-v3 2.5.1 → 2.7.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
@@ -21,7 +21,8 @@ const translator = createGoogleV3Translator({
21
21
  glossaryConfig: {
22
22
  glossary: "projects/my-project/locations/us-central1/glossaries/product-terms"
23
23
  },
24
- labels: { application: "survey" }
24
+ labels: { application: "survey" },
25
+ onBatchReport: (report) => console.info(report)
25
26
  });
26
27
 
27
28
  const japanese = await translator.translateText("Thank you", "ja", "en");
@@ -30,3 +31,7 @@ const japanese = await translator.translateText("Thank you", "ja", "en");
30
31
  Keep OAuth access tokens on a trusted server. `translateBatch` defaults to at most 250 items and 25,000 UTF-8 bytes per
31
32
  request (hard limits: 1,024 items and 30,000 bytes). Network errors, HTTP 429, and HTTP 5xx responses are retried; customize
32
33
  batch and retry behavior with `batchLimits` and `retry`.
34
+
35
+ Blank and whitespace-only inputs are omitted from API requests and restored as empty output strings in their original
36
+ positions. `onBatchReport` receives `totalChunks`, Unicode-code-point `totalCharacters`, aggregate retry attempts, total
37
+ duration, `cacheHitCount`, `cacheMissCount`, and `evictionCount` after each `translateBatch` call.
package/dist/index.cjs CHANGED
@@ -176,7 +176,10 @@ function createGoogleV3Translator(options) {
176
176
  }
177
177
  }
178
178
  if (response?.ok === true) {
179
- return parseTranslations(await response.text(), texts.length, glossaryConfig !== void 0);
179
+ return {
180
+ translations: parseTranslations(await response.text(), texts.length, glossaryConfig !== void 0),
181
+ retryAttempts: attempt
182
+ };
180
183
  }
181
184
  const retryable = response === void 0 || response.status === 429 || response.status >= 500 && response.status <= 599;
182
185
  if (retryable && attempt < maxRetries) {
@@ -200,11 +203,33 @@ function createGoogleV3Translator(options) {
200
203
  }
201
204
  const target = requireNonEmpty(targetLocale, "targetLocale");
202
205
  const source = sourceLocale === void 0 ? void 0 : requireNonEmpty(sourceLocale, "sourceLocale");
206
+ const nonEmptyEntries = texts.flatMap((text, index) => text.trim().length === 0 ? [] : [{ text, index }]);
207
+ const nonEmptyTexts = nonEmptyEntries.map((entry) => entry.text);
208
+ const chunks = splitTranslationBatch(nonEmptyTexts, batchLimits);
209
+ const startedAt = now();
203
210
  const translated = [];
204
- for (const chunk of splitTranslationBatch(texts, batchLimits)) {
205
- translated.push(...await translateChunk(chunk, target, source));
211
+ let retryAttempts = 0;
212
+ for (const chunk of chunks) {
213
+ const result = await translateChunk(chunk, target, source);
214
+ translated.push(...result.translations);
215
+ retryAttempts += result.retryAttempts;
206
216
  }
207
- return translated;
217
+ const restored = Array.from({ length: texts.length }, () => "");
218
+ for (const [translatedIndex, entry] of nonEmptyEntries.entries()) {
219
+ const value = translated[translatedIndex];
220
+ if (value === void 0) throw new Error("Google Translation Advanced returned an incomplete translation batch.");
221
+ restored[entry.index] = value;
222
+ }
223
+ options.onBatchReport?.({
224
+ totalChunks: chunks.length,
225
+ totalCharacters: nonEmptyTexts.reduce((total, text) => total + [...text].length, 0),
226
+ retryAttempts,
227
+ durationMs: Math.max(0, now() - startedAt),
228
+ cacheHitCount: 0,
229
+ cacheMissCount: nonEmptyTexts.length,
230
+ evictionCount: 0
231
+ });
232
+ return restored;
208
233
  };
209
234
  return {
210
235
  async translateText(text, targetLocale, sourceLocale) {
package/dist/index.d.cts CHANGED
@@ -21,6 +21,7 @@ interface GoogleV3TranslatorOptions {
21
21
  readonly sleep?: (milliseconds: number) => Promise<void>;
22
22
  readonly random?: () => number;
23
23
  readonly now?: () => number;
24
+ readonly onBatchReport?: (report: TranslationBatchReport) => void;
24
25
  }
25
26
  interface BatchSplitLimits {
26
27
  readonly maxItems?: number;
@@ -32,7 +33,16 @@ interface RetryConfig {
32
33
  readonly baseDelayMs?: number;
33
34
  readonly maxDelayMs?: number;
34
35
  }
36
+ interface TranslationBatchReport {
37
+ readonly totalChunks: number;
38
+ readonly totalCharacters: number;
39
+ readonly retryAttempts: number;
40
+ readonly durationMs: number;
41
+ readonly cacheHitCount: number;
42
+ readonly cacheMissCount: number;
43
+ readonly evictionCount: number;
44
+ }
35
45
  declare function splitTranslationBatch(texts: readonly string[], limits?: BatchSplitLimits): string[][];
36
46
  declare function createGoogleV3Translator(options: GoogleV3TranslatorOptions): AsyncTranslationAdapter;
37
47
 
38
- export { type BatchSplitLimits, type GoogleV3GlossaryConfig, type GoogleV3TranslatorOptions, type RetryConfig, createGoogleV3Translator, splitTranslationBatch };
48
+ export { type BatchSplitLimits, type GoogleV3GlossaryConfig, type GoogleV3TranslatorOptions, type RetryConfig, type TranslationBatchReport, createGoogleV3Translator, splitTranslationBatch };
package/dist/index.d.ts CHANGED
@@ -21,6 +21,7 @@ interface GoogleV3TranslatorOptions {
21
21
  readonly sleep?: (milliseconds: number) => Promise<void>;
22
22
  readonly random?: () => number;
23
23
  readonly now?: () => number;
24
+ readonly onBatchReport?: (report: TranslationBatchReport) => void;
24
25
  }
25
26
  interface BatchSplitLimits {
26
27
  readonly maxItems?: number;
@@ -32,7 +33,16 @@ interface RetryConfig {
32
33
  readonly baseDelayMs?: number;
33
34
  readonly maxDelayMs?: number;
34
35
  }
36
+ interface TranslationBatchReport {
37
+ readonly totalChunks: number;
38
+ readonly totalCharacters: number;
39
+ readonly retryAttempts: number;
40
+ readonly durationMs: number;
41
+ readonly cacheHitCount: number;
42
+ readonly cacheMissCount: number;
43
+ readonly evictionCount: number;
44
+ }
35
45
  declare function splitTranslationBatch(texts: readonly string[], limits?: BatchSplitLimits): string[][];
36
46
  declare function createGoogleV3Translator(options: GoogleV3TranslatorOptions): AsyncTranslationAdapter;
37
47
 
38
- export { type BatchSplitLimits, type GoogleV3GlossaryConfig, type GoogleV3TranslatorOptions, type RetryConfig, createGoogleV3Translator, splitTranslationBatch };
48
+ export { type BatchSplitLimits, type GoogleV3GlossaryConfig, type GoogleV3TranslatorOptions, type RetryConfig, type TranslationBatchReport, createGoogleV3Translator, splitTranslationBatch };
package/dist/index.js CHANGED
@@ -151,7 +151,10 @@ function createGoogleV3Translator(options) {
151
151
  }
152
152
  }
153
153
  if (response?.ok === true) {
154
- return parseTranslations(await response.text(), texts.length, glossaryConfig !== void 0);
154
+ return {
155
+ translations: parseTranslations(await response.text(), texts.length, glossaryConfig !== void 0),
156
+ retryAttempts: attempt
157
+ };
155
158
  }
156
159
  const retryable = response === void 0 || response.status === 429 || response.status >= 500 && response.status <= 599;
157
160
  if (retryable && attempt < maxRetries) {
@@ -175,11 +178,33 @@ function createGoogleV3Translator(options) {
175
178
  }
176
179
  const target = requireNonEmpty(targetLocale, "targetLocale");
177
180
  const source = sourceLocale === void 0 ? void 0 : requireNonEmpty(sourceLocale, "sourceLocale");
181
+ const nonEmptyEntries = texts.flatMap((text, index) => text.trim().length === 0 ? [] : [{ text, index }]);
182
+ const nonEmptyTexts = nonEmptyEntries.map((entry) => entry.text);
183
+ const chunks = splitTranslationBatch(nonEmptyTexts, batchLimits);
184
+ const startedAt = now();
178
185
  const translated = [];
179
- for (const chunk of splitTranslationBatch(texts, batchLimits)) {
180
- translated.push(...await translateChunk(chunk, target, source));
186
+ let retryAttempts = 0;
187
+ for (const chunk of chunks) {
188
+ const result = await translateChunk(chunk, target, source);
189
+ translated.push(...result.translations);
190
+ retryAttempts += result.retryAttempts;
181
191
  }
182
- return translated;
192
+ const restored = Array.from({ length: texts.length }, () => "");
193
+ for (const [translatedIndex, entry] of nonEmptyEntries.entries()) {
194
+ const value = translated[translatedIndex];
195
+ if (value === void 0) throw new Error("Google Translation Advanced returned an incomplete translation batch.");
196
+ restored[entry.index] = value;
197
+ }
198
+ options.onBatchReport?.({
199
+ totalChunks: chunks.length,
200
+ totalCharacters: nonEmptyTexts.reduce((total, text) => total + [...text].length, 0),
201
+ retryAttempts,
202
+ durationMs: Math.max(0, now() - startedAt),
203
+ cacheHitCount: 0,
204
+ cacheMissCount: nonEmptyTexts.length,
205
+ evictionCount: 0
206
+ });
207
+ return restored;
183
208
  };
184
209
  return {
185
210
  async translateText(text, targetLocale, sourceLocale) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@form-engine-ts/translator-google-v3",
3
- "version": "2.5.1",
3
+ "version": "2.7.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -40,7 +40,7 @@
40
40
  "typescript"
41
41
  ],
42
42
  "dependencies": {
43
- "@form-engine-ts/core": "2.5.1"
43
+ "@form-engine-ts/core": "2.7.0"
44
44
  },
45
45
  "scripts": {
46
46
  "build": "tsup src/index.ts --format esm,cjs --dts --clean --external @form-engine-ts/core",