support changing numeral system

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