v3.22.0
Nuxt I18n Micro v3.22.0 — Formats, Cache & Translation Memory
Date: 2026-07-30
Version: v3.22.0

We're announcing v3.22.0: Vue I18n-style named number/date formats with a formatter cache, CDN-friendly translation payload caching (content fingerprint + httpCacheDuration), and a Translation Memory API to read and replace the active dictionary at runtime.
What's New?
Named numberFormats / datetimeFormats + formatter cache
Vue I18n-compatible named formats and faster Intl formatting:
- Config:
numberFormats/datetimeFormatsper locale - API:
$tn(1000, 'currency'),$td(date, 'short')(+ locale override and option merges) FormatServicecachesIntl.NumberFormat/DateTimeFormat/RelativeTimeFormatby locale+options
See Methods — $tn / $td and Module options.
dateBuild defaults to a content fingerprint
?v= on /_locales requests used to default to Date.now(), while responses are served immutable for a year. Every rebuild therefore invalidated every client's dictionary, even when no translation had changed.
The default is now a SHA-256 fingerprint of the translation sources, in layer order. Rebuilds with untouched translations keep the same URL. Setting dateBuild explicitly still wins. See Module options — dateBuild.
httpCacheDuration for /_locales payloads
The built-in /{apiBaseUrl}/:page/:locale/data.json route now sends HTTP Cache-Control for browsers and CDN:
- Option:
httpCacheDuration(seconds, default31536000/ 1 year) - Header:
Cache-Control: public, max-age=…, immutable - Safe with existing
dateBuildcache-busting (?v=...);0disables the header; not applied in development
Analog of @nuxtjs/i18n v10.2.0 experimental.httpCacheDuration, as an explicit response header.
Compressed public payloads
nitro.compressPublicAssets now reaches the translation payloads copied into the public directory (.gz + .br). Nitro compresses public assets before the copy happens, so previously the payloads were the one uncompressed part of a static build — 6.65 MB raw versus 1.01 MB gzip on the playground index. The module still never enables compression on its own. See Performance.
resolveTranslations() and setTranslation(key, value)
Runtime helpers to read and replace the active translation dictionary in memory:
resolveTranslations()returns the full tree that$t()reads from for the active locale and route — useful for DevTools, tests, and runtime editors. When a second layer is live (fallback locale or Nuxt page-transition hot-reload), the dump keeps nested shape viamergeTranslationLayersand only uses flat dotted keys for scalar-vs-object collisions that a single tree cannot otherwise express.setTranslation(key, value)replaces the value at a key (top-level, dotted path, object, string, or scalar). This is a replace, not a merge; use$mergeTranslationswhen siblings should survive.- Available on
useI18n(),useNuxtApp(), and framework i18n instances inherited from@i18n-micro/core. @i18n-micro/test-utilsadds matchingresolveTranslations/setTranslationhelpers for unit tests.
getAllTranslations() removed from Vue package
Use resolveTranslations() for the active lookup tree. For a full storage dump in Vue, use getStorage() or getRouteCache().
Breaking Changes
Nothing in the public config surface requires app code edits for typical usage. These matter if you reached into runtime internals:
- The SSR payload moved from
useState('i18n-ssr-chunks')tonuxtApp.payload.data['i18n-ssr-chunks']. It still carries full translation chunks for every(locale, route)loaded during SSR — the same dictionaries as before, in a slot Nuxt can externalize to_payload.jsonon prerender.useState('i18n-ssr-chunks')now returns nothing. Reading translations that way was never supported, but it was described in the cache API docs, so it is called out here. NuxtTranslationLoaderOptionsexposessetSsrChunk. The loader writes each merged chunk intopayload.dataon the server as it loads.getSsrChunksis not used.nitro.compressPublicAssetsnow emits.gz/.brnext to the copied payloads. Expect more files in public output if you had it enabled. Deploy tooling that enumerates the translation directory may need to account for them.- Payload URLs change once on upgrade, because
?v=switches from a build timestamp to a content fingerprint. Clients re-download the dictionary on the first request after the upgrade and then keep it across subsequent deploys — which is the point. getAllTranslations()removed from@i18n-micro/vue. UseresolveTranslations()/getStorage()/getRouteCache()instead.
Bug Fixes
<i18n-switcher>— omits locales withdisabled: truefrom the dropdown.$getLocales()still returns the full list for your own code, while built-in SEO/meta output excludes disabled locales.- Switcher styles —
cursor: not-allowedapplies to the current locale viaactiveLinkStyle/customActiveLinkStyle; restoredcustomDisabledLinkStylefor backward compatibility and apply it to the switcher button when the current locale isdisabled: true. - Dev HMR — a write that leaves file content unchanged (editor save-on-blur, formatter rewrite) no longer triggers a re-merge. Root-locale changes rebuild every page for that locale, so this was expensive to spend on a no-op.
- Dev HMR — pages are re-merged concurrently on a root-locale change instead of one after another.
- Page transitions — same-locale navigation keeps the outgoing chunk as a fallthrough layer until
page:transition:finish, instead of an expensive deep merge on every nav.
Why It Matters
- Vue I18n-style formatting without pulling in a heavier stack.
- CDN-friendly translation URLs that stay stable across rebuilds when the dictionary did not change.
- A supported runtime API for inspecting and patching the live dictionary — DevTools, tests, and editors no longer need private helpers.
Full changelog will be published with the release on GitHub.
Fix: infinite redirect loop with app.baseURL + strategy: 'prefix' (#234)
Date: 2026-07-03
Server-side redirect plugin (06.redirect.ts) now strips runtimeConfig.app.baseURL from getRequestURL(event).pathname before locale detection. Fixes ERR_TOO_MANY_REDIRECTS when the app is served under a sub-path (e.g. /examples → /examples/ja once, not /examples/ja/examples/ja/...).