This site provides a machine-readable index at /llms.txt.

Skip to main content Skip to navigation

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 LanguageSwitcher is rendered automatically; the above is the reference wiring for replaced layouts or bare AddPennington hosts.

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; FallbackNotice is a pure presentation surface.

See also

  • Related reference: Navigation components — sibling Pennington.UI reference page for TableOfContentsNavigation and OutlineNavigation.
  • Related reference: Content components — sibling Pennington.UI reference page for Card, Badge, CodeBlock, and the rest of the content-authoring surface.
  • Related reference: JSON-LD schema types — the record types (JsonLdArticle, JsonLdBreadcrumbList, JsonLdWebSite) that StructuredData serializes.
  • How-to: Add a second locale to your site — tutorial that wires LanguageSwitcher and FallbackNotice end-to-end via AddDocSite.