1922 lines
73 KiB
TypeScript
1922 lines
73 KiB
TypeScript
import { useI18n as useVueI18n } from 'vue-i18n';
|
|
import moment from 'moment-timezone';
|
|
|
|
import type { PartialRecord, TypeAndName, TypeAndDisplayName, LocalizedSwitchOption } from '@/core/base.ts';
|
|
|
|
import { type LanguageInfo, type LanguageOption, ALL_LANGUAGES, DEFAULT_LANGUAGE } from '@/locales/index.ts';
|
|
|
|
import {
|
|
type DateFormat,
|
|
type TimeFormat,
|
|
type LocalizedMeridiemIndicator,
|
|
type LocalizedDateTimeFormat,
|
|
type LocalizedDateRange,
|
|
type LocalizedRecentMonthDateRange,
|
|
type UnixTimeRange,
|
|
Month,
|
|
WeekDay,
|
|
MeridiemIndicator,
|
|
LongDateFormat,
|
|
ShortDateFormat,
|
|
LongTimeFormat,
|
|
ShortTimeFormat,
|
|
DateRange,
|
|
DateRangeScene,
|
|
LANGUAGE_DEFAULT_DATE_TIME_FORMAT_VALUE
|
|
} from '@/core/datetime.ts';
|
|
|
|
import {
|
|
type LocalizedTimezoneInfo,
|
|
TimezoneTypeForStatistics
|
|
} from '@/core/timezone.ts';
|
|
|
|
import {
|
|
type NumberFormatOptions,
|
|
type NumeralSymbolType,
|
|
type LocalizedNumeralSymbolType,
|
|
type LocalizedDigitGroupingType,
|
|
DecimalSeparator,
|
|
DigitGroupingSymbol,
|
|
DigitGroupingType
|
|
} from '@/core/numeral.ts';
|
|
|
|
import {
|
|
type LocalizedCurrencyInfo,
|
|
type CurrencyPrependAndAppendText,
|
|
CurrencyDisplayType,
|
|
CurrencySortingType
|
|
} from '@/core/currency.ts';
|
|
|
|
import {
|
|
FiscalYearStart,
|
|
FiscalYearFormat,
|
|
FiscalYearUnixTime,
|
|
LANGUAGE_DEFAULT_FISCAL_YEAR_FORMAT_VALUE,
|
|
} from '@/core/fiscalyear.ts';
|
|
|
|
import {
|
|
CoordinateDisplayType
|
|
} from '@/core/coordinate.ts';
|
|
|
|
import {
|
|
PresetAmountColor
|
|
} from '@/core/color.ts';
|
|
|
|
import {
|
|
type LocalizedAccountCategory,
|
|
AccountType,
|
|
AccountCategory
|
|
} from '@/core/account.ts';
|
|
|
|
import {
|
|
type PresetCategory,
|
|
type LocalizedPresetCategory,
|
|
type LocalizedPresetSubCategory,
|
|
CategoryType,
|
|
ALL_CATEGORY_TYPES
|
|
} from '@/core/category.ts';
|
|
|
|
import {
|
|
TransactionEditScopeType,
|
|
TransactionTagFilterType,
|
|
ImportTransactionColumnType
|
|
} from '@/core/transaction.ts';
|
|
|
|
import {
|
|
ScheduledTemplateFrequencyType
|
|
} from '@/core/template.ts';
|
|
|
|
import {
|
|
StatisticsAnalysisType,
|
|
CategoricalChartType,
|
|
TrendChartType,
|
|
ChartDataType,
|
|
ChartSortingType,
|
|
ChartDateAggregationType
|
|
} from '@/core/statistics.ts';
|
|
|
|
import {
|
|
type LocalizedImportFileType,
|
|
type LocalizedImportFileTypeSubType,
|
|
type LocalizedImportFileTypeSupportedEncodings,
|
|
type LocalizedImportFileDocument,
|
|
} from '@/core/file.ts';
|
|
|
|
import type { LocaleDefaultSettings } from '@/core/setting.ts';
|
|
import type { ErrorResponse } from '@/core/api.ts';
|
|
|
|
import { UTC_TIMEZONE, ALL_TIMEZONES } from '@/consts/timezone.ts';
|
|
import { ALL_CURRENCIES } from '@/consts/currency.ts';
|
|
import { DEFAULT_EXPENSE_CATEGORIES, DEFAULT_INCOME_CATEGORIES, DEFAULT_TRANSFER_CATEGORIES } from '@/consts/category.ts';
|
|
import { KnownErrorCode, SPECIFIED_API_NOT_FOUND_ERRORS, PARAMETERIZED_ERRORS } from '@/consts/api.ts';
|
|
import { DEFAULT_DOCUMENT_LANGUAGE_FOR_IMPORT_FILE, SUPPORTED_DOCUMENT_LANGUAGES_FOR_IMPORT_FILE, SUPPORTED_IMPORT_FILE_TYPES } from '@/consts/file.ts';
|
|
|
|
import {
|
|
type CategorizedAccount,
|
|
Account,
|
|
AccountWithDisplayBalance,
|
|
CategorizedAccountWithDisplayBalance
|
|
} from '@/models/account.ts';
|
|
import type { LatestExchangeRateResponse, LocalizedLatestExchangeRate } from '@/models/exchange_rate.ts';
|
|
|
|
import {
|
|
isDefined,
|
|
isObject,
|
|
isString,
|
|
isNumber,
|
|
isBoolean
|
|
} from '@/lib/common.ts';
|
|
|
|
import {
|
|
formatCurrentTime,
|
|
formatDate,
|
|
formatMonthDay,
|
|
formatUnixTime,
|
|
getBrowserTimezoneOffset,
|
|
getBrowserTimezoneOffsetMinutes,
|
|
getCurrentUnixTime,
|
|
getDateTimeFormatType,
|
|
getFiscalYearTimeRangeFromUnixTime,
|
|
getFiscalYearTimeRangeFromYear,
|
|
getRecentMonthDateRanges,
|
|
getTimeDifferenceHoursAndMinutes,
|
|
getTimezoneOffset,
|
|
getTimezoneOffsetMinutes,
|
|
getYear,
|
|
isDateRangeMatchFullMonths,
|
|
isDateRangeMatchFullYears,
|
|
isPM,
|
|
parseDateFromUnixTime,
|
|
} from '@/lib/datetime.ts';
|
|
|
|
import {
|
|
appendDigitGroupingSymbol,
|
|
parseAmount,
|
|
formatAmount,
|
|
formatNumber,
|
|
formatPercent,
|
|
formatExchangeRateAmount,
|
|
getAdaptiveDisplayAmountRate
|
|
} from '@/lib/numeral.ts';
|
|
|
|
import {
|
|
getCurrencyFraction,
|
|
appendCurrencySymbol,
|
|
getAmountPrependAndAppendCurrencySymbol
|
|
} from '@/lib/currency.ts';
|
|
|
|
import {
|
|
getCategorizedAccountsMap,
|
|
getAllFilteredAccountsBalance
|
|
} from '@/lib/account.ts';
|
|
|
|
import services from '@/lib/services.ts';
|
|
import logger from '@/lib/logger.ts';
|
|
|
|
import { useSettingsStore } from '@/stores/setting.ts';
|
|
import { useUserStore } from '@/stores/user.ts';
|
|
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
|
|
|
export interface LocalizedErrorParameter {
|
|
readonly key: string;
|
|
readonly localized: boolean;
|
|
readonly value: string;
|
|
}
|
|
|
|
export interface LocalizedError {
|
|
readonly message: string;
|
|
readonly parameters?: LocalizedErrorParameter[];
|
|
}
|
|
|
|
export function getI18nOptions(): object {
|
|
return {
|
|
legacy: false,
|
|
locale: DEFAULT_LANGUAGE,
|
|
fallbackLocale: DEFAULT_LANGUAGE,
|
|
formatFallbackMessages: true,
|
|
messages: (function () {
|
|
const messages: Record<string, object> = {};
|
|
|
|
for (const languageKey in ALL_LANGUAGES) {
|
|
if (!Object.prototype.hasOwnProperty.call(ALL_LANGUAGES, languageKey)) {
|
|
continue;
|
|
}
|
|
|
|
const languageInfo = ALL_LANGUAGES[languageKey];
|
|
messages[languageKey] = languageInfo.content;
|
|
}
|
|
|
|
return messages;
|
|
})()
|
|
};
|
|
}
|
|
|
|
export function useI18n() {
|
|
const { t, locale } = useVueI18n();
|
|
|
|
const settingsStore = useSettingsStore();
|
|
const userStore = useUserStore();
|
|
const exchangeRatesStore = useExchangeRatesStore();
|
|
|
|
// private functions
|
|
function getLanguageDisplayName(languageName: string): string {
|
|
return t(`language.${languageName}`);
|
|
}
|
|
|
|
function getDefaultLanguage(): string {
|
|
if (!window || !window.navigator) {
|
|
return DEFAULT_LANGUAGE;
|
|
}
|
|
|
|
let browserLanguage = window.navigator.browserLanguage || window.navigator.language;
|
|
|
|
if (!browserLanguage) {
|
|
return DEFAULT_LANGUAGE;
|
|
}
|
|
|
|
if (!ALL_LANGUAGES[browserLanguage]) {
|
|
const languageKey = getLanguageKeyFromLanguageAlias(browserLanguage);
|
|
|
|
if (languageKey) {
|
|
browserLanguage = languageKey;
|
|
}
|
|
}
|
|
|
|
if (!ALL_LANGUAGES[browserLanguage] && browserLanguage.split('-').length > 1) { // maybe language-script-region
|
|
const languageTagParts = browserLanguage.split('-');
|
|
browserLanguage = languageTagParts[0] + '-' + languageTagParts[1];
|
|
|
|
if (!ALL_LANGUAGES[browserLanguage]) {
|
|
const languageKey = getLanguageKeyFromLanguageAlias(browserLanguage);
|
|
|
|
if (languageKey) {
|
|
browserLanguage = languageKey;
|
|
}
|
|
}
|
|
|
|
if (!ALL_LANGUAGES[browserLanguage]) {
|
|
browserLanguage = languageTagParts[0];
|
|
const languageKey = getLanguageKeyFromLanguageAlias(browserLanguage);
|
|
|
|
if (languageKey) {
|
|
browserLanguage = languageKey;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ALL_LANGUAGES[browserLanguage]) {
|
|
return DEFAULT_LANGUAGE;
|
|
}
|
|
|
|
return browserLanguage;
|
|
}
|
|
|
|
function getLanguageKeyFromLanguageAlias(alias: string): string | null {
|
|
for (const languageKey in ALL_LANGUAGES) {
|
|
if (!Object.prototype.hasOwnProperty.call(ALL_LANGUAGES, languageKey)) {
|
|
continue;
|
|
}
|
|
|
|
if (languageKey.toLowerCase() === alias.toLowerCase()) {
|
|
return languageKey;
|
|
}
|
|
|
|
const langInfo = ALL_LANGUAGES[languageKey];
|
|
const aliases = langInfo.aliases;
|
|
|
|
if (!aliases || aliases.length < 1) {
|
|
continue;
|
|
}
|
|
|
|
for (let i = 0; i < aliases.length; i++) {
|
|
if (aliases[i].toLowerCase() === alias.toLowerCase()) {
|
|
return languageKey;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function getLocalizedError(error: ErrorResponse): LocalizedError {
|
|
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?: LocalizedErrorParameter[]): Record<string, string> {
|
|
const localizedParameters: Record<string, string> = {};
|
|
|
|
if (parameters) {
|
|
for (let i = 0; i < parameters.length; i++) {
|
|
const parameter = parameters[i];
|
|
|
|
if (parameter.localized) {
|
|
localizedParameters[parameter.key] = t(`parameter.${parameter.value}`);
|
|
} else {
|
|
localizedParameters[parameter.key] = parameter.value;
|
|
}
|
|
}
|
|
}
|
|
|
|
return localizedParameters;
|
|
}
|
|
|
|
function getAllCurrencyDisplayTypes(): TypeAndDisplayName[] {
|
|
const defaultCurrencyDisplayTypeName = t('default.currencyDisplayType');
|
|
let defaultCurrencyDisplayType = CurrencyDisplayType.parse(defaultCurrencyDisplayTypeName);
|
|
|
|
if (!defaultCurrencyDisplayType) {
|
|
defaultCurrencyDisplayType = CurrencyDisplayType.Default;
|
|
}
|
|
|
|
const defaultCurrency = userStore.currentUserDefaultCurrency;
|
|
|
|
const ret = [];
|
|
const defaultSampleValue = getFormattedAmountWithCurrency(12345, defaultCurrency, false, defaultCurrencyDisplayType);
|
|
|
|
ret.push({
|
|
type: CurrencyDisplayType.LanguageDefaultType,
|
|
displayName: `${t('Language Default')} (${defaultSampleValue})`
|
|
});
|
|
|
|
const allCurrencyDisplayTypes = CurrencyDisplayType.values();
|
|
|
|
for (let i = 0; i < allCurrencyDisplayTypes.length; i++) {
|
|
const type = allCurrencyDisplayTypes[i];
|
|
const sampleValue = getFormattedAmountWithCurrency(12345, defaultCurrency, false, type);
|
|
const displayName = `${t(type.name)} (${sampleValue})`
|
|
|
|
ret.push({
|
|
type: type.type,
|
|
displayName: displayName
|
|
});
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getLocalizedDisplayNameAndType(typeAndNames: TypeAndName[]): TypeAndDisplayName[] {
|
|
const ret: TypeAndDisplayName[] = [];
|
|
|
|
for (let i = 0; i < typeAndNames.length; i++) {
|
|
const nameAndType = typeAndNames[i];
|
|
|
|
ret.push({
|
|
type: nameAndType.type,
|
|
displayName: t(nameAndType.name)
|
|
});
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getLocalizedDisplayNameAndTypeWithSystemDefault(typeAndNames: TypeAndName[], defaultValue: number, defaultType: TypeAndName): TypeAndDisplayName[] {
|
|
const ret: TypeAndDisplayName[] = [];
|
|
|
|
ret.push({
|
|
type: defaultValue,
|
|
displayName: t('System Default') + (defaultType.name ? ` (${t(defaultType.name)})` : '')
|
|
});
|
|
|
|
for (let i = 0; i < typeAndNames.length; i++) {
|
|
const nameAndType = typeAndNames[i];
|
|
|
|
ret.push({
|
|
type: nameAndType.type,
|
|
displayName: t(nameAndType.name)
|
|
});
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getLocalizedNumeralSeparatorFormats<T extends NumeralSymbolType>(allSeparatorArray: T[], localeDefaultType: T | undefined, systemDefaultType: T, languageDefaultValue: number): LocalizedNumeralSymbolType[] {
|
|
let defaultSeparatorType: T | undefined = localeDefaultType;
|
|
|
|
if (!defaultSeparatorType) {
|
|
defaultSeparatorType = systemDefaultType;
|
|
}
|
|
|
|
const ret: LocalizedNumeralSymbolType[] = [];
|
|
|
|
ret.push({
|
|
type: languageDefaultValue,
|
|
symbol: defaultSeparatorType.symbol,
|
|
displayName: `${t('Language Default')} (${defaultSeparatorType.symbol})`
|
|
});
|
|
|
|
for (let i = 0; i < allSeparatorArray.length; i++) {
|
|
const type = allSeparatorArray[i];
|
|
|
|
ret.push({
|
|
type: type.type,
|
|
symbol: type.symbol,
|
|
displayName: `${t('numeral.' + type.name)} (${type.symbol})`
|
|
});
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getAllMonthNames(type: string): string[] {
|
|
const ret = [];
|
|
const allMonths = Month.values();
|
|
|
|
for (let i = 0; i < allMonths.length; i++) {
|
|
const month = allMonths[i];
|
|
ret.push(t(`datetime.${month.name}.${type}`));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getAllWeekdayNames(type: string): string[] {
|
|
const ret = [];
|
|
const allWeekDays = WeekDay.values();
|
|
|
|
for (let i = 0; i < allWeekDays.length; i++) {
|
|
const weekDay = allWeekDays[i];
|
|
ret.push(t(`datetime.${weekDay.name}.${type}`));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getLocalizedDateTimeType<T extends DateFormat | TimeFormat>(allFormatMap: Record<string, T>, allFormatArray: T[], formatTypeValue: number, languageDefaultTypeNameKey: string, systemDefaultFormatType: T): T {
|
|
return getDateTimeFormatType(allFormatMap, allFormatArray, formatTypeValue, t(`default.${languageDefaultTypeNameKey}`), systemDefaultFormatType);
|
|
}
|
|
|
|
function getLocalizedDateTimeFormat<T extends DateFormat | TimeFormat>(type: string, allFormatMap: Record<string, T>, allFormatArray: T[], formatTypeValue: number, languageDefaultTypeNameKey: string, systemDefaultFormatType: T): string {
|
|
const formatType = getLocalizedDateTimeType(allFormatMap, allFormatArray, formatTypeValue, languageDefaultTypeNameKey, systemDefaultFormatType);
|
|
return t(`format.${type}.${formatType.key}`);
|
|
}
|
|
|
|
function getLocalizedLongDateFormat(): string {
|
|
return getLocalizedDateTimeFormat<LongDateFormat>('longDate', LongDateFormat.all(), LongDateFormat.values(), userStore.currentUserLongDateFormat, 'longDateFormat', LongDateFormat.Default);
|
|
}
|
|
|
|
function getLocalizedShortDateFormat(): string {
|
|
return getLocalizedDateTimeFormat<ShortDateFormat>('shortDate', ShortDateFormat.all(), ShortDateFormat.values(), userStore.currentUserShortDateFormat, 'shortDateFormat', ShortDateFormat.Default);
|
|
}
|
|
|
|
function getLocalizedLongYearFormat(): string {
|
|
return getLocalizedDateTimeFormat<LongDateFormat>('longYear', LongDateFormat.all(), LongDateFormat.values(), userStore.currentUserLongDateFormat, 'longDateFormat', LongDateFormat.Default);
|
|
}
|
|
|
|
function getLocalizedShortYearFormat(): string {
|
|
return getLocalizedDateTimeFormat<ShortDateFormat>('shortYear', ShortDateFormat.all(), ShortDateFormat.values(), userStore.currentUserShortDateFormat, 'shortDateFormat', ShortDateFormat.Default);
|
|
}
|
|
|
|
function getLocalizedLongYearMonthFormat(): string {
|
|
return getLocalizedDateTimeFormat<LongDateFormat>('longYearMonth', LongDateFormat.all(), LongDateFormat.values(), userStore.currentUserLongDateFormat, 'longDateFormat', LongDateFormat.Default);
|
|
}
|
|
|
|
function getLocalizedShortYearMonthFormat(): string {
|
|
return getLocalizedDateTimeFormat<ShortDateFormat>('shortYearMonth', ShortDateFormat.all(), ShortDateFormat.values(), userStore.currentUserShortDateFormat, 'shortDateFormat', ShortDateFormat.Default);
|
|
}
|
|
|
|
function getLocalizedLongMonthDayFormat(): string {
|
|
return getLocalizedDateTimeFormat<LongDateFormat>('longMonthDay', LongDateFormat.all(), LongDateFormat.values(), userStore.currentUserLongDateFormat, 'longDateFormat', LongDateFormat.Default);
|
|
}
|
|
|
|
function getLocalizedShortMonthDayFormat(): string {
|
|
return getLocalizedDateTimeFormat<ShortDateFormat>('shortMonthDay', ShortDateFormat.all(), ShortDateFormat.values(), userStore.currentUserShortDateFormat, 'shortDateFormat', ShortDateFormat.Default);
|
|
}
|
|
|
|
function getLocalizedLongTimeFormat(): string {
|
|
return getLocalizedDateTimeFormat<LongTimeFormat>('longTime', LongTimeFormat.all(), LongTimeFormat.values(), userStore.currentUserLongTimeFormat, 'longTimeFormat', LongTimeFormat.Default);
|
|
}
|
|
|
|
function getLocalizedShortTimeFormat(): string {
|
|
return getLocalizedDateTimeFormat<ShortTimeFormat>('shortTime', ShortTimeFormat.all(), ShortTimeFormat.values(), userStore.currentUserShortTimeFormat, 'shortTimeFormat', ShortTimeFormat.Default);
|
|
}
|
|
|
|
function getNumberFormatOptions(currencyCode?: string): NumberFormatOptions {
|
|
return {
|
|
decimalSeparator: getCurrentDecimalSeparator(),
|
|
decimalNumberCount: getCurrencyFraction(currencyCode),
|
|
digitGroupingSymbol: getCurrentDigitGroupingSymbol(),
|
|
digitGrouping: getCurrentDigitGroupingType(),
|
|
};
|
|
}
|
|
|
|
function getCurrencyUnitName(currencyCode: string, isPlural: boolean): string {
|
|
const currencyInfo = ALL_CURRENCIES[currencyCode];
|
|
|
|
if (currencyInfo && currencyInfo.unit) {
|
|
if (isPlural) {
|
|
return t(`currency.unit.${currencyInfo.unit}.plural`);
|
|
} else {
|
|
return t(`currency.unit.${currencyInfo.unit}.normal`);
|
|
}
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
function getCurrentCurrencyDisplayType(): CurrencyDisplayType {
|
|
let currencyDisplayType = CurrencyDisplayType.valueOf(userStore.currentUserCurrencyDisplayType);
|
|
|
|
if (!currencyDisplayType) {
|
|
const defaultCurrencyDisplayTypeName = t('default.currencyDisplayType');
|
|
currencyDisplayType = CurrencyDisplayType.parse(defaultCurrencyDisplayTypeName);
|
|
}
|
|
|
|
if (!currencyDisplayType) {
|
|
currencyDisplayType = CurrencyDisplayType.Default;
|
|
}
|
|
|
|
return currencyDisplayType;
|
|
}
|
|
|
|
// public functions
|
|
function translateIf(text: string | undefined, isTranslate?: boolean): string {
|
|
if (!isDefined(text)) {
|
|
return '';
|
|
}
|
|
|
|
if (isTranslate) {
|
|
return t(text);
|
|
}
|
|
|
|
return text;
|
|
}
|
|
|
|
function translateError(message: string | { error: ErrorResponse }): string {
|
|
let finalMessage = '';
|
|
let parameters = {};
|
|
|
|
if (isObject(message) && isObject(message.error)) {
|
|
const localizedError = getLocalizedError(message.error);
|
|
finalMessage = localizedError.message;
|
|
parameters = getLocalizedErrorParameters(localizedError.parameters);
|
|
} else if (isString(message)) {
|
|
finalMessage = message;
|
|
} else {
|
|
return '';
|
|
}
|
|
|
|
return t(finalMessage, parameters);
|
|
}
|
|
|
|
function joinMultiText(textArray: string[]): string {
|
|
if (!textArray || !textArray.length) {
|
|
return '';
|
|
}
|
|
|
|
const separator = t('format.misc.multiTextJoinSeparator');
|
|
|
|
return textArray.join(separator);
|
|
}
|
|
|
|
function getServerTipContent(tipConfig: Record<string, string>): string {
|
|
if (!tipConfig) {
|
|
return '';
|
|
}
|
|
|
|
const currentLanguage = getCurrentLanguageTag();
|
|
|
|
if (isString(tipConfig[currentLanguage])) {
|
|
return tipConfig[currentLanguage];
|
|
}
|
|
|
|
return tipConfig['default'] || '';
|
|
}
|
|
|
|
function getCurrentLanguageTag(): string {
|
|
return locale.value;
|
|
}
|
|
|
|
function getCurrentLanguageInfo(): LanguageInfo {
|
|
const languageInfo = getLanguageInfo(locale.value);
|
|
|
|
if (languageInfo) {
|
|
return languageInfo;
|
|
}
|
|
|
|
return getLanguageInfo(getDefaultLanguage()) as LanguageInfo;
|
|
}
|
|
|
|
function getCurrentLanguageDisplayName(): string {
|
|
const currentLanguageInfo = getCurrentLanguageInfo();
|
|
return currentLanguageInfo.displayName;
|
|
}
|
|
|
|
function getDefaultCurrency(): string {
|
|
return t('default.currency');
|
|
}
|
|
|
|
function getDefaultFirstDayOfWeek(): string {
|
|
return t('default.firstDayOfWeek');
|
|
}
|
|
|
|
function getDefaultFiscalYearFormat(): string {
|
|
return t('default.fiscalYearFormat');
|
|
}
|
|
|
|
function getAllLanguageOptions(includeSystemDefault: boolean): LanguageOption[] {
|
|
const ret: LanguageOption[] = [];
|
|
|
|
for (const languageTag in ALL_LANGUAGES) {
|
|
if (!Object.prototype.hasOwnProperty.call(ALL_LANGUAGES, languageTag)) {
|
|
continue;
|
|
}
|
|
|
|
const languageInfo = ALL_LANGUAGES[languageTag];
|
|
const displayName = languageInfo.displayName;
|
|
const languageNameInCurrentLanguage = getLanguageDisplayName(languageInfo.name);
|
|
|
|
ret.push({
|
|
languageTag: languageTag,
|
|
displayName: languageNameInCurrentLanguage,
|
|
nativeDisplayName: displayName
|
|
});
|
|
}
|
|
|
|
ret.sort(function (lang1, lang2) {
|
|
return lang1.languageTag.localeCompare(lang2.languageTag);
|
|
});
|
|
|
|
if (includeSystemDefault) {
|
|
ret.splice(0, 0, {
|
|
languageTag: '',
|
|
displayName: '',
|
|
nativeDisplayName: t('System Default')
|
|
});
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getAllEnableDisableOptions(): LocalizedSwitchOption[] {
|
|
return [{
|
|
value: true,
|
|
displayName: t('Enable')
|
|
},{
|
|
value: false,
|
|
displayName: t('Disable')
|
|
}];
|
|
}
|
|
|
|
function getAllCurrencies(): LocalizedCurrencyInfo[] {
|
|
const allCurrencies: LocalizedCurrencyInfo[] = [];
|
|
|
|
for (const currencyCode in ALL_CURRENCIES) {
|
|
if (!Object.prototype.hasOwnProperty.call(ALL_CURRENCIES, currencyCode)) {
|
|
continue;
|
|
}
|
|
|
|
const localizedCurrencyInfo: LocalizedCurrencyInfo = {
|
|
currencyCode: currencyCode,
|
|
displayName: getCurrencyName(currencyCode)
|
|
};
|
|
|
|
allCurrencies.push(localizedCurrencyInfo);
|
|
}
|
|
|
|
allCurrencies.sort(function(c1, c2) {
|
|
return c1.displayName.localeCompare(c2.displayName);
|
|
})
|
|
|
|
return allCurrencies;
|
|
}
|
|
|
|
function getAllMeridiemIndicators(): LocalizedMeridiemIndicator {
|
|
const allMeridiemIndicators = MeridiemIndicator.values();
|
|
const meridiemIndicatorNames = [];
|
|
const localizedMeridiemIndicatorNames = [];
|
|
|
|
for (let i = 0; i < allMeridiemIndicators.length; i++) {
|
|
const indicator = allMeridiemIndicators[i];
|
|
|
|
meridiemIndicatorNames.push(indicator.name);
|
|
localizedMeridiemIndicatorNames.push(t(`datetime.${indicator.name}.content`));
|
|
}
|
|
|
|
return {
|
|
values: meridiemIndicatorNames,
|
|
displayValues: localizedMeridiemIndicatorNames
|
|
};
|
|
}
|
|
|
|
function getAllLongMonthNames(): string[] {
|
|
return getAllMonthNames('long');
|
|
}
|
|
|
|
function getAllShortMonthNames(): string[] {
|
|
return getAllMonthNames('short');
|
|
}
|
|
|
|
function getAllLongWeekdayNames(): string[] {
|
|
return getAllWeekdayNames('long');
|
|
}
|
|
|
|
function getAllShortWeekdayNames(): string[] {
|
|
return getAllWeekdayNames('short');
|
|
}
|
|
|
|
function getAllMinWeekdayNames(): string[] {
|
|
return getAllWeekdayNames('min');
|
|
}
|
|
|
|
function getAllWeekDays(firstDayOfWeek?: number): TypeAndDisplayName[] {
|
|
const ret: TypeAndDisplayName[] = [];
|
|
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: t(`datetime.${weekDay.name}.long`)
|
|
});
|
|
}
|
|
|
|
for (let i = 0; i < firstDayOfWeek; i++) {
|
|
const weekDay = allWeekDays[i];
|
|
|
|
ret.push({
|
|
type: weekDay.type,
|
|
displayName: t(`datetime.${weekDay.name}.long`)
|
|
});
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getLocalizedDateTimeFormats<T extends DateFormat | TimeFormat>(type: string, allFormatMap: Record<string, T>, allFormatArray: T[], languageDefaultTypeNameKey: string, systemDefaultFormatType: T): LocalizedDateTimeFormat[] {
|
|
const defaultFormat = getLocalizedDateTimeFormat<T>(type, allFormatMap, allFormatArray, LANGUAGE_DEFAULT_DATE_TIME_FORMAT_VALUE, languageDefaultTypeNameKey, systemDefaultFormatType);
|
|
const ret: LocalizedDateTimeFormat[] = [];
|
|
|
|
ret.push({
|
|
type: LANGUAGE_DEFAULT_DATE_TIME_FORMAT_VALUE,
|
|
format: defaultFormat,
|
|
displayName: `${t('Language Default')} (${formatCurrentTime(defaultFormat)})`
|
|
});
|
|
|
|
for (let i = 0; i < allFormatArray.length; i++) {
|
|
const formatType = allFormatArray[i];
|
|
const format = t(`format.${type}.${formatType.key}`);
|
|
|
|
ret.push({
|
|
type: formatType.type,
|
|
format: format,
|
|
displayName: formatCurrentTime(format)
|
|
});
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getAllDateRanges(scene: DateRangeScene, includeCustom?: boolean, includeBillingCycle?: boolean): LocalizedDateRange[] {
|
|
const ret: LocalizedDateRange[] = [];
|
|
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: t(dateRange.name),
|
|
isBillingCycle: dateRange.isBillingCycle
|
|
});
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (includeCustom || dateRange.type !== DateRange.Custom.type) {
|
|
ret.push({
|
|
type: dateRange.type,
|
|
displayName: t(dateRange.name)
|
|
});
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getAllRecentMonthDateRanges(includeAll: boolean, includeCustom: boolean): LocalizedRecentMonthDateRange[] {
|
|
const allRecentMonthDateRanges: LocalizedRecentMonthDateRange[] = [];
|
|
const recentDateRanges = getRecentMonthDateRanges(12);
|
|
|
|
if (includeAll) {
|
|
allRecentMonthDateRanges.push({
|
|
dateType: DateRange.All.type,
|
|
minTime: 0,
|
|
maxTime: 0,
|
|
displayName: t('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, getLocalizedLongYearMonthFormat())
|
|
});
|
|
}
|
|
|
|
if (includeCustom) {
|
|
allRecentMonthDateRanges.push({
|
|
dateType: DateRange.Custom.type,
|
|
minTime: 0,
|
|
maxTime: 0,
|
|
displayName: t('Custom Date')
|
|
});
|
|
}
|
|
|
|
return allRecentMonthDateRanges;
|
|
}
|
|
|
|
function getAllTimezones(includeSystemDefault?: boolean): LocalizedTimezoneInfo[] {
|
|
const defaultTimezoneOffset = getBrowserTimezoneOffset();
|
|
const defaultTimezoneOffsetMinutes = getBrowserTimezoneOffsetMinutes();
|
|
const allTimezoneInfos: LocalizedTimezoneInfo[] = [];
|
|
|
|
for (let i = 0; i < ALL_TIMEZONES.length; i++) {
|
|
const utcOffset = (ALL_TIMEZONES[i].timezoneName !== UTC_TIMEZONE.timezoneName ? getTimezoneOffset(ALL_TIMEZONES[i].timezoneName) : '');
|
|
const displayName = t(`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 = t('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 getAllTimezoneTypesUsedForStatistics(currentTimezone?: string): TypeAndDisplayName[] {
|
|
const currentTimezoneOffset = getTimezoneOffset(currentTimezone);
|
|
|
|
return [
|
|
{
|
|
type: TimezoneTypeForStatistics.ApplicationTimezone.type,
|
|
displayName: t(TimezoneTypeForStatistics.ApplicationTimezone.name) + ` (UTC${currentTimezoneOffset})`
|
|
},
|
|
{
|
|
type: TimezoneTypeForStatistics.TransactionTimezone.type,
|
|
displayName: t(TimezoneTypeForStatistics.TransactionTimezone.name)
|
|
}
|
|
];
|
|
}
|
|
|
|
function getAllFiscalYearFormats(): TypeAndDisplayName[] {
|
|
const now = getCurrentUnixTime();
|
|
let fiscalYearStart = userStore.currentUserFiscalYearStart;
|
|
|
|
if (!fiscalYearStart) {
|
|
fiscalYearStart = FiscalYearStart.Default.value;
|
|
}
|
|
|
|
const currentFiscalYearRange = getFiscalYearTimeRangeFromUnixTime(now, fiscalYearStart);
|
|
const ret: TypeAndDisplayName[] = [];
|
|
|
|
let fiscalYearFormat = FiscalYearFormat.parse(getDefaultFiscalYearFormat());
|
|
|
|
if (!fiscalYearFormat) {
|
|
fiscalYearFormat = FiscalYearFormat.Default;
|
|
}
|
|
|
|
ret.push({
|
|
type: LANGUAGE_DEFAULT_FISCAL_YEAR_FORMAT_VALUE,
|
|
displayName: `${t('Language Default')} (${formatTimeRangeToFiscalYearFormat(fiscalYearFormat, currentFiscalYearRange)})`
|
|
});
|
|
|
|
const allFiscalYearFormats = FiscalYearFormat.values();
|
|
|
|
for (let i = 0; i < allFiscalYearFormats.length; i++) {
|
|
const format = allFiscalYearFormats[i];
|
|
|
|
ret.push({
|
|
type: format.type,
|
|
displayName: formatTimeRangeToFiscalYearFormat(format, currentFiscalYearRange),
|
|
});
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getAllDigitGroupingTypes(): LocalizedDigitGroupingType[] {
|
|
const defaultDigitGroupingTypeName = t('default.digitGrouping');
|
|
let defaultDigitGroupingType = DigitGroupingType.parse(defaultDigitGroupingTypeName);
|
|
|
|
if (!defaultDigitGroupingType) {
|
|
defaultDigitGroupingType = DigitGroupingType.Default;
|
|
}
|
|
|
|
const ret: LocalizedDigitGroupingType[] = [];
|
|
|
|
ret.push({
|
|
type: DigitGroupingType.LanguageDefaultType,
|
|
enabled: defaultDigitGroupingType.enabled,
|
|
displayName: `${t('Language Default')} (${t('numeral.' + defaultDigitGroupingType.name)})`
|
|
});
|
|
|
|
const allDigitGroupingTypes = DigitGroupingType.values();
|
|
|
|
for (let i = 0; i < allDigitGroupingTypes.length; i++) {
|
|
const type = allDigitGroupingTypes[i];
|
|
|
|
ret.push({
|
|
type: type.type,
|
|
enabled: type.enabled,
|
|
displayName: t('numeral.' + type.name)
|
|
});
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getAllExpenseIncomeAmountColors(categoryType: CategoryType): TypeAndDisplayName[] {
|
|
const ret: TypeAndDisplayName[] = [];
|
|
let defaultAmountName = '';
|
|
|
|
if (categoryType === CategoryType.Expense) {
|
|
defaultAmountName = PresetAmountColor.DefaultExpenseColor.name;
|
|
} else if (categoryType === CategoryType.Income) { // income
|
|
defaultAmountName = PresetAmountColor.DefaultIncomeColor.name;
|
|
}
|
|
|
|
if (defaultAmountName) {
|
|
defaultAmountName = t('color.amount.' + defaultAmountName);
|
|
}
|
|
|
|
ret.push({
|
|
type: PresetAmountColor.SystemDefaultType,
|
|
displayName: t('System Default') + (defaultAmountName ? ` (${defaultAmountName})` : '')
|
|
});
|
|
|
|
const allPresetAmountColors = PresetAmountColor.values();
|
|
|
|
for (let i = 0; i < allPresetAmountColors.length; i++) {
|
|
const amountColor = allPresetAmountColors[i];
|
|
|
|
ret.push({
|
|
type: amountColor.type,
|
|
displayName: t('color.amount.' + amountColor.name)
|
|
});
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getAllAccountCategories(): LocalizedAccountCategory[] {
|
|
const ret: LocalizedAccountCategory[] = [];
|
|
const allCategories = AccountCategory.values();
|
|
|
|
for (let i = 0; i < allCategories.length; i++) {
|
|
const accountCategory = allCategories[i];
|
|
|
|
ret.push({
|
|
type: accountCategory.type,
|
|
displayName: t(accountCategory.name),
|
|
defaultAccountIconId: accountCategory.defaultAccountIconId
|
|
});
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function getAllTransactionDefaultCategories(categoryType: 0 | CategoryType, locale: string): PartialRecord<CategoryType, LocalizedPresetCategory[]> {
|
|
const allCategories: PartialRecord<CategoryType, LocalizedPresetCategory[]> = {};
|
|
const categoryTypes: CategoryType[] = [];
|
|
|
|
if (categoryType === 0) {
|
|
categoryTypes.push(...ALL_CATEGORY_TYPES);
|
|
} else {
|
|
categoryTypes.push(categoryType);
|
|
}
|
|
|
|
for (let i = 0; i < categoryTypes.length; i++) {
|
|
const categories: LocalizedPresetCategory[] = [];
|
|
const categoryType = categoryTypes[i];
|
|
let defaultCategories: PresetCategory[] = [];
|
|
|
|
if (categoryType === CategoryType.Income) {
|
|
defaultCategories = DEFAULT_INCOME_CATEGORIES;
|
|
} else if (categoryType === CategoryType.Expense) {
|
|
defaultCategories = DEFAULT_EXPENSE_CATEGORIES;
|
|
} else if (categoryType === CategoryType.Transfer) {
|
|
defaultCategories = DEFAULT_TRANSFER_CATEGORIES;
|
|
}
|
|
|
|
for (let j = 0; j < defaultCategories.length; j++) {
|
|
const category = defaultCategories[j];
|
|
|
|
const submitCategory: LocalizedPresetCategory = {
|
|
name: t('category.' + category.name, {}, { locale: locale }),
|
|
type: categoryType,
|
|
icon: category.categoryIconId,
|
|
color: category.color,
|
|
subCategories: []
|
|
};
|
|
|
|
for (let k = 0; k < category.subCategories.length; k++) {
|
|
const subCategory = category.subCategories[k];
|
|
const submitSubCategory: LocalizedPresetSubCategory = {
|
|
name: t('category.' + subCategory.name, {}, { locale: locale }),
|
|
type: categoryType,
|
|
icon: subCategory.categoryIconId,
|
|
color: subCategory.color
|
|
};
|
|
|
|
submitCategory.subCategories.push(submitSubCategory);
|
|
}
|
|
|
|
categories.push(submitCategory);
|
|
}
|
|
|
|
allCategories[categoryType] = categories;
|
|
}
|
|
|
|
return allCategories;
|
|
}
|
|
|
|
function getAllDisplayExchangeRates(exchangeRatesData?: LatestExchangeRateResponse): LocalizedLatestExchangeRate[] {
|
|
const availableExchangeRates: LocalizedLatestExchangeRate[] = [];
|
|
|
|
if (!exchangeRatesData || !exchangeRatesData.exchangeRates) {
|
|
return availableExchangeRates;
|
|
}
|
|
|
|
for (let i = 0; i < exchangeRatesData.exchangeRates.length; i++) {
|
|
const exchangeRate = exchangeRatesData.exchangeRates[i];
|
|
|
|
availableExchangeRates.push({
|
|
currencyCode: exchangeRate.currency,
|
|
currencyDisplayName: getCurrencyName(exchangeRate.currency),
|
|
rate: exchangeRate.rate
|
|
});
|
|
}
|
|
|
|
if (settingsStore.appSettings.currencySortByInExchangeRatesPage === CurrencySortingType.Name.type) {
|
|
availableExchangeRates.sort(function(c1, c2) {
|
|
return c1.currencyDisplayName.localeCompare(c2.currencyDisplayName);
|
|
});
|
|
} else if (settingsStore.appSettings.currencySortByInExchangeRatesPage === CurrencySortingType.CurrencyCode.type) {
|
|
availableExchangeRates.sort(function(c1, c2) {
|
|
return c1.currencyCode.localeCompare(c2.currencyCode);
|
|
});
|
|
} else if (settingsStore.appSettings.currencySortByInExchangeRatesPage === CurrencySortingType.ExchangeRate.type) {
|
|
availableExchangeRates.sort(function(c1, c2) {
|
|
const rate1 = parseFloat(c1.rate);
|
|
const rate2 = parseFloat(c2.rate);
|
|
|
|
if (rate1 > rate2) {
|
|
return 1;
|
|
} else if (rate1 < rate2) {
|
|
return -1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
});
|
|
}
|
|
|
|
return availableExchangeRates;
|
|
}
|
|
|
|
function getAllSupportedImportFileTypes(): LocalizedImportFileType[] {
|
|
const allSupportedImportFileTypes: LocalizedImportFileType[] = [];
|
|
|
|
for (let i = 0; i < SUPPORTED_IMPORT_FILE_TYPES.length; i++) {
|
|
const fileType = SUPPORTED_IMPORT_FILE_TYPES[i];
|
|
let document: LocalizedImportFileDocument | undefined;
|
|
|
|
if (fileType.document) {
|
|
let documentLanguage = '';
|
|
let documentDisplayLanguageName = '';
|
|
let documentAnchor = '';
|
|
|
|
if (fileType.document.supportMultiLanguages === true) {
|
|
documentLanguage = getCurrentLanguageTag();
|
|
|
|
if (SUPPORTED_DOCUMENT_LANGUAGES_FOR_IMPORT_FILE[documentLanguage] === documentLanguage) {
|
|
documentAnchor = t(`document.anchor.export_and_import.${fileType.document.anchor}`);
|
|
} else if (SUPPORTED_DOCUMENT_LANGUAGES_FOR_IMPORT_FILE[documentLanguage]) {
|
|
documentLanguage = SUPPORTED_DOCUMENT_LANGUAGES_FOR_IMPORT_FILE[documentLanguage];
|
|
documentAnchor = t(`document.anchor.export_and_import.${fileType.document.anchor}`, {}, { locale: documentLanguage });
|
|
} else {
|
|
documentLanguage = DEFAULT_DOCUMENT_LANGUAGE_FOR_IMPORT_FILE;
|
|
documentAnchor = t(`document.anchor.export_and_import.${fileType.document.anchor}`, {}, { locale: documentLanguage });
|
|
}
|
|
} else if (isString(fileType.document.supportMultiLanguages) && ALL_LANGUAGES[fileType.document.supportMultiLanguages]) {
|
|
documentLanguage = fileType.document.supportMultiLanguages;
|
|
documentAnchor = fileType.document.anchor;
|
|
}
|
|
|
|
if (documentLanguage && documentLanguage !== getCurrentLanguageTag()) {
|
|
documentDisplayLanguageName = getLanguageDisplayName(ALL_LANGUAGES[documentLanguage].name);
|
|
}
|
|
|
|
if (documentLanguage) {
|
|
documentLanguage = documentLanguage.replace(/-/g, '_');
|
|
}
|
|
|
|
if (documentAnchor) {
|
|
documentAnchor = documentAnchor.toLowerCase().replace(/ /g, '-');
|
|
}
|
|
|
|
if (documentLanguage === DEFAULT_LANGUAGE) {
|
|
documentLanguage = '';
|
|
}
|
|
|
|
document = {
|
|
language: documentLanguage,
|
|
displayLanguageName: documentDisplayLanguageName,
|
|
anchor: documentAnchor
|
|
};
|
|
} else {
|
|
document = undefined;
|
|
}
|
|
|
|
const subTypes: LocalizedImportFileTypeSubType[] = [];
|
|
|
|
if (fileType.subTypes) {
|
|
for (let i = 0; i < fileType.subTypes.length; i++) {
|
|
const subType = fileType.subTypes[i];
|
|
const localizedSubType: LocalizedImportFileTypeSubType = {
|
|
type: subType.type,
|
|
displayName: t(subType.name),
|
|
extensions: subType.extensions
|
|
};
|
|
|
|
subTypes.push(localizedSubType);
|
|
}
|
|
}
|
|
|
|
const supportedEncodings: LocalizedImportFileTypeSupportedEncodings[] = [];
|
|
|
|
if (fileType.supportedEncodings) {
|
|
for (let i = 0; i < fileType.supportedEncodings.length; i++) {
|
|
const encoding = fileType.supportedEncodings[i];
|
|
const localizedEncoding: LocalizedImportFileTypeSupportedEncodings = {
|
|
encoding: encoding,
|
|
displayName: t(`encoding.${encoding}`)
|
|
};
|
|
|
|
supportedEncodings.push(localizedEncoding);
|
|
}
|
|
}
|
|
|
|
const localizedFileType: LocalizedImportFileType = {
|
|
type: fileType.type,
|
|
displayName: t(fileType.name),
|
|
extensions: fileType.extensions,
|
|
subTypes: subTypes.length ? subTypes : undefined,
|
|
supportedEncodings: supportedEncodings.length ? supportedEncodings : undefined,
|
|
dataFromTextbox: fileType.dataFromTextbox,
|
|
document: document
|
|
};
|
|
allSupportedImportFileTypes.push(localizedFileType);
|
|
}
|
|
|
|
return allSupportedImportFileTypes;
|
|
}
|
|
|
|
function getLanguageInfo(languageKey: string): LanguageInfo | undefined {
|
|
return ALL_LANGUAGES[languageKey];
|
|
}
|
|
|
|
function getMonthShortName(monthName: string): string {
|
|
return t(`datetime.${monthName}.short`);
|
|
}
|
|
|
|
function getMonthLongName(monthName: string): string {
|
|
return t(`datetime.${monthName}.long`);
|
|
}
|
|
|
|
function getMonthdayOrdinal(monthDay: number): string {
|
|
return t(`datetime.monthDayOrdinal.${monthDay}`);
|
|
}
|
|
|
|
function getMonthdayShortName(monthDay: number): string {
|
|
return t('format.misc.monthDay', {
|
|
ordinal: getMonthdayOrdinal(monthDay)
|
|
});
|
|
}
|
|
|
|
function getWeekdayShortName(weekDayName: string): string {
|
|
return t(`datetime.${weekDayName}.short`);
|
|
}
|
|
|
|
function getWeekdayLongName(weekDayName: string): string {
|
|
return t(`datetime.${weekDayName}.long`);
|
|
}
|
|
|
|
function getMultiMonthdayShortNames(monthDays: number[]): string {
|
|
if (!monthDays) {
|
|
return '';
|
|
}
|
|
|
|
if (monthDays.length === 1) {
|
|
return t('format.misc.monthDay', {
|
|
ordinal: getMonthdayOrdinal(monthDays[0])
|
|
});
|
|
} else {
|
|
return t('format.misc.monthDays', {
|
|
multiMonthDays: joinMultiText(monthDays.map(monthDay =>
|
|
t('format.misc.eachMonthDayInMonthDays', {
|
|
ordinal: getMonthdayOrdinal(monthDay)
|
|
})))
|
|
});
|
|
}
|
|
}
|
|
|
|
function getMultiWeekdayLongNames(weekdayTypes: number[], firstDayOfWeek?: number): string {
|
|
const weekdayTypesMap: Record<number, boolean> = {};
|
|
|
|
if (!isNumber(firstDayOfWeek)) {
|
|
firstDayOfWeek = WeekDay.DefaultFirstDay.type;
|
|
}
|
|
|
|
for (let i = 0; i < weekdayTypes.length; i++) {
|
|
weekdayTypesMap[weekdayTypes[i]] = true;
|
|
}
|
|
|
|
const allWeekDays = getAllWeekDays(firstDayOfWeek);
|
|
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);
|
|
}
|
|
|
|
function getCurrentDecimalSeparator(): string {
|
|
let decimalSeparatorType = DecimalSeparator.valueOf(userStore.currentUserDecimalSeparator);
|
|
|
|
if (!decimalSeparatorType) {
|
|
const defaultDecimalSeparatorTypeName = t('default.decimalSeparator');
|
|
decimalSeparatorType = DecimalSeparator.parse(defaultDecimalSeparatorTypeName);
|
|
|
|
if (!decimalSeparatorType) {
|
|
decimalSeparatorType = DecimalSeparator.Default;
|
|
}
|
|
}
|
|
|
|
return decimalSeparatorType.symbol;
|
|
}
|
|
|
|
function getCurrentDigitGroupingSymbol(): string {
|
|
let digitGroupingSymbolType = DigitGroupingSymbol.valueOf(userStore.currentUserDigitGroupingSymbol);
|
|
|
|
if (!digitGroupingSymbolType) {
|
|
const defaultDigitGroupingSymbolTypeName = t('default.digitGroupingSymbol');
|
|
digitGroupingSymbolType = DigitGroupingSymbol.parse(defaultDigitGroupingSymbolTypeName);
|
|
|
|
if (!digitGroupingSymbolType) {
|
|
digitGroupingSymbolType = DigitGroupingSymbol.Default;
|
|
}
|
|
}
|
|
|
|
return digitGroupingSymbolType.symbol;
|
|
}
|
|
|
|
function getCurrentDigitGroupingType(): number {
|
|
let digitGroupingType = DigitGroupingType.valueOf(userStore.currentUserDigitGrouping);
|
|
|
|
if (!digitGroupingType) {
|
|
const defaultDigitGroupingTypeName = t('default.digitGrouping');
|
|
digitGroupingType = DigitGroupingType.parse(defaultDigitGroupingTypeName);
|
|
|
|
if (!digitGroupingType) {
|
|
digitGroupingType = DigitGroupingType.Default;
|
|
}
|
|
}
|
|
|
|
return digitGroupingType.type;
|
|
}
|
|
|
|
function getCurrentFiscalYearFormatType(): number {
|
|
let fiscalYearFormat = FiscalYearFormat.valueOf(userStore.currentUserFiscalYearFormat);
|
|
|
|
if (!fiscalYearFormat) {
|
|
const defaultFiscalYearFormatTypeName = getDefaultFiscalYearFormat();
|
|
fiscalYearFormat = FiscalYearFormat.parse(defaultFiscalYearFormatTypeName);
|
|
|
|
if (!fiscalYearFormat) {
|
|
fiscalYearFormat = FiscalYearFormat.Default;
|
|
}
|
|
}
|
|
|
|
return fiscalYearFormat.type;
|
|
}
|
|
|
|
function getCurrencyName(currencyCode: string): string {
|
|
return t(`currency.name.${currencyCode}`);
|
|
}
|
|
|
|
function isLongDateMonthAfterYear(): boolean {
|
|
return getLocalizedDateTimeType(LongDateFormat.all(), LongDateFormat.values(), userStore.currentUserLongDateFormat, 'longDateFormat', LongDateFormat.Default).isMonthAfterYear;
|
|
}
|
|
|
|
function isShortDateMonthAfterYear(): boolean {
|
|
return getLocalizedDateTimeType(ShortDateFormat.all(), ShortDateFormat.values(), userStore.currentUserShortDateFormat, 'shortDateFormat', ShortDateFormat.Default).isMonthAfterYear;
|
|
}
|
|
|
|
function isLongTime24HourFormat(): boolean {
|
|
return getLocalizedDateTimeType(LongTimeFormat.all(), LongTimeFormat.values(), userStore.currentUserLongTimeFormat, 'longTimeFormat', LongTimeFormat.Default).is24HourFormat;
|
|
}
|
|
|
|
function isLongTimeMeridiemIndicatorFirst(): boolean {
|
|
return getLocalizedDateTimeType(LongTimeFormat.all(), LongTimeFormat.values(), userStore.currentUserLongTimeFormat, 'longTimeFormat', LongTimeFormat.Default).isMeridiemIndicatorFirst || false;
|
|
}
|
|
|
|
function isShortTime24HourFormat(): boolean {
|
|
return getLocalizedDateTimeType(ShortTimeFormat.all(), ShortTimeFormat.values(), userStore.currentUserShortTimeFormat, 'shortTimeFormat', ShortTimeFormat.Default).is24HourFormat;
|
|
}
|
|
|
|
function isShortTimeMeridiemIndicatorFirst(): boolean {
|
|
return getLocalizedDateTimeType(ShortTimeFormat.all(), ShortTimeFormat.values(), userStore.currentUserShortTimeFormat, 'shortTimeFormat', ShortTimeFormat.Default).isMeridiemIndicatorFirst || false;
|
|
}
|
|
|
|
function formatDateToLongDate(date: string): string {
|
|
return formatDate(date, getLocalizedLongDateFormat());
|
|
}
|
|
|
|
function formatMonthDayToLongDay(monthDay: string): string {
|
|
return formatMonthDay(monthDay, getLocalizedLongMonthDayFormat());
|
|
}
|
|
|
|
function formatYearQuarter(year: number, quarter: number): string {
|
|
if (1 <= quarter && quarter <= 4) {
|
|
return t('format.yearQuarter.q' + quarter, {
|
|
year: year,
|
|
quarter: quarter
|
|
});
|
|
} else {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
function formatDateRange(dateType: number, startTime: number, endTime: number): string {
|
|
if (dateType === DateRange.All.type) {
|
|
return t(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 t(dateRange.name);
|
|
}
|
|
}
|
|
|
|
if (isDateRangeMatchFullYears(startTime, endTime)) {
|
|
const format = getLocalizedShortYearFormat();
|
|
const displayStartTime = formatUnixTime(startTime, format);
|
|
const displayEndTime = formatUnixTime(endTime, format);
|
|
|
|
return displayStartTime !== displayEndTime ? `${displayStartTime} ~ ${displayEndTime}` : displayStartTime;
|
|
}
|
|
|
|
if (isDateRangeMatchFullMonths(startTime, endTime)) {
|
|
const format = getLocalizedShortYearMonthFormat();
|
|
const displayStartTime = formatUnixTime(startTime, format);
|
|
const displayEndTime = formatUnixTime(endTime, format);
|
|
|
|
return displayStartTime !== displayEndTime ? `${displayStartTime} ~ ${displayEndTime}` : displayStartTime;
|
|
}
|
|
|
|
const startTimeYear = getYear(parseDateFromUnixTime(startTime));
|
|
const endTimeYear = getYear(parseDateFromUnixTime(endTime));
|
|
|
|
const format = getLocalizedShortDateFormat();
|
|
const displayStartTime = formatUnixTime(startTime, format);
|
|
const displayEndTime = formatUnixTime(endTime, format);
|
|
|
|
if (displayStartTime === displayEndTime) {
|
|
return displayStartTime;
|
|
} else if (startTimeYear === endTimeYear) {
|
|
const displayShortEndTime = formatUnixTime(endTime, getLocalizedShortMonthDayFormat());
|
|
return `${displayStartTime} ~ ${displayShortEndTime}`;
|
|
}
|
|
|
|
return `${displayStartTime} ~ ${displayEndTime}`;
|
|
}
|
|
|
|
function formatTimeRangeToFiscalYearFormat(format: FiscalYearFormat, timeRange: FiscalYearUnixTime | UnixTimeRange): string {
|
|
if (!format) {
|
|
format = FiscalYearFormat.Default;
|
|
}
|
|
|
|
return t('format.fiscalYear.' + format.typeName, {
|
|
StartYYYY: formatUnixTime(timeRange.minUnixTime, 'YYYY'),
|
|
StartYY: formatUnixTime(timeRange.minUnixTime, 'YY'),
|
|
EndYYYY: formatUnixTime(timeRange.maxUnixTime, 'YYYY'),
|
|
EndYY: formatUnixTime(timeRange.maxUnixTime, 'YY'),
|
|
});
|
|
}
|
|
|
|
function formatUnixTimeToFiscalYear(unixTime: number): string {
|
|
let fiscalYearFormat = FiscalYearFormat.valueOf(getCurrentFiscalYearFormatType());
|
|
|
|
if (!fiscalYearFormat) {
|
|
fiscalYearFormat = FiscalYearFormat.Default;
|
|
}
|
|
|
|
const timeRange = getFiscalYearTimeRangeFromUnixTime(unixTime, userStore.currentUserFiscalYearStart);
|
|
return formatTimeRangeToFiscalYearFormat(fiscalYearFormat, timeRange);
|
|
}
|
|
|
|
function formatYearToFiscalYear(year: number) {
|
|
let fiscalYearFormat = FiscalYearFormat.valueOf(getCurrentFiscalYearFormatType());
|
|
|
|
if (!fiscalYearFormat) {
|
|
fiscalYearFormat = FiscalYearFormat.Default;
|
|
}
|
|
|
|
const timeRange = getFiscalYearTimeRangeFromYear(year, userStore.currentUserFiscalYearStart);
|
|
return formatTimeRangeToFiscalYearFormat(fiscalYearFormat, timeRange);
|
|
}
|
|
|
|
function formatFiscalYearStartToLongDay(fiscalYearStartValue: number) {
|
|
let fiscalYearStart = FiscalYearStart.valueOf(fiscalYearStartValue);
|
|
|
|
if (!fiscalYearStart) {
|
|
fiscalYearStart = FiscalYearStart.Default;
|
|
}
|
|
|
|
return formatMonthDayToLongDay(fiscalYearStart.toMonthDashDayString());
|
|
}
|
|
|
|
function getTimezoneDifferenceDisplayText(utcOffset: number): string {
|
|
const defaultTimezoneOffset = getTimezoneOffsetMinutes();
|
|
const offsetTime = getTimeDifferenceHoursAndMinutes(utcOffset - defaultTimezoneOffset);
|
|
|
|
if (utcOffset > defaultTimezoneOffset) {
|
|
if (offsetTime.offsetMinutes) {
|
|
return t('format.misc.hoursMinutesAheadOfDefaultTimezone', {
|
|
hours: offsetTime.offsetHours,
|
|
minutes: offsetTime.offsetMinutes
|
|
});
|
|
} else {
|
|
return t('format.misc.hoursAheadOfDefaultTimezone', {
|
|
hours: offsetTime.offsetHours
|
|
});
|
|
}
|
|
} else if (utcOffset < defaultTimezoneOffset) {
|
|
if (offsetTime.offsetMinutes) {
|
|
return t('format.misc.hoursMinutesBehindDefaultTimezone', {
|
|
hours: offsetTime.offsetHours,
|
|
minutes: offsetTime.offsetMinutes
|
|
});
|
|
} else {
|
|
return t('format.misc.hoursBehindDefaultTimezone', {
|
|
hours: offsetTime.offsetHours
|
|
});
|
|
}
|
|
} else {
|
|
return t('Same time as default timezone');
|
|
}
|
|
}
|
|
|
|
function getNumberWithDigitGroupingSymbol(value: number | string): string {
|
|
const numberFormatOptions = getNumberFormatOptions();
|
|
return appendDigitGroupingSymbol(value, numberFormatOptions);
|
|
}
|
|
|
|
function getParsedAmountNumber(value: string): number {
|
|
const numberFormatOptions = getNumberFormatOptions();
|
|
return parseAmount(value, numberFormatOptions);
|
|
}
|
|
|
|
function getFormattedAmount(value: number | string, currencyCode?: string): string {
|
|
const numberFormatOptions = getNumberFormatOptions(currencyCode);
|
|
return formatAmount(value, numberFormatOptions);
|
|
}
|
|
|
|
function getFormattedAmountWithCurrency(value: number | string, currencyCode?: string | false, notConvertValue?: boolean, currencyDisplayType?: CurrencyDisplayType): string {
|
|
if (isNumber(value)) {
|
|
value = value.toString();
|
|
}
|
|
|
|
let textualValue = value;
|
|
const isPlural: boolean = textualValue !== '100' && textualValue !== '-100';
|
|
|
|
if (!notConvertValue) {
|
|
const numberFormatOptions = getNumberFormatOptions();
|
|
const hasIncompleteFlag = isString(textualValue) && textualValue.charAt(textualValue.length - 1) === '+';
|
|
|
|
if (hasIncompleteFlag) {
|
|
textualValue = textualValue.substring(0, textualValue.length - 1);
|
|
}
|
|
|
|
textualValue = formatAmount(textualValue, numberFormatOptions);
|
|
|
|
if (hasIncompleteFlag) {
|
|
textualValue = textualValue + '+';
|
|
}
|
|
}
|
|
|
|
let finalCurrencyCode = '';
|
|
|
|
if (!isBoolean(currencyCode) && !currencyCode) {
|
|
finalCurrencyCode = userStore.currentUserDefaultCurrency;
|
|
} else if (isBoolean(currencyCode) && !currencyCode) {
|
|
finalCurrencyCode = '';
|
|
} else {
|
|
finalCurrencyCode = currencyCode;
|
|
}
|
|
|
|
if (!finalCurrencyCode) {
|
|
return textualValue;
|
|
}
|
|
|
|
if (!currencyDisplayType) {
|
|
currencyDisplayType = getCurrentCurrencyDisplayType();
|
|
}
|
|
|
|
const currencyUnit = getCurrencyUnitName(finalCurrencyCode, isPlural);
|
|
const currencyName = getCurrencyName(finalCurrencyCode);
|
|
return appendCurrencySymbol(textualValue, currencyDisplayType, finalCurrencyCode, currencyUnit, currencyName, isPlural);
|
|
}
|
|
|
|
function getFormattedNumber(value: number, precision: number): string {
|
|
const numberFormatOptions = getNumberFormatOptions();
|
|
return formatNumber(value, precision, numberFormatOptions);
|
|
}
|
|
|
|
function getFormattedPercentValue(value: number, precision: number, lowPrecisionValue: string): string {
|
|
const numberFormatOptions = getNumberFormatOptions();
|
|
return formatPercent(value, precision, lowPrecisionValue, numberFormatOptions);
|
|
}
|
|
|
|
function getFormattedExchangeRateAmount(value: number | string): string {
|
|
const numberFormatOptions = getNumberFormatOptions();
|
|
return formatExchangeRateAmount(value, numberFormatOptions);
|
|
}
|
|
|
|
function getAdaptiveAmountRate(amount1: number, amount2: number, fromExchangeRate: { rate: string }, toExchangeRate: { rate: string }): string | null {
|
|
const numberFormatOptions = getNumberFormatOptions();
|
|
return getAdaptiveDisplayAmountRate(amount1, amount2, fromExchangeRate, toExchangeRate, numberFormatOptions);
|
|
}
|
|
|
|
function getAmountPrependAndAppendText(currencyCode: string, isPlural: boolean): CurrencyPrependAndAppendText | null {
|
|
const currencyDisplayType = getCurrentCurrencyDisplayType();
|
|
const currencyUnit = getCurrencyUnitName(currencyCode, isPlural);
|
|
const currencyName = getCurrencyName(currencyCode);
|
|
return getAmountPrependAndAppendCurrencySymbol(currencyDisplayType, currencyCode, currencyUnit, currencyName, isPlural);
|
|
}
|
|
|
|
function getCategorizedAccountsWithDisplayBalance(allVisibleAccounts: Account[], showAccountBalance: boolean): CategorizedAccountWithDisplayBalance[] {
|
|
const ret: CategorizedAccountWithDisplayBalance[] = [];
|
|
const defaultCurrency = userStore.currentUserDefaultCurrency;
|
|
const allCategories = AccountCategory.values();
|
|
const categorizedAccounts: Record<number, CategorizedAccount> = getCategorizedAccountsMap(Account.cloneAccounts(allVisibleAccounts));
|
|
|
|
for (let i = 0; i < allCategories.length; i++) {
|
|
const category = allCategories[i];
|
|
|
|
if (!categorizedAccounts[category.type]) {
|
|
continue;
|
|
}
|
|
|
|
const accountCategory = categorizedAccounts[category.type];
|
|
const accountsWithDisplayBalance: AccountWithDisplayBalance[] = [];
|
|
|
|
if (accountCategory.accounts) {
|
|
for (let i = 0; i < accountCategory.accounts.length; i++) {
|
|
const account = accountCategory.accounts[i];
|
|
let accountWithDisplaceBalance: AccountWithDisplayBalance;
|
|
|
|
if (showAccountBalance && account.isAsset) {
|
|
accountWithDisplaceBalance = AccountWithDisplayBalance.fromAccount(account, getFormattedAmountWithCurrency(account.balance, account.currency));
|
|
} else if (showAccountBalance && account.isLiability) {
|
|
accountWithDisplaceBalance = AccountWithDisplayBalance.fromAccount(account, getFormattedAmountWithCurrency(-account.balance, account.currency));
|
|
} else {
|
|
accountWithDisplaceBalance = AccountWithDisplayBalance.fromAccount(account, '***');
|
|
}
|
|
|
|
accountsWithDisplayBalance.push(accountWithDisplaceBalance);
|
|
}
|
|
}
|
|
|
|
let finalTotalBalance = '';
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
finalTotalBalance = totalBalance.toString();
|
|
|
|
if (hasUnCalculatedAmount) {
|
|
finalTotalBalance = finalTotalBalance + '+';
|
|
}
|
|
|
|
finalTotalBalance = getFormattedAmountWithCurrency(finalTotalBalance, defaultCurrency);
|
|
} else {
|
|
finalTotalBalance = '***';
|
|
}
|
|
|
|
const accountCategoryWithDisplayBalance = CategorizedAccountWithDisplayBalance.of(accountCategory, accountsWithDisplayBalance, finalTotalBalance);
|
|
ret.push(accountCategoryWithDisplayBalance);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function setLanguage(languageKey: string | null, force?: boolean): LocaleDefaultSettings | null {
|
|
if (!languageKey) {
|
|
languageKey = getDefaultLanguage();
|
|
logger.info(`No specified language, use browser default language ${languageKey}`);
|
|
}
|
|
|
|
if (!getLanguageInfo(languageKey)) {
|
|
languageKey = getDefaultLanguage();
|
|
logger.warn(`Not found language ${languageKey}, use browser default language ${languageKey}`);
|
|
}
|
|
|
|
if (!force && locale.value === languageKey) {
|
|
logger.info(`Current locale is already ${languageKey}`);
|
|
return null;
|
|
}
|
|
|
|
logger.info(`Apply current language to ${languageKey}`);
|
|
|
|
locale.value = languageKey;
|
|
moment.updateLocale(languageKey, {
|
|
months : getAllLongMonthNames(),
|
|
monthsShort : getAllShortMonthNames(),
|
|
weekdays : getAllLongWeekdayNames(),
|
|
weekdaysShort : getAllShortWeekdayNames(),
|
|
weekdaysMin : getAllMinWeekdayNames(),
|
|
meridiem: function (hours) {
|
|
if (isPM(hours)) {
|
|
return t(`datetime.${MeridiemIndicator.PM.name}.content`);
|
|
} else {
|
|
return t(`datetime.${MeridiemIndicator.AM.name}.content`);
|
|
}
|
|
}
|
|
});
|
|
|
|
services.setLocale(languageKey);
|
|
document.querySelector('html')?.setAttribute('lang', languageKey);
|
|
|
|
const defaultCurrency = getDefaultCurrency();
|
|
const defaultFirstDayOfWeekName = getDefaultFirstDayOfWeek();
|
|
let defaultFirstDayOfWeek = WeekDay.DefaultFirstDay.type;
|
|
|
|
if (WeekDay.parse(defaultFirstDayOfWeekName)) {
|
|
defaultFirstDayOfWeek = (WeekDay.parse(defaultFirstDayOfWeekName) as WeekDay).type;
|
|
}
|
|
|
|
return {
|
|
currency: defaultCurrency,
|
|
firstDayOfWeek: defaultFirstDayOfWeek
|
|
};
|
|
}
|
|
|
|
function setTimeZone(timezone: string): void {
|
|
if (timezone) {
|
|
moment.tz.setDefault(timezone);
|
|
} else {
|
|
moment.tz.setDefault();
|
|
}
|
|
}
|
|
|
|
function initLocale(lastUserLanguage?: string, timezone?: string): LocaleDefaultSettings | null {
|
|
let localeDefaultSettings: LocaleDefaultSettings | null = null;
|
|
|
|
if (lastUserLanguage && getLanguageInfo(lastUserLanguage)) {
|
|
logger.info(`Last user language is ${lastUserLanguage}`);
|
|
localeDefaultSettings = setLanguage(lastUserLanguage, true);
|
|
} else {
|
|
localeDefaultSettings = setLanguage(null, true);
|
|
}
|
|
|
|
if (timezone) {
|
|
logger.info(`Current timezone is ${timezone}`);
|
|
setTimeZone(timezone);
|
|
} else {
|
|
logger.info(`No timezone is set, use browser default ${getTimezoneOffset()} (maybe ${moment.tz.guess(true)})`);
|
|
}
|
|
|
|
return localeDefaultSettings;
|
|
}
|
|
|
|
return {
|
|
// common functions
|
|
tt: t,
|
|
ti: translateIf,
|
|
te: translateError,
|
|
joinMultiText,
|
|
getServerTipContent,
|
|
// get current language info
|
|
getCurrentLanguageTag,
|
|
getCurrentLanguageInfo,
|
|
getCurrentLanguageDisplayName,
|
|
// get localization default type
|
|
getDefaultCurrency,
|
|
getDefaultFirstDayOfWeek,
|
|
getDefaultFiscalYearFormat,
|
|
// get all localized info of specified type
|
|
getAllLanguageOptions,
|
|
getAllEnableDisableOptions,
|
|
getAllCurrencies,
|
|
getAllMeridiemIndicators,
|
|
getAllLongMonthNames,
|
|
getAllShortMonthNames,
|
|
getAllLongWeekdayNames,
|
|
getAllShortWeekdayNames,
|
|
getAllMinWeekdayNames,
|
|
getAllWeekDays,
|
|
getAllLongDateFormats: () => getLocalizedDateTimeFormats<LongDateFormat>('longDate', LongDateFormat.all(), LongDateFormat.values(), 'longDateFormat', LongDateFormat.Default),
|
|
getAllShortDateFormats: () => getLocalizedDateTimeFormats<ShortDateFormat>('shortDate', ShortDateFormat.all(), ShortDateFormat.values(), 'shortDateFormat', ShortDateFormat.Default),
|
|
getAllLongTimeFormats: () => getLocalizedDateTimeFormats<LongTimeFormat>('longTime', LongTimeFormat.all(), LongTimeFormat.values(), 'longTimeFormat', LongTimeFormat.Default),
|
|
getAllShortTimeFormats: () => getLocalizedDateTimeFormats<ShortTimeFormat>('shortTime', ShortTimeFormat.all(), ShortTimeFormat.values(), 'shortTimeFormat', ShortTimeFormat.Default),
|
|
getAllFiscalYearFormats,
|
|
getAllDateRanges,
|
|
getAllRecentMonthDateRanges,
|
|
getAllTimezones,
|
|
getAllTimezoneTypesUsedForStatistics,
|
|
getAllDecimalSeparators: () => getLocalizedNumeralSeparatorFormats(DecimalSeparator.values(), DecimalSeparator.parse(t('default.decimalSeparator')), DecimalSeparator.Default, DecimalSeparator.LanguageDefaultType),
|
|
getAllDigitGroupingSymbols: () => getLocalizedNumeralSeparatorFormats(DigitGroupingSymbol.values(), DigitGroupingSymbol.parse(t('default.digitGroupingSymbol')), DigitGroupingSymbol.Default, DigitGroupingSymbol.LanguageDefaultType),
|
|
getAllDigitGroupingTypes,
|
|
getAllCurrencyDisplayTypes,
|
|
getAllCurrencySortingTypes: () => getLocalizedDisplayNameAndType(CurrencySortingType.values()),
|
|
getAllCoordinateDisplayTypes: () => getLocalizedDisplayNameAndTypeWithSystemDefault(CoordinateDisplayType.values(), CoordinateDisplayType.SystemDefaultType, CoordinateDisplayType.Default),
|
|
getAllExpenseAmountColors: () => getAllExpenseIncomeAmountColors(CategoryType.Expense),
|
|
getAllIncomeAmountColors: () => getAllExpenseIncomeAmountColors(CategoryType.Income),
|
|
getAllAccountCategories,
|
|
getAllAccountTypes: () => getLocalizedDisplayNameAndType(AccountType.values()),
|
|
getAllCategoricalChartTypes: () => getLocalizedDisplayNameAndType(CategoricalChartType.values()),
|
|
getAllTrendChartTypes: () => getLocalizedDisplayNameAndType(TrendChartType.values()),
|
|
getAllStatisticsChartDataTypes: (analysisType: StatisticsAnalysisType) => getLocalizedDisplayNameAndType(ChartDataType.values(analysisType)),
|
|
getAllStatisticsSortingTypes: () => getLocalizedDisplayNameAndType(ChartSortingType.values()),
|
|
getAllStatisticsDateAggregationTypes: () => getLocalizedDisplayNameAndType(ChartDateAggregationType.values()),
|
|
getAllTransactionEditScopeTypes: () => getLocalizedDisplayNameAndType(TransactionEditScopeType.values()),
|
|
getAllTransactionTagFilterTypes: () => getLocalizedDisplayNameAndType(TransactionTagFilterType.values()),
|
|
getAllTransactionScheduledFrequencyTypes: () => getLocalizedDisplayNameAndType(ScheduledTemplateFrequencyType.values()),
|
|
getAllImportTransactionColumnTypes: () => getLocalizedDisplayNameAndType(ImportTransactionColumnType.values()),
|
|
getAllTransactionDefaultCategories,
|
|
getAllDisplayExchangeRates,
|
|
getAllSupportedImportFileTypes,
|
|
// get localized info
|
|
getLanguageInfo,
|
|
getMonthShortName,
|
|
getMonthLongName,
|
|
getMonthdayOrdinal,
|
|
getMonthdayShortName,
|
|
getWeekdayShortName,
|
|
getWeekdayLongName,
|
|
getMultiMonthdayShortNames,
|
|
getMultiWeekdayLongNames,
|
|
getCurrentFiscalYearFormatType,
|
|
getCurrentDecimalSeparator,
|
|
getCurrentDigitGroupingSymbol,
|
|
getCurrentDigitGroupingType,
|
|
getCurrencyName,
|
|
isLongDateMonthAfterYear,
|
|
isShortDateMonthAfterYear,
|
|
isLongTime24HourFormat,
|
|
isLongTimeMeridiemIndicatorFirst,
|
|
isShortTime24HourFormat,
|
|
isShortTimeMeridiemIndicatorFirst,
|
|
// format functions
|
|
formatUnixTimeToLongDateTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongDateFormat() + ' ' + getLocalizedLongTimeFormat(), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToShortDateTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortDateFormat() + ' ' + getLocalizedShortTimeFormat(), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToLongDate: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongDateFormat(), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToShortDate: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortDateFormat(), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToLongYear: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongYearFormat(), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToShortYear: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortYearFormat(), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToLongMonth: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, 'MMMM', utcOffset, currentUtcOffset),
|
|
formatUnixTimeToShortMonth: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, 'MMM', utcOffset, currentUtcOffset),
|
|
formatUnixTimeToLongYearMonth: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongYearMonthFormat(), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToShortYearMonth: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortYearMonthFormat(), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToLongMonthDay: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongMonthDayFormat(), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToShortMonthDay: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortMonthDayFormat(), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToLongTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongTimeFormat(), utcOffset, currentUtcOffset),
|
|
formatUnixTimeToShortTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortTimeFormat(), utcOffset, currentUtcOffset),
|
|
formatDateToLongDate,
|
|
formatMonthDayToLongDay,
|
|
formatYearQuarter,
|
|
formatDateRange,
|
|
formatFiscalYearStartToLongDay,
|
|
formatTimeRangeToFiscalYearFormat,
|
|
formatUnixTimeToFiscalYear,
|
|
formatYearToFiscalYear,
|
|
getTimezoneDifferenceDisplayText,
|
|
appendDigitGroupingSymbol: getNumberWithDigitGroupingSymbol,
|
|
parseAmount: getParsedAmountNumber,
|
|
formatAmount: getFormattedAmount,
|
|
formatAmountWithCurrency: getFormattedAmountWithCurrency,
|
|
formatNumber: getFormattedNumber,
|
|
formatPercent: getFormattedPercentValue,
|
|
formatExchangeRateAmount: getFormattedExchangeRateAmount,
|
|
getAdaptiveAmountRate,
|
|
getAmountPrependAndAppendText,
|
|
getCategorizedAccountsWithDisplayBalance,
|
|
// localization setting functions
|
|
setLanguage,
|
|
setTimeZone,
|
|
initLocale
|
|
};
|
|
}
|