@intlify/shared review
@intlify/shared 11.4.10 is the utility layer used inside Vue I18n and other Intlify packages. Its root export includes value guards, simple `{token}` substitution, display conversion, source-code frames, cache-key generation, HTML escaping, translation-markup sanitization, an object copier, and a synchronous typed emitter. Version 11.4.9 changed `deepCopy()` so arrays are copied recursively instead of retaining references to the source; 11.4.10 republishes the package with the Vue I18n release that fixes devtools group IDs for AST keys. This is published internal infrastructure with almost no package-level API documentation, not a general localization API.
Our @intlify/shared 11.4.8 install took 1.3 seconds, used 1 MB, and returned 0 audit findings; current 11.4.10 remains a small fit for code that must match Vue I18n internals. Most applications should leave it transitive because Node 22, sparse direct-use docs, and monorepo-coupled releases outweigh the convenience of its mixed utility bag.
We installed it
| Install | ✓ · 1.3s | 1 package on disk · 1 MB |
| Import | ✓ | ESM import works · require() works · CommonJS package with exports map |
| Browser | 2.4 KB | gzipped (4.8 KB minified), bundled with esbuild |
| Types | ✓ | TypeScript types bundled |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does @intlify/shared install cleanly?
Yes. In a fresh container with an empty cache, npm install @intlify/shared finished in 1 seconds, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.
How much does @intlify/shared add to a browser bundle?
2.4 KB gzipped (4.8 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.
Does @intlify/shared work with both ESM and CommonJS?
Yes. Both import '@intlify/shared' and require('@intlify/shared') worked in Node 22 in our run. The package is published as CommonJS with an exports map.
Does @intlify/shared include TypeScript types?
Yes, type declarations ship inside the package, so no @types install is needed.
@intlify/shared or @vue/shared: which should you use?
@vue/shared: Use it when Vue-internal utility parity matters and the needed helper comes from the source project Intlify credits. Our @intlify/shared 11.4.8 install took 1.3 seconds, used 1 MB, and returned 0 audit findings; current 11.4.10 remains a small fit for code that must match Vue I18n internals.
When should you not use @intlify/shared?
Application code only needs ordinary type guards or object helpers. @vue/shared or a focused package has a clearer audience than Intlify's internal support module.
Use it if
- An Intlify extension must behave exactly like the Vue I18n 11 implementation it sits beside.
- A debugging tool needs the same code-frame, display-string, or devtools group-ID helpers as the monorepo.
- Translation processing depends on Intlify's specific cache-key or markup-sanitization behavior.
- You have read the 11.4.10 declarations and can keep this direct dependency aligned with other `@intlify` packages.
- Application code only needs ordinary type guards or object helpers. `@vue/shared` or a focused package has a clearer audience than Intlify's internal support module.
- The runtime is below Node 22. Both 11.4.8 from our install and current 11.4.10 declare Node 22 or newer.
- You need a full HTML sanitizer. `sanitizeTranslatedHtml()` rewrites attribute hazards but does not parse and remove arbitrary elements such as script tags.
- You expect ICU messages, plurals, or locale rules from `format()`. It only substitutes alphanumeric placeholders like `{name}` and fills a missing key with an empty string.
- Independent versioning matters. `@intlify/shared` ships on the Vue I18n release train, so an unrelated core fix can publish a new shared package version.
- Asynchronous event delivery or listener isolation is required. `createEmitter()` calls handlers in the same stack and lets a thrown handler stop the emit call.
Setup reality
We installed @intlify/shared 11.4.8 in a fresh Node 22 Bookworm sandbox in 1.3 seconds. It left one package and 1 MB on disk, while the package itself was 116 KB unpacked. npm audit found 0 known vulnerabilities. The measured version has 0 direct and 0 peer dependencies, bundled TypeScript declarations, and an MIT license. Its CommonJS package has an exports map; both require() and ESM import worked.
The registry now serves 11.4.10, released on August 25, 2026. Current metadata still requires Node 22 or newer and has no dependencies. The exports map selects ESM, CommonJS, browser, production, and development builds from the package root. Import from @intlify/shared and let the runtime choose; the exposed dist/* path exists for tooling, but pinning an application to a generated filename couples it to packaging details. No credentials, config, or compilation step is needed.
The public surface is broader than the README, which only calls the module Intlify's shared utility package and credits code forked from Vue and mitt. Read the declarations before direct use. createEmitter() is synchronous and has no once() helper. format() is token replacement, friendlyJSONstringify() escapes three characters after JSON serialization, and toDisplayString() can throw on circular arrays or plain objects because it calls JSON.stringify().
Version 11.4.9 fixed deepCopy() so nested arrays receive new arrays rather than sharing the source reference; it still mutates an existing destination and skips __proto__. sanitizeTranslatedHtml() handles quoted and unquoted attributes, event-handler names, JavaScript URLs, and style url() values, yet it remains string rewriting rather than an HTML parser. Our browser build measured 4.8 KB minified and 2.4 KB gzipped for an import of the package, small enough for Intlify internals but unnecessary when an app needs only one familiar guard.
Patterns
Replace named message tokens format-named-token
import { format } from '@intlify/shared'
const text = format('Hello {name}, {count} items remain', {
name: 'Ada',
count: 3
})`format()` recognizes alphanumeric names only. Missing keys turn into empty strings, and no locale grammar or plural selection runs.
Replace numeric message tokens format-positional-token
import { format } from '@intlify/shared'
const text = format('{0} of {1}', 3, 10)Numeric placeholders index the remaining arguments. Use Vue I18n itself when the sentence needs locale-aware choices.
Match Intlify's format cache identity make-format-cache-key
import { generateFormatCacheKey } from '@intlify/shared'
const key = generateFormatCacheKey(
'en-US',
'invoice.total',
'{amount, number, currency}'
)The output is serialized from fixed locale, key, and source properties. It is not designed as a security token or hash.
Escape Intlify's three JSON trouble characters serialize-friendly-json
import { friendlyJSONstringify } from '@intlify/shared'
const json = friendlyJSONstringify({ text: "it's line
two" })The helper escapes U+2028, U+2029, and apostrophes after `JSON.stringify()`. It does not make arbitrary JSON safe for every HTML context.
Use the package's runtime guards narrow-value-types
import { isArray, isDate, isPlainObject, isPromise } from '@intlify/shared'
if (isDate(value)) console.log(value.toISOString())
if (isArray(value)) console.log(value.length)
if (isPlainObject(value)) console.log(Object.keys(value))
if (isPromise(value)) await value`isPromise()` accepts any object with callable `then` and `catch` properties; it does not require a native Promise instance.
Render a value for debug output display-debug-value
import { toDisplayString } from '@intlify/shared'
console.log(toDisplayString(null))
console.log(toDisplayString({ count: 2 }))
console.log(toDisplayString(['en', 'fr']))Arrays and ordinary objects use two-space JSON. Circular structures throw from `JSON.stringify()`.
Point to a source-string error build-code-frame
import { generateCodeFrame } from '@intlify/shared'
const source = 'first line\nhello {name\nlast line'
const start = source.indexOf('{name')
console.error(generateCodeFrame(source, start, start + 5))Offsets are JavaScript string positions. The frame includes up to 2 surrounding lines on either side.
Send a typed synchronous event emit-typed-event
import { createEmitter } from '@intlify/shared'
type Events = { saved: { id: string }; failed: Error }
const emitter = createEmitter<Events>()
const onSaved = (value?: Events['saved']) => console.log(value?.id)
emitter.on('saved', onSaved)
emitter.emit('saved', { id: '42' })
emitter.off('saved', onSaved)Handlers run immediately. Keep the same function reference for `off()`, and expect thrown listener errors to escape `emit()`.
Observe every emitter event listen-all-events
const logEvent = (type, payload) => console.log(type, payload)
emitter.on('*', logEvent)
emitter.emit('saved', { id: '42' })
emitter.off('*', logEvent)Wildcard listeners run after listeners for the named event and receive the event name before the payload.
Escape a value used as HTML text escape-html-text
import { escapeHtml } from '@intlify/shared'
const safe = escapeHtml(userText)
container.innerHTML = `<p>${safe}</p>`The helper also escapes slash and equals. Assigning `textContent` is simpler when markup is not required.
Neutralize dangerous translation attributes sanitize-translation-markup
import { sanitizeTranslatedHtml } from '@intlify/shared'
const html = sanitizeTranslatedHtml(
'<a href="javascript:alert(1)" onclick="steal()">Help</a>'
)The function rewrites risky attributes and URLs. It does not remove arbitrary elements, so it cannot replace an HTML parser-based sanitizer for untrusted markup.
Copy messages into an existing object copy-message-tree
import { deepCopy } from '@intlify/shared'
const target = { nav: { home: 'Home' } }
deepCopy({ nav: { account: 'Account' }, tags: ['new'] }, target)`deepCopy()` mutates the destination and skips `__proto__`. Since 11.4.9, nested arrays receive new arrays instead of retaining source references.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| @vue/shared | npm | Use it when Vue-internal utility parity matters and the needed helper comes from the source project Intlify credits. |
| lodash-es | npm | Use it for documented collection and object utilities that are maintained for direct application use. |
| mitt | npm | Use it when the only requirement is the tiny emitter model on which Intlify's emitter is based. |
More utils guides
lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

