# Data shapes

The on-disk format. You only need this to edit the dataset or to build a new
language binding — consumers get resolved objects from their binding's own API.

## Data shapes

### `data/allergens.json`

```json
{ "key": "WHEAT", "group": "CEREALS", "isMember": true, "icon": "cereals" }
```

### `data/translations/allergens/de.json`

```json
{
  "WHEAT": {
    "name": "Weizen",
    "declaration": "Enthält Getreide und glutenhaltige Erzeugnisse",
    "description": "Weizen und Weizenprodukte"
  }
}
```

### `data/declarations.json`

```json
{ "key": "NITRITE_CURING_SALT", "category": "ADDITIVE" }
```

### `data/translations/declarations/de.json`

```json
{
  "NITRITE_CURING_SALT": {
    "name": "mit Nitritpökelsalz",
    "description": "Enthält Nitritpökelsalz"
  }
}
```

---

## Layout

Structural truth at the top, labels underneath — a language never touches structural data, and structural data never carries a language.

```
data/
│  ── sources, hand-maintained ──────────────────────────────────
├── allergens.json               28 keys: key, group, isMember, icon
├── declarations.json            22 keys: key, category, icon
├── codes.json                   Menuella Codes: { "WHEAT": "A6", … }
├── translations/
│   ├── allergens/<lang>.json    { "WHEAT": { name, declaration, description }, … }
│   └── declarations/<lang>.json { "COLORING": { name, description }, … }
│
│  ── generated by `npm run generate` ───────────────────────────
└── bundles/<lang>.json          sources above, pre-joined and ready to render

icons/<group>.svg                15 solid 24×24 glyphs, currentColor
index.js  index.d.ts             key constants, type guards, and every type
```

**Why `bundles/` as well as `translations/`?** They are the same labels at two
altitudes. `translations/` is what a *translator* edits — one small file per
language, no structure in sight. `bundles/` is what an *app* renders — structure,
label and icon already joined, so a client needs no lookup table of its own. The
duplication is deliberate and costs about 70 kB; `npm run verify` fails if the
two ever disagree.

Three axes, kept apart on purpose: **structure** (no language, no numbering), **language** (`translations/`), and **numbering** (`codes.json`).

**Why split?** Adding a language adds *one file per module* and can't clobber another translation. Every translation file is an **object keyed by the structural key**, so a lookup is `labels[key]` — O(1), no join step, no scanning an array.

---
