valtech-components 2.0.291 → 2.0.292

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.
@@ -1543,11 +1543,20 @@ class TextContent {
1543
1543
  return this.text;
1544
1544
  }
1545
1545
  }
1546
- var LangOption;
1547
- (function (LangOption) {
1548
- LangOption["ES"] = "es";
1549
- LangOption["EN"] = "en";
1550
- })(LangOption || (LangOption = {}));
1546
+ /**
1547
+ * Common language constants for convenience.
1548
+ * Users can still use any language code string directly.
1549
+ */
1550
+ const LANGUAGES = {
1551
+ ES: 'es',
1552
+ EN: 'en',
1553
+ FR: 'fr',
1554
+ DE: 'de',
1555
+ PT: 'pt',
1556
+ IT: 'it',
1557
+ ZH: 'zh',
1558
+ JA: 'ja',
1559
+ };
1551
1560
 
1552
1561
  /**
1553
1562
  * LangService - Reactive language and content management service.
@@ -1555,6 +1564,9 @@ var LangOption;
1555
1564
  * This service provides reactive content management with Observable-based language switching.
1556
1565
  * Components can subscribe to content changes and automatically update when the language changes.
1557
1566
  *
1567
+ * The service automatically detects available languages from the content configuration
1568
+ * and provides intelligent fallbacks with console warnings for missing translations.
1569
+ *
1558
1570
  * @example Basic usage:
1559
1571
  * ```typescript
1560
1572
  * constructor(private langService: LangService) {}
@@ -1574,12 +1586,120 @@ var LangOption;
1574
1586
  */
