digit grouping type supports Indian Number Grouping

This commit is contained in:
MaysWind
2025-08-15 23:58:15 +08:00
parent 2f8d4ad5e4
commit 274aa6a17c
19 changed files with 100 additions and 38 deletions
+7 -4
View File
@@ -69,10 +69,11 @@ type DigitGroupingType byte
// Digit Grouping Type
const (
DIGIT_GROUPING_TYPE_DEFAULT DigitGroupingType = 0
DIGIT_GROUPING_TYPE_NONE DigitGroupingType = 1
DIGIT_GROUPING_TYPE_THOUSANDS_SEPARATOR DigitGroupingType = 2
DIGIT_GROUPING_TYPE_INVALID DigitGroupingType = 255
DIGIT_GROUPING_TYPE_DEFAULT DigitGroupingType = 0
DIGIT_GROUPING_TYPE_NONE DigitGroupingType = 1
DIGIT_GROUPING_TYPE_THOUSANDS_SEPARATOR DigitGroupingType = 2
DIGIT_GROUPING_TYPE_INDIAN_NUMBER_GROUPING DigitGroupingType = 3
DIGIT_GROUPING_TYPE_INVALID DigitGroupingType = 255
)
// String returns a textual representation of the digit grouping type enum
@@ -84,6 +85,8 @@ func (d DigitGroupingType) String() string {
return "None"
case DIGIT_GROUPING_TYPE_THOUSANDS_SEPARATOR:
return "Thousands Separator"
case DIGIT_GROUPING_TYPE_INDIAN_NUMBER_GROUPING:
return "Indian Number Grouping"
case DIGIT_GROUPING_TYPE_INVALID:
return "Invalid"
default:
+1 -1
View File
@@ -200,7 +200,7 @@ type UserProfileUpdateRequest struct {
FiscalYearFormat *core.FiscalYearFormat `json:"fiscalYearFormat" binding:"omitempty,min=0,max=5"`
DecimalSeparator *core.DecimalSeparator `json:"decimalSeparator" binding:"omitempty,min=0,max=3"`
DigitGroupingSymbol *core.DigitGroupingSymbol `json:"digitGroupingSymbol" binding:"omitempty,min=0,max=4"`
DigitGrouping *core.DigitGroupingType `json:"digitGrouping" binding:"omitempty,min=0,max=2"`
DigitGrouping *core.DigitGroupingType `json:"digitGrouping" binding:"omitempty,min=0,max=3"`
CurrencyDisplayType *core.CurrencyDisplayType `json:"currencyDisplayType" binding:"omitempty,min=0,max=11"`
CoordinateDisplayType *core.CoordinateDisplayType `json:"coordinateDisplayType" binding:"omitempty,min=0,max=6"`
ExpenseAmountColor *AmountColorType `json:"expenseAmountColor" binding:"omitempty,min=0,max=4"`
+1 -1
View File
@@ -321,7 +321,7 @@ func (s *UserService) UpdateUser(c core.Context, user *models.User, modifyUserLa
updateCols = append(updateCols, "digit_grouping_symbol")
}
if core.DIGIT_GROUPING_TYPE_DEFAULT <= user.DigitGrouping && user.DigitGrouping <= core.DIGIT_GROUPING_TYPE_THOUSANDS_SEPARATOR {
if core.DIGIT_GROUPING_TYPE_DEFAULT <= user.DigitGrouping && user.DigitGrouping <= core.DIGIT_GROUPING_TYPE_INDIAN_NUMBER_GROUPING {
updateCols = append(updateCols, "digit_grouping")
}
+49 -3
View File
@@ -110,8 +110,52 @@ export class DigitGroupingType implements TypeAndName {
private static readonly allInstancesByTypeName: Record<string, DigitGroupingType> = {};
public static readonly LanguageDefaultType: number = 0;
public static readonly None = new DigitGroupingType(1, 'None', 'None', false);
public static readonly ThousandsSeparator = new DigitGroupingType(2, 'ThousandsSeparator', 'Thousands Separator', true);
public static readonly None = new DigitGroupingType(1, 'None', 'None', false,
(numericChars: string[]) => {
return numericChars.join('');
}
);
public static readonly ThousandsSeparator = new DigitGroupingType(2, 'ThousandsSeparator', 'Thousands Separator', true,
(numericChars: string[], digitGroupingSymbol: string) => {
if (numericChars.length <= 3) {
return numericChars.join('');
}
let ret = '';
for (let i = numericChars.length - 1, j = 0; i >= 0; i--, j++) {
if (j > 0 && j % 3 === 0) {
ret = digitGroupingSymbol + ret;
}
ret = numericChars[i] + ret;
}
return ret;
}
);
public static readonly IndianNumberGrouping = new DigitGroupingType(3, 'IndianNumberGrouping', 'Indian Number Grouping', true,
(numericChars: string[], digitGroupingSymbol: string) => {
if (numericChars.length <= 3) {
return numericChars.join('');
}
let ret = '';
const length = numericChars.length;
for (let i = length - 1, j = 0; i >= 0; i--, j++) {
if (j === 3) {
ret = digitGroupingSymbol + ret;
} else if (j > 3 && (j - 3) % 2 === 0) {
ret = digitGroupingSymbol + ret;
}
ret = numericChars[i] + ret;
}
return ret;
}
);
public static readonly Default = DigitGroupingType.ThousandsSeparator;
@@ -119,12 +163,14 @@ export class DigitGroupingType implements TypeAndName {
public readonly typeName: string;
public readonly name: string;
public readonly enabled: boolean;
public readonly format: (numericChars: string[], digitGroupingSymbol: string) => string;
private constructor(type: number, typeName: string, name: string, enabled: boolean) {
private constructor(type: number, typeName: string, name: string, enabled: boolean, format: (numericChars: string[], digitGroupingSymbol: string) => string) {
this.type = type;
this.typeName = typeName;
this.name = name;
this.enabled = enabled;
this.format = format;
DigitGroupingType.allInstances.push(this);
DigitGroupingType.allInstancesByType[type] = this;
+13 -13
View File
@@ -30,11 +30,17 @@ export function appendDigitGroupingSymbol(value: number | string, options: Numbe
options = {};
}
if (!isNumber(options.digitGrouping) || options.digitGrouping === DigitGroupingType.None.type) {
if (!isNumber(options.digitGrouping)) {
return textualValue;
}
if (textualValue.length <= 3) {
const digitGroupingType = DigitGroupingType.valueOf(options.digitGrouping);
if (!digitGroupingType || !digitGroupingType.enabled) {
return textualValue;
}
if (textualValue.length <= 1) {
return textualValue;
}
@@ -44,6 +50,10 @@ export function appendDigitGroupingSymbol(value: number | string, options: Numbe
textualValue = textualValue.substring(1);
}
if (textualValue.length <= 1) {
return textualValue;
}
const digitGroupingSymbol = options.digitGroupingSymbol || DigitGroupingSymbol.Default.symbol;
const decimalSeparator = options.decimalSeparator || DecimalSeparator.Default.symbol;
@@ -63,17 +73,7 @@ export function appendDigitGroupingSymbol(value: number | string, options: Numbe
}
}
let newInteger = '';
if (options.digitGrouping === DigitGroupingType.ThousandsSeparator.type) {
for (let i = integerChars.length - 1, j = 0; i >= 0; i--, j++) {
if (j % 3 === 0 && j > 0) {
newInteger = digitGroupingSymbol + newInteger;
}
newInteger = integerChars[i] + newInteger;
}
}
let newInteger = digitGroupingType.format(integerChars, digitGroupingSymbol);
if (negative) {
newInteger = `-${newInteger}`;
+2 -1
View File
@@ -265,7 +265,8 @@
"Space": "Leerzeichen",
"Apostrophe": "Apostroph",
"None": "Keine",
"Thousands Separator": "Tausender Trennzeichen"
"Thousands Separator": "Tausender Trennzeichen",
"Indian Number Grouping": "Indian Number Grouping"
},
"color": {
"amount": {
+2 -1
View File
@@ -265,7 +265,8 @@
"Space": "Space",
"Apostrophe": "Apostrophe",
"None": "None",
"Thousands Separator": "Thousands Separator"
"Thousands Separator": "Thousands Separator",
"Indian Number Grouping": "Indian Number Grouping"
},
"color": {
"amount": {
+2 -1
View File
@@ -265,7 +265,8 @@
"Space": "Espacio",
"Apostrophe": "Apóstrofe",
"None": "Ninguno",
"Thousands Separator": "Separador de miles"
"Thousands Separator": "Separador de miles",
"Indian Number Grouping": "Indian Number Grouping"
},
"color": {
"amount": {
+3 -2
View File
@@ -1030,7 +1030,7 @@ export function useI18n() {
return ret;
}
function getAllDigitGroupingTypes(): LocalizedDigitGroupingType[] {
function getAllDigitGroupingTypes(digitGroupingSymbol: string): LocalizedDigitGroupingType[] {
const defaultDigitGroupingTypeName = t('default.digitGrouping');
let defaultDigitGroupingType = DigitGroupingType.parse(defaultDigitGroupingTypeName);
@@ -1050,11 +1050,12 @@ export function useI18n() {
for (let i = 0; i < allDigitGroupingTypes.length; i++) {
const type = allDigitGroupingTypes[i];
const sampleValue = type.format('123456789'.split(''), digitGroupingSymbol);
ret.push({
type: type.type,
enabled: type.enabled,
displayName: t('numeral.' + type.name)
displayName: `${t('numeral.' + type.name)} (${sampleValue})`
});
}
+2 -1
View File
@@ -265,7 +265,8 @@
"Space": "Spazio",
"Apostrophe": "Apostrofo",
"None": "Nulla",
"Thousands Separator": "Separatore migliaia"
"Thousands Separator": "Separatore migliaia",
"Indian Number Grouping": "Indian Number Grouping"
},
"color": {
"amount": {
+2 -1
View File
@@ -265,7 +265,8 @@
"Space": "スペース",
"Apostrophe": "アポストロフィ",
"None": "なし",
"Thousands Separator": "千の桁区切り"
"Thousands Separator": "千の桁区切り",
"Indian Number Grouping": "Indian Number Grouping"
},
"color": {
"amount": {
+2 -1
View File
@@ -265,7 +265,8 @@
"Space": "Spatie",
"Apostrophe": "Apostrof",
"None": "Geen",
"Thousands Separator": "Scheidingsteken voor duizendtallen"
"Thousands Separator": "Scheidingsteken voor duizendtallen",
"Indian Number Grouping": "Indian Number Grouping"
},
"color": {
"amount": {
+2 -1
View File
@@ -265,7 +265,8 @@
"Space": "Espaço",
"Apostrophe": "Apóstrofo",
"None": "Nenhum",
"Thousands Separator": "Separador de Milhares"
"Thousands Separator": "Separador de Milhares",
"Indian Number Grouping": "Indian Number Grouping"
},
"color": {
"amount": {
+2 -1
View File
@@ -265,7 +265,8 @@
"Space": "Пробел",
"Apostrophe": "Апостроф",
"None": "Нет",
"Thousands Separator": "Разделитель тысяч"
"Thousands Separator": "Разделитель тысяч",
"Indian Number Grouping": "Indian Number Grouping"
},
"color": {
"amount": {
+2 -1
View File
@@ -265,7 +265,8 @@
"Space": "Пробіл",
"Apostrophe": "Апостроф",
"None": "Немає",
"Thousands Separator": "Роздільник тисяч"
"Thousands Separator": "Роздільник тисяч",
"Indian Number Grouping": "Indian Number Grouping"
},
"color": {
"amount": {
+2 -1
View File
@@ -265,7 +265,8 @@
"Space": "Khoảng trắng",
"Apostrophe": "Dấu nháy đơn",
"None": "Không có",
"Thousands Separator": "Dấu phân cách hàng nghìn"
"Thousands Separator": "Dấu phân cách hàng nghìn",
"Indian Number Grouping": "Indian Number Grouping"
},
"color": {
"amount": {
+2 -1
View File
@@ -265,7 +265,8 @@
"Space": "空格",
"Apostrophe": "撇号",
"None": "无",
"Thousands Separator": "千位分隔符"
"Thousands Separator": "千位分隔符",
"Indian Number Grouping": "印度数字分组"
},
"color": {
"amount": {
+2 -1
View File
@@ -265,7 +265,8 @@
"Space": "空格",
"Apostrophe": "撇號",
"None": "無",
"Thousands Separator": "千位分隔符"
"Thousands Separator": "千位分隔符",
"Indian Number Grouping": "印度數字分組"
},
"color": {
"amount": {
+2 -2
View File
@@ -8,7 +8,7 @@ import { useOverviewStore } from '@/stores/overview.ts';
import type { TypeAndDisplayName } from '@/core/base.ts';
import { WeekDay } from '@/core/datetime.ts';
import type { LocalizedDigitGroupingType } from '@/core/numeral.ts';
import { type LocalizedDigitGroupingType, DigitGroupingSymbol } from '@/core/numeral.ts';
import { type UserBasicInfo, User } from '@/models/user.ts';
import { type CategorizedAccount, Account} from '@/models/account.ts';
@@ -64,7 +64,7 @@ export function useUserProfilePageBase() {
const allFiscalYearFormats = computed<TypeAndDisplayName[]>(() => getAllFiscalYearFormats());
const allDecimalSeparators = computed<TypeAndDisplayName[]>(() => getAllDecimalSeparators());
const allDigitGroupingSymbols = computed<TypeAndDisplayName[]>(() => getAllDigitGroupingSymbols());
const allDigitGroupingTypes = computed<LocalizedDigitGroupingType[]>(() => getAllDigitGroupingTypes());
const allDigitGroupingTypes = computed<LocalizedDigitGroupingType[]>(() => getAllDigitGroupingTypes(DigitGroupingSymbol.valueOf(newProfile.value.digitGroupingSymbol)?.symbol || DigitGroupingSymbol.Default.symbol));
const allCurrencyDisplayTypes = computed<TypeAndDisplayName[]>(() => getAllCurrencyDisplayTypes());
const allCoordinateDisplayTypes = computed<TypeAndDisplayName[]>(() => getAllCoordinateDisplayTypes());
const allExpenseAmountColorTypes = computed<TypeAndDisplayName[]>(() => getAllExpenseAmountColors());