@dataclouder/ngx-core 0.1.26 → 0.1.30
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/fesm2022/dataclouder-ngx-core.mjs +148 -54
- package/fesm2022/dataclouder-ngx-core.mjs.map +1 -1
- package/lib/components/base-form/entity-base-form.d.ts +6 -1
- package/lib/components/list-filter-bar/dc-list-filter-bar.component.d.ts +7 -3
- package/lib/models/extension.model.d.ts +1 -2
- package/lib/models/filter.models.d.ts +6 -1
- package/lib/models/languages.model.d.ts +1 -0
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, Input, Component, output, ChangeDetectionStrategy,
|
|
2
|
+
import { input, Input, Component, inject, output, ChangeDetectionStrategy, HostListener, ChangeDetectorRef, Injectable, Pipe, signal, effect, ViewChild, Directive, InjectionToken, Optional, Inject } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/forms';
|
|
4
|
-
import { FormsModule } from '@angular/forms';
|
|
4
|
+
import { FormBuilder, FormsModule, ReactiveFormsModule, FormGroup, FormArray } from '@angular/forms';
|
|
5
5
|
import * as i1$1 from 'primeng/button';
|
|
6
6
|
import { ButtonModule } from 'primeng/button';
|
|
7
7
|
import * as i4 from 'primeng/dialog';
|
|
@@ -93,6 +93,7 @@ const sortTypes = [
|
|
|
93
93
|
const DEFAULT_FILTERS = { filters: {}, page: 0, rowsPerPage: 10, sort: { _id: -1 } };
|
|
94
94
|
class DCFilterBarComponent {
|
|
95
95
|
constructor() {
|
|
96
|
+
this.fb = inject(FormBuilder);
|
|
96
97
|
// Signal Inputs
|
|
97
98
|
this.items = input([]);
|
|
98
99
|
this.options = input({ showCreateButton: true });
|
|
@@ -102,8 +103,6 @@ class DCFilterBarComponent {
|
|
|
102
103
|
this.onFilterAction = output();
|
|
103
104
|
this.onChangeSort = output();
|
|
104
105
|
this.onNew = output();
|
|
105
|
-
// Internal State
|
|
106
|
-
this.customFilterModels = [];
|
|
107
106
|
this.availibleFilters = availibleFilters;
|
|
108
107
|
this.sortOptions = sortOptions;
|
|
109
108
|
this.isSearchVisible = false;
|
|
@@ -115,19 +114,20 @@ class DCFilterBarComponent {
|
|
|
115
114
|
this.dateRange = [];
|
|
116
115
|
}
|
|
117
116
|
ngOnInit() {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
// this.availibleFilters.push({
|
|
124
|
-
// name: filter.name,
|
|
125
|
-
// type: filter.type,
|
|
126
|
-
// options: filter.options,
|
|
127
|
-
// });
|
|
128
|
-
}
|
|
117
|
+
this.buildCustomFiltersForm();
|
|
118
|
+
}
|
|
119
|
+
ngOnChanges(changes) {
|
|
120
|
+
if (changes['customFilters']) {
|
|
121
|
+
this.buildCustomFiltersForm();
|
|
129
122
|
}
|
|
130
123
|
}
|
|
124
|
+
buildCustomFiltersForm() {
|
|
125
|
+
const formControls = {};
|
|
126
|
+
for (const filter of this.customFilters) {
|
|
127
|
+
formControls[filter.field] = [filter.defaultValue || null];
|
|
128
|
+
}
|
|
129
|
+
this.customFiltersForm = this.fb.group(formControls);
|
|
130
|
+
}
|
|
131
131
|
changeFilter(event) {
|
|
132
132
|
console.log('Filter changed');
|
|
133
133
|
}
|
|
@@ -154,6 +154,14 @@ class DCFilterBarComponent {
|
|
|
154
154
|
this.doItemAction({ action: 'filterChange', item: this.filter });
|
|
155
155
|
}
|
|
156
156
|
applyFilters() {
|
|
157
|
+
const customFilterValues = this.customFiltersForm.value;
|
|
158
|
+
const activeFilters = Object.entries(customFilterValues).reduce((acc, [key, value]) => {
|
|
159
|
+
if (value !== null && value !== undefined && value !== '') {
|
|
160
|
+
acc[key] = value;
|
|
161
|
+
}
|
|
162
|
+
return acc;
|
|
163
|
+
}, {});
|
|
164
|
+
this.filter.filters = { ...this.filter.filters, ...activeFilters };
|
|
157
165
|
this.doItemAction({ action: 'filterChange', item: this.filter });
|
|
158
166
|
this.isFilterVisible = false;
|
|
159
167
|
}
|
|
@@ -161,11 +169,11 @@ class DCFilterBarComponent {
|
|
|
161
169
|
this.onFilterAction.emit(filterEvent);
|
|
162
170
|
}
|
|
163
171
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCFilterBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
164
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: DCFilterBarComponent, isStandalone: true, selector: "dc-filter-bar", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, customFilters: { classPropertyName: "customFilters", publicName: "customFilters", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onFilterAction: "onFilterAction", onChangeSort: "onChangeSort", onNew: "onNew" }, ngImport: i0, template: "<div class=\"background-bar\">\n <div class=\"button-flex\">\n <div>\n <p-button icon=\"pi pi-search\" label=\"buscar\" severity=\"secondary\" (click)=\"isSearchVisible = true\" />\n </div>\n\n @if (options()?.showCreateButton) {\n <span class=\"admin\">\n <i style=\"position: absolute; right: -5px; top: -5px; z-index: 2; color: grey\" class=\"pi pi-key\"></i>\n <p-button icon=\"pi pi-plus\" label=\"Crear Nueva\" severity=\"secondary\" (click)=\"createNew()\" />\n </span>\n }\n </div>\n\n @if(options()?.showViewButton){\n <p-button icon=\"pi pi-objects-column\" variant=\"text\" (click)=\"doItemAction({ action: 'changeView', item: null })\" severity=\"secondary\"></p-button>\n } @if(options()?.showActions){ @for(item of items(); track $index) {\n <p-button [icon]=\"item.icon\" variant=\"text\" (click)=\"doItemAction({ action: item.title, item: item })\" severity=\"secondary\"></p-button>\n }\n\n <div class=\"button-flex\">\n <p-button icon=\"pi pi-filter\" label=\"Filtrar\" severity=\"secondary\" (click)=\"isFilterVisible = true\" />\n </div>\n }\n</div>\n\n@if (placeholder) {\n<span class=\"search-flex\" (click)=\"search(null)\"> <i class=\"pi pi-times\"></i>{{ placeholder }} </span>\n}\n\n<p-dialog [(visible)]=\"isSearchVisible\" [dismissableMask]=\"true\" [modal]=\"true\" [showHeader]=\"false\" (onHide)=\"isSearchVisible = false\">\n <p>Haz una b\u00FAsqueda (Enter)</p>\n <div>\n <span>\n <input (keydown.enter)=\"search(placeholder)\" type=\"text\" pInputText [(ngModel)]=\"placeholder\" />\n </span>\n </div>\n</p-dialog>\n\n<p-dialog [(visible)]=\"isFilterVisible\" [modal]=\"true\" [style]=\"{ width: '70vw', height: '70vh' }\" [header]=\"'Filtros'\">\n <div class=\"flex flex-column gap-4\">\n <!-- Sort Options -->\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">Ordenar por</label>\n <p-select [options]=\"sortOptions\" [(ngModel)]=\"selectedSort\" optionLabel=\"label\" [style]=\"{ width: '100%' }\" placeholder=\"Seleccionar orden\"> </p-select>\n </div>\n\n <p-multiselect\n [options]=\"availibleFilters\"\n [(ngModel)]=\"selectedFilters\"\n optionLabel=\"name\"\n placeholder=\"Filtros R\u00E1pidos\"\n [maxSelectedLabels]=\"3\"\n styleClass=\"w-full md:w-80\" />\n\n <!-- Date Filter -->\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">Rango de fechas</label>\n <p-calendar\n [(ngModel)]=\"dateRange\"\n selectionMode=\"range\"\n [showButtonBar]=\"true\"\n [style]=\"{ width: '100%' }\"\n placeholder=\"Seleccionar fechas\"\n dateFormat=\"dd/mm/yy\">\n </p-calendar>\n </div>\n\n @if (customFilters?.length > 0) {\n <h4>Filtros Personalizados (No terminado...) </h4>\n <h6>Encontrar la forma de que cada custom filter se renderize como un nuevo form.</h6>\n @for (filter of customFilters; track filter.name) {\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">{{ filter.name }}</label>\n </div>\n } }\n\n <!-- Recent/All Toggle -->\n </div>\n\n <ng-template pTemplate=\"footer\">\n <div class=\"flex justify-content-end gap-2\">\n <p-button label=\"Limpiar\" icon=\"pi pi-trash\" (click)=\"clearFilters()\" styleClass=\"p-button-text\"> </p-button>\n <p-button label=\"Aplicar\" icon=\"pi pi-check\" (click)=\"applyFilters()\" severity=\"primary\"> </p-button>\n </div>\n </ng-template>\n</p-dialog>\n", styles: [":host{display:block}.admin{margin-left:10px;position:relative}.background-bar{background-color:var(--p-primary-color);display:flex;border-radius:10px;justify-content:space-between;padding:10px}.button-flex{display:flex;margin-right:10px}.white{color:#fff}.search-flex{margin-left:10px}.search-dialog{width:750px;-webkit-backdrop-filter:blur(70px);backdrop-filter:blur(70px)}.border-none{border:none}.bg-black-alpha-50{background-color:var(--p-primary-color)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i4.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i5.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i6.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "style", "styleClass", "panelStyle", "panelStyleClass", "inputId", "disabled", "fluid", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "variant", "appendTo", "dataKey", "name", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "size", "showClear", "autofocus", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "defaultLabel", "placeholder", "options", "filterValue", "itemSize", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: CalendarModule }, { kind: "component", type: i7.Calendar, selector: "p-calendar", inputs: ["iconDisplay", "style", "styleClass", "inputStyle", "inputId", "name", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "disabled", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "fluid", "icon", "appendTo", "readonlyInput", "shortYearCutoff", "monthNavigator", "yearNavigator", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "required", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "variant", "minDate", "maxDate", "disabledDates", "disabledDays", "yearRange", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "locale", "view", "defaultDate"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
172
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: DCFilterBarComponent, isStandalone: true, selector: "dc-filter-bar", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, customFilters: { classPropertyName: "customFilters", publicName: "customFilters", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onFilterAction: "onFilterAction", onChangeSort: "onChangeSort", onNew: "onNew" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"background-bar\">\n <div class=\"button-flex\">\n <div>\n <p-button icon=\"pi pi-search\" label=\"buscar\" severity=\"secondary\" (click)=\"isSearchVisible = true\" />\n </div>\n\n @if (options()?.showCreateButton) {\n <span class=\"admin\">\n <i style=\"position: absolute; right: -5px; top: -5px; z-index: 2; color: grey\" class=\"pi pi-key\"></i>\n <p-button icon=\"pi pi-plus\" label=\"Crear Nueva\" severity=\"secondary\" (click)=\"createNew()\" />\n </span>\n }\n </div>\n\n @if(options()?.showViewButton){\n <p-button icon=\"pi pi-objects-column\" variant=\"text\" (click)=\"doItemAction({ action: 'changeView', item: null })\" severity=\"secondary\"></p-button>\n } @if(options()?.showActions){ @for(item of items(); track $index) {\n <p-button [icon]=\"item.icon\" variant=\"text\" (click)=\"doItemAction({ action: item.title, item: item })\" severity=\"secondary\"></p-button>\n }\n\n <div class=\"button-flex\">\n <p-button icon=\"pi pi-filter\" label=\"Filtrar\" severity=\"secondary\" (click)=\"isFilterVisible = true\" />\n </div>\n }\n</div>\n\n@if (placeholder) {\n<span class=\"search-flex\" (click)=\"search(null)\"> <i class=\"pi pi-times\"></i>{{ placeholder }} </span>\n}\n\n<p-dialog [(visible)]=\"isSearchVisible\" [dismissableMask]=\"true\" [modal]=\"true\" [showHeader]=\"false\" (onHide)=\"isSearchVisible = false\">\n <p>Haz una b\u00FAsqueda (Enter)</p>\n <div>\n <span>\n <input (keydown.enter)=\"search(placeholder)\" type=\"text\" pInputText [(ngModel)]=\"placeholder\" />\n </span>\n </div>\n</p-dialog>\n\n<p-dialog [(visible)]=\"isFilterVisible\" [modal]=\"true\" [style]=\"{ width: '70vw', height: '70vh' }\" [header]=\"'Filtros'\">\n <div class=\"flex flex-column gap-4\">\n <!-- Sort Options -->\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">Ordenar por</label>\n <p-select [options]=\"sortOptions\" [(ngModel)]=\"selectedSort\" optionLabel=\"label\" [style]=\"{ width: '100%' }\" placeholder=\"Seleccionar orden\"> </p-select>\n </div>\n\n <p-multiselect\n [options]=\"availibleFilters\"\n [(ngModel)]=\"selectedFilters\"\n optionLabel=\"name\"\n placeholder=\"Filtros R\u00E1pidos\"\n [maxSelectedLabels]=\"3\"\n styleClass=\"w-full md:w-80\" />\n\n <!-- Date Filter -->\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">Rango de fechas</label>\n <p-calendar\n [(ngModel)]=\"dateRange\"\n selectionMode=\"range\"\n [showButtonBar]=\"true\"\n [style]=\"{ width: '100%' }\"\n placeholder=\"Seleccionar fechas\"\n dateFormat=\"dd/mm/yy\">\n </p-calendar>\n </div>\n\n @if (customFilters?.length > 0) {\n <form [formGroup]=\"customFiltersForm\">\n <h4>Filtros Personalizados</h4>\n @for (customFilter of customFilters; track customFilter.field) {\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">{{ customFilter.name }}</label>\n @switch (customFilter.type) { @case ('select') {\n <p-select\n [options]=\"customFilter.options\"\n [formControlName]=\"customFilter.field\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [style]=\"{ width: '100%' }\"\n placeholder=\"Seleccionar {{ customFilter.name }}\" />\n } @case ('string') {\n <input type=\"text\" pInputText [formControlName]=\"customFilter.field\" class=\"w-full\" />\n } @case ('date') {\n <p-calendar [formControlName]=\"customFilter.field\" [style]=\"{ width: '100%' }\" dateFormat=\"dd/mm/yy\"></p-calendar>\n } }\n </div>\n }\n </form>\n }\n\n <!-- Recent/All Toggle -->\n </div>\n\n <ng-template pTemplate=\"footer\">\n <div class=\"flex justify-content-end gap-2\">\n <p-button label=\"Limpiar\" icon=\"pi pi-trash\" (click)=\"clearFilters()\" styleClass=\"p-button-text\"> </p-button>\n <p-button label=\"Aplicar\" icon=\"pi pi-check\" (click)=\"applyFilters()\" severity=\"primary\"> </p-button>\n </div>\n </ng-template>\n</p-dialog>\n", styles: [":host{display:block}.admin{margin-left:10px;position:relative}.background-bar{background-color:var(--p-primary-color);display:flex;border-radius:10px;justify-content:space-between;padding:10px}.button-flex{display:flex;margin-right:10px}.white{color:#fff}.search-flex{margin-left:10px}.search-dialog{width:750px;-webkit-backdrop-filter:blur(70px);backdrop-filter:blur(70px)}.border-none{border:none}.bg-black-alpha-50{background-color:var(--p-primary-color)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i4.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i5.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i6.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "style", "styleClass", "panelStyle", "panelStyleClass", "inputId", "disabled", "fluid", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "variant", "appendTo", "dataKey", "name", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "size", "showClear", "autofocus", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "defaultLabel", "placeholder", "options", "filterValue", "itemSize", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: CalendarModule }, { kind: "component", type: i7.Calendar, selector: "p-calendar", inputs: ["iconDisplay", "style", "styleClass", "inputStyle", "inputId", "name", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "disabled", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "fluid", "icon", "appendTo", "readonlyInput", "shortYearCutoff", "monthNavigator", "yearNavigator", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "required", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "variant", "minDate", "maxDate", "disabledDates", "disabledDays", "yearRange", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "locale", "view", "defaultDate"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
165
173
|
}
|
|
166
174
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCFilterBarComponent, decorators: [{
|
|
167
175
|
type: Component,
|
|
168
|
-
args: [{ selector: 'dc-filter-bar', standalone: true, imports: [FormsModule, ButtonModule, DialogModule, SelectModule, MultiSelectModule, CalendarModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"background-bar\">\n <div class=\"button-flex\">\n <div>\n <p-button icon=\"pi pi-search\" label=\"buscar\" severity=\"secondary\" (click)=\"isSearchVisible = true\" />\n </div>\n\n @if (options()?.showCreateButton) {\n <span class=\"admin\">\n <i style=\"position: absolute; right: -5px; top: -5px; z-index: 2; color: grey\" class=\"pi pi-key\"></i>\n <p-button icon=\"pi pi-plus\" label=\"Crear Nueva\" severity=\"secondary\" (click)=\"createNew()\" />\n </span>\n }\n </div>\n\n @if(options()?.showViewButton){\n <p-button icon=\"pi pi-objects-column\" variant=\"text\" (click)=\"doItemAction({ action: 'changeView', item: null })\" severity=\"secondary\"></p-button>\n } @if(options()?.showActions){ @for(item of items(); track $index) {\n <p-button [icon]=\"item.icon\" variant=\"text\" (click)=\"doItemAction({ action: item.title, item: item })\" severity=\"secondary\"></p-button>\n }\n\n <div class=\"button-flex\">\n <p-button icon=\"pi pi-filter\" label=\"Filtrar\" severity=\"secondary\" (click)=\"isFilterVisible = true\" />\n </div>\n }\n</div>\n\n@if (placeholder) {\n<span class=\"search-flex\" (click)=\"search(null)\"> <i class=\"pi pi-times\"></i>{{ placeholder }} </span>\n}\n\n<p-dialog [(visible)]=\"isSearchVisible\" [dismissableMask]=\"true\" [modal]=\"true\" [showHeader]=\"false\" (onHide)=\"isSearchVisible = false\">\n <p>Haz una b\u00FAsqueda (Enter)</p>\n <div>\n <span>\n <input (keydown.enter)=\"search(placeholder)\" type=\"text\" pInputText [(ngModel)]=\"placeholder\" />\n </span>\n </div>\n</p-dialog>\n\n<p-dialog [(visible)]=\"isFilterVisible\" [modal]=\"true\" [style]=\"{ width: '70vw', height: '70vh' }\" [header]=\"'Filtros'\">\n <div class=\"flex flex-column gap-4\">\n <!-- Sort Options -->\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">Ordenar por</label>\n <p-select [options]=\"sortOptions\" [(ngModel)]=\"selectedSort\" optionLabel=\"label\" [style]=\"{ width: '100%' }\" placeholder=\"Seleccionar orden\"> </p-select>\n </div>\n\n <p-multiselect\n [options]=\"availibleFilters\"\n [(ngModel)]=\"selectedFilters\"\n optionLabel=\"name\"\n placeholder=\"Filtros R\u00E1pidos\"\n [maxSelectedLabels]=\"3\"\n styleClass=\"w-full md:w-80\" />\n\n <!-- Date Filter -->\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">Rango de fechas</label>\n <p-calendar\n [(ngModel)]=\"dateRange\"\n selectionMode=\"range\"\n [showButtonBar]=\"true\"\n [style]=\"{ width: '100%' }\"\n placeholder=\"Seleccionar fechas\"\n dateFormat=\"dd/mm/yy\">\n </p-calendar>\n </div>\n\n @if (customFilters?.length > 0) {\n <h4>Filtros Personalizados
|
|
176
|
+
args: [{ selector: 'dc-filter-bar', standalone: true, imports: [FormsModule, ReactiveFormsModule, ButtonModule, DialogModule, SelectModule, MultiSelectModule, CalendarModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"background-bar\">\n <div class=\"button-flex\">\n <div>\n <p-button icon=\"pi pi-search\" label=\"buscar\" severity=\"secondary\" (click)=\"isSearchVisible = true\" />\n </div>\n\n @if (options()?.showCreateButton) {\n <span class=\"admin\">\n <i style=\"position: absolute; right: -5px; top: -5px; z-index: 2; color: grey\" class=\"pi pi-key\"></i>\n <p-button icon=\"pi pi-plus\" label=\"Crear Nueva\" severity=\"secondary\" (click)=\"createNew()\" />\n </span>\n }\n </div>\n\n @if(options()?.showViewButton){\n <p-button icon=\"pi pi-objects-column\" variant=\"text\" (click)=\"doItemAction({ action: 'changeView', item: null })\" severity=\"secondary\"></p-button>\n } @if(options()?.showActions){ @for(item of items(); track $index) {\n <p-button [icon]=\"item.icon\" variant=\"text\" (click)=\"doItemAction({ action: item.title, item: item })\" severity=\"secondary\"></p-button>\n }\n\n <div class=\"button-flex\">\n <p-button icon=\"pi pi-filter\" label=\"Filtrar\" severity=\"secondary\" (click)=\"isFilterVisible = true\" />\n </div>\n }\n</div>\n\n@if (placeholder) {\n<span class=\"search-flex\" (click)=\"search(null)\"> <i class=\"pi pi-times\"></i>{{ placeholder }} </span>\n}\n\n<p-dialog [(visible)]=\"isSearchVisible\" [dismissableMask]=\"true\" [modal]=\"true\" [showHeader]=\"false\" (onHide)=\"isSearchVisible = false\">\n <p>Haz una b\u00FAsqueda (Enter)</p>\n <div>\n <span>\n <input (keydown.enter)=\"search(placeholder)\" type=\"text\" pInputText [(ngModel)]=\"placeholder\" />\n </span>\n </div>\n</p-dialog>\n\n<p-dialog [(visible)]=\"isFilterVisible\" [modal]=\"true\" [style]=\"{ width: '70vw', height: '70vh' }\" [header]=\"'Filtros'\">\n <div class=\"flex flex-column gap-4\">\n <!-- Sort Options -->\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">Ordenar por</label>\n <p-select [options]=\"sortOptions\" [(ngModel)]=\"selectedSort\" optionLabel=\"label\" [style]=\"{ width: '100%' }\" placeholder=\"Seleccionar orden\"> </p-select>\n </div>\n\n <p-multiselect\n [options]=\"availibleFilters\"\n [(ngModel)]=\"selectedFilters\"\n optionLabel=\"name\"\n placeholder=\"Filtros R\u00E1pidos\"\n [maxSelectedLabels]=\"3\"\n styleClass=\"w-full md:w-80\" />\n\n <!-- Date Filter -->\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">Rango de fechas</label>\n <p-calendar\n [(ngModel)]=\"dateRange\"\n selectionMode=\"range\"\n [showButtonBar]=\"true\"\n [style]=\"{ width: '100%' }\"\n placeholder=\"Seleccionar fechas\"\n dateFormat=\"dd/mm/yy\">\n </p-calendar>\n </div>\n\n @if (customFilters?.length > 0) {\n <form [formGroup]=\"customFiltersForm\">\n <h4>Filtros Personalizados</h4>\n @for (customFilter of customFilters; track customFilter.field) {\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">{{ customFilter.name }}</label>\n @switch (customFilter.type) { @case ('select') {\n <p-select\n [options]=\"customFilter.options\"\n [formControlName]=\"customFilter.field\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [style]=\"{ width: '100%' }\"\n placeholder=\"Seleccionar {{ customFilter.name }}\" />\n } @case ('string') {\n <input type=\"text\" pInputText [formControlName]=\"customFilter.field\" class=\"w-full\" />\n } @case ('date') {\n <p-calendar [formControlName]=\"customFilter.field\" [style]=\"{ width: '100%' }\" dateFormat=\"dd/mm/yy\"></p-calendar>\n } }\n </div>\n }\n </form>\n }\n\n <!-- Recent/All Toggle -->\n </div>\n\n <ng-template pTemplate=\"footer\">\n <div class=\"flex justify-content-end gap-2\">\n <p-button label=\"Limpiar\" icon=\"pi pi-trash\" (click)=\"clearFilters()\" styleClass=\"p-button-text\"> </p-button>\n <p-button label=\"Aplicar\" icon=\"pi pi-check\" (click)=\"applyFilters()\" severity=\"primary\"> </p-button>\n </div>\n </ng-template>\n</p-dialog>\n", styles: [":host{display:block}.admin{margin-left:10px;position:relative}.background-bar{background-color:var(--p-primary-color);display:flex;border-radius:10px;justify-content:space-between;padding:10px}.button-flex{display:flex;margin-right:10px}.white{color:#fff}.search-flex{margin-left:10px}.search-dialog{width:750px;-webkit-backdrop-filter:blur(70px);backdrop-filter:blur(70px)}.border-none{border:none}.bg-black-alpha-50{background-color:var(--p-primary-color)}\n"] }]
|
|
169
177
|
}], propDecorators: { customFilters: [{
|
|
170
178
|
type: Input
|
|
171
179
|
}] } });
|
|
@@ -994,10 +1002,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
|
|
|
994
1002
|
type: Directive
|
|
995
1003
|
}], ctorParameters: () => [] });
|
|
996
1004
|
|
|
1005
|
+
const TOAST_ALERTS_TOKEN = new InjectionToken('Toast alerts Service');
|
|
1006
|
+
class ToastAlertsAbstractService {
|
|
1007
|
+
}
|
|
1008
|
+
function provideToastAlert(serviceImplementation) {
|
|
1009
|
+
return [
|
|
1010
|
+
{
|
|
1011
|
+
provide: TOAST_ALERTS_TOKEN,
|
|
1012
|
+
useExisting: serviceImplementation,
|
|
1013
|
+
},
|
|
1014
|
+
];
|
|
1015
|
+
}
|
|
1016
|
+
// @deprecated, moved to ngx-vertex
|
|
1017
|
+
var AudioSpeed;
|
|
1018
|
+
(function (AudioSpeed) {
|
|
1019
|
+
AudioSpeed["VerySlow"] = "verySlow";
|
|
1020
|
+
AudioSpeed["Slow"] = "slow";
|
|
1021
|
+
AudioSpeed["Regular"] = "regular";
|
|
1022
|
+
AudioSpeed["Fast"] = "fast";
|
|
1023
|
+
AudioSpeed["VeryFast"] = "veryFast";
|
|
1024
|
+
})(AudioSpeed || (AudioSpeed = {}));
|
|
1025
|
+
const AudioSpeedReverse = {
|
|
1026
|
+
[AudioSpeed.VerySlow]: 1,
|
|
1027
|
+
[AudioSpeed.Slow]: 2,
|
|
1028
|
+
[AudioSpeed.Regular]: 3,
|
|
1029
|
+
[AudioSpeed.Fast]: 4,
|
|
1030
|
+
[AudioSpeed.VeryFast]: 5,
|
|
1031
|
+
};
|
|
1032
|
+
class IAIModel {
|
|
1033
|
+
}
|
|
1034
|
+
// Since it not clear if this bellows to chat AI Or user i put here.
|
|
1035
|
+
class ChatUserSettings {
|
|
1036
|
+
}
|
|
1037
|
+
|
|
997
1038
|
class EntityBaseFormComponent {
|
|
998
1039
|
constructor() {
|
|
999
1040
|
this.route = inject(ActivatedRoute);
|
|
1000
1041
|
this.router = inject(Router);
|
|
1042
|
+
this.toastService = inject(TOAST_ALERTS_TOKEN, { optional: true });
|
|
1001
1043
|
this.entity = signal(undefined);
|
|
1002
1044
|
this.entityId = toSignal(this.route.paramMap.pipe(map((params) => params.get('id'))));
|
|
1003
1045
|
this.loadEntityEffect = effect(async () => {
|
|
@@ -1011,8 +1053,8 @@ class EntityBaseFormComponent {
|
|
|
1011
1053
|
}
|
|
1012
1054
|
}
|
|
1013
1055
|
catch (err) {
|
|
1056
|
+
this.toastService?.error({ title: 'Error', subtitle: 'Error loading entity' });
|
|
1014
1057
|
console.error('Error loading entity', err);
|
|
1015
|
-
// TODO: Consider adding a generic error toast message
|
|
1016
1058
|
}
|
|
1017
1059
|
}
|
|
1018
1060
|
else {
|
|
@@ -1025,16 +1067,15 @@ class EntityBaseFormComponent {
|
|
|
1025
1067
|
}
|
|
1026
1068
|
}
|
|
1027
1069
|
catch (err) {
|
|
1070
|
+
this.toastService?.error({ title: 'Error', subtitle: 'Error creating new entity' });
|
|
1028
1071
|
console.error('Error creating new entity', err);
|
|
1029
|
-
// TODO: Consider adding a generic error toast message
|
|
1030
1072
|
}
|
|
1031
1073
|
}
|
|
1032
1074
|
}, { allowSignalWrites: true });
|
|
1033
1075
|
}
|
|
1034
1076
|
async save() {
|
|
1035
1077
|
if (this.form.invalid) {
|
|
1036
|
-
|
|
1037
|
-
console.error('Form is invalid');
|
|
1078
|
+
this.toastService?.error({ title: 'Error', subtitle: 'Form is invalid' });
|
|
1038
1079
|
}
|
|
1039
1080
|
const entityData = { ...this.form.value, _id: this.entityId() };
|
|
1040
1081
|
const result = await this.entityCommunicationService.createOrUpdate(entityData);
|
|
@@ -1042,6 +1083,32 @@ class EntityBaseFormComponent {
|
|
|
1042
1083
|
this.patchForm(result);
|
|
1043
1084
|
return result;
|
|
1044
1085
|
}
|
|
1086
|
+
getDirtyValues(form) {
|
|
1087
|
+
const dirtyValues = {};
|
|
1088
|
+
Object.keys(form.controls).forEach((key) => {
|
|
1089
|
+
const currentControl = form.get(key);
|
|
1090
|
+
if (!currentControl?.dirty) {
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
if (currentControl instanceof FormGroup) {
|
|
1094
|
+
const nestedDirtyValues = this.getDirtyValues(currentControl);
|
|
1095
|
+
if (Object.keys(nestedDirtyValues).length > 0) {
|
|
1096
|
+
dirtyValues[key] = nestedDirtyValues;
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
else if (currentControl instanceof FormArray) {
|
|
1100
|
+
dirtyValues[key] = currentControl.getRawValue();
|
|
1101
|
+
}
|
|
1102
|
+
else {
|
|
1103
|
+
dirtyValues[key] = currentControl.value;
|
|
1104
|
+
}
|
|
1105
|
+
});
|
|
1106
|
+
return dirtyValues;
|
|
1107
|
+
}
|
|
1108
|
+
saveDirtyValues() {
|
|
1109
|
+
const dirtyValues = this.getDirtyValues(this.form);
|
|
1110
|
+
return this.entityCommunicationService.partialUpdate(this.entityId(), dirtyValues);
|
|
1111
|
+
}
|
|
1045
1112
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: EntityBaseFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1046
1113
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: EntityBaseFormComponent, isStandalone: true, ngImport: i0 }); }
|
|
1047
1114
|
}
|
|
@@ -1049,39 +1116,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImpor
|
|
|
1049
1116
|
type: Directive
|
|
1050
1117
|
}] });
|
|
1051
1118
|
|
|
1052
|
-
const TOAST_ALERTS_TOKEN = new InjectionToken('Toast alerts Service');
|
|
1053
|
-
class ToastAlertsAbstractService {
|
|
1054
|
-
}
|
|
1055
|
-
function provideToastAlert(serviceImplementation) {
|
|
1056
|
-
return [
|
|
1057
|
-
{
|
|
1058
|
-
provide: TOAST_ALERTS_TOKEN,
|
|
1059
|
-
useExisting: serviceImplementation,
|
|
1060
|
-
},
|
|
1061
|
-
];
|
|
1062
|
-
}
|
|
1063
|
-
// @deprecated, moved to ngx-vertex
|
|
1064
|
-
var AudioSpeed;
|
|
1065
|
-
(function (AudioSpeed) {
|
|
1066
|
-
AudioSpeed["VerySlow"] = "verySlow";
|
|
1067
|
-
AudioSpeed["Slow"] = "slow";
|
|
1068
|
-
AudioSpeed["Regular"] = "regular";
|
|
1069
|
-
AudioSpeed["Fast"] = "fast";
|
|
1070
|
-
AudioSpeed["VeryFast"] = "veryFast";
|
|
1071
|
-
})(AudioSpeed || (AudioSpeed = {}));
|
|
1072
|
-
const AudioSpeedReverse = {
|
|
1073
|
-
[AudioSpeed.VerySlow]: 1,
|
|
1074
|
-
[AudioSpeed.Slow]: 2,
|
|
1075
|
-
[AudioSpeed.Regular]: 3,
|
|
1076
|
-
[AudioSpeed.Fast]: 4,
|
|
1077
|
-
[AudioSpeed.VeryFast]: 5,
|
|
1078
|
-
};
|
|
1079
|
-
class IAIModel {
|
|
1080
|
-
}
|
|
1081
|
-
// Since it not clear if this bellows to chat AI Or user i put here.
|
|
1082
|
-
class ChatUserSettings {
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
1119
|
var EModelQuality;
|
|
1086
1120
|
(function (EModelQuality) {
|
|
1087
1121
|
EModelQuality["FAST"] = "fast";
|
|
@@ -1855,6 +1889,7 @@ const LANGUAGES = {
|
|
|
1855
1889
|
es: 'Inglés',
|
|
1856
1890
|
},
|
|
1857
1891
|
status: 'ready',
|
|
1892
|
+
speakers: 1500000000,
|
|
1858
1893
|
},
|
|
1859
1894
|
es: {
|
|
1860
1895
|
nativeName: 'Español',
|
|
@@ -1890,6 +1925,7 @@ const LANGUAGES = {
|
|
|
1890
1925
|
es: 'Español',
|
|
1891
1926
|
},
|
|
1892
1927
|
status: 'almostready',
|
|
1928
|
+
speakers: 592000000,
|
|
1893
1929
|
},
|
|
1894
1930
|
de: {
|
|
1895
1931
|
nativeName: 'Deutsch',
|
|
@@ -1904,6 +1940,7 @@ const LANGUAGES = {
|
|
|
1904
1940
|
es: 'Alemán',
|
|
1905
1941
|
},
|
|
1906
1942
|
status: 'almostready',
|
|
1943
|
+
speakers: 135000000,
|
|
1907
1944
|
},
|
|
1908
1945
|
fr: {
|
|
1909
1946
|
nativeName: 'Français',
|
|
@@ -1918,6 +1955,7 @@ const LANGUAGES = {
|
|
|
1918
1955
|
es: 'Francés',
|
|
1919
1956
|
},
|
|
1920
1957
|
status: 'almostready',
|
|
1958
|
+
speakers: 300000000,
|
|
1921
1959
|
},
|
|
1922
1960
|
zh: {
|
|
1923
1961
|
nativeName: '中文 (Zhōngwén)',
|
|
@@ -1932,6 +1970,7 @@ const LANGUAGES = {
|
|
|
1932
1970
|
es: 'Chino (Mandarín)',
|
|
1933
1971
|
},
|
|
1934
1972
|
status: 'almostready',
|
|
1973
|
+
speakers: 1120000000,
|
|
1935
1974
|
},
|
|
1936
1975
|
it: {
|
|
1937
1976
|
nativeName: 'Italiano',
|
|
@@ -1946,6 +1985,7 @@ const LANGUAGES = {
|
|
|
1946
1985
|
es: 'Italiano',
|
|
1947
1986
|
},
|
|
1948
1987
|
status: 'almostready',
|
|
1988
|
+
speakers: 67000000,
|
|
1949
1989
|
},
|
|
1950
1990
|
pt: {
|
|
1951
1991
|
nativeName: 'Português',
|
|
@@ -1960,6 +2000,7 @@ const LANGUAGES = {
|
|
|
1960
2000
|
es: 'Portugués',
|
|
1961
2001
|
},
|
|
1962
2002
|
status: 'ready',
|
|
2003
|
+
speakers: 258000000,
|
|
1963
2004
|
},
|
|
1964
2005
|
ja: {
|
|
1965
2006
|
nativeName: '日本語 (Nihongo)',
|
|
@@ -1974,6 +2015,7 @@ const LANGUAGES = {
|
|
|
1974
2015
|
es: 'Japonés',
|
|
1975
2016
|
},
|
|
1976
2017
|
status: 'almostready',
|
|
2018
|
+
speakers: 125000000,
|
|
1977
2019
|
},
|
|
1978
2020
|
nl: {
|
|
1979
2021
|
nativeName: 'Nederlands',
|
|
@@ -1988,6 +2030,7 @@ const LANGUAGES = {
|
|
|
1988
2030
|
es: 'Neerlandés',
|
|
1989
2031
|
},
|
|
1990
2032
|
status: 'commingsoon',
|
|
2033
|
+
speakers: 25000000,
|
|
1991
2034
|
},
|
|
1992
2035
|
ru: {
|
|
1993
2036
|
nativeName: 'Русский (Russkiy)',
|
|
@@ -2002,6 +2045,7 @@ const LANGUAGES = {
|
|
|
2002
2045
|
es: 'Ruso',
|
|
2003
2046
|
},
|
|
2004
2047
|
status: 'commingsoon',
|
|
2048
|
+
speakers: 258000000,
|
|
2005
2049
|
},
|
|
2006
2050
|
ko: {
|
|
2007
2051
|
nativeName: '한국어 (Hangugeo)',
|
|
@@ -2016,6 +2060,7 @@ const LANGUAGES = {
|
|
|
2016
2060
|
es: 'Coreano',
|
|
2017
2061
|
},
|
|
2018
2062
|
status: 'almostready',
|
|
2063
|
+
speakers: 82000000,
|
|
2019
2064
|
},
|
|
2020
2065
|
pl: {
|
|
2021
2066
|
nativeName: 'Polski',
|
|
@@ -2030,6 +2075,7 @@ const LANGUAGES = {
|
|
|
2030
2075
|
es: 'Polaco',
|
|
2031
2076
|
},
|
|
2032
2077
|
status: 'commingsoon',
|
|
2078
|
+
speakers: 40000000,
|
|
2033
2079
|
},
|
|
2034
2080
|
sv: {
|
|
2035
2081
|
nativeName: 'Svenska',
|
|
@@ -2044,6 +2090,7 @@ const LANGUAGES = {
|
|
|
2044
2090
|
es: 'Sueco',
|
|
2045
2091
|
},
|
|
2046
2092
|
status: 'commingsoon',
|
|
2093
|
+
speakers: 10000000,
|
|
2047
2094
|
},
|
|
2048
2095
|
tr: {
|
|
2049
2096
|
nativeName: 'Türkçe',
|
|
@@ -2058,6 +2105,7 @@ const LANGUAGES = {
|
|
|
2058
2105
|
es: 'Turco',
|
|
2059
2106
|
},
|
|
2060
2107
|
status: 'commingsoon',
|
|
2108
|
+
speakers: 88000000,
|
|
2061
2109
|
},
|
|
2062
2110
|
ar: {
|
|
2063
2111
|
nativeName: 'العربية (Al-Arabiyyah)',
|
|
@@ -2098,6 +2146,7 @@ const LANGUAGES = {
|
|
|
2098
2146
|
es: 'Árabe',
|
|
2099
2147
|
},
|
|
2100
2148
|
status: 'commingsoon',
|
|
2149
|
+
speakers: 422000000,
|
|
2101
2150
|
},
|
|
2102
2151
|
vi: {
|
|
2103
2152
|
nativeName: 'Tiếng Việt',
|
|
@@ -2112,6 +2161,7 @@ const LANGUAGES = {
|
|
|
2112
2161
|
es: 'Vietnamita',
|
|
2113
2162
|
},
|
|
2114
2163
|
status: 'commingsoon',
|
|
2164
|
+
speakers: 90000000,
|
|
2115
2165
|
},
|
|
2116
2166
|
id: {
|
|
2117
2167
|
nativeName: 'Bahasa Indonesia',
|
|
@@ -2126,6 +2176,7 @@ const LANGUAGES = {
|
|
|
2126
2176
|
es: 'Indonesio',
|
|
2127
2177
|
},
|
|
2128
2178
|
status: 'commingsoon',
|
|
2179
|
+
speakers: 199000000,
|
|
2129
2180
|
},
|
|
2130
2181
|
da: {
|
|
2131
2182
|
nativeName: 'Dansk',
|
|
@@ -2140,6 +2191,7 @@ const LANGUAGES = {
|
|
|
2140
2191
|
es: 'Danés',
|
|
2141
2192
|
},
|
|
2142
2193
|
status: 'commingsoon',
|
|
2194
|
+
speakers: 6000000,
|
|
2143
2195
|
},
|
|
2144
2196
|
no: {
|
|
2145
2197
|
nativeName: 'Norsk',
|
|
@@ -2154,6 +2206,7 @@ const LANGUAGES = {
|
|
|
2154
2206
|
es: 'Noruego',
|
|
2155
2207
|
},
|
|
2156
2208
|
status: 'commingsoon',
|
|
2209
|
+
speakers: 5300000,
|
|
2157
2210
|
},
|
|
2158
2211
|
fi: {
|
|
2159
2212
|
nativeName: 'Suomi',
|
|
@@ -2168,6 +2221,7 @@ const LANGUAGES = {
|
|
|
2168
2221
|
es: 'Finlandés',
|
|
2169
2222
|
},
|
|
2170
2223
|
status: 'commingsoon',
|
|
2224
|
+
speakers: 5400000,
|
|
2171
2225
|
},
|
|
2172
2226
|
cs: {
|
|
2173
2227
|
nativeName: 'Čeština',
|
|
@@ -2182,6 +2236,7 @@ const LANGUAGES = {
|
|
|
2182
2236
|
es: 'Checo',
|
|
2183
2237
|
},
|
|
2184
2238
|
status: 'commingsoon',
|
|
2239
|
+
speakers: 10700000,
|
|
2185
2240
|
},
|
|
2186
2241
|
el: {
|
|
2187
2242
|
nativeName: 'Ελληνικά (Elliniká)',
|
|
@@ -2196,6 +2251,7 @@ const LANGUAGES = {
|
|
|
2196
2251
|
es: 'Griego',
|
|
2197
2252
|
},
|
|
2198
2253
|
status: 'commingsoon',
|
|
2254
|
+
speakers: 13500000,
|
|
2199
2255
|
},
|
|
2200
2256
|
hu: {
|
|
2201
2257
|
nativeName: 'Magyar',
|
|
@@ -2210,6 +2266,7 @@ const LANGUAGES = {
|
|
|
2210
2266
|
es: 'Húngaro',
|
|
2211
2267
|
},
|
|
2212
2268
|
status: 'commingsoon',
|
|
2269
|
+
speakers: 13000000,
|
|
2213
2270
|
},
|
|
2214
2271
|
ro: {
|
|
2215
2272
|
nativeName: 'Română',
|
|
@@ -2224,6 +2281,7 @@ const LANGUAGES = {
|
|
|
2224
2281
|
es: 'Rumano',
|
|
2225
2282
|
},
|
|
2226
2283
|
status: 'commingsoon',
|
|
2284
|
+
speakers: 24000000,
|
|
2227
2285
|
},
|
|
2228
2286
|
uk: {
|
|
2229
2287
|
nativeName: 'Українська (Ukrainska)',
|
|
@@ -2238,6 +2296,7 @@ const LANGUAGES = {
|
|
|
2238
2296
|
es: 'Ucraniano',
|
|
2239
2297
|
},
|
|
2240
2298
|
status: 'commingsoon',
|
|
2299
|
+
speakers: 33000000,
|
|
2241
2300
|
},
|
|
2242
2301
|
he: {
|
|
2243
2302
|
nativeName: 'עברית (Ivrit)',
|
|
@@ -2252,6 +2311,7 @@ const LANGUAGES = {
|
|
|
2252
2311
|
es: 'Hebreo',
|
|
2253
2312
|
},
|
|
2254
2313
|
status: 'commingsoon',
|
|
2314
|
+
speakers: 9000000,
|
|
2255
2315
|
},
|
|
2256
2316
|
th: {
|
|
2257
2317
|
nativeName: 'ภาษาไทย (Phasa Thai)',
|
|
@@ -2266,6 +2326,7 @@ const LANGUAGES = {
|
|
|
2266
2326
|
es: 'Tailandés',
|
|
2267
2327
|
},
|
|
2268
2328
|
status: 'commingsoon',
|
|
2329
|
+
speakers: 69000000,
|
|
2269
2330
|
},
|
|
2270
2331
|
hi: {
|
|
2271
2332
|
nativeName: 'हिन्दी (Hindī)',
|
|
@@ -2280,6 +2341,7 @@ const LANGUAGES = {
|
|
|
2280
2341
|
es: 'Hindi',
|
|
2281
2342
|
},
|
|
2282
2343
|
status: 'commingsoon',
|
|
2344
|
+
speakers: 602000000,
|
|
2283
2345
|
},
|
|
2284
2346
|
ca: {
|
|
2285
2347
|
nativeName: 'Català',
|
|
@@ -2294,6 +2356,7 @@ const LANGUAGES = {
|
|
|
2294
2356
|
es: 'Catalán',
|
|
2295
2357
|
},
|
|
2296
2358
|
status: 'commingsoon',
|
|
2359
|
+
speakers: 10000000,
|
|
2297
2360
|
},
|
|
2298
2361
|
bg: {
|
|
2299
2362
|
nativeName: 'Български (Balgarski)',
|
|
@@ -2308,6 +2371,7 @@ const LANGUAGES = {
|
|
|
2308
2371
|
es: 'Búlgaro',
|
|
2309
2372
|
},
|
|
2310
2373
|
status: 'commingsoon',
|
|
2374
|
+
speakers: 9000000,
|
|
2311
2375
|
},
|
|
2312
2376
|
eo: {
|
|
2313
2377
|
nativeName: 'Esperanto',
|
|
@@ -2322,6 +2386,7 @@ const LANGUAGES = {
|
|
|
2322
2386
|
es: 'Esperanto',
|
|
2323
2387
|
},
|
|
2324
2388
|
status: 'commingsoon',
|
|
2389
|
+
speakers: 2000000,
|
|
2325
2390
|
},
|
|
2326
2391
|
ia: {
|
|
2327
2392
|
nativeName: 'Interlingua',
|
|
@@ -2336,6 +2401,7 @@ const LANGUAGES = {
|
|
|
2336
2401
|
es: 'Interlingua',
|
|
2337
2402
|
},
|
|
2338
2403
|
status: 'commingsoon',
|
|
2404
|
+
speakers: 1500,
|
|
2339
2405
|
},
|
|
2340
2406
|
hr: {
|
|
2341
2407
|
nativeName: 'Hrvatski',
|
|
@@ -2350,6 +2416,7 @@ const LANGUAGES = {
|
|
|
2350
2416
|
es: 'Croata',
|
|
2351
2417
|
},
|
|
2352
2418
|
status: 'commingsoon',
|
|
2419
|
+
speakers: 5700000,
|
|
2353
2420
|
},
|
|
2354
2421
|
sk: {
|
|
2355
2422
|
nativeName: 'Slovenčina',
|
|
@@ -2364,6 +2431,7 @@ const LANGUAGES = {
|
|
|
2364
2431
|
es: 'Eslovaco',
|
|
2365
2432
|
},
|
|
2366
2433
|
status: 'commingsoon',
|
|
2434
|
+
speakers: 5400000,
|
|
2367
2435
|
},
|
|
2368
2436
|
fil: {
|
|
2369
2437
|
nativeName: 'Filipino',
|
|
@@ -2378,6 +2446,7 @@ const LANGUAGES = {
|
|
|
2378
2446
|
es: 'Filipino',
|
|
2379
2447
|
},
|
|
2380
2448
|
status: 'commingsoon',
|
|
2449
|
+
speakers: 109000000,
|
|
2381
2450
|
},
|
|
2382
2451
|
tl: {
|
|
2383
2452
|
// Tagalog often used as base for Filipino, but distinct ISO code
|
|
@@ -2393,6 +2462,7 @@ const LANGUAGES = {
|
|
|
2393
2462
|
es: 'Tagalo',
|
|
2394
2463
|
},
|
|
2395
2464
|
status: 'commingsoon',
|
|
2465
|
+
speakers: 109000000,
|
|
2396
2466
|
},
|
|
2397
2467
|
lt: {
|
|
2398
2468
|
nativeName: 'Lietuvių',
|
|
@@ -2407,6 +2477,7 @@ const LANGUAGES = {
|
|
|
2407
2477
|
es: 'Lituano',
|
|
2408
2478
|
},
|
|
2409
2479
|
status: 'commingsoon',
|
|
2480
|
+
speakers: 2800000,
|
|
2410
2481
|
},
|
|
2411
2482
|
lv: {
|
|
2412
2483
|
nativeName: 'Latviešu',
|
|
@@ -2421,6 +2492,7 @@ const LANGUAGES = {
|
|
|
2421
2492
|
es: 'Letón',
|
|
2422
2493
|
},
|
|
2423
2494
|
status: 'commingsoon',
|
|
2495
|
+
speakers: 1900000,
|
|
2424
2496
|
},
|
|
2425
2497
|
sl: {
|
|
2426
2498
|
nativeName: 'Slovenščina',
|
|
@@ -2435,6 +2507,7 @@ const LANGUAGES = {
|
|
|
2435
2507
|
es: 'Esloveno',
|
|
2436
2508
|
},
|
|
2437
2509
|
status: 'commingsoon',
|
|
2510
|
+
speakers: 2500000,
|
|
2438
2511
|
},
|
|
2439
2512
|
et: {
|
|
2440
2513
|
nativeName: 'Eesti',
|
|
@@ -2449,6 +2522,7 @@ const LANGUAGES = {
|
|
|
2449
2522
|
es: 'Estonio',
|
|
2450
2523
|
},
|
|
2451
2524
|
status: 'commingsoon',
|
|
2525
|
+
speakers: 1100000,
|
|
2452
2526
|
},
|
|
2453
2527
|
ms: {
|
|
2454
2528
|
nativeName: 'Bahasa Melayu',
|
|
@@ -2463,6 +2537,7 @@ const LANGUAGES = {
|
|
|
2463
2537
|
es: 'Malayo',
|
|
2464
2538
|
},
|
|
2465
2539
|
status: 'commingsoon',
|
|
2540
|
+
speakers: 290000000,
|
|
2466
2541
|
},
|
|
2467
2542
|
sw: {
|
|
2468
2543
|
nativeName: 'Kiswahili',
|
|
@@ -2477,6 +2552,7 @@ const LANGUAGES = {
|
|
|
2477
2552
|
es: 'Suajili',
|
|
2478
2553
|
},
|
|
2479
2554
|
status: 'commingsoon',
|
|
2555
|
+
speakers: 200000000,
|
|
2480
2556
|
},
|
|
2481
2557
|
fa: {
|
|
2482
2558
|
nativeName: 'فارسی (Fārsī)',
|
|
@@ -2491,6 +2567,7 @@ const LANGUAGES = {
|
|
|
2491
2567
|
es: 'Persa',
|
|
2492
2568
|
},
|
|
2493
2569
|
status: 'commingsoon',
|
|
2570
|
+
speakers: 110000000,
|
|
2494
2571
|
},
|
|
2495
2572
|
bn: {
|
|
2496
2573
|
nativeName: 'বাংলা (Bangla)',
|
|
@@ -2505,6 +2582,7 @@ const LANGUAGES = {
|
|
|
2505
2582
|
es: 'Bengalí',
|
|
2506
2583
|
},
|
|
2507
2584
|
status: 'commingsoon',
|
|
2585
|
+
speakers: 272000000,
|
|
2508
2586
|
},
|
|
2509
2587
|
ur: {
|
|
2510
2588
|
nativeName: 'اردو (Urdū)',
|
|
@@ -2519,6 +2597,7 @@ const LANGUAGES = {
|
|
|
2519
2597
|
es: 'Urdu',
|
|
2520
2598
|
},
|
|
2521
2599
|
status: 'commingsoon',
|
|
2600
|
+
speakers: 231000000,
|
|
2522
2601
|
},
|
|
2523
2602
|
sr: {
|
|
2524
2603
|
nativeName: 'Српски (Srpski)',
|
|
@@ -2533,6 +2612,7 @@ const LANGUAGES = {
|
|
|
2533
2612
|
es: 'Serbio',
|
|
2534
2613
|
},
|
|
2535
2614
|
status: 'commingsoon',
|
|
2615
|
+
speakers: 9000000,
|
|
2536
2616
|
},
|
|
2537
2617
|
is: {
|
|
2538
2618
|
nativeName: 'Íslenska',
|
|
@@ -2547,6 +2627,7 @@ const LANGUAGES = {
|
|
|
2547
2627
|
es: 'Islandés',
|
|
2548
2628
|
},
|
|
2549
2629
|
status: 'commingsoon',
|
|
2630
|
+
speakers: 314000,
|
|
2550
2631
|
},
|
|
2551
2632
|
ta: {
|
|
2552
2633
|
nativeName: 'தமிழ் (Tamiḻ)',
|
|
@@ -2561,6 +2642,7 @@ const LANGUAGES = {
|
|
|
2561
2642
|
es: 'Tamil',
|
|
2562
2643
|
},
|
|
2563
2644
|
status: 'commingsoon',
|
|
2645
|
+
speakers: 86000000,
|
|
2564
2646
|
},
|
|
2565
2647
|
mr: {
|
|
2566
2648
|
nativeName: 'मराठी (Marāṭhī)',
|
|
@@ -2575,6 +2657,7 @@ const LANGUAGES = {
|
|
|
2575
2657
|
es: 'Maratí',
|
|
2576
2658
|
},
|
|
2577
2659
|
status: 'commingsoon',
|
|
2660
|
+
speakers: 99000000,
|
|
2578
2661
|
},
|
|
2579
2662
|
my: {
|
|
2580
2663
|
nativeName: 'မြန်မာဘာသာ (Myanmar)',
|
|
@@ -2589,6 +2672,7 @@ const LANGUAGES = {
|
|
|
2589
2672
|
es: 'Birmano',
|
|
2590
2673
|
},
|
|
2591
2674
|
status: 'commingsoon',
|
|
2675
|
+
speakers: 43000000,
|
|
2592
2676
|
},
|
|
2593
2677
|
cy: {
|
|
2594
2678
|
nativeName: 'Cymraeg',
|
|
@@ -2603,6 +2687,7 @@ const LANGUAGES = {
|
|
|
2603
2687
|
es: 'Galés',
|
|
2604
2688
|
},
|
|
2605
2689
|
status: 'commingsoon',
|
|
2690
|
+
speakers: 724000,
|
|
2606
2691
|
},
|
|
2607
2692
|
ha: {
|
|
2608
2693
|
nativeName: 'Hausa',
|
|
@@ -2617,6 +2702,7 @@ const LANGUAGES = {
|
|
|
2617
2702
|
es: 'Hausa',
|
|
2618
2703
|
},
|
|
2619
2704
|
status: 'commingsoon',
|
|
2705
|
+
speakers: 130000000,
|
|
2620
2706
|
},
|
|
2621
2707
|
eu: {
|
|
2622
2708
|
nativeName: 'Euskara',
|
|
@@ -2631,6 +2717,7 @@ const LANGUAGES = {
|
|
|
2631
2717
|
es: 'Vasco',
|
|
2632
2718
|
},
|
|
2633
2719
|
status: 'commingsoon',
|
|
2720
|
+
speakers: 750000,
|
|
2634
2721
|
},
|
|
2635
2722
|
ga: {
|
|
2636
2723
|
nativeName: 'Gaeilge',
|
|
@@ -2645,6 +2732,7 @@ const LANGUAGES = {
|
|
|
2645
2732
|
es: 'Irlandés',
|
|
2646
2733
|
},
|
|
2647
2734
|
status: 'commingsoon',
|
|
2735
|
+
speakers: 1900000,
|
|
2648
2736
|
},
|
|
2649
2737
|
sd: {
|
|
2650
2738
|
nativeName: 'سنڌي (Sindhī)',
|
|
@@ -2659,6 +2747,7 @@ const LANGUAGES = {
|
|
|
2659
2747
|
es: 'Sindi',
|
|
2660
2748
|
},
|
|
2661
2749
|
status: 'commingsoon',
|
|
2750
|
+
speakers: 32000000,
|
|
2662
2751
|
},
|
|
2663
2752
|
am: {
|
|
2664
2753
|
nativeName: 'አማርኛ (Amarəñña)',
|
|
@@ -2673,6 +2762,7 @@ const LANGUAGES = {
|
|
|
2673
2762
|
es: 'Amárico',
|
|
2674
2763
|
},
|
|
2675
2764
|
status: 'commingsoon',
|
|
2765
|
+
speakers: 57000000,
|
|
2676
2766
|
},
|
|
2677
2767
|
jv: {
|
|
2678
2768
|
nativeName: 'Basa Jawa',
|
|
@@ -2687,6 +2777,7 @@ const LANGUAGES = {
|
|
|
2687
2777
|
es: 'Javanés',
|
|
2688
2778
|
},
|
|
2689
2779
|
status: 'commingsoon',
|
|
2780
|
+
speakers: 68000000,
|
|
2690
2781
|
},
|
|
2691
2782
|
km: {
|
|
2692
2783
|
nativeName: 'ភាសាខ្មែរ (Phéasa Khmér)',
|
|
@@ -2701,6 +2792,7 @@ const LANGUAGES = {
|
|
|
2701
2792
|
es: 'Jemer',
|
|
2702
2793
|
},
|
|
2703
2794
|
status: 'commingsoon',
|
|
2795
|
+
speakers: 16000000,
|
|
2704
2796
|
},
|
|
2705
2797
|
yo: {
|
|
2706
2798
|
nativeName: 'Yorùbá',
|
|
@@ -2715,6 +2807,7 @@ const LANGUAGES = {
|
|
|
2715
2807
|
es: 'Yoruba',
|
|
2716
2808
|
},
|
|
2717
2809
|
status: 'commingsoon',
|
|
2810
|
+
speakers: 50000000,
|
|
2718
2811
|
},
|
|
2719
2812
|
gl: {
|
|
2720
2813
|
nativeName: 'Galego',
|
|
@@ -2729,6 +2822,7 @@ const LANGUAGES = {
|
|
|
2729
2822
|
es: 'Gallego',
|
|
2730
2823
|
},
|
|
2731
2824
|
status: 'commingsoon',
|
|
2825
|
+
speakers: 2400000,
|
|
2732
2826
|
},
|
|
2733
2827
|
};
|
|
2734
2828
|
function getLangDesc(langCode, lang) {
|