@salesforce/ui-bundle-template-feature-angular-language-switcher 12.5.4
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/LICENSE.txt +82 -0
- package/README.md +193 -0
- package/dist/.forceignore +15 -0
- package/dist/.husky/pre-commit +4 -0
- package/dist/.prettierignore +11 -0
- package/dist/.prettierrc +17 -0
- package/dist/CHANGELOG.md +5238 -0
- package/dist/README.md +77 -0
- package/dist/config/project-scratch-def.json +13 -0
- package/dist/eslint.config.js +7 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/.forceignore +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/.graphqlrc.yml +2 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/.postcssrc.json +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/.prettierignore +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/.prettierrc +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/CHANGELOG.md +4 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/README.md +85 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/angular.json +98 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/codegen.yml +95 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/components.json +6 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/e2e/app.spec.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/esbuild/api-version.mjs +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/esbuild/graphql-codegen.mjs +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/eslint-plugin-angular-graphql.js +148 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/eslint.config.js +76 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/feature-angular-language-switcher.uibundle-meta.xml +7 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/middleware/html.mjs +3 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/middleware/proxy.mjs +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/package.json +69 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/playwright.config.ts +25 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/public/favicon.ico +0 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/scripts/get-graphql-schema.mjs +69 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/scripts/rewrite-e2e-assets.mjs +30 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/api/data-client.service.spec.ts +184 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/api/data-client.service.ts +74 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/app.config.ts +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/app.html +1 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/app.routes.ts +26 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/app.spec.ts +18 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/app.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/layout/app-layout/app-layout.html +51 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/layout/app-layout/app-layout.spec.ts +63 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/layout/app-layout/app-layout.ts +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/alert/alert.html +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/alert/alert.ts +41 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/button/button.html +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/button/button.ts +66 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/card/card.ts +100 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/collapsible/collapsible.html +38 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/collapsible/collapsible.ts +21 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/date-picker/date-picker.html +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/date-picker/date-picker.ts +49 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/date-range-picker/date-range-picker.html +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/date-range-picker/date-range-picker.ts +69 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/dialog/dialog.html +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/dialog/dialog.ts +40 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/dropdown-menu/dropdown-menu.html +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/dropdown-menu/dropdown-menu.ts +100 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/field/field.html +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/field/field.ts +28 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/field-appearance.ts +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/field-size.ts +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/icon/icon.ts +68 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/input/input.html +34 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/input/input.ts +79 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/label/label.ts +21 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/paginator/paginator.html +74 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/paginator/paginator.ts +93 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/paginator/types.ts +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/popover/popover.html +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/popover/popover.ts +37 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/select/select.html +36 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/select/select.ts +63 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/separator/separator.ts +31 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/skeleton/skeleton.ts +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/components/ui/spinner/spinner.ts +28 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/features/language-switcher/__examples__/html-middleware-site-example.ts +41 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/features/language-switcher/__examples__/language-switcher-example.ts +41 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/features/language-switcher/build-language-url.ts +158 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/features/language-switcher/index.ts +28 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/features/language-switcher/language-switcher.html +22 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/features/language-switcher/language-switcher.ts +110 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/features/language-switcher/languages.ts +46 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/pages/home/home.html +6 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/pages/home/home.spec.ts +23 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/pages/home/home.ts +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/pages/not-found/not-found.html +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/pages/not-found/not-found.spec.ts +33 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/pages/not-found/not-found.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/alert/hlm-alert-action.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/alert/hlm-alert-description.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/alert/hlm-alert-title.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/alert/hlm-alert.ts +35 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/alert/index.ts +16 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/button/hlm-button.token.ts +22 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/button/hlm-button.ts +72 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/button/index.ts +6 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/calendar/hlm-calendar-multi.ts +195 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/calendar/hlm-calendar-range.ts +194 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/calendar/hlm-calendar.ts +189 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/calendar/hlm-month-year-calendar.ts +119 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/calendar/index.ts +16 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/card/hlm-card-action.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/card/hlm-card-avatar.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/card/hlm-card-content.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/card/hlm-card-description.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/card/hlm-card-footer.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/card/hlm-card-header.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/card/hlm-card-title.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/card/hlm-card.token.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/card/hlm-card.ts +22 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/card/index.ts +28 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/collapsible/hlm-collapsible-content.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/collapsible/hlm-collapsible-trigger.ts +9 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/collapsible/hlm-collapsible.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/collapsible/index.ts +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/date-picker/hlm-date-multi-input.ts +104 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/date-picker/hlm-date-picker-anchor.ts +23 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/date-picker/hlm-date-picker-input.ts +118 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/date-picker/hlm-date-picker-multi.token.ts +109 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/date-picker/hlm-date-picker-multi.ts +220 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/date-picker/hlm-date-picker-trigger.ts +104 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/date-picker/hlm-date-picker.token.ts +69 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/date-picker/hlm-date-picker.ts +203 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/date-picker/hlm-date-range-input.ts +120 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/date-picker/hlm-date-range-picker.token.ts +86 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/date-picker/hlm-date-range-picker.ts +252 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/date-picker/hlm-month-year-input.ts +105 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/date-picker/hlm-month-year-picker.token.ts +89 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/date-picker/hlm-month-year-picker.ts +196 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/date-picker/index.ts +38 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dialog/hlm-dialog-close.ts +9 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dialog/hlm-dialog-content.ts +74 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dialog/hlm-dialog-description.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dialog/hlm-dialog-footer.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dialog/hlm-dialog-header.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dialog/hlm-dialog-overlay.ts +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dialog/hlm-dialog-portal.ts +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dialog/hlm-dialog-title.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dialog/hlm-dialog-trigger.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dialog/hlm-dialog.service.ts +46 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dialog/hlm-dialog.ts +24 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dialog/index.ts +35 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/hlm-dropdown-menu-checkbox-indicator.ts +21 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/hlm-dropdown-menu-checkbox.ts +54 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/hlm-dropdown-menu-focus-on-hover.ts +35 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/hlm-dropdown-menu-group.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/hlm-dropdown-menu-item-sub-indicator.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/hlm-dropdown-menu-item.ts +42 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/hlm-dropdown-menu-label.ts +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/hlm-dropdown-menu-radio-indicator.ts +21 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/hlm-dropdown-menu-radio.ts +49 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/hlm-dropdown-menu-separator.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/hlm-dropdown-menu-shortcut.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/hlm-dropdown-menu-sub-trigger.ts +52 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/hlm-dropdown-menu-sub.ts +53 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/hlm-dropdown-menu-token.ts +26 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/hlm-dropdown-menu-trigger.ts +46 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/hlm-dropdown-menu.ts +57 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/dropdown-menu/index.ts +49 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/field/hlm-field-content.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/field/hlm-field-description.ts +53 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/field/hlm-field-error.ts +100 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/field/hlm-field-group.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/field/hlm-field-label.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/field/hlm-field-legend.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/field/hlm-field-separator.ts +24 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/field/hlm-field-set.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/field/hlm-field-title.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/field/hlm-field.ts +47 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/field/index.ts +34 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/input/hlm-input.ts +21 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/input/index.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/input-group/hlm-input-group-addon.ts +40 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/input-group/hlm-input-group-button.ts +47 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/input-group/hlm-input-group-input.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/input-group/hlm-input-group-text.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/input-group/hlm-input-group.ts +18 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/input-group/index.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/label/hlm-label.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/label/index.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/label/label.html +11 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/pagination/hlm-numbered-pagination-query-params.ts +191 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/pagination/hlm-numbered-pagination.ts +290 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/pagination/hlm-pagination-content.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/pagination/hlm-pagination-ellipsis.ts +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/pagination/hlm-pagination-item.ts +7 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/pagination/hlm-pagination-link.ts +51 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/pagination/hlm-pagination-next.ts +65 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/pagination/hlm-pagination-previous.ts +65 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/pagination/hlm-pagination.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/pagination/index.ts +31 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/popover/hlm-popover-content.ts +25 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/popover/hlm-popover-description.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/popover/hlm-popover-header.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/popover/hlm-popover-portal.ts +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/popover/hlm-popover-title.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/popover/hlm-popover-trigger.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/popover/hlm-popover.ts +23 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/popover/index.ts +25 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/hlm-select-content.ts +44 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/hlm-select-group.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/hlm-select-item.ts +36 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/hlm-select-label.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/hlm-select-multiple.ts +37 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/hlm-select-placeholder.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/hlm-select-portal.ts +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/hlm-select-scroll-down.ts +22 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/hlm-select-scroll-up.ts +22 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/hlm-select-separator.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/hlm-select-trigger.ts +59 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/hlm-select-value-template.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/hlm-select-value.ts +18 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/hlm-select-values-content.ts +9 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/hlm-select-values.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/hlm-select.ts +37 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/select/index.ts +52 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/separator/hlm-separator.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/separator/index.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/skeleton/hlm-skeleton.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/skeleton/index.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/spinner/hlm-spinner.ts +26 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/spinner/index.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/utils/hlm.ts +313 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/utils/index.ts +2 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/shared/utils/provide-spartan-hlm.ts +34 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/app/utils/async-data.ts +99 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/index.html +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/main.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/styles.css +139 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/src/types/sf-globals.d.ts +23 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/tsconfig.app.json +11 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/tsconfig.json +36 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/tsconfig.spec.json +10 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-language-switcher/ui-bundle.json +7 -0
- package/dist/jest.config.js +6 -0
- package/dist/package-lock.json +12554 -0
- package/dist/package.json +46 -0
- package/dist/scripts/apex/hello.apex +10 -0
- package/dist/scripts/gitignore-templates.json +4 -0
- package/dist/scripts/graphql-search.sh +191 -0
- package/dist/scripts/org-setup-config-schema.mjs +132 -0
- package/dist/scripts/org-setup-dev.mjs +114 -0
- package/dist/scripts/org-setup-url.mjs +108 -0
- package/dist/scripts/org-setup-utils.mjs +569 -0
- package/dist/scripts/org-setup-xml.mjs +278 -0
- package/dist/scripts/org-setup.config.json +5 -0
- package/dist/scripts/org-setup.mjs +2537 -0
- package/dist/scripts/sf-project-setup.mjs +103 -0
- package/dist/scripts/soql/account.soql +6 -0
- package/dist/scripts/validate-org-setup-config.mjs +38 -0
- package/dist/sfdx-project.json +12 -0
- package/package.json +46 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
@if (label()) {
|
|
2
|
+
<label hlmLabel [for]="labelId" class="mb-1.5 block">{{ label() }}</label>
|
|
3
|
+
}
|
|
4
|
+
@if (!multiple()) {
|
|
5
|
+
<hlm-select
|
|
6
|
+
[value]="value()"
|
|
7
|
+
(valueChange)="onSingleChange($event)"
|
|
8
|
+
[disabled]="disabled()"
|
|
9
|
+
[itemToString]="itemToString"
|
|
10
|
+
>
|
|
11
|
+
<hlm-select-trigger [buttonId]="labelId" [size]="size()" [class]="triggerClasses()">
|
|
12
|
+
<hlm-select-value [placeholder]="placeholder()" />
|
|
13
|
+
</hlm-select-trigger>
|
|
14
|
+
<hlm-select-content *hlmSelectPortal>
|
|
15
|
+
@for (option of options(); track option.value) {
|
|
16
|
+
<hlm-select-item [value]="option.value">{{ option.label }}</hlm-select-item>
|
|
17
|
+
}
|
|
18
|
+
</hlm-select-content>
|
|
19
|
+
</hlm-select>
|
|
20
|
+
} @else {
|
|
21
|
+
<hlm-select-multiple
|
|
22
|
+
[value]="$any(values())"
|
|
23
|
+
(valueChange)="onMultiChange($event)"
|
|
24
|
+
[disabled]="disabled()"
|
|
25
|
+
[itemToString]="itemToString"
|
|
26
|
+
>
|
|
27
|
+
<hlm-select-trigger [buttonId]="labelId" [size]="size()" [class]="triggerClasses()">
|
|
28
|
+
<hlm-select-value [placeholder]="placeholder()" />
|
|
29
|
+
</hlm-select-trigger>
|
|
30
|
+
<hlm-select-content *hlmSelectPortal>
|
|
31
|
+
@for (option of options(); track option.value) {
|
|
32
|
+
<hlm-select-item [value]="option.value">{{ option.label }}</hlm-select-item>
|
|
33
|
+
}
|
|
34
|
+
</hlm-select-content>
|
|
35
|
+
</hlm-select-multiple>
|
|
36
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
import {
|
|
7
|
+
ChangeDetectionStrategy,
|
|
8
|
+
Component,
|
|
9
|
+
booleanAttribute,
|
|
10
|
+
computed,
|
|
11
|
+
input,
|
|
12
|
+
model,
|
|
13
|
+
} from '@angular/core';
|
|
14
|
+
import { HlmSelectImports } from '@spartan-ng/styles/select';
|
|
15
|
+
import { HlmLabelImports } from '@spartan-ng/styles/label';
|
|
16
|
+
import type { AppFieldSize } from '../field-size';
|
|
17
|
+
import type { AppFieldAppearance } from '../field-appearance';
|
|
18
|
+
|
|
19
|
+
export interface AppSelectOption {
|
|
20
|
+
value: string;
|
|
21
|
+
label: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@Component({
|
|
25
|
+
selector: 'app-select',
|
|
26
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
27
|
+
imports: [HlmSelectImports, HlmLabelImports],
|
|
28
|
+
host: { class: 'block min-w-0' },
|
|
29
|
+
templateUrl: './select.html',
|
|
30
|
+
})
|
|
31
|
+
export class SelectComponent {
|
|
32
|
+
readonly value = model<string>('');
|
|
33
|
+
readonly values = model<readonly string[]>([]);
|
|
34
|
+
readonly multiple = input(false, { transform: booleanAttribute });
|
|
35
|
+
readonly options = input<readonly AppSelectOption[]>([]);
|
|
36
|
+
readonly placeholder = input<string>('');
|
|
37
|
+
readonly label = input<string>('');
|
|
38
|
+
readonly disabled = input(false, { transform: booleanAttribute });
|
|
39
|
+
readonly appearance = input<AppFieldAppearance>('outline');
|
|
40
|
+
readonly size = input<AppFieldSize>('default');
|
|
41
|
+
|
|
42
|
+
private static _uid = 0;
|
|
43
|
+
protected readonly labelId = `app-select-${SelectComponent._uid++}`;
|
|
44
|
+
|
|
45
|
+
protected readonly itemToString = (value: string): string => {
|
|
46
|
+
return this.options().find((o) => o.value === value)?.label ?? value;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
protected readonly triggerClasses = computed(() => {
|
|
50
|
+
if (this.appearance() === 'fill') return 'border-transparent bg-muted';
|
|
51
|
+
return '';
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
protected onSingleChange(event: string | null | undefined): void {
|
|
55
|
+
this.value.set(event ?? '');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
protected onMultiChange(event: string[] | readonly string[] | null | undefined): void {
|
|
59
|
+
this.values.set(event ?? []);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const SelectImports = [SelectComponent] as const;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
import { booleanAttribute, ChangeDetectionStrategy, Component, input } from '@angular/core';
|
|
7
|
+
import { BrnSeparator } from '@spartan-ng/brain/separator';
|
|
8
|
+
import { hlmSeparatorClass } from '@spartan-ng/styles/separator';
|
|
9
|
+
import { classes } from '@spartan-ng/styles/utils';
|
|
10
|
+
|
|
11
|
+
export type AppSeparatorOrientation = 'horizontal' | 'vertical';
|
|
12
|
+
|
|
13
|
+
@Component({
|
|
14
|
+
selector: 'app-separator',
|
|
15
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
16
|
+
hostDirectives: [{ directive: BrnSeparator, inputs: ['orientation', 'decorative'] }],
|
|
17
|
+
host: {
|
|
18
|
+
'data-slot': 'separator',
|
|
19
|
+
},
|
|
20
|
+
template: '',
|
|
21
|
+
})
|
|
22
|
+
export class SeparatorComponent {
|
|
23
|
+
readonly orientation = input<AppSeparatorOrientation>('horizontal');
|
|
24
|
+
readonly decorative = input(true, { transform: booleanAttribute });
|
|
25
|
+
|
|
26
|
+
constructor() {
|
|
27
|
+
classes(() => hlmSeparatorClass);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const SeparatorImports = [SeparatorComponent] as const;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
7
|
+
import { HlmSkeleton } from '@spartan-ng/styles/skeleton';
|
|
8
|
+
|
|
9
|
+
@Component({
|
|
10
|
+
selector: 'app-skeleton',
|
|
11
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
12
|
+
hostDirectives: [HlmSkeleton],
|
|
13
|
+
host: {
|
|
14
|
+
'aria-hidden': 'true',
|
|
15
|
+
},
|
|
16
|
+
template: '<ng-content />',
|
|
17
|
+
})
|
|
18
|
+
export class SkeletonComponent {}
|
|
19
|
+
|
|
20
|
+
export const SkeletonImports = [SkeletonComponent] as const;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
import { ChangeDetectionStrategy, Component, input } from '@angular/core';
|
|
7
|
+
import { HlmSpinnerImports } from '@spartan-ng/styles/spinner';
|
|
8
|
+
import { classes } from '@spartan-ng/styles/utils';
|
|
9
|
+
|
|
10
|
+
@Component({
|
|
11
|
+
selector: 'app-spinner',
|
|
12
|
+
imports: [HlmSpinnerImports],
|
|
13
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
14
|
+
host: {
|
|
15
|
+
role: 'status',
|
|
16
|
+
'[attr.aria-label]': 'ariaLabel()',
|
|
17
|
+
},
|
|
18
|
+
template: `<hlm-spinner />`,
|
|
19
|
+
})
|
|
20
|
+
export class SpinnerComponent {
|
|
21
|
+
public readonly ariaLabel = input<string>('Loading', { alias: 'aria-label' });
|
|
22
|
+
|
|
23
|
+
constructor() {
|
|
24
|
+
classes(() => 'text-[length:--spacing(4)]');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const SpinnerImports = [SpinnerComponent] as const;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Example: switching your app's `middleware/html.mjs` to the SITE entry of
|
|
9
|
+
* `@salesforce/angular-plugin-ui-bundle` so language switching works in local dev.
|
|
10
|
+
*
|
|
11
|
+
* This file is illustrative — it is copied into the app as an example, not used
|
|
12
|
+
* directly. Apply the change below to your real `middleware/html.mjs`.
|
|
13
|
+
*
|
|
14
|
+
* WHY: On a deployed Experience site the platform injects `SFDC_ENV.language`
|
|
15
|
+
* and folds the active language into `SFDC_ENV.basePath` (e.g. `/shop/fr`),
|
|
16
|
+
* recomputed from the URL on every load. The generic local Angular dev server
|
|
17
|
+
* does neither — `SFDC_ENV.language` is absent and `basePath` is always `/` — so
|
|
18
|
+
* the switcher can't route a non-default language locally (the reload 404s and
|
|
19
|
+
* the labels never flip). The SITE entry mirrors production for local dev only.
|
|
20
|
+
*
|
|
21
|
+
* HOW: change the import from `createHtmlMiddleware` to `createSiteHtmlMiddleware`
|
|
22
|
+
* (same package), and pass the feature's supported `LANGUAGES` (the single source
|
|
23
|
+
* of truth). The middleware needs the language CODES, so map the `{ code, label }`
|
|
24
|
+
* list to codes. Pass `defaultLanguage` explicitly so the middleware knows which
|
|
25
|
+
* language is served un-prefixed at `/`.
|
|
26
|
+
*
|
|
27
|
+
* This has NO effect on a deployed build; the middleware only runs in local dev.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
// In your middleware/html.mjs, replace:
|
|
31
|
+
// import { createHtmlMiddleware } from "@salesforce/angular-plugin-ui-bundle";
|
|
32
|
+
// export default await createHtmlMiddleware();
|
|
33
|
+
//
|
|
34
|
+
// with:
|
|
35
|
+
import { createSiteHtmlMiddleware } from "@salesforce/angular-plugin-ui-bundle";
|
|
36
|
+
import { DEFAULT_LANGUAGE, LANGUAGES } from "../languages";
|
|
37
|
+
|
|
38
|
+
export default await createSiteHtmlMiddleware({
|
|
39
|
+
languages: LANGUAGES.map((l) => l.code),
|
|
40
|
+
defaultLanguage: DEFAULT_LANGUAGE,
|
|
41
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Example: mounting <app-language-switcher /> in an app layout/header.
|
|
9
|
+
*
|
|
10
|
+
* This file is illustrative — it is copied into the app as an example, not wired
|
|
11
|
+
* into routing. To adopt the switcher, add `LanguageSwitcherComponent` to your
|
|
12
|
+
* layout component's `imports` array and place `<app-language-switcher />` in the
|
|
13
|
+
* template wherever your app's chrome lives (typically the nav/header in
|
|
14
|
+
* `app-layout.ts`). It manages its own state from the URL + SFDC_ENV, so no
|
|
15
|
+
* inputs are required.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { Component } from "@angular/core";
|
|
19
|
+
import { RouterOutlet } from "@angular/router";
|
|
20
|
+
import { LanguageSwitcherComponent } from "../index";
|
|
21
|
+
|
|
22
|
+
@Component({
|
|
23
|
+
selector: "app-layout-with-language-switcher",
|
|
24
|
+
standalone: true,
|
|
25
|
+
imports: [RouterOutlet, LanguageSwitcherComponent],
|
|
26
|
+
template: `
|
|
27
|
+
<nav class="bg-white border-b border-gray-200">
|
|
28
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
29
|
+
<div class="flex justify-between items-center h-16">
|
|
30
|
+
<span class="text-xl font-semibold text-gray-900">Angular App</span>
|
|
31
|
+
<div class="flex items-center gap-2">
|
|
32
|
+
<!-- Drop the switcher anywhere in your header/chrome. -->
|
|
33
|
+
<app-language-switcher />
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</nav>
|
|
38
|
+
<router-outlet />
|
|
39
|
+
`,
|
|
40
|
+
})
|
|
41
|
+
export class AppLayoutWithLanguageSwitcherComponent {}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Strip leading and trailing slashes from a path fragment. */
|
|
8
|
+
function trimSlashes(value: string): string {
|
|
9
|
+
return value.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Convert a Salesforce locale code to the form used in the URL path.
|
|
14
|
+
*
|
|
15
|
+
* Locale codes use underscores (e.g. `en_US`), but URL path segments use hyphens
|
|
16
|
+
* (e.g. `en-US`). This maps a code to its URL segment.
|
|
17
|
+
*/
|
|
18
|
+
function codeToUrlSegment(code: string): string {
|
|
19
|
+
return code.replace(/_/g, "-");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Convert a hyphenated language token back to a Salesforce locale code — the
|
|
24
|
+
* inverse of {@link codeToUrlSegment} (e.g. `en-US` → `en_US`). Locale codes
|
|
25
|
+
* never contain hyphens, so this remapping is unambiguous. Used both for URL
|
|
26
|
+
* path segments and for the hyphenated `SFDC_ENV.language` value the platform
|
|
27
|
+
* injects (e.g. `"en-US"`), which share the same hyphen convention.
|
|
28
|
+
*/
|
|
29
|
+
export function urlSegmentToCode(segment: string): string {
|
|
30
|
+
return segment.replace(/-/g, "_");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Recover the true, language-free site root from `basePath`.
|
|
35
|
+
*
|
|
36
|
+
* When a non-default language is active, the platform folds the language segment
|
|
37
|
+
* into `SFDC_ENV.basePath` itself — `/shop` becomes `/shop/fr` — rather than
|
|
38
|
+
* leaving `basePath` as the stable site root with the language living in the path
|
|
39
|
+
* after it. If we took `basePath` at face value, the language segment would be
|
|
40
|
+
* treated as part of the base and never seen as a leading language segment, so
|
|
41
|
+
* switching to the default (which should remove the segment) and switching
|
|
42
|
+
* between non-default languages (which should replace it) would both fail.
|
|
43
|
+
*
|
|
44
|
+
* Strip a single trailing segment when it is a known language (remapped from its
|
|
45
|
+
* URL form back to a locale code), yielding the language-free site root so the
|
|
46
|
+
* rest of this module can treat the leading path segment after it as the language.
|
|
47
|
+
*/
|
|
48
|
+
function normalizeBasePath(basePath: string, knownCodes: ReadonlySet<string>): string {
|
|
49
|
+
const segments = trimSlashes(basePath).split("/").filter(Boolean);
|
|
50
|
+
const last = segments[segments.length - 1];
|
|
51
|
+
if (last && knownCodes.has(urlSegmentToCode(last))) {
|
|
52
|
+
segments.pop();
|
|
53
|
+
}
|
|
54
|
+
return segments.join("/");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Return the path segments that live AFTER `basePath` in `pathname`.
|
|
59
|
+
* Both are compared with leading/trailing slashes normalized.
|
|
60
|
+
*/
|
|
61
|
+
function segmentsAfterBase(pathname: string, basePath: string): string[] {
|
|
62
|
+
const base = trimSlashes(basePath);
|
|
63
|
+
const trimmedPath = trimSlashes(pathname);
|
|
64
|
+
|
|
65
|
+
let rest = trimmedPath;
|
|
66
|
+
if (base && (trimmedPath === base || trimmedPath.startsWith(`${base}/`))) {
|
|
67
|
+
rest = trimmedPath.slice(base.length);
|
|
68
|
+
}
|
|
69
|
+
return trimSlashes(rest).split("/").filter(Boolean);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Read the language encoded in a URL: the first path segment after `basePath`,
|
|
74
|
+
* remapped from its URL form (hyphens) back to a locale code (underscores) and
|
|
75
|
+
* returned only when it is one of `knownCodes`. Returns `undefined` when the
|
|
76
|
+
* leading segment is absent or is not a known language code.
|
|
77
|
+
*
|
|
78
|
+
* @param currentUrl Absolute URL to inspect (e.g. `window.location.href`).
|
|
79
|
+
* @param basePath Site root path (e.g. `SFDC_ENV.basePath`); may be `""`.
|
|
80
|
+
* @param knownCodes Language codes considered valid leading segments.
|
|
81
|
+
* @returns The matched locale code (e.g. `en_US`), or `undefined`.
|
|
82
|
+
*/
|
|
83
|
+
export function getLanguageFromUrl(
|
|
84
|
+
currentUrl: string,
|
|
85
|
+
basePath: string,
|
|
86
|
+
knownCodes: ReadonlySet<string>,
|
|
87
|
+
): string | undefined {
|
|
88
|
+
const { pathname } = new URL(currentUrl);
|
|
89
|
+
const siteRoot = normalizeBasePath(basePath, knownCodes);
|
|
90
|
+
const [first] = segmentsAfterBase(pathname, siteRoot);
|
|
91
|
+
if (!first) {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
const code = urlSegmentToCode(first);
|
|
95
|
+
return knownCodes.has(code) ? code : undefined;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Rewrite `currentUrl` so `language` is reflected in the first path segment after
|
|
100
|
+
* `basePath`. The rest of the path, the query string, and the hash are preserved.
|
|
101
|
+
*
|
|
102
|
+
* The leading segment after `basePath` is examined and remapped from its URL form
|
|
103
|
+
* (hyphens) back to a locale code before being compared against `knownCodes`:
|
|
104
|
+
*
|
|
105
|
+
* - **Default language** (`language === defaultLanguage`): the default is the
|
|
106
|
+
* implicit, un-prefixed language, so NO segment is written. An existing
|
|
107
|
+
* known-language leading segment is REMOVED (`/shop/fr/page` → `/shop/page`);
|
|
108
|
+
* if there is none, the path is left unchanged.
|
|
109
|
+
* - **Non-default language**: an existing known-language leading segment is
|
|
110
|
+
* REPLACED — so switching never stacks segments (`/en-US/fr/page`) — otherwise
|
|
111
|
+
* the language is INSERTED as a new first segment. The written segment uses the
|
|
112
|
+
* URL form of the code (underscores → hyphens, e.g. `en_US` → `en-US`).
|
|
113
|
+
*
|
|
114
|
+
* When a non-default language is active the platform folds that language into
|
|
115
|
+
* `basePath` itself (`/shop` → `/shop/fr`); a trailing known-language segment is
|
|
116
|
+
* stripped from `basePath` first (see {@link normalizeBasePath}) so the leading
|
|
117
|
+
* segment after the true site root is always what gets replaced/removed/inserted.
|
|
118
|
+
*
|
|
119
|
+
* `basePath` is matched with trailing slashes normalized, and the result never
|
|
120
|
+
* contains double slashes.
|
|
121
|
+
*
|
|
122
|
+
* @param currentUrl Absolute URL to rewrite (e.g. `window.location.href`).
|
|
123
|
+
* @param basePath Site root path (e.g. `SFDC_ENV.basePath`); may be `""`.
|
|
124
|
+
* @param language Locale code to reflect after `basePath` (e.g. `en_US`).
|
|
125
|
+
* @param knownCodes Language codes eligible for the leading-segment check.
|
|
126
|
+
* @param defaultLanguage Locale code that is served without a URL segment.
|
|
127
|
+
* @returns The rewritten absolute URL as a string.
|
|
128
|
+
*/
|
|
129
|
+
export function buildLanguageUrl(
|
|
130
|
+
currentUrl: string,
|
|
131
|
+
basePath: string,
|
|
132
|
+
language: string,
|
|
133
|
+
knownCodes: ReadonlySet<string>,
|
|
134
|
+
defaultLanguage: string,
|
|
135
|
+
): string {
|
|
136
|
+
const url = new URL(currentUrl);
|
|
137
|
+
|
|
138
|
+
const base = normalizeBasePath(basePath, knownCodes);
|
|
139
|
+
const segments = segmentsAfterBase(url.pathname, base);
|
|
140
|
+
const leadingIsLanguage = segments.length > 0 && knownCodes.has(urlSegmentToCode(segments[0]));
|
|
141
|
+
|
|
142
|
+
if (language === defaultLanguage) {
|
|
143
|
+
// The default language is served un-prefixed. Drop an existing language
|
|
144
|
+
// segment so switching back to default removes it, rather than writing one.
|
|
145
|
+
if (leadingIsLanguage) {
|
|
146
|
+
segments.shift();
|
|
147
|
+
}
|
|
148
|
+
} else if (leadingIsLanguage) {
|
|
149
|
+
segments[0] = codeToUrlSegment(language);
|
|
150
|
+
} else {
|
|
151
|
+
segments.unshift(codeToUrlSegment(language));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const rebuiltPath = [base, ...segments].filter(Boolean).join("/");
|
|
155
|
+
url.pathname = `/${rebuiltPath}`;
|
|
156
|
+
|
|
157
|
+
return url.toString();
|
|
158
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Public API for the Angular language switcher feature.
|
|
9
|
+
*
|
|
10
|
+
* Most apps only need:
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { LanguageSwitcherComponent } from ".../features/language-switcher";
|
|
13
|
+
* // Add to component imports: [LanguageSwitcherComponent]
|
|
14
|
+
* // Use in template: <app-language-switcher />
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Lower-level pieces are exported for custom UIs and testing:
|
|
18
|
+
* - {@link getCurrentLanguage} to read the active language
|
|
19
|
+
* - {@link buildLanguageUrl} to compute the rewritten URL yourself
|
|
20
|
+
* - {@link LANGUAGES} / {@link DEFAULT_LANGUAGE} for the supported set
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
export { LanguageSwitcherComponent, getCurrentLanguage } from "./language-switcher";
|
|
24
|
+
|
|
25
|
+
export { buildLanguageUrl, getLanguageFromUrl, urlSegmentToCode } from "./build-language-url";
|
|
26
|
+
|
|
27
|
+
export { LANGUAGES, DEFAULT_LANGUAGE, LANGUAGE_CODES } from "./languages";
|
|
28
|
+
export type { LanguageOption } from "./languages";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
@if (hasMultipleLanguages) {
|
|
2
|
+
<app-dropdown-menu align="end" [aria-label]="accessibleLabel()" [triggerClass]="triggerClass">
|
|
3
|
+
<span trigger class="inline-flex items-center gap-1.5">
|
|
4
|
+
<app-icon name="globe" size="16" class="inline-flex" />
|
|
5
|
+
<span>{{ currentLanguageLabel }}</span>
|
|
6
|
+
<app-icon name="chevronDown" size="14" class="inline-flex opacity-50" />
|
|
7
|
+
</span>
|
|
8
|
+
|
|
9
|
+
<ng-template appDropdownMenuContent>
|
|
10
|
+
@for (language of languages; track language.code) {
|
|
11
|
+
<button appDropdownMenuItem type="button" (triggered)="switchLanguage(language.code)">
|
|
12
|
+
@if (language.code === currentLanguage) {
|
|
13
|
+
<app-icon name="check" size="14" class="mr-2" />
|
|
14
|
+
} @else {
|
|
15
|
+
<span class="mr-2 inline-block size-3.5"></span>
|
|
16
|
+
}
|
|
17
|
+
<span>{{ language.label }}</span>
|
|
18
|
+
</button>
|
|
19
|
+
}
|
|
20
|
+
</ng-template>
|
|
21
|
+
</app-dropdown-menu>
|
|
22
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Drop-in language switcher for B2X (Experience) Angular apps.
|
|
9
|
+
*
|
|
10
|
+
* Renders a dropdown menu of the site's supported {@link LANGUAGES} using the
|
|
11
|
+
* shared `app-dropdown-menu` component. Choosing a language rewrites the current
|
|
12
|
+
* URL so the chosen code becomes the first path segment after `basePath` (see
|
|
13
|
+
* {@link buildLanguageUrl}) and reloads the page via `window.location.assign`.
|
|
14
|
+
* A full reload lets the platform serve the correctly localized content — this
|
|
15
|
+
* component owns only the URL rewrite.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { ChangeDetectionStrategy, Component, computed, input } from "@angular/core";
|
|
19
|
+
|
|
20
|
+
import { DropdownMenuImports } from "../../components/ui/dropdown-menu/dropdown-menu";
|
|
21
|
+
import { IconComponent } from "../../components/ui/icon/icon";
|
|
22
|
+
import { buildLanguageUrl, getLanguageFromUrl, urlSegmentToCode } from "./build-language-url";
|
|
23
|
+
import { DEFAULT_LANGUAGE, LANGUAGE_CODES, LANGUAGES } from "./languages";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The subset of `SFDC_ENV` this component reads. We type it structurally here
|
|
27
|
+
* (rather than relying on the ambient `SfdcEnv`) so the feature type-checks in
|
|
28
|
+
* isolation: its ambient augmentation intentionally declares only `language?`,
|
|
29
|
+
* while `basePath` is provided by the platform types once composed into an app.
|
|
30
|
+
*/
|
|
31
|
+
interface SfdcEnvSubset {
|
|
32
|
+
basePath?: string;
|
|
33
|
+
/** Page locale in hyphenated form, e.g. "en-US" (the platform's injected form). */
|
|
34
|
+
language?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Read `SFDC_ENV` off the global scope without assuming it exists. */
|
|
38
|
+
function getSfdcEnv(): SfdcEnvSubset | undefined {
|
|
39
|
+
return (globalThis as { SFDC_ENV?: SfdcEnvSubset }).SFDC_ENV;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Resolve the active language, in precedence order:
|
|
44
|
+
*
|
|
45
|
+
* 1. `SFDC_ENV.language` — authoritative when the platform provides it. The
|
|
46
|
+
* platform injects this in hyphenated form (e.g. `"en-US"`), so it is
|
|
47
|
+
* remapped back to a locale code (`en_US`) before matching, mirroring how the
|
|
48
|
+
* URL segment is handled.
|
|
49
|
+
* 2. The leading URL path segment after `basePath`, when it is a supported
|
|
50
|
+
* language code — reflects the page the user is actually viewing (e.g. a
|
|
51
|
+
* direct hit on `/shop/fr/catalog`) even before the runtime populates
|
|
52
|
+
* `SFDC_ENV.language`.
|
|
53
|
+
* 3. {@link DEFAULT_LANGUAGE}.
|
|
54
|
+
*
|
|
55
|
+
* Only codes in {@link LANGUAGES} are honored; anything else falls through.
|
|
56
|
+
*/
|
|
57
|
+
export function getCurrentLanguage(): string {
|
|
58
|
+
const envLanguage = getSfdcEnv()?.language;
|
|
59
|
+
if (envLanguage) {
|
|
60
|
+
const envCode = urlSegmentToCode(envLanguage);
|
|
61
|
+
if (LANGUAGE_CODES.has(envCode)) {
|
|
62
|
+
return envCode;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const basePath = getSfdcEnv()?.basePath ?? "";
|
|
67
|
+
const urlLanguage = getLanguageFromUrl(window.location.href, basePath, LANGUAGE_CODES);
|
|
68
|
+
return urlLanguage ?? DEFAULT_LANGUAGE;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@Component({
|
|
72
|
+
selector: "app-language-switcher",
|
|
73
|
+
standalone: true,
|
|
74
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
75
|
+
imports: [...DropdownMenuImports, IconComponent],
|
|
76
|
+
templateUrl: "./language-switcher.html",
|
|
77
|
+
})
|
|
78
|
+
export class LanguageSwitcherComponent {
|
|
79
|
+
/** Accessible label prefix for the dropdown trigger. Defaults to "Language". */
|
|
80
|
+
readonly label = input<string>("Language");
|
|
81
|
+
|
|
82
|
+
readonly languages = LANGUAGES;
|
|
83
|
+
readonly currentLanguage = getCurrentLanguage();
|
|
84
|
+
readonly hasMultipleLanguages = LANGUAGES.length >= 2;
|
|
85
|
+
|
|
86
|
+
/** The label of the currently active language (for display in the trigger). */
|
|
87
|
+
readonly currentLanguageLabel =
|
|
88
|
+
LANGUAGES.find((l) => l.code === this.currentLanguage)?.label ?? "";
|
|
89
|
+
|
|
90
|
+
/** Accessible label that includes the visible current-language text (WCAG 2.5.3). */
|
|
91
|
+
readonly accessibleLabel = computed(() => `${this.label()}: ${this.currentLanguageLabel}`);
|
|
92
|
+
|
|
93
|
+
/** Classes applied to the dropdown-menu's trigger button. */
|
|
94
|
+
readonly triggerClass =
|
|
95
|
+
"inline-flex items-center gap-1.5 rounded-md border border-border bg-card px-3 py-1.5 text-sm text-foreground hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none";
|
|
96
|
+
|
|
97
|
+
switchLanguage(code: string): void {
|
|
98
|
+
if (code === this.currentLanguage) return;
|
|
99
|
+
|
|
100
|
+
const basePath = getSfdcEnv()?.basePath ?? "";
|
|
101
|
+
const nextUrl = buildLanguageUrl(
|
|
102
|
+
window.location.href,
|
|
103
|
+
basePath,
|
|
104
|
+
code,
|
|
105
|
+
LANGUAGE_CODES,
|
|
106
|
+
DEFAULT_LANGUAGE,
|
|
107
|
+
);
|
|
108
|
+
window.location.assign(nextUrl);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** A single language option offered by the switcher. */
|
|
8
|
+
export interface LanguageOption {
|
|
9
|
+
/** Salesforce locale code, e.g. "en_US". Used as the URL path segment. */
|
|
10
|
+
code: string;
|
|
11
|
+
/** Human-readable label shown in the dropdown, e.g. "English". */
|
|
12
|
+
label: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The languages this app offers in the switcher.
|
|
17
|
+
*
|
|
18
|
+
* IMPORTANT — keep this list in sync BY HAND with the site's language settings:
|
|
19
|
+
* digitalExperiences/site/<siteName>/sfdc_cms__languageSettings/content.json
|
|
20
|
+
*
|
|
21
|
+
* There is no runtime API to read `sfdc_cms__languageSettings` on a published
|
|
22
|
+
* site, so the supported languages are baked into the bundle at authoring time.
|
|
23
|
+
* When the site's content.json changes, update this array (and
|
|
24
|
+
* {@link DEFAULT_LANGUAGE}) to match.
|
|
25
|
+
*
|
|
26
|
+
* `code` values are Salesforce locale codes (underscores). They are converted to
|
|
27
|
+
* hyphenated form for use as the first URL path segment after `basePath` (e.g.
|
|
28
|
+
* `en_US` → `/en-US/...`, `fr` → `/fr/...`). Display order here is the order shown
|
|
29
|
+
* in the dropdown.
|
|
30
|
+
*/
|
|
31
|
+
export const LANGUAGES: readonly LanguageOption[] = [
|
|
32
|
+
{ code: "en_US", label: "English" },
|
|
33
|
+
{ code: "fr", label: "Français" },
|
|
34
|
+
{ code: "es", label: "Español" },
|
|
35
|
+
{ code: "de", label: "Deutsch" },
|
|
36
|
+
{ code: "ja", label: "日本語" },
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Language used when `SFDC_ENV.language` is missing or is not one of
|
|
41
|
+
* {@link LANGUAGES}. Should match the site's default language in content.json.
|
|
42
|
+
*/
|
|
43
|
+
export const DEFAULT_LANGUAGE = "en_US";
|
|
44
|
+
|
|
45
|
+
/** Set of known language codes, for fast membership checks. */
|
|
46
|
+
export const LANGUAGE_CODES: ReadonlySet<string> = new Set(LANGUAGES.map((l) => l.code));
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { TestBed } from '@angular/core/testing';
|
|
2
|
+
import { HomeComponent } from './home';
|
|
3
|
+
|
|
4
|
+
describe('HomeComponent', () => {
|
|
5
|
+
beforeEach(async () => {
|
|
6
|
+
await TestBed.configureTestingModule({
|
|
7
|
+
imports: [HomeComponent],
|
|
8
|
+
}).compileComponents();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should create the component', () => {
|
|
12
|
+
const fixture = TestBed.createComponent(HomeComponent);
|
|
13
|
+
const component = fixture.componentInstance;
|
|
14
|
+
expect(component).toBeTruthy();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should render main landmark', async () => {
|
|
18
|
+
const fixture = TestBed.createComponent(HomeComponent);
|
|
19
|
+
await fixture.whenStable();
|
|
20
|
+
const compiled = fixture.nativeElement as HTMLElement;
|
|
21
|
+
expect(compiled.querySelector('main')).toBeTruthy();
|
|
22
|
+
});
|
|
23
|
+
});
|