fix some numerals were not displayed according to the numerical system

This commit is contained in:
MaysWind
2025-08-29 00:18:46 +08:00
parent 0e634d83f4
commit 8f6adaa417
13 changed files with 145 additions and 83 deletions
+10 -5
View File
@@ -3,6 +3,7 @@ import { ref, computed } from 'vue';
import { useI18n } from '@/locales/helpers.ts';
import { type NameValue } from '@/core/base.ts';
import { NumeralSystem } from '@/core/numeral.ts';
export interface TimePickerValue {
value: string;
@@ -12,6 +13,7 @@ export interface TimePickerValue {
export function useDateTimeSelectionBase() {
const {
getAllMeridiemIndicators,
getCurrentNumeralSystemType,
isLongTime24HourFormat,
isLongTimeMeridiemIndicatorFirst,
isLongTimeHourTwoDigits,
@@ -25,14 +27,17 @@ export function useDateTimeSelectionBase() {
const isSecondTwoDigits = ref<boolean>(isLongTimeSecondTwoDigits());
const isMeridiemIndicatorFirst = ref<boolean>(isLongTimeMeridiemIndicatorFirst() || false);
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
const meridiemItems = computed<NameValue[]>(() => getAllMeridiemIndicators());
function getDisplayTimeValue(value: number, forceTwoDigits: boolean): string {
if (forceTwoDigits && value < 10) {
return `0${value}`;
} else {
return value.toString();
let textualValue = value.toString();
if (forceTwoDigits) {
textualValue = textualValue.padStart(2, NumeralSystem.WesternArabicNumerals.digitZero);
}
return numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(textualValue);
}
function generateAllHours(count: number, forceTwoDigits: boolean): TimePickerValue[] {
@@ -43,7 +48,7 @@ export function useDateTimeSelectionBase() {
for (let i = 0; i < count; i++) {
if (!is24Hour.value) {
ret.push({
value: '12',
value: getDisplayTimeValue(12, forceTwoDigits),
itemsIndex: i
});
}
+15 -9
View File
@@ -13,7 +13,7 @@
@click="currentPage = parseInt(page)"
v-if="page !== '...'"
>
<span>{{ page }}</span>
<span>{{ getDisplayPage(page) }}</span>
</v-btn>
<v-btn variant="text"
color="default"
@@ -31,8 +31,8 @@
<v-list-item class="text-sm" :density="density">
<v-list-item-title class="cursor-pointer">
<v-autocomplete width="100"
item-title="page"
item-value="page"
item-title="name"
item-value="value"
auto-select-first="exact"
:density="density"
:items="allPages"
@@ -52,6 +52,8 @@ import { ref, computed } from 'vue';
import { useI18n } from '@/locales/helpers.ts';
import type { NameNumeralValue } from '@/core/base.ts';
import type { NumeralSystem } from '@/core/numeral.ts';
import type { ComponentDensity } from '@/lib/ui/desktop.ts';
const props = defineProps<{
@@ -66,17 +68,21 @@ const emit = defineEmits<{
(e: 'update:modelValue', value: number): void;
}>();
const { tt } = useI18n();
const { tt, getCurrentNumeralSystemType } = useI18n();
const showMenus = ref<Record<string, boolean>>({});
const allPages = computed<{ page: number }[]>(() => {
const pages = [];
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
function getDisplayPage(page: number | string): string {
return numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(page.toString());
}
const allPages = computed<NameNumeralValue[]>(() => {
const pages: NameNumeralValue[] = [];
for (let i = 1; i <= props.totalPageCount; i++) {
pages.push({
page: i
});
pages.push({ value: i, name: getDisplayPage(i) });
}
return pages;
+13 -2
View File
@@ -10,7 +10,7 @@
<div class="d-flex align-center justify-center" style="block-size: 24px; inline-size: 24px;">
<div class="slide-group-stepper-indicator"></div>
</div>
<h4 class="text-h4 step-number">{{ `0${idx + 1}` }}</h4>
<h4 class="text-h4 step-number">{{ getDisplayStep(idx + 1) }}</h4>
</div>
<div style="line-height: 0;">
<h6 class="text-sm font-weight-medium step-title">{{ step.title }}</h6>
@@ -31,7 +31,7 @@
<div class="d-flex align-center justify-center" style="block-size: 24px; inline-size: 24px;">
<div class="slide-group-stepper-indicator"></div>
</div>
<h4 class="text-h4 step-number">{{ `0${idx + 1}` }}</h4>
<h4 class="text-h4 step-number">{{ getDisplayStep(idx + 1) }}</h4>
</div>
<div style="line-height: 0;">
<h6 class="text-sm font-weight-medium step-title">{{ step.title }}</h6>
@@ -46,6 +46,10 @@
<script setup lang="ts">
import { computed } from 'vue';
import { useI18n } from '@/locales/helpers.ts';
import { NumeralSystem } from '@/core/numeral.ts';
export interface StepBarItem {
name: string;
title: string;
@@ -63,8 +67,15 @@ const emit = defineEmits<{
(e: 'step:change', stepName: string): void;
}>();
const { getCurrentNumeralSystemType } = useI18n();
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
const isClickable = computed<boolean>(() => props.clickable !== 'false' && props.clickable !== false);
function getDisplayStep(index: number): string {
return numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(index.toString().padStart(2, NumeralSystem.WesternArabicNumerals.digitZero));
}
function changeStep(step: StepBarItem): void {
if (isClickable.value) {
emit('step:change', step.name);
+5
View File
@@ -8,6 +8,11 @@ export interface NameValue {
readonly value: string;
}
export interface NameNumeralValue {
readonly name: string;
readonly value: number;
}
export interface TypeAndName {
readonly type: number;
readonly name: string;
+6 -6
View File
@@ -60,14 +60,14 @@ type DateTimeTokenFormatFunction = (d: MomentDateTime, options: DateTimeFormatOp
class MomentDateTime implements DateTime {
private static readonly tokenFormatFuncs: Record<string, DateTimeTokenFormatFunction> = {
'YY': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarYear(options), minNumeralLength: 2, maxLength: 2 }),
'YYYY': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarYear(options), minNumeralLength: 4 }),
'M': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarMonth(options) }),
'MM': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarMonth(options), minNumeralLength: 2 }),
'YY': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarYear(options), hasNumeral: true, minNumeralLength: 2, maxLength: 2 }),
'YYYY': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarYear(options), hasNumeral: true, minNumeralLength: 4 }),
'M': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarMonth(options), hasNumeral: true }),
'MM': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarMonth(options), hasNumeral: true, minNumeralLength: 2 }),
'MMM': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarMonthDisplayShortName(options) }),
'MMMM': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarMonthDisplayName(options) }),
'D': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarDay(options) }),
'DD': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarDay(options), minNumeralLength: 2 }),
'D': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarDay(options), hasNumeral: true }),
'DD': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getLocalizedCalendarDay(options), hasNumeral: true, minNumeralLength: 2 }),
'dd': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getWeekDayDisplayMinName(options) }),
'ddd': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getWeekDayDisplayShortName(options) }),
'dddd': (d: MomentDateTime, options: DateTimeFormatOptions) => ofObject<DateTimeFormatResult>({ value: d.getWeekDayDisplayName(options) }),
+16 -13
View File
@@ -1069,12 +1069,13 @@ export function useI18n() {
}
function getAllTimezones(includeSystemDefault?: boolean): LocalizedTimezoneInfo[] {
const defaultTimezoneOffset = getBrowserTimezoneOffset();
const numeralSystem = getCurrentNumeralSystemType();
const defaultTimezoneOffset = numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(getBrowserTimezoneOffset());
const defaultTimezoneOffsetMinutes = getBrowserTimezoneOffsetMinutes();
const allTimezoneInfos: LocalizedTimezoneInfo[] = [];
for (let i = 0; i < ALL_TIMEZONES.length; i++) {
const utcOffset = (ALL_TIMEZONES[i].timezoneName !== UTC_TIMEZONE.timezoneName ? getTimezoneOffset(ALL_TIMEZONES[i].timezoneName) : '');
const utcOffset = (ALL_TIMEZONES[i].timezoneName !== UTC_TIMEZONE.timezoneName ? numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(getTimezoneOffset(ALL_TIMEZONES[i].timezoneName)) : '');
const displayName = t(`timezone.${ALL_TIMEZONES[i].displayName}`);
allTimezoneInfos.push({
@@ -1099,11 +1100,11 @@ export function useI18n() {
}
allTimezoneInfos.sort(function (c1, c2) {
const utcOffset1 = parseInt(c1.utcOffset.replace(':', ''));
const utcOffset2 = parseInt(c2.utcOffset.replace(':', ''));
const utcOffsetMinutes1 = c1.utcOffsetMinutes;
const utcOffsetMinutes2 = c2.utcOffsetMinutes;
if (utcOffset1 !== utcOffset2) {
return utcOffset1 - utcOffset2;
if (utcOffsetMinutes1 !== utcOffsetMinutes2) {
return utcOffsetMinutes1 - utcOffsetMinutes2;
}
return c1.displayName.localeCompare(c2.displayName);
@@ -1113,7 +1114,8 @@ export function useI18n() {
}
function getAllTimezoneTypesUsedForStatistics(currentTimezone?: string): TypeAndDisplayName[] {
const currentTimezoneOffset = getTimezoneOffset(currentTimezone);
const numeralSystem = getCurrentNumeralSystemType();
const currentTimezoneOffset = numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(getTimezoneOffset(currentTimezone));
return [
{
@@ -1836,29 +1838,30 @@ export function useI18n() {
}
function getTimezoneDifferenceDisplayText(utcOffset: number): string {
const numeralSystem = getCurrentNumeralSystemType();
const defaultTimezoneOffset = getTimezoneOffsetMinutes();
const offsetTime = getTimeDifferenceHoursAndMinutes(utcOffset - defaultTimezoneOffset);
if (utcOffset > defaultTimezoneOffset) {
if (offsetTime.offsetMinutes) {
return t('format.misc.hoursMinutesAheadOfDefaultTimezone', {
hours: offsetTime.offsetHours,
minutes: offsetTime.offsetMinutes
hours: numeralSystem.formatNumber(offsetTime.offsetHours),
minutes: numeralSystem.formatNumber(offsetTime.offsetMinutes)
});
} else {
return t('format.misc.hoursAheadOfDefaultTimezone', {
hours: offsetTime.offsetHours
hours: numeralSystem.formatNumber(offsetTime.offsetHours)
});
}
} else if (utcOffset < defaultTimezoneOffset) {
if (offsetTime.offsetMinutes) {
return t('format.misc.hoursMinutesBehindDefaultTimezone', {
hours: offsetTime.offsetHours,
minutes: offsetTime.offsetMinutes
hours: numeralSystem.formatNumber(offsetTime.offsetHours),
minutes: numeralSystem.formatNumber(offsetTime.offsetMinutes)
});
} else {
return t('format.misc.hoursBehindDefaultTimezone', {
hours: offsetTime.offsetHours
hours: numeralSystem.formatNumber(offsetTime.offsetHours)
});
}
} else {
@@ -10,11 +10,12 @@ import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
import { useTransactionsStore } from '@/stores/transaction.ts';
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
import { DISPLAY_HIDDEN_AMOUNT } from '@/consts/numeral.ts';
import type { NumeralSystem } from '@/core/numeral.ts';
import type { WeekDayValue } from '@/core/datetime.ts';
import type { LocalizedTimezoneInfo } from '@/core/timezone.ts';
import { TransactionType } from '@/core/transaction.ts';
import { TemplateType } from '@/core/template.ts';
import { DISPLAY_HIDDEN_AMOUNT } from '@/consts/numeral.ts';
import { TRANSACTION_MAX_PICTURE_COUNT } from '@/consts/transaction.ts';
import { Account, type CategorizedAccountWithDisplayBalance } from '@/models/account.ts';
@@ -59,6 +60,7 @@ export function useTransactionEditPageBase(type: TransactionEditPageType, initMo
const {
tt,
getAllTimezones,
getCurrentNumeralSystemType,
getTimezoneDifferenceDisplayText,
formatAmountToLocalizedNumeralsWithCurrency,
getAdaptiveAmountRate,
@@ -89,6 +91,7 @@ export function useTransactionEditPageBase(type: TransactionEditPageType, initMo
const transaction = ref<Transaction | TransactionTemplate>(createNewTransactionModel(transactionDefaultType));
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
const currentTimezoneOffsetMinutes = computed<number>(() => getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone));
const showAccountBalance = computed<boolean>(() => settingsStore.appSettings.showAccountBalance);
const defaultCurrency = computed<string>(() => userStore.currentUserDefaultCurrency);
@@ -265,7 +268,8 @@ export function useTransactionEditPageBase(type: TransactionEditPageType, initMo
});
const transactionDisplayTimezone = computed<string>(() => {
return `UTC${getUtcOffsetByUtcOffsetMinutes(transaction.value.utcOffset)}`;
const utcOffset = numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(getUtcOffsetByUtcOffsetMinutes(transaction.value.utcOffset));
return `UTC${utcOffset}`;
});
const transactionTimezoneTimeDifference = computed<string>(() => {
@@ -416,6 +420,7 @@ export function useTransactionEditPageBase(type: TransactionEditPageType, initMo
setGeoLocationByClickMap,
transaction,
// computed states
numeralSystem,
currentTimezoneOffsetMinutes,
showAccountBalance,
defaultCurrency,
@@ -10,6 +10,7 @@ import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
import { type TransactionListFilter, type TransactionMonthList, useTransactionsStore } from '@/stores/transaction.ts';
import type { TypeAndName } from '@/core/base.ts';
import type { NumeralSystem } from '@/core/numeral.ts';
import { type TextualYearMonthDay, type Year0BasedMonth, type LocalizedDateRange, type WeekDayValue, DateRange, DateRangeScene } from '@/core/datetime.ts';
import { AccountType } from '@/core/account.ts';
import { TransactionType } from '@/core/transaction.ts';
@@ -74,6 +75,7 @@ export function useTransactionListPageBase() {
const {
tt,
getAllDateRanges,
getCurrentNumeralSystemType,
formatUnixTimeToLongDateTime,
formatUnixTimeToLongDate,
formatUnixTimeToLongYearMonth,
@@ -95,6 +97,7 @@ export function useTransactionListPageBase() {
const customMaxDatetime = ref<number>(0);
const currentCalendarDate = ref<TextualYearMonthDay | ''>('');
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
const currentTimezoneOffsetMinutes = computed<number>(() => getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone));
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
const fiscalYearStart = computed<number>(() => userStore.currentUserFiscalYearStart);
@@ -288,11 +291,13 @@ export function useTransactionListPageBase() {
}
function getDisplayTimezone(transaction: Transaction): string {
return `UTC${getUtcOffsetByUtcOffsetMinutes(transaction.utcOffset)}`;
const utcOffset = numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(getUtcOffsetByUtcOffsetMinutes(transaction.utcOffset));
return `UTC${utcOffset}`;
}
function getDisplayTimeInDefaultTimezone(transaction: Transaction): string {
return `${formatUnixTimeToLongDateTime(transaction.time)} (UTC${getTimezoneOffset(settingsStore.appSettings.timeZone)})`;
const utcOffset = numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(getTimezoneOffset(settingsStore.appSettings.timeZone));
return `${formatUnixTimeToLongDateTime(transaction.time)} (UTC${utcOffset})`;
}
function getDisplayAmount(transaction: Transaction): string {
+6 -2
View File
@@ -51,7 +51,7 @@
<v-card-text>
<div class="mb-8">
<span class="text-body-1" v-if="!loadingOverview || (allAccounts && allAccounts.length)">{{ tt('format.misc.youHaveAccounts', { count: allAccounts.length }) }}</span>
<span class="text-body-1" v-if="!loadingOverview || (allAccounts && allAccounts.length)">{{ tt('format.misc.youHaveAccounts', { count: displayAccountCount }) }}</span>
<v-skeleton-loader class="skeleton-no-margin mt-1 mb-2 pb-1" width="200px" type="text" :loading="true" v-else-if="loadingOverview && (!allAccounts || !allAccounts.length)"></v-skeleton-loader>
</div>
@@ -201,6 +201,7 @@ import { useHomePageBase } from '@/views/base/HomePageBase.ts';
import { useAccountsStore } from '@/stores/account.ts';
import { useOverviewStore } from '@/stores/overview.ts';
import { type NumeralSystem } from '@/core/numeral.ts';
import { DateRange } from '@/core/datetime.ts';
import { ThemeType } from '@/core/theme.ts';
import { type TransactionMonthlyIncomeAndExpenseData, LATEST_12MONTHS_TRANSACTION_AMOUNTS_REQUEST_TYPES } from '@/models/transaction.ts';
@@ -227,7 +228,7 @@ type SnackBarType = InstanceType<typeof SnackBar>;
const router = useRouter();
const theme = useTheme();
const { tt } = useI18n();
const { tt, getCurrentNumeralSystemType } = useI18n();
const {
showAmountInHomePage,
allAccounts,
@@ -248,6 +249,9 @@ const snackbar = useTemplateRef<SnackBarType>('snackbar');
const loadingOverview = ref<boolean>(true);
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
const displayAccountCount = computed<string>(() => allAccounts.value ? numeralSystem.value.formatNumber(allAccounts.value.length) : numeralSystem.value.digitZero);
function clickMonthlyIncomeOrExpense(e: MonthlyIncomeAndExpenseCardClickEvent): void {
const minTime = e.monthStartTime;
@@ -209,7 +209,7 @@
{{ tt('Transactions Per Page') }}
</span>
<v-select class="ms-2" density="compact" max-width="100"
item-title="title"
item-title="name"
item-value="value"
:disabled="loading"
:items="reconciliationStatementsTablePageOptions"
@@ -278,6 +278,8 @@ import { useAccountsStore } from '@/stores/account.ts';
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
import { useTransactionsStore } from '@/stores/transaction.ts';
import type { NameNumeralValue } from '@/core/base.ts';
import type { NumeralSystem } from '@/core/numeral.ts';
import { TransactionType } from '@/core/transaction.ts';
import { AccountBalanceTrendChartType, ChartDateAggregationType } from '@/core/statistics.ts';
import { KnownFileType } from '@/core/file.ts';
@@ -310,16 +312,11 @@ type SnackBarType = InstanceType<typeof SnackBar>;
type AmountInputDialogType = InstanceType<typeof AmountInputDialog>;
type EditDialogType = InstanceType<typeof EditDialog>;
interface ReconciliationStatementDialogTablePageOption {
value: number;
title: string;
}
const emit = defineEmits<{
(e: 'error', message: string): void;
}>();
const { tt, formatNumberToLocalizedNumerals } = useI18n();
const { tt, getCurrentNumeralSystemType, formatNumberToLocalizedNumerals } = useI18n();
const {
accountId,
@@ -383,7 +380,8 @@ const chartDataDateAggregationType = ref<number | undefined>(undefined);
let rejectFunc: ((reason?: unknown) => void) | null = null;
const reconciliationStatementsTablePageOptions = computed<ReconciliationStatementDialogTablePageOption[]>(() => getTablePageOptions(reconciliationStatements.value?.transactions.length));
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
const reconciliationStatementsTablePageOptions = computed<NameNumeralValue[]>(() => getTablePageOptions(reconciliationStatements.value?.transactions.length));
const totalPageCount = computed<number>(() => {
if (!reconciliationStatements.value || !reconciliationStatements.value.transactions || reconciliationStatements.value.transactions.length < 1) {
@@ -414,11 +412,11 @@ const dataTableHeaders = computed<object[]>(() => {
return headers;
});
function getTablePageOptions(linesCount?: number): ReconciliationStatementDialogTablePageOption[] {
const pageOptions: ReconciliationStatementDialogTablePageOption[] = [];
function getTablePageOptions(linesCount?: number): NameNumeralValue[] {
const pageOptions: NameNumeralValue[] = [];
if (!linesCount || linesCount < 1) {
pageOptions.push({ value: -1, title: tt('All') });
pageOptions.push({ value: -1, name: tt('All') });
return pageOptions;
}
@@ -431,10 +429,10 @@ function getTablePageOptions(linesCount?: number): ReconciliationStatementDialog
break;
}
pageOptions.push({ value: count, title: count.toString() });
pageOptions.push({ value: count, name: numeralSystem.value.formatNumber(count) });
}
pageOptions.push({ value: -1, title: tt('All') });
pageOptions.push({ value: -1, name: tt('All') });
return pageOptions;
}
+22 -5
View File
@@ -33,8 +33,11 @@
</div>
<div class="mx-6 mt-4" v-if="pageType === TransactionListPageType.List.type">
<span class="text-subtitle-2">{{ tt('Transactions Per Page') }}</span>
<v-select class="mt-2" density="compact" :disabled="loading"
:items="[ 5, 10, 15, 20, 25, 30, 50 ]"
<v-select class="mt-2" density="compact"
item-title="name"
item-value="value"
:disabled="loading"
:items="allPageCounts"
v-model="countPerPage"
/>
</div>
@@ -666,7 +669,7 @@ import { useTransactionsStore } from '@/stores/transaction.ts';
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.ts';
import { useDesktopPageStore } from '@/stores/desktopPage.ts';
import type { TypeAndDisplayName } from '@/core/base.ts';
import type { NameNumeralValue, TypeAndDisplayName } from '@/core/base.ts';
import {
type Year0BasedMonth,
type LocalizedRecentMonthDateRange,
@@ -674,7 +677,7 @@ import {
DateRangeScene,
DateRange
} from '@/core/datetime.ts';
import { AmountFilterType } from '@/core/numeral.ts';
import { type NumeralSystem, AmountFilterType } from '@/core/numeral.ts';
import { ThemeType } from '@/core/theme.ts';
import { TransactionType, TransactionTagFilterType } from '@/core/transaction.ts';
import { TemplateType } from '@/core/template.ts';
@@ -774,7 +777,8 @@ const {
tt,
getAllRecentMonthDateRanges,
getAllTransactionTagFilterTypes,
getWeekdayLongName
getWeekdayLongName,
getCurrentNumeralSystemType
} = useI18n();
const {
@@ -874,6 +878,19 @@ const showFilterCategoryDialog = ref<boolean>(false);
const showFilterTagDialog = ref<boolean>(false);
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
const allPageCounts = computed<NameNumeralValue[]>(() => {
const pageCounts: NameNumeralValue[] = [];
const availableCountPerPage: number[] = [ 5, 10, 15, 20, 25, 30, 50 ];
for (let i = 0; i < availableCountPerPage.length; i++) {
const count = availableCountPerPage[i];
pageCounts.push({ value: count, name: numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(count.toString()) });
}
return pageCounts;
});
const recentMonthDateRanges = computed<LocalizedRecentMonthDateRange[]>(() => getAllRecentMonthDateRanges(pageType.value === TransactionListPageType.List.type, true));
@@ -503,7 +503,7 @@
<v-spacer/>
<span>{{ tt('Lines Per Page') }}</span>
<v-select class="ms-2" density="compact" max-width="100"
item-title="title"
item-title="name"
item-value="value"
:disabled="loading || submitting"
:items="parsedFileLinesTablePageOptions"
@@ -794,12 +794,12 @@
<div class="title-and-toolbar d-flex align-center text-no-wrap mt-2"
v-if="importTransactions && importTransactions.length > 10">
<span :class="{ 'text-error': selectedInvalidTransactionCount > 0 }">
{{ tt('format.misc.selectedCount', { count: selectedImportTransactionCount, totalCount: importTransactions.length }) }}
{{ tt('format.misc.selectedCount', { count: getDisplayCount(selectedImportTransactionCount), totalCount: getDisplayCount(importTransactions.length) }) }}
</span>
<v-spacer/>
<span>{{ tt('Transactions Per Page') }}</span>
<v-select class="ms-2" density="compact" max-width="100"
item-title="title"
item-title="name"
item-value="value"
:disabled="loading || submitting"
:items="importTransactionsTablePageOptions"
@@ -815,7 +815,7 @@
</v-window-item>
<v-window-item value="finalResult">
<h4 class="text-h4 mb-1">{{ tt('Data Import Completed') }}</h4>
<p class="my-5">{{ tt('format.misc.importTransactionResult', { count: importedCount }) }}</p>
<p class="my-5">{{ tt('format.misc.importTransactionResult', { count: getDisplayCount(importedCount || 0) }) }}</p>
</v-window-item>
</v-window>
@@ -906,8 +906,8 @@ import { useTransactionsStore } from '@/stores/transaction.ts';
import { useOverviewStore } from '@/stores/overview.ts';
import { useStatisticsStore } from '@/stores/statistics.ts';
import type { NameValue, TypeAndDisplayName } from '@/core/base.ts';
import { KnownAmountFormat } from '@/core/numeral.ts';
import type { NameValue, NameNumeralValue, TypeAndDisplayName } from '@/core/base.ts';
import { type NumeralSystem, KnownAmountFormat } from '@/core/numeral.ts';
import { KnownDateTimeFormat } from '@/core/datetime.ts';
import { KnownDateTimezoneFormat } from '@/core/timezone.ts';
import { CategoryType } from '@/core/category.ts';
@@ -992,11 +992,6 @@ interface ImportTransactionDialogFilter {
description: string | null; // null for 'All Description'
}
interface ImportTransactionsDialogTablePageOption {
value: number;
title: string;
}
defineProps<{
persistent?: boolean;
}>();
@@ -1005,6 +1000,7 @@ const {
tt,
getAllImportTransactionColumnTypes,
getAllSupportedImportFileCagtegoryAndTypes,
getCurrentNumeralSystemType,
formatUnixTimeToLongDateTime,
formatAmountToLocalizedNumeralsWithCurrency,
formatNumberToLocalizedNumerals,
@@ -1063,6 +1059,7 @@ const submitting = ref<boolean>(false);
let resolveFunc: (() => void) | null = null;
let rejectFunc: ((reason?: unknown) => void) | null = null;
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
const showAccountBalance = computed<boolean>(() => settingsStore.appSettings.showAccountBalance);
const currentTimezoneOffsetMinutes = computed<number>(() => getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone));
@@ -1252,7 +1249,7 @@ const parsedFileLinesHeaders = computed<object[]>(() => {
return headers;
});
const parsedFileLinesTablePageOptions = computed<ImportTransactionsDialogTablePageOption[]>(() => getTablePageOptions(parsedFileLines.value?.length));
const parsedFileLinesTablePageOptions = computed<NameNumeralValue[]>(() => getTablePageOptions(parsedFileLines.value?.length));
const parsedFileAllTransactionTypes = computed<string[]>(() => parsedFileDataColumnMapping.value.parseFileAllTransactionTypes(parsedFileData.value));
const parsedFileValidMappedTransactionTypes = computed<Record<string, TransactionType>>(() => parsedFileDataColumnMapping.value.parseFileValidMappedTransactionTypes(parsedFileData.value));
@@ -1282,7 +1279,7 @@ const importTransactionHeaders = computed<object[]>(() => {
];
});
const importTransactionsTablePageOptions = computed<ImportTransactionsDialogTablePageOption[]>(() => getTablePageOptions(importTransactions.value?.length));
const importTransactionsTablePageOptions = computed<NameNumeralValue[]>(() => getTablePageOptions(importTransactions.value?.length));
const totalPageCount = computed<number>(() => {
if (!importTransactions.value || importTransactions.value.length < 1) {
@@ -1490,11 +1487,15 @@ const displayFilterCustomDateRange = computed<string>(() => {
return `${minDisplayTime} - ${maxDisplayTime}`
});
function getTablePageOptions(linesCount?: number): ImportTransactionsDialogTablePageOption[] {
const pageOptions: ImportTransactionsDialogTablePageOption[] = [];
function getDisplayCount(count: number): string {
return numeralSystem.value.formatNumber(count);
}
function getTablePageOptions(linesCount?: number): NameNumeralValue[] {
const pageOptions: NameNumeralValue[] = [];
if (!linesCount || linesCount < 1) {
pageOptions.push({ value: -1, title: tt('All') });
pageOptions.push({ value: -1, name: tt('All') });
return pageOptions;
}
@@ -1507,10 +1508,10 @@ function getTablePageOptions(linesCount?: number): ImportTransactionsDialogTable
break;
}
pageOptions.push({ value: count, title: count.toString() });
pageOptions.push({ value: count, name: getDisplayCount(count) });
}
pageOptions.push({ value: -1, title: tt('All') });
pageOptions.push({ value: -1, name: tt('All') });
return pageOptions;
}
@@ -2110,7 +2111,7 @@ function submit(): void {
}
confirmDialog.value?.open('format.misc.confirmImportTransactions', {
count: transactions.length
count: getDisplayCount(transactions.length)
}).then(() => {
editingTransaction.value = null;
editingTags.value = [];
@@ -2379,7 +2380,7 @@ function showBatchReplaceDialog(type: BatchReplaceDialogDataType): void {
if (updatedCount > 0) {
snackbar.value?.showMessage('format.misc.youHaveUpdatedTransactions', {
count: updatedCount
count: getDisplayCount(updatedCount)
});
}
});
@@ -2463,7 +2464,7 @@ function showReplaceInvalidItemDialog(type: BatchReplaceDialogDataType, invalidI
if (updatedCount > 0) {
snackbar.value?.showMessage('format.misc.youHaveUpdatedTransactions', {
count: updatedCount
count: getDisplayCount(updatedCount)
});
}
});
@@ -2535,7 +2536,7 @@ function showReplaceAllTypesDialog(): void {
if (updatedCount > 0) {
snackbar.value?.showMessage('format.misc.youHaveUpdatedTransactions', {
count: updatedCount
count: getDisplayCount(updatedCount)
});
}
});
@@ -2607,7 +2608,7 @@ function showBatchCreateInvalidItemDialog(type: BatchCreateDialogDataType, inval
if (updatedCount > 0) {
snackbar.value?.showMessage('format.misc.youHaveUpdatedTransactions', {
count: updatedCount
count: getDisplayCount(updatedCount)
});
}
});
+3 -1
View File
@@ -553,6 +553,7 @@ const {
geoLocationStatus,
setGeoLocationByClickMap,
transaction,
numeralSystem,
currentTimezoneOffsetMinutes,
defaultCurrency,
defaultAccountId,
@@ -662,7 +663,8 @@ const transactionDisplayTime = computed<string>(() => {
return formatUnixTimeToLongTime(getActualUnixTimeForStore(transaction.value.time, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
}
return `${formatUnixTimeToLongTime(getActualUnixTimeForStore(transaction.value.time, transaction.value.utcOffset, getBrowserTimezoneOffsetMinutes()))} (UTC${getTimezoneOffset(settingsStore.appSettings.timeZone)})`;
const utcOffset = numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(getTimezoneOffset(settingsStore.appSettings.timeZone));
return `${formatUnixTimeToLongTime(getActualUnixTimeForStore(transaction.value.time, transaction.value.utcOffset, getBrowserTimezoneOffsetMinutes()))} (UTC${utcOffset})`;
});
const transactionDisplayTimezoneName = computed<string>(() => {