TwoSky.WebComponents.LanguageBanner
1.1.0
dotnet add package TwoSky.WebComponents.LanguageBanner --version 1.1.0
NuGet\Install-Package TwoSky.WebComponents.LanguageBanner -Version 1.1.0
<PackageReference Include="TwoSky.WebComponents.LanguageBanner" Version="1.1.0" />
<PackageVersion Include="TwoSky.WebComponents.LanguageBanner" Version="1.1.0" />
<PackageReference Include="TwoSky.WebComponents.LanguageBanner" />
paket add TwoSky.WebComponents.LanguageBanner --version 1.1.0
#r "nuget: TwoSky.WebComponents.LanguageBanner, 1.1.0"
#:package TwoSky.WebComponents.LanguageBanner@1.1.0
#addin nuget:?package=TwoSky.WebComponents.LanguageBanner&version=1.1.0
#tool nuget:?package=TwoSky.WebComponents.LanguageBanner&version=1.1.0
LanguageBanner
A language selection banner web component that detects when the user's preferred language differs from the current page language. It offers to persist the current language as the user's preference or dismiss the banner for the session.
This plugin is only compatible with the Web3 Vidyano client.
Installation
After installing the NuGet package, add the following import to your app.ts:
import "../language-banner/language-banner";
Rebuild the frontend code after making this change. Then choose how the component reaches the page:
Stock Vidyano client (<vi-app>) — automatic injection
Opt a website in by adding a LanguageBanner key to its entry in App_Data/websites.json:
"CareAdmin": { "Type": 4, "Bindings": ["*/careadmin"], "LanguageBanner": "menu-footer" }
The plugin then injects the following element as the first child of <vi-app> when that website's index.html is served:
<ts-language-banner slot="menu-footer" display-mode="dropdown" theme="menu"></ts-language-banner>
vi-app forwards the menu-footer slot into the menu footer; with theme="menu" the component overlays the <vi-user> actions row, centred between the settings and sign-out buttons. Selecting a language switches the session language and reloads, after which the mismatch banner offers to use that language everywhere — the same flow as manual placement. Nothing is injected when the key is missing, when the page has no <vi-app>, or when a ts-language-banner element is already present.
Custom pages — manual placement
For a custom shell (e.g. a <ca-app> webshop) add the element yourself, in the navigation bar:
<ts-language-banner display-mode="dropdown"></ts-language-banner>
Both can be combined in one application: enable the key on the stock website only and keep manual placement in the custom page.
UserSettings "Language" field
Installing the plugin registers a CronosAdvanced.RegisterLoadUserSettingsHook handler that removes the Language attribute from Vidyano's UserSettings persistent object — but only for requests coming through a website that has the LanguageBanner key, i.e. where the dropdown replaces it. Websites without the key keep the field. To keep the field everywhere, set this in Startup:
Service.Plugins.LanguageBanner.HideUserSettingsLanguage = false;
Note: a module Advanced that overrides LoadUserSettings must call base.LoadUserSettings(args) or the handler does not run.
Display Modes
The component supports two display modes via the display-mode attribute:
Dropdown (default)
Shows a globe icon with the current language code. Clicking opens a dropdown menu with available languages.
<ts-language-banner display-mode="dropdown"></ts-language-banner>
Buttons
Shows all available languages as side-by-side buttons, with the active language highlighted.
<ts-language-banner display-mode="buttons"></ts-language-banner>
Attributes
| Attribute | Default | Description |
|---|---|---|
display-mode |
dropdown |
dropdown or buttons (see above) |
theme |
(empty) | menu adapts the component to the stock vi-app shell: the dropdown sits in the vi-user actions row, in a gap the component reserves between the middle buttons (inline margins on vi-user's buttons, sized to the trigger, so it also works when privacy/profiler/feedback buttons are enabled), the popup opens upwards; the mismatch banner overlays the top of the page as in every other placement (it is rendered as a top-layer popover, so it always stays above the application) |
hide-banner |
off | Never render the language mismatch banner |
persist-on-select |
off | Selecting a language first calls UpdateApplicationLanguage (persists Person.ApplicationLanguage, refreshes the PreferredLanguage cookie) and then reloads. Without it a selection only switches the session language via the requestedLanguage cookie |
hide-banner and persist-on-select are meant to be used together for a silent switch: the selection is saved immediately, so preferred and current language cannot diverge and the banner is not needed. Neither is set by default nor by the automatic injection, so the default flow is always: session switch + banner offering to persist.
Language Mismatch Banner
When the user's preferred language (stored in a PreferredLanguage cookie, set by CronosCore) differs from the current page language, a banner appears with two options:
- "Use {language} everywhere" - Calls the
CronosWeb.UpdateApplicationLanguageendpoint to persist the current language as the user'sPerson.ApplicationLanguage - "Dismiss for now" - Hides the banner until the next page load
Events
The component fires the following custom events:
| Event | Detail | Description |
|---|---|---|
language-persist |
{ language: string } |
User clicked "Use everywhere" |
language-dismiss |
{ from: string, to: string } |
User clicked "Dismiss" |
language-select |
{ language: string } |
User selected a language from dropdown/buttons |
Translatable Messages
The plugin registers the following client-side messages (en, nl, fr):
LanguageBanner_Message- The mismatch banner messageLanguageBanner_UseEverywhere- The persist button labelLanguageBanner_Dismiss- The dismiss button labelLanguageBanner_LanguageName_en- Language name for EnglishLanguageBanner_LanguageName_nl- Language name for DutchLanguageBanner_LanguageName_fr- Language name for French
Styling
The component uses Shadow DOM. You can customize its appearance via CSS custom properties and ::part() selectors.
CSS Custom Properties
Override these on the host element or any ancestor:
| Variable | Default | Description |
|---|---|---|
--language-banner-bg |
#f8f9fa |
Banner background color |
--language-banner-color |
#212529 |
Banner text color |
--language-banner-padding |
12px 20px |
Banner padding |
--language-banner-shadow |
0 2px 5px rgba(0,0,0,0.1) |
Banner box shadow |
--language-banner-z-index |
1050 |
Banner z-index |
--language-banner-font-size |
14px |
Banner font size |
--language-banner-btn-padding |
8px 15px |
Button padding |
--language-banner-btn-radius |
4px |
Button border radius |
--language-banner-primary-bg |
#007bff |
"Use everywhere" button background |
--language-banner-primary-color |
white |
"Use everywhere" button text color |
--language-banner-primary-hover-bg |
#0056b3 |
"Use everywhere" button hover background |
--language-banner-secondary-bg |
#6c757d |
"Dismiss" button background |
--language-banner-secondary-color |
white |
"Dismiss" button text color |
--language-banner-secondary-hover-bg |
#545b62 |
"Dismiss" button hover background |
Example:
ts-language-banner {
--language-banner-primary-bg: var(--theme-color);
--language-banner-primary-hover-bg: var(--theme-color-lighter);
--language-banner-bg: var(--theme-color-faint);
}
CSS ::part() Selectors
For full styling control, target individual elements:
| Part name | Element |
|---|---|
banner |
The mismatch notification banner |
banner-content |
Banner message container |
banner-icon |
Globe icon in the banner |
banner-message |
Banner text |
banner-actions |
Banner button container |
btn-primary |
"Use everywhere" button |
btn-secondary |
"Dismiss" button |
dropdown |
Dropdown mode container |
trigger |
Dropdown trigger button |
menu |
Dropdown menu |
menu-item |
Dropdown menu item |
buttons |
Buttons mode container |
button |
Individual language button |
button-active |
Active language button |
Example:
ts-language-banner::part(banner) {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
ts-language-banner::part(btn-primary) {
background-color: white;
color: #764ba2;
}
Dependencies
- CronosCore (CronosCore#742) - Provides:
PreferredLanguagecookie set on login fromPerson.ApplicationLanguage(opt-in viaPreferredLanguageCookie.Enabled)CronosWeb.UpdateApplicationLanguage()— endpoint that forwards to CronosCentral viaClientInvokerand refreshes the cookie on successCronosAdvanced.RegisterLoadUserSettingsHook()(CronosCore.Common 3.31.0+) — used to hide the UserSettingsLanguagefield. The generatedService/Plugins/LanguageBanner.g.cscompiles inside your project against the CronosCore version you reference; the package itself declares no CronosCore dependency.
Consuming App Setup
Enable the preferred language cookie in your authenticator service constructor:
public MyAuthenticatorService()
: base(..., preferredLanguageCookie: PreferredLanguageCookie.Enabled)
{ }
No additional wiring is needed — CronosWeb.UpdateApplicationLanguage() handles the CronosCentral API call and cookie refresh automatically. Requires services.AddCronosCore() to be registered.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Vidyano (>= 6.0.20260820.6492)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.