Skip to content

Commit b28c7e9

Browse files
Merge pull request mui#5187 from oliviertassinari/datepicker-improve-i18n
[DatePicker] Improve the i18n support
2 parents 5a81d38 + c50317a commit b28c7e9

12 files changed

Lines changed: 249 additions & 89 deletions

File tree

docs/src/app/components/pages/components/DatePicker/ExampleInternational.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ let DateTimeFormat;
77
/**
88
* Use the native Intl.DateTimeFormat if available, or a polyfill if not.
99
*/
10-
if (areIntlLocalesSupported(['fr'])) {
10+
if (areIntlLocalesSupported(['fr', 'fa-IR'])) {
1111
DateTimeFormat = global.Intl.DateTimeFormat;
1212
} else {
1313
const IntlPolyfill = require('intl');
1414
DateTimeFormat = IntlPolyfill.DateTimeFormat;
1515
require('intl/locale-data/jsonp/fr');
16+
require('intl/locale-data/jsonp/fa-IR');
1617
}
1718

1819
/**
@@ -34,6 +35,13 @@ const DatePickerExampleInternational = () => (
3435
cancelLabel="Annuler"
3536
locale="fr"
3637
/>
38+
<DatePicker
39+
hintText="fa-IR locale"
40+
DateTimeFormat={DateTimeFormat}
41+
okLabel="خوب"
42+
cancelLabel="لغو کردن"
43+
locale="fa-IR"
44+
/>
3745
<DatePicker
3846
hintText="en-US locale"
3947
locale="en-US"

src/DatePicker/Calendar.js

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {
1717
dateTimeFormat,
1818
isAfterDate,
1919
isBeforeDate,
20-
getWeekArray,
2120
getFirstDayOfMonth,
2221
localizedWeekday,
2322
monthDiff,
@@ -222,21 +221,23 @@ class Calendar extends Component {
222221
};
223222

224223
yearSelector() {
225-
if (!this.props.disableYearSelection) return (
226-
<CalendarYear
227-
key={'years'}
228-
displayDate={this.state.displayDate}
229-
onTouchTapYear={this.handleTouchTapYear}
230-
selectedDate={this.state.selectedDate}
231-
minDate={this.props.minDate}
232-
maxDate={this.props.maxDate}
233-
/>
234-
);
224+
if (!this.props.disableYearSelection) {
225+
return (
226+
<CalendarYear
227+
key="years"
228+
DateTimeFormat={this.props.DateTimeFormat}
229+
locale={this.props.locale}
230+
onTouchTapYear={this.handleTouchTapYear}
231+
selectedDate={this.state.selectedDate}
232+
minDate={this.props.minDate}
233+
maxDate={this.props.maxDate}
234+
/>
235+
);
236+
}
235237
}
236238

237239
render() {
238240
const {prepareStyles} = this.context.muiTheme;
239-
const weekCount = getWeekArray(this.state.displayDate, this.props.firstDayOfWeek).length;
240241
const toolbarInteractions = this.getToolbarInteractions();
241242
const isLandscape = this.props.mode === 'landscape';
242243
const {calendarTextColor} = this.context.muiTheme.datePicker;
@@ -291,6 +292,8 @@ class Calendar extends Component {
291292
const weekTitleDayStyle = prepareStyles(styles.weekTitleDay);
292293

293294
const {
295+
minDate,
296+
maxDate,
294297
cancelLabel,
295298
DateTimeFormat,
296299
firstDayOfWeek,
@@ -315,7 +318,6 @@ class Calendar extends Component {
315318
monthDaySelected={this.state.displayMonthDay}
316319
mode={this.props.mode}
317320
selectedDate={this.state.selectedDate}
318-
weekCount={weekCount}
319321
/>
320322
<div style={prepareStyles(styles.calendar)}>
321323
{this.state.displayMonthDay &&
@@ -337,11 +339,13 @@ class Calendar extends Component {
337339
</div>
338340
<SlideInTransitionGroup direction={this.state.transitionDirection} style={styles.transitionSlide}>
339341
<CalendarMonth
342+
DateTimeFormat={DateTimeFormat}
343+
locale={locale}
340344
displayDate={this.state.displayDate}
341345
firstDayOfWeek={this.props.firstDayOfWeek}
342346
key={this.state.displayDate.toDateString()}
343-
minDate={this.props.minDate}
344-
maxDate={this.props.maxDate}
347+
minDate={minDate}
348+
maxDate={maxDate}
345349
onTouchTapDay={this.handleTouchTapDay}
346350
ref="calendar"
347351
selectedDate={this.state.selectedDate}

src/DatePicker/CalendarMonth.js

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,34 @@ import React, {Component, PropTypes} from 'react';
22
import {isBetweenDates, isEqualDate, getWeekArray} from './dateUtils';
33
import DayButton from './DayButton';
44

5+
const styles = {
6+
root: {
7+
display: 'flex',
8+
flexDirection: 'column',
9+
justifyContent: 'flex-start',
10+
fontWeight: 400,
11+
height: 228,
12+
lineHeight: 2,
13+
position: 'relative',
14+
textAlign: 'center',
15+
MozPaddingStart: 0,
16+
},
17+
week: {
18+
display: 'flex',
19+
flexDirection: 'row',
20+
justifyContent: 'space-around',
21+
height: 34,
22+
marginBottom: 2,
23+
},
24+
};
25+
526
class CalendarMonth extends Component {
627
static propTypes = {
28+
DateTimeFormat: PropTypes.func.isRequired,
729
autoOk: PropTypes.bool,
830
displayDate: PropTypes.object.isRequired,
931
firstDayOfWeek: PropTypes.number,
32+
locale: PropTypes.string.isRequired,
1033
maxDate: PropTypes.object,
1134
minDate: PropTypes.object,
1235
onTouchTapDay: PropTypes.func,
@@ -19,7 +42,9 @@ class CalendarMonth extends Component {
1942
}
2043

2144
handleTouchTapDay = (event, date) => {
22-
if (this.props.onTouchTapDay) this.props.onTouchTapDay(event, date);
45+
if (this.props.onTouchTapDay) {
46+
this.props.onTouchTapDay(event, date);
47+
}
2348
};
2449

2550
shouldDisableDate(day) {
@@ -35,16 +60,22 @@ class CalendarMonth extends Component {
3560

3661
return weekArray.map((week, i) => {
3762
return (
38-
<div key={i} style={this.styles.week}>
63+
<div key={i} style={styles.week}>
3964
{this.getDayElements(week, i)}
4065
</div>
4166
);
4267
}, this);
4368
}
4469

4570
getDayElements(week, i) {
71+
const {
72+
DateTimeFormat,
73+
locale,
74+
selectedDate,
75+
} = this.props;
76+
4677
return week.map((day, j) => {
47-
const isSameDate = isEqualDate(this.props.selectedDate, day);
78+
const isSameDate = isEqualDate(selectedDate, day);
4879
const disabled = this.shouldDisableDate(day);
4980
const selected = !disabled && isSameDate;
5081

@@ -54,6 +85,8 @@ class CalendarMonth extends Component {
5485

5586
return (
5687
<DayButton
88+
DateTimeFormat={DateTimeFormat}
89+
locale={locale}
5790
date={day}
5891
disabled={disabled}
5992
key={`db${(i + j)}`}
@@ -64,30 +97,9 @@ class CalendarMonth extends Component {
6497
}, this);
6598
}
6699

67-
styles = {
68-
root: {
69-
display: 'flex',
70-
flexDirection: 'column',
71-
justifyContent: 'flex-start',
72-
fontWeight: 400,
73-
height: 228,
74-
lineHeight: 2,
75-
position: 'relative',
76-
textAlign: 'center',
77-
MozPaddingStart: 0,
78-
},
79-
week: {
80-
display: 'flex',
81-
flexDirection: 'row',
82-
justifyContent: 'space-around',
83-
height: 34,
84-
marginBottom: 2,
85-
},
86-
};
87-
88100
render() {
89101
return (
90-
<div style={this.styles.root}>
102+
<div style={styles.root}>
91103
{this.getWeekElements()}
92104
</div>
93105
);

src/DatePicker/CalendarYear.js

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import {cloneDate} from './dateUtils';
55

66
class CalendarYear extends Component {
77
static propTypes = {
8-
displayDate: PropTypes.object.isRequired,
9-
maxDate: PropTypes.object,
10-
minDate: PropTypes.object,
8+
DateTimeFormat: PropTypes.func.isRequired,
9+
locale: PropTypes.string.isRequired,
10+
maxDate: PropTypes.object.isRequired,
11+
minDate: PropTypes.object.isRequired,
1112
onTouchTapYear: PropTypes.func,
1213
selectedDate: PropTypes.object.isRequired,
1314
wordings: PropTypes.object,
@@ -26,27 +27,41 @@ class CalendarYear extends Component {
2627
}
2728

2829
getYears() {
29-
const minYear = this.props.minDate.getFullYear();
30-
const maxYear = this.props.maxDate.getFullYear();
31-
30+
const {
31+
DateTimeFormat,
32+
locale,
33+
minDate,
34+
maxDate,
35+
selectedDate,
36+
} = this.props;
37+
38+
const minYear = minDate.getFullYear();
39+
const maxYear = maxDate.getFullYear();
3240
const years = [];
33-
const dateCheck = cloneDate(this.props.selectedDate);
41+
const dateCheck = cloneDate(selectedDate);
42+
3443
for (let year = minYear; year <= maxYear; year++) {
3544
dateCheck.setFullYear(year);
36-
const selected = this.props.selectedDate.getFullYear() === year;
37-
let selectedProps = {};
45+
const selected = selectedDate.getFullYear() === year;
46+
const selectedProps = {};
3847
if (selected) {
39-
selectedProps = {ref: 'selectedYearButton'};
48+
selectedProps.ref = 'selectedYearButton';
4049
}
4150

51+
const yearFormated = new DateTimeFormat(locale, {
52+
year: 'numeric',
53+
}).format(dateCheck);
54+
4255
const yearButton = (
4356
<YearButton
4457
key={`yb${year}`}
4558
onTouchTap={this.handleTouchTapYear}
4659
selected={selected}
4760
year={year}
4861
{...selectedProps}
49-
/>
62+
>
63+
{yearFormated}
64+
</YearButton>
5065
);
5166

5267
years.push(yearButton);
@@ -56,7 +71,9 @@ class CalendarYear extends Component {
5671
}
5772

5873
scrollToSelectedYear() {
59-
if (this.refs.selectedYearButton === undefined) return;
74+
if (this.refs.selectedYearButton === undefined) {
75+
return;
76+
}
6077

6178
const container = ReactDOM.findDOMNode(this);
6279
const yearButtonNode = ReactDOM.findDOMNode(this.refs.selectedYearButton);
@@ -69,16 +86,22 @@ class CalendarYear extends Component {
6986
}
7087

7188
handleTouchTapYear = (event, year) => {
72-
if (this.props.onTouchTapYear) this.props.onTouchTapYear(event, year);
89+
if (this.props.onTouchTapYear) {
90+
this.props.onTouchTapYear(event, year);
91+
}
7392
};
7493

7594
render() {
76-
const years = this.getYears();
77-
const backgroundColor = this.context.muiTheme.datePicker.calendarYearBackgroundColor;
78-
const {prepareStyles} = this.context.muiTheme;
95+
const {
96+
prepareStyles,
97+
datePicker: {
98+
calendarYearBackgroundColor,
99+
},
100+
} = this.context.muiTheme;
101+
79102
const styles = {
80103
root: {
81-
backgroundColor: backgroundColor,
104+
backgroundColor: calendarYearBackgroundColor,
82105
height: 'inherit',
83106
lineHeight: '35px',
84107
overflowX: 'hidden',
@@ -96,7 +119,7 @@ class CalendarYear extends Component {
96119
return (
97120
<div style={prepareStyles(styles.root)}>
98121
<div style={prepareStyles(styles.child)}>
99-
{years}
122+
{this.getYears()}
100123
</div>
101124
</div>
102125
);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* eslint-env mocha */
2+
3+
import React from 'react';
4+
import {shallow} from 'enzyme';
5+
import {assert} from 'chai';
6+
import getMuiTheme from '../styles/getMuiTheme';
7+
import {dateTimeFormat, addYears} from './dateUtils';
8+
import CalendarYear from './CalendarYear';
9+
import YearButton from './YearButton';
10+
11+
describe('<CalendarYear />', () => {
12+
const muiTheme = getMuiTheme();
13+
const shallowWithContext = (node) => shallow(node, {context: {muiTheme}});
14+
15+
describe('i18n', () => {
16+
it('should format the year correctly', () => {
17+
const date = new Date(1448967059892); // Tue, 01 Dec 2015 10:50:59 GMT
18+
const minDate = addYears(date, -100);
19+
const maxDate = addYears(date, 100);
20+
21+
const wrapper = shallowWithContext(
22+
<CalendarYear
23+
selectedDate={date}
24+
DateTimeFormat={dateTimeFormat}
25+
minDate={minDate}
26+
maxDate={maxDate}
27+
locale="en-US"
28+
/>
29+
);
30+
31+
assert.strictEqual(wrapper.find(YearButton).length, 201);
32+
assert.strictEqual(wrapper.find(YearButton).at(0).props().children, '1915');
33+
});
34+
});
35+
});

0 commit comments

Comments
 (0)