feat(i18n): server-genererad prosa -> nyckel+params (min dag, ombokning, scan-diff)
- Min-dag-noten: noteKey (estimateNote/computedNote) bredvid svensk note; klient t(noteKey).
- Ombokningsskäl (planning.ts): rescheduleReasonKey + params bredvid rescheduleReasonSv;
klient t(key, {title}). Workerns två andra ombokningstexter lämnade på svensk fallback.
- Scan-diff: reasonCode-enum (6 koder) bredvid reasonSv; klient t(scanDiff.reason.<code>).
- 8 nya nycklar i alla 12 språk. Ingen beslutslogik rörd; alla Sv-fält kvar som fallback.
- Kvar som egna spår: recept-säkerhetsmeddelanden + substitutions-data (översättningstabell).
- typecheck grönt (20/20), vakt grön, inventory-engine 53/53 tester.
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,19 @@ export interface NewScanObservation {
|
||||
|
||||
export type ScanDiffRowKind = "new_item" | "moved" | "quantity_changed" | "vanished" | "unchanged";
|
||||
|
||||
/**
|
||||
* Stabil, översättbar kod för varje distinkt motivering. Klienten översätter
|
||||
* via i18n-nyckeln `scanDiff.reason.<code>`; `reason` (svenska) är fallback.
|
||||
* En kod per unikt meddelande – finare än `kind` (t.ex. flyttad vs flyttad+mängd).
|
||||
*/
|
||||
export type ScanDiffReasonCode =
|
||||
| "moved_and_qty"
|
||||
| "moved"
|
||||
| "qty_changed"
|
||||
| "unchanged"
|
||||
| "new_item"
|
||||
| "vanished";
|
||||
|
||||
export interface ScanDiffRow {
|
||||
kind: ScanDiffRowKind;
|
||||
previousItemId?: string;
|
||||
@@ -32,8 +45,10 @@ export interface ScanDiffRow {
|
||||
newLocationId?: string;
|
||||
/** Konfidens för slutsatsen (0–1). */
|
||||
confidence: number;
|
||||
/** Mänsklig läsbar motivering. */
|
||||
/** Mänsklig läsbar motivering (svenska) – fallback när klienten saknar översättning. */
|
||||
reason: string;
|
||||
/** Stabil kod för klientöversättning (`scanDiff.reason.<code>`). */
|
||||
reasonCode: ScanDiffReasonCode;
|
||||
}
|
||||
|
||||
export interface ScanDiffResult {
|
||||
@@ -104,6 +119,7 @@ export function diffScans(
|
||||
newLocationId: obs.storageLocationId,
|
||||
confidence: round2(bestMatch.score * obs.observationConfidence),
|
||||
reason: "Flyttad och ändrad mängd",
|
||||
reasonCode: "moved_and_qty",
|
||||
});
|
||||
} else if (locationChanged) {
|
||||
rows.push({
|
||||
@@ -117,6 +133,7 @@ export function diffScans(
|
||||
newLocationId: obs.storageLocationId,
|
||||
confidence: round2(bestMatch.score * obs.observationConfidence),
|
||||
reason: "Flyttad till annan plats",
|
||||
reasonCode: "moved",
|
||||
});
|
||||
} else if (quantityChanged) {
|
||||
rows.push({
|
||||
@@ -130,6 +147,7 @@ export function diffScans(
|
||||
newLocationId: obs.storageLocationId,
|
||||
confidence: round2(bestMatch.score * obs.observationConfidence),
|
||||
reason: "Ändrad mängd",
|
||||
reasonCode: "qty_changed",
|
||||
});
|
||||
} else {
|
||||
rows.push({
|
||||
@@ -143,6 +161,7 @@ export function diffScans(
|
||||
newLocationId: obs.storageLocationId,
|
||||
confidence: round2(bestMatch.score * obs.observationConfidence),
|
||||
reason: "Oförändrad",
|
||||
reasonCode: "unchanged",
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -160,6 +179,7 @@ export function diffScans(
|
||||
newLocationId: obs.storageLocationId,
|
||||
confidence: round2(obs.observationConfidence),
|
||||
reason: "Ny vara på bilden",
|
||||
reasonCode: "new_item",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -176,6 +196,7 @@ export function diffScans(
|
||||
previousLocationId: item.storageLocationId,
|
||||
confidence: 0.6,
|
||||
reason: "Saknas på nya bilden — bekräfta att den är slut",
|
||||
reasonCode: "vanished",
|
||||
});
|
||||
pendingVanishedIds.push(item.id);
|
||||
}
|
||||
|
||||
@@ -484,6 +484,9 @@ export interface WeekPlanEntry {
|
||||
status: "planned" | "cooked" | "skipped" | "moved";
|
||||
/** Förklaring vid dynamisk omplanering (spec §25). */
|
||||
rescheduleReasonSv?: string;
|
||||
/** Översättbar form av omplaneringsmotiveringen: i18n-nyckel + parametrar. */
|
||||
rescheduleReasonKey?: string;
|
||||
rescheduleReasonParams?: Record<string, string | number>;
|
||||
sortOrder: number;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user