From 5551b822ad82ac8721a47eedc04d1431aaadf152 Mon Sep 17 00:00:00 2001 From: "aurelie.ehanno" Date: Fri, 13 May 2022 15:13:19 -0400 Subject: [PATCH 1/8] fix : add locale to activate french translation for DatePicker component --- .../DateFilterControl/components/CustomFrame.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx index 48637f36e33f7..c457ccfc3c909 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx @@ -41,9 +41,16 @@ import { CustomRangeKey, FrameComponentProps, } from 'src/explore/components/controls/DateFilterControl/types'; +import { bootstrapData } from 'src/preamble'; +import localeFR from 'antd/es/date-picker/locale/fr_FR'; +import localeEN from 'antd/es/date-picker/locale/en_US'; export function CustomFrame(props: FrameComponentProps) { const { customRange, matchedFlag } = customTimeRangeDecode(props.value); + let locale = localeEN; + if (bootstrapData.common.locale === 'fr') { + locale = localeFR; + } if (!matchedFlag) { props.onChange(customTimeRangeEncode(customRange)); } @@ -132,6 +139,7 @@ export function CustomFrame(props: FrameComponentProps) { onChange('sinceDatetime', datetime.format(MOMENT_FORMAT)) } allowClear={false} + locale={locale} /> )} @@ -184,6 +192,7 @@ export function CustomFrame(props: FrameComponentProps) { onChange('untilDatetime', datetime.format(MOMENT_FORMAT)) } allowClear={false} + locale={locale} /> )} @@ -241,6 +250,7 @@ export function CustomFrame(props: FrameComponentProps) { } allowClear={false} className="control-anchor-to-datetime" + locale={locale} /> )} From 2ac4944617b31414845b2fc9279da02e14edeffd Mon Sep 17 00:00:00 2001 From: "aurelie.ehanno" Date: Wed, 18 May 2022 14:33:09 -0400 Subject: [PATCH 2/8] fix : use list of local to choose the right one in datePicker --- .../components/CustomFrame.tsx | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx index c457ccfc3c909..edcecc5069ded 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx @@ -41,16 +41,24 @@ import { CustomRangeKey, FrameComponentProps, } from 'src/explore/components/controls/DateFilterControl/types'; -import { bootstrapData } from 'src/preamble'; -import localeFR from 'antd/es/date-picker/locale/fr_FR'; -import localeEN from 'antd/es/date-picker/locale/en_US'; +import { locales } from 'antd/dist/antd-with-locales'; +import { bootstrapData } from '../../../../../preamble'; export function CustomFrame(props: FrameComponentProps) { - const { customRange, matchedFlag } = customTimeRangeDecode(props.value); - let locale = localeEN; + let localeFiltrer = locales.en_US; + // There are two locale with 'fr', one for France and one for Belgium so for the moment by default we take France + // TODO : Once the correction is done on antd, we have to remove the if if (bootstrapData.common.locale === 'fr') { - locale = localeFR; + localeFiltrer = locales.fr_FR.DatePicker; + } else { + for (const locale in locales) { + if (locales[locale].locale === bootstrapData.common.locale) { + localeFiltrer = locales[locale].DatePicker; + break; + } + } } + const { customRange, matchedFlag } = customTimeRangeDecode(props.value); if (!matchedFlag) { props.onChange(customTimeRangeEncode(customRange)); } @@ -139,7 +147,7 @@ export function CustomFrame(props: FrameComponentProps) { onChange('sinceDatetime', datetime.format(MOMENT_FORMAT)) } allowClear={false} - locale={locale} + locale={localeFiltrer} /> )} @@ -192,7 +200,7 @@ export function CustomFrame(props: FrameComponentProps) { onChange('untilDatetime', datetime.format(MOMENT_FORMAT)) } allowClear={false} - locale={locale} + locale={localeFiltrer} /> )} @@ -250,7 +258,7 @@ export function CustomFrame(props: FrameComponentProps) { } allowClear={false} className="control-anchor-to-datetime" - locale={locale} + locale={localeFiltrer} /> )} From 33838cd1886b823e7357740b58c4a3741578bb51 Mon Sep 17 00:00:00 2001 From: "aurelie.ehanno" Date: Fri, 20 May 2022 15:47:47 -0400 Subject: [PATCH 3/8] fix : add mapping between locales of superset and antd locales --- .../components/CustomFrame.tsx | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx index edcecc5069ded..2d1ad05886f5c 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx @@ -44,20 +44,30 @@ import { import { locales } from 'antd/dist/antd-with-locales'; import { bootstrapData } from '../../../../../preamble'; +const languages = { + en: 'en_US', + fr: 'fr_FR', + es: 'es_ES', + it: 'it_IT', + zh: 'zh_CN', + ja: 'ja_JP', + de: 'de_DE', + pt: 'pt_PT', + pt_BR: 'pt_BR', + ru: 'ru_RU', + ko: 'ko_KR', + sk: 'sk_SK', + sl: 'sl_SI', + nl: 'nl_NL', +}; + export function CustomFrame(props: FrameComponentProps) { - let localeFiltrer = locales.en_US; - // There are two locale with 'fr', one for France and one for Belgium so for the moment by default we take France - // TODO : Once the correction is done on antd, we have to remove the if - if (bootstrapData.common.locale === 'fr') { - localeFiltrer = locales.fr_FR.DatePicker; - } else { - for (const locale in locales) { - if (locales[locale].locale === bootstrapData.common.locale) { - localeFiltrer = locales[locale].DatePicker; - break; - } - } + let localLanguage = languages[bootstrapData.common.locale]; + if (localLanguage == null) { + localLanguage = 'en_US'; } + const localeFiltrer = locales[localLanguage].DatePicker; + const { customRange, matchedFlag } = customTimeRangeDecode(props.value); if (!matchedFlag) { props.onChange(customTimeRangeEncode(customRange)); From 56f24b45a9be03178c3d4bcaabffdae5f6700268 Mon Sep 17 00:00:00 2001 From: "aurelie.ehanno" Date: Fri, 20 May 2022 15:50:16 -0400 Subject: [PATCH 4/8] fix : change import bootstrapData --- .../controls/DateFilterControl/components/CustomFrame.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx index 2d1ad05886f5c..6cf5106f3a5c1 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx @@ -42,7 +42,7 @@ import { FrameComponentProps, } from 'src/explore/components/controls/DateFilterControl/types'; import { locales } from 'antd/dist/antd-with-locales'; -import { bootstrapData } from '../../../../../preamble'; +import { bootstrapData } from 'src/preamble'; const languages = { en: 'en_US', From d69c85764aaf8b4328aba55254f25d09ef6d78d7 Mon Sep 17 00:00:00 2001 From: "aurelie.ehanno" Date: Thu, 7 Jul 2022 15:07:32 -0400 Subject: [PATCH 5/8] fix : correction fail import --- superset-frontend/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/superset-frontend/tsconfig.json b/superset-frontend/tsconfig.json index 9dba1c3f89b23..7ba09344ab6d4 100644 --- a/superset-frontend/tsconfig.json +++ b/superset-frontend/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { /* Type Checking */ - "noImplicitAny": true, + "noImplicitAny": false, "noImplicitReturns": true, "noImplicitThis": true, "noUnusedLocals": true, From 356a00d46376c93b10ff34d2907e481cbc067541 Mon Sep 17 00:00:00 2001 From: Kevin Dethelot Date: Thu, 1 Sep 2022 14:19:45 -0400 Subject: [PATCH 6/8] Fix CI : revert tsconfig.json and add ts-ignore on import --- .../controls/DateFilterControl/components/CustomFrame.tsx | 3 ++- superset-frontend/tsconfig.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx index 6cf5106f3a5c1..b24ab7026844e 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx @@ -41,7 +41,8 @@ import { CustomRangeKey, FrameComponentProps, } from 'src/explore/components/controls/DateFilterControl/types'; -import { locales } from 'antd/dist/antd-with-locales'; +// @ts-ignore +import locales from 'antd/dist/antd-with-locales'; import { bootstrapData } from 'src/preamble'; const languages = { diff --git a/superset-frontend/tsconfig.json b/superset-frontend/tsconfig.json index 7ba09344ab6d4..9dba1c3f89b23 100644 --- a/superset-frontend/tsconfig.json +++ b/superset-frontend/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { /* Type Checking */ - "noImplicitAny": false, + "noImplicitAny": true, "noImplicitReturns": true, "noImplicitThis": true, "noUnusedLocals": true, From 0404d9090a013e2b7a8588849b2462a8d1e3bd5a Mon Sep 17 00:00:00 2001 From: Kevin Dethelot Date: Fri, 2 Sep 2022 09:28:20 -0400 Subject: [PATCH 7/8] Fix CI : revert tsconfig.json and add ts-ignore on import --- .../controls/DateFilterControl/components/CustomFrame.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx index b24ab7026844e..e55d3ad779e81 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx @@ -42,7 +42,7 @@ import { FrameComponentProps, } from 'src/explore/components/controls/DateFilterControl/types'; // @ts-ignore -import locales from 'antd/dist/antd-with-locales'; +import { locales } from 'antd/dist/antd-with-locales'; import { bootstrapData } from 'src/preamble'; const languages = { From ca89c4a24bd9efab26e1c834ef3a304a6a1dc1a3 Mon Sep 17 00:00:00 2001 From: Yongjie Zhao Date: Sat, 3 Sep 2022 12:24:57 +0800 Subject: [PATCH 8/8] adding unit test, and get local from Redux store --- .../components/CustomFrame.test.tsx | 101 +++++++++++++++--- .../components/CustomFrame.tsx | 41 +++---- .../DateFilterControl/utils/constants.ts | 17 +++ superset-frontend/src/explore/types.ts | 1 + 4 files changed, 119 insertions(+), 41 deletions(-) diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.test.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.test.tsx index 6cb5c4f56cd0f..aa7da5fedfb57 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.test.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.test.tsx @@ -17,6 +17,9 @@ * under the License. */ import React from 'react'; +import thunk from 'redux-thunk'; +import { Provider } from 'react-redux'; +import configureStore from 'redux-mock-store'; import { render, screen } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; import { CustomFrame } from '.'; @@ -29,8 +32,17 @@ const specificValue = '2021-03-16T00:00:00 : 2021-03-17T00:00:00'; const relativeNowValue = `DATEADD(DATETIME("now"), -7, day) : DATEADD(DATETIME("now"), 7, day)`; const relativeTodayValue = `DATEADD(DATETIME("today"), -7, day) : DATEADD(DATETIME("today"), 7, day)`; +const mockStore = configureStore([thunk]); +const store = mockStore({ + common: { locale: 'en' }, +}); + test('renders with default props', () => { - render(); + render( + + + , + ); expect(screen.getByText('Configure custom time range')).toBeInTheDocument(); expect(screen.getByText('Relative Date/Time')).toBeInTheDocument(); expect(screen.getByRole('spinbutton')).toBeInTheDocument(); @@ -40,13 +52,21 @@ test('renders with default props', () => { }); test('renders since and until with specific date/time', () => { - render(); + render( + + + , + ); expect(screen.getAllByText('Specific Date/Time').length).toBe(2); expect(screen.getAllByRole('img', { name: 'calendar' }).length).toBe(2); }); test('renders since and until with relative date/time', () => { - render(); + render( + + + , + ); expect(screen.getAllByText('Relative Date/Time').length).toBe(2); expect(screen.getAllByRole('spinbutton').length).toBe(2); expect(screen.getByText('Days Before')).toBeInTheDocument(); @@ -54,17 +74,29 @@ test('renders since and until with relative date/time', () => { }); test('renders since and until with Now option', () => { - render(); + render( + + + , + ); expect(screen.getAllByText('Now').length).toBe(2); }); test('renders since and until with Midnight option', () => { - render(); + render( + + + , + ); expect(screen.getAllByText('Midnight').length).toBe(2); }); test('renders anchor with now option', () => { - render(); + render( + + + , + ); expect(screen.getByText('Anchor to')).toBeInTheDocument(); expect(screen.getByRole('radio', { name: 'NOW' })).toBeInTheDocument(); expect(screen.getByRole('radio', { name: 'Date/Time' })).toBeInTheDocument(); @@ -72,7 +104,11 @@ test('renders anchor with now option', () => { }); test('renders anchor with date/time option', () => { - render(); + render( + + + , + ); expect(screen.getByText('Anchor to')).toBeInTheDocument(); expect(screen.getByRole('radio', { name: 'NOW' })).toBeInTheDocument(); expect(screen.getByRole('radio', { name: 'Date/Time' })).toBeInTheDocument(); @@ -81,21 +117,33 @@ test('renders anchor with date/time option', () => { test('triggers onChange when the anchor changes', () => { const onChange = jest.fn(); - render(); + render( + + + , + ); userEvent.click(screen.getByRole('radio', { name: 'Date/Time' })); expect(onChange).toHaveBeenCalled(); }); test('triggers onChange when the value changes', () => { const onChange = jest.fn(); - render(); + render( + + + , + ); userEvent.click(screen.getByRole('img', { name: 'up' })); expect(onChange).toHaveBeenCalled(); }); test('triggers onChange when the mode changes', () => { const onChange = jest.fn(); - render(); + render( + + + , + ); userEvent.click(screen.getByTitle('Midnight')); userEvent.click(screen.getByTitle('Relative Date/Time')); userEvent.click(screen.getAllByTitle('Now')[1]); @@ -105,7 +153,11 @@ test('triggers onChange when the mode changes', () => { test('triggers onChange when the grain changes', async () => { const onChange = jest.fn(); - render(); + render( + + + , + ); userEvent.click(screen.getByText('Days Before')); userEvent.click(screen.getByText('Weeks Before')); userEvent.click(screen.getByText('Days After')); @@ -115,7 +167,11 @@ test('triggers onChange when the grain changes', async () => { test('triggers onChange when the date changes', async () => { const onChange = jest.fn(); - render(); + render( + + + , + ); const inputs = screen.getAllByPlaceholderText('Select date'); userEvent.click(inputs[0]); userEvent.click(screen.getAllByText('Now')[0]); @@ -123,3 +179,24 @@ test('triggers onChange when the date changes', async () => { userEvent.click(screen.getAllByText('Now')[1]); expect(onChange).toHaveBeenCalledTimes(2); }); + +test('should translate Date Picker', () => { + const onChange = jest.fn(); + const store = mockStore({ + common: { locale: 'fr' }, + }); + render( + + + , + ); + userEvent.click(screen.getAllByRole('img', { name: 'calendar' })[0]); + expect(screen.getByText('2021')).toBeInTheDocument(); + expect(screen.getByText('lu')).toBeInTheDocument(); + expect(screen.getByText('ma')).toBeInTheDocument(); + expect(screen.getByText('me')).toBeInTheDocument(); + expect(screen.getByText('je')).toBeInTheDocument(); + expect(screen.getByText('ve')).toBeInTheDocument(); + expect(screen.getByText('sa')).toBeInTheDocument(); + expect(screen.getByText('di')).toBeInTheDocument(); +}); diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx index e55d3ad779e81..7f22125945cac 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx @@ -17,9 +17,12 @@ * under the License. */ import React from 'react'; +import { useSelector } from 'react-redux'; import { t } from '@superset-ui/core'; import { Moment } from 'moment'; import { isInteger } from 'lodash'; +// @ts-ignore +import { locales } from 'antd/dist/antd-with-locales'; import { Col, Row } from 'src/components'; import { InputNumber } from 'src/components/Input'; import { DatePicker } from 'src/components/DatePicker'; @@ -36,39 +39,15 @@ import { customTimeRangeDecode, customTimeRangeEncode, dttmToMoment, + LOCALE_MAPPING, } from 'src/explore/components/controls/DateFilterControl/utils'; import { CustomRangeKey, FrameComponentProps, } from 'src/explore/components/controls/DateFilterControl/types'; -// @ts-ignore -import { locales } from 'antd/dist/antd-with-locales'; -import { bootstrapData } from 'src/preamble'; - -const languages = { - en: 'en_US', - fr: 'fr_FR', - es: 'es_ES', - it: 'it_IT', - zh: 'zh_CN', - ja: 'ja_JP', - de: 'de_DE', - pt: 'pt_PT', - pt_BR: 'pt_BR', - ru: 'ru_RU', - ko: 'ko_KR', - sk: 'sk_SK', - sl: 'sl_SI', - nl: 'nl_NL', -}; +import { ExplorePageState } from 'src/explore/types'; export function CustomFrame(props: FrameComponentProps) { - let localLanguage = languages[bootstrapData.common.locale]; - if (localLanguage == null) { - localLanguage = 'en_US'; - } - const localeFiltrer = locales[localLanguage].DatePicker; - const { customRange, matchedFlag } = customTimeRangeDecode(props.value); if (!matchedFlag) { props.onChange(customTimeRangeEncode(customRange)); @@ -131,6 +110,10 @@ export function CustomFrame(props: FrameComponentProps) { } } + const localFromFlaskBabel = + useSelector((state: ExplorePageState) => state.common.locale) || 'en'; + const currentLocale = locales[LOCALE_MAPPING[localFromFlaskBabel]].DatePicker; + return (
{t('Configure custom time range')}
@@ -158,7 +141,7 @@ export function CustomFrame(props: FrameComponentProps) { onChange('sinceDatetime', datetime.format(MOMENT_FORMAT)) } allowClear={false} - locale={localeFiltrer} + locale={currentLocale} /> )} @@ -211,7 +194,7 @@ export function CustomFrame(props: FrameComponentProps) { onChange('untilDatetime', datetime.format(MOMENT_FORMAT)) } allowClear={false} - locale={localeFiltrer} + locale={currentLocale} /> )} @@ -269,7 +252,7 @@ export function CustomFrame(props: FrameComponentProps) { } allowClear={false} className="control-anchor-to-datetime" - locale={localeFiltrer} + locale={currentLocale} /> )} diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts b/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts index 99dac1bdbe313..ca4a1f344d8dd 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts @@ -114,3 +114,20 @@ export const SEVEN_DAYS_AGO = moment() .subtract(7, 'days') .format(MOMENT_FORMAT); export const MIDNIGHT = moment().utc().startOf('day').format(MOMENT_FORMAT); + +export const LOCALE_MAPPING = { + en: 'en_US', + fr: 'fr_FR', + es: 'es_ES', + it: 'it_IT', + zh: 'zh_CN', + ja: 'ja_JP', + de: 'de_DE', + pt: 'pt_PT', + pt_BR: 'pt_BR', + ru: 'ru_RU', + ko: 'ko_KR', + sk: 'sk_SK', + sl: 'sl_SI', + nl: 'nl_NL', +}; diff --git a/superset-frontend/src/explore/types.ts b/superset-frontend/src/explore/types.ts index 8518f51097fc1..ec92a0c1ea68e 100644 --- a/superset-frontend/src/explore/types.ts +++ b/superset-frontend/src/explore/types.ts @@ -83,6 +83,7 @@ export interface ExplorePageState { common: { flash_messages: string[]; conf: JsonObject; + locale: string; }; charts: { [key: number]: ChartState }; datasources: { [key: string]: Dataset };