@zeesoft/i18n-verify 2.0.2 → 2.1.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.
Files changed (37) hide show
  1. package/dist/driver/adapters/cypress.js +2 -1
  2. package/dist/driver/adapters/nightwatch.js +43 -2
  3. package/dist/driver/baseDriver.js +24 -0
  4. package/dist/index.js +10 -5
  5. package/dist/lib/i18n.js +125 -43
  6. package/dist/{utils → lib}/reports.js +42 -27
  7. package/dist/lib/validator/string.js +2 -2
  8. package/dist/template/report.html +1678 -0
  9. package/dist/utils/cache.js +15 -15
  10. package/dist/utils/constants.js +8 -5
  11. package/dist/utils/file.js +8 -4
  12. package/dist/utils/logs.js +30 -11
  13. package/dist/utils/objects/cacheData.js +14 -33
  14. package/dist/utils/objects/metaData.js +7 -26
  15. package/dist/utils/objects/reportData.js +0 -18
  16. package/dist/utils/objects/statData.js +43 -28
  17. package/dist/utils/objects/stringData.js +4 -7
  18. package/dist/utils/reportFactory/base.js +15 -7
  19. package/dist/utils/reportFactory/html/index.js +13 -9
  20. package/dist/utils/reportFactory/html/template/body.js +110 -0
  21. package/dist/utils/reportFactory/html/template/css.js +446 -409
  22. package/dist/utils/reportFactory/html/template/html.js +15 -112
  23. package/dist/utils/reportFactory/html/template/javascript/data.js +59 -1
  24. package/dist/utils/reportFactory/html/template/javascript/global.js +19 -0
  25. package/dist/utils/reportFactory/html/template/javascript/grid.js +54 -80
  26. package/dist/utils/reportFactory/html/template/javascript/index.js +7 -7
  27. package/dist/utils/reportFactory/html/template/javascript/insight.js +226 -201
  28. package/dist/utils/reportFactory/html/template/javascript/menuBar.js +40 -35
  29. package/dist/utils/reportFactory/html/template/javascript/overview.js +725 -533
  30. package/dist/utils/reportFactory/index.js +4 -6
  31. package/dist/utils/reportFactory/table.js +95 -0
  32. package/dist/utils/resource.js +10 -6
  33. package/dist/utils/runtime.js +23 -3
  34. package/dist/utils/scripts/postinstall.js +3 -2
  35. package/package.json +8 -3
  36. package/types/index.d.ts +46 -0
  37. package/dist/utils/reportsTable.js +0 -71
