UNPKG

@wordpress/components

Version:
170 lines (166 loc) 4.81 kB
/** * WordPress dependencies */ import { __, sprintf } from '@wordpress/i18n'; import { useMemo } from '@wordpress/element'; /** * Internal dependencies */ import type { Modifiers, BaseProps } from '../types'; function isLocaleRTL( localeCode: string ) { const localeObj = new Intl.Locale( localeCode ); if ( 'getTextInfo' in localeObj ) { // @ts-expect-error - getTextInfo is not typed yet // see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getTextInfo return localeObj.getTextInfo().direction === 'rtl'; } return [ 'ar', // Arabic 'he', // Hebrew 'fa', // Persian (Farsi) 'ur', // Urdu 'ps', // Pashto 'syr', // Syriac 'dv', // Divehi 'ku', // Kurdish (Sorani) 'yi', // Yiddish ].includes( localeObj.language ); } /** * Returns localization props for the calendar components. * * Notes: * - the following props should be intended as defaults, and should * be overridden by consumer props if listed as public props. * - It is possible for the translated strings to use a different locale * than the formatted dates and the computed `dir`. This is because the * translation function doesn't expose the locale used for the translated * strings, meaning that the dates are formatted using the `locale` prop. * For a correct localized experience, consumers should make sure that * translation context and `locale` prop are consistent. * @param props * @param props.locale * @param props.timeZone * @param props.mode */ export const useLocalizationProps = ( { locale, timeZone, mode, }: { locale: NonNullable< BaseProps[ 'locale' ] >; timeZone: BaseProps[ 'timeZone' ]; mode: 'single' | 'range'; } ) => { return useMemo( () => { // ie. April 2025 const monthNameFormatter = new Intl.DateTimeFormat( locale.code, { year: 'numeric', month: 'long', timeZone, } ); // ie. M, T, W, T, F, S, S const weekdayNarrowFormatter = new Intl.DateTimeFormat( locale.code, { weekday: 'narrow', timeZone, } ); // ie. Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday const weekdayLongFormatter = new Intl.DateTimeFormat( locale.code, { weekday: 'long', timeZone, } ); // ie. Monday, April 29, 2025 const fullDateFormatter = new Intl.DateTimeFormat( locale.code, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', timeZone, } ); // Note: the following props should be intended as defaults, and should // be overridden by consumer props if listed as public props. return { 'aria-label': mode === 'single' ? __( 'Date calendar' ) : __( 'Date range calendar' ), labels: { /** * The label for the month grid. * @param date */ labelGrid: ( date: Date ) => monthNameFormatter.format( date ), /** * The label for the gridcell, when the calendar is not interactive. * @param date * @param modifiers */ labelGridcell: ( date: Date, /** The modifiers for the day. */ modifiers?: Modifiers ) => { const formattedDate = fullDateFormatter.format( date ); let label = formattedDate; if ( modifiers?.today ) { label = sprintf( // translators: %s is the full date (e.g. "Monday, April 29, 2025") __( 'Today, %s' ), formattedDate ); } return label; }, /** The label for the "next month" button. */ labelNext: () => __( 'Go to the Next Month' ), /** The label for the "previous month" button. */ labelPrevious: () => __( 'Go to the Previous Month' ), /** * The label for the day button. * @param date * @param modifiers */ labelDayButton: ( date: Date, /** The modifiers for the day. */ modifiers?: Modifiers ) => { const formattedDate = fullDateFormatter.format( date ); let label = formattedDate; if ( modifiers?.today ) { label = sprintf( // translators: %s is the full date (e.g. "Monday, April 29, 2025") __( 'Today, %s' ), formattedDate ); } if ( modifiers?.selected ) { label = sprintf( // translators: %s is the full date (e.g. "Monday, April 29, 2025") __( '%s, selected' ), formattedDate ); } return label; }, /** * The label for the weekday. * @param date */ labelWeekday: ( date: Date ) => weekdayLongFormatter.format( date ), }, locale, dir: isLocaleRTL( locale.code ) ? 'rtl' : 'ltr', formatters: { formatWeekdayName: ( date: Date ) => { return weekdayNarrowFormatter.format( date ); }, formatCaption: ( date: Date ) => { return monthNameFormatter.format( date ); }, }, timeZone, } as const; }, [ locale, timeZone, mode ] ); };