valtech-components 2.0.290 → 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.
- package/esm2022/lib/examples/comprehensive-link-test.component.mjs +208 -0
- package/esm2022/lib/examples/custom-content-demo.component.mjs +3 -3
- package/esm2022/lib/examples/link-processing-example.component.mjs +26 -4
- package/esm2022/lib/examples/multi-language-demo.component.mjs +304 -0
- package/esm2022/lib/services/lang-provider/content.mjs +33 -2
- package/esm2022/lib/services/lang-provider/lang-provider.service.mjs +199 -13
- package/esm2022/lib/services/lang-provider/types.mjs +15 -6
- package/esm2022/lib/services/link-processor.service.mjs +70 -27
- package/esm2022/public-api.mjs +3 -1
- package/fesm2022/valtech-components.mjs +839 -48
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/examples/comprehensive-link-test.component.d.ts +23 -0
- package/lib/examples/link-processing-example.component.d.ts +1 -0
- package/lib/examples/multi-language-demo.component.d.ts +34 -0
- package/lib/services/lang-provider/content.d.ts +4 -1
- package/lib/services/lang-provider/lang-provider.service.d.ts +64 -2
- package/lib/services/lang-provider/types.d.ts +19 -4
- package/lib/services/link-processor.service.d.ts +6 -0
- package/package.json +1 -1
- package/public-api.d.ts +2 -0
- package/src/lib/components/styles/overrides.scss +2 -2
|
@@ -1024,13 +1024,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
1024
1024
|
class LinkProcessorService {
|
|
1025
1025
|
constructor(sanitizer) {
|
|
1026
1026
|
this.sanitizer = sanitizer;
|
|
1027
|
-
// Regex para detectar URLs completas (http/https) -
|
|
1028
|
-
this.urlRegex = /(https?:\/\/[^\s]
|
|
1029
|
-
// Regex para detectar rutas internas
|
|
1030
|
-
this.internalRouteRegex = /(\s|^)(\/[^\s]
|
|
1027
|
+
// Regex para detectar URLs completas (http/https) - captura toda la URL y luego limpiamos puntuación
|
|
1028
|
+
this.urlRegex = /(https?:\/\/[^\s]+)/g;
|
|
1029
|
+
// Regex para detectar rutas internas - captura toda la ruta y luego limpiamos puntuación
|
|
1030
|
+
this.internalRouteRegex = /(\s|^)(\/[^\s]*)/g;
|
|
1031
1031
|
// Regex para detectar enlaces estilo Markdown [texto](url)
|
|
1032
1032
|
this.markdownLinkRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
|
|
1033
1033
|
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Limpia la puntuación del final de una URL.
|
|
1036
|
+
* Mantiene caracteres válidos de URL pero remueve signos de puntuación comunes al final.
|
|
1037
|
+
* Preserva parámetros de consulta, fragmentos y caracteres válidos en URLs.
|
|
1038
|
+
*/
|
|
1039
|
+
cleanUrlPunctuation(url) {
|
|
1040
|
+
// Caracteres que consideramos puntuación al final de oración, pero NO parte de URLs
|
|
1041
|
+
// No incluimos & o = que son parte de query params, ni # que es parte de fragmentos
|
|
1042
|
+
const trailingPunctuation = /[.,;!?)]+$/;
|
|
1043
|
+
// Casos especiales: si la URL termina con paréntesis pero no tiene paréntesis de apertura
|
|
1044
|
+
// probablemente el paréntesis no es parte de la URL
|
|
1045
|
+
const hasOpeningParen = url.includes('(');
|
|
1046
|
+
const endsWithClosingParen = url.endsWith(')');
|
|
1047
|
+
if (endsWithClosingParen && !hasOpeningParen) {
|
|
1048
|
+
// Remover el paréntesis de cierre si no hay uno de apertura
|
|
1049
|
+
url = url.replace(/\)$/, '');
|
|
1050
|
+
}
|
|
1051
|
+
return url.replace(trailingPunctuation, '');
|
|
1052
|
+
}
|
|
1034
1053
|
/**
|
|
1035
1054
|
* Procesa texto para convertir enlaces en elementos <a> clickeables.
|
|
1036
1055
|
* Detecta automáticamente URLs externas, rutas internas y enlaces estilo Markdown.
|
|
@@ -1060,8 +1079,13 @@ class LinkProcessorService {
|
|
|
1060
1079
|
let processedText = text;
|
|
1061
1080
|
// 1. Procesar enlaces estilo Markdown [texto](url) primero
|
|
1062
1081
|
if (processMarkdownLinks) {
|
|
1063
|
-
this.markdownLinkRegex
|
|
1064
|
-
|
|
1082
|
+
const markdownMatches = Array.from(processedText.matchAll(this.markdownLinkRegex));
|
|
1083
|
+
// Procesar de atrás hacia adelante para mantener las posiciones
|
|
1084
|
+
for (let i = markdownMatches.length - 1; i >= 0; i--) {
|
|
1085
|
+
const match = markdownMatches[i];
|
|
1086
|
+
const [fullMatch, linkText, url] = match;
|
|
1087
|
+
const startIndex = match.index;
|
|
1088
|
+
const endIndex = startIndex + fullMatch.length;
|
|
1065
1089
|
hasLinks = true;
|
|
1066
1090
|
const isExternal = /^https?:\/\//.test(url);
|
|
1067
1091
|
const target = (isExternal ? openExternalInNewTab : openInternalInNewTab)
|
|
@@ -1071,45 +1095,64 @@ class LinkProcessorService {
|
|
|
1071
1095
|
: '';
|
|
1072
1096
|
const typeClass = isExternal ? externalLinkClass : internalLinkClass;
|
|
1073
1097
|
const classes = `${linkClass} ${typeClass}`.trim();
|
|
1074
|
-
|
|
1075
|
-
|
|
1098
|
+
const linkHtml = `<a href="${url}"${target} class="${classes}">${linkText}</a>`;
|
|
1099
|
+
processedText =
|
|
1100
|
+
processedText.substring(0, startIndex) + linkHtml + processedText.substring(endIndex);
|
|
1101
|
+
}
|
|
1076
1102
|
}
|
|
1077
|
-
// 2. Procesar URLs externas directas
|
|
1078
|
-
this.urlRegex
|
|
1079
|
-
|
|
1103
|
+
// 2. Procesar URLs externas directas
|
|
1104
|
+
const urlMatches = Array.from(processedText.matchAll(this.urlRegex));
|
|
1105
|
+
// Procesar de atrás hacia adelante para mantener las posiciones
|
|
1106
|
+
for (let i = urlMatches.length - 1; i >= 0; i--) {
|
|
1107
|
+
const match = urlMatches[i];
|
|
1108
|
+
const [fullMatch, url] = match;
|
|
1109
|
+
const startIndex = match.index;
|
|
1110
|
+
const endIndex = startIndex + fullMatch.length;
|
|
1080
1111
|
// Verificar que no esté ya dentro de un enlace HTML existente
|
|
1081
|
-
const
|
|
1082
|
-
const textBefore = processedText.substring(0, urlPosition);
|
|
1083
|
-
// Buscar la última apertura y cierre de enlace antes de esta posición
|
|
1112
|
+
const textBefore = processedText.substring(0, startIndex);
|
|
1084
1113
|
const lastOpenTag = textBefore.lastIndexOf('<a ');
|
|
1085
1114
|
const lastCloseTag = textBefore.lastIndexOf('</a>');
|
|
1086
1115
|
// Si hay un tag <a abierto sin cerrar, no procesamos
|
|
1087
1116
|
if (lastOpenTag > lastCloseTag) {
|
|
1088
|
-
|
|
1117
|
+
continue;
|
|
1089
1118
|
}
|
|
1119
|
+
// Limpiar puntuación del final de la URL
|
|
1120
|
+
const cleanUrl = this.cleanUrlPunctuation(url);
|
|
1121
|
+
const punctuationRemoved = url !== cleanUrl;
|
|
1122
|
+
const punctuation = punctuationRemoved ? url.substring(cleanUrl.length) : '';
|
|
1090
1123
|
hasLinks = true;
|
|
1091
1124
|
const target = openExternalInNewTab ? ' target="_blank" rel="noopener noreferrer"' : '';
|
|
1092
1125
|
const classes = `${linkClass} ${externalLinkClass}`.trim();
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1126
|
+
const linkHtml = `<a href="${cleanUrl}"${target} class="${classes}">${cleanUrl}</a>`;
|
|
1127
|
+
// Reemplazar el URL original con el enlace + puntuación si existía
|
|
1128
|
+
const replacement = punctuationRemoved ? linkHtml + punctuation : linkHtml;
|
|
1129
|
+
processedText =
|
|
1130
|
+
processedText.substring(0, startIndex) + replacement + processedText.substring(endIndex);
|
|
1131
|
+
}
|
|
1132
|
+
// 3. Procesar rutas internas
|
|
1133
|
+
const internalMatches = Array.from(processedText.matchAll(this.internalRouteRegex));
|
|
1134
|
+
// Procesar de atrás hacia adelante para mantener las posiciones
|
|
1135
|
+
for (let i = internalMatches.length - 1; i >= 0; i--) {
|
|
1136
|
+
const match = internalMatches[i];
|
|
1137
|
+
const [fullMatch, prefix, route] = match;
|
|
1138
|
+
const startIndex = match.index;
|
|
1139
|
+
const endIndex = startIndex + fullMatch.length;
|
|
1098
1140
|
// Verificar que no esté ya dentro de un enlace HTML existente
|
|
1099
|
-
const
|
|
1100
|
-
const textBefore = processedText.substring(0, matchPosition);
|
|
1101
|
-
// Buscar la última apertura y cierre de enlace antes de esta posición
|
|
1141
|
+
const textBefore = processedText.substring(0, startIndex);
|
|
1102
1142
|
const lastOpenTag = textBefore.lastIndexOf('<a ');
|
|
1103
1143
|
const lastCloseTag = textBefore.lastIndexOf('</a>');
|
|
1104
1144
|
// Si hay un tag <a abierto sin cerrar, no procesamos
|
|
1105
1145
|
if (lastOpenTag > lastCloseTag) {
|
|
1106
|
-
|
|
1146
|
+
continue;
|
|
1107
1147
|
}
|
|
1108
1148
|
hasLinks = true;
|
|
1109
1149
|
const target = openInternalInNewTab ? ' target="_blank"' : '';
|
|
1110
1150
|
const classes = `${linkClass} ${internalLinkClass}`.trim();
|
|
1111
|
-
|
|
1112
|
-
|
|
1151
|
+
const linkHtml = `<a href="${route}"${target} class="${classes}">${route}</a>`;
|
|
1152
|
+
const replacement = `${prefix}${linkHtml}`;
|
|
1153
|
+
processedText =
|
|
1154
|
+
processedText.substring(0, startIndex) + replacement + processedText.substring(endIndex);
|
|
1155
|
+
}
|
|
1113
1156
|
// Si hay enlaces, sanitizar el HTML
|
|
1114
1157
|
if (hasLinks) {
|
|
1115
1158
|
return this.sanitizer.bypassSecurityTrustHtml(processedText);
|
|
@@ -1500,11 +1543,20 @@ class TextContent {
|
|
|
1500
1543
|
return this.text;
|
|
1501
1544
|
}
|
|
1502
1545
|
}
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
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
|
+
};
|
|
1508
1560
|
|
|
1509
1561
|
/**
|
|
1510
1562
|
* LangService - Reactive language and content management service.
|
|
@@ -1512,6 +1564,9 @@ var LangOption;
|
|
|
1512
1564
|
* This service provides reactive content management with Observable-based language switching.
|
|
1513
1565
|
* Components can subscribe to content changes and automatically update when the language changes.
|
|
1514
1566
|
*
|
|
1567
|
+
* The service automatically detects available languages from the content configuration
|
|
1568
|
+
* and provides intelligent fallbacks with console warnings for missing translations.
|
|
1569
|
+
*
|
|
1515
1570
|
* @example Basic usage:
|
|
1516
1571
|
* ```typescript
|
|
1517
1572
|
* constructor(private langService: LangService) {}
|
|
@@ -1531,12 +1586,120 @@ var LangOption;
|
|
|
1531
1586
|
*/
|
|
1532
1587
|
class LangService {
|
|
1533
1588
|
constructor(config) {
|
|
1534
|
-
this.
|
|
1535
|
-
|
|
1589
|
+
this.availableLanguages = [];
|
|
1590
|
+
this.warnedMissingLanguages = new Set();
|
|
1591
|
+
console.log('LangService: Injected config:', config);
|
|
1536
1592
|
this.content = config.content;
|
|
1537
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
|
|
1538
1599
|
const current = LocalStorageService.get(LANG);
|
|
1539
|
-
|
|
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
|
+
};
|
|
1540
1703
|
}
|
|
1541
1704
|
/**
|
|
1542
1705
|
* Observable that emits the current language whenever it changes.
|
|
@@ -1551,13 +1714,32 @@ class LangService {
|
|
|
1551
1714
|
get currentLang() {
|
|
1552
1715
|
return this.selectedLang.value;
|
|
1553
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
|
+
}
|
|
1554
1729
|
/**
|
|
1555
1730
|
* Set the current language and persist it to localStorage.
|
|
1556
1731
|
* This will trigger updates in all reactive content subscriptions.
|
|
1557
1732
|
*
|
|
1733
|
+
* Validates that the language is available and warns if not.
|
|
1734
|
+
*
|
|
1558
1735
|
* @param lang - The language to set
|
|
1559
1736
|
*/
|
|
1560
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
|
+
}
|
|
1561
1743
|
this.selectedLang.next(lang);
|
|
1562
1744
|
LocalStorageService.set(LANG, lang);
|
|
1563
1745
|
}
|
|
@@ -1567,10 +1749,12 @@ class LangService {
|
|
|
1567
1749
|
* @deprecated Use getText() or getContent() for better type safety
|
|
1568
1750
|
*/
|
|
1569
1751
|
Text(className) {
|
|
1570
|
-
|
|
1752
|
+
const componentContent = this.content[className];
|
|
1753
|
+
return componentContent?.Content[this.selectedLang.value] || {};
|
|
1571
1754
|
}
|
|
1572
1755
|
/**
|
|
1573
1756
|
* Get a single content string synchronously for the current language.
|
|
1757
|
+
* Provides intelligent fallback with warnings for missing translations.
|
|
1574
1758
|
*
|
|
1575
1759
|
* @param className - The component class name
|
|
1576
1760
|
* @param key - The text key
|
|
@@ -1578,12 +1762,16 @@ class LangService {
|
|
|
1578
1762
|
* @returns The text string or fallback
|
|
1579
1763
|
*/
|
|
1580
1764
|
getText(className, key, fallback) {
|
|
1581
|
-
const
|
|
1582
|
-
|
|
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}]`;
|
|
1583
1770
|
}
|
|
1584
1771
|
/**
|
|
1585
1772
|
* Get a reactive Observable for a specific text key that updates when language changes.
|
|
1586
1773
|
* This is the recommended method for components that need reactive content.
|
|
1774
|
+
* Provides intelligent fallback with warnings for missing translations.
|
|
1587
1775
|
*
|
|
1588
1776
|
* @param className - The component class name
|
|
1589
1777
|
* @param key - The text key
|
|
@@ -1592,12 +1780,16 @@ class LangService {
|
|
|
1592
1780
|
*/
|
|
1593
1781
|
getContent(className, key, fallback) {
|
|
1594
1782
|
return this.currentLang$.pipe(map(lang => {
|
|
1595
|
-
const
|
|
1596
|
-
|
|
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}]`;
|
|
1597
1788
|
}), distinctUntilChanged());
|
|
1598
1789
|
}
|
|
1599
1790
|
/**
|
|
1600
1791
|
* Get reactive content for multiple keys at once.
|
|
1792
|
+
* Provides intelligent fallback with warnings for missing translations.
|
|
1601
1793
|
*
|
|
1602
1794
|
* @param className - The component class name
|
|
1603
1795
|
* @param keys - Array of text keys to retrieve
|
|
@@ -1605,16 +1797,19 @@ class LangService {
|
|
|
1605
1797
|
*/
|
|
1606
1798
|
getMultipleContent(className, keys) {
|
|
1607
1799
|
return this.currentLang$.pipe(map(lang => {
|
|
1608
|
-
const classContent = this.content[className]?.Content[lang] || {};
|
|
1609
1800
|
const result = {};
|
|
1610
1801
|
keys.forEach(key => {
|
|
1611
|
-
|
|
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}]`;
|
|
1612
1807
|
});
|
|
1613
1808
|
return result;
|
|
1614
1809
|
}), distinctUntilChanged((prev, curr) => JSON.stringify(prev) === JSON.stringify(curr)));
|
|
1615
1810
|
}
|
|
1616
1811
|
/**
|
|
1617
|
-
* Check if a content key exists for a component.
|
|
1812
|
+
* Check if a content key exists for a component in any available language.
|
|
1618
1813
|
*
|
|
1619
1814
|
* @param className - The component class name
|
|
1620
1815
|
* @param key - The text key
|
|
@@ -1626,6 +1821,49 @@ class LangService {
|
|
|
1626
1821
|
return false;
|
|
1627
1822
|
return Object.values(classContent.Content).some(langContent => langContent && typeof langContent[key] === 'string');
|
|
1628
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
|
+
}
|
|
1629
1867
|
// Legacy getters/setters for backward compatibility
|
|
1630
1868
|
get Lang() {
|
|
1631
1869
|
return this.currentLang;
|
|
@@ -6270,6 +6508,211 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
6270
6508
|
type: Output
|
|
6271
6509
|
}] } });
|
|
6272
6510
|
|
|
6511
|
+
/**
|
|
6512
|
+
* ComprehensiveLinkTestComponent - Componente de prueba exhaustiva para el procesamiento de enlaces.
|
|
6513
|
+
*
|
|
6514
|
+
* Este componente demuestra todos los casos edge y escenarios complejos de procesamiento de enlaces,
|
|
6515
|
+
* incluyendo puntuación, URLs complejas, y mezclas de formatos.
|
|
6516
|
+
*
|
|
6517
|
+
* @example Uso en template:
|
|
6518
|
+
* ```html
|
|
6519
|
+
* <val-comprehensive-link-test></val-comprehensive-link-test>
|
|
6520
|
+
* ```
|
|
6521
|
+
*/
|
|
6522
|
+
class ComprehensiveLinkTestComponent {
|
|
6523
|
+
constructor() {
|
|
6524
|
+
this.punctuationProps = {
|
|
6525
|
+
content: 'Diferentes puntuaciones: https://angular.io, también https://github.com! ¿Conoces https://typescript.org? Final: https://rxjs.dev. Entre paréntesis (https://zone.js) y con comillas "https://ionic.io".',
|
|
6526
|
+
size: 'medium',
|
|
6527
|
+
color: 'dark',
|
|
6528
|
+
bold: false,
|
|
6529
|
+
processLinks: true,
|
|
6530
|
+
linkConfig: {
|
|
6531
|
+
openExternalInNewTab: true,
|
|
6532
|
+
linkClass: 'test-punctuation',
|
|
6533
|
+
externalLinkClass: 'test-external',
|
|
6534
|
+
},
|
|
6535
|
+
};
|
|
6536
|
+
this.complexUrlProps = {
|
|
6537
|
+
content: 'URLs complejas: https://api.github.com/repos/angular/angular/issues?state=open&sort=updated&per_page=50, búsqueda https://google.com/search?q=angular+ionic+components#results, y documentación https://angular.io/guide/getting-started#development-environment.',
|
|
6538
|
+
size: 'medium',
|
|
6539
|
+
color: 'dark',
|
|
6540
|
+
bold: false,
|
|
6541
|
+
processLinks: true,
|
|
6542
|
+
linkConfig: {
|
|
6543
|
+
openExternalInNewTab: true,
|
|
6544
|
+
linkClass: 'test-complex',
|
|
6545
|
+
externalLinkClass: 'test-external',
|
|
6546
|
+
},
|
|
6547
|
+
};
|
|
6548
|
+
this.parenthesesProps = {
|
|
6549
|
+
content: 'Paréntesis de contexto (ver https://docs.angular.io) vs URLs con paréntesis https://example.com/api/method(param) en el contenido. También funciona (https://ionic.io/docs).',
|
|
6550
|
+
size: 'medium',
|
|
6551
|
+
color: 'dark',
|
|
6552
|
+
bold: false,
|
|
6553
|
+
processLinks: true,
|
|
6554
|
+
linkConfig: {
|
|
6555
|
+
openExternalInNewTab: true,
|
|
6556
|
+
linkClass: 'test-parentheses',
|
|
6557
|
+
externalLinkClass: 'test-external',
|
|
6558
|
+
},
|
|
6559
|
+
};
|
|
6560
|
+
this.mixedFormatsProps = {
|
|
6561
|
+
content: 'Formatos mezclados: [Documentación oficial](https://angular.io/docs), enlace directo https://github.com/angular/angular, ruta interna /dashboard/settings, [guía de inicio](/getting-started), y API https://api.example.com/v1/users?active=true.',
|
|
6562
|
+
size: 'medium',
|
|
6563
|
+
color: 'dark',
|
|
6564
|
+
bold: false,
|
|
6565
|
+
processLinks: true,
|
|
6566
|
+
linkConfig: {
|
|
6567
|
+
openExternalInNewTab: true,
|
|
6568
|
+
openInternalInNewTab: false,
|
|
6569
|
+
processMarkdownLinks: true,
|
|
6570
|
+
linkClass: 'test-mixed',
|
|
6571
|
+
externalLinkClass: 'test-external',
|
|
6572
|
+
internalLinkClass: 'test-internal',
|
|
6573
|
+
},
|
|
6574
|
+
};
|
|
6575
|
+
this.edgeCasesProps = {
|
|
6576
|
+
content: 'Casos extremos: "https://quoted-url.com", múltiple puntuación https://example.com?!!, URL al final de oración https://final-url.org. También consecutivos: https://first.com y https://second.com.',
|
|
6577
|
+
size: 'medium',
|
|
6578
|
+
color: 'dark',
|
|
6579
|
+
bold: false,
|
|
6580
|
+
processLinks: true,
|
|
6581
|
+
linkConfig: {
|
|
6582
|
+
openExternalInNewTab: true,
|
|
6583
|
+
linkClass: 'test-edge',
|
|
6584
|
+
externalLinkClass: 'test-external',
|
|
6585
|
+
},
|
|
6586
|
+
};
|
|
6587
|
+
this.devUrlsProps = {
|
|
6588
|
+
content: 'URLs de desarrollo: http://localhost:4200/dashboard, servidor local https://127.0.0.1:8080/api/status, desarrollo http://dev.example.com:3000/debug?verbose=true, y túnel https://abc123.ngrok.io/webhook.',
|
|
6589
|
+
size: 'medium',
|
|
6590
|
+
color: 'dark',
|
|
6591
|
+
bold: false,
|
|
6592
|
+
processLinks: true,
|
|
6593
|
+
linkConfig: {
|
|
6594
|
+
openExternalInNewTab: false, // Para desarrollo, puede ser útil no abrir en nueva pestaña
|
|
6595
|
+
linkClass: 'test-dev',
|
|
6596
|
+
externalLinkClass: 'test-dev-external',
|
|
6597
|
+
},
|
|
6598
|
+
};
|
|
6599
|
+
}
|
|
6600
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ComprehensiveLinkTestComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6601
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: ComprehensiveLinkTestComponent, isStandalone: true, selector: "val-comprehensive-link-test", ngImport: i0, template: `
|
|
6602
|
+
<div class="comprehensive-test">
|
|
6603
|
+
<h2>Prueba Exhaustiva de Procesamiento de Enlaces</h2>
|
|
6604
|
+
|
|
6605
|
+
<div class="test-section">
|
|
6606
|
+
<h3>✅ Puntuación Final - SOLUCIONADO</h3>
|
|
6607
|
+
<val-text [props]="punctuationProps"></val-text>
|
|
6608
|
+
<p class="note">
|
|
6609
|
+
<strong>Esperado:</strong> Los enlaces no incluyen puntuación final (.,;!?), pero la puntuación se preserva
|
|
6610
|
+
como texto después del enlace.
|
|
6611
|
+
</p>
|
|
6612
|
+
</div>
|
|
6613
|
+
|
|
6614
|
+
<div class="test-section">
|
|
6615
|
+
<h3>✅ URLs Complejas con Parámetros - SOLUCIONADO</h3>
|
|
6616
|
+
<val-text [props]="complexUrlProps"></val-text>
|
|
6617
|
+
<p class="note">
|
|
6618
|
+
<strong>Esperado:</strong> URLs con query params, fragmentos y rutas complejas se preservan completamente.
|
|
6619
|
+
</p>
|
|
6620
|
+
</div>
|
|
6621
|
+
|
|
6622
|
+
<div class="test-section">
|
|
6623
|
+
<h3>✅ Paréntesis Inteligentes - SOLUCIONADO</h3>
|
|
6624
|
+
<val-text [props]="parenthesesProps"></val-text>
|
|
6625
|
+
<p class="note">
|
|
6626
|
+
<strong>Esperado:</strong> Paréntesis de contexto (texto) vs paréntesis de URL se manejan correctamente.
|
|
6627
|
+
</p>
|
|
6628
|
+
</div>
|
|
6629
|
+
|
|
6630
|
+
<div class="test-section">
|
|
6631
|
+
<h3>✅ Mezcla de Formatos - SOLUCIONADO</h3>
|
|
6632
|
+
<val-text [props]="mixedFormatsProps"></val-text>
|
|
6633
|
+
<p class="note">
|
|
6634
|
+
<strong>Esperado:</strong> Enlaces Markdown, URLs directas y rutas internas coexisten sin conflictos.
|
|
6635
|
+
</p>
|
|
6636
|
+
</div>
|
|
6637
|
+
|
|
6638
|
+
<div class="test-section">
|
|
6639
|
+
<h3>✅ Casos Extremos - SOLUCIONADO</h3>
|
|
6640
|
+
<val-text [props]="edgeCasesProps"></val-text>
|
|
6641
|
+
<p class="note">
|
|
6642
|
+
<strong>Esperado:</strong> Comillas, múltiple puntuación, y URLs al final de oraciones se procesan
|
|
6643
|
+
correctamente.
|
|
6644
|
+
</p>
|
|
6645
|
+
</div>
|
|
6646
|
+
|
|
6647
|
+
<div class="test-section">
|
|
6648
|
+
<h3>✅ URLs de Desarrollo - SOLUCIONADO</h3>
|
|
6649
|
+
<val-text [props]="devUrlsProps"></val-text>
|
|
6650
|
+
<p class="note">
|
|
6651
|
+
<strong>Esperado:</strong> URLs de localhost, puertos, y rutas de desarrollo se detectan correctamente.
|
|
6652
|
+
</p>
|
|
6653
|
+
</div>
|
|
6654
|
+
</div>
|
|
6655
|
+
`, isInline: true, styles: [".comprehensive-test{padding:20px;max-width:1000px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.test-section{margin-bottom:32px;padding:20px;border:2px solid var(--ion-color-success, #2dd36f);border-radius:12px;background:var(--ion-color-success-tint, #42d77d) 10}h2{color:var(--ion-color-primary, #3880ff);margin-bottom:24px;text-align:center}h3{color:var(--ion-color-success, #2dd36f);margin-bottom:16px;font-size:18px;display:flex;align-items:center;gap:8px}.note{margin-top:12px;padding:12px;background:var(--ion-color-light, #f4f5f8);border-radius:8px;font-size:14px;color:var(--ion-color-medium, #92949c);border-left:4px solid var(--ion-color-primary, #3880ff)}.note strong{color:var(--ion-color-dark, #222428)}\n"], dependencies: [{ kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }] }); }
|
|
6656
|
+
}
|
|
6657
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ComprehensiveLinkTestComponent, decorators: [{
|
|
6658
|
+
type: Component,
|
|
6659
|
+
args: [{ selector: 'val-comprehensive-link-test', standalone: true, imports: [TextComponent], template: `
|
|
6660
|
+
<div class="comprehensive-test">
|
|
6661
|
+
<h2>Prueba Exhaustiva de Procesamiento de Enlaces</h2>
|
|
6662
|
+
|
|
6663
|
+
<div class="test-section">
|
|
6664
|
+
<h3>✅ Puntuación Final - SOLUCIONADO</h3>
|
|
6665
|
+
<val-text [props]="punctuationProps"></val-text>
|
|
6666
|
+
<p class="note">
|
|
6667
|
+
<strong>Esperado:</strong> Los enlaces no incluyen puntuación final (.,;!?), pero la puntuación se preserva
|
|
6668
|
+
como texto después del enlace.
|
|
6669
|
+
</p>
|
|
6670
|
+
</div>
|
|
6671
|
+
|
|
6672
|
+
<div class="test-section">
|
|
6673
|
+
<h3>✅ URLs Complejas con Parámetros - SOLUCIONADO</h3>
|
|
6674
|
+
<val-text [props]="complexUrlProps"></val-text>
|
|
6675
|
+
<p class="note">
|
|
6676
|
+
<strong>Esperado:</strong> URLs con query params, fragmentos y rutas complejas se preservan completamente.
|
|
6677
|
+
</p>
|
|
6678
|
+
</div>
|
|
6679
|
+
|
|
6680
|
+
<div class="test-section">
|
|
6681
|
+
<h3>✅ Paréntesis Inteligentes - SOLUCIONADO</h3>
|
|
6682
|
+
<val-text [props]="parenthesesProps"></val-text>
|
|
6683
|
+
<p class="note">
|
|
6684
|
+
<strong>Esperado:</strong> Paréntesis de contexto (texto) vs paréntesis de URL se manejan correctamente.
|
|
6685
|
+
</p>
|
|
6686
|
+
</div>
|
|
6687
|
+
|
|
6688
|
+
<div class="test-section">
|
|
6689
|
+
<h3>✅ Mezcla de Formatos - SOLUCIONADO</h3>
|
|
6690
|
+
<val-text [props]="mixedFormatsProps"></val-text>
|
|
6691
|
+
<p class="note">
|
|
6692
|
+
<strong>Esperado:</strong> Enlaces Markdown, URLs directas y rutas internas coexisten sin conflictos.
|
|
6693
|
+
</p>
|
|
6694
|
+
</div>
|
|
6695
|
+
|
|
6696
|
+
<div class="test-section">
|
|
6697
|
+
<h3>✅ Casos Extremos - SOLUCIONADO</h3>
|
|
6698
|
+
<val-text [props]="edgeCasesProps"></val-text>
|
|
6699
|
+
<p class="note">
|
|
6700
|
+
<strong>Esperado:</strong> Comillas, múltiple puntuación, y URLs al final de oraciones se procesan
|
|
6701
|
+
correctamente.
|
|
6702
|
+
</p>
|
|
6703
|
+
</div>
|
|
6704
|
+
|
|
6705
|
+
<div class="test-section">
|
|
6706
|
+
<h3>✅ URLs de Desarrollo - SOLUCIONADO</h3>
|
|
6707
|
+
<val-text [props]="devUrlsProps"></val-text>
|
|
6708
|
+
<p class="note">
|
|
6709
|
+
<strong>Esperado:</strong> URLs de localhost, puertos, y rutas de desarrollo se detectan correctamente.
|
|
6710
|
+
</p>
|
|
6711
|
+
</div>
|
|
6712
|
+
</div>
|
|
6713
|
+
`, styles: [".comprehensive-test{padding:20px;max-width:1000px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.test-section{margin-bottom:32px;padding:20px;border:2px solid var(--ion-color-success, #2dd36f);border-radius:12px;background:var(--ion-color-success-tint, #42d77d) 10}h2{color:var(--ion-color-primary, #3880ff);margin-bottom:24px;text-align:center}h3{color:var(--ion-color-success, #2dd36f);margin-bottom:16px;font-size:18px;display:flex;align-items:center;gap:8px}.note{margin-top:12px;padding:12px;background:var(--ion-color-light, #f4f5f8);border-radius:8px;font-size:14px;color:var(--ion-color-medium, #92949c);border-left:4px solid var(--ion-color-primary, #3880ff)}.note strong{color:var(--ion-color-dark, #222428)}\n"] }]
|
|
6714
|
+
}] });
|
|
6715
|
+
|
|
6273
6716
|
class CustomContentDemoComponent {
|
|
6274
6717
|
constructor() {
|
|
6275
6718
|
this.content = inject(ContentService);
|
|
@@ -6316,7 +6759,7 @@ class CustomContentDemoComponent {
|
|
|
6316
6759
|
this.diagnoseConfiguration();
|
|
6317
6760
|
}
|
|
6318
6761
|
switchLanguage() {
|
|
6319
|
-
const newLang = this.currentLang === 'es' ?
|
|
6762
|
+
const newLang = this.currentLang === 'es' ? LANGUAGES.EN : LANGUAGES.ES;
|
|
6320
6763
|
this.content.setLang(newLang);
|
|
6321
6764
|
// Actualizar textos síncronos después del cambio
|
|
6322
6765
|
setTimeout(() => {
|
|
@@ -6654,7 +7097,7 @@ class LinkProcessingExampleComponent {
|
|
|
6654
7097
|
},
|
|
6655
7098
|
};
|
|
6656
7099
|
this.punctuationTestProps = {
|
|
6657
|
-
content: 'URLs con puntuación: https://ionicframework.com/docs,
|
|
7100
|
+
content: 'URLs con puntuación final: https://ionicframework.com/docs, también https://angular.io! Pregunta sobre https://github.com/angular? Y punto final: https://typescript.org. Paréntesis (https://rxjs.dev) y comillas "https://zone.js". ¡Todos funcionan!',
|
|
6658
7101
|
size: 'medium',
|
|
6659
7102
|
color: 'dark',
|
|
6660
7103
|
bold: false,
|
|
@@ -6665,6 +7108,18 @@ class LinkProcessingExampleComponent {
|
|
|
6665
7108
|
externalLinkClass: 'external-punct',
|
|
6666
7109
|
},
|
|
6667
7110
|
};
|
|
7111
|
+
this.complexUrlsProps = {
|
|
7112
|
+
content: 'URLs complejas: https://example.com/path?param=value&other=123#section, búsqueda en https://google.com/search?q=angular+components, y API https://api.github.com/repos/owner/repo/issues?state=open. Todos con parámetros y fragmentos.',
|
|
7113
|
+
size: 'medium',
|
|
7114
|
+
color: 'dark',
|
|
7115
|
+
bold: false,
|
|
7116
|
+
processLinks: true,
|
|
7117
|
+
linkConfig: {
|
|
7118
|
+
openExternalInNewTab: true,
|
|
7119
|
+
linkClass: 'complex-url',
|
|
7120
|
+
externalLinkClass: 'complex-external',
|
|
7121
|
+
},
|
|
7122
|
+
};
|
|
6668
7123
|
}
|
|
6669
7124
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LinkProcessingExampleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6670
7125
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: LinkProcessingExampleComponent, isStandalone: true, selector: "val-link-processing-example", ngImport: i0, template: `
|
|
@@ -6710,8 +7165,13 @@ class LinkProcessingExampleComponent {
|
|
|
6710
7165
|
<h3>Corrección de puntuación en URLs:</h3>
|
|
6711
7166
|
<val-text [props]="punctuationTestProps"></val-text>
|
|
6712
7167
|
</div>
|
|
7168
|
+
|
|
7169
|
+
<div class="example-section">
|
|
7170
|
+
<h3>URLs complejas con parámetros y fragmentos:</h3>
|
|
7171
|
+
<val-text [props]="complexUrlsProps"></val-text>
|
|
7172
|
+
</div>
|
|
6713
7173
|
</div>
|
|
6714
|
-
`, isInline: true, styles: [".
|
|
7174
|
+
`, isInline: true, 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"], dependencies: [{ kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }] }); }
|
|
6715
7175
|
}
|
|
6716
7176
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LinkProcessingExampleComponent, decorators: [{
|
|
6717
7177
|
type: Component,
|
|
@@ -6758,10 +7218,310 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
6758
7218
|
<h3>Corrección de puntuación en URLs:</h3>
|
|
6759
7219
|
<val-text [props]="punctuationTestProps"></val-text>
|
|
6760
7220
|
</div>
|
|
7221
|
+
|
|
7222
|
+
<div class="example-section">
|
|
7223
|
+
<h3>URLs complejas con parámetros y fragmentos:</h3>
|
|
7224
|
+
<val-text [props]="complexUrlsProps"></val-text>
|
|
7225
|
+
</div>
|
|
6761
7226
|
</div>
|
|
6762
|
-
`, styles: [".
|
|
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"] }]
|
|
6763
7228
|
}] });
|
|
6764
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
|
+
|
|
6765
7525
|
const text = {
|
|
6766
7526
|
es: {
|
|
6767
7527
|
spanish: 'Español',
|
|
@@ -6777,7 +7537,10 @@ var LangSettings = new TextContent(text);
|
|
|
6777
7537
|
/**
|
|
6778
7538
|
* Global content that can be used across all components.
|
|
6779
7539
|
* These are common texts like buttons, actions, states, etc.
|
|
6780
|
-
* 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.
|
|
6781
7544
|
*/
|
|
6782
7545
|
const globalContentData = {
|
|
6783
7546
|
es: {
|
|
@@ -6848,6 +7611,34 @@ const globalContentData = {
|
|
|
6848
7611
|
// Common placeholders
|
|
6849
7612
|
searchPlaceholder: 'Search...',
|
|
6850
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
|
+
},
|
|
6851
7642
|
};
|
|
6852
7643
|
const GlobalContent = new TextContent(globalContentData);
|
|
6853
7644
|
const content = {
|
|
@@ -6910,5 +7701,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
6910
7701
|
* Generated bundle index. Do not edit.
|
|
6911
7702
|
*/
|
|
6912
7703
|
|
|
6913
|
-
export { ActionType, AlertBoxComponent, AvatarComponent, BannerComponent, BaseDefault, BoxComponent, ButtonComponent, ButtonGroupComponent, CardComponent, CardSection, CardType, CheckInputComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CommentInputComponent, ComponentStates, 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,
|
|
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 };
|
|
6914
7705
|
//# sourceMappingURL=valtech-components.mjs.map
|