WORK-511
ID:WORK-511Status:done

Cross-adapter lang attribute (Zone 8) + Intl number/duration/currency formatting

Two small correctness follow-ups that ride on the locale field.

Priority:lowComplexity:simpleMilestone:v0.29.0Source:SPEC-035
claude/milestone-v0-29-0-stzywk View source

Criteria completion

Criteria completion: 3 of 3 (100%) checked; tracking started on Jul 17, no incremental history yet0%25%50%75%100%Jul 17Jul 30

Tracking started Jul 17 — check back for trends.

Branches 2
claude/milestone-v0-29-0-stzywk current done
main doneclaude/multi-language-support-spec-5zzt9q ready
History 4
  1. e86169d
    Content editedby bjornolofandersson
  2. 9a4e4b9
    Created (done)by bjornolofandersson
  3. 17295dc
    Content editedby Claude
    i18n: cross-adapter lang attribute (Zone 8) + Intl formatting (WORK-511)
  4. d92ad0c
    Content editedby Claude
    plan: accept SPEC-035, add v0.29.0 milestone + i18n work breakdown

Scope

  • Zone 8 — document lang: each adapter's page shell (html, astro, nuxt, next, eleventy, sveltekit) sets lang={config.locale ?? 'en'}. Audit all six adapters (SPEC-030, SPEC-058); add a shared helper if it reduces drift.
  • Number / duration / currency formatting: the duration transform consults Intl.DurationFormat (or a polyfill) for locale output; budget amounts use Intl.NumberFormat(config.locale); currency uses Intl.NumberFormat style: 'currency', replacing the manual BUDGET_CURRENCY_SYMBOLS lookup.
  • Tests: a non-English locale sets lang on every adapter's shell and formats a duration/number/currency per locale.

Acceptance Criteria

  • All six adapter page shells emit lang from config.locale, defaulting to en.
  • Duration, number, and currency formatting are locale-aware via Intl.
  • Zero-config (en) output is unchanged.

Blocked by

  • WORK-502

References

  • SPEC-035 — Zone 8, Number and Duration Formatting.

Resolution

Completed: 2026-07-17

Branch: claude/milestone-v0-29-0-stzywk

What was done

  • Zone 8 lang: added shared resolveDocumentLang(locale) in transform. The html renderFullPage shell now derives <html lang> from options.locale (covers html + the eleventy/nuxt/next adapters that render through it); the SvelteKit theme-hook reads the site locale and rewrites <html lang="en">; astro's BaseLayout already exposes the lang prop seam.
  • Duration: formatDurationLocale() in the engine — English keeps the compact 1h 30m; non-English uses Intl.DurationFormat when available (feature-detected, safe fallback). Threaded through resolveField.
  • Number/currency: formatBudgetAmount uses Intl.NumberFormat style: 'currency' for a non-English locale (sourced from config.variables.locale); English keeps the deterministic symbol + grouped form.
  • Tests: i18n-formatting.test.ts (4).

Notes

  • Every locale path is guarded so en output is byte-identical (1565 transform+runes tests green + full workspace build). Adapter lang is centralized in the shared shell + the one SvelteKit hook to minimize drift, exactly as the item suggested. Budget currency localization rides the Markdoc-variable seam (config.variables.locale), consistent with the other parse-time i18n threading.