Back to blog
2026-03-23 Thijs Creemers

Release: v1.0.1-alpha-6

We just tagged v1.0.1-alpha-6. Here is a summary of what changed.

New i18n Library

The biggest addition in this release is boundary-i18n, a new internationalisation library following ADR-013. It brings first-class multi-language support to Boundary apps without changing any handler or service signatures.

How it works

Translation keys are expressed as [:t :key] markers inside Hiccup trees. A postwalk in boundary.i18n.shell.render resolves them to strings before HTML is emitted. The translation function is injected into the Ring request map by wrap-i18n middleware, so UI functions stay pure.

;; Simple lookup
[:t :user/sign-in]

;; With interpolation
[:t :user/greeting {:name "Alice"}]

;; With plural count
[:t :user/items {:n 3} 3]

Locale chain

wrap-i18n builds a locale chain from: user locale → tenant locale → default locale → :en fallback. Missing keys gracefully degrade to (str key) — they never throw.

Catalogues

Translations live in EDN files, one per locale, on the classpath:

boundary/i18n/translations/en.edn
boundary/i18n/translations/nl.edn

Keys are qualified keywords grouped by module (:user/*, :common/*, :admin/*, etc.).

Integrant wiring

:boundary/i18n {:catalogue-path "boundary/i18n/translations"
                :default-locale :en
                :dev?           true}

Set :dev? true during development to wrap resolved markers in [:span {:data-i18n "…​"}] for browser inspection.

Babashka tooling

# Find a key
bb i18n:find :user/sign-in

# Check for untranslated string literals in core/ui.clj files
bb i18n:scan

# Report missing translations across locales
bb i18n:missing

# Report unused catalogue keys
bb i18n:unused

The bb i18n:scan command is wired into CI and exits non-zero if unexternalised string literals remain in UI files.

User profile i18n

The user profile and preferences UI (boundary.user.core.profile_ui) now uses i18n markers throughout. As a bonus, a new language preference field has been added: users can now set their preferred language (English or Dutch), and the UI renders in the selected locale.

Bug Fixes

Tenant: PostgreSQL JSON settings parsing

Fixed a bug in boundary.tenant.shell.persistence where the :settings JSON column was not correctly deserialised when PostgreSQL returned it as a PGobject. The value is now properly parsed in all three cases: nil, plain String, and PGobject.

Admin: _method not filtered from update payloads

Fixed a bug in the admin HTTP layer where the _method form field (used for method override) was not stripped before passing the body map to the update handler. This caused spurious validation errors on update forms that used PUT via POST override.

Various small fixes

Several small issues surfaced during development of the ecommerce-api example have been resolved, including edge cases in case conversion, middleware ordering, and resource cleanup.

What’s Next

I will keep bug hunting and fix issues while testing.

Feedback and issues welcome on GitHub.