From 8ea8a9fe2af4fbab31e700d575b2e4e30a09cef2 Mon Sep 17 00:00:00 2001 From: MaysWind Date: Wed, 31 Dec 2025 00:38:36 +0800 Subject: [PATCH] add time-based categories "Transaction Day of Week", "Transaction Day of Month", "Transaction Month of Year" and "Transaction Quarter of Year" in insights & explore --- src/core/explore.ts | 4 +++ src/locales/de.json | 11 +++--- src/locales/en.json | 11 +++--- src/locales/es.json | 11 +++--- src/locales/fr.json | 11 +++--- src/locales/helpers.ts | 17 ++++++++-- src/locales/it.json | 11 +++--- src/locales/ja.json | 11 +++--- src/locales/kn.json | 11 +++--- src/locales/ko.json | 11 +++--- src/locales/nl.json | 11 +++--- src/locales/pt_BR.json | 11 +++--- src/locales/ru.json | 11 +++--- src/locales/sl.json | 11 +++--- src/locales/th.json | 11 +++--- src/locales/tr.json | 11 +++--- src/locales/uk.json | 11 +++--- src/locales/vi.json | 11 +++--- src/locales/zh_Hans.json | 11 +++--- src/locales/zh_Hant.json | 11 +++--- src/stores/explore.ts | 34 +++++++++++++++++++ .../desktop/insights/tabs/ExploreChartTab.vue | 15 ++++++++ 22 files changed, 193 insertions(+), 75 deletions(-) diff --git a/src/core/explore.ts b/src/core/explore.ts index fef098be..db03b194 100644 --- a/src/core/explore.ts +++ b/src/core/explore.ts @@ -205,6 +205,10 @@ export class TransactionExploreDataDimension implements NameValue { public static readonly DateTimeByYearQuarter = new TransactionExploreDataDimension('Transaction Year-Quarter', TransactionExploreDataDimensionType.DateTimeByYearQuarter); public static readonly DateTimeByYear = new TransactionExploreDataDimension('Transaction Year', TransactionExploreDataDimensionType.DateTimeByYear); public static readonly DateTimeByFiscalYear = new TransactionExploreDataDimension('Transaction Fiscal Year', TransactionExploreDataDimensionType.DateTimeByFiscalYear); + public static readonly DateTimeByDayOfWeek = new TransactionExploreDataDimension('Transaction Day of Week', TransactionExploreDataDimensionType.DateTimeByDayOfWeek); + public static readonly DateTimeByDayOfMonth = new TransactionExploreDataDimension('Transaction Day of Month', TransactionExploreDataDimensionType.DateTimeByDayOfMonth); + public static readonly DateTimeByMonthOfYear = new TransactionExploreDataDimension('Transaction Month of Year', TransactionExploreDataDimensionType.DateTimeByMonthOfYear); + public static readonly DateTimeByQuarterOfYear = new TransactionExploreDataDimension('Transaction Quarter of Year', TransactionExploreDataDimensionType.DateTimeByQuarterOfYear); public static readonly TransactionType = new TransactionExploreDataDimension('Transaction Type', TransactionExploreDataDimensionType.TransactionType); public static readonly SourceAccount = new TransactionExploreDataDimension('Source Account', TransactionExploreDataDimensionType.SourceAccount); public static readonly SourceAccountCategory = new TransactionExploreDataDimension('Source Account Category', TransactionExploreDataDimensionType.SourceAccountCategory); diff --git a/src/locales/de.json b/src/locales/de.json index 2761e348..1f17d81d 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -97,10 +97,7 @@ "hh_mm_a": "hh:mm A" }, "yearQuarter": { - "q1": "Q1 {year}", - "q2": "Q2 {year}", - "q3": "Q3 {year}", - "q4": "Q4 {year}" + "content": "{quarter} {year}" }, "fiscalYear": { "StartYYYY_EndYYYY": "GJ {StartYYYY}-{EndYYYY}", @@ -282,6 +279,12 @@ "29": "29.", "30": "30.", "31": "31." + }, + "quarter": { + "q1": "Q1", + "q2": "Q2", + "q3": "Q3", + "q4": "Q4" } }, "granularity": { diff --git a/src/locales/en.json b/src/locales/en.json index 5c62cd10..cb77138b 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -97,10 +97,7 @@ "hh_mm_a": "hh:mm A" }, "yearQuarter": { - "q1": "Q1 {year}", - "q2": "Q2 {year}", - "q3": "Q3 {year}", - "q4": "Q4 {year}" + "content": "{quarter} {year}" }, "fiscalYear": { "StartYYYY_EndYYYY": "FY {StartYYYY}-{EndYYYY}", @@ -282,6 +279,12 @@ "29": "29th", "30": "30th", "31": "31th" + }, + "quarter": { + "q1": "Q1", + "q2": "Q2", + "q3": "Q3", + "q4": "Q4" } }, "granularity": { diff --git a/src/locales/es.json b/src/locales/es.json index 9a9be2d1..b7c05678 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -97,10 +97,7 @@ "hh_mm_a": "h:mm A" }, "yearQuarter": { - "q1": "T1 {year}", - "q2": "T2 {year}", - "q3": "T3 {year}", - "q4": "T4 {year}" + "content": "{quarter} {year}" }, "fiscalYear": { "StartYYYY_EndYYYY": "Ejercicio {StartYYYY}-{EndYYYY}", @@ -282,6 +279,12 @@ "29": "29", "30": "30", "31": "31" + }, + "quarter": { + "q1": "T1", + "q2": "T2", + "q3": "T3", + "q4": "T4" } }, "granularity": { diff --git a/src/locales/fr.json b/src/locales/fr.json index a324730f..1d1cc715 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -97,10 +97,7 @@ "hh_mm_a": "hh:mm A" }, "yearQuarter": { - "q1": "T1 {year}", - "q2": "T2 {year}", - "q3": "T3 {year}", - "q4": "T4 {year}" + "content": "{quarter} {year}" }, "fiscalYear": { "StartYYYY_EndYYYY": "Exercice {StartYYYY}-{EndYYYY}", @@ -282,6 +279,12 @@ "29": "29e", "30": "30e", "31": "31e" + }, + "quarter": { + "q1": "T1", + "q2": "T2", + "q3": "T3", + "q4": "T4" } }, "granularity": { diff --git a/src/locales/helpers.ts b/src/locales/helpers.ts index ed0b0f30..3d2e470f 100644 --- a/src/locales/helpers.ts +++ b/src/locales/helpers.ts @@ -785,10 +785,12 @@ export function useI18n() { } function formatYearQuarter(year: string, quarter: number): string { - if (1 <= quarter && quarter <= 4) { - return t('format.yearQuarter.q' + quarter, { + const quarterName = getQuarterName(quarter); + + if (quarterName) { + return t('format.yearQuarter.content', { year: year, - quarter: quarter + quarter: getQuarterName(quarter) }); } else { return ''; @@ -1590,6 +1592,14 @@ export function useI18n() { return t(`datetime.${weekDay.name}.long`); } + function getQuarterName(quarter: number): string { + if (1 <= quarter && quarter <= 4) { + return t('datetime.quarter.q' + quarter); + } else { + return ''; + } + } + function getMultiMonthdayShortNames(monthDays: number[]): string { if (!monthDays) { return ''; @@ -2392,6 +2402,7 @@ export function useI18n() { getMonthdayShortName, getWeekdayShortName, getWeekdayLongName, + getQuarterName, getMultiMonthdayShortNames, getMultiWeekdayLongNames, getAllLocalizedDigits, diff --git a/src/locales/it.json b/src/locales/it.json index 881353e7..af4f61e4 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -97,10 +97,7 @@ "hh_mm_a": "hh:mm A" }, "yearQuarter": { - "q1": "T1 {year}", - "q2": "T2 {year}", - "q3": "T3 {year}", - "q4": "T4 {year}" + "content": "{quarter} {year}" }, "fiscalYear": { "StartYYYY_EndYYYY": "AF {StartYYYY}-{EndYYYY}", @@ -282,6 +279,12 @@ "29": "29", "30": "30", "31": "31" + }, + "quarter": { + "q1": "T1", + "q2": "T2", + "q3": "T3", + "q4": "T4" } }, "granularity": { diff --git a/src/locales/ja.json b/src/locales/ja.json index 4f2456ef..af484bde 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -97,10 +97,7 @@ "hh_mm_a": "hh:mm A" }, "yearQuarter": { - "q1": "{year}年第1四半期", - "q2": "{year}年第2四半期", - "q3": "{year}年第3四半期", - "q4": "{year}年第4四半期" + "content": "{year}年{quarter}" }, "fiscalYear": { "StartYYYY_EndYYYY": "{StartYYYY}-{EndYYYY}年度", @@ -282,6 +279,12 @@ "29": "29", "30": "30", "31": "31" + }, + "quarter": { + "q1": "第1四半期", + "q2": "第2四半期", + "q3": "第3四半期", + "q4": "第4四半期" } }, "granularity": { diff --git a/src/locales/kn.json b/src/locales/kn.json index 83b3de03..f7dcfd1f 100644 --- a/src/locales/kn.json +++ b/src/locales/kn.json @@ -97,10 +97,7 @@ "hh_mm_a": "hh:mm A" }, "yearQuarter": { - "q1": "Q1 {year}", - "q2": "Q2 {year}", - "q3": "Q3 {year}", - "q4": "Q4 {year}" + "content": "{quarter} {year}" }, "fiscalYear": { "StartYYYY_EndYYYY": "ವಿತ್ತೀಯ ವರ್ಷ {StartYYYY}-{EndYYYY}", @@ -282,6 +279,12 @@ "29": "29ನೇ", "30": "30ನೇ", "31": "31ನೇ" + }, + "quarter": { + "q1": "Q1", + "q2": "Q2", + "q3": "Q3", + "q4": "Q4" } }, "granularity": { diff --git a/src/locales/ko.json b/src/locales/ko.json index 5abfdcb1..c0693a98 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -97,10 +97,7 @@ "hh_mm_a": "hh:mm A" }, "yearQuarter": { - "q1": "{year}년 1사분기", - "q2": "{year}년 2사분기", - "q3": "{year}년 3사분기", - "q4": "{year}년 4사분기" + "content": "{year}년 {quarter}" }, "fiscalYear": { "StartYYYY_EndYYYY": "{StartYYYY}-{EndYYYY}년도", @@ -282,6 +279,12 @@ "29": "29", "30": "30", "31": "31" + }, + "quarter": { + "q1": "1사분기", + "q2": "2사분기", + "q3": "3사분기", + "q4": "4사분기" } }, "granularity": { diff --git a/src/locales/nl.json b/src/locales/nl.json index 70a80175..e37a0552 100644 --- a/src/locales/nl.json +++ b/src/locales/nl.json @@ -97,10 +97,7 @@ "hh_mm_a": "hh:mm A" }, "yearQuarter": { - "q1": "Q1 {year}", - "q2": "Q2 {year}", - "q3": "Q3 {year}", - "q4": "Q4 {year}" + "content": "{quarter} {year}" }, "fiscalYear": { "StartYYYY_EndYYYY": "Boekjaar {StartYYYY}/{EndYYYY}", @@ -282,6 +279,12 @@ "29": "29e", "30": "30e", "31": "31e" + }, + "quarter": { + "q1": "Q1", + "q2": "Q2", + "q3": "Q3", + "q4": "Q4" } }, "granularity": { diff --git a/src/locales/pt_BR.json b/src/locales/pt_BR.json index b8b8b4d7..06884012 100644 --- a/src/locales/pt_BR.json +++ b/src/locales/pt_BR.json @@ -97,10 +97,7 @@ "hh_mm_a": "hh:mm A" }, "yearQuarter": { - "q1": "T1 {year}", - "q2": "T2 {year}", - "q3": "T3 {year}", - "q4": "T4 {year}" + "content": "{quarter} {year}" }, "fiscalYear": { "StartYYYY_EndYYYY": "AF {StartYYYY}-{EndYYYY}", @@ -282,6 +279,12 @@ "29": "29º", "30": "30º", "31": "31º" + }, + "quarter": { + "q1": "T1", + "q2": "T2", + "q3": "T3", + "q4": "T4" } }, "granularity": { diff --git a/src/locales/ru.json b/src/locales/ru.json index bed1a465..0bff1fe8 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -97,10 +97,7 @@ "hh_mm_a": "h:mm A" }, "yearQuarter": { - "q1": "1 квартал {year} г.", - "q2": "2 квартал {year} г.", - "q3": "3 квартал {year} г.", - "q4": "4 квартал {year} г." + "content": "{quarter} {year} г." }, "fiscalYear": { "StartYYYY_EndYYYY": "ФГ {StartYYYY}-{EndYYYY}", @@ -282,6 +279,12 @@ "29": "29-й", "30": "30-й", "31": "31-й" + }, + "quarter": { + "q1": "1 квартал", + "q2": "2 квартал", + "q3": "3 квартал", + "q4": "4 квартал" } }, "granularity": { diff --git a/src/locales/sl.json b/src/locales/sl.json index b9c81320..b956d92c 100644 --- a/src/locales/sl.json +++ b/src/locales/sl.json @@ -97,10 +97,7 @@ "hh_mm_a": "hh:mm A" }, "yearQuarter": { - "q1": "Q1 {year}", - "q2": "Q2 {year}", - "q3": "Q3 {year}", - "q4": "Q4 {year}" + "content": "{quarter} {year}" }, "fiscalYear": { "StartYYYY_EndYYYY": "PL {StartYYYY}-{EndYYYY}", @@ -282,6 +279,12 @@ "29": "29.", "30": "30.", "31": "31." + }, + "quarter": { + "q1": "Q1", + "q2": "Q2", + "q3": "Q3", + "q4": "Q4" } }, "granularity": { diff --git a/src/locales/th.json b/src/locales/th.json index 908890f6..0c0876d3 100644 --- a/src/locales/th.json +++ b/src/locales/th.json @@ -97,10 +97,7 @@ "hh_mm_a": "h:mm A" }, "yearQuarter": { - "q1": "ไตรมาสที่ 1 {year}", - "q2": "ไตรมาสที่ 2 {year}", - "q3": "ไตรมาสที่ 3 {year}", - "q4": "ไตรมาสที่ 4 {year}" + "content": "{quarter} {year}" }, "fiscalYear": { "StartYYYY_EndYYYY": "ปีงบประมาณ {StartYYYY}-{EndYYYY}", @@ -282,6 +279,12 @@ "29": "วันที่ 29", "30": "วันที่ 30", "31": "วันที่ 31" + }, + "quarter": { + "q1": "ไตรมาสที่ 1", + "q2": "ไตรมาสที่ 2", + "q3": "ไตรมาสที่ 3", + "q4": "ไตรมาสที่ 4" } }, "granularity": { diff --git a/src/locales/tr.json b/src/locales/tr.json index c964434a..cb903841 100644 --- a/src/locales/tr.json +++ b/src/locales/tr.json @@ -97,10 +97,7 @@ "hh_mm_a": "hh:mm A" }, "yearQuarter": { - "q1": "{year} 1. çeyrek", - "q2": "{year} 2. çeyrek", - "q3": "{year} 3. çeyrek", - "q4": "{year} 4. çeyrek" + "content": "{year} {quarter}" }, "fiscalYear": { "StartYYYY_EndYYYY": "{StartYYYY}-{EndYYYY} mali yılı", @@ -282,6 +279,12 @@ "29": "29.", "30": "30.", "31": "31." + }, + "quarter": { + "q1": "1. çeyrek", + "q2": "2. çeyrek", + "q3": "3. çeyrek", + "q4": "4. çeyrek" } }, "granularity": { diff --git a/src/locales/uk.json b/src/locales/uk.json index 776ef452..0c0eb98f 100644 --- a/src/locales/uk.json +++ b/src/locales/uk.json @@ -97,10 +97,7 @@ "hh_mm_a": "hh:mm A" }, "yearQuarter": { - "q1": "1 квартал {year} р.", - "q2": "2 квартал {year} р.", - "q3": "3 квартал {year} р.", - "q4": "4 квартал {year} р." + "content": "{quarter} {year} р." }, "fiscalYear": { "StartYYYY_EndYYYY": "{StartYYYY}-{EndYYYY} фінансовий рік", @@ -282,6 +279,12 @@ "29": "29-й", "30": "30-й", "31": "31-й" + }, + "quarter": { + "q1": "1 квартал", + "q2": "2 квартал", + "q3": "3 квартал", + "q4": "4 квартал" } }, "granularity": { diff --git a/src/locales/vi.json b/src/locales/vi.json index 86213f4c..84125d90 100644 --- a/src/locales/vi.json +++ b/src/locales/vi.json @@ -97,10 +97,7 @@ "hh_mm_a": "hh:mm A" }, "yearQuarter": { - "q1": "Quý 1 năm {year}", - "q2": "Quý 2 năm {year}", - "q3": "Quý 3 năm {year}", - "q4": "Quý 4 năm {year}" + "content": "{quarter} năm {year}" }, "fiscalYear": { "StartYYYY_EndYYYY": "FY {StartYYYY}-{EndYYYY}", @@ -282,6 +279,12 @@ "29": "Ngày 29", "30": "Ngày 30", "31": "Ngày 31" + }, + "quarter": { + "q1": "Quý 1", + "q2": "Quý 2", + "q3": "Quý 3", + "q4": "Quý 4" } }, "granularity": { diff --git a/src/locales/zh_Hans.json b/src/locales/zh_Hans.json index 3e70992c..45b1c2e9 100644 --- a/src/locales/zh_Hans.json +++ b/src/locales/zh_Hans.json @@ -97,10 +97,7 @@ "hh_mm_a": "hh:mm A" }, "yearQuarter": { - "q1": "{year}Q1", - "q2": "{year}Q2", - "q3": "{year}Q3", - "q4": "{year}Q4" + "content": "{year}{quarter}" }, "fiscalYear": { "StartYYYY_EndYYYY": "{StartYYYY}-{EndYYYY}财年", @@ -282,6 +279,12 @@ "29": "29", "30": "30", "31": "31" + }, + "quarter": { + "q1": "Q1", + "q2": "Q2", + "q3": "Q3", + "q4": "Q4" } }, "granularity": { diff --git a/src/locales/zh_Hant.json b/src/locales/zh_Hant.json index 4ba0cd70..ff752ddb 100644 --- a/src/locales/zh_Hant.json +++ b/src/locales/zh_Hant.json @@ -97,10 +97,7 @@ "hh_mm_a": "hh:mm A" }, "yearQuarter": { - "q1": "{year}Q1", - "q2": "{year}Q2", - "q3": "{year}Q3", - "q4": "{year}Q4" + "content": "{year}{quarter}" }, "fiscalYear": { "StartYYYY_EndYYYY": "{StartYYYY}-{EndYYYY}財政年度", @@ -282,6 +279,12 @@ "29": "29", "30": "30", "31": "31" + }, + "quarter": { + "q1": "Q1", + "q2": "Q2", + "q3": "Q3", + "q4": "Q4" } }, "granularity": { diff --git a/src/stores/explore.ts b/src/stores/explore.ts index 4ffda279..52a770b5 100644 --- a/src/stores/explore.ts +++ b/src/stores/explore.ts @@ -42,6 +42,8 @@ import { isEquals, } from '@/lib/common.ts'; import { + parseDateTimeFromUnixTime, + parseDateTimeFromUnixTimeWithTimezoneOffset, getYearFirstUnixTimeBySpecifiedUnixTime, getQuarterFirstUnixTimeBySpecifiedUnixTime, getMonthFirstUnixTimeBySpecifiedUnixTime, @@ -203,6 +205,38 @@ export const useExploresStore = defineStore('explores', () => { categoryId: unixTime, categoryIdType: TransactionExploreDimensionType.Other }; + } else if (dimension === TransactionExploreDataDimension.DateTimeByDayOfWeek) { + const dateTime = isDefined(transactionTimeUtfOffset) ? parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, transactionTimeUtfOffset) : parseDateTimeFromUnixTime(transaction.time); + + return { + categoryName: dateTime.getWeekDay().name, + categoryId: dateTime.getWeekDay().type.toString(10), + categoryIdType: TransactionExploreDimensionType.Other + }; + } else if (dimension === TransactionExploreDataDimension.DateTimeByDayOfMonth) { + const dateTime = isDefined(transactionTimeUtfOffset) ? parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, transactionTimeUtfOffset) : parseDateTimeFromUnixTime(transaction.time); + + return { + categoryName: dateTime.getGregorianCalendarDay().toString(10), + categoryId: dateTime.getGregorianCalendarDay().toString(10), + categoryIdType: TransactionExploreDimensionType.Other + }; + } else if (dimension === TransactionExploreDataDimension.DateTimeByMonthOfYear) { + const dateTime = isDefined(transactionTimeUtfOffset) ? parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, transactionTimeUtfOffset) : parseDateTimeFromUnixTime(transaction.time); + + return { + categoryName: dateTime.getGregorianCalendarMonth().toString(10), + categoryId: dateTime.getGregorianCalendarMonth().toString(10), + categoryIdType: TransactionExploreDimensionType.Other + }; + } else if (dimension === TransactionExploreDataDimension.DateTimeByQuarterOfYear) { + const dateTime = isDefined(transactionTimeUtfOffset) ? parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, transactionTimeUtfOffset) : parseDateTimeFromUnixTime(transaction.time); + + return { + categoryName: dateTime.getGregorianCalendarQuarter().toString(10), + categoryId: dateTime.getGregorianCalendarQuarter().toString(10), + categoryIdType: TransactionExploreDimensionType.Other + }; } else if (dimension === TransactionExploreDataDimension.TransactionType) { let transactionTypeName = 'Unknown'; diff --git a/src/views/desktop/insights/tabs/ExploreChartTab.vue b/src/views/desktop/insights/tabs/ExploreChartTab.vue index c3c8d60c..a333f684 100644 --- a/src/views/desktop/insights/tabs/ExploreChartTab.vue +++ b/src/views/desktop/insights/tabs/ExploreChartTab.vue @@ -137,6 +137,7 @@ import { } from '@/stores/explore.ts'; import { type NameValue } from '@/core/base.ts'; +import { Month, WeekDay } from '@/core/datetime.ts'; import { TransactionExploreChartTypeValue, TransactionExploreChartType, @@ -174,6 +175,10 @@ const { getAllTransactionExploreDataDimensions, getAllTransactionExploreValueMetrics, getAllTransactionExploreChartTypes, + getMonthLongName, + getMonthdayShortName, + getWeekdayLongName, + getQuarterName, formatDateTimeToShortDateTime, formatDateTimeToShortDate, formatDateTimeToGregorianLikeShortYear, @@ -269,6 +274,16 @@ function getCategoriedDataDisplayName(info: CategoriedInfo | SeriesedInfo): stri displayName = formatDateTimeToGregorianLikeShortYear(parseDateTimeFromUnixTime(parseInt(name))); } else if (dimessionType === TransactionExploreDataDimension.DateTimeByFiscalYear.value) { displayName = formatDateTimeToGregorianLikeFiscalYear(parseDateTimeFromUnixTime(parseInt(name))); + } else if (dimessionType === TransactionExploreDataDimension.DateTimeByDayOfWeek.value) { + const weekDay = WeekDay.parse(name); + displayName = weekDay ? getWeekdayLongName(weekDay) : tt('Unknown'); + } else if (dimessionType === TransactionExploreDataDimension.DateTimeByDayOfMonth.value) { + displayName = getMonthdayShortName(parseInt(name)); + } else if (dimessionType === TransactionExploreDataDimension.DateTimeByMonthOfYear.value) { + const month = Month.valueOf(parseInt(name)); + displayName = month ? getMonthLongName(month.name) : tt('Unknown'); + } else if (dimessionType === TransactionExploreDataDimension.DateTimeByQuarterOfYear.value) { + displayName = getQuarterName(parseInt(name)); } if (dimessionType === TransactionExploreDataDimension.SourceAmount.value