From 30254117b281acdbcbb51bd5118895beba282c42 Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Thu, 16 Jul 2026 08:55:39 -0300 Subject: [PATCH 1/9] PivotGrid - KBN - Add ARIA attributes to area fields --- .../tests/common/pivotGrid/kbn/fields.ts | 29 ++++++++++++ .../pivot_grid/field_chooser/a11y.test.ts | 44 +++++++++++++++++++ .../grids/pivot_grid/field_chooser/a11y.ts | 41 +++++++++++++++++ .../field_chooser/m_field_chooser.ts | 7 +++ .../field_chooser/m_field_chooser_base.ts | 18 ++++++++ .../pivot_grid/fields_area/m_fields_area.ts | 36 ++++++++++++--- .../js/localization/messages/ar.json | 4 ++ .../js/localization/messages/bg.json | 4 ++ .../js/localization/messages/ca.json | 4 ++ .../js/localization/messages/cs.json | 4 ++ .../js/localization/messages/da.json | 4 ++ .../js/localization/messages/de.json | 4 ++ .../js/localization/messages/el.json | 4 ++ .../js/localization/messages/en.json | 4 ++ .../js/localization/messages/es.json | 4 ++ .../js/localization/messages/fa.json | 4 ++ .../js/localization/messages/fi.json | 4 ++ .../js/localization/messages/fr.json | 4 ++ .../js/localization/messages/hi.json | 4 ++ .../js/localization/messages/hu.json | 4 ++ .../js/localization/messages/it.json | 4 ++ .../js/localization/messages/ja.json | 4 ++ .../js/localization/messages/ko.json | 4 ++ .../js/localization/messages/lt.json | 4 ++ .../js/localization/messages/lv.json | 4 ++ .../js/localization/messages/nb.json | 4 ++ .../js/localization/messages/nl.json | 4 ++ .../js/localization/messages/pl.json | 4 ++ .../js/localization/messages/pt-BR.json | 4 ++ .../js/localization/messages/pt-PT.json | 4 ++ .../js/localization/messages/pt.json | 4 ++ .../js/localization/messages/ro.json | 4 ++ .../js/localization/messages/ru.json | 4 ++ .../js/localization/messages/sl.json | 4 ++ .../js/localization/messages/sv.json | 4 ++ .../js/localization/messages/tr.json | 4 ++ .../js/localization/messages/uk.json | 4 ++ .../js/localization/messages/vi.json | 4 ++ .../js/localization/messages/zh-CN.json | 4 ++ .../js/localization/messages/zh-Hans.json | 4 ++ .../js/localization/messages/zh-tw.json | 4 ++ .../js/localization/messages/zh.json | 4 ++ .../pivotGrid.markup.tests.js | 17 ++++--- 43 files changed, 325 insertions(+), 11 deletions(-) create mode 100644 packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.test.ts create mode 100644 packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.ts diff --git a/e2e/testcafe-devextreme/tests/common/pivotGrid/kbn/fields.ts b/e2e/testcafe-devextreme/tests/common/pivotGrid/kbn/fields.ts index 86a80a6d87a2..2d8973d973ef 100644 --- a/e2e/testcafe-devextreme/tests/common/pivotGrid/kbn/fields.ts +++ b/e2e/testcafe-devextreme/tests/common/pivotGrid/kbn/fields.ts @@ -1,5 +1,6 @@ import PivotGrid from 'devextreme-testcafe-models/pivotGrid'; import HeaderFilter from 'devextreme-testcafe-models/dataGrid/headers/headerFilter'; +import { Selector } from 'testcafe'; import url from '../../../../helpers/getPageUrl'; import { createWidget } from '../../../../helpers/createWidget'; @@ -107,6 +108,34 @@ const createConfig = () => ({ const testTitlePrefix = isFieldChooser ? 'Field Chooser' : 'PivotGrid'; + const getAreaFieldsContainer = (area: string) => (isFieldChooser + ? Selector(`.dx-pivotgridfieldchooser .dx-area-fields[group="${area}"]`) + : Selector(`.dx-pivotgrid-fields-area[group="${area}"]`)); + + test(`${testTitlePrefix}: Fields should be exposed as menu items of an area menubar`, async (t) => { + const pivotGrid = new PivotGrid(PIVOT_GRID_SELECTOR); + + if (isFieldChooser) { + await t.click(pivotGrid.getFieldChooserButton()); + } + + const rowAreaContainer = getAreaFieldsContainer('row'); + const menubar = rowAreaContainer.find('[role="menubar"]'); + const firstField = getField(pivotGrid, 'row', 0); + + await t + .expect(menubar.count) + .eql(1, 'the area has a single menubar') + .expect(menubar.getAttribute('aria-label')) + .eql('Row Fields', 'the menubar is labelled with the area name'); + + await t + .expect(firstField.getAttribute('role')) + .eql('menuitem', 'a field is exposed as a menu item') + .expect(firstField.getAttribute('aria-label')) + .eql('Field: Region, Sort order: ascending', 'the field label includes the name and the sorting state'); + }).before(async () => createWidget('dxPivotGrid', createConfig())); + ['filter', 'data', 'column', 'row'].forEach((area) => { test(`${testTitlePrefix}: Fields in ${area} area should be focusable by tab`, async (t) => { const pivotGrid = new PivotGrid(PIVOT_GRID_SELECTOR); diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.test.ts b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.test.ts new file mode 100644 index 000000000000..9f4e74a69d1f --- /dev/null +++ b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.test.ts @@ -0,0 +1,44 @@ +import { + beforeAll, describe, expect, it, +} from '@jest/globals'; +import messageLocalization from '@js/common/core/localization/message'; + +import { getFieldItemA11yLabel } from './a11y'; + +describe('getFieldItemA11yLabel', () => { + beforeAll(() => { + // @ts-expect-error load is not declared on the localization typing + messageLocalization.load({ + en: { + 'dxPivotGrid-ariaFieldLabel': 'Field: {0}', + 'dxPivotGrid-ariaFieldHeaderFilterLabel': 'Header filter applied', + 'dxPivotGrid-ariaFieldISortAscLabel': 'Sort order: ascending', + 'dxPivotGrid-ariaFieldSortDescLabel': 'Sort order: descending', + }, + }); + }); + + it('should contain only the field name by default', () => { + expect(getFieldItemA11yLabel('Region', {})).toBe('Field: Region'); + }); + + it('should append the ascending sorting state', () => { + expect(getFieldItemA11yLabel('Region', { sortOrder: 'asc' })) + .toBe('Field: Region, Sort order: ascending'); + }); + + it('should append the descending sorting state', () => { + expect(getFieldItemA11yLabel('Region', { sortOrder: 'desc' })) + .toBe('Field: Region, Sort order: descending'); + }); + + it('should append the header filter state', () => { + expect(getFieldItemA11yLabel('Region', { hasHeaderFilterValue: true })) + .toBe('Field: Region, Header filter applied'); + }); + + it('should compose all parts in a stable order', () => { + expect(getFieldItemA11yLabel('Region', { sortOrder: 'asc', hasHeaderFilterValue: true })) + .toBe('Field: Region, Header filter applied, Sort order: ascending'); + }); +}); diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.ts b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.ts new file mode 100644 index 000000000000..69f94216181e --- /dev/null +++ b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.ts @@ -0,0 +1,41 @@ +import messageLocalization from '@js/common/core/localization/message'; + +import type { SortOrderType } from './const'; +import { SORT_ORDER } from './const'; + +const I18N_KEYS = { + fieldLabel: 'dxPivotGrid-ariaFieldLabel', + hasHeaderFilter: 'dxPivotGrid-ariaFieldHeaderFilterLabel', + sortingAsc: 'dxPivotGrid-ariaFieldISortAscLabel', + sortingDesc: 'dxPivotGrid-ariaFieldSortDescLabel', +}; + +const I18N_MESSAGE_SEPARATOR = ', '; + +export interface FieldItemA11yOptions { + sortOrder?: SortOrderType; + hasHeaderFilterValue?: boolean; +} + +const getSortingLabel = (sortOrder?: SortOrderType): string | null => { + switch (sortOrder) { + case SORT_ORDER.ascending: + return messageLocalization.format(I18N_KEYS.sortingAsc); + case SORT_ORDER.descending: + return messageLocalization.format(I18N_KEYS.sortingDesc); + default: + return null; + } +}; + +export const getFieldItemA11yLabel = ( + caption: string, + { sortOrder, hasHeaderFilterValue }: FieldItemA11yOptions, +): string => [ + // @ts-expect-error format typing does not accept substitution args + messageLocalization.format(I18N_KEYS.fieldLabel, caption), + hasHeaderFilterValue ? messageLocalization.format(I18N_KEYS.hasHeaderFilter) : null, + getSortingLabel(sortOrder), +] + .filter((message) => !!message) + .join(I18N_MESSAGE_SEPARATOR); diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser.ts b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser.ts index bf0bb3312ec2..8c5a845897e9 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser.ts @@ -547,6 +547,13 @@ export class FieldChooser extends FieldChooserBase { that.renderField(field, true).appendTo($container); } }); + + // A menubar without menu items is invalid ARIA, so an empty area stays + // without the role until fields are dropped into it. + const hasFields = !!$container.children().length; + $container + .attr('role', hasFields ? 'menubar' : null) + .attr('aria-label', hasFields ? that.option(`texts.${area}Fields`) : null); } _renderArea(container, area) { diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser_base.ts b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser_base.ts index 3323acb54ba1..7ac5bc9477b1 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser_base.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser_base.ts @@ -21,6 +21,8 @@ import sortingMixin from '@ts/grids/grid_core/sorting/m_sorting_mixin'; import { createPath, foreachTree } from '../m_widget_utils'; import SortableModule from '../sortable/m_sortable'; +import { getFieldItemA11yLabel } from './a11y'; +import type { SortOrderType } from './const'; import { ATTRIBUTES, CLASSES } from './const'; import { dragAndDropItemRender } from './dom'; import { reverseSortOrder, shouldCancelDragging } from './utils'; @@ -211,9 +213,25 @@ export class FieldChooserBase extends mixinWidget { $fieldElement.attr(ATTRIBUTES.itemGroup, field.groupName); } + $fieldElement + .attr('role', 'menuitem') + .attr('aria-label', this._getFieldItemAriaLabel(field, caption)); + return $fieldElement; } + private _getFieldItemAriaLabel(field, caption: string): string { + // The sort indicator is rendered for every sortable non-data field, with + // ascending shown by default, so the label mirrors the visible state. + const sortOrder = field.allowSorting && field.area !== 'data' + ? (field.sortOrder === 'desc' ? 'desc' : 'asc') as SortOrderType + : undefined; + const hasHeaderFilterValue = fieldHasHeaderFilter(this._dataSource, field) + && !!getMainGroupField(this._dataSource, field).filterValues?.length; + + return getFieldItemA11yLabel(caption, { sortOrder, hasHeaderFilterValue }); + } + // eslint-disable-next-line @typescript-eslint/no-unused-vars _clean(value?) { } diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/fields_area/m_fields_area.ts b/packages/devextreme/js/__internal/grids/pivot_grid/fields_area/m_fields_area.ts index 4ae33e0c31d1..7ca2d455c2e9 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/fields_area/m_fields_area.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/fields_area/m_fields_area.ts @@ -46,7 +46,7 @@ class FieldsArea extends AreaItem { .attr('group', this._area); } - _createTableElement() { + _getAreaLabel() { const localizationMessageMap = { row: 'dxPivotGrid-rowFields', column: 'dxPivotGrid-columnFields', @@ -54,9 +54,12 @@ class FieldsArea extends AreaItem { filter: 'dxPivotGrid-filterFields', }; + return localizationMessage.format(localizationMessageMap[this._area]); + } + + _createTableElement() { return $('') - .attr('role', 'group') - .attr('aria-label', localizationMessage.format(localizationMessageMap[this._area])); + .attr('role', 'presentation'); } isVisible() { @@ -145,7 +148,10 @@ class FieldsArea extends AreaItem { const groupElement = this.groupElement(); const isVisible = this.isVisible(); const fieldChooserBase = that.component.$element().dxPivotGridFieldChooserBase('instance'); - const head = $('').addClass('dx-pivotgrid-fields-area-head').appendTo(tableElement); + const head = $('') + .addClass('dx-pivotgrid-fields-area-head') + .attr('role', 'presentation') + .appendTo(tableElement); const area = that._area; const row = $(''); @@ -158,7 +164,9 @@ class FieldsArea extends AreaItem { each(data, (index: number, field) => { if (field.area === area && field.visible !== false) { - const td = $(' + + `); + const data = createSection('tbody', ` + + `); + document.body.append(columns, data); + + describeDataCellsWithHeaders(columns, undefined, data); + + const cells = data.querySelectorAll('td'); + expect(getDescribingCells(cells[0])).toEqual([ + document.getElementById('group'), + document.getElementById('q1'), + ]); + expect(getDescribingCells(cells[1])).toEqual([ + document.getElementById('group'), + document.getElementById('q2'), + ]); + expect(getDescribingCells(cells[2])).toEqual([ + document.getElementById('total'), + ]); + }); + + it('should reference the row header path including rowspan groups', () => { + const rows = createSection('tbody', ` + + + `); + const data = createSection('tbody', ` + + + `); + document.body.append(rows, data); + + describeDataCellsWithHeaders(undefined, rows, data); + + const cells = data.querySelectorAll('td'); + expect(getDescribingCells(cells[0])).toEqual([ + document.getElementById('africa'), + document.getElementById('cairo'), + ]); + expect(getDescribingCells(cells[1])).toEqual([ + document.getElementById('africa'), + document.getElementById('luxor'), + ]); + }); + + it('should combine row and column paths in the row-then-column order', () => { + const columns = createSection('thead', ''); + const rows = createSection('tbody', ''); + const data = createSection('tbody', ''); + document.body.append(columns, rows, data); + + describeDataCellsWithHeaders(columns, rows, data); + + expect(getDescribingCells(data.querySelector('td'))).toEqual([ + document.getElementById('r'), + document.getElementById('c'), + ]); + }); + + it('should respect the virtual scrolling index offset', () => { + const columns = createSection('thead', ''); + const data = createSection('tbody', ''); + document.body.append(columns, data); + + describeDataCellsWithHeaders(columns, undefined, data); + + const cells = data.querySelectorAll('td'); + expect(getDescribingCells(cells[0])).toEqual([document.getElementById('c5')]); + expect(getDescribingCells(cells[1])).toEqual([document.getElementById('c6')]); + }); + + it('should reuse existing header cell ids and keep generated ones stable across runs', () => { + const columns = createSection('thead', ''); + const data = createSection('tbody', ''); + document.body.append(columns, data); + + describeDataCellsWithHeaders(columns, undefined, data); + const generatedId = (columns.querySelectorAll('td')[1]).id; + describeDataCellsWithHeaders(columns, undefined, data); + + expect((columns.querySelectorAll('td')[0]).id).toBe('existing'); + expect((columns.querySelectorAll('td')[1]).id).toBe(generatedId); + expect(generatedId).toMatch(/^dx-/); + }); + + it('should remove a stale description when no header chains match', () => { + const data = createSection('tbody', ''); + document.body.append(data); + + describeDataCellsWithHeaders(undefined, undefined, data); + + expect(data.querySelector('td')?.hasAttribute('aria-describedby')).toBe(false); + }); +}); diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/a11y/data_cell_description.ts b/packages/devextreme/js/__internal/grids/pivot_grid/a11y/data_cell_description.ts new file mode 100644 index 000000000000..fb27ee83b0a7 --- /dev/null +++ b/packages/devextreme/js/__internal/grids/pivot_grid/a11y/data_cell_description.ts @@ -0,0 +1,101 @@ +import Guid from '@js/core/guid'; + +import { buildCellMatrix } from '../keyboard_navigation/table_cell_navigation'; + +type ChainMap = Map; + +const ensureId = (cell: HTMLTableCellElement): string => { + if (!cell.id) { + cell.id = `dx-${new Guid()}`; + } + return cell.id; +}; + +const getUniqueChainIds = (cells: (HTMLTableCellElement | undefined)[]): string => { + const chain: HTMLTableCellElement[] = []; + + cells.forEach((cell) => { + if (cell && !chain.includes(cell)) { + chain.push(cell); + } + }); + + return chain.map(ensureId).join(' '); +}; + +// The aria index attributes are affine to the rendered position (a constant +// virtual-scrolling offset per render), so a single sampled cell is enough to +// translate matrix positions into aria index keys. +const getColumnChains = (section: HTMLTableSectionElement | undefined): ChainMap => { + const chains: ChainMap = new Map(); + const matrix = section ? buildCellMatrix(section) : []; + const leafRow = matrix[matrix.length - 1] ?? []; + + const sampleCell = leafRow.find((cell) => cell?.hasAttribute('aria-colindex')); + if (!sampleCell) { + return chains; + } + const offset = Number(sampleCell.getAttribute('aria-colindex')) - leafRow.indexOf(sampleCell); + + leafRow.forEach((_, columnIndex) => { + chains.set( + String(columnIndex + offset), + getUniqueChainIds(matrix.map((row) => row[columnIndex])), + ); + }); + + return chains; +}; + +const getRowChains = (section: HTMLTableSectionElement | undefined): ChainMap => { + const chains: ChainMap = new Map(); + const matrix = section ? buildCellMatrix(section) : []; + + const sampleCell = matrix + .flat() + .find((cell) => cell?.hasAttribute('aria-rowindex')); + if (!sampleCell) { + return chains; + } + const sampleRow = (sampleCell.parentElement as HTMLTableRowElement).sectionRowIndex; + const offset = Number(sampleCell.getAttribute('aria-rowindex')) - sampleRow; + + matrix.forEach((row, rowIndex) => { + chains.set(String(rowIndex + offset), getUniqueChainIds(row)); + }); + + return chains; +}; + +// Associates every data cell with the row and column header cells covering it +// via aria-describedby. The header areas live in separate tables, so the +// native headers/id mechanism is not applicable; aria-describedby keeps the +// cell value as the accessible name and announces the header path as the +// description. +export function describeDataCellsWithHeaders( + columnsSection: HTMLTableSectionElement | undefined, + rowsSection: HTMLTableSectionElement | undefined, + dataSection: HTMLTableSectionElement | undefined, +): void { + if (!dataSection) { + return; + } + + const columnChains = getColumnChains(columnsSection); + const rowChains = getRowChains(rowsSection); + + Array.from(dataSection.rows).forEach((row) => { + Array.from(row.cells).forEach((cell) => { + const description = [ + rowChains.get(cell.getAttribute('aria-rowindex') ?? ''), + columnChains.get(cell.getAttribute('aria-colindex') ?? ''), + ].filter((ids) => !!ids).join(' '); + + if (description) { + cell.setAttribute('aria-describedby', description); + } else { + cell.removeAttribute('aria-describedby'); + } + }); + }); +} diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts b/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts index d664a42739c0..b56d91979261 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts @@ -26,6 +26,7 @@ import { current, isGeneric } from '@js/ui/themes'; import Widget from '@ts/core/widget/widget'; import gridCoreUtils from '@ts/grids/grid_core/m_utils'; +import { describeDataCellsWithHeaders } from './a11y/data_cell_description'; import { ChartIntegrationMixin } from './chart_integration/m_chart_integration'; import DataAreaImport from './data_area/m_data_area'; import DataControllerImport from './data_controller/m_data_controller'; @@ -1518,6 +1519,12 @@ class PivotGrid extends Widget { .attr('aria-owns', tableIds) .attr('aria-rowcount', this._dataController.totalRowCount()) .attr('aria-colcount', this._dataController.totalColumnCount()); + + describeDataCellsWithHeaders( + columnsArea.headElement().get(0), + rowsArea.tableElement().children('tbody').get(0), + dataArea.tableElement().children('tbody').get(0), + ); } _update(isFirstDrawing) { diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js index 2018b9dbc554..509f11554632 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js @@ -339,6 +339,49 @@ QUnit.module('PivotGrid accessibility markup', { }); }); + QUnit.test('Data cells are described by their row and column header cells', function(assert) { + if(!windowUtils.hasWindow()) { + assert.expect(0); + return; + } + + const pivotGrid = createPivotGrid({ + width: 600, height: 400, + dataSource: createExpandableDataSource() + }); + this.clock.tick(10); + + const $columnArea = pivotGrid.$element().find('.dx-pivotgrid-horizontal-headers'); + const $rowsArea = pivotGrid.$element().find('.dx-pivotgrid-vertical-headers'); + const $dataArea = pivotGrid.$element().find('.dx-pivotgrid-area-data'); + + $dataArea.find('td').each((_, dataCell) => { + const describedBy = dataCell.getAttribute('aria-describedby'); + + assert.ok(describedBy, 'data cell has aria-describedby'); + + describedBy.split(' ').forEach((id) => { + const header = document.getElementById(id); + + assert.ok(header, `referenced element #${id} exists`); + assert.ok( + $columnArea.find(header).length || $rowsArea.find(header).length, + 'referenced element is a row or column header cell' + ); + }); + }); + + const firstDataCell = $dataArea.find('td').get(0); + const describedTexts = firstDataCell.getAttribute('aria-describedby') + .split(' ') + .map((id) => document.getElementById(id).textContent.trim()); + const firstRowHeaderText = $rowsArea.find('td').first().text().trim(); + const firstColumnHeaderText = $columnArea.find('td').first().text().trim(); + + assert.ok(describedTexts.includes(firstRowHeaderText), 'description includes the row header caption'); + assert.ok(describedTexts.includes(firstColumnHeaderText), 'description includes the column header caption'); + }); + QUnit.test('Row header and data cells have aria-rowindex along shared row axis', function(assert) { if(!windowUtils.hasWindow()) { assert.expect(0); From c201add42b6a2fda6bb0ad62abe9512de18b220b Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Fri, 17 Jul 2026 19:21:51 -0300 Subject: [PATCH 9/9] PivotGrid - Resolve area sections defensively for partially stubbed areas --- .../devextreme/js/__internal/grids/pivot_grid/m_widget.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts b/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts index b56d91979261..3e8a2c750766 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts @@ -1520,10 +1520,12 @@ class PivotGrid extends Widget { .attr('aria-rowcount', this._dataController.totalRowCount()) .attr('aria-colcount', this._dataController.totalColumnCount()); + // The areas can be partially stubbed in tests, so the sections are + // resolved defensively. describeDataCellsWithHeaders( - columnsArea.headElement().get(0), - rowsArea.tableElement().children('tbody').get(0), - dataArea.tableElement().children('tbody').get(0), + columnsArea.headElement?.()?.get(0), + rowsArea.tableElement()?.children('tbody').get(0), + dataArea.tableElement()?.children('tbody').get(0), ); }
').append(fieldChooserBase.renderField(field, field.area === 'row')); + const td = $('') + .attr('role', 'none') + .append(fieldChooserBase.renderField(field, field.area === 'row')); const indicators = td.find('.dx-column-indicators'); if (indicators.length && that._shouldCreateButton()) { indicators.insertAfter((indicators as any).next()); @@ -167,7 +175,23 @@ class FieldsArea extends AreaItem { renderGroupConnector(field, data[index + 1], data[index - 1], td); } }); - if (!row.children().length) { + if (row.children().length) { + // Expose the fields as a menubar of menu items, consistent with the + // field chooser and CardView. The menubar role lives on the table + // element (it is invalid on a table row); thead/tr/td are kept out of + // the accessibility tree so the field items become the menubar's items. + row.attr('role', 'presentation'); + tableElement + .attr('role', 'menubar') + .attr('aria-label', this._getAreaLabel()); + } else { + // A menubar without menu items is invalid ARIA, so an empty area keeps + // the plain placeholder text and the table stays presentational. The + // role is reset explicitly because the table element is reused across + // re-renders. + tableElement + .attr('role', 'presentation') + .removeAttr('aria-label'); $('').append($(DIV).addClass('dx-empty-area-text').text(this.option(`fieldPanel.texts.${area}FieldArea`))).appendTo(row); } diff --git a/packages/devextreme/js/localization/messages/ar.json b/packages/devextreme/js/localization/messages/ar.json index 0c0bbb248d7a..f1416dcd61f2 100644 --- a/packages/devextreme/js/localization/messages/ar.json +++ b/packages/devextreme/js/localization/messages/ar.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "إفلات حقول البيانات هنا", "dxPivotGrid-rowFieldArea": "إفلات حقول الصف هنا", "dxPivotGrid-filterFieldArea": "إفلات حقول التصفية هنا", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "من {0} إلى {1}", "dxScheduler-ariaLabel": "المجدول. عرض {0}: {1} مع {2} مواعيد", diff --git a/packages/devextreme/js/localization/messages/bg.json b/packages/devextreme/js/localization/messages/bg.json index 2f366d172a26..8aed0475e472 100644 --- a/packages/devextreme/js/localization/messages/bg.json +++ b/packages/devextreme/js/localization/messages/bg.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Пуснете полета с данни тук", "dxPivotGrid-rowFieldArea": "Пуснете полета на реда тук", "dxPivotGrid-filterFieldArea": "Пуснете полета за филтриране тук", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "от {0} до {1}", "dxScheduler-ariaLabel": "Планиращ. Изглед {0}: {1} с {2} срещи", diff --git a/packages/devextreme/js/localization/messages/ca.json b/packages/devextreme/js/localization/messages/ca.json index e6048fce76ea..c8d8929854f9 100644 --- a/packages/devextreme/js/localization/messages/ca.json +++ b/packages/devextreme/js/localization/messages/ca.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Deixar els camps de dades aquí", "dxPivotGrid-rowFieldArea": "Els camps de fila de la fila aquí", "dxPivotGrid-filterFieldArea": "Els camps de filtre de baixada aquí", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "de {0} a {1}", "dxScheduler-ariaLabel": "Planificador. Vista {0}: {1} amb {2} cites", diff --git a/packages/devextreme/js/localization/messages/cs.json b/packages/devextreme/js/localization/messages/cs.json index 8b0101b4a5c4..90d1b6035aff 100644 --- a/packages/devextreme/js/localization/messages/cs.json +++ b/packages/devextreme/js/localization/messages/cs.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Zde vložte pole dat", "dxPivotGrid-rowFieldArea": "Zde vložte pole řádků", "dxPivotGrid-filterFieldArea": "Zde vložte filtr pole", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "od {0} do {1}", "dxScheduler-ariaLabel": "Plánovač. Zobrazení {0}: {1} s {2} schůzkami", diff --git a/packages/devextreme/js/localization/messages/da.json b/packages/devextreme/js/localization/messages/da.json index d7a4c2742cca..dcaf4c5437e3 100644 --- a/packages/devextreme/js/localization/messages/da.json +++ b/packages/devextreme/js/localization/messages/da.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Slip datafelter her", "dxPivotGrid-rowFieldArea": "Slip rækkefelter her", "dxPivotGrid-filterFieldArea": "Slip filterfelter her", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "fra {0} til {1}", "dxScheduler-ariaLabel": "Planlægger. {0} visning: {1} med {2} aftaler", diff --git a/packages/devextreme/js/localization/messages/de.json b/packages/devextreme/js/localization/messages/de.json index d14b0b30d688..9d34fedf0b77 100644 --- a/packages/devextreme/js/localization/messages/de.json +++ b/packages/devextreme/js/localization/messages/de.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Datenfelder hierher ziehen", "dxPivotGrid-rowFieldArea": "Zeilenfelder hierher ziehen", "dxPivotGrid-filterFieldArea": "Filterfelder hierher ziehen", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "von {0} bis {1}", "dxScheduler-ariaLabel": "Planer. {0} Ansicht: {1} mit {2} Terminen", diff --git a/packages/devextreme/js/localization/messages/el.json b/packages/devextreme/js/localization/messages/el.json index 2ace941c689c..2a0291976ece 100644 --- a/packages/devextreme/js/localization/messages/el.json +++ b/packages/devextreme/js/localization/messages/el.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Τοποθετήστε τα πεδία δεδομένων εδώ", "dxPivotGrid-rowFieldArea": "Τοποθετήστε τα πεδία γραμμών εδώ", "dxPivotGrid-filterFieldArea": "Τοποθετήστε τα πεδία φίλτρων εδώ", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "από {0} έως {1}", "dxScheduler-ariaLabel": "Χρονοδιάγραμμα. Προβολή {0}: {1} με {2} ραντεβού", diff --git a/packages/devextreme/js/localization/messages/en.json b/packages/devextreme/js/localization/messages/en.json index f7e629931ce9..600c85c6f71a 100644 --- a/packages/devextreme/js/localization/messages/en.json +++ b/packages/devextreme/js/localization/messages/en.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Drop Data Fields Here", "dxPivotGrid-rowFieldArea": "Drop Row Fields Here", "dxPivotGrid-filterFieldArea": "Drop Filter Fields Here", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "from {0} to {1}", "dxScheduler-ariaLabel": "Scheduler. {0} view: {1} with {2} appointments", diff --git a/packages/devextreme/js/localization/messages/es.json b/packages/devextreme/js/localization/messages/es.json index 9dc3543fe8fc..96636b8ad054 100644 --- a/packages/devextreme/js/localization/messages/es.json +++ b/packages/devextreme/js/localization/messages/es.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Arrastra campos de dato aquí", "dxPivotGrid-rowFieldArea": "Arrastra campos de fila aquí", "dxPivotGrid-filterFieldArea": "Arrastra campos de filtro aquí", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "desde {0} hasta {1}", "dxScheduler-ariaLabel": "Programador. Vista {0}: {1} con {2} citas", diff --git a/packages/devextreme/js/localization/messages/fa.json b/packages/devextreme/js/localization/messages/fa.json index 3191cfcc8315..8c69074ae12b 100644 --- a/packages/devextreme/js/localization/messages/fa.json +++ b/packages/devextreme/js/localization/messages/fa.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "فیلدهای داده ای را به اینجا انتقال دهید (درگ نمایید)", "dxPivotGrid-rowFieldArea": "فیلدهای مربوط به سطر را به اینجا انتقال دهید (درگ نمایید)", "dxPivotGrid-filterFieldArea": "فیلدهای مربوط به فیلتر را به اینجا انتقال دهید (درگ نمایید)", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "از {0} تا {1}", "dxScheduler-ariaLabel": "زمانبندی. نمای {0}: {1} با {2} قرار ملاقات", diff --git a/packages/devextreme/js/localization/messages/fi.json b/packages/devextreme/js/localization/messages/fi.json index 8e90fb99eebf..859c86c87f35 100644 --- a/packages/devextreme/js/localization/messages/fi.json +++ b/packages/devextreme/js/localization/messages/fi.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Pudota tietokentät tähän", "dxPivotGrid-rowFieldArea": "Pudota rivikentät tähän", "dxPivotGrid-filterFieldArea": "Pudota suodatinkentät tähän", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "{0}–{1}", "dxScheduler-ariaLabel": "Kalenteri. {0} näkymä: {1}, {2} tapaamista", diff --git a/packages/devextreme/js/localization/messages/fr.json b/packages/devextreme/js/localization/messages/fr.json index fd4c092b2250..be2247c2687c 100644 --- a/packages/devextreme/js/localization/messages/fr.json +++ b/packages/devextreme/js/localization/messages/fr.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Déposer les champs de données ici", "dxPivotGrid-rowFieldArea": "Déposer les champs de ligne ici", "dxPivotGrid-filterFieldArea": "Déposer les champs de filtre ici", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "de {0} à {1}", "dxScheduler-ariaLabel": "Agenda. {0} vue : {1} avec {2} rendez-vous", diff --git a/packages/devextreme/js/localization/messages/hi.json b/packages/devextreme/js/localization/messages/hi.json index 1c1f79392548..cf6378cce52e 100644 --- a/packages/devextreme/js/localization/messages/hi.json +++ b/packages/devextreme/js/localization/messages/hi.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "डेटा फ़ील्ड यहां छोड़ें", "dxPivotGrid-rowFieldArea": "पंक्ति फ़ील्ड्स को यहां छोड़ें", "dxPivotGrid-filterFieldArea": "फ़िल्टर फ़ील्ड यहां छोड़ें", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "{0} से {1} तक", "dxScheduler-ariaLabel": "अनुसूचक. {0} दृश्य: {1} {2} नियुक्तियों के साथ", diff --git a/packages/devextreme/js/localization/messages/hu.json b/packages/devextreme/js/localization/messages/hu.json index f94c9113dc64..5e8a0690148b 100644 --- a/packages/devextreme/js/localization/messages/hu.json +++ b/packages/devextreme/js/localization/messages/hu.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Húzza az adatmezőket ide", "dxPivotGrid-rowFieldArea": "Húzza a sormezőket ide", "dxPivotGrid-filterFieldArea": "Húzza a szűrőmezőket ide", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "{0}-tól {1}-ig", "dxScheduler-ariaLabel": "Ütemező. {0} nézet: {1}, {2} eseménnyel", diff --git a/packages/devextreme/js/localization/messages/it.json b/packages/devextreme/js/localization/messages/it.json index 9318c530353e..921d88720022 100644 --- a/packages/devextreme/js/localization/messages/it.json +++ b/packages/devextreme/js/localization/messages/it.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Trascina qui i campi dati", "dxPivotGrid-rowFieldArea": "Trascina qui i campi riga", "dxPivotGrid-filterFieldArea": "Trascina qui i campi filtro", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "da {0} a {1}", "dxScheduler-ariaLabel": "Pianificatore. Vista {0}: {1} con {2} appuntamenti", diff --git a/packages/devextreme/js/localization/messages/ja.json b/packages/devextreme/js/localization/messages/ja.json index 80b25947b215..086e3a745449 100644 --- a/packages/devextreme/js/localization/messages/ja.json +++ b/packages/devextreme/js/localization/messages/ja.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "データ フィールドをこちらへドラッグ&ドロップ", "dxPivotGrid-rowFieldArea": "行フィールドをこちらへドラッグ&ドロップ", "dxPivotGrid-filterFieldArea": "フィルター フィールドをこちらへドラッグ&ドロップ", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "{0} から {1} まで", "dxScheduler-ariaLabel": "スケジューラー。{0} ビュー: {2} 件の予定がある {1}", diff --git a/packages/devextreme/js/localization/messages/ko.json b/packages/devextreme/js/localization/messages/ko.json index cf9d06164045..c4ade42c2f02 100644 --- a/packages/devextreme/js/localization/messages/ko.json +++ b/packages/devextreme/js/localization/messages/ko.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "여기에 데이터 필드를 놓으세요", "dxPivotGrid-rowFieldArea": "여기에 행 필드를 놓으세요", "dxPivotGrid-filterFieldArea": "여기에 필터 필드를 놓으세요", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "{0}부터 {1}까지", "dxScheduler-ariaLabel": "스케줄러. {0} 보기: {1}, 일정 {2}개", diff --git a/packages/devextreme/js/localization/messages/lt.json b/packages/devextreme/js/localization/messages/lt.json index 3c8e76cb9281..1cabd91244c2 100644 --- a/packages/devextreme/js/localization/messages/lt.json +++ b/packages/devextreme/js/localization/messages/lt.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Vilkite duomenų laukus čia", "dxPivotGrid-rowFieldArea": "Vilkite eilučių laukus čia", "dxPivotGrid-filterFieldArea": "Vilkite filtrų laukus čia", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "nuo {0} iki {1}", "dxScheduler-ariaLabel": "Planuotuvas. {0} vaizdas: {1} su {2} įvykių", diff --git a/packages/devextreme/js/localization/messages/lv.json b/packages/devextreme/js/localization/messages/lv.json index 0d440c827f0d..a12bab972580 100644 --- a/packages/devextreme/js/localization/messages/lv.json +++ b/packages/devextreme/js/localization/messages/lv.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Velciet datu laukus šeit", "dxPivotGrid-rowFieldArea": "Velciet rindu laukus šeit", "dxPivotGrid-filterFieldArea": "Velciet filtra laukus šeit", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "no {0} līdz {1}", "dxScheduler-ariaLabel": "Plānotājs. {0} skats: {1} ar {2} apmeklējumiem", diff --git a/packages/devextreme/js/localization/messages/nb.json b/packages/devextreme/js/localization/messages/nb.json index 0c547e60b574..a9db3cd1f13d 100644 --- a/packages/devextreme/js/localization/messages/nb.json +++ b/packages/devextreme/js/localization/messages/nb.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Slipp datafelter her", "dxPivotGrid-rowFieldArea": "Slipp radfelter her", "dxPivotGrid-filterFieldArea": "Slipp filterfelter her", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "fra {0} til {1}", "dxScheduler-ariaLabel": "Planlegger. {0}-visning: {1} med {2} avtaler", diff --git a/packages/devextreme/js/localization/messages/nl.json b/packages/devextreme/js/localization/messages/nl.json index 4a7387378b25..096d4d9b6011 100644 --- a/packages/devextreme/js/localization/messages/nl.json +++ b/packages/devextreme/js/localization/messages/nl.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Sleep gegevensvelden hier", "dxPivotGrid-rowFieldArea": "Sleep rijvelden hier", "dxPivotGrid-filterFieldArea": "Sleep filtervelden hier", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "van {0} tot {1}", "dxScheduler-ariaLabel": "Planner. {0} weergave: {1} met {2} afspraken", diff --git a/packages/devextreme/js/localization/messages/pl.json b/packages/devextreme/js/localization/messages/pl.json index 91610788ae6b..b8ed1ffae65e 100644 --- a/packages/devextreme/js/localization/messages/pl.json +++ b/packages/devextreme/js/localization/messages/pl.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Przeciągnij pola danych tutaj", "dxPivotGrid-rowFieldArea": "Przeciągnij pola wiersza/-y tutaj", "dxPivotGrid-filterFieldArea": "Przeciągnij pola filtra tutaj", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "od {0} do {1}", "dxScheduler-ariaLabel": "Harmonogram. Widok {0}: {1}, liczba spotkań: {2}", diff --git a/packages/devextreme/js/localization/messages/pt-BR.json b/packages/devextreme/js/localization/messages/pt-BR.json index df9a1caec94b..496a6aa856ef 100644 --- a/packages/devextreme/js/localization/messages/pt-BR.json +++ b/packages/devextreme/js/localization/messages/pt-BR.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Arraste os campos de dados até aqui", "dxPivotGrid-rowFieldArea": "Arraste os campos de linha até aqui", "dxPivotGrid-filterFieldArea": "Arraste os campos de filtro até aqui", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "de {0} a {1}", "dxScheduler-ariaLabel": "Agendador. Visualização {0}: {1} com {2} compromissos", diff --git a/packages/devextreme/js/localization/messages/pt-PT.json b/packages/devextreme/js/localization/messages/pt-PT.json index 8ede950af7c7..7a51c9f2ac53 100644 --- a/packages/devextreme/js/localization/messages/pt-PT.json +++ b/packages/devextreme/js/localization/messages/pt-PT.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Arraste os campos de dados até aqui", "dxPivotGrid-rowFieldArea": "Arraste os campos de linha até aqui", "dxPivotGrid-filterFieldArea": "Arraste os campos de filtro até aqui", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "de {0} a {1}", "dxScheduler-ariaLabel": "Agendador. Visualização {0}: {1} com {2} compromissos", diff --git a/packages/devextreme/js/localization/messages/pt.json b/packages/devextreme/js/localization/messages/pt.json index 5637d420d6f3..940a30b7502b 100644 --- a/packages/devextreme/js/localization/messages/pt.json +++ b/packages/devextreme/js/localization/messages/pt.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Arraste os campos de dados até aqui", "dxPivotGrid-rowFieldArea": "Arraste os campos de linha até aqui", "dxPivotGrid-filterFieldArea": "Arraste os campos de filtro até aqui", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "de {0} a {1}", "dxScheduler-ariaLabel": "Agendador. Visualização {0}: {1} com {2} compromissos", diff --git a/packages/devextreme/js/localization/messages/ro.json b/packages/devextreme/js/localization/messages/ro.json index 2699cfbb2199..c973681f639f 100644 --- a/packages/devextreme/js/localization/messages/ro.json +++ b/packages/devextreme/js/localization/messages/ro.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Plasați câmpurile de date aici", "dxPivotGrid-rowFieldArea": "Plasați câmpurile rândului aici", "dxPivotGrid-filterFieldArea": "Plasați câmpurile de filtrare aici", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "de la {0} până la {1}", "dxScheduler-ariaLabel": "Planificator. Vedere {0}: {1} cu {2} programări", diff --git a/packages/devextreme/js/localization/messages/ru.json b/packages/devextreme/js/localization/messages/ru.json index d8fc74d72b0a..27b00e1adf60 100644 --- a/packages/devextreme/js/localization/messages/ru.json +++ b/packages/devextreme/js/localization/messages/ru.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Перетащите поля данных cюда", "dxPivotGrid-rowFieldArea": "Перетащите поля строк cюда", "dxPivotGrid-filterFieldArea": "Перетащите поля фильтров cюда", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "с {0} по {1}", "dxScheduler-ariaLabel": "Планировщик. Вид {0}: {1}, записей: {2}", diff --git a/packages/devextreme/js/localization/messages/sl.json b/packages/devextreme/js/localization/messages/sl.json index 334073c40a76..f49b686be821 100644 --- a/packages/devextreme/js/localization/messages/sl.json +++ b/packages/devextreme/js/localization/messages/sl.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Povleci podatke tukaj", "dxPivotGrid-rowFieldArea": "Povleci vrstice tukaj", "dxPivotGrid-filterFieldArea": "Povleci filtre tukaj", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "od {0} do {1}", "dxScheduler-ariaLabel": "Načrtovalnik. Pogled {0}: {1} z {2} dogodki", diff --git a/packages/devextreme/js/localization/messages/sv.json b/packages/devextreme/js/localization/messages/sv.json index 2045b9878b15..267b4ff95f4d 100644 --- a/packages/devextreme/js/localization/messages/sv.json +++ b/packages/devextreme/js/localization/messages/sv.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Släpp datafält här", "dxPivotGrid-rowFieldArea": "Släpp radfält här", "dxPivotGrid-filterFieldArea": "Släpp filterfält här", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "från {0} till {1}", "dxScheduler-ariaLabel": "Schemaläggare. {0}-vy: {1} med {2} bokningar", diff --git a/packages/devextreme/js/localization/messages/tr.json b/packages/devextreme/js/localization/messages/tr.json index bcb5f6d3f6b2..c7469e5b211d 100644 --- a/packages/devextreme/js/localization/messages/tr.json +++ b/packages/devextreme/js/localization/messages/tr.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Veri Alanlarını Buraya Bırak", "dxPivotGrid-rowFieldArea": "Satır Alanlarını Buraya Bırak", "dxPivotGrid-filterFieldArea": "Filtre Alanlarını Buraya Bırak", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "{0} - {1}", "dxScheduler-ariaLabel": "Zamanlayıcı. {0} görünümü: {1}, {2} randevu", diff --git a/packages/devextreme/js/localization/messages/uk.json b/packages/devextreme/js/localization/messages/uk.json index dc1d48262688..95f8529862bd 100644 --- a/packages/devextreme/js/localization/messages/uk.json +++ b/packages/devextreme/js/localization/messages/uk.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Перетягніть поля даних сюди", "dxPivotGrid-rowFieldArea": "Перетягніть поля рядків сюди", "dxPivotGrid-filterFieldArea": "Перетягніть поля фільтрації сюди", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "з {0} по {1}", "dxScheduler-ariaLabel": "Планувальник. Вид {0}: {1}, подій: {2}", diff --git a/packages/devextreme/js/localization/messages/vi.json b/packages/devextreme/js/localization/messages/vi.json index 82168e2b3296..59e701cfde0b 100644 --- a/packages/devextreme/js/localization/messages/vi.json +++ b/packages/devextreme/js/localization/messages/vi.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "Thả các trường dữ liệu vào đây", "dxPivotGrid-rowFieldArea": "Thả các trường của hàng vào đây", "dxPivotGrid-filterFieldArea": "Thả bộ lọc các trường vào đây", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "từ {0} đến {1}", "dxScheduler-ariaLabel": "Lịch biểu. Chế độ xem {0}: {1} với {2} cuộc hẹn", diff --git a/packages/devextreme/js/localization/messages/zh-CN.json b/packages/devextreme/js/localization/messages/zh-CN.json index a60231563edf..6c57f39d4314 100644 --- a/packages/devextreme/js/localization/messages/zh-CN.json +++ b/packages/devextreme/js/localization/messages/zh-CN.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "将数据拖动到此处", "dxPivotGrid-rowFieldArea": "将行字段拖到此处", "dxPivotGrid-filterFieldArea": "拖动筛选字段到此处", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "从 {0} 到 {1}", "dxScheduler-ariaLabel": "日程表。{0} 视图:{1},共 {2} 个日程", diff --git a/packages/devextreme/js/localization/messages/zh-Hans.json b/packages/devextreme/js/localization/messages/zh-Hans.json index 6050b2769248..b760713eef61 100644 --- a/packages/devextreme/js/localization/messages/zh-Hans.json +++ b/packages/devextreme/js/localization/messages/zh-Hans.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "将数据拖动到此处", "dxPivotGrid-rowFieldArea": "将行字段拖到此处", "dxPivotGrid-filterFieldArea": "拖动筛选字段到此处", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "从 {0} 到 {1}", "dxScheduler-ariaLabel": "日程表。{0} 视图:{1},共 {2} 个日程", diff --git a/packages/devextreme/js/localization/messages/zh-tw.json b/packages/devextreme/js/localization/messages/zh-tw.json index 2ffba427171f..8cffe465b044 100644 --- a/packages/devextreme/js/localization/messages/zh-tw.json +++ b/packages/devextreme/js/localization/messages/zh-tw.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "將資料拖動到此處", "dxPivotGrid-rowFieldArea": "將列欄位拖曳至此", "dxPivotGrid-filterFieldArea": "拖動篩選欄位到此處", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "從 {0} 到 {1}", "dxScheduler-ariaLabel": "日程表。{0} 視圖:{1},共 {2} 個日程", diff --git a/packages/devextreme/js/localization/messages/zh.json b/packages/devextreme/js/localization/messages/zh.json index 6885efa6b29c..1af2b7ffa1bb 100644 --- a/packages/devextreme/js/localization/messages/zh.json +++ b/packages/devextreme/js/localization/messages/zh.json @@ -284,6 +284,10 @@ "dxPivotGrid-dataFieldArea": "将数据拖动到此处", "dxPivotGrid-rowFieldArea": "将行字段拖到此处", "dxPivotGrid-filterFieldArea": "拖动筛选字段到此处", + "dxPivotGrid-ariaFieldLabel": "Field: {0}", + "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", + "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "从 {0} 到 {1}", "dxScheduler-ariaLabel": "日程表。{0} 视图:{1},共 {2} 个日程", diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js index 1438b0258bfc..6d5d8d0199bb 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js @@ -239,7 +239,7 @@ QUnit.module('PivotGrid accessibility markup', { assert.equal($outerTable.attr('role'), 'presentation'); }); - QUnit.test('Field-area tables have role="group" and localized aria-label', function(assert) { + QUnit.test('Populated field-area tables are exposed as a labelled menubar', function(assert) { if(!windowUtils.hasWindow()) { assert.expect(0); return; @@ -261,8 +261,7 @@ QUnit.module('PivotGrid accessibility markup', { const expectedLabels = { row: 'Row Fields', column: 'Column Fields', - data: 'Data Fields', - filter: 'Filter Fields' + data: 'Data Fields' }; Object.keys(expectedLabels).forEach((area) => { @@ -270,9 +269,17 @@ QUnit.module('PivotGrid accessibility markup', { .find(`.dx-area-fields[group="${area}"] > table`); assert.strictEqual($table.length, 1, `${area} field table exists`); - assert.strictEqual($table.attr('role'), 'group'); - assert.strictEqual($table.attr('aria-label'), expectedLabels[area]); + assert.strictEqual($table.attr('role'), 'menubar', `${area} field table is a menubar`); + assert.strictEqual($table.attr('aria-label'), expectedLabels[area], `${area} menubar has localized label`); }); + + // The filter area has no fields in this data source; a menubar without + // menu items is invalid ARIA, so its table stays presentational. + const $filterTable = pivotGrid.$element() + .find('.dx-area-fields[group="filter"] > table'); + + assert.strictEqual($filterTable.attr('role'), 'presentation', 'empty filter area table is presentational'); + assert.strictEqual($filterTable.attr('aria-label'), undefined, 'empty filter area table has no aria-label'); }); QUnit.test('Scrollable containers have no tabindex', function(assert) { From eaa408315b5966cc684481dceda5c0b0047df06b Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Thu, 16 Jul 2026 13:14:39 -0300 Subject: [PATCH 2/9] PivotGrid - KBN - Fix ascending sort ARIA field message key typo --- .../js/__internal/grids/pivot_grid/field_chooser/a11y.test.ts | 2 +- .../js/__internal/grids/pivot_grid/field_chooser/a11y.ts | 2 +- packages/devextreme/js/localization/messages/ar.json | 2 +- packages/devextreme/js/localization/messages/bg.json | 2 +- packages/devextreme/js/localization/messages/ca.json | 2 +- packages/devextreme/js/localization/messages/cs.json | 2 +- packages/devextreme/js/localization/messages/da.json | 2 +- packages/devextreme/js/localization/messages/de.json | 2 +- packages/devextreme/js/localization/messages/el.json | 2 +- packages/devextreme/js/localization/messages/en.json | 2 +- packages/devextreme/js/localization/messages/es.json | 2 +- packages/devextreme/js/localization/messages/fa.json | 2 +- packages/devextreme/js/localization/messages/fi.json | 2 +- packages/devextreme/js/localization/messages/fr.json | 2 +- packages/devextreme/js/localization/messages/hi.json | 2 +- packages/devextreme/js/localization/messages/hu.json | 2 +- packages/devextreme/js/localization/messages/it.json | 2 +- packages/devextreme/js/localization/messages/ja.json | 2 +- packages/devextreme/js/localization/messages/ko.json | 2 +- packages/devextreme/js/localization/messages/lt.json | 2 +- packages/devextreme/js/localization/messages/lv.json | 2 +- packages/devextreme/js/localization/messages/nb.json | 2 +- packages/devextreme/js/localization/messages/nl.json | 2 +- packages/devextreme/js/localization/messages/pl.json | 2 +- packages/devextreme/js/localization/messages/pt-BR.json | 2 +- packages/devextreme/js/localization/messages/pt-PT.json | 2 +- packages/devextreme/js/localization/messages/pt.json | 2 +- packages/devextreme/js/localization/messages/ro.json | 2 +- packages/devextreme/js/localization/messages/ru.json | 2 +- packages/devextreme/js/localization/messages/sl.json | 2 +- packages/devextreme/js/localization/messages/sv.json | 2 +- packages/devextreme/js/localization/messages/tr.json | 2 +- packages/devextreme/js/localization/messages/uk.json | 2 +- packages/devextreme/js/localization/messages/vi.json | 2 +- packages/devextreme/js/localization/messages/zh-CN.json | 2 +- packages/devextreme/js/localization/messages/zh-Hans.json | 2 +- packages/devextreme/js/localization/messages/zh-tw.json | 2 +- packages/devextreme/js/localization/messages/zh.json | 2 +- 38 files changed, 38 insertions(+), 38 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.test.ts b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.test.ts index 9f4e74a69d1f..2aa7ec1782c8 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.test.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.test.ts @@ -12,7 +12,7 @@ describe('getFieldItemA11yLabel', () => { en: { 'dxPivotGrid-ariaFieldLabel': 'Field: {0}', 'dxPivotGrid-ariaFieldHeaderFilterLabel': 'Header filter applied', - 'dxPivotGrid-ariaFieldISortAscLabel': 'Sort order: ascending', + 'dxPivotGrid-ariaFieldSortAscLabel': 'Sort order: ascending', 'dxPivotGrid-ariaFieldSortDescLabel': 'Sort order: descending', }, }); diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.ts b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.ts index 69f94216181e..ba96debfe86b 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.ts @@ -6,7 +6,7 @@ import { SORT_ORDER } from './const'; const I18N_KEYS = { fieldLabel: 'dxPivotGrid-ariaFieldLabel', hasHeaderFilter: 'dxPivotGrid-ariaFieldHeaderFilterLabel', - sortingAsc: 'dxPivotGrid-ariaFieldISortAscLabel', + sortingAsc: 'dxPivotGrid-ariaFieldSortAscLabel', sortingDesc: 'dxPivotGrid-ariaFieldSortDescLabel', }; diff --git a/packages/devextreme/js/localization/messages/ar.json b/packages/devextreme/js/localization/messages/ar.json index f1416dcd61f2..a4fc5ae8d3cc 100644 --- a/packages/devextreme/js/localization/messages/ar.json +++ b/packages/devextreme/js/localization/messages/ar.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "إفلات حقول التصفية هنا", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "من {0} إلى {1}", diff --git a/packages/devextreme/js/localization/messages/bg.json b/packages/devextreme/js/localization/messages/bg.json index 8aed0475e472..5e2996351015 100644 --- a/packages/devextreme/js/localization/messages/bg.json +++ b/packages/devextreme/js/localization/messages/bg.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Пуснете полета за филтриране тук", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "от {0} до {1}", diff --git a/packages/devextreme/js/localization/messages/ca.json b/packages/devextreme/js/localization/messages/ca.json index c8d8929854f9..b51a0f2af8e9 100644 --- a/packages/devextreme/js/localization/messages/ca.json +++ b/packages/devextreme/js/localization/messages/ca.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Els camps de filtre de baixada aquí", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "de {0} a {1}", diff --git a/packages/devextreme/js/localization/messages/cs.json b/packages/devextreme/js/localization/messages/cs.json index 90d1b6035aff..799b44364db5 100644 --- a/packages/devextreme/js/localization/messages/cs.json +++ b/packages/devextreme/js/localization/messages/cs.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Zde vložte filtr pole", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "od {0} do {1}", diff --git a/packages/devextreme/js/localization/messages/da.json b/packages/devextreme/js/localization/messages/da.json index dcaf4c5437e3..e8744ef60607 100644 --- a/packages/devextreme/js/localization/messages/da.json +++ b/packages/devextreme/js/localization/messages/da.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Slip filterfelter her", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "fra {0} til {1}", diff --git a/packages/devextreme/js/localization/messages/de.json b/packages/devextreme/js/localization/messages/de.json index 9d34fedf0b77..da189f64d9a2 100644 --- a/packages/devextreme/js/localization/messages/de.json +++ b/packages/devextreme/js/localization/messages/de.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Filterfelder hierher ziehen", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "von {0} bis {1}", diff --git a/packages/devextreme/js/localization/messages/el.json b/packages/devextreme/js/localization/messages/el.json index 2a0291976ece..2eb026325056 100644 --- a/packages/devextreme/js/localization/messages/el.json +++ b/packages/devextreme/js/localization/messages/el.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Τοποθετήστε τα πεδία φίλτρων εδώ", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "από {0} έως {1}", diff --git a/packages/devextreme/js/localization/messages/en.json b/packages/devextreme/js/localization/messages/en.json index 600c85c6f71a..d2a75091b633 100644 --- a/packages/devextreme/js/localization/messages/en.json +++ b/packages/devextreme/js/localization/messages/en.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Drop Filter Fields Here", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "from {0} to {1}", diff --git a/packages/devextreme/js/localization/messages/es.json b/packages/devextreme/js/localization/messages/es.json index 96636b8ad054..63cca532cafa 100644 --- a/packages/devextreme/js/localization/messages/es.json +++ b/packages/devextreme/js/localization/messages/es.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Arrastra campos de filtro aquí", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "desde {0} hasta {1}", diff --git a/packages/devextreme/js/localization/messages/fa.json b/packages/devextreme/js/localization/messages/fa.json index 8c69074ae12b..84747c34cc15 100644 --- a/packages/devextreme/js/localization/messages/fa.json +++ b/packages/devextreme/js/localization/messages/fa.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "فیلدهای مربوط به فیلتر را به اینجا انتقال دهید (درگ نمایید)", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "از {0} تا {1}", diff --git a/packages/devextreme/js/localization/messages/fi.json b/packages/devextreme/js/localization/messages/fi.json index 859c86c87f35..9359c4170f35 100644 --- a/packages/devextreme/js/localization/messages/fi.json +++ b/packages/devextreme/js/localization/messages/fi.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Pudota suodatinkentät tähän", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "{0}–{1}", diff --git a/packages/devextreme/js/localization/messages/fr.json b/packages/devextreme/js/localization/messages/fr.json index be2247c2687c..3ecbcb998195 100644 --- a/packages/devextreme/js/localization/messages/fr.json +++ b/packages/devextreme/js/localization/messages/fr.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Déposer les champs de filtre ici", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "de {0} à {1}", diff --git a/packages/devextreme/js/localization/messages/hi.json b/packages/devextreme/js/localization/messages/hi.json index cf6378cce52e..3f6dc1bfce78 100644 --- a/packages/devextreme/js/localization/messages/hi.json +++ b/packages/devextreme/js/localization/messages/hi.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "फ़िल्टर फ़ील्ड यहां छोड़ें", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "{0} से {1} तक", diff --git a/packages/devextreme/js/localization/messages/hu.json b/packages/devextreme/js/localization/messages/hu.json index 5e8a0690148b..4a941c9f1491 100644 --- a/packages/devextreme/js/localization/messages/hu.json +++ b/packages/devextreme/js/localization/messages/hu.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Húzza a szűrőmezőket ide", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "{0}-tól {1}-ig", diff --git a/packages/devextreme/js/localization/messages/it.json b/packages/devextreme/js/localization/messages/it.json index 921d88720022..159cab37c0ab 100644 --- a/packages/devextreme/js/localization/messages/it.json +++ b/packages/devextreme/js/localization/messages/it.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Trascina qui i campi filtro", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "da {0} a {1}", diff --git a/packages/devextreme/js/localization/messages/ja.json b/packages/devextreme/js/localization/messages/ja.json index 086e3a745449..8e76e2ab0a65 100644 --- a/packages/devextreme/js/localization/messages/ja.json +++ b/packages/devextreme/js/localization/messages/ja.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "フィルター フィールドをこちらへドラッグ&ドロップ", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "{0} から {1} まで", diff --git a/packages/devextreme/js/localization/messages/ko.json b/packages/devextreme/js/localization/messages/ko.json index c4ade42c2f02..4dd8a71874cb 100644 --- a/packages/devextreme/js/localization/messages/ko.json +++ b/packages/devextreme/js/localization/messages/ko.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "여기에 필터 필드를 놓으세요", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "{0}부터 {1}까지", diff --git a/packages/devextreme/js/localization/messages/lt.json b/packages/devextreme/js/localization/messages/lt.json index 1cabd91244c2..d8d0a9a4324e 100644 --- a/packages/devextreme/js/localization/messages/lt.json +++ b/packages/devextreme/js/localization/messages/lt.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Vilkite filtrų laukus čia", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "nuo {0} iki {1}", diff --git a/packages/devextreme/js/localization/messages/lv.json b/packages/devextreme/js/localization/messages/lv.json index a12bab972580..5ac6eecf5aea 100644 --- a/packages/devextreme/js/localization/messages/lv.json +++ b/packages/devextreme/js/localization/messages/lv.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Velciet filtra laukus šeit", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "no {0} līdz {1}", diff --git a/packages/devextreme/js/localization/messages/nb.json b/packages/devextreme/js/localization/messages/nb.json index a9db3cd1f13d..8939e2e28c9f 100644 --- a/packages/devextreme/js/localization/messages/nb.json +++ b/packages/devextreme/js/localization/messages/nb.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Slipp filterfelter her", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "fra {0} til {1}", diff --git a/packages/devextreme/js/localization/messages/nl.json b/packages/devextreme/js/localization/messages/nl.json index 096d4d9b6011..5f975045e198 100644 --- a/packages/devextreme/js/localization/messages/nl.json +++ b/packages/devextreme/js/localization/messages/nl.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Sleep filtervelden hier", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "van {0} tot {1}", diff --git a/packages/devextreme/js/localization/messages/pl.json b/packages/devextreme/js/localization/messages/pl.json index b8ed1ffae65e..10614b63277b 100644 --- a/packages/devextreme/js/localization/messages/pl.json +++ b/packages/devextreme/js/localization/messages/pl.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Przeciągnij pola filtra tutaj", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "od {0} do {1}", diff --git a/packages/devextreme/js/localization/messages/pt-BR.json b/packages/devextreme/js/localization/messages/pt-BR.json index 496a6aa856ef..f9b20ab6eb4e 100644 --- a/packages/devextreme/js/localization/messages/pt-BR.json +++ b/packages/devextreme/js/localization/messages/pt-BR.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Arraste os campos de filtro até aqui", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "de {0} a {1}", diff --git a/packages/devextreme/js/localization/messages/pt-PT.json b/packages/devextreme/js/localization/messages/pt-PT.json index 7a51c9f2ac53..533d65c9bd15 100644 --- a/packages/devextreme/js/localization/messages/pt-PT.json +++ b/packages/devextreme/js/localization/messages/pt-PT.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Arraste os campos de filtro até aqui", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "de {0} a {1}", diff --git a/packages/devextreme/js/localization/messages/pt.json b/packages/devextreme/js/localization/messages/pt.json index 940a30b7502b..9978032f4b04 100644 --- a/packages/devextreme/js/localization/messages/pt.json +++ b/packages/devextreme/js/localization/messages/pt.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Arraste os campos de filtro até aqui", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "de {0} a {1}", diff --git a/packages/devextreme/js/localization/messages/ro.json b/packages/devextreme/js/localization/messages/ro.json index c973681f639f..7190c2cb9eec 100644 --- a/packages/devextreme/js/localization/messages/ro.json +++ b/packages/devextreme/js/localization/messages/ro.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Plasați câmpurile de filtrare aici", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "de la {0} până la {1}", diff --git a/packages/devextreme/js/localization/messages/ru.json b/packages/devextreme/js/localization/messages/ru.json index 27b00e1adf60..afc4286a40db 100644 --- a/packages/devextreme/js/localization/messages/ru.json +++ b/packages/devextreme/js/localization/messages/ru.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Перетащите поля фильтров cюда", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "с {0} по {1}", diff --git a/packages/devextreme/js/localization/messages/sl.json b/packages/devextreme/js/localization/messages/sl.json index f49b686be821..4e86689e08b2 100644 --- a/packages/devextreme/js/localization/messages/sl.json +++ b/packages/devextreme/js/localization/messages/sl.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Povleci filtre tukaj", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "od {0} do {1}", diff --git a/packages/devextreme/js/localization/messages/sv.json b/packages/devextreme/js/localization/messages/sv.json index 267b4ff95f4d..ccb82ae633fa 100644 --- a/packages/devextreme/js/localization/messages/sv.json +++ b/packages/devextreme/js/localization/messages/sv.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Släpp filterfält här", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "från {0} till {1}", diff --git a/packages/devextreme/js/localization/messages/tr.json b/packages/devextreme/js/localization/messages/tr.json index c7469e5b211d..1e35f4886024 100644 --- a/packages/devextreme/js/localization/messages/tr.json +++ b/packages/devextreme/js/localization/messages/tr.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Filtre Alanlarını Buraya Bırak", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "{0} - {1}", diff --git a/packages/devextreme/js/localization/messages/uk.json b/packages/devextreme/js/localization/messages/uk.json index 95f8529862bd..ddac2bfc0809 100644 --- a/packages/devextreme/js/localization/messages/uk.json +++ b/packages/devextreme/js/localization/messages/uk.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Перетягніть поля фільтрації сюди", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "з {0} по {1}", diff --git a/packages/devextreme/js/localization/messages/vi.json b/packages/devextreme/js/localization/messages/vi.json index 59e701cfde0b..1e26061d81e6 100644 --- a/packages/devextreme/js/localization/messages/vi.json +++ b/packages/devextreme/js/localization/messages/vi.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "Thả bộ lọc các trường vào đây", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "từ {0} đến {1}", diff --git a/packages/devextreme/js/localization/messages/zh-CN.json b/packages/devextreme/js/localization/messages/zh-CN.json index 6c57f39d4314..14f6ae69ca3c 100644 --- a/packages/devextreme/js/localization/messages/zh-CN.json +++ b/packages/devextreme/js/localization/messages/zh-CN.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "拖动筛选字段到此处", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "从 {0} 到 {1}", diff --git a/packages/devextreme/js/localization/messages/zh-Hans.json b/packages/devextreme/js/localization/messages/zh-Hans.json index b760713eef61..5eaf1ae8822f 100644 --- a/packages/devextreme/js/localization/messages/zh-Hans.json +++ b/packages/devextreme/js/localization/messages/zh-Hans.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "拖动筛选字段到此处", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "从 {0} 到 {1}", diff --git a/packages/devextreme/js/localization/messages/zh-tw.json b/packages/devextreme/js/localization/messages/zh-tw.json index 8cffe465b044..d9ca42213791 100644 --- a/packages/devextreme/js/localization/messages/zh-tw.json +++ b/packages/devextreme/js/localization/messages/zh-tw.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "拖動篩選欄位到此處", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "從 {0} 到 {1}", diff --git a/packages/devextreme/js/localization/messages/zh.json b/packages/devextreme/js/localization/messages/zh.json index 1af2b7ffa1bb..32c5ebf3baaa 100644 --- a/packages/devextreme/js/localization/messages/zh.json +++ b/packages/devextreme/js/localization/messages/zh.json @@ -286,7 +286,7 @@ "dxPivotGrid-filterFieldArea": "拖动筛选字段到此处", "dxPivotGrid-ariaFieldLabel": "Field: {0}", "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", - "dxPivotGrid-ariaFieldISortAscLabel": "Sort order: ascending", + "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", "dxScheduler-dateRange": "从 {0} 到 {1}", From 745ab500000a37fe4471ca0ff131a351acc8d1a7 Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Fri, 17 Jul 2026 12:49:54 -0300 Subject: [PATCH 3/9] PivotGrid - KBN - Reset stale menubar role on hidden field areas --- .../__internal/grids/pivot_grid/fields_area/m_fields_area.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/fields_area/m_fields_area.ts b/packages/devextreme/js/__internal/grids/pivot_grid/fields_area/m_fields_area.ts index 7ca2d455c2e9..5f2ce5e9afc6 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/fields_area/m_fields_area.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/fields_area/m_fields_area.ts @@ -159,6 +159,11 @@ class FieldsArea extends AreaItem { tableElement.addClass('dx-area-field-container'); if (!isVisible) { + // The reused table element may carry the menubar role from the previous + // render, so it is reset even though the hidden area skips rendering. + tableElement + .attr('role', 'presentation') + .removeAttr('aria-label'); return; } From 81b084a0d3df7ce9de9899bf7dcc51a7563cca9c Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Fri, 17 Jul 2026 13:31:52 -0300 Subject: [PATCH 4/9] PivotGrid - Add axe accessibility tests --- .../tests/accessibility/pivotGrid.ts | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 e2e/testcafe-devextreme/tests/accessibility/pivotGrid.ts diff --git a/e2e/testcafe-devextreme/tests/accessibility/pivotGrid.ts b/e2e/testcafe-devextreme/tests/accessibility/pivotGrid.ts new file mode 100644 index 000000000000..d5a9dc3b1b02 --- /dev/null +++ b/e2e/testcafe-devextreme/tests/accessibility/pivotGrid.ts @@ -0,0 +1,106 @@ +import PivotGrid from 'devextreme-testcafe-models/pivotGrid'; +import { Selector } from 'testcafe'; +import url from '../../helpers/getPageUrl'; +import { createWidget } from '../../helpers/createWidget'; +import { a11yCheck } from '../../helpers/accessibility/utils'; + +fixture.disablePageReloads`PivotGrid - Accessibility` + .page(url(__dirname, '../container.html')); + +const PIVOT_GRID_SELECTOR = '#container'; + +const createConfig = () => ({ + width: 1000, + allowSorting: true, + allowSortingBySummary: true, + allowFiltering: true, + allowExpandAll: true, + showBorders: true, + fieldPanel: { + visible: true, + }, + fieldChooser: { + enabled: true, + height: 500, + }, + dataSource: { + fields: [{ + dataField: 'country', + area: 'filter', + }, { + caption: 'Region', + width: 120, + dataField: 'region', + area: 'row', + }, { + caption: 'City', + dataField: 'city', + width: 150, + area: 'row', + }, { + caption: 'Country', + dataField: 'country', + area: 'column', + }, { + dataField: 'date', + dataType: 'date', + area: 'column', + }, { + groupName: 'date', + groupInterval: 'year', + expanded: true, + area: 'column', + }, { + caption: 'Sales', + dataField: 'amount', + dataType: 'number', + summaryType: 'sum', + area: 'data', + }], + store: [{ + region: 'Africa', + country: 'Egypt', + city: 'Cairo', + amount: 500, + date: new Date('2015-05-26'), + }, { + region: 'South America', + country: 'Argentina', + city: 'Buenos Aires', + amount: 780, + date: new Date('2015-05-07'), + }], + }, +}); + +test('grid with field panel', async (t) => { + await a11yCheck(t, {}, PIVOT_GRID_SELECTOR); +}).before(async () => createWidget('dxPivotGrid', createConfig())); + +test('field chooser popup', async (t) => { + const pivotGrid = new PivotGrid(PIVOT_GRID_SELECTOR); + + await t.click(pivotGrid.getFieldChooserButton()); + + await a11yCheck(t); +}).before(async () => createWidget('dxPivotGrid', createConfig())); + +test('header filter popup', async (t) => { + const pivotGrid = new PivotGrid(PIVOT_GRID_SELECTOR); + const filterIcon = pivotGrid + .getColumnHeaderArea() + .getHeaderFilterIcon() + .element; + + await t.click(filterIcon); + + await a11yCheck(t); +}).before(async () => createWidget('dxPivotGrid', createConfig())); + +test('cell context menu', async (t) => { + const columnHeaderCell = Selector('.dx-pivotgrid-horizontal-headers td[tabindex]'); + + await t.rightClick(columnHeaderCell); + + await a11yCheck(t); +}).before(async () => createWidget('dxPivotGrid', createConfig())); From 827e285516cc05fbd6bc41ea0e7803f0ba7506f7 Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Fri, 17 Jul 2026 13:31:56 -0300 Subject: [PATCH 5/9] PivotGrid - Describe field area keyboard interactions via aria-description --- .../pivot_grid/field_chooser/a11y.test.ts | 33 ++++++++++++------- .../grids/pivot_grid/field_chooser/a11y.ts | 4 +++ .../field_chooser/m_field_chooser.ts | 4 ++- .../pivot_grid/fields_area/m_fields_area.ts | 10 ++++-- .../js/localization/messages/ar.json | 1 + .../js/localization/messages/bg.json | 1 + .../js/localization/messages/ca.json | 1 + .../js/localization/messages/cs.json | 1 + .../js/localization/messages/da.json | 1 + .../js/localization/messages/de.json | 1 + .../js/localization/messages/el.json | 1 + .../js/localization/messages/en.json | 1 + .../js/localization/messages/es.json | 1 + .../js/localization/messages/fa.json | 1 + .../js/localization/messages/fi.json | 1 + .../js/localization/messages/fr.json | 1 + .../js/localization/messages/hi.json | 1 + .../js/localization/messages/hu.json | 1 + .../js/localization/messages/it.json | 1 + .../js/localization/messages/ja.json | 1 + .../js/localization/messages/ko.json | 1 + .../js/localization/messages/lt.json | 1 + .../js/localization/messages/lv.json | 1 + .../js/localization/messages/nb.json | 1 + .../js/localization/messages/nl.json | 1 + .../js/localization/messages/pl.json | 1 + .../js/localization/messages/pt-BR.json | 1 + .../js/localization/messages/pt-PT.json | 1 + .../js/localization/messages/pt.json | 1 + .../js/localization/messages/ro.json | 1 + .../js/localization/messages/ru.json | 1 + .../js/localization/messages/sl.json | 1 + .../js/localization/messages/sv.json | 1 + .../js/localization/messages/tr.json | 1 + .../js/localization/messages/uk.json | 1 + .../js/localization/messages/vi.json | 1 + .../js/localization/messages/zh-CN.json | 1 + .../js/localization/messages/zh-Hans.json | 1 + .../js/localization/messages/zh-tw.json | 1 + .../js/localization/messages/zh.json | 1 + .../pivotGrid.markup.tests.js | 2 ++ 41 files changed, 73 insertions(+), 16 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.test.ts b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.test.ts index 2aa7ec1782c8..cbd896a3d203 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.test.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.test.ts @@ -3,21 +3,24 @@ import { } from '@jest/globals'; import messageLocalization from '@js/common/core/localization/message'; -import { getFieldItemA11yLabel } from './a11y'; +import { getFieldItemA11yLabel, getFieldsAreaA11yDescription } from './a11y'; -describe('getFieldItemA11yLabel', () => { - beforeAll(() => { - // @ts-expect-error load is not declared on the localization typing - messageLocalization.load({ - en: { - 'dxPivotGrid-ariaFieldLabel': 'Field: {0}', - 'dxPivotGrid-ariaFieldHeaderFilterLabel': 'Header filter applied', - 'dxPivotGrid-ariaFieldSortAscLabel': 'Sort order: ascending', - 'dxPivotGrid-ariaFieldSortDescLabel': 'Sort order: descending', - }, - }); +const AREA_DESCRIPTION = 'Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu'; + +beforeAll(() => { + // @ts-expect-error load is not declared on the localization typing + messageLocalization.load({ + en: { + 'dxPivotGrid-ariaFieldLabel': 'Field: {0}', + 'dxPivotGrid-ariaFieldHeaderFilterLabel': 'Header filter applied', + 'dxPivotGrid-ariaFieldSortAscLabel': 'Sort order: ascending', + 'dxPivotGrid-ariaFieldSortDescLabel': 'Sort order: descending', + 'dxPivotGrid-ariaFieldsAreaDescription': AREA_DESCRIPTION, + }, }); +}); +describe('getFieldItemA11yLabel', () => { it('should contain only the field name by default', () => { expect(getFieldItemA11yLabel('Region', {})).toBe('Field: Region'); }); @@ -42,3 +45,9 @@ describe('getFieldItemA11yLabel', () => { .toBe('Field: Region, Header filter applied, Sort order: ascending'); }); }); + +describe('getFieldsAreaA11yDescription', () => { + it('should return the localized interaction description', () => { + expect(getFieldsAreaA11yDescription()).toBe(AREA_DESCRIPTION); + }); +}); diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.ts b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.ts index ba96debfe86b..34e3424d1f76 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/a11y.ts @@ -8,6 +8,7 @@ const I18N_KEYS = { hasHeaderFilter: 'dxPivotGrid-ariaFieldHeaderFilterLabel', sortingAsc: 'dxPivotGrid-ariaFieldSortAscLabel', sortingDesc: 'dxPivotGrid-ariaFieldSortDescLabel', + fieldsAreaDescription: 'dxPivotGrid-ariaFieldsAreaDescription', }; const I18N_MESSAGE_SEPARATOR = ', '; @@ -28,6 +29,9 @@ const getSortingLabel = (sortOrder?: SortOrderType): string | null => { } }; +export const getFieldsAreaA11yDescription = (): string => messageLocalization + .format(I18N_KEYS.fieldsAreaDescription); + export const getFieldItemA11yLabel = ( caption: string, { sortOrder, hasHeaderFilterValue }: FieldItemA11yOptions, diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser.ts b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser.ts index b045f3620481..01a4f1e31d27 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser.ts @@ -12,6 +12,7 @@ import ContextMenu from '@js/ui/context_menu'; import TreeView from '@js/ui/tree_view'; import { foreachDataLevel, getCompareFunction } from '../m_widget_utils'; +import { getFieldsAreaA11yDescription } from './a11y'; import { ATTRIBUTES, CLASSES, ICONS } from './const'; import { FieldChooserBase } from './m_field_chooser_base'; @@ -554,7 +555,8 @@ export class FieldChooser extends FieldChooserBase { const hasFields = !!$container.children().length; $container .attr('role', hasFields ? 'menubar' : null) - .attr('aria-label', hasFields ? that.option(`texts.${area}Fields`) : null); + .attr('aria-label', hasFields ? that.option(`texts.${area}Fields`) : null) + .attr('aria-description', hasFields ? getFieldsAreaA11yDescription() : null); } _renderArea(container, area) { diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/fields_area/m_fields_area.ts b/packages/devextreme/js/__internal/grids/pivot_grid/fields_area/m_fields_area.ts index 5f2ce5e9afc6..ef9448927f70 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/fields_area/m_fields_area.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/fields_area/m_fields_area.ts @@ -9,6 +9,7 @@ import Popup from '@js/ui/popup/ui.popup'; import { capitalize } from '@ts/core/utils/capitalize'; import { AreaItem } from '../area_item/m_area_item'; +import { getFieldsAreaA11yDescription } from '../field_chooser/a11y'; const DIV = '
'; @@ -163,7 +164,8 @@ class FieldsArea extends AreaItem { // render, so it is reset even though the hidden area skips rendering. tableElement .attr('role', 'presentation') - .removeAttr('aria-label'); + .removeAttr('aria-label') + .removeAttr('aria-description'); return; } @@ -188,7 +190,8 @@ class FieldsArea extends AreaItem { row.attr('role', 'presentation'); tableElement .attr('role', 'menubar') - .attr('aria-label', this._getAreaLabel()); + .attr('aria-label', this._getAreaLabel()) + .attr('aria-description', getFieldsAreaA11yDescription()); } else { // A menubar without menu items is invalid ARIA, so an empty area keeps // the plain placeholder text and the table stays presentational. The @@ -196,7 +199,8 @@ class FieldsArea extends AreaItem { // re-renders. tableElement .attr('role', 'presentation') - .removeAttr('aria-label'); + .removeAttr('aria-label') + .removeAttr('aria-description'); $('
').append($(DIV).addClass('dx-empty-area-text').text(this.option(`fieldPanel.texts.${area}FieldArea`))).appendTo(row); } diff --git a/packages/devextreme/js/localization/messages/ar.json b/packages/devextreme/js/localization/messages/ar.json index a4fc5ae8d3cc..1494f4550c7b 100644 --- a/packages/devextreme/js/localization/messages/ar.json +++ b/packages/devextreme/js/localization/messages/ar.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "من {0} إلى {1}", "dxScheduler-ariaLabel": "المجدول. عرض {0}: {1} مع {2} مواعيد", diff --git a/packages/devextreme/js/localization/messages/bg.json b/packages/devextreme/js/localization/messages/bg.json index 5e2996351015..5471b88035de 100644 --- a/packages/devextreme/js/localization/messages/bg.json +++ b/packages/devextreme/js/localization/messages/bg.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "от {0} до {1}", "dxScheduler-ariaLabel": "Планиращ. Изглед {0}: {1} с {2} срещи", diff --git a/packages/devextreme/js/localization/messages/ca.json b/packages/devextreme/js/localization/messages/ca.json index b51a0f2af8e9..b3ad530a7371 100644 --- a/packages/devextreme/js/localization/messages/ca.json +++ b/packages/devextreme/js/localization/messages/ca.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "de {0} a {1}", "dxScheduler-ariaLabel": "Planificador. Vista {0}: {1} amb {2} cites", diff --git a/packages/devextreme/js/localization/messages/cs.json b/packages/devextreme/js/localization/messages/cs.json index 799b44364db5..65d9167147de 100644 --- a/packages/devextreme/js/localization/messages/cs.json +++ b/packages/devextreme/js/localization/messages/cs.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "od {0} do {1}", "dxScheduler-ariaLabel": "Plánovač. Zobrazení {0}: {1} s {2} schůzkami", diff --git a/packages/devextreme/js/localization/messages/da.json b/packages/devextreme/js/localization/messages/da.json index e8744ef60607..beed4beca18b 100644 --- a/packages/devextreme/js/localization/messages/da.json +++ b/packages/devextreme/js/localization/messages/da.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "fra {0} til {1}", "dxScheduler-ariaLabel": "Planlægger. {0} visning: {1} med {2} aftaler", diff --git a/packages/devextreme/js/localization/messages/de.json b/packages/devextreme/js/localization/messages/de.json index da189f64d9a2..000e35e50d45 100644 --- a/packages/devextreme/js/localization/messages/de.json +++ b/packages/devextreme/js/localization/messages/de.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "von {0} bis {1}", "dxScheduler-ariaLabel": "Planer. {0} Ansicht: {1} mit {2} Terminen", diff --git a/packages/devextreme/js/localization/messages/el.json b/packages/devextreme/js/localization/messages/el.json index 2eb026325056..2dea7899684c 100644 --- a/packages/devextreme/js/localization/messages/el.json +++ b/packages/devextreme/js/localization/messages/el.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "από {0} έως {1}", "dxScheduler-ariaLabel": "Χρονοδιάγραμμα. Προβολή {0}: {1} με {2} ραντεβού", diff --git a/packages/devextreme/js/localization/messages/en.json b/packages/devextreme/js/localization/messages/en.json index d2a75091b633..cd72599595bf 100644 --- a/packages/devextreme/js/localization/messages/en.json +++ b/packages/devextreme/js/localization/messages/en.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "from {0} to {1}", "dxScheduler-ariaLabel": "Scheduler. {0} view: {1} with {2} appointments", diff --git a/packages/devextreme/js/localization/messages/es.json b/packages/devextreme/js/localization/messages/es.json index 63cca532cafa..8dfae2975cf1 100644 --- a/packages/devextreme/js/localization/messages/es.json +++ b/packages/devextreme/js/localization/messages/es.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "desde {0} hasta {1}", "dxScheduler-ariaLabel": "Programador. Vista {0}: {1} con {2} citas", diff --git a/packages/devextreme/js/localization/messages/fa.json b/packages/devextreme/js/localization/messages/fa.json index 84747c34cc15..a1c5a186a7c7 100644 --- a/packages/devextreme/js/localization/messages/fa.json +++ b/packages/devextreme/js/localization/messages/fa.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "از {0} تا {1}", "dxScheduler-ariaLabel": "زمانبندی. نمای {0}: {1} با {2} قرار ملاقات", diff --git a/packages/devextreme/js/localization/messages/fi.json b/packages/devextreme/js/localization/messages/fi.json index 9359c4170f35..65cc2ee5d63e 100644 --- a/packages/devextreme/js/localization/messages/fi.json +++ b/packages/devextreme/js/localization/messages/fi.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "{0}–{1}", "dxScheduler-ariaLabel": "Kalenteri. {0} näkymä: {1}, {2} tapaamista", diff --git a/packages/devextreme/js/localization/messages/fr.json b/packages/devextreme/js/localization/messages/fr.json index 3ecbcb998195..6fd233c42e21 100644 --- a/packages/devextreme/js/localization/messages/fr.json +++ b/packages/devextreme/js/localization/messages/fr.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "de {0} à {1}", "dxScheduler-ariaLabel": "Agenda. {0} vue : {1} avec {2} rendez-vous", diff --git a/packages/devextreme/js/localization/messages/hi.json b/packages/devextreme/js/localization/messages/hi.json index 3f6dc1bfce78..8d5b3aff28fb 100644 --- a/packages/devextreme/js/localization/messages/hi.json +++ b/packages/devextreme/js/localization/messages/hi.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "{0} से {1} तक", "dxScheduler-ariaLabel": "अनुसूचक. {0} दृश्य: {1} {2} नियुक्तियों के साथ", diff --git a/packages/devextreme/js/localization/messages/hu.json b/packages/devextreme/js/localization/messages/hu.json index 4a941c9f1491..7b3965d86af5 100644 --- a/packages/devextreme/js/localization/messages/hu.json +++ b/packages/devextreme/js/localization/messages/hu.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "{0}-tól {1}-ig", "dxScheduler-ariaLabel": "Ütemező. {0} nézet: {1}, {2} eseménnyel", diff --git a/packages/devextreme/js/localization/messages/it.json b/packages/devextreme/js/localization/messages/it.json index 159cab37c0ab..044cffdbcdb8 100644 --- a/packages/devextreme/js/localization/messages/it.json +++ b/packages/devextreme/js/localization/messages/it.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "da {0} a {1}", "dxScheduler-ariaLabel": "Pianificatore. Vista {0}: {1} con {2} appuntamenti", diff --git a/packages/devextreme/js/localization/messages/ja.json b/packages/devextreme/js/localization/messages/ja.json index 8e76e2ab0a65..69dd7c165412 100644 --- a/packages/devextreme/js/localization/messages/ja.json +++ b/packages/devextreme/js/localization/messages/ja.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "{0} から {1} まで", "dxScheduler-ariaLabel": "スケジューラー。{0} ビュー: {2} 件の予定がある {1}", diff --git a/packages/devextreme/js/localization/messages/ko.json b/packages/devextreme/js/localization/messages/ko.json index 4dd8a71874cb..b6c7d3c0ad1b 100644 --- a/packages/devextreme/js/localization/messages/ko.json +++ b/packages/devextreme/js/localization/messages/ko.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "{0}부터 {1}까지", "dxScheduler-ariaLabel": "스케줄러. {0} 보기: {1}, 일정 {2}개", diff --git a/packages/devextreme/js/localization/messages/lt.json b/packages/devextreme/js/localization/messages/lt.json index d8d0a9a4324e..3e22b1d98c44 100644 --- a/packages/devextreme/js/localization/messages/lt.json +++ b/packages/devextreme/js/localization/messages/lt.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "nuo {0} iki {1}", "dxScheduler-ariaLabel": "Planuotuvas. {0} vaizdas: {1} su {2} įvykių", diff --git a/packages/devextreme/js/localization/messages/lv.json b/packages/devextreme/js/localization/messages/lv.json index 5ac6eecf5aea..ca52ca02489c 100644 --- a/packages/devextreme/js/localization/messages/lv.json +++ b/packages/devextreme/js/localization/messages/lv.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "no {0} līdz {1}", "dxScheduler-ariaLabel": "Plānotājs. {0} skats: {1} ar {2} apmeklējumiem", diff --git a/packages/devextreme/js/localization/messages/nb.json b/packages/devextreme/js/localization/messages/nb.json index 8939e2e28c9f..8059316faff5 100644 --- a/packages/devextreme/js/localization/messages/nb.json +++ b/packages/devextreme/js/localization/messages/nb.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "fra {0} til {1}", "dxScheduler-ariaLabel": "Planlegger. {0}-visning: {1} med {2} avtaler", diff --git a/packages/devextreme/js/localization/messages/nl.json b/packages/devextreme/js/localization/messages/nl.json index 5f975045e198..19b577b2f8fc 100644 --- a/packages/devextreme/js/localization/messages/nl.json +++ b/packages/devextreme/js/localization/messages/nl.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "van {0} tot {1}", "dxScheduler-ariaLabel": "Planner. {0} weergave: {1} met {2} afspraken", diff --git a/packages/devextreme/js/localization/messages/pl.json b/packages/devextreme/js/localization/messages/pl.json index 10614b63277b..606db7fd3436 100644 --- a/packages/devextreme/js/localization/messages/pl.json +++ b/packages/devextreme/js/localization/messages/pl.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "od {0} do {1}", "dxScheduler-ariaLabel": "Harmonogram. Widok {0}: {1}, liczba spotkań: {2}", diff --git a/packages/devextreme/js/localization/messages/pt-BR.json b/packages/devextreme/js/localization/messages/pt-BR.json index f9b20ab6eb4e..187301ce3c46 100644 --- a/packages/devextreme/js/localization/messages/pt-BR.json +++ b/packages/devextreme/js/localization/messages/pt-BR.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "de {0} a {1}", "dxScheduler-ariaLabel": "Agendador. Visualização {0}: {1} com {2} compromissos", diff --git a/packages/devextreme/js/localization/messages/pt-PT.json b/packages/devextreme/js/localization/messages/pt-PT.json index 533d65c9bd15..c65b214e866b 100644 --- a/packages/devextreme/js/localization/messages/pt-PT.json +++ b/packages/devextreme/js/localization/messages/pt-PT.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "de {0} a {1}", "dxScheduler-ariaLabel": "Agendador. Visualização {0}: {1} com {2} compromissos", diff --git a/packages/devextreme/js/localization/messages/pt.json b/packages/devextreme/js/localization/messages/pt.json index 9978032f4b04..c2d4c9acd648 100644 --- a/packages/devextreme/js/localization/messages/pt.json +++ b/packages/devextreme/js/localization/messages/pt.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "de {0} a {1}", "dxScheduler-ariaLabel": "Agendador. Visualização {0}: {1} com {2} compromissos", diff --git a/packages/devextreme/js/localization/messages/ro.json b/packages/devextreme/js/localization/messages/ro.json index 7190c2cb9eec..5952a344d34f 100644 --- a/packages/devextreme/js/localization/messages/ro.json +++ b/packages/devextreme/js/localization/messages/ro.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "de la {0} până la {1}", "dxScheduler-ariaLabel": "Planificator. Vedere {0}: {1} cu {2} programări", diff --git a/packages/devextreme/js/localization/messages/ru.json b/packages/devextreme/js/localization/messages/ru.json index afc4286a40db..cf99f090ca53 100644 --- a/packages/devextreme/js/localization/messages/ru.json +++ b/packages/devextreme/js/localization/messages/ru.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "с {0} по {1}", "dxScheduler-ariaLabel": "Планировщик. Вид {0}: {1}, записей: {2}", diff --git a/packages/devextreme/js/localization/messages/sl.json b/packages/devextreme/js/localization/messages/sl.json index 4e86689e08b2..642b37fe61a9 100644 --- a/packages/devextreme/js/localization/messages/sl.json +++ b/packages/devextreme/js/localization/messages/sl.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "od {0} do {1}", "dxScheduler-ariaLabel": "Načrtovalnik. Pogled {0}: {1} z {2} dogodki", diff --git a/packages/devextreme/js/localization/messages/sv.json b/packages/devextreme/js/localization/messages/sv.json index ccb82ae633fa..bf5bcace26aa 100644 --- a/packages/devextreme/js/localization/messages/sv.json +++ b/packages/devextreme/js/localization/messages/sv.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "från {0} till {1}", "dxScheduler-ariaLabel": "Schemaläggare. {0}-vy: {1} med {2} bokningar", diff --git a/packages/devextreme/js/localization/messages/tr.json b/packages/devextreme/js/localization/messages/tr.json index 1e35f4886024..be576db493a4 100644 --- a/packages/devextreme/js/localization/messages/tr.json +++ b/packages/devextreme/js/localization/messages/tr.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "{0} - {1}", "dxScheduler-ariaLabel": "Zamanlayıcı. {0} görünümü: {1}, {2} randevu", diff --git a/packages/devextreme/js/localization/messages/uk.json b/packages/devextreme/js/localization/messages/uk.json index ddac2bfc0809..27af6ea144aa 100644 --- a/packages/devextreme/js/localization/messages/uk.json +++ b/packages/devextreme/js/localization/messages/uk.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "з {0} по {1}", "dxScheduler-ariaLabel": "Планувальник. Вид {0}: {1}, подій: {2}", diff --git a/packages/devextreme/js/localization/messages/vi.json b/packages/devextreme/js/localization/messages/vi.json index 1e26061d81e6..aa8e4dac9760 100644 --- a/packages/devextreme/js/localization/messages/vi.json +++ b/packages/devextreme/js/localization/messages/vi.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "từ {0} đến {1}", "dxScheduler-ariaLabel": "Lịch biểu. Chế độ xem {0}: {1} với {2} cuộc hẹn", diff --git a/packages/devextreme/js/localization/messages/zh-CN.json b/packages/devextreme/js/localization/messages/zh-CN.json index 14f6ae69ca3c..9744677d9377 100644 --- a/packages/devextreme/js/localization/messages/zh-CN.json +++ b/packages/devextreme/js/localization/messages/zh-CN.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "从 {0} 到 {1}", "dxScheduler-ariaLabel": "日程表。{0} 视图:{1},共 {2} 个日程", diff --git a/packages/devextreme/js/localization/messages/zh-Hans.json b/packages/devextreme/js/localization/messages/zh-Hans.json index 5eaf1ae8822f..78df5e0e447f 100644 --- a/packages/devextreme/js/localization/messages/zh-Hans.json +++ b/packages/devextreme/js/localization/messages/zh-Hans.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "从 {0} 到 {1}", "dxScheduler-ariaLabel": "日程表。{0} 视图:{1},共 {2} 个日程", diff --git a/packages/devextreme/js/localization/messages/zh-tw.json b/packages/devextreme/js/localization/messages/zh-tw.json index d9ca42213791..0fd718756c76 100644 --- a/packages/devextreme/js/localization/messages/zh-tw.json +++ b/packages/devextreme/js/localization/messages/zh-tw.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "從 {0} 到 {1}", "dxScheduler-ariaLabel": "日程表。{0} 視圖:{1},共 {2} 個日程", diff --git a/packages/devextreme/js/localization/messages/zh.json b/packages/devextreme/js/localization/messages/zh.json index 32c5ebf3baaa..63bed7ec40b7 100644 --- a/packages/devextreme/js/localization/messages/zh.json +++ b/packages/devextreme/js/localization/messages/zh.json @@ -288,6 +288,7 @@ "dxPivotGrid-ariaFieldHeaderFilterLabel": "Header filter applied", "dxPivotGrid-ariaFieldSortAscLabel": "Sort order: ascending", "dxPivotGrid-ariaFieldSortDescLabel": "Sort order: descending", + "dxPivotGrid-ariaFieldsAreaDescription": "Press Enter or Space to sort by the field, Alt + Down arrow to open the header filter, Shift + F10 to open the context menu", "dxScheduler-dateRange": "从 {0} 到 {1}", "dxScheduler-ariaLabel": "日程表。{0} 视图:{1},共 {2} 个日程", diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js index eb4019396c83..2018b9dbc554 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.pivotGrid/pivotGrid.markup.tests.js @@ -271,6 +271,7 @@ QUnit.module('PivotGrid accessibility markup', { assert.strictEqual($table.length, 1, `${area} field table exists`); assert.strictEqual($table.attr('role'), 'menubar', `${area} field table is a menubar`); assert.strictEqual($table.attr('aria-label'), expectedLabels[area], `${area} menubar has localized label`); + assert.ok($table.attr('aria-description'), `${area} menubar has an interaction description`); }); // The filter area has no fields in this data source; a menubar without @@ -280,6 +281,7 @@ QUnit.module('PivotGrid accessibility markup', { assert.strictEqual($filterTable.attr('role'), 'presentation', 'empty filter area table is presentational'); assert.strictEqual($filterTable.attr('aria-label'), undefined, 'empty filter area table has no aria-label'); + assert.strictEqual($filterTable.attr('aria-description'), undefined, 'empty filter area table has no aria-description'); }); QUnit.test('Scrollable containers have no tabindex', function(assert) { From 089cf9713d53af23d9883f2f0ca832c8cae036d7 Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Fri, 17 Jul 2026 13:32:14 -0300 Subject: [PATCH 6/9] PivotGrid - Open field context menu from keyboard --- .../tests/common/pivotGrid/kbn/fields.ts | 53 ++++++++++++++++++- .../field_chooser/m_field_chooser_base.ts | 29 ++++++++++ .../__internal/grids/pivot_grid/m_widget.ts | 15 +++++- 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/e2e/testcafe-devextreme/tests/common/pivotGrid/kbn/fields.ts b/e2e/testcafe-devextreme/tests/common/pivotGrid/kbn/fields.ts index b153dfce0b37..82c00f69979d 100644 --- a/e2e/testcafe-devextreme/tests/common/pivotGrid/kbn/fields.ts +++ b/e2e/testcafe-devextreme/tests/common/pivotGrid/kbn/fields.ts @@ -127,7 +127,9 @@ const createConfig = () => ({ .expect(menubar.count) .eql(1, 'the area has a single menubar') .expect(menubar.getAttribute('aria-label')) - .eql('Row Fields', 'the menubar is labelled with the area name'); + .eql('Row Fields', 'the menubar is labelled with the area name') + .expect(menubar.getAttribute('aria-description')) + .ok('the menubar describes the available keyboard interactions'); await t .expect(firstField.getAttribute('role')) @@ -405,3 +407,52 @@ test('FieldChooser: Should traverse fields in all areas by tab', async (t) => { .expect(dataFirstField.focused) .ok('first field in data area is focused'); }).before(async () => createWidget('dxPivotGrid', createConfig())); + +test('PivotGrid: Should open the context menu by Shift+F10 on a field', async (t) => { + const pivotGrid = new PivotGrid(PIVOT_GRID_SELECTOR); + const firstField = pivotGrid.getRowHeaderArea().getField(0); + const contextMenuItem = Selector('.dx-context-menu .dx-menu-item-text').withText('Show Field Chooser'); + + await t + .click(firstField) + .expect(firstField.focused) + .ok('field is focused after click') + .pressKey('shift+f10') + .expect(contextMenuItem.visible) + .ok('the field context menu is shown after Shift+F10'); +}).before(async () => createWidget('dxPivotGrid', createConfig())); + +test('PivotGrid: Field should have focus after the context menu is closed', async (t) => { + const pivotGrid = new PivotGrid(PIVOT_GRID_SELECTOR); + const firstField = pivotGrid.getRowHeaderArea().getField(0); + const contextMenuItem = Selector('.dx-context-menu .dx-menu-item-text').withText('Show Field Chooser'); + + await t + .click(firstField) + .pressKey('shift+f10') + .expect(contextMenuItem.visible) + .ok('the field context menu is shown after Shift+F10'); + + await t + .pressKey('esc') + .expect(firstField.focused) + .ok('the field is focused after the context menu is closed'); +}).before(async () => createWidget('dxPivotGrid', createConfig())); + +test('FieldChooser: Shift+F10 on a popup field should not open the grid context menu', async (t) => { + const pivotGrid = new PivotGrid(PIVOT_GRID_SELECTOR); + const fieldChooser = pivotGrid.getFieldChooser(); + const contextMenu = Selector('.dx-context-menu .dx-menu-item-text'); + + await t.click(pivotGrid.getFieldChooserButton()); + + const firstField = fieldChooser.getRowAreaItem(0); + + // Parity with the mouse: right-click on the popup fields does not show the + // grid context menu either. + await t + .click(firstField) + .pressKey('shift+f10') + .expect(contextMenu.exists) + .notOk('the grid context menu is not shown for a field chooser popup field'); +}).before(async () => createWidget('dxPivotGrid', createConfig())); diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser_base.ts b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser_base.ts index 1fbd0eed1d7f..3d06f7b11384 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser_base.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser_base.ts @@ -48,6 +48,11 @@ function isFieldNavigationEvent(e): boolean { && !e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey; } +function isContextMenuKeyEvent(e): boolean { + return e.type === 'keydown' + && (e.key === 'ContextMenu' || (e.shiftKey && e.key === 'F10')); +} + class HeaderFilterView extends HeaderFilterViewBase { _getSearchExpr(options, headerFilterOptions) { options.useDefaultSearchExpr = true; @@ -127,6 +132,7 @@ export class FieldChooserBase extends mixinWidget { allowFieldDragging: true, applyChangesMode: 'instantly', state: null, + onFieldContextMenuKeyDown: null, headerFilter: { width: 252, height: 325, @@ -424,6 +430,11 @@ export class FieldChooserBase extends mixinWidget { return; } + if (isContextMenuKeyEvent(e)) { + this._handleFieldContextMenuKey(e, field); + return; + } + if (!isClick) { return; } @@ -555,6 +566,24 @@ export class FieldChooserBase extends mixinWidget { return FIELD_NAVIGATION_DELTAS[key]; } + private _handleFieldContextMenuKey(e, field): void { + const onContextMenuKey = this.option('onFieldContextMenuKeyDown'); + + if (!field.area || !onContextMenuKey) { + return; + } + + const navigation = this._getFieldNavigation(field.area); + + // The event can bubble to another instance subscribed to an ancestor + // element; the field then does not belong to this instance's items. + if (!navigation.getItems().includes(e.currentTarget)) { + return; + } + + onContextMenuKey(e, navigation); + } + private _handleFieldNavigation(e, field): void { if (!field.area) { return; diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts b/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts index f122d1881117..d664a42739c0 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/m_widget.ts @@ -1053,7 +1053,19 @@ class PivotGrid extends Widget { const cell = e.currentTarget; const navigation = this._getCellAreaNavigation(cell); - if (!navigation || !this._contextMenu) { + if (!navigation) { + return; + } + + this._showContextMenuFromKeyboard(e, navigation); + } + + _handleFieldContextMenuKeyDown(e, navigation: RovingTabIndex) { + this._showContextMenuFromKeyboard(e, navigation); + } + + _showContextMenuFromKeyboard(e, navigation: RovingTabIndex) { + if (!this._contextMenu) { return; } @@ -1449,6 +1461,7 @@ class PivotGrid extends Widget { visible: that.option('visible'), // @ts-expect-error ts-error remoteSort: that.option('scrolling.mode') === 'virtual', + onFieldContextMenuKeyDown: that._handleFieldContextMenuKeyDown.bind(that), }; if (that._fieldChooserBase) { From 982706dd39ad84e2805f1f3b3374bca1e4192a3b Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Fri, 17 Jul 2026 13:53:10 -0300 Subject: [PATCH 7/9] PivotGrid - Handle the context menu handler option change and dispatch Shift+F10 in e2e --- .../tests/common/pivotGrid/kbn/fields.ts | 12 +++++++++--- .../pivot_grid/field_chooser/m_field_chooser_base.ts | 3 +++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/e2e/testcafe-devextreme/tests/common/pivotGrid/kbn/fields.ts b/e2e/testcafe-devextreme/tests/common/pivotGrid/kbn/fields.ts index 82c00f69979d..011f13651e09 100644 --- a/e2e/testcafe-devextreme/tests/common/pivotGrid/kbn/fields.ts +++ b/e2e/testcafe-devextreme/tests/common/pivotGrid/kbn/fields.ts @@ -408,6 +408,12 @@ test('FieldChooser: Should traverse fields in all areas by tab', async (t) => { .ok('first field in data area is focused'); }).before(async () => createWidget('dxPivotGrid', createConfig())); +// TestCafe's pressKey does not support function keys (F1-F12), so the Shift+F10 +// shortcut is reproduced by dispatching the keydown event on the focused field. +const SHIFT_F10_KEYDOWN = { + key: 'F10', code: 'F10', shiftKey: true, bubbles: true, cancelable: true, +}; + test('PivotGrid: Should open the context menu by Shift+F10 on a field', async (t) => { const pivotGrid = new PivotGrid(PIVOT_GRID_SELECTOR); const firstField = pivotGrid.getRowHeaderArea().getField(0); @@ -417,7 +423,7 @@ test('PivotGrid: Should open the context menu by Shift+F10 on a field', async (t .click(firstField) .expect(firstField.focused) .ok('field is focused after click') - .pressKey('shift+f10') + .dispatchEvent(firstField, 'keydown', SHIFT_F10_KEYDOWN) .expect(contextMenuItem.visible) .ok('the field context menu is shown after Shift+F10'); }).before(async () => createWidget('dxPivotGrid', createConfig())); @@ -429,7 +435,7 @@ test('PivotGrid: Field should have focus after the context menu is closed', asyn await t .click(firstField) - .pressKey('shift+f10') + .dispatchEvent(firstField, 'keydown', SHIFT_F10_KEYDOWN) .expect(contextMenuItem.visible) .ok('the field context menu is shown after Shift+F10'); @@ -452,7 +458,7 @@ test('FieldChooser: Shift+F10 on a popup field should not open the grid context // grid context menu either. await t .click(firstField) - .pressKey('shift+f10') + .dispatchEvent(firstField, 'keydown', SHIFT_F10_KEYDOWN) .expect(contextMenu.exists) .notOk('the grid context menu is not shown for a field chooser popup field'); }).before(async () => createWidget('dxPivotGrid', createConfig())); diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser_base.ts b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser_base.ts index 3d06f7b11384..38c947799b82 100644 --- a/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser_base.ts +++ b/packages/devextreme/js/__internal/grids/pivot_grid/field_chooser/m_field_chooser_base.ts @@ -193,6 +193,9 @@ export class FieldChooserBase extends mixinWidget { break; case 'applyChangesMode': case 'remoteSort': + case 'onFieldContextMenuKeyDown': + // The context menu handler is read from the options on each keydown, + // so a runtime change requires no re-render. break; case 'state': if (this._skipStateChange || !this._dataSource) { From 1a468919252528895685634f91ad43a097e88293 Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Fri, 17 Jul 2026 19:07:07 -0300 Subject: [PATCH 8/9] PivotGrid - Describe data cells with their row and column headers --- .../a11y/data_cell_description.test.ts | 115 ++++++++++++++++++ .../pivot_grid/a11y/data_cell_description.ts | 101 +++++++++++++++ .../__internal/grids/pivot_grid/m_widget.ts | 7 ++ .../pivotGrid.markup.tests.js | 43 +++++++ 4 files changed, 266 insertions(+) create mode 100644 packages/devextreme/js/__internal/grids/pivot_grid/a11y/data_cell_description.test.ts create mode 100644 packages/devextreme/js/__internal/grids/pivot_grid/a11y/data_cell_description.ts diff --git a/packages/devextreme/js/__internal/grids/pivot_grid/a11y/data_cell_description.test.ts b/packages/devextreme/js/__internal/grids/pivot_grid/a11y/data_cell_description.test.ts new file mode 100644 index 000000000000..7f25d74ac399 --- /dev/null +++ b/packages/devextreme/js/__internal/grids/pivot_grid/a11y/data_cell_description.test.ts @@ -0,0 +1,115 @@ +import { describe, expect, it } from '@jest/globals'; + +import { describeDataCellsWithHeaders } from './data_cell_description'; + +const createSection = (tag: 'thead' | 'tbody', rowsHtml: string): HTMLTableSectionElement => { + const table = document.createElement('table'); + table.innerHTML = `<${tag}>${rowsHtml}`; + return table.querySelector(tag) as HTMLTableSectionElement; +}; + +const getDescribingCells = (cell: HTMLTableCellElement | null): (Element | null)[] => (cell?.getAttribute('aria-describedby') ?? '') + .split(' ') + .filter((id) => !!id) + .map((id) => document.getElementById(id)); + +describe('describeDataCellsWithHeaders', () => { + it('should reference the column header path including colspan groups', () => { + const columns = createSection('thead', ` +
2015Grand Total
Q1Q2
102030
AfricaCairo
Luxor
10
20
2015
Africa
10
20152016
1020
20152016
1020
10