@adminforth/i18n 1.0.8 → 1.0.10

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/Changelog.md ADDED
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [v1.0.10]
9
+
10
+ ## Fixed
11
+
12
+ - fix automatic translations for duplicate strings
13
+ - improve slavik pluralization generations by splitting the requests
package/dist/index.js CHANGED
@@ -12,6 +12,19 @@ import iso6391 from 'iso-639-1';
12
12
  import path from 'path';
13
13
  import fs from 'fs-extra';
14
14
  import chokidar from 'chokidar';
15
+ const SLAVIC_PLURAL_EXAMPLES = {
16
+ uk: 'яблук | Яблуко | Яблука | Яблук', // zero | singular | 2-4 | 5+
17
+ bg: 'ябълки | ябълка | ябълки | ябълки', // zero | singular | 2-4 | 5+
18
+ cs: 'jablek | jablko | jablka | jablek', // zero | singular | 2-4 | 5+
19
+ hr: 'jabuka | jabuka | jabuke | jabuka', // zero | singular | 2-4 | 5+
20
+ mk: 'јаболка | јаболко | јаболка | јаболка', // zero | singular | 2-4 | 5+
21
+ pl: 'jabłek | jabłko | jabłka | jabłek', // zero | singular | 2-4 | 5+
22
+ sk: 'jabĺk | jablko | jablká | jabĺk', // zero | singular | 2-4 | 5+
23
+ sl: 'jabolk | jabolko | jabolka | jabolk', // zero | singular | 2-4 | 5+
24
+ sr: 'јабука | јабука | јабуке | јабука', // zero | singular | 2-4 | 5+
25
+ be: 'яблыкаў | яблык | яблыкі | яблыкаў', // zero | singular | 2-4 | 5+
26
+ ru: 'яблок | яблоко | яблока | яблок', // zero | singular | 2-4 | 5+
27
+ };
15
28
  class CachingAdapterMemory {
16
29
  constructor() {
17
30
  this.cache = {};
@@ -295,6 +308,7 @@ export default class I18N extends AdminForthPlugin {
295
308
  });
296
309
  });
297
310
  }
