Consumer integration: localized diagnostics

Updated Jul 27, 2026

Zamburak uses injection-first localization. The host application owns locale negotiation and loader lifecycle; Zamburak never reads process locale environment variables or maintains mutable global state.

Host-owned loader setup

Create a FluentLanguageLoader in the host application and pass it through a FluentLocalizerAdapter that implements the Localizer trait:

use zamburak_core::i18n::{FluentLocalizerAdapter, Localizer};
use i18n_embed::fluent::FluentLanguageLoader;

let loader: FluentLanguageLoader = /* host-configured loader */;
let localizer: Box<dyn Localizer> = Box::new(
    FluentLocalizerAdapter::new(loader),
);

When no localization backend is configured, use the deterministic fallback:

use zamburak_core::i18n::NoOpLocalizer;

let localizer = NoOpLocalizer;

Loading Zamburak embedded assets

Zamburak publishes embedded .ftl translation assets via Localizations. Load them into the host-owned loader so Zamburak messages are available:

use zamburak_core::i18n::Localizations;

loader.load_assets(&Localizations, &requested_locales);

Resolution order is:

  1. host application catalogue entries,
  2. Zamburak bundled entries for the requested locale,
  3. Zamburak bundled en-US entries,
  4. caller-provided fallback text.

Rendering localized diagnostics

Zamburak diagnostics expose a render_localized method that accepts an injected &dyn Localizer plus caller fallback copy:

let message = diagnostic.render_localized(&localizer, "fallback text");

Formatting failures and missing translations fall through the resolution chain and always produce deterministic output. See adr-002-localization-and-internationalization-with-fluent.md for the full design rationale.