From 7cc3c32eb2fbeb92abc2b415287776402b545d91 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Mon, 1 Sep 2025 11:29:45 +0200 Subject: [PATCH] fix: date localizations for chart (#10581) Adds date localization to the charts on the analytics page. In doing so, I have extracted the default locales that we allow the user to set into constants, so that we can reference it from other places. I have also sorted the list and added my personal favorite format (ja) to it. Because we have multiple charts on the analytics page, it felt weird that only one chart should follow your preferred format. It also aligns the existing charts' tooltip date format with the new one (`P` instead of `PPP`). In short: previously, the charts would show you only your system locale (I think), which for me defaults to en-US, regardless of what setting you'd set in your profile. Now we respect your setting as long as it's one of the default ones. Before (date formatting is en-US): image After (date formatting is sv-SE): image --- .../LineChart/createChartOptions.ts | 8 ++++- .../CreationArchiveChart.tsx | 6 ++++ .../component/insights/getDateFnsLocale.ts | 33 +++++++++++++++++++ .../user/Profile/ProfileTab/ProfileTab.tsx | 14 ++------ frontend/src/constants/defaultLocales.ts | 13 ++++++++ 5 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 frontend/src/component/insights/getDateFnsLocale.ts create mode 100644 frontend/src/constants/defaultLocales.ts diff --git a/frontend/src/component/insights/components/LineChart/createChartOptions.ts b/frontend/src/component/insights/components/LineChart/createChartOptions.ts index 82a515ff67..7b9abc0022 100644 --- a/frontend/src/component/insights/components/LineChart/createChartOptions.ts +++ b/frontend/src/component/insights/components/LineChart/createChartOptions.ts @@ -4,6 +4,7 @@ import type { TooltipState } from './ChartTooltip/ChartTooltip.jsx'; import { createTooltip } from './createTooltip.js'; import { legendOptions } from './legendOptions.js'; import type { ChartOptions } from 'chart.js'; +import { getDateFnsLocale } from 'component/insights/getDateFnsLocale.js'; export const createOptions = ( theme: Theme, @@ -59,10 +60,15 @@ export const createOptions = ( }, }, x: { + adapters: { + date: { + locale: getDateFnsLocale(locationSettings.locale), + }, + }, type: 'time', time: { unit: 'week', - tooltipFormat: 'PPP', + tooltipFormat: 'P', }, grid: { color: 'transparent', diff --git a/frontend/src/component/insights/componentsChart/CreationArchiveChart/CreationArchiveChart.tsx b/frontend/src/component/insights/componentsChart/CreationArchiveChart/CreationArchiveChart.tsx index 52a30975e1..0be2d7b4b6 100644 --- a/frontend/src/component/insights/componentsChart/CreationArchiveChart/CreationArchiveChart.tsx +++ b/frontend/src/component/insights/componentsChart/CreationArchiveChart/CreationArchiveChart.tsx @@ -23,6 +23,7 @@ import type { WeekData, RawWeekData } from './types.ts'; import { createTooltip } from 'component/insights/components/LineChart/createTooltip.ts'; import { CreationArchiveRatioTooltip } from './CreationArchiveRatioTooltip.tsx'; import { Chart } from 'react-chartjs-2'; +import { getDateFnsLocale } from '../../getDateFnsLocale.ts'; ChartJS.register( CategoryScale, @@ -161,6 +162,11 @@ export const CreationArchiveChart: FC = ({ locale: locationSettings.locale, scales: { x: { + adapters: { + date: { + locale: getDateFnsLocale(locationSettings.locale), + }, + }, type: 'time' as const, display: true, time: { diff --git a/frontend/src/component/insights/getDateFnsLocale.ts b/frontend/src/component/insights/getDateFnsLocale.ts new file mode 100644 index 0000000000..88ee3d1969 --- /dev/null +++ b/frontend/src/component/insights/getDateFnsLocale.ts @@ -0,0 +1,33 @@ +import 'chartjs-adapter-date-fns'; +import { + cs, + de, + da, + enGB, + enIN, + enUS, + fr, + nb, + ptBR, + sv, + ja, +} from 'date-fns/locale'; +import type { defaultLocales } from 'constants/defaultLocales'; + +const dateFnsLocales: { [key in (typeof defaultLocales)[number]]: Locale } = { + cs: cs, + 'da-DK': da, + de: de, + 'en-GB': enGB, + 'en-IN': enIN, + 'en-US': enUS, + 'fr-FR': fr, + ja: ja, + 'nb-NO': nb, + 'pt-BR': ptBR, + 'sv-SE': sv, +}; + +export const getDateFnsLocale = (locale: string): Locale => { + return dateFnsLocales[locale] ?? enUS; +}; diff --git a/frontend/src/component/user/Profile/ProfileTab/ProfileTab.tsx b/frontend/src/component/user/Profile/ProfileTab/ProfileTab.tsx index 1f5098975f..8294844bad 100644 --- a/frontend/src/component/user/Profile/ProfileTab/ProfileTab.tsx +++ b/frontend/src/component/user/Profile/ProfileTab/ProfileTab.tsx @@ -22,6 +22,7 @@ import { RoleBadge } from 'component/common/RoleBadge/RoleBadge'; import { useUiFlag } from 'hooks/useUiFlag'; import { ProductivityEmailSubscription } from './ProductivityEmailSubscription.tsx'; import { formatDateYMDHM } from 'utils/formatDate.ts'; +import { defaultLocales } from '../../../../constants/defaultLocales.ts'; const StyledHeader = styled('div')(({ theme }) => ({ display: 'flex', @@ -116,17 +117,8 @@ export const ProfileTab = ({ user }: IProfileTabProps) => { const [currentLocale, setCurrentLocale] = useState(); const exampleDateId = useId(); - const [possibleLocales, setPossibleLocales] = useState([ - 'en-US', - 'en-GB', - 'nb-NO', - 'sv-SE', - 'da-DK', - 'en-IN', - 'de', - 'cs', - 'pt-BR', - 'fr-FR', + const [possibleLocales, setPossibleLocales] = useState([ + ...defaultLocales, ]); useEffect(() => { diff --git a/frontend/src/constants/defaultLocales.ts b/frontend/src/constants/defaultLocales.ts new file mode 100644 index 0000000000..bb0e3dcc63 --- /dev/null +++ b/frontend/src/constants/defaultLocales.ts @@ -0,0 +1,13 @@ +export const defaultLocales = [ + 'cs', + 'da-DK', + 'de', + 'en-GB', + 'en-IN', + 'en-US', + 'fr-FR', + 'ja', + 'nb-NO', + 'pt-BR', + 'sv-SE', +] as const;