Commit 7a11aee2975 for woocommerce

commit 7a11aee29755f5ad85546d5b99666c22dbc44a41
Author: Miroslav Mitev <m1r0@users.noreply.github.com>
Date:   Tue Sep 22 11:48:22 2026 +0300

    Fix Analytics calendar day labels reading out the wrong date (#68514)

diff --git a/packages/js/components/changelog/fix-calendar-day-aria-label-format b/packages/js/components/changelog/fix-calendar-day-aria-label-format
new file mode 100644
index 00000000000..0914207c2ec
--- /dev/null
+++ b/packages/js/components/changelog/fix-calendar-day-aria-label-format
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix the DateRange calendar labelling each day with the wrong date.
diff --git a/packages/js/components/src/calendar/date-range.js b/packages/js/components/src/calendar/date-range.js
index b1c39388a9f..e55f006092b 100644
--- a/packages/js/components/src/calendar/date-range.js
+++ b/packages/js/components/src/calendar/date-range.js
@@ -23,6 +23,18 @@ import DateInput from './input';
 import phrases from './phrases';

 const isRTL = () => document.documentElement.dir === 'rtl';
+
+// react-dates builds each day's aria-label with moment, defaulting to 'dddd, LL'.
+// WordPress seeds `LL` with the PHP `date_format` option, which moment misreads as its
+// own tokens, so use moment tokens here instead. Called at render time so the
+// translation is read after the locale data loads.
+const getDayAriaLabelFormat = () =>
+	__(
+		/* translators: Moment.js format for the date a screen reader reads out on a calendar day. Keep the moment tokens (dddd, MMMM, D, YYYY) and reorder them to suit the locale. */
+		'dddd, MMMM D, YYYY',
+		'woocommerce'
+	);
+
 // Blur event sources
 const CONTAINER_DIV = 'container';
 const NEXT_MONTH_CLICK = 'onNextMonthClick';
@@ -266,6 +278,7 @@ class DateRange extends Component {
 							before
 						) }
 						phrases={ phrases }
+						dayAriaLabelFormat={ getDayAriaLabelFormat() }
 					/>
 				</div>
 			</div>
diff --git a/packages/js/components/src/calendar/test/date-range.js b/packages/js/components/src/calendar/test/date-range.js
new file mode 100644
index 00000000000..8190dc02d3f
--- /dev/null
+++ b/packages/js/components/src/calendar/test/date-range.js
@@ -0,0 +1,101 @@
+/**
+ * External dependencies
+ */
+import { render } from '@testing-library/react';
+import { createElement } from '@wordpress/element';
+import { resetLocaleData, setLocaleData } from '@wordpress/i18n';
+import moment from 'moment';
+
+/**
+ * Internal dependencies
+ */
+import DateRange from '../date-range';
+
+// The moments have to be built inside the test: moment.updateLocale() swaps the
+// locale object, and existing moments (and their clones) keep the old one.
+const renderDateRange = () =>
+	render(
+		<DateRange
+			after={ moment( '2026-08-01' ) }
+			before={ moment( '2026-08-20' ) }
+			afterText="08/01/2026"
+			beforeText="08/20/2026"
+			focusedInput="startDate"
+			onUpdate={ () => {} }
+			shortDateFormat="MM/DD/YYYY"
+		/>
+	);
+
+const getDayLabels = ( container ) =>
+	Array.from(
+		container.querySelectorAll( 'td.CalendarDay[aria-label]' )
+	).map( ( day ) => day.getAttribute( 'aria-label' ) );
+
+// WordPress seeds moment's long date formats with the site's PHP `date_format`
+// option, which moment reads as its own tokens.
+const seedLongDateFormat = ( format ) =>
+	moment.updateLocale( moment.locale(), {
+		longDateFormat: { LL: format },
+	} );
+
+// 'F j, Y' is the WordPress default, and moment prints its tokens literally.
+// 'd/m/Y' is worse: moment reads `d` as the weekday index and `m` as minutes,
+// so it renders a plausible but wrong date.
+const phpDateFormats = [ 'F j, Y', 'd/m/Y' ];
+
+describe( 'DateRange', () => {
+	let originalLongDateFormat;
+
+	beforeEach( () => {
+		originalLongDateFormat = moment.localeData().longDateFormat( 'LL' );
+	} );
+
+	afterEach( () => {
+		seedLongDateFormat( originalLongDateFormat );
+		resetLocaleData();
+	} );
+
+	it.each( phpDateFormats )(
+		'labels calendar days with a real date when `LL` is "%s"',
+		( phpDateFormat ) => {
+			seedLongDateFormat( phpDateFormat );
+
+			const { container } = renderDateRange();
+			const labels = getDayLabels( container );
+
+			expect( labels ).toContain( 'Selected. Saturday, August 1, 2026' );
+			expect( labels ).toContain(
+				'Select Wednesday, August 26, 2026 as a start date.'
+			);
+		}
+	);
+
+	it.each( phpDateFormats )(
+		'labels every day with a real date when `LL` is "%s"',
+		( phpDateFormat ) => {
+			seedLongDateFormat( phpDateFormat );
+
+			const { container } = renderDateRange();
+			const labels = getDayLabels( container );
+
+			expect( labels.length ).toBeGreaterThan( 0 );
+			labels.forEach( ( label ) => {
+				expect( label ).toMatch(
+					/[A-Z][a-z]+day, [A-Z][a-z]+ \d{1,2}, \d{4}/
+				);
+			} );
+		}
+	);
+
+	it( 'labels calendar days with the translated format', () => {
+		setLocaleData(
+			{ 'dddd, MMMM D, YYYY': [ 'dddd, D. MMMM YYYY' ] },
+			'woocommerce'
+		);
+
+		const { container } = renderDateRange();
+		const labels = getDayLabels( container );
+
+		expect( labels ).toContain( 'Selected. Saturday, 1. August 2026' );
+	} );
+} );
diff --git a/plugins/woocommerce/changelog/fix-calendar-day-aria-label-format b/plugins/woocommerce/changelog/fix-calendar-day-aria-label-format
new file mode 100644
index 00000000000..84ce1b7ce0c
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-calendar-day-aria-label-format
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Analytics: fix the custom date range calendar reading out the wrong date to screen reader users.