support changing numeral system
This commit is contained in:
+2
-1
@@ -951,10 +951,11 @@ func printUserInfo(user *models.User) {
|
||||
fmt.Printf("[LongTimeFormat] %s (%d)\n", user.LongTimeFormat, user.LongTimeFormat)
|
||||
fmt.Printf("[ShortTimeFormat] %s (%d)\n", user.ShortTimeFormat, user.ShortTimeFormat)
|
||||
fmt.Printf("[FiscalYearFormat] %s (%d)\n", user.FiscalYearFormat, user.FiscalYearFormat)
|
||||
fmt.Printf("[CurrencyDisplayType] %s (%d)\n", user.CurrencyDisplayType, user.CurrencyDisplayType)
|
||||
fmt.Printf("[NumeralSystem] %s (%d)\n", user.NumeralSystem, user.NumeralSystem)
|
||||
fmt.Printf("[DecimalSeparator] %s (%d)\n", user.DecimalSeparator, user.DecimalSeparator)
|
||||
fmt.Printf("[DigitGroupingSymbol] %s (%d)\n", user.DigitGroupingSymbol, user.DigitGroupingSymbol)
|
||||
fmt.Printf("[DigitGrouping] %s (%d)\n", user.DigitGrouping, user.DigitGrouping)
|
||||
fmt.Printf("[CurrencyDisplayType] %s (%d)\n", user.CurrencyDisplayType, user.CurrencyDisplayType)
|
||||
fmt.Printf("[CoordinateDisplayType] %s (%d)\n", user.CoordinateDisplayType, user.CoordinateDisplayType)
|
||||
fmt.Printf("[ExpenseAmountColor] %s (%d)\n", user.ExpenseAmountColor, user.ExpenseAmountColor)
|
||||
fmt.Printf("[IncomeAmountColor] %s (%d)\n", user.IncomeAmountColor, user.IncomeAmountColor)
|
||||
|
||||
+18
-9
@@ -404,6 +404,24 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
userNew.FiscalYearFormat = core.FISCAL_YEAR_FORMAT_INVALID
|
||||
}
|
||||
|
||||
if userUpdateReq.CurrencyDisplayType != nil && *userUpdateReq.CurrencyDisplayType != user.CurrencyDisplayType {
|
||||
user.CurrencyDisplayType = *userUpdateReq.CurrencyDisplayType
|
||||
userNew.CurrencyDisplayType = *userUpdateReq.CurrencyDisplayType
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
} else {
|
||||
userNew.CurrencyDisplayType = core.CURRENCY_DISPLAY_TYPE_INVALID
|
||||
}
|
||||
|
||||
if userUpdateReq.NumeralSystem != nil && *userUpdateReq.NumeralSystem != user.NumeralSystem {
|
||||
user.NumeralSystem = *userUpdateReq.NumeralSystem
|
||||
userNew.NumeralSystem = *userUpdateReq.NumeralSystem
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
} else {
|
||||
userNew.NumeralSystem = core.NUMERAL_SYSTEM_INVALID
|
||||
}
|
||||
|
||||
if userUpdateReq.DecimalSeparator != nil && *userUpdateReq.DecimalSeparator != user.DecimalSeparator {
|
||||
user.DecimalSeparator = *userUpdateReq.DecimalSeparator
|
||||
userNew.DecimalSeparator = *userUpdateReq.DecimalSeparator
|
||||
@@ -431,15 +449,6 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
|
||||
userNew.DigitGrouping = core.DIGIT_GROUPING_TYPE_INVALID
|
||||
}
|
||||
|
||||
if userUpdateReq.CurrencyDisplayType != nil && *userUpdateReq.CurrencyDisplayType != user.CurrencyDisplayType {
|
||||
user.CurrencyDisplayType = *userUpdateReq.CurrencyDisplayType
|
||||
userNew.CurrencyDisplayType = *userUpdateReq.CurrencyDisplayType
|
||||
modifyProfileBasicInfo = true
|
||||
anythingUpdate = true
|
||||
} else {
|
||||
userNew.CurrencyDisplayType = core.CURRENCY_DISPLAY_TYPE_INVALID
|
||||
}
|
||||
|
||||
if userUpdateReq.CoordinateDisplayType != nil && *userUpdateReq.CoordinateDisplayType != user.CoordinateDisplayType {
|
||||
user.CoordinateDisplayType = *userUpdateReq.CoordinateDisplayType
|
||||
userNew.CoordinateDisplayType = *userUpdateReq.CoordinateDisplayType
|
||||
|
||||
@@ -4,6 +4,40 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// NumeralSystem represents the type of numeral system
|
||||
type NumeralSystem byte
|
||||
|
||||
// Numeral System
|
||||
const (
|
||||
NUMERAL_SYSTEM_DEFAULT NumeralSystem = 0
|
||||
NUMERAL_SYSTEM_WESTERN_ARABIC_NUMERALS NumeralSystem = 1
|
||||
NUMERAL_SYSTEM_EASTERN_ARABIC_NUMERALS NumeralSystem = 2
|
||||
NUMERAL_SYSTEM_PERSIAN_DIGITS NumeralSystem = 3
|
||||
NUMERAL_SYSTEM_BURMESE_NUMERALS NumeralSystem = 4
|
||||
NUMERAL_SYSTEM_DEVANAGARI_NUMERALS NumeralSystem = 5
|
||||
NUMERAL_SYSTEM_INVALID NumeralSystem = 255
|
||||
)
|
||||
|
||||
// String returns a textual representation of the decimal separator enum
|
||||
func (f NumeralSystem) String() string {
|
||||
switch f {
|
||||
case NUMERAL_SYSTEM_DEFAULT:
|
||||
return "Default"
|
||||
case NUMERAL_SYSTEM_WESTERN_ARABIC_NUMERALS:
|
||||
return "Western Arabic Numerals"
|
||||
case NUMERAL_SYSTEM_EASTERN_ARABIC_NUMERALS:
|
||||
return "Eastern Arabic Numerals"
|
||||
case NUMERAL_SYSTEM_PERSIAN_DIGITS:
|
||||
return "Persian Digits"
|
||||
case NUMERAL_SYSTEM_BURMESE_NUMERALS:
|
||||
return "Burmese Numerals"
|
||||
case NUMERAL_SYSTEM_DEVANAGARI_NUMERALS:
|
||||
return "Devanagari Numerals"
|
||||
default:
|
||||
return fmt.Sprintf("Invalid(%d)", int(f))
|
||||
}
|
||||
}
|
||||
|
||||
// DecimalSeparator represents the type of decimal separator
|
||||
type DecimalSeparator byte
|
||||
|
||||
|
||||
+8
-4
@@ -100,10 +100,11 @@ type User struct {
|
||||
LongTimeFormat core.LongTimeFormat `xorm:"TINYINT"`
|
||||
ShortTimeFormat core.ShortTimeFormat `xorm:"TINYINT"`
|
||||
FiscalYearFormat core.FiscalYearFormat `xorm:"TINYINT"`
|
||||
CurrencyDisplayType core.CurrencyDisplayType `xorm:"TINYINT"`
|
||||
NumeralSystem core.NumeralSystem `xorm:"TINYINT"`
|
||||
DecimalSeparator core.DecimalSeparator `xorm:"TINYINT"`
|
||||
DigitGroupingSymbol core.DigitGroupingSymbol `xorm:"TINYINT"`
|
||||
DigitGrouping core.DigitGroupingType `xorm:"TINYINT"`
|
||||
CurrencyDisplayType core.CurrencyDisplayType `xorm:"TINYINT"`
|
||||
CoordinateDisplayType core.CoordinateDisplayType `xorm:"TINYINT"`
|
||||
ExpenseAmountColor AmountColorType `xorm:"TINYINT"`
|
||||
IncomeAmountColor AmountColorType `xorm:"TINYINT"`
|
||||
@@ -135,10 +136,11 @@ type UserBasicInfo struct {
|
||||
LongTimeFormat core.LongTimeFormat `json:"longTimeFormat"`
|
||||
ShortTimeFormat core.ShortTimeFormat `json:"shortTimeFormat"`
|
||||
FiscalYearFormat core.FiscalYearFormat `json:"fiscalYearFormat"`
|
||||
CurrencyDisplayType core.CurrencyDisplayType `json:"currencyDisplayType"`
|
||||
NumeralSystem core.NumeralSystem `json:"numeralSystem"`
|
||||
DecimalSeparator core.DecimalSeparator `json:"decimalSeparator"`
|
||||
DigitGroupingSymbol core.DigitGroupingSymbol `json:"digitGroupingSymbol"`
|
||||
DigitGrouping core.DigitGroupingType `json:"digitGrouping"`
|
||||
CurrencyDisplayType core.CurrencyDisplayType `json:"currencyDisplayType"`
|
||||
CoordinateDisplayType core.CoordinateDisplayType `json:"coordinateDisplayType"`
|
||||
ExpenseAmountColor AmountColorType `json:"expenseAmountColor"`
|
||||
IncomeAmountColor AmountColorType `json:"incomeAmountColor"`
|
||||
@@ -198,10 +200,11 @@ type UserProfileUpdateRequest struct {
|
||||
LongTimeFormat *core.LongTimeFormat `json:"longTimeFormat" binding:"omitempty,min=0,max=3"`
|
||||
ShortTimeFormat *core.ShortTimeFormat `json:"shortTimeFormat" binding:"omitempty,min=0,max=3"`
|
||||
FiscalYearFormat *core.FiscalYearFormat `json:"fiscalYearFormat" binding:"omitempty,min=0,max=5"`
|
||||
CurrencyDisplayType *core.CurrencyDisplayType `json:"currencyDisplayType" binding:"omitempty,min=0,max=11"`
|
||||
NumeralSystem *core.NumeralSystem `json:"numeralSystem" binding:"omitempty,min=0,max=5"`
|
||||
DecimalSeparator *core.DecimalSeparator `json:"decimalSeparator" binding:"omitempty,min=0,max=3"`
|
||||
DigitGroupingSymbol *core.DigitGroupingSymbol `json:"digitGroupingSymbol" binding:"omitempty,min=0,max=4"`
|
||||
DigitGrouping *core.DigitGroupingType `json:"digitGrouping" binding:"omitempty,min=0,max=3"`
|
||||
CurrencyDisplayType *core.CurrencyDisplayType `json:"currencyDisplayType" binding:"omitempty,min=0,max=11"`
|
||||
CoordinateDisplayType *core.CoordinateDisplayType `json:"coordinateDisplayType" binding:"omitempty,min=0,max=6"`
|
||||
ExpenseAmountColor *AmountColorType `json:"expenseAmountColor" binding:"omitempty,min=0,max=4"`
|
||||
IncomeAmountColor *AmountColorType `json:"incomeAmountColor" binding:"omitempty,min=0,max=4"`
|
||||
@@ -287,9 +290,10 @@ func (u *User) ToUserBasicInfo(avatarProvider core.UserAvatarProviderType, avata
|
||||
ShortTimeFormat: u.ShortTimeFormat,
|
||||
DecimalSeparator: u.DecimalSeparator,
|
||||
FiscalYearFormat: u.FiscalYearFormat,
|
||||
CurrencyDisplayType: u.CurrencyDisplayType,
|
||||
NumeralSystem: u.NumeralSystem,
|
||||
DigitGroupingSymbol: u.DigitGroupingSymbol,
|
||||
DigitGrouping: u.DigitGrouping,
|
||||
CurrencyDisplayType: u.CurrencyDisplayType,
|
||||
CoordinateDisplayType: u.CoordinateDisplayType,
|
||||
ExpenseAmountColor: u.ExpenseAmountColor,
|
||||
IncomeAmountColor: u.IncomeAmountColor,
|
||||
|
||||
@@ -313,6 +313,14 @@ func (s *UserService) UpdateUser(c core.Context, user *models.User, modifyUserLa
|
||||
updateCols = append(updateCols, "fiscal_year_format")
|
||||
}
|
||||
|
||||
if core.CURRENCY_DISPLAY_TYPE_DEFAULT <= user.CurrencyDisplayType && user.CurrencyDisplayType <= core.CURRENCY_DISPLAY_TYPE_NAME_AFTER_AMOUNT {
|
||||
updateCols = append(updateCols, "currency_display_type")
|
||||
}
|
||||
|
||||
if core.NUMERAL_SYSTEM_DEFAULT <= user.NumeralSystem && user.NumeralSystem <= core.NUMERAL_SYSTEM_DEVANAGARI_NUMERALS {
|
||||
updateCols = append(updateCols, "numeral_system")
|
||||
}
|
||||
|
||||
if core.DECIMAL_SEPARATOR_DEFAULT <= user.DecimalSeparator && user.DecimalSeparator <= core.DECIMAL_SEPARATOR_COMMA {
|
||||
updateCols = append(updateCols, "decimal_separator")
|
||||
}
|
||||
@@ -325,10 +333,6 @@ func (s *UserService) UpdateUser(c core.Context, user *models.User, modifyUserLa
|
||||
updateCols = append(updateCols, "digit_grouping")
|
||||
}
|
||||
|
||||
if core.CURRENCY_DISPLAY_TYPE_DEFAULT <= user.CurrencyDisplayType && user.CurrencyDisplayType <= core.CURRENCY_DISPLAY_TYPE_NAME_AFTER_AMOUNT {
|
||||
updateCols = append(updateCols, "currency_display_type")
|
||||
}
|
||||
|
||||
if core.COORDINATE_DISPLAY_TYPE_DEFAULT <= user.CoordinateDisplayType && user.CoordinateDisplayType <= core.COORDINATE_DISPLAY_TYPE_LONGITUDE_LATITUDE_DEGREES_MINUTES_SECONDS {
|
||||
updateCols = append(updateCols, "coordinate_display_type")
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ import { ref } from 'vue';
|
||||
|
||||
import { useI18n } from '@/locales/helpers.ts';
|
||||
|
||||
import { NumeralSystem } from '@/core/numeral.ts';
|
||||
|
||||
import { removeAll } from '@/lib/common.ts';
|
||||
import logger from '@/lib/logger.ts';
|
||||
|
||||
@@ -19,6 +21,7 @@ export type GetValidFormattedValueFunction = (value: number, textualValue: strin
|
||||
|
||||
export function useCommonNumberInputBase(props: CommonNumberInputProps, maxDecimalCount: number, initValue: string, parseNumber: ParseNumberFunction, formatNumber: FormatNumberFunction, getValidFormattedValue: GetValidFormattedValueFunction) {
|
||||
const {
|
||||
getCurrentNumeralSystemType,
|
||||
getCurrentDecimalSeparator,
|
||||
getCurrentDigitGroupingSymbol
|
||||
} = useI18n();
|
||||
@@ -38,10 +41,11 @@ export function useCommonNumberInputBase(props: CommonNumberInputProps, maxDecim
|
||||
return;
|
||||
}
|
||||
|
||||
const numeralSystem = getCurrentNumeralSystemType();
|
||||
const digitGroupingSymbol = getCurrentDigitGroupingSymbol();
|
||||
const decimalSeparator = getCurrentDecimalSeparator();
|
||||
|
||||
if (!('0' <= e.key && e.key <= '9') && e.key !== '-' && e.key !== decimalSeparator) {
|
||||
if (!NumeralSystem.WesternArabicNumerals.isDigit(e.key) && !numeralSystem.isDigit(e.key) && e.key !== '-' && e.key !== decimalSeparator) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
@@ -86,7 +90,7 @@ export function useCommonNumberInputBase(props: CommonNumberInputProps, maxDecim
|
||||
str = str.substring(1);
|
||||
}
|
||||
|
||||
str = (negative ? '-0' : '0') + str;
|
||||
str = (negative ? `-${numeralSystem.digitZero}` : numeralSystem.digitZero) + str;
|
||||
target.value = str;
|
||||
currentValue.value = target.value;
|
||||
e.preventDefault();
|
||||
@@ -98,14 +102,14 @@ export function useCommonNumberInputBase(props: CommonNumberInputProps, maxDecim
|
||||
|
||||
if (decimalIndex >= 0) {
|
||||
decimalLength = str.length - str.indexOf(decimalSeparator) - 1;
|
||||
} else if ((str.startsWith('0') && str.length >= 2) || (str.startsWith('-0') && str.length >= 3)) {
|
||||
} else if ((str.startsWith(numeralSystem.digitZero) && str.length >= 2) || (str.startsWith(`-${numeralSystem.digitZero}`) && str.length >= 3)) {
|
||||
const negative = str.charAt(0) === '-';
|
||||
|
||||
if (negative) {
|
||||
str = str.substring(1);
|
||||
}
|
||||
|
||||
while (str.charAt(0) === '0' && (str.length >= 2 || e.key !== '0')) {
|
||||
while (str.charAt(0) === numeralSystem.digitZero && (str.length >= 2 || e.key !== numeralSystem.digitZero)) {
|
||||
str = str.substring(1);
|
||||
}
|
||||
|
||||
@@ -138,7 +142,7 @@ export function useCommonNumberInputBase(props: CommonNumberInputProps, maxDecim
|
||||
}
|
||||
} catch (ex) {
|
||||
logger.warn('cannot parse input number, original value is ' + str, ex);
|
||||
target.value = '0';
|
||||
target.value = numeralSystem.digitZero;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useI18n } from '@/locales/helpers.ts';
|
||||
import { type CommonNumberInputProps, useCommonNumberInputBase } from '@/components/base/CommonNumberInputBase.ts';
|
||||
|
||||
import { isNumber, replaceAll, removeAll } from '@/lib/common.ts';
|
||||
import { NumeralSystem } from '@/core/numeral.ts';
|
||||
|
||||
export interface NumberInputProps extends CommonNumberInputProps {
|
||||
minValue?: number;
|
||||
@@ -17,6 +18,7 @@ export interface NumberInputEmits {
|
||||
|
||||
export function useNumberInputBase(props: NumberInputProps, emit: NumberInputEmits) {
|
||||
const {
|
||||
getCurrentNumeralSystemType,
|
||||
getCurrentDecimalSeparator,
|
||||
getCurrentDigitGroupingSymbol
|
||||
} = useI18n();
|
||||
@@ -32,17 +34,20 @@ export function useNumberInputBase(props: NumberInputProps, emit: NumberInputEmi
|
||||
return 0;
|
||||
}
|
||||
|
||||
const numeralSystem = getCurrentNumeralSystemType();
|
||||
const decimalSeparator = getCurrentDecimalSeparator();
|
||||
|
||||
let finalValue = '';
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
if (!('0' <= value[i] && value[i] <= '9') && value[i] !== '-' && value[i] !== decimalSeparator) {
|
||||
if (!NumeralSystem.WesternArabicNumerals.isDigit(value[i]) && !numeralSystem.isDigit(value[i]) && value[i] !== '-' && value[i] !== decimalSeparator) {
|
||||
break;
|
||||
}
|
||||
|
||||
finalValue += value[i];
|
||||
}
|
||||
|
||||
finalValue = numeralSystem.replaceLocalizedDigitsToWesternArabicDigits(finalValue);
|
||||
|
||||
if (decimalSeparator !== '.') {
|
||||
finalValue = replaceAll(finalValue, decimalSeparator, '.');
|
||||
}
|
||||
@@ -65,50 +70,72 @@ export function useNumberInputBase(props: NumberInputProps, emit: NumberInputEmi
|
||||
}
|
||||
|
||||
function getFormattedValue(value: number): string {
|
||||
const numeralSystem = getCurrentNumeralSystemType();
|
||||
|
||||
if (!Number.isNaN(value) && Number.isFinite(value)) {
|
||||
const decimalSeparator = getCurrentDecimalSeparator();
|
||||
|
||||
if (isNumber(props.maxDecimalCount) && props.maxDecimalCount >= 0) {
|
||||
return replaceAll(value.toFixed(props.maxDecimalCount), '.', decimalSeparator);
|
||||
return replaceAll(numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(value.toFixed(props.maxDecimalCount)), '.', decimalSeparator);
|
||||
} else {
|
||||
return replaceAll(value.toString(), '.', decimalSeparator);
|
||||
return replaceAll(numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(value.toString(10)), '.', decimalSeparator);
|
||||
}
|
||||
}
|
||||
|
||||
return '0';
|
||||
return numeralSystem.digitZero;
|
||||
}
|
||||
|
||||
watch(() => props.modelValue, (newValue) => {
|
||||
const numeralSystem = getCurrentNumeralSystemType();
|
||||
const numericCurrentValue = parseNumber(currentValue.value);
|
||||
|
||||
if (newValue !== numericCurrentValue) {
|
||||
const newStringValue = getFormattedValue(newValue);
|
||||
|
||||
if (!(newStringValue === '0' && currentValue.value === '')) {
|
||||
if (!(newStringValue === numeralSystem.digitZero && currentValue.value === '')) {
|
||||
currentValue.value = newStringValue;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
watch(currentValue, (newValue) => {
|
||||
const numeralSystem = getCurrentNumeralSystemType();
|
||||
let actualNumeralSystem: NumeralSystem | undefined = undefined;
|
||||
let finalValue = '';
|
||||
|
||||
if (newValue) {
|
||||
const decimalSeparator = getCurrentDecimalSeparator();
|
||||
|
||||
for (let i = 0; i < newValue.length; i++) {
|
||||
if (!('0' <= newValue[i] && newValue[i] <= '9') && newValue[i] !== '-' && newValue[i] !== decimalSeparator) {
|
||||
break;
|
||||
if (newValue[0] === '-' || newValue[0] === decimalSeparator) {
|
||||
actualNumeralSystem = NumeralSystem.detect(newValue[1]);
|
||||
} else {
|
||||
actualNumeralSystem = NumeralSystem.detect(newValue[0]);
|
||||
}
|
||||
|
||||
if (actualNumeralSystem && (actualNumeralSystem.type === NumeralSystem.WesternArabicNumerals.type || actualNumeralSystem.type === numeralSystem.type)) {
|
||||
for (let i = 0; i < newValue.length; i++) {
|
||||
if (!NumeralSystem.WesternArabicNumerals.isDigit(newValue[i]) && !numeralSystem.isDigit(newValue[i]) && newValue[i] !== '-' && newValue[i] !== decimalSeparator) {
|
||||
break;
|
||||
}
|
||||
|
||||
finalValue += newValue[i];
|
||||
}
|
||||
|
||||
finalValue += newValue[i];
|
||||
finalValue = numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(finalValue);
|
||||
} else if (newValue === '-' || newValue === decimalSeparator || newValue === `-${decimalSeparator}`) {
|
||||
finalValue = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (finalValue !== newValue) {
|
||||
currentValue.value = finalValue;
|
||||
} else {
|
||||
const value: number = parseNumber(finalValue);
|
||||
let value: number = parseNumber(finalValue);
|
||||
|
||||
if (Number.isNaN(value) || !Number.isFinite(value)) {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
emit('update:modelValue', value);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -35,7 +35,7 @@ export interface CommonPieChartProps {
|
||||
}
|
||||
|
||||
export function usePieChartBase(props: CommonPieChartProps) {
|
||||
const { formatAmountWithCurrency, formatPercent } = useI18n();
|
||||
const { formatAmountToLocalizedNumeralsWithCurrency, formatPercentToLocalizedNumerals } = useI18n();
|
||||
|
||||
const selectedIndex = ref<number>(0);
|
||||
|
||||
@@ -72,8 +72,8 @@ export function usePieChartBase(props: CommonPieChartProps) {
|
||||
sourceItem: item
|
||||
};
|
||||
|
||||
finalItem.displayPercent = formatPercent(finalItem.percent, 2, '<0.01');
|
||||
finalItem.displayValue = formatAmountWithCurrency(finalItem.value, props.defaultCurrency);
|
||||
finalItem.displayPercent = formatPercentToLocalizedNumerals(finalItem.percent, 2, '<0.01');
|
||||
finalItem.displayValue = formatAmountToLocalizedNumeralsWithCurrency(finalItem.value, props.defaultCurrency);
|
||||
|
||||
validItems.push(finalItem);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, useTemplateRef } from 'vue';
|
||||
|
||||
import { useI18n } from '@/locales/helpers.ts';
|
||||
|
||||
import { NumeralSystem } from '@/core/numeral.ts';
|
||||
|
||||
interface PinCode {
|
||||
value: string;
|
||||
inputType: string;
|
||||
@@ -42,6 +46,8 @@ const emit = defineEmits<{
|
||||
(e: 'pincode:confirm', value: string): void;
|
||||
}>();
|
||||
|
||||
const { getCurrentNumeralSystemType } = useI18n();
|
||||
|
||||
const codes = ref<PinCode[]>([]);
|
||||
const pinCodeInputs = useTemplateRef<HTMLInputElement[]>('pin-code-input');
|
||||
|
||||
@@ -148,6 +154,8 @@ function setNextFocus(index: number): void {
|
||||
}
|
||||
|
||||
function onKeydown(index: number, event: KeyboardEvent): void {
|
||||
const numeralSystem = getCurrentNumeralSystemType();
|
||||
|
||||
if (event.altKey || (event.key.indexOf('F') === 0 && (event.key.length === 2 || event.key.length === 3))) {
|
||||
return;
|
||||
}
|
||||
@@ -208,13 +216,23 @@ function onKeydown(index: number, event: KeyboardEvent): void {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.key.length === 1 && '0' <= event.key && event.key <= '9') {
|
||||
codes.value[index].value = event.key;
|
||||
setInputType(index);
|
||||
setNextFocus(index);
|
||||
if (event.key.length === 1) {
|
||||
let digit = '';
|
||||
|
||||
if (props.autoConfirm && finalPinCode.value.length === props.length) {
|
||||
emit('pincode:confirm', finalPinCode.value);
|
||||
if (NumeralSystem.WesternArabicNumerals.isDigit(event.key)) {
|
||||
digit = event.key;
|
||||
} else if (numeralSystem.isDigit(event.key)) {
|
||||
digit = numeralSystem.replaceLocalizedDigitsToWesternArabicDigits(event.key);
|
||||
}
|
||||
|
||||
if (digit) {
|
||||
codes.value[index].value = digit;
|
||||
setInputType(index);
|
||||
setNextFocus(index);
|
||||
|
||||
if (props.autoConfirm && finalPinCode.value.length === props.length) {
|
||||
emit('pincode:confirm', finalPinCode.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ interface AccountBalanceTrendsChartDataItem {
|
||||
const props = defineProps<DesktopAccountBalanceTrendsChartProps>();
|
||||
|
||||
const theme = useTheme();
|
||||
const { tt, formatAmountWithCurrency } = useI18n();
|
||||
const { tt, formatAmountToLocalizedNumeralsWithCurrency } = useI18n();
|
||||
const { allDataItems, allDisplayDateRanges } = useAccountBalanceTrendsChartBase(props);
|
||||
|
||||
const userStore = useUserStore();
|
||||
@@ -129,8 +129,8 @@ const yAxisWidth = computed<number>(() => {
|
||||
}
|
||||
}
|
||||
|
||||
const maxValueText = formatAmountWithCurrency(maxValue, props.account.currency);
|
||||
const minValueText = formatAmountWithCurrency(minValue, props.account.currency);
|
||||
const maxValueText = formatAmountToLocalizedNumeralsWithCurrency(maxValue, props.account.currency);
|
||||
const minValueText = formatAmountToLocalizedNumeralsWithCurrency(minValue, props.account.currency);
|
||||
const maxLengthText = maxValueText.length > minValueText.length ? maxValueText : minValueText;
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
@@ -175,27 +175,27 @@ const chartOptions = computed<object>(() => {
|
||||
const displayItems: NameValue[] = [
|
||||
{
|
||||
name: tt('Opening Balance'),
|
||||
value: formatAmountWithCurrency(dataItem.openingBalance, props.account.currency)
|
||||
value: formatAmountToLocalizedNumeralsWithCurrency(dataItem.openingBalance, props.account.currency)
|
||||
},
|
||||
{
|
||||
name: tt('Closing Balance'),
|
||||
value: formatAmountWithCurrency(dataItem.closingBalance, props.account.currency)
|
||||
value: formatAmountToLocalizedNumeralsWithCurrency(dataItem.closingBalance, props.account.currency)
|
||||
},
|
||||
{
|
||||
name: tt('Minimum Balance'),
|
||||
value: formatAmountWithCurrency(dataItem.minimumBalance, props.account.currency)
|
||||
value: formatAmountToLocalizedNumeralsWithCurrency(dataItem.minimumBalance, props.account.currency)
|
||||
},
|
||||
{
|
||||
name: tt('Maximum Balance'),
|
||||
value: formatAmountWithCurrency(dataItem.maximumBalance, props.account.currency)
|
||||
value: formatAmountToLocalizedNumeralsWithCurrency(dataItem.maximumBalance, props.account.currency)
|
||||
},
|
||||
{
|
||||
name: tt('Median Balance'),
|
||||
value: formatAmountWithCurrency(dataItem.medianBalance, props.account.currency)
|
||||
value: formatAmountToLocalizedNumeralsWithCurrency(dataItem.medianBalance, props.account.currency)
|
||||
},
|
||||
{
|
||||
name: tt('Average Balance'),
|
||||
value: formatAmountWithCurrency(dataItem.averageBalance, props.account.currency)
|
||||
value: formatAmountToLocalizedNumeralsWithCurrency(dataItem.averageBalance, props.account.currency)
|
||||
}
|
||||
];
|
||||
|
||||
@@ -210,7 +210,7 @@ const chartOptions = computed<object>(() => {
|
||||
return tooltip;
|
||||
} else {
|
||||
const amount = params[0].data as number;
|
||||
const value = formatAmountWithCurrency(amount, props.account.currency);
|
||||
const value = formatAmountToLocalizedNumeralsWithCurrency(amount, props.account.currency);
|
||||
|
||||
return `${params[0].name}<br/>`
|
||||
+ '<div><span class="chart-pointer" style="background-color: #' + DEFAULT_CHART_COLORS[0] + '"></span>'
|
||||
@@ -234,13 +234,13 @@ const chartOptions = computed<object>(() => {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: (value: string) => {
|
||||
return formatAmountWithCurrency(value, props.account.currency);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(parseInt(value), props.account.currency);
|
||||
}
|
||||
},
|
||||
axisPointer: {
|
||||
label: {
|
||||
formatter: (params: CallbackDataParams) => {
|
||||
return formatAmountWithCurrency(Math.floor(params.value as number), props.account.currency);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(Math.floor(params.value as number), props.account.currency);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -74,11 +74,11 @@ import { ref, computed, useTemplateRef, watch } from 'vue';
|
||||
import { useI18n } from '@/locales/helpers.ts';
|
||||
import { type CommonNumberInputProps, useCommonNumberInputBase } from '@/components/base/CommonNumberInputBase.ts';
|
||||
|
||||
import { DecimalSeparator } from '@/core/numeral.ts';
|
||||
import { NumeralSystem, DecimalSeparator } from '@/core/numeral.ts';
|
||||
import type { CurrencyPrependAndAppendText } from '@/core/currency.ts';
|
||||
import { DEFAULT_DECIMAL_NUMBER_COUNT } from '@/consts/numeral.ts';
|
||||
import { TRANSACTION_MIN_AMOUNT, TRANSACTION_MAX_AMOUNT } from '@/consts/transaction.ts';
|
||||
import { isNumber, replaceAll, removeAll } from '@/lib/common.ts';
|
||||
import { isNumber, replaceAll } from '@/lib/common.ts';
|
||||
import { evaluateExpression } from '@/lib/evaluator.ts';
|
||||
import type { ComponentDensity } from '@/lib/ui/desktop.ts';
|
||||
import logger from '@/lib/logger.ts';
|
||||
@@ -112,11 +112,11 @@ const emit = defineEmits<{
|
||||
|
||||
const {
|
||||
tt,
|
||||
getCurrentNumeralSystemType,
|
||||
getCurrentDecimalSeparator,
|
||||
getCurrentDigitGroupingSymbol,
|
||||
parseAmount,
|
||||
formatAmount,
|
||||
formatNumber,
|
||||
parseAmountFromLocalizedNumerals,
|
||||
formatAmountToLocalizedNumeralsWithoutDigitGrouping,
|
||||
formatNumberToLocalizedNumerals,
|
||||
getAmountPrependAndAppendText
|
||||
} = useI18n();
|
||||
|
||||
@@ -124,7 +124,7 @@ const {
|
||||
currentValue,
|
||||
onKeyUpDown,
|
||||
onPaste
|
||||
} = useCommonNumberInputBase(props, DEFAULT_DECIMAL_NUMBER_COUNT, getInitedFormattedValue(props.modelValue, props.flipNegative), parseAmount, getFormattedValue, getValidFormattedValue);
|
||||
} = useCommonNumberInputBase(props, DEFAULT_DECIMAL_NUMBER_COUNT, getInitedFormattedValue(props.modelValue, props.flipNegative), parseAmountFromLocalizedNumerals, getFormattedValue, getValidFormattedValue);
|
||||
|
||||
const snackbar = useTemplateRef<SnackBarType>('snackbar');
|
||||
|
||||
@@ -135,7 +135,7 @@ const rules = [
|
||||
}
|
||||
|
||||
try {
|
||||
const val = parseAmount(v);
|
||||
const val = parseAmountFromLocalizedNumerals(v);
|
||||
|
||||
if (Number.isNaN(val) || !Number.isFinite(val)) {
|
||||
return tt('Amount value is not number');
|
||||
@@ -205,6 +205,7 @@ function enterFormulaMode(): void {
|
||||
|
||||
function calculateFormula(): void {
|
||||
const systemDecimalSeparator = DecimalSeparator.Dot.symbol;
|
||||
const numeralSystem = getCurrentNumeralSystemType();
|
||||
const decimalSeparator = getCurrentDecimalSeparator();
|
||||
let finalFormula = currentFormula.value;
|
||||
|
||||
@@ -215,12 +216,13 @@ function calculateFormula(): void {
|
||||
finalFormula = replaceAll(currentFormula.value, decimalSeparator, systemDecimalSeparator);
|
||||
}
|
||||
|
||||
finalFormula = numeralSystem.replaceLocalizedDigitsToWesternArabicDigits(finalFormula);
|
||||
const calculatedValue = evaluateExpression(finalFormula);
|
||||
|
||||
if (isNumber(calculatedValue)) {
|
||||
const textualValue = formatNumber(calculatedValue, 2);
|
||||
const textualValue = formatNumberToLocalizedNumerals(calculatedValue, 2);
|
||||
const hasDecimalSeparator = textualValue.indexOf(decimalSeparator) >= 0;
|
||||
currentValue.value = getValidFormattedValue(calculatedValue, textualValue, hasDecimalSeparator);
|
||||
currentValue.value = getValidFormattedValue(calculatedValue * 100, textualValue, hasDecimalSeparator);
|
||||
formulaMode.value = false;
|
||||
} else {
|
||||
snackbar.value?.showMessage('Formula is invalid');
|
||||
@@ -273,33 +275,36 @@ function getInitedFormattedValue(value: number, flipNegative?: boolean): string
|
||||
}
|
||||
|
||||
function getFormattedValue(value: number): string {
|
||||
const numeralSystem = getCurrentNumeralSystemType();
|
||||
|
||||
if (!Number.isNaN(value) && Number.isFinite(value)) {
|
||||
const digitGroupingSymbol = getCurrentDigitGroupingSymbol();
|
||||
return removeAll(formatAmount(value, props.currency), digitGroupingSymbol);
|
||||
return formatAmountToLocalizedNumeralsWithoutDigitGrouping(value, props.currency);
|
||||
}
|
||||
|
||||
return '0';
|
||||
return numeralSystem.digitZero;
|
||||
}
|
||||
|
||||
function getDisplayCurrencyPrependAndAppendText(): CurrencyPrependAndAppendText | null {
|
||||
const numericCurrentValue = parseAmount(currentValue.value);
|
||||
const numericCurrentValue = parseAmountFromLocalizedNumerals(currentValue.value);
|
||||
const isPlural = numericCurrentValue !== 100 && numericCurrentValue !== -100;
|
||||
|
||||
return getAmountPrependAndAppendText(props.currency, isPlural);
|
||||
}
|
||||
|
||||
watch(() => props.currency, () => {
|
||||
const numeralSystem = getCurrentNumeralSystemType();
|
||||
const newStringValue = getInitedFormattedValue(props.modelValue, props.flipNegative);
|
||||
|
||||
if (!(newStringValue === '0' && currentValue.value === '')) {
|
||||
if (!(newStringValue === numeralSystem.digitZero && currentValue.value === '')) {
|
||||
currentValue.value = newStringValue;
|
||||
}
|
||||
});
|
||||
|
||||
watch(() => props.flipNegative, (newValue) => {
|
||||
const numeralSystem = getCurrentNumeralSystemType();
|
||||
const newStringValue = getInitedFormattedValue(props.modelValue, newValue);
|
||||
|
||||
if (!(newStringValue === '0' && currentValue.value === '')) {
|
||||
if (!(newStringValue === numeralSystem.digitZero && currentValue.value === '')) {
|
||||
currentValue.value = newStringValue;
|
||||
}
|
||||
});
|
||||
@@ -309,36 +314,55 @@ watch(() => props.modelValue, (newValue) => {
|
||||
newValue = -newValue;
|
||||
}
|
||||
|
||||
const numericCurrentValue = parseAmount(currentValue.value);
|
||||
const numeralSystem = getCurrentNumeralSystemType();
|
||||
const numericCurrentValue = parseAmountFromLocalizedNumerals(currentValue.value);
|
||||
|
||||
if (newValue !== numericCurrentValue) {
|
||||
const newStringValue = getFormattedValue(newValue);
|
||||
|
||||
if (!(newStringValue === '0' && currentValue.value === '')) {
|
||||
if (!(newStringValue === numeralSystem.digitZero && currentValue.value === '')) {
|
||||
currentValue.value = newStringValue;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
watch(currentValue, (newValue) => {
|
||||
const numeralSystem = getCurrentNumeralSystemType();
|
||||
let actualNumeralSystem: NumeralSystem | undefined = undefined;
|
||||
let finalValue = '';
|
||||
|
||||
if (newValue) {
|
||||
const decimalSeparator = getCurrentDecimalSeparator();
|
||||
|
||||
for (let i = 0; i < newValue.length; i++) {
|
||||
if (!('0' <= newValue[i] && newValue[i] <= '9') && newValue[i] !== '-' && newValue[i] !== decimalSeparator) {
|
||||
break;
|
||||
if (newValue[0] === '-' || newValue[0] === decimalSeparator) {
|
||||
actualNumeralSystem = NumeralSystem.detect(newValue[1]);
|
||||
} else {
|
||||
actualNumeralSystem = NumeralSystem.detect(newValue[0]);
|
||||
}
|
||||
|
||||
if (actualNumeralSystem && (actualNumeralSystem.type === NumeralSystem.WesternArabicNumerals.type || actualNumeralSystem.type === numeralSystem.type)) {
|
||||
for (let i = 0; i < newValue.length; i++) {
|
||||
if (!NumeralSystem.WesternArabicNumerals.isDigit(newValue[i]) && !numeralSystem.isDigit(newValue[i]) && newValue[i] !== '-' && newValue[i] !== decimalSeparator) {
|
||||
break;
|
||||
}
|
||||
|
||||
finalValue += newValue[i];
|
||||
}
|
||||
|
||||
finalValue += newValue[i];
|
||||
finalValue = numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(finalValue);
|
||||
} else if (newValue === '-' || newValue === decimalSeparator || newValue === `-${decimalSeparator}`) {
|
||||
finalValue = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (finalValue !== newValue) {
|
||||
currentValue.value = finalValue;
|
||||
} else {
|
||||
let value: number = parseAmount(finalValue);
|
||||
let value: number = parseAmountFromLocalizedNumerals(finalValue);
|
||||
|
||||
if (Number.isNaN(value) || !Number.isFinite(value)) {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
if (props.flipNegative) {
|
||||
value = -value;
|
||||
|
||||
@@ -25,9 +25,6 @@ import {
|
||||
isArray,
|
||||
isNumber
|
||||
} from '@/lib/common.ts';
|
||||
import {
|
||||
formatAmount
|
||||
} from '@/lib/numeral.ts';
|
||||
import {
|
||||
getYearMonthFirstUnixTime,
|
||||
getYearMonthLastUnixTime,
|
||||
@@ -73,7 +70,16 @@ const emit = defineEmits<{
|
||||
}>();
|
||||
|
||||
const theme = useTheme();
|
||||
const { tt, formatUnixTimeToShortYear, formatYearQuarter, formatUnixTimeToShortYearMonth, formatUnixTimeToFiscalYear, formatAmountWithCurrency } = useI18n();
|
||||
|
||||
const { tt,
|
||||
formatUnixTimeToShortYear,
|
||||
formatYearQuarter,
|
||||
formatUnixTimeToShortYearMonth,
|
||||
formatUnixTimeToFiscalYear,
|
||||
formatAmountToWesternArabicNumeralsWithoutDigitGrouping,
|
||||
formatAmountToLocalizedNumeralsWithCurrency
|
||||
} = useI18n();
|
||||
|
||||
const { allDateRanges, getItemName, getColor } = useMonthlyTrendsChartBase(props);
|
||||
|
||||
const userStore = useUserStore();
|
||||
@@ -252,8 +258,8 @@ const yAxisWidth = computed<number>(() => {
|
||||
}
|
||||
}
|
||||
|
||||
const maxValueText = formatAmountWithCurrency(maxValue, props.defaultCurrency);
|
||||
const minValueText = formatAmountWithCurrency(minValue, props.defaultCurrency);
|
||||
const maxValueText = formatAmountToLocalizedNumeralsWithCurrency(maxValue, props.defaultCurrency);
|
||||
const minValueText = formatAmountToLocalizedNumeralsWithCurrency(minValue, props.defaultCurrency);
|
||||
const maxLengthText = maxValueText.length > minValueText.length ? maxValueText : minValueText;
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
@@ -319,7 +325,7 @@ const chartOptions = computed<object>(() => {
|
||||
const item = displayItems[i];
|
||||
|
||||
if (displayItems.length === 1 || item.totalAmount !== 0) {
|
||||
const value = formatAmountWithCurrency(item.totalAmount, props.defaultCurrency);
|
||||
const value = formatAmountToLocalizedNumeralsWithCurrency(item.totalAmount, props.defaultCurrency);
|
||||
tooltip += '<div><span class="chart-pointer" style="background-color: ' + item.color + '"></span>';
|
||||
tooltip += `<span>${item.name}</span><span style="margin-left: 20px; float: right">${value}</span><br/>`;
|
||||
tooltip += '</div>';
|
||||
@@ -327,7 +333,7 @@ const chartOptions = computed<object>(() => {
|
||||
}
|
||||
|
||||
if (props.showTotalAmountInTooltip) {
|
||||
const displayTotalAmount = formatAmountWithCurrency(totalAmount, props.defaultCurrency);
|
||||
const displayTotalAmount = formatAmountToLocalizedNumeralsWithCurrency(totalAmount, props.defaultCurrency);
|
||||
tooltip = '<div style="border-bottom: ' + (isDarkMode.value ? '#eee' : '#333') + ' dashed 1px">'
|
||||
+ '<span class="chart-pointer" style="background-color: ' + (isDarkMode.value ? '#eee' : '#333') + '"></span>'
|
||||
+ `<span>${tt('Total Amount')}</span><span style="margin-left: 20px; float: right">${displayTotalAmount}</span><br/>`
|
||||
@@ -367,13 +373,13 @@ const chartOptions = computed<object>(() => {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: (value: string) => {
|
||||
return formatAmountWithCurrency(value, props.defaultCurrency);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(parseInt(value), props.defaultCurrency);
|
||||
}
|
||||
},
|
||||
axisPointer: {
|
||||
label: {
|
||||
formatter: (params: CallbackDataParams) => {
|
||||
return formatAmountWithCurrency(Math.floor(params.value as number), props.defaultCurrency);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(Math.floor(params.value as number), props.defaultCurrency);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -443,7 +449,7 @@ function exportData(): { headers: string[], data: string[][] } {
|
||||
for (let i = 0; i < allDisplayDateRanges.value.length; i++) {
|
||||
const row: string[] = [];
|
||||
row.push(allDisplayDateRanges.value[i]);
|
||||
row.push(...allSeries.value.map(item => formatAmount(item.data[i], {})));
|
||||
row.push(...allSeries.value.map(item => formatAmountToWesternArabicNumeralsWithoutDigitGrouping(item.data[i])));
|
||||
data.push(row);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ const emit = defineEmits<{
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const { formatAmountWithCurrency } = useI18n();
|
||||
const { formatAmountToLocalizedNumeralsWithCurrency } = useI18n();
|
||||
const { selectedIndex, validItems } = usePieChartBase(props);
|
||||
|
||||
const selectedLegends = ref<Record<string, boolean> | null>(null);
|
||||
@@ -133,7 +133,7 @@ const chartOptions = computed<object>(() => {
|
||||
formatter: (params: CallbackDataParams) => {
|
||||
const dataItem = params.data as DesktopPieChartDataItem;
|
||||
const name = dataItem ? dataItem.displayName : '';
|
||||
const value = dataItem ? dataItem.displayValue : formatAmountWithCurrency(params.value as number);
|
||||
const value = dataItem ? dataItem.displayValue : formatAmountToLocalizedNumeralsWithCurrency(params.value as number);
|
||||
let percent = dataItem ? dataItem.displayPercent : (params.percent + '%');
|
||||
|
||||
if (hasUnselectedItem.value) {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
:style="`top: ${virtualDataItems.topPosition}px`"
|
||||
:virtual-list-index="item.index"
|
||||
:title="item.displayDate"
|
||||
:after="formatAmountWithCurrency(item.closingBalance, account.currency)"
|
||||
:after="formatAmountToLocalizedNumeralsWithCurrency(item.closingBalance, account.currency)"
|
||||
v-for="item in virtualDataItems.items"
|
||||
>
|
||||
<template #media>
|
||||
@@ -80,7 +80,7 @@ interface MobileAccountBalanceTrendsChartVirtualListData {
|
||||
|
||||
const props = defineProps<MobileAccountBalanceTrendsChartProps>();
|
||||
|
||||
const { tt, formatAmountWithCurrency } = useI18n();
|
||||
const { tt, formatAmountToLocalizedNumeralsWithCurrency } = useI18n();
|
||||
const { allDataItems } = useAccountBalanceTrendsChartBase(props);
|
||||
|
||||
const virtualDataItems = ref<MobileAccountBalanceTrendsChartVirtualListData>({
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
</template>
|
||||
|
||||
<template #after>
|
||||
<span>{{ formatAmountWithCurrency(item.totalAmount, defaultCurrency) }}</span>
|
||||
<span>{{ formatAmountToLocalizedNumeralsWithCurrency(item.totalAmount, defaultCurrency) }}</span>
|
||||
</template>
|
||||
|
||||
<template #inner-end>
|
||||
@@ -148,7 +148,15 @@ const emit = defineEmits<{
|
||||
(e: 'click', value: MonthlyTrendsBarChartClickEvent): void;
|
||||
}>();
|
||||
|
||||
const { tt, formatUnixTimeToShortYear, formatYearQuarter, formatUnixTimeToShortYearMonth, formatUnixTimeToFiscalYear, formatAmountWithCurrency } = useI18n();
|
||||
const {
|
||||
tt,
|
||||
formatUnixTimeToShortYear,
|
||||
formatYearQuarter,
|
||||
formatUnixTimeToShortYearMonth,
|
||||
formatUnixTimeToFiscalYear,
|
||||
formatAmountToLocalizedNumeralsWithCurrency
|
||||
} = useI18n();
|
||||
|
||||
const { allDateRanges, getItemName, getColor } = useMonthlyTrendsChartBase(props);
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
@@ -11,37 +11,37 @@
|
||||
</div>
|
||||
<div class="numpad-buttons">
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(7)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">7</span>
|
||||
<span class="numpad-button-text numpad-button-text-normal">{{ digits[7] }}</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(8)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">8</span>
|
||||
<span class="numpad-button-text numpad-button-text-normal">{{ digits[8] }}</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(9)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">9</span>
|
||||
<span class="numpad-button-text numpad-button-text-normal">{{ digits[9] }}</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-function no-right-border" @click="setSymbol('×')">
|
||||
<span class="numpad-button-text numpad-button-text-normal">×</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(4)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">4</span>
|
||||
<span class="numpad-button-text numpad-button-text-normal">{{ digits[4] }}</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(5)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">5</span>
|
||||
<span class="numpad-button-text numpad-button-text-normal">{{ digits[5] }}</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(6)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">6</span>
|
||||
<span class="numpad-button-text numpad-button-text-normal">{{ digits[6] }}</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-function no-right-border" @click="setSymbol('−')">
|
||||
<span class="numpad-button-text numpad-button-text-normal">−</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(1)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">1</span>
|
||||
<span class="numpad-button-text numpad-button-text-normal">{{ digits[1] }}</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(2)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">2</span>
|
||||
<span class="numpad-button-text numpad-button-text-normal">{{ digits[2] }}</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(3)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">3</span>
|
||||
<span class="numpad-button-text numpad-button-text-normal">{{ digits[3] }}</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-function no-right-border" @click="setSymbol('+')">
|
||||
<span class="numpad-button-text numpad-button-text-normal">+</span>
|
||||
@@ -50,10 +50,10 @@
|
||||
<span class="numpad-button-text numpad-button-text-normal">{{ decimalSeparator }}</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" v-if="!supportDecimalSeparator" @click="inputDoubleNum(0)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">00</span>
|
||||
<span class="numpad-button-text numpad-button-text-normal">{{ digits[0] + digits[0] }}</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(0)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">0</span>
|
||||
<span class="numpad-button-text numpad-button-text-normal">{{ digits[0] }}</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="backspace" @taphold="clear()">
|
||||
<span class="numpad-button-text numpad-button-text-normal">
|
||||
@@ -74,8 +74,9 @@ import { ref, computed, watch } from 'vue';
|
||||
import { useI18n } from '@/locales/helpers.ts';
|
||||
import { useI18nUIComponents } from '@/lib/ui/mobile.ts';
|
||||
|
||||
import { NumeralSystem } from '@/core/numeral.ts';
|
||||
import { ALL_CURRENCIES } from '@/consts/currency.ts';
|
||||
import { isString, isNumber, removeAll } from '@/lib/common.ts';
|
||||
import { isNumber } from '@/lib/common.ts';
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: number;
|
||||
@@ -94,11 +95,12 @@ const emit = defineEmits<{
|
||||
|
||||
const {
|
||||
tt,
|
||||
getAllLocalizedDigits,
|
||||
getCurrentNumeralSystemType,
|
||||
getCurrentDecimalSeparator,
|
||||
getCurrentDigitGroupingSymbol,
|
||||
appendDigitGroupingSymbol,
|
||||
parseAmount,
|
||||
formatAmount
|
||||
parseAmountFromWesternArabicNumerals,
|
||||
formatAmountToWesternArabicNumeralsWithoutDigitGrouping,
|
||||
appendDigitGroupingSymbolAndDecimalSeparator
|
||||
} = useI18n();
|
||||
const { showToast } = useI18nUIComponents();
|
||||
|
||||
@@ -106,6 +108,7 @@ const previousValue = ref<string>('');
|
||||
const currentSymbol = ref<string>('');
|
||||
const currentValue = ref<string>(getInitedStringValue(props.modelValue, props.flipNegative));
|
||||
|
||||
const digits = computed<string[]>(() => getAllLocalizedDigits());
|
||||
const decimalSeparator = computed<string>(() => getCurrentDecimalSeparator());
|
||||
|
||||
const supportDecimalSeparator = computed<boolean>(() => {
|
||||
@@ -117,8 +120,21 @@ const supportDecimalSeparator = computed<boolean>(() => {
|
||||
});
|
||||
|
||||
const currentDisplay = computed<string>(() => {
|
||||
const finalPreviousValue = appendDigitGroupingSymbol(previousValue.value);
|
||||
const finalCurrentValue = appendDigitGroupingSymbol(currentValue.value);
|
||||
const numeralSystem = getCurrentNumeralSystemType();
|
||||
const finalPreviousValue = appendDigitGroupingSymbolAndDecimalSeparator(numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(previousValue.value));
|
||||
let finalCurrentValue = currentValue.value;
|
||||
let currentValueSuffix = '';
|
||||
|
||||
if (finalCurrentValue && finalCurrentValue[finalCurrentValue.length - 1] === decimalSeparator.value) {
|
||||
finalCurrentValue = finalCurrentValue.substring(0, finalCurrentValue.length - 1);
|
||||
currentValueSuffix = decimalSeparator.value;
|
||||
}
|
||||
|
||||
finalCurrentValue = appendDigitGroupingSymbolAndDecimalSeparator(numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(finalCurrentValue));
|
||||
|
||||
if (currentValueSuffix) {
|
||||
finalCurrentValue += currentValueSuffix;
|
||||
}
|
||||
|
||||
if (currentSymbol.value) {
|
||||
return `${finalPreviousValue} ${currentSymbol.value} ${finalCurrentValue}`;
|
||||
@@ -150,45 +166,39 @@ function getInitedStringValue(value: number, flipNegative?: boolean): string {
|
||||
value = -value;
|
||||
}
|
||||
|
||||
return getStringValue(value);
|
||||
return getStringValue(value, true);
|
||||
}
|
||||
|
||||
function getStringValue(value: number | string): string {
|
||||
if (!isNumber(value) && !isString(value)) {
|
||||
function getStringValue(value: number, hideZero: boolean): string {
|
||||
if (!isNumber(value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let str = formatAmount(value, props.currency);
|
||||
|
||||
const digitGroupingSymbol = getCurrentDigitGroupingSymbol();
|
||||
|
||||
if (str.indexOf(digitGroupingSymbol) >= 0) {
|
||||
str = removeAll(str, digitGroupingSymbol);
|
||||
}
|
||||
const textualNumber = formatAmountToWesternArabicNumeralsWithoutDigitGrouping(value, props.currency);
|
||||
|
||||
const decimalSeparator = getCurrentDecimalSeparator();
|
||||
const decimalSeparatorPos = str.indexOf(decimalSeparator);
|
||||
const decimalSeparatorPos = textualNumber.indexOf(decimalSeparator);
|
||||
|
||||
if (decimalSeparatorPos < 0) {
|
||||
if (str === '0') {
|
||||
if (hideZero && textualNumber === NumeralSystem.WesternArabicNumerals.digitZero) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return str;
|
||||
return textualNumber;
|
||||
}
|
||||
|
||||
const integer = str.substring(0, decimalSeparatorPos);
|
||||
const decimals = str.substring(decimalSeparatorPos + 1, str.length);
|
||||
const integer = textualNumber.substring(0, decimalSeparatorPos);
|
||||
const decimals = textualNumber.substring(decimalSeparatorPos + 1, textualNumber.length);
|
||||
let newDecimals = '';
|
||||
|
||||
for (let i = decimals.length - 1; i >= 0; i--) {
|
||||
if (decimals[i] !== '0' || newDecimals.length > 0) {
|
||||
if (decimals[i] !== NumeralSystem.WesternArabicNumerals.digitZero || newDecimals.length > 0) {
|
||||
newDecimals = decimals[i] + newDecimals;
|
||||
}
|
||||
}
|
||||
|
||||
if (newDecimals.length < 1) {
|
||||
if (integer === '0') {
|
||||
if (hideZero && integer === NumeralSystem.WesternArabicNumerals.digitZero) {
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -204,10 +214,10 @@ function inputNum(num: number): void {
|
||||
currentSymbol.value = '';
|
||||
}
|
||||
|
||||
if (currentValue.value === '0') {
|
||||
if (currentValue.value === NumeralSystem.WesternArabicNumerals.digitZero) {
|
||||
currentValue.value = num.toString();
|
||||
return;
|
||||
} else if (currentValue.value === '-0') {
|
||||
} else if (currentValue.value === `-${NumeralSystem.WesternArabicNumerals.digitZero}`) {
|
||||
currentValue.value = '-' + num.toString();
|
||||
return;
|
||||
}
|
||||
@@ -221,7 +231,7 @@ function inputNum(num: number): void {
|
||||
const newValue = currentValue.value + num.toString();
|
||||
|
||||
if (isNumber(props.minValue)) {
|
||||
const current = parseAmount(newValue);
|
||||
const current = parseAmountFromWesternArabicNumerals(newValue);
|
||||
|
||||
if (current < (props.minValue)) {
|
||||
return;
|
||||
@@ -229,7 +239,7 @@ function inputNum(num: number): void {
|
||||
}
|
||||
|
||||
if (isNumber(props.maxValue)) {
|
||||
const current = parseAmount(newValue);
|
||||
const current = parseAmountFromWesternArabicNumerals(newValue);
|
||||
|
||||
if (current > (props.maxValue)) {
|
||||
return;
|
||||
@@ -255,9 +265,9 @@ function inputDecimalSeparator(): void {
|
||||
}
|
||||
|
||||
if (currentValue.value.length < 1) {
|
||||
currentValue.value = '0';
|
||||
currentValue.value = NumeralSystem.WesternArabicNumerals.digitZero;
|
||||
} else if (currentValue.value === '-') {
|
||||
currentValue.value = '-0';
|
||||
currentValue.value = '-' + NumeralSystem.WesternArabicNumerals.digitZero;
|
||||
}
|
||||
|
||||
currentValue.value = currentValue.value + decimalSeparator.value;
|
||||
@@ -302,8 +312,8 @@ function clear(): void {
|
||||
|
||||
function confirm(): boolean {
|
||||
if (currentSymbol.value && currentValue.value.length >= 1) {
|
||||
const previous = parseAmount(previousValue.value);
|
||||
const current = parseAmount(currentValue.value);
|
||||
const previous = parseAmountFromWesternArabicNumerals(previousValue.value);
|
||||
const current = parseAmountFromWesternArabicNumerals(currentValue.value);
|
||||
let finalValue = 0;
|
||||
|
||||
switch (currentSymbol.value) {
|
||||
@@ -334,7 +344,7 @@ function confirm(): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
currentValue.value = getStringValue(finalValue);
|
||||
currentValue.value = getStringValue(finalValue, false);
|
||||
previousValue.value = '';
|
||||
currentSymbol.value = '';
|
||||
|
||||
@@ -346,7 +356,7 @@ function confirm(): boolean {
|
||||
|
||||
return true;
|
||||
} else {
|
||||
let value: number = parseAmount(currentValue.value);
|
||||
let value: number = parseAmountFromWesternArabicNumerals(currentValue.value);
|
||||
|
||||
if (props.flipNegative) {
|
||||
value = -value;
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
import type { HiddenAmount } from '@/core/numeral.ts';
|
||||
|
||||
export const DEFAULT_DECIMAL_NUMBER_COUNT: number = 2;
|
||||
export const MAX_SUPPORTED_DECIMAL_NUMBER_COUNT: number = 2;
|
||||
|
||||
export const DISPLAY_HIDDEN_AMOUNT: HiddenAmount = '***';
|
||||
export const INCOMPLETE_AMOUNT_SUFFIX: string = '+';
|
||||
|
||||
+168
-3
@@ -1,13 +1,21 @@
|
||||
import type { TypeAndName, TypeAndDisplayName } from '@/core/base.ts';
|
||||
|
||||
export type HiddenAmount = '***';
|
||||
|
||||
export interface NumberFormatOptions {
|
||||
readonly digitGrouping?: number;
|
||||
readonly digitGroupingSymbol?: string;
|
||||
readonly numeralSystem: NumeralSystem;
|
||||
readonly digitGrouping: DigitGroupingType;
|
||||
readonly digitGroupingSymbol: string;
|
||||
readonly decimalSeparator: string;
|
||||
readonly decimalNumberCount?: number;
|
||||
readonly decimalSeparator?: string;
|
||||
readonly trimTailZero?: boolean;
|
||||
}
|
||||
|
||||
export interface NumberWithSuffix {
|
||||
readonly value: number;
|
||||
readonly suffix: string;
|
||||
}
|
||||
|
||||
export interface NumeralSymbolType {
|
||||
readonly type: number;
|
||||
readonly name: string;
|
||||
@@ -26,6 +34,163 @@ export interface LocalizedDigitGroupingType extends TypeAndDisplayName {
|
||||
readonly displayName: string;
|
||||
}
|
||||
|
||||
export class NumeralSystem implements TypeAndName {
|
||||
private static readonly allInstances: NumeralSystem[] = [];
|
||||
private static readonly allInstancesByType: Record<number, NumeralSystem> = {};
|
||||
private static readonly allInstancesByTypeName: Record<string, NumeralSystem> = {};
|
||||
private static readonly allDigitsToWesternArabic: Record<string, number> = {};
|
||||
private static readonly allDigitsToNumeralSystem: Record<string, NumeralSystem> = {};
|
||||
|
||||
public static readonly LanguageDefaultType: number = 0;
|
||||
public static readonly WesternArabicNumerals = new NumeralSystem(1, 'WesternArabicNumerals', 'Western Arabic Numerals', '\u0030');
|
||||
public static readonly EasternArabicNumerals = new NumeralSystem(2, 'EasternArabicNumerals', 'Eastern Arabic Numerals', '\u0660');
|
||||
public static readonly PersianDigits = new NumeralSystem(3, 'PersianDigits', 'Persian Digits', '\u06F0');
|
||||
public static readonly BurmeseNumerals = new NumeralSystem(4, 'BurmeseNumerals', 'Burmese Numerals', '\u1040');
|
||||
public static readonly DevanagariNumerals = new NumeralSystem(5, 'DevanagariNumerals', 'Devanagari Numerals', '\u0966');
|
||||
|
||||
public static readonly Default = NumeralSystem.WesternArabicNumerals;
|
||||
|
||||
public readonly type: number;
|
||||
public readonly typeName: string;
|
||||
public readonly name: string;
|
||||
public readonly digitZero: string;
|
||||
public readonly doubleDigitZero: string;
|
||||
public readonly textualAllDigits: string;
|
||||
private readonly allDigits: string[];
|
||||
private readonly digitsToWesternArabic: Record<string, number> = {};
|
||||
|
||||
private constructor(type: number, typeName: string, name: string, digitZero: string) {
|
||||
this.type = type;
|
||||
this.typeName = typeName;
|
||||
this.name = name;
|
||||
this.digitZero = digitZero;
|
||||
this.doubleDigitZero = digitZero + digitZero;
|
||||
this.allDigits = [];
|
||||
this.digitsToWesternArabic = {};
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const digit = String.fromCharCode(this.digitZero.charCodeAt(0) + i);
|
||||
this.allDigits.push(digit);
|
||||
this.digitsToWesternArabic[digit] = i;
|
||||
NumeralSystem.allDigitsToWesternArabic[digit] = i;
|
||||
NumeralSystem.allDigitsToNumeralSystem[digit] = this;
|
||||
}
|
||||
|
||||
this.textualAllDigits = this.allDigits.join('');
|
||||
|
||||
NumeralSystem.allInstances.push(this);
|
||||
NumeralSystem.allInstancesByType[type] = this;
|
||||
NumeralSystem.allInstancesByTypeName[typeName] = this;
|
||||
}
|
||||
|
||||
public getAllDigits(): string[] {
|
||||
return this.allDigits.slice();
|
||||
}
|
||||
|
||||
public isDigit(digit: string): boolean {
|
||||
return this.digitsToWesternArabic.hasOwnProperty(digit);
|
||||
}
|
||||
|
||||
public getLocalizedDigit(digit: number): string {
|
||||
if (digit < 0 || digit > 9) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return this.allDigits[digit];
|
||||
}
|
||||
|
||||
public parseInt(value: string): number {
|
||||
if (!value) {
|
||||
return Number.NaN;
|
||||
}
|
||||
|
||||
if (this.type === NumeralSystem.WesternArabicNumerals.type) {
|
||||
return parseInt(value, 10);
|
||||
} else {
|
||||
const westernArabicValue = this.replaceLocalizedDigitsToWesternArabicDigits(value);
|
||||
return parseInt(westernArabicValue, 10);
|
||||
}
|
||||
}
|
||||
|
||||
public formatNumber(value: number): string {
|
||||
if (Number.isNaN(value) || !Number.isFinite(value)) {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
if (this.type === NumeralSystem.WesternArabicNumerals.type) {
|
||||
return value.toString(10);
|
||||
}
|
||||
|
||||
if (value === 0) {
|
||||
return this.digitZero;
|
||||
}
|
||||
|
||||
return this.replaceWesternArabicDigitsToLocalizedDigits(value.toString(10));
|
||||
}
|
||||
|
||||
public replaceWesternArabicDigitsToLocalizedDigits(value: string): string {
|
||||
if (!value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let result = '';
|
||||
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
const ch = value[i];
|
||||
|
||||
if (NumeralSystem.WesternArabicNumerals.isDigit(ch)) {
|
||||
const digit = NumeralSystem.WesternArabicNumerals.digitsToWesternArabic[ch];
|
||||
result += this.allDigits[digit];
|
||||
} else {
|
||||
result += ch;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public replaceLocalizedDigitsToWesternArabicDigits(value: string): string {
|
||||
if (!value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let result = '';
|
||||
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
const ch = value[i];
|
||||
|
||||
if (this.isDigit(ch)) {
|
||||
const digit = this.digitsToWesternArabic[ch];
|
||||
result += NumeralSystem.WesternArabicNumerals.allDigits[digit];
|
||||
} else {
|
||||
result += ch;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static values(): NumeralSystem[] {
|
||||
return NumeralSystem.allInstances;
|
||||
}
|
||||
|
||||
public static valueOf(type: number): NumeralSystem | undefined {
|
||||
return NumeralSystem.allInstancesByType[type];
|
||||
}
|
||||
|
||||
public static parse(typeName: string): NumeralSystem | undefined {
|
||||
return NumeralSystem.allInstancesByTypeName[typeName];
|
||||
}
|
||||
|
||||
public static detect(digit: string): NumeralSystem | undefined {
|
||||
return NumeralSystem.allDigitsToNumeralSystem[digit];
|
||||
}
|
||||
|
||||
public static toNumber(digit: string): number | undefined {
|
||||
return NumeralSystem.allDigitsToWesternArabic[digit];
|
||||
}
|
||||
}
|
||||
|
||||
export class DecimalSeparator implements TypeAndName, NumeralSymbolType {
|
||||
private static readonly allInstances: DecimalSeparator[] = [];
|
||||
private static readonly allInstancesByType: Record<number, DecimalSeparator> = {};
|
||||
|
||||
+1
-7
@@ -1,8 +1,6 @@
|
||||
import { CurrencyDisplaySymbol, CurrencyDisplayLocation, type CurrencyPrependAndAppendText, CurrencyDisplayType } from '@/core/currency.ts';
|
||||
import { ALL_CURRENCIES, DEFAULT_CURRENCY_SYMBOL } from '@/consts/currency.ts';
|
||||
|
||||
import { isNumber } from './common.ts';
|
||||
|
||||
export function getCurrencyFraction(currencyCode?: string): number | undefined {
|
||||
if (!currencyCode) {
|
||||
return undefined;
|
||||
@@ -12,11 +10,7 @@ export function getCurrencyFraction(currencyCode?: string): number | undefined {
|
||||
return currencyInfo?.fraction;
|
||||
}
|
||||
|
||||
export function appendCurrencySymbol(value: number | string, currencyDisplayType: CurrencyDisplayType, currencyCode: string, currencyUnit: string, currencyName: string, isPlural: boolean): string {
|
||||
if (isNumber(value)) {
|
||||
value = value.toString();
|
||||
}
|
||||
|
||||
export function appendCurrencySymbol(value: string, currencyDisplayType: CurrencyDisplayType, currencyCode: string, currencyUnit: string, currencyName: string, isPlural: boolean): string {
|
||||
const symbol = getAmountPrependAndAppendCurrencySymbol(currencyDisplayType, currencyCode, currencyUnit, currencyName, isPlural);
|
||||
|
||||
if (!symbol) {
|
||||
|
||||
+136
-182
@@ -1,7 +1,14 @@
|
||||
import { type NumberFormatOptions, DecimalSeparator, DigitGroupingSymbol, DigitGroupingType } from '@/core/numeral.ts';
|
||||
import { DEFAULT_DECIMAL_NUMBER_COUNT, MAX_SUPPORTED_DECIMAL_NUMBER_COUNT } from '@/consts/numeral.ts';
|
||||
import {
|
||||
type HiddenAmount,
|
||||
type NumberFormatOptions,
|
||||
NumeralSystem,
|
||||
DecimalSeparator,
|
||||
DigitGroupingSymbol
|
||||
} from '@/core/numeral.ts';
|
||||
|
||||
import { isString, isNumber, replaceAll, removeAll } from './common.ts';
|
||||
import { DEFAULT_DECIMAL_NUMBER_COUNT, MAX_SUPPORTED_DECIMAL_NUMBER_COUNT, DISPLAY_HIDDEN_AMOUNT } from '@/consts/numeral.ts';
|
||||
|
||||
import { isDefined, isString, isNumber, replaceAll, removeAll } from './common.ts';
|
||||
|
||||
export function sumAmounts(amounts: number[]): number {
|
||||
let sum = 0;
|
||||
@@ -13,138 +20,77 @@ export function sumAmounts(amounts: number[]): number {
|
||||
return sum;
|
||||
}
|
||||
|
||||
export function appendDigitGroupingSymbol(value: number | string, options: NumberFormatOptions): string {
|
||||
let textualValue = '';
|
||||
|
||||
if (isNumber(value)) {
|
||||
textualValue = value.toString();
|
||||
} else {
|
||||
textualValue = value;
|
||||
}
|
||||
|
||||
if (!textualValue) {
|
||||
return textualValue;
|
||||
}
|
||||
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
if (!isNumber(options.digitGrouping)) {
|
||||
return textualValue;
|
||||
}
|
||||
|
||||
const digitGroupingType = DigitGroupingType.valueOf(options.digitGrouping);
|
||||
|
||||
if (!digitGroupingType || !digitGroupingType.enabled) {
|
||||
return textualValue;
|
||||
}
|
||||
|
||||
if (textualValue.length <= 1) {
|
||||
return textualValue;
|
||||
}
|
||||
|
||||
const negative = textualValue.charAt(0) === '-';
|
||||
|
||||
if (negative) {
|
||||
textualValue = textualValue.substring(1);
|
||||
}
|
||||
|
||||
if (textualValue.length <= 1) {
|
||||
return textualValue;
|
||||
export function appendDigitGroupingSymbolAndDecimalSeparator(textualNumber: string, options: NumberFormatOptions): string {
|
||||
if (!textualNumber) {
|
||||
return textualNumber;
|
||||
}
|
||||
|
||||
const numeralSystem = options.numeralSystem || NumeralSystem.Default;
|
||||
const digitGroupingType = options.digitGrouping;
|
||||
const digitGroupingSymbol = options.digitGroupingSymbol || DigitGroupingSymbol.Default.symbol;
|
||||
const decimalSeparator = options.decimalSeparator || DecimalSeparator.Default.symbol;
|
||||
|
||||
const integerChars = [];
|
||||
const negative = textualNumber.charAt(0) === '-';
|
||||
|
||||
if (negative) {
|
||||
textualNumber = textualNumber.substring(1);
|
||||
}
|
||||
|
||||
const integerChars: string[] = [];
|
||||
const decimalChars: string[] = [];
|
||||
let currentDecimalSeparator = '';
|
||||
let decimals = '';
|
||||
|
||||
for (let i = 0; i < textualValue.length; i++) {
|
||||
const ch = textualValue.charAt(i);
|
||||
if (textualNumber === DISPLAY_HIDDEN_AMOUNT) {
|
||||
for (let i = 0; i < textualNumber.length - 2; i++) {
|
||||
integerChars.push(textualNumber.charAt(i));
|
||||
}
|
||||
|
||||
if ('0' <= ch && ch <= '9') {
|
||||
integerChars.push(ch);
|
||||
} else {
|
||||
currentDecimalSeparator = ch;
|
||||
decimals = textualValue.substring(i + 1);
|
||||
break;
|
||||
const decimalStartIndex = Math.max(0, textualNumber.length - 2);
|
||||
|
||||
for (let i = decimalStartIndex; i < textualNumber.length; i++) {
|
||||
decimalChars.push(textualNumber.charAt(i));
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < textualNumber.length; i++) {
|
||||
const ch = textualNumber.charAt(i);
|
||||
|
||||
if (!currentDecimalSeparator) {
|
||||
if (numeralSystem.isDigit(ch)) {
|
||||
integerChars.push(ch);
|
||||
} else {
|
||||
currentDecimalSeparator = ch;
|
||||
}
|
||||
} else {
|
||||
if (numeralSystem.isDigit(ch)) {
|
||||
decimalChars.push(ch);
|
||||
} else {
|
||||
throw new Error('Number \"' + textualNumber + '\" is not a valid textual number');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let newInteger = digitGroupingType.format(integerChars, digitGroupingSymbol);
|
||||
|
||||
if (negative) {
|
||||
newInteger = `-${newInteger}`;
|
||||
}
|
||||
|
||||
if (currentDecimalSeparator) {
|
||||
return `${newInteger}${decimalSeparator}${decimals}`;
|
||||
} else {
|
||||
return newInteger;
|
||||
}
|
||||
}
|
||||
|
||||
export function appendDecimalSeparator(value: number | string, options: NumberFormatOptions): string {
|
||||
let textualValue = '';
|
||||
|
||||
if (isNumber(value)) {
|
||||
textualValue = value.toString();
|
||||
} else {
|
||||
textualValue = value;
|
||||
}
|
||||
|
||||
if (!textualValue) {
|
||||
return textualValue;
|
||||
}
|
||||
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
if (!isString(options.decimalSeparator)) {
|
||||
return textualValue;
|
||||
}
|
||||
|
||||
if (textualValue.length < 1) {
|
||||
return textualValue;
|
||||
}
|
||||
|
||||
const negative = textualValue.charAt(0) === '-';
|
||||
|
||||
if (negative) {
|
||||
textualValue = textualValue.substring(1);
|
||||
}
|
||||
|
||||
const decimalSeparator = options.decimalSeparator || DecimalSeparator.Default.symbol;
|
||||
|
||||
let currentDecimalSeparator = '';
|
||||
let integer = '';
|
||||
let decimals = '';
|
||||
|
||||
for (let i = 0; i < textualValue.length; i++) {
|
||||
const ch = textualValue.charAt(i);
|
||||
|
||||
if ('0' <= ch && ch <= '9') {
|
||||
integer += ch;
|
||||
} else {
|
||||
currentDecimalSeparator = ch;
|
||||
decimals = textualValue.substring(i + 1);
|
||||
break;
|
||||
}
|
||||
if (digitGroupingType) {
|
||||
integer = digitGroupingType.format(integerChars, digitGroupingSymbol);
|
||||
} else {
|
||||
integer = integerChars.join('');
|
||||
}
|
||||
|
||||
const decimals = decimalChars.join('');
|
||||
|
||||
if (decimals) {
|
||||
textualNumber = `${integer}${decimalSeparator}${decimals}`;
|
||||
} else {
|
||||
textualNumber = integer;
|
||||
}
|
||||
|
||||
if (negative) {
|
||||
integer = `-${integer}`;
|
||||
textualNumber = `-${textualNumber}`;
|
||||
}
|
||||
|
||||
if (currentDecimalSeparator) {
|
||||
return `${integer}${decimalSeparator}${decimals}`;
|
||||
} else {
|
||||
return integer;
|
||||
}
|
||||
return textualNumber;
|
||||
}
|
||||
|
||||
export function parseAmount(str: string, options: NumberFormatOptions): number {
|
||||
@@ -152,10 +98,6 @@ export function parseAmount(str: string, options: NumberFormatOptions): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
if (!str || str.length < 1) {
|
||||
return 0;
|
||||
}
|
||||
@@ -172,6 +114,7 @@ export function parseAmount(str: string, options: NumberFormatOptions): number {
|
||||
|
||||
const sign = negative ? -1 : 1;
|
||||
|
||||
const numeralSystem = options.numeralSystem || NumeralSystem.Default;
|
||||
const decimalSeparator = options.decimalSeparator || DecimalSeparator.Default.symbol;
|
||||
const digitGroupingSymbol = options.digitGroupingSymbol || DigitGroupingSymbol.Default.symbol;
|
||||
|
||||
@@ -182,9 +125,9 @@ export function parseAmount(str: string, options: NumberFormatOptions): number {
|
||||
let decimalSeparatorPos = str.indexOf(decimalSeparator);
|
||||
|
||||
if (decimalSeparatorPos < 0) {
|
||||
return sign * parseInt(str) * 100;
|
||||
return sign * numeralSystem.parseInt(str) * 100;
|
||||
} else if (decimalSeparatorPos === 0) {
|
||||
str = '0' + str;
|
||||
str = numeralSystem.digitZero + str;
|
||||
decimalSeparatorPos++;
|
||||
}
|
||||
|
||||
@@ -192,39 +135,36 @@ export function parseAmount(str: string, options: NumberFormatOptions): number {
|
||||
const decimals = str.substring(decimalSeparatorPos + 1, str.length);
|
||||
|
||||
if (decimals.length < 1) {
|
||||
return sign * parseInt(integer) * 100;
|
||||
return sign * numeralSystem.parseInt(integer) * 100;
|
||||
} else if (decimals.length === 1) {
|
||||
return sign * parseInt(integer) * 100 + sign * parseInt(decimals) * 10;
|
||||
return sign * numeralSystem.parseInt(integer) * 100 + sign * numeralSystem.parseInt(decimals) * 10;
|
||||
} else if (decimals.length === 2) {
|
||||
return sign * parseInt(integer) * 100 + sign * parseInt(decimals);
|
||||
return sign * numeralSystem.parseInt(integer) * 100 + sign * numeralSystem.parseInt(decimals);
|
||||
} else {
|
||||
return sign * parseInt(integer) * 100 + sign * parseInt(decimals.substring(0, 2));
|
||||
return sign * numeralSystem.parseInt(integer) * 100 + sign * numeralSystem.parseInt(decimals.substring(0, 2));
|
||||
}
|
||||
}
|
||||
|
||||
export function formatAmount(value: number | string, options: NumberFormatOptions): string {
|
||||
let textualValue = '';
|
||||
|
||||
if (isNumber(value)) {
|
||||
textualValue = value.toString();
|
||||
} else {
|
||||
textualValue = value;
|
||||
export function formatAmount(value: number, options: NumberFormatOptions): string {
|
||||
if (!Number.isSafeInteger(value)) {
|
||||
throw new Error('Number \"' + value + '\" is not amount number');
|
||||
}
|
||||
|
||||
if (!textualValue) {
|
||||
return textualValue;
|
||||
const numeralSystem = options.numeralSystem || NumeralSystem.Default;
|
||||
let textualNumber = numeralSystem.formatNumber(value);
|
||||
|
||||
if (!textualNumber) {
|
||||
return textualNumber;
|
||||
}
|
||||
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
const negative = textualValue.charAt(0) === '-';
|
||||
const negative = textualNumber.charAt(0) === '-';
|
||||
|
||||
if (negative) {
|
||||
textualValue = textualValue.substring(1);
|
||||
textualNumber = textualNumber.substring(1);
|
||||
}
|
||||
|
||||
const digitGroupingType = options.digitGrouping;
|
||||
const digitGroupingSymbol = options.digitGroupingSymbol || DigitGroupingSymbol.Default.symbol;
|
||||
const decimalSeparator = options.decimalSeparator || DecimalSeparator.Default.symbol;
|
||||
let decimalNumberCount = options.decimalNumberCount;
|
||||
|
||||
@@ -232,62 +172,75 @@ export function formatAmount(value: number | string, options: NumberFormatOption
|
||||
decimalNumberCount = DEFAULT_DECIMAL_NUMBER_COUNT;
|
||||
}
|
||||
|
||||
let integer = '0';
|
||||
let decimals = '00';
|
||||
let integer = numeralSystem.digitZero;
|
||||
let decimals = numeralSystem.doubleDigitZero;
|
||||
|
||||
if (textualValue.length > 2) {
|
||||
integer = textualValue.substring(0, textualValue.length - 2);
|
||||
decimals = textualValue.substring(textualValue.length - 2);
|
||||
} else if (textualValue.length === 2) {
|
||||
decimals = textualValue;
|
||||
} else if (textualValue.length === 1) {
|
||||
decimals = '0' + textualValue;
|
||||
if (textualNumber.length > 2) {
|
||||
integer = textualNumber.substring(0, textualNumber.length - 2);
|
||||
decimals = textualNumber.substring(textualNumber.length - 2);
|
||||
} else if (textualNumber.length === 2) {
|
||||
decimals = textualNumber;
|
||||
} else if (textualNumber.length === 1) {
|
||||
decimals = numeralSystem.digitZero + textualNumber;
|
||||
}
|
||||
|
||||
if (decimalNumberCount === 0) {
|
||||
if (decimals === '00') {
|
||||
if (decimals === numeralSystem.doubleDigitZero) {
|
||||
decimals = '';
|
||||
} else if (decimals.charAt(1) === '0') {
|
||||
} else if (decimals.charAt(1) === numeralSystem.digitZero) {
|
||||
decimals = decimals.charAt(0);
|
||||
}
|
||||
} else if (decimalNumberCount === 1) {
|
||||
if (decimals.charAt(1) === '0') {
|
||||
if (decimals.charAt(1) === numeralSystem.digitZero) {
|
||||
decimals = decimals.charAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.trimTailZero) {
|
||||
if (decimals.charAt(0) === '0' && decimals.charAt(1) === '0') {
|
||||
if (decimals.charAt(0) === numeralSystem.digitZero && decimals.charAt(1) === numeralSystem.digitZero) {
|
||||
decimals = '';
|
||||
} else if (decimals.charAt(0) !== '0' && decimals.charAt(1) === '0') {
|
||||
} else if (decimals.charAt(0) !== numeralSystem.digitZero && decimals.charAt(1) === numeralSystem.digitZero) {
|
||||
decimals = decimals.charAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
integer = appendDigitGroupingSymbol(integer, options);
|
||||
if (integer && integer.length > 1 && digitGroupingType) {
|
||||
integer = digitGroupingType.format(integer.split(''), digitGroupingSymbol);
|
||||
}
|
||||
|
||||
if (decimals !== '') {
|
||||
textualValue = `${integer}${decimalSeparator}${decimals}`;
|
||||
if (decimals) {
|
||||
textualNumber = `${integer}${decimalSeparator}${decimals}`;
|
||||
} else {
|
||||
textualValue = integer;
|
||||
textualNumber = integer;
|
||||
}
|
||||
|
||||
if (negative) {
|
||||
textualValue = `-${textualValue}`;
|
||||
textualNumber = `-${textualNumber}`;
|
||||
}
|
||||
|
||||
return textualValue;
|
||||
return textualNumber;
|
||||
}
|
||||
|
||||
export function formatNumber(value: number, precision: number, options: NumberFormatOptions): string {
|
||||
const ratio = Math.pow(10, precision);
|
||||
const normalizedValue = Math.floor(value * ratio);
|
||||
const textualValue = (normalizedValue / ratio).toString();
|
||||
export function formatHiddenAmount(value: HiddenAmount, options: NumberFormatOptions): string {
|
||||
return appendDigitGroupingSymbolAndDecimalSeparator(value, options);
|
||||
}
|
||||
|
||||
return appendDecimalSeparator(textualValue, options);
|
||||
export function formatNumber(value: number, options: NumberFormatOptions, precision?: number): string {
|
||||
const numeralSystem = options.numeralSystem || NumeralSystem.Default;
|
||||
|
||||
if (isDefined(precision)) {
|
||||
const ratio = Math.pow(10, precision);
|
||||
const normalizedValue = Math.floor(value * ratio);
|
||||
const textualValue = numeralSystem.formatNumber(normalizedValue / ratio);
|
||||
return appendDigitGroupingSymbolAndDecimalSeparator(textualValue, options);
|
||||
} else {
|
||||
const textualValue = numeralSystem.formatNumber(value);
|
||||
return appendDigitGroupingSymbolAndDecimalSeparator(textualValue, options);
|
||||
}
|
||||
}
|
||||
|
||||
export function formatPercent(value: number, precision: number, lowPrecisionValue: string, options: NumberFormatOptions): string {
|
||||
const numeralSystem = options.numeralSystem || NumeralSystem.Default;
|
||||
const ratio = Math.pow(10, precision);
|
||||
const normalizedValue = Math.floor(value * ratio);
|
||||
|
||||
@@ -295,6 +248,8 @@ export function formatPercent(value: number, precision: number, lowPrecisionValu
|
||||
const systemDecimalSeparator = DecimalSeparator.Dot.symbol;
|
||||
const decimalSeparator = options.decimalSeparator || DecimalSeparator.Default.symbol;
|
||||
|
||||
lowPrecisionValue = numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(lowPrecisionValue);
|
||||
|
||||
if (systemDecimalSeparator === decimalSeparator) {
|
||||
return lowPrecisionValue + '%';
|
||||
}
|
||||
@@ -302,7 +257,7 @@ export function formatPercent(value: number, precision: number, lowPrecisionValu
|
||||
return replaceAll(lowPrecisionValue, systemDecimalSeparator, decimalSeparator) + '%';
|
||||
}
|
||||
|
||||
return formatNumber(value, precision, options) + '%';
|
||||
return formatNumber(value, options, precision) + '%';
|
||||
}
|
||||
|
||||
export function getAmountWithDecimalNumberCount(amount: number, decimalNumberCount: number): number {
|
||||
@@ -315,32 +270,31 @@ export function getAmountWithDecimalNumberCount(amount: number, decimalNumberCou
|
||||
return amount;
|
||||
}
|
||||
|
||||
export function formatExchangeRateAmount(exchangeRateAmount: number | string, options: NumberFormatOptions): string {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
const rateStr = exchangeRateAmount.toString();
|
||||
export function formatExchangeRateAmount(exchangeRateAmount: number, options: NumberFormatOptions): string {
|
||||
const numeralSystem = options.numeralSystem || NumeralSystem.Default;
|
||||
const rateStr = numeralSystem.formatNumber(exchangeRateAmount);
|
||||
const decimalSeparator = DecimalSeparator.Dot.symbol;
|
||||
|
||||
if (rateStr.indexOf(decimalSeparator) < 0) {
|
||||
return appendDigitGroupingSymbol(rateStr, options);
|
||||
return appendDigitGroupingSymbolAndDecimalSeparator(rateStr, options);
|
||||
} else {
|
||||
let firstNonZeroPos = 0;
|
||||
|
||||
for (let i = 0; i < rateStr.length; i++) {
|
||||
if (rateStr.charAt(i) !== decimalSeparator && rateStr.charAt(i) !== '0') {
|
||||
if (rateStr.charAt(i) !== decimalSeparator && rateStr.charAt(i) !== numeralSystem.digitZero) {
|
||||
firstNonZeroPos = Math.min(i + 4, rateStr.length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const trimmedRateStr = rateStr.substring(0, Math.max(6, Math.max(firstNonZeroPos, rateStr.indexOf(decimalSeparator) + 2)));
|
||||
return appendDigitGroupingSymbol(trimmedRateStr, options);
|
||||
return appendDigitGroupingSymbolAndDecimalSeparator(trimmedRateStr, options);
|
||||
}
|
||||
}
|
||||
|
||||
export function getAdaptiveDisplayAmountRate(amount1: number, amount2: number, fromExchangeRate: { rate: string }, toExchangeRate: { rate: string }, options: NumberFormatOptions): string | null {
|
||||
const numeralSystem = options.numeralSystem || NumeralSystem.Default;
|
||||
|
||||
if (!amount1 || !amount2 || amount1 === amount2) {
|
||||
if (!fromExchangeRate || !fromExchangeRate.rate || !toExchangeRate || !toExchangeRate.rate) {
|
||||
return null;
|
||||
@@ -351,13 +305,13 @@ export function getAdaptiveDisplayAmountRate(amount1: number, amount2: number, f
|
||||
}
|
||||
|
||||
if (amount1 > amount2) {
|
||||
const rateStr = (amount1 / amount2).toString();
|
||||
const displayRateStr = formatExchangeRateAmount(rateStr, options);
|
||||
return `${displayRateStr} : 1`;
|
||||
const rate = amount1 / amount2;
|
||||
const displayRateStr = formatExchangeRateAmount(rate, options);
|
||||
return `${displayRateStr} : ${numeralSystem.getLocalizedDigit(1)}`;
|
||||
} else {
|
||||
const rateStr = (amount2 / amount1).toString();
|
||||
const displayRateStr = formatExchangeRateAmount(rateStr, options);
|
||||
return `1 : ${displayRateStr}`;
|
||||
const rate = amount2 / amount1;
|
||||
const displayRateStr = formatExchangeRateAmount(rate, options);
|
||||
return `${numeralSystem.getLocalizedDigit(1)} : ${displayRateStr}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"shortDateFormat": "DDMMYYYY",
|
||||
"longTimeFormat": "HHMMSS",
|
||||
"shortTimeFormat": "HHMM",
|
||||
"numeralSystem": "WesternArabicNumerals",
|
||||
"decimalSeparator": "Comma",
|
||||
"digitGroupingSymbol": "Dot",
|
||||
"digitGrouping": "ThousandsSeparator",
|
||||
@@ -260,6 +261,11 @@
|
||||
"Daily": "Daily"
|
||||
},
|
||||
"numeral": {
|
||||
"Western Arabic Numerals": "Western Arabic Numerals",
|
||||
"Eastern Arabic Numerals": "Eastern Arabic Numerals",
|
||||
"Persian Digits": "Persian Digits",
|
||||
"Burmese Numerals": "Burmese Numerals",
|
||||
"Devanagari Numerals": "Devanagari Numerals",
|
||||
"Dot": "Punkt",
|
||||
"Comma": "Komma",
|
||||
"Space": "Leerzeichen",
|
||||
@@ -1497,6 +1503,7 @@
|
||||
"Long Time Format": "Langes Zeitformat",
|
||||
"Short Time Format": "Kurzes Zeitformat",
|
||||
"Fiscal Year Format": "Fiscal Year Format",
|
||||
"Numeral System": "Numeral System",
|
||||
"Decimal Separator": "Dezimaltrennzeichen",
|
||||
"Digit Grouping Symbol": "Zifferngruppierungssymbol",
|
||||
"Digit Grouping": "Zifferngruppierung",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"shortDateFormat": "MMDDYYYY",
|
||||
"longTimeFormat": "HHMMSSA",
|
||||
"shortTimeFormat": "HHMMA",
|
||||
"numeralSystem": "WesternArabicNumerals",
|
||||
"decimalSeparator": "Dot",
|
||||
"digitGroupingSymbol": "Comma",
|
||||
"digitGrouping": "ThousandsSeparator",
|
||||
@@ -260,6 +261,11 @@
|
||||
"Daily": "Daily"
|
||||
},
|
||||
"numeral": {
|
||||
"Western Arabic Numerals": "Western Arabic Numerals",
|
||||
"Eastern Arabic Numerals": "Eastern Arabic Numerals",
|
||||
"Persian Digits": "Persian Digits",
|
||||
"Burmese Numerals": "Burmese Numerals",
|
||||
"Devanagari Numerals": "Devanagari Numerals",
|
||||
"Dot": "Dot",
|
||||
"Comma": "Comma",
|
||||
"Space": "Space",
|
||||
@@ -1497,6 +1503,7 @@
|
||||
"Long Time Format": "Long Time Format",
|
||||
"Short Time Format": "Short Time Format",
|
||||
"Fiscal Year Format": "Fiscal Year Format",
|
||||
"Numeral System": "Numeral System",
|
||||
"Decimal Separator": "Decimal Separator",
|
||||
"Digit Grouping Symbol": "Digit Grouping Symbol",
|
||||
"Digit Grouping": "Digit Grouping",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"shortDateFormat": "DDMMYYYY",
|
||||
"longTimeFormat": "HHMMSS",
|
||||
"shortTimeFormat": "HHMM",
|
||||
"numeralSystem": "WesternArabicNumerals",
|
||||
"decimalSeparator": "Comma",
|
||||
"digitGroupingSymbol": "Dot",
|
||||
"digitGrouping": "ThousandsSeparator",
|
||||
@@ -260,6 +261,11 @@
|
||||
"Daily": "Daily"
|
||||
},
|
||||
"numeral": {
|
||||
"Western Arabic Numerals": "Western Arabic Numerals",
|
||||
"Eastern Arabic Numerals": "Eastern Arabic Numerals",
|
||||
"Persian Digits": "Persian Digits",
|
||||
"Burmese Numerals": "Burmese Numerals",
|
||||
"Devanagari Numerals": "Devanagari Numerals",
|
||||
"Dot": "Punto",
|
||||
"Comma": "Coma",
|
||||
"Space": "Espacio",
|
||||
@@ -1497,6 +1503,7 @@
|
||||
"Long Time Format": "Formato largo de hora",
|
||||
"Short Time Format": "Formato corto de hora",
|
||||
"Fiscal Year Format": "Fiscal Year Format",
|
||||
"Numeral System": "Numeral System",
|
||||
"Decimal Separator": "Separador decimal",
|
||||
"Digit Grouping Symbol": "Símbolo de agrupación de dígitos",
|
||||
"Digit Grouping": "Agrupación de dígitos",
|
||||
|
||||
+179
-83
@@ -32,10 +32,13 @@ import {
|
||||
} from '@/core/timezone.ts';
|
||||
|
||||
import {
|
||||
type HiddenAmount,
|
||||
type NumberFormatOptions,
|
||||
type NumberWithSuffix,
|
||||
type NumeralSymbolType,
|
||||
type LocalizedNumeralSymbolType,
|
||||
type LocalizedDigitGroupingType,
|
||||
NumeralSystem,
|
||||
DecimalSeparator,
|
||||
DigitGroupingSymbol,
|
||||
DigitGroupingType
|
||||
@@ -110,6 +113,7 @@ import {
|
||||
import type { LocaleDefaultSettings } from '@/core/setting.ts';
|
||||
import type { ErrorResponse } from '@/core/api.ts';
|
||||
|
||||
import { DISPLAY_HIDDEN_AMOUNT, INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numeral.ts';
|
||||
import { UTC_TIMEZONE, ALL_TIMEZONES } from '@/consts/timezone.ts';
|
||||
import { ALL_CURRENCIES } from '@/consts/currency.ts';
|
||||
import { DEFAULT_EXPENSE_CATEGORIES, DEFAULT_INCOME_CATEGORIES, DEFAULT_TRANSFER_CATEGORIES } from '@/consts/category.ts';
|
||||
@@ -156,9 +160,10 @@ import {
|
||||
} from '@/lib/datetime.ts';
|
||||
|
||||
import {
|
||||
appendDigitGroupingSymbol,
|
||||
appendDigitGroupingSymbolAndDecimalSeparator,
|
||||
parseAmount,
|
||||
formatAmount,
|
||||
formatHiddenAmount,
|
||||
formatNumber,
|
||||
formatPercent,
|
||||
formatExchangeRateAmount,
|
||||
@@ -401,7 +406,7 @@ export function useI18n() {
|
||||
return localizedParameters;
|
||||
}
|
||||
|
||||
function getAllCurrencyDisplayTypes(): TypeAndDisplayName[] {
|
||||
function getAllCurrencyDisplayTypes(numeralSystem: NumeralSystem, decimalSeparator: string): TypeAndDisplayName[] {
|
||||
const defaultCurrencyDisplayTypeName = t('default.currencyDisplayType');
|
||||
let defaultCurrencyDisplayType = CurrencyDisplayType.parse(defaultCurrencyDisplayTypeName);
|
||||
|
||||
@@ -412,7 +417,7 @@ export function useI18n() {
|
||||
const defaultCurrency = userStore.currentUserDefaultCurrency;
|
||||
|
||||
const ret = [];
|
||||
const defaultSampleValue = getFormattedAmountWithCurrency(12345, defaultCurrency, false, defaultCurrencyDisplayType);
|
||||
const defaultSampleValue = getFormattedAmountWithCurrency(12345, defaultCurrency, defaultCurrencyDisplayType, numeralSystem, decimalSeparator);
|
||||
|
||||
ret.push({
|
||||
type: CurrencyDisplayType.LanguageDefaultType,
|
||||
@@ -423,7 +428,7 @@ export function useI18n() {
|
||||
|
||||
for (let i = 0; i < allCurrencyDisplayTypes.length; i++) {
|
||||
const type = allCurrencyDisplayTypes[i];
|
||||
const sampleValue = getFormattedAmountWithCurrency(12345, defaultCurrency, false, type);
|
||||
const sampleValue = getFormattedAmountWithCurrency(12345, defaultCurrency, type, numeralSystem, decimalSeparator);
|
||||
const displayName = `${t(type.name)} (${sampleValue})`
|
||||
|
||||
ret.push({
|
||||
@@ -587,12 +592,30 @@ export function useI18n() {
|
||||
return getLocalizedDateTimeFormat<ShortTimeFormat>('shortTime', ShortTimeFormat.all(), ShortTimeFormat.values(), userStore.currentUserShortTimeFormat, 'shortTimeFormat', ShortTimeFormat.Default);
|
||||
}
|
||||
|
||||
function getNumberFormatOptions(currencyCode?: string): NumberFormatOptions {
|
||||
function getNumberFormatOptions({numeralSystem, digitGrouping, decimalSeparator, currencyCode}: {
|
||||
numeralSystem?: NumeralSystem,
|
||||
digitGrouping?: DigitGroupingType,
|
||||
decimalSeparator?: string,
|
||||
currencyCode?: string
|
||||
}): NumberFormatOptions {
|
||||
if (!isDefined(numeralSystem)) {
|
||||
numeralSystem = getCurrentNumeralSystemType();
|
||||
}
|
||||
|
||||
if (!isDefined(digitGrouping)) {
|
||||
digitGrouping = getCurrentDigitGroupingType();
|
||||
}
|
||||
|
||||
if (!isDefined(decimalSeparator)) {
|
||||
decimalSeparator = getCurrentDecimalSeparator();
|
||||
}
|
||||
|
||||
return {
|
||||
decimalSeparator: getCurrentDecimalSeparator(),
|
||||
decimalNumberCount: getCurrencyFraction(currencyCode),
|
||||
numeralSystem: numeralSystem,
|
||||
digitGrouping: digitGrouping,
|
||||
digitGroupingSymbol: getCurrentDigitGroupingSymbol(),
|
||||
digitGrouping: getCurrentDigitGroupingType(),
|
||||
decimalSeparator: decimalSeparator,
|
||||
decimalNumberCount: getCurrencyFraction(currencyCode),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -744,7 +767,7 @@ export function useI18n() {
|
||||
return [{
|
||||
value: true,
|
||||
displayName: t('Enable')
|
||||
},{
|
||||
}, {
|
||||
value: false,
|
||||
displayName: t('Disable')
|
||||
}];
|
||||
@@ -766,7 +789,7 @@ export function useI18n() {
|
||||
allCurrencies.push(localizedCurrencyInfo);
|
||||
}
|
||||
|
||||
allCurrencies.sort(function(c1, c2) {
|
||||
allCurrencies.sort(function (c1, c2) {
|
||||
return c1.displayName.localeCompare(c2.displayName);
|
||||
})
|
||||
|
||||
@@ -965,7 +988,7 @@ export function useI18n() {
|
||||
});
|
||||
}
|
||||
|
||||
allTimezoneInfos.sort(function(c1, c2) {
|
||||
allTimezoneInfos.sort(function (c1, c2) {
|
||||
const utcOffset1 = parseInt(c1.utcOffset.replace(':', ''));
|
||||
const utcOffset2 = parseInt(c2.utcOffset.replace(':', ''));
|
||||
|
||||
@@ -1030,7 +1053,36 @@ export function useI18n() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
function getAllDigitGroupingTypes(digitGroupingSymbol: string): LocalizedDigitGroupingType[] {
|
||||
function getAllNumeralSystemTypes(): TypeAndDisplayName[] {
|
||||
const defaultNumeralSystemTypeName = t('default.numeralSystem');
|
||||
let defaultNumeralSystemType = NumeralSystem.parse(defaultNumeralSystemTypeName);
|
||||
|
||||
if (!defaultNumeralSystemType) {
|
||||
defaultNumeralSystemType = NumeralSystem.Default;
|
||||
}
|
||||
|
||||
const ret: TypeAndDisplayName[] = [];
|
||||
|
||||
ret.push({
|
||||
type: NumeralSystem.LanguageDefaultType,
|
||||
displayName: `${t('Language Default')} (${defaultNumeralSystemType.textualAllDigits})`
|
||||
});
|
||||
|
||||
const allNumeralSystemTypes = NumeralSystem.values();
|
||||
|
||||
for (let i = 0; i < allNumeralSystemTypes.length; i++) {
|
||||
const type = allNumeralSystemTypes[i];
|
||||
|
||||
ret.push({
|
||||
type: type.type,
|
||||
displayName: `${t('numeral.' + type.name)} (${type.textualAllDigits})`
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function getAllDigitGroupingTypes(numeralSystem: NumeralSystem, digitGroupingSymbol: string): LocalizedDigitGroupingType[] {
|
||||
const defaultDigitGroupingTypeName = t('default.digitGrouping');
|
||||
let defaultDigitGroupingType = DigitGroupingType.parse(defaultDigitGroupingTypeName);
|
||||
|
||||
@@ -1047,10 +1099,11 @@ export function useI18n() {
|
||||
});
|
||||
|
||||
const allDigitGroupingTypes = DigitGroupingType.values();
|
||||
const numberCharacters = numeralSystem.replaceWesternArabicDigitsToLocalizedDigits('123456789').split('');
|
||||
|
||||
for (let i = 0; i < allDigitGroupingTypes.length; i++) {
|
||||
const type = allDigitGroupingTypes[i];
|
||||
const sampleValue = type.format('123456789'.split(''), digitGroupingSymbol);
|
||||
const sampleValue = type.format(numberCharacters, digitGroupingSymbol);
|
||||
|
||||
ret.push({
|
||||
type: type.type,
|
||||
@@ -1185,15 +1238,15 @@ export function useI18n() {
|
||||
}
|
||||
|
||||
if (settingsStore.appSettings.currencySortByInExchangeRatesPage === CurrencySortingType.Name.type) {
|
||||
availableExchangeRates.sort(function(c1, c2) {
|
||||
availableExchangeRates.sort(function (c1, c2) {
|
||||
return c1.currencyDisplayName.localeCompare(c2.currencyDisplayName);
|
||||
});
|
||||
} else if (settingsStore.appSettings.currencySortByInExchangeRatesPage === CurrencySortingType.CurrencyCode.type) {
|
||||
availableExchangeRates.sort(function(c1, c2) {
|
||||
availableExchangeRates.sort(function (c1, c2) {
|
||||
return c1.currencyCode.localeCompare(c2.currencyCode);
|
||||
});
|
||||
} else if (settingsStore.appSettings.currencySortByInExchangeRatesPage === CurrencySortingType.ExchangeRate.type) {
|
||||
availableExchangeRates.sort(function(c1, c2) {
|
||||
availableExchangeRates.sort(function (c1, c2) {
|
||||
const rate1 = parseFloat(c1.rate);
|
||||
const rate2 = parseFloat(c2.rate);
|
||||
|
||||
@@ -1382,6 +1435,26 @@ export function useI18n() {
|
||||
return joinMultiText(finalWeekdayNames);
|
||||
}
|
||||
|
||||
function getAllLocalizedDigits(): string[] {
|
||||
const numeralSystem = getCurrentNumeralSystemType();
|
||||
return numeralSystem.getAllDigits();
|
||||
}
|
||||
|
||||
function getCurrentNumeralSystemType(): NumeralSystem {
|
||||
let numeralSystemType = NumeralSystem.valueOf(userStore.currentUserNumeralSystem);
|
||||
|
||||
if (!numeralSystemType) {
|
||||
const defaultNumeralSystemTypeName = t('default.numeralSystem');
|
||||
numeralSystemType = NumeralSystem.parse(defaultNumeralSystemTypeName);
|
||||
|
||||
if (!numeralSystemType) {
|
||||
numeralSystemType = NumeralSystem.Default;
|
||||
}
|
||||
}
|
||||
|
||||
return numeralSystemType;
|
||||
}
|
||||
|
||||
function getCurrentDecimalSeparator(): string {
|
||||
let decimalSeparatorType = DecimalSeparator.valueOf(userStore.currentUserDecimalSeparator);
|
||||
|
||||
@@ -1412,7 +1485,7 @@ export function useI18n() {
|
||||
return digitGroupingSymbolType.symbol;
|
||||
}
|
||||
|
||||
function getCurrentDigitGroupingType(): number {
|
||||
function getCurrentDigitGroupingType(): DigitGroupingType {
|
||||
let digitGroupingType = DigitGroupingType.valueOf(userStore.currentUserDigitGrouping);
|
||||
|
||||
if (!digitGroupingType) {
|
||||
@@ -1424,7 +1497,7 @@ export function useI18n() {
|
||||
}
|
||||
}
|
||||
|
||||
return digitGroupingType.type;
|
||||
return digitGroupingType;
|
||||
}
|
||||
|
||||
function getCurrentFiscalYearFormatType(): number {
|
||||
@@ -1443,6 +1516,10 @@ export function useI18n() {
|
||||
}
|
||||
|
||||
function getCurrencyName(currencyCode: string): string {
|
||||
if (!currencyCode) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return t(`currency.name.${currencyCode}`);
|
||||
}
|
||||
|
||||
@@ -1633,44 +1710,17 @@ export function useI18n() {
|
||||
}
|
||||
}
|
||||
|
||||
function getNumberWithDigitGroupingSymbol(value: number | string): string {
|
||||
const numberFormatOptions = getNumberFormatOptions();
|
||||
return appendDigitGroupingSymbol(value, numberFormatOptions);
|
||||
}
|
||||
|
||||
function getParsedAmountNumber(value: string): number {
|
||||
const numberFormatOptions = getNumberFormatOptions();
|
||||
function getParsedAmountNumber(value: string, numeralSystem?: NumeralSystem): number {
|
||||
const numberFormatOptions = getNumberFormatOptions({ numeralSystem });
|
||||
return parseAmount(value, numberFormatOptions);
|
||||
}
|
||||
|
||||
function getFormattedAmount(value: number | string, currencyCode?: string): string {
|
||||
const numberFormatOptions = getNumberFormatOptions(currencyCode);
|
||||
function getFormattedAmount(value: number, numeralSystem?: NumeralSystem, digitGrouping?: DigitGroupingType, currencyCode?: string): string {
|
||||
const numberFormatOptions = getNumberFormatOptions({ numeralSystem, digitGrouping, currencyCode });
|
||||
return formatAmount(value, numberFormatOptions);
|
||||
}
|
||||
|
||||
function getFormattedAmountWithCurrency(value: number | string, currencyCode?: string | false, notConvertValue?: boolean, currencyDisplayType?: CurrencyDisplayType): string {
|
||||
if (isNumber(value)) {
|
||||
value = value.toString();
|
||||
}
|
||||
|
||||
let textualValue = value;
|
||||
const isPlural: boolean = textualValue !== '100' && textualValue !== '-100';
|
||||
|
||||
if (!notConvertValue) {
|
||||
const numberFormatOptions = getNumberFormatOptions();
|
||||
const hasIncompleteFlag = isString(textualValue) && textualValue.charAt(textualValue.length - 1) === '+';
|
||||
|
||||
if (hasIncompleteFlag) {
|
||||
textualValue = textualValue.substring(0, textualValue.length - 1);
|
||||
}
|
||||
|
||||
textualValue = formatAmount(textualValue, numberFormatOptions);
|
||||
|
||||
if (hasIncompleteFlag) {
|
||||
textualValue = textualValue + '+';
|
||||
}
|
||||
}
|
||||
|
||||
function getFormattedAmountWithCurrency(value: number | HiddenAmount | NumberWithSuffix, currencyCode?: string | false, currencyDisplayType?: CurrencyDisplayType, numeralSystem?: NumeralSystem, decimalSeparator?: string): string {
|
||||
let finalCurrencyCode = '';
|
||||
|
||||
if (!isBoolean(currencyCode) && !currencyCode) {
|
||||
@@ -1681,36 +1731,74 @@ export function useI18n() {
|
||||
finalCurrencyCode = currencyCode;
|
||||
}
|
||||
|
||||
if (!finalCurrencyCode) {
|
||||
return textualValue;
|
||||
}
|
||||
|
||||
if (!currencyDisplayType) {
|
||||
currencyDisplayType = getCurrentCurrencyDisplayType();
|
||||
}
|
||||
|
||||
const currencyUnit = getCurrencyUnitName(finalCurrencyCode, isPlural);
|
||||
if (!numeralSystem) {
|
||||
numeralSystem = getCurrentNumeralSystemType();
|
||||
}
|
||||
|
||||
let suffix = '';
|
||||
|
||||
if (isObject(value) && isNumber(value.value) && isString(value.suffix)) {
|
||||
suffix = value.suffix;
|
||||
value = value.value;
|
||||
}
|
||||
|
||||
const numberFormatOptions = getNumberFormatOptions({ numeralSystem, decimalSeparator, currencyCode: finalCurrencyCode });
|
||||
const currencyName = getCurrencyName(finalCurrencyCode);
|
||||
return appendCurrencySymbol(textualValue, currencyDisplayType, finalCurrencyCode, currencyUnit, currencyName, isPlural);
|
||||
|
||||
if (isNumber(value)) {
|
||||
const isPlural: boolean = value !== 100 && value !== -100;
|
||||
const textualValue = formatAmount(value, numberFormatOptions);
|
||||
|
||||
if (!finalCurrencyCode) {
|
||||
return textualValue;
|
||||
}
|
||||
|
||||
const currencyUnit = getCurrencyUnitName(finalCurrencyCode, isPlural);
|
||||
const ret = appendCurrencySymbol(textualValue, currencyDisplayType, finalCurrencyCode, currencyUnit, currencyName, isPlural);
|
||||
|
||||
if (suffix) {
|
||||
return ret + suffix;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
} else if (isString(value)) {
|
||||
const isPlural: boolean = true;
|
||||
const textualValue = formatHiddenAmount(value, numberFormatOptions);
|
||||
|
||||
if (!finalCurrencyCode) {
|
||||
return textualValue;
|
||||
}
|
||||
|
||||
const currencyUnit = getCurrencyUnitName(finalCurrencyCode, isPlural);
|
||||
return appendCurrencySymbol(textualValue, currencyDisplayType, finalCurrencyCode, currencyUnit, currencyName, isPlural);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function getFormattedNumber(value: number, precision: number): string {
|
||||
const numberFormatOptions = getNumberFormatOptions();
|
||||
return formatNumber(value, precision, numberFormatOptions);
|
||||
function getFormattedNumber(value: number, numeralSystem?: NumeralSystem, precision?: number): string {
|
||||
const numberFormatOptions = getNumberFormatOptions({ numeralSystem, digitGrouping: DigitGroupingType.None });
|
||||
return formatNumber(value, numberFormatOptions, precision);
|
||||
}
|
||||
|
||||
function getFormattedPercentValue(value: number, precision: number, lowPrecisionValue: string): string {
|
||||
const numberFormatOptions = getNumberFormatOptions();
|
||||
function getFormattedPercentValue(value: number, precision: number, lowPrecisionValue: string, numeralSystem?: NumeralSystem): string {
|
||||
const numberFormatOptions = getNumberFormatOptions({ numeralSystem });
|
||||
return formatPercent(value, precision, lowPrecisionValue, numberFormatOptions);
|
||||
}
|
||||
|
||||
function getFormattedExchangeRateAmount(value: number | string): string {
|
||||
const numberFormatOptions = getNumberFormatOptions();
|
||||
function getFormattedExchangeRateAmount(value: number, numeralSystem?: NumeralSystem): string {
|
||||
const numberFormatOptions = getNumberFormatOptions({ numeralSystem });
|
||||
return formatExchangeRateAmount(value, numberFormatOptions);
|
||||
}
|
||||
|
||||
function getAdaptiveAmountRate(amount1: number, amount2: number, fromExchangeRate: { rate: string }, toExchangeRate: { rate: string }): string | null {
|
||||
const numberFormatOptions = getNumberFormatOptions();
|
||||
function getAdaptiveAmountRate(amount1: number, amount2: number, fromExchangeRate: {
|
||||
rate: string
|
||||
}, toExchangeRate: { rate: string }): string | null {
|
||||
const numberFormatOptions = getNumberFormatOptions({});
|
||||
return getAdaptiveDisplayAmountRate(amount1, amount2, fromExchangeRate, toExchangeRate, numberFormatOptions);
|
||||
}
|
||||
|
||||
@@ -1747,7 +1835,7 @@ export function useI18n() {
|
||||
} else if (showAccountBalance && account.isLiability) {
|
||||
accountWithDisplaceBalance = AccountWithDisplayBalance.fromAccount(account, getFormattedAmountWithCurrency(-account.balance, account.currency));
|
||||
} else {
|
||||
accountWithDisplaceBalance = AccountWithDisplayBalance.fromAccount(account, '***');
|
||||
accountWithDisplaceBalance = AccountWithDisplayBalance.fromAccount(account, DISPLAY_HIDDEN_AMOUNT);
|
||||
}
|
||||
|
||||
accountsWithDisplayBalance.push(accountWithDisplaceBalance);
|
||||
@@ -1784,15 +1872,13 @@ export function useI18n() {
|
||||
}
|
||||
}
|
||||
|
||||
finalTotalBalance = totalBalance.toString();
|
||||
finalTotalBalance = getFormattedAmountWithCurrency(totalBalance, defaultCurrency);
|
||||
|
||||
if (hasUnCalculatedAmount) {
|
||||
finalTotalBalance = finalTotalBalance + '+';
|
||||
finalTotalBalance = finalTotalBalance + INCOMPLETE_AMOUNT_SUFFIX;
|
||||
}
|
||||
|
||||
finalTotalBalance = getFormattedAmountWithCurrency(finalTotalBalance, defaultCurrency);
|
||||
} else {
|
||||
finalTotalBalance = '***';
|
||||
finalTotalBalance = DISPLAY_HIDDEN_AMOUNT;
|
||||
}
|
||||
|
||||
const accountCategoryWithDisplayBalance = CategorizedAccountWithDisplayBalance.of(accountCategory, accountsWithDisplayBalance, finalTotalBalance);
|
||||
@@ -1822,11 +1908,11 @@ export function useI18n() {
|
||||
|
||||
locale.value = languageKey;
|
||||
moment.updateLocale(languageKey, {
|
||||
months : getAllLongMonthNames(),
|
||||
monthsShort : getAllShortMonthNames(),
|
||||
weekdays : getAllLongWeekdayNames(),
|
||||
weekdaysShort : getAllShortWeekdayNames(),
|
||||
weekdaysMin : getAllMinWeekdayNames(),
|
||||
months: getAllLongMonthNames(),
|
||||
monthsShort: getAllShortMonthNames(),
|
||||
weekdays: getAllLongWeekdayNames(),
|
||||
weekdaysShort: getAllShortWeekdayNames(),
|
||||
weekdaysMin: getAllMinWeekdayNames(),
|
||||
meridiem: function (hours) {
|
||||
if (isPM(hours)) {
|
||||
return t(`datetime.${MeridiemIndicator.PM.name}.content`);
|
||||
@@ -1924,6 +2010,7 @@ export function useI18n() {
|
||||
getAllRecentMonthDateRanges,
|
||||
getAllTimezones,
|
||||
getAllTimezoneTypesUsedForStatistics,
|
||||
getAllNumeralSystemTypes,
|
||||
getAllDecimalSeparators: () => getLocalizedNumeralSeparatorFormats(DecimalSeparator.values(), DecimalSeparator.parse(t('default.decimalSeparator')), DecimalSeparator.Default, DecimalSeparator.LanguageDefaultType),
|
||||
getAllDigitGroupingSymbols: () => getLocalizedNumeralSeparatorFormats(DigitGroupingSymbol.values(), DigitGroupingSymbol.parse(t('default.digitGroupingSymbol')), DigitGroupingSymbol.Default, DigitGroupingSymbol.LanguageDefaultType),
|
||||
getAllDigitGroupingTypes,
|
||||
@@ -1958,7 +2045,9 @@ export function useI18n() {
|
||||
getWeekdayLongName,
|
||||
getMultiMonthdayShortNames,
|
||||
getMultiWeekdayLongNames,
|
||||
getAllLocalizedDigits,
|
||||
getCurrentFiscalYearFormatType,
|
||||
getCurrentNumeralSystemType,
|
||||
getCurrentDecimalSeparator,
|
||||
getCurrentDigitGroupingSymbol,
|
||||
getCurrentDigitGroupingType,
|
||||
@@ -1997,13 +2086,20 @@ export function useI18n() {
|
||||
formatUnixTimeToFiscalYear,
|
||||
formatYearToFiscalYear,
|
||||
getTimezoneDifferenceDisplayText,
|
||||
appendDigitGroupingSymbol: getNumberWithDigitGroupingSymbol,
|
||||
parseAmount: getParsedAmountNumber,
|
||||
formatAmount: getFormattedAmount,
|
||||
formatAmountWithCurrency: getFormattedAmountWithCurrency,
|
||||
formatNumber: getFormattedNumber,
|
||||
formatPercent: getFormattedPercentValue,
|
||||
formatExchangeRateAmount: getFormattedExchangeRateAmount,
|
||||
parseAmountFromLocalizedNumerals: (value: string) => getParsedAmountNumber(value),
|
||||
parseAmountFromWesternArabicNumerals: (value: string) => getParsedAmountNumber(value, NumeralSystem.WesternArabicNumerals),
|
||||
formatAmountToLocalizedNumerals: (value: number, currencyCode?: string) => getFormattedAmount(value, undefined, undefined, currencyCode),
|
||||
formatAmountToWesternArabicNumerals: (value: number, currencyCode?: string) => getFormattedAmount(value, NumeralSystem.WesternArabicNumerals, undefined, currencyCode),
|
||||
formatAmountToLocalizedNumeralsWithoutDigitGrouping: (value: number, currencyCode?: string) => getFormattedAmount(value, undefined, DigitGroupingType.None, currencyCode),
|
||||
formatAmountToWesternArabicNumeralsWithoutDigitGrouping: (value: number, currencyCode?: string) => getFormattedAmount(value, NumeralSystem.WesternArabicNumerals, DigitGroupingType.None, currencyCode),
|
||||
formatAmountToLocalizedNumeralsWithCurrency: (value: number | HiddenAmount | NumberWithSuffix, currencyCode?: string | false, currencyDisplayType?: CurrencyDisplayType) => getFormattedAmountWithCurrency(value, currencyCode, currencyDisplayType),
|
||||
formatAmountToWesternArabicNumeralsWithCurrency: (value: number | HiddenAmount | NumberWithSuffix, currencyCode?: string | false, currencyDisplayType?: CurrencyDisplayType) => getFormattedAmountWithCurrency(value, currencyCode, currencyDisplayType, NumeralSystem.WesternArabicNumerals),
|
||||
formatNumberToLocalizedNumerals: (value: number, precision?: number) => getFormattedNumber(value, undefined, precision),
|
||||
formatNumberToWesternArabicNumerals: (value: number, precision?: number) => getFormattedNumber(value, NumeralSystem.WesternArabicNumerals, precision),
|
||||
formatPercentToLocalizedNumerals: (value: number, precision: number, lowPrecisionValue: string) => getFormattedPercentValue(value, precision, lowPrecisionValue),
|
||||
formatPercentToWesternArabicNumerals: (value: number, precision: number, lowPrecisionValue: string) => getFormattedPercentValue(value, precision, lowPrecisionValue, NumeralSystem.WesternArabicNumerals),
|
||||
formatExchangeRateAmountToWesternArabicNumerals: (value: number) => getFormattedExchangeRateAmount(value, NumeralSystem.WesternArabicNumerals),
|
||||
appendDigitGroupingSymbolAndDecimalSeparator: (value: string) => appendDigitGroupingSymbolAndDecimalSeparator(value, getNumberFormatOptions({})),
|
||||
getAdaptiveAmountRate,
|
||||
getAmountPrependAndAppendText,
|
||||
getCategorizedAccountsWithDisplayBalance,
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"shortDateFormat": "DDMMYYYY",
|
||||
"longTimeFormat": "HHMMSS",
|
||||
"shortTimeFormat": "HHMM",
|
||||
"numeralSystem": "WesternArabicNumerals",
|
||||
"decimalSeparator": "Comma",
|
||||
"digitGroupingSymbol": "Dot",
|
||||
"digitGrouping": "ThousandsSeparator",
|
||||
@@ -260,6 +261,11 @@
|
||||
"Daily": "Daily"
|
||||
},
|
||||
"numeral": {
|
||||
"Western Arabic Numerals": "Western Arabic Numerals",
|
||||
"Eastern Arabic Numerals": "Eastern Arabic Numerals",
|
||||
"Persian Digits": "Persian Digits",
|
||||
"Burmese Numerals": "Burmese Numerals",
|
||||
"Devanagari Numerals": "Devanagari Numerals",
|
||||
"Dot": "Punto",
|
||||
"Comma": "Virgola",
|
||||
"Space": "Spazio",
|
||||
@@ -1497,6 +1503,7 @@
|
||||
"Long Time Format": "Formato ora lungo",
|
||||
"Short Time Format": "Formato ora breve",
|
||||
"Fiscal Year Format": "Fiscal Year Format",
|
||||
"Numeral System": "Numeral System",
|
||||
"Decimal Separator": "Separatore decimale",
|
||||
"Digit Grouping Symbol": "Simbolo di raggruppamento cifre",
|
||||
"Digit Grouping": "Raggruppamento cifre",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"shortDateFormat": "YYYYMMDD",
|
||||
"longTimeFormat": "HHMMSS",
|
||||
"shortTimeFormat": "HHMM",
|
||||
"numeralSystem": "WesternArabicNumerals",
|
||||
"decimalSeparator": "Dot",
|
||||
"digitGroupingSymbol": "Comma",
|
||||
"digitGrouping": "ThousandsSeparator",
|
||||
@@ -260,6 +261,11 @@
|
||||
"Daily": "Daily"
|
||||
},
|
||||
"numeral": {
|
||||
"Western Arabic Numerals": "Western Arabic Numerals",
|
||||
"Eastern Arabic Numerals": "Eastern Arabic Numerals",
|
||||
"Persian Digits": "Persian Digits",
|
||||
"Burmese Numerals": "Burmese Numerals",
|
||||
"Devanagari Numerals": "Devanagari Numerals",
|
||||
"Dot": "ドット",
|
||||
"Comma": "コンマ",
|
||||
"Space": "スペース",
|
||||
@@ -1497,6 +1503,7 @@
|
||||
"Long Time Format": "長い時間形式",
|
||||
"Short Time Format": "短い時間形式",
|
||||
"Fiscal Year Format": "Fiscal Year Format",
|
||||
"Numeral System": "Numeral System",
|
||||
"Decimal Separator": "小数点",
|
||||
"Digit Grouping Symbol": "桁区切り記号",
|
||||
"Digit Grouping": "桁区切り位置",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"shortDateFormat": "DDMMYYYY",
|
||||
"longTimeFormat": "HHMMSS",
|
||||
"shortTimeFormat": "HHMM",
|
||||
"numeralSystem": "WesternArabicNumerals",
|
||||
"decimalSeparator": "Comma",
|
||||
"digitGroupingSymbol": "Dot",
|
||||
"digitGrouping": "ThousandsSeparator",
|
||||
@@ -260,6 +261,11 @@
|
||||
"Daily": "Dagelijks"
|
||||
},
|
||||
"numeral": {
|
||||
"Western Arabic Numerals": "Western Arabic Numerals",
|
||||
"Eastern Arabic Numerals": "Eastern Arabic Numerals",
|
||||
"Persian Digits": "Persian Digits",
|
||||
"Burmese Numerals": "Burmese Numerals",
|
||||
"Devanagari Numerals": "Devanagari Numerals",
|
||||
"Dot": "Punt",
|
||||
"Comma": "Komma",
|
||||
"Space": "Spatie",
|
||||
@@ -1497,6 +1503,7 @@
|
||||
"Long Time Format": "Lang tijdsformaat",
|
||||
"Short Time Format": "Kort tijdsformaat",
|
||||
"Fiscal Year Format": "Boekjaarformaat",
|
||||
"Numeral System": "Numeral System",
|
||||
"Decimal Separator": "Decimaalteken",
|
||||
"Digit Grouping Symbol": "Scheidingsteken voor duizendtallen",
|
||||
"Digit Grouping": "Groeperen van cijfers",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"shortDateFormat": "DDMMYYYY",
|
||||
"longTimeFormat": "HHMMSS",
|
||||
"shortTimeFormat": "HHMM",
|
||||
"numeralSystem": "WesternArabicNumerals",
|
||||
"decimalSeparator": "Comma",
|
||||
"digitGroupingSymbol": "Space",
|
||||
"digitGrouping": "ThousandsSeparator",
|
||||
@@ -260,6 +261,11 @@
|
||||
"Daily": "Daily"
|
||||
},
|
||||
"numeral": {
|
||||
"Western Arabic Numerals": "Western Arabic Numerals",
|
||||
"Eastern Arabic Numerals": "Eastern Arabic Numerals",
|
||||
"Persian Digits": "Persian Digits",
|
||||
"Burmese Numerals": "Burmese Numerals",
|
||||
"Devanagari Numerals": "Devanagari Numerals",
|
||||
"Dot": "Ponto",
|
||||
"Comma": "Vírgula",
|
||||
"Space": "Espaço",
|
||||
@@ -1497,6 +1503,7 @@
|
||||
"Long Time Format": "Formato de Hora Longa",
|
||||
"Short Time Format": "Formato de Hora Curta",
|
||||
"Fiscal Year Format": "Formato do Ano Fiscal",
|
||||
"Numeral System": "Numeral System",
|
||||
"Decimal Separator": "Separador Decimal",
|
||||
"Digit Grouping Symbol": "Símbolo de Agrupamento de Dígitos",
|
||||
"Digit Grouping": "Agrupamento de Dígitos",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"shortDateFormat": "DDMMYYYY",
|
||||
"longTimeFormat": "HHMMSS",
|
||||
"shortTimeFormat": "HHMM",
|
||||
"numeralSystem": "WesternArabicNumerals",
|
||||
"decimalSeparator": "Comma",
|
||||
"digitGroupingSymbol": "Space",
|
||||
"digitGrouping": "ThousandsSeparator",
|
||||
@@ -260,6 +261,11 @@
|
||||
"Daily": "Daily"
|
||||
},
|
||||
"numeral": {
|
||||
"Western Arabic Numerals": "Western Arabic Numerals",
|
||||
"Eastern Arabic Numerals": "Eastern Arabic Numerals",
|
||||
"Persian Digits": "Persian Digits",
|
||||
"Burmese Numerals": "Burmese Numerals",
|
||||
"Devanagari Numerals": "Devanagari Numerals",
|
||||
"Dot": "Точка",
|
||||
"Comma": "Запятая",
|
||||
"Space": "Пробел",
|
||||
@@ -1497,6 +1503,7 @@
|
||||
"Long Time Format": "Длинный формат времени",
|
||||
"Short Time Format": "Короткий формат времени",
|
||||
"Fiscal Year Format": "Fiscal Year Format",
|
||||
"Numeral System": "Numeral System",
|
||||
"Decimal Separator": "Разделитель десятичных",
|
||||
"Digit Grouping Symbol": "Символ группировки цифр",
|
||||
"Digit Grouping": "Группировка цифр",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"shortDateFormat": "DDMMYYYY",
|
||||
"longTimeFormat": "HHMMSS",
|
||||
"shortTimeFormat": "HHMM",
|
||||
"numeralSystem": "WesternArabicNumerals",
|
||||
"decimalSeparator": "Comma",
|
||||
"digitGroupingSymbol": "Space",
|
||||
"digitGrouping": "ThousandsSeparator",
|
||||
@@ -260,6 +261,11 @@
|
||||
"Daily": "Daily"
|
||||
},
|
||||
"numeral": {
|
||||
"Western Arabic Numerals": "Western Arabic Numerals",
|
||||
"Eastern Arabic Numerals": "Eastern Arabic Numerals",
|
||||
"Persian Digits": "Persian Digits",
|
||||
"Burmese Numerals": "Burmese Numerals",
|
||||
"Devanagari Numerals": "Devanagari Numerals",
|
||||
"Dot": "Крапка",
|
||||
"Comma": "Кома",
|
||||
"Space": "Пробіл",
|
||||
@@ -1497,6 +1503,7 @@
|
||||
"Long Time Format": "Довгий формат часу",
|
||||
"Short Time Format": "Короткий формат часу",
|
||||
"Fiscal Year Format": "Fiscal Year Format",
|
||||
"Numeral System": "Numeral System",
|
||||
"Decimal Separator": "Десятковий роздільник",
|
||||
"Digit Grouping Symbol": "Символ групування цифр",
|
||||
"Digit Grouping": "Групування цифр",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"shortDateFormat": "DDMMYYYY",
|
||||
"longTimeFormat": "HHMMSSA",
|
||||
"shortTimeFormat": "HHMMA",
|
||||
"numeralSystem": "WesternArabicNumerals",
|
||||
"decimalSeparator": "Comma",
|
||||
"digitGroupingSymbol": "Dot",
|
||||
"digitGrouping": "ThousandsSeparator",
|
||||
@@ -260,6 +261,11 @@
|
||||
"Daily": "Daily"
|
||||
},
|
||||
"numeral": {
|
||||
"Western Arabic Numerals": "Western Arabic Numerals",
|
||||
"Eastern Arabic Numerals": "Eastern Arabic Numerals",
|
||||
"Persian Digits": "Persian Digits",
|
||||
"Burmese Numerals": "Burmese Numerals",
|
||||
"Devanagari Numerals": "Devanagari Numerals",
|
||||
"Dot": "Dấu chấm",
|
||||
"Comma": "Dấu phẩy",
|
||||
"Space": "Khoảng trắng",
|
||||
@@ -1497,6 +1503,7 @@
|
||||
"Long Time Format": "Định dạng thời gian dài",
|
||||
"Short Time Format": "Định dạng thời gian ngắn",
|
||||
"Fiscal Year Format": "Fiscal Year Format",
|
||||
"Numeral System": "Numeral System",
|
||||
"Decimal Separator": "Dấu phân cách thập phân",
|
||||
"Digit Grouping Symbol": "Ký hiệu nhóm chữ số",
|
||||
"Digit Grouping": "Nhóm chữ số",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"shortDateFormat": "YYYYMMDD",
|
||||
"longTimeFormat": "HHMMSS",
|
||||
"shortTimeFormat": "HHMM",
|
||||
"numeralSystem": "WesternArabicNumerals",
|
||||
"decimalSeparator": "Dot",
|
||||
"digitGroupingSymbol": "Comma",
|
||||
"digitGrouping": "ThousandsSeparator",
|
||||
@@ -260,6 +261,11 @@
|
||||
"Daily": "按天"
|
||||
},
|
||||
"numeral": {
|
||||
"Western Arabic Numerals": "阿拉伯数字",
|
||||
"Eastern Arabic Numerals": "东阿拉伯数字",
|
||||
"Persian Digits": "波斯数字",
|
||||
"Burmese Numerals": "缅甸数字",
|
||||
"Devanagari Numerals": "天城文数字",
|
||||
"Dot": "句点",
|
||||
"Comma": "逗号",
|
||||
"Space": "空格",
|
||||
@@ -1497,6 +1503,7 @@
|
||||
"Long Time Format": "长时间格式",
|
||||
"Short Time Format": "短时间格式",
|
||||
"Fiscal Year Format": "财年格式",
|
||||
"Numeral System": "数字系统",
|
||||
"Decimal Separator": "小数点",
|
||||
"Digit Grouping Symbol": "数字分组符号",
|
||||
"Digit Grouping": "数字分组",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"shortDateFormat": "YYYYMMDD",
|
||||
"longTimeFormat": "AHHMMSS",
|
||||
"shortTimeFormat": "AHHMM",
|
||||
"numeralSystem": "WesternArabicNumerals",
|
||||
"decimalSeparator": "Dot",
|
||||
"digitGroupingSymbol": "Comma",
|
||||
"digitGrouping": "ThousandsSeparator",
|
||||
@@ -260,6 +261,11 @@
|
||||
"Daily": "依日期"
|
||||
},
|
||||
"numeral": {
|
||||
"Western Arabic Numerals": "阿拉伯數字",
|
||||
"Eastern Arabic Numerals": "東阿拉伯數字",
|
||||
"Persian Digits": "波斯數字",
|
||||
"Burmese Numerals": "緬甸數字",
|
||||
"Devanagari Numerals": "天城文數字",
|
||||
"Dot": "句點",
|
||||
"Comma": "逗號",
|
||||
"Space": "空格",
|
||||
@@ -1497,6 +1503,7 @@
|
||||
"Long Time Format": "長時間格式",
|
||||
"Short Time Format": "短時間格式",
|
||||
"Fiscal Year Format": "財政年度格式",
|
||||
"Numeral System": "數字系統",
|
||||
"Decimal Separator": "小數點",
|
||||
"Digit Grouping Symbol": "數字分組符號",
|
||||
"Digit Grouping": "數字分組",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { HiddenAmount, NumberWithSuffix } from '@/core/numeral.ts';
|
||||
import type { ColorValue } from '@/core/color.ts';
|
||||
import { AccountType, AccountCategory } from '@/core/account.ts';
|
||||
import { PARENT_ACCOUNT_CURRENCY_PLACEHOLDER } from '@/consts/currency.ts';
|
||||
@@ -638,7 +639,7 @@ export interface AccountBalance {
|
||||
}
|
||||
|
||||
export interface AccountDisplayBalance {
|
||||
readonly balance: string;
|
||||
readonly balance: number | HiddenAmount | NumberWithSuffix;
|
||||
readonly currency: string;
|
||||
}
|
||||
|
||||
|
||||
+15
-8
@@ -1,5 +1,5 @@
|
||||
import { LongDateFormat, ShortDateFormat, LongTimeFormat, ShortTimeFormat } from '@/core/datetime.ts';
|
||||
import { DecimalSeparator, DigitGroupingSymbol, DigitGroupingType } from '@/core/numeral.ts';
|
||||
import { NumeralSystem, DecimalSeparator, DigitGroupingSymbol, DigitGroupingType } from '@/core/numeral.ts';
|
||||
import { CurrencyDisplayType } from '@/core/currency.ts';
|
||||
import { CoordinateDisplayType } from '@/core/coordinate.ts';
|
||||
import { PresetAmountColor } from '@/core/color.ts';
|
||||
@@ -25,10 +25,11 @@ export class User {
|
||||
public longTimeFormat: number = EMPTY_USER_BASIC_INFO.longTimeFormat;
|
||||
public shortTimeFormat: number = EMPTY_USER_BASIC_INFO.shortTimeFormat;
|
||||
public fiscalYearFormat: number = EMPTY_USER_BASIC_INFO.fiscalYearFormat;
|
||||
public currencyDisplayType: number = EMPTY_USER_BASIC_INFO.currencyDisplayType;
|
||||
public numeralSystem: number = EMPTY_USER_BASIC_INFO.numeralSystem;
|
||||
public decimalSeparator: number = EMPTY_USER_BASIC_INFO.decimalSeparator;
|
||||
public digitGroupingSymbol: number = EMPTY_USER_BASIC_INFO.digitGroupingSymbol;
|
||||
public digitGrouping: number = EMPTY_USER_BASIC_INFO.digitGrouping;
|
||||
public currencyDisplayType: number = EMPTY_USER_BASIC_INFO.currencyDisplayType;
|
||||
public coordinateDisplayType: number = EMPTY_USER_BASIC_INFO.coordinateDisplayType;
|
||||
public expenseAmountColor: number = EMPTY_USER_BASIC_INFO.expenseAmountColor;
|
||||
public incomeAmountColor: number = EMPTY_USER_BASIC_INFO.incomeAmountColor;
|
||||
@@ -54,10 +55,11 @@ export class User {
|
||||
this.longTimeFormat = user.longTimeFormat;
|
||||
this.shortTimeFormat = user.shortTimeFormat;
|
||||
this.fiscalYearFormat = user.fiscalYearFormat;
|
||||
this.currencyDisplayType = user.currencyDisplayType;
|
||||
this.numeralSystem = user.numeralSystem;
|
||||
this.decimalSeparator = user.decimalSeparator;
|
||||
this.digitGroupingSymbol = user.digitGroupingSymbol;
|
||||
this.digitGrouping = user.digitGrouping;
|
||||
this.currencyDisplayType = user.currencyDisplayType;
|
||||
this.coordinateDisplayType = user.coordinateDisplayType;
|
||||
this.expenseAmountColor = user.expenseAmountColor;
|
||||
this.incomeAmountColor = user.incomeAmountColor;
|
||||
@@ -93,10 +95,11 @@ export class User {
|
||||
longTimeFormat: this.longTimeFormat,
|
||||
shortTimeFormat: this.shortTimeFormat,
|
||||
fiscalYearFormat: this.fiscalYearFormat,
|
||||
currencyDisplayType: this.currencyDisplayType,
|
||||
numeralSystem: this.numeralSystem,
|
||||
decimalSeparator: this.decimalSeparator,
|
||||
digitGroupingSymbol: this.digitGroupingSymbol,
|
||||
digitGrouping: this.digitGrouping,
|
||||
currencyDisplayType: this.currencyDisplayType,
|
||||
coordinateDisplayType: this.coordinateDisplayType,
|
||||
expenseAmountColor: this.expenseAmountColor,
|
||||
incomeAmountColor: this.incomeAmountColor
|
||||
@@ -113,10 +116,11 @@ export class User {
|
||||
user.longTimeFormat = userInfo.longTimeFormat;
|
||||
user.shortTimeFormat = userInfo.shortTimeFormat;
|
||||
user.fiscalYearFormat = userInfo.fiscalYearFormat;
|
||||
user.currencyDisplayType = userInfo.currencyDisplayType;
|
||||
user.numeralSystem = userInfo.numeralSystem;
|
||||
user.decimalSeparator = userInfo.decimalSeparator;
|
||||
user.digitGroupingSymbol = userInfo.digitGroupingSymbol;
|
||||
user.digitGrouping = userInfo.digitGrouping;
|
||||
user.currencyDisplayType = userInfo.currencyDisplayType;
|
||||
user.coordinateDisplayType = userInfo.coordinateDisplayType;
|
||||
user.expenseAmountColor = userInfo.expenseAmountColor;
|
||||
user.incomeAmountColor = userInfo.incomeAmountColor;
|
||||
@@ -146,10 +150,11 @@ export interface UserBasicInfo {
|
||||
readonly longTimeFormat: number;
|
||||
readonly shortTimeFormat: number;
|
||||
readonly fiscalYearFormat: number;
|
||||
readonly currencyDisplayType: number;
|
||||
readonly numeralSystem: number;
|
||||
readonly decimalSeparator: number;
|
||||
readonly digitGroupingSymbol: number;
|
||||
readonly digitGrouping: number;
|
||||
readonly currencyDisplayType: number;
|
||||
readonly coordinateDisplayType: number;
|
||||
readonly expenseAmountColor: number;
|
||||
readonly incomeAmountColor: number;
|
||||
@@ -199,10 +204,11 @@ export interface UserProfileUpdateRequest {
|
||||
readonly longTimeFormat?: number;
|
||||
readonly shortTimeFormat?: number;
|
||||
readonly fiscalYearFormat?: number;
|
||||
readonly currencyDisplayType?: number;
|
||||
readonly numeralSystem?: number;
|
||||
readonly decimalSeparator?: number;
|
||||
readonly digitGroupingSymbol?: number;
|
||||
readonly digitGrouping?: number;
|
||||
readonly currencyDisplayType?: number;
|
||||
readonly coordinateDisplayType?: number;
|
||||
readonly expenseAmountColor?: number;
|
||||
readonly incomeAmountColor?: number;
|
||||
@@ -234,10 +240,11 @@ export const EMPTY_USER_BASIC_INFO: UserBasicInfo = {
|
||||
longTimeFormat: LongTimeFormat.Default.type,
|
||||
shortTimeFormat: ShortTimeFormat.Default.type,
|
||||
fiscalYearFormat: FiscalYearFormat.Default.type,
|
||||
currencyDisplayType: CurrencyDisplayType.Default.type,
|
||||
numeralSystem: NumeralSystem.Default.type,
|
||||
decimalSeparator: DecimalSeparator.LanguageDefaultType,
|
||||
digitGroupingSymbol: DigitGroupingSymbol.LanguageDefaultType,
|
||||
digitGrouping: DigitGroupingType.LanguageDefaultType,
|
||||
currencyDisplayType: CurrencyDisplayType.Default.type,
|
||||
coordinateDisplayType: CoordinateDisplayType.Default.type,
|
||||
expenseAmountColor: PresetAmountColor.DefaultExpenseColor.type,
|
||||
incomeAmountColor: PresetAmountColor.DefaultIncomeColor.type,
|
||||
|
||||
+44
-31
@@ -6,8 +6,10 @@ import { useUserStore } from './user.ts';
|
||||
import { useExchangeRatesStore } from './exchangeRates.ts';
|
||||
|
||||
import type { BeforeResolveFunction } from '@/core/base.ts';
|
||||
|
||||
import type { HiddenAmount, NumberWithSuffix } from '@/core/numeral.ts';
|
||||
import { AccountType, AccountCategory } from '@/core/account.ts';
|
||||
import { DISPLAY_HIDDEN_AMOUNT, INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numeral.ts';
|
||||
|
||||
import {
|
||||
type AccountNewDisplayOrderRequest,
|
||||
type AccountDisplayBalance,
|
||||
@@ -486,9 +488,9 @@ export const useAccountsStore = defineStore('accounts', () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
function getNetAssets(showAccountBalance: boolean): string {
|
||||
function getNetAssets(showAccountBalance: boolean): number | HiddenAmount | NumberWithSuffix {
|
||||
if (!showAccountBalance) {
|
||||
return '***';
|
||||
return DISPLAY_HIDDEN_AMOUNT;
|
||||
}
|
||||
|
||||
const accountsBalance = getAllFilteredAccountsBalance(allCategorizedAccountsMap.value, account =>
|
||||
@@ -513,15 +515,18 @@ export const useAccountsStore = defineStore('accounts', () => {
|
||||
}
|
||||
|
||||
if (hasUnCalculatedAmount) {
|
||||
return netAssets + '+';
|
||||
return {
|
||||
value: netAssets,
|
||||
suffix: INCOMPLETE_AMOUNT_SUFFIX
|
||||
};
|
||||
} else {
|
||||
return netAssets.toString();
|
||||
return netAssets;
|
||||
}
|
||||
}
|
||||
|
||||
function getTotalAssets(showAccountBalance: boolean): string {
|
||||
function getTotalAssets(showAccountBalance: boolean): number | HiddenAmount | NumberWithSuffix {
|
||||
if (!showAccountBalance) {
|
||||
return '***';
|
||||
return DISPLAY_HIDDEN_AMOUNT;
|
||||
}
|
||||
|
||||
const accountsBalance = getAllFilteredAccountsBalance(allCategorizedAccountsMap.value, account =>
|
||||
@@ -546,15 +551,18 @@ export const useAccountsStore = defineStore('accounts', () => {
|
||||
}
|
||||
|
||||
if (hasUnCalculatedAmount) {
|
||||
return totalAssets + '+';
|
||||
return {
|
||||
value: totalAssets,
|
||||
suffix: INCOMPLETE_AMOUNT_SUFFIX
|
||||
};
|
||||
} else {
|
||||
return totalAssets.toString();
|
||||
return totalAssets;
|
||||
}
|
||||
}
|
||||
|
||||
function getTotalLiabilities(showAccountBalance: boolean): string {
|
||||
function getTotalLiabilities(showAccountBalance: boolean): number | HiddenAmount | NumberWithSuffix {
|
||||
if (!showAccountBalance) {
|
||||
return '***';
|
||||
return DISPLAY_HIDDEN_AMOUNT;
|
||||
}
|
||||
|
||||
const accountsBalance = getAllFilteredAccountsBalance(allCategorizedAccountsMap.value, account =>
|
||||
@@ -579,15 +587,18 @@ export const useAccountsStore = defineStore('accounts', () => {
|
||||
}
|
||||
|
||||
if (hasUnCalculatedAmount) {
|
||||
return totalLiabilities + '+';
|
||||
return {
|
||||
value: totalLiabilities,
|
||||
suffix: INCOMPLETE_AMOUNT_SUFFIX
|
||||
};
|
||||
} else {
|
||||
return totalLiabilities.toString();
|
||||
return totalLiabilities;
|
||||
}
|
||||
}
|
||||
|
||||
function getAccountCategoryTotalBalance(showAccountBalance: boolean, accountCategory: AccountCategory): string {
|
||||
function getAccountCategoryTotalBalance(showAccountBalance: boolean, accountCategory: AccountCategory): number | HiddenAmount | NumberWithSuffix {
|
||||
if (!showAccountBalance) {
|
||||
return '***';
|
||||
return DISPLAY_HIDDEN_AMOUNT;
|
||||
}
|
||||
|
||||
const accountsBalance = getAllFilteredAccountsBalance(allCategorizedAccountsMap.value, account => account.category === accountCategory.type);
|
||||
@@ -622,27 +633,30 @@ export const useAccountsStore = defineStore('accounts', () => {
|
||||
}
|
||||
|
||||
if (hasUnCalculatedAmount) {
|
||||
return totalBalance + '+';
|
||||
return {
|
||||
value: totalBalance,
|
||||
suffix: INCOMPLETE_AMOUNT_SUFFIX
|
||||
};
|
||||
} else {
|
||||
return totalBalance.toString();
|
||||
return totalBalance;
|
||||
}
|
||||
}
|
||||
|
||||
function getAccountBalance(showAccountBalance: boolean, account: Account): string | null {
|
||||
function getAccountBalance(showAccountBalance: boolean, account: Account): number | HiddenAmount | null {
|
||||
if (account.type !== AccountType.SingleAccount.type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (showAccountBalance) {
|
||||
if (account.isAsset) {
|
||||
return account.balance.toString();
|
||||
return account.balance;
|
||||
} else if (account.isLiability) {
|
||||
return (-account.balance).toString();
|
||||
return -account.balance;
|
||||
} else {
|
||||
return account.balance.toString();
|
||||
return account.balance;
|
||||
}
|
||||
} else {
|
||||
return '***';
|
||||
return DISPLAY_HIDDEN_AMOUNT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,7 +669,7 @@ export const useAccountsStore = defineStore('accounts', () => {
|
||||
|
||||
if (!account.subAccounts || !account.subAccounts.length) {
|
||||
return {
|
||||
balance: showAccountBalance ? '0' : '***',
|
||||
balance: showAccountBalance ? 0 : DISPLAY_HIDDEN_AMOUNT,
|
||||
currency: resultCurrency
|
||||
};
|
||||
}
|
||||
@@ -679,7 +693,7 @@ export const useAccountsStore = defineStore('accounts', () => {
|
||||
|
||||
if (allSubAccountCurrencies.length === 0) {
|
||||
return {
|
||||
balance: showAccountBalance ? '0' : '***',
|
||||
balance: showAccountBalance ? 0 : DISPLAY_HIDDEN_AMOUNT,
|
||||
currency: resultCurrency
|
||||
};
|
||||
}
|
||||
@@ -700,7 +714,7 @@ export const useAccountsStore = defineStore('accounts', () => {
|
||||
if (subAccountId) {
|
||||
if (subAccountId === subAccount.id) {
|
||||
return {
|
||||
balance: showAccountBalance ? getAccountBalance(showAccountBalance, subAccount) as string : '***',
|
||||
balance: showAccountBalance ? getAccountBalance(showAccountBalance, subAccount) as number : DISPLAY_HIDDEN_AMOUNT,
|
||||
currency: subAccount.currency
|
||||
};
|
||||
}
|
||||
@@ -736,14 +750,13 @@ export const useAccountsStore = defineStore('accounts', () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
let displayTotalBalance = totalBalance.toString();
|
||||
|
||||
if (hasUnCalculatedAmount) {
|
||||
displayTotalBalance += '+';
|
||||
}
|
||||
const displayTotalBalance: NumberWithSuffix = {
|
||||
value: totalBalance,
|
||||
suffix: hasUnCalculatedAmount ? INCOMPLETE_AMOUNT_SUFFIX : ''
|
||||
};
|
||||
|
||||
return {
|
||||
balance: showAccountBalance ? displayTotalBalance : '***',
|
||||
balance: showAccountBalance ? displayTotalBalance : DISPLAY_HIDDEN_AMOUNT,
|
||||
currency: resultCurrency
|
||||
};
|
||||
}
|
||||
|
||||
+12
-6
@@ -99,6 +99,16 @@ export const useUserStore = defineStore('user', () => {
|
||||
return userInfo.fiscalYearFormat;
|
||||
});
|
||||
|
||||
const currentUserCurrencyDisplayType = computed<number>(() => {
|
||||
const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO;
|
||||
return userInfo.currencyDisplayType;
|
||||
});
|
||||
|
||||
const currentUserNumeralSystem = computed<number>(() => {
|
||||
const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO;
|
||||
return userInfo.numeralSystem;
|
||||
});
|
||||
|
||||
const currentUserDecimalSeparator = computed<number>(() => {
|
||||
const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO;
|
||||
return userInfo.decimalSeparator;
|
||||
@@ -114,11 +124,6 @@ export const useUserStore = defineStore('user', () => {
|
||||
return userInfo.digitGrouping;
|
||||
});
|
||||
|
||||
const currentUserCurrencyDisplayType = computed<number>(() => {
|
||||
const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO;
|
||||
return userInfo.currencyDisplayType;
|
||||
});
|
||||
|
||||
const currentUserCoordinateDisplayType = computed<number>(() => {
|
||||
const userInfo = currentUserBasicInfo.value || EMPTY_USER_BASIC_INFO;
|
||||
return userInfo.coordinateDisplayType;
|
||||
@@ -422,10 +427,11 @@ export const useUserStore = defineStore('user', () => {
|
||||
currentUserLongTimeFormat,
|
||||
currentUserShortTimeFormat,
|
||||
currentUserFiscalYearFormat,
|
||||
currentUserCurrencyDisplayType,
|
||||
currentUserNumeralSystem,
|
||||
currentUserDecimalSeparator,
|
||||
currentUserDigitGroupingSymbol,
|
||||
currentUserDigitGrouping,
|
||||
currentUserCurrencyDisplayType,
|
||||
currentUserCoordinateDisplayType,
|
||||
currentUserExpenseAmountColor,
|
||||
currentUserIncomeAmountColor,
|
||||
|
||||
@@ -14,7 +14,7 @@ import type {
|
||||
import { getExchangedAmountByRate } from '@/lib/numeral.ts';
|
||||
|
||||
export function useExchangeRatesPageBase() {
|
||||
const { getAllDisplayExchangeRates, formatUnixTimeToLongDate, parseAmount } = useI18n();
|
||||
const { getAllDisplayExchangeRates, formatUnixTimeToLongDate, parseAmountFromWesternArabicNumerals } = useI18n();
|
||||
|
||||
const userStore = useUserStore();
|
||||
const exchangeRatesStore = useExchangeRatesStore();
|
||||
@@ -49,7 +49,7 @@ export function useExchangeRatesPageBase() {
|
||||
|
||||
function setAsBaseline(currency: string, amount: string): void {
|
||||
baseCurrency.value = currency;
|
||||
baseAmount.value = parseAmount(amount);
|
||||
baseAmount.value = parseAmountFromWesternArabicNumerals(amount);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -7,6 +7,9 @@ import { useUserStore } from '@/stores/user.ts';
|
||||
import { useAccountsStore } from '@/stores/account.ts';
|
||||
import { useOverviewStore } from '@/stores/overview.ts';
|
||||
|
||||
import type { HiddenAmount, NumberWithSuffix } from '@/core/numeral.ts';
|
||||
import { DISPLAY_HIDDEN_AMOUNT, INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numeral.ts';
|
||||
|
||||
import { Account } from '@/models/account.ts';
|
||||
import type {
|
||||
TransactionOverviewResponse,
|
||||
@@ -20,7 +23,7 @@ export function useHomePageBase() {
|
||||
formatUnixTimeToLongYear,
|
||||
formatUnixTimeToLongMonth,
|
||||
formatUnixTimeToLongMonthDay,
|
||||
formatAmountWithCurrency
|
||||
formatAmountToLocalizedNumeralsWithCurrency
|
||||
} = useI18n();
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
@@ -37,18 +40,18 @@ export function useHomePageBase() {
|
||||
const allAccounts = computed<Account[]>(() => accountsStore.allAccounts);
|
||||
|
||||
const netAssets = computed<string>(() => {
|
||||
const netAssets = accountsStore.getNetAssets(showAmountInHomePage.value);
|
||||
return formatAmountWithCurrency(netAssets, defaultCurrency.value);
|
||||
const netAssets: number | HiddenAmount | NumberWithSuffix = accountsStore.getNetAssets(showAmountInHomePage.value);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(netAssets, defaultCurrency.value);
|
||||
});
|
||||
|
||||
const totalAssets = computed<string>(() => {
|
||||
const totalAssets = accountsStore.getTotalAssets(showAmountInHomePage.value);
|
||||
return formatAmountWithCurrency(totalAssets, defaultCurrency.value);
|
||||
const totalAssets: number | HiddenAmount | NumberWithSuffix = accountsStore.getTotalAssets(showAmountInHomePage.value);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(totalAssets, defaultCurrency.value);
|
||||
});
|
||||
|
||||
const totalLiabilities = computed<string>(() => {
|
||||
const totalLiabilities = accountsStore.getTotalLiabilities(showAmountInHomePage.value);
|
||||
return formatAmountWithCurrency(totalLiabilities, defaultCurrency.value);
|
||||
const totalLiabilities: number | HiddenAmount | NumberWithSuffix = accountsStore.getTotalLiabilities(showAmountInHomePage.value);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(totalLiabilities, defaultCurrency.value);
|
||||
});
|
||||
|
||||
const displayDateRange = computed<TransactionOverviewDisplayTime>(() => {
|
||||
@@ -75,10 +78,10 @@ export function useHomePageBase() {
|
||||
|
||||
function getDisplayAmount(amount: number, incomplete: boolean): string {
|
||||
if (!showAmountInHomePage.value) {
|
||||
return formatAmountWithCurrency('***', defaultCurrency.value);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(DISPLAY_HIDDEN_AMOUNT, defaultCurrency.value);
|
||||
}
|
||||
|
||||
return formatAmountWithCurrency(amount, defaultCurrency.value) + (incomplete ? '+' : '');
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(amount, defaultCurrency.value) + (incomplete ? INCOMPLETE_AMOUNT_SUFFIX : '');
|
||||
}
|
||||
|
||||
function getDisplayIncomeAmount(category: TransactionOverviewResponseItem): string {
|
||||
|
||||
@@ -6,14 +6,15 @@ import { useSettingsStore } from '@/stores/setting.ts';
|
||||
import { useUserStore } from '@/stores/user.ts';
|
||||
import { useAccountsStore } from '@/stores/account.ts';
|
||||
|
||||
import type { HiddenAmount, NumberWithSuffix } from '@/core/numeral.ts';
|
||||
import type { WeekDayValue } from '@/core/datetime.ts';
|
||||
import { type AccountCategory, AccountType } from '@/core/account.ts';
|
||||
import type { Account, CategorizedAccount } from '@/models/account.ts';
|
||||
|
||||
import { isObject, isString } from '@/lib/common.ts';
|
||||
import { isObject, isNumber, isString } from '@/lib/common.ts';
|
||||
|
||||
export function useAccountListPageBaseBase() {
|
||||
const { formatAmountWithCurrency } = useI18n();
|
||||
const { formatAmountToLocalizedNumeralsWithCurrency } = useI18n();
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
const userStore = useUserStore();
|
||||
@@ -37,18 +38,18 @@ export function useAccountListPageBaseBase() {
|
||||
const allAccountCount = computed<number>(() => accountsStore.allAvailableAccountsCount);
|
||||
|
||||
const netAssets = computed<string>(() => {
|
||||
const netAssets = accountsStore.getNetAssets(showAccountBalance.value);
|
||||
return formatAmountWithCurrency(netAssets, defaultCurrency.value);
|
||||
const netAssets: number | HiddenAmount | NumberWithSuffix = accountsStore.getNetAssets(showAccountBalance.value);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(netAssets, defaultCurrency.value);
|
||||
});
|
||||
|
||||
const totalAssets = computed<string>(() => {
|
||||
const totalAssets = accountsStore.getTotalAssets(showAccountBalance.value);
|
||||
return formatAmountWithCurrency(totalAssets, defaultCurrency.value);
|
||||
const totalAssets: number | HiddenAmount | NumberWithSuffix = accountsStore.getTotalAssets(showAccountBalance.value);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(totalAssets, defaultCurrency.value);
|
||||
});
|
||||
|
||||
const totalLiabilities = computed<string>(() => {
|
||||
const totalLiabilities = accountsStore.getTotalLiabilities(showAccountBalance.value);
|
||||
return formatAmountWithCurrency(totalLiabilities, defaultCurrency.value);
|
||||
const totalLiabilities: number | HiddenAmount | NumberWithSuffix = accountsStore.getTotalLiabilities(showAccountBalance.value);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(totalLiabilities, defaultCurrency.value);
|
||||
});
|
||||
|
||||
function accountCategoryTotalBalance(accountCategory?: AccountCategory): string {
|
||||
@@ -56,19 +57,19 @@ export function useAccountListPageBaseBase() {
|
||||
return '';
|
||||
}
|
||||
|
||||
const totalBalance = accountsStore.getAccountCategoryTotalBalance(showAccountBalance.value, accountCategory);
|
||||
return formatAmountWithCurrency(totalBalance, defaultCurrency.value);
|
||||
const totalBalance: number | HiddenAmount | NumberWithSuffix = accountsStore.getAccountCategoryTotalBalance(showAccountBalance.value, accountCategory);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(totalBalance, defaultCurrency.value);
|
||||
}
|
||||
|
||||
function accountBalance(account: Account, currentSubAccountId?: string): string | null {
|
||||
if (account.type === AccountType.SingleAccount.type) {
|
||||
const balance = accountsStore.getAccountBalance(showAccountBalance.value, account);
|
||||
const balance: number| HiddenAmount | null = accountsStore.getAccountBalance(showAccountBalance.value, account);
|
||||
|
||||
if (!isString(balance)) {
|
||||
if (!isNumber(balance) && !isString(balance)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return formatAmountWithCurrency(balance, account.currency);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(balance, account.currency);
|
||||
} else if (account.type === AccountType.MultiSubAccounts.type) {
|
||||
const balanceResult = accountsStore.getAccountSubAccountBalance(showAccountBalance.value, showHidden.value, account, currentSubAccountId);
|
||||
|
||||
@@ -76,7 +77,7 @@ export function useAccountListPageBaseBase() {
|
||||
return '';
|
||||
}
|
||||
|
||||
return formatAmountWithCurrency(balanceResult.balance, balanceResult.currency);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(balanceResult.balance, balanceResult.currency);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -18,10 +18,7 @@ import type {
|
||||
TransactionReconciliationStatementResponseItem
|
||||
} from '@/models/transaction.ts';
|
||||
|
||||
import {
|
||||
replaceAll,
|
||||
removeAll
|
||||
} from '@/lib/common.ts';
|
||||
import { replaceAll } from '@/lib/common.ts';
|
||||
|
||||
import {
|
||||
getUtcOffsetByUtcOffsetMinutes,
|
||||
@@ -36,12 +33,11 @@ export function useReconciliationStatementPageBase() {
|
||||
tt,
|
||||
getAllAccountBalanceTrendChartTypes,
|
||||
getAllStatisticsDateAggregationTypesWithShortName,
|
||||
getCurrentDigitGroupingSymbol,
|
||||
formatUnixTimeToLongDateTime,
|
||||
formatUnixTimeToLongDate,
|
||||
formatUnixTimeToShortTime,
|
||||
formatAmount,
|
||||
formatAmountWithCurrency
|
||||
formatAmountToWesternArabicNumeralsWithoutDigitGrouping,
|
||||
formatAmountToLocalizedNumeralsWithCurrency
|
||||
} = useI18n();
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
@@ -90,30 +86,30 @@ export function useReconciliationStatementPageBase() {
|
||||
});
|
||||
|
||||
const displayTotalInflows = computed<string>(() => {
|
||||
return formatAmountWithCurrency(reconciliationStatements.value?.totalInflows ?? 0, currentAccountCurrency.value);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(reconciliationStatements.value?.totalInflows ?? 0, currentAccountCurrency.value);
|
||||
});
|
||||
|
||||
const displayTotalOutflows = computed<string>(() => {
|
||||
return formatAmountWithCurrency(reconciliationStatements.value?.totalOutflows ?? 0, currentAccountCurrency.value);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(reconciliationStatements.value?.totalOutflows ?? 0, currentAccountCurrency.value);
|
||||
});
|
||||
|
||||
const displayTotalBalance = computed<string>(() => {
|
||||
return formatAmountWithCurrency((reconciliationStatements?.value?.totalInflows ?? 0) - (reconciliationStatements.value?.totalOutflows ?? 0), currentAccountCurrency.value);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency((reconciliationStatements?.value?.totalInflows ?? 0) - (reconciliationStatements.value?.totalOutflows ?? 0), currentAccountCurrency.value);
|
||||
});
|
||||
|
||||
const displayOpeningBalance = computed<string>(() => {
|
||||
if (isCurrentLiabilityAccount.value) {
|
||||
return formatAmountWithCurrency(-(reconciliationStatements?.value?.openingBalance ?? 0), currentAccountCurrency.value);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(-(reconciliationStatements?.value?.openingBalance ?? 0), currentAccountCurrency.value);
|
||||
} else {
|
||||
return formatAmountWithCurrency(reconciliationStatements?.value?.openingBalance ?? 0, currentAccountCurrency.value);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(reconciliationStatements?.value?.openingBalance ?? 0, currentAccountCurrency.value);
|
||||
}
|
||||
});
|
||||
|
||||
const displayClosingBalance = computed<string>(() => {
|
||||
if (isCurrentLiabilityAccount.value) {
|
||||
return formatAmountWithCurrency(-(reconciliationStatements?.value?.closingBalance ?? 0), currentAccountCurrency.value);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(-(reconciliationStatements?.value?.closingBalance ?? 0), currentAccountCurrency.value);
|
||||
} else {
|
||||
return formatAmountWithCurrency(reconciliationStatements?.value?.closingBalance ?? 0, currentAccountCurrency.value);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(reconciliationStatements?.value?.closingBalance ?? 0, currentAccountCurrency.value);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -159,7 +155,7 @@ export function useReconciliationStatementPageBase() {
|
||||
currency = allAccountsMap.value[transaction.sourceAccountId].currency;
|
||||
}
|
||||
|
||||
return formatAmountWithCurrency(transaction.sourceAmount, currency);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(transaction.sourceAmount, currency);
|
||||
}
|
||||
|
||||
function getDisplayDestinationAmount(transaction: TransactionReconciliationStatementResponseItem): string {
|
||||
@@ -169,7 +165,7 @@ export function useReconciliationStatementPageBase() {
|
||||
currency = allAccountsMap.value[transaction.destinationAccountId].currency;
|
||||
}
|
||||
|
||||
return formatAmountWithCurrency(transaction.destinationAmount, currency);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(transaction.destinationAmount, currency);
|
||||
}
|
||||
|
||||
function getDisplayAccountBalance(transaction: TransactionReconciliationStatementResponseItem): string {
|
||||
@@ -187,9 +183,9 @@ export function useReconciliationStatementPageBase() {
|
||||
}
|
||||
|
||||
if (isLiabilityAccount) {
|
||||
return formatAmountWithCurrency(-transaction.accountClosingBalance, currency);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(-transaction.accountClosingBalance, currency);
|
||||
} else {
|
||||
return formatAmountWithCurrency(transaction.accountClosingBalance, currency);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(transaction.accountClosingBalance, currency);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,7 +196,6 @@ export function useReconciliationStatementPageBase() {
|
||||
separator = '\t';
|
||||
}
|
||||
|
||||
const digitGroupingSymbol = getCurrentDigitGroupingSymbol();
|
||||
const accountBalanceName = isCurrentLiabilityAccount.value ? 'Account Outstanding Balance' : 'Account Balance';
|
||||
|
||||
const header = [
|
||||
@@ -218,13 +213,13 @@ export function useReconciliationStatementPageBase() {
|
||||
const transactionTime = getUnixTime(parseDateFromUnixTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value));
|
||||
const type = getDisplayTransactionType(transaction);
|
||||
let categoryName = allCategoriesMap.value[transaction.categoryId]?.name || '';
|
||||
let displayAmount = removeAll(formatAmount(transaction.sourceAmount), digitGroupingSymbol);
|
||||
let displayAmount = formatAmountToWesternArabicNumeralsWithoutDigitGrouping(transaction.sourceAmount);
|
||||
let displayAccountName = allAccountsMap.value[transaction.sourceAccountId]?.name || '';
|
||||
|
||||
if (transaction.type === TransactionType.ModifyBalance) {
|
||||
categoryName = tt('Modify Balance');
|
||||
} else if (transaction.type === TransactionType.Transfer && transaction.destinationAccountId === accountId.value) {
|
||||
displayAmount = removeAll(formatAmount(transaction.destinationAmount), digitGroupingSymbol);
|
||||
displayAmount = formatAmountToWesternArabicNumeralsWithoutDigitGrouping(transaction.destinationAmount);
|
||||
}
|
||||
|
||||
if (transaction.type === TransactionType.Transfer && allAccountsMap.value[transaction.destinationAccountId]) {
|
||||
@@ -234,9 +229,9 @@ export function useReconciliationStatementPageBase() {
|
||||
let displayAccountBalance = '';
|
||||
|
||||
if (isCurrentLiabilityAccount.value) {
|
||||
displayAccountBalance = removeAll(formatAmount(-transaction.accountClosingBalance), digitGroupingSymbol);
|
||||
displayAccountBalance = formatAmountToWesternArabicNumeralsWithoutDigitGrouping(-transaction.accountClosingBalance);
|
||||
} else {
|
||||
displayAccountBalance = removeAll(formatAmount(transaction.accountClosingBalance), digitGroupingSymbol);
|
||||
displayAccountBalance = formatAmountToWesternArabicNumeralsWithoutDigitGrouping(transaction.accountClosingBalance);
|
||||
}
|
||||
|
||||
let description = transaction.comment || '';
|
||||
|
||||
@@ -9,6 +9,7 @@ import { type TransactionStatisticsFilter, useStatisticsStore } from '@/stores/s
|
||||
import type { TypeAndDisplayName } from '@/core/base.ts';
|
||||
import { type LocalizedDateRange, type WeekDayValue, DateRangeScene, DateRange } from '@/core/datetime.ts';
|
||||
import { StatisticsAnalysisType, ChartDataType, ChartSortingType, ChartDateAggregationType } from '@/core/statistics.ts';
|
||||
import { DISPLAY_HIDDEN_AMOUNT } from '@/consts/numeral.ts';
|
||||
import type { TransactionCategoricalAnalysisData, TransactionTrendsAnalysisData } from '@/models/transaction.ts';
|
||||
|
||||
import { limitText, findNameByType, findDisplayNameByType } from '@/lib/common.ts';
|
||||
@@ -23,7 +24,7 @@ export function useStatisticsTransactionPageBase() {
|
||||
formatUnixTimeToLongDateTime,
|
||||
formatUnixTimeToLongYearMonth,
|
||||
formatDateRange,
|
||||
formatAmountWithCurrency
|
||||
formatAmountToLocalizedNumeralsWithCurrency
|
||||
} = useI18n();
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
@@ -200,13 +201,13 @@ export function useStatisticsTransactionPageBase() {
|
||||
const trendsAnalysisData = computed<TransactionTrendsAnalysisData | null>(() => statisticsStore.trendsAnalysisData);
|
||||
|
||||
function getDisplayAmount(amount: number, currency: string, textLimit?: number): string {
|
||||
const finalAmount = formatAmountWithCurrency(amount, currency);
|
||||
const finalAmount = formatAmountToLocalizedNumeralsWithCurrency(amount, currency);
|
||||
|
||||
if (!showAccountBalance.value
|
||||
&& (query.value.chartDataType === ChartDataType.AccountTotalAssets.type
|
||||
|| query.value.chartDataType === ChartDataType.AccountTotalLiabilities.type)
|
||||
) {
|
||||
return '***';
|
||||
return DISPLAY_HIDDEN_AMOUNT;
|
||||
}
|
||||
|
||||
if (textLimit) {
|
||||
|
||||
@@ -10,6 +10,7 @@ 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 { WeekDayValue } from '@/core/datetime.ts';
|
||||
import type { LocalizedTimezoneInfo } from '@/core/timezone.ts';
|
||||
import { TransactionType } from '@/core/transaction.ts';
|
||||
@@ -59,7 +60,7 @@ export function useTransactionEditPageBase(type: TransactionEditPageType, initMo
|
||||
tt,
|
||||
getAllTimezones,
|
||||
getTimezoneDifferenceDisplayText,
|
||||
formatAmountWithCurrency,
|
||||
formatAmountToLocalizedNumeralsWithCurrency,
|
||||
getAdaptiveAmountRate,
|
||||
getCategorizedAccountsWithDisplayBalance
|
||||
} = useI18n();
|
||||
@@ -360,12 +361,12 @@ export function useTransactionEditPageBase(type: TransactionEditPageType, initMo
|
||||
}
|
||||
}
|
||||
|
||||
function getDisplayAmount(amount: number | string, hideAmount: boolean, currencyCode: string): string {
|
||||
function getDisplayAmount(amount: number, hideAmount: boolean, currencyCode: string): string {
|
||||
if (hideAmount) {
|
||||
return formatAmountWithCurrency('***', currencyCode);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(DISPLAY_HIDDEN_AMOUNT, currencyCode);
|
||||
}
|
||||
|
||||
return formatAmountWithCurrency(amount, currencyCode);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(amount, currencyCode);
|
||||
}
|
||||
|
||||
function getTransactionPictureUrl(pictureInfo?: TransactionPictureInfoBasicResponse | null): string | undefined {
|
||||
|
||||
@@ -13,6 +13,7 @@ import type { TypeAndName } from '@/core/base.ts';
|
||||
import { type LocalizedDateRange, type WeekDayValue, DateRange, DateRangeScene } from '@/core/datetime.ts';
|
||||
import { AccountType } from '@/core/account.ts';
|
||||
import { TransactionType } from '@/core/transaction.ts';
|
||||
import { DISPLAY_HIDDEN_AMOUNT, INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numeral.ts';
|
||||
|
||||
import type { Account } from '@/models/account.ts';
|
||||
import type { TransactionCategory } from '@/models/transaction_category.ts';
|
||||
@@ -84,7 +85,7 @@ export function useTransactionListPageBase() {
|
||||
formatUnixTimeToLongYearMonth,
|
||||
formatUnixTimeToShortTime,
|
||||
formatDateRange,
|
||||
formatAmountWithCurrency
|
||||
formatAmountToLocalizedNumeralsWithCurrency
|
||||
} = useI18n();
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
@@ -231,7 +232,7 @@ export function useTransactionListPageBase() {
|
||||
const displayAmount: string[] = [];
|
||||
|
||||
for (let i = 1; i < amountFilterItems.length; i++) {
|
||||
displayAmount.push(formatAmountWithCurrency(amountFilterItems[i], false));
|
||||
displayAmount.push(formatAmountToLocalizedNumeralsWithCurrency(parseInt(amountFilterItems[i]), false));
|
||||
}
|
||||
|
||||
return displayAmount.join(' ~ ');
|
||||
@@ -279,10 +280,10 @@ export function useTransactionListPageBase() {
|
||||
|
||||
function formatAmount(amount: number, hideAmount: boolean, currencyCode: string): string {
|
||||
if (hideAmount) {
|
||||
return formatAmountWithCurrency('***', currencyCode);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(DISPLAY_HIDDEN_AMOUNT, currencyCode);
|
||||
}
|
||||
|
||||
return formatAmountWithCurrency(amount, currencyCode);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(amount, currencyCode);
|
||||
}
|
||||
|
||||
function getDisplayTime(transaction: Transaction): string {
|
||||
@@ -337,8 +338,8 @@ export function useTransactionListPageBase() {
|
||||
}
|
||||
|
||||
function getDisplayMonthTotalAmount(amount: number, currency: string | false, symbol: string, incomplete: boolean): string {
|
||||
const displayAmount = formatAmountWithCurrency(amount, currency);
|
||||
return symbol + displayAmount + (incomplete ? '+' : '');
|
||||
const displayAmount = formatAmountToLocalizedNumeralsWithCurrency(amount, currency);
|
||||
return symbol + displayAmount + (incomplete ? INCOMPLETE_AMOUNT_SUFFIX : '');
|
||||
}
|
||||
|
||||
function getTransactionTypeName(type: number | null, defaultName: string): string {
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useUserStore } from '@/stores/user.ts';
|
||||
import type { DataStatisticsResponse, DisplayDataStatistics } from '@/models/data_management.ts';
|
||||
|
||||
export function useDataManagementPageBase() {
|
||||
const { tt, appendDigitGroupingSymbol } = useI18n();
|
||||
const { tt, formatNumberToLocalizedNumerals } = useI18n();
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
@@ -19,13 +19,13 @@ export function useDataManagementPageBase() {
|
||||
}
|
||||
|
||||
return {
|
||||
totalTransactionCount: appendDigitGroupingSymbol(dataStatistics.value.totalTransactionCount),
|
||||
totalAccountCount: appendDigitGroupingSymbol(dataStatistics.value.totalAccountCount),
|
||||
totalTransactionCategoryCount: appendDigitGroupingSymbol(dataStatistics.value.totalTransactionCategoryCount),
|
||||
totalTransactionTagCount: appendDigitGroupingSymbol(dataStatistics.value.totalTransactionTagCount),
|
||||
totalTransactionPictureCount: appendDigitGroupingSymbol(dataStatistics.value.totalTransactionPictureCount),
|
||||
totalTransactionTemplateCount: appendDigitGroupingSymbol(dataStatistics.value.totalTransactionTemplateCount),
|
||||
totalScheduledTransactionCount: appendDigitGroupingSymbol(dataStatistics.value.totalScheduledTransactionCount)
|
||||
totalTransactionCount: formatNumberToLocalizedNumerals(parseInt(dataStatistics.value.totalTransactionCount)),
|
||||
totalAccountCount: formatNumberToLocalizedNumerals(parseInt(dataStatistics.value.totalAccountCount)),
|
||||
totalTransactionCategoryCount: formatNumberToLocalizedNumerals(parseInt(dataStatistics.value.totalTransactionCategoryCount)),
|
||||
totalTransactionTagCount: formatNumberToLocalizedNumerals(parseInt(dataStatistics.value.totalTransactionTagCount)),
|
||||
totalTransactionPictureCount: formatNumberToLocalizedNumerals(parseInt(dataStatistics.value.totalTransactionPictureCount)),
|
||||
totalTransactionTemplateCount: formatNumberToLocalizedNumerals(parseInt(dataStatistics.value.totalTransactionTemplateCount)),
|
||||
totalScheduledTransactionCount: formatNumberToLocalizedNumerals(parseInt(dataStatistics.value.totalScheduledTransactionCount))
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useOverviewStore } from '@/stores/overview.ts';
|
||||
|
||||
import type { TypeAndDisplayName } from '@/core/base.ts';
|
||||
import { WeekDay } from '@/core/datetime.ts';
|
||||
import { type LocalizedDigitGroupingType, DigitGroupingSymbol } from '@/core/numeral.ts';
|
||||
import { type LocalizedDigitGroupingType, NumeralSystem, DecimalSeparator, DigitGroupingSymbol } from '@/core/numeral.ts';
|
||||
|
||||
import { type UserBasicInfo, User } from '@/models/user.ts';
|
||||
import { type CategorizedAccount, Account} from '@/models/account.ts';
|
||||
@@ -27,10 +27,11 @@ export function useUserProfilePageBase() {
|
||||
getAllLongTimeFormats,
|
||||
getAllShortTimeFormats,
|
||||
getAllFiscalYearFormats,
|
||||
getAllCurrencyDisplayTypes,
|
||||
getAllNumeralSystemTypes,
|
||||
getAllDecimalSeparators,
|
||||
getAllDigitGroupingSymbols,
|
||||
getAllDigitGroupingTypes,
|
||||
getAllCurrencyDisplayTypes,
|
||||
getAllCoordinateDisplayTypes,
|
||||
getAllExpenseAmountColors,
|
||||
getAllIncomeAmountColors,
|
||||
@@ -62,10 +63,11 @@ export function useUserProfilePageBase() {
|
||||
const allLongTimeFormats = computed<TypeAndDisplayName[]>(() => getAllLongTimeFormats());
|
||||
const allShortTimeFormats = computed<TypeAndDisplayName[]>(() => getAllShortTimeFormats());
|
||||
const allFiscalYearFormats = computed<TypeAndDisplayName[]>(() => getAllFiscalYearFormats());
|
||||
const allCurrencyDisplayTypes = computed<TypeAndDisplayName[]>(() => getAllCurrencyDisplayTypes(NumeralSystem.valueOf(newProfile.value.numeralSystem) ?? NumeralSystem.Default, DecimalSeparator.valueOf(newProfile.value.decimalSeparator)?.symbol || DecimalSeparator.Default.symbol));
|
||||
const allNumeralSystemTypes = computed<TypeAndDisplayName[]>(() => getAllNumeralSystemTypes());
|
||||
const allDecimalSeparators = computed<TypeAndDisplayName[]>(() => getAllDecimalSeparators());
|
||||
const allDigitGroupingSymbols = computed<TypeAndDisplayName[]>(() => getAllDigitGroupingSymbols());
|
||||
const allDigitGroupingTypes = computed<LocalizedDigitGroupingType[]>(() => getAllDigitGroupingTypes(DigitGroupingSymbol.valueOf(newProfile.value.digitGroupingSymbol)?.symbol || DigitGroupingSymbol.Default.symbol));
|
||||
const allCurrencyDisplayTypes = computed<TypeAndDisplayName[]>(() => getAllCurrencyDisplayTypes());
|
||||
const allDigitGroupingTypes = computed<LocalizedDigitGroupingType[]>(() => getAllDigitGroupingTypes(NumeralSystem.valueOf(newProfile.value.numeralSystem) ?? NumeralSystem.Default, DigitGroupingSymbol.valueOf(newProfile.value.digitGroupingSymbol)?.symbol || DigitGroupingSymbol.Default.symbol));
|
||||
const allCoordinateDisplayTypes = computed<TypeAndDisplayName[]>(() => getAllCoordinateDisplayTypes());
|
||||
const allExpenseAmountColorTypes = computed<TypeAndDisplayName[]>(() => getAllExpenseAmountColors());
|
||||
const allIncomeAmountColorTypes = computed<TypeAndDisplayName[]>(() => getAllIncomeAmountColors());
|
||||
@@ -108,10 +110,11 @@ export function useUserProfilePageBase() {
|
||||
newProfile.value.longTimeFormat === oldProfile.value.longTimeFormat &&
|
||||
newProfile.value.shortTimeFormat === oldProfile.value.shortTimeFormat &&
|
||||
newProfile.value.fiscalYearFormat === oldProfile.value.fiscalYearFormat &&
|
||||
newProfile.value.currencyDisplayType === oldProfile.value.currencyDisplayType &&
|
||||
newProfile.value.numeralSystem === oldProfile.value.numeralSystem &&
|
||||
newProfile.value.decimalSeparator === oldProfile.value.decimalSeparator &&
|
||||
newProfile.value.digitGroupingSymbol === oldProfile.value.digitGroupingSymbol &&
|
||||
newProfile.value.digitGrouping === oldProfile.value.digitGrouping &&
|
||||
newProfile.value.currencyDisplayType === oldProfile.value.currencyDisplayType &&
|
||||
newProfile.value.coordinateDisplayType === oldProfile.value.coordinateDisplayType &&
|
||||
newProfile.value.expenseAmountColor === oldProfile.value.expenseAmountColor &&
|
||||
newProfile.value.incomeAmountColor === oldProfile.value.incomeAmountColor) {
|
||||
@@ -199,10 +202,11 @@ export function useUserProfilePageBase() {
|
||||
allLongTimeFormats,
|
||||
allShortTimeFormats,
|
||||
allFiscalYearFormats,
|
||||
allCurrencyDisplayTypes,
|
||||
allNumeralSystemTypes,
|
||||
allDecimalSeparators,
|
||||
allDigitGroupingSymbols,
|
||||
allDigitGroupingTypes,
|
||||
allCurrencyDisplayTypes,
|
||||
allCoordinateDisplayTypes,
|
||||
allExpenseAmountColorTypes,
|
||||
allIncomeAmountColorTypes,
|
||||
|
||||
@@ -202,7 +202,7 @@
|
||||
<v-skeleton-loader class="skeleton-no-margin ml-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
|
||||
</span>
|
||||
<span class="ml-2" v-else-if="!loading">
|
||||
{{ reconciliationStatements?.transactions.length ?? 0 }}
|
||||
{{ formatNumberToLocalizedNumerals(reconciliationStatements?.transactions.length ?? 0) }}
|
||||
</span>
|
||||
<v-spacer/>
|
||||
<span v-if="reconciliationStatements && reconciliationStatements.transactions && reconciliationStatements.transactions.length > 10">
|
||||
@@ -319,7 +319,7 @@ const emit = defineEmits<{
|
||||
(e: 'error', message: string): void;
|
||||
}>();
|
||||
|
||||
const { tt } = useI18n();
|
||||
const { tt, formatNumberToLocalizedNumerals } = useI18n();
|
||||
|
||||
const {
|
||||
accountId,
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
density="comfortable" variant="text"
|
||||
:class="{ 'd-none': loading, 'hover-display': !loading }"
|
||||
v-if="exchangeRate.currencyCode !== baseCurrency"
|
||||
@click="setAsBaseline(exchangeRate.currencyCode, getFinalConvertedAmount(exchangeRate))">
|
||||
@click="setAsBaseline(exchangeRate.currencyCode, getFinalConvertedAmount(exchangeRate, false))">
|
||||
{{ tt('Set as Base') }}
|
||||
</v-btn>
|
||||
<v-btn class="px-2" color="default"
|
||||
@@ -134,7 +134,7 @@
|
||||
</template>
|
||||
{{ tt('Delete') }}
|
||||
</v-btn>
|
||||
<span class="ml-3">{{ getFinalConvertedAmount(exchangeRate) }}</span>
|
||||
<span class="ml-3">{{ getFinalConvertedAmount(exchangeRate, true) }}</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -168,6 +168,8 @@ import { useExchangeRatesPageBase } from '@/views/base/ExchangeRatesPageBase.ts'
|
||||
|
||||
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
||||
|
||||
import { NumeralSystem } from '@/core/numeral.ts';
|
||||
|
||||
import type { LocalizedLatestExchangeRate } from '@/models/exchange_rate.ts';
|
||||
|
||||
import logger from '@/lib/logger.ts';
|
||||
@@ -184,7 +186,7 @@ type UpdateDialogType = InstanceType<typeof UpdateDialog>;
|
||||
|
||||
const { mdAndUp } = useDisplay();
|
||||
|
||||
const { tt, formatExchangeRateAmount } = useI18n();
|
||||
const { tt, getCurrentNumeralSystemType, formatExchangeRateAmountToWesternArabicNumerals } = useI18n();
|
||||
const {
|
||||
baseCurrency,
|
||||
baseAmount,
|
||||
@@ -283,9 +285,15 @@ function remove(currency: string): void {
|
||||
});
|
||||
}
|
||||
|
||||
function getFinalConvertedAmount(toExchangeRate: LocalizedLatestExchangeRate): string {
|
||||
function getFinalConvertedAmount(toExchangeRate: LocalizedLatestExchangeRate, displayLocalizedDigits: boolean): string {
|
||||
const numeralSystem = getCurrentNumeralSystemType();
|
||||
|
||||
if (!baseCurrency.value) {
|
||||
return '0';
|
||||
if (displayLocalizedDigits) {
|
||||
return numeralSystem.digitZero;
|
||||
} else {
|
||||
return NumeralSystem.WesternArabicNumerals.digitZero;
|
||||
}
|
||||
}
|
||||
|
||||
const fromExchangeRate = exchangeRatesStore.latestExchangeRateMap[baseCurrency.value];
|
||||
@@ -299,10 +307,20 @@ function getFinalConvertedAmount(toExchangeRate: LocalizedLatestExchangeRate): s
|
||||
}
|
||||
|
||||
if (!exchangeRateAmount) {
|
||||
return '0';
|
||||
if (displayLocalizedDigits) {
|
||||
return numeralSystem.digitZero;
|
||||
} else {
|
||||
return NumeralSystem.WesternArabicNumerals.digitZero;
|
||||
}
|
||||
}
|
||||
|
||||
return formatExchangeRateAmount(exchangeRateAmount);
|
||||
let ret = formatExchangeRateAmountToWesternArabicNumerals(exchangeRateAmount);
|
||||
|
||||
if (displayLocalizedDigits) {
|
||||
ret = numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
watch(mdAndUp, (newValue) => {
|
||||
|
||||
@@ -34,8 +34,12 @@ import { useI18n } from '@/locales/helpers.ts';
|
||||
import { useSettingsStore } from '@/stores/setting.ts';
|
||||
import { useUserStore } from '@/stores/user.ts';
|
||||
|
||||
import type { HiddenAmount } from '@/core/numeral.ts';
|
||||
import { TransactionType } from '@/core/transaction.ts';
|
||||
import { DISPLAY_HIDDEN_AMOUNT, INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numeral.ts';
|
||||
|
||||
import { type TransactionMonthlyIncomeAndExpenseData } from '@/models/transaction.ts';
|
||||
|
||||
import {
|
||||
parseDateFromUnixTime,
|
||||
getMonthName
|
||||
@@ -59,7 +63,7 @@ const emit = defineEmits<{
|
||||
(e: 'click', event: MonthlyIncomeAndExpenseCardClickEvent): void;
|
||||
}>();
|
||||
|
||||
const { tt, getMonthShortName, formatAmountWithCurrency } = useI18n();
|
||||
const { tt, getMonthShortName, formatAmountToLocalizedNumeralsWithCurrency } = useI18n();
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
const userStore = useUserStore();
|
||||
@@ -275,16 +279,16 @@ const chartOptions = computed<object>(() => {
|
||||
};
|
||||
});
|
||||
|
||||
function getDisplayCurrency(value: number | string, currencyCode: string): string {
|
||||
return formatAmountWithCurrency(value, currencyCode);
|
||||
function getDisplayCurrency(value: number | HiddenAmount, currencyCode: string): string {
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(value, currencyCode);
|
||||
}
|
||||
|
||||
function getDisplayAmount(amount: number, incomplete: boolean): string {
|
||||
if (!showAmountInHomePage.value) {
|
||||
return getDisplayCurrency('***', defaultCurrency.value);
|
||||
return getDisplayCurrency(DISPLAY_HIDDEN_AMOUNT, defaultCurrency.value);
|
||||
}
|
||||
|
||||
return getDisplayCurrency(amount, defaultCurrency.value) + (incomplete ? '+' : '');
|
||||
return getDisplayCurrency(amount, defaultCurrency.value) + (incomplete ? INCOMPLETE_AMOUNT_SUFFIX : '');
|
||||
}
|
||||
|
||||
function getDisplayIncomeAmount(data: TransactionMonthlyIncomeAndExpenseData): string {
|
||||
|
||||
@@ -238,7 +238,7 @@
|
||||
<div class="d-flex flex-column ml-2">
|
||||
<div class="d-flex">
|
||||
<span>{{ item.name }}</span>
|
||||
<small class="statistics-percent" v-if="item.percent >= 0">{{ formatPercent(item.percent, 2, '<0.01') }}</small>
|
||||
<small class="statistics-percent" v-if="item.percent >= 0">{{ formatPercentToLocalizedNumerals(item.percent, 2, '<0.01') }}</small>
|
||||
<v-spacer/>
|
||||
<span class="statistics-amount">{{ getDisplayAmount(item.totalAmount, defaultCurrency) }}</span>
|
||||
</div>
|
||||
@@ -374,9 +374,6 @@ import {
|
||||
isNumber,
|
||||
arrayItemToObjectField
|
||||
} from '@/lib/common.ts';
|
||||
import {
|
||||
formatAmount
|
||||
} from '@/lib/numeral.ts';
|
||||
import {
|
||||
getYearAndMonthFromUnixTime,
|
||||
getYearMonthFirstUnixTime,
|
||||
@@ -426,7 +423,14 @@ const props = defineProps<TransactionStatisticsProps>();
|
||||
const router = useRouter();
|
||||
const display = useDisplay();
|
||||
const theme = useTheme();
|
||||
const { tt, getAllCategoricalChartTypes, getAllTrendChartTypes, formatPercent } = useI18n();
|
||||
|
||||
const {
|
||||
tt,
|
||||
getAllCategoricalChartTypes,
|
||||
getAllTrendChartTypes,
|
||||
formatAmountToWesternArabicNumeralsWithoutDigitGrouping,
|
||||
formatPercentToLocalizedNumerals
|
||||
} = useI18n();
|
||||
|
||||
const {
|
||||
loading,
|
||||
@@ -956,7 +960,7 @@ function exportResults(): void {
|
||||
.filter(item => !item.hidden)
|
||||
.map(item => [
|
||||
item.name,
|
||||
formatAmount(item.totalAmount, {}),
|
||||
formatAmountToWesternArabicNumeralsWithoutDigitGrouping(item.totalAmount),
|
||||
item.percent.toFixed(4)
|
||||
])
|
||||
});
|
||||
|
||||
@@ -824,7 +824,7 @@
|
||||
<v-btn color="teal" :disabled="submitting || !!editingTransaction || selectedImportTransactionCount < 1 || selectedInvalidTransactionCount > 0"
|
||||
:append-icon="!submitting ? mdiArrowRight : undefined" @click="submit"
|
||||
v-if="currentStep === 'checkData'">
|
||||
{{ (submitting && importProcess > 0 ? tt('format.misc.importingTransactions', { process: formatNumber(importProcess, 2) }) : tt('Import')) }}
|
||||
{{ (submitting && importProcess > 0 ? tt('format.misc.importingTransactions', { process: formatNumberToLocalizedNumerals(importProcess, 2) }) : tt('Import')) }}
|
||||
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
|
||||
</v-btn>
|
||||
<v-btn color="secondary" variant="tonal"
|
||||
@@ -998,8 +998,8 @@ const {
|
||||
getAllImportTransactionColumnTypes,
|
||||
getAllSupportedImportFileTypes,
|
||||
formatUnixTimeToLongDateTime,
|
||||
formatAmountWithCurrency,
|
||||
formatNumber,
|
||||
formatAmountToLocalizedNumeralsWithCurrency,
|
||||
formatNumberToLocalizedNumerals,
|
||||
getCategorizedAccountsWithDisplayBalance
|
||||
} = useI18n();
|
||||
|
||||
@@ -1680,7 +1680,7 @@ function getDisplayTimezone(transaction: ImportTransaction): string {
|
||||
}
|
||||
|
||||
function getDisplayCurrency(value: number, currencyCode: string): string {
|
||||
return formatAmountWithCurrency(value, currencyCode);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(value, currencyCode);
|
||||
}
|
||||
|
||||
function getTransactionDisplayAmount(transaction: ImportTransaction): string {
|
||||
|
||||
@@ -243,6 +243,19 @@
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6">
|
||||
<v-select
|
||||
item-title="displayName"
|
||||
item-value="type"
|
||||
persistent-placeholder
|
||||
:disabled="loading || saving"
|
||||
:label="tt('Numeral System')"
|
||||
:placeholder="tt('Numeral System')"
|
||||
:items="allNumeralSystemTypes"
|
||||
v-model="newProfile.numeralSystem"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6">
|
||||
<v-select
|
||||
item-title="displayName"
|
||||
@@ -401,10 +414,11 @@ const {
|
||||
allLongTimeFormats,
|
||||
allShortTimeFormats,
|
||||
allFiscalYearFormats,
|
||||
allCurrencyDisplayTypes,
|
||||
allNumeralSystemTypes,
|
||||
allDecimalSeparators,
|
||||
allDigitGroupingSymbols,
|
||||
allDigitGroupingTypes,
|
||||
allCurrencyDisplayTypes,
|
||||
allCoordinateDisplayTypes,
|
||||
allExpenseAmountColorTypes,
|
||||
allIncomeAmountColorTypes,
|
||||
|
||||
@@ -556,8 +556,17 @@ const props = defineProps<{
|
||||
f7router: Router.Router;
|
||||
}>();
|
||||
|
||||
const { tt, getAllCurrencies, getCurrencyName, formatUnixTimeToLongDate, formatUnixTimeToLongTime, formatAmountWithCurrency } = useI18n();
|
||||
const {
|
||||
tt,
|
||||
getAllCurrencies,
|
||||
getCurrencyName,
|
||||
formatUnixTimeToLongDate,
|
||||
formatUnixTimeToLongTime,
|
||||
formatAmountToLocalizedNumeralsWithCurrency
|
||||
} = useI18n();
|
||||
|
||||
const { showAlert, showToast, routeBackOnError } = useI18nUIComponents();
|
||||
|
||||
const {
|
||||
editAccountId,
|
||||
clientSessionId,
|
||||
@@ -604,7 +613,7 @@ const allCurrencies = computed<LocalizedCurrencyInfo[]>(() => getAllCurrencies()
|
||||
|
||||
function formatAccountDisplayBalance(selectedAccount: Account): string {
|
||||
const balance = account.value.isLiability ? -selectedAccount.balance : selectedAccount.balance;
|
||||
return formatAmountWithCurrency(balance, selectedAccount.currency);
|
||||
return formatAmountToLocalizedNumeralsWithCurrency(balance, selectedAccount.currency);
|
||||
}
|
||||
|
||||
function formatAccountBalanceDate(account: Account): string {
|
||||
|
||||
@@ -76,8 +76,8 @@
|
||||
|
||||
<f7-list strong inset dividers class="margin-vertical" v-if="finishQuery && !loading">
|
||||
<f7-list-item :title="tt('Total Transactions')"
|
||||
:after="reconciliationStatements?.transactions.length"
|
||||
v-if="reconciliationStatements?.transactions.length"></f7-list-item>
|
||||
:after="formatNumberToLocalizedNumerals(reconciliationStatements.transactions.length)"
|
||||
v-if="reconciliationStatements && reconciliationStatements.transactions"></f7-list-item>
|
||||
<f7-list-item :title="tt('Total Inflows')" :after="displayTotalInflows"></f7-list-item>
|
||||
<f7-list-item :title="tt('Total Outflows')" :after="displayTotalOutflows"></f7-list-item>
|
||||
<f7-list-item :title="tt('Net Cash Flow')" :after="displayTotalBalance"></f7-list-item>
|
||||
@@ -386,7 +386,7 @@ const props = defineProps<{
|
||||
f7router: Router.Router;
|
||||
}>();
|
||||
|
||||
const { tt, getAllDateRanges, formatUnixTimeToLongDateTime } = useI18n();
|
||||
const { tt, getAllDateRanges, formatUnixTimeToLongDateTime, formatNumberToLocalizedNumerals } = useI18n();
|
||||
const { showAlert, showToast, routeBackOnError } = useI18nUIComponents();
|
||||
|
||||
const {
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
<f7-list strong inset dividers class="margin-vertical" v-if="exchangeRatesData && exchangeRatesData.exchangeRates && exchangeRatesData.exchangeRates.length">
|
||||
<f7-list-item swipeout
|
||||
:id="getExchangeRateDomId(exchangeRate)"
|
||||
:after="getFinalConvertedAmount(exchangeRate)"
|
||||
:after="getFinalConvertedAmount(exchangeRate, true)"
|
||||
:key="baseCurrencyChangedTime + '_' + exchangeRate.currencyCode" v-for="exchangeRate in availableExchangeRates"
|
||||
@swipeout:closed="onExchangeRateSwipeoutClosed()">
|
||||
<template #title>
|
||||
@@ -70,7 +70,7 @@
|
||||
<f7-swipeout-button color="primary" close
|
||||
:text="tt('Set as Base')"
|
||||
:class="{ 'disabled': exchangeRate.currencyCode === baseCurrency }"
|
||||
@click="setAsBaseline(exchangeRate.currencyCode, getFinalConvertedAmount(exchangeRate)); settingBaseLine = true"
|
||||
@click="setAsBaseline(exchangeRate.currencyCode, getFinalConvertedAmount(exchangeRate, false)); settingBaseLine = true"
|
||||
v-if="settingBaseLine || exchangeRate.currencyCode !== baseCurrency"></f7-swipeout-button>
|
||||
<f7-swipeout-button color="red" class="padding-left padding-right"
|
||||
@click="remove(exchangeRate, false)"
|
||||
@@ -134,6 +134,7 @@ import { useExchangeRatesPageBase } from '@/views/base/ExchangeRatesPageBase.ts'
|
||||
|
||||
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
||||
|
||||
import { NumeralSystem } from '@/core/numeral.ts';
|
||||
import { TRANSACTION_MIN_AMOUNT, TRANSACTION_MAX_AMOUNT } from '@/consts/transaction.ts';
|
||||
|
||||
import type { LocalizedLatestExchangeRate } from '@/models/exchange_rate.ts';
|
||||
@@ -146,8 +147,16 @@ const props = defineProps<{
|
||||
f7router: Router.Router;
|
||||
}>();
|
||||
|
||||
const { tt, getCurrencyName, formatAmount, formatExchangeRateAmount } = useI18n();
|
||||
const {
|
||||
tt,
|
||||
getCurrentNumeralSystemType,
|
||||
getCurrencyName,
|
||||
formatAmountToLocalizedNumerals,
|
||||
formatExchangeRateAmountToWesternArabicNumerals
|
||||
} = useI18n();
|
||||
|
||||
const { showAlert, showToast } = useI18nUIComponents();
|
||||
|
||||
const {
|
||||
baseCurrency,
|
||||
baseAmount,
|
||||
@@ -171,7 +180,7 @@ const showBaseAmountSheet = ref<boolean>(false);
|
||||
const customExchangeRateToDelete = ref<LocalizedLatestExchangeRate | null>(null);
|
||||
const showDeleteActionSheet = ref<boolean>(false);
|
||||
|
||||
const displayBaseAmount = computed<string>(() => formatAmount(baseAmount.value, baseCurrency.value));
|
||||
const displayBaseAmount = computed<string>(() => formatAmountToLocalizedNumerals(baseAmount.value, baseCurrency.value));
|
||||
const baseAmountFontSizeClass = computed<string>(() => {
|
||||
if (baseAmount.value >= 100000000 || baseAmount.value <= -100000000) {
|
||||
return 'ebk-small-amount';
|
||||
@@ -260,15 +269,26 @@ function remove(customExchangeRate: LocalizedLatestExchangeRate | null, confirm:
|
||||
});
|
||||
}
|
||||
|
||||
function getFinalConvertedAmount(toExchangeRate: LocalizedLatestExchangeRate): string {
|
||||
function getFinalConvertedAmount(toExchangeRate: LocalizedLatestExchangeRate, displayLocalizedDigits: boolean): string {
|
||||
const numeralSystem = getCurrentNumeralSystemType();
|
||||
const fromExchangeRate = exchangeRatesStore.latestExchangeRateMap[baseCurrency.value];
|
||||
const exchangeRateAmount = getConvertedAmount(baseAmount.value / 100, fromExchangeRate, toExchangeRate);
|
||||
|
||||
if (!exchangeRateAmount) {
|
||||
return '0';
|
||||
if (displayLocalizedDigits) {
|
||||
return numeralSystem.digitZero;
|
||||
} else {
|
||||
return NumeralSystem.WesternArabicNumerals.digitZero;
|
||||
}
|
||||
}
|
||||
|
||||
return formatExchangeRateAmount(exchangeRateAmount);
|
||||
let ret = formatExchangeRateAmountToWesternArabicNumerals(exchangeRateAmount);
|
||||
|
||||
if (displayLocalizedDigits) {
|
||||
ret = numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function onExchangeRateSwipeoutClosed(): void {
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
<template #title>
|
||||
<small>{{ currentLongYearMonth }}</small>
|
||||
<small class="transaction-amount-statistics">
|
||||
<span class="text-income">{{ `+${formatAmountWithCurrency('12345')}` }}</span>
|
||||
<span class="text-expense">{{ `-${formatAmountWithCurrency('67890')}` }}</span>
|
||||
<span class="text-income">{{ `+${formatAmountToLocalizedNumeralsWithCurrency(12345)}` }}</span>
|
||||
<span class="text-expense">{{ `-${formatAmountToLocalizedNumeralsWithCurrency(67890)}` }}</span>
|
||||
</small>
|
||||
<f7-icon class="combination-list-chevron-icon" f7="chevron_up"></f7-icon>
|
||||
</template>
|
||||
@@ -53,7 +53,7 @@
|
||||
</div>
|
||||
<div class="item-after">
|
||||
<div class="transaction-amount">
|
||||
<span>{{ formatAmountWithCurrency('12345') }}</span>
|
||||
<span>{{ formatAmountToLocalizedNumeralsWithCurrency(12345) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -128,7 +128,7 @@ const props = defineProps<{
|
||||
f7router: Router.Router;
|
||||
}>();
|
||||
|
||||
const { tt, getWeekdayShortName, formatUnixTimeToLongYearMonth, formatUnixTimeToShortTime, formatAmountWithCurrency } = useI18n();
|
||||
const { tt, getWeekdayShortName, formatUnixTimeToLongYearMonth, formatUnixTimeToShortTime, formatAmountToLocalizedNumeralsWithCurrency } = useI18n();
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@
|
||||
<template #title>
|
||||
<div class="statistics-list-item-text">
|
||||
<span>{{ item.name }}</span>
|
||||
<small class="statistics-percent" v-if="item.percent >= 0">{{ formatPercent(item.percent, 2, '<0.01') }}</small>
|
||||
<small class="statistics-percent" v-if="item.percent >= 0">{{ formatPercentToLocalizedNumerals(item.percent, 2, '<0.01') }}</small>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -367,7 +367,7 @@ const props = defineProps<{
|
||||
f7router: Router.Router;
|
||||
}>();
|
||||
|
||||
const { tt, getAllCategoricalChartTypes, formatPercent } = useI18n();
|
||||
const { tt, getAllCategoricalChartTypes, formatPercentToLocalizedNumerals } = useI18n();
|
||||
const { showPrompt, showToast, routeBackOnError } = useI18nUIComponents();
|
||||
|
||||
const {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
class="ebk-small-amount"
|
||||
link="#" no-chevron
|
||||
:header="amount1Header"
|
||||
:title="formatAmountWithCurrency(amount1)"
|
||||
:title="formatAmountToLocalizedNumeralsWithCurrency(amount1)"
|
||||
@click="showAmount1Sheet = true"
|
||||
>
|
||||
<number-pad-sheet :min-value="TRANSACTION_MIN_AMOUNT"
|
||||
@@ -27,7 +27,7 @@
|
||||
class="ebk-small-amount"
|
||||
link="#" no-chevron
|
||||
:header="amount2Header"
|
||||
:title="formatAmountWithCurrency(amount2)"
|
||||
:title="formatAmountToLocalizedNumeralsWithCurrency(amount2)"
|
||||
@click="showAmount2Sheet = true"
|
||||
v-if="amountCount === 2"
|
||||
>
|
||||
@@ -76,7 +76,7 @@ const amount2 = ref<number>(0);
|
||||
const showAmount1Sheet = ref<boolean>(false);
|
||||
const showAmount2Sheet = ref<boolean>(false);
|
||||
|
||||
const { tt, formatAmountWithCurrency } = useI18n();
|
||||
const { tt, formatAmountToLocalizedNumeralsWithCurrency } = useI18n();
|
||||
const { showToast } = useI18nUIComponents();
|
||||
|
||||
const transactionsStore = useTransactionsStore();
|
||||
|
||||
@@ -343,6 +343,26 @@
|
||||
</list-item-selection-popup>
|
||||
</f7-list-item>
|
||||
|
||||
<f7-list-item
|
||||
link="#"
|
||||
class="list-item-with-header-and-title list-item-no-item-after"
|
||||
:header="tt('Numeral System')"
|
||||
:title="findDisplayNameByType(allNumeralSystemTypes, newProfile.numeralSystem)"
|
||||
@click="showNumberSystemPopup = true"
|
||||
>
|
||||
<list-item-selection-popup value-type="item"
|
||||
key-field="type" value-field="type"
|
||||
title-field="displayName"
|
||||
:title="tt('Numeral System')"
|
||||
:enable-filter="true"
|
||||
:filter-placeholder="tt('Numeral System')"
|
||||
:filter-no-items-text="tt('No results')"
|
||||
:items="allNumeralSystemTypes"
|
||||
v-model:show="showNumberSystemPopup"
|
||||
v-model="newProfile.numeralSystem">
|
||||
</list-item-selection-popup>
|
||||
</f7-list-item>
|
||||
|
||||
<f7-list-item
|
||||
link="#"
|
||||
class="list-item-with-header-and-title list-item-no-item-after"
|
||||
@@ -536,10 +556,11 @@ const {
|
||||
allLongTimeFormats,
|
||||
allShortTimeFormats,
|
||||
allFiscalYearFormats,
|
||||
allCurrencyDisplayTypes,
|
||||
allNumeralSystemTypes,
|
||||
allDecimalSeparators,
|
||||
allDigitGroupingSymbols,
|
||||
allDigitGroupingTypes,
|
||||
allCurrencyDisplayTypes,
|
||||
allCoordinateDisplayTypes,
|
||||
allExpenseAmountColorTypes,
|
||||
allIncomeAmountColorTypes,
|
||||
@@ -577,6 +598,7 @@ const showLongTimeFormatPopup = ref<boolean>(false);
|
||||
const showShortTimeFormatPopup = ref<boolean>(false);
|
||||
const showFiscalYearFormatPopup = ref<boolean>(false);
|
||||
const showCurrencyDisplayTypePopup = ref<boolean>(false);
|
||||
const showNumberSystemPopup = ref<boolean>(false);
|
||||
const showDigitGroupingPopup = ref<boolean>(false);
|
||||
const showDigitGroupingSymbolPopup = ref<boolean>(false);
|
||||
const showDecimalSeparatorPopup = ref<boolean>(false);
|
||||
|
||||
Reference in New Issue
Block a user