poly-lexis 0.1.0 → 0.2.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
@@ -1,36 +1,36 @@
1
- # Lexis
1
+ # poly-lexis
2
2
 
3
3
  A powerful CLI and library for managing i18n translations with validation, auto-translation, and TypeScript type generation.
4
4
 
5
5
  ## Overview
6
6
 
7
- Lexis provides a complete solution for managing internationalization (i18n) in your applications. It offers smart translation management with automatic validation, Google Translate integration for auto-filling missing translations, and TypeScript type generation for type-safe translations.
7
+ poly-lexis provides a complete solution for managing internationalization (i18n) in your applications. It offers smart translation management with automatic validation, Google Translate integration for auto-filling missing translations, and TypeScript type generation for type-safe translations.
8
8
 
9
9
  ## Installation
10
10
 
11
11
  ```bash
12
- npm install lexis
12
+ npm install poly-lexis
13
13
  # or
14
- yarn add lexis
14
+ yarn add poly-lexis
15
15
  # or
16
- pnpm add lexis
16
+ pnpm add poly-lexis
17
17
  ```
18
18
 
19
19
  ## Quick Start
20
20
 
21
21
  ```bash
22
22
  # Initialize translations in your project
23
- npx lexis
23
+ npx poly-lexis
24
24
 
25
25
  # Add a new translation key
26
- npx lexis add
26
+ npx poly-lexis add
27
27
 
28
28
  # Auto-fill missing translations
29
29
  export GOOGLE_TRANSLATE_API_KEY=your_key
30
- npx lexis --auto-fill
30
+ npx poly-lexis --auto-fill
31
31
 
32
32
  # Validate and generate types
33
- npx lexis
33
+ npx poly-lexis
34
34
  ```
35
35
 
36
36
  ## Features
@@ -51,32 +51,32 @@ Run without any command to validate, auto-fill (optional), and generate types:
51
51
 
52
52
  ```bash
53
53
  # Basic validation and type generation
54
- lexis
54
+ poly-lexis
55
55
 
56
56
  # With auto-translation
57
- lexis --auto-fill
57
+ poly-lexis --auto-fill
58
58
 
59
59
  # Auto-fill only specific language
60
- lexis --auto-fill --language fr
60
+ poly-lexis --auto-fill --language fr
61
61
 
62
62
  # Dry run to preview changes
63
- lexis --auto-fill --dry-run
63
+ poly-lexis --auto-fill --dry-run
64
64
 
65
65
  # Skip type generation
66
- lexis --skip-types
66
+ poly-lexis --skip-types
67
67
  ```
68
68
 
69
69
  ### Add Translation Keys
70
70
 
71
71
  ```bash
72
72
  # Interactive mode
73
- lexis add
73
+ poly-lexis add
74
74
 
75
75
  # With flags
76
- lexis add --namespace common --key HELLO --value "Hello"
76
+ poly-lexis add --namespace common --key HELLO --value "Hello"
77
77
 
78
78
  # With auto-translation
79
- lexis add -n common -k WELCOME -v "Welcome" --auto-fill
79
+ poly-lexis add -n common -k WELCOME -v "Welcome" --auto-fill
80
80
  ```
81
81
 
82
82
  ### CLI Options
@@ -97,7 +97,7 @@ lexis add -n common -k WELCOME -v "Welcome" --auto-fill
97
97
 
98
98
  ## Configuration
99
99
 
100
- Lexis uses a `.translationsrc.json` file in your project root for configuration:
100
+ poly-lexis uses a `.translationsrc.json` file in your project root for configuration:
101
101
 
102
102
  ```json
103
103
  {
@@ -157,12 +157,12 @@ Translation files are organized by namespace and language:
157
157
 
158
158
  ## Programmatic API
159
159
 
160
- Lexis can be used as a library in your Node.js code:
160
+ poly-lexis can be used as a library in your Node.js code:
161
161
 
162
162
  ### Initialize Translations
163
163
 
164
164
  ```typescript
165
- import { initTranslationsInteractive } from 'lexis';
165
+ import { initTranslationsInteractive } from 'poly-lexis';
166
166
 
167
167
  await initTranslationsInteractive(process.cwd());
