13 — State Management (i18n Module)
- 1. State domain
- 2. Cubit breakdown (console, (planned))
- 3. State flow — catalog delivery (mobile)
- 4. State flow — key editor save (console, (planned))
- 5. Rules
Client state for catalog delivery (mobile) and the (planned) console. Framework conventions per 00-shared/06_State_Management.md.
1. State domain
| State | Lives where | Source |
|---|---|---|
| Locale | server request context (ctx.locale) | tenant-context.service.ts:58-60 |
| Catalog (flat map) | app-side cache (per locale) | getMessages response, i18n.service.ts:47-49 |
| Catalog version/hash (planned) | app cache + response header | — |
| Editor state (keys, dirty, parity) | console Cubits | 06_Screen_Specifications.md |
| Coverage/drift report | console Cubit, fetched on demand | GET /api/v1/i18n/drift (planned) |
2. Cubit breakdown (console, (planned))
| Cubit | State | Events |
|---|---|---|
CatalogCubit | { locale, catalog: Map<String,String>, version, status: loading/ready/error } | fetch(locale), localeChanged, refresh |
KeyListCubit | { keys, filters: {namespace, missingIn: String?, hasParams}, page, hasMore, status } | search(q), toggleFilter(f), loadMore(), bulkDelete(ids) |
KeyEditorCubit | { key, params, values: Map<locale,String>, dirty: Set<locale>, parity: Map<locale,ParityStatus>, version, saving } | load(key), editValue(locale,v), save(), delete(), reload() |
LocaleCubit | { locales: Map<tag,{coverage,direction,status}>, promoting } | load(), add(tag), promote(tag), demote(tag) |
SyncCubit | { report, lastRunAt, exporting } | run(), export() |
Parity computation (pure function, unit-testable):
parity(locale) = diff(valueParams(value), sourceParams(en)) using
/\{(\w+)\}/g (i18n.service.ts:42-44).
3. State flow — catalog delivery (mobile)
flowchart LR
A[App start] --> B[Resolve locale<br/>Accept-Language]
B --> C{Catalog cached?}
C -->|yes| D[Render cached]
C -->|no| E[GET /i18n/messages?locale]
E --> F{200?}
F -->|yes| G[Store map keyed by locale]
F -->|no| H[Retry backoff x3]
H --> I{ok?}
I -->|no| J[Offline state + banner]
G --> D
J --> K[Retry on connectivity]
K --> E
4. State flow — key editor save (console, (planned))
flowchart LR
A[editValue] --> B[Mark dirty]
B --> C[Debounce 300ms parity check]
C --> D{Parity ok?}
D -->|no| E[Amber warn / red block]
D -->|yes| F[Enable Save]
F --> G[PUT /i18n/keys/:key]
G --> H{201?}
H -->|yes| I[Clear dirty + snackbar]
H -->|409| J[Conflict dialog<br/>reload/overwrite]
H -->|network| K[Banner + keep draft]
5. Rules
- Catalog map is immutable after fetch; updates replace the whole map (locale keyed) — no partial mutation.
- Editor keeps in-memory drafts; leaving with
dirtynon-empty triggers the unsaved-changes guard (10 §3). - One locale per catalog fetch; locale switch swaps the map, never merges.
- Console state is local-only today (no server push); WebSocket refresh of coverage (forward-looking).