792 lines
31 KiB
JavaScript
792 lines
31 KiB
JavaScript
import { DEFAULT_LANGUAGE, ALL_LANGUAGES } from '@/locales/index.ts';
|
|
|
|
import { WeekDay, LongDateFormat, ShortDateFormat, LongTimeFormat, ShortTimeFormat, DateRange } from '@/core/datetime.ts';
|
|
import { DecimalSeparator, DigitGroupingSymbol, DigitGroupingType } from '@/core/numeral.ts';
|
|
import { CurrencyDisplayType } from '@/core/currency.ts'
|
|
import { AccountCategory } from '@/core/account.ts';
|
|
import { TransactionTagFilterType } from '@/core/transaction.ts';
|
|
|
|
import { UTC_TIMEZONE, ALL_TIMEZONES } from '@/consts/timezone.ts';
|
|
import { ALL_CURRENCIES } from '@/consts/currency.ts';
|
|
import { SUPPORTED_IMPORT_FILE_TYPES } from '@/consts/file.ts';
|
|
import { KnownErrorCode, SPECIFIED_API_NOT_FOUND_ERRORS, PARAMETERIZED_ERRORS } from '@/consts/api.ts';
|
|
|
|
import {
|
|
isString,
|
|
isNumber,
|
|
isBoolean,
|
|
copyObjectTo
|
|
} from '@/lib/common.ts';
|
|
|
|
import {
|
|
parseDateFromUnixTime,
|
|
formatUnixTime,
|
|
getYear,
|
|
getTimezoneOffset,
|
|
getTimezoneOffsetMinutes,
|
|
getBrowserTimezoneOffset,
|
|
getBrowserTimezoneOffsetMinutes,
|
|
getTimeDifferenceHoursAndMinutes,
|
|
getDateTimeFormatType,
|
|
getRecentMonthDateRanges,
|
|
isDateRangeMatchFullYears,
|
|
isDateRangeMatchFullMonths
|
|
} from '@/lib/datetime.ts';
|
|
|
|
import {
|
|
formatAmount,
|
|
getAdaptiveDisplayAmountRate
|
|
} from '@/lib/numeral.ts';
|
|
|
|
import {
|
|
getCurrencyFraction,
|
|
appendCurrencySymbol
|
|
} from '@/lib/currency.ts';
|
|
|
|
import {
|
|
getCategorizedAccountsMap,
|
|
getAllFilteredAccountsBalance
|
|
} from '@/lib/account.ts';
|
|
|
|
function getLanguageDisplayName(translateFn, languageName) {
|
|
return translateFn(`language.${languageName}`);
|
|
}
|
|
|
|
function getCurrentLanguageTag(i18nGlobal) {
|
|
return i18nGlobal.locale;
|
|
}
|
|
|
|
function getLocalizedDisplayNameAndType(typeAndNames, translateFn) {
|
|
const ret = [];
|
|
|
|
for (let i = 0; i < typeAndNames.length; i++) {
|
|
const nameAndType = typeAndNames[i];
|
|
|
|
ret.push({
|
|
type: nameAndType.type,
|
|
displayName: translateFn(nameAndType.name)
|
|
});
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getCurrencyName(currencyCode, translateFn) {
|
|
return translateFn(`currency.name.${currencyCode}`);
|
|
}
|
|
|
|
function getCurrencyUnitName(currencyCode, isPlural, translateFn) {
|
|
const currencyInfo = ALL_CURRENCIES[currencyCode];
|
|
|
|
if (currencyInfo && currencyInfo.unit) {
|
|
if (isPlural) {
|
|
return translateFn(`currency.unit.${currencyInfo.unit}.plural`);
|
|
} else {
|
|
return translateFn(`currency.unit.${currencyInfo.unit}.normal`);
|
|
}
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
function getMonthdayOrdinal(monthDay, translateFn) {
|
|
return translateFn(`datetime.monthDayOrdinal.${monthDay}`);
|
|
}
|
|
|
|
function getWeekdayShortName(weekDayName, translateFn) {
|
|
return translateFn(`datetime.${weekDayName}.short`);
|
|
}
|
|
|
|
function getWeekdayLongName(weekDayName, translateFn) {
|
|
return translateFn(`datetime.${weekDayName}.long`);
|
|
}
|
|
|
|
function getMultiMonthdayShortNames(monthDays, translateFn) {
|
|
if (!monthDays) {
|
|
return '';
|
|
}
|
|
|
|
if (monthDays.length === 1) {
|
|
return translateFn('format.misc.monthDay', {
|
|
ordinal: getMonthdayOrdinal(monthDays[0], translateFn)
|
|
});
|
|
} else {
|
|
return translateFn('format.misc.monthDays', {
|
|
multiMonthDays: joinMultiText(monthDays.map(monthDay =>
|
|
translateFn('format.misc.eachMonthDayInMonthDays', {
|
|
ordinal: getMonthdayOrdinal(monthDay, translateFn)
|
|
})), translateFn)
|
|
});
|
|
}
|
|
}
|
|
|
|
function getMultiWeekdayLongNames(weekdayTypes, firstDayOfWeek, translateFn) {
|
|
const weekdayTypesMap = {};
|
|
|
|
if (!isNumber(firstDayOfWeek)) {
|
|
firstDayOfWeek = WeekDay.DefaultFirstDay.type;
|
|
}
|
|
|
|
for (let i = 0; i < weekdayTypes.length; i++) {
|
|
weekdayTypesMap[weekdayTypes[i]] = true;
|
|
}
|
|
|
|
const allWeekDays = getAllWeekDays(firstDayOfWeek, translateFn);
|
|
const finalWeekdayNames = [];
|
|
|
|
for (let i = 0; i < allWeekDays.length; i++) {
|
|
const weekDay = allWeekDays[i];
|
|
|
|
if (weekdayTypesMap[weekDay.type]) {
|
|
finalWeekdayNames.push(weekDay.displayName);
|
|
}
|
|
}
|
|
|
|
return joinMultiText(finalWeekdayNames, translateFn);
|
|
}
|
|
|
|
function getI18nLongDateFormat(translateFn, formatTypeValue) {
|
|
const defaultLongDateFormatTypeName = translateFn('default.longDateFormat');
|
|
return getDateTimeFormat(translateFn, LongDateFormat.all(), LongDateFormat.values(), 'format.longDate', defaultLongDateFormatTypeName, LongDateFormat.Default, formatTypeValue);
|
|
}
|
|
|
|
function getI18nShortDateFormat(translateFn, formatTypeValue) {
|
|
const defaultShortDateFormatTypeName = translateFn('default.shortDateFormat');
|
|
return getDateTimeFormat(translateFn, ShortDateFormat.all(), ShortDateFormat.values(), 'format.shortDate', defaultShortDateFormatTypeName, ShortDateFormat.Default, formatTypeValue);
|
|
}
|
|
|
|
function getI18nLongYearFormat(translateFn, formatTypeValue) {
|
|
const defaultLongDateFormatTypeName = translateFn('default.longDateFormat');
|
|
return getDateTimeFormat(translateFn, LongDateFormat.all(), LongDateFormat.values(), 'format.longYear', defaultLongDateFormatTypeName, LongDateFormat.Default, formatTypeValue);
|
|
}
|
|
|
|
function getI18nShortYearFormat(translateFn, formatTypeValue) {
|
|
const defaultShortDateFormatTypeName = translateFn('default.shortDateFormat');
|
|
return getDateTimeFormat(translateFn, ShortDateFormat.all(), ShortDateFormat.values(), 'format.shortYear', defaultShortDateFormatTypeName, ShortDateFormat.Default, formatTypeValue);
|
|
}
|
|
|
|
function getI18nLongYearMonthFormat(translateFn, formatTypeValue) {
|
|
const defaultLongDateFormatTypeName = translateFn('default.longDateFormat');
|
|
return getDateTimeFormat(translateFn, LongDateFormat.all(), LongDateFormat.values(), 'format.longYearMonth', defaultLongDateFormatTypeName, LongDateFormat.Default, formatTypeValue);
|
|
}
|
|
|
|
function getI18nShortYearMonthFormat(translateFn, formatTypeValue) {
|
|
const defaultShortDateFormatTypeName = translateFn('default.shortDateFormat');
|
|
return getDateTimeFormat(translateFn, ShortDateFormat.all(), ShortDateFormat.values(), 'format.shortYearMonth', defaultShortDateFormatTypeName, ShortDateFormat.Default, formatTypeValue);
|
|
}
|
|
|
|
function getI18nLongMonthDayFormat(translateFn, formatTypeValue) {
|
|
const defaultLongDateFormatTypeName = translateFn('default.longDateFormat');
|
|
return getDateTimeFormat(translateFn, LongDateFormat.all(), LongDateFormat.values(), 'format.longMonthDay', defaultLongDateFormatTypeName, LongDateFormat.Default, formatTypeValue);
|
|
}
|
|
|
|
function getI18nShortMonthDayFormat(translateFn, formatTypeValue) {
|
|
const defaultShortDateFormatTypeName = translateFn('default.shortDateFormat');
|
|
return getDateTimeFormat(translateFn, ShortDateFormat.all(), ShortDateFormat.values(), 'format.shortMonthDay', defaultShortDateFormatTypeName, ShortDateFormat.Default, formatTypeValue);
|
|
}
|
|
|
|
function getI18nLongTimeFormat(translateFn, formatTypeValue) {
|
|
const defaultLongTimeFormatTypeName = translateFn('default.longTimeFormat');
|
|
return getDateTimeFormat(translateFn, LongTimeFormat.all(), LongTimeFormat.values(), 'format.longTime', defaultLongTimeFormatTypeName, LongTimeFormat.Default, formatTypeValue);
|
|
}
|
|
|
|
function getI18nShortTimeFormat(translateFn, formatTypeValue) {
|
|
const defaultShortTimeFormatTypeName = translateFn('default.shortTimeFormat');
|
|
return getDateTimeFormat(translateFn, ShortTimeFormat.all(), ShortTimeFormat.values(), 'format.shortTime', defaultShortTimeFormatTypeName, ShortTimeFormat.Default, formatTypeValue);
|
|
}
|
|
|
|
function getDateTimeFormat(translateFn, allFormatMap, allFormatArray, localeFormatPathPrefix, localeDefaultFormatTypeName, systemDefaultFormatType, formatTypeValue) {
|
|
const type = getDateTimeFormatType(allFormatMap, allFormatArray, formatTypeValue, localeDefaultFormatTypeName, systemDefaultFormatType);
|
|
return translateFn(`${localeFormatPathPrefix}.${type.key}`);
|
|
}
|
|
|
|
function getAllTimezones(includeSystemDefault, translateFn) {
|
|
const defaultTimezoneOffset = getBrowserTimezoneOffset();
|
|
const defaultTimezoneOffsetMinutes = getBrowserTimezoneOffsetMinutes();
|
|
const allTimezoneInfos = [];
|
|
|
|
for (let i = 0; i < ALL_TIMEZONES.length; i++) {
|
|
const utcOffset = (ALL_TIMEZONES[i].timezoneName !== UTC_TIMEZONE.timezoneName ? getTimezoneOffset(ALL_TIMEZONES[i].timezoneName) : '');
|
|
const displayName = translateFn(`timezone.${ALL_TIMEZONES[i].displayName}`);
|
|
|
|
allTimezoneInfos.push({
|
|
name: ALL_TIMEZONES[i].timezoneName,
|
|
utcOffset: utcOffset,
|
|
utcOffsetMinutes: getTimezoneOffsetMinutes(ALL_TIMEZONES[i].timezoneName),
|
|
displayName: displayName,
|
|
displayNameWithUtcOffset: `(UTC${utcOffset}) ${displayName}`
|
|
});
|
|
}
|
|
|
|
if (includeSystemDefault) {
|
|
const defaultDisplayName = translateFn('System Default');
|
|
|
|
allTimezoneInfos.push({
|
|
name: '',
|
|
utcOffset: defaultTimezoneOffset,
|
|
utcOffsetMinutes: defaultTimezoneOffsetMinutes,
|
|
displayName: defaultDisplayName,
|
|
displayNameWithUtcOffset: `(UTC${defaultTimezoneOffset}) ${defaultDisplayName}`
|
|
});
|
|
}
|
|
|
|
allTimezoneInfos.sort(function(c1, c2) {
|
|
const utcOffset1 = parseInt(c1.utcOffset.replace(':', ''));
|
|
const utcOffset2 = parseInt(c2.utcOffset.replace(':', ''));
|
|
|
|
if (utcOffset1 !== utcOffset2) {
|
|
return utcOffset1 - utcOffset2;
|
|
}
|
|
|
|
return c1.displayName.localeCompare(c2.displayName);
|
|
})
|
|
|
|
return allTimezoneInfos;
|
|
}
|
|
|
|
function getTimezoneDifferenceDisplayText(utcOffset, translateFn) {
|
|
const defaultTimezoneOffset = getTimezoneOffsetMinutes();
|
|
const offsetTime = getTimeDifferenceHoursAndMinutes(utcOffset - defaultTimezoneOffset);
|
|
|
|
if (utcOffset > defaultTimezoneOffset) {
|
|
if (offsetTime.offsetMinutes) {
|
|
return translateFn('format.misc.hoursMinutesAheadOfDefaultTimezone', {
|
|
hours: offsetTime.offsetHours,
|
|
minutes: offsetTime.offsetMinutes
|
|
});
|
|
} else {
|
|
return translateFn('format.misc.hoursAheadOfDefaultTimezone', {
|
|
hours: offsetTime.offsetHours
|
|
});
|
|
}
|
|
} else if (utcOffset < defaultTimezoneOffset) {
|
|
if (offsetTime.offsetMinutes) {
|
|
return translateFn('format.misc.hoursMinutesBehindDefaultTimezone', {
|
|
hours: offsetTime.offsetHours,
|
|
minutes: offsetTime.offsetMinutes
|
|
});
|
|
} else {
|
|
return translateFn('format.misc.hoursBehindDefaultTimezone', {
|
|
hours: offsetTime.offsetHours
|
|
});
|
|
}
|
|
} else {
|
|
return translateFn('Same time as default timezone');
|
|
}
|
|
}
|
|
|
|
function getAllWeekDays(firstDayOfWeek, translateFn) {
|
|
const ret = [];
|
|
const allWeekDays = WeekDay.values();
|
|
|
|
if (!isNumber(firstDayOfWeek)) {
|
|
firstDayOfWeek = WeekDay.DefaultFirstDay.type;
|
|
}
|
|
|
|
for (let i = firstDayOfWeek; i < allWeekDays.length; i++) {
|
|
const weekDay = allWeekDays[i];
|
|
|
|
ret.push({
|
|
type: weekDay.type,
|
|
displayName: translateFn(`datetime.${weekDay.name}.long`)
|
|
});
|
|
}
|
|
|
|
for (let i = 0; i < firstDayOfWeek; i++) {
|
|
const weekDay = allWeekDays[i];
|
|
|
|
ret.push({
|
|
type: weekDay.type,
|
|
displayName: translateFn(`datetime.${weekDay.name}.long`)
|
|
});
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getAllDateRanges(scene, includeCustom, includeBillingCycle, translateFn) {
|
|
const ret = [];
|
|
const allDateRanges = DateRange.values();
|
|
|
|
for (let i = 0; i < allDateRanges.length; i++) {
|
|
const dateRange = allDateRanges[i];
|
|
|
|
if (!dateRange.isAvailableForScene(scene)) {
|
|
continue;
|
|
}
|
|
|
|
if (dateRange.isBillingCycle) {
|
|
if (includeBillingCycle) {
|
|
ret.push({
|
|
type: dateRange.type,
|
|
displayName: translateFn(dateRange.name),
|
|
isBillingCycle: dateRange.isBillingCycle
|
|
});
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (includeCustom || dateRange.type !== DateRange.Custom.type) {
|
|
ret.push({
|
|
type: dateRange.type,
|
|
displayName: translateFn(dateRange.name)
|
|
});
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getAllRecentMonthDateRanges(userStore, includeAll, includeCustom, translateFn) {
|
|
const allRecentMonthDateRanges = [];
|
|
const recentDateRanges = getRecentMonthDateRanges(12);
|
|
|
|
if (includeAll) {
|
|
allRecentMonthDateRanges.push({
|
|
dateType: DateRange.All.type,
|
|
minTime: 0,
|
|
maxTime: 0,
|
|
displayName: translateFn('All')
|
|
});
|
|
}
|
|
|
|
for (let i = 0; i < recentDateRanges.length; i++) {
|
|
const recentDateRange = recentDateRanges[i];
|
|
|
|
allRecentMonthDateRanges.push({
|
|
dateType: recentDateRange.dateType,
|
|
minTime: recentDateRange.minTime,
|
|
maxTime: recentDateRange.maxTime,
|
|
year: recentDateRange.year,
|
|
month: recentDateRange.month,
|
|
isPreset: true,
|
|
displayName: formatUnixTime(recentDateRange.minTime, getI18nLongYearMonthFormat(translateFn, userStore.currentUserLongDateFormat))
|
|
});
|
|
}
|
|
|
|
if (includeCustom) {
|
|
allRecentMonthDateRanges.push({
|
|
dateType: DateRange.Custom.type,
|
|
minTime: 0,
|
|
maxTime: 0,
|
|
displayName: translateFn('Custom Date')
|
|
});
|
|
}
|
|
|
|
return allRecentMonthDateRanges;
|
|
}
|
|
|
|
function getDateRangeDisplayName(userStore, dateType, startTime, endTime, translateFn) {
|
|
if (dateType === DateRange.All.type) {
|
|
return translateFn(DateRange.All.name);
|
|
}
|
|
|
|
const allDateRanges = DateRange.values();
|
|
|
|
for (let i = 0; i < allDateRanges.length; i++) {
|
|
const dateRange = allDateRanges[i];
|
|
|
|
if (dateRange && dateRange.type !== DateRange.Custom.type && dateRange.type === dateType && dateRange.name) {
|
|
return translateFn(dateRange.name);
|
|
}
|
|
}
|
|
|
|
if (isDateRangeMatchFullYears(startTime, endTime)) {
|
|
const displayStartTime = formatUnixTime(startTime, getI18nShortYearFormat(translateFn, userStore.currentUserShortDateFormat));
|
|
const displayEndTime = formatUnixTime(endTime, getI18nShortYearFormat(translateFn, userStore.currentUserShortDateFormat));
|
|
|
|
return displayStartTime !== displayEndTime ? `${displayStartTime} ~ ${displayEndTime}` : displayStartTime;
|
|
}
|
|
|
|
if (isDateRangeMatchFullMonths(startTime, endTime)) {
|
|
const displayStartTime = formatUnixTime(startTime, getI18nShortYearMonthFormat(translateFn, userStore.currentUserShortDateFormat));
|
|
const displayEndTime = formatUnixTime(endTime, getI18nShortYearMonthFormat(translateFn, userStore.currentUserShortDateFormat));
|
|
|
|
return displayStartTime !== displayEndTime ? `${displayStartTime} ~ ${displayEndTime}` : displayStartTime;
|
|
}
|
|
|
|
const startTimeYear = getYear(parseDateFromUnixTime(startTime));
|
|
const endTimeYear = getYear(parseDateFromUnixTime(endTime));
|
|
|
|
const displayStartTime = formatUnixTime(startTime, getI18nShortDateFormat(translateFn, userStore.currentUserShortDateFormat));
|
|
const displayEndTime = formatUnixTime(endTime, getI18nShortDateFormat(translateFn, userStore.currentUserShortDateFormat));
|
|
|
|
if (displayStartTime === displayEndTime) {
|
|
return displayStartTime;
|
|
} else if (startTimeYear === endTimeYear) {
|
|
const displayShortEndTime = formatUnixTime(endTime, getI18nShortMonthDayFormat(translateFn, userStore.currentUserShortDateFormat));
|
|
return `${displayStartTime} ~ ${displayShortEndTime}`;
|
|
}
|
|
|
|
return `${displayStartTime} ~ ${displayEndTime}`;
|
|
}
|
|
|
|
function getCurrentDecimalSeparator(translateFn, decimalSeparator) {
|
|
let decimalSeparatorType = DecimalSeparator.valueOf(decimalSeparator);
|
|
|
|
if (!decimalSeparatorType) {
|
|
const defaultDecimalSeparatorTypeName = translateFn('default.decimalSeparator');
|
|
decimalSeparatorType = DecimalSeparator.parse(defaultDecimalSeparatorTypeName);
|
|
|
|
if (!decimalSeparatorType) {
|
|
decimalSeparatorType = DecimalSeparator.Default;
|
|
}
|
|
}
|
|
|
|
return decimalSeparatorType.symbol;
|
|
}
|
|
|
|
function getCurrentDigitGroupingSymbol(translateFn, digitGroupingSymbol) {
|
|
let digitGroupingSymbolType = DigitGroupingSymbol.valueOf(digitGroupingSymbol);
|
|
|
|
if (!digitGroupingSymbolType) {
|
|
const defaultDigitGroupingSymbolTypeName = translateFn('default.digitGroupingSymbol');
|
|
digitGroupingSymbolType = DigitGroupingSymbol.parse(defaultDigitGroupingSymbolTypeName);
|
|
|
|
if (!digitGroupingSymbolType) {
|
|
digitGroupingSymbolType = DigitGroupingSymbol.Default;
|
|
}
|
|
}
|
|
|
|
return digitGroupingSymbolType.symbol;
|
|
}
|
|
|
|
function getCurrentDigitGroupingType(translateFn, digitGrouping) {
|
|
let digitGroupingType = DigitGroupingType.valueOf(digitGrouping);
|
|
|
|
if (!digitGroupingType) {
|
|
const defaultDigitGroupingTypeName = translateFn('default.digitGrouping');
|
|
digitGroupingType = DigitGroupingType.parse(defaultDigitGroupingTypeName);
|
|
|
|
if (!digitGroupingType) {
|
|
digitGroupingType = DigitGroupingType.Default;
|
|
}
|
|
}
|
|
|
|
return digitGroupingType.type;
|
|
}
|
|
|
|
function getNumberFormatOptions(translateFn, userStore, currencyCode) {
|
|
return {
|
|
decimalSeparator: getCurrentDecimalSeparator(translateFn, userStore.currentUserDecimalSeparator),
|
|
decimalNumberCount: getCurrencyFraction(currencyCode),
|
|
digitGroupingSymbol: getCurrentDigitGroupingSymbol(translateFn, userStore.currentUserDigitGroupingSymbol),
|
|
digitGrouping: getCurrentDigitGroupingType(translateFn, userStore.currentUserDigitGrouping),
|
|
};
|
|
}
|
|
|
|
function getFormattedAmount(value, translateFn, userStore, currencyCode) {
|
|
const numberFormatOptions = getNumberFormatOptions(translateFn, userStore, currencyCode);
|
|
return formatAmount(value, numberFormatOptions);
|
|
}
|
|
|
|
function getCurrentCurrencyDisplayType(translateFn, userStore) {
|
|
let currencyDisplayType = CurrencyDisplayType.valueOf(userStore.currentUserCurrencyDisplayType);
|
|
|
|
if (!currencyDisplayType) {
|
|
const defaultCurrencyDisplayTypeName = translateFn('default.currencyDisplayType');
|
|
currencyDisplayType = CurrencyDisplayType.parse(defaultCurrencyDisplayTypeName);
|
|
}
|
|
|
|
if (!currencyDisplayType) {
|
|
currencyDisplayType = CurrencyDisplayType.Default;
|
|
}
|
|
|
|
return currencyDisplayType;
|
|
}
|
|
|
|
function getFormattedAmountWithCurrency(value, currencyCode, translateFn, userStore, settingsStore, notConvertValue, currencyDisplayType) {
|
|
if (!isNumber(value) && !isString(value)) {
|
|
return value;
|
|
}
|
|
|
|
if (isNumber(value)) {
|
|
value = value.toString();
|
|
}
|
|
|
|
const isPlural = value !== '100' && value !== '-100';
|
|
|
|
if (!notConvertValue) {
|
|
const numberFormatOptions = getNumberFormatOptions(translateFn, userStore, currencyCode);
|
|
const hasIncompleteFlag = isString(value) && value.charAt(value.length - 1) === '+';
|
|
|
|
if (hasIncompleteFlag) {
|
|
value = value.substring(0, value.length - 1);
|
|
}
|
|
|
|
value = formatAmount(value, numberFormatOptions);
|
|
|
|
if (hasIncompleteFlag) {
|
|
value = value + '+';
|
|
}
|
|
}
|
|
|
|
if (!isBoolean(currencyCode) && !currencyCode) {
|
|
currencyCode = userStore.currentUserDefaultCurrency;
|
|
} else if (isBoolean(currencyCode) && !currencyCode) {
|
|
currencyCode = '';
|
|
}
|
|
|
|
if (!currencyCode) {
|
|
return value;
|
|
}
|
|
|
|
if (!currencyDisplayType) {
|
|
currencyDisplayType = getCurrentCurrencyDisplayType(translateFn, userStore);
|
|
}
|
|
|
|
const currencyUnit = getCurrencyUnitName(currencyCode, isPlural, translateFn);
|
|
const currencyName = getCurrencyName(currencyCode, translateFn);
|
|
return appendCurrencySymbol(value, currencyDisplayType, currencyCode, currencyUnit, currencyName, isPlural);
|
|
}
|
|
|
|
function getAdaptiveAmountRate(amount1, amount2, fromExchangeRate, toExchangeRate, translateFn, userStore) {
|
|
const numberFormatOptions = getNumberFormatOptions(translateFn, userStore);
|
|
return getAdaptiveDisplayAmountRate(amount1, amount2, fromExchangeRate, toExchangeRate, numberFormatOptions);
|
|
}
|
|
|
|
function getAllTransactionTagFilterTypes(translateFn) {
|
|
return getLocalizedDisplayNameAndType(TransactionTagFilterType.values(), translateFn);
|
|
}
|
|
|
|
function getAllSupportedImportFileTypes(i18nGlobal, translateFn) {
|
|
const allSupportedImportFileTypes = [];
|
|
|
|
for (let i = 0; i < SUPPORTED_IMPORT_FILE_TYPES.length; i++) {
|
|
const fileType = SUPPORTED_IMPORT_FILE_TYPES[i];
|
|
let document = {
|
|
language: '',
|
|
displayLanguageName: '',
|
|
anchor: ''
|
|
};
|
|
|
|
if (fileType.document) {
|
|
if (fileType.document.supportMultiLanguages === true) {
|
|
document.language = getCurrentLanguageTag(i18nGlobal);
|
|
document.anchor = translateFn(`document.anchor.export_and_import.${fileType.document.anchor}`);
|
|
} else if (isString(fileType.document.supportMultiLanguages) && ALL_LANGUAGES[fileType.document.supportMultiLanguages]) {
|
|
document.language = fileType.document.supportMultiLanguages;
|
|
|
|
if (document.language !== getCurrentLanguageTag(i18nGlobal)) {
|
|
document.displayLanguageName = getLanguageDisplayName(translateFn, ALL_LANGUAGES[fileType.document.supportMultiLanguages].name);
|
|
}
|
|
|
|
document.anchor = fileType.document.anchor;
|
|
}
|
|
|
|
if (document.language) {
|
|
document.language = document.language.replace(/-/g, '_');
|
|
}
|
|
|
|
if (document.anchor) {
|
|
document.anchor = document.anchor.toLowerCase().replace(/ /g, '-');
|
|
}
|
|
|
|
if (document.language === DEFAULT_LANGUAGE) {
|
|
document.language = '';
|
|
}
|
|
} else {
|
|
document = null;
|
|
}
|
|
|
|
const subTypes = [];
|
|
|
|
if (fileType.subTypes) {
|
|
for (let i = 0; i < fileType.subTypes.length; i++) {
|
|
const subType = fileType.subTypes[i];
|
|
|
|
subTypes.push({
|
|
type: subType.type,
|
|
displayName: translateFn(subType.name),
|
|
extensions: subType.extensions
|
|
});
|
|
}
|
|
}
|
|
|
|
allSupportedImportFileTypes.push({
|
|
type: fileType.type,
|
|
displayName: translateFn(fileType.name),
|
|
extensions: fileType.extensions,
|
|
subTypes: subTypes.length ? subTypes : undefined,
|
|
document: document
|
|
});
|
|
}
|
|
|
|
return allSupportedImportFileTypes;
|
|
}
|
|
|
|
function getCategorizedAccountsWithDisplayBalance(allVisibleAccounts, showAccountBalance, defaultCurrency, userStore, settingsStore, exchangeRatesStore, translateFn) {
|
|
const ret = [];
|
|
const allCategories = AccountCategory.values();
|
|
const categorizedAccounts = copyObjectTo(getCategorizedAccountsMap(allVisibleAccounts), {});
|
|
|
|
for (let i = 0; i < allCategories.length; i++) {
|
|
const category = allCategories[i];
|
|
|
|
if (!categorizedAccounts[category.type]) {
|
|
continue;
|
|
}
|
|
|
|
const accountCategory = categorizedAccounts[category.type];
|
|
|
|
if (accountCategory.accounts) {
|
|
for (let i = 0; i < accountCategory.accounts.length; i++) {
|
|
const account = accountCategory.accounts[i];
|
|
|
|
if (showAccountBalance && account.isAsset) {
|
|
account.displayBalance = getFormattedAmountWithCurrency(account.balance, account.currency, translateFn, userStore, settingsStore);
|
|
} else if (showAccountBalance && account.isLiability) {
|
|
account.displayBalance = getFormattedAmountWithCurrency(-account.balance, account.currency, translateFn, userStore, settingsStore);
|
|
} else {
|
|
account.displayBalance = '***';
|
|
}
|
|
}
|
|
}
|
|
|
|
if (showAccountBalance) {
|
|
const accountsBalance = getAllFilteredAccountsBalance(categorizedAccounts, account => account.category === accountCategory.category);
|
|
let totalBalance = 0;
|
|
let hasUnCalculatedAmount = false;
|
|
|
|
for (let i = 0; i < accountsBalance.length; i++) {
|
|
if (accountsBalance[i].currency === defaultCurrency) {
|
|
if (accountsBalance[i].isAsset) {
|
|
totalBalance += accountsBalance[i].balance;
|
|
} else if (accountsBalance[i].isLiability) {
|
|
totalBalance -= accountsBalance[i].balance;
|
|
}
|
|
} else {
|
|
const balance = exchangeRatesStore.getExchangedAmount(accountsBalance[i].balance, accountsBalance[i].currency, defaultCurrency);
|
|
|
|
if (!isNumber(balance)) {
|
|
hasUnCalculatedAmount = true;
|
|
continue;
|
|
}
|
|
|
|
if (accountsBalance[i].isAsset) {
|
|
totalBalance += Math.floor(balance);
|
|
} else if (accountsBalance[i].isLiability) {
|
|
totalBalance -= Math.floor(balance);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hasUnCalculatedAmount) {
|
|
totalBalance = totalBalance + '+';
|
|
}
|
|
|
|
accountCategory.displayBalance = getFormattedAmountWithCurrency(totalBalance, defaultCurrency, translateFn, userStore, settingsStore);
|
|
} else {
|
|
accountCategory.displayBalance = '***';
|
|
}
|
|
|
|
ret.push(accountCategory);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function joinMultiText(textArray, translateFn) {
|
|
if (!textArray || !textArray.length) {
|
|
return '';
|
|
}
|
|
|
|
const separator = translateFn('format.misc.multiTextJoinSeparator');
|
|
|
|
return textArray.join(separator);
|
|
}
|
|
|
|
function getLocalizedError(error) {
|
|
if (error.errorCode === KnownErrorCode.ApiNotFound && SPECIFIED_API_NOT_FOUND_ERRORS[error.path]) {
|
|
return {
|
|
message: `${SPECIFIED_API_NOT_FOUND_ERRORS[error.path].message}`
|
|
};
|
|
}
|
|
|
|
if (error.errorCode !== KnownErrorCode.ValidatorError) {
|
|
return {
|
|
message: `error.${error.errorMessage}`
|
|
};
|
|
}
|
|
|
|
for (let i = 0; i < PARAMETERIZED_ERRORS.length; i++) {
|
|
const errorInfo = PARAMETERIZED_ERRORS[i];
|
|
const matches = error.errorMessage.match(errorInfo.regex);
|
|
|
|
if (matches && matches.length === errorInfo.parameters.length + 1) {
|
|
return {
|
|
message: `parameterizedError.${errorInfo.localeKey}`,
|
|
parameters: errorInfo.parameters.map((param, index) => {
|
|
return {
|
|
key: param.field,
|
|
localized: param.localized,
|
|
value: matches[index + 1]
|
|
}
|
|
})
|
|
};
|
|
}
|
|
}
|
|
|
|
return {
|
|
message: `error.${error.errorMessage}`
|
|
};
|
|
}
|
|
|
|
function getLocalizedErrorParameters(parameters, i18nFunc) {
|
|
let localizedParameters = {};
|
|
|
|
if (parameters) {
|
|
for (let i = 0; i < parameters.length; i++) {
|
|
const parameter = parameters[i];
|
|
|
|
if (parameter.localized) {
|
|
localizedParameters[parameter.key] = i18nFunc(`parameter.${parameter.value}`);
|
|
} else {
|
|
localizedParameters[parameter.key] = parameter.value;
|
|
}
|
|
}
|
|
}
|
|
|
|
return localizedParameters;
|
|
}
|
|
|
|
export function translateError(message, translateFn) {
|
|
let parameters = {};
|
|
|
|
if (message && message.error) {
|
|
const localizedError = getLocalizedError(message.error);
|
|
message = localizedError.message;
|
|
parameters = getLocalizedErrorParameters(localizedError.parameters, translateFn);
|
|
}
|
|
|
|
return translateFn(message, parameters);
|
|
}
|
|
|
|
export function i18nFunctions(i18nGlobal) {
|
|
return {
|
|
getWeekdayShortName: (weekDay) => getWeekdayShortName(weekDay, i18nGlobal.t),
|
|
getWeekdayLongName: (weekDay) => getWeekdayLongName(weekDay, i18nGlobal.t),
|
|
getMultiMonthdayShortNames: (monthdays) => getMultiMonthdayShortNames(monthdays, i18nGlobal.t),
|
|
getMultiWeekdayLongNames: (weekdayTypes, firstDayOfWeek) => getMultiWeekdayLongNames(weekdayTypes, firstDayOfWeek, i18nGlobal.t),
|
|
formatUnixTimeToLongDateTime: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nLongDateFormat(i18nGlobal.t, userStore.currentUserLongDateFormat) + ' ' + getI18nLongTimeFormat(i18nGlobal.t, userStore.currentUserLongTimeFormat), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToLongDate: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nLongDateFormat(i18nGlobal.t, userStore.currentUserLongDateFormat), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToLongYear: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nLongYearFormat(i18nGlobal.t, userStore.currentUserLongDateFormat), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToLongYearMonth: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nLongYearMonthFormat(i18nGlobal.t, userStore.currentUserLongDateFormat), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToLongMonthDay: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nLongMonthDayFormat(i18nGlobal.t, userStore.currentUserLongDateFormat), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToLongTime: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nLongTimeFormat(i18nGlobal.t, userStore.currentUserLongTimeFormat), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToShortTime: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nShortTimeFormat(i18nGlobal.t, userStore.currentUserShortTimeFormat), utcOffset, currentUtcOffset),
|
|
getAllTimezones: (includeSystemDefault) => getAllTimezones(includeSystemDefault, i18nGlobal.t),
|
|
getTimezoneDifferenceDisplayText: (utcOffset) => getTimezoneDifferenceDisplayText(utcOffset, i18nGlobal.t),
|
|
getAllDateRanges: (scene, includeCustom, includeBillingCycle) => getAllDateRanges(scene, includeCustom, includeBillingCycle, i18nGlobal.t),
|
|
getAllRecentMonthDateRanges: (userStore, includeAll, includeCustom) => getAllRecentMonthDateRanges(userStore, includeAll, includeCustom, i18nGlobal.t),
|
|
getDateRangeDisplayName: (userStore, dateType, startTime, endTime) => getDateRangeDisplayName(userStore, dateType, startTime, endTime, i18nGlobal.t),
|
|
formatAmount: (userStore, value, currencyCode) => getFormattedAmount(value, i18nGlobal.t, userStore, currencyCode),
|
|
formatAmountWithCurrency: (settingsStore, userStore, value, currencyCode) => getFormattedAmountWithCurrency(value, currencyCode, i18nGlobal.t, userStore, settingsStore),
|
|
getAdaptiveAmountRate: (userStore, amount1, amount2, fromExchangeRate, toExchangeRate) => getAdaptiveAmountRate(amount1, amount2, fromExchangeRate, toExchangeRate, i18nGlobal.t, userStore),
|
|
getAllTransactionTagFilterTypes: () => getAllTransactionTagFilterTypes(i18nGlobal.t),
|
|
getAllSupportedImportFileTypes: () => getAllSupportedImportFileTypes(i18nGlobal, i18nGlobal.t),
|
|
getCategorizedAccountsWithDisplayBalance: (allVisibleAccounts, showAccountBalance, defaultCurrency, settingsStore, userStore, exchangeRatesStore) => getCategorizedAccountsWithDisplayBalance(allVisibleAccounts, showAccountBalance, defaultCurrency, userStore, settingsStore, exchangeRatesStore, i18nGlobal.t)
|
|
};
|
|
}
|