@@ -0,0 +1,1678 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <meta name="author" content="zeesoft" />
7
+ <meta name="description" content="I18n verification report" />
8
+ <title>I18n Verifcation Report | 9/4/2024, 2:25:15 am</title>
9
+ <style>
10
+ * {
11
+ user-select: none;
12
+ }
13
+
14
+ body {
15
+ margin: 0;
16
+ display: flex;
17
+ flex-direction: column;
18
+ font-family: Arial, sans-serif;
19
+ font-family: 'Helvetica Neue', Arial, sans-serif;
20
+ -webkit-font-smoothing: antialiased; /* Webkit-based browsers */
21
+ -moz-osx-font-smoothing: grayscale; /* Firefox on OS X */
22
+ font-smooth: always; /* Non-standard, some browsers */
23
+ }
24
+
25
+ header {
26
+ background-color: #333;
27
+ height: 5rem;
28
+ }
29
+
30
+ main {
31
+ display: flex;
32
+ direction: column;
33
+ width: 100%;
34
+ height: calc(100vh - 5rem);
35
+ }
36
+
37
+ .sidebar {
38
+ width: 16rem;
39
+ height: 100%;
40
+ background-color: #333;
41
+ color: #fff;
42
+ padding: 20px;
43
+ box-sizing: border-box;
44
+ float: left;
45
+ }
46
+
47
+ .logo {
48
+ font-size: 2rem;
49
+ letter-spacing: 0.1rem;
50
+ color: #14cf96;
51
+ font-weight: bold;
52
+ padding-top: 1.8rem;
53
+ padding-left: 2rem;
54
+ }
55
+
56
+ .menu {
57
+ list-style-type: none;
58
+ padding: 0;
59
+ margin: 0;
60
+ }
61
+
62
+ .menu-item {
63
+ margin-bottom: 10px;
64
+ }
65
+
66
+ .menu-item a {
67
+ color: #fff;
68
+ text-decoration: none;
69
+ display: block;
70
+ padding: 10px;
71
+ border-radius: 5px;
72
+ font-size: 1.05rem;
73
+ }
74
+
75
+ .menu-item a:hover {
76
+ background-color: #555;
77
+ }
78
+
79
+ .submenu {
80
+ display: none;
81
+ list-style-type: none;
82
+ padding-left: 20px;
83
+ }
84
+
85
+ .menu-item.has-submenu > a::after {
86
+ content: '⯆';
87
+ float: right;
88
+ margin-left: 5px;
89
+ }
90
+
91
+ .menu-item.has-submenu.selected > a::after {
92
+ content: '⯅';
93
+ float: right;
94
+ margin-left: 5px;
95
+ }
96
+
97
+ .menu-item.selected > a {
98
+ background-color: #555;
99
+ }
100
+
101
+ .submenu .sub-menu-item {
102
+ margin: 3px auto;
103
+ }
104
+
105
+ .submenu .sub-menu-item a:hover {
106
+ background-color: #777;
107
+ }
108
+
109
+ .submenu .sub-menu-item.selected a {
110
+ background-color: #555 !important;
111
+ }
112
+
113
+ .submenu.active {
114
+ display: block !important;
115
+ }
116
+
117
+ .content-wrapper {
118
+ padding: 1rem;
119
+ float: left;
120
+ width: calc(100% - 16rem);
121
+ background-color: #f4f4f4;
122
+ overflow: hidden;
123
+ }
124
+
125
+ .content {
126
+ display: none;
127
+ }
128
+
129
+ .content .title {
130
+ font-size: 1rem;
131
+ color: #080404e2;
132
+ font-weight: 600;
133
+ }
134
+
135
+ .content .title::after {
136
+ content: ':';
137
+ }
138
+
139
+ .content.active {
140
+ display: flex !important;
141
+ flex-direction: column;
142
+ gap: 0.9rem;
143
+ flex-wrap: wrap;
144
+ transition: all 2s ease-in-out;
145
+ }
146
+
147
+ .sidebar .footer {
148
+ bottom: 5px;
149
+ position: absolute;
150
+ font-size: 12.4px;
151
+ color: #14cf96;
152
+ font-family: system-ui;
153
+ }
154
+
155
+ #overview {
156
+ flex-direction: row;
157
+ justify-content: space-between;
158
+ }
159
+
160
+ #overview .card {
161
+ display: flex;
162
+ flex-direction: column;
163
+ width: 25rem;
164
+ height: 12.5rem;
165
+ border: 1px solid #ddd;
166
+ box-shadow: 0 22px 35px -16px rgba(0, 0, 0, 0.3);
167
+ border-radius: 5px;
168
+ background: white;
169
+ padding: 1rem;
170
+ }
171
+
172
+ #overview .overall-quality {
173
+ height: 20rem;
174
+ flex-basis: 100%;
175
+ line-height: 14px;
176
+ }
177
+
178
+ #overview .overall-quality .section {
179
+ display: flex;
180
+ flex-direction: row;
181
+ }
182
+
183
+ #overview .overall-quality .section .block {
184
+ width: 50%;
185
+ }
186
+
187
+ #overview .overall-quality .section .block article {
188
+ padding: 5px;
189
+ }
190
+
191
+ #overview .overall-quality .section .block article p.desc {
192
+ font-size: 0.9em;
193
+ }
194
+
195
+ #overview .overall-quality .section .block article .items li {
196
+ font-size: 0.87em;
197
+ }
198
+
199
+ #overview .overall-quality .section .block article .items li .detail {
200
+ margin-top: -10px;
201
+ }
202
+
203
+ #overview .overall-quality .section .block .graph {
204
+ margin-top: 1.5em;
205
+ }
206
+
207
+ #overview .string-quality,
208
+ #overview .number-quality,
209
+ #overview .datetime-quality,
210
+ #overview .skipped-items {
211
+ flex-basis: 45%;
212
+ }
213
+
214
+ #overview .string-quality .graph,
215
+ #overview .number-quality .graph,
216
+ #overview .datetime-quality .graph,
217
+ #overview .skipped-items .graph {
218
+ align-self: center;
219
+ }
220
+
221
+ #overview .string-quality .graph {
222
+ margin-left: 4rem;
223
+ }
224
+
225
+ #overview .number-quality.card,
226
+ #overview .datetime-quality.card {
227
+ height: 13rem;
228
+ }
229
+
230
+ #overview .number-quality .graph,
231
+ #overview .datetime-quality .graph {
232
+ margin-top: -0.9rem;
233
+ margin-left: 4.5rem;
234
+ }
235
+
236
+ #insights .cards {
237
+ display: flex;
238
+ flex-direction: column;
239
+ gap: 1.5rem;
240
+ }
241
+
242
+ #insights .cards .holder {
243
+ display: flex;
244
+ flex-direction: row;
245
+ gap: 1.5rem;
246
+ flex-wrap: wrap;
247
+ }
248
+
249
+ #insights .cards .card {
250
+ display: flex;
251
+ flex-direction: column;
252
+ width: 20rem;
253
+ min-height: 10rem;
254
+ border: 1px solid #ddd;
255
+ box-shadow: 0 22px 35px -16px rgba(0, 0, 0, 0.3);
256
+ border-radius: 5px;
257
+ background: white;
258
+ }
259
+
260
+ #insights .cards .card:hover {
261
+ transform: scale(1.015);
262
+ box-shadow: 0 22px 35px -16px #07ff7d33;
263
+ cursor: pointer;
264
+ transition: all 0.1s ease-in-out;
265
+ }
266
+
267
+ #insights .cards .card .title {
268
+ height: 2.5rem;
269
+ font-size: 1rem;
270
+ padding-top: 1rem;
271
+ font-weight: 500;
272
+ width: calc(100% - 1rem);
273
+ background: #0c5ad9d6;
274
+ border-top-left-radius: 5px;
275
+ border-top-right-radius: 5px;
276
+ padding-left: 1rem;
277
+ color: white;
278
+ }
279
+
280
+ #insights .cards .card .title::after {
281
+ content: '';
282
+ }
283
+
284
+ #insights .cards .card .card-content {
285
+ display: flex;
286
+ flex-direction: column;
287
+ gap: 1rem;
288
+ padding: 1rem;
289
+ }
290
+
291
+ #insights .cards .card .status-bar {
292
+ display: flex;
293
+ flex-direction: column;
294
+ gap: 0.8rem;
295
+ }
296
+
297
+ #insights .cards .card .status-bar .bar-container .name {
298
+ font-size: 0.78rem;
299
+ -webkit-font-smoothing: antialiased;
300
+ -moz-osx-font-smoothing: grayscale;
301
+ }
302
+
303
+ #insights .cards .card .status-bar .bar-container .name::after {
304
+ content: ':';
305
+ }
306
+
307
+ #insights .cards .card .status-bar .bar-container .bar-holder {
308
+ width: 100%;
309
+ height: 10px;
310
+ border: 1px solid #00000038;
311
+ border-radius: 2px;
312
+ }
313
+
314
+ #insights .cards .card .status-bar .bar-container .bar-holder .bar {
315
+ background-color: #14cf96;
316
+ height: 100%;
317
+ font-size: 0.63rem;
318
+ text-align: right;
319
+ color: white;
320
+ }
321
+
322
+ #insights .cards .card .stat {
323
+ display: flex;
324
+ flex-direction: column;
325
+ gap: 0.3rem;
326
+ border: 0.5px solid #00000012;
327
+ border-radius: 6px;
328
+ }
329
+
330
+ #insights .cards .card .stat table td {
331
+ font-size: 0.78rem;
332
+ -webkit-font-smoothing: antialiased;
333
+ -moz-osx-font-smoothing: grayscale;
334
+ }
335
+
336
+ #insights .cards .card .stat table td.name {
337
+ width: 70%;
338
+ }
339
+
340
+ #insights .cards .card .stat table td.value::before {
341
+ content: ': ';
342
+ }
343
+
344
+ #locale {
345
+ background: white;
346
+ padding: 12px;
347
+ border-radius: 5px;
348
+ padding-top: 20px;
349
+ }
350
+
351
+ #locale .title {
352
+ content: ':';
353
+ }
354
+
355
+ #locale .coverage-info {
356
+ margin-top: 1rem;
357
+ width: 100%;
358
+ height: 80vh;
359
+ padding-right: 1rem;
360
+ padding-left: 0.1rem;
361
+ }
362
+
363
+ #locale table thead th select.filter {
364
+ margin-left: 1rem;
365
+ max-width: 8rem;
366
+ text-overflow: ellipsis;
367
+ }
368
+
369
+ #locale .image-viewer {
370
+ display: none;
371
+ position: fixed;
372
+ z-index: 9999;
373
+ top: 0;
374
+ left: 0;
375
+ width: 100%;
376
+ height: 100%;
377
+ background-color: rgba(0, 0, 0, 0.8);
378
+ text-align: center;
379
+ }
380
+
381
+ #locale .image-container {
382
+ position: relative;
383
+ top: 50%;
384
+ transform: translateY(-50%);
385
+ display: inline-block;
386
+ }
387
+
388
+ #locale .image-viewer img {
389
+ max-width: 90%;
390
+ max-height: 90%;
391
+ }
392
+
393
+ #locale .close-button {
394
+ position: absolute;
395
+ top: 0.5rem;
396
+ right: 1rem;
397
+ color: #ffffffbf;
398
+ font-size: 3.1rem;
399
+ cursor: pointer;
400
+ }
401
+
402
+ #locale .close-button:hover {
403
+ color: white;
404
+ }
405
+
406
+ #locale table td .view-screenshot-btn {
407
+ color: blue;
408
+ }
409
+
410
+ @media (max-width: 768px) {
411
+ .sidebar {
412
+ width: 16rem;
413
+ padding: 10px;
414
+ }
415
+ }
416
+ </style>
417
+ <!-- 3rd party dependecies -->
418
+ <link
419
+ rel="stylesheet"
420
+ href="https://cdn.datatables.net/2.0.3/css/dataTables.dataTables.min.css"
421
+ />
422
+ <script
423
+ src="https://code.jquery.com/jquery-3.7.1.slim.min.js"
424
+ integrity="sha256-kmHvs0B+OpCW5GVHUNjv9rOmY0IvSIRcf7zGUDTDQM8="
425
+ crossorigin="anonymous"
426
+ defer
427
+ ></script>
428
+ <script src="https://cdn.jsdelivr.net/npm/apexcharts" defer></script>
429
+ <script
430
+ src="https://cdn.datatables.net/2.0.3/js/dataTables.min.js"
431
+ defer
432
+ ></script>
433
+ <script type="text/javascript">
434
+ var DataStore;
435
+ // global functions
436
+ function openImageViewer(imageSrc) {
437
+ var imageView = document.getElementById('imageView');
438
+ imageView.src = imageSrc;
439
+ document.getElementById('imageViewer').style.display = 'block';
440
+ }
441
+
442
+ function closeImageViewer() {
443
+ delete document.getElementById('imageView').src;
444
+ document.getElementById('imageViewer').style.display = 'none';
445
+ }
446
+
447
+ // DataStore
448
+ (() => {
449
+ // set appData
450
+ var appData = {
451
+ defaultLocale: '',
452
+ timeStamp: null,
453
+ success: false,
454
+ metaData: {
455
+ stats: {},
456
+ statsByLocale: {
457
+ en_US: {}
458
+ }
459
+ },
460
+ stringsData: {
461
+ en_US: {},
462
+ fr_FR: {},
463
+ ja_JP: {}
464
+ }
465
+ };
466
+
467
+ function SimpleDataStore() {
468
+ this._getData = () => appData;
469
+
470
+ this.ranSuccessfully = () => this._getData().success;
471
+
472
+ this.getTimestamp = () => this._getData().timeStamp;
473
+
474
+ this.isDefaultLocale = (locale) =>
475
+ locale === this._getData().defaultLocale;
476
+
477
+ this.getLocalesData = () => this._getData().stringsData;
478
+
479
+ this.getLocales = () => Object.keys(this.getLocalesData());
480
+
481
+ this.getStatByLocale = (locale) =>
482
+ this._getData().metaData.statsByLocale[locale] || {};
483
+
484
+ this.getOverallStats = () => this._getData().metaData.stats;
485
+
486
+ this.getDataByLocale = (locale) =>
487
+ this._getData().stringsData[locale] || {};
488
+ }
489
+
490
+ DataStore = new SimpleDataStore();
491
+ })();
492
+
493
+ (() => {
494
+ // for sidebar menu
495
+ const loadContent = (section, highlightMenu = false) => {
496
+ if (highlightMenu) {
497
+ document
498
+ .querySelector('li[data-page="overview"]')
499
+ ?.classList.add('selected');
500
+ }
501
+
502
+ const contents = document.querySelectorAll('.content');
503
+ contents.forEach((content) => {
504
+ content.id !== section
505
+ ? content.classList.remove('active')
506
+ : content.classList.add('active');
507
+
508
+ section === 'overview' &&
509
+ window.persistOverviewCharts &&
510
+ window.persistOverviewCharts();
511
+
512
+ window.currentPage = section;
513
+ });
514
+ };
515
+
516
+ document.addEventListener('DOMContentLoaded', function () {
517
+ const createMenuItems = (() => {
518
+ const ul = document.querySelector('.sidebar .submenu');
519
+ const createListItems = (locale) => {
520
+ const li = document.createElement('li');
521
+ li.classList.add('sub-menu-item');
522
+ li.dataset.locale = locale;
523
+
524
+ const a = document.createElement('a');
525
+ a.href = '#';
526
+ a.textContent = locale;
527
+
528
+ li.appendChild(a);
529
+ return li;
530
+ };
531
+
532
+ for (const locale of DataStore.getLocales()) {
533
+ ul.appendChild(createListItems(locale));
534
+ }
535
+ })();
536
+
537
+ const menuItems = document.querySelectorAll('.menu-item'),
538
+ submenuItems = document.querySelectorAll('.sub-menu-item');
539
+
540
+ menuItems.forEach((item) => {
541
+ item.addEventListener('click', function (event) {
542
+ const selectedMenuItem = document.querySelector(
543
+ '.menu-item.selected'
544
+ ),
545
+ selectedSubmenu = document.querySelector('.submenu.active'),
546
+ page = item.dataset.page;
547
+
548
+ if (selectedMenuItem) {
549
+ selectedMenuItem.classList.remove('selected');
550
+ }
551
+
552
+ if (selectedSubmenu) {
553
+ selectedSubmenu.classList.remove('active');
554
+ }
555
+
556
+ if (item.classList.contains('has-submenu')) {
557
+ event.preventDefault();
558
+ item.classList.add('selected');
559
+ const submenu = item.querySelector('.submenu');
560
+ submenu.classList.add('active');
561
+ } else {
562
+ item.classList.add('selected');
563
+ }
564
+
565
+ if (selectedSubmenu) {
566
+ selectedSubmenu
567
+ .querySelectorAll('.sub-menu-item')
568
+ .forEach((submenuItem) => {
569
+ submenuItem.textContent !== item.textContent &&
570
+ submenuItem.classList.remove('selected');
571
+ });
572
+ }
573
+
574
+ loadContent(page);
575
+ });
576
+
577
+ loadContent('overview', true);
578
+ });
579
+
580
+ submenuItems.forEach((sItem) => {
581
+ sItem.addEventListener('click', function (event) {
582
+ const selectedSubMenuItem = document.querySelector(
583
+ '.sub-menu-item.selected'
584
+ );
585
+ event.preventDefault();
586
+ event.stopPropagation();
587
+
588
+ if (selectedSubMenuItem) {
589
+ selectedSubMenuItem.classList.remove('selected');
590
+ window.previousSelectedLocale =
591
+ selectedSubMenuItem.dataset.locale;
592
+ }
593
+
594
+ sItem.classList.add('selected');
595
+ loadContent('locale');
596
+ });
597
+ });
598
+
599
+ // update footer info
600
+ const footer = document.querySelector('.sidebar .footer');
601
+ footer.textContent = `${new Date().getFullYear()} @ Zeesoft. All rights reserved.`;
602
+ });
603
+ })();
604
+
605
+ // overview content
606
+ (() => {
607
+ document.addEventListener('DOMContentLoaded', function () {
608
+ let overviewChart,
609
+ stringChart,
610
+ dateTimeChart,
611
+ numberChart,
612
+ ignoredChart;
613
+
614
+ window.persistOverviewCharts = () => {
615
+ const reset = (chart) => {
616
+ chart.resetSeries(true, true);
617
+ };
618
+
619
+ reset(overviewChart);
620
+ reset(stringChart);
621
+ reset(dateTimeChart);
622
+ reset(numberChart);
623
+ reset(ignoredChart);
624
+ };
625
+
626
+ renderOverallChart();
627
+ renderStringChart();
628
+ renderIgnoredChart();
629
+ renderNumberChart();
630
+ renderDatetimeChart();
631
+
632
+ function renderOverallChart() {
633
+ const overallStats = DataStore.getOverallStats();
634
+ const reviewed = overallStats.reviewed;
635
+ const locales = DataStore.getLocales().length;
636
+ const type = {
637
+ I18NED: 'Internationalized',
638
+ NOT_I18NED: 'Not Internationalized',
639
+ SKIPPED: 'Skipped'
640
+ },
641
+ valueMap = {
642
+ [type.I18NED]:
643
+ overallStats.localizedStrings +
644
+ overallStats.partialStrings + // TODO: need to confirm
645
+ overallStats.untranslatedStrings +
646
+ overallStats.localizedDateTime +
647
+ overallStats.localizedDate +
648
+ overallStats.localizedTime +
649
+ overallStats.localizedNumber +
650
+ overallStats.localizedCurrency +
651
+ overallStats.localizedPercentage,
652
+ [type.NOT_I18NED]:
653
+ overallStats.notLocalizedStrings +
654
+ overallStats.notLocalizedDateTime +
655
+ overallStats.notLocalizedDate +
656
+ overallStats.notLocalizedTime +
657
+ overallStats.notLocalizedNumber +
658
+ overallStats.notLocalizedCurrency +
659
+ overallStats.notLocalizedPercentage,
660
+ [type.SKIPPED]:
661
+ overallStats.dnt +
662
+ overallStats.ignored +
663
+ overallStats.autoIgnored +
664
+ overallStats.userInput
665
+ },
666
+ percentageCalc = (value) => ((value / reviewed) * 100).toFixed(0);
667
+
668
+ var options = {
669
+ series: [
670
+ {
671
+ name: '',
672
+ data: [
673
+ percentageCalc(valueMap[type.I18NED]),
674
+ percentageCalc(valueMap[type.NOT_I18NED]),
675
+ percentageCalc(valueMap[type.SKIPPED])
676
+ ]
677
+ }
678
+ ],
679
+ chart: {
680
+ type: 'bar',
681
+ height: 200,
682
+ toolbar: {
683
+ show: false
684
+ },
685
+ animations: {
686
+ enabled: true,
687
+ easing: 'easeinout',
688
+ speed: 800,
689
+ animateGradually: {
690
+ enabled: true,
691
+ delay: 150
692
+ },
693
+ dynamicAnimation: {
694
+ enabled: true,
695
+ speed: 350
696
+ }
697
+ }
698
+ },
699
+ plotOptions: {
700
+ bar: {
701
+ horizontal: true,
702
+ borderRadius: 3,
703
+ dataLabels: {
704
+ position: 'right'
705
+ }
706
+ }
707
+ },
708
+ title: {
709
+ text: `Total Reviewed strings in ${locales} locales: ${reviewed}`,
710
+ align: 'center',
711
+ floating: true,
712
+ style: {
713
+ fontSize: '14px',
714
+ fontWeight: 'bold'
715
+ }
716
+ },
717
+ dataLabels: {
718
+ enabled: true,
719
+ style: {
720
+ colors: ['#080404b0']
721
+ },
722
+ formatter: (val) => {
723
+ return `${val}%`;
724
+ }
725
+ },
726
+ xaxis: {
727
+ categories: [type.I18NED, type.NOT_I18NED, type.SKIPPED],
728
+ min: 0,
729
+ max: 100,
730
+ labels: {
731
+ formatter: (v) => `${v}%`
732
+ }
733
+ },
734
+ yaxis: {
735
+ labels: {
736
+ style: {
737
+ fontSize: '13px'
738
+ }
739
+ }
740
+ },
741
+ colors: [
742
+ (v) => {
743
+ switch (v.dataPointIndex) {
744
+ case 0:
745
+ return '#31E994'; //green
746
+ case 1:
747
+ return '#ff8173'; //red
748
+ case 2:
749
+ return '#f5eb5f'; //yellow
750
+ }
751
+ }
752
+ ],
753
+ tooltip: {
754
+ theme: 'dark',
755
+ x: {
756
+ formatter: function (v) {
757
+ switch (v) {
758
+ case type.NOT_I18NED:
759
+ return `Total Number of ${v}, Partially Localized and Encoding issue instances`;
760
+
761
+ default:
762
+ return `Total Number of ${v} instances`;
763
+ }
764
+ }
765
+ },
766
+ y: {
767
+ formatter: function (v) {
768
+ return `${v}%`;
769
+ }
770
+ }
771
+ }
772
+ };
773
+
774
+ (overviewChart = new ApexCharts(
775
+ document.querySelector('.overall-quality .graph'),
776
+ options
777
+ )).render();
778
+ }
779
+
780
+ function renderStringChart() {
781
+ const overallStats = DataStore.getOverallStats();
782
+ const type = {
783
+ LOCALIZED: 'Localized',
784
+ PARTIAL: 'Partially Localized',
785
+ NOT_LOCALIZED: 'Not Localized',
786
+ UNTRANSLATED: 'Untranslated',
787
+ ENCODING: 'Encoding Issue',
788
+ IGNORED: 'Ignored'
789
+ },
790
+ valueMap = {
791
+ [type.LOCALIZED]: overallStats.localizedStrings,
792
+ [type.PARTIAL]: overallStats.partialStrings,
793
+ [type.NOT_LOCALIZED]: overallStats.notLocalizedStrings,
794
+ [type.UNTRANSLATED]: overallStats.untranslatedStrings,
795
+ [type.ENCODING]: overallStats.encoding,
796
+ [type.IGNORED]:
797
+ overallStats.dnt +
798
+ overallStats.ignored +
799
+ overallStats.autoIgnored +
800
+ overallStats.userInput
801
+ },
802
+ total = Object.values(valueMap).reduce(
803
+ (acc, curr) => acc + curr,
804
+ 0
805
+ ),
806
+ options = {
807
+ series: [
808
+ valueMap[type.LOCALIZED],
809
+ valueMap[type.PARTIAL],
810
+ valueMap[type.NOT_LOCALIZED],
811
+ valueMap[type.IGNORED],
812
+ valueMap[type.ENCODING],
813
+ valueMap[type.UNTRANSLATED]
814
+ ],
815
+ chart: {
816
+ width: 430,
817
+ type: 'pie',
818
+ animations: {
819
+ enabled: true,
820
+ easing: 'easeinout',
821
+ speed: 800,
822
+ animateGradually: {
823
+ enabled: true,
824
+ delay: 150
825
+ },
826
+ dynamicAnimation: {
827
+ enabled: true,
828
+ speed: 350
829
+ }
830
+ }
831
+ },
832
+ labels: [
833
+ type.LOCALIZED,
834
+ type.PARTIAL,
835
+ type.NOT_LOCALIZED,
836
+ type.IGNORED,
837
+ type.ENCODING,
838
+ type.UNTRANSLATED
839
+ ],
840
+ tooltip: {
841
+ theme: 'dark',
842
+ y: {
843
+ formatter: function (v, { config }) {
844
+ return `${Number(
845
+ (v /
846
+ config.series.reduce((acc, curr) => acc + curr, 0)) *
847
+ 100
848
+ ).toFixed(0)}%`;
849
+ },
850
+ title: {
851
+ formatter: function (a) {
852
+ return `Total Number of ${a} strings including all locales`;
853
+ }
854
+ }
855
+ }
856
+ },
857
+ colors: [
858
+ ({ seriesIndex, w }) => {
859
+ const currType = w.config.labels[seriesIndex];
860
+
861
+ switch (currType) {
862
+ case type.LOCALIZED:
863
+ return '#31E994';
864
+ case type.NOT_LOCALIZED:
865
+ return '#E44242';
866
+ case type.PARTIAL:
867
+ return '#DADF40';
868
+ case type.UNTRANSLATED:
869
+ return '#4C57EC';
870
+ case type.IGNORED:
871
+ return '#AFA6AB';
872
+ case type.ENCODING:
873
+ return '#F44E9E';
874
+
875
+ default:
876
+ return '';
877
+ }
878
+ }
879
+ ],
880
+ legend: {
881
+ offsetX: -50,
882
+ width: 170,
883
+ formatter: (seriesName, a, b, c) =>
884
+ `${seriesName} (${(
885
+ (valueMap[seriesName] / total) *
886
+ 100
887
+ ).toFixed(0)}%)`
888
+ },
889
+ dataLabels: {
890
+ formatter: (v) => `${Number(v).toFixed(0)}%`,
891
+ dropShadow: { enabled: false },
892
+ style: {
893
+ colors: ['#080404b0']
894
+ }
895
+ }
896
+ };
897
+
898
+ (stringChart = new ApexCharts(
899
+ document.querySelector('.string-quality .graph'),
900
+ options
901
+ )).render();
902
+ }
903
+
904
+ function renderIgnoredChart() {
905
+ const overallStats = DataStore.getOverallStats();
906
+ const type = {
907
+ DNT: 'DNT',
908
+ IGNORED: 'Ignored',
909
+ USER_INPUTS: 'User Inputs'
910
+ },
911
+ valueMap = {
912
+ [type.DNT]: overallStats.dnt,
913
+ [type.IGNORED]: overallStats.ignored + overallStats.autoIgnored,
914
+ [type.USER_INPUTS]: overallStats.userInput
915
+ },
916
+ total = Object.values(valueMap).reduce(
917
+ (acc, curr) => acc + curr,
918
+ 0
919
+ );
920
+ options = {
921
+ series: [
922
+ valueMap[type.DNT],
923
+ valueMap[type.IGNORED],
924
+ valueMap[type.USER_INPUTS]
925
+ ],
926
+ chart: {
927
+ width: 385,
928
+ type: 'pie',
929
+ animations: {
930
+ enabled: true,
931
+ easing: 'easeinout',
932
+ speed: 800,
933
+ animateGradually: {
934
+ enabled: true,
935
+ delay: 150
936
+ },
937
+ dynamicAnimation: {
938
+ enabled: true,
939
+ speed: 350
940
+ }
941
+ }
942
+ },
943
+ labels: [type.DNT, type.IGNORED, type.USER_INPUTS],
944
+ tooltip: {
945
+ theme: 'dark',
946
+ y: {
947
+ formatter: function (v, { config }) {
948
+ return `${Number(
949
+ (v / config.series.reduce((acc, curr) => acc + curr, 0)) *
950
+ 100
951
+ ).toFixed(0)}%`;
952
+ },
953
+ title: {
954
+ formatter: function (a) {
955
+ return `Total Number of localized ${a} instances including all locales`;
956
+ }
957
+ }
958
+ }
959
+ },
960
+ colors: [
961
+ ({ seriesIndex, w }) => {
962
+ const currType = w.config.labels[seriesIndex];
963
+
964
+ switch (currType) {
965
+ case type.DNT:
966
+ return '#31E994';
967
+ case type.IGNORED:
968
+ return '#3AD1F3';
969
+ case type.USER_INPUTS:
970
+ return '#DADF40';
971
+
972
+ default:
973
+ return '';
974
+ }
975
+ }
976
+ ],
977
+ legend: {
978
+ offsetX: -40,
979
+ formatter: (seriesName) =>
980
+ `${seriesName} (${(
981
+ (valueMap[seriesName] / total) *
982
+ 100
983
+ ).toFixed(0)}%)`
984
+ },
985
+ dataLabels: {
986
+ formatter: (v) => `${Number(v).toFixed(0)}%`,
987
+ style: {
988
+ colors: ['#080404b0']
989
+ },
990
+ dropShadow: { enabled: false }
991
+ }
992
+ };
993
+
994
+ (ignoredChart = new ApexCharts(
995
+ document.querySelector('.skipped-items .graph'),
996
+ options
997
+ )).render();
998
+ }
999
+
1000
+ function renderNumberChart() {
1001
+ const overallStats = DataStore.getOverallStats();
1002
+ const types = ['Number', 'Currency', 'Percentage'],
1003
+ data = {
1004
+ number_i18n: overallStats.localizedNumber,
1005
+ currency_i18n: overallStats.localizedCurrency,
1006
+ percentage_i18n: overallStats.localizedPercentage,
1007
+ number_not_i18n: overallStats.notLocalizedNumber,
1008
+ currency_not_i18n: overallStats.notLocalizedCurrency,
1009
+ percentage_not_i18n: overallStats.notLocalizedPercentage
1010
+ },
1011
+ total = Object.values(data).reduce((acc, curr) => acc + curr, 0),
1012
+ percentageCalc = (v, t) => ((v / t) * 100).toFixed(0),
1013
+ i18nPercentage = percentageCalc(
1014
+ data.number_i18n + data.percentage_i18n + data.currency_i18n,
1015
+ total
1016
+ ),
1017
+ nonI18nPercentage = percentageCalc(
1018
+ data.number_not_i18n +
1019
+ data.percentage_not_i18n +
1020
+ data.currency_not_i18n,
1021
+ total
1022
+ ),
1023
+ numberTotal = data.number_i18n + data.number_not_i18n,
1024
+ currencyTotal = data.currency_i18n + data.currency_not_i18n,
1025
+ percentageTotal = data.percentage_i18n + data.percentage_not_i18n,
1026
+ numberI18n = percentageCalc(data.number_i18n, numberTotal),
1027
+ currencyI18n = percentageCalc(data.currency_i18n, currencyTotal),
1028
+ percentageI18n = percentageCalc(
1029
+ data.percentage_i18n,
1030
+ currencyTotal
1031
+ ),
1032
+ numberNotI18n = percentageCalc(data.number_not_i18n, numberTotal),
1033
+ currencyNotI18n = percentageCalc(
1034
+ data.currency_not_i18n,
1035
+ currencyTotal
1036
+ ),
1037
+ percentageNotI18n = percentageCalc(
1038
+ data.percentage_not_i18n,
1039
+ currencyTotal
1040
+ ),
1041
+ options = {
1042
+ series: [
1043
+ {
1044
+ name: 'Internationalized',
1045
+ data: [numberI18n, currencyI18n, percentageI18n]
1046
+ },
1047
+ {
1048
+ name: 'Not Internationalized',
1049
+ data: [numberNotI18n, currencyNotI18n, percentageNotI18n]
1050
+ }
1051
+ ],
1052
+ chart: {
1053
+ type: 'bar',
1054
+ height: 220,
1055
+ width: 500,
1056
+ toolbar: {
1057
+ show: false
1058
+ },
1059
+ animations: {
1060
+ enabled: true,
1061
+ easing: 'easeinout',
1062
+ speed: 800,
1063
+ animateGradually: {
1064
+ enabled: true,
1065
+ delay: 150
1066
+ },
1067
+ dynamicAnimation: {
1068
+ enabled: true,
1069
+ speed: 350
1070
+ }
1071
+ }
1072
+ },
1073
+ dataLabels: {
1074
+ enabled: true,
1075
+ dropShadow: { enabled: false },
1076
+ style: {
1077
+ colors: ['#080404b0']
1078
+ },
1079
+ formatter: (val) => {
1080
+ return `${val}%`;
1081
+ }
1082
+ },
1083
+ stroke: {
1084
+ show: true,
1085
+ width: 1,
1086
+ colors: ['#fff']
1087
+ },
1088
+ tooltip: {
1089
+ theme: 'dark',
1090
+ shared: true,
1091
+ intersect: false
1092
+ },
1093
+ xaxis: {
1094
+ categories: types
1095
+ },
1096
+ yaxis: {
1097
+ min: 0,
1098
+ max: 100,
1099
+ labels: {
1100
+ formatter: (v) => `${v}%`
1101
+ }
1102
+ },
1103
+ colors: ['#31E994', '#ff8173'],
1104
+ legend: {
1105
+ offsetX: -13,
1106
+ position: 'right',
1107
+ formatter: (seriesName) => {
1108
+ if (seriesName === 'Internationalized') {
1109
+ return `${seriesName} (${i18nPercentage}%)`;
1110
+ }
1111
+ return `${seriesName} (${nonI18nPercentage}%)`;
1112
+ }
1113
+ },
1114
+ plotOptions: {
1115
+ bar: {
1116
+ borderRadius: 3,
1117
+ columnWidth: '85%'
1118
+ }
1119
+ }
1120
+ };
1121
+
1122
+ (numberChart = new ApexCharts(
1123
+ document.querySelector('.number-quality .graph'),
1124
+ options
1125
+ )).render();
1126
+ }
1127
+
1128
+ function renderDatetimeChart() {
1129
+ const overallStats = DataStore.getOverallStats();
1130
+ const types = ['Date', 'Time', 'DateTime'],
1131
+ data = {
1132
+ date_i18n: overallStats.localizedDate,
1133
+ time_i18n: overallStats.localizedTime,
1134
+ date_time_i18n: overallStats.localizedDateTime,
1135
+ date_not_i18n: overallStats.notLocalizedDate,
1136
+ time_not_i18n: overallStats.notLocalizedTime,
1137
+ date_time_not_i18n: overallStats.notLocalizedDateTime
1138
+ },
1139
+ total = Object.values(data).reduce((acc, curr) => acc + curr, 0),
1140
+ percentageCalc = (v, t) => ((v / t) * 100).toFixed(0),
1141
+ i18nPercentage = percentageCalc(
1142
+ data.date_i18n + data.time_i18n + data.date_time_i18n,
1143
+ total
1144
+ ),
1145
+ nonI18nPercentage = percentageCalc(
1146
+ data.date_not_i18n +
1147
+ data.time_not_i18n +
1148
+ data.date_time_not_i18n,
1149
+ total
1150
+ ),
1151
+ dateTotal = data.date_i18n + data.date_not_i18n,
1152
+ timeTotal = data.time_i18n + data.time_not_i18n,
1153
+ dateTimeTotal = data.date_time_i18n + data.date_time_not_i18n,
1154
+ dateI18n = percentageCalc(data.date_i18n, dateTotal),
1155
+ timeI18n = percentageCalc(data.time_i18n, timeTotal),
1156
+ dateTimeI18n = percentageCalc(data.date_time_i18n, dateTimeTotal),
1157
+ dateNotI18n = percentageCalc(data.date_not_i18n, dateTotal),
1158
+ timeNotI18n = percentageCalc(data.time_not_i18n, timeTotal),
1159
+ dateTimeNotI18n = percentageCalc(
1160
+ data.date_time_not_i18n,
1161
+ dateTimeTotal
1162
+ ),
1163
+ options = {
1164
+ series: [
1165
+ {
1166
+ name: 'Internationalized',
1167
+ data: [dateI18n, timeI18n, dateTimeI18n]
1168
+ },
1169
+ {
1170
+ name: 'Not Internationalized',
1171
+ data: [dateNotI18n, timeNotI18n, dateTimeNotI18n]
1172
+ }
1173
+ ],
1174
+ chart: {
1175
+ type: 'bar',
1176
+ height: 220,
1177
+ width: 500,
1178
+ toolbar: {
1179
+ show: false
1180
+ },
1181
+ animations: {
1182
+ enabled: true,
1183
+ easing: 'easeinout',
1184
+ speed: 800,
1185
+ animateGradually: {
1186
+ enabled: true,
1187
+ delay: 150
1188
+ },
1189
+ dynamicAnimation: {
1190
+ enabled: true,
1191
+ speed: 350
1192
+ }
1193
+ }
1194
+ },
1195
+ dataLabels: {
1196
+ enabled: true,
1197
+ dropShadow: { enabled: false },
1198
+ style: {
1199
+ colors: ['#080404b0']
1200
+ },
1201
+ formatter: (val) => {
1202
+ return `${val}%`;
1203
+ }
1204
+ },
1205
+ stroke: {
1206
+ show: true,
1207
+ width: 1,
1208
+ colors: ['#fff']
1209
+ },
1210
+ tooltip: {
1211
+ theme: 'dark',
1212
+ shared: true,
1213
+ intersect: false
1214
+ },
1215
+ xaxis: {
1216
+ categories: types
1217
+ },
1218
+ yaxis: {
1219
+ min: 0,
1220
+ max: 100,
1221
+ labels: {
1222
+ formatter: (v) => `${v}%`
1223
+ }
1224
+ },
1225
+ colors: ['#31E994', '#ff8173'],
1226
+ legend: {
1227
+ offsetX: 4,
1228
+ position: 'right',
1229
+ formatter: (seriesName) => {
1230
+ if (seriesName === 'Internationalized') {
1231
+ return `${seriesName} (${i18nPercentage}%)`;
1232
+ }
1233
+ return `${seriesName} (${nonI18nPercentage}%)`;
1234
+ }
1235
+ },
1236
+ plotOptions: {
1237
+ bar: {
1238
+ borderRadius: 3,
1239
+ columnWidth: '85%'
1240
+ }
1241
+ }
1242
+ };
1243
+
1244
+ (dateTimeChart = new ApexCharts(
1245
+ document.querySelector('.datetime-quality .graph'),
1246
+ options
1247
+ )).render();
1248
+ }
1249
+ });
1250
+ })();
1251
+
1252
+ // insights content
1253
+ (() => {
1254
+ document.addEventListener('DOMContentLoaded', function () {
1255
+ renderCards();
1256
+
1257
+ // helper methods to generate cards and its sections
1258
+ function createStatSection(locale, data) {
1259
+ const isDefaultLocale = DataStore.isDefaultLocale(locale);
1260
+ const holder = document.createElement('div');
1261
+ const table = document.createElement('table');
1262
+ const tbody = document.createElement('tbody');
1263
+ const name = document.createElement('div');
1264
+ const tableData = {
1265
+ Reviewed: data.reviewed,
1266
+ 'Internationlized Strings':
1267
+ data.localizedStrings +
1268
+ data.untranslatedStrings +
1269
+ data.partialStrings,
1270
+ 'Not Internationlized Strings': data.notLocalizedStrings,
1271
+ 'Untranslated Strings': data.untranslatedStrings,
1272
+ 'Encoding Issue Strings': data.encoding,
1273
+ 'DNT Strings': data.dnt,
1274
+ 'Ignored Strings': data.ignored,
1275
+ 'Auto Ignored Strings': data.autoIgnored,
1276
+ 'User Input Strings': data.userInput,
1277
+ 'Internationlized Numbers': data.localizedNumber,
1278
+ 'Not Internationlized Numbers': data.notLocalizedNumber,
1279
+ 'Internationlized Currency': data.localizedCurrency,
1280
+ 'Not Internationlized Currency': data.notLocalizedCurrency,
1281
+ 'Not Internationlized Numbers': data.notLocalizedNumber,
1282
+ 'Internationlized Percentage': data.localizedPercentage,
1283
+ 'Not Internationlized Percentage': data.notLocalizedPercentage,
1284
+ 'Internationlized Date': data.localizedDate,
1285
+ 'Not Internationlized Date': data.notLocalizedDate,
1286
+ 'Internationlized Time': data.localizedTime,
1287
+ 'Not Internationlized Time': data.notLocalizedTime,
1288
+ 'Internationlized DateTime': data.localizedDate,
1289
+ 'Not Internationlized DateTime': data.notLocalizedDateTime
1290
+ };
1291
+ const addRow = (name, value) => {
1292
+ const row = document.createElement('tr');
1293
+
1294
+ const col1 = document.createElement('td');
1295
+ col1.classList.add('name');
1296
+ col1.textContent = name;
1297
+
1298
+ const col2 = document.createElement('td');
1299
+ col2.classList.add('value');
1300
+ col2.textContent = value;
1301
+
1302
+ row.appendChild(col1);
1303
+ row.appendChild(col2);
1304
+ return row;
1305
+ };
1306
+
1307
+ for (const rowData of Object.entries(tableData)) {
1308
+ if (!isDefaultLocale || rowData[0] !== 'Untranslated Strings') {
1309
+ tbody.appendChild(addRow(rowData[0], rowData[1]));
1310
+ }
1311
+ }
1312
+
1313
+ holder.classList.add('stat');
1314
+ name.classList.add('name');
1315
+ name.textContent = 'Summary';
1316
+ holder.append(name);
1317
+
1318
+ table.appendChild(tbody);
1319
+ holder.appendChild(table);
1320
+ return holder;
1321
+ }
1322
+
1323
+ function createStatusBarSection(locale, data) {
1324
+ const holder = document.createElement('div');
1325
+ holder.classList.add('status-bar');
1326
+
1327
+ const generateBarEl = (name, total, current) => {
1328
+ current = (current / total) * 100;
1329
+ const holder = document.createElement('div');
1330
+ holder.classList.add('bar-container');
1331
+
1332
+ const nameHolder = document.createElement('div');
1333
+ nameHolder.classList.add('name');
1334
+ nameHolder.textContent = name;
1335
+
1336
+ const barHolder = document.createElement('div');
1337
+ barHolder.classList.add('bar-holder');
1338
+
1339
+ const bar = document.createElement('div');
1340
+ bar.classList.add('bar');
1341
+ bar.style.width = `${current}%`;
1342
+ bar.textContent = `${current}%`;
1343
+
1344
+ barHolder.appendChild(bar);
1345
+ holder.appendChild(nameHolder);
1346
+ holder.appendChild(barHolder);
1347
+
1348
+ return holder;
1349
+ };
1350
+
1351
+ const isDefaultLocale = DataStore.isDefaultLocale(locale),
1352
+ totalI18nCount = isDefaultLocale
1353
+ ? 100
1354
+ : data.localizedStrings +
1355
+ data.untranslatedStrings +
1356
+ data.partialStrings +
1357
+ data.notLocalizedStrings,
1358
+ i18nStrings = isDefaultLocale
1359
+ ? 100
1360
+ : data.localizedStrings +
1361
+ data.untranslatedStrings +
1362
+ data.partialStrings,
1363
+ totalLocCount = isDefaultLocale
1364
+ ? 100
1365
+ : totalI18nCount - data.untranslatedStrings,
1366
+ totalNumberCount = isDefaultLocale
1367
+ ? 100
1368
+ : data.localizedNumber +
1369
+ data.localizedCurrency +
1370
+ data.localizedPercentage +
1371
+ data.notLocalizedPercentage +
1372
+ data.notLocalizedCurrency +
1373
+ data.notLocalizedNumber,
1374
+ i18nNumbers = isDefaultLocale
1375
+ ? 100
1376
+ : totalNumberCount -
1377
+ data.notLocalizedPercentage +
1378
+ data.notLocalizedCurrency +
1379
+ data.notLocalizedNumber,
1380
+ totalI18nDateTimeCount = isDefaultLocale
1381
+ ? 100
1382
+ : data.localizedDate +
1383
+ data.localizedDateTime +
1384
+ data.localizedTime +
1385
+ data.notLocalizedDate +
1386
+ data.notLocalizedDateTime +
1387
+ data.notLocalizedTime,
1388
+ i18nDateTime = isDefaultLocale
1389
+ ? 100
1390
+ : totalI18nDateTimeCount -
1391
+ data.notLocalizedDate +
1392
+ data.notLocalizedDateTime +
1393
+ data.notLocalizedTime;
1394
+
1395
+ holder.appendChild(
1396
+ generateBarEl('String I18n level', totalI18nCount, i18nStrings)
1397
+ );
1398
+
1399
+ holder.appendChild(
1400
+ generateBarEl('String L10n level', totalI18nCount, totalLocCount)
1401
+ );
1402
+
1403
+ holder.appendChild(
1404
+ generateBarEl('Number I18n level', totalNumberCount, i18nNumbers)
1405
+ );
1406
+
1407
+ holder.appendChild(
1408
+ generateBarEl(
1409
+ 'DateTime I18n level',
1410
+ totalI18nDateTimeCount,
1411
+ i18nDateTime
1412
+ )
1413
+ );
1414
+ return holder;
1415
+ }
1416
+
1417
+ function generateCardContents(locale, data) {
1418
+ const cardContent = document.createElement('div');
1419
+ cardContent.classList.add('card-content');
1420
+
1421
+ cardContent.appendChild(createStatusBarSection(locale, data));
1422
+ cardContent.appendChild(createStatSection(locale, data));
1423
+ return cardContent;
1424
+ }
1425
+
1426
+ function createCardEl(locale, data) {
1427
+ const card = document.createElement('div');
1428
+ const title = document.createElement('div');
1429
+ card.classList.add('card');
1430
+ card.dataset.locale = locale;
1431
+ title.classList.add('title');
1432
+ title.textContent = `${locale} details`;
1433
+
1434
+ // fire menu selection event on clicking the card
1435
+ card.addEventListener('click', () => {
1436
+ const previousSelectedSubMenu = document.querySelector(
1437
+ `.sub-menu-item.selected`
1438
+ );
1439
+ if (previousSelectedSubMenu) {
1440
+ window.previousSelectedLocale =
1441
+ previousSelectedSubMenu.dataset.locale;
1442
+ }
1443
+
1444
+ document
1445
+ .querySelector(`.sub-menu-item[data-locale="${locale}"]`)
1446
+ .click();
1447
+ });
1448
+
1449
+ card.appendChild(title);
1450
+ card.appendChild(generateCardContents(locale, data));
1451
+ return card;
1452
+ }
1453
+
1454
+ function renderCards() {
1455
+ // read from global variable appData;
1456
+ const localeInfo = DataStore.getLocalesData();
1457
+
1458
+ if (Object.keys(localeInfo).length) {
1459
+ const cardHolder = document.querySelector(
1460
+ '#insights .cards .holder'
1461
+ );
1462
+ for (const locale in localeInfo) {
1463
+ const cardEl = createCardEl(locale, localeInfo[locale]);
1464
+ cardHolder.appendChild(cardEl);
1465
+ }
1466
+ }
1467
+ }
1468
+ });
1469
+ })();
1470
+
1471
+ // locale grid
1472
+ (() => {
1473
+ document.addEventListener('DOMContentLoaded', function () {
1474
+ let table;
1475
+ document.querySelectorAll('.sub-menu-item').forEach((menu) => {
1476
+ menu.addEventListener('click', (e) => {
1477
+ render(e.currentTarget.dataset.locale);
1478
+ });
1479
+ });
1480
+
1481
+ const updateTitle = (locale) => {
1482
+ document.querySelector(
1483
+ '#locale .title'
1484
+ ).textContent = `${locale} I18n Coverage Details`;
1485
+ };
1486
+
1487
+ const buildGrid = (locale) => {
1488
+ const data = DataStore.getDataByLocale(locale);
1489
+ $.fn.dataTable.ext.errMode = 'none';
1490
+ const dataSet = Object.entries(data).map((entry) => [
1491
+ entry[0],
1492
+ entry[1].type,
1493
+ entry[1].description,
1494
+ entry[1].imagePath
1495
+ ]);
1496
+ table = new DataTable('#locale .coverage-info table', {
1497
+ columns: [
1498
+ { title: 'String' },
1499
+ { title: 'Type' },
1500
+ { title: 'Page' },
1501
+ { title: 'Screenshot' }
1502
+ ],
1503
+ columnDefs: [
1504
+ {
1505
+ targets: 3,
1506
+ orderable: false,
1507
+ searchable: false,
1508
+ data: null,
1509
+ render: function (data) {
1510
+ return `<a href="#" class="view-screenshot-btn" onclick="openImageViewer('${data[3]}')">View Screenshot</a>`;
1511
+ }
1512
+ }
1513
+ ],
1514
+ data: dataSet,
1515
+ initComplete: function () {
1516
+ this.api()
1517
+ .columns()
1518
+ .every(function () {
1519
+ const column = this;
1520
+
1521
+ if (column[0][0] === 3) {
1522
+ return;
1523
+ }
1524
+
1525
+ const select = $(
1526
+ '<select class="filter dt-input"><option value="">Filter By</option></select>'
1527
+ )
1528
+ .appendTo($(column.header()).before())
1529
+ .on('change', function () {
1530
+ const val = $.fn.dataTable.util.escapeRegex(
1531
+ $(this).val()
1532
+ );
1533
+
1534
+ column
1535
+ .search(val ? '^' + val + '$' : '', true, false)
1536
+ .draw();
1537
+ })
1538
+ .on('click', function (e) {
1539
+ e.stopPropagation();
1540
+ e.stopImmediatePropagation();
1541
+ });
1542
+
1543
+ column
1544
+ .data()
1545
+ .unique()
1546
+ .sort()
1547
+ .each(function (d, j) {
1548
+ select.append(
1549
+ '<option value="' + d + '">' + d + '</option>'
1550
+ );
1551
+ });
1552
+ });
1553
+ },
1554
+ sScrollY:
1555
+ document
1556
+ .querySelector('#locale .coverage-info')
1557
+ .getBoundingClientRect().height - 142,
1558
+ pageLength: 25,
1559
+ lengthMenu: [10, 25, 50, 100]
1560
+ });
1561
+ };
1562
+
1563
+ const render = (locale) => {
1564
+ if (table) {
1565
+ table.destroy();
1566
+ }
1567
+ updateTitle(locale);
1568
+ buildGrid(locale);
1569
+ };
1570
+ });
1571
+ })();
1572
+ </script>
1573
+ </head>
1574
+ <body>
1575
+ <header><div class="logo">zQA Report</div></header>
1576
+ <main>
1577
+ <div class="sidebar">
1578
+ <ul class="menu" id="menu">
1579
+ <li class="menu-item" data-page="overview">
1580
+ <a href="#">Overview</a>
1581
+ </li>
1582
+ <li class="menu-item has-submenu" data-page="insights">
1583
+ <a href="#" data-page="insights">Insights</a>
1584
+ <ul class="submenu"></ul>
1585
+ </li>
1586
+ </ul>
1587
+ <div class="footer"></div>
1588
+ </div>
1589
+ <div class="content-wrapper">
1590
+ <div id="overview" class="content">
1591
+ <div class="overall-quality card">
1592
+ <span class="title">Overall I18n Coverage</span>
1593
+ <div class="section">
1594
+ <div class="block">
1595
+ <article>
1596
+ <p class="desc">
1597
+ zI18n-Verify report provides a comprehensive information
1598
+ about the I18n and L10n quailty of your application.
1599
+ </p>
1600
+ <ul class="items">
1601
+ <li>
1602
+ <h4>Reviewed:</h4>
1603
+ <p class="detail">
1604
+ Total strings which are captured and processed by
1605
+ zI18n-Verify.
1606
+ </p>
1607
+ </li>
1608
+ <li>
1609
+ <h4>Internationlized:</h4>
1610
+ <p class="detail">
1611
+ Different types of value like string, number, date-time
1612
+ which are properly Internationalized.
1613
+ </p>
1614
+ </li>
1615
+ <li>
1616
+ <h4>Not Internationalized:</h4>
1617
+ <p class="detail">
1618
+ Values which are not Internationalized. Also includes
1619
+ Partially Localized strings and Encoding Issues.
1620
+ </p>
1621
+ </li>
1622
+ <li>
1623
+ <h4>Skipped:</h4>
1624
+ <p class="detail">
1625
+ Values which are skipped from processing because they
1626
+ are listed in DNT / Ignored lists or contains Auto
1627
+ Ignored pattern / User input pattern.
1628
+ </p>
1629
+ </li>
1630
+ </ul>
1631
+ </article>
1632
+ </div>
1633
+ <div class="block">
1634
+ <div class="graph"></div>
1635
+ </div>
1636
+ </div>
1637
+ </div>
1638
+ <div class="string-quality card">
1639
+ <span class="title">String Coverage</span>
1640
+ <div class="graph"></div>
1641
+ </div>
1642
+ <div class="skipped-items card">
1643
+ <span class="title">Skipped Items</span>
1644
+ <div class="graph"></div>
1645
+ </div>
1646
+ <div class="number-quality card">
1647
+ <span class="title">Number Coverage</span>
1648
+ <div class="graph"></div>
1649
+ </div>
1650
+ <div class="datetime-quality card">
1651
+ <span class="title">DateTime Coverage</span>
1652
+ <div class="graph"></div>
1653
+ </div>
1654
+ </div>
1655
+ <div id="insights" class="content">
1656
+ <div class="cards">
1657
+ <span class="title">Locale Quality</span>
1658
+ <div class="holder"></div>
1659
+ </div>
1660
+ </div>
1661
+ <div id="locale" class="content">
1662
+ <span class="title">Locale Quality</span>
1663
+ <div class="coverage-info">
1664
+ <table class="row-border hover order-column stripe"></table>
1665
+ </div>
1666
+ <div id="imageViewer" class="image-viewer">
1667
+ <span class="close-button" onclick="closeImageViewer()"
1668
+ >&times;</span
1669
+ >
1670
+ <div class="image-container">
1671
+ <img id="imageView" src="" alt="Image" />
1672
+ </div>
1673
+ </div>
1674
+ </div>
1675
+ </div>
1676
+ </main>
1677
+ </body>
1678
+ </html>