Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
6716ca7
Global format config. Add tests
GoodDayForSurf Apr 2, 2026
a434b9d
Global format config. Implementation for dateFormat, dateTimeFormat, …
GoodDayForSurf Apr 2, 2026
3a8179f
Merge branch '26_1' into 26_1_global_format
GoodDayForSurf Apr 2, 2026
722f5ca
Global format config. Implementation for dateFormat, dateTimeFormat, …
GoodDayForSurf Apr 2, 2026
0ec8e32
Merge branch '26_1' into 26_1_global_format
GoodDayForSurf Apr 2, 2026
d1e97af
Global format config. Implementation for dateFormat, dateTimeFormat, …
GoodDayForSurf Apr 2, 2026
a862455
Merge remote-tracking branch 'my/26_1_global_format' into 26_1_global…
GoodDayForSurf Apr 2, 2026
2922132
Global format config. Implementation for dateFormat, dateTimeFormat, …
GoodDayForSurf Apr 2, 2026
57dad57
Global format config. Implementation for dateFormat, dateTimeFormat, …
GoodDayForSurf Apr 2, 2026
026930e
Global format config. Implementation for dateFormat, dateTimeFormat, …
GoodDayForSurf Apr 2, 2026
bd86b8a
Global format config. Implementation for dateFormat, dateTimeFormat, …
GoodDayForSurf Apr 3, 2026
bd3bcbd
Global format config. Implementation for dateFormat, dateTimeFormat, …
GoodDayForSurf Apr 3, 2026
77d63d2
Global format config. Implementation for dateFormat, dateTimeFormat, …
GoodDayForSurf Apr 3, 2026
dbd3064
Global format config. Implementation for dateFormat, dateTimeFormat, …
GoodDayForSurf Apr 3, 2026
73904b5
Global format config. Implementation for dateFormat, dateTimeFormat, …
GoodDayForSurf Apr 3, 2026
a58d9ee
Global format config. Implementation for dateFormat, dateTimeFormat, …
GoodDayForSurf Apr 3, 2026
9c64a68
Merge branch '26_1' into 26_1_global_format
GoodDayForSurf Apr 3, 2026
9e3c6fc
Merge branch '26_1' into 26_1_global_format
GoodDayForSurf Apr 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import accountingFormats from '@ts/core/localization/cldr-data/accounting_format
import localizationCoreUtils from '@ts/core/localization/core';
import type { FormatConfig as BaseFormatConfig, LocalizationFormat } from '@ts/core/localization/number';
import openXmlCurrencyFormat from '@ts/core/localization/open_xml_currency_format';
import { getGlobalFormatByDataType } from '@ts/core/m_global_format_config';