1575
1587
  class LangService {
1576
1588
  constructor(config) {
1577
- this.default = LangOption.ES;
1578
- console.log('injected config: ', config);
1589
+ this.availableLanguages = [];
1590
+ this.warnedMissingLanguages = new Set();
1591
+ console.log('LangService: Injected config:', config);
1579
1592
  this.content = config.content;
1580
1593
  this.config = config;
1594
+ // Detect available languages from content
1595
+ this.detectAvailableLanguages();
1596
+ // Set default language (prefer Spanish, then English, then first available)
1597
+ this.defaultLang = this.determineDefaultLanguage();
1598
+ // Initialize with stored language or default
1581
1599
  const current = LocalStorageService.get(LANG);
1582
- this.selectedLang = new BehaviorSubject(current || this.default);
1600
+ const initialLang = this.validateLanguage(current) || this.defaultLang;
1601
+ this.selectedLang = new BehaviorSubject(initialLang);
1602
+ console.log('LangService: Initialized with languages:', {
1603
+ available: this.availableLanguages,
1604
+ default: this.defaultLang,
1605
+ current: initialLang,
1606
+ });
1607
+ }
1608
+ /**
1609
+ * Detect available languages from the content configuration.
1610
+ * Scans all component content to find which languages are actually configured.
1611
+ */
1612
+ detectAvailableLanguages() {
1613
+ const languageSet = new Set();
1614
+ Object.values(this.content).forEach(componentContent => {
1615
+ if (componentContent?.Content) {
1616
+ Object.keys(componentContent.Content).forEach(lang => {
1617
+ languageSet.add(lang);
1618
+ });
1619
+ }
1620
+ });
1621
+ this.availableLanguages = Array.from(languageSet).sort();
1622
+ if (this.availableLanguages.length === 0) {
1623
+ console.warn('LangService: No languages detected in content configuration!');
1624
+ this.availableLanguages = [LANGUAGES.ES]; // Fallback
1625
+ }
1626
+ }
1627
+ /**
1628
+ * Determine the best default language based on available content.
1629
+ */
1630
+ determineDefaultLanguage() {
1631
+ // Preference order: Spanish, English, then first available
1632
+ const preferredOrder = [LANGUAGES.ES, LANGUAGES.EN];
1633
+ for (const preferred of preferredOrder) {
1634
+ if (this.availableLanguages.includes(preferred)) {
1635
+ return preferred;
1636
+ }
1637
+ }
1638
+ return this.availableLanguages[0];
1639
+ }
1640
+ /**
1641
+ * Validate if a language is available in the content.
1642
+ */
1643
+ validateLanguage(lang) {
1644
+ if (!lang)
1645
+ return null;
1646
+ return this.availableLanguages.includes(lang) ? lang : null;
1647
+ }
1648
+ /**
1649
+ * Get the best available language for a component and key.
1650
+ * Provides intelligent fallback with warnings.
1651
+ */
1652
+ getBestAvailableContent(className, key, requestedLang) {
1653
+ const componentContent = this.content[className];
1654
+ if (!componentContent) {
1655
+ return {
1656
+ content: undefined,
1657
+ actualLang: requestedLang,
1658
+ shouldWarn: false,
1659
+ };
1660
+ }
1661
+ // Try requested language first
1662
+ const requestedContent = componentContent.Content[requestedLang];
1663
+ if (requestedContent?.[key]) {
1664
+ return {
1665
+ content: requestedContent[key],
1666
+ actualLang: requestedLang,
1667
+ shouldWarn: false,
1668
+ };
1669
+ }
1670
+ // Language not available, try fallbacks
1671
+ const warningKey = `${className}.${key}.${requestedLang}`;
1672
+ const shouldWarn = !this.warnedMissingLanguages.has(warningKey);
1673
+ if (shouldWarn) {
1674
+ this.warnedMissingLanguages.add(warningKey);
1675
+ }
1676
+ // Try default language
1677
+ if (requestedLang !== this.defaultLang) {
1678
+ const defaultContent = componentContent.Content[this.defaultLang];
1679
+ if (defaultContent?.[key]) {
1680
+ return {
1681
+ content: defaultContent[key],
1682
+ actualLang: this.defaultLang,
1683
+ shouldWarn,
1684
+ };
1685
+ }
1686
+ }
1687
+ // Try first available language
1688
+ for (const availableLang of this.availableLanguages) {
1689
+ const availableContent = componentContent.Content[availableLang];
1690
+ if (availableContent?.[key]) {
1691
+ return {
1692
+ content: availableContent[key],
1693
+ actualLang: availableLang,
1694
+ shouldWarn,
1695
+ };
1696
+ }
1697
+ }
1698
+ return {
1699
+ content: undefined,
1700
+ actualLang: requestedLang,
1701
+ shouldWarn,
1702
+ };
1583
1703
  }
1584
1704
  /**
1585
1705
  * Observable that emits the current language whenever it changes.
@@ -1594,13 +1714,32 @@ class LangService {
1594
1714
  get currentLang() {
1595
1715
  return this.selectedLang.value;
1596
1716
  }
1717
+ /**
1718
+ * Get array of available languages detected from content.
1719
+ */
1720
+ get availableLangs() {
1721
+ return [...this.availableLanguages];
1722
+ }
1723
+ /**
1724
+ * Get the default language.
1725
+ */
1726
+ get defaultLanguage() {
1727
+ return this.defaultLang;
1728
+ }
1597
1729
  /**
1598
1730
  * Set the current language and persist it to localStorage.
1599
1731
  * This will trigger updates in all reactive content subscriptions.
1600
1732
  *
1733
+ * Validates that the language is available and warns if not.
1734
+ *
1601
1735
  * @param lang - The language to set
1602
1736
  */
1603
1737
  setLang(lang) {
1738
+ if (!this.availableLanguages.includes(lang)) {
1739
+ console.warn(`LangService: Language "${lang}" is not available. Available languages:`, this.availableLanguages);
1740
+ console.warn(`LangService: Falling back to default language "${this.defaultLang}"`);
1741
+ lang = this.defaultLang;
1742
+ }
1604
1743
  this.selectedLang.next(lang);
1605
1744
  LocalStorageService.set(LANG, lang);
1606
1745
  }
@@ -1610,10 +1749,12 @@ class LangService {
1610
1749
  * @deprecated Use getText() or getContent() for better type safety
1611
1750
  */
1612
1751
  Text(className) {
1613
- return this.content[className].Content[this.selectedLang.value];
1752
+ const componentContent = this.content[className];
1753
+ return componentContent?.Content[this.selectedLang.value] || {};
1614
1754
  }
1615
1755
  /**
1616
1756
  * Get a single content string synchronously for the current language.
1757
+ * Provides intelligent fallback with warnings for missing translations.
1617
1758
  *
1618
1759
  * @param className - The component class name
1619
1760
  * @param key - The text key
@@ -1621,12 +1762,16 @@ class LangService {
1621
1762
  * @returns The text string or fallback
1622
1763
  */
1623
1764
  getText(className, key, fallback) {
1624
- const classContent = this.content[className]?.Content[this.selectedLang.value];
1625
- return classContent?.[key] || fallback || `[${className}.${key}]`;
1765
+ const result = this.getBestAvailableContent(className, key, this.selectedLang.value);
1766
+ if (result.shouldWarn && result.actualLang !== this.selectedLang.value) {
1767
+ console.warn(`LangService: Content "${className}.${key}" not available in "${this.selectedLang.value}".`, `Using "${result.actualLang}" instead. Available languages:`, this.availableLanguages);
1768
+ }
1769
+ return result.content || fallback || `[${className}.${key}]`;
1626
1770
  }
1627
1771
  /**
1628
1772
  * Get a reactive Observable for a specific text key that updates when language changes.
1629
1773
  * This is the recommended method for components that need reactive content.
1774
+ * Provides intelligent fallback with warnings for missing translations.
1630
1775
  *
1631
1776
  * @param className - The component class name
1632
1777
  * @param key - The text key
@@ -1635,12 +1780,16 @@ class LangService {
1635
1780
  */
1636
1781
  getContent(className, key, fallback) {
1637
1782
  return this.currentLang$.pipe(map(lang => {
1638
- const classContent = this.content[className]?.Content[lang];
1639
- return classContent?.[key] || fallback || `[${className}.${key}]`;
1783
+ const result = this.getBestAvailableContent(className, key, lang);
1784
+ if (result.shouldWarn && result.actualLang !== lang) {
1785
+ console.warn(`LangService: Content "${className}.${key}" not available in "${lang}".`, `Using "${result.actualLang}" instead. Available languages:`, this.availableLanguages);
1786
+ }
1787
+ return result.content || fallback || `[${className}.${key}]`;
1640
1788
  }), distinctUntilChanged());
1641
1789
  }
1642
1790
  /**
1643
1791
  * Get reactive content for multiple keys at once.
1792
+ * Provides intelligent fallback with warnings for missing translations.
1644
1793
  *
1645
1794
  * @param className - The component class name
1646
1795
  * @param keys - Array of text keys to retrieve
@@ -1648,16 +1797,19 @@ class LangService {
1648
1797
  */
1649
1798
  getMultipleContent(className, keys) {
1650
1799
  return this.currentLang$.pipe(map(lang => {
1651
- const classContent = this.content[className]?.Content[lang] || {};
1652
1800
  const result = {};
1653
1801
  keys.forEach(key => {
1654
- result[key] = classContent[key] || `[${className}.${key}]`;
1802
+ const contentResult = this.getBestAvailableContent(className, key, lang);
1803
+ if (contentResult.shouldWarn && contentResult.actualLang !== lang) {
1804
+ console.warn(`LangService: Content "${className}.${key}" not available in "${lang}".`, `Using "${contentResult.actualLang}" instead.`);
1805
+ }
1806
+ result[key] = contentResult.content || `[${className}.${key}]`;
1655
1807
  });
1656
1808
  return result;
1657
1809
  }), distinctUntilChanged((prev, curr) => JSON.stringify(prev) === JSON.stringify(curr)));
1658
1810
  }
1659
1811
  /**
1660
- * Check if a content key exists for a component.
1812
+ * Check if a content key exists for a component in any available language.
1661
1813
  *
1662
1814
  * @param className - The component class name
1663
1815
  * @param key - The text key
@@ -1669,6 +1821,49 @@ class LangService {
1669
1821
  return false;
1670
1822
  return Object.values(classContent.Content).some(langContent => langContent && typeof langContent[key] === 'string');
1671
1823
  }
1824
+ /**
1825
+ * Check if a content key exists for a component in a specific language.
1826
+ *
1827
+ * @param className - The component class name
1828
+ * @param key - The text key
1829
+ * @param lang - The language to check (defaults to current language)
1830
+ * @returns True if the key exists in the specified language
1831
+ */
1832
+ hasContentInLanguage(className, key, lang) {
1833
+ const targetLang = lang || this.currentLang;
1834
+ const classContent = this.content[className]?.Content[targetLang];
1835
+ return classContent && typeof classContent[key] === 'string';
1836
+ }
1837
+ /**
1838
+ * Get available languages for a specific component.
1839
+ *
1840
+ * @param className - The component class name
1841
+ * @returns Array of language codes available for the component
1842
+ */
1843
+ getAvailableLanguagesForComponent(className) {
1844
+ const classContent = this.content[className];
1845
+ if (!classContent)
1846
+ return [];
1847
+ return Object.keys(classContent.Content).filter(lang => classContent.Content[lang] && Object.keys(classContent.Content[lang]).length > 0);
1848
+ }
1849
+ /**
1850
+ * Get missing content keys for a component in a specific language.
1851
+ * Useful for identifying incomplete translations.
1852
+ *
1853
+ * @param className - The component class name
1854
+ * @param lang - The language to check
1855
+ * @param referenceLang - The reference language to compare against (defaults to default language)
1856
+ * @returns Array of missing keys
1857
+ */
1858
+ getMissingContentKeys(className, lang, referenceLang) {
1859
+ const refLang = referenceLang || this.defaultLang;
1860
+ const classContent = this.content[className];
1861
+ if (!classContent)
1862
+ return [];
1863
+ const referenceContent = classContent.Content[refLang] || {};
1864
+ const targetContent = classContent.Content[lang] || {};
1865
+ return Object.keys(referenceContent).filter(key => !targetContent[key] || typeof targetContent[key] !== 'string');
1866
+ }
1672
1867
  // Legacy getters/setters for backward compatibility
1673
1868
  get Lang() {
1674
1869
  return this.currentLang;
@@ -6564,7 +6759,7 @@ class CustomContentDemoComponent {
6564
6759
  this.diagnoseConfiguration();
6565
6760
  }
6566
6761
  switchLanguage() {
6567
- const newLang = this.currentLang === 'es' ? LangOption.EN : LangOption.ES;
6762
+ const newLang = this.currentLang === 'es' ? LANGUAGES.EN : LANGUAGES.ES;
6568
6763
  this.content.setLang(newLang);
6569
6764
  // Actualizar textos síncronos después del cambio
6570
6765
  setTimeout(() => {
@@ -7032,6 +7227,301 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
7032
7227
  `, styles: [".example-section{margin-bottom:24px;padding:16px;border:1px solid var(--ion-color-light, #f4f5f8);border-radius:8px;background:var(--ion-color-light-tint, #f5f6f9)}h2{color:var(--ion-color-primary, #3880ff);margin-bottom:20px}h3{color:var(--ion-color-dark, #222428);margin-bottom:10px;font-size:16px}\n"] }]
7033
7228
  }] });
7034
7229
 
7230
+ /**
7231
+ * MultiLanguageDemoComponent - Demuestra el sistema de idiomas flexible.
7232
+ *
7233
+ * Este componente muestra cómo el sistema maneja múltiples idiomas,
7234
+ * fallbacks automáticos y warnings por traducciones faltantes.
7235
+ */
7236
+ class MultiLanguageDemoComponent {
7237
+ constructor(content, langService) {
7238
+ this.content = content;
7239
+ this.langService = langService;
7240
+ this.availableLanguages = [];
7241
+ this.analysisResults = null;
7242
+ // Global content observables
7243
+ this.okButton$ = this.content.fromContent({ key: 'ok' });
7244
+ this.cancelButton$ = this.content.fromContent({ key: 'cancel' });
7245
+ this.saveButton$ = this.content.fromContent({ key: 'save' });
7246
+ this.deleteButton$ = this.content.fromContent({ key: 'delete' });
7247
+ // Content that might have missing translations
7248
+ this.nextButton$ = this.content.fromContent({ key: 'next', fallback: 'Next' });
7249
+ this.finishButton$ = this.content.fromContent({ key: 'finish', fallback: 'Finish' });
7250
+ this.searchPlaceholder$ = this.content.fromContent({ key: 'searchPlaceholder', fallback: 'Search...' });
7251
+ this.noDataMessage$ = this.content.fromContent({ key: 'noData', fallback: 'No data available' });
7252
+ }
7253
+ ngOnInit() {
7254
+ this.availableLanguages = this.langService.availableLangs;
7255
+ }
7256
+ switchLanguage(lang) {
7257
+ console.log(`Switching to language: ${lang}`);
7258
+ this.langService.setLang(lang);
7259
+ this.analysisResults = null; // Reset analysis when language changes
7260
+ }
7261
+ getLanguageName(lang) {
7262
+ const names = {
7263
+ [LANGUAGES.ES]: 'Español',
7264
+ [LANGUAGES.EN]: 'English',
7265
+ [LANGUAGES.FR]: 'Français',
7266
+ [LANGUAGES.DE]: 'Deutsch',
7267
+ pt: 'Português',
7268
+ };
7269
+ return names[lang] || lang.toUpperCase();
7270
+ }
7271
+ analyzeCurrentComponent() {
7272
+ const componentName = '_global'; // Analyzing global content for this demo
7273
+ const availableLanguages = this.langService.getAvailableLanguagesForComponent(componentName);
7274
+ const missingKeys = this.langService.getMissingContentKeys(componentName, this.langService.currentLang);
7275
+ this.analysisResults = {
7276
+ availableLanguages,
7277
+ missingKeys,
7278
+ };
7279
+ console.log('Component analysis results:', this.analysisResults);
7280
+ }
7281
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MultiLanguageDemoComponent, deps: [{ token: ContentService }, { token: LangService }], target: i0.ɵɵFactoryTarget.Component }); }
7282
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: MultiLanguageDemoComponent, isStandalone: true, selector: "val-multi-language-demo", ngImport: i0, template: `
7283
+ <div class="multi-lang-demo">
7284
+ <h2>Sistema de Idiomas Flexible</h2>
7285
+
7286
+ <div class="language-info">
7287
+ <h3>Información del Sistema:</h3>
7288
+ <p><strong>Idioma actual:</strong> {{ langService.currentLang }}</p>
7289
+ <p><strong>Idioma por defecto:</strong> {{ langService.defaultLanguage }}</p>
7290
+ <p><strong>Idiomas disponibles:</strong> {{ langService.availableLangs.join(', ') }}</p>
7291
+ </div>
7292
+
7293
+ <div class="language-switcher">
7294
+ <h3>Cambiar Idioma:</h3>
7295
+ <div class="button-group">
7296
+ <button
7297
+ *ngFor="let lang of availableLanguages"
7298
+ [class.active]="lang === langService.currentLang"
7299
+ (click)="switchLanguage(lang)"
7300
+ >
7301
+ {{ getLanguageName(lang) }}
7302
+ </button>
7303
+ <!-- Ejemplo de idioma no disponible -->
7304
+ <button (click)="switchLanguage('pt')">Português (no disponible)</button>
7305
+ </div>
7306
+ </div>
7307
+
7308
+ <div class="content-examples">
7309
+ <h3>Contenido Global:</h3>
7310
+ <div class="example-grid">
7311
+ <val-text
7312
+ [props]="{ content: okButton$ | async, size: 'medium', color: 'dark', bold: false, processLinks: false }"
7313
+ ></val-text>
7314
+ <val-text
7315
+ [props]="{
7316
+ content: cancelButton$ | async,
7317
+ size: 'medium',
7318
+ color: 'dark',
7319
+ bold: false,
7320
+ processLinks: false,
7321
+ }"
7322
+ ></val-text>
7323
+ <val-text
7324
+ [props]="{ content: saveButton$ | async, size: 'medium', color: 'dark', bold: false, processLinks: false }"
7325
+ ></val-text>
7326
+ <val-text
7327
+ [props]="{
7328
+ content: deleteButton$ | async,
7329
+ size: 'medium',
7330
+ color: 'dark',
7331
+ bold: false,
7332
+ processLinks: false,
7333
+ }"
7334
+ ></val-text>
7335
+ </div>
7336
+
7337
+ <h3>Contenido con Fallback (algunas traducciones faltantes):</h3>
7338
+ <div class="example-grid">
7339
+ <val-text
7340
+ [props]="{ content: nextButton$ | async, size: 'medium', color: 'dark', bold: false, processLinks: false }"
7341
+ ></val-text>
7342
+ <val-text
7343
+ [props]="{
7344
+ content: finishButton$ | async,
7345
+ size: 'medium',
7346
+ color: 'dark',
7347
+ bold: false,
7348
+ processLinks: false,
7349
+ }"
7350
+ ></val-text>
7351
+ <val-text
7352
+ [props]="{
7353
+ content: searchPlaceholder$ | async,
7354
+ size: 'medium',
7355
+ color: 'dark',
7356
+ bold: false,
7357
+ processLinks: false,
7358
+ }"
7359
+ ></val-text>
7360
+ <val-text
7361
+ [props]="{
7362
+ content: noDataMessage$ | async,
7363
+ size: 'medium',
7364
+ color: 'dark',
7365
+ bold: false,
7366
+ processLinks: false,
7367
+ }"
7368
+ ></val-text>
7369
+ </div>
7370
+ </div>
7371
+
7372
+ <div class="warning-info">
7373
+ <h3>Información de Warnings:</h3>
7374
+ <p>
7375
+ Abre la consola del navegador para ver los warnings cuando cambies a idiomas con traducciones incompletas
7376
+ (francés, alemán).
7377
+ </p>
7378
+ <p>El sistema automáticamente usará el idioma por defecto o el primer idioma disponible como fallback.</p>
7379
+ </div>
7380
+
7381
+ <div class="component-analysis">
7382
+ <h3>Análisis del Componente:</h3>
7383
+ <button (click)="analyzeCurrentComponent()">Analizar Contenido</button>
7384
+ <div *ngIf="analysisResults" class="analysis-results">
7385
+ <p>
7386
+ <strong>Idiomas disponibles para este componente:</strong>
7387
+ {{ analysisResults.availableLanguages.join(', ') }}
7388
+ </p>
7389
+ <div *ngIf="analysisResults.missingKeys.length > 0">
7390
+ <p>
7391
+ <strong>Claves faltantes en {{ langService.currentLang }}:</strong>
7392
+ </p>
7393
+ <ul>
7394
+ <li *ngFor="let key of analysisResults.missingKeys">{{ key }}</li>
7395
+ </ul>
7396
+ </div>
7397
+ </div>
7398
+ </div>
7399
+ </div>
7400
+ `, isInline: true, styles: [".multi-lang-demo{padding:20px;max-width:800px}.language-info,.content-examples,.warning-info,.component-analysis{margin:20px 0;padding:15px;border:1px solid var(--ion-color-light, #f4f5f8);border-radius:8px;background:var(--ion-color-light-tint, #f5f6f9)}.button-group{display:flex;gap:10px;flex-wrap:wrap}.button-group button{padding:8px 16px;border:1px solid var(--ion-color-primary, #3880ff);background:#fff;color:var(--ion-color-primary, #3880ff);border-radius:4px;cursor:pointer;transition:all .2s}.button-group button:hover{background:var(--ion-color-primary-tint, #4992ff);color:#fff}.button-group button.active{background:var(--ion-color-primary, #3880ff);color:#fff}.example-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:10px;margin-top:10px}.analysis-results{margin-top:10px;padding:10px;background:#fff;border-radius:4px}h2{color:var(--ion-color-primary, #3880ff)}h3{color:var(--ion-color-dark, #222428);margin-bottom:10px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }] }); }
7401
+ }
7402
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MultiLanguageDemoComponent, decorators: [{
7403
+ type: Component,
7404
+ args: [{ selector: 'val-multi-language-demo', standalone: true, imports: [CommonModule, TextComponent, ButtonComponent], template: `
7405
+ <div class="multi-lang-demo">
7406
+ <h2>Sistema de Idiomas Flexible</h2>
7407
+
7408
+ <div class="language-info">
7409
+ <h3>Información del Sistema:</h3>
7410
+ <p><strong>Idioma actual:</strong> {{ langService.currentLang }}</p>
7411
+ <p><strong>Idioma por defecto:</strong> {{ langService.defaultLanguage }}</p>
7412
+ <p><strong>Idiomas disponibles:</strong> {{ langService.availableLangs.join(', ') }}</p>
7413
+ </div>
7414
+
7415
+ <div class="language-switcher">
7416
+ <h3>Cambiar Idioma:</h3>
7417
+ <div class="button-group">
7418
+ <button
7419
+ *ngFor="let lang of availableLanguages"
7420
+ [class.active]="lang === langService.currentLang"
7421
+ (click)="switchLanguage(lang)"
7422
+ >
7423
+ {{ getLanguageName(lang) }}
7424
+ </button>
7425
+ <!-- Ejemplo de idioma no disponible -->
7426
+ <button (click)="switchLanguage('pt')">Português (no disponible)</button>
7427
+ </div>
7428
+ </div>
7429
+
7430
+ <div class="content-examples">
7431
+ <h3>Contenido Global:</h3>
7432
+ <div class="example-grid">
7433
+ <val-text
7434
+ [props]="{ content: okButton$ | async, size: 'medium', color: 'dark', bold: false, processLinks: false }"
7435
+ ></val-text>
7436
+ <val-text
7437
+ [props]="{
7438
+ content: cancelButton$ | async,
7439
+ size: 'medium',
7440
+ color: 'dark',
7441
+ bold: false,
7442
+ processLinks: false,
7443
+ }"
7444
+ ></val-text>
7445
+ <val-text
7446
+ [props]="{ content: saveButton$ | async, size: 'medium', color: 'dark', bold: false, processLinks: false }"
7447
+ ></val-text>
7448
+ <val-text
7449
+ [props]="{
7450
+ content: deleteButton$ | async,
7451
+ size: 'medium',
7452
+ color: 'dark',
7453
+ bold: false,
7454
+ processLinks: false,
7455
+ }"
7456
+ ></val-text>
7457
+ </div>
7458
+
7459
+ <h3>Contenido con Fallback (algunas traducciones faltantes):</h3>
7460
+ <div class="example-grid">
7461
+ <val-text
7462
+ [props]="{ content: nextButton$ | async, size: 'medium', color: 'dark', bold: false, processLinks: false }"
7463
+ ></val-text>
7464
+ <val-text
7465
+ [props]="{
7466
+ content: finishButton$ | async,
7467
+ size: 'medium',
7468
+ color: 'dark',
7469
+ bold: false,
7470
+ processLinks: false,
7471
+ }"
7472
+ ></val-text>
7473
+ <val-text
7474
+ [props]="{
7475
+ content: searchPlaceholder$ | async,
7476
+ size: 'medium',
7477
+ color: 'dark',
7478
+ bold: false,
7479
+ processLinks: false,
7480
+ }"
7481
+ ></val-text>
7482
+ <val-text
7483
+ [props]="{
7484
+ content: noDataMessage$ | async,
7485
+ size: 'medium',
7486
+ color: 'dark',
7487
+ bold: false,
7488
+ processLinks: false,
7489
+ }"
7490
+ ></val-text>
7491
+ </div>
7492
+ </div>
7493
+
7494
+ <div class="warning-info">
7495
+ <h3>Información de Warnings:</h3>
7496
+ <p>
7497
+ Abre la consola del navegador para ver los warnings cuando cambies a idiomas con traducciones incompletas
7498
+ (francés, alemán).
7499
+ </p>
7500
+ <p>El sistema automáticamente usará el idioma por defecto o el primer idioma disponible como fallback.</p>
7501
+ </div>
7502
+
7503
+ <div class="component-analysis">
7504
+ <h3>Análisis del Componente:</h3>
7505
+ <button (click)="analyzeCurrentComponent()">Analizar Contenido</button>
7506
+ <div *ngIf="analysisResults" class="analysis-results">
7507
+ <p>
7508
+ <strong>Idiomas disponibles para este componente:</strong>
7509
+ {{ analysisResults.availableLanguages.join(', ') }}
7510
+ </p>
7511
+ <div *ngIf="analysisResults.missingKeys.length > 0">
7512
+ <p>
7513
+ <strong>Claves faltantes en {{ langService.currentLang }}:</strong>
7514
+ </p>
7515
+ <ul>
7516
+ <li *ngFor="let key of analysisResults.missingKeys">{{ key }}</li>
7517
+ </ul>
7518
+ </div>
7519
+ </div>
7520
+ </div>
7521
+ </div>
7522
+ `, styles: [".multi-lang-demo{padding:20px;max-width:800px}.language-info,.content-examples,.warning-info,.component-analysis{margin:20px 0;padding:15px;border:1px solid var(--ion-color-light, #f4f5f8);border-radius:8px;background:var(--ion-color-light-tint, #f5f6f9)}.button-group{display:flex;gap:10px;flex-wrap:wrap}.button-group button{padding:8px 16px;border:1px solid var(--ion-color-primary, #3880ff);background:#fff;color:var(--ion-color-primary, #3880ff);border-radius:4px;cursor:pointer;transition:all .2s}.button-group button:hover{background:var(--ion-color-primary-tint, #4992ff);color:#fff}.button-group button.active{background:var(--ion-color-primary, #3880ff);color:#fff}.example-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:10px;margin-top:10px}.analysis-results{margin-top:10px;padding:10px;background:#fff;border-radius:4px}h2{color:var(--ion-color-primary, #3880ff)}h3{color:var(--ion-color-dark, #222428);margin-bottom:10px}\n"] }]
7523
+ }], ctorParameters: () => [{ type: ContentService }, { type: LangService }] });
7524
+
7035
7525
  const text = {
7036
7526
  es: {
7037
7527
  spanish: 'Español',
@@ -7047,7 +7537,10 @@ var LangSettings = new TextContent(text);
7047
7537
  /**
7048
7538
  * Global content that can be used across all components.
7049
7539
  * These are common texts like buttons, actions, states, etc.
7050
- * Structure: {es: {key1: 'value1', key2: 'value2'}, en: {key1: 'value1', key2: 'value2'}}
7540
+ * Structure: {es: {key1: 'value1', key2: 'value2'}, en: {key1: 'value1', key2: 'value2'}, fr: {...}}
7541
+ *
7542
+ * Note: You can add any language code. The system will automatically detect available languages
7543
+ * and provide intelligent fallbacks with warnings for missing translations.
7051
7544
  */
7052
7545
  const globalContentData = {
7053
7546
  es: {
@@ -7118,6 +7611,34 @@ const globalContentData = {
7118
7611
  // Common placeholders
7119
7612
  searchPlaceholder: 'Search...',
7120
7613
  },
7614
+ fr: {
7615
+ // Common buttons - Example of partial translation (missing some keys intentionally)
7616
+ ok: 'OK',
7617
+ cancel: 'Annuler',
7618
+ save: 'Sauvegarder',
7619
+ delete: 'Supprimer',
7620
+ edit: 'Modifier',
7621
+ close: 'Fermer',
7622
+ back: 'Retour',
7623
+ // Common states and messages (intentionally incomplete to show fallback behavior)
7624
+ loading: 'Chargement...',
7625
+ error: 'Erreur',
7626
+ success: 'Succès',
7627
+ // Common confirmations
7628
+ areYouSure: 'Êtes-vous sûr?',
7629
+ },
7630
+ de: {
7631
+ // Common buttons - Another example of partial translation
7632
+ ok: 'OK',
7633
+ cancel: 'Abbrechen',
7634
+ save: 'Speichern',
7635
+ delete: 'Löschen',
7636
+ // Common states and messages
7637
+ loading: 'Laden...',
7638
+ error: 'Fehler',
7639
+ // Common confirmations
7640
+ areYouSure: 'Sind Sie sicher?',
7641
+ },
7121
7642
  };
7122
7643
  const GlobalContent = new TextContent(globalContentData);
7123
7644
  const content = {
@@ -7180,5 +7701,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
7180
7701
  * Generated bundle index. Do not edit.
7181
7702
  */
7182
7703
 
7183
- export { ActionType, AlertBoxComponent, AvatarComponent, BannerComponent, BaseDefault, BoxComponent, ButtonComponent, ButtonGroupComponent, CardComponent, CardSection, CardType, CheckInputComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CommentInputComponent, ComponentStates, ComprehensiveLinkTestComponent, ContentLoaderComponent, ContentService, CustomContentDemoComponent, DateInputComponent, DisplayComponent, DividerComponent, DownloadService, EmailInputComponent, ExpandableTextComponent, FileInputComponent, FooterComponent, FormComponent, FormFooterComponent, GlobalContent, HeaderComponent, HintComponent, HourInputComponent, HrefComponent, Icon, IconComponent, IconService, ImageComponent, InAppBrowserService, InputType, ItemListComponent, LangOption, LangService, LayeredCardComponent, LayoutComponent, LinkComponent, LinkProcessingExampleComponent, LinkProcessorService, LinksCakeComponent, LocalStorageService, MOTION, NavigationService, NoContentComponent, NotesBoxComponent, NumberInputComponent, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PasswordInputComponent, PinInputComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProgressBarComponent, ProgressStatusComponent, PrompterComponent, RadioInputComponent, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SelectSearchComponent, SimpleComponent, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, TextComponent, TextContent, TextInputComponent, ThemeOption, ThemeService, TitleBlockComponent, TitleComponent, ToastService, ToolbarActionType, ToolbarComponent, ValtechConfigService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, content, createContentHelper, createTextProps, fromContent, fromContentWithInterpolation, fromMultipleContent, globalContentData, goToTop, interpolateContent, isAtEnd, maxLength, replaceSpecialChars, resolveColor, resolveInputDefaultValue };
7704
+ export { ActionType, AlertBoxComponent, AvatarComponent, BannerComponent, BaseDefault, BoxComponent, ButtonComponent, ButtonGroupComponent, CardComponent, CardSection, CardType, CheckInputComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CommentInputComponent, ComponentStates, ComprehensiveLinkTestComponent, ContentLoaderComponent, ContentService, CustomContentDemoComponent, DateInputComponent, DisplayComponent, DividerComponent, DownloadService, EmailInputComponent, ExpandableTextComponent, FileInputComponent, FooterComponent, FormComponent, FormFooterComponent, GlobalContent, HeaderComponent, HintComponent, HourInputComponent, HrefComponent, Icon, IconComponent, IconService, ImageComponent, InAppBrowserService, InputType, ItemListComponent, LANGUAGES, LangService, LayeredCardComponent, LayoutComponent, LinkComponent, LinkProcessingExampleComponent, LinkProcessorService, LinksCakeComponent, LocalStorageService, MOTION, MultiLanguageDemoComponent, NavigationService, NoContentComponent, NotesBoxComponent, NumberInputComponent, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PasswordInputComponent, PinInputComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProgressBarComponent, ProgressStatusComponent, PrompterComponent, RadioInputComponent, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SelectSearchComponent, SimpleComponent, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, TextComponent, TextContent, TextInputComponent, ThemeOption, ThemeService, TitleBlockComponent, TitleComponent, ToastService, ToolbarActionType, ToolbarComponent, ValtechConfigService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, content, createContentHelper, createTextProps, fromContent, fromContentWithInterpolation, fromMultipleContent, globalContentData, goToTop, interpolateContent, isAtEnd, maxLength, replaceSpecialChars, resolveColor, resolveInputDefaultValue };
7184
7705
  //# sourceMappingURL=valtech-components.mjs.map