@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.
- package/README.md +71 -0
- package/package.json +54 -0
- package/src/domain/entities/translation.entity.d.ts +30 -0
- package/src/domain/entities/translation.entity.d.ts.map +1 -0
- package/src/domain/entities/translation.entity.js +5 -0
- package/src/domain/entities/translation.entity.ts +33 -0
- package/src/domain/interfaces/translation-service.interface.d.ts +21 -0
- package/src/domain/interfaces/translation-service.interface.d.ts.map +1 -0
- package/src/domain/interfaces/translation-service.interface.js +1 -0
- package/src/domain/interfaces/translation-service.interface.ts +33 -0
- package/src/index.d.ts +11 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +10 -0
- package/src/index.ts +11 -0
- package/src/infrastructure/constants/index.d.ts +11 -0
- package/src/infrastructure/constants/index.d.ts.map +1 -0
- package/src/infrastructure/constants/index.js +10 -0
- package/src/infrastructure/constants/index.ts +13 -0
- package/src/infrastructure/services/cli.service.d.ts +11 -0
- package/src/infrastructure/services/cli.service.d.ts.map +1 -0
- package/src/infrastructure/services/cli.service.js +95 -0
- package/src/infrastructure/services/cli.service.ts +129 -0
- package/src/infrastructure/services/google-translate.service.d.ts +20 -0
- package/src/infrastructure/services/google-translate.service.d.ts.map +1 -0
- package/src/infrastructure/services/google-translate.service.js +202 -0
- package/src/infrastructure/services/google-translate.service.ts +279 -0
- package/src/infrastructure/utils/file.util.d.ts +10 -0
- package/src/infrastructure/utils/file.util.d.ts.map +1 -0
- package/src/infrastructure/utils/file.util.js +41 -0
- package/src/infrastructure/utils/file.util.ts +46 -0
- package/src/infrastructure/utils/rate-limit.util.d.ts +11 -0
- package/src/infrastructure/utils/rate-limit.util.d.ts.map +1 -0
- package/src/infrastructure/utils/rate-limit.util.js +20 -0
- package/src/infrastructure/utils/rate-limit.util.ts +25 -0
- package/src/infrastructure/utils/text-validator.util.d.ts +16 -0
- package/src/infrastructure/utils/text-validator.util.d.ts.map +1 -0
- package/src/infrastructure/utils/text-validator.util.js +34 -0
- package/src/infrastructure/utils/text-validator.util.ts +31 -0
- package/src/scripts/cli.d.ts +6 -0
- package/src/scripts/cli.d.ts.map +1 -0
- package/src/scripts/cli.js +41 -0
- 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,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 @@
|
|
|
1
|
+
export {};
|
|
@@ -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"}
|