interface CurrencySymbolInfo {
position: 'before' | 'after';
Expand Down Expand Up @@ -106,6 +107,13 @@ export default {
return value;
}

const globalNumberFormat = getGlobalFormatByDataType('number');

if (!format && globalNumberFormat) {
// eslint-disable-next-line no-param-reassign
format = globalNumberFormat as LocalizationFormat;
}

// eslint-disable-next-line no-param-reassign
format = this._normalizeFormat(format) as FormatConfig;

Expand Down
7 changes: 7 additions & 0 deletions packages/devextreme/js/__internal/core/localization/number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import currencyLocalization from '@ts/core/localization/currency';
import intlNumberLocalization from '@ts/core/localization/intl/number';
import { getFormatter } from '@ts/core/localization/ldml/number';
import { toFixed } from '@ts/core/localization/utils';
import { getGlobalFormatByDataType } from '@ts/core/m_global_format_config';
import { escapeRegExp } from '@ts/core/utils/m_common';
import { injector as dependencyInjector } from '@ts/core/utils/m_dependency_injector';
import { each } from '@ts/core/utils/m_iterator';
Expand Down Expand Up @@ -321,6 +322,12 @@ const numberLocalization = dependencyInjector({
return value;
}

const globalNumberFormat = getGlobalFormatByDataType('number');

if (!format && globalNumberFormat) {
format = globalNumberFormat as LocalizationFormat;
}

// @ts-expect-error
format = format?.formatter || format;

Expand Down
5 changes: 5 additions & 0 deletions packages/devextreme/js/__internal/core/m_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ const config = {
useLegacyVisibleIndex: false,
versionAssertions: [],
copyStylesToShadowDom: true,
dateFormat: undefined,
timeFormat: undefined,
dateTimeFormat: undefined,
numberFormat: undefined,
dateTimeFormatPresets: undefined,

floatingActionButtonConfig: {
icon: 'add',
Expand Down
62 changes: 62 additions & 0 deletions packages/devextreme/js/__internal/core/m_global_format_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import config from '@js/core/config';
import coreLocalization from '@js/common/core/localization/core';
import parentLocales from '@ts/core/localization/cldr-data/parent_locales';
import getParentLocale from '@ts/core/localization/parentLocale';
import { isFunction, isPlainObject, isString } from '@js/core/utils/type';

const hasOwn = Object.prototype.hasOwnProperty;

const resolveByLocaleMap = (localeMap) => {
let currentLocale = coreLocalization.locale();

while(currentLocale) {
if(hasOwn.call(localeMap, currentLocale) && localeMap[currentLocale] !== undefined) {
return localeMap[currentLocale];
}

currentLocale = getParentLocale(parentLocales, currentLocale);
}

if(hasOwn.call(localeMap, 'default')) {
return localeMap.default;
}

return undefined;
};

const resolveGlobalFormat = (optionName) => {
const optionValue = config()[optionName];

if(optionValue === undefined) {
return undefined;
}

if(isString(optionValue) || isFunction(optionValue)) {
return optionValue;
}

if(isPlainObject(optionValue)) {
return resolveByLocaleMap(optionValue);
}

return undefined;
};

export const getGlobalFormatByDataType = (dataType) => {
switch(dataType) {
case 'date':
return resolveGlobalFormat('dateFormat');
case 'datetime':
return resolveGlobalFormat('dateTimeFormat');
case 'time':
return resolveGlobalFormat('timeFormat');
case 'number':
return resolveGlobalFormat('numberFormat');
default:
return undefined;
}
};

export default {
getGlobalFormatByDataType,
};
21 changes: 19 additions & 2 deletions packages/devextreme/js/__internal/grids/grid_core/m_utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @ts-check

import eventsEngine from '@js/common/core/events/core/events_engine';
import dateLocalization from '@js/common/core/localization/date';
import DataSource from '@js/common/data/data_source';
import { normalizeDataSourceOptions } from '@js/common/data/data_source/utils';
import { normalizeSortingInfo as normalizeSortingInfoUtility } from '@js/common/data/utils';
Expand All @@ -19,6 +20,7 @@ import { getWindow } from '@js/core/utils/window';
import formatHelper from '@js/format_helper';
import LoadPanel from '@js/ui/load_panel';
import sharedFiltering from '@js/ui/shared/filtering';
import { getGlobalFormatByDataType } from '@ts/core/m_global_format_config';
import { isNumeric } from '@ts/core/utils/m_type';
import type { Column } from '@ts/grids/grid_core/columns_controller/types';
import type { ColumnPoint } from '@ts/grids/grid_core/m_types';
Expand Down Expand Up @@ -83,6 +85,21 @@ function isDateType(dataType) {
return dataType === 'date' || dataType === 'datetime';
}

const getGlobalFormat = (dataType) => {
const globalFormat = getGlobalFormatByDataType(dataType);

if (!globalFormat) {
return undefined;
}

return isString(globalFormat)
? (value) => {
const dateValue = value instanceof Date ? value : new Date(value);
return isNaN(dateValue.getTime()) ? '' : dateLocalization.format(dateValue, globalFormat);
}
: globalFormat;
};

const setEmptyText = function ($container) {
$container.get(0).textContent = '\u00A0';
};
Expand Down Expand Up @@ -389,9 +406,9 @@ export default {
getFormatByDataType(dataType) {
switch (dataType) {
case 'date':
return 'shortDate';
return getGlobalFormat('date') || 'shortDate';
case 'datetime':
return 'shortDateShortTime';
return getGlobalFormat('datetime') || 'shortDateShortTime';
default:
return undefined;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import type { DataType, Format } from '@js/common';
import dateLocalization from '@js/common/core/localization/date';
import { compileGetter, getPathParts } from '@js/core/utils/data';
import { captionize } from '@js/core/utils/inflector';
import {
isDefined,
isString, type,
} from '@js/core/utils/type';
import { getGlobalFormatByDataType } from '@ts/core/m_global_format_config';
import { getTreeNodeByPath, setTreeNodeByPath } from '@ts/grids/new/grid_core/utils/tree/index';
import type { ComponentType } from 'inferno';

Expand Down Expand Up @@ -222,15 +224,43 @@ export const getValueDataType = (
: dataType as DataType;
};

const getGlobalFormat = (
dataType: 'date' | 'datetime',
): Format | undefined => {
const globalFormat = getGlobalFormatByDataType(dataType);

if (!globalFormat) {
return undefined;
}

if (isString(globalFormat)) {
return (
(value: Date | string | number) => {
const dateValue = value instanceof Date ? value : new Date(value);

return isNaN(dateValue.getTime())
? ''
: dateLocalization.format(dateValue, globalFormat) as string;
}
) as unknown as Format;
}

return globalFormat as Format;
};

export const getColumnFormat = (
column: Partial<Pick<Column, 'format' | 'dataType'>>,
): Format | undefined => {
if (column.format) {
return column.format;
}

if (column.dataType === 'date' || column.dataType === 'datetime') {
return 'shortDate';
if (column.dataType === 'date') {
return getGlobalFormat('date') || 'shortDate';
}

if (column.dataType === 'datetime') {
return getGlobalFormat('datetime') || 'shortDateShortTime';
}

return undefined;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import dateLocalization from '@js/common/core/localization/date';
import messageLocalization from '@js/common/core/localization/message';
import type { ViewType } from '@js/ui/scheduler';

import { formatImplicitSchedulerDate, formatImplicitSchedulerMonth } from '../utils/global_formats';
import type { NormalizedView } from '../utils/options/types';

const KEYS = {
Expand All @@ -22,8 +22,8 @@ const viewTypeLocalization: Record<ViewType, string> = {
timelineWorkWeek: 'dxScheduler-switcherTimelineWorkWeek',
};

const localizeMonth = (date: Date): string => String(dateLocalization.format(date, 'monthAndYear'));
const localizeDate = (date: Date): string => `${dateLocalization.format(date, 'monthAndDay')}, ${dateLocalization.format(date, 'year')}`;
const localizeMonth = (date: Date): string => formatImplicitSchedulerMonth(date);
const localizeDate = (date: Date): string => formatImplicitSchedulerDate(date);
const localizeCurrentIndicator = (
date: Date,
startDate: Date,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import dateLocalization from '@js/common/core/localization/date';
import messageLocalization from '@js/common/core/localization/message';
import { isDefined } from '@js/core/utils/type';

import { formatImplicitSchedulerDate, formatImplicitSchedulerTime } from '../../utils/global_formats';
import type { AppointmentProperties } from './m_types';

const localizeDate = (date: Date): string => `${dateLocalization.format(date, 'monthAndDay')}, ${dateLocalization.format(date, 'year')}`;

const localizeTime = (date: Date): string => `${dateLocalization.format(date, 'shorttime')}`;
const localizeDate = (date: Date): string => formatImplicitSchedulerDate(date);
const localizeTime = (date: Date): string => formatImplicitSchedulerTime(date);

const getDate = (options: AppointmentProperties, propName: 'endDate' | 'startDate'): Date => {
const result = options.dataAccessors.get(propName, options.data);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,29 @@
import dateLocalization from '@js/common/core/localization/date';
import dateUtils from '@js/core/utils/date';
import { getGlobalFormatByDataType } from '@ts/core/m_global_format_config';

import type { TargetedAppointment, ViewType } from '../../types';

const formatTooltipDatePart = (date: Date): string => {
const globalFormat = getGlobalFormatByDataType('date');

if (globalFormat) {
return dateLocalization.format(date, globalFormat) as string;
}

return String(dateLocalization.format(date, 'monthandday'));
};

const formatTooltipTimePart = (date: Date): string => {
const globalFormat = getGlobalFormatByDataType('time');

if (globalFormat) {
return dateLocalization.format(date, globalFormat) as string;
}

return String(dateLocalization.format(date, 'shorttime'));
};

export enum DateFormatType {
DATETIME = 'DATETIME',
TIME = 'TIME',
Expand All @@ -25,24 +46,17 @@ export const getDateFormatType = (
};

export const getDateText = (startDate: Date, endDate: Date, formatType: DateFormatType): string => {
const dateFormat = 'monthandday';
const timeFormat = 'shorttime';
const isSameDate = dateUtils.sameDate(startDate, endDate);

switch (formatType) {
case DateFormatType.DATETIME:
return [
dateLocalization.format(startDate, dateFormat),
' ',
dateLocalization.format(startDate, timeFormat),
' - ',
isSameDate ? '' : `${dateLocalization.format(endDate, dateFormat)} `,
dateLocalization.format(endDate, timeFormat),
].join('');
return isSameDate
? `${formatTooltipDatePart(startDate)} ${formatTooltipTimePart(startDate)} - ${formatTooltipTimePart(endDate)}`
: `${formatTooltipDatePart(startDate)} ${formatTooltipTimePart(startDate)} - ${formatTooltipDatePart(endDate)} ${formatTooltipTimePart(endDate)}`;
case DateFormatType.TIME:
return `${dateLocalization.format(startDate, timeFormat)} - ${dateLocalization.format(endDate, timeFormat)}`;
return `${formatTooltipTimePart(startDate)} - ${formatTooltipTimePart(endDate)}`;
case DateFormatType.DATE:
return `${dateLocalization.format(startDate, dateFormat)}${isSameDate ? '' : ` - ${dateLocalization.format(endDate, dateFormat)}`}`;
return `${formatTooltipDatePart(startDate)}${isSameDate ? '' : ` - ${formatTooltipDatePart(endDate)}`}`;
default:
return '';
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { locate, move } from '@js/common/core/animation/translator';
import dateLocalization from '@js/common/core/localization/date';
import messageLocalization from '@js/common/core/localization/message';
import $, { type dxElementWrapper } from '@js/core/renderer';
import { FunctionTemplate } from '@js/core/templates/function_template';
Expand All @@ -9,6 +8,7 @@ import type { Appointment } from '@js/ui/scheduler';
import { APPOINTMENT_SETTINGS_KEY, LIST_ITEM_CLASS, LIST_ITEM_DATA_KEY } from './constants';
import type Scheduler from './m_scheduler';
import type { AppointmentTooltipItem, CompactAppointmentOptions, TargetedAppointment } from './types';
import { formatImplicitSchedulerDate } from './utils/global_formats';

const APPOINTMENT_COLLECTOR_CLASS = 'dx-scheduler-appointment-collector';
const COMPACT_APPOINTMENT_COLLECTOR_CLASS = `${APPOINTMENT_COLLECTOR_CLASS}-compact`;
Expand Down Expand Up @@ -185,7 +185,7 @@ export class CompactAppointmentsHelper {
}

private localizeDate(date) {
return `${dateLocalization.format(date, 'monthAndDay')}, ${dateLocalization.format(date, 'year')}`;
return formatImplicitSchedulerDate(date);
}

private getDateText(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import dateLocalization from '@js/common/core/localization/date';
import dateUtils from '@js/core/utils/date';

import type { CalculateStartViewDate } from '../../types';
import { formatImplicitSchedulerTime } from '../../utils/global_formats';
import {
getCalculatedFirstDayOfWeek,
getValidCellDateForLocalTimeFormat,
Expand Down Expand Up @@ -29,7 +30,7 @@ export const getTimePanelCellText = (
viewOffset,
});

return dateLocalization.format(validTimeDate, 'shorttime') as string;
return formatImplicitSchedulerTime(validTimeDate);
};

export const getIntervalDuration = (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import dateLocalization from '@js/common/core/localization/date';
import { getGlobalFormatByDataType } from '@ts/core/m_global_format_config';

export const formatImplicitSchedulerDate = (date: Date): string => {
const globalDateFormat = getGlobalFormatByDataType('date');

if (globalDateFormat) {
return dateLocalization.format(date, globalDateFormat) as string;
}

return `${dateLocalization.format(date, 'monthAndDay')}, ${dateLocalization.format(date, 'year')}`;
};

export const formatImplicitSchedulerMonth = (date: Date): string => {
const globalDateFormat = getGlobalFormatByDataType('date');

if (globalDateFormat) {
return dateLocalization.format(date, globalDateFormat) as string;
}

return String(dateLocalization.format(date, 'monthAndYear'));
};

export const formatImplicitSchedulerTime = (date: Date): string => {
const globalTimeFormat = getGlobalFormatByDataType('time');

return dateLocalization.format(date, globalTimeFormat || 'shorttime') as string;
};
Loading
Loading