311
+ // returns translated count
298
312
  bulkTranslate(_a) {
299
313
  return __awaiter(this, arguments, void 0, function* ({ selectedIds }) {
300
314
  const needToTranslateByLang = {};
@@ -318,17 +332,24 @@ export default class I18N extends AdminForthPlugin {
318
332
  }
319
333
  const maxKeysInOneReq = 10;
320
334
  const updateStrings = {};
321
- const translateToLang = (langIsoCode, strings) => __awaiter(this, void 0, void 0, function* () {
335
+ const translateToLang = (langIsoCode_1, strings_1, ...args_1) => __awaiter(this, [langIsoCode_1, strings_1, ...args_1], void 0, function* (langIsoCode, strings, plurals = false) {
336
+ if (strings.length === 0) {
337
+ return 0;
338
+ }
322
339
  if (strings.length > maxKeysInOneReq) {
340
+ let totalTranslated = 0;
323
341
  for (let i = 0; i < strings.length; i += maxKeysInOneReq) {
324
342
  const slicedStrings = strings.slice(i, i + maxKeysInOneReq);
325
- yield translateToLang(langIsoCode, slicedStrings);
343
+ console.log('🪲🔪slicedStrings ', slicedStrings);
344
+ totalTranslated += yield translateToLang(langIsoCode, slicedStrings, plurals);
326
345
  }
327
- return;
346
+ return totalTranslated;
328
347
  }
329
348
  const lang = langIsoCode;
349
+ const requestSlavicPlurals = Object.keys(SLAVIC_PLURAL_EXAMPLES).includes(lang) && plurals;
330
350
  const prompt = `
331
351
  I need to translate strings in JSON to ${lang} language from English for my web app.
352
+ ${requestSlavicPlurals ? `You should provide 4 translations (in format zero | singular | 2-4 | 5+) e.g. ${SLAVIC_PLURAL_EXAMPLES[lang]}` : ''}
332
353
  Keep keys, as is, write translation into values! Here are the strings:
333
354
 
334
355
  \`\`\`json
@@ -363,22 +384,29 @@ ${JSON.stringify(strings.reduce((acc, s) => {
363
384
  const translationsTargeted = translations.filter(t => t[this.enFieldName] === enStr);
364
385
  // might be several with same en_string
365
386
  for (const translation of translationsTargeted) {
366
- translation[this.trFieldNames[lang]] = translatedStr;
387
+ //translation[this.trFieldNames[lang]] = translatedStr;
367
388
  // process.env.HEAVY_DEBUG && console.log(`🪲translated to ${lang} ${translation.en_string}, ${translatedStr}`)
368
- if (!updateStrings[enStr]) {
369
- updateStrings[enStr] = {
389
+ if (!updateStrings[translation[this.primaryKeyFieldName]]) {
390
+ updateStrings[translation[this.primaryKeyFieldName]] = {
370
391
  updates: {},
392
+ translatedStr,
371
393
  category: translation[this.options.categoryFieldName],
372
394
  strId: translation[this.primaryKeyFieldName],
373
395
  };
374
396
  }
375
- updateStrings[enStr].updates[this.trFieldNames[lang]] = translatedStr;
397
+ updateStrings[translation[this.primaryKeyFieldName]].updates[this.trFieldNames[lang]] = translatedStr;
376
398
  }
377
399
  }
400
+ return res.length;
378
401
  });
379
402
  const langsInvolved = new Set(Object.keys(needToTranslateByLang));
403
+ let totalTranslated = 0;
380
404
  yield Promise.all(Object.entries(needToTranslateByLang).map((_b) => __awaiter(this, [_b], void 0, function* ([lang, strings]) {
381
- yield translateToLang(lang, strings);
405
+ // first translate without plurals
406
+ const stringsWithoutPlurals = strings.filter(s => !s.en_string.includes('|'));
407
+ totalTranslated += yield translateToLang(lang, stringsWithoutPlurals, false);
408
+ const stringsWithPlurals = strings.filter(s => s.en_string.includes('|'));
409
+ totalTranslated += yield translateToLang(lang, stringsWithPlurals, true);
382
410
  })));
383
411
  yield Promise.all(Object.entries(updateStrings).map((_c) => __awaiter(this, [_c], void 0, function* ([_, { updates, strId }]) {
384
412
  // because this will translate all languages, we can set completedLangs to all languages
@@ -391,6 +419,7 @@ ${JSON.stringify(strings.reduce((acc, s) => {
391
419
  this.cache.clear(`${this.resourceConfig.resourceId}:${category}:${lang}:${enStr}`);
392
420
  }
393
421
  }
422
+ return totalTranslated;
394
423
  });
395
424
  }
396
425
  processExtractedMessages(adminforth, filePath) {
package/index.ts CHANGED
@@ -6,6 +6,20 @@ import path from 'path';
6
6
  import fs from 'fs-extra';
7
7
  import chokidar from 'chokidar';
8
8
 
9
+ const SLAVIC_PLURAL_EXAMPLES = {
10
+ uk: 'яблук | Яблуко | Яблука | Яблук', // zero | singular | 2-4 | 5+
11
+ bg: 'ябълки | ябълка | ябълки | ябълки', // zero | singular | 2-4 | 5+
12
+ cs: 'jablek | jablko | jablka | jablek', // zero | singular | 2-4 | 5+
13
+ hr: 'jabuka | jabuka | jabuke | jabuka', // zero | singular | 2-4 | 5+
14
+ mk: 'јаболка | јаболко | јаболка | јаболка', // zero | singular | 2-4 | 5+
15
+ pl: 'jabłek | jabłko | jabłka | jabłek', // zero | singular | 2-4 | 5+
16
+ sk: 'jabĺk | jablko | jablká | jabĺk', // zero | singular | 2-4 | 5+
17
+ sl: 'jabolk | jabolko | jabolka | jabolk', // zero | singular | 2-4 | 5+
18
+ sr: 'јабука | јабука | јабуке | јабука', // zero | singular | 2-4 | 5+
19
+ be: 'яблыкаў | яблык | яблыкі | яблыкаў', // zero | singular | 2-4 | 5+
20
+ ru: 'яблок | яблоко | яблока | яблок', // zero | singular | 2-4 | 5+
21
+ };
22
+
9
23
  interface ICachingAdapter {
10
24
  get(key: string): Promise<any>;
11
25
  set(key: string, value: any): Promise<void>;
@@ -333,7 +347,8 @@ export default class I18N extends AdminForthPlugin {
333
347
  });
334
348
  }
335
349
 
336
- async bulkTranslate({ selectedIds }: { selectedIds: string[] }) {
350
+ // returns translated count
351
+ async bulkTranslate({ selectedIds }: { selectedIds: string[] }): Promise<number> {
337
352
 
338
353
  const needToTranslateByLang : Partial<
339
354
  Record<
@@ -368,22 +383,33 @@ export default class I18N extends AdminForthPlugin {
368
383
  const maxKeysInOneReq = 10;
369
384
 
370
385
  const updateStrings: Record<string, {
371
- updates: any, category: string, strId: string
386
+ updates: any,
387
+ category: string,
388
+ strId: string,
389
+ translatedStr: string
372
390
  }> = {};
373
391
 
374
- const translateToLang = async (langIsoCode: LanguageCode, strings: { en_string: string, category: string }[]) => {
375
-
392
+ const translateToLang = async (langIsoCode: LanguageCode, strings: { en_string: string, category: string }[], plurals=false): Promise<number> => {
393
+ if (strings.length === 0) {
394
+ return 0;
395
+ }
376
396
 
377
397
  if (strings.length > maxKeysInOneReq) {
398
+ let totalTranslated = 0;
378
399
  for (let i = 0; i < strings.length; i += maxKeysInOneReq) {
379
400
  const slicedStrings = strings.slice(i, i + maxKeysInOneReq);
380
- await translateToLang(langIsoCode, slicedStrings);
401
+ console.log('🪲🔪slicedStrings ', slicedStrings);
402
+ totalTranslated += await translateToLang(langIsoCode, slicedStrings, plurals);
381
403
  }
382
- return;
404
+ return totalTranslated;
383
405
  }
384
406
  const lang = langIsoCode;
407
+
408
+ const requestSlavicPlurals = Object.keys(SLAVIC_PLURAL_EXAMPLES).includes(lang) && plurals;
409
+
385
410
  const prompt = `
386
411
  I need to translate strings in JSON to ${lang} language from English for my web app.
412
+ ${requestSlavicPlurals ? `You should provide 4 translations (in format zero | singular | 2-4 | 5+) e.g. ${SLAVIC_PLURAL_EXAMPLES[lang]}` : ''}
387
413
  Keep keys, as is, write translation into values! Here are the strings:
388
414
 
389
415
  \`\`\`json
@@ -424,29 +450,42 @@ ${
424
450
  return;
425
451
  }
426
452
  res = JSON.parse(res);
427
- for (const [enStr, translatedStr] of Object.entries(res)) {
453
+
454
+
455
+ for (const [enStr, translatedStr] of Object.entries(res) as [string, string][]) {
428
456
  const translationsTargeted = translations.filter(t => t[this.enFieldName] === enStr);
429
457
  // might be several with same en_string
430
458
  for (const translation of translationsTargeted) {
431
- translation[this.trFieldNames[lang]] = translatedStr;
459
+ //translation[this.trFieldNames[lang]] = translatedStr;
432
460
  // process.env.HEAVY_DEBUG && console.log(`🪲translated to ${lang} ${translation.en_string}, ${translatedStr}`)
433
- if (!updateStrings[enStr]) {
434
- updateStrings[enStr] = {
461
+ if (!updateStrings[translation[this.primaryKeyFieldName]]) {
462
+
463
+ updateStrings[translation[this.primaryKeyFieldName]] = {
435
464
  updates: {},
465
+ translatedStr,
436
466
  category: translation[this.options.categoryFieldName],
437
467
  strId: translation[this.primaryKeyFieldName],
438
468
  };
439
469
  }
440
- updateStrings[enStr].updates[this.trFieldNames[lang]] = translatedStr;
470
+ updateStrings[
471
+ translation[this.primaryKeyFieldName]
472
+ ].updates[this.trFieldNames[lang]] = translatedStr;
441
473
  }
442
474
  }
443
475
 
476
+ return res.length;
444
477
  }
445
478
 
446
479
  const langsInvolved = new Set(Object.keys(needToTranslateByLang));
447
480
 
481
+ let totalTranslated = 0;
448
482
  await Promise.all(Object.entries(needToTranslateByLang).map(async ([lang, strings]: [LanguageCode, { en_string: string, category: string }[]]) => {
449
- await translateToLang(lang, strings);
483
+ // first translate without plurals
484
+ const stringsWithoutPlurals = strings.filter(s => !s.en_string.includes('|'));
485
+ totalTranslated += await translateToLang(lang, stringsWithoutPlurals, false);
486
+
487
+ const stringsWithPlurals = strings.filter(s => s.en_string.includes('|'));
488
+ totalTranslated += await translateToLang(lang, stringsWithPlurals, true);
450
489
  }));
451
490
 
452
491
  await Promise.all(
@@ -470,6 +509,8 @@ ${
470
509
  }
471
510
  }
472
511
 
512
+ return totalTranslated;
513
+
473
514
  }
474
515
 
475
516
  async processExtractedMessages(adminforth: IAdminForth, filePath: string) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/i18n",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",