xertica-ui 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -1
- package/README.md +27 -3
- package/assets/xertica-logo.svg +37 -37
- package/assets/xertica-x-logo.svg +20 -20
- package/bin/cli.ts +477 -70
- package/bin/generate-tokens.ts +262 -262
- package/bin/language-config.ts +361 -361
- package/components/assets/xertica-orbe-animation.ts +1162 -1162
- package/components/assistant/code-block/code-block.stories.tsx +57 -57
- package/components/assistant/code-block/code-block.test.tsx +44 -44
- package/components/assistant/code-block/index.ts +1 -1
- package/components/assistant/formatted-document/formatted-document.stories.tsx +51 -51
- package/components/assistant/formatted-document/formatted-document.test.tsx +42 -42
- package/components/assistant/formatted-document/index.ts +1 -1
- package/components/assistant/index.ts +6 -6
- package/components/assistant/markdown-message/MarkdownMessage.tsx +152 -152
- package/components/assistant/markdown-message/index.ts +1 -1
- package/components/assistant/markdown-message/markdown-message.stories.tsx +50 -50
- package/components/assistant/markdown-message/markdown-message.test.tsx +33 -33
- package/components/assistant/modern-chat-input/ModernChatInput.tsx +554 -554
- package/components/assistant/modern-chat-input/index.ts +1 -1
- package/components/assistant/modern-chat-input/modern-chat-input.stories.tsx +131 -131
- package/components/assistant/modern-chat-input/modern-chat-input.test.tsx +79 -79
- package/components/assistant/xertica-assistant/index.ts +3 -3
- package/components/assistant/xertica-assistant/parts/AssistantTypingIndicator.tsx +41 -41
- package/components/assistant/xertica-assistant/parts/index.ts +16 -16
- package/components/assistant/xertica-assistant/types.ts +134 -134
- package/components/assistant/xertica-assistant/xertica-assistant.stories.tsx +407 -407
- package/components/assistant/xertica-assistant/xertica-assistant.test.tsx +65 -65
- package/components/blocks/card-patterns/ActivityCardSkeleton.tsx +56 -56
- package/components/blocks/card-patterns/FeatureCard.tsx +109 -109
- package/components/blocks/card-patterns/FeatureCardSkeleton.tsx +63 -63
- package/components/blocks/card-patterns/NotificationCardSkeleton.tsx +81 -81
- package/components/blocks/card-patterns/ProfileCardSkeleton.tsx +69 -69
- package/components/blocks/card-patterns/ProjectCardSkeleton.tsx +72 -72
- package/components/blocks/card-patterns/QuickActionCard.tsx +68 -68
- package/components/blocks/card-patterns/QuickActionCardSkeleton.tsx +44 -44
- package/components/blocks/card-patterns/card-patterns.mdx +123 -123
- package/components/blocks/index.ts +1 -1
- package/components/brand/branding/branding.stories.tsx +57 -57
- package/components/brand/index.ts +6 -6
- package/components/brand/language-selector/LanguageSelector.tsx +102 -102
- package/components/brand/language-selector/index.ts +1 -1
- package/components/brand/language-selector/language-selector.mdx +126 -126
- package/components/brand/language-selector/language-selector.stories.tsx +114 -114
- package/components/brand/language-selector/language-selector.test.tsx +101 -101
- package/components/brand/theme-toggle/index.ts +1 -1
- package/components/brand/theme-toggle/theme-toggle.stories.tsx +34 -34
- package/components/brand/theme-toggle/theme-toggle.test.tsx +34 -34
- package/components/brand/xertica-logo/XerticaLogo.stories.tsx +82 -82
- package/components/brand/xertica-logo/XerticaLogo.tsx +104 -104
- package/components/brand/xertica-logo/index.ts +1 -1
- package/components/brand/xertica-logo/xertica-logo.test.tsx +26 -26
- package/components/brand/xertica-orbe/XerticaOrbe.tsx +1927 -1927
- package/components/brand/xertica-orbe/index.ts +1 -1
- package/components/brand/xertica-orbe/xertica-orbe.stories.tsx +40 -40
- package/components/brand/xertica-orbe/xertica-orbe.test.tsx +19 -19
- package/components/brand/xertica-provider/XerticaProvider.tsx +112 -112
- package/components/brand/xertica-provider/index.ts +1 -1
- package/components/brand/xertica-provider/xertica-provider.mdx +61 -61
- package/components/brand/xertica-provider/xertica-provider.test.tsx +74 -74
- package/components/brand/xertica-xlogo/XerticaXLogo.stories.tsx +79 -79
- package/components/brand/xertica-xlogo/XerticaXLogo.tsx +65 -65
- package/components/brand/xertica-xlogo/index.ts +1 -1
- package/components/brand/xertica-xlogo/xertica-xlogo.test.tsx +16 -16
- package/components/examples/ApiKeyMapExample.tsx +71 -71
- package/components/examples/DrawingMapExample.tsx +565 -565
- package/components/examples/FilterableMapExample.tsx +393 -393
- package/components/examples/LocationPickerExample.tsx +348 -348
- package/components/examples/MapExamples.tsx +268 -268
- package/components/examples/MapGmpExample.tsx +169 -169
- package/components/examples/MapShowcase.tsx +471 -471
- package/components/examples/RouteMapExamples.tsx +329 -329
- package/components/examples/SidebarLogoExample.tsx +65 -65
- package/components/examples/SimpleFilterableMap.tsx +219 -219
- package/components/examples/index.ts +45 -45
- package/components/figma/ImageWithFallback.tsx +27 -27
- package/components/hooks/index.ts +13 -13
- package/components/hooks/use-layout-shortcuts.ts +43 -43
- package/components/layout/header/header.stories.tsx +204 -204
- package/components/layout/header/header.test.tsx +75 -75
- package/components/layout/header/header.tsx +349 -349
- package/components/layout/header/index.ts +1 -1
- package/components/layout/index.ts +2 -2
- package/components/layout/sidebar/index.ts +3 -3
- package/components/layout/sidebar/sidebar.mdx +1 -1
- package/components/layout/sidebar/sidebar.stories.tsx +586 -586
- package/components/layout/sidebar/sidebar.test.tsx +76 -76
- package/components/layout/sidebar/use-sidebar.ts +104 -104
- package/components/media/audio-player/AudioPlayer.stories.tsx +124 -124
- package/components/media/audio-player/AudioPlayer.test.tsx +106 -106
- package/components/media/audio-player/AudioPlayer.tsx +1 -1
- package/components/media/audio-player/index.ts +1 -1
- package/components/media/audio-player/use-audio-player.ts +312 -312
- package/components/media/index.ts +3 -3
- package/components/media/video-player/VideoPlayer.stories.tsx +98 -98
- package/components/media/video-player/VideoPlayer.test.tsx +73 -73
- package/components/media/video-player/index.ts +1 -1
- package/components/pages/forgot-password-page/ForgotPasswordPage.stories.tsx +24 -24
- package/components/pages/forgot-password-page/ForgotPasswordPage.tsx +188 -188
- package/components/pages/forgot-password-page/forgot-password-page.test.tsx +45 -45
- package/components/pages/forgot-password-page/index.ts +1 -1
- package/components/pages/home-content/HomeContent.stories.tsx +43 -43
- package/components/pages/home-content/HomeContent.tsx +1 -1
- package/components/pages/home-content/home-content.mdx +62 -62
- package/components/pages/home-content/index.ts +1 -1
- package/components/pages/home-page/HomePage.stories.tsx +39 -39
- package/components/pages/home-page/home-page.mdx +53 -53
- package/components/pages/home-page/home-page.test.tsx +53 -53
- package/components/pages/home-page/index.ts +1 -1
- package/components/pages/index.ts +8 -8
- package/components/pages/login-page/LoginPage.stories.tsx +39 -39
- package/components/pages/login-page/index.ts +1 -1
- package/components/pages/login-page/login-page.test.tsx +63 -63
- package/components/pages/reset-password-page/ResetPasswordPage.stories.tsx +24 -24
- package/components/pages/reset-password-page/index.ts +1 -1
- package/components/pages/template-content/TemplateContent.stories.tsx +43 -43
- package/components/pages/template-content/TemplateContent.tsx +1 -1
- package/components/pages/template-content/index.ts +1 -1
- package/components/pages/template-content/template-content.mdx +61 -61
- package/components/pages/template-page/TemplatePage.stories.tsx +39 -39
- package/components/pages/template-page/TemplatePage.tsx +62 -62
- package/components/pages/template-page/index.ts +1 -1
- package/components/pages/template-page/template-page.mdx +53 -53
- package/components/pages/template-page/template-page.test.tsx +52 -52
- package/components/pages/verify-email-page/VerifyEmailPage.stories.tsx +41 -41
- package/components/pages/verify-email-page/index.ts +1 -1
- package/components/public-api-smoke.test.tsx +52 -52
- package/components/shared/CustomTooltipContent.tsx +48 -48
- package/components/shared/assistant-utils.test.ts +16 -16
- package/components/shared/assistant-utils.ts +225 -225
- package/components/shared/error-boundary.stories.tsx +132 -132
- package/components/shared/error-boundary.tsx +154 -154
- package/components/shared/error-fallbacks.tsx +226 -226
- package/components/shared/layout-constants.ts +8 -8
- package/components/shared/navigation.ts +35 -35
- package/components/shared/use-mobile.test.ts +16 -16
- package/components/shared/use-mobile.ts +36 -36
- package/components/shared/utils.test.ts +14 -14
- package/components/shared/utils.ts +6 -6
- package/components/ui/accordion/accordion.mdx +8 -8
- package/components/ui/accordion/accordion.stories.tsx +105 -105
- package/components/ui/accordion/accordion.test.tsx +59 -59
- package/components/ui/accordion/accordion.tsx +77 -77
- package/components/ui/accordion/index.ts +1 -1
- package/components/ui/alert/alert.mdx +8 -8
- package/components/ui/alert/alert.stories.tsx +86 -86
- package/components/ui/alert/alert.test.tsx +53 -53
- package/components/ui/alert/alert.tsx +93 -93
- package/components/ui/alert/index.ts +1 -1
- package/components/ui/alert-dialog/alert-dialog.mdx +8 -8
- package/components/ui/alert-dialog/alert-dialog.stories.tsx +84 -84
- package/components/ui/alert-dialog/alert-dialog.test.tsx +70 -70
- package/components/ui/alert-dialog/alert-dialog.tsx +149 -149
- package/components/ui/alert-dialog/index.ts +1 -1
- package/components/ui/aspect-ratio/aspect-ratio.mdx +8 -8
- package/components/ui/aspect-ratio/aspect-ratio.stories.tsx +46 -46
- package/components/ui/aspect-ratio/aspect-ratio.test.tsx +28 -28
- package/components/ui/aspect-ratio/aspect-ratio.tsx +20 -20
- package/components/ui/aspect-ratio/index.ts +1 -1
- package/components/ui/assistant-chart/AssistantChart.tsx +64 -64
- package/components/ui/assistant-chart/assistant-chart.mdx +8 -8
- package/components/ui/assistant-chart/assistant-chart.stories.tsx +44 -44
- package/components/ui/assistant-chart/assistant-chart.test.tsx +46 -46
- package/components/ui/assistant-chart/index.ts +1 -1
- package/components/ui/avatar/avatar.mdx +8 -8
- package/components/ui/avatar/avatar.stories.tsx +86 -86
- package/components/ui/avatar/avatar.test.tsx +55 -55
- package/components/ui/avatar/avatar.tsx +71 -71
- package/components/ui/avatar/index.ts +1 -1
- package/components/ui/badge/badge.mdx +8 -8
- package/components/ui/badge/badge.stories.tsx +72 -72
- package/components/ui/badge/badge.test.tsx +40 -40
- package/components/ui/badge/badge.tsx +58 -58
- package/components/ui/badge/index.ts +1 -1
- package/components/ui/breadcrumb/breadcrumb.mdx +8 -8
- package/components/ui/breadcrumb/breadcrumb.stories.tsx +123 -123
- package/components/ui/breadcrumb/breadcrumb.test.tsx +70 -70
- package/components/ui/breadcrumb/breadcrumb.tsx +114 -114
- package/components/ui/breadcrumb/index.ts +1 -1
- package/components/ui/button/button.mdx +8 -8
- package/components/ui/button/button.stories.tsx +183 -183
- package/components/ui/button/button.test.tsx +64 -64
- package/components/ui/button/button.tsx +98 -98
- package/components/ui/button/index.ts +1 -1
- package/components/ui/calendar/calendar.mdx +8 -8
- package/components/ui/calendar/calendar.stories.tsx +108 -108
- package/components/ui/calendar/calendar.test.tsx +53 -53
- package/components/ui/calendar/calendar.tsx +230 -230
- package/components/ui/calendar/index.ts +1 -1
- package/components/ui/card/card.mdx +8 -8
- package/components/ui/card/card.stories.tsx +301 -301
- package/components/ui/card/card.test.tsx +55 -55
- package/components/ui/card/card.tsx +83 -83
- package/components/ui/card/index.ts +1 -1
- package/components/ui/carousel/carousel.mdx +8 -8
- package/components/ui/carousel/carousel.stories.tsx +80 -80
- package/components/ui/carousel/carousel.test.tsx +75 -75
- package/components/ui/carousel/carousel.tsx +242 -242
- package/components/ui/carousel/index.ts +1 -1
- package/components/ui/chart/chart.mdx +8 -8
- package/components/ui/chart/chart.stories.tsx +1328 -1328
- package/components/ui/chart/chart.test.tsx +178 -178
- package/components/ui/chart/chart.tsx +2232 -2232
- package/components/ui/chart/index.ts +1 -1
- package/components/ui/checkbox/checkbox.mdx +8 -8
- package/components/ui/checkbox/checkbox.stories.tsx +109 -109
- package/components/ui/checkbox/checkbox.test.tsx +49 -49
- package/components/ui/checkbox/checkbox.tsx +68 -68
- package/components/ui/checkbox/index.ts +1 -1
- package/components/ui/collapsible/collapsible.mdx +8 -8
- package/components/ui/collapsible/collapsible.stories.tsx +45 -45
- package/components/ui/collapsible/collapsible.test.tsx +51 -51
- package/components/ui/collapsible/collapsible.tsx +32 -32
- package/components/ui/collapsible/index.ts +1 -1
- package/components/ui/command/command.mdx +8 -8
- package/components/ui/command/command.stories.tsx +134 -134
- package/components/ui/command/command.test.tsx +48 -48
- package/components/ui/command/command.tsx +163 -163
- package/components/ui/command/index.ts +1 -1
- package/components/ui/context-menu/context-menu.mdx +8 -8
- package/components/ui/context-menu/context-menu.stories.tsx +76 -76
- package/components/ui/context-menu/context-menu.test.tsx +61 -61
- package/components/ui/context-menu/context-menu.tsx +236 -236
- package/components/ui/context-menu/index.ts +1 -1
- package/components/ui/dialog/dialog.mdx +8 -8
- package/components/ui/dialog/dialog.stories.tsx +174 -174
- package/components/ui/dialog/dialog.test.tsx +78 -78
- package/components/ui/dialog/dialog.tsx +189 -189
- package/components/ui/dialog/index.ts +1 -1
- package/components/ui/drawer/drawer.mdx +8 -8
- package/components/ui/drawer/drawer.stories.tsx +71 -71
- package/components/ui/drawer/drawer.test.tsx +67 -67
- package/components/ui/drawer/drawer.tsx +146 -146
- package/components/ui/drawer/index.ts +1 -1
- package/components/ui/dropdown-menu/dropdown-menu.mdx +8 -8
- package/components/ui/dropdown-menu/dropdown-menu.stories.tsx +156 -156
- package/components/ui/dropdown-menu/dropdown-menu.test.tsx +62 -62
- package/components/ui/dropdown-menu/dropdown-menu.tsx +240 -240
- package/components/ui/dropdown-menu/index.ts +1 -1
- package/components/ui/empty/empty.mdx +8 -8
- package/components/ui/empty/empty.stories.tsx +85 -85
- package/components/ui/empty/empty.test.tsx +31 -31
- package/components/ui/empty/empty.tsx +88 -88
- package/components/ui/empty/index.ts +1 -1
- package/components/ui/file-upload/file-upload.mdx +8 -8
- package/components/ui/file-upload/file-upload.stories.tsx +144 -144
- package/components/ui/file-upload/file-upload.test.tsx +65 -65
- package/components/ui/file-upload/file-upload.tsx +142 -142
- package/components/ui/file-upload/index.ts +2 -2
- package/components/ui/file-upload/use-file-upload.ts +177 -177
- package/components/ui/form/form.stories.tsx +85 -85
- package/components/ui/form/form.test.tsx +75 -75
- package/components/ui/form/form.tsx +163 -163
- package/components/ui/form/index.ts +1 -1
- package/components/ui/google-maps-loader/google-maps-loader.test.tsx +35 -35
- package/components/ui/google-maps-loader/google-maps-loader.tsx +465 -465
- package/components/ui/google-maps-loader/index.ts +1 -1
- package/components/ui/hover-card/hover-card.mdx +8 -8
- package/components/ui/hover-card/hover-card.stories.tsx +61 -61
- package/components/ui/hover-card/hover-card.test.tsx +48 -48
- package/components/ui/hover-card/hover-card.tsx +50 -50
- package/components/ui/hover-card/index.ts +1 -1
- package/components/ui/index.ts +400 -400
- package/components/ui/input/index.ts +1 -1
- package/components/ui/input/input.mdx +8 -8
- package/components/ui/input/input.stories.tsx +153 -153
- package/components/ui/input/input.test.tsx +47 -47
- package/components/ui/input/input.tsx +57 -57
- package/components/ui/input-otp/index.ts +1 -1
- package/components/ui/input-otp/input-otp.mdx +8 -8
- package/components/ui/input-otp/input-otp.stories.tsx +120 -120
- package/components/ui/input-otp/input-otp.test.tsx +74 -74
- package/components/ui/input-otp/input-otp.tsx +101 -101
- package/components/ui/label/index.ts +1 -1
- package/components/ui/label/label.mdx +8 -8
- package/components/ui/label/label.stories.tsx +74 -74
- package/components/ui/label/label.test.tsx +45 -45
- package/components/ui/label/label.tsx +53 -53
- package/components/ui/map/index.ts +1 -1
- package/components/ui/map/map.mdx +8 -8
- package/components/ui/map/map.stories.tsx +86 -86
- package/components/ui/map/map.test.tsx +82 -82
- package/components/ui/map/map.tsx +506 -506
- package/components/ui/map/mock.test.tsx +13 -13
- package/components/ui/map-config/index.ts +1 -1
- package/components/ui/map-config/map-config.ts +18 -18
- package/components/ui/map-layers/index.ts +1 -1
- package/components/ui/map-layers/map-layers.test.tsx +48 -48
- package/components/ui/map-layers/map-layers.tsx +126 -126
- package/components/ui/map.exports/index.ts +1 -1
- package/components/ui/map.exports/map.exports.ts +31 -31
- package/components/ui/menubar/index.ts +1 -1
- package/components/ui/menubar/menubar.mdx +8 -8
- package/components/ui/menubar/menubar.stories.tsx +130 -130
- package/components/ui/menubar/menubar.test.tsx +53 -53
- package/components/ui/menubar/menubar.tsx +265 -265
- package/components/ui/navigation-menu/index.ts +1 -1
- package/components/ui/navigation-menu/navigation-menu.mdx +8 -8
- package/components/ui/navigation-menu/navigation-menu.stories.tsx +126 -126
- package/components/ui/navigation-menu/navigation-menu.test.tsx +47 -47
- package/components/ui/navigation-menu/navigation-menu.tsx +165 -165
- package/components/ui/notification-badge/index.ts +1 -1
- package/components/ui/notification-badge/notification-badge.mdx +8 -8
- package/components/ui/notification-badge/notification-badge.stories.tsx +66 -66
- package/components/ui/notification-badge/notification-badge.test.tsx +61 -61
- package/components/ui/notification-badge/notification-badge.tsx +91 -91
- package/components/ui/page-header/index.ts +1 -1
- package/components/ui/page-header/page-header.stories.tsx +69 -69
- package/components/ui/page-header/page-header.test.tsx +37 -37
- package/components/ui/page-header/page-header.tsx +124 -124
- package/components/ui/pagination/index.ts +3 -3
- package/components/ui/pagination/pagination.mdx +8 -8
- package/components/ui/pagination/pagination.stories.tsx +210 -210
- package/components/ui/pagination/pagination.test.tsx +63 -63
- package/components/ui/pagination/pagination.tsx +140 -140
- package/components/ui/pagination/use-pagination.ts +173 -173
- package/components/ui/popover/index.ts +1 -1
- package/components/ui/popover/popover.mdx +8 -8
- package/components/ui/popover/popover.stories.tsx +73 -73
- package/components/ui/popover/popover.test.tsx +48 -48
- package/components/ui/popover/popover.tsx +54 -54
- package/components/ui/progress/index.ts +1 -1
- package/components/ui/progress/progress.mdx +8 -8
- package/components/ui/progress/progress.stories.tsx +55 -55
- package/components/ui/progress/progress.test.tsx +23 -23
- package/components/ui/progress/progress.tsx +68 -68
- package/components/ui/radio-group/index.ts +1 -1
- package/components/ui/radio-group/radio-group.mdx +8 -8
- package/components/ui/radio-group/radio-group.stories.tsx +114 -114
- package/components/ui/radio-group/radio-group.test.tsx +78 -78
- package/components/ui/radio-group/radio-group.tsx +93 -93
- package/components/ui/rating/index.ts +1 -1
- package/components/ui/rating/rating.mdx +8 -8
- package/components/ui/rating/rating.stories.tsx +50 -50
- package/components/ui/rating/rating.test.tsx +48 -48
- package/components/ui/rating/rating.tsx +145 -145
- package/components/ui/resizable/index.ts +1 -1
- package/components/ui/resizable/resizable.mdx +8 -8
- package/components/ui/resizable/resizable.stories.tsx +88 -88
- package/components/ui/resizable/resizable.test.tsx +61 -61
- package/components/ui/resizable/resizable.tsx +452 -452
- package/components/ui/rich-text-editor/index.ts +7 -7
- package/components/ui/rich-text-editor/rich-text-editor.stories.tsx +290 -290
- package/components/ui/rich-text-editor/rich-text-editor.test.tsx +86 -86
- package/components/ui/rich-text-editor/rich-text-editor.tsx +634 -634
- package/components/ui/rich-text-editor/use-rich-text-editor.ts +453 -453
- package/components/ui/route-map/index.ts +1 -1
- package/components/ui/route-map/route-map.mdx +8 -8
- package/components/ui/route-map/route-map.stories.tsx +48 -48
- package/components/ui/route-map/route-map.test.tsx +108 -108
- package/components/ui/route-map/route-map.tsx +349 -349
- package/components/ui/scroll-area/index.ts +1 -1
- package/components/ui/scroll-area/scroll-area.mdx +8 -8
- package/components/ui/scroll-area/scroll-area.stories.tsx +31 -31
- package/components/ui/scroll-area/scroll-area.test.tsx +27 -27
- package/components/ui/scroll-area/scroll-area.tsx +70 -70
- package/components/ui/search/index.ts +1 -1
- package/components/ui/search/search.mdx +8 -8
- package/components/ui/search/search.stories.tsx +107 -107
- package/components/ui/search/search.test.tsx +67 -67
- package/components/ui/search/search.tsx +141 -141
- package/components/ui/select/index.ts +1 -1
- package/components/ui/select/select.mdx +8 -8
- package/components/ui/select/select.stories.tsx +163 -163
- package/components/ui/select/select.test.tsx +99 -99
- package/components/ui/select/select.tsx +195 -195
- package/components/ui/separator/index.ts +1 -1
- package/components/ui/separator/separator.mdx +8 -8
- package/components/ui/separator/separator.stories.tsx +55 -55
- package/components/ui/separator/separator.test.tsx +23 -23
- package/components/ui/separator/separator.tsx +39 -39
- package/components/ui/sheet/index.ts +1 -1
- package/components/ui/sheet/sheet.mdx +8 -8
- package/components/ui/sheet/sheet.stories.tsx +93 -93
- package/components/ui/sheet/sheet.test.tsx +62 -62
- package/components/ui/sheet/sheet.tsx +149 -149
- package/components/ui/simple-map/index.ts +1 -1
- package/components/ui/simple-map/simple-map.mdx +8 -8
- package/components/ui/simple-map/simple-map.stories.tsx +44 -44
- package/components/ui/simple-map/simple-map.test.tsx +36 -36
- package/components/ui/simple-map/simple-map.tsx +92 -92
- package/components/ui/skeleton/index.ts +1 -1
- package/components/ui/skeleton/skeleton.mdx +8 -8
- package/components/ui/skeleton/skeleton.stories.tsx +36 -36
- package/components/ui/skeleton/skeleton.test.tsx +19 -19
- package/components/ui/skeleton/skeleton.tsx +25 -25
- package/components/ui/slider/index.ts +1 -1
- package/components/ui/slider/slider.mdx +8 -8
- package/components/ui/slider/slider.stories.tsx +44 -44
- package/components/ui/slider/slider.test.tsx +25 -25
- package/components/ui/slider/slider.tsx +66 -66
- package/components/ui/sonner/index.ts +1 -1
- package/components/ui/sonner/sonner.mdx +8 -8
- package/components/ui/sonner/sonner.stories.tsx +41 -41
- package/components/ui/sonner/sonner.test.tsx +24 -24
- package/components/ui/sonner/sonner.tsx +74 -74
- package/components/ui/stats-card/stats-card-skeleton.tsx +62 -62
- package/components/ui/stats-card/stats-card.mdx +8 -8
- package/components/ui/stats-card/stats-card.test.tsx +34 -34
- package/components/ui/stats-card/stats-card.tsx +93 -93
- package/components/ui/stepper/index.ts +3 -3
- package/components/ui/stepper/stepper.mdx +8 -8
- package/components/ui/stepper/stepper.stories.tsx +171 -171
- package/components/ui/stepper/stepper.test.tsx +47 -47
- package/components/ui/stepper/stepper.tsx +190 -190
- package/components/ui/stepper/use-stepper.ts +139 -139
- package/components/ui/switch/index.ts +1 -1
- package/components/ui/switch/switch.mdx +8 -8
- package/components/ui/switch/switch.stories.tsx +93 -93
- package/components/ui/switch/switch.test.tsx +44 -44
- package/components/ui/switch/switch.tsx +70 -70
- package/components/ui/table/index.ts +1 -1
- package/components/ui/table/table.mdx +8 -8
- package/components/ui/table/table.stories.tsx +114 -114
- package/components/ui/table/table.test.tsx +43 -43
- package/components/ui/table/table.tsx +104 -104
- package/components/ui/tabs/index.ts +1 -1
- package/components/ui/tabs/tabs.mdx +8 -8
- package/components/ui/tabs/tabs.stories.tsx +140 -140
- package/components/ui/tabs/tabs.test.tsx +50 -50
- package/components/ui/tabs/tabs.tsx +66 -66
- package/components/ui/textarea/index.ts +1 -1
- package/components/ui/textarea/textarea.mdx +8 -8
- package/components/ui/textarea/textarea.stories.tsx +69 -69
- package/components/ui/textarea/textarea.test.tsx +41 -41
- package/components/ui/textarea/textarea.tsx +61 -61
- package/components/ui/timeline/index.ts +1 -1
- package/components/ui/timeline/timeline.mdx +8 -8
- package/components/ui/timeline/timeline.stories.tsx +97 -97
- package/components/ui/timeline/timeline.test.tsx +53 -53
- package/components/ui/timeline/timeline.tsx +124 -124
- package/components/ui/toggle/index.ts +1 -1
- package/components/ui/toggle/toggle.mdx +8 -8
- package/components/ui/toggle/toggle.stories.tsx +56 -56
- package/components/ui/toggle/toggle.test.tsx +32 -32
- package/components/ui/toggle/toggle.tsx +55 -55
- package/components/ui/toggle-group/index.ts +1 -1
- package/components/ui/toggle-group/toggle-group.mdx +8 -8
- package/components/ui/toggle-group/toggle-group.stories.tsx +66 -66
- package/components/ui/toggle-group/toggle-group.test.tsx +47 -47
- package/components/ui/toggle-group/toggle-group.tsx +79 -79
- package/components/ui/tooltip/index.ts +1 -1
- package/components/ui/tooltip/tooltip.mdx +8 -8
- package/components/ui/tooltip/tooltip.stories.tsx +83 -83
- package/components/ui/tooltip/tooltip.test.tsx +39 -39
- package/components/ui/tooltip/tooltip.tsx +69 -69
- package/components/ui/tree-view/index.ts +4 -4
- package/components/ui/tree-view/tree-view.mdx +8 -8
- package/components/ui/tree-view/tree-view.stories.tsx +154 -154
- package/components/ui/tree-view/tree-view.test.tsx +58 -58
- package/components/ui/tree-view/tree-view.tsx +171 -171
- package/components/ui/tree-view/use-tree-view.ts +237 -237
- package/contexts/ApiKeyContext.test.tsx +26 -26
- package/contexts/ApiKeyContext.tsx +196 -196
- package/contexts/AssistenteContext.test.tsx +17 -17
- package/contexts/AssistenteContext.tsx +113 -113
- package/contexts/AuthContext.tsx +118 -118
- package/contexts/BrandColorsContext.test.tsx +21 -21
- package/contexts/BrandColorsContext.tsx +251 -251
- package/contexts/LanguageContext.test.tsx +121 -121
- package/contexts/LanguageContext.tsx +251 -251
- package/contexts/LayoutContext.test.tsx +29 -29
- package/contexts/LayoutContext.tsx +140 -140
- package/contexts/ThemeContext.test.tsx +38 -38
- package/contexts/ThemeContext.tsx +111 -111
- package/contexts/index.ts +8 -8
- package/contexts/theme-data.ts +340 -340
- package/dist/{AssistantChart-BAx9VQvb.cjs → AssistantChart-Bdd44uBn.cjs} +388 -127
- package/dist/{AssistantChart-CVko2A1W.js → AssistantChart-CFhDdGyU.js} +391 -130
- package/dist/AssistantChart-COGiOV-g.cjs +3541 -0
- package/dist/AssistantChart-CWX1OWNM.js +3373 -0
- package/dist/{AssistantChart-CVzmmhx4.js → AssistantChart-C_hwFRRr.js} +4 -4
- package/dist/{AssistantChart-BAudAfne.cjs → AssistantChart-CldVCVDe.cjs} +5 -5
- package/dist/{AssistantChart-BP8upjMk.js → AssistantChart-Cu3m7RBo.js} +5 -5
- package/dist/AssistantChart-CxGjH7Qk.js +3477 -0
- package/dist/AssistantChart-DIpshm3i.js +4784 -0
- package/dist/AssistantChart-D_PTeu8P.cjs +3503 -0
- package/dist/{AssistantChart-9w31gdAb.cjs → AssistantChart-DoZCyS5r.cjs} +4 -4
- package/dist/AssistantChart-zjsy2GaZ.cjs +4810 -0
- package/dist/AudioPlayer-9psiEucT.cjs +1282 -0
- package/dist/AudioPlayer-B1lt5cPl.cjs +989 -0
- package/dist/AudioPlayer-BZ7bibzU.cjs +982 -0
- package/dist/AudioPlayer-BpRPS4-1.cjs +1277 -0
- package/dist/AudioPlayer-C12BjQBV.cjs +997 -0
- package/dist/{AudioPlayer-1ypwE2Wh.cjs → AudioPlayer-CFeV8t-5.cjs} +1 -1
- package/dist/{AudioPlayer-DuKXrCfy.js → AudioPlayer-CGRUtUdN.js} +1 -1
- package/dist/AudioPlayer-Coly3q5R.js +1278 -0
- package/dist/AudioPlayer-CySJIyvL.js +937 -0
- package/dist/AudioPlayer-DMcG_c7L.js +990 -0
- package/dist/AudioPlayer-DcFKRJE_.js +998 -0
- package/dist/AudioPlayer-Dp2bD1Gk.js +1278 -0
- package/dist/AudioPlayer-IAU5q5T1.cjs +936 -0
- package/dist/AudioPlayer-e8LfNoqO.js +983 -0
- package/dist/BrandColorsContext-565dDHd5.js +660 -0
- package/dist/BrandColorsContext-BcJbtkqn.cjs +659 -0
- package/dist/BrandColorsContext-DZT7JjeD.js +659 -0
- package/dist/BrandColorsContext-awnBCmC4.cjs +666 -0
- package/dist/{xertica-assistant-Qp3ydksa.cjs → CodeBlock-7TTgmdGG.cjs} +263 -51
- package/dist/{xertica-assistant-gnCJdcZY.js → CodeBlock-BeSt1h5P.js} +219 -7
- package/dist/CodeBlock-BgfYL_rD.cjs +2094 -0
- package/dist/CodeBlock-BlcqlA9M.cjs +2094 -0
- package/dist/CodeBlock-Bnmeu5ez.cjs +2094 -0
- package/dist/CodeBlock-BtfPlbAI.js +2078 -0
- package/dist/CodeBlock-CIySIuYr.js +2078 -0
- package/dist/CodeBlock-CuPtUM-7.cjs +2094 -0
- package/dist/CodeBlock-D6ffWXgc.js +2078 -0
- package/dist/CodeBlock-D8dcwbit.cjs +2094 -0
- package/dist/CodeBlock-DMZrFnlw.cjs +2094 -0
- package/dist/CodeBlock-DYkTfR0f.js +221 -0
- package/dist/CodeBlock-DlBehYN8.js +2078 -0
- package/dist/CodeBlock-DnYNI8rQ.js +2078 -0
- package/dist/CodeBlock-DvKWbSnE.cjs +2094 -0
- package/dist/CodeBlock-DwMCfkFY.js +2078 -0
- package/dist/CodeBlock-Dy6CNYyj.js +2078 -0
- package/dist/CodeBlock-EOvp9cVu.cjs +223 -0
- package/dist/CodeBlock-U1pPOQI7.cjs +2094 -0
- package/dist/CodeBlock-f_GpNhEB.js +2078 -0
- package/dist/CodeBlock-oB6u8nI1.js +2078 -0
- package/dist/CodeBlock-tZC31B73.cjs +2094 -0
- package/dist/CustomTooltipContent-BhdIeBEg.cjs +54 -0
- package/dist/CustomTooltipContent-CNbVB2NS.js +33 -0
- package/dist/FeatureCard-BZ4CYxFf.cjs +497 -0
- package/dist/FeatureCard-CxC-7C-C.cjs +300 -0
- package/dist/FeatureCard-DNycVGwT.js +485 -0
- package/dist/FeatureCard-DbHWCb4E.js +301 -0
- package/dist/FeatureCardSkeleton-DZqc96mt.js +27 -0
- package/dist/FeatureCardSkeleton-pTa0YNKP.cjs +29 -0
- package/dist/ImageWithFallback-CGtidP6B.cjs +4542 -0
- package/dist/ImageWithFallback-lsg3pdFg.js +4508 -0
- package/dist/{LanguageContext-DvUt5jBg.cjs → LanguageContext-B_KFTCzT.cjs} +2 -2
- package/dist/{LanguageContext-BwhwC3G2.js → LanguageContext-CS14yCpi.js} +2 -2
- package/dist/LanguageSelector-B5YfbHra.js +231 -0
- package/dist/LanguageSelector-D6uacAIM.cjs +230 -0
- package/dist/LayoutContext-B45-e9DI.cjs +93 -0
- package/dist/LayoutContext-BAql6ZRY.js +97 -0
- package/dist/LayoutContext-BEq_-n98.cjs +96 -0
- package/dist/LayoutContext-Bav3UMEA.js +94 -0
- package/dist/LayoutContext-BvK-ggDa.cjs +96 -0
- package/dist/LayoutContext-DNl1xSoX.js +92 -0
- package/dist/{ThemeContext-ept8jhXI.js → ThemeContext-BWq9ACPo.js} +8 -13
- package/dist/ThemeContext-BXjrgUjW.js +1917 -0
- package/dist/{ThemeContext-Bo-W2WZH.js → ThemeContext-BgclCB35.js} +3 -3
- package/dist/{ThemeContext-CP3a0jxy.cjs → ThemeContext-Bmod0Cg2.cjs} +8 -13
- package/dist/ThemeContext-BoH4NLfN.js +734 -0
- package/dist/{ThemeContext-BbBNoFTG.js → ThemeContext-C2EwAPDt.js} +2 -2
- package/dist/{ThemeContext-U4dEYc6C.cjs → ThemeContext-CGk3KK0k.cjs} +1 -8
- package/dist/ThemeContext-CMD3z2Dz.cjs +1930 -0
- package/dist/{ThemeContext-D3LzacmG.js → ThemeContext-CQSo4Iwc.js} +1 -8
- package/dist/{ThemeContext-BblcjQup.cjs → ThemeContext-DQUOeziy.cjs} +3 -3
- package/dist/ThemeContext-j5aGtPky.cjs +1924 -0
- package/dist/ThemeContext-r69W20Xg.cjs +733 -0
- package/dist/{ThemeContext-Cmr8Ex8H.cjs → ThemeContext-vTjumZeM.cjs} +2 -2
- package/dist/ThemeContext-x_F2zsnv.js +1923 -0
- package/dist/{VerifyEmailPage-BRSP-Pwt.cjs → VerifyEmailPage--1Vurewl.cjs} +3 -3
- package/dist/{VerifyEmailPage-BE-L9mB7.js → VerifyEmailPage-1WwWczAn.js} +12 -22
- package/dist/{VerifyEmailPage-DF2ilhum.cjs → VerifyEmailPage-B4peJjAT.cjs} +356 -334
- package/dist/{VerifyEmailPage-CR7kb5df.cjs → VerifyEmailPage-BComraR7.cjs} +12 -22
- package/dist/{VerifyEmailPage-BiRm7Nh4.cjs → VerifyEmailPage-By3Jf__L.cjs} +348 -329
- package/dist/VerifyEmailPage-ByerOcm4.cjs +3232 -0
- package/dist/{VerifyEmailPage-CbgjOF0v.js → VerifyEmailPage-C0c2e5n0.js} +7 -7
- package/dist/{VerifyEmailPage-EhudUdqF.js → VerifyEmailPage-C5TNQTBa.js} +355 -343
- package/dist/{VerifyEmailPage-Dt7zgA4w.cjs → VerifyEmailPage-CFLMls1p.cjs} +4 -4
- package/dist/{VerifyEmailPage-vYHbYK3q.js → VerifyEmailPage-CJLz3jrn.js} +347 -338
- package/dist/VerifyEmailPage-COiyNl1y.js +2825 -0
- package/dist/{VerifyEmailPage-DMBh4NM9.cjs → VerifyEmailPage-CYXtbKi3.cjs} +1 -1
- package/dist/{VerifyEmailPage-DTtFfC-J.js → VerifyEmailPage-CgMxRb4z.js} +3 -3
- package/dist/VerifyEmailPage-CqKsR2v8.js +2827 -0
- package/dist/{VerifyEmailPage-Bae2cBXT.cjs → VerifyEmailPage-Cwi3kbol.cjs} +7 -7
- package/dist/{VerifyEmailPage-BIBOKV7Z.js → VerifyEmailPage-DSBMRHtl.js} +36 -41
- package/dist/{VerifyEmailPage-hdB8JQGv.cjs → VerifyEmailPage-De6bQjrz.cjs} +36 -41
- package/dist/VerifyEmailPage-DgIid028.js +3223 -0
- package/dist/VerifyEmailPage-DjQKRlUS.cjs +2824 -0
- package/dist/{VerifyEmailPage-CdYPSJoO.js → VerifyEmailPage-DvMLZgFt.js} +1 -1
- package/dist/{VerifyEmailPage-C_ihbcth.js → VerifyEmailPage-MTD7AG1Z.js} +4 -4
- package/dist/{VerifyEmailPage-Bvfv8HVQ.js → VerifyEmailPage-RrUApqBN.js} +3 -3
- package/dist/{VerifyEmailPage-D-FRj5TU.cjs → VerifyEmailPage-VoMI7MYH.cjs} +3 -3
- package/dist/VerifyEmailPage-s-1X3LDJ.cjs +2826 -0
- package/dist/XerticaOrbe-KL1RBHzw.cjs +1354 -0
- package/dist/XerticaOrbe-Uk2JML1-.cjs +1927 -0
- package/dist/XerticaOrbe-jA5T2iOk.js +1925 -0
- package/dist/XerticaOrbe-zwS1p2a8.js +1355 -0
- package/dist/XerticaProvider-6btlAlzc.js +17 -0
- package/dist/{XerticaProvider-siSt9uG2.js → XerticaProvider-B7EVH-NF.js} +2 -2
- package/dist/{XerticaProvider-CjQAQPcn.cjs → XerticaProvider-BIrqfZ-i.cjs} +11 -8
- package/dist/XerticaProvider-BNoNOxQ5.cjs +16 -0
- package/dist/{XerticaProvider-CWgby5mY.js → XerticaProvider-BSyFrmC0.js} +1 -1
- package/dist/XerticaProvider-BlY2limY.cjs +38 -0
- package/dist/{XerticaProvider-CWs6EwNa.js → XerticaProvider-C1DKnvLh.js} +4 -4
- package/dist/{XerticaProvider-AbWlr7Af.cjs → XerticaProvider-CBGc4EMA.cjs} +4 -4
- package/dist/{XerticaProvider-BITjgC5p.js → XerticaProvider-CEoWMTxu.js} +2 -2
- package/dist/{XerticaProvider-AChwphCO.cjs → XerticaProvider-CiNKjMx1.cjs} +1 -1
- package/dist/{XerticaProvider-By8q3Roe.cjs → XerticaProvider-CllrbMEJ.cjs} +2 -2
- package/dist/{XerticaProvider-B8CaV7xu.cjs → XerticaProvider-D-yNhF94.cjs} +1 -1
- package/dist/XerticaProvider-DDuiIcKo.js +39 -0
- package/dist/{XerticaProvider-D5lLumH-.js → XerticaProvider-DUOJg9iX.js} +10 -10
- package/dist/{XerticaProvider-DQtvJU7m.js → XerticaProvider-DYq4JWtg.js} +1 -1
- package/dist/{XerticaProvider-qQUDop71.cjs → XerticaProvider-Dl_b72_l.cjs} +11 -8
- package/dist/{XerticaProvider-CUYJZc32.js → XerticaProvider-Dt5HEzbQ.js} +10 -10
- package/dist/{XerticaProvider-CW9hpCdF.cjs → XerticaProvider-ET0ihewn.cjs} +2 -2
- package/dist/XerticaProvider-cI9hSs27.cjs +38 -0
- package/dist/XerticaProvider-hSwhNQex.js +39 -0
- package/dist/{XerticaXLogo-8TTzBjHw.cjs → XerticaXLogo-B2svDGZh.cjs} +1 -1
- package/dist/{XerticaXLogo-ChryA6xj.js → XerticaXLogo-B7xQ5dhi.js} +1 -1
- package/dist/{XerticaXLogo-CziKMQil.cjs → XerticaXLogo-CQUUjXoH.cjs} +8 -8
- package/dist/{XerticaXLogo-DfUvz-lD.js → XerticaXLogo-Cmsp-Eey.js} +9 -9
- package/dist/{XerticaXLogo-CFuIlYFH.js → XerticaXLogo-CowGv7BC.js} +1 -1
- package/dist/{XerticaXLogo-DHz5SugF.js → XerticaXLogo-DZbo4vOE.js} +12 -12
- package/dist/{XerticaXLogo-kslQ8Tk_.cjs → XerticaXLogo-Zw2B276b.cjs} +1 -1
- package/dist/{XerticaXLogo-CU-U-GP4.cjs → XerticaXLogo-bvZSgwGF.cjs} +13 -7
- package/dist/{XerticaXLogo-BWaag64t.js → XerticaXLogo-mqjoBiLI.js} +12 -12
- package/dist/{XerticaXLogo-DTee_y8X.cjs → XerticaXLogo-uQgwns_E.cjs} +13 -7
- package/dist/alert-dialog-BOje--vD.js +847 -0
- package/dist/alert-dialog-BtEuQqrg.cjs +870 -0
- package/dist/{alert-dialog-yckpaOpy.cjs → alert-dialog-DSKByiKZ.cjs} +3 -3
- package/dist/alert-dialog-DhwPioBa.cjs +885 -0
- package/dist/alert-dialog-DqlRW_An.js +831 -0
- package/dist/{alert-dialog-iDe5VE5o.js → alert-dialog-s-vmNkJ_.js} +3 -3
- package/dist/assistant.cjs.js +8 -4
- package/dist/assistant.es.js +5 -11
- package/dist/avatar-3kO2Anrp.js +54 -0
- package/dist/avatar-BCM7YQRC.cjs +77 -0
- package/dist/blocks.cjs.js +9 -4
- package/dist/blocks.es.js +2 -16
- package/dist/brand.cjs.js +10 -5
- package/dist/brand.es.js +3 -11
- package/dist/breadcrumb-BKtHF4gk.cjs +98 -0
- package/dist/breadcrumb-CqJ7bHY5.js +161 -0
- package/dist/breadcrumb-ifNsA7Zl.js +90 -0
- package/dist/breadcrumb-m9Hb2_XN.cjs +177 -0
- package/dist/button-0BlA47It.cjs +85 -0
- package/dist/button-DZHzN1Gd.js +62 -0
- package/dist/cli.js +391 -66
- package/dist/components/assistant/xertica-assistant/hooks/index.d.ts +6 -0
- package/dist/components/assistant/xertica-assistant/hooks/use-assistant-conversations.d.ts +21 -0
- package/dist/components/assistant/xertica-assistant/hooks/use-assistant-messages.d.ts +49 -0
- package/dist/components/assistant/xertica-assistant/hooks/use-assistant-suggestions.d.ts +16 -0
- package/dist/components/blocks/audio-player/AudioPlayer.d.ts +35 -0
- package/dist/components/blocks/audio-player/index.d.ts +1 -0
- package/dist/components/blocks/document-editor/DocumentEditor.d.ts +26 -0
- package/dist/components/blocks/document-editor/index.d.ts +1 -0
- package/dist/components/blocks/podcast-player/PodcastPlayer.d.ts +41 -0
- package/dist/components/blocks/podcast-player/index.d.ts +1 -0
- package/dist/components/ui/chart/parts/chart-dashboard.d.ts +113 -0
- package/dist/components/ui/chart/parts/chart-metric.d.ts +118 -0
- package/dist/components/ui/chart/parts/chart-primitives.d.ts +101 -0
- package/dist/components/ui/chart/parts/chart-shared.d.ts +20 -0
- package/dist/components/ui/chart/parts/chart-utils.d.ts +12 -0
- package/dist/components/ui/chart/parts/index.d.ts +5 -0
- package/dist/dropdown-menu-BDB5CmQs.cjs +247 -0
- package/dist/dropdown-menu-BMcykFDf.cjs +225 -0
- package/dist/dropdown-menu-DQidbKBD.js +231 -0
- package/dist/dropdown-menu-Dn_eV2Xb.js +190 -0
- package/dist/google-maps-loader-BCe58h9D.js +308 -0
- package/dist/google-maps-loader-BFWp6VPd.js +287 -0
- package/dist/google-maps-loader-BKcdgFbu.cjs +312 -0
- package/dist/{google-maps-loader-t2IlYBzw.js → google-maps-loader-CTYySAun.js} +4 -0
- package/dist/google-maps-loader-CumCNXeG.js +312 -0
- package/dist/{google-maps-loader-BqsYL48U.cjs → google-maps-loader-Y-QkD-Li.cjs} +5 -0
- package/dist/google-maps-loader-casMyxlo.cjs +316 -0
- package/dist/google-maps-loader-eS3uQ5TA.cjs +287 -0
- package/dist/header-Cgy6vYPk.cjs +731 -0
- package/dist/header-DRlT4jgI.js +715 -0
- package/dist/header-Dux00SI4.cjs +731 -0
- package/dist/header-EkGKXPsD.js +715 -0
- package/dist/header-WfEywpyc.cjs +731 -0
- package/dist/header-tifNQn2U.js +715 -0
- package/dist/hooks.cjs.js +12 -8
- package/dist/hooks.es.js +10 -27
- package/dist/index-9GWd0qxq.cjs +12 -0
- package/dist/index-BabBx2pa.js +6 -0
- package/dist/index-BhapVLVj.js +8 -0
- package/dist/{index-D3RLKRAs.cjs → index-COtD8bRW.cjs} +1 -1
- package/dist/index-D6fxYEY8.cjs +7 -0
- package/dist/index-DAIp0_HK.js +8 -0
- package/dist/index-DW5tYe26.js +8 -0
- package/dist/index-GA__GvnG.cjs +7 -0
- package/dist/index.cjs.js +37 -32
- package/dist/index.es.js +30 -363
- package/dist/index.umd.js +1043 -470
- package/dist/input-2R4loU86.js +127 -0
- package/dist/input-C_UiS2Py.cjs +152 -0
- package/dist/input-DWANSKGb.cjs +145 -0
- package/dist/input-cc-PTD4R.js +123 -0
- package/dist/layout.cjs.js +10 -6
- package/dist/layout.es.js +7 -9
- package/dist/media.cjs.js +8 -3
- package/dist/media.es.js +1 -6
- package/dist/pages.cjs.js +8 -3
- package/dist/pages.es.js +1 -11
- package/dist/progress-C7Lti5wo.js +80 -0
- package/dist/progress-Cqwxbqs1.cjs +103 -0
- package/dist/progress-DPtzoVV8.js +175 -0
- package/dist/progress-EeaoqqUs.cjs +191 -0
- package/dist/rich-text-editor-0mraWT5y.cjs +2376 -0
- package/dist/rich-text-editor-B-IkcPD0.js +2874 -0
- package/dist/rich-text-editor-B6jMRLzk.cjs +1939 -0
- package/dist/rich-text-editor-B8_oYcIR.js +1730 -0
- package/dist/rich-text-editor-B9UbSXNb.js +1203 -0
- package/dist/rich-text-editor-BYuRBNBU.js +2373 -0
- package/dist/rich-text-editor-Bb9pySTs.cjs +2374 -0
- package/dist/rich-text-editor-BcL6L3cm.cjs +2374 -0
- package/dist/rich-text-editor-BoVZYtTs.cjs +2391 -0
- package/dist/rich-text-editor-Bp3zQqMC.js +2954 -0
- package/dist/rich-text-editor-CMgSN_w2.js +1189 -0
- package/dist/rich-text-editor-CPV1lEPH.cjs +1748 -0
- package/dist/rich-text-editor-CeucBdIv.cjs +2971 -0
- package/dist/rich-text-editor-CoKqbCtu.cjs +1799 -0
- package/dist/rich-text-editor-Cw56T_mB.js +2356 -0
- package/dist/rich-text-editor-Cyt8qs2b.js +1921 -0
- package/dist/rich-text-editor-D6H84OcX.cjs +1220 -0
- package/dist/rich-text-editor-D76gD-QI.js +2328 -0
- package/dist/rich-text-editor-DKkokOnA.js +1781 -0
- package/dist/rich-text-editor-DNsdpN64.cjs +2359 -0
- package/dist/rich-text-editor-DfG8bCyY.js +2358 -0
- package/dist/rich-text-editor-DqLICivI.js +2832 -0
- package/dist/rich-text-editor-DxO1Hz3a.cjs +2903 -0
- package/dist/rich-text-editor-Dxjw31Z4.js +2341 -0
- package/dist/rich-text-editor-DzP0Epmb.js +2356 -0
- package/dist/rich-text-editor-bRkNoeZY.cjs +2891 -0
- package/dist/rich-text-editor-lyYE2ZG5.cjs +1207 -0
- package/dist/rich-text-editor-skplNlBM.cjs +2345 -0
- package/dist/select-Bkbr0f-Z.cjs +162 -0
- package/dist/select-CH6v_KcQ.cjs +161 -0
- package/dist/select-CvIVdX2n.js +145 -0
- package/dist/select-D-xvCZK2.js +130 -0
- package/dist/{sidebar-CplprZpM.js → sidebar-3XyzjVBw.js} +40 -49
- package/dist/{sidebar-OTO_up7Z.js → sidebar-B6SlKZYN.js} +40 -49
- package/dist/{sidebar-CmvwjnVb.js → sidebar-BViy8Eeu.js} +17 -9
- package/dist/{sidebar-Dz7bd3zP.js → sidebar-BbVIQvlP.js} +1 -1
- package/dist/{sidebar-CVUGHOS_.cjs → sidebar-BxGXsDAd.cjs} +16 -8
- package/dist/sidebar-CK_0ZQHj.cjs +803 -0
- package/dist/{sidebar-KIS0C2JH.js → sidebar-CRMiBtAi.js} +1 -1
- package/dist/sidebar-CUuOvYhK.js +787 -0
- package/dist/{sidebar-zowjejT2.cjs → sidebar-CZ2mWaMM.cjs} +1 -1
- package/dist/{sidebar-CA6_ek3f.js → sidebar-CrQDDdcz.js} +24 -33
- package/dist/{sidebar-BvF5I2Ue.cjs → sidebar-DAaY8bRU.cjs} +24 -33
- package/dist/sidebar-DQj1z3jG.cjs +758 -0
- package/dist/sidebar-Djn5syhi.cjs +786 -0
- package/dist/{sidebar-B3EYhli0.cjs → sidebar-DyYvgyBj.cjs} +41 -46
- package/dist/sidebar-LluMXfam.js +759 -0
- package/dist/sidebar-_rT7rBMk.js +787 -0
- package/dist/{sidebar-B9NR0lCe.cjs → sidebar-nzPoVHBQ.cjs} +41 -46
- package/dist/{sidebar-C5B_LHek.cjs → sidebar-q7P2Godd.cjs} +1 -1
- package/dist/skeleton-DjiHerJn.cjs +87 -0
- package/dist/skeleton-DtR5tkYe.js +78 -0
- package/dist/slider-B00b9SVK.cjs +78 -0
- package/dist/slider-Bc5Hd0y1.js +56 -0
- package/dist/slider-DQCNUUMj.js +56 -0
- package/dist/slider-N7hFFj6X.cjs +73 -0
- package/dist/sonner-B-jWlik1.cjs +68 -0
- package/dist/sonner-C9tiqj4f.js +47 -0
- package/dist/tooltip-D8n9UYoU.cjs +72 -0
- package/dist/tooltip-Ded96neP.cjs +137 -0
- package/dist/tooltip-HDOoD2-0.js +120 -0
- package/dist/tooltip-RtbSmPYJ.js +48 -0
- package/dist/ui.cjs.js +23 -18
- package/dist/ui.es.js +16 -303
- package/dist/use-audio-player-B31J-aqh.cjs +187 -0
- package/dist/use-audio-player-B78fd2ct.js +188 -0
- package/dist/use-audio-player-BkmEmj8Q.js +185 -0
- package/dist/use-audio-player-CLFTWFW1.cjs +184 -0
- package/dist/use-audio-player-CLLn00I6.js +188 -0
- package/dist/use-audio-player-DGvhPrgR.cjs +190 -0
- package/dist/{use-audio-player-Dn1NR9xN.cjs → use-audio-player-NKsWyjWu.cjs} +7 -3
- package/dist/{use-audio-player-Bkh23vQ3.js → use-audio-player-nv8ZSGa1.js} +7 -3
- package/dist/use-file-upload-BcjEo2S5.js +404 -0
- package/dist/use-file-upload-CRJR68Tj.cjs +403 -0
- package/dist/use-mobile-B0hNy_Y6.cjs +4303 -0
- package/dist/use-mobile-BXuYROXM.js +4202 -0
- package/dist/use-mobile-Bbd51ASU.cjs +4392 -0
- package/dist/use-mobile-BdXTRb0Z.cjs +51 -0
- package/dist/use-mobile-Bk6CX-TC.js +4359 -0
- package/dist/use-mobile-BvYdisLP.js +4202 -0
- package/dist/use-mobile-BzuxjzNX.cjs +4392 -0
- package/dist/use-mobile-CG2-SdXV.cjs +4235 -0
- package/dist/use-mobile-CKb5pqTs.js +4269 -0
- package/dist/use-mobile-CYuAuGDl.js +4202 -0
- package/dist/use-mobile-CaENcqm-.js +4508 -0
- package/dist/use-mobile-CbrYgJGJ.js +4203 -0
- package/dist/use-mobile-Cd4xPrKq.cjs +46 -0
- package/dist/use-mobile-Ce2cBAQe.js +29 -0
- package/dist/use-mobile-DMOvImGQ.cjs +4542 -0
- package/dist/use-mobile-DRB3BQgD.cjs +4235 -0
- package/dist/use-mobile-DZvv7QMR.js +4359 -0
- package/dist/use-mobile-DdI_TXam.cjs +4235 -0
- package/dist/use-mobile-DlceKf8a.js +4359 -0
- package/dist/use-mobile-DsOnow1o.cjs +4236 -0
- package/dist/use-mobile-Kcj6jSnK.cjs +4392 -0
- package/dist/use-mobile-bnKcua_i.js +4202 -0
- package/dist/use-mobile-j4w2Jrf1.js +30 -0
- package/dist/use-mobile-ncXBeE2z.cjs +4235 -0
- package/dist/use-rich-text-editor-DjiddBGv.js +282 -0
- package/dist/use-rich-text-editor-lpeswbCs.cjs +281 -0
- package/dist/xertica-assistant-B687qEPU.js +2165 -0
- package/dist/xertica-assistant-BdiZag0h.js +2187 -0
- package/dist/xertica-assistant-CrgTb6Hs.cjs +2155 -0
- package/dist/xertica-assistant-DCsnQyi5.js +2156 -0
- package/dist/xertica-assistant-DUBpmEgo.cjs +2186 -0
- package/dist/{xertica-assistant-Bj3vBCq_.cjs → xertica-assistant-V_IdW4WF.cjs} +27 -9
- package/dist/{xertica-assistant-BMqdyRVi.js → xertica-assistant-ciJaWqm1.js} +28 -10
- package/dist/{xertica-assistant-B1IaHXnB.cjs → xertica-assistant-dyP7KHM5.cjs} +533 -392
- package/dist/xertica-assistant-sOHwTgIP.cjs +2172 -0
- package/dist/{xertica-assistant-DPsESB6t.js → xertica-assistant-yX1CFBBo.js} +535 -394
- package/dist/xertica-ui.css +2 -2
- package/docs/ai-usage.md +195 -195
- package/docs/components/accordion.md +109 -109
- package/docs/components/alert-dialog.md +127 -127
- package/docs/components/alert.md +106 -106
- package/docs/components/aspect-ratio.md +58 -58
- package/docs/components/assistant-chart.md +47 -47
- package/docs/components/assistant.md +2 -0
- package/docs/components/audio-player.md +167 -167
- package/docs/components/avatar.md +101 -101
- package/docs/components/badge.md +84 -84
- package/docs/components/breadcrumb.md +104 -104
- package/docs/components/button.md +156 -156
- package/docs/components/calendar.md +141 -141
- package/docs/components/card.md +245 -245
- package/docs/components/carousel.md +100 -100
- package/docs/components/chart.md +638 -638
- package/docs/components/checkbox.md +88 -88
- package/docs/components/code-block.md +105 -105
- package/docs/components/collapsible.md +86 -86
- package/docs/components/command.md +113 -113
- package/docs/components/context-menu.md +81 -81
- package/docs/components/dialog.md +198 -198
- package/docs/components/drawer.md +105 -105
- package/docs/components/dropdown-menu.md +127 -127
- package/docs/components/empty.md +127 -127
- package/docs/components/error-boundary.md +191 -191
- package/docs/components/file-upload.md +189 -189
- package/docs/components/floating-media-wrapper.md +63 -63
- package/docs/components/form.md +177 -177
- package/docs/components/formatted-document.md +105 -105
- package/docs/components/google-maps-loader.md +44 -44
- package/docs/components/header.md +177 -177
- package/docs/components/hover-card.md +86 -86
- package/docs/components/image-with-fallback.md +107 -107
- package/docs/components/input-otp.md +95 -95
- package/docs/components/input.md +130 -130
- package/docs/components/label.md +69 -69
- package/docs/components/language-selector.md +172 -172
- package/docs/components/map-layers.md +138 -138
- package/docs/components/map.md +84 -84
- package/docs/components/markdown-message.md +47 -47
- package/docs/components/menubar.md +89 -89
- package/docs/components/modern-chat-input.md +164 -164
- package/docs/components/navigation-menu.md +83 -83
- package/docs/components/notification-badge.md +78 -78
- package/docs/components/page-header.md +93 -93
- package/docs/components/pages.md +309 -309
- package/docs/components/pagination.md +334 -334
- package/docs/components/popover.md +116 -116
- package/docs/components/progress.md +103 -103
- package/docs/components/radio-group.md +133 -133
- package/docs/components/rating.md +77 -77
- package/docs/components/resizable.md +84 -84
- package/docs/components/rich-text-editor.md +255 -255
- package/docs/components/route-map.md +124 -124
- package/docs/components/scroll-area.md +58 -58
- package/docs/components/search.md +87 -87
- package/docs/components/select.md +144 -144
- package/docs/components/separator.md +58 -58
- package/docs/components/sheet.md +122 -122
- package/docs/components/sidebar.md +314 -314
- package/docs/components/simple-map.md +51 -51
- package/docs/components/skeleton.md +99 -99
- package/docs/components/slider.md +84 -84
- package/docs/components/sonner.md +115 -115
- package/docs/components/stats-card.md +120 -120
- package/docs/components/stepper.md +268 -268
- package/docs/components/switch.md +106 -106
- package/docs/components/table.md +138 -138
- package/docs/components/tabs.md +117 -117
- package/docs/components/textarea.md +86 -86
- package/docs/components/theme-toggle.md +73 -73
- package/docs/components/timeline.md +121 -121
- package/docs/components/toggle-group.md +68 -68
- package/docs/components/toggle.md +62 -62
- package/docs/components/tooltip.md +116 -116
- package/docs/components/tree-view.md +238 -238
- package/docs/components/use-mobile.md +96 -96
- package/docs/components/video-player.md +68 -68
- package/docs/components/xertica-logo.md +36 -36
- package/docs/components/xertica-orbe.md +35 -35
- package/docs/components/xertica-provider.md +65 -65
- package/docs/components/xertica-xlogo.md +35 -35
- package/docs/decision-tree.md +293 -293
- package/docs/form-sizing.md +162 -162
- package/docs/getting-started.md +24 -12
- package/docs/i18n.md +476 -476
- package/docs/installation.md +267 -267
- package/docs/layout.md +143 -143
- package/docs/patterns/analytics.md +194 -194
- package/docs/patterns/crud.md +149 -149
- package/docs/patterns/dashboard.md +138 -138
- package/docs/patterns/detail-page.md +296 -296
- package/docs/patterns/form.md +241 -241
- package/docs/patterns/login.md +156 -156
- package/docs/patterns/settings.md +368 -368
- package/docs/patterns/wizard.md +213 -213
- package/hooks/useTheme.test.tsx +16 -16
- package/hooks/useTheme.ts +4 -4
- package/imports/Podcast.tsx +540 -540
- package/imports/XerticaAi.tsx +46 -46
- package/imports/XerticaX.tsx +15 -15
- package/imports/svg-aueiaqngck.ts +20 -20
- package/imports/svg-v9krss1ozd.ts +23 -23
- package/imports/svg-vhrdofe3qe.ts +6 -6
- package/llms-compact.txt +2 -1
- package/llms.txt +2 -1
- package/mcp/resources.json +22 -22
- package/mcp/tools.json +35 -35
- package/package.json +10 -4
- package/scripts/ai-validator.ts +91 -91
- package/scripts/cleanup-case-dupes.ts +62 -62
- package/scripts/generate-ai-manifests.ts +107 -107
- package/styles/globals.css +13 -13
- package/styles/xertica/app-overrides/chat.css +61 -61
- package/styles/xertica/app-overrides/scrollbar.css +33 -33
- package/styles/xertica/base.css +84 -71
- package/styles/xertica/integrations/google-maps.css +76 -76
- package/styles/xertica/integrations/sonner.css +73 -73
- package/styles/xertica/theme-map.css +102 -99
- package/styles/xertica/tokens.css +240 -236
- package/templates/.prettierignore +4 -4
- package/templates/.prettierrc +10 -10
- package/templates/CLAUDE.md +116 -131
- package/templates/eslint.config.js +26 -26
- package/templates/package.json +3 -3
- package/templates/postcss.config.js +6 -6
- package/templates/src/app/components/AppLayout.tsx +55 -55
- package/templates/src/app/components/AuthGuard.tsx +82 -82
- package/templates/src/app/context/AuthContext.tsx +108 -108
- package/templates/src/features/assistant/data/mock.ts +75 -75
- package/templates/src/features/assistant/hooks/useAssistantConfig.ts +20 -20
- package/templates/src/features/auth/index.ts +4 -4
- package/templates/src/features/auth/ui/AuthPageShell.tsx +32 -32
- package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +9 -7
- package/templates/src/features/auth/ui/LoginContent.tsx +10 -8
- package/templates/src/features/auth/ui/ResetPasswordContent.tsx +17 -15
- package/templates/src/features/auth/ui/SocialLoginButtons.tsx +9 -4
- package/templates/src/features/auth/ui/VerifyEmailContent.tsx +11 -9
- package/templates/src/features/home/data/mock.ts +35 -35
- package/templates/src/features/home/hooks/useFeatureCards.ts +20 -20
- package/templates/src/features/home/store/dashboardStore.ts +25 -25
- package/templates/src/features/home/ui/HomeContent.tsx +1 -1
- package/templates/src/features/template/index.ts +5 -5
- package/templates/src/features/template/ui/CrudTemplate.tsx +115 -115
- package/templates/src/features/template/ui/DashboardTemplate.tsx +110 -110
- package/templates/src/features/template/ui/FormTemplate.tsx +117 -117
- package/templates/src/features/template/ui/LoginTemplate.tsx +59 -59
- package/templates/src/features/template/ui/TemplateContent.tsx +1314 -1314
- package/templates/src/i18n.ts +124 -124
- package/templates/src/locales/en/common.json +21 -21
- package/templates/src/locales/en/components/activityCard.json +10 -10
- package/templates/src/locales/en/components/assistant.json +119 -105
- package/templates/src/locales/en/components/media.json +29 -29
- package/templates/src/locales/en/components/notificationCard.json +5 -5
- package/templates/src/locales/en/components/profileCard.json +8 -8
- package/templates/src/locales/en/components/projectCard.json +10 -10
- package/templates/src/locales/en/components/sidebar.json +14 -14
- package/templates/src/locales/en/components/stats.json +8 -8
- package/templates/src/locales/en/components/team.json +14 -14
- package/templates/src/locales/en/errors.json +9 -9
- package/templates/src/locales/en/languageSelector.json +7 -7
- package/templates/src/locales/en/nav.json +6 -6
- package/templates/src/locales/en/pages/crudTemplate.json +25 -25
- package/templates/src/locales/en/pages/dashboardTemplate.json +20 -20
- package/templates/src/locales/en/pages/forgotPassword.json +10 -0
- package/templates/src/locales/en/pages/formTemplate.json +16 -16
- package/templates/src/locales/en/pages/home.json +7 -7
- package/templates/src/locales/en/pages/login.json +15 -15
- package/templates/src/locales/en/pages/loginTemplate.json +9 -9
- package/templates/src/locales/en/pages/resetPassword.json +18 -18
- package/templates/src/locales/en/pages/templates.json +317 -317
- package/templates/src/locales/en/pages/verifyEmail.json +12 -12
- package/templates/src/locales/en/themeToggle.json +6 -6
- package/templates/src/locales/es/common.json +21 -21
- package/templates/src/locales/es/components/activityCard.json +10 -10
- package/templates/src/locales/es/components/assistant.json +119 -105
- package/templates/src/locales/es/components/media.json +29 -29
- package/templates/src/locales/es/components/notificationCard.json +5 -5
- package/templates/src/locales/es/components/profileCard.json +8 -8
- package/templates/src/locales/es/components/projectCard.json +10 -10
- package/templates/src/locales/es/components/sidebar.json +14 -14
- package/templates/src/locales/es/components/stats.json +8 -8
- package/templates/src/locales/es/components/team.json +14 -14
- package/templates/src/locales/es/errors.json +9 -9
- package/templates/src/locales/es/languageSelector.json +7 -7
- package/templates/src/locales/es/nav.json +6 -6
- package/templates/src/locales/es/pages/crudTemplate.json +25 -25
- package/templates/src/locales/es/pages/dashboardTemplate.json +20 -20
- package/templates/src/locales/es/pages/forgotPassword.json +10 -0
- package/templates/src/locales/es/pages/formTemplate.json +16 -16
- package/templates/src/locales/es/pages/home.json +7 -7
- package/templates/src/locales/es/pages/login.json +15 -15
- package/templates/src/locales/es/pages/loginTemplate.json +9 -9
- package/templates/src/locales/es/pages/resetPassword.json +18 -18
- package/templates/src/locales/es/pages/templates.json +317 -317
- package/templates/src/locales/es/pages/verifyEmail.json +12 -12
- package/templates/src/locales/es/themeToggle.json +6 -6
- package/templates/src/locales/pt-BR/common.json +21 -21
- package/templates/src/locales/pt-BR/components/activityCard.json +10 -10
- package/templates/src/locales/pt-BR/components/assistant.json +119 -105
- package/templates/src/locales/pt-BR/components/media.json +29 -29
- package/templates/src/locales/pt-BR/components/notificationCard.json +5 -5
- package/templates/src/locales/pt-BR/components/profileCard.json +8 -8
- package/templates/src/locales/pt-BR/components/projectCard.json +10 -10
- package/templates/src/locales/pt-BR/components/sidebar.json +14 -14
- package/templates/src/locales/pt-BR/components/stats.json +8 -8
- package/templates/src/locales/pt-BR/components/team.json +14 -14
- package/templates/src/locales/pt-BR/errors.json +9 -9
- package/templates/src/locales/pt-BR/languageSelector.json +7 -7
- package/templates/src/locales/pt-BR/nav.json +6 -6
- package/templates/src/locales/pt-BR/pages/crudTemplate.json +25 -25
- package/templates/src/locales/pt-BR/pages/dashboardTemplate.json +20 -20
- package/templates/src/locales/pt-BR/pages/forgotPassword.json +10 -0
- package/templates/src/locales/pt-BR/pages/formTemplate.json +16 -16
- package/templates/src/locales/pt-BR/pages/home.json +7 -7
- package/templates/src/locales/pt-BR/pages/login.json +15 -15
- package/templates/src/locales/pt-BR/pages/loginTemplate.json +9 -9
- package/templates/src/locales/pt-BR/pages/resetPassword.json +18 -18
- package/templates/src/locales/pt-BR/pages/templates.json +317 -317
- package/templates/src/locales/pt-BR/pages/verifyEmail.json +12 -12
- package/templates/src/locales/pt-BR/themeToggle.json +6 -6
- package/templates/src/main.tsx +11 -11
- package/templates/src/pages/AssistantPage.tsx +37 -36
- package/templates/src/pages/ForgotPasswordPage.tsx +6 -6
- package/templates/src/pages/LoginPage.tsx +10 -10
- package/templates/src/pages/ResetPasswordPage.tsx +6 -6
- package/templates/src/pages/TemplatePage.tsx +28 -28
- package/templates/src/pages/VerifyEmailPage.tsx +6 -6
- package/templates/src/shared/config/navigation.ts +19 -19
- package/templates/src/shared/error-boundary.tsx +154 -154
- package/templates/src/shared/error-fallbacks.tsx +226 -226
- package/templates/src/shared/lib/auth.ts +20 -20
- package/templates/src/shared/types/auth.ts +3 -3
- package/templates/src/styles/index.css +95 -95
- package/templates/src/styles/xertica/tokens.css +240 -236
- package/templates/tsconfig.json +25 -25
- package/templates/tsconfig.node.json +12 -12
- package/templates/vite-env.d.ts +1 -1
- package/templates/vite.config.ts +1 -1
- package/utils/color-utils.ts +72 -72
- package/utils/demo-responses.test.ts +10 -10
- package/utils/demo-responses.ts +151 -151
- package/utils/gemini.test.ts +25 -25
- package/utils/gemini.ts +155 -155
- package/dist/ThemeContext-CpqYShLq.cjs +0 -324
- package/dist/ThemeContext-Du2nE1PL.js +0 -325
- package/dist/ThemeContext-GeEBTJ3q.cjs +0 -1621
- package/dist/ThemeContext-JyLK9B1o.js +0 -1622
- package/dist/index-CkTUgOwX.js +0 -8
- package/dist/{rich-text-editor-BmsjY03B.js → rich-text-editor-DgF8s7xW.js} +26 -26
- package/dist/{rich-text-editor-GS2kpTAK.cjs → rich-text-editor-mWoaSCE4.cjs} +26 -26
package/docs/i18n.md
CHANGED
|
@@ -1,476 +1,476 @@
|
|
|
1
|
-
# Internationalization (i18n) — Xertica UI
|
|
2
|
-
|
|
3
|
-
Xertica UI projects use **`i18next`** with the **`react-i18next`** binding for all UI string translations. The `LanguageSelector` component is wired directly to `i18next` — changing the language immediately updates every `useTranslation()` consumer in the app and invalidates the React Query cache so that data-layer strings (mock API responses) also refresh.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Setup
|
|
8
|
-
|
|
9
|
-
### 1. Install
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
npm install i18next react-i18next
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Both packages are listed in `templates/package.json` and are installed automatically by `npx xertica-ui@latest init`.
|
|
16
|
-
|
|
17
|
-
### 2. Create locale files
|
|
18
|
-
|
|
19
|
-
Locales are organized as one **folder per language**, split by category:
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
src/locales/
|
|
23
|
-
├── .languages.json ← CLI-managed selection ({ "version": 1, "codes": [...] })
|
|
24
|
-
├── pt-BR/ ← default & fallback (only your selected languages are present)
|
|
25
|
-
│ ├── common.json ← shared action labels (view, edit, save, cancel…)
|
|
26
|
-
│ ├── nav.json ← navigation labels
|
|
27
|
-
│ ├── errors.json ← error boundary UI
|
|
28
|
-
│ ├── languageSelector.json ← language picker UI
|
|
29
|
-
│ ├── themeToggle.json ← theme toggle UI
|
|
30
|
-
│ ├── pages/
|
|
31
|
-
│ │ ├── home.json
|
|
32
|
-
│ │ ├── templates.json
|
|
33
|
-
│ │ ├── login.json
|
|
34
|
-
│ │ ├── resetPassword.json
|
|
35
|
-
│ │ ├── verifyEmail.json
|
|
36
|
-
│ │ ├── loginTemplate.json ← starter template pages
|
|
37
|
-
│ │ ├── formTemplate.json
|
|
38
|
-
│ │ ├── dashboardTemplate.json
|
|
39
|
-
│ │ └── crudTemplate.json
|
|
40
|
-
│ └── components/
|
|
41
|
-
│ ├── assistant.json
|
|
42
|
-
│ ├── sidebar.json
|
|
43
|
-
│ ├── media.json
|
|
44
|
-
│ ├── projectCard.json
|
|
45
|
-
│ ├── profileCard.json
|
|
46
|
-
│ ├── notificationCard.json
|
|
47
|
-
│ ├── activityCard.json
|
|
48
|
-
│ ├── stats.json
|
|
49
|
-
│ └── team.json
|
|
50
|
-
├── en/ ← same structure
|
|
51
|
-
└── es/ ← same structure
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Each JSON file contains only the keys for its category (no top-level wrapper key). For example, `locales/pt-BR/common.json`:
|
|
55
|
-
|
|
56
|
-
```json
|
|
57
|
-
{ "view": "Visualizar", "edit": "Editar", "loading": "Carregando...", "cancel": "Cancelar" }
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
And `locales/pt-BR/pages/home.json`:
|
|
61
|
-
|
|
62
|
-
```json
|
|
63
|
-
{ "welcome": "Bem-vindo ao Design System!", "subtitle": "...", "templateCliTitle": "Template CLI" }
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
> All files under `locales/<lang>/` are automatically discovered by `import.meta.glob` in `i18n.ts`. Adding a new JSON file requires no changes to `i18n.ts` — Vite picks it up on the next build.
|
|
67
|
-
|
|
68
|
-
### 3. Create `src/i18n.ts`
|
|
69
|
-
|
|
70
|
-
```ts
|
|
71
|
-
import i18n from 'i18next';
|
|
72
|
-
import { initReactI18next } from 'react-i18next';
|
|
73
|
-
|
|
74
|
-
// Merges the split JSON files (pages/, components/) into one flat bundle per language.
|
|
75
|
-
// The key is the file basename — folder (pages/components) is discarded.
|
|
76
|
-
// Adding a new JSON file under locales/<lang>/... is auto-discovered by Vite.
|
|
77
|
-
function bundleLang(chunks: Record<string, unknown>): Record<string, unknown> {
|
|
78
|
-
const out: Record<string, unknown> = {};
|
|
79
|
-
for (const [filePath, value] of Object.entries(chunks)) {
|
|
80
|
-
const base = filePath.split('/').pop();
|
|
81
|
-
if (!base) continue;
|
|
82
|
-
out[base.replace(/\.json$/, '')] = value;
|
|
83
|
-
}
|
|
84
|
-
return out;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// `import.meta.glob` requires a literal pattern — one call per language.
|
|
88
|
-
// `eager: true` inlines the JSON at build time (no runtime fetch).
|
|
89
|
-
const ptBR = bundleLang(
|
|
90
|
-
import.meta.glob('./locales/pt-BR/**/*.json', { eager: true, import: 'default' })
|
|
91
|
-
);
|
|
92
|
-
const en = bundleLang(
|
|
93
|
-
import.meta.glob('./locales/en/**/*.json', { eager: true, import: 'default' })
|
|
94
|
-
);
|
|
95
|
-
const es = bundleLang(
|
|
96
|
-
import.meta.glob('./locales/es/**/*.json', { eager: true, import: 'default' })
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
const savedLanguage =
|
|
100
|
-
typeof window !== 'undefined'
|
|
101
|
-
? (localStorage.getItem('xertica_language') ?? 'pt-BR')
|
|
102
|
-
: 'pt-BR';
|
|
103
|
-
|
|
104
|
-
i18n.use(initReactI18next).init({
|
|
105
|
-
resources: {
|
|
106
|
-
'pt-BR': { translation: ptBR },
|
|
107
|
-
en: { translation: en },
|
|
108
|
-
es: { translation: es },
|
|
109
|
-
},
|
|
110
|
-
lng: savedLanguage,
|
|
111
|
-
fallbackLng: 'pt-BR',
|
|
112
|
-
interpolation: { escapeValue: false }, // React escapes already
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
export default i18n;
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
### 4. Initialize before rendering
|
|
119
|
-
|
|
120
|
-
```ts
|
|
121
|
-
// src/main.tsx — BEFORE any component import
|
|
122
|
-
import './i18n'; // side-effect: initializes i18next synchronously
|
|
123
|
-
import App from './app/App';
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
---
|
|
127
|
-
|
|
128
|
-
## Using Translations in Components
|
|
129
|
-
|
|
130
|
-
```tsx
|
|
131
|
-
import { useTranslation } from 'react-i18next';
|
|
132
|
-
|
|
133
|
-
function HomeContent() {
|
|
134
|
-
const { t } = useTranslation();
|
|
135
|
-
|
|
136
|
-
return (
|
|
137
|
-
<div>
|
|
138
|
-
<h1>{t('home.welcome')}</h1>
|
|
139
|
-
<p>{t('home.subtitle')}</p>
|
|
140
|
-
<button>{t('common.view')}</button>
|
|
141
|
-
</div>
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
### Interpolation
|
|
147
|
-
|
|
148
|
-
```json
|
|
149
|
-
{ "team": { "showing": "Exibindo {{count}} de {{total}} usuários" } }
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
```tsx
|
|
153
|
-
t('team.showing', { count: 5, total: 127 })
|
|
154
|
-
// → "Exibindo 5 de 127 usuários"
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
---
|
|
158
|
-
|
|
159
|
-
## Language Switching
|
|
160
|
-
|
|
161
|
-
The `LanguageSelector` component (from `xertica-ui/brand`) handles the full switching flow automatically:
|
|
162
|
-
|
|
163
|
-
1. User selects a language in the dropdown
|
|
164
|
-
2. `setLanguage(lang)` is called on `LanguageContext`
|
|
165
|
-
3. `LanguageContext` writes to `localStorage` (key: `xertica_language`) and calls `i18n.changeLanguage(lang)`
|
|
166
|
-
4. All components using `useTranslation()` re-render with the new locale
|
|
167
|
-
5. `queryClient.invalidateQueries()` is called — React Query refetches any query whose result contains translated strings
|
|
168
|
-
|
|
169
|
-
```tsx
|
|
170
|
-
// Manual language change (without LanguageSelector)
|
|
171
|
-
import { useLanguage } from 'xertica-ui/hooks';
|
|
172
|
-
|
|
173
|
-
const { setLanguage } = useLanguage();
|
|
174
|
-
setLanguage('en'); // persists + calls i18n.changeLanguage('en') + invalidates React Query cache
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### Language codes
|
|
178
|
-
|
|
179
|
-
| Code | Display | Stored as |
|
|
180
|
-
|---|---|---|
|
|
181
|
-
| `'pt-BR'` | Português (BR) | `'pt-BR'` in `localStorage` |
|
|
182
|
-
| `'en'` | English | `'en'` |
|
|
183
|
-
| `'es'` | Español | `'es'` |
|
|
184
|
-
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
## Translation Key Namespaces
|
|
188
|
-
|
|
189
|
-
The project uses a single `translation` namespace. Each top-level key maps to a separate JSON file under `locales/<lang>/`:
|
|
190
|
-
|
|
191
|
-
**Root files** (`locales/<lang>/<key>.json`):
|
|
192
|
-
|
|
193
|
-
| Namespace | File | Example keys |
|
|
194
|
-
|---|---|---|
|
|
195
|
-
| `common` | `common.json` | `common.view`, `common.edit`, `common.loading`, `common.close`, `common.copied` |
|
|
196
|
-
| `nav` | `nav.json` | `nav.home`, `nav.designSystem`, `nav.settings` |
|
|
197
|
-
| `errors` | `errors.json` | `errors.somethingWentWrong`, `errors.tryAgain`, `errors.pageLoadError` |
|
|
198
|
-
| `languageSelector` | `languageSelector.json` | `languageSelector.label`, `languageSelector.ptBR` |
|
|
199
|
-
| `themeToggle` | `themeToggle.json` | `themeToggle.switchToLight`, `themeToggle.darkMode` |
|
|
200
|
-
|
|
201
|
-
**Page files** (`locales/<lang>/pages/<key>.json`):
|
|
202
|
-
|
|
203
|
-
| Namespace | File | Example keys |
|
|
204
|
-
|---|---|---|
|
|
205
|
-
| `home` | `pages/home.json` | `home.welcome`, `home.subtitle`, `home.templateCliTitle` |
|
|
206
|
-
| `templates` | `pages/templates.json` | `templates.title`, `templates.alerts.infoTitle`, `templates.forms.firstName` |
|
|
207
|
-
| `login` | `pages/login.json` | `login.heading`, `login.submit`, `login.forgotPassword` |
|
|
208
|
-
| `resetPassword` | `pages/resetPassword.json` | `resetPassword.heading`, `resetPassword.errorMismatch` |
|
|
209
|
-
| `verifyEmail` | `pages/verifyEmail.json` | `verifyEmail.heading`, `verifyEmail.resend` |
|
|
210
|
-
| `loginTemplate` | `pages/loginTemplate.json` | `loginTemplate.title`, `loginTemplate.submit` |
|
|
211
|
-
| `formTemplate` | `pages/formTemplate.json` | `formTemplate.title`, `formTemplate.save`, `formTemplate.errors.fullNameRequired` |
|
|
212
|
-
| `dashboardTemplate` | `pages/dashboardTemplate.json` | `dashboardTemplate.title`, `dashboardTemplate.stats.totalRevenue` |
|
|
213
|
-
| `crudTemplate` | `pages/crudTemplate.json` | `crudTemplate.title`, `crudTemplate.actions.editProfile` |
|
|
214
|
-
|
|
215
|
-
**Component files** (`locales/<lang>/components/<key>.json`):
|
|
216
|
-
|
|
217
|
-
| Namespace | File | Example keys |
|
|
218
|
-
|---|---|---|
|
|
219
|
-
| `assistant` | `components/assistant.json` | `assistant.title`, `assistant.inputPlaceholder`, `assistant.tabs.chat`, `assistant.feedbackDialog.title` |
|
|
220
|
-
| `sidebar` | `components/sidebar.json` | `sidebar.collapse`, `sidebar.logout`, `sidebar.moreOptions` |
|
|
221
|
-
| `media` | `components/media.json` | `media.play`, `media.pause`, `media.downloadAudio`, `media.floatingMode` |
|
|
222
|
-
| `projectCard` | `components/projectCard.json` | `projectCard.progress`, `projectCard.status.active` |
|
|
223
|
-
| `profileCard` | `components/profileCard.json` | `profileCard.status.online`, `profileCard.status.busy` |
|
|
224
|
-
| `notificationCard` | `components/notificationCard.json` | `notificationCard.title`, `notificationCard.markAllRead` |
|
|
225
|
-
| `activityCard` | `components/activityCard.json` | `activityCard.title`, `activityCard.type.create` |
|
|
226
|
-
| `stats` | `components/stats.json` | `stats.totalUsers`, `stats.last30Days` |
|
|
227
|
-
| `team` | `components/team.json` | `team.name`, `team.roles.Developer`, `team.showing` |
|
|
228
|
-
|
|
229
|
-
---
|
|
230
|
-
|
|
231
|
-
## Translating Mock Data
|
|
232
|
-
|
|
233
|
-
Mock data fetch functions use `i18n.t()` (the instance, not the hook) so they respond to the active language when called from a React Query `queryFn`:
|
|
234
|
-
|
|
235
|
-
```ts
|
|
236
|
-
// features/home/data/mock.ts
|
|
237
|
-
import i18n from '../../../i18n';
|
|
238
|
-
|
|
239
|
-
export async function fetchFeatureCards(): Promise<FeatureCard[]> {
|
|
240
|
-
return [{
|
|
241
|
-
id: 'template-cli',
|
|
242
|
-
title: i18n.t('home.templateCliTitle'), // ← translated at query time
|
|
243
|
-
description: i18n.t('home.templateCliDescription'),
|
|
244
|
-
}];
|
|
245
|
-
}
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
### Language-aware React Query Keys
|
|
249
|
-
|
|
250
|
-
Every hook that returns translated strings includes the active language in its `queryKey` so that each locale gets its own cache slot and switches instantly without a page reload:
|
|
251
|
-
|
|
252
|
-
```ts
|
|
253
|
-
// features/home/hooks/useFeatureCards.ts
|
|
254
|
-
import { useLanguage } from 'xertica-ui/hooks';
|
|
255
|
-
|
|
256
|
-
export function useFeatureCards() {
|
|
257
|
-
const { language } = useLanguage();
|
|
258
|
-
return useQuery({
|
|
259
|
-
queryKey: ['home', 'feature-cards', language], // ← language as third element
|
|
260
|
-
queryFn: fetchFeatureCards,
|
|
261
|
-
staleTime: 10 * 60 * 1000,
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
**Why this works:**
|
|
267
|
-
- Switching from `pt-BR` → `en` changes the queryKey to `['home', 'feature-cards', 'en']`
|
|
268
|
-
- React Query finds no cache entry for this key → triggers an immediate refetch
|
|
269
|
-
- `fetchFeatureCards()` runs again → `i18n.t()` now returns English strings
|
|
270
|
-
- Switching back to `pt-BR` → cache hit (Portuguese data still stored) → instant, no refetch
|
|
271
|
-
|
|
272
|
-
The `setLanguage()` call in `LanguageContext` also calls `queryClient.invalidateQueries()` as a defensive backstop for any query not yet updated to include `language` in its key.
|
|
273
|
-
|
|
274
|
-
### Fallback factory functions (not frozen constants)
|
|
275
|
-
|
|
276
|
-
When you need static fallback data while a query loads, use **factory functions** (not `const` arrays):
|
|
277
|
-
|
|
278
|
-
```ts
|
|
279
|
-
// ✅ Correct — evaluated at call time, always returns current language
|
|
280
|
-
export function getMockRichSuggestions(): Suggestion[] {
|
|
281
|
-
return [
|
|
282
|
-
{ id: 'rich-1', text: i18n.t('assistant.richSuggestions.viewPerformance') },
|
|
283
|
-
];
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// ❌ Wrong — i18n.t() runs once at module load, frozen in initial language
|
|
287
|
-
export const MOCK_RICH_SUGGESTIONS = [
|
|
288
|
-
{ id: 'rich-1', text: i18n.t('assistant.richSuggestions.viewPerformance') },
|
|
289
|
-
];
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
```tsx
|
|
293
|
-
// Usage in component
|
|
294
|
-
richSuggestions={assistantConfig?.richSuggestions ?? getMockRichSuggestions()}
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
---
|
|
298
|
-
|
|
299
|
-
## Configuring Available Languages
|
|
300
|
-
|
|
301
|
-
The set of languages a project supports is configured **at runtime** via the `availableLanguages` prop on `<XerticaProvider>` (or `<LanguageProvider>`). The library ships with built-in support for `pt-BR`, `en`, and `es` (exposed as `DEFAULT_LANGUAGES`), but the system is fully extensible.
|
|
302
|
-
|
|
303
|
-
### Choosing languages via the CLI
|
|
304
|
-
|
|
305
|
-
When you scaffold a new project, the CLI asks you which languages to enable:
|
|
306
|
-
|
|
307
|
-
```bash
|
|
308
|
-
$ npx xertica-ui init my-app
|
|
309
|
-
✔ Which pages/templates to include? › Login, Home, Template
|
|
310
|
-
✔ Which languages should the app support? › Português (BR), English, Español
|
|
311
|
-
✔ Select the default color theme: › Xertica
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
Pick **all three** (default), **two**, or **just one**:
|
|
315
|
-
- **All three** — the CLI omits the `availableLanguages` prop entirely (the library default already matches).
|
|
316
|
-
- **Two or one** — the CLI injects the explicit `availableLanguages` array into `src/app/App.tsx`.
|
|
317
|
-
- **Just one (monolingual)** — additionally, the `LanguageSelector` auto-hides because there is nothing to switch between. A header banner comment in `App.tsx` documents this.
|
|
318
|
-
|
|
319
|
-
The CLI also:
|
|
320
|
-
- Copies **only** the locale **folders** for the selected languages into `src/locales/` (no orphan files). Each language is a directory tree with split JSON files.
|
|
321
|
-
- Generates `src/i18n.ts` with `import.meta.glob` calls for exactly those languages — Vite auto-discovers all JSON files in the folder at build time.
|
|
322
|
-
- Persists the selection in `src/locales/.languages.json` so the `update` command can preserve it.
|
|
323
|
-
|
|
324
|
-
### Adding or removing languages later
|
|
325
|
-
|
|
326
|
-
Run `npx xertica-ui update` and choose **Languages**:
|
|
327
|
-
|
|
328
|
-
```bash
|
|
329
|
-
$ npx xertica-ui update
|
|
330
|
-
✔ What do you want to update? › Languages
|
|
331
|
-
|
|
332
|
-
Current languages: Português (BR), English
|
|
333
|
-
|
|
334
|
-
✔ Select the languages this project should support: › Português (BR), English, Español
|
|
335
|
-
|
|
336
|
-
+ es
|
|
337
|
-
|
|
338
|
-
⚠️ This will regenerate src/app/App.tsx and src/i18n.ts (preserving language-only changes). Continue? › yes
|
|
339
|
-
✔ Languages updated successfully!
|
|
340
|
-
Copied: es/
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
The command:
|
|
344
|
-
1. Computes the add/remove diff and shows it to you.
|
|
345
|
-
2. Copies the newly-added locale **folders** from `node_modules/xertica-ui/templates/src/locales/<lang>/`.
|
|
346
|
-
3. Removes the **folders** of unselected languages from your project (also removes any legacy flat `<lang>.json` files if upgrading from pre-2.2.0).
|
|
347
|
-
4. Regenerates `src/i18n.ts` and `src/app/App.tsx` to reflect the new set.
|
|
348
|
-
5. Updates `src/locales/.languages.json`.
|
|
349
|
-
|
|
350
|
-
> The `update` → **Project files** flow also reads `.languages.json` and preserves your selection — updating `App.tsx` and `i18n.ts` won't reset your languages to the defaults.
|
|
351
|
-
|
|
352
|
-
### Default — three built-in languages
|
|
353
|
-
|
|
354
|
-
When you don't pass `availableLanguages`, the provider uses `DEFAULT_LANGUAGES`:
|
|
355
|
-
|
|
356
|
-
```tsx
|
|
357
|
-
import { XerticaProvider } from 'xertica-ui';
|
|
358
|
-
|
|
359
|
-
<XerticaProvider>
|
|
360
|
-
{/* pt-BR, en, es are all available — selector shows all three */}
|
|
361
|
-
</XerticaProvider>
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
### Monolingual — single language, no selector
|
|
365
|
-
|
|
366
|
-
Pass a single-element array to lock the app to one language. The `LanguageSelector` component **auto-hides** because there is nothing to switch to:
|
|
367
|
-
|
|
368
|
-
```tsx
|
|
369
|
-
<XerticaProvider availableLanguages={[{ code: 'en', label: 'English' }]}>
|
|
370
|
-
{/* App is permanently English. LanguageSelector renders nothing. */}
|
|
371
|
-
</XerticaProvider>
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
To force the selector to render even when monolingual (e.g. for a future-proofing placeholder), pass `<LanguageSelector showWhenMonolingual />`.
|
|
375
|
-
|
|
376
|
-
### Adding a new language at runtime
|
|
377
|
-
|
|
378
|
-
There are two ways to add a language without editing `src/i18n.ts`.
|
|
379
|
-
|
|
380
|
-
**Option A — declarative, via `availableLanguages`** (recommended):
|
|
381
|
-
|
|
382
|
-
```tsx
|
|
383
|
-
import { XerticaProvider, DEFAULT_LANGUAGES } from 'xertica-ui';
|
|
384
|
-
import fr from './locales/fr.json';
|
|
385
|
-
|
|
386
|
-
<XerticaProvider
|
|
387
|
-
availableLanguages={[
|
|
388
|
-
...DEFAULT_LANGUAGES,
|
|
389
|
-
{ code: 'fr', label: 'Français', shortLabel: 'FR', resources: fr },
|
|
390
|
-
]}
|
|
391
|
-
>
|
|
392
|
-
{/* French now appears in the selector; its strings are registered automatically */}
|
|
393
|
-
</XerticaProvider>
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
The provider calls `i18n.addResourceBundle()` on mount for any entry that carries `resources`.
|
|
397
|
-
|
|
398
|
-
**Option B — imperative, via `registerLanguageResource`**:
|
|
399
|
-
|
|
400
|
-
```ts
|
|
401
|
-
import { registerLanguageResource } from 'xertica-ui';
|
|
402
|
-
import fr from './locales/fr.json';
|
|
403
|
-
|
|
404
|
-
registerLanguageResource('fr', fr);
|
|
405
|
-
// Then list it on the provider
|
|
406
|
-
<XerticaProvider availableLanguages={[
|
|
407
|
-
...DEFAULT_LANGUAGES,
|
|
408
|
-
{ code: 'fr', label: 'Français', shortLabel: 'FR' },
|
|
409
|
-
]}>
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
### Removing built-in languages
|
|
413
|
-
|
|
414
|
-
Just omit them from `availableLanguages`. The translation bundles registered in `src/i18n.ts` remain loaded (they're cheap) but they're invisible to the UI:
|
|
415
|
-
|
|
416
|
-
```tsx
|
|
417
|
-
<XerticaProvider availableLanguages={[
|
|
418
|
-
{ code: 'pt-BR', label: 'Português' },
|
|
419
|
-
{ code: 'en', label: 'English' },
|
|
420
|
-
]}>
|
|
421
|
-
{/* Only Portuguese and English appear — Spanish is hidden */}
|
|
422
|
-
</XerticaProvider>
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
### Statically (library-only) — adding a built-in default
|
|
426
|
-
|
|
427
|
-
Only used when contributing to the library itself, not for app consumers:
|
|
428
|
-
|
|
429
|
-
1. Create `locales/<code>/` folder mirroring an existing language (copy `locales/en/` as a starting point, then translate all values)
|
|
430
|
-
2. `i18n.ts` uses `import.meta.glob` — **no import changes needed**. Vite auto-discovers the new folder on the next build.
|
|
431
|
-
3. Add a `LanguageDefinition` entry to `DEFAULT_LANGUAGES` in `contexts/LanguageContext.tsx`
|
|
432
|
-
4. Add an entry to `SUPPORTED_LANGUAGES` in `bin/language-config.ts` so the CLI exposes it in its prompts
|
|
433
|
-
5. Mirror the same folder structure under `templates/src/locales/<code>/` for the scaffold template
|
|
434
|
-
|
|
435
|
-
### `LanguageDefinition` shape
|
|
436
|
-
|
|
437
|
-
```ts
|
|
438
|
-
interface LanguageDefinition {
|
|
439
|
-
/** BCP-47 language code stored in localStorage and passed to i18n.changeLanguage() */
|
|
440
|
-
code: string;
|
|
441
|
-
/** Full display label shown in the LanguageSelector dropdown */
|
|
442
|
-
label: string;
|
|
443
|
-
/** Short label shown in `variant="minimal"` (e.g. "PT", "EN"). Defaults to code.slice(0,2).toUpperCase() */
|
|
444
|
-
shortLabel?: string;
|
|
445
|
-
/** Optional translation JSON. When provided, it is registered with i18next automatically. */
|
|
446
|
-
resources?: Record<string, unknown>;
|
|
447
|
-
}
|
|
448
|
-
```
|
|
449
|
-
|
|
450
|
-
### `useLanguage()` extras
|
|
451
|
-
|
|
452
|
-
```ts
|
|
453
|
-
const {
|
|
454
|
-
language, // current locale code
|
|
455
|
-
setLanguage, // change locale + persist + invalidate React Query
|
|
456
|
-
availableLanguages, // LanguageDefinition[] currently configured
|
|
457
|
-
isMonolingual, // true when availableLanguages.length === 1
|
|
458
|
-
} = useLanguage();
|
|
459
|
-
```
|
|
460
|
-
|
|
461
|
-
---
|
|
462
|
-
|
|
463
|
-
## AI Rules
|
|
464
|
-
|
|
465
|
-
- **ALWAYS import `'./i18n'` in `main.tsx` before any component** — if omitted, `useTranslation()` falls back to returning the raw key string
|
|
466
|
-
- **Use `t('namespace.key')` for all user-facing strings** — never hardcode text in JSX
|
|
467
|
-
- **Use `i18n.t()` (the instance) in non-component code** (mock fetch functions, utility files) — `useTranslation()` is a hook and can only be called inside React components and custom hooks
|
|
468
|
-
- **Include `language` in the `queryKey`** for every React Query hook that returns translated strings — this gives each locale its own cache slot and enables instant switching without reload
|
|
469
|
-
- **Use factory functions, not frozen constants**, when you need pre-translated fallback arrays — `const arr = [i18n.t(...)]` evaluates once at module load and is permanently frozen
|
|
470
|
-
- **Never hardcode language fallbacks in JSX** — add missing keys to the appropriate file under `locales/<lang>/` instead
|
|
471
|
-
- `setLanguage()` from `useLanguage()` is the single point of control — it persists to `localStorage`, calls `i18n.changeLanguage()`, and invalidates the React Query cache
|
|
472
|
-
- Import `useLanguage` from `'xertica-ui/hooks'` (or directly from `'xertica-ui'`) — both resolve to the same export. The `xertica-ui/brand` subpath exports only the `LanguageSelector` component and `Language` type, NOT the `useLanguage` hook.
|
|
473
|
-
- The `fallbackLng: 'pt-BR'` ensures missing keys in `en.json` or `es.json` display the Portuguese fallback instead of the raw key string
|
|
474
|
-
- **The set of available languages is runtime-configurable** — pass `availableLanguages` to `<XerticaProvider>` to add, remove, or restrict to a single locale. Never modify `DEFAULT_LANGUAGES` directly
|
|
475
|
-
- **The `LanguageSelector` auto-hides when `isMonolingual` is true** — do not conditionally render it yourself; pass it `showWhenMonolingual` if you want it visible
|
|
476
|
-
- **`Language` is typed as `string`** (not a strict union) to support runtime-added locales. Use `LanguageDefinition['code']` from `useLanguage().availableLanguages` for autocomplete
|
|
1
|
+
# Internationalization (i18n) — Xertica UI
|
|
2
|
+
|
|
3
|
+
Xertica UI projects use **`i18next`** with the **`react-i18next`** binding for all UI string translations. The `LanguageSelector` component is wired directly to `i18next` — changing the language immediately updates every `useTranslation()` consumer in the app and invalidates the React Query cache so that data-layer strings (mock API responses) also refresh.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
### 1. Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install i18next react-i18next
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Both packages are listed in `templates/package.json` and are installed automatically by `npx xertica-ui@latest init`.
|
|
16
|
+
|
|
17
|
+
### 2. Create locale files
|
|
18
|
+
|
|
19
|
+
Locales are organized as one **folder per language**, split by category:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
src/locales/
|
|
23
|
+
├── .languages.json ← CLI-managed selection ({ "version": 1, "codes": [...] })
|
|
24
|
+
├── pt-BR/ ← default & fallback (only your selected languages are present)
|
|
25
|
+
│ ├── common.json ← shared action labels (view, edit, save, cancel…)
|
|
26
|
+
│ ├── nav.json ← navigation labels
|
|
27
|
+
│ ├── errors.json ← error boundary UI
|
|
28
|
+
│ ├── languageSelector.json ← language picker UI
|
|
29
|
+
│ ├── themeToggle.json ← theme toggle UI
|
|
30
|
+
│ ├── pages/
|
|
31
|
+
│ │ ├── home.json
|
|
32
|
+
│ │ ├── templates.json
|
|
33
|
+
│ │ ├── login.json
|
|
34
|
+
│ │ ├── resetPassword.json
|
|
35
|
+
│ │ ├── verifyEmail.json
|
|
36
|
+
│ │ ├── loginTemplate.json ← starter template pages
|
|
37
|
+
│ │ ├── formTemplate.json
|
|
38
|
+
│ │ ├── dashboardTemplate.json
|
|
39
|
+
│ │ └── crudTemplate.json
|
|
40
|
+
│ └── components/
|
|
41
|
+
│ ├── assistant.json
|
|
42
|
+
│ ├── sidebar.json
|
|
43
|
+
│ ├── media.json
|
|
44
|
+
│ ├── projectCard.json
|
|
45
|
+
│ ├── profileCard.json
|
|
46
|
+
│ ├── notificationCard.json
|
|
47
|
+
│ ├── activityCard.json
|
|
48
|
+
│ ├── stats.json
|
|
49
|
+
│ └── team.json
|
|
50
|
+
├── en/ ← same structure
|
|
51
|
+
└── es/ ← same structure
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Each JSON file contains only the keys for its category (no top-level wrapper key). For example, `locales/pt-BR/common.json`:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{ "view": "Visualizar", "edit": "Editar", "loading": "Carregando...", "cancel": "Cancelar" }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
And `locales/pt-BR/pages/home.json`:
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{ "welcome": "Bem-vindo ao Design System!", "subtitle": "...", "templateCliTitle": "Template CLI" }
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
> All files under `locales/<lang>/` are automatically discovered by `import.meta.glob` in `i18n.ts`. Adding a new JSON file requires no changes to `i18n.ts` — Vite picks it up on the next build.
|
|
67
|
+
|
|
68
|
+
### 3. Create `src/i18n.ts`
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import i18n from 'i18next';
|
|
72
|
+
import { initReactI18next } from 'react-i18next';
|
|
73
|
+
|
|
74
|
+
// Merges the split JSON files (pages/, components/) into one flat bundle per language.
|
|
75
|
+
// The key is the file basename — folder (pages/components) is discarded.
|
|
76
|
+
// Adding a new JSON file under locales/<lang>/... is auto-discovered by Vite.
|
|
77
|
+
function bundleLang(chunks: Record<string, unknown>): Record<string, unknown> {
|
|
78
|
+
const out: Record<string, unknown> = {};
|
|
79
|
+
for (const [filePath, value] of Object.entries(chunks)) {
|
|
80
|
+
const base = filePath.split('/').pop();
|
|
81
|
+
if (!base) continue;
|
|
82
|
+
out[base.replace(/\.json$/, '')] = value;
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// `import.meta.glob` requires a literal pattern — one call per language.
|
|
88
|
+
// `eager: true` inlines the JSON at build time (no runtime fetch).
|
|
89
|
+
const ptBR = bundleLang(
|
|
90
|
+
import.meta.glob('./locales/pt-BR/**/*.json', { eager: true, import: 'default' })
|
|
91
|
+
);
|
|
92
|
+
const en = bundleLang(
|
|
93
|
+
import.meta.glob('./locales/en/**/*.json', { eager: true, import: 'default' })
|
|
94
|
+
);
|
|
95
|
+
const es = bundleLang(
|
|
96
|
+
import.meta.glob('./locales/es/**/*.json', { eager: true, import: 'default' })
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const savedLanguage =
|
|
100
|
+
typeof window !== 'undefined'
|
|
101
|
+
? (localStorage.getItem('xertica_language') ?? 'pt-BR')
|
|
102
|
+
: 'pt-BR';
|
|
103
|
+
|
|
104
|
+
i18n.use(initReactI18next).init({
|
|
105
|
+
resources: {
|
|
106
|
+
'pt-BR': { translation: ptBR },
|
|
107
|
+
en: { translation: en },
|
|
108
|
+
es: { translation: es },
|
|
109
|
+
},
|
|
110
|
+
lng: savedLanguage,
|
|
111
|
+
fallbackLng: 'pt-BR',
|
|
112
|
+
interpolation: { escapeValue: false }, // React escapes already
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
export default i18n;
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 4. Initialize before rendering
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
// src/main.tsx — BEFORE any component import
|
|
122
|
+
import './i18n'; // side-effect: initializes i18next synchronously
|
|
123
|
+
import App from './app/App';
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Using Translations in Components
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
import { useTranslation } from 'react-i18next';
|
|
132
|
+
|
|
133
|
+
function HomeContent() {
|
|
134
|
+
const { t } = useTranslation();
|
|
135
|
+
|
|
136
|
+
return (
|
|
137
|
+
<div>
|
|
138
|
+
<h1>{t('home.welcome')}</h1>
|
|
139
|
+
<p>{t('home.subtitle')}</p>
|
|
140
|
+
<button>{t('common.view')}</button>
|
|
141
|
+
</div>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Interpolation
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{ "team": { "showing": "Exibindo {{count}} de {{total}} usuários" } }
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
t('team.showing', { count: 5, total: 127 })
|
|
154
|
+
// → "Exibindo 5 de 127 usuários"
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Language Switching
|
|
160
|
+
|
|
161
|
+
The `LanguageSelector` component (from `xertica-ui/brand`) handles the full switching flow automatically:
|
|
162
|
+
|
|
163
|
+
1. User selects a language in the dropdown
|
|
164
|
+
2. `setLanguage(lang)` is called on `LanguageContext`
|
|
165
|
+
3. `LanguageContext` writes to `localStorage` (key: `xertica_language`) and calls `i18n.changeLanguage(lang)`
|
|
166
|
+
4. All components using `useTranslation()` re-render with the new locale
|
|
167
|
+
5. `queryClient.invalidateQueries()` is called — React Query refetches any query whose result contains translated strings
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
// Manual language change (without LanguageSelector)
|
|
171
|
+
import { useLanguage } from 'xertica-ui/hooks';
|
|
172
|
+
|
|
173
|
+
const { setLanguage } = useLanguage();
|
|
174
|
+
setLanguage('en'); // persists + calls i18n.changeLanguage('en') + invalidates React Query cache
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Language codes
|
|
178
|
+
|
|
179
|
+
| Code | Display | Stored as |
|
|
180
|
+
|---|---|---|
|
|
181
|
+
| `'pt-BR'` | Português (BR) | `'pt-BR'` in `localStorage` |
|
|
182
|
+
| `'en'` | English | `'en'` |
|
|
183
|
+
| `'es'` | Español | `'es'` |
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Translation Key Namespaces
|
|
188
|
+
|
|
189
|
+
The project uses a single `translation` namespace. Each top-level key maps to a separate JSON file under `locales/<lang>/`:
|
|
190
|
+
|
|
191
|
+
**Root files** (`locales/<lang>/<key>.json`):
|
|
192
|
+
|
|
193
|
+
| Namespace | File | Example keys |
|
|
194
|
+
|---|---|---|
|
|
195
|
+
| `common` | `common.json` | `common.view`, `common.edit`, `common.loading`, `common.close`, `common.copied` |
|
|
196
|
+
| `nav` | `nav.json` | `nav.home`, `nav.designSystem`, `nav.settings` |
|
|
197
|
+
| `errors` | `errors.json` | `errors.somethingWentWrong`, `errors.tryAgain`, `errors.pageLoadError` |
|
|
198
|
+
| `languageSelector` | `languageSelector.json` | `languageSelector.label`, `languageSelector.ptBR` |
|
|
199
|
+
| `themeToggle` | `themeToggle.json` | `themeToggle.switchToLight`, `themeToggle.darkMode` |
|
|
200
|
+
|
|
201
|
+
**Page files** (`locales/<lang>/pages/<key>.json`):
|
|
202
|
+
|
|
203
|
+
| Namespace | File | Example keys |
|
|
204
|
+
|---|---|---|
|
|
205
|
+
| `home` | `pages/home.json` | `home.welcome`, `home.subtitle`, `home.templateCliTitle` |
|
|
206
|
+
| `templates` | `pages/templates.json` | `templates.title`, `templates.alerts.infoTitle`, `templates.forms.firstName` |
|
|
207
|
+
| `login` | `pages/login.json` | `login.heading`, `login.submit`, `login.forgotPassword` |
|
|
208
|
+
| `resetPassword` | `pages/resetPassword.json` | `resetPassword.heading`, `resetPassword.errorMismatch` |
|
|
209
|
+
| `verifyEmail` | `pages/verifyEmail.json` | `verifyEmail.heading`, `verifyEmail.resend` |
|
|
210
|
+
| `loginTemplate` | `pages/loginTemplate.json` | `loginTemplate.title`, `loginTemplate.submit` |
|
|
211
|
+
| `formTemplate` | `pages/formTemplate.json` | `formTemplate.title`, `formTemplate.save`, `formTemplate.errors.fullNameRequired` |
|
|
212
|
+
| `dashboardTemplate` | `pages/dashboardTemplate.json` | `dashboardTemplate.title`, `dashboardTemplate.stats.totalRevenue` |
|
|
213
|
+
| `crudTemplate` | `pages/crudTemplate.json` | `crudTemplate.title`, `crudTemplate.actions.editProfile` |
|
|
214
|
+
|
|
215
|
+
**Component files** (`locales/<lang>/components/<key>.json`):
|
|
216
|
+
|
|
217
|
+
| Namespace | File | Example keys |
|
|
218
|
+
|---|---|---|
|
|
219
|
+
| `assistant` | `components/assistant.json` | `assistant.title`, `assistant.inputPlaceholder`, `assistant.tabs.chat`, `assistant.feedbackDialog.title` |
|
|
220
|
+
| `sidebar` | `components/sidebar.json` | `sidebar.collapse`, `sidebar.logout`, `sidebar.moreOptions` |
|
|
221
|
+
| `media` | `components/media.json` | `media.play`, `media.pause`, `media.downloadAudio`, `media.floatingMode` |
|
|
222
|
+
| `projectCard` | `components/projectCard.json` | `projectCard.progress`, `projectCard.status.active` |
|
|
223
|
+
| `profileCard` | `components/profileCard.json` | `profileCard.status.online`, `profileCard.status.busy` |
|
|
224
|
+
| `notificationCard` | `components/notificationCard.json` | `notificationCard.title`, `notificationCard.markAllRead` |
|
|
225
|
+
| `activityCard` | `components/activityCard.json` | `activityCard.title`, `activityCard.type.create` |
|
|
226
|
+
| `stats` | `components/stats.json` | `stats.totalUsers`, `stats.last30Days` |
|
|
227
|
+
| `team` | `components/team.json` | `team.name`, `team.roles.Developer`, `team.showing` |
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Translating Mock Data
|
|
232
|
+
|
|
233
|
+
Mock data fetch functions use `i18n.t()` (the instance, not the hook) so they respond to the active language when called from a React Query `queryFn`:
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
// features/home/data/mock.ts
|
|
237
|
+
import i18n from '../../../i18n';
|
|
238
|
+
|
|
239
|
+
export async function fetchFeatureCards(): Promise<FeatureCard[]> {
|
|
240
|
+
return [{
|
|
241
|
+
id: 'template-cli',
|
|
242
|
+
title: i18n.t('home.templateCliTitle'), // ← translated at query time
|
|
243
|
+
description: i18n.t('home.templateCliDescription'),
|
|
244
|
+
}];
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Language-aware React Query Keys
|
|
249
|
+
|
|
250
|
+
Every hook that returns translated strings includes the active language in its `queryKey` so that each locale gets its own cache slot and switches instantly without a page reload:
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
// features/home/hooks/useFeatureCards.ts
|
|
254
|
+
import { useLanguage } from 'xertica-ui/hooks';
|
|
255
|
+
|
|
256
|
+
export function useFeatureCards() {
|
|
257
|
+
const { language } = useLanguage();
|
|
258
|
+
return useQuery({
|
|
259
|
+
queryKey: ['home', 'feature-cards', language], // ← language as third element
|
|
260
|
+
queryFn: fetchFeatureCards,
|
|
261
|
+
staleTime: 10 * 60 * 1000,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**Why this works:**
|
|
267
|
+
- Switching from `pt-BR` → `en` changes the queryKey to `['home', 'feature-cards', 'en']`
|
|
268
|
+
- React Query finds no cache entry for this key → triggers an immediate refetch
|
|
269
|
+
- `fetchFeatureCards()` runs again → `i18n.t()` now returns English strings
|
|
270
|
+
- Switching back to `pt-BR` → cache hit (Portuguese data still stored) → instant, no refetch
|
|
271
|
+
|
|
272
|
+
The `setLanguage()` call in `LanguageContext` also calls `queryClient.invalidateQueries()` as a defensive backstop for any query not yet updated to include `language` in its key.
|
|
273
|
+
|
|
274
|
+
### Fallback factory functions (not frozen constants)
|
|
275
|
+
|
|
276
|
+
When you need static fallback data while a query loads, use **factory functions** (not `const` arrays):
|
|
277
|
+
|
|
278
|
+
```ts
|
|
279
|
+
// ✅ Correct — evaluated at call time, always returns current language
|
|
280
|
+
export function getMockRichSuggestions(): Suggestion[] {
|
|
281
|
+
return [
|
|
282
|
+
{ id: 'rich-1', text: i18n.t('assistant.richSuggestions.viewPerformance') },
|
|
283
|
+
];
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// ❌ Wrong — i18n.t() runs once at module load, frozen in initial language
|
|
287
|
+
export const MOCK_RICH_SUGGESTIONS = [
|
|
288
|
+
{ id: 'rich-1', text: i18n.t('assistant.richSuggestions.viewPerformance') },
|
|
289
|
+
];
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
```tsx
|
|
293
|
+
// Usage in component
|
|
294
|
+
richSuggestions={assistantConfig?.richSuggestions ?? getMockRichSuggestions()}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## Configuring Available Languages
|
|
300
|
+
|
|
301
|
+
The set of languages a project supports is configured **at runtime** via the `availableLanguages` prop on `<XerticaProvider>` (or `<LanguageProvider>`). The library ships with built-in support for `pt-BR`, `en`, and `es` (exposed as `DEFAULT_LANGUAGES`), but the system is fully extensible.
|
|
302
|
+
|
|
303
|
+
### Choosing languages via the CLI
|
|
304
|
+
|
|
305
|
+
When you scaffold a new project, the CLI asks you which languages to enable:
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
$ npx xertica-ui init my-app
|
|
309
|
+
✔ Which pages/templates to include? › Login, Home, Template
|
|
310
|
+
✔ Which languages should the app support? › Português (BR), English, Español
|
|
311
|
+
✔ Select the default color theme: › Xertica
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Pick **all three** (default), **two**, or **just one**:
|
|
315
|
+
- **All three** — the CLI omits the `availableLanguages` prop entirely (the library default already matches).
|
|
316
|
+
- **Two or one** — the CLI injects the explicit `availableLanguages` array into `src/app/App.tsx`.
|
|
317
|
+
- **Just one (monolingual)** — additionally, the `LanguageSelector` auto-hides because there is nothing to switch between. A header banner comment in `App.tsx` documents this.
|
|
318
|
+
|
|
319
|
+
The CLI also:
|
|
320
|
+
- Copies **only** the locale **folders** for the selected languages into `src/locales/` (no orphan files). Each language is a directory tree with split JSON files.
|
|
321
|
+
- Generates `src/i18n.ts` with `import.meta.glob` calls for exactly those languages — Vite auto-discovers all JSON files in the folder at build time.
|
|
322
|
+
- Persists the selection in `src/locales/.languages.json` so the `update` command can preserve it.
|
|
323
|
+
|
|
324
|
+
### Adding or removing languages later
|
|
325
|
+
|
|
326
|
+
Run `npx xertica-ui update` and choose **Languages**:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
$ npx xertica-ui update
|
|
330
|
+
✔ What do you want to update? › Languages
|
|
331
|
+
|
|
332
|
+
Current languages: Português (BR), English
|
|
333
|
+
|
|
334
|
+
✔ Select the languages this project should support: › Português (BR), English, Español
|
|
335
|
+
|
|
336
|
+
+ es
|
|
337
|
+
|
|
338
|
+
⚠️ This will regenerate src/app/App.tsx and src/i18n.ts (preserving language-only changes). Continue? › yes
|
|
339
|
+
✔ Languages updated successfully!
|
|
340
|
+
Copied: es/
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
The command:
|
|
344
|
+
1. Computes the add/remove diff and shows it to you.
|
|
345
|
+
2. Copies the newly-added locale **folders** from `node_modules/xertica-ui/templates/src/locales/<lang>/`.
|
|
346
|
+
3. Removes the **folders** of unselected languages from your project (also removes any legacy flat `<lang>.json` files if upgrading from pre-2.2.0).
|
|
347
|
+
4. Regenerates `src/i18n.ts` and `src/app/App.tsx` to reflect the new set.
|
|
348
|
+
5. Updates `src/locales/.languages.json`.
|
|
349
|
+
|
|
350
|
+
> The `update` → **Project files** flow also reads `.languages.json` and preserves your selection — updating `App.tsx` and `i18n.ts` won't reset your languages to the defaults.
|
|
351
|
+
|
|
352
|
+
### Default — three built-in languages
|
|
353
|
+
|
|
354
|
+
When you don't pass `availableLanguages`, the provider uses `DEFAULT_LANGUAGES`:
|
|
355
|
+
|
|
356
|
+
```tsx
|
|
357
|
+
import { XerticaProvider } from 'xertica-ui';
|
|
358
|
+
|
|
359
|
+
<XerticaProvider>
|
|
360
|
+
{/* pt-BR, en, es are all available — selector shows all three */}
|
|
361
|
+
</XerticaProvider>
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Monolingual — single language, no selector
|
|
365
|
+
|
|
366
|
+
Pass a single-element array to lock the app to one language. The `LanguageSelector` component **auto-hides** because there is nothing to switch to:
|
|
367
|
+
|
|
368
|
+
```tsx
|
|
369
|
+
<XerticaProvider availableLanguages={[{ code: 'en', label: 'English' }]}>
|
|
370
|
+
{/* App is permanently English. LanguageSelector renders nothing. */}
|
|
371
|
+
</XerticaProvider>
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
To force the selector to render even when monolingual (e.g. for a future-proofing placeholder), pass `<LanguageSelector showWhenMonolingual />`.
|
|
375
|
+
|
|
376
|
+
### Adding a new language at runtime
|
|
377
|
+
|
|
378
|
+
There are two ways to add a language without editing `src/i18n.ts`.
|
|
379
|
+
|
|
380
|
+
**Option A — declarative, via `availableLanguages`** (recommended):
|
|
381
|
+
|
|
382
|
+
```tsx
|
|
383
|
+
import { XerticaProvider, DEFAULT_LANGUAGES } from 'xertica-ui';
|
|
384
|
+
import fr from './locales/fr.json';
|
|
385
|
+
|
|
386
|
+
<XerticaProvider
|
|
387
|
+
availableLanguages={[
|
|
388
|
+
...DEFAULT_LANGUAGES,
|
|
389
|
+
{ code: 'fr', label: 'Français', shortLabel: 'FR', resources: fr },
|
|
390
|
+
]}
|
|
391
|
+
>
|
|
392
|
+
{/* French now appears in the selector; its strings are registered automatically */}
|
|
393
|
+
</XerticaProvider>
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
The provider calls `i18n.addResourceBundle()` on mount for any entry that carries `resources`.
|
|
397
|
+
|
|
398
|
+
**Option B — imperative, via `registerLanguageResource`**:
|
|
399
|
+
|
|
400
|
+
```ts
|
|
401
|
+
import { registerLanguageResource } from 'xertica-ui';
|
|
402
|
+
import fr from './locales/fr.json';
|
|
403
|
+
|
|
404
|
+
registerLanguageResource('fr', fr);
|
|
405
|
+
// Then list it on the provider
|
|
406
|
+
<XerticaProvider availableLanguages={[
|
|
407
|
+
...DEFAULT_LANGUAGES,
|
|
408
|
+
{ code: 'fr', label: 'Français', shortLabel: 'FR' },
|
|
409
|
+
]}>
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Removing built-in languages
|
|
413
|
+
|
|
414
|
+
Just omit them from `availableLanguages`. The translation bundles registered in `src/i18n.ts` remain loaded (they're cheap) but they're invisible to the UI:
|
|
415
|
+
|
|
416
|
+
```tsx
|
|
417
|
+
<XerticaProvider availableLanguages={[
|
|
418
|
+
{ code: 'pt-BR', label: 'Português' },
|
|
419
|
+
{ code: 'en', label: 'English' },
|
|
420
|
+
]}>
|
|
421
|
+
{/* Only Portuguese and English appear — Spanish is hidden */}
|
|
422
|
+
</XerticaProvider>
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Statically (library-only) — adding a built-in default
|
|
426
|
+
|
|
427
|
+
Only used when contributing to the library itself, not for app consumers:
|
|
428
|
+
|
|
429
|
+
1. Create `locales/<code>/` folder mirroring an existing language (copy `locales/en/` as a starting point, then translate all values)
|
|
430
|
+
2. `i18n.ts` uses `import.meta.glob` — **no import changes needed**. Vite auto-discovers the new folder on the next build.
|
|
431
|
+
3. Add a `LanguageDefinition` entry to `DEFAULT_LANGUAGES` in `contexts/LanguageContext.tsx`
|
|
432
|
+
4. Add an entry to `SUPPORTED_LANGUAGES` in `bin/language-config.ts` so the CLI exposes it in its prompts
|
|
433
|
+
5. Mirror the same folder structure under `templates/src/locales/<code>/` for the scaffold template
|
|
434
|
+
|
|
435
|
+
### `LanguageDefinition` shape
|
|
436
|
+
|
|
437
|
+
```ts
|
|
438
|
+
interface LanguageDefinition {
|
|
439
|
+
/** BCP-47 language code stored in localStorage and passed to i18n.changeLanguage() */
|
|
440
|
+
code: string;
|
|
441
|
+
/** Full display label shown in the LanguageSelector dropdown */
|
|
442
|
+
label: string;
|
|
443
|
+
/** Short label shown in `variant="minimal"` (e.g. "PT", "EN"). Defaults to code.slice(0,2).toUpperCase() */
|
|
444
|
+
shortLabel?: string;
|
|
445
|
+
/** Optional translation JSON. When provided, it is registered with i18next automatically. */
|
|
446
|
+
resources?: Record<string, unknown>;
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### `useLanguage()` extras
|
|
451
|
+
|
|
452
|
+
```ts
|
|
453
|
+
const {
|
|
454
|
+
language, // current locale code
|
|
455
|
+
setLanguage, // change locale + persist + invalidate React Query
|
|
456
|
+
availableLanguages, // LanguageDefinition[] currently configured
|
|
457
|
+
isMonolingual, // true when availableLanguages.length === 1
|
|
458
|
+
} = useLanguage();
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
## AI Rules
|
|
464
|
+
|
|
465
|
+
- **ALWAYS import `'./i18n'` in `main.tsx` before any component** — if omitted, `useTranslation()` falls back to returning the raw key string
|
|
466
|
+
- **Use `t('namespace.key')` for all user-facing strings** — never hardcode text in JSX
|
|
467
|
+
- **Use `i18n.t()` (the instance) in non-component code** (mock fetch functions, utility files) — `useTranslation()` is a hook and can only be called inside React components and custom hooks
|
|
468
|
+
- **Include `language` in the `queryKey`** for every React Query hook that returns translated strings — this gives each locale its own cache slot and enables instant switching without reload
|
|
469
|
+
- **Use factory functions, not frozen constants**, when you need pre-translated fallback arrays — `const arr = [i18n.t(...)]` evaluates once at module load and is permanently frozen
|
|
470
|
+
- **Never hardcode language fallbacks in JSX** — add missing keys to the appropriate file under `locales/<lang>/` instead
|
|
471
|
+
- `setLanguage()` from `useLanguage()` is the single point of control — it persists to `localStorage`, calls `i18n.changeLanguage()`, and invalidates the React Query cache
|
|
472
|
+
- Import `useLanguage` from `'xertica-ui/hooks'` (or directly from `'xertica-ui'`) — both resolve to the same export. The `xertica-ui/brand` subpath exports only the `LanguageSelector` component and `Language` type, NOT the `useLanguage` hook.
|
|
473
|
+
- The `fallbackLng: 'pt-BR'` ensures missing keys in `en.json` or `es.json` display the Portuguese fallback instead of the raw key string
|
|
474
|
+
- **The set of available languages is runtime-configurable** — pass `availableLanguages` to `<XerticaProvider>` to add, remove, or restrict to a single locale. Never modify `DEFAULT_LANGUAGES` directly
|
|
475
|
+
- **The `LanguageSelector` auto-hides when `isMonolingual` is true** — do not conditionally render it yourself; pass it `showWhenMonolingual` if you want it visible
|
|
476
|
+
- **`Language` is typed as `string`** (not a strict union) to support runtime-added locales. Use `LanguageDefinition['code']` from `useLanguage().availableLanguages` for autocomplete
|