Skip to content

Commit

Permalink
[adapters] Fix localisation of the placeholder (mui#6547)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexfauquette authored Oct 19, 2022
1 parent 955179e commit a4fedc1
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 6 deletions.
67 changes: 67 additions & 0 deletions packages/x-date-pickers/src/AdapterDateFns/localization.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import * as React from 'react';
import TextField from '@mui/material/TextField';
import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';
import { screen } from '@mui/monorepo/test/utils/createRenderer';
import { expect } from 'chai';
import { createPickerRenderer } from 'test/utils/pickers-utils';
import fr from 'date-fns/locale/fr';
import de from 'date-fns/locale/de';

const testDate = new Date(2018, 4, 15, 9, 35);
const localizedTexts = {
undefined: {
placeholder: 'mm/dd/yyyy hh:mm (a|p)m',
value: '05/15/2018 09:35 am',
},
fr: {
placeholder: 'dd/mm/y hh:mm',
value: '15/05/2018 09:35',
},
de: {
placeholder: 'dd.mm.y hh:mm',
value: '15.05.2018 09:35',
},
};
describe('<AdapterDateFns />', () => {
Object.keys(localizedTexts).forEach((localeKey) => {
const localeName = localeKey === 'undefined' ? 'default' : `"${localeKey}"`;
const localeObject = localeKey === 'undefined' ? undefined : { fr, de }[localeKey];

describe(`test with the ${localeName} locale`, () => {
const { render, adapter } = createPickerRenderer({
clock: 'fake',
adapterName: 'date-fns',
locale: localeObject,
});

it('should have correct placeholder', () => {
render(
<DateTimePicker
renderInput={(params) => <TextField {...params} />}
value={null}
onChange={() => {}}
disableMaskedInput
/>,
);

expect(screen.getByRole('textbox')).to.have.attr(
'placeholder',
localizedTexts[localeKey].placeholder,
);
});

it('should have well formatted value', () => {
render(
<DateTimePicker
renderInput={(params) => <TextField {...params} />}
value={adapter.date(testDate)}
onChange={() => {}}
disableMaskedInput
/>,
);

expect(screen.getByRole('textbox')).to.have.value(localizedTexts[localeKey].value);
});
});
});
});
67 changes: 67 additions & 0 deletions packages/x-date-pickers/src/AdapterDayjs/localization.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import * as React from 'react';
import TextField from '@mui/material/TextField';
import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';
import { screen } from '@mui/monorepo/test/utils/createRenderer';
import { expect } from 'chai';
import { createPickerRenderer } from 'test/utils/pickers-utils';
import 'dayjs/locale/fr';
import 'dayjs/locale/de';

const testDate = new Date(2018, 4, 15, 9, 35);
const localizedTexts = {
undefined: {
placeholder: 'mm/dd/yyyy hh:mm (a|p)m',
value: '05/15/2018 09:35 AM',
},
fr: {
placeholder: 'dd/mm/yyyy hh:mm',
value: '15/05/2018 09:35',
},
de: {
placeholder: 'dd.mm.yyyy hh:mm',
value: '15.05.2018 09:35',
},
};
describe('<AdapterDayjs />', () => {
Object.keys(localizedTexts).forEach((localeKey) => {
const localeName = localeKey === 'undefined' ? 'default' : `"${localeKey}"`;
const localeObject = localeKey === 'undefined' ? undefined : { code: localeKey };

describe(`test with the ${localeName} locale`, () => {
const { render, adapter } = createPickerRenderer({
clock: 'fake',
adapterName: 'dayjs',
locale: localeObject,
});

it('should have correct placeholder', () => {
render(
<DateTimePicker
renderInput={(params) => <TextField {...params} />}
value={null}
onChange={() => {}}
disableMaskedInput
/>,
);

expect(screen.getByRole('textbox')).to.have.attr(
'placeholder',
localizedTexts[localeKey].placeholder,
);
});

it('should have well formatted value', () => {
render(
<DateTimePicker
renderInput={(params) => <TextField {...params} />}
value={adapter.date(testDate)}
onChange={() => {}}
disableMaskedInput
/>,
);

expect(screen.getByRole('textbox')).to.have.value(localizedTexts[localeKey].value);
});
});
});
});
3 changes: 1 addition & 2 deletions packages/x-date-pickers/src/AdapterLuxon/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ const formatTokenMap: MuiFormatTokenMap = {
export class AdapterLuxon extends BaseAdapterLuxon implements MuiPickerFieldAdapter<DateTime> {
public formatTokenMap = formatTokenMap;

// eslint-disable-next-line class-methods-use-this
public expandFormat = (format: string) => {
if (!DateTime.expandFormat) {
throw Error(
Expand All @@ -54,7 +53,7 @@ export class AdapterLuxon extends BaseAdapterLuxon implements MuiPickerFieldAdap
// The returned format can contain `yyyyy` which means year between 4 and 6 digits.
// This value is supported by luxon parser but not luxon formatter.
// To avoid conflicts, we replace it by 4 digits which is enough for most use-cases.
return DateTime.expandFormat(format).replace('yyyyy', 'yyyy');
return DateTime.expandFormat(format, { locale: this.locale }).replace('yyyyy', 'yyyy');
};

// Redefined here just to show how it can be written using expandFormat
Expand Down
65 changes: 65 additions & 0 deletions packages/x-date-pickers/src/AdapterLuxon/localization.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import * as React from 'react';
import TextField from '@mui/material/TextField';
import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';
import { screen } from '@mui/monorepo/test/utils/createRenderer';
import { expect } from 'chai';
import { createPickerRenderer } from 'test/utils/pickers-utils';

const testDate = new Date(2018, 4, 15, 9, 35);
const localizedTexts = {
undefined: {
placeholder: 'm/d/yyyy hh:mm (a|p)m',
value: '5/15/2018 09:35 AM',
},
fr: {
placeholder: 'd/m/yyyy h:m',
value: '15/05/2018 09:35',
},
de: {
placeholder: 'd.m.yyyy h:m',
value: '15.5.2018 09:35',
},
};
describe('<AdapterLuxon />', () => {
Object.keys(localizedTexts).forEach((localeKey) => {
const localeName = localeKey === 'undefined' ? 'default' : `"${localeKey}"`;
const localeObject = localeKey === 'undefined' ? undefined : { code: localeKey };

describe(`test with the ${localeName} locale`, () => {
const { render, adapter } = createPickerRenderer({
clock: 'fake',
adapterName: 'luxon',
locale: localeObject,
});

it('should have correct placeholder', () => {
render(
<DateTimePicker
renderInput={(params) => <TextField {...params} />}
value={null}
onChange={() => {}}
disableMaskedInput
/>,
);

expect(screen.getByRole('textbox')).to.have.attr(
'placeholder',
localizedTexts[localeKey].placeholder,
);
});

it('should have well formatted value', () => {
render(
<DateTimePicker
renderInput={(params) => <TextField {...params} />}
value={adapter.date(testDate)}
onChange={() => {}}
disableMaskedInput
/>,
);

expect(screen.getByRole('textbox')).to.have.value(localizedTexts[localeKey].value);
});
});
});
});
4 changes: 3 additions & 1 deletion packages/x-date-pickers/src/AdapterMoment/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ export class AdapterMoment
.map((token) => {
const firstCharacter = token[0];
if (firstCharacter === 'L' || firstCharacter === ';') {
return this.moment.localeData().longDateFormat(token as LongDateFormatKey);
return this.moment
.localeData(this.getCurrentLocaleCode())
.longDateFormat(token as LongDateFormatKey);
}

return token;
Expand Down
66 changes: 66 additions & 0 deletions packages/x-date-pickers/src/AdapterMoment/localization.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import * as React from 'react';
import TextField from '@mui/material/TextField';
import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';
import { screen } from '@mui/monorepo/test/utils/createRenderer';
import { expect } from 'chai';
import { createPickerRenderer } from 'test/utils/pickers-utils';
import 'moment/locale/de';
import 'moment/locale/fr';

const testDate = new Date(2018, 4, 15, 9, 35);
const localizedTexts = {
en: {
placeholder: 'mm/dd/yyyy hh:mm',
value: '05/15/2018 09:35',
},
fr: {
placeholder: 'dd/mm/yyyy hh:mm',
value: '15/05/2018 09:35',
},
de: {
placeholder: 'dd.mm.yyyy hh:mm',
value: '15.05.2018 09:35',
},
};
describe('<AdapterMoment />', () => {
Object.keys(localizedTexts).forEach((localeKey) => {
const localeObject = { code: localeKey };

describe(`test with the locale "${localeKey}"`, () => {
const { render, adapter } = createPickerRenderer({
clock: 'fake',
adapterName: 'moment',
locale: localeObject,
});

it('should have correct placeholder', () => {
render(
<DateTimePicker
renderInput={(params) => <TextField {...params} />}
value={null}
onChange={() => {}}
disableMaskedInput
/>,
);

expect(screen.getByRole('textbox')).to.have.attr(
'placeholder',
localizedTexts[localeKey].placeholder,
);
});

it('should have well formatted value', () => {
render(
<DateTimePicker
renderInput={(params) => <TextField {...params} />}
value={adapter.date(testDate)}
onChange={() => {}}
disableMaskedInput
/>,
);

expect(screen.getByRole('textbox')).to.have.value(localizedTexts[localeKey].value);
});
});
});
});
16 changes: 13 additions & 3 deletions test/utils/pickers-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon';
import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment';
import { MuiPickersAdapter } from '@mui/x-date-pickers/internals';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import sinon from 'sinon';
import { useControlled } from '@mui/material/utils';

const availableAdapters = {
const availableAdapters: { [key: string]: new (...args: any) => MuiPickersAdapter<any> } = {
'date-fns': AdapterDateFns,
dayjs: AdapterDayjs,
luxon: AdapterLuxon,
Expand Down Expand Up @@ -61,6 +62,7 @@ export const FakeTransitionComponent = React.forwardRef<HTMLDivElement, Transiti
interface CreatePickerRendererOptions extends CreateRendererOptions {
// Set-up locale with date-fns object. Other are deduced from `locale.code`
locale?: Locale;
adapterName?: 'date-fns' | 'dayjs' | 'luxon' | 'moment';
}

export function wrapPickerMount(mount: (node: React.ReactNode) => import('enzyme').ReactWrapper) {
Expand All @@ -70,18 +72,25 @@ export function wrapPickerMount(mount: (node: React.ReactNode) => import('enzyme

export function createPickerRenderer({
locale,
adapterName,
...createRendererOptions
}: CreatePickerRendererOptions = {}) {
const { clock, render: clientRender } = createRenderer(createRendererOptions);

let adapterLocale = adapterToUse.lib === 'date-fns' ? locale : locale?.code;
let adapterLocale = (adapterName ?? adapterToUse.lib) === 'date-fns' ? locale : locale?.code;

if (typeof adapterLocale === 'string' && adapterLocale.length > 2) {
adapterLocale = adapterLocale.slice(0, 2);
}
const adapter = adapterName
? new availableAdapters[adapterName]({ locale: adapterLocale })
: new AdapterClassToUse({ locale: adapterLocale });
function Wrapper({ children }: { children?: React.ReactNode }) {
return (
<LocalizationProvider adapterLocale={adapterLocale} dateAdapter={AdapterClassToUse}>
<LocalizationProvider
adapterLocale={adapterLocale}
dateAdapter={adapterName ? availableAdapters[adapterName] : AdapterClassToUse}
>
{children}
</LocalizationProvider>
);
Expand All @@ -92,6 +101,7 @@ export function createPickerRenderer({
render(node: React.ReactElement, options?: Omit<RenderOptions, 'wrapper'>) {
return clientRender(node, { ...options, wrapper: Wrapper });
},
adapter,
};
}

Expand Down

0 comments on commit a4fedc1

Please sign in to comment.