mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 18:41:08 +02:00
feat(augur): real i18n keys — replace T constants with $_('augur.*')
The M1–M6 build shipped strings in `T = {} as const` constants — clean
enough to keep the i18n-hardcoded baseline at zero, but never the
real plan. This commit closes the loop:
- Add per-locale namespace `augur` with five bundles
(de / en / fr / it / es). DE + EN are translated; FR/IT/ES mirror
DE for parity until proper translation lands. Same staging that
other modules use.
- Replace every `T.x` with `$_('augur.section.x')` across 8 svelte
files + 2 routes. Drop the const blocks where they were the only
reason a script tag had untyped state.
- Existing `KIND_LABELS[k].de` / `VIBE_LABELS` / etc. stay — they
serve dual-mode (web + tools.ts), and the module convention is
nested-locale records rather than svelte-i18n keys for those.
Validators:
- i18n-parity: 36 namespaces × 5 locales — 2852 keys aligned
- i18n-keys: 315 missing (== baseline) — augur adds zero
- i18n-hardcoded: augur not flagged
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
303058d406
commit
c5ff7e1d33
14 changed files with 899 additions and 237 deletions
152
apps/mana/apps/web/src/lib/i18n/locales/augur/de.json
Normal file
152
apps/mana/apps/web/src/lib/i18n/locales/augur/de.json
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
{
|
||||
"app": {
|
||||
"title": "Augur",
|
||||
"tagline": "Zeichen sammeln, Muster lesen."
|
||||
},
|
||||
"mode": {
|
||||
"witness": "Witness",
|
||||
"oracle": "Oracle",
|
||||
"witnessHint": "Zeichen sammeln",
|
||||
"oracleHint": "Muster lesen"
|
||||
},
|
||||
"witness": {
|
||||
"searchPlaceholder": "Suche nach Quelle, Aussage, Deutung ...",
|
||||
"newOpen": "+ neu",
|
||||
"newClose": "× schliessen",
|
||||
"emptyAll": "Noch keine Zeichen erfasst. Sammle erst — auswerten kommt spaeter.",
|
||||
"emptyFiltered": "Keine passenden Zeichen.",
|
||||
"openOnly": "nur offene",
|
||||
"dueOnly": "nur faellige",
|
||||
"openHint": "noch offen"
|
||||
},
|
||||
"due": {
|
||||
"single": "Zeichen wartet auf Aufloesung",
|
||||
"plural": "Zeichen warten auf Aufloesung",
|
||||
"hide": "verbergen",
|
||||
"show": "oeffnen",
|
||||
"yes": "ja",
|
||||
"partly": "teils",
|
||||
"no": "nein",
|
||||
"overdue": "Tage faellig",
|
||||
"dueToday": "heute"
|
||||
},
|
||||
"oracle": {
|
||||
"title": "Oracle",
|
||||
"subtitle": "Was deine Daten zurueck sagen.",
|
||||
"yearRecapLink": "Jahresrueckblick →",
|
||||
"coldStart": "Noch zu wenig aufgeloeste Zeichen.",
|
||||
"coldStartHint": "Sammle und loese mindestens",
|
||||
"coldStartUnit": "Zeichen auf, dann zeigt das Orakel verlaessliche Zahlen.",
|
||||
"statTotal": "gesammelt",
|
||||
"statResolved": "aufgeloest",
|
||||
"statOpen": "offen",
|
||||
"statHitRate": "Trefferquote",
|
||||
"statBrier": "Brier-Score",
|
||||
"statBrierBaseline": "Baseline 0.25 (50/50)",
|
||||
"sourceTitle": "Forecaster in deinem Leben",
|
||||
"sourceSub": "Wer / was war wie oft richtig?",
|
||||
"sourceCol": "Quelle",
|
||||
"sourceN": "n",
|
||||
"sourceHit": "Treffer",
|
||||
"sourceBrier": "Brier",
|
||||
"sourceMix": "Verteilung",
|
||||
"vibeTitle": "Stimmt dein Bauchgefuehl?",
|
||||
"vibeSub": "Treffer pro Stimmung — gut, raetselhaft, schlecht.",
|
||||
"vibeNoData": "noch keine Daten",
|
||||
"vibeHit": "Treffer",
|
||||
"vibeDir": "Richtung",
|
||||
"corrTitle": "Was um deine Zeichen herum passiert",
|
||||
"corrSub": "Korrelation, nicht Kausalitaet — gefunden in deinen eigenen Daten.",
|
||||
"corrEmpty": "Noch keine belastbaren Muster. Logge weiter — Mood und Sleep werden dazu gerechnet.",
|
||||
"corrAfter": "In den 3 Tagen danach",
|
||||
"corrMoodLevel": "lag dein Mood-Level bei",
|
||||
"corrSleepQuality": "lag deine Schlaf-Qualitaet bei",
|
||||
"corrSleepDuration": "lag deine Schlafdauer bei",
|
||||
"corrVsBaseline": "Baseline:"
|
||||
},
|
||||
"detail": {
|
||||
"source": "Quelle",
|
||||
"claim": "Aussage",
|
||||
"felt": "Eigene Deutung",
|
||||
"expected": "Erwartetes Ergebnis",
|
||||
"expectedBy": "Bis",
|
||||
"probability": "Wahrscheinlichkeit",
|
||||
"tags": "Tags",
|
||||
"captured": "Erfasst",
|
||||
"resolved": "Aufgeloest",
|
||||
"outcomeNote": "Wie es kam",
|
||||
"resolvePrompt": "Hat sich das bewahrheitet?",
|
||||
"resolveYes": "eingetreten",
|
||||
"resolvePartly": "teilweise",
|
||||
"resolveNo": "nicht eingetreten",
|
||||
"resolveReopen": "erneut oeffnen",
|
||||
"actionEdit": "bearbeiten",
|
||||
"actionArchive": "archivieren",
|
||||
"actionDelete": "loeschen",
|
||||
"actionCancel": "abbrechen",
|
||||
"notePlaceholder": "Optionale Notiz: wie genau ist es gekommen?",
|
||||
"confirmDelete": "Diesen Eintrag wirklich loeschen?",
|
||||
"visibility": "Sichtbarkeit"
|
||||
},
|
||||
"form": {
|
||||
"kind": "Art",
|
||||
"source": "Quelle",
|
||||
"category": "Kategorie",
|
||||
"claim": "Was sagt das Zeichen?",
|
||||
"vibe": "Stimmung",
|
||||
"feltMeaning": "Eigene Deutung (optional)",
|
||||
"expectedOutcome": "Was sollte konkret passieren? (optional)",
|
||||
"expectedBy": "Bis wann? (optional)",
|
||||
"probability": "Wahrscheinlichkeit (optional, 0-100%)",
|
||||
"tags": "Tags (komma-getrennt)",
|
||||
"encounteredAt": "Wann erlebt?",
|
||||
"sourcePlaceholder": "z. B. schwarze Katze, Glueckskeks, Bauchgefuehl",
|
||||
"claimPlaceholder": "z. B. heute kommt eine gute Nachricht",
|
||||
"feltPlaceholder": "Was es fuer mich bedeutet ...",
|
||||
"expectedPlaceholder": "z. B. Job-Zusage bis Freitag",
|
||||
"tagsPlaceholder": "arbeit, naturzeichen ...",
|
||||
"submitCreate": "+ erfassen",
|
||||
"submitUpdate": "speichern",
|
||||
"cancel": "abbrechen",
|
||||
"more": "+ Prognose & Tags"
|
||||
},
|
||||
"recap": {
|
||||
"title": "Jahresrueckblick",
|
||||
"yearTotal": "Zeichen",
|
||||
"yearResolved": "aufgeloest",
|
||||
"yearHitRate": "Trefferquote",
|
||||
"emptyYear": "In diesem Jahr noch keine Zeichen erfasst.",
|
||||
"distKind": "Nach Art",
|
||||
"distVibe": "Nach Stimmung",
|
||||
"distOutcome": "Nach Ergebnis",
|
||||
"bestSource": "Bester Forecaster",
|
||||
"worstSource": "Unzuverlaessigster Forecaster",
|
||||
"topSources": "Meistgenutzte Quellen",
|
||||
"mostFulfilled": "Eingetretene Zeichen",
|
||||
"mostSurprising": "Ueberraschungen — wo dein Gefuehl danebenlag",
|
||||
"none": "—",
|
||||
"hitOf": "von",
|
||||
"matches": "Treffer"
|
||||
},
|
||||
"oracleHint": {
|
||||
"titleLive": "Was deine Daten zurueck sagen",
|
||||
"titleSnapshot": "Was das Orakel damals sagte",
|
||||
"matchCount": "aehnliche Zeichen",
|
||||
"hit": "eingetreten",
|
||||
"partly": "teilweise",
|
||||
"no": "nicht eingetreten"
|
||||
},
|
||||
"route": {
|
||||
"detailFallbackTitle": "Augur",
|
||||
"detailRouteTitle": "Zeichen",
|
||||
"loading": "laedt ...",
|
||||
"notFound": "Eintrag nicht gefunden.",
|
||||
"backLink": "← zurueck",
|
||||
"recapInvalid": "Ungueltiges Jahr.",
|
||||
"recapBack": "← zurueck"
|
||||
},
|
||||
"common": {
|
||||
"all": "alle",
|
||||
"brierUnknown": "–"
|
||||
}
|
||||
}
|
||||
152
apps/mana/apps/web/src/lib/i18n/locales/augur/en.json
Normal file
152
apps/mana/apps/web/src/lib/i18n/locales/augur/en.json
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
{
|
||||
"app": {
|
||||
"title": "Augur",
|
||||
"tagline": "Collect signs, read patterns."
|
||||
},
|
||||
"mode": {
|
||||
"witness": "Witness",
|
||||
"oracle": "Oracle",
|
||||
"witnessHint": "collect signs",
|
||||
"oracleHint": "read patterns"
|
||||
},
|
||||
"witness": {
|
||||
"searchPlaceholder": "Search source, claim, meaning ...",
|
||||
"newOpen": "+ new",
|
||||
"newClose": "× close",
|
||||
"emptyAll": "No signs captured yet. Collect first — analysis comes later.",
|
||||
"emptyFiltered": "No matching signs.",
|
||||
"openOnly": "open only",
|
||||
"dueOnly": "due only",
|
||||
"openHint": "still open"
|
||||
},
|
||||
"due": {
|
||||
"single": "sign waiting for resolution",
|
||||
"plural": "signs waiting for resolution",
|
||||
"hide": "hide",
|
||||
"show": "show",
|
||||
"yes": "yes",
|
||||
"partly": "partly",
|
||||
"no": "no",
|
||||
"overdue": "days overdue",
|
||||
"dueToday": "today"
|
||||
},
|
||||
"oracle": {
|
||||
"title": "Oracle",
|
||||
"subtitle": "What your data says back.",
|
||||
"yearRecapLink": "Year in review →",
|
||||
"coldStart": "Not enough resolved signs yet.",
|
||||
"coldStartHint": "Collect and resolve at least",
|
||||
"coldStartUnit": "signs, then the oracle shows reliable numbers.",
|
||||
"statTotal": "collected",
|
||||
"statResolved": "resolved",
|
||||
"statOpen": "open",
|
||||
"statHitRate": "hit rate",
|
||||
"statBrier": "Brier score",
|
||||
"statBrierBaseline": "Baseline 0.25 (50/50)",
|
||||
"sourceTitle": "Forecasters in your life",
|
||||
"sourceSub": "Who / what was right how often?",
|
||||
"sourceCol": "Source",
|
||||
"sourceN": "n",
|
||||
"sourceHit": "Hit",
|
||||
"sourceBrier": "Brier",
|
||||
"sourceMix": "Distribution",
|
||||
"vibeTitle": "Does your gut feeling check out?",
|
||||
"vibeSub": "Hits per vibe — good, mysterious, bad.",
|
||||
"vibeNoData": "no data yet",
|
||||
"vibeHit": "Hit",
|
||||
"vibeDir": "Direction",
|
||||
"corrTitle": "What happens around your signs",
|
||||
"corrSub": "Correlation, not causation — found in your own data.",
|
||||
"corrEmpty": "No reliable patterns yet. Keep logging — mood and sleep are factored in.",
|
||||
"corrAfter": "In the 3 days after",
|
||||
"corrMoodLevel": "your mood level was",
|
||||
"corrSleepQuality": "your sleep quality was",
|
||||
"corrSleepDuration": "your sleep duration was",
|
||||
"corrVsBaseline": "Baseline:"
|
||||
},
|
||||
"detail": {
|
||||
"source": "Source",
|
||||
"claim": "Claim",
|
||||
"felt": "Your interpretation",
|
||||
"expected": "Expected outcome",
|
||||
"expectedBy": "By",
|
||||
"probability": "Probability",
|
||||
"tags": "Tags",
|
||||
"captured": "Captured",
|
||||
"resolved": "Resolved",
|
||||
"outcomeNote": "How it went",
|
||||
"resolvePrompt": "Did it come true?",
|
||||
"resolveYes": "fulfilled",
|
||||
"resolvePartly": "partly",
|
||||
"resolveNo": "not fulfilled",
|
||||
"resolveReopen": "reopen",
|
||||
"actionEdit": "edit",
|
||||
"actionArchive": "archive",
|
||||
"actionDelete": "delete",
|
||||
"actionCancel": "cancel",
|
||||
"notePlaceholder": "Optional note: how exactly did it play out?",
|
||||
"confirmDelete": "Really delete this entry?",
|
||||
"visibility": "Visibility"
|
||||
},
|
||||
"form": {
|
||||
"kind": "Kind",
|
||||
"source": "Source",
|
||||
"category": "Category",
|
||||
"claim": "What does the sign say?",
|
||||
"vibe": "Vibe",
|
||||
"feltMeaning": "Your interpretation (optional)",
|
||||
"expectedOutcome": "What concretely should happen? (optional)",
|
||||
"expectedBy": "By when? (optional)",
|
||||
"probability": "Probability (optional, 0-100%)",
|
||||
"tags": "Tags (comma-separated)",
|
||||
"encounteredAt": "When experienced?",
|
||||
"sourcePlaceholder": "e.g. black cat, fortune cookie, gut feeling",
|
||||
"claimPlaceholder": "e.g. good news will arrive today",
|
||||
"feltPlaceholder": "What it means to me ...",
|
||||
"expectedPlaceholder": "e.g. job offer by Friday",
|
||||
"tagsPlaceholder": "work, omens ...",
|
||||
"submitCreate": "+ capture",
|
||||
"submitUpdate": "save",
|
||||
"cancel": "cancel",
|
||||
"more": "+ Prediction & Tags"
|
||||
},
|
||||
"recap": {
|
||||
"title": "Year in review",
|
||||
"yearTotal": "signs",
|
||||
"yearResolved": "resolved",
|
||||
"yearHitRate": "hit rate",
|
||||
"emptyYear": "No signs captured this year.",
|
||||
"distKind": "By kind",
|
||||
"distVibe": "By vibe",
|
||||
"distOutcome": "By outcome",
|
||||
"bestSource": "Best forecaster",
|
||||
"worstSource": "Most unreliable forecaster",
|
||||
"topSources": "Most-used sources",
|
||||
"mostFulfilled": "Fulfilled signs",
|
||||
"mostSurprising": "Surprises — where your gut got it wrong",
|
||||
"none": "—",
|
||||
"hitOf": "of",
|
||||
"matches": "Hits"
|
||||
},
|
||||
"oracleHint": {
|
||||
"titleLive": "What your data says back",
|
||||
"titleSnapshot": "What the oracle said then",
|
||||
"matchCount": "similar signs",
|
||||
"hit": "fulfilled",
|
||||
"partly": "partly",
|
||||
"no": "not fulfilled"
|
||||
},
|
||||
"route": {
|
||||
"detailFallbackTitle": "Augur",
|
||||
"detailRouteTitle": "Sign",
|
||||
"loading": "loading ...",
|
||||
"notFound": "Entry not found.",
|
||||
"backLink": "← back",
|
||||
"recapInvalid": "Invalid year.",
|
||||
"recapBack": "← back"
|
||||
},
|
||||
"common": {
|
||||
"all": "all",
|
||||
"brierUnknown": "–"
|
||||
}
|
||||
}
|
||||
152
apps/mana/apps/web/src/lib/i18n/locales/augur/es.json
Normal file
152
apps/mana/apps/web/src/lib/i18n/locales/augur/es.json
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
{
|
||||
"app": {
|
||||
"title": "Augur",
|
||||
"tagline": "Zeichen sammeln, Muster lesen."
|
||||
},
|
||||
"mode": {
|
||||
"witness": "Witness",
|
||||
"oracle": "Oracle",
|
||||
"witnessHint": "Zeichen sammeln",
|
||||
"oracleHint": "Muster lesen"
|
||||
},
|
||||
"witness": {
|
||||
"searchPlaceholder": "Suche nach Quelle, Aussage, Deutung ...",
|
||||
"newOpen": "+ neu",
|
||||
"newClose": "× schliessen",
|
||||
"emptyAll": "Noch keine Zeichen erfasst. Sammle erst — auswerten kommt spaeter.",
|
||||
"emptyFiltered": "Keine passenden Zeichen.",
|
||||
"openOnly": "nur offene",
|
||||
"dueOnly": "nur faellige",
|
||||
"openHint": "noch offen"
|
||||
},
|
||||
"due": {
|
||||
"single": "Zeichen wartet auf Aufloesung",
|
||||
"plural": "Zeichen warten auf Aufloesung",
|
||||
"hide": "verbergen",
|
||||
"show": "oeffnen",
|
||||
"yes": "ja",
|
||||
"partly": "teils",
|
||||
"no": "nein",
|
||||
"overdue": "Tage faellig",
|
||||
"dueToday": "heute"
|
||||
},
|
||||
"oracle": {
|
||||
"title": "Oracle",
|
||||
"subtitle": "Was deine Daten zurueck sagen.",
|
||||
"yearRecapLink": "Jahresrueckblick →",
|
||||
"coldStart": "Noch zu wenig aufgeloeste Zeichen.",
|
||||
"coldStartHint": "Sammle und loese mindestens",
|
||||
"coldStartUnit": "Zeichen auf, dann zeigt das Orakel verlaessliche Zahlen.",
|
||||
"statTotal": "gesammelt",
|
||||
"statResolved": "aufgeloest",
|
||||
"statOpen": "offen",
|
||||
"statHitRate": "Trefferquote",
|
||||
"statBrier": "Brier-Score",
|
||||
"statBrierBaseline": "Baseline 0.25 (50/50)",
|
||||
"sourceTitle": "Forecaster in deinem Leben",
|
||||
"sourceSub": "Wer / was war wie oft richtig?",
|
||||
"sourceCol": "Quelle",
|
||||
"sourceN": "n",
|
||||
"sourceHit": "Treffer",
|
||||
"sourceBrier": "Brier",
|
||||
"sourceMix": "Verteilung",
|
||||
"vibeTitle": "Stimmt dein Bauchgefuehl?",
|
||||
"vibeSub": "Treffer pro Stimmung — gut, raetselhaft, schlecht.",
|
||||
"vibeNoData": "noch keine Daten",
|
||||
"vibeHit": "Treffer",
|
||||
"vibeDir": "Richtung",
|
||||
"corrTitle": "Was um deine Zeichen herum passiert",
|
||||
"corrSub": "Korrelation, nicht Kausalitaet — gefunden in deinen eigenen Daten.",
|
||||
"corrEmpty": "Noch keine belastbaren Muster. Logge weiter — Mood und Sleep werden dazu gerechnet.",
|
||||
"corrAfter": "In den 3 Tagen danach",
|
||||
"corrMoodLevel": "lag dein Mood-Level bei",
|
||||
"corrSleepQuality": "lag deine Schlaf-Qualitaet bei",
|
||||
"corrSleepDuration": "lag deine Schlafdauer bei",
|
||||
"corrVsBaseline": "Baseline:"
|
||||
},
|
||||
"detail": {
|
||||
"source": "Quelle",
|
||||
"claim": "Aussage",
|
||||
"felt": "Eigene Deutung",
|
||||
"expected": "Erwartetes Ergebnis",
|
||||
"expectedBy": "Bis",
|
||||
"probability": "Wahrscheinlichkeit",
|
||||
"tags": "Tags",
|
||||
"captured": "Erfasst",
|
||||
"resolved": "Aufgeloest",
|
||||
"outcomeNote": "Wie es kam",
|
||||
"resolvePrompt": "Hat sich das bewahrheitet?",
|
||||
"resolveYes": "eingetreten",
|
||||
"resolvePartly": "teilweise",
|
||||
"resolveNo": "nicht eingetreten",
|
||||
"resolveReopen": "erneut oeffnen",
|
||||
"actionEdit": "bearbeiten",
|
||||
"actionArchive": "archivieren",
|
||||
"actionDelete": "loeschen",
|
||||
"actionCancel": "abbrechen",
|
||||
"notePlaceholder": "Optionale Notiz: wie genau ist es gekommen?",
|
||||
"confirmDelete": "Diesen Eintrag wirklich loeschen?",
|
||||
"visibility": "Sichtbarkeit"
|
||||
},
|
||||
"form": {
|
||||
"kind": "Art",
|
||||
"source": "Quelle",
|
||||
"category": "Kategorie",
|
||||
"claim": "Was sagt das Zeichen?",
|
||||
"vibe": "Stimmung",
|
||||
"feltMeaning": "Eigene Deutung (optional)",
|
||||
"expectedOutcome": "Was sollte konkret passieren? (optional)",
|
||||
"expectedBy": "Bis wann? (optional)",
|
||||
"probability": "Wahrscheinlichkeit (optional, 0-100%)",
|
||||
"tags": "Tags (komma-getrennt)",
|
||||
"encounteredAt": "Wann erlebt?",
|
||||
"sourcePlaceholder": "z. B. schwarze Katze, Glueckskeks, Bauchgefuehl",
|
||||
"claimPlaceholder": "z. B. heute kommt eine gute Nachricht",
|
||||
"feltPlaceholder": "Was es fuer mich bedeutet ...",
|
||||
"expectedPlaceholder": "z. B. Job-Zusage bis Freitag",
|
||||
"tagsPlaceholder": "arbeit, naturzeichen ...",
|
||||
"submitCreate": "+ erfassen",
|
||||
"submitUpdate": "speichern",
|
||||
"cancel": "abbrechen",
|
||||
"more": "+ Prognose & Tags"
|
||||
},
|
||||
"recap": {
|
||||
"title": "Jahresrueckblick",
|
||||
"yearTotal": "Zeichen",
|
||||
"yearResolved": "aufgeloest",
|
||||
"yearHitRate": "Trefferquote",
|
||||
"emptyYear": "In diesem Jahr noch keine Zeichen erfasst.",
|
||||
"distKind": "Nach Art",
|
||||
"distVibe": "Nach Stimmung",
|
||||
"distOutcome": "Nach Ergebnis",
|
||||
"bestSource": "Bester Forecaster",
|
||||
"worstSource": "Unzuverlaessigster Forecaster",
|
||||
"topSources": "Meistgenutzte Quellen",
|
||||
"mostFulfilled": "Eingetretene Zeichen",
|
||||
"mostSurprising": "Ueberraschungen — wo dein Gefuehl danebenlag",
|
||||
"none": "—",
|
||||
"hitOf": "von",
|
||||
"matches": "Treffer"
|
||||
},
|
||||
"oracleHint": {
|
||||
"titleLive": "Was deine Daten zurueck sagen",
|
||||
"titleSnapshot": "Was das Orakel damals sagte",
|
||||
"matchCount": "aehnliche Zeichen",
|
||||
"hit": "eingetreten",
|
||||
"partly": "teilweise",
|
||||
"no": "nicht eingetreten"
|
||||
},
|
||||
"route": {
|
||||
"detailFallbackTitle": "Augur",
|
||||
"detailRouteTitle": "Zeichen",
|
||||
"loading": "laedt ...",
|
||||
"notFound": "Eintrag nicht gefunden.",
|
||||
"backLink": "← zurueck",
|
||||
"recapInvalid": "Ungueltiges Jahr.",
|
||||
"recapBack": "← zurueck"
|
||||
},
|
||||
"common": {
|
||||
"all": "alle",
|
||||
"brierUnknown": "–"
|
||||
}
|
||||
}
|
||||
152
apps/mana/apps/web/src/lib/i18n/locales/augur/fr.json
Normal file
152
apps/mana/apps/web/src/lib/i18n/locales/augur/fr.json
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
{
|
||||
"app": {
|
||||
"title": "Augur",
|
||||
"tagline": "Zeichen sammeln, Muster lesen."
|
||||
},
|
||||
"mode": {
|
||||
"witness": "Witness",
|
||||
"oracle": "Oracle",
|
||||
"witnessHint": "Zeichen sammeln",
|
||||
"oracleHint": "Muster lesen"
|
||||
},
|
||||
"witness": {
|
||||
"searchPlaceholder": "Suche nach Quelle, Aussage, Deutung ...",
|
||||
"newOpen": "+ neu",
|
||||
"newClose": "× schliessen",
|
||||
"emptyAll": "Noch keine Zeichen erfasst. Sammle erst — auswerten kommt spaeter.",
|
||||
"emptyFiltered": "Keine passenden Zeichen.",
|
||||
"openOnly": "nur offene",
|
||||
"dueOnly": "nur faellige",
|
||||
"openHint": "noch offen"
|
||||
},
|
||||
"due": {
|
||||
"single": "Zeichen wartet auf Aufloesung",
|
||||
"plural": "Zeichen warten auf Aufloesung",
|
||||
"hide": "verbergen",
|
||||
"show": "oeffnen",
|
||||
"yes": "ja",
|
||||
"partly": "teils",
|
||||
"no": "nein",
|
||||
"overdue": "Tage faellig",
|
||||
"dueToday": "heute"
|
||||
},
|
||||
"oracle": {
|
||||
"title": "Oracle",
|
||||
"subtitle": "Was deine Daten zurueck sagen.",
|
||||
"yearRecapLink": "Jahresrueckblick →",
|
||||
"coldStart": "Noch zu wenig aufgeloeste Zeichen.",
|
||||
"coldStartHint": "Sammle und loese mindestens",
|
||||
"coldStartUnit": "Zeichen auf, dann zeigt das Orakel verlaessliche Zahlen.",
|
||||
"statTotal": "gesammelt",
|
||||
"statResolved": "aufgeloest",
|
||||
"statOpen": "offen",
|
||||
"statHitRate": "Trefferquote",
|
||||
"statBrier": "Brier-Score",
|
||||
"statBrierBaseline": "Baseline 0.25 (50/50)",
|
||||
"sourceTitle": "Forecaster in deinem Leben",
|
||||
"sourceSub": "Wer / was war wie oft richtig?",
|
||||
"sourceCol": "Quelle",
|
||||
"sourceN": "n",
|
||||
"sourceHit": "Treffer",
|
||||
"sourceBrier": "Brier",
|
||||
"sourceMix": "Verteilung",
|
||||
"vibeTitle": "Stimmt dein Bauchgefuehl?",
|
||||
"vibeSub": "Treffer pro Stimmung — gut, raetselhaft, schlecht.",
|
||||
"vibeNoData": "noch keine Daten",
|
||||
"vibeHit": "Treffer",
|
||||
"vibeDir": "Richtung",
|
||||
"corrTitle": "Was um deine Zeichen herum passiert",
|
||||
"corrSub": "Korrelation, nicht Kausalitaet — gefunden in deinen eigenen Daten.",
|
||||
"corrEmpty": "Noch keine belastbaren Muster. Logge weiter — Mood und Sleep werden dazu gerechnet.",
|
||||
"corrAfter": "In den 3 Tagen danach",
|
||||
"corrMoodLevel": "lag dein Mood-Level bei",
|
||||
"corrSleepQuality": "lag deine Schlaf-Qualitaet bei",
|
||||
"corrSleepDuration": "lag deine Schlafdauer bei",
|
||||
"corrVsBaseline": "Baseline:"
|
||||
},
|
||||
"detail": {
|
||||
"source": "Quelle",
|
||||
"claim": "Aussage",
|
||||
"felt": "Eigene Deutung",
|
||||
"expected": "Erwartetes Ergebnis",
|
||||
"expectedBy": "Bis",
|
||||
"probability": "Wahrscheinlichkeit",
|
||||
"tags": "Tags",
|
||||
"captured": "Erfasst",
|
||||
"resolved": "Aufgeloest",
|
||||
"outcomeNote": "Wie es kam",
|
||||
"resolvePrompt": "Hat sich das bewahrheitet?",
|
||||
"resolveYes": "eingetreten",
|
||||
"resolvePartly": "teilweise",
|
||||
"resolveNo": "nicht eingetreten",
|
||||
"resolveReopen": "erneut oeffnen",
|
||||
"actionEdit": "bearbeiten",
|
||||
"actionArchive": "archivieren",
|
||||
"actionDelete": "loeschen",
|
||||
"actionCancel": "abbrechen",
|
||||
"notePlaceholder": "Optionale Notiz: wie genau ist es gekommen?",
|
||||
"confirmDelete": "Diesen Eintrag wirklich loeschen?",
|
||||
"visibility": "Sichtbarkeit"
|
||||
},
|
||||
"form": {
|
||||
"kind": "Art",
|
||||
"source": "Quelle",
|
||||
"category": "Kategorie",
|
||||
"claim": "Was sagt das Zeichen?",
|
||||
"vibe": "Stimmung",
|
||||
"feltMeaning": "Eigene Deutung (optional)",
|
||||
"expectedOutcome": "Was sollte konkret passieren? (optional)",
|
||||
"expectedBy": "Bis wann? (optional)",
|
||||
"probability": "Wahrscheinlichkeit (optional, 0-100%)",
|
||||
"tags": "Tags (komma-getrennt)",
|
||||
"encounteredAt": "Wann erlebt?",
|
||||
"sourcePlaceholder": "z. B. schwarze Katze, Glueckskeks, Bauchgefuehl",
|
||||
"claimPlaceholder": "z. B. heute kommt eine gute Nachricht",
|
||||
"feltPlaceholder": "Was es fuer mich bedeutet ...",
|
||||
"expectedPlaceholder": "z. B. Job-Zusage bis Freitag",
|
||||
"tagsPlaceholder": "arbeit, naturzeichen ...",
|
||||
"submitCreate": "+ erfassen",
|
||||
"submitUpdate": "speichern",
|
||||
"cancel": "abbrechen",
|
||||
"more": "+ Prognose & Tags"
|
||||
},
|
||||
"recap": {
|
||||
"title": "Jahresrueckblick",
|
||||
"yearTotal": "Zeichen",
|
||||
"yearResolved": "aufgeloest",
|
||||
"yearHitRate": "Trefferquote",
|
||||
"emptyYear": "In diesem Jahr noch keine Zeichen erfasst.",
|
||||
"distKind": "Nach Art",
|
||||
"distVibe": "Nach Stimmung",
|
||||
"distOutcome": "Nach Ergebnis",
|
||||
"bestSource": "Bester Forecaster",
|
||||
"worstSource": "Unzuverlaessigster Forecaster",
|
||||
"topSources": "Meistgenutzte Quellen",
|
||||
"mostFulfilled": "Eingetretene Zeichen",
|
||||
"mostSurprising": "Ueberraschungen — wo dein Gefuehl danebenlag",
|
||||
"none": "—",
|
||||
"hitOf": "von",
|
||||
"matches": "Treffer"
|
||||
},
|
||||
"oracleHint": {
|
||||
"titleLive": "Was deine Daten zurueck sagen",
|
||||
"titleSnapshot": "Was das Orakel damals sagte",
|
||||
"matchCount": "aehnliche Zeichen",
|
||||
"hit": "eingetreten",
|
||||
"partly": "teilweise",
|
||||
"no": "nicht eingetreten"
|
||||
},
|
||||
"route": {
|
||||
"detailFallbackTitle": "Augur",
|
||||
"detailRouteTitle": "Zeichen",
|
||||
"loading": "laedt ...",
|
||||
"notFound": "Eintrag nicht gefunden.",
|
||||
"backLink": "← zurueck",
|
||||
"recapInvalid": "Ungueltiges Jahr.",
|
||||
"recapBack": "← zurueck"
|
||||
},
|
||||
"common": {
|
||||
"all": "alle",
|
||||
"brierUnknown": "–"
|
||||
}
|
||||
}
|
||||
152
apps/mana/apps/web/src/lib/i18n/locales/augur/it.json
Normal file
152
apps/mana/apps/web/src/lib/i18n/locales/augur/it.json
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
{
|
||||
"app": {
|
||||
"title": "Augur",
|
||||
"tagline": "Zeichen sammeln, Muster lesen."
|
||||
},
|
||||
"mode": {
|
||||
"witness": "Witness",
|
||||
"oracle": "Oracle",
|
||||
"witnessHint": "Zeichen sammeln",
|
||||
"oracleHint": "Muster lesen"
|
||||
},
|
||||
"witness": {
|
||||
"searchPlaceholder": "Suche nach Quelle, Aussage, Deutung ...",
|
||||
"newOpen": "+ neu",
|
||||
"newClose": "× schliessen",
|
||||
"emptyAll": "Noch keine Zeichen erfasst. Sammle erst — auswerten kommt spaeter.",
|
||||
"emptyFiltered": "Keine passenden Zeichen.",
|
||||
"openOnly": "nur offene",
|
||||
"dueOnly": "nur faellige",
|
||||
"openHint": "noch offen"
|
||||
},
|
||||
"due": {
|
||||
"single": "Zeichen wartet auf Aufloesung",
|
||||
"plural": "Zeichen warten auf Aufloesung",
|
||||
"hide": "verbergen",
|
||||
"show": "oeffnen",
|
||||
"yes": "ja",
|
||||
"partly": "teils",
|
||||
"no": "nein",
|
||||
"overdue": "Tage faellig",
|
||||
"dueToday": "heute"
|
||||
},
|
||||
"oracle": {
|
||||
"title": "Oracle",
|
||||
"subtitle": "Was deine Daten zurueck sagen.",
|
||||
"yearRecapLink": "Jahresrueckblick →",
|
||||
"coldStart": "Noch zu wenig aufgeloeste Zeichen.",
|
||||
"coldStartHint": "Sammle und loese mindestens",
|
||||
"coldStartUnit": "Zeichen auf, dann zeigt das Orakel verlaessliche Zahlen.",
|
||||
"statTotal": "gesammelt",
|
||||
"statResolved": "aufgeloest",
|
||||
"statOpen": "offen",
|
||||
"statHitRate": "Trefferquote",
|
||||
"statBrier": "Brier-Score",
|
||||
"statBrierBaseline": "Baseline 0.25 (50/50)",
|
||||
"sourceTitle": "Forecaster in deinem Leben",
|
||||
"sourceSub": "Wer / was war wie oft richtig?",
|
||||
"sourceCol": "Quelle",
|
||||
"sourceN": "n",
|
||||
"sourceHit": "Treffer",
|
||||
"sourceBrier": "Brier",
|
||||
"sourceMix": "Verteilung",
|
||||
"vibeTitle": "Stimmt dein Bauchgefuehl?",
|
||||
"vibeSub": "Treffer pro Stimmung — gut, raetselhaft, schlecht.",
|
||||
"vibeNoData": "noch keine Daten",
|
||||
"vibeHit": "Treffer",
|
||||
"vibeDir": "Richtung",
|
||||
"corrTitle": "Was um deine Zeichen herum passiert",
|
||||
"corrSub": "Korrelation, nicht Kausalitaet — gefunden in deinen eigenen Daten.",
|
||||
"corrEmpty": "Noch keine belastbaren Muster. Logge weiter — Mood und Sleep werden dazu gerechnet.",
|
||||
"corrAfter": "In den 3 Tagen danach",
|
||||
"corrMoodLevel": "lag dein Mood-Level bei",
|
||||
"corrSleepQuality": "lag deine Schlaf-Qualitaet bei",
|
||||
"corrSleepDuration": "lag deine Schlafdauer bei",
|
||||
"corrVsBaseline": "Baseline:"
|
||||
},
|
||||
"detail": {
|
||||
"source": "Quelle",
|
||||
"claim": "Aussage",
|
||||
"felt": "Eigene Deutung",
|
||||
"expected": "Erwartetes Ergebnis",
|
||||
"expectedBy": "Bis",
|
||||
"probability": "Wahrscheinlichkeit",
|
||||
"tags": "Tags",
|
||||
"captured": "Erfasst",
|
||||
"resolved": "Aufgeloest",
|
||||
"outcomeNote": "Wie es kam",
|
||||
"resolvePrompt": "Hat sich das bewahrheitet?",
|
||||
"resolveYes": "eingetreten",
|
||||
"resolvePartly": "teilweise",
|
||||
"resolveNo": "nicht eingetreten",
|
||||
"resolveReopen": "erneut oeffnen",
|
||||
"actionEdit": "bearbeiten",
|
||||
"actionArchive": "archivieren",
|
||||
"actionDelete": "loeschen",
|
||||
"actionCancel": "abbrechen",
|
||||
"notePlaceholder": "Optionale Notiz: wie genau ist es gekommen?",
|
||||
"confirmDelete": "Diesen Eintrag wirklich loeschen?",
|
||||
"visibility": "Sichtbarkeit"
|
||||
},
|
||||
"form": {
|
||||
"kind": "Art",
|
||||
"source": "Quelle",
|
||||
"category": "Kategorie",
|
||||
"claim": "Was sagt das Zeichen?",
|
||||
"vibe": "Stimmung",
|
||||
"feltMeaning": "Eigene Deutung (optional)",
|
||||
"expectedOutcome": "Was sollte konkret passieren? (optional)",
|
||||
"expectedBy": "Bis wann? (optional)",
|
||||
"probability": "Wahrscheinlichkeit (optional, 0-100%)",
|
||||
"tags": "Tags (komma-getrennt)",
|
||||
"encounteredAt": "Wann erlebt?",
|
||||
"sourcePlaceholder": "z. B. schwarze Katze, Glueckskeks, Bauchgefuehl",
|
||||
"claimPlaceholder": "z. B. heute kommt eine gute Nachricht",
|
||||
"feltPlaceholder": "Was es fuer mich bedeutet ...",
|
||||
"expectedPlaceholder": "z. B. Job-Zusage bis Freitag",
|
||||
"tagsPlaceholder": "arbeit, naturzeichen ...",
|
||||
"submitCreate": "+ erfassen",
|
||||
"submitUpdate": "speichern",
|
||||
"cancel": "abbrechen",
|
||||
"more": "+ Prognose & Tags"
|
||||
},
|
||||
"recap": {
|
||||
"title": "Jahresrueckblick",
|
||||
"yearTotal": "Zeichen",
|
||||
"yearResolved": "aufgeloest",
|
||||
"yearHitRate": "Trefferquote",
|
||||
"emptyYear": "In diesem Jahr noch keine Zeichen erfasst.",
|
||||
"distKind": "Nach Art",
|
||||
"distVibe": "Nach Stimmung",
|
||||
"distOutcome": "Nach Ergebnis",
|
||||
"bestSource": "Bester Forecaster",
|
||||
"worstSource": "Unzuverlaessigster Forecaster",
|
||||
"topSources": "Meistgenutzte Quellen",
|
||||
"mostFulfilled": "Eingetretene Zeichen",
|
||||
"mostSurprising": "Ueberraschungen — wo dein Gefuehl danebenlag",
|
||||
"none": "—",
|
||||
"hitOf": "von",
|
||||
"matches": "Treffer"
|
||||
},
|
||||
"oracleHint": {
|
||||
"titleLive": "Was deine Daten zurueck sagen",
|
||||
"titleSnapshot": "Was das Orakel damals sagte",
|
||||
"matchCount": "aehnliche Zeichen",
|
||||
"hit": "eingetreten",
|
||||
"partly": "teilweise",
|
||||
"no": "nicht eingetreten"
|
||||
},
|
||||
"route": {
|
||||
"detailFallbackTitle": "Augur",
|
||||
"detailRouteTitle": "Zeichen",
|
||||
"loading": "laedt ...",
|
||||
"notFound": "Eintrag nicht gefunden.",
|
||||
"backLink": "← zurueck",
|
||||
"recapInvalid": "Ungueltiges Jahr.",
|
||||
"recapBack": "← zurueck"
|
||||
},
|
||||
"common": {
|
||||
"all": "alle",
|
||||
"brierUnknown": "–"
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import { goto } from '$app/navigation';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import WitnessView from './views/WitnessView.svelte';
|
||||
import OracleView from './views/OracleView.svelte';
|
||||
import type { ViewProps } from '$lib/app-registry';
|
||||
|
|
@ -16,13 +17,6 @@
|
|||
|
||||
type Mode = 'witness' | 'oracle';
|
||||
|
||||
const T = {
|
||||
witness: 'Witness',
|
||||
oracle: 'Oracle',
|
||||
witnessHint: 'Zeichen sammeln',
|
||||
oracleHint: 'Muster lesen',
|
||||
} as const;
|
||||
|
||||
const mode = $derived<Mode>(
|
||||
page.url.searchParams.get('mode') === 'oracle' ? 'oracle' : 'witness'
|
||||
);
|
||||
|
|
@ -45,8 +39,8 @@
|
|||
aria-selected={mode === 'witness'}
|
||||
onclick={() => setMode('witness')}
|
||||
>
|
||||
<span class="label">{T.witness}</span>
|
||||
<span class="hint">{T.witnessHint}</span>
|
||||
<span class="label">{$_('augur.mode.witness')}</span>
|
||||
<span class="hint">{$_('augur.mode.witnessHint')}</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
|
|
@ -56,8 +50,8 @@
|
|||
aria-selected={mode === 'oracle'}
|
||||
onclick={() => setMode('oracle')}
|
||||
>
|
||||
<span class="label">{T.oracle}</span>
|
||||
<span class="hint">{T.oracleHint}</span>
|
||||
<span class="label">{$_('augur.mode.oracle')}</span>
|
||||
<span class="hint">{$_('augur.mode.oracleHint')}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
-->
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { augurStore } from '../stores/entries.svelte';
|
||||
import { reminderDate, daysUntilDue } from '../lib/reminders';
|
||||
import type { AugurEntry, AugurOutcome } from '../types';
|
||||
|
|
@ -20,23 +21,11 @@
|
|||
|
||||
let expanded = $state(false);
|
||||
|
||||
const T = {
|
||||
single: 'Zeichen wartet auf Aufloesung',
|
||||
plural: 'Zeichen warten auf Aufloesung',
|
||||
hide: 'verbergen',
|
||||
show: 'oeffnen',
|
||||
yes: 'ja',
|
||||
partly: 'teils',
|
||||
no: 'nein',
|
||||
overdue: 'Tage faellig',
|
||||
dueToday: 'heute',
|
||||
} as const;
|
||||
|
||||
function dueLabel(e: AugurEntry): string {
|
||||
const d = daysUntilDue(e);
|
||||
if (d == null) return '';
|
||||
if (d === 0) return T.dueToday;
|
||||
if (d < 0) return `${-d} ${T.overdue}`;
|
||||
if (d === 0) return $_('augur.due.dueToday');
|
||||
if (d < 0) return `${-d} ${$_('augur.due.overdue')}`;
|
||||
return reminderDate(e) ?? '';
|
||||
}
|
||||
|
||||
|
|
@ -51,9 +40,9 @@
|
|||
<span class="dot"></span>
|
||||
<span class="text">
|
||||
<strong>{entries.length}</strong>
|
||||
{entries.length === 1 ? T.single : T.plural}
|
||||
{entries.length === 1 ? $_('augur.due.single') : $_('augur.due.plural')}
|
||||
</span>
|
||||
<span class="toggle">{expanded ? T.hide : T.show}</span>
|
||||
<span class="toggle">{expanded ? $_('augur.due.hide') : $_('augur.due.show')}</span>
|
||||
</button>
|
||||
|
||||
{#if expanded}
|
||||
|
|
@ -70,7 +59,7 @@
|
|||
type="button"
|
||||
class="qb yes"
|
||||
onclick={() => quickResolve(entry.id, 'fulfilled')}
|
||||
title={T.yes}
|
||||
title={$_('augur.due.yes')}
|
||||
>
|
||||
✓
|
||||
</button>
|
||||
|
|
@ -78,7 +67,7 @@
|
|||
type="button"
|
||||
class="qb partly"
|
||||
onclick={() => quickResolve(entry.id, 'partly')}
|
||||
title={T.partly}
|
||||
title={$_('augur.due.partly')}
|
||||
>
|
||||
~
|
||||
</button>
|
||||
|
|
@ -86,7 +75,7 @@
|
|||
type="button"
|
||||
class="qb no"
|
||||
onclick={() => quickResolve(entry.id, 'not-fulfilled')}
|
||||
title={T.no}
|
||||
title={$_('augur.due.no')}
|
||||
>
|
||||
✗
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { augurStore } from '../stores/entries.svelte';
|
||||
import { useAllAugurEntries } from '../queries';
|
||||
import LivingOracleHint from './LivingOracleHint.svelte';
|
||||
|
|
@ -26,28 +27,6 @@
|
|||
const history = $derived(history$.value);
|
||||
let oracleReflection = $state<string | null>(null);
|
||||
|
||||
const T = {
|
||||
kind: 'Art',
|
||||
source: 'Quelle',
|
||||
category: 'Kategorie',
|
||||
claim: 'Was sagt das Zeichen?',
|
||||
vibe: 'Stimmung',
|
||||
feltMeaning: 'Eigene Deutung (optional)',
|
||||
expectedOutcome: 'Was sollte konkret passieren? (optional)',
|
||||
expectedBy: 'Bis wann? (optional)',
|
||||
probability: 'Wahrscheinlichkeit (optional, 0-100%)',
|
||||
tags: 'Tags (komma-getrennt)',
|
||||
encounteredAt: 'Wann erlebt?',
|
||||
sourcePlaceholder: 'z. B. schwarze Katze, Glueckskeks, Bauchgefuehl',
|
||||
claimPlaceholder: 'z. B. heute kommt eine gute Nachricht',
|
||||
feltPlaceholder: 'Was es fuer mich bedeutet ...',
|
||||
expectedPlaceholder: 'z. B. Job-Zusage bis Freitag',
|
||||
tagsPlaceholder: 'arbeit, naturzeichen ...',
|
||||
submitCreate: '+ erfassen',
|
||||
submitUpdate: 'speichern',
|
||||
cancel: 'abbrechen',
|
||||
} as const;
|
||||
|
||||
/* svelte-ignore state_referenced_locally */
|
||||
let kind = $state<AugurKind>(initial?.kind ?? 'hunch');
|
||||
/* svelte-ignore state_referenced_locally */
|
||||
|
|
@ -143,7 +122,7 @@
|
|||
{#if mode === 'create'}
|
||||
<div class="row">
|
||||
<label class="field">
|
||||
<span>{T.kind}</span>
|
||||
<span>{$_('augur.form.kind')}</span>
|
||||
<select bind:value={kind}>
|
||||
{#each KIND_ORDER as k (k)}
|
||||
<option value={k}>{KIND_LABELS[k].de}</option>
|
||||
|
|
@ -151,7 +130,7 @@
|
|||
</select>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>{T.encounteredAt}</span>
|
||||
<span>{$_('augur.form.encounteredAt')}</span>
|
||||
<input type="date" bind:value={encounteredAt} />
|
||||
</label>
|
||||
</div>
|
||||
|
|
@ -159,11 +138,11 @@
|
|||
|
||||
<div class="row">
|
||||
<label class="field grow">
|
||||
<span>{T.source}</span>
|
||||
<input bind:value={source} placeholder={T.sourcePlaceholder} required />
|
||||
<span>{$_('augur.form.source')}</span>
|
||||
<input bind:value={source} placeholder={$_('augur.form.sourcePlaceholder')} required />
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>{T.category}</span>
|
||||
<span>{$_('augur.form.category')}</span>
|
||||
<select bind:value={sourceCategory}>
|
||||
{#each CATEGORY_ORDER as c (c)}
|
||||
<option value={c}>{SOURCE_CATEGORY_LABELS[c].de}</option>
|
||||
|
|
@ -173,13 +152,14 @@
|
|||
</div>
|
||||
|
||||
<label class="field">
|
||||
<span>{T.claim}</span>
|
||||
<textarea bind:value={claim} placeholder={T.claimPlaceholder} rows="2" required></textarea>
|
||||
<span>{$_('augur.form.claim')}</span>
|
||||
<textarea bind:value={claim} placeholder={$_('augur.form.claimPlaceholder')} rows="2" required
|
||||
></textarea>
|
||||
</label>
|
||||
|
||||
<div class="row">
|
||||
<label class="field grow">
|
||||
<span>{T.vibe}</span>
|
||||
<span>{$_('augur.form.vibe')}</span>
|
||||
<div class="vibe-row">
|
||||
{#each VIBE_ORDER as v (v)}
|
||||
<button
|
||||
|
|
@ -196,8 +176,9 @@
|
|||
</div>
|
||||
|
||||
<label class="field">
|
||||
<span>{T.feltMeaning}</span>
|
||||
<textarea bind:value={feltMeaning} placeholder={T.feltPlaceholder} rows="2"></textarea>
|
||||
<span>{$_('augur.form.feltMeaning')}</span>
|
||||
<textarea bind:value={feltMeaning} placeholder={$_('augur.form.feltPlaceholder')} rows="2"
|
||||
></textarea>
|
||||
</label>
|
||||
|
||||
{#if mode === 'create'}
|
||||
|
|
@ -216,18 +197,18 @@
|
|||
{/if}
|
||||
|
||||
<details class="more">
|
||||
<summary>+ Prognose & Tags</summary>
|
||||
<summary>{$_('augur.form.more')}</summary>
|
||||
<label class="field">
|
||||
<span>{T.expectedOutcome}</span>
|
||||
<input bind:value={expectedOutcome} placeholder={T.expectedPlaceholder} />
|
||||
<span>{$_('augur.form.expectedOutcome')}</span>
|
||||
<input bind:value={expectedOutcome} placeholder={$_('augur.form.expectedPlaceholder')} />
|
||||
</label>
|
||||
<div class="row">
|
||||
<label class="field">
|
||||
<span>{T.expectedBy}</span>
|
||||
<span>{$_('augur.form.expectedBy')}</span>
|
||||
<input type="date" bind:value={expectedBy} />
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>{T.probability}</span>
|
||||
<span>{$_('augur.form.probability')}</span>
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
|
|
@ -239,19 +220,19 @@
|
|||
</label>
|
||||
</div>
|
||||
<label class="field">
|
||||
<span>{T.tags}</span>
|
||||
<input bind:value={tagsText} placeholder={T.tagsPlaceholder} />
|
||||
<span>{$_('augur.form.tags')}</span>
|
||||
<input bind:value={tagsText} placeholder={$_('augur.form.tagsPlaceholder')} />
|
||||
</label>
|
||||
</details>
|
||||
|
||||
<div class="actions">
|
||||
{#if onclose}
|
||||
<button type="button" class="btn ghost" onclick={() => onclose?.()} disabled={saving}>
|
||||
{T.cancel}
|
||||
{$_('augur.form.cancel')}
|
||||
</button>
|
||||
{/if}
|
||||
<button type="submit" class="btn primary" disabled={saving}>
|
||||
{mode === 'edit' ? T.submitUpdate : T.submitCreate}
|
||||
{mode === 'edit' ? $_('augur.form.submitUpdate') : $_('augur.form.submitCreate')}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
*at the time*, alongside what actually happened.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { _ } from 'svelte-i18n';
|
||||
import {
|
||||
findMatches,
|
||||
fingerprint,
|
||||
|
|
@ -50,15 +51,6 @@
|
|||
|
||||
let props: Props = $props();
|
||||
|
||||
const T = {
|
||||
title: 'Was deine Daten zurueck sagen',
|
||||
titleSnapshot: 'Was das Orakel damals sagte',
|
||||
matchCount: 'aehnliche Zeichen',
|
||||
hit: 'eingetreten',
|
||||
partly: 'teilweise',
|
||||
no: 'nicht eingetreten',
|
||||
} as const;
|
||||
|
||||
const liveResult = $derived.by(() => {
|
||||
if (props.mode === 'snapshot') return null;
|
||||
const fp: Fingerprint | null = fingerprint(props.input);
|
||||
|
|
@ -80,7 +72,7 @@
|
|||
<aside class="hint snapshot">
|
||||
<header>
|
||||
<span class="dot"></span>
|
||||
<span class="title">{T.titleSnapshot}</span>
|
||||
<span class="title">{$_('augur.oracleHint.titleSnapshot')}</span>
|
||||
</header>
|
||||
<p class="text">{props.snapshot}</p>
|
||||
</aside>
|
||||
|
|
@ -89,18 +81,30 @@
|
|||
<aside class="hint live">
|
||||
<header>
|
||||
<span class="dot"></span>
|
||||
<span class="title">{T.title}</span>
|
||||
<span class="title">{$_('augur.oracleHint.titleLive')}</span>
|
||||
</header>
|
||||
<p class="text">{liveResult.text}</p>
|
||||
<div class="bars">
|
||||
{#if liveResult.set.fulfilled > 0}
|
||||
<span class="bar yes" style:flex={liveResult.set.fulfilled} title={T.hit}></span>
|
||||
<span
|
||||
class="bar yes"
|
||||
style:flex={liveResult.set.fulfilled}
|
||||
title={$_('augur.oracleHint.hit')}
|
||||
></span>
|
||||
{/if}
|
||||
{#if liveResult.set.partly > 0}
|
||||
<span class="bar partly" style:flex={liveResult.set.partly} title={T.partly}></span>
|
||||
<span
|
||||
class="bar partly"
|
||||
style:flex={liveResult.set.partly}
|
||||
title={$_('augur.oracleHint.partly')}
|
||||
></span>
|
||||
{/if}
|
||||
{#if liveResult.set.notFulfilled > 0}
|
||||
<span class="bar no" style:flex={liveResult.set.notFulfilled} title={T.no}></span>
|
||||
<span
|
||||
class="bar no"
|
||||
style:flex={liveResult.set.notFulfilled}
|
||||
title={$_('augur.oracleHint.no')}
|
||||
></span>
|
||||
{/if}
|
||||
</div>
|
||||
</aside>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
needs the mood/sleep query layer pulled in. Not in this PR.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { useAllAugurEntries } from '../queries';
|
||||
import {
|
||||
calibrationPerSource,
|
||||
|
|
@ -26,43 +27,8 @@
|
|||
import { useMoodByDate, useSleepByDate } from '../lib/signal-bridge.svelte';
|
||||
import { KIND_LABELS, SOURCE_CATEGORY_LABELS, VIBE_LABELS, VIBE_COLORS } from '../types';
|
||||
|
||||
const T = {
|
||||
title: 'Oracle',
|
||||
subtitle: 'Was deine Daten zurueck sagen.',
|
||||
coldStart: 'Noch zu wenig aufgeloeste Zeichen.',
|
||||
coldStartHint: 'Sammle und loese mindestens',
|
||||
coldStartUnit: 'Zeichen auf, dann zeigt das Orakel verlaessliche Zahlen.',
|
||||
statTotal: 'gesammelt',
|
||||
statResolved: 'aufgeloest',
|
||||
statOpen: 'offen',
|
||||
statHitRate: 'Trefferquote',
|
||||
statBrier: 'Brier-Score',
|
||||
statBrierBaseline: 'Baseline 0.25 (50/50)',
|
||||
sourceTitle: 'Forecaster in deinem Leben',
|
||||
sourceSub: 'Wer / was war wie oft richtig?',
|
||||
sourceCol: 'Quelle',
|
||||
sourceN: 'n',
|
||||
sourceHit: 'Treffer',
|
||||
sourceBrier: 'Brier',
|
||||
sourceMix: 'Verteilung',
|
||||
vibeTitle: 'Stimmt dein Bauchgefuehl?',
|
||||
vibeSub: 'Treffer pro Stimmung — gut, raetselhaft, schlecht.',
|
||||
vibeNoData: 'noch keine Daten',
|
||||
vibeHit: 'Treffer',
|
||||
vibeDir: 'Richtung',
|
||||
brierUnknown: '–',
|
||||
corrTitle: 'Was um deine Zeichen herum passiert',
|
||||
corrSub: 'Korrelation, nicht Kausalitaet — gefunden in deinen eigenen Daten.',
|
||||
corrEmpty:
|
||||
'Noch keine belastbaren Muster. Logge weiter — Mood und Sleep werden dazu gerechnet.',
|
||||
corrAfter: 'In den 3 Tagen danach',
|
||||
corrMoodLevel: 'lag dein Mood-Level bei',
|
||||
corrSleepQuality: 'lag deine Schlaf-Qualitaet bei',
|
||||
corrSleepDuration: 'lag deine Schlafdauer bei',
|
||||
corrVsBaseline: 'Baseline:',
|
||||
corrUnits: { min: 'min', score: '/10', score5: '/5' },
|
||||
yearRecapLink: 'Jahresrueckblick →',
|
||||
} as const;
|
||||
// Metric units stay as constants — they're not translated, just symbolic.
|
||||
const METRIC_UNITS = { min: 'min', score: '/10', score5: '/5' } as const;
|
||||
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
|
|
@ -82,22 +48,22 @@
|
|||
function metricLabel(f: CorrelationFinding): string {
|
||||
switch (f.metric) {
|
||||
case 'mood-level':
|
||||
return T.corrMoodLevel;
|
||||
return $_('augur.oracle.corrMoodLevel');
|
||||
case 'sleep-quality':
|
||||
return T.corrSleepQuality;
|
||||
return $_('augur.oracle.corrSleepQuality');
|
||||
case 'sleep-duration':
|
||||
return T.corrSleepDuration;
|
||||
return $_('augur.oracle.corrSleepDuration');
|
||||
}
|
||||
}
|
||||
|
||||
function metricUnit(f: CorrelationFinding): string {
|
||||
switch (f.metric) {
|
||||
case 'mood-level':
|
||||
return T.corrUnits.score;
|
||||
return METRIC_UNITS.score;
|
||||
case 'sleep-quality':
|
||||
return T.corrUnits.score5;
|
||||
return METRIC_UNITS.score5;
|
||||
case 'sleep-duration':
|
||||
return T.corrUnits.min;
|
||||
return METRIC_UNITS.min;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,12 +83,12 @@
|
|||
}
|
||||
|
||||
function pct(value: number | null): string {
|
||||
if (value == null) return T.brierUnknown;
|
||||
if (value == null) return $_('augur.common.brierUnknown');
|
||||
return `${Math.round(value * 100)}%`;
|
||||
}
|
||||
|
||||
function brier(value: number | null): string {
|
||||
if (value == null) return T.brierUnknown;
|
||||
if (value == null) return $_('augur.common.brierUnknown');
|
||||
return value.toFixed(3);
|
||||
}
|
||||
|
||||
|
|
@ -132,42 +98,42 @@
|
|||
<div class="oracle">
|
||||
<header class="head">
|
||||
<div>
|
||||
<h2>{T.title}</h2>
|
||||
<p class="sub">{T.subtitle}</p>
|
||||
<h2>{$_('augur.oracle.title')}</h2>
|
||||
<p class="sub">{$_('augur.oracle.subtitle')}</p>
|
||||
</div>
|
||||
<a class="recap-link" href="/augur/recap/{currentYear}">{T.yearRecapLink}</a>
|
||||
<a class="recap-link" href="/augur/recap/{currentYear}">{$_('augur.oracle.yearRecapLink')}</a>
|
||||
</header>
|
||||
|
||||
<section class="stats">
|
||||
<div class="stat">
|
||||
<span class="stat-num">{stats.total}</span>
|
||||
<span class="stat-label">{T.statTotal}</span>
|
||||
<span class="stat-label">{$_('augur.oracle.statTotal')}</span>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="stat-num">{stats.resolved}</span>
|
||||
<span class="stat-label">{T.statResolved}</span>
|
||||
<span class="stat-label">{$_('augur.oracle.statResolved')}</span>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="stat-num">{stats.open}</span>
|
||||
<span class="stat-label">{T.statOpen}</span>
|
||||
<span class="stat-label">{$_('augur.oracle.statOpen')}</span>
|
||||
</div>
|
||||
<div class="stat highlight">
|
||||
<span class="stat-num">{pct(stats.hitRate)}</span>
|
||||
<span class="stat-label">{T.statHitRate}</span>
|
||||
<span class="stat-label">{$_('augur.oracle.statHitRate')}</span>
|
||||
</div>
|
||||
<div class="stat" title={T.statBrierBaseline}>
|
||||
<div class="stat" title={$_('augur.oracle.statBrierBaseline')}>
|
||||
<span class="stat-num">{brier(stats.brier)}</span>
|
||||
<span class="stat-label">{T.statBrier} ({stats.brierN})</span>
|
||||
<span class="stat-label">{$_('augur.oracle.statBrier')} ({stats.brierN})</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{#if isColdStart}
|
||||
<section class="cold-start">
|
||||
<p>{T.coldStart}</p>
|
||||
<p>{$_('augur.oracle.coldStart')}</p>
|
||||
<p class="hint">
|
||||
{T.coldStartHint}
|
||||
{$_('augur.oracle.coldStartHint')}
|
||||
<strong>{ORACLE_COLD_START_MIN}</strong>
|
||||
{T.coldStartUnit}
|
||||
{$_('augur.oracle.coldStartUnit')}
|
||||
</p>
|
||||
<div class="progress">
|
||||
<div
|
||||
|
|
@ -179,20 +145,20 @@
|
|||
{:else}
|
||||
<section class="block">
|
||||
<header class="block-head">
|
||||
<h3>{T.sourceTitle}</h3>
|
||||
<p>{T.sourceSub}</p>
|
||||
<h3>{$_('augur.oracle.sourceTitle')}</h3>
|
||||
<p>{$_('augur.oracle.sourceSub')}</p>
|
||||
</header>
|
||||
{#if sourceRows.length === 0}
|
||||
<p class="empty">{T.vibeNoData}</p>
|
||||
<p class="empty">{$_('augur.oracle.vibeNoData')}</p>
|
||||
{:else}
|
||||
<table class="ranked">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{T.sourceCol}</th>
|
||||
<th class="num">{T.sourceN}</th>
|
||||
<th class="num">{T.sourceHit}</th>
|
||||
<th class="num">{T.sourceBrier}</th>
|
||||
<th class="mix">{T.sourceMix}</th>
|
||||
<th>{$_('augur.oracle.sourceCol')}</th>
|
||||
<th class="num">{$_('augur.oracle.sourceN')}</th>
|
||||
<th class="num">{$_('augur.oracle.sourceHit')}</th>
|
||||
<th class="num">{$_('augur.oracle.sourceBrier')}</th>
|
||||
<th class="mix">{$_('augur.oracle.sourceMix')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -229,11 +195,11 @@
|
|||
|
||||
<section class="block">
|
||||
<header class="block-head">
|
||||
<h3>{T.corrTitle}</h3>
|
||||
<p>{T.corrSub}</p>
|
||||
<h3>{$_('augur.oracle.corrTitle')}</h3>
|
||||
<p>{$_('augur.oracle.corrSub')}</p>
|
||||
</header>
|
||||
{#if correlations.length === 0}
|
||||
<p class="empty">{T.corrEmpty}</p>
|
||||
<p class="empty">{$_('augur.oracle.corrEmpty')}</p>
|
||||
{:else}
|
||||
<ul class="corr-list">
|
||||
{#each correlations.slice(0, 6) as f (f.dimension + f.bucket + f.metric + f.windowDays)}
|
||||
|
|
@ -247,10 +213,10 @@
|
|||
<span class="corr-n">n={f.n}</span>
|
||||
</div>
|
||||
<p class="corr-text">
|
||||
{T.corrAfter}
|
||||
{$_('augur.oracle.corrAfter')}
|
||||
{bucketLabel(f).toLowerCase()}-Zeichen {metricLabel(f)}
|
||||
<strong>{fmt(f.bucketMean, f.metric)}{metricUnit(f)}</strong>
|
||||
— {T.corrVsBaseline}
|
||||
— {$_('augur.oracle.corrVsBaseline')}
|
||||
{fmt(f.baseline, f.metric)}{metricUnit(f)}.
|
||||
</p>
|
||||
</li>
|
||||
|
|
@ -261,21 +227,21 @@
|
|||
|
||||
<section class="block">
|
||||
<header class="block-head">
|
||||
<h3>{T.vibeTitle}</h3>
|
||||
<p>{T.vibeSub}</p>
|
||||
<h3>{$_('augur.oracle.vibeTitle')}</h3>
|
||||
<p>{$_('augur.oracle.vibeSub')}</p>
|
||||
</header>
|
||||
<div class="vibe-grid">
|
||||
{#each vibeRows as row (row.vibe)}
|
||||
<div class="vibe-card" style:--vibe-color={VIBE_COLORS[row.vibe]}>
|
||||
<div class="vibe-label">{VIBE_LABELS[row.vibe].de}</div>
|
||||
{#if row.n === 0}
|
||||
<div class="vibe-empty">{T.vibeNoData}</div>
|
||||
<div class="vibe-empty">{$_('augur.oracle.vibeNoData')}</div>
|
||||
{:else}
|
||||
<div class="vibe-rate">{pct(row.hitRate)}</div>
|
||||
<div class="vibe-meta">{T.vibeHit} (n={row.n})</div>
|
||||
<div class="vibe-meta">{$_('augur.oracle.vibeHit')} (n={row.n})</div>
|
||||
{#if row.directionalHitRate != null}
|
||||
<div class="vibe-rate small">{pct(row.directionalHitRate)}</div>
|
||||
<div class="vibe-meta">{T.vibeDir}</div>
|
||||
<div class="vibe-meta">{$_('augur.oracle.vibeDir')}</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
-->
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import KindTabs from '../components/KindTabs.svelte';
|
||||
import EntryCard from '../components/EntryCard.svelte';
|
||||
import EntryForm from '../components/EntryForm.svelte';
|
||||
|
|
@ -22,17 +23,6 @@
|
|||
import { isDue } from '../lib/reminders';
|
||||
import type { AugurEntry, AugurKind } from '../types';
|
||||
|
||||
const T = {
|
||||
searchPlaceholder: 'Suche nach Quelle, Aussage, Deutung ...',
|
||||
newOpen: '+ neu',
|
||||
newClose: '× schliessen',
|
||||
emptyAll: 'Noch keine Zeichen erfasst. Sammle erst — auswerten kommt spaeter.',
|
||||
emptyFiltered: 'Keine passenden Zeichen.',
|
||||
openOnly: 'nur offene',
|
||||
dueOnly: 'nur faellige',
|
||||
openHint: 'noch offen',
|
||||
} as const;
|
||||
|
||||
let entries$ = useAllAugurEntries();
|
||||
let entries = $derived(entries$.value);
|
||||
|
||||
|
|
@ -75,7 +65,7 @@
|
|||
type="search"
|
||||
class="search"
|
||||
bind:value={searchQuery}
|
||||
placeholder={T.searchPlaceholder}
|
||||
placeholder={$_('augur.witness.searchPlaceholder')}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
|
|
@ -84,7 +74,7 @@
|
|||
onclick={() => (showCreate = !showCreate)}
|
||||
aria-expanded={showCreate}
|
||||
>
|
||||
{showCreate ? T.newClose : T.newOpen}
|
||||
{showCreate ? $_('augur.witness.newClose') : $_('augur.witness.newOpen')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
@ -99,14 +89,14 @@
|
|||
<div class="filter-row">
|
||||
<label class="open-toggle">
|
||||
<input type="checkbox" bind:checked={showOpenOnly} />
|
||||
<span>{T.openOnly}</span>
|
||||
<span>{$_('augur.witness.openOnly')}</span>
|
||||
{#if unresolvedCount > 0}
|
||||
<span class="badge open">{unresolvedCount} {T.openHint}</span>
|
||||
<span class="badge open">{unresolvedCount} {$_('augur.witness.openHint')}</span>
|
||||
{/if}
|
||||
</label>
|
||||
<label class="open-toggle">
|
||||
<input type="checkbox" bind:checked={showDueOnly} />
|
||||
<span>{T.dueOnly}</span>
|
||||
<span>{$_('augur.witness.dueOnly')}</span>
|
||||
{#if dueEntries.length > 0}
|
||||
<span class="badge due">{dueEntries.length}</span>
|
||||
{/if}
|
||||
|
|
@ -116,7 +106,7 @@
|
|||
|
||||
{#if filtered.length === 0}
|
||||
<p class="empty">
|
||||
{entries.length === 0 ? T.emptyAll : T.emptyFiltered}
|
||||
{entries.length === 0 ? $_('augur.witness.emptyAll') : $_('augur.witness.emptyFiltered')}
|
||||
</p>
|
||||
{:else}
|
||||
<ul class="grid">
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
-->
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { useAllAugurEntries } from '../queries';
|
||||
import { buildYearRecap } from '../lib/year-recap';
|
||||
import {
|
||||
|
|
@ -29,31 +30,12 @@
|
|||
|
||||
let { year }: { year: number } = $props();
|
||||
|
||||
const T = {
|
||||
title: 'Jahresrueckblick',
|
||||
yearTotal: 'Zeichen',
|
||||
yearResolved: 'aufgeloest',
|
||||
yearHitRate: 'Trefferquote',
|
||||
emptyYear: 'In diesem Jahr noch keine Zeichen erfasst.',
|
||||
distKind: 'Nach Art',
|
||||
distVibe: 'Nach Stimmung',
|
||||
distOutcome: 'Nach Ergebnis',
|
||||
bestSource: 'Bester Forecaster',
|
||||
worstSource: 'Unzuverlaessigster Forecaster',
|
||||
topSources: 'Meistgenutzte Quellen',
|
||||
mostFulfilled: 'Eingetretene Zeichen',
|
||||
mostSurprising: 'Ueberraschungen — wo dein Gefuehl danebenlag',
|
||||
none: '—',
|
||||
hitOf: 'von',
|
||||
matches: 'Treffer',
|
||||
} as const;
|
||||
|
||||
const entries$ = useAllAugurEntries();
|
||||
const entries = $derived(entries$.value);
|
||||
const recap = $derived(buildYearRecap(entries, year));
|
||||
|
||||
function pct(v: number | null): string {
|
||||
if (v == null) return T.none;
|
||||
if (v == null) return $_('augur.recap.none');
|
||||
return `${Math.round(v * 100)}%`;
|
||||
}
|
||||
|
||||
|
|
@ -65,30 +47,30 @@
|
|||
<div class="recap">
|
||||
<header class="head">
|
||||
<div class="year">{year}</div>
|
||||
<h2>{T.title}</h2>
|
||||
<h2>{$_('augur.recap.title')}</h2>
|
||||
</header>
|
||||
|
||||
{#if recap.total === 0}
|
||||
<p class="empty">{T.emptyYear}</p>
|
||||
<p class="empty">{$_('augur.recap.emptyYear')}</p>
|
||||
{:else}
|
||||
<section class="headline">
|
||||
<div class="big-stat">
|
||||
<span class="num">{recap.total}</span>
|
||||
<span class="lbl">{T.yearTotal}</span>
|
||||
<span class="lbl">{$_('augur.recap.yearTotal')}</span>
|
||||
</div>
|
||||
<div class="big-stat">
|
||||
<span class="num">{recap.resolved}</span>
|
||||
<span class="lbl">{T.yearResolved}</span>
|
||||
<span class="lbl">{$_('augur.recap.yearResolved')}</span>
|
||||
</div>
|
||||
<div class="big-stat highlight">
|
||||
<span class="num">{pct(recap.hitRate)}</span>
|
||||
<span class="lbl">{T.yearHitRate}</span>
|
||||
<span class="lbl">{$_('augur.recap.yearHitRate')}</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="dist-row">
|
||||
<div class="dist">
|
||||
<h4>{T.distKind}</h4>
|
||||
<h4>{$_('augur.recap.distKind')}</h4>
|
||||
<ul>
|
||||
{#each Object.entries(recap.byKind) as [k, n] (k)}
|
||||
<li>
|
||||
|
|
@ -99,7 +81,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class="dist">
|
||||
<h4>{T.distVibe}</h4>
|
||||
<h4>{$_('augur.recap.distVibe')}</h4>
|
||||
<ul>
|
||||
{#each Object.entries(recap.byVibe) as [v, n] (v)}
|
||||
<li>
|
||||
|
|
@ -112,7 +94,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class="dist">
|
||||
<h4>{T.distOutcome}</h4>
|
||||
<h4>{$_('augur.recap.distOutcome')}</h4>
|
||||
<ul>
|
||||
{#each Object.entries(recap.byOutcome) as [o, n] (o)}
|
||||
<li>
|
||||
|
|
@ -126,34 +108,42 @@
|
|||
|
||||
<section class="forecaster-row">
|
||||
<div class="forecaster best">
|
||||
<h4>{T.bestSource}</h4>
|
||||
<h4>{$_('augur.recap.bestSource')}</h4>
|
||||
{#if recap.bestSource}
|
||||
<div class="fc-name">
|
||||
{SOURCE_CATEGORY_LABELS[recap.bestSource.sourceCategory].de}
|
||||
</div>
|
||||
<div class="fc-num">{pct(recap.bestSource.hitRate)}</div>
|
||||
<div class="fc-meta">{recap.bestSource.fulfilled} {T.hitOf} {recap.bestSource.n}</div>
|
||||
<div class="fc-meta">
|
||||
{recap.bestSource.fulfilled}
|
||||
{$_('augur.recap.hitOf')}
|
||||
{recap.bestSource.n}
|
||||
</div>
|
||||
{:else}
|
||||
<p class="fc-empty">{T.none}</p>
|
||||
<p class="fc-empty">{$_('augur.recap.none')}</p>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="forecaster worst">
|
||||
<h4>{T.worstSource}</h4>
|
||||
<h4>{$_('augur.recap.worstSource')}</h4>
|
||||
{#if recap.worstSource}
|
||||
<div class="fc-name">
|
||||
{SOURCE_CATEGORY_LABELS[recap.worstSource.sourceCategory].de}
|
||||
</div>
|
||||
<div class="fc-num">{pct(recap.worstSource.hitRate)}</div>
|
||||
<div class="fc-meta">{recap.worstSource.fulfilled} {T.hitOf} {recap.worstSource.n}</div>
|
||||
<div class="fc-meta">
|
||||
{recap.worstSource.fulfilled}
|
||||
{$_('augur.recap.hitOf')}
|
||||
{recap.worstSource.n}
|
||||
</div>
|
||||
{:else}
|
||||
<p class="fc-empty">{T.none}</p>
|
||||
<p class="fc-empty">{$_('augur.recap.none')}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{#if recap.topCategories.length > 0}
|
||||
<section class="block">
|
||||
<h3>{T.topSources}</h3>
|
||||
<h3>{$_('augur.recap.topSources')}</h3>
|
||||
<ul class="ranked-list">
|
||||
{#each recap.topCategories as cat (cat.category)}
|
||||
<li>
|
||||
|
|
@ -173,7 +163,7 @@
|
|||
|
||||
{#if recap.mostFulfilled.length > 0}
|
||||
<section class="block">
|
||||
<h3>{T.mostFulfilled}</h3>
|
||||
<h3>{$_('augur.recap.mostFulfilled')}</h3>
|
||||
<div class="card-grid">
|
||||
{#each recap.mostFulfilled as entry (entry.id)}
|
||||
<EntryCard {entry} onclick={openEntry} />
|
||||
|
|
@ -184,7 +174,7 @@
|
|||
|
||||
{#if recap.mostSurprising.length > 0}
|
||||
<section class="block">
|
||||
<h3>{T.mostSurprising}</h3>
|
||||
<h3>{$_('augur.recap.mostSurprising')}</h3>
|
||||
<div class="card-grid">
|
||||
{#each recap.mostSurprising as entry (entry.id)}
|
||||
<EntryCard {entry} onclick={openEntry} />
|
||||
|
|
|
|||
|
|
@ -1,32 +1,25 @@
|
|||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import DetailView from '$lib/modules/augur/views/DetailView.svelte';
|
||||
import { useAllAugurEntries } from '$lib/modules/augur/queries';
|
||||
import { RoutePage } from '$lib/components/shell';
|
||||
|
||||
const entries$ = useAllAugurEntries();
|
||||
const entry = $derived(entries$.value.find((e) => e.id === page.params.id));
|
||||
|
||||
const T = {
|
||||
fallbackTitle: 'Augur',
|
||||
routeTitle: 'Zeichen',
|
||||
loading: 'laedt ...',
|
||||
notFound: 'Eintrag nicht gefunden.',
|
||||
backLink: '← zurueck',
|
||||
} as const;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{entry?.source ?? T.fallbackTitle} - Mana</title>
|
||||
<title>{entry?.source ?? $_('augur.route.detailFallbackTitle')} - Mana</title>
|
||||
</svelte:head>
|
||||
|
||||
<RoutePage appId="augur" backHref="/augur" title={T.routeTitle}>
|
||||
<RoutePage appId="augur" backHref="/augur" title={$_('augur.route.detailRouteTitle')}>
|
||||
{#if entries$.loading}
|
||||
<p class="state">{T.loading}</p>
|
||||
<p class="state">{$_('augur.route.loading')}</p>
|
||||
{:else if !entry}
|
||||
<div class="state">
|
||||
<p>{T.notFound}</p>
|
||||
<a href="/augur">{T.backLink}</a>
|
||||
<p>{$_('augur.route.notFound')}</p>
|
||||
<a href="/augur">{$_('augur.route.backLink')}</a>
|
||||
</div>
|
||||
{:else}
|
||||
<DetailView {entry} />
|
||||
|
|
|
|||
|
|
@ -1,14 +1,9 @@
|
|||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import YearRecapView from '$lib/modules/augur/views/YearRecapView.svelte';
|
||||
import { RoutePage } from '$lib/components/shell';
|
||||
|
||||
const T = {
|
||||
title: 'Jahresrueckblick',
|
||||
invalid: 'Ungueltiges Jahr.',
|
||||
back: '← zurueck',
|
||||
} as const;
|
||||
|
||||
const year = $derived.by(() => {
|
||||
const raw = page.params.year;
|
||||
if (!raw) return null;
|
||||
|
|
@ -19,14 +14,14 @@
|
|||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{year ?? T.title} - Augur - Mana</title>
|
||||
<title>{year ?? $_('augur.recap.title')} - Augur - Mana</title>
|
||||
</svelte:head>
|
||||
|
||||
<RoutePage appId="augur" backHref="/augur?mode=oracle" title={T.title}>
|
||||
<RoutePage appId="augur" backHref="/augur?mode=oracle" title={$_('augur.recap.title')}>
|
||||
{#if year == null}
|
||||
<div class="state">
|
||||
<p>{T.invalid}</p>
|
||||
<a href="/augur">{T.back}</a>
|
||||
<p>{$_('augur.route.recapInvalid')}</p>
|
||||
<a href="/augur">{$_('augur.route.recapBack')}</a>
|
||||
</div>
|
||||
{:else}
|
||||
<YearRecapView {year} />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue