@umituz/web-localization 1.1.4 → 1.1.6
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/package.json +1 -1
- package/src/domain/interfaces/translation-service.interface.ts +0 -1
- package/src/infrastructure/constants/index.ts +3 -3
- package/src/infrastructure/services/cli.service.ts +2 -0
- package/src/infrastructure/services/google-translate.service.ts +8 -8
- package/src/infrastructure/utils/rate-limit.util.ts +2 -2
- package/src/infrastructure/utils/text-validator.util.ts +2 -4
package/package.json
CHANGED
|
@@ -12,6 +12,6 @@ export const DEFAULT_LOCALES_DIR = "src/locales";
|
|
|
12
12
|
export const DEFAULT_SOURCE_DIR = "src";
|
|
13
13
|
export const DEFAULT_BASE_LANGUAGE = "en-US";
|
|
14
14
|
|
|
15
|
-
//
|
|
16
|
-
export const
|
|
17
|
-
export const
|
|
15
|
+
// Translation batch settings
|
|
16
|
+
export const TRANSLATION_BATCH_SIZE = 50;
|
|
17
|
+
export const TRANSLATION_CONCURRENCY_LIMIT = 10;
|
|
@@ -129,6 +129,8 @@ export class CLIService {
|
|
|
129
129
|
if (stats.successCount > 0) {
|
|
130
130
|
fs.writeFileSync(targetPath, generateTypeScriptContent(targetData, langCode));
|
|
131
131
|
console.log(chalk.green(` ✅ Successfully translated ${stats.successCount} keys.`));
|
|
132
|
+
} else if (stats.failureCount > 0) {
|
|
133
|
+
console.log(chalk.red(` ❌ Failed to translate ${stats.failureCount} keys.`));
|
|
132
134
|
} else {
|
|
133
135
|
console.log(chalk.gray(" ✨ Already up to date."));
|
|
134
136
|
}
|
|
@@ -23,6 +23,8 @@ import {
|
|
|
23
23
|
DEFAULT_MIN_DELAY,
|
|
24
24
|
DEFAULT_TIMEOUT,
|
|
25
25
|
DEFAULT_MAX_RETRIES,
|
|
26
|
+
TRANSLATION_BATCH_SIZE,
|
|
27
|
+
TRANSLATION_CONCURRENCY_LIMIT,
|
|
26
28
|
} from "../constants/index.js";
|
|
27
29
|
|
|
28
30
|
class GoogleTranslateService implements ITranslationService {
|
|
@@ -127,11 +129,10 @@ class GoogleTranslateService implements ITranslationService {
|
|
|
127
129
|
}
|
|
128
130
|
|
|
129
131
|
// Process requests concurrently with controlled parallelism
|
|
130
|
-
const concurrencyLimit = 10;
|
|
131
132
|
const chunks: TranslationRequest[][] = [];
|
|
132
133
|
|
|
133
|
-
for (let i = 0; i < requests.length; i +=
|
|
134
|
-
chunks.push(requests.slice(i, i +
|
|
134
|
+
for (let i = 0; i < requests.length; i += TRANSLATION_CONCURRENCY_LIMIT) {
|
|
135
|
+
chunks.push(requests.slice(i, i + TRANSLATION_CONCURRENCY_LIMIT));
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
for (const chunk of chunks) {
|
|
@@ -213,7 +214,7 @@ class GoogleTranslateService implements ITranslationService {
|
|
|
213
214
|
);
|
|
214
215
|
} else if (typeof enValue === "string") {
|
|
215
216
|
stats.totalCount++;
|
|
216
|
-
if (force || needsTranslation(targetValue
|
|
217
|
+
if (force || needsTranslation(targetValue)) {
|
|
217
218
|
textsToTranslate.push({key, enValue, currentPath});
|
|
218
219
|
} else {
|
|
219
220
|
stats.skippedCount++;
|
|
@@ -222,9 +223,8 @@ class GoogleTranslateService implements ITranslationService {
|
|
|
222
223
|
}
|
|
223
224
|
|
|
224
225
|
if (textsToTranslate.length > 0) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
const batch = textsToTranslate.slice(i, i + batchSize);
|
|
226
|
+
for (let i = 0; i < textsToTranslate.length; i += TRANSLATION_BATCH_SIZE) {
|
|
227
|
+
const batch = textsToTranslate.slice(i, i + TRANSLATION_BATCH_SIZE);
|
|
228
228
|
const results = await this.translateBatch(
|
|
229
229
|
batch.map(item => ({
|
|
230
230
|
text: item.enValue,
|
|
@@ -324,7 +324,7 @@ class GoogleTranslateService implements ITranslationService {
|
|
|
324
324
|
return translatedStr;
|
|
325
325
|
} catch (error) {
|
|
326
326
|
clearTimeout(timeoutId);
|
|
327
|
-
if (attempt === retries) {
|
|
327
|
+
if (attempt === retries - 1) {
|
|
328
328
|
throw error;
|
|
329
329
|
}
|
|
330
330
|
const delay = backoffMs * Math.pow(2, attempt);
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
* @description Controls the frequency of API requests
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { DEFAULT_MIN_DELAY } from "../constants/index.js";
|
|
7
7
|
|
|
8
8
|
export class RateLimiter {
|
|
9
9
|
private lastRequestTime = 0;
|
|
10
10
|
private readonly minDelay: number;
|
|
11
11
|
|
|
12
|
-
constructor(minDelay =
|
|
12
|
+
constructor(minDelay = DEFAULT_MIN_DELAY) {
|
|
13
13
|
if (minDelay < 0) {
|
|
14
14
|
throw new Error("minDelay must be non-negative");
|
|
15
15
|
}
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
// Default words/patterns to skip during translation
|
|
6
6
|
const DEFAULT_SKIPLIST = ["@umituz"] as const;
|
|
7
|
-
const skiplist = [...DEFAULT_SKIPLIST];
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* Validates if the text is suitable for translation
|
|
@@ -20,15 +19,14 @@ export function isValidText(text: unknown): text is string {
|
|
|
20
19
|
* Checks if a word should be skipped (e.g., proper nouns, symbols)
|
|
21
20
|
*/
|
|
22
21
|
export function shouldSkipWord(text: string): boolean {
|
|
23
|
-
return
|
|
22
|
+
return DEFAULT_SKIPLIST.some(word => text.includes(word));
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
/**
|
|
27
26
|
* Determines if a key needs translation
|
|
28
27
|
*/
|
|
29
|
-
export function needsTranslation(targetValue: unknown
|
|
28
|
+
export function needsTranslation(targetValue: unknown): boolean {
|
|
30
29
|
if (typeof targetValue !== "string") return true;
|
|
31
30
|
if (targetValue.length === 0) return true; // Empty string means untranslated
|
|
32
|
-
// Do NOT return true if target === source anymore, to avoid infinite translations for words that are identical in both languages
|
|
33
31
|
return false;
|
|
34
32
|
}
|