AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
Rust 기반 카탈로그 엔진으로 번역을 파싱·업데이트·검토·감사·컴파일, 누락·오류·노후를 CI 진단으로 전환
Parse, update, review, audit, and compile translations with a Rust-native catalog engine. Missing strings, ICU mistakes, stale copy, and weak coverage can become CI diagnostics before they reach produ
개발 도구Rust · JavaScriptGitHub @sebastian-software온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
Rust-native translation catalog engine for Gettext PO, ICU MessageFormat, and FCL catalogs.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Part of Ferramenta, a family of Rust tools.
Rust-native translation catalog engine for Gettext PO, ICU MessageFormat, and FCL catalogs.
Documentation: ferrocat.dev — guides, API overview, benchmarks, and architecture decisions.
ferrocat is a Rust-native translation catalog engine. It treats localized copy as product data: parse it, update it, review it, measure it, audit it, and compile it into runtime payloads your application can ship with confidence.README 전문 보기 ↗Part of Ferramenta, a family of Rust tools.
Rust-native translation catalog engine for Gettext PO, ICU MessageFormat, and FCL catalogs.
Documentation: ferrocat.dev — guides, API overview, benchmarks, and architecture decisions.
ferrocat is a Rust-native translation catalog engine. It treats localized copy as product data: parse it, update it, review it, measure it, audit it, and compile it into runtime payloads your application can ship with confidence.
The practical problem is simple: translations change constantly, and most projects need more than "load a JSON file at runtime." Teams need source identity, translator context, reviewable diffs, coverage numbers, release checks, fallback behavior, and a runtime shape that does not hide catalog problems until production. Ferrocat is built for that middle layer.
You do not need to know PO files, ICU MessageFormat, or FCL to get started. What matters is that the catalog stays inspectable, testable, benchmarked, and portable across host-language adapters, instead of disappearing into format-specific tooling.
pofile-ts is Ferrocat's TypeScript predecessor. It is retained as an archived reference and benchmark baseline; further development is focused on Ferrocat.
cargo add ferrocat
The public Rust entry point is the ferrocat crate. It re-exports the stable Rust surface from the lower-level workspace crates:
ferrocat: umbrella crate and recommended dependency for application codeferrocat-po: PO parsing, serialization, low-level merge helpers, and feature-gated higher-level catalog workflowsferrocat-icu: ICU MessageFormat parsing, structural helpers, source/translation compatibility diagnostics, and semantic message metadata helpersFor non-Rust CI release gates, install the CLI package and run ferrocat audit:
cargo install ferrocat-cli
ferrocat audit --source-locale en --source locales/en.po --target de=locales/de.po
The ferrocat-cli GitHub release also publishes a prebuilt Linux musl archive for x86_64-unknown-linux-musl. The archive is named ferrocat-<version>-x86_64-unknown-linux-musl.tar.gz and contains the ferrocat binary plus license and README metadata.
use ferrocat::{SerializeOptions, parse_po, stringify_po};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut file = parse_po(
r#"
msgid "hello"
msgstr "world"
"#,
)?;
file.items[0].msgstr = "Welt".to_owned().into();
let rendered = stringify_po(&file, &SerializeOptions::default());
assert!(rendered.contains(r#"msgstr "Welt""#));
Ok(())
}
For the common "merge fresh extracted messages into an existing catalog" workflow, merge_catalog is the lean Gettext-style entry point. For N-way catalog overlays and msgcat-style set operations, use combine_catalogs; when catalogs already live on disk, combine_catalog_files adds format inference and atomic output replacement around the same semantics. For version-control workflows, merge_catalogs_three_way accepts explicit ancestor, ours, and theirs roles and preserves deletions instead of treating the ancestor as another overlay. Use convert_catalog or convert_catalog_file for explicit ICU-native PO ↔ FCL conversion without treating conversion as a one-input combine. For release checks across a source catalog and target catalogs, use audit_catalogs. For dashboards or translator handoffs, use measure_catalog_coverage and review_catalogs. For application delivery, compile requested-locale artifacts with fallback and ICU diagnostics; use compile_catalog_artifact_report when host tooling also needs per-message resolution provenance without changing the runtime artifact shape.
Coverage, audit, and review inputs should be parsed with
parse_catalog_for_review. It returns a normalized catalog that retains only
semantic fuzzy identities, so active #, fuzzy PO and f=fuzzy FCL entries do
not count as translated. The ordinary parse_catalog path continues to skip
opaque flags and translator comments for high-throughput consumers that do not
request report state.
Beyond the basics, Ferrocat exposes byte-oriented and allocation-light borrowed parsers for hot paths, ICU analysis and source/translation compatibility checks (analyze_icu, compare_icu_messages, validate_icu_formatter_support), policy-aware apostrophe canonicalization and compiled-key derivation, ICU-aware pseudolocalization, semantic metadata normalization around msgid + msgctxt, and AI-translation metadata that high-level writers clear automatically once a human edits the text. ICU scope is MessageFormat v1; MessageFormat 2 is tracked as a future standard but is not a near-term target.
src/App.tsx#CheckoutButton or src/i18n.ts#formatInvoiceStatus, plural forms, and obsolete entries in a model that application code can reason about.Intl.Collator("en-US") across PO, FCL, update, and combine output. PO can group by source origin while retaining the same identity tie-break; FCL always keeps its own collated line-order invariant.Ferrocat is part of the Palamedes ecosystem. Palamedes is the OSS i18n framework for JavaScript and TypeScript apps; Ferrocat supplies the shared catalog engine underneath it. JavaScript and TypeScript access is a Palamedes concern, including the palamedes-node N-API bridge in that repository; this repository stays the pure-Rust catalog engine.
Ferrocat is a new catalog layer, but it is not invented in a vacuum. It keeps the useful parts of established translation workflows and makes them available through a Rust API:
Ferrocat is not trying to replace every part of an i18n stack. If you already know the existing landscape, this is the gap it fills:
| Common approach | What works well | Where Ferrocat helps |
|---|---|---|
| GNU gettext-style tooling | Mature PO conventions, translator metadata, broad ecosystem familiarity | Rust-native APIs, explicit conflict policy, structured diagnostics, ICU-native workflows, and app-ready runtime artifacts |
| Framework-specific i18n packages | Great authoring ergonomics and runtime adapters inside one host ecosystem | Shared catalog semantics that can be reused by Palamedes or other adapters instead of reimplemented per framework |
| Custom JSON catalogs | Easy loading and deployment | Stronger update semantics, reviewable FCL storage, source/translation QA, and a path back to translator-friendly PO workflows |
| ICU-only message handling | Powerful plural, select, formatter, and rich-text syntax | Structural analysis and compatibility checks that catch missing arguments, formatter drift, tag mismatch, and branch changes before shipping |
Ferrocat does not currently ship first-party WebAssembly, N-API, Python, Go, or other host-language bindings from this repository. Host integration is layered on top of the Rust API: JS/TS applications should look to Palamedes and its palamedes-node bridge, while other ecosystems can use the Rust crates directly, the ferrocat CLI audit gate, or host-specific bindings maintained at that layer.
Ferrocat's benchmark suite compares file-to-file catalog workloads against common PO libraries and tools on the same fixtures. The published table below uses the 10k-message gettext catalog from the checked-in benchmark reports (Apple M1 Ultra, median throughput):
| Workload | Ferrocat | pofile-ts (Node) | gettext/gettext (PHP) | Babel (Python) | polib (Python) | GNU msgmerge |
|---|---|---|---|---|---|---|
| Parse | 725 MiB/s | 149 | 53 | - | 22 | - |
| Update with new strings | 291 MiB/s | 43 | 16 | - | 8.1 | 4.8 |
| Full catalog update | 150 MiB/s | 42 | - | 8.9 | 8.2 | 4.8 |
The Node baseline is pofile-ts, a speed-focused fork of the widely used pofile, so the JavaScript comparison targets a fast implementation rather than an easy one. The update benchmark parses existing and freshly extracted files, merges by exact identity, and serializes the result, which is where Ferrocat's byte-oriented scanning and move-not-clone catalog paths matter most.
The full catalog update row is Ferrocat's high-level update_catalog on the same files: on top of the plain update it analyzes ICU message structure, tracks placeholders, and produces deterministic output. The comparison now includes Babel's real Catalog.update path for Python; even with that extra work, Ferrocat's full update runs about 3.4x ahead of the fastest non-Ferrocat workflow update and roughly 31x ahead of GNU msgmerge.
See the benchmark methodology and the checked-in reports under benchmark/results/ for host details, fixture definitions, noise handling, and the full matrix.
At the high-level catalog layer, ferrocat supports three explicit combinations of storage format and message semantics. You do not need to choose every mode on day one; the point is that migrations stay visible in code.
| Mode | Storage format | Message model | Use when you want to... |
|---|---|---|---|
| Classic Gettext catalog mode | Gettext PO | Gettext-compatible plurals | stay close to traditional gettext catalogs and msgid_plural / msgstr[n] workflows |
| ICU-native Gettext PO mode | Gettext PO | ICU MessageFormat | keep Gettext PO files and tooling, but author richer ICU plural/select/formatting messages |
| ICU-native FCL catalog mode | FCL catalog storage | ICU MessageFormat | move to one-entry-per-line, tab-separated records that are easier to diff, merge, batch, and hand to external systems |
There is intentionally no FCL + gettext-plural mode; gettext plural behavior stays a PO concern, while FCL is the ICU-native machine storage format for ICU-native catalogs. Generate FCL through the catalog layer by choosing CatalogMode::IcuFcl in parse_catalog, update_catalog, conversion, or file-based update flows; keep PO when external translator tools need gettext compatibility. The in-repo FCL format specification documents the exact line format, escaping rules, and architecture decisions behind that storage mode.
The published crates default to the full current API surface. Use
default-features = false when you want the low-level PO and ICU parsers without
the catalog workflow layer.
catalog enables high-level catalog parsing, updates, combining, conversion,
audits, machine-translation metadata, plural handling, FCL storage, and
runtime artifact compilation.serde enables serialization support for tooling, cache, schema, report, and
runtime artifact shapes.compile, mt, and plurals are reserved subsystem aliases that currently
imply catalog; they do not reduce or split the catalog API surface yet.See the API overview for the crate-by-crate feature profile details.
1.94.0x86_64-unknown-linux-musl is validated in CI and published as a smoke-tested GitHub Release archive for ferrocat-cli#[non_exhaustive] additions); every break is listed in the changelog with migration notesmessage() plus optional position() metadata with zero-based byte offset and one-based line/column when source context is availableIf you already know what kind of question you have, these are the fastest entry points:
ferrocat changelogFerramenta — A family of Rust tools.
The content pipeline
| Tool | Job |
|---|---|
| ferroni | Oniguruma-compatible regex engine |
| ferriki | Shiki-compatible syntax highlighting |
| ferromark | Markdown to HTML with a secure default and every GFM extension included. |
The language workshop
| Tool | Job |
|---|---|
| ferrolex | Spell checking for text and code |
| palamedes | Internationalization for TypeScript applications |
On the workbench
| Tool | Job |
|---|---|
| ferrovia | SVGO-compatible SVG optimizer |
| ferralk | Glob matching and parallel filesystem walking |
| ferrugo | PDF previews for untrusted files |