168
168
  ```
@@ -170,7 +170,7 @@ await initTranslationsInteractive(process.cwd());
170
170
  ### Add Translation Key
171
171
 
172
172
  ```typescript
173
- import { addTranslationKey } from 'lexis';
173
+ import { addTranslationKey } from 'poly-lexis';
174
174
 
175
175
  await addTranslationKey(process.cwd(), {
176
176
  namespace: 'common',
@@ -184,7 +184,7 @@ await addTranslationKey(process.cwd(), {
184
184
  ### Validate Translations
185
185
 
186
186
  ```typescript
187
- import { validateTranslations } from 'lexis';
187
+ import { validateTranslations } from 'poly-lexis';
188
188
 
189
189
  const result = await validateTranslations(
190
190
  '/path/to/translations',
@@ -200,7 +200,7 @@ if (!result.valid) {
200
200
  ### Generate TypeScript Types
201
201
 
202
202
  ```typescript
203
- import { generateTranslationTypes } from 'lexis';
203
+ import { generateTranslationTypes } from 'poly-lexis';
204
204
 
205
205
  generateTranslationTypes(process.cwd());
206
206
  ```
@@ -208,7 +208,7 @@ generateTranslationTypes(process.cwd());
208
208
  ### Auto-fill Missing Translations
209
209
 
210
210
  ```typescript
211
- import { autoFillTranslations } from 'lexis';
211
+ import { autoFillTranslations } from 'poly-lexis';
212
212
 
213
213
  await autoFillTranslations({
214
214
  translationsPath: '/path/to/translations',
@@ -48,7 +48,8 @@ function writeTranslation(translationsPath, language, namespace, translations) {
48
48
  fs.mkdirSync(langPath, { recursive: true });
49
49
  }
50
50
  const filePath = path2.join(langPath, `${namespace}.json`);
51
- fs.writeFileSync(filePath, JSON.stringify(translations, null, 2) + "\n", "utf-8");
51
+ fs.writeFileSync(filePath, `${JSON.stringify(translations, null, 2)}
52
+ `, "utf-8");
52
53
  }
53
54
  function getAvailableLanguages(translationsPath) {
54
55
  if (!fs.existsSync(translationsPath)) {
@@ -106,54 +107,274 @@ var init_schema = __esm({
106
107
  "use strict";
107
108
  init_esm_shims();
108
109
  SUPPORTED_LANGUAGES = [
110
+ "af",
111
+ // Afrikaans
112
+ "sq",
113
+ // Albanian
114
+ "am",
115
+ // Amharic
116
+ "ar",
117
+ // Arabic
118
+ "hy",
119
+ // Armenian
120
+ "as",
121
+ // Assamese
122
+ "ay",
123
+ // Aymara
124
+ "az",
125
+ // Azerbaijani
126
+ "bm",
127
+ // Bambara
128
+ "eu",
129
+ // Basque
130
+ "be",
131
+ // Belarusian
132
+ "bn",
133
+ // Bengali
134
+ "bho",
135
+ // Bhojpuri
136
+ "bs",
137
+ // Bosnian
138
+ "bg",
139
+ // Bulgarian
140
+ "ca",
141
+ // Catalan
142
+ "ceb",
143
+ // Cebuano
144
+ "ny",
145
+ // Chichewa
146
+ "zh",
147
+ // Chinese (Simplified) - Google uses 'zh' or 'zh-CN'
148
+ "zh_cn",
149
+ // Chinese (Simplified) - alternative format
150
+ "zh_tw",
151
+ // Chinese (Traditional)
152
+ "co",
153
+ // Corsican
154
+ "hr",
155
+ // Croatian
156
+ "cs",
157
+ // Czech
158
+ "da",
159
+ // Danish
160
+ "dv",
161
+ // Dhivehi
162
+ "doi",
163
+ // Dogri
164
+ "nl",
165
+ // Dutch
109
166
  "en",
110
167
  // English
168
+ "eo",
169
+ // Esperanto
170
+ "et",
171
+ // Estonian
172
+ "ee",
173
+ // Ewe
174
+ "tl",
175
+ // Filipino (Tagalog)
176
+ "fi",
177
+ // Finnish
111
178
  "fr",
112
179
  // French
113
- "it",
114
- // Italian
115
- "pl",
116
- // Polish
117
- "es",
118
- // Spanish
119
- "pt",
120
- // Portuguese
180
+ "gl",
181
+ // Galician
182
+ "ka",
183
+ // Georgian
121
184
  "de",
122
185
  // German
123
- "de_at",
124
- // German (Austria)
125
- "nl",
126
- // Dutch
127
- "sv",
128
- // Swedish
186
+ "el",
187
+ // Greek
188
+ "gn",
189
+ // Guarani
190
+ "gu",
191
+ // Gujarati
192
+ "ht",
193
+ // Haitian Creole
194
+ "ha",
195
+ // Hausa
196
+ "haw",
197
+ // Hawaiian
198
+ "iw",
199
+ // Hebrew (legacy code, 'he' is preferred)
200
+ "he",
201
+ // Hebrew
202
+ "hi",
203
+ // Hindi
204
+ "hmn",
205
+ // Hmong
129
206
  "hu",
130
207
  // Hungarian
131
- "cs",
132
- // Czech
208
+ "is",
209
+ // Icelandic
210
+ "ig",
211
+ // Igbo
212
+ "ilo",
213
+ // Ilocano
214
+ "id",
215
+ // Indonesian
216
+ "ga",
217
+ // Irish
218
+ "it",
219
+ // Italian
133
220
  "ja",
134
221
  // Japanese
135
- "zh_hk",
136
- // Chinese (Hong Kong)
137
- "zh_cn",
138
- // Chinese (Simplified)
222
+ "jw",
223
+ // Javanese
224
+ "kn",
225
+ // Kannada
226
+ "kk",
227
+ // Kazakh
228
+ "km",
229
+ // Khmer
230
+ "rw",
231
+ // Kinyarwanda
232
+ "gom",
233
+ // Konkani
139
234
  "ko",
140
235
  // Korean
236
+ "kri",
237
+ // Krio
238
+ "ku",
239
+ // Kurdish (Kurmanji)
240
+ "ckb",
241
+ // Kurdish (Sorani)
242
+ "ky",
243
+ // Kyrgyz
244
+ "lo",
245
+ // Lao
246
+ "la",
247
+ // Latin
248
+ "lv",
249
+ // Latvian
250
+ "ln",
251
+ // Lingala
252
+ "lt",
253
+ // Lithuanian
254
+ "lg",
255
+ // Luganda
256
+ "lb",
257
+ // Luxembourgish
258
+ "mk",
259
+ // Macedonian
260
+ "mai",
261
+ // Maithili
262
+ "mg",
263
+ // Malagasy
264
+ "ms",
265
+ // Malay
266
+ "ml",
267
+ // Malayalam
268
+ "mt",
269
+ // Maltese
270
+ "mi",
271
+ // Maori
272
+ "mr",
273
+ // Marathi
274
+ "mni",
275
+ // Meiteilon (Manipuri)
276
+ "lus",
277
+ // Mizo
278
+ "mn",
279
+ // Mongolian
280
+ "my",
281
+ // Myanmar (Burmese)
282
+ "ne",
283
+ // Nepali
284
+ "no",
285
+ // Norwegian
286
+ "or",
287
+ // Odia
288
+ "om",
289
+ // Oromo
290
+ "ps",
291
+ // Pashto
292
+ "fa",
293
+ // Persian
294
+ "pl",
295
+ // Polish
296
+ "pt",
297
+ // Portuguese
298
+ "pt_br",
299
+ // Portuguese (Brazil)
300
+ "pa",
301
+ // Punjabi
302
+ "qu",
303
+ // Quechua
304
+ "ro",
305
+ // Romanian
141
306
  "ru",
142
307
  // Russian
143
- "ar",
144
- // Arabic
145
- "he",
146
- // Hebrew
308
+ "sm",
309
+ // Samoan
310
+ "sa",
311
+ // Sanskrit
312
+ "gd",
313
+ // Scottish Gaelic
314
+ "sr",
315
+ // Serbian
316
+ "st",
317
+ // Sesotho
318
+ "sn",
319
+ // Shona
320
+ "sd",
321
+ // Sindhi
322
+ "si",
323
+ // Sinhala
324
+ "sk",
325
+ // Slovak
326
+ "sl",
327
+ // Slovenian
328
+ "so",
329
+ // Somali
330
+ "es",
331
+ // Spanish
332
+ "su",
333
+ // Sundanese
334
+ "sw",
335
+ // Swahili
336
+ "sv",
337
+ // Swedish
338
+ "tg",
339
+ // Tajik
340
+ "ta",
341
+ // Tamil
342
+ "tt",
343
+ // Tatar
344
+ "te",
345
+ // Telugu
346
+ "th",
347
+ // Thai
348
+ "ti",
349
+ // Tigrinya
350
+ "ts",
351
+ // Tsonga
147
352
  "tr",
148
353
  // Turkish
149
- "da",
150
- // Danish
151
- "fi",
152
- // Finnish
153
- "no",
154
- // Norwegian
155
- "pt_br"
156
- // Portuguese (Brazil)
354
+ "tk",
355
+ // Turkmen
356
+ "ak",
357
+ // Twi
358
+ "uk",
359
+ // Ukrainian
360
+ "ur",
361
+ // Urdu
362
+ "ug",
363
+ // Uyghur
364
+ "uz",
365
+ // Uzbek
366
+ "vi",
367
+ // Vietnamese
368
+ "cy",
369
+ // Welsh
370
+ "xh",
371
+ // Xhosa
372
+ "yi",
373
+ // Yiddish
374
+ "yo",
375
+ // Yoruba
376
+ "zu"
377
+ // Zulu
157
378
  ];
158
379
  }
159
380
  });
@@ -255,7 +476,8 @@ function initTranslations(projectRoot, config = {}) {
255
476
  ERROR: "Error",
256
477
  SUCCESS: "Success"
257
478
  };
258
- fs2.writeFileSync(commonPath, JSON.stringify(sampleTranslations, null, 2) + "\n", "utf-8");
479
+ fs2.writeFileSync(commonPath, `${JSON.stringify(sampleTranslations, null, 2)}
480
+ `, "utf-8");
259
481
  console.log(`Created sample file: ${commonPath}`);
260
482
  }
261
483
  for (const lang of languages) {
@@ -275,7 +497,8 @@ function initTranslations(projectRoot, config = {}) {
275
497
  sourceLanguage,
276
498
  typesOutputPath: finalConfig.typesOutputPath
277
499
  };
278
- fs2.writeFileSync(configPath, JSON.stringify(configContent, null, 2) + "\n", "utf-8");
500
+ fs2.writeFileSync(configPath, `${JSON.stringify(configContent, null, 2)}
501
+ `, "utf-8");
279
502
  console.log(`Created config file: ${configPath}`);
280
503
  }
281
504
  console.log("=====");
@@ -357,7 +580,10 @@ function generateTranslationTypes(projectRoot = process.cwd()) {
357
580
  console.log(`Generated types with ${allKeys.length} keys and ${namespaces.length} namespaces`);
358
581
  console.log(`Output: ${outputFilePath}`);
359
582
  try {
360
- execSync(`pnpm biome format --write ${outputFilePath}`, { stdio: "inherit", cwd: projectRoot });
583
+ execSync(`pnpm biome format --write ${outputFilePath}`, {
584
+ stdio: "inherit",
585
+ cwd: projectRoot
586
+ });
361
587
  } catch {
362
588
  console.warn("Failed to format with Biome, continuing without formatting...");
363
589
  }
@@ -384,10 +610,10 @@ var init_generate_types = __esm({
384
610
  // src/cli/translations.ts
385
611
  init_esm_shims();
386
612
  import "dotenv/config";
387
- import { confirm as confirm2, input as input2, select } from "@inquirer/prompts";
388
613
  import * as fs5 from "fs";
389
614
  import * as path10 from "path";
390
615
  import { parseArgs } from "util";
616
+ import { confirm as confirm2, input as input2, select } from "@inquirer/prompts";
391
617
 
392
618
  // src/translations/cli/add-key.ts
393
619
  init_esm_shims();
@@ -395,10 +621,10 @@ import * as path4 from "path";
395
621
 
396
622
  // src/translations/utils/translator.ts
397
623
  init_esm_shims();
398
- async function translateText(text, targetLang, sourceLang = "en", apiKey) {
399
- if (!apiKey) {
400
- throw new Error("Google Translate API key is required. Set GOOGLE_TRANSLATE_API_KEY environment variable.");
401
- }
624
+
625
+ // src/translations/utils/google-translate-provider.ts
626
+ init_esm_shims();
627
+ function preserveVariables(text) {
402
628
  const variableMap = /* @__PURE__ */ new Map();
403
629
  let placeholderIndex = 0;
404
630
  const textWithPlaceholders = text.replace(/\{\{([^}]+)\}\}/g, (match) => {
@@ -407,29 +633,81 @@ async function translateText(text, targetLang, sourceLang = "en", apiKey) {
407
633
  placeholderIndex++;
408
634
  return placeholder;
409
635
  });
410
- const url = `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`;
411
- const response = await fetch(url, {
412
- method: "POST",
413
- headers: {
414
- "Content-Type": "application/json"
415
- },
416
- body: JSON.stringify({
417
- q: textWithPlaceholders,
418
- source: sourceLang,
419
- target: targetLang.split("_")[0],
420
- // Convert 'pt_BR' to 'pt'
421
- format: "text"
422
- })
423
- });
424
- const data = await response.json();
425
- if (data.error) {
426
- throw new Error(`Google Translate API error: ${data.error.message}`);
427
- }
428
- let translatedText = data.data.translations[0].translatedText;
636
+ return { textWithPlaceholders, variableMap };
637
+ }
638
+ function restoreVariables(text, variableMap) {
639
+ let result = text;
429
640
  for (const [placeholder, original] of variableMap) {
430
- translatedText = translatedText.replace(new RegExp(placeholder, "g"), original);
641
+ result = result.replace(new RegExp(placeholder, "g"), original);
642
+ }
643
+ return result;
644
+ }
645
+ var GoogleTranslateProvider = class {
646
+ async translate(options) {
647
+ const { text, sourceLang, targetLang, apiKey } = options;
648
+ if (!apiKey) {
649
+ throw new Error(
650
+ "Google Translate API key is required. Set GOOGLE_TRANSLATE_API_KEY environment variable or provide apiKey in options."
651
+ );
652
+ }
653
+ const { textWithPlaceholders, variableMap } = preserveVariables(text);
654
+ const url = `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`;
655
+ const response = await fetch(url, {
656
+ method: "POST",
657
+ headers: {
658
+ "Content-Type": "application/json"
659
+ },
660
+ body: JSON.stringify({
661
+ q: textWithPlaceholders,
662
+ source: sourceLang,
663
+ target: targetLang.split("_")[0],
664
+ // Convert 'pt_BR' to 'pt'
665
+ format: "text"
666
+ })
667
+ });
668
+ const data = await response.json();
669
+ if (data.error) {
670
+ throw new Error(`Google Translate API error: ${data.error.message}`);
671
+ }
672
+ const translatedText = data.data.translations[0].translatedText;
673
+ return restoreVariables(translatedText, variableMap);
674
+ }
675
+ async translateBatch(texts, sourceLang, targetLang, apiKey, delayMs = 100) {
676
+ const results = [];
677
+ for (const text of texts) {
678
+ const translated = await this.translate({
679
+ text,
680
+ sourceLang,
681
+ targetLang,
682
+ apiKey
683
+ });
684
+ results.push(translated);
685
+ if (delayMs > 0) {
686
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
687
+ }
688
+ }
689
+ return results;
431
690
  }
432
- return translatedText;
691
+ async validateConfig() {
692
+ const apiKey = process.env.GOOGLE_TRANSLATE_API_KEY;
693
+ return !!apiKey;
694
+ }
695
+ };
696
+
697
+ // src/translations/utils/translator.ts
698
+ var defaultProvider = new GoogleTranslateProvider();
699
+ var customProvider = null;
700
+ function getTranslationProvider() {
701
+ return customProvider || defaultProvider;
702
+ }
703
+ async function translateText(text, targetLang, sourceLang = "en", apiKey) {
704
+ const provider = getTranslationProvider();
705
+ return provider.translate({
706
+ text,
707
+ sourceLang,
708
+ targetLang,
709
+ apiKey
710
+ });
433
711
  }
434
712
 
435
713
  // src/translations/cli/add-key.ts