From 166cf87e95354d698ea8b3775d25209b8ca129fe Mon Sep 17 00:00:00 2001 From: kaivalya Date: Thu, 9 Jul 2026 15:41:51 +0200 Subject: [PATCH] F8: Date formatting uses Intl per app language MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit formatDate special-cased only French, so Danish users saw US mm/dd/yyyy; formatDateTime mixed a manual French format with toLocaleString() (OS-locale dependent) for everyone else. Both now use Intl.DateTimeFormat with a fixed app-language -> BCP-47 map (en-US, fr-FR, da-DK — same mapping as useSpeech), 2-digit day/month so output stays deterministic per language: en 03/15/2026, fr 15/03/2026, da 15.03.2026. Adds a Danish format test. Co-Authored-By: Claude Fable 5 --- src/utils/dateFormatter.js | 45 +++++++++++++++++++------------------- tests/test_step9_stats.py | 23 +++++++++++++++++++ 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/utils/dateFormatter.js b/src/utils/dateFormatter.js index de99a9e..5d9d4fc 100644 --- a/src/utils/dateFormatter.js +++ b/src/utils/dateFormatter.js @@ -1,20 +1,24 @@ import i18next from 'i18next' +// App language → BCP-47 tag (same mapping as useSpeech.js). Fixed tags keep +// the output deterministic per app language regardless of the OS locale, so +// tests can assert it (en: 03/15/2026, fr: 15/03/2026, da: 15.03.2026). +const LANG_MAP = { en: 'en-US', fr: 'fr-FR', da: 'da-DK' } + +function toLangTag(lang) { + return LANG_MAP[lang || i18next.language] || LANG_MAP.en +} + export function formatDate(date, lang) { if (!date) return '' const d = date instanceof Date ? date : new Date(date) if (isNaN(d.getTime())) return '' - lang = lang || i18next.language || 'en' - const pad = (n) => String(n).padStart(2, '0') - const dd = pad(d.getDate()) - const mm = pad(d.getMonth() + 1) - const yyyy = d.getFullYear() - - if (lang === 'fr') { - return `${dd}/${mm}/${yyyy}` - } - return `${mm}/${dd}/${yyyy}` + return new Intl.DateTimeFormat(toLangTag(lang), { + day: '2-digit', + month: '2-digit', + year: 'numeric', + }).format(d) } export function formatItemDuration(ms) { @@ -46,17 +50,12 @@ export function formatDateTime(date, lang) { const d = date instanceof Date ? date : new Date(date) if (isNaN(d.getTime())) return '' - lang = lang || i18next.language || 'en' - const pad = (n) => String(n).padStart(2, '0') - const dd = pad(d.getDate()) - const mm = pad(d.getMonth() + 1) - const yyyy = d.getFullYear() - const HH = pad(d.getHours()) - const min = pad(d.getMinutes()) - const ss = pad(d.getSeconds()) - - if (lang === 'fr') { - return `${dd}/${mm}/${yyyy}, ${HH}:${min}:${ss}` - } - return d.toLocaleString() + return new Intl.DateTimeFormat(toLangTag(lang), { + day: '2-digit', + month: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + }).format(d) } diff --git a/tests/test_step9_stats.py b/tests/test_step9_stats.py index db8bddd..59ad34e 100644 --- a/tests/test_step9_stats.py +++ b/tests/test_step9_stats.py @@ -4,6 +4,7 @@ Step 9 — Statistics - test_stats_shows_empty_when_no_date: StatsView shows empty message when no creation date - test_stats_date_format_english: Date is formatted as MM/DD/YYYY in English - test_stats_date_format_french: Date is formatted as DD/MM/YYYY in French +- test_stats_date_format_danish: Date is formatted as DD.MM.YYYY in Danish - test_stats_date_format_updates_on_language_change: Switching language updates the date format reactively - test_stats_date_range_tabs_visible: All four date range tabs are rendered - test_stats_summary_cards_zero_when_no_data: Summary cards show 0 when no execution logs exist @@ -240,6 +241,28 @@ def test_stats_date_format_french(page: Page, app_url: str): page.wait_for_timeout(300) +def test_stats_date_format_danish(page: Page, app_url: str): + """Date is formatted as DD.MM.YYYY in Danish (not the US fallback).""" + _set_date_and_reload(page, app_url, _KNOWN_DATE) + + page.click('a[href="#/settings"]') + page.wait_for_url("**/#/settings", timeout=5000) + page.wait_for_selector('[data-testid="settings-language"]') + page.select_option('[data-testid="settings-language"]', 'da') + page.wait_for_timeout(500) + + _go_to_stats(page) + + text = page.locator('[data-testid="stats-using-since"]').text_content() + assert '15.03.2026' in text, f"Expected Danish date format, got: {text}" + + page.click('a[href="#/settings"]') + page.wait_for_url("**/#/settings", timeout=5000) + page.wait_for_selector('[data-testid="settings-language"]') + page.select_option('[data-testid="settings-language"]', 'en') + page.wait_for_timeout(300) + + def test_stats_date_format_updates_on_language_change(page: Page, app_url: str): """Switching language updates the date format reactively without navigation.""" _set_date_and_reload(page, app_url, _KNOWN_DATE)