Utility components
Pennington.UI ships three utility Razor components — LanguageSwitcher, StructuredData, and FallbackNotice — that handle locale selection, JSON-LD head injection, and fallback-locale notification respectively. All three live in namespace Pennington.UI.Components and are made available via the @using Pennington.UI.Components import.
LanguageSwitcher
Renders a <details>-backed dropdown of alternate-language links pre-wired for SPA reload via the data-spa-reload attribute; hides itself when fewer than two locales are available, and auto-computes the list from LocaleContext and LocalizationOptions when AlternateLanguages is null or empty.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
AlternateLanguages |
IReadOnlyList<AlternateLanguageItem>? |
null |
Explicit list of alternate-language items; when null or empty, the component auto-computes the list from the injected LocaleContext and LocalizationOptions. |
AlternateLanguageItem
Nested record type that callers supply when constructing an explicit AlternateLanguages list; DocSite's MainLayout builds one instance per locale per-request from ContentResolver.GetAlternateLanguagesAsync.
| Name | Type | Description |
|---|---|---|
Locale |
string |
Locale code written to the data-locale attribute on the rendered <a>. |
DisplayName |
string |
Visible label used in the dropdown row and as the currently-selected summary text. |
Url |
string |
href written on the anchor; typically a locale-prefixed canonical path. |
IsCurrentLocale |
bool |
When true, the row renders with current-locale styling (font-semibold and the primary accent color). |
Example
The DocSite MainLayout (src/Pennington.DocSite/Components/Layout/MainLayout.razor) shows the production wiring: guard on LocalizationOptions.IsMultiLocale, then pass the pre-computed _langSwitcherItems list.
@if (LocalizationOptions.IsMultiLocale)
{
<LanguageSwitcher AlternateLanguages="_langSwitcherItems" />
}
Note: In a DocSite host
LanguageSwitcheris rendered automatically; the above is the reference wiring for replaced layouts or bareAddPenningtonhosts.
StructuredData
<HeadContent>
@if (_articleJson != null)
{
<script type="application/ld+json">@((MarkupString)_articleJson)</script>
}
@if (_breadcrumbJson != null)
{
<script type="application/ld+json">@((MarkupString)_breadcrumbJson)</script>
}
@if (_webSiteJson != null)
{
<script type="application/ld+json">@((MarkupString)_webSiteJson)</script>
}
</HeadContent>
@code {
[Parameter] public JsonLdArticle? Article { get; set; }
[Parameter] public JsonLdBreadcrumbList? Breadcrumbs { get; set; }
[Parameter] public JsonLdWebSite? WebSite { get; set; }
private string? _articleJson;
private string? _breadcrumbJson;
private string? _webSiteJson;
protected override void OnParametersSet()
{
_articleJson = Article is not null ? JsonLdSerializer.SerializeArticle(Article) : null;
_breadcrumbJson = Breadcrumbs is not null ? JsonLdSerializer.SerializeBreadcrumbList(Breadcrumbs) : null;
_webSiteJson = WebSite is not null ? JsonLdSerializer.SerializeWebSite(WebSite) : null;
}
}
Emits up to three <script type="application/ld+json"> tags into the document <head> via <HeadContent>, one each for JsonLdArticle, JsonLdBreadcrumbList, and JsonLdWebSite; each payload is serialized with JsonLdSerializer and rendered only when the corresponding parameter is non-null.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
Article |
JsonLdArticle? |
null |
Schema.org Article payload emitted when non-null, serialized by JsonLdSerializer.SerializeArticle. |
Breadcrumbs |
JsonLdBreadcrumbList? |
null |
Schema.org BreadcrumbList payload emitted when non-null, serialized by JsonLdSerializer.SerializeBreadcrumbList. |
WebSite |
JsonLdWebSite? |
null |
Schema.org WebSite payload emitted when non-null, serialized by JsonLdSerializer.SerializeWebSite; typically rendered once on the home page. |
Example
The DocSite Pages component (src/Pennington.DocSite/Components/Layout/Pages.razor) emits StructuredData gated on CanonicalBaseUrl being set — article and breadcrumb on content pages, website on the home page:
@if (!string.IsNullOrEmpty(Options.CanonicalBaseUrl))
{
<StructuredData Article="@article" Breadcrumbs="@breadcrumbs" WebSite="@webSite" />
}
Note: The JSON-LD payload record types are documented at Pennington.StructuredData.JsonLdArticle.
FallbackNotice
@if (!string.IsNullOrEmpty(RequestedLocale))
{
<div class="mb-6 rounded-lg border border-amber-300 dark:border-amber-600/50 bg-amber-50 dark:bg-amber-950/30 px-4 py-3 text-sm text-amber-800 dark:text-amber-200">
<svg xmlns="http://www.w3.org/2000/svg" class="inline-block h-4 w-4 mr-1.5 -mt-0.5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" clip-rule="evenodd" />
</svg>
This page is not yet available in <strong>@RequestedLocale</strong>. Showing the <strong>@DefaultLocale</strong> version.
</div>
}
@code {
[Parameter] public string? RequestedLocale { get; set; }
[Parameter] public string? DefaultLocale { get; set; }
}
Renders an inline amber notice banner above the article region when the requested locale has no translation and the page is being served from the default locale; renders nothing when RequestedLocale is null or empty.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
RequestedLocale |
string? |
null |
Locale code the visitor requested; when non-null and non-empty, the notice renders and displays this value as the unavailable locale. |
DefaultLocale |
string? |
null |
Locale code the page is served in; displayed in the notice as the locale the visitor sees instead. |
Example
DocSiteArticle (src/Pennington.DocSite/Slots/Components/DocSiteArticle.razor) places FallbackNotice above the article header whenever a non-empty FallbackRequestedLocale is supplied by the content resolver:
<FallbackNotice RequestedLocale="@Article.FallbackRequestedLocale"
DefaultLocale="@LocalizationOptions.DefaultLocale" />
Note: Fallback detection is owned by
ContentResolver;FallbackNoticeis a pure presentation surface.
See also
- Related reference: Navigation components — sibling
Pennington.UIreference page forTableOfContentsNavigationandOutlineNavigation. - Related reference: Content components — sibling
Pennington.UIreference page forCard,Badge,CodeBlock, and the rest of the content-authoring surface. - Related reference: JSON-LD schema types — the record types (
JsonLdArticle,JsonLdBreadcrumbList,JsonLdWebSite) thatStructuredDataserializes. - How-to: Add a second locale to your site — tutorial that wires
LanguageSwitcherandFallbackNoticeend-to-end viaAddDocSite.