Release v0.14.5
[0.14.5] — 2026-07-10
Revision of 0.14.0 — the review release. A hard audit of what 0.14.0 shipped found three real defects, all fixed here: the devtools overlay froze the page (its own MutationObserver re-triggered on its own panel writes — infinite microtask loop), '' catalog entries were treated inconsistently across the toolchain (the runtime rendered them as blank holes while extract/check/render call them untranslated — and render's '' handling silently did nothing for nested catalogs), and the new hreflang alternates were being voided by cross-locale canonicals (mirrored pages kept the source page's <link rel="canonical">, which search engines prefer over hreflang). Ready to publish. One behavior change ('' now falls back — see Changed), no API removals, no new dependencies.
Fixed
- Devtools freeze (
verbaly/devtools):attachDevtools's MutationObserver re-fired on its ownpanel.innerHTML/tooltip writes — in a real browser the microtask queue never drained and the tab hung the moment the overlay mounted. The observer now ignores mutations originating inside its own panel/tip. Regression test drains the observer microtasks and asserts the scan count settles (the 0.14.0 tests were synchronous and couldn't see the loop). renderHtml''handling with nested catalogs (@verbaly/compiler): the "''counts as untranslated → fall back" cleanup iterated only top-level entries, so with nested catalogs (verbaly-web's shape) it silently kept''and the static output diverged from the runtime. The cleanup is deleted — the core lookup now implements the semantics (see Changed), nested or flat, and render output == post-hydration output is guaranteed again.RenderHtmlOptions.catalogsis officially widened to accept nested trees (Catalogs | Record<string, MessageTree>).- Cross-locale canonical voided hreflang (
@verbaly/compiler): mirrored locale pages carried the source page's<link rel="canonical">(andog:url) — a canonical pointing at another locale tells search engines to fold the page into it, neutralizing the hreflang set 0.14.0 introduced.renderHtmlnow rewritesrel="canonical"hrefs andog:urlcontent to the locale's own URL when they match the source URL (alternates present). A canonical deliberately pointing elsewhere is left untouched; source-locale pass and re-runs are no-ops (idempotent).
Changed
''= untranslated, now everywhere (verbalycore — behavior change, call it out): the lookup chain skips empty-string entries and keeps falling back (es: ''→ensource text;''in every locale of the chain → miss: warn + key). Why:extractscaffolds new keys as''andcheckcounts''as missing — the runtime was the one place that treated''as a valid message and rendered a blank hole in the UI. Standard i18n behavior (source text beats invisible content) and the render/runtime FOUC divergence disappears. If you relied on''to intentionally render nothing, use a single space' 'or restructure the key (verbaly-web does exactly this — see Docs impact).has()/inspect()follow the same rule.packages/core/src/types.tsis a text file again (internal, no API change): the type-level message parser used two raw NUL bytes as its escape sentinel, which made git treat the file as binary since the initial commit (no reviewable diffs — how the audit had to find this the hard way). The raw bytes are now the\u0000escape sequence — identical type semantics, verified by typecheck + the full suite.
Notes
- 359 tests (core 146 · compiler 144 · svelte 22 · vue 12 · react 11 · unplugin 9 · vite 15) — was 353; +3 core (
''fallback ×2, devtools loop regression), +3 compiler (nested'', canonical/og:url rewrite ×2). - Bench re-run (ritual): lookup 31.2×, interpolation 10.6×, plural 4.3×, currency 4.5× vs i18next 26 — in family with 0.14.0 (27.9×/11.0×/5.0×/5.1×; machine variance). The
''check (if (msg)vs!== undefined) costs nothing on the hot path. - Bundle check: tree-shaken
createVerbalyruntime 3.28 KB min+gzip (flat), full core surface 4.61 KB (was 4.63),verbaly/devtools1.62 KB (was 1.58 — the observer guard). - publint All good ×7 + arethetypeswrong core/react/vue node16 CJS/ESM 🟢 (known-OK:
verbaly/devtoolsnode10 view, predates subpath exports). Tarballs verified (core shipsdist/devtools.*;@verbaly/viteworkspace:*→0.14.5, peerverbaly→^0.14.5). - API surface: no additions, no removals.
RenderHtmlOptions.catalogstype widened (accepts what already worked at runtime). No new dependencies.