Persist Flat, Render as Tree

Persist Flat, Render as Tree

Store hierarchical data flat and reconstruct the hierarchy at render time, rather than persisting a nested structure. The localization-helper keeps keys as flat, dot-namespaced strings in JSON and only builds a tree when drawing the UI:

{ "en-US": { "general.action.delete": "Delete" } }   // persisted: flat
general → action → delete   // rendered: tree, built lazily

(treeBuilder.ts:18-66 — split on ., group, sort each level; stateless and deterministic)

Why decouple the format from the shape:

  • The persistent file stays diff-friendly, greppable, and order-independent — "general.action.delete" is one searchable line, not a path through nested braces.
  • The UI hierarchy can be reorganized (regroup, collapse, re-sort) without ever migrating the stored data, because the tree is derived, not stored.
  • Reconstruction is a pure function of the flat keys, so two different views (tree, table, locale-columns) can project the same data differently — exactly the row-shape projection in Grid Columns Are Row-Object Keys Projected into Augmentable Descriptors, and the pure-projection principle of Stateless Editor Panel as Pure Projection.

The general rule: the storage format should optimize for durability and tooling (flat, flat-diffable, stable); the in-memory shape should optimize for the view. When the hierarchy is implicit in a delimiter, you get both for free.