# What changed in @inlang/plugin-message-format

> 30 changes in @inlang/plugin-message-format 4 from its official release notes, upgrade guides and advisories: 4 breaking, 5 new APIs and options. Each one cited. Sources checked 2026-10-25. HTML: https://unstale.sh/npm/@inlang/plugin-message-format/

To see which of these apply to a repository, run `npx @unstale/cli init` in it.

## @inlang/plugin-message-format 4

### Breaking changes

- Complex messages alongside keys that share their prefix are read as written, and keys that are not messages are ignored. Values that are neither strings nor complex messages now fail import with an error naming the key. (4.5.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#450)
- Numeric key segments are written as object keys rather than arrays, and existing arrays with numeric message keys are read back as those messages. An existing array remains until one of its messages is edited. (4.5.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#450)
- Placeholders with functions are written as local declarations, preserving function names and options when messages are exported and imported. Older plugin versions read this syntax as variable names, so update the plugin everywhere project files are read. (4.5.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#450)
- Sorting now applies only to message keys and nested message objects; variants, declarations, and selectors retain their order, preventing catch-all variants from being selected before other variants. (4.5.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#450)

### New APIs and options

- Local formatter declaration options can use `$variable` to reference an input variable instead of treating its name as a literal string; exported declarations round-trip as `key=$variable`. (4.4.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#440)
- Markup option and attribute values now support quoted literals using `|...|`. (4.3.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#430)
- Markup options can reference variables with `key=$variable`, and referenced variables are inferred in declarations. (4.3.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#430)
- Message patterns now support escaping literal braces with \{ and \}, and a literal backslash with \\. (4.2.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#420)
- Adds an optional setting to sort message keys when exporting files in ascending or descending order. (4.1.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#410)

### Performance

- Imports are faster through fewer parsing operations, batched unambiguous fresh imports, preserved variant order, and cached property lookups while retaining conflict handling and partial-import behavior. (4.5.3) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#453)
- Large message-format projects import faster by indexing bundles by id. (4.4.2) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#443), [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#442)

### Behavior and default changes

- Markup option and attribute values now support escaped `|` and `\` characters. (4.3.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#430)

### Tooling

- Publishes TypeScript declarations and explicit type exports for the plugin, making its types available to consumers. (4.4.5) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#445)

### Fixes and other changes

- Every {locale} and legacy {languageTag} placeholder is replaced when resolving resource paths, allowing catalogs with the locale in both a directory and filename to be imported correctly. (4.5.5) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#455)
- Variants whose keys contain dots are read and written with the dot, preventing their text from being lost on the next import. (4.5.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#450)
- Un-annotated local declarations and quoted literal locals now import. Exact-number selectors are exported before their plural so they can win over a category that also selects that number. (4.5.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#450)
- When current files are passed to exportFiles, unchanged messages keep their exact text and file formatting; new messages are inserted after the preceding message, and removed messages are dropped. (4.5.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#450)
- The JSON plugins' helper now re-imports kept files in project load order, including exported files at the positions they replace, preventing stale overlapping messages from overriding edits on the next load. (4.5.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#450)
- A message whose key starts with another message's key is no longer dropped on export; it is written with the rest of its key flat in the deepest object it fits in. (4.5.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#450)
- A plain string stays a plain string when another locale uses a plural or select, and a placeholder declared as a local in another locale no longer adds an input declaration there. (4.5.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#450)
- Variants that can be selected but would lose to an earlier variant are written earlier according to MessageFormat 2 preference and locale plural rules; other variants and unchanged messages keep their order and bytes. (4.5.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#450)
- Fixes the file-schema export to reference published JavaScript and declarations. (4.4.5) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#445)
- Exporting no longer mutates declaration or variant-match order. (4.4.4) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#444)
- Placeholder inputs that follow existing declarations are preserved. (4.4.4) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#444)
- Whitespace around every selector match is trimmed to fix message-format round trips. (4.4.4) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#444)
- Input declarations referenced by local message-format declarations are now inferred. (4.4.1) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#441)
- Declaration options now allow optional whitespace around `=`, so options such as `currency = $priceCurrency` are not dropped. (4.4.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#440)
- Markup attributes now support roundtrip preservation. (4.3.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#430)
- Malformed markup placeholders are now validated. (4.3.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#430)
- Markup options now support roundtrip preservation. (4.3.0) — [release notes](https://github.com/opral/inlang/blob/6cf0158a7d5084933521d36c48c1548b4bea2e13/packages/plugins/inlang-message-format/CHANGELOG.md#430)
