One catalog core, not ten formats
Keep source text, context, plurals, notes, source origins, and obsolete entries in a single model your application code can reason about.
Part of the Ferro family · forged in Rust
Ferrocat is a Rust-native catalog engine that parses and merges translation catalogs several times faster than the Node tooling most JS and TS teams run today, then treats that copy as product data you can review, audit, and compile for production. Catalog problems stay in CI, where they belong.
Hand-tuned SIMD and zero-copy scanning under the hood. The kind of parser you don’t write in an afternoon.
cargo add ferrocatFerrocat is one of six focused tools from the same workshop. Shared engineering, shared release discipline, each one replacing a slower or heavier dependency in the JavaScript and Rust toolchain.
Most projects treat translations as files to load, not data to review. Ferrocat moves the catalog into the same discipline as your source: explicit identity, real diffs, checks before release.
V8 is not a slow target. Node’s JIT is one of the fastest dynamic runtimes ever shipped, which is exactly why most JS and TS i18n tooling feels fine until you put it next to compiled Rust. On the same 10k-message catalog, reading the same files, Ferrocat still parses several times faster than the quickest Node parser—and the PHP and Python stacks, with no JIT that helps here, fall much further back.
None of this comes free with picking Rust. The hot path is written by hand: memchr scanning, NEON SIMD on Apple Silicon, borrowed parsing that never copies the source, and a merge that moves data instead of cloning it. Months of low-level work you inherit the moment you add the crate.
Parsing is mostly raw scanning, and a warm JIT is genuinely good at raw scanning, so the parse gap is the narrowest one on this page. The honest part is admitting that. Updating is the real release-time job: parse the existing catalog, parse the freshly extracted strings, merge by identity, and write it back. Once allocation and serialization dominate, the JIT’s edge fades and the zero-copy, move-not-clone hot path pulls further ahead—which is why the update lead is wider than the parse lead. The GNU msgmerge bar is not a launch-cost artifact either: the benchmark records an empty-run baseline, and its fixed process and I/O overhead is about 2% of the measured time on this corpus, so the gap is real work. The Node baseline, pofile-ts, is our own performance fork of the popular pofile—so the fastest JS parser here is one we built, and Rust still leads it ~3x; the unforked original sits about 220x back. The parse chart uses borrowed, zero-copy parsing; reading into a fully owned model still reaches 362 MiB/s. Serialization runs at about 1.16 GiB/s on the same corpus. Median of 10 runs on an Apple M1 Ultra, every tool reading the same files (pofile-ts 4.0.3, gettext-parser 9.0.2, polib 1.2.0, gettext/gettext 5.7.3, GNU gettext 1.0). Methodology and full report.
A parser is only the start. The harder work is what happens around it: handoffs, coverage thresholds, runtime provenance, pseudo-locales, and checks your release process can trust.
Keep source text, context, plurals, notes, source origins, and obsolete entries in a single model your application code can reason about.
Merge freshly extracted messages into existing catalogs by exact identity. No fuzzy matching, no hidden ID changes, no silent conflict resolution.
Audit for missing locales, empty translations, stale targets, ICU errors, metadata conflicts, and obsolete entries. Coverage reports make the gap visible before release day.
Compare catalog states before a translator handoff. New strings, removed strings, changed translations, and which machine translations a human has edited since: all in one report.
Analyze placeholders, formatters, plurals, selects, and tags. Runtime-specific formatter support stays explicit, so unsupported message shapes fail before they ship.
Compile locale-resolved payloads with stable keys, explicit fallback, missing-message records, and provenance rows for host tools that need to show where a string came from.
Pseudolocalize final ICU messages and compiled artifacts while preserving placeholders, plural selectors, formatter syntax, and rich-text tags.
Tag any machine-written value (AI model, TMS, or a script) with an integrity lock plus optional model and confidence. Ship it as-is by default; when a human corrects one, the lock stops matching, so your next re-translation run won't silently overwrite their fix.
Each job is a Rust API you can call on its own or chain into a release pipeline. Start small, then add the checks that match your risk.
Read PO or FCL into one catalog model. Borrowed parsing keeps the hot path tight on large files.
Merge new messages and combine catalogs, preserving existing translations before anything else.
Summarize coverage and catalog-state changes before translator handoff or CI thresholds.
Run release checks across source and target locales with diagnostics CI can read.
Emit host-neutral runtime artifacts, provenance reports, and pseudo-locale variants.
Pick the storage and message model per project. Migrations stay visible in code instead of hiding in tooling.
The catalog shape translation tools already understand, with comments, references, and plural forms preserved.
Keep translator-facing PO files while authoring placeholders, formatting, plurals, selects, and structural diagnostics.
Ordinary git merges stop losing untouched translations: one canonical, sorted entry per line means only real edits collide. It also parses ~45% faster and stores ~12% smaller than the same catalog as PO.
Palamedes is the i18n framework for application teams: macros, message extraction, and adapters for Vite and Next.js. Ferrocat is the catalog engine beneath it, so JS and TS teams get Rust-speed parsing and QA without writing Rust.
Macros, message extraction, framework adapters, and runtime loading for application developers.
Explore PalamedesParsing, deterministic updates, review reports, release QA, runtime artifacts, and pseudo-locale output. Usable directly from Rust or through the ferrocat-cli audit gate.
How they fit togetherFerrocat's behavior is pinned by conformance fixtures derived from upstream gettext, crate-level coverage gates, and benchmark regression checks that run on pull requests.
Maintained by Sebastian Software
Ferrocat and the Ferro family are built and maintained by Sebastian Software. We ship dependable open source for the JavaScript, TypeScript, and Rust ecosystems, and we use every one of these tools in production ourselves.
Start with one catalog and a single audit call. Add coverage, review reports, runtime artifacts, pseudo-locales, and AI metadata when the workflow needs them.