From f5e992daad49b9415228b67a81dd00d91f05466c Mon Sep 17 00:00:00 2001 From: heaven Date: Wed, 13 May 2026 23:30:52 +0300 Subject: [PATCH] fix(time): use Intl numeric day-month-year everywhere so chat day dividers follow the system locale instead of hardcoded English full-month --- src/app/components/room-intro/RoomIntro.tsx | 4 ++-- src/app/features/room/RoomTimeline.tsx | 4 ++-- .../features/room/jump-to-time/JumpToTime.tsx | 4 ++-- src/app/utils/time.ts | 21 +++++++++++++------ 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/app/components/room-intro/RoomIntro.tsx b/src/app/components/room-intro/RoomIntro.tsx index 4de2a67e..ab62dbcc 100644 --- a/src/app/components/room-intro/RoomIntro.tsx +++ b/src/app/components/room-intro/RoomIntro.tsx @@ -7,7 +7,7 @@ import { getMemberDisplayName, getStateEvent } from '../../utils/room'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix'; import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback'; -import { timeDayMonthYear, timeHourMinute } from '../../utils/time'; +import { timeDayMonYear, timeHourMinute } from '../../utils/time'; import { useRoomNavigate } from '../../hooks/useRoomNavigate'; import { RoomAvatar } from '../room-avatar'; import { nameInitials } from '../../utils/common'; @@ -75,7 +75,7 @@ export const RoomIntro = as<'div', RoomIntroProps>(({ room, ...props }, ref) => i18nKey="Room.created_by" values={{ creator: creatorName, - date: timeDayMonthYear(ts), + date: timeDayMonYear(ts), time: timeHourMinute(ts), }} components={{ bold: }} diff --git a/src/app/features/room/RoomTimeline.tsx b/src/app/features/room/RoomTimeline.tsx index 34d970ba..9f5f2f83 100644 --- a/src/app/features/room/RoomTimeline.tsx +++ b/src/app/features/room/RoomTimeline.tsx @@ -105,7 +105,7 @@ import { markAsRead } from '../../utils/notifications'; import { useDebounce } from '../../hooks/useDebounce'; import { getResizeObserverEntry, useResizeObserver } from '../../hooks/useResizeObserver'; import * as css from './RoomTimeline.css'; -import { inSameDay, minuteDifference, timeDayMonthYear, today, yesterday } from '../../utils/time'; +import { inSameDay, minuteDifference, timeDayMonYear, today, yesterday } from '../../utils/time'; import { isEmptyEditor } from '../../components/editor'; import { draftKey, roomIdToReplyDraftAtomFamily } from '../../state/room/roomInputDrafts'; import { usePowerLevelsContext } from '../../hooks/usePowerLevels'; @@ -2211,7 +2211,7 @@ export function RoomTimeline({ const dayLabel = (() => { if (today(mEvent.getTs())) return t('Room.today'); if (yesterday(mEvent.getTs())) return t('Room.yesterday'); - return timeDayMonthYear(mEvent.getTs()); + return timeDayMonYear(mEvent.getTs()); })(); const renderDayDivider = () => ( diff --git a/src/app/features/room/jump-to-time/JumpToTime.tsx b/src/app/features/room/jump-to-time/JumpToTime.tsx index 7caf6312..e8677a92 100644 --- a/src/app/features/room/jump-to-time/JumpToTime.tsx +++ b/src/app/features/room/jump-to-time/JumpToTime.tsx @@ -28,7 +28,7 @@ import { useAlive } from '../../../hooks/useAlive'; import { useStateEvent } from '../../../hooks/useStateEvent'; import { useRoom } from '../../../hooks/useRoom'; import { StateEvent } from '../../../../types/matrix/room'; -import { getToday, getYesterday, timeDayMonthYear, timeHourMinute } from '../../../utils/time'; +import { getToday, getYesterday, timeDayMonYear, timeHourMinute } from '../../../utils/time'; import { DatePicker, TimePicker } from '../../../components/time-date'; type JumpToTimeProps = { @@ -168,7 +168,7 @@ export function JumpToTime({ onCancel, onSubmit }: JumpToTimeProps) { after={} onClick={handleDatePicker} > - {timeDayMonthYear(ts)} + {timeDayMonYear(ts)} { export const SYSTEM_HOUR_24: boolean = detectSystemHour24(); -// 24-hour systems get the European day-month-year layout; 12-hour systems get -// the American month-day-year layout. -const SYSTEM_DAY_MON_YEAR_FORMAT = SYSTEM_HOUR_24 ? 'DD/MM/YYYY' : 'MM/DD/YYYY'; +// Locale picks its own day-month-year order and separator: de-DE/ru-RU yield +// "13.05.2026", en-GB "13/05/2026", en-US "05/13/2026". Built once at module +// load — locale doesn't change without a page reload. +const dayMonYearFormatter: Pick = (() => { + try { + return new Intl.DateTimeFormat(undefined, { + day: '2-digit', + month: '2-digit', + year: 'numeric', + }); + } catch { + return { format: (date: Date) => dayjs(date).format('DD.MM.YYYY') }; + } +})(); export const today = (ts: number): boolean => dayjs(ts).isToday(); @@ -45,9 +56,7 @@ export const timeYear = (ts: number): string => dayjs(ts).format('YYYY'); export const timeHourMinute = (ts: number): string => dayjs(ts).format(SYSTEM_HOUR_24 ? 'HH:mm' : 'hh:mm A'); -export const timeDayMonYear = (ts: number): string => dayjs(ts).format(SYSTEM_DAY_MON_YEAR_FORMAT); - -export const timeDayMonthYear = (ts: number): string => dayjs(ts).format('D MMMM YYYY'); +export const timeDayMonYear = (ts: number): string => dayMonYearFormatter.format(new Date(ts)); export const daysInMonth = (month: number, year: number): number => dayjs(`${year}-${month}-1`).daysInMonth();