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.
- package/esm2022/lib/examples/custom-content-demo.component.mjs +3 -3
- 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/public-api.mjs +2 -1
- package/fesm2022/valtech-components.mjs +540 -19
- package/fesm2022/valtech-components.mjs.map +1 -1
- 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/package.json +1 -1
- package/public-api.d.ts +1 -0
|
@@ -1543,11 +1543,20 @@ class TextContent {
|
|
|
1543
1543
|
return this.text;
|
|
1544
1544
|
}
|
|
1545
1545
|
}
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
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.
|
|
1578
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1625
|
-
|
|
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
|
|
1639
|
-
|
|
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
|
-
|
|
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' ?
|
|
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,
|
|
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
|