mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-16 12:59:39 +02:00
refactor(cycles): make date formatting locale-aware
Replace hardcoded 'de-DE' toLocaleDateString calls across ListView,
CyclesWidget, and pure helpers with the active svelte-i18n locale.
Pure helpers in queries.ts now take their locale (and for relative
dates, their labels) as parameters so they stay pure and testable:
- formatLogDate(iso, labels, dateLocale)
- groupLogsByMonth(logs, dateLocale)
- New RelativeDateLabels type, exported from the module barrel
ListView builds relativeLabels from $_ and threads dateLocale through;
CyclesWidget does the same using a tiny $locale-derived helper.
New i18n keys cycles.relativeDate.{today,yesterday,daysAgo} across
all five locales (real de/en translations, stubs for it/fr/es).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1ba5948ce5
commit
343804b25c
9 changed files with 79 additions and 15 deletions
|
|
@ -57,6 +57,11 @@
|
|||
"nextPeriod": "Nächste Periode:",
|
||||
"fertileWindow": "Fruchtbares Fenster:"
|
||||
},
|
||||
"relativeDate": {
|
||||
"today": "Heute",
|
||||
"yesterday": "Gestern",
|
||||
"daysAgo": "vor {days} Tagen"
|
||||
},
|
||||
"empty": "Tippe oben auf eine Blutungsstärke, um deinen ersten Tag festzuhalten — oder starte direkt eine Periode.",
|
||||
"confirm": {
|
||||
"deleteEntry": "Tageseintrag vom {date} wirklich löschen?",
|
||||
|
|
|
|||
|
|
@ -57,6 +57,11 @@
|
|||
"nextPeriod": "Next period:",
|
||||
"fertileWindow": "Fertile window:"
|
||||
},
|
||||
"relativeDate": {
|
||||
"today": "Today",
|
||||
"yesterday": "Yesterday",
|
||||
"daysAgo": "{days} days ago"
|
||||
},
|
||||
"empty": "Tap a flow level above to log your first day — or start a period directly.",
|
||||
"confirm": {
|
||||
"deleteEntry": "Really delete the entry from {date}?",
|
||||
|
|
|
|||
|
|
@ -57,6 +57,11 @@
|
|||
"nextPeriod": "Next period:",
|
||||
"fertileWindow": "Fertile window:"
|
||||
},
|
||||
"relativeDate": {
|
||||
"today": "Today",
|
||||
"yesterday": "Yesterday",
|
||||
"daysAgo": "{days} days ago"
|
||||
},
|
||||
"empty": "Tap a flow level above to log your first day — or start a period directly.",
|
||||
"confirm": {
|
||||
"deleteEntry": "Really delete the entry from {date}?",
|
||||
|
|
|
|||
|
|
@ -57,6 +57,11 @@
|
|||
"nextPeriod": "Next period:",
|
||||
"fertileWindow": "Fertile window:"
|
||||
},
|
||||
"relativeDate": {
|
||||
"today": "Today",
|
||||
"yesterday": "Yesterday",
|
||||
"daysAgo": "{days} days ago"
|
||||
},
|
||||
"empty": "Tap a flow level above to log your first day — or start a period directly.",
|
||||
"confirm": {
|
||||
"deleteEntry": "Really delete the entry from {date}?",
|
||||
|
|
|
|||
|
|
@ -57,6 +57,11 @@
|
|||
"nextPeriod": "Next period:",
|
||||
"fertileWindow": "Fertile window:"
|
||||
},
|
||||
"relativeDate": {
|
||||
"today": "Today",
|
||||
"yesterday": "Yesterday",
|
||||
"daysAgo": "{days} days ago"
|
||||
},
|
||||
"empty": "Tap a flow level above to log your first day — or start a period directly.",
|
||||
"confirm": {
|
||||
"deleteEntry": "Really delete the entry from {date}?",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
* + Vorhersage pro Render ab. Linkt zur /cycles Route.
|
||||
*/
|
||||
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { _, locale } from 'svelte-i18n';
|
||||
import { liveQuery } from 'dexie';
|
||||
import { db } from '$lib/data/database';
|
||||
import { derivePhase, getCycleDayNumber } from '$lib/modules/cycles/utils/phase';
|
||||
|
|
@ -48,9 +48,14 @@
|
|||
const daysUntil = $derived(daysUntilNextPeriod(cycles));
|
||||
const nextPeriod = $derived(predictNextPeriodStart(cycles));
|
||||
|
||||
const dateLocale = $derived.by(() => {
|
||||
const l = $locale ?? 'de';
|
||||
return l === 'de' ? 'de-DE' : l;
|
||||
});
|
||||
|
||||
function formatShortDate(iso: string | null): string {
|
||||
if (!iso) return '—';
|
||||
return new Date(iso).toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit' });
|
||||
return new Date(iso).toLocaleDateString(dateLocale, { day: '2-digit', month: '2-digit' });
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@
|
|||
Aktueller Zyklus, heutiger Quick-Log, einfache Statistiken.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { _, locale } from 'svelte-i18n';
|
||||
import {
|
||||
formatLogDate,
|
||||
useAllCycles,
|
||||
useAllDayLogs,
|
||||
useAllSymptoms,
|
||||
useCurrentCycle,
|
||||
type RelativeDateLabels,
|
||||
} from './queries';
|
||||
import { cyclesStore } from './stores/cycles.svelte';
|
||||
import { dayLogsStore } from './stores/dayLogs.svelte';
|
||||
|
|
@ -40,6 +41,19 @@
|
|||
let symptoms = $derived(symptoms$.value);
|
||||
let currentCycle = $derived(current$.value);
|
||||
|
||||
// Locale-aware date formatting: use the active svelte-i18n locale, with
|
||||
// 'de-DE' as a fallback since the project defaults to German.
|
||||
const dateLocale = $derived.by(() => {
|
||||
const l = $locale ?? 'de';
|
||||
return l === 'de' ? 'de-DE' : l;
|
||||
});
|
||||
|
||||
const relativeLabels = $derived<RelativeDateLabels>({
|
||||
today: $_('cycles.relativeDate.today'),
|
||||
yesterday: $_('cycles.relativeDate.yesterday'),
|
||||
daysAgo: (n: number) => $_('cycles.relativeDate.daysAgo', { values: { days: n } }),
|
||||
});
|
||||
|
||||
let phase = $derived(derivePhase(todayIso, cycles));
|
||||
let cycleDay = $derived(currentCycle ? getCycleDayNumber(todayIso, currentCycle) : null);
|
||||
let stats = $derived(computeCycleStats(cycles));
|
||||
|
|
@ -115,7 +129,7 @@
|
|||
backToToday();
|
||||
return;
|
||||
}
|
||||
const dateStr = new Date(editingDate).toLocaleDateString('de-DE');
|
||||
const dateStr = new Date(editingDate).toLocaleDateString(dateLocale);
|
||||
const ok = confirm($_('cycles.confirm.deleteEntry', { values: { date: dateStr } }));
|
||||
if (!ok) return;
|
||||
await dayLogsStore.deleteLog(editingLog.id);
|
||||
|
|
@ -135,7 +149,7 @@
|
|||
|
||||
function formatDate(iso: string | null): string {
|
||||
if (!iso) return '—';
|
||||
return new Date(iso).toLocaleDateString('de-DE', {
|
||||
return new Date(iso).toLocaleDateString(dateLocale, {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
});
|
||||
|
|
@ -199,7 +213,7 @@
|
|||
<div class="edit-banner">
|
||||
<span class="edit-banner-label">
|
||||
{$_('cycles.label.editing')}
|
||||
<strong>{new Date(editingDate).toLocaleDateString('de-DE')}</strong>
|
||||
<strong>{new Date(editingDate).toLocaleDateString(dateLocale)}</strong>
|
||||
</span>
|
||||
<div class="edit-banner-actions">
|
||||
{#if editingLog}
|
||||
|
|
@ -347,7 +361,9 @@
|
|||
<span class="log-flow" style="background: {FLOW_COLORS[log.flow]}"></span>
|
||||
<div class="log-content">
|
||||
<div class="log-top">
|
||||
<span class="log-date">{formatLogDate(log.logDate)}</span>
|
||||
<span class="log-date"
|
||||
>{formatLogDate(log.logDate, relativeLabels, dateLocale)}</span
|
||||
>
|
||||
{#if log.flow !== 'none'}
|
||||
<span class="log-tag">{$_(`cycles.flow.${log.flow}`)}</span>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ export {
|
|||
groupLogsByMonth,
|
||||
formatLogDate,
|
||||
} from './queries';
|
||||
export type { RelativeDateLabels } from './queries';
|
||||
|
||||
// ─── Utils ───────────────────────────────────────────────
|
||||
export { derivePhase, findCycleForDate, getCycleDayNumber, daysBetween } from './utils/phase';
|
||||
|
|
|
|||
|
|
@ -122,14 +122,23 @@ export function useAllSymptoms() {
|
|||
|
||||
// ─── Pure Helpers ──────────────────────────────────────────
|
||||
|
||||
/** Group day logs by ISO month label. */
|
||||
/** Labels a caller must provide to formatLogDate so it can be locale-aware. */
|
||||
export interface RelativeDateLabels {
|
||||
today: string;
|
||||
yesterday: string;
|
||||
/** Template for "N days ago", receives the numeric count. */
|
||||
daysAgo: (days: number) => string;
|
||||
}
|
||||
|
||||
/** Group day logs by localized month label. */
|
||||
export function groupLogsByMonth(
|
||||
logs: CycleDayLog[]
|
||||
logs: CycleDayLog[],
|
||||
dateLocale: string = 'de-DE'
|
||||
): Array<{ label: string; logs: CycleDayLog[] }> {
|
||||
const groups = new Map<string, CycleDayLog[]>();
|
||||
for (const l of logs) {
|
||||
const date = new Date(l.logDate);
|
||||
const label = date.toLocaleDateString('de-DE', { month: 'long', year: 'numeric' });
|
||||
const label = date.toLocaleDateString(dateLocale, { month: 'long', year: 'numeric' });
|
||||
const bucket = groups.get(label) ?? [];
|
||||
bucket.push(l);
|
||||
groups.set(label, bucket);
|
||||
|
|
@ -137,12 +146,20 @@ export function groupLogsByMonth(
|
|||
return Array.from(groups, ([label, logs]) => ({ label, logs }));
|
||||
}
|
||||
|
||||
export function formatLogDate(iso: string): string {
|
||||
/**
|
||||
* Format a log date relative to today using caller-provided labels.
|
||||
* Falls back to absolute date formatting via `dateLocale` when >= 7 days ago.
|
||||
*/
|
||||
export function formatLogDate(
|
||||
iso: string,
|
||||
labels: RelativeDateLabels,
|
||||
dateLocale: string = 'de-DE'
|
||||
): string {
|
||||
const date = new Date(iso);
|
||||
const today = new Date();
|
||||
const diffDays = Math.floor((today.getTime() - date.getTime()) / 86_400_000);
|
||||
if (diffDays === 0) return 'Heute';
|
||||
if (diffDays === 1) return 'Gestern';
|
||||
if (diffDays < 7) return `vor ${diffDays} Tagen`;
|
||||
return date.toLocaleDateString('de-DE', { day: 'numeric', month: 'short', year: 'numeric' });
|
||||
if (diffDays === 0) return labels.today;
|
||||
if (diffDays === 1) return labels.yesterday;
|
||||
if (diffDays < 7) return labels.daysAgo(diffDays);
|
||||
return date.toLocaleDateString(dateLocale, { day: 'numeric', month: 'short', year: 'numeric' });
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue