@adminforth/i18n 1.0.11 → 1.0.13

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 CHANGED
@@ -5,9 +5,29 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+
9
+
10
+
11
+ ## [1.0.13]
12
+
13
+ - Deduplicate frontend strings before creating translations
14
+
15
+
16
+ ## [1.0.12]
17
+
18
+ ### Fixed
19
+
20
+ - live mode frontend translations loading when tmp dir is nopt preserver (e.g. docker cached /tmp pipeline)
21
+
22
+ ## [1.0.11]
23
+
24
+ ### Fixed
25
+
26
+ - cache invalidations on delete
27
+
8
28
  ## [v1.0.10]
9
29
 
10
- ## Fixed
30
+ ### Fixed
11
31
 
12
32
  - fix automatic translations for duplicate strings
13
33
  - improve slavik pluralization generations by splitting the requests
@@ -43,7 +43,7 @@
43
43
  import 'flag-icon-css/css/flag-icons.min.css';
44
44
  import { IconCaretDownSolid } from '@iconify-prerendered/vue-flowbite';
45
45
 
46
- import { setLang, getCountryCodeFromLangCode, getLocalLang } from './langCommon';
46
+ import { setLang, getCountryCodeFromLangCode, getLocalLang, setLocalLang } from './langCommon';
47
47
 
48
48
  import { computed, ref, onMounted, watch } from 'vue';
49
49
  import { useI18n } from 'vue-i18n';
@@ -56,7 +56,7 @@ const props = defineProps(['meta', 'resource']);
56
56
  const selectedLanguage = ref('');
57
57
 
58
58
  function doChangeLang(lang) {
59
- setLang({ setLocaleMessage, locale }, props.meta.pluginInstanceId, lang);
59
+ setLocalLang(lang);
60
60
  // unfortunately, we need this to recall all APIs
61
61
  document.location.reload();
62
62
 
@@ -43,7 +43,7 @@
43
43
  import 'flag-icon-css/css/flag-icons.min.css';
44
44
  import { IconCaretDownSolid } from '@iconify-prerendered/vue-flowbite';
45
45
 
46
- import { setLang, getCountryCodeFromLangCode, getLocalLang } from './langCommon';
46
+ import { setLang, getCountryCodeFromLangCode, getLocalLang, setLocalLang } from './langCommon';
47
47
 
48
48
  import { computed, ref, onMounted, watch } from 'vue';
49
49
  import { useI18n } from 'vue-i18n';
@@ -56,7 +56,7 @@ const props = defineProps(['meta', 'resource']);
56
56
  const selectedLanguage = ref('');
57
57
 
58
58
  function doChangeLang(lang) {
59
- setLang({ setLocaleMessage, locale }, props.meta.pluginInstanceId, lang);
59
+ setLocalLang(lang);
60
60
  // unfortunately, we need this to recall all APIs
61
61
  document.location.reload();
62
62
 
package/dist/index.js CHANGED
@@ -287,7 +287,7 @@ export default class I18N extends AdminForthPlugin {
287
287
  this.updateUntranslatedMenuBadge();
288
288
  return {
289
289
  ok: true, error: undefined,
290
- successMessage: yield tr(`Translated {count} items`, 'frontend', { count: selectedIds.length }),
290
+ successMessage: yield tr(`Translated {count} items`, 'backend', { count: selectedIds.length }),
291
291
  };
292
292
  })
293
293
  });
@@ -444,7 +444,13 @@ ${JSON.stringify(strings.reduce((acc, s) => {
444
444
  return;
445
445
  }
446
446
  // loop over missingKeys[i].path and add them to database if not exists
447
- yield Promise.all(messages.missingKeys.map((missingKey) => __awaiter(this, void 0, void 0, function* () {
447
+ const missingKeysDeduplicated = messages.missingKeys.reduce((acc, missingKey) => {
448
+ if (!acc.find((a) => a.path === missingKey.path)) {
449
+ acc.push(missingKey);
450
+ }
451
+ return acc;
452
+ }, []);
453
+ yield Promise.all(missingKeysDeduplicated.map((missingKey) => __awaiter(this, void 0, void 0, function* () {
448
454
  const key = missingKey.path;
449
455
  const file = missingKey.file;
450
456
  const category = 'frontend';
@@ -469,18 +475,20 @@ ${JSON.stringify(strings.reduce((acc, s) => {
469
475
  }
470
476
  tryProcessAndWatch(adminforth) {
471
477
  return __awaiter(this, void 0, void 0, function* () {
472
- const spaDir = adminforth.codeInjector.spaTmpPath();
478
+ const serveDir = adminforth.codeInjector.getServeDir();
473
479
  // messages file is in i18n-messages.json
474
- const messagesFile = path.join(spaDir, '..', 'spa_tmp', 'i18n-messages.json');
475
- console.log('🪲messagesFile', messagesFile);
480
+ const messagesFile = path.join(serveDir, 'i18n-messages.json');
481
+ process.env.HEAVY_DEBUG && console.log('🪲🔔messagesFile read started', messagesFile);
476
482
  this.processExtractedMessages(adminforth, messagesFile);
477
483
  // we use watcher because file can't be yet created when we start - bundleNow can be done in build time or can be done now
478
484
  // that is why we make attempt to process it now and then watch for changes
479
485
  const w = chokidar.watch(messagesFile, { persistent: true });
480
486
  w.on('change', () => {
487
+ process.env.HEAVY_DEBUG && console.log('🪲🔔messagesFile change', messagesFile);
481
488
  this.processExtractedMessages(adminforth, messagesFile);
482
489
  });
483
490
  w.on('add', () => {
491
+ process.env.HEAVY_DEBUG && console.log('🪲🔔messagesFile add', messagesFile);
484
492
  this.processExtractedMessages(adminforth, messagesFile);
485
493
  });
486
494
  });
@@ -518,10 +526,15 @@ ${JSON.stringify(strings.reduce((acc, s) => {
518
526
  if (!msg) {
519
527
  return msg;
520
528
  }
529
+ if (category === 'frontend') {
530
+ throw new Error(`Category 'frontend' is reserved for frontend messages, use any other category for backend messages`);
531
+ }
521
532
  // console.log('🪲tr', msg, category, lang);
522
533
  // if lang is not supported , throw
523
534
  if (!this.options.supportedLanguages.includes(lang)) {
524
- throw new Error(`Language ${lang} is not entered to be supported by requested by browser in request headers accept-language`);
535
+ lang = 'en'; // for now simply fallback to english
536
+ // throwing like line below might be too strict, e.g. for custom apis made with fetch which don't pass accept-language
537
+ // throw new Error(`Language ${lang} is not entered to be supported by requested by browser in request headers accept-language`);
525
538
  }
526
539
  let result;
527
540
  // try to get translation from cache
package/index.ts CHANGED
@@ -326,7 +326,7 @@ export default class I18N extends AdminForthPlugin {
326
326
  this.updateUntranslatedMenuBadge();
327
327
  return {
328
328
  ok: true, error: undefined,
329
- successMessage: await tr(`Translated {count} items`, 'frontend', {count: selectedIds.length}),
329
+ successMessage: await tr(`Translated {count} items`, 'backend', {count: selectedIds.length}),
330
330
  };
331
331
  }
332
332
  }
@@ -535,7 +535,15 @@ ${
535
535
  return;
536
536
  }
537
537
  // loop over missingKeys[i].path and add them to database if not exists
538
- await Promise.all(messages.missingKeys.map(async (missingKey: any) => {
538
+
539
+ const missingKeysDeduplicated = messages.missingKeys.reduce((acc: any[], missingKey: any) => {
540
+ if (!acc.find((a) => a.path === missingKey.path)) {
541
+ acc.push(missingKey);
542
+ }
543
+ return acc;
544
+ }, []);
545
+
546
+ await Promise.all(missingKeysDeduplicated.map(async (missingKey: any) => {
539
547
  const key = missingKey.path;
540
548
  const file = missingKey.file;
541
549
  const category = 'frontend';
@@ -560,24 +568,26 @@ ${
560
568
 
561
569
  // updateBadge
562
570
  this.updateUntranslatedMenuBadge()
563
-
564
-
565
571
  }
566
572
 
567
573
 
568
574
  async tryProcessAndWatch(adminforth: IAdminForth) {
569
- const spaDir = adminforth.codeInjector.spaTmpPath();
575
+ const serveDir = adminforth.codeInjector.getServeDir();
570
576
  // messages file is in i18n-messages.json
571
- const messagesFile = path.join(spaDir, '..', 'spa_tmp', 'i18n-messages.json');
572
- console.log('🪲messagesFile', messagesFile);
577
+ const messagesFile = path.join(serveDir, 'i18n-messages.json');
578
+ process.env.HEAVY_DEBUG && console.log('🪲🔔messagesFile read started', messagesFile);
573
579
  this.processExtractedMessages(adminforth, messagesFile);
574
580
  // we use watcher because file can't be yet created when we start - bundleNow can be done in build time or can be done now
575
581
  // that is why we make attempt to process it now and then watch for changes
576
582
  const w = chokidar.watch(messagesFile, { persistent: true });
577
583
  w.on('change', () => {
584
+ process.env.HEAVY_DEBUG && console.log('🪲🔔messagesFile change', messagesFile);
585
+
578
586
  this.processExtractedMessages(adminforth, messagesFile);
579
587
  });
580
588
  w.on('add', () => {
589
+ process.env.HEAVY_DEBUG && console.log('🪲🔔messagesFile add', messagesFile);
590
+
581
591
  this.processExtractedMessages(adminforth, messagesFile);
582
592
  });
583
593
 
@@ -619,11 +629,18 @@ ${
619
629
  if (!msg) {
620
630
  return msg;
621
631
  }
632
+
633
+ if (category === 'frontend') {
634
+ throw new Error(`Category 'frontend' is reserved for frontend messages, use any other category for backend messages`);
635
+ }
622
636
  // console.log('🪲tr', msg, category, lang);
623
637
 
624
638
  // if lang is not supported , throw
625
639
  if (!this.options.supportedLanguages.includes(lang as LanguageCode)) {
626
- throw new Error(`Language ${lang} is not entered to be supported by requested by browser in request headers accept-language`);
640
+ lang = 'en'; // for now simply fallback to english
641
+
642
+ // throwing like line below might be too strict, e.g. for custom apis made with fetch which don't pass accept-language
643
+ // throw new Error(`Language ${lang} is not entered to be supported by requested by browser in request headers accept-language`);
627
644
  }
628
645
 
629
646
  let result;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/i18n",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",