@umituz/web-localization 1.0.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.
Files changed (42) hide show
  1. package/README.md +71 -0
  2. package/package.json +54 -0
  3. package/src/domain/entities/translation.entity.d.ts +30 -0
  4. package/src/domain/entities/translation.entity.d.ts.map +1 -0
  5. package/src/domain/entities/translation.entity.js +5 -0
  6. package/src/domain/entities/translation.entity.ts +33 -0
  7. package/src/domain/interfaces/translation-service.interface.d.ts +21 -0
  8. package/src/domain/interfaces/translation-service.interface.d.ts.map +1 -0
  9. package/src/domain/interfaces/translation-service.interface.js +1 -0
  10. package/src/domain/interfaces/translation-service.interface.ts +33 -0
  11. package/src/index.d.ts +11 -0
  12. package/src/index.d.ts.map +1 -0
  13. package/src/index.js +10 -0
  14. package/src/index.ts +11 -0
  15. package/src/infrastructure/constants/index.d.ts +11 -0
  16. package/src/infrastructure/constants/index.d.ts.map +1 -0
  17. package/src/infrastructure/constants/index.js +10 -0
  18. package/src/infrastructure/constants/index.ts +13 -0
  19. package/src/infrastructure/services/cli.service.d.ts +11 -0
  20. package/src/infrastructure/services/cli.service.d.ts.map +1 -0
  21. package/src/infrastructure/services/cli.service.js +95 -0
  22. package/src/infrastructure/services/cli.service.ts +129 -0
  23. package/src/infrastructure/services/google-translate.service.d.ts +20 -0
  24. package/src/infrastructure/services/google-translate.service.d.ts.map +1 -0
  25. package/src/infrastructure/services/google-translate.service.js +202 -0
  26. package/src/infrastructure/services/google-translate.service.ts +279 -0
  27. package/src/infrastructure/utils/file.util.d.ts +10 -0
  28. package/src/infrastructure/utils/file.util.d.ts.map +1 -0
  29. package/src/infrastructure/utils/file.util.js +41 -0
  30. package/src/infrastructure/utils/file.util.ts +46 -0
  31. package/src/infrastructure/utils/rate-limit.util.d.ts +11 -0
  32. package/src/infrastructure/utils/rate-limit.util.d.ts.map +1 -0
  33. package/src/infrastructure/utils/rate-limit.util.js +20 -0
  34. package/src/infrastructure/utils/rate-limit.util.ts +25 -0
  35. package/src/infrastructure/utils/text-validator.util.d.ts +16 -0
  36. package/src/infrastructure/utils/text-validator.util.d.ts.map +1 -0
  37. package/src/infrastructure/utils/text-validator.util.js +34 -0
  38. package/src/infrastructure/utils/text-validator.util.ts +31 -0
  39. package/src/scripts/cli.d.ts +6 -0
  40. package/src/scripts/cli.d.ts.map +1 -0
  41. package/src/scripts/cli.js +41 -0
  42. package/src/scripts/cli.ts +46 -0
