Skip to content

ADR 0006: Separate the PO Core from the High-Level Catalog API

  • Status: Accepted
  • Date: 2026-03-16

Context

ferrocat started as a fast PO parser and serializer with an explicit focus on low-level performance.

That core is still important:

  • it maps closely to actual PO file structure
  • it enables owned and borrowed parsing modes
  • it serves benchmark-heavy and tooling-oriented workflows

At the same time, product-facing workflows need a different abstraction level.

Typical tasks such as:

  • updating a catalog from extracted messages
  • parsing a catalog into a structured application model
  • reading and writing catalog files as one operation

are not best expressed in terms of raw PO items, msgstr[n], or file-shaped mutation.

These workflows also need a stable surface for future Node/N-API usage, where exposing low-level PO-core structures directly would leak format-centric details and internal ownership choices.

The project now has both layers:

  • the PO core (parse_po, parse_po_borrowed, stringify_po, low-level merge helpers)
  • the high-level catalog API (parse_catalog, update_catalog, update_catalog_file)

Decision

Keep the PO core and the high-level catalog API as distinct layers with different responsibilities.

The PO core is:

  • format-oriented
  • performance-oriented
  • suitable for low-level tooling and internal building blocks

The high-level catalog API is:

  • task-oriented
  • owned and N-API-friendly
  • centered around canonical catalog semantics rather than raw PO structure

The high-level API may use the PO core internally, but it should not be shaped by PO-core implementation details.

Concretely:

  • low-level PO parsing and serialization remain public and supported
  • high-level catalog operations remain the preferred product-facing API
  • borrowed lifetimes and PO-core item details should not leak into the first high-level API surface
  • export format is a configuration choice of the high-level API, not its semantic center

Consequences

Positive:

  • low-level and high-level users both get APIs that fit their actual tasks
  • Node/N-API integration has a cleaner public boundary
  • the PO core can stay aggressively optimized without dictating product-facing ergonomics
  • the catalog layer can evolve toward ICU-oriented semantics without destabilizing the low-level core

Negative:

  • there are now two API layers to document and maintain
  • some translation logic exists above the PO core rather than directly inside it
  • contributors need to be clear about which layer a new feature belongs to