Skip to content

Commit

Permalink
feat(useLocale): add useLocale hook to unify locale
Browse files Browse the repository at this point in the history
  • Loading branch information
msyavuz committed Jan 9, 2025
1 parent ace0177 commit 5b22577
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 77 deletions.
52 changes: 31 additions & 21 deletions superset-frontend/src/components/ListView/Filters/DateRange.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ import { RangePicker } from 'src/components/DatePicker';
import { FormLabel } from 'src/components/Form';
import { extendedDayjs } from 'src/utils/dates';
import { Dayjs } from 'dayjs';
import Loading from 'src/components/Loading';
import { AntdThemeProvider } from 'src/components/AntdThemeProvider';
import { useLocale } from 'src/hooks/useLocale';
import { BaseFilter, FilterHandler } from './Base';

interface DateRangeFilterProps extends BaseFilter {
Expand Down Expand Up @@ -56,35 +59,42 @@ function DateRangeFilter(
return [extendedDayjs(value[0]), extendedDayjs(value[1])];
}, [value]);

const locale = useLocale();

useImperativeHandle(ref, () => ({
clearFilter: () => {
setValue(null);
onSubmit([]);
},
}));

if (locale === null) {
return <Loading position="inline-centered" />;
}
return (
<RangeFilterContainer>
<FormLabel>{Header}</FormLabel>
<RangePicker
placeholder={[t('Start date'), t('End date')]}
showTime
value={dayjsValue}
onCalendarChange={(dayjsRange: [Dayjs, Dayjs]) => {
if (!dayjsRange?.[0]?.valueOf() || !dayjsRange?.[1]?.valueOf()) {
setValue(null);
onSubmit([]);
return;
}
const changeValue = [
dayjsRange[0]?.valueOf() ?? 0,
dayjsRange[1]?.valueOf() ?? 0,
] as ValueState;
setValue(changeValue);
onSubmit(changeValue);
}}
/>
</RangeFilterContainer>
<AntdThemeProvider locale={locale}>
<RangeFilterContainer>
<FormLabel>{Header}</FormLabel>
<RangePicker
placeholder={[t('Start date'), t('End date')]}
showTime
value={dayjsValue}
onCalendarChange={(dayjsRange: [Dayjs, Dayjs]) => {
if (!dayjsRange?.[0]?.valueOf() || !dayjsRange?.[1]?.valueOf()) {
setValue(null);
onSubmit([]);
return;
}
const changeValue = [
dayjsRange[0]?.valueOf() ?? 0,
dayjsRange[1]?.valueOf() ?? 0,
] as ValueState;
setValue(changeValue);
onSubmit(changeValue);
}}
/>
</RangeFilterContainer>
</AntdThemeProvider>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
import { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { isInteger } from 'lodash';
import { t, customTimeRangeDecode } from '@superset-ui/core';
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
Expand All @@ -35,23 +33,19 @@ import {
MIDNIGHT,
customTimeRangeEncode,
dttmToDayjs,
LOCALE_MAPPING,
} from 'src/explore/components/controls/DateFilterControl/utils';
import {
CustomRangeKey,
FrameComponentProps,
} from 'src/explore/components/controls/DateFilterControl/types';
import { ExplorePageState } from 'src/explore/types';
import Loading from 'src/components/Loading';
import dayjs, { Dayjs } from 'dayjs';
import { Dayjs } from 'dayjs';
import { AntdThemeProvider } from 'src/components/AntdThemeProvider';
import { Locale } from 'antd-v5/es/locale';
import { useLocale } from 'src/hooks/useLocale';

export function CustomFrame(props: FrameComponentProps) {
const { customRange, matchedFlag } = customTimeRangeDecode(props.value);
const [datePickerLocale, setDatePickerLocale] = useState<
Locale | undefined | null
>(null);
const datePickerLocale = useLocale();
if (!matchedFlag) {
props.onChange(customTimeRangeEncode(customRange));
}
Expand Down Expand Up @@ -113,31 +107,6 @@ export function CustomFrame(props: FrameComponentProps) {
}
}

// check if there is a locale defined for explore
const localFromFlaskBabel = useSelector(
(state: ExplorePageState) => state?.common?.locale,
);

// An undefined datePickerLocale is acceptable if no match is found in the LOCALE_MAPPING[localFromFlaskBabel] lookup
// and will fall back to antd's default locale when the antd DataPicker's prop locale === undefined
// This also protects us from the case where state is populated with a locale that antd locales does not recognize
useEffect(() => {
if (datePickerLocale === null) {
if (localFromFlaskBabel && LOCALE_MAPPING[localFromFlaskBabel]) {
LOCALE_MAPPING[localFromFlaskBabel]()
.then((locale: { default: Locale }) => {
setDatePickerLocale(locale.default);
import(`dayjs/locale/${localFromFlaskBabel}`).then(() => {
dayjs.locale(localFromFlaskBabel);
});
})
.catch(() => setDatePickerLocale(undefined));
} else {
setDatePickerLocale(undefined);
}
}
}, [datePickerLocale, localFromFlaskBabel]);

if (datePickerLocale === null) {
return <Loading position="inline-centered" />;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,23 +141,6 @@ export const MIDNIGHT = extendedDayjs()
.startOf('day')
.format(DAYJS_FORMAT);

export const LOCALE_MAPPING = {
en: () => import('antd-v5/locale/en_US'),
fr: () => import('antd-v5/locale/fr_FR'),
es: () => import('antd-v5/locale/es_ES'),
it: () => import('antd-v5/locale/it_IT'),
zh: () => import('antd-v5/locale/zh_CN'),
ja: () => import('antd-v5/locale/ja_JP'),
de: () => import('antd-v5/locale/de_DE'),
pt: () => import('antd-v5/locale/pt_PT'),
pt_BR: () => import('antd-v5/locale/pt_BR'),
ru: () => import('antd-v5/locale/ru_RU'),
ko: () => import('antd-v5/locale/ko_KR'),
sk: () => import('antd-v5/locale/sk_SK'),
sl: () => import('antd-v5/locale/sl_SI'),
nl: () => import('antd-v5/locale/nl_NL'),
};

export enum DateFilterTestKey {
CommonFrame = 'common-frame',
ModalOverlay = 'modal-overlay',
Expand Down
71 changes: 71 additions & 0 deletions superset-frontend/src/hooks/useLocale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { Locale } from 'antd-v5/es/locale';
import dayjs from 'dayjs';
import { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { ExplorePageState } from 'src/explore/types';

export const LOCALE_MAPPING = {
en: () => import('antd-v5/locale/en_US'),
fr: () => import('antd-v5/locale/fr_FR'),
es: () => import('antd-v5/locale/es_ES'),
it: () => import('antd-v5/locale/it_IT'),
zh: () => import('antd-v5/locale/zh_CN'),
ja: () => import('antd-v5/locale/ja_JP'),
de: () => import('antd-v5/locale/de_DE'),
pt: () => import('antd-v5/locale/pt_PT'),
pt_BR: () => import('antd-v5/locale/pt_BR'),
ru: () => import('antd-v5/locale/ru_RU'),
ko: () => import('antd-v5/locale/ko_KR'),
sk: () => import('antd-v5/locale/sk_SK'),
sl: () => import('antd-v5/locale/sl_SI'),
nl: () => import('antd-v5/locale/nl_NL'),
};

export const useLocale = (): Locale | undefined | null => {
const [datePickerLocale, setDatePickerLocale] = useState<
Locale | undefined | null
>(null);

// Retrieve the locale from Redux store
const localFromFlaskBabel = useSelector(
(state: ExplorePageState) => state?.common?.locale,
);

useEffect(() => {
if (datePickerLocale === null) {
if (localFromFlaskBabel && LOCALE_MAPPING[localFromFlaskBabel]) {
LOCALE_MAPPING[localFromFlaskBabel]()
.then((locale: { default: Locale }) => {
setDatePickerLocale(locale.default);
import(`dayjs/locale/${localFromFlaskBabel}.js`).then(() => {
dayjs.locale(localFromFlaskBabel);
});
})
.catch(() => setDatePickerLocale(undefined));
} else {
setDatePickerLocale(undefined);
}
}
}, [datePickerLocale, localFromFlaskBabel]);

return datePickerLocale;
};
5 changes: 0 additions & 5 deletions superset-frontend/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,6 @@ const plugins = [
chunks: [],
filename: '500.html',
}),
// Dayjs locales to keep
new webpack.ContextReplacementPlugin(
/dayjs[/\\]locale$/,
new RegExp(`^./(${getAvailableTranslationCodes().join('|')})$`),
),
];

if (!process.env.CI) {
Expand Down

0 comments on commit 5b22577

Please sign in to comment.