Skip to content

Commit bd9efe6

Browse files
authored
Scheduler: View switcher text is not translated by localization in v25.1.4 (#31114)
1 parent ca94d49 commit bd9efe6

File tree

3 files changed

+131
-10
lines changed

3 files changed

+131
-10
lines changed

packages/devextreme/js/__internal/scheduler/header/m_utils.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import dateLocalization from '@js/common/core/localization/date';
22
import dateUtils from '@js/core/utils/date';
3-
import { isFunction } from '@js/core/utils/type';
3+
import { isFunction, isObject } from '@js/core/utils/type';
4+
import messageLocalization from '@js/localization/message';
45
import type { DateNavigatorTextInfo, Properties } from '@js/ui/scheduler';
56
import type { IntervalOptions, Step } from '@ts/scheduler/header/types';
6-
import type { NormalizedView, ViewType } from '@ts/scheduler/utils/options/types';
7+
import type { NormalizedView, RawViewType, ViewType } from '@ts/scheduler/utils/options/types';
78

89
import type { Direction } from './constants';
910

@@ -324,9 +325,30 @@ const STEP_MAP: Record<ViewType, Step> = {
324325
agenda: 'agenda',
325326
} as const;
326327

327-
export const getStep = (type: ViewType): Step => STEP_MAP[type];
328+
export const getViewName = (view: RawViewType): string | undefined => {
329+
if (isObject(view)) {
330+
return view.name ?? view.type;
331+
}
332+
333+
return view;
334+
};
335+
336+
export const getViewText = (view: RawViewType): string => {
337+
const viewName = getViewName(view);
338+
const viewText = messageLocalization.format(`dxScheduler-switcher${viewName}`);
339+
340+
if (!viewText) {
341+
return viewName ?? '';
342+
}
343+
344+
return viewText;
345+
};
328346

329-
export const getViewName = (view: NormalizedView): string | undefined => view.name ?? view.type;
347+
export const formatViews = (
348+
views: NormalizedView[],
349+
): NormalizedView[] => views.map((view) => ({ ...view, text: getViewText(view) }));
350+
351+
export const getStep = (type: ViewType): Step => STEP_MAP[type];
330352

331353
export const isOneView = (
332354
views: NormalizedView[],
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/* eslint-disable i18n/no-russian-character */
2+
/* eslint-disable spellcheck/spell-checker */
3+
import {
4+
afterEach, describe, expect, it,
5+
} from '@jest/globals';
6+
import type { dxElementWrapper } from '@js/core/renderer';
7+
import $ from '@js/core/renderer';
8+
import { loadMessages, locale } from '@js/localization';
9+
10+
import type { Properties as SchedulerProperties } from '../../../ui/scheduler';
11+
import Scheduler from '../../../ui/scheduler';
12+
13+
const SCHEDULER_CONTAINER_ID = 'schedulerContainer';
14+
15+
const SELECTORS = {
16+
schedulerContainer: '#schedulerContainer',
17+
invisibleState: '.dx-state-invisible',
18+
viewSwitcher: '.dx-scheduler-view-switcher',
19+
viewSwitcherButton: '.dx-scheduler-view-switcher .dx-button',
20+
};
21+
22+
const createScheduler = (options: SchedulerProperties): Promise<{
23+
$container: dxElementWrapper; instance: Scheduler;
24+
}> => new Promise((resolve) => {
25+
const $container = $('<div>')
26+
.attr('id', SCHEDULER_CONTAINER_ID)
27+
.appendTo(document.body);
28+
29+
const instance = new Scheduler($container.get(0) as HTMLDivElement, {
30+
...options,
31+
onContentReady: (): void => {
32+
resolve({ $container, instance });
33+
},
34+
});
35+
});
36+
37+
describe('ViewSwitcher', () => {
38+
afterEach(() => {
39+
const $container = $(SELECTORS.schedulerContainer);
40+
41+
const scheduler = ($container as any).dxScheduler('instance') as Scheduler;
42+
43+
scheduler.dispose();
44+
$container.remove();
45+
});
46+
47+
describe('Localization', () => {
48+
it('should display Russian view names when locale is set to Russian', async () => {
49+
loadMessages({
50+
ru: {
51+
'dxScheduler-switcherDay': 'День',
52+
'dxScheduler-switcherWeek': 'Неделя',
53+
'dxScheduler-switcherMonth': 'Месяц',
54+
},
55+
});
56+
locale('ru');
57+
58+
const { $container } = await createScheduler({
59+
useDropDownViewSwitcher: false,
60+
currentView: 'day',
61+
views: ['day', 'week', 'month'],
62+
});
63+
64+
const buttons = $container.find(SELECTORS.viewSwitcherButton);
65+
const buttonTexts: string[] = [];
66+
buttons.each((_, button) => {
67+
buttonTexts.push($(button).text());
68+
return true;
69+
});
70+
71+
expect(buttonTexts).toContain('День');
72+
expect(buttonTexts).toContain('Неделя');
73+
expect(buttonTexts).toContain('Месяц');
74+
});
75+
76+
it('should display Russian view names in dropdown switcher when locale is set to Russian', async () => {
77+
loadMessages({
78+
ru: {
79+
'dxScheduler-switcherDay': 'День',
80+
'dxScheduler-switcherWeek': 'Неделя',
81+
'dxScheduler-switcherMonth': 'Месяц',
82+
},
83+
});
84+
locale('ru');
85+
86+
const { $container } = await createScheduler({
87+
useDropDownViewSwitcher: true,
88+
currentView: 'day',
89+
views: ['day', 'week', 'month'],
90+
});
91+
92+
const viewSwitcher = $container.find(SELECTORS.viewSwitcher);
93+
const dropdown = viewSwitcher.find('.dx-dropdownbutton');
94+
const buttonText = dropdown.find('.dx-button-text');
95+
96+
expect(buttonText.text()).toBe('День');
97+
});
98+
});
99+
});

packages/devextreme/js/__internal/scheduler/header/m_view_switcher.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { Item as ToolbarItem } from '@js/ui/toolbar';
44
import type { NormalizedView } from '../utils/options/types';
55
import type { SchedulerHeader } from './m_header';
66
import {
7+
formatViews,
78
getViewName,
89
isOneView,
910
} from './m_utils';
@@ -15,7 +16,7 @@ const ClASS = {
1516
};
1617

1718
const getViewsAndSelectedView = (header: SchedulerHeader) => {
18-
const views = header.option('views');
19+
const views = formatViews(header.option('views'));
1920
const selectedView = header.option('currentView').name;
2021
const isSelectedViewInViews = views.some((view) => view.name === selectedView);
2122

@@ -30,7 +31,6 @@ export const getTabViewSwitcher = (header: SchedulerHeader, item): ToolbarItem =
3031

3132
// @ts-expect-error
3233
const stylingMode = isFluent() ? 'outlined' : 'contained';
33-
const items = views.map((view) => ({ ...view, text: view.name }));
3434

3535
return {
3636
widget: 'dxButtonGroup',
@@ -39,7 +39,7 @@ export const getTabViewSwitcher = (header: SchedulerHeader, item): ToolbarItem =
3939
name: 'viewSwitcher',
4040
cssClass: ClASS.container,
4141
options: {
42-
items,
42+
items: views,
4343
keyExpr: 'name',
4444
selectedItemKeys: [selectedView],
4545
stylingMode,
@@ -55,7 +55,7 @@ export const getTabViewSwitcher = (header: SchedulerHeader, item): ToolbarItem =
5555
},
5656
},
5757
...item,
58-
};
58+
} as ToolbarItem;
5959
};
6060

6161
export const getDropDownViewSwitcher = (header: SchedulerHeader, item): ToolbarItem => {
@@ -73,7 +73,7 @@ export const getDropDownViewSwitcher = (header: SchedulerHeader, item): ToolbarI
7373
useSelectMode: true,
7474
keyExpr: 'name',
7575
selectedItemKey: selectedView,
76-
displayExpr: 'name',
76+
displayExpr: 'text',
7777
showArrowIcon: !isOnlyOneView,
7878
elementAttr: {
7979
class: ClASS.dropDownButton,
@@ -102,5 +102,5 @@ export const getDropDownViewSwitcher = (header: SchedulerHeader, item): ToolbarI
102102
},
103103
},
104104
...item,
105-
};
105+
} as ToolbarItem;
106106
};

0 commit comments

Comments
 (0)