@umituz/web-localization 1.1.0 → 1.1.2

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/dist/index.d.ts CHANGED
@@ -8,4 +8,5 @@ export * from "./infrastructure/services/google-translate.service";
8
8
  export * from "./infrastructure/constants";
9
9
  export * from "./infrastructure/utils/text-validator.util";
10
10
  export * from "./infrastructure/utils/rate-limit.util";
11
+ export * from "./integrations/i18n.setup";
11
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/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;AACvD,cAAc,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -8,3 +8,4 @@ export * from "./infrastructure/services/google-translate.service";
8
8
  export * from "./infrastructure/constants";
9
9
  export * from "./infrastructure/utils/text-validator.util";
10
10
  export * from "./infrastructure/utils/rate-limit.util";
11
+ export * from "./integrations/i18n.setup";
@@ -2,6 +2,7 @@ export interface SyncOptions {
2
2
  localesDir?: string;
3
3
  sourceDir?: string;
4
4
  baseLang?: string;
5
+ force?: boolean;
5
6
  }
6
7
  export declare class CLIService {
7
8
  sync(options?: SyncOptions): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"cli.service.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/services/cli.service.ts"],"names":[],"mappings":"AAUA,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;IA0D9C,SAAS,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;CAsD1D;AAED,eAAO,MAAM,UAAU,YAAmB,CAAC"}