package/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # @umituz/web-localization 🌍
2
+
3
+ A powerful localization package for web applications with built-in automatic Google Translate integration.
4
+
5
+ ## πŸš€ Features
6
+
7
+ - **Automatic Translation**: Uses Google Translate API to fill in missing translations.
8
+ - **Key Synchronization**: Automatically syncs directory structures from a base language (e.g., `en-US.ts`) to other language files.
9
+ - **Deep Nesting**: Supports deeply nested JSON structures for complex localization needs.
10
+ - **CLI Tools**: Easy-to-use command line interface for developers.
11
+
12
+ ## πŸ“¦ Installation
13
+
14
+ ```bash
15
+ npm install @umituz/web-localization
16
+ ```
17
+
18
+ ## πŸ› οΈ Usage
19
+
20
+ ### CLI Commands
21
+
22
+ First, set up your locales directory:
23
+
24
+ ```bash
25
+ mkdir -p src/locales
26
+ touch src/locales/en-US.ts src/locales/tr-TR.ts
27
+ ```
28
+
29
+ #### Sync Keys
30
+
31
+ Synchronizes all missing keys from the base language to target languages:
32
+
33
+ ```bash
34
+ npx web-loc sync --locales-dir src/locales --base-lang en-US
35
+ ```
36
+
37
+ #### Translate Automatically
38
+
39
+ Uses Google Translate to translate all missing keys:
40
+
41
+ ```bash
42
+ npx web-loc translate --locales-dir src/locales --base-lang en-US
43
+ ```
44
+
45
+ ### Script Usage
46
+
47
+ You can also use the translation service directly in your scripts:
48
+
49
+ ```typescript
50
+ import { googleTranslateService } from "@umituz/web-localization";
51
+
52
+ await googleTranslateService.initialize({});
53
+ const response = await googleTranslateService.translate({
54
+ text: "Hello World",
55
+ targetLanguage: "tr"
56
+ });
57
+
58
+ console.log(response.translatedText); // "Merhaba DΓΌnya"
59
+ ```
60
+
61
+ ## πŸ“ Package Structure
62
+
63
+ Following the `@umituz` new package structure:
64
+
65
+ - `src/domain`: Entities and Interfaces
66
+ - `src/infrastructure`: Services, Utils, Constants
67
+ - `src/presentation`: Components and Hooks (React Web helpers coming soon)
68
+
69
+ ---
70
+
71
+ Developed by **umituz** ⚑
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@umituz/web-localization",
3
+ "version": "1.0.1",
4
+ "description": "Google Translate integrated localization package for web applications",
5
+ "main": "./src/index.ts",
6
+ "types": "./src/index.ts",
7
+ "sideEffects": false,
8
+ "type": "module",
9
+ "bin": {
10
+ "web-loc": "./src/scripts/cli.ts"
11
+ },
12
+ "exports": {
13
+ ".": "./src/index.ts",
14
+ "./services": "./src/infrastructure/services/index.ts",
15
+ "./utils": "./src/infrastructure/utils/index.ts",
16
+ "./package.json": "./package.json"
17
+ },
18
+ "scripts": {
19
+ "typecheck": "tsc --noEmit",
20
+ "lint": "eslint .",
21
+ "build": "tsc",
22
+ "version:patch": "npm version patch -m 'chore: release v%s'",
23
+ "version:minor": "npm version minor -m 'chore: release v%s'",
24
+ "version:major": "npm version major -m 'chore: release v%s'"
25
+ },
26
+ "keywords": [
27
+ "localization",
28
+ "i18n",
29
+ "google-translate",
30
+ "web"
31
+ ],
32
+ "author": "umituz",
33
+ "license": "MIT",
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "dependencies": {
38
+ "commander": "^12.0.0",
39
+ "chalk": "^5.3.0",
40
+ "dotenv": "^16.4.5"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^20.12.7",
44
+ "typescript": "^5.4.5",
45
+ "eslint": "^8.57.0",
46
+ "@typescript-eslint/parser": "^7.7.0",
47
+ "@typescript-eslint/eslint-plugin": "^7.7.0"
48
+ },
49
+ "files": [
50
+ "src",
51
+ "README.md",
52
+ "LICENSE"
53
+ ]
54
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Translation Entity
3
+ * @description Data structures for translation requests and responses
4
+ */
5
+ export interface TranslationRequest {
6
+ readonly text: string;
7
+ readonly targetLanguage: string;
8
+ readonly sourceLanguage?: string;
9
+ }
10
+ export interface TranslationResponse {
11
+ readonly originalText: string;
12
+ readonly translatedText: string;
13
+ readonly sourceLanguage: string;
14
+ readonly targetLanguage: string;
15
+ readonly success: boolean;
16
+ readonly error?: string;
17
+ }
18
+ export interface TranslationItem {
19
+ readonly key: string;
20
+ readonly from: string;
21
+ readonly to: string;
22
+ }
23
+ export interface TranslationStats {
24
+ totalCount: number;
25
+ successCount: number;
26
+ failureCount: number;
27
+ skippedCount: number;
28
+ translatedKeys: TranslationItem[];
29
+ }
30
+ //# sourceMappingURL=translation.entity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translation.entity.d.ts","sourceRoot":"","sources":["translation.entity.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,eAAe,EAAE,CAAC;CACnC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Translation Entity
3
+ * @description Data structures for translation requests and responses
4
+ */
5
+ export {};
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Translation Entity
3
+ * @description Data structures for translation requests and responses
4
+ */
5
+
6
+ export interface TranslationRequest {
7
+ readonly text: string;
8
+ readonly targetLanguage: string;
9
+ readonly sourceLanguage?: string;
10
+ }
11
+
12
+ export interface TranslationResponse {
13
+ readonly originalText: string;
14
+ readonly translatedText: string;
15
+ readonly sourceLanguage: string;
16
+ readonly targetLanguage: string;
17
+ readonly success: boolean;
18
+ readonly error?: string;
19
+ }
20
+
21
+ export interface TranslationItem {
22
+ readonly key: string;
23
+ readonly from: string;
24
+ readonly to: string;
25
+ }
26
+
27
+ export interface TranslationStats {
28
+ totalCount: number;
29
+ successCount: number;
30
+ failureCount: number;
31
+ skippedCount: number;
32
+ translatedKeys: TranslationItem[];
33
+ }
@@ -0,0 +1,21 @@
1
+ import type { TranslationRequest, TranslationResponse, TranslationStats } from "../entities/translation.entity";
2
+ /**
3
+ * Translation Service Config
4
+ */
5
+ export interface TranslationServiceConfig {
6
+ minDelay?: number;
7
+ maxRetries?: number;
8
+ timeout?: number;
9
+ apiKey?: string;
10
+ }
11
+ /**
12
+ * Translation Service Interface
13
+ */
14
+ export interface ITranslationService {
15
+ initialize(config: TranslationServiceConfig): void;
16
+ isInitialized(): boolean;
17
+ translate(request: TranslationRequest): Promise<TranslationResponse>;
18
+ translateBatch(requests: TranslationRequest[]): Promise<TranslationStats>;
19
+ translateObject(sourceObject: Record<string, unknown>, targetObject: Record<string, unknown>, targetLanguage: string, path?: string, stats?: TranslationStats, onTranslate?: (key: string, from: string, to: string) => void): Promise<void>;
20
+ }
21
+ //# sourceMappingURL=translation-service.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translation-service.interface.d.ts","sourceRoot":"","sources":["translation-service.interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,gCAAgC,CAAC;AAExC;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,MAAM,EAAE,wBAAwB,GAAG,IAAI,CAAC;IACnD,aAAa,IAAI,OAAO,CAAC;IACzB,SAAS,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACrE,cAAc,CAAC,QAAQ,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC1E,eAAe,CACb,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,cAAc,EAAE,MAAM,EACtB,IAAI,CAAC,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,gBAAgB,EACxB,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,GAC5D,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB"}
@@ -0,0 +1,33 @@
1
+ import type {
2
+ TranslationRequest,
3
+ TranslationResponse,
4
+ TranslationStats,
5
+ } from "../entities/translation.entity";
6
+
7
+ /**
8
+ * Translation Service Config
9
+ */
10
+ export interface TranslationServiceConfig {
11
+ minDelay?: number;
12
+ maxRetries?: number;
13
+ timeout?: number;
14
+ apiKey?: string; // Optional if using public API
15
+ }
16
+
17
+ /**
18
+ * Translation Service Interface
19
+ */
20
+ export interface ITranslationService {
21
+ initialize(config: TranslationServiceConfig): void;
22
+ isInitialized(): boolean;
23
+ translate(request: TranslationRequest): Promise<TranslationResponse>;
24
+ translateBatch(requests: TranslationRequest[]): Promise<TranslationStats>;
25
+ translateObject(
26
+ sourceObject: Record<string, unknown>,
27
+ targetObject: Record<string, unknown>,
28
+ targetLanguage: string,
29
+ path?: string,
30
+ stats?: TranslationStats,
31
+ onTranslate?: (key: string, from: string, to: string) => void
32
+ ): Promise<void>;
33
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @umituz/web-localization
3
+ * Google Translate integrated localization package for web applications
4
+ */
5
+ export * from "./domain/entities/translation.entity";
6
+ export * from "./domain/interfaces/translation-service.interface";
7
+ export * from "./infrastructure/services/google-translate.service";
8
+ export * from "./infrastructure/constants";
9
+ export * from "./infrastructure/utils/text-validator.util";
10
+ export * from "./infrastructure/utils/rate-limit.util";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,sCAAsC,CAAC;AACrD,cAAc,mDAAmD,CAAC;AAClE,cAAc,oDAAoD,CAAC;AACnE,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,wCAAwC,CAAC"}
package/src/index.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @umituz/web-localization
3
+ * Google Translate integrated localization package for web applications
4
+ */
5
+ export * from "./domain/entities/translation.entity";
6
+ export * from "./domain/interfaces/translation-service.interface";
7
+ export * from "./infrastructure/services/google-translate.service";
8
+ export * from "./infrastructure/constants";
9
+ export * from "./infrastructure/utils/text-validator.util";
10
+ export * from "./infrastructure/utils/rate-limit.util";
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @umituz/web-localization
3
+ * Google Translate integrated localization package for web applications
4
+ */
5
+
6
+ export * from "./domain/entities/translation.entity";
7
+ export * from "./domain/interfaces/translation-service.interface";
8
+ export * from "./infrastructure/services/google-translate.service";
9
+ export * from "./infrastructure/constants";
10
+ export * from "./infrastructure/utils/text-validator.util";
11
+ export * from "./infrastructure/utils/rate-limit.util";
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Localization Constants
3
+ */
4
+ export declare const GOOGLE_TRANSLATE_API_URL = "https://translate.googleapis.com/translate_a/single";
5
+ export declare const DEFAULT_MIN_DELAY = 100;
6
+ export declare const DEFAULT_MAX_RETRIES = 3;
7
+ export declare const DEFAULT_TIMEOUT = 10000;
8
+ export declare const DEFAULT_LOCALES_DIR = "src/locales";
9
+ export declare const DEFAULT_SOURCE_DIR = "src";
10
+ export declare const DEFAULT_BASE_LANGUAGE = "en-US";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,wBAAwB,wDAAwD,CAAC;AAE9F,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,eAAO,MAAM,eAAe,QAAQ,CAAC;AAErC,eAAO,MAAM,mBAAmB,gBAAgB,CAAC;AACjD,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AACxC,eAAO,MAAM,qBAAqB,UAAU,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Localization Constants
3
+ */
4
+ export const GOOGLE_TRANSLATE_API_URL = "https://translate.googleapis.com/translate_a/single";
5
+ export const DEFAULT_MIN_DELAY = 100;
6
+ export const DEFAULT_MAX_RETRIES = 3;
7
+ export const DEFAULT_TIMEOUT = 10000;
8
+ export const DEFAULT_LOCALES_DIR = "src/locales";
9
+ export const DEFAULT_SOURCE_DIR = "src";
10
+ export const DEFAULT_BASE_LANGUAGE = "en-US";
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Localization Constants
3
+ */
4
+
5
+ export const GOOGLE_TRANSLATE_API_URL = "https://translate.googleapis.com/translate_a/single";
6
+
7
+ export const DEFAULT_MIN_DELAY = 100;
8
+ export const DEFAULT_MAX_RETRIES = 3;
9
+ export const DEFAULT_TIMEOUT = 10000;
10
+
11
+ export const DEFAULT_LOCALES_DIR = "src/locales";
12
+ export const DEFAULT_SOURCE_DIR = "src";
13
+ export const DEFAULT_BASE_LANGUAGE = "en-US";
@@ -0,0 +1,11 @@
1
+ export interface SyncOptions {
2
+ localesDir?: string;
3
+ sourceDir?: string;
4
+ baseLang?: string;
5
+ }
6
+ export declare class CLIService {
7
+ sync(options?: SyncOptions): Promise<void>;
8
+ translate(options?: SyncOptions): Promise<void>;
9
+ }
10
+ export declare const cliService: CLIService;
11
+ //# sourceMappingURL=cli.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.service.d.ts","sourceRoot":"","sources":["cli.service.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,UAAU;IACf,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsD9C,SAAS,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;CAsD1D;AAED,eAAO,MAAM,UAAU,YAAmB,CAAC"}
@@ -0,0 +1,95 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import chalk from "chalk";
4
+ import { googleTranslateService } from "./google-translate.service";
5
+ import { parseTypeScriptFile, generateTypeScriptContent } from "../utils/file.util";
6
+ import { DEFAULT_LOCALES_DIR, DEFAULT_BASE_LANGUAGE } from "../constants";
7
+ export class CLIService {
8
+ async sync(options = {}) {
9
+ const localesDir = path.resolve(process.cwd(), options.localesDir || DEFAULT_LOCALES_DIR);
10
+ const baseLang = options.baseLang || DEFAULT_BASE_LANGUAGE;
11
+ const baseLangPath = path.join(localesDir, `${baseLang}.ts`);
12
+ if (!fs.existsSync(localesDir)) {
13
+ console.error(chalk.red(`❌ Locales directory not found: ${localesDir}`));
14
+ return;
15
+ }
16
+ if (!fs.existsSync(baseLangPath)) {
17
+ console.error(chalk.red(`❌ Base language file not found: ${baseLangPath}`));
18
+ return;
19
+ }
20
+ const baseData = parseTypeScriptFile(baseLangPath);
21
+ const files = fs.readdirSync(localesDir)
22
+ .filter(f => f.match(/^[a-z]{2}-[A-Z]{2}\.ts$/) && f !== `${baseLang}.ts`)
23
+ .sort();
24
+ console.log(chalk.blue(`πŸ“Š Found ${files.length} languages to sync with ${baseLang}.\n`));
25
+ for (const file of files) {
26
+ const targetPath = path.join(localesDir, file);
27
+ const targetData = parseTypeScriptFile(targetPath);
28
+ const langCode = file.replace(".ts", "");
29
+ // Deep merge with base data structure
30
+ const syncObject = (source, target) => {
31
+ const result = { ...target };
32
+ for (const key in source) {
33
+ if (typeof source[key] === "object" && source[key] !== null) {
34
+ result[key] = syncObject(source[key], target[key] || {});
35
+ }
36
+ else if (target[key] === undefined) {
37
+ result[key] = source[key];
38
+ }
39
+ }
40
+ // Remove extra keys
41
+ for (const key in target) {
42
+ if (source[key] === undefined) {
43
+ delete result[key];
44
+ }
45
+ }
46
+ return result;
47
+ };
48
+ const syncedData = syncObject(baseData, targetData);
49
+ fs.writeFileSync(targetPath, generateTypeScriptContent(syncedData, langCode));
50
+ console.log(chalk.green(` 🌍 ${langCode}: Synced structure.`));
51
+ }
52
+ console.log(chalk.bold.green("\nβœ… Synchronization completed!"));
53
+ }
54
+ async translate(options = {}) {
55
+ const localesDir = path.resolve(process.cwd(), options.localesDir || DEFAULT_LOCALES_DIR);
56
+ const baseLang = options.baseLang || DEFAULT_BASE_LANGUAGE;
57
+ const baseLangPath = path.join(localesDir, `${baseLang}.ts`);
58
+ if (!fs.existsSync(baseLangPath)) {
59
+ console.error(chalk.red(`❌ Base language file not found: ${baseLangPath}`));
60
+ return;
61
+ }
62
+ googleTranslateService.initialize({});
63
+ const baseData = parseTypeScriptFile(baseLangPath);
64
+ const files = fs.readdirSync(localesDir)
65
+ .filter(f => f.match(/^[a-z]{2}-[A-Z]{2}\.ts$/) && f !== `${baseLang}.ts`)
66
+ .sort();
67
+ console.log(chalk.blue.bold(`πŸš€ Starting automatic translation for ${files.length} languages...\n`));
68
+ for (const file of files) {
69
+ const targetPath = path.join(localesDir, file);
70
+ const targetData = parseTypeScriptFile(targetPath);
71
+ const langCode = file.replace(".ts", "");
72
+ const stats = {
73
+ totalCount: 0,
74
+ successCount: 0,
75
+ failureCount: 0,
76
+ skippedCount: 0,
77
+ translatedKeys: []
78
+ };
79
+ console.log(chalk.yellow(`🌍 Translating ${langCode}...`));
80
+ await googleTranslateService.translateObject(baseData, targetData, langCode.split("-")[0], // ISO 639-1
81
+ "", stats, (key, from, to) => {
82
+ process.stdout.write(chalk.gray(` β€’ ${key}: ${from.substring(0, 15)}... β†’ ${to.substring(0, 15)}...\r`));
83
+ });
84
+ if (stats.successCount > 0) {
85
+ fs.writeFileSync(targetPath, generateTypeScriptContent(targetData, langCode));
86
+ console.log(chalk.green(` βœ… Successfully translated ${stats.successCount} keys.`));
87
+ }
88
+ else {
89
+ console.log(chalk.gray(" ✨ Already up to date."));
90
+ }
91
+ }
92
+ console.log(chalk.bold.green("\nβœ… All translations completed!"));
93
+ }
94
+ }
95
+ export const cliService = new CLIService();
@@ -0,0 +1,129 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import chalk from "chalk";
4
+ import { googleTranslateService } from "./google-translate.service";
5
+ import { parseTypeScriptFile, generateTypeScriptContent } from "../utils/file.util";
6
+ import {
7
+ DEFAULT_LOCALES_DIR,
8
+ DEFAULT_SOURCE_DIR,
9
+ DEFAULT_BASE_LANGUAGE
10
+ } from "../constants";
11
+
12
+ export interface SyncOptions {
13
+ localesDir?: string;
14
+ sourceDir?: string;
15
+ baseLang?: string;
16
+ }
17
+
18
+ export class CLIService {
19
+ async sync(options: SyncOptions = {}): Promise<void> {
20
+ const localesDir = path.resolve(process.cwd(), options.localesDir || DEFAULT_LOCALES_DIR);
21
+ const baseLang = options.baseLang || DEFAULT_BASE_LANGUAGE;
22
+ const baseLangPath = path.join(localesDir, `${baseLang}.ts`);
23
+
24
+ if (!fs.existsSync(localesDir)) {
25
+ console.error(chalk.red(`❌ Locales directory not found: ${localesDir}`));
26
+ return;
27
+ }
28
+
29
+ if (!fs.existsSync(baseLangPath)) {
30
+ console.error(chalk.red(`❌ Base language file not found: ${baseLangPath}`));
31
+ return;
32
+ }
33
+
34
+ const baseData = parseTypeScriptFile(baseLangPath);
35
+ const files = fs.readdirSync(localesDir)
36
+ .filter(f => f.match(/^[a-z]{2}-[A-Z]{2}\.ts$/) && f !== `${baseLang}.ts`)
37
+ .sort();
38
+
39
+ console.log(chalk.blue(`πŸ“Š Found ${files.length} languages to sync with ${baseLang}.\n`));
40
+
41
+ for (const file of files) {
42
+ const targetPath = path.join(localesDir, file);
43
+ const targetData = parseTypeScriptFile(targetPath);
44
+ const langCode = file.replace(".ts", "");
45
+
46
+ // Deep merge with base data structure
47
+ const syncObject = (source: any, target: any) => {
48
+ const result = { ...target };
49
+ for (const key in source) {
50
+ if (typeof source[key] === "object" && source[key] !== null) {
51
+ result[key] = syncObject(source[key], target[key] || {});
52
+ } else if (target[key] === undefined) {
53
+ result[key] = source[key];
54
+ }
55
+ }
56
+ // Remove extra keys
57
+ for (const key in target) {
58
+ if (source[key] === undefined) {
59
+ delete result[key];
60
+ }
61
+ }
62
+ return result;
63
+ };
64
+
65
+ const syncedData = syncObject(baseData, targetData);
66
+ fs.writeFileSync(targetPath, generateTypeScriptContent(syncedData, langCode));
67
+ console.log(chalk.green(` 🌍 ${langCode}: Synced structure.`));
68
+ }
69
+
70
+ console.log(chalk.bold.green("\nβœ… Synchronization completed!"));
71
+ }
72
+
73
+ async translate(options: SyncOptions = {}): Promise<void> {
74
+ const localesDir = path.resolve(process.cwd(), options.localesDir || DEFAULT_LOCALES_DIR);
75
+ const baseLang = options.baseLang || DEFAULT_BASE_LANGUAGE;
76
+ const baseLangPath = path.join(localesDir, `${baseLang}.ts`);
77
+
78
+ if (!fs.existsSync(baseLangPath)) {
79
+ console.error(chalk.red(`❌ Base language file not found: ${baseLangPath}`));
80
+ return;
81
+ }
82
+
83
+ googleTranslateService.initialize({});
84
+ const baseData = parseTypeScriptFile(baseLangPath);
85
+ const files = fs.readdirSync(localesDir)
86
+ .filter(f => f.match(/^[a-z]{2}-[A-Z]{2}\.ts$/) && f !== `${baseLang}.ts`)
87
+ .sort();
88
+
89
+ console.log(chalk.blue.bold(`πŸš€ Starting automatic translation for ${files.length} languages...\n`));
90
+
91
+ for (const file of files) {
92
+ const targetPath = path.join(localesDir, file);
93
+ const targetData = parseTypeScriptFile(targetPath);
94
+ const langCode = file.replace(".ts", "");
95
+
96
+ const stats = {
97
+ totalCount: 0,
98
+ successCount: 0,
99
+ failureCount: 0,
100
+ skippedCount: 0,
101
+ translatedKeys: []
102
+ };
103
+
104
+ console.log(chalk.yellow(`🌍 Translating ${langCode}...`));
105
+
106
+ await googleTranslateService.translateObject(
107
+ baseData,
108
+ targetData,
109
+ langCode.split("-")[0], // ISO 639-1
110
+ "",
111
+ stats,
112
+ (key, from, to) => {
113
+ process.stdout.write(chalk.gray(` β€’ ${key}: ${from.substring(0, 15)}... β†’ ${to.substring(0, 15)}...\r`));
114
+ }
115
+ );
116
+
117
+ if (stats.successCount > 0) {
118
+ fs.writeFileSync(targetPath, generateTypeScriptContent(targetData, langCode));
119
+ console.log(chalk.green(` βœ… Successfully translated ${stats.successCount} keys.`));
120
+ } else {
121
+ console.log(chalk.gray(" ✨ Already up to date."));
122
+ }
123
+ }
124
+
125
+ console.log(chalk.bold.green("\nβœ… All translations completed!"));
126
+ }
127
+ }
128
+
129
+ export const cliService = new CLIService();
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Google Translate Service
3
+ * @description Main translation service using Google Translate API
4
+ */
5
+ import type { TranslationRequest, TranslationResponse, TranslationStats } from "../../domain/entities/translation.entity";
6
+ import type { ITranslationService, TranslationServiceConfig } from "../../domain/interfaces/translation-service.interface";
7
+ declare class GoogleTranslateService implements ITranslationService {
8
+ private config;
9
+ private rateLimiter;
10
+ initialize(config: TranslationServiceConfig): void;
11
+ isInitialized(): boolean;
12
+ private ensureInitialized;
13
+ translate(request: TranslationRequest): Promise<TranslationResponse>;
14
+ translateBatch(requests: TranslationRequest[]): Promise<TranslationStats>;
15
+ translateObject(sourceObject: Record<string, unknown>, targetObject: Record<string, unknown>, targetLanguage: string, path?: string, stats?: TranslationStats, onTranslate?: (key: string, from: string, to: string) => void): Promise<void>;
16
+ private callTranslateAPI;
17
+ }
18
+ export declare const googleTranslateService: GoogleTranslateService;
19
+ export { GoogleTranslateService };
20
+ //# sourceMappingURL=google-translate.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-translate.service.d.ts","sourceRoot":"","sources":["google-translate.service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,0CAA0C,CAAC;AAClD,OAAO,KAAK,EACV,mBAAmB,EACnB,wBAAwB,EACzB,MAAM,uDAAuD,CAAC;AAa/D,cAAM,sBAAuB,YAAW,mBAAmB;IACzD,OAAO,CAAC,MAAM,CAAyC;IACvD,OAAO,CAAC,WAAW,CAA4B;IAE/C,UAAU,CAAC,MAAM,EAAE,wBAAwB,GAAG,IAAI;IASlD,aAAa,IAAI,OAAO;IAIxB,OAAO,CAAC,iBAAiB;IAQnB,SAAS,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAsDpE,cAAc,CAAC,QAAQ,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAyDzE,eAAe,CACnB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,cAAc,EAAE,MAAM,EACtB,IAAI,SAAK,EACT,KAAK,GAAE,gBAMN,EACD,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,GAC5D,OAAO,CAAC,IAAI,CAAC;YA6DF,gBAAgB;CAuC/B;AAED,eAAO,MAAM,sBAAsB,wBAA+B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,CAAC"}