F8: Date formatting uses Intl per app language

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 <noreply@anthropic.com>
This commit is contained in:
David 2026-07-09 15:41:51 +02:00
parent e3847edae1
commit 166cf87e95
2 changed files with 45 additions and 23 deletions

View file

@ -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)
}

View file

@ -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)