1
+ {"version":3,"file":"cli.service.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/services/cli.service.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,UAAU;IACf,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IA0D9C,SAAS,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;CAuD1D;AAED,eAAO,MAAM,UAAU,YAAmB,CAAC"}
@@ -81,7 +81,7 @@ export class CLIService {
81
81
  await googleTranslateService.translateObject(baseData, targetData, langCode.split("-")[0], // ISO 639-1
82
82
  "", stats, (key, from, to) => {
83
83
  process.stdout.write(chalk.gray(` • ${key}: ${from.substring(0, 15)}... → ${to.substring(0, 15)}...\r`));
84
- });
84
+ }, options.force);
85
85
  if (stats.successCount > 0) {
86
86
  fs.writeFileSync(targetPath, generateTypeScriptContent(targetData, langCode));
87
87
  console.log(chalk.green(` ✅ Successfully translated ${stats.successCount} keys.`));
@@ -12,7 +12,7 @@ declare class GoogleTranslateService implements ITranslationService {
12
12
  private ensureInitialized;
13
13
  translate(request: TranslationRequest): Promise<TranslationResponse>;
14
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>;
15
+ translateObject(sourceObject: Record<string, unknown>, targetObject: Record<string, unknown>, targetLanguage: string, path?: string, stats?: TranslationStats, onTranslate?: (key: string, from: string, to: string) => void, force?: boolean): Promise<void>;
16
16
  private callTranslateAPI;
17
17
  }
18
18
  export declare const googleTranslateService: GoogleTranslateService;
@@ -1 +1 @@
1
- {"version":3,"file":"google-translate.service.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/services/google-translate.service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,6CAA6C,CAAC;AACrD,OAAO,KAAK,EACV,mBAAmB,EACnB,wBAAwB,EACzB,MAAM,0DAA0D,CAAC;AAalE,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;CAkF/B;AAED,eAAO,MAAM,sBAAsB,wBAA+B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
1
+ {"version":3,"file":"google-translate.service.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/services/google-translate.service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,6CAA6C,CAAC;AACrD,OAAO,KAAK,EACV,mBAAmB,EACnB,wBAAwB,EACzB,MAAM,0DAA0D,CAAC;AAalE,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,EAC7D,KAAK,UAAQ,GACZ,OAAO,CAAC,IAAI,CAAC;YAiEF,gBAAgB;CAkF/B;AAED,eAAO,MAAM,sBAAsB,wBAA+B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
@@ -118,7 +118,7 @@ class GoogleTranslateService {
118
118
  failureCount: 0,
119
119
  skippedCount: 0,
120
120
  translatedKeys: [],
121
- }, onTranslate) {
121
+ }, onTranslate, force = false) {
122
122
  if (!sourceObject || typeof sourceObject !== "object")
123
123
  return;
124
124
  if (!targetObject || typeof targetObject !== "object")
@@ -135,11 +135,11 @@ class GoogleTranslateService {
135
135
  if (!targetObject[key] || typeof targetObject[key] !== "object") {
136
136
  targetObject[key] = {};
137
137
  }
138
- await this.translateObject(enValue, targetObject[key], targetLanguage, currentPath, stats, onTranslate);
138
+ await this.translateObject(enValue, targetObject[key], targetLanguage, currentPath, stats, onTranslate, force);
139
139
  }
140
140
  else if (typeof enValue === "string") {
141
141
  stats.totalCount++;
142
- if (needsTranslation(targetValue, enValue)) {
142
+ if (force || needsTranslation(targetValue, enValue)) {
143
143
  textsToTranslate.push({ key, enValue, currentPath });
144
144
  }
145
145
  else {
@@ -161,10 +161,14 @@ class GoogleTranslateService {
161
161
  const translatedItem = results.translatedKeys[resultIndex];
162
162
  if (translatedItem && translatedItem.from === enValue && translatedItem.to !== enValue) {
163
163
  targetObject[key] = translatedItem.to;
164
+ stats.successCount++;
164
165
  if (onTranslate)
165
166
  onTranslate(currentPath, enValue, translatedItem.to);
166
167
  resultIndex++;
167
168
  }
169
+ else {
170
+ stats.failureCount++;
171
+ }
168
172
  }
169
173
  }
170
174
  }
@@ -0,0 +1,23 @@
1
+ import i18n from 'i18next';
2
+ export interface SetupI18nOptions {
3
+ resources: Record<string, {
4
+ translation: any;
5
+ }>;
6
+ defaultLng?: string;
7
+ fallbackLng?: string;
8
+ onInit?: (instance: typeof i18n) => void;
9
+ detection?: any;
10
+ seo?: {
11
+ titleKey: string;
12
+ descriptionKey: string;
13
+ defaultImage?: string;
14
+ twitterHandle?: string;
15
+ };
16
+ }
17
+ /**
18
+ * Static i18n initialization to simplify main app code.
19
+ * @description All common configuration including SEO integration is hidden inside this package.
20
+ */
21
+ export declare function setupI18n(options: SetupI18nOptions): import("i18next").i18n;
22
+ export default i18n;
23
+ //# sourceMappingURL=i18n.setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.setup.d.ts","sourceRoot":"","sources":["../../src/integrations/i18n.setup.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,SAAS,CAAC;AAK3B,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,WAAW,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,IAAI,KAAK,IAAI,CAAC;IACzC,SAAS,CAAC,EAAE,GAAG,CAAC;IAChB,GAAG,CAAC,EAAE;QACJ,QAAQ,EAAE,MAAM,CAAC;QACjB,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,0BAoClD;AAED,eAAe,IAAI,CAAC"}
@@ -0,0 +1,38 @@
1
+ import i18n from 'i18next';
2
+ import { initReactI18next } from 'react-i18next';
3
+ import LanguageDetector from 'i18next-browser-languagedetector';
4
+ import { initSEO } from '@umituz/web-seo';
5
+ /**
6
+ * Static i18n initialization to simplify main app code.
7
+ * @description All common configuration including SEO integration is hidden inside this package.
8
+ */
9
+ export function setupI18n(options) {
10
+ const { resources, defaultLng = 'en-US', fallbackLng = 'en-US', onInit, detection = {
11
+ order: ['localStorage', 'navigator'],
12
+ caches: ['localStorage'],
13
+ }, seo, } = options;
14
+ i18n
15
+ .use(LanguageDetector)
16
+ .use(initReactI18next)
17
+ .init({
18
+ resources,
19
+ lng: defaultLng,
20
+ fallbackLng,
21
+ interpolation: {
22
+ escapeValue: false,
23
+ },
24
+ detection,
25
+ })
26
+ .then(() => {
27
+ if (seo) {
28
+ initSEO({
29
+ i18n,
30
+ ...seo,
31
+ });
32
+ }
33
+ if (onInit)
34
+ onInit(i18n);
35
+ });
36
+ return i18n;
37
+ }
38
+ export default i18n;
@@ -29,6 +29,7 @@ program
29
29
  .description("Automatically translate missing strings using Google Translate")
30
30
  .option("-d, --locales-dir <dir>", "Directory containing locale files", "src/locales")
31
31
  .option("-b, --base-lang <lang>", "Base language code", "en-US")
32
+ .option("-f, --force", "Force re-translation of all strings", false)
32
33
  .action(async (options) => {
33
34
  try {
34
35
  await cliService.translate(options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/web-localization",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Google Translate integrated localization package for web applications",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -13,6 +13,7 @@
13
13
  ".": "./src/index.ts",
14
14
  "./services": "./src/infrastructure/services/index.ts",
15
15
  "./utils": "./src/infrastructure/utils/index.ts",
16
+ "./setup": "./src/integrations/i18n.setup.ts",
16
17
  "./package.json": "./package.json"
17
18
  },
18
19
  "scripts": {
@@ -38,7 +39,11 @@
38
39
  "chalk": "^5.3.0",
39
40
  "commander": "^12.0.0",
40
41
  "dotenv": "^16.4.5",
41
- "ts-morph": "^27.0.2"
42
+ "ts-morph": "^27.0.2",
43
+ "i18next": "^23.11.2",
44
+ "react-i18next": "^14.1.1",
45
+ "i18next-browser-languagedetector": "^7.2.1",
46
+ "@umituz/web-seo": "file:../web-seo"
42
47
  },
43
48
  "devDependencies": {
44
49
  "@types/node": "^20.12.7",
package/src/index.ts CHANGED
@@ -9,3 +9,4 @@ export * from "./infrastructure/services/google-translate.service";
9
9
  export * from "./infrastructure/constants";
10
10
  export * from "./infrastructure/utils/text-validator.util";
11
11
  export * from "./infrastructure/utils/rate-limit.util";
12
+ export * from "./integrations/i18n.setup";
@@ -12,6 +12,7 @@ export interface SyncOptions {
12
12
  localesDir?: string;
13
13
  sourceDir?: string;
14
14
  baseLang?: string;
15
+ force?: boolean;
15
16
  }
16
17
 
17
18
  export class CLIService {
@@ -114,7 +115,8 @@ export class CLIService {
114
115
  stats,
115
116
  (key, from, to) => {
116
117
  process.stdout.write(chalk.gray(` • ${key}: ${from.substring(0, 15)}... → ${to.substring(0, 15)}...\r`));
117
- }
118
+ },
119
+ options.force
118
120
  );
119
121
 
120
122
  if (stats.successCount > 0) {
@@ -172,7 +172,8 @@ class GoogleTranslateService implements ITranslationService {
172
172
  skippedCount: 0,
173
173
  translatedKeys: [],
174
174
  },
175
- onTranslate?: (key: string, from: string, to: string) => void
175
+ onTranslate?: (key: string, from: string, to: string) => void,
176
+ force = false
176
177
  ): Promise<void> {
177
178
  if (!sourceObject || typeof sourceObject !== "object") return;
178
179
  if (!targetObject || typeof targetObject !== "object") return;
@@ -196,11 +197,12 @@ class GoogleTranslateService implements ITranslationService {
196
197
  targetLanguage,
197
198
  currentPath,
198
199
  stats,
199
- onTranslate
200
+ onTranslate,
201
+ force
200
202
  );
201
203
  } else if (typeof enValue === "string") {
202
204
  stats.totalCount++;
203
- if (needsTranslation(targetValue, enValue)) {
205
+ if (force || needsTranslation(targetValue, enValue)) {
204
206
  textsToTranslate.push({key, enValue, currentPath});
205
207
  } else {
206
208
  stats.skippedCount++;
@@ -226,8 +228,11 @@ class GoogleTranslateService implements ITranslationService {
226
228
 
227
229
  if (translatedItem && translatedItem.from === enValue && translatedItem.to !== enValue) {
228
230
  targetObject[key] = translatedItem.to;
231
+ stats.successCount++;
229
232
  if (onTranslate) onTranslate(currentPath, enValue, translatedItem.to);
230
233
  resultIndex++;
234
+ } else {
235
+ stats.failureCount++;
231
236
  }
232
237
  }
233
238
  }
@@ -0,0 +1,62 @@
1
+ import i18n from 'i18next';
2
+ import { initReactI18next } from 'react-i18next';
3
+ import LanguageDetector from 'i18next-browser-languagedetector';
4
+ import { initSEO } from '@umituz/web-seo';
5
+
6
+ export interface SetupI18nOptions {
7
+ resources: Record<string, { translation: any }>;
8
+ defaultLng?: string;
9
+ fallbackLng?: string;
10
+ onInit?: (instance: typeof i18n) => void;
11
+ detection?: any;
12
+ seo?: {
13
+ titleKey: string;
14
+ descriptionKey: string;
15
+ defaultImage?: string;
16
+ twitterHandle?: string;
17
+ };
18
+ }
19
+
20
+ /**
21
+ * Static i18n initialization to simplify main app code.
22
+ * @description All common configuration including SEO integration is hidden inside this package.
23
+ */
24
+ export function setupI18n(options: SetupI18nOptions) {
25
+ const {
26
+ resources,
27
+ defaultLng = 'en-US',
28
+ fallbackLng = 'en-US',
29
+ onInit,
30
+ detection = {
31
+ order: ['localStorage', 'navigator'],
32
+ caches: ['localStorage'],
33
+ },
34
+ seo,
35
+ } = options;
36
+
37
+ i18n
38
+ .use(LanguageDetector)
39
+ .use(initReactI18next)
40
+ .init({
41
+ resources,
42
+ lng: defaultLng,
43
+ fallbackLng,
44
+ interpolation: {
45
+ escapeValue: false,
46
+ },
47
+ detection,
48
+ })
49
+ .then(() => {
50
+ if (seo) {
51
+ initSEO({
52
+ i18n,
53
+ ...seo,
54
+ });
55
+ }
56
+ if (onInit) onInit(i18n);
57
+ });
58
+
59
+ return i18n;
60
+ }
61
+
62
+ export default i18n;
@@ -34,6 +34,7 @@ program
34
34
  .description("Automatically translate missing strings using Google Translate")
35
35
  .option("-d, --locales-dir <dir>", "Directory containing locale files", "src/locales")
36
36
  .option("-b, --base-lang <lang>", "Base language code", "en-US")
37
+ .option("-f, --force", "Force re-translation of all strings", false)
37
38
  .action(async (options) => {
38
39
  try {
39
40
  await cliService.translate(options);