user settings supports language and date&time format

This commit is contained in:
MaysWind
2023-06-04 21:08:48 +08:00
parent 999ca6274c
commit 0a106026dd
33 changed files with 1082 additions and 285 deletions
+8 -3
View File
@@ -398,10 +398,15 @@ func printUserInfo(user *models.User) {
fmt.Printf("[Nickname] %s\n", user.Nickname)
fmt.Printf("[Password] %s\n", user.Password)
fmt.Printf("[Salt] %s\n", user.Salt)
fmt.Printf("[DefaultCurrency] %s\n", user.DefaultCurrency)
fmt.Printf("[DefaultAccountId] %d\n", user.DefaultAccountId)
fmt.Printf("[FirstDayOfWeek] %s\n", user.FirstDayOfWeek)
fmt.Printf("[TransactionEditScope] %s\n", user.TransactionEditScope)
fmt.Printf("[TransactionEditScope] %s (%d)\n", user.TransactionEditScope, user.TransactionEditScope)
fmt.Printf("[Language] %s\n", user.Language)
fmt.Printf("[DefaultCurrency] %s\n", user.DefaultCurrency)
fmt.Printf("[FirstDayOfWeek] %s (%d)\n", user.FirstDayOfWeek, user.FirstDayOfWeek)
fmt.Printf("[LongDateFormat] %s (%d)\n", user.LongDateFormat, user.LongDateFormat)
fmt.Printf("[ShortDateFormat] %s (%d)\n", user.ShortDateFormat, user.ShortDateFormat)
fmt.Printf("[LongTimeFormat] %s (%d)\n", user.LongTimeFormat, user.LongTimeFormat)
fmt.Printf("[ShortTimeFormat] %s (%d)\n", user.ShortTimeFormat, user.ShortTimeFormat)
fmt.Printf("[Deleted] %t\n", user.Deleted)
fmt.Printf("[EmailVerified] %t\n", user.EmailVerified)
fmt.Printf("[CreatedAt] %s (%d)\n", utils.FormatUnixTimeToLongDateTimeInServerTimezone(user.CreatedUnixTime), user.CreatedUnixTime)
+57 -15
View File
@@ -57,6 +57,7 @@ func (a *UsersApi) UserRegisterHandler(c *core.Context) (interface{}, *errs.Erro
Email: userRegisterReq.Email,
Nickname: userRegisterReq.Nickname,
Password: userRegisterReq.Password,
Language: userRegisterReq.Language,
DefaultCurrency: userRegisterReq.DefaultCurrency,
FirstDayOfWeek: userRegisterReq.FirstDayOfWeek,
TransactionEditScope: models.TRANSACTION_EDIT_SCOPE_ALL,
@@ -161,12 +162,6 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.Context) (interface{}, *errs
anythingUpdate = true
}
if userUpdateReq.DefaultCurrency != "" && userUpdateReq.DefaultCurrency != user.DefaultCurrency {
user.DefaultCurrency = userUpdateReq.DefaultCurrency
userNew.DefaultCurrency = userUpdateReq.DefaultCurrency
anythingUpdate = true
}
if userUpdateReq.DefaultAccountId > 0 && userUpdateReq.DefaultAccountId != user.DefaultAccountId {
accounts, err := a.accounts.GetAccountsByAccountIds(uid, []int64{userUpdateReq.DefaultAccountId})
@@ -179,14 +174,6 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.Context) (interface{}, *errs
anythingUpdate = true
}
if userUpdateReq.FirstDayOfWeek != nil && *userUpdateReq.FirstDayOfWeek != user.FirstDayOfWeek {
user.FirstDayOfWeek = *userUpdateReq.FirstDayOfWeek
userNew.FirstDayOfWeek = *userUpdateReq.FirstDayOfWeek
anythingUpdate = true
} else {
userNew.FirstDayOfWeek = models.WEEKDAY_INVALID
}
if userUpdateReq.TransactionEditScope != nil && *userUpdateReq.TransactionEditScope != user.TransactionEditScope {
user.TransactionEditScope = *userUpdateReq.TransactionEditScope
userNew.TransactionEditScope = *userUpdateReq.TransactionEditScope
@@ -195,11 +182,66 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.Context) (interface{}, *errs
userNew.TransactionEditScope = models.TRANSACTION_EDIT_SCOPE_INVALID
}
modifyUserLanguage := false
if userUpdateReq.Language != user.Language {
user.Language = userUpdateReq.Language
userNew.Language = userUpdateReq.Language
modifyUserLanguage = true
anythingUpdate = true
}
if userUpdateReq.DefaultCurrency != "" && userUpdateReq.DefaultCurrency != user.DefaultCurrency {
user.DefaultCurrency = userUpdateReq.DefaultCurrency
userNew.DefaultCurrency = userUpdateReq.DefaultCurrency
anythingUpdate = true
}
if userUpdateReq.FirstDayOfWeek != nil && *userUpdateReq.FirstDayOfWeek != user.FirstDayOfWeek {
user.FirstDayOfWeek = *userUpdateReq.FirstDayOfWeek
userNew.FirstDayOfWeek = *userUpdateReq.FirstDayOfWeek
anythingUpdate = true
} else {
userNew.FirstDayOfWeek = models.WEEKDAY_INVALID
}
if userUpdateReq.LongDateFormat != nil && *userUpdateReq.LongDateFormat != user.LongDateFormat {
user.LongDateFormat = *userUpdateReq.LongDateFormat
userNew.LongDateFormat = *userUpdateReq.LongDateFormat
anythingUpdate = true
} else {
userNew.LongDateFormat = models.LONG_DATE_FORMAT_INVALID
}
if userUpdateReq.ShortDateFormat != nil && *userUpdateReq.ShortDateFormat != user.ShortDateFormat {
user.ShortDateFormat = *userUpdateReq.ShortDateFormat
userNew.ShortDateFormat = *userUpdateReq.ShortDateFormat
anythingUpdate = true
} else {
userNew.ShortDateFormat = models.SHORT_DATE_FORMAT_INVALID
}
if userUpdateReq.LongTimeFormat != nil && *userUpdateReq.LongTimeFormat != user.LongTimeFormat {
user.LongTimeFormat = *userUpdateReq.LongTimeFormat
userNew.LongTimeFormat = *userUpdateReq.LongTimeFormat
anythingUpdate = true
} else {
userNew.LongTimeFormat = models.LONG_TIME_FORMAT_INVALID
}
if userUpdateReq.ShortTimeFormat != nil && *userUpdateReq.ShortTimeFormat != user.ShortTimeFormat {
user.ShortTimeFormat = *userUpdateReq.ShortTimeFormat
userNew.ShortTimeFormat = *userUpdateReq.ShortTimeFormat
anythingUpdate = true
} else {
userNew.ShortTimeFormat = models.SHORT_TIME_FORMAT_INVALID
}
if !anythingUpdate {
return nil, errs.ErrNothingWillBeUpdated
}
keyProfileUpdated, err := a.users.UpdateUser(userNew)
keyProfileUpdated, err := a.users.UpdateUser(userNew, modifyUserLanguage)
if err != nil {
log.ErrorfWithRequestId(c, "[users.UserUpdateProfileHandler] failed to update user \"uid:%d\", because %s", user.Uid, err.Error())
+1 -1
View File
@@ -142,7 +142,7 @@ func (l *UserDataCli) ModifyUserPassword(c *cli.Context, username string, passwo
Password: password,
}
_, err = l.users.UpdateUser(userNew)
_, err = l.users.UpdateUser(userNew, false)
if err != nil {
log.BootErrorf("[user_data.ModifyUserPassword] failed to update user \"%s\" password, because %s", user.Username, err.Error())
+162
View File
@@ -0,0 +1,162 @@
package models
import "fmt"
// WeekDay represents week day
type WeekDay byte
// Week days
const (
WEEKDAY_SUNDAY WeekDay = 0
WEEKDAY_MONDAY WeekDay = 1
WEEKDAY_TUESDAY WeekDay = 2
WEEKDAY_WEDNESDAY WeekDay = 3
WEEKDAY_THURSDAY WeekDay = 4
WEEKDAY_FRIDAY WeekDay = 5
WEEKDAY_SATURDAY WeekDay = 6
WEEKDAY_INVALID WeekDay = 255
)
// String returns a textual representation of the week day enum
func (d WeekDay) String() string {
switch d {
case WEEKDAY_SUNDAY:
return "Sunday"
case WEEKDAY_MONDAY:
return "Monday"
case WEEKDAY_TUESDAY:
return "Tuesday"
case WEEKDAY_WEDNESDAY:
return "Wednesday"
case WEEKDAY_THURSDAY:
return "Thursday"
case WEEKDAY_FRIDAY:
return "Friday"
case WEEKDAY_SATURDAY:
return "Saturday"
case WEEKDAY_INVALID:
return "Invalid"
default:
return fmt.Sprintf("Invalid(%d)", int(d))
}
}
// LongDateFormat represents long date format
type LongDateFormat byte
// Long Date Format
const (
LONG_DATE_FORMAT_DEFAULT LongDateFormat = 0
LONG_DATE_FORMAT_YYYY_M_D LongDateFormat = 1
LONG_DATE_FORMAT_M_D_YYYY LongDateFormat = 2
LONG_DATE_FORMAT_D_M_YYYY LongDateFormat = 3
LONG_DATE_FORMAT_INVALID LongDateFormat = 255
)
// String returns a textual representation of the long date format enum
func (f LongDateFormat) String() string {
switch f {
case LONG_DATE_FORMAT_DEFAULT:
return "Default"
case LONG_DATE_FORMAT_YYYY_M_D:
return "YYYY_MM_D"
case LONG_DATE_FORMAT_M_D_YYYY:
return "M_D_YYYY"
case LONG_DATE_FORMAT_D_M_YYYY:
return "D_M_YYYY"
case LONG_DATE_FORMAT_INVALID:
return "Invalid"
default:
return fmt.Sprintf("Invalid(%d)", int(f))
}
}
// ShortDateFormat represents short date format
type ShortDateFormat byte
// Short Date Format
const (
SHORT_DATE_FORMAT_DEFAULT ShortDateFormat = 0
SHORT_DATE_FORMAT_YYYY_M_D ShortDateFormat = 1
SHORT_DATE_FORMAT_M_D_YYYY ShortDateFormat = 2
SHORT_DATE_FORMAT_D_M_YYYY ShortDateFormat = 3
SHORT_DATE_FORMAT_INVALID ShortDateFormat = 255
)
// String returns a textual representation of the short date format enum
func (f ShortDateFormat) String() string {
switch f {
case SHORT_DATE_FORMAT_DEFAULT:
return "Default"
case SHORT_DATE_FORMAT_YYYY_M_D:
return "YYYY_MM_D"
case SHORT_DATE_FORMAT_M_D_YYYY:
return "M_D_YYYY"
case SHORT_DATE_FORMAT_D_M_YYYY:
return "D_M_YYYY"
case SHORT_DATE_FORMAT_INVALID:
return "Invalid"
default:
return fmt.Sprintf("Invalid(%d)", int(f))
}
}
// LongTimeFormat represents long time format
type LongTimeFormat byte
// Long Time Format
const (
LONG_TIME_FORMAT_DEFAULT LongTimeFormat = 0
LONG_TIME_FORMAT_HH_MM_SS LongTimeFormat = 1
LONG_TIME_FORMAT_A_HH_MM_SS LongTimeFormat = 2
LONG_TIME_FORMAT_HH_MM_SS_A LongTimeFormat = 3
LONG_TIME_FORMAT_INVALID LongTimeFormat = 255
)
// String returns a textual representation of the long time format enum
func (f LongTimeFormat) String() string {
switch f {
case LONG_TIME_FORMAT_DEFAULT:
return "Default"
case LONG_TIME_FORMAT_HH_MM_SS:
return "HH_MM_SS"
case LONG_TIME_FORMAT_A_HH_MM_SS:
return "A_HH_MM_SS"
case LONG_TIME_FORMAT_HH_MM_SS_A:
return "HH_MM_SS_A"
case LONG_TIME_FORMAT_INVALID:
return "Invalid"
default:
return fmt.Sprintf("Invalid(%d)", int(f))
}
}
// ShortTimeFormat represents short time format
type ShortTimeFormat byte
// Short Time Format
const (
SHORT_TIME_FORMAT_DEFAULT ShortTimeFormat = 0
SHORT_TIME_FORMAT_HH_MM ShortTimeFormat = 1
SHORT_TIME_FORMAT_A_HH_MM ShortTimeFormat = 2
SHORT_TIME_FORMAT_HH_MM_A ShortTimeFormat = 3
SHORT_TIME_FORMAT_INVALID ShortTimeFormat = 255
)
// String returns a textual representation of the short time format enum
func (f ShortTimeFormat) String() string {
switch f {
case SHORT_TIME_FORMAT_DEFAULT:
return "Default"
case SHORT_TIME_FORMAT_HH_MM:
return "HH_MM"
case SHORT_TIME_FORMAT_A_HH_MM:
return "A_HH_MM"
case SHORT_TIME_FORMAT_HH_MM_A:
return "HH_MM_A"
case SHORT_TIME_FORMAT_INVALID:
return "Invalid"
default:
return fmt.Sprintf("Invalid(%d)", int(f))
}
}
+43 -51
View File
@@ -7,45 +7,6 @@ import (
"github.com/mayswind/ezbookkeeping/pkg/utils"
)
// WeekDay represents week day
type WeekDay byte
// Week days
const (
WEEKDAY_SUNDAY WeekDay = 0
WEEKDAY_MONDAY WeekDay = 1
WEEKDAY_TUESDAY WeekDay = 2
WEEKDAY_WEDNESDAY WeekDay = 3
WEEKDAY_THURSDAY WeekDay = 4
WEEKDAY_FRIDAY WeekDay = 5
WEEKDAY_SATURDAY WeekDay = 6
WEEKDAY_INVALID WeekDay = 255
)
// String returns a textual representation of the week day enum
func (d WeekDay) String() string {
switch d {
case WEEKDAY_SUNDAY:
return "Sunday"
case WEEKDAY_MONDAY:
return "Monday"
case WEEKDAY_TUESDAY:
return "Tuesday"
case WEEKDAY_WEDNESDAY:
return "Wednesday"
case WEEKDAY_THURSDAY:
return "Thursday"
case WEEKDAY_FRIDAY:
return "Friday"
case WEEKDAY_SATURDAY:
return "Saturday"
case WEEKDAY_INVALID:
return "Invalid"
default:
return fmt.Sprintf("Invalid(%d)", int(d))
}
}
// TransactionEditScope represents the scope which transaction can be edited
type TransactionEditScope byte
@@ -93,10 +54,15 @@ type User struct {
Nickname string `xorm:"VARCHAR(64) NOT NULL"`
Password string `xorm:"VARCHAR(64) NOT NULL"`
Salt string `xorm:"VARCHAR(10) NOT NULL"`
DefaultCurrency string `xorm:"VARCHAR(3) NOT NULL"`
DefaultAccountId int64
FirstDayOfWeek WeekDay `xorm:"TINYINT NOT NULL"`
TransactionEditScope TransactionEditScope `xorm:"TINYINT NOT NULL"`
Language string `xorm:"VARCHAR(10)"`
DefaultCurrency string `xorm:"VARCHAR(3) NOT NULL"`
FirstDayOfWeek WeekDay `xorm:"TINYINT NOT NULL"`
LongDateFormat LongDateFormat `xorm:"TINYINT"`
ShortDateFormat ShortDateFormat `xorm:"TINYINT"`
LongTimeFormat LongTimeFormat `xorm:"TINYINT"`
ShortTimeFormat ShortTimeFormat `xorm:"TINYINT"`
Deleted bool `xorm:"NOT NULL"`
EmailVerified bool `xorm:"NOT NULL"`
CreatedUnixTime int64
@@ -110,10 +76,15 @@ type UserBasicInfo struct {
Username string `json:"username"`
Email string `json:"email"`
Nickname string `json:"nickname"`
DefaultCurrency string `json:"defaultCurrency"`
DefaultAccountId int64 `json:"defaultAccountId,string"`
FirstDayOfWeek WeekDay `json:"firstDayOfWeek"`
TransactionEditScope TransactionEditScope `json:"transactionEditScope"`
Language string `json:"language"`
DefaultCurrency string `json:"defaultCurrency"`
FirstDayOfWeek WeekDay `json:"firstDayOfWeek"`
LongDateFormat LongDateFormat `json:"longDateFormat"`
ShortDateFormat ShortDateFormat `json:"shortDateFormat"`
LongTimeFormat LongTimeFormat `json:"longTimeFormat"`
ShortTimeFormat ShortTimeFormat `json:"shortTimeFormat"`
}
// UserLoginRequest represents all parameters of user login request
@@ -128,6 +99,7 @@ type UserRegisterRequest struct {
Email string `json:"email" binding:"required,notBlank,max=100,validEmail"`
Nickname string `json:"nickname" binding:"required,notBlank,max=64"`
Password string `json:"password" binding:"required,min=6,max=128"`
Language string `json:"language" binding:"required,min=2,max=16"`
DefaultCurrency string `json:"defaultCurrency" binding:"required,len=3,validCurrency"`
FirstDayOfWeek WeekDay `json:"firstDayOfWeek" binding:"min=0,max=6"`
}
@@ -138,10 +110,15 @@ type UserProfileUpdateRequest struct {
Nickname string `json:"nickname" binding:"omitempty,notBlank,max=64"`
Password string `json:"password" binding:"omitempty,min=6,max=128"`
OldPassword string `json:"oldPassword" binding:"omitempty,min=6,max=128"`
DefaultCurrency string `json:"defaultCurrency" binding:"omitempty,len=3,validCurrency"`
DefaultAccountId int64 `json:"defaultAccountId,string" binding:"omitempty,min=1"`
FirstDayOfWeek *WeekDay `json:"firstDayOfWeek" binding:"omitempty,min=0,max=6"`
TransactionEditScope *TransactionEditScope `json:"transactionEditScope" binding:"omitempty,min=0,max=7"`
Language string `json:"language" binding:"omitempty,min=2,max=16"`
DefaultCurrency string `json:"defaultCurrency" binding:"omitempty,len=3,validCurrency"`
FirstDayOfWeek *WeekDay `json:"firstDayOfWeek" binding:"omitempty,min=0,max=6"`
LongDateFormat *LongDateFormat `json:"longDateFormat" binding:"omitempty,min=0,max=3"`
ShortDateFormat *ShortDateFormat `json:"shortDateFormat" binding:"omitempty,min=0,max=3"`
LongTimeFormat *LongTimeFormat `json:"longTimeFormat" binding:"omitempty,min=0,max=3"`
ShortTimeFormat *ShortTimeFormat `json:"shortTimeFormat" binding:"omitempty,min=0,max=3"`
}
// UserProfileUpdateResponse represents the data returns to frontend after updating profile
@@ -155,10 +132,15 @@ type UserProfileResponse struct {
Username string `json:"username"`
Email string `json:"email"`
Nickname string `json:"nickname"`
DefaultCurrency string `json:"defaultCurrency"`
DefaultAccountId int64 `json:"defaultAccountId,string"`
FirstDayOfWeek WeekDay `json:"firstDayOfWeek"`
TransactionEditScope TransactionEditScope `json:"transactionEditScope"`
Language string `json:"language"`
DefaultCurrency string `json:"defaultCurrency"`
FirstDayOfWeek WeekDay `json:"firstDayOfWeek"`
LongDateFormat LongDateFormat `json:"longDateFormat"`
ShortDateFormat ShortDateFormat `json:"shortDateFormat"`
LongTimeFormat LongTimeFormat `json:"longTimeFormat"`
ShortTimeFormat ShortTimeFormat `json:"shortTimeFormat"`
LastLoginAt int64 `json:"lastLoginAt"`
}
@@ -210,10 +192,15 @@ func (u *User) ToUserBasicInfo() *UserBasicInfo {
Username: u.Username,
Email: u.Email,
Nickname: u.Nickname,
DefaultCurrency: u.DefaultCurrency,
DefaultAccountId: u.DefaultAccountId,
FirstDayOfWeek: u.FirstDayOfWeek,
TransactionEditScope: u.TransactionEditScope,
Language: u.Language,
DefaultCurrency: u.DefaultCurrency,
FirstDayOfWeek: u.FirstDayOfWeek,
LongDateFormat: u.LongDateFormat,
ShortDateFormat: u.ShortDateFormat,
LongTimeFormat: u.LongTimeFormat,
ShortTimeFormat: u.ShortTimeFormat,
}
}
@@ -223,10 +210,15 @@ func (u *User) ToUserProfileResponse() *UserProfileResponse {
Username: u.Username,
Email: u.Email,
Nickname: u.Nickname,
DefaultCurrency: u.DefaultCurrency,
DefaultAccountId: u.DefaultAccountId,
FirstDayOfWeek: u.FirstDayOfWeek,
TransactionEditScope: u.TransactionEditScope,
Language: u.Language,
DefaultCurrency: u.DefaultCurrency,
FirstDayOfWeek: u.FirstDayOfWeek,
LongDateFormat: u.LongDateFormat,
ShortDateFormat: u.ShortDateFormat,
LongTimeFormat: u.LongTimeFormat,
ShortTimeFormat: u.ShortTimeFormat,
LastLoginAt: u.LastLoginUnixTime,
}
}
+27 -7
View File
@@ -150,7 +150,7 @@ func (s *UserService) CreateUser(user *models.User) error {
}
// UpdateUser saves an existed user model to database
func (s *UserService) UpdateUser(user *models.User) (keyProfileUpdated bool, err error) {
func (s *UserService) UpdateUser(user *models.User, modifyUserLanguage bool) (keyProfileUpdated bool, err error) {
if user.Uid <= 0 {
return false, errs.ErrUserIdInvalid
}
@@ -186,20 +186,40 @@ func (s *UserService) UpdateUser(user *models.User) (keyProfileUpdated bool, err
updateCols = append(updateCols, "nickname")
}
if user.DefaultCurrency != "" {
updateCols = append(updateCols, "default_currency")
}
if user.DefaultAccountId > 0 {
updateCols = append(updateCols, "default_account_id")
}
if models.TRANSACTION_EDIT_SCOPE_NONE <= user.TransactionEditScope && user.TransactionEditScope <= models.TRANSACTION_EDIT_SCOPE_THIS_YEAR_OR_LATER {
updateCols = append(updateCols, "transaction_edit_scope")
}
if modifyUserLanguage || user.Language != "" {
updateCols = append(updateCols, "language")
}
if user.DefaultCurrency != "" {
updateCols = append(updateCols, "default_currency")
}
if models.WEEKDAY_SUNDAY <= user.FirstDayOfWeek && user.FirstDayOfWeek <= models.WEEKDAY_SATURDAY {
updateCols = append(updateCols, "first_day_of_week")
}
if models.TRANSACTION_EDIT_SCOPE_NONE <= user.TransactionEditScope && user.TransactionEditScope <= models.TRANSACTION_EDIT_SCOPE_THIS_YEAR_OR_LATER {
updateCols = append(updateCols, "transaction_edit_scope")
if models.LONG_DATE_FORMAT_DEFAULT <= user.LongDateFormat && user.LongDateFormat <= models.LONG_DATE_FORMAT_D_M_YYYY {
updateCols = append(updateCols, "long_date_format")
}
if models.SHORT_DATE_FORMAT_DEFAULT <= user.ShortDateFormat && user.ShortDateFormat <= models.SHORT_DATE_FORMAT_D_M_YYYY {
updateCols = append(updateCols, "short_date_format")
}
if models.LONG_TIME_FORMAT_DEFAULT <= user.LongTimeFormat && user.LongTimeFormat <= models.LONG_TIME_FORMAT_HH_MM_SS_A {
updateCols = append(updateCols, "long_time_format")
}
if models.SHORT_TIME_FORMAT_DEFAULT <= user.ShortTimeFormat && user.ShortTimeFormat <= models.SHORT_TIME_FORMAT_HH_MM_A {
updateCols = append(updateCols, "short_time_format")
}
user.UpdatedUnixTime = now
+11 -5
View File
@@ -75,14 +75,20 @@ export default {
}
},
created() {
if (this.$user.isUserLogined()) {
if (!this.$settings.isEnableApplicationLock()) {
const self = this;
if (self.$user.isUserLogined()) {
if (!self.$settings.isEnableApplicationLock()) {
// refresh token if user is logined
this.$store.dispatch('refreshTokenAndRevokeOldToken');
self.$store.dispatch('refreshTokenAndRevokeOldToken').then(response => {
if (response.user && response.user.language) {
self.$locale.setLanguage(response.user.language);
}
});
// auto refresh exchange rates data
if (this.$settings.isAutoUpdateExchangeRatesData()) {
this.$store.dispatch('getLatestExchangeRates', { silent: true, force: false });
if (self.$settings.isAutoUpdateExchangeRatesData()) {
self.$store.dispatch('getLatestExchangeRates', { silent: true, force: false });
}
}
}
@@ -95,16 +95,15 @@ export default {
return this.$utilities.arrangeArrayWithNewStartIndex(this.$locale.getAllMinWeekdayNames(), this.firstDayOfWeek);
},
is24Hour() {
const datetimeFormat = this.$t('format.datetime.long');
return this.$utilities.is24HourFormat(datetimeFormat);
return this.$locale.isLongTime24HourFormat();
},
beginDateTime() {
const actualBeginUnixTime = this.$utilities.getActualUnixTimeForStore(this.$utilities.getUnixTime(this.dateRange[0]), this.$utilities.getTimezoneOffsetMinutes(), this.$utilities.getBrowserTimezoneOffsetMinutes());
return this.$utilities.formatUnixTime(actualBeginUnixTime, this.$t('format.datetime.long'));
return this.$utilities.formatUnixTime(actualBeginUnixTime, this.$locale.getLongDateTimeFormat());
},
endDateTime() {
const actualEndUnixTime = this.$utilities.getActualUnixTimeForStore(this.$utilities.getUnixTime(this.dateRange[1]), this.$utilities.getTimezoneOffsetMinutes(), this.$utilities.getBrowserTimezoneOffsetMinutes());
return this.$utilities.formatUnixTime(actualEndUnixTime, this.$t('format.datetime.long'));
return this.$utilities.formatUnixTime(actualEndUnixTime, this.$locale.getLongDateTimeFormat());
},
presetRanges() {
const presetRanges = [];
@@ -70,8 +70,7 @@ export default {
return this.$utilities.arrangeArrayWithNewStartIndex(this.$locale.getAllMinWeekdayNames(), this.firstDayOfWeek);
},
is24Hour() {
const datetimeFormat = this.$t('format.datetime.long');
return this.$utilities.is24HourFormat(datetimeFormat);
return this.$locale.isLongTime24HourFormat();
}
},
methods: {
+109 -1
View File
@@ -39,6 +39,96 @@ const allWeekDaysArray = [
allWeekDays.Saturday
];
const allLongDateFormat = {
YYYYMMDD: {
type: 1,
key: 'yyyy_mm_dd'
},
MMDDYYYY: {
type: 2,
key: 'mm_dd_yyyy'
},
DDMMYYYY: {
type: 3,
key: 'dd_mm_yyyy'
}
};
const allLongDateFormatArray = [
allLongDateFormat.YYYYMMDD,
allLongDateFormat.MMDDYYYY,
allLongDateFormat.DDMMYYYY
];
const allShortDateFormat = {
YYYYMMDD: {
type: 1,
key: 'yyyy_mm_dd'
},
MMDDYYYY: {
type: 2,
key: 'mm_dd_yyyy'
},
DDMMYYYY: {
type: 3,
key: 'dd_mm_yyyy'
}
};
const allShortDateFormatArray = [
allShortDateFormat.YYYYMMDD,
allShortDateFormat.MMDDYYYY,
allShortDateFormat.DDMMYYYY
];
const allLongTimeFormat = {
HHMMSS: {
type: 1,
key: 'hh_mm_ss',
is24HourFormat: true
},
AHHMMSS: {
type: 2,
key: 'a_hh_mm_ss',
is24HourFormat: false
},
HHMMSSA: {
type: 3,
key: 'hh_mm_ss_a',
is24HourFormat: false
}
};
const allLongTimeFormatArray = [
allLongTimeFormat.HHMMSS,
allLongTimeFormat.AHHMMSS,
allLongTimeFormat.HHMMSSA
];
const allShortTimeFormat = {
HHMM: {
type: 1,
key: 'hh_mm',
is24HourFormat: true
},
AHHMM: {
type: 2,
key: 'a_hh_mm',
is24HourFormat: false
},
HHMMA: {
type: 3,
key: 'hh_mm_a',
is24HourFormat: false
}
};
const allShortTimeFormatArray = [
allShortTimeFormat.HHMM,
allShortTimeFormat.AHHMM,
allShortTimeFormat.HHMMA
];
const allDateRanges = {
All: {
type: 0,
@@ -91,10 +181,28 @@ const allDateRanges = {
};
const defaultFirstDayOfWeek = allWeekDays.Sunday.type;
const defaultLongDateFormat = allLongDateFormat.YYYYMMDD;
const defaultShortDateFormat = allShortDateFormat.YYYYMMDD;
const defaultLongTimeFormat = allLongTimeFormat.HHMMSS;
const defaultShortTimeFormat = allShortTimeFormat.HHMM;
const defaultDateTimeFormatValue = 0;
export default {
allWeekDays: allWeekDays,
allWeekDaysArray: allWeekDaysArray,
allLongDateFormat: allLongDateFormat,
allLongDateFormatArray: allLongDateFormatArray,
allShortDateFormat: allShortDateFormat,
allShortDateFormatArray: allShortDateFormatArray,
allLongTimeFormat: allLongTimeFormat,
allLongTimeFormatArray: allLongTimeFormatArray,
allShortTimeFormat: allShortTimeFormat,
allShortTimeFormatArray: allShortTimeFormatArray,
allDateRanges: allDateRanges,
defaultFirstDayOfWeek: defaultFirstDayOfWeek
defaultFirstDayOfWeek: defaultFirstDayOfWeek,
defaultLongDateFormat: defaultLongDateFormat,
defaultShortDateFormat: defaultShortDateFormat,
defaultLongTimeFormat: defaultLongTimeFormat,
defaultShortTimeFormat: defaultShortTimeFormat,
defaultDateTimeFormatValue: defaultDateTimeFormatValue,
};
+114
View File
@@ -1,4 +1,5 @@
import { defaultLanguage, allLanguages } from '../locales/index.js';
import datetime from "../consts/datetime.js";
import timezone from "../consts/timezone.js";
import currency from "../consts/currency.js";
import settings from "./settings.js";
@@ -250,6 +251,88 @@ export function getAllMinWeekdayNames(translateFn) {
];
}
export function getAllLongDateFormats(translateFn) {
const defaultLongDateFormatTypeName = translateFn('default.longDateFormat');
return getDateTimeFormats(translateFn, datetime.allLongDateFormat, datetime.allLongDateFormatArray, 'format.longDate', defaultLongDateFormatTypeName, datetime.defaultLongDateFormat);
}
export function getAllShortDateFormats(translateFn) {
const defaultShortDateFormatTypeName = translateFn('default.shortDateFormat');
return getDateTimeFormats(translateFn, datetime.allShortDateFormat, datetime.allShortDateFormatArray, 'format.shortDate', defaultShortDateFormatTypeName, datetime.defaultShortDateFormat);
}
export function getAllLongTimeFormats(translateFn) {
const defaultLongTimeFormatTypeName = translateFn('default.longTimeFormat');
return getDateTimeFormats(translateFn, datetime.allLongTimeFormat, datetime.allLongTimeFormatArray, 'format.longTime', defaultLongTimeFormatTypeName, datetime.defaultLongTimeFormat);
}
export function getAllShortTimeFormats(translateFn) {
const defaultShortTimeFormatTypeName = translateFn('default.shortTimeFormat');
return getDateTimeFormats(translateFn, datetime.allShortTimeFormat, datetime.allShortTimeFormatArray, 'format.shortTime', defaultShortTimeFormatTypeName, datetime.defaultShortTimeFormat);
}
export function getI18nLongDateFormat(translateFn, formatTypeValue) {
const defaultLongDateFormatTypeName = translateFn('default.longDateFormat');
return getDateTimeFormat(translateFn, datetime.allLongDateFormat, datetime.allLongDateFormatArray, 'format.longDate', defaultLongDateFormatTypeName, datetime.defaultLongDateFormat, formatTypeValue);
}
export function getI18nShortDateFormat(translateFn, formatTypeValue) {
const defaultShortDateFormatTypeName = translateFn('default.shortDateFormat');
return getDateTimeFormat(translateFn, datetime.allShortDateFormat, datetime.allShortDateFormatArray, 'format.shortDate', defaultShortDateFormatTypeName, datetime.defaultShortDateFormat, formatTypeValue);
}
export function getI18nLongYearFormat(translateFn, formatTypeValue) {
const defaultLongDateFormatTypeName = translateFn('default.longDateFormat');
return getDateTimeFormat(translateFn, datetime.allLongDateFormat, datetime.allLongDateFormatArray, 'format.longYear', defaultLongDateFormatTypeName, datetime.defaultLongDateFormat, formatTypeValue);
}
export function getI18nShortYearFormat(translateFn, formatTypeValue) {
const defaultShortDateFormatTypeName = translateFn('default.shortDateFormat');
return getDateTimeFormat(translateFn, datetime.allShortDateFormat, datetime.allShortDateFormatArray, 'format.shortYear', defaultShortDateFormatTypeName, datetime.defaultShortDateFormat, formatTypeValue);
}
export function getI18nLongYearMonthFormat(translateFn, formatTypeValue) {
const defaultLongDateFormatTypeName = translateFn('default.longDateFormat');
return getDateTimeFormat(translateFn, datetime.allLongDateFormat, datetime.allLongDateFormatArray, 'format.longYearMonth', defaultLongDateFormatTypeName, datetime.defaultLongDateFormat, formatTypeValue);
}
export function getI18nShortYearMonthFormat(translateFn, formatTypeValue) {
const defaultShortDateFormatTypeName = translateFn('default.shortDateFormat');
return getDateTimeFormat(translateFn, datetime.allShortDateFormat, datetime.allShortDateFormatArray, 'format.shortYearMonth', defaultShortDateFormatTypeName, datetime.defaultShortDateFormat, formatTypeValue);
}
export function getI18nLongMonthDayFormat(translateFn, formatTypeValue) {
const defaultLongDateFormatTypeName = translateFn('default.longDateFormat');
return getDateTimeFormat(translateFn, datetime.allLongDateFormat, datetime.allLongDateFormatArray, 'format.longMonthDay', defaultLongDateFormatTypeName, datetime.defaultLongDateFormat, formatTypeValue);
}
export function getI18nShortMonthDayFormat(translateFn, formatTypeValue) {
const defaultShortDateFormatTypeName = translateFn('default.shortDateFormat');
return getDateTimeFormat(translateFn, datetime.allShortDateFormat, datetime.allShortDateFormatArray, 'format.shortMonthDay', defaultShortDateFormatTypeName, datetime.defaultShortDateFormat, formatTypeValue);
}
export function getI18nLongTimeFormat(translateFn, formatTypeValue) {
const defaultLongTimeFormatTypeName = translateFn('default.longTimeFormat');
return getDateTimeFormat(translateFn, datetime.allLongTimeFormat, datetime.allLongTimeFormatArray, 'format.longTime', defaultLongTimeFormatTypeName, datetime.defaultLongTimeFormat, formatTypeValue);
}
export function getI18nShortTimeFormat(translateFn, formatTypeValue) {
const defaultShortTimeFormatTypeName = translateFn('default.shortTimeFormat');
return getDateTimeFormat(translateFn, datetime.allShortTimeFormat, datetime.allShortTimeFormatArray, 'format.shortTime', defaultShortTimeFormatTypeName, datetime.defaultShortTimeFormat, formatTypeValue);
}
export function isLongTime24HourFormat(translateFn, formatTypeValue) {
const defaultLongTimeFormatTypeName = translateFn('default.longTimeFormat');
const type = utilities.getDateTimeFormatType(datetime.allLongTimeFormat, datetime.allLongTimeFormatArray, defaultLongTimeFormatTypeName, datetime.defaultLongTimeFormat, formatTypeValue);
return type.is24HourFormat;
}
export function isShortTime24HourFormat(translateFn, formatTypeValue) {
const defaultShortTimeFormatTypeName = translateFn('default.shortTimeFormat');
const type = utilities.getDateTimeFormatType(datetime.allShortTimeFormat, datetime.allShortTimeFormatArray, defaultShortTimeFormatTypeName, datetime.defaultShortTimeFormat, formatTypeValue);
return type.is24HourFormat;
}
export function getAllTimezones(includeSystemDefault, translateFn) {
const defaultTimezoneOffset = utilities.getTimezoneOffset();
const defaultTimezoneOffsetMinutes = utilities.getTimezoneOffsetMinutes();
@@ -462,3 +545,34 @@ function getLocaleFromLanguageAlias(alias) {
return null;
}
function getDateTimeFormats(translateFn, allFormatMap, allFormatArray, localeFormatPathPrefix, localeDefaultFormatTypeName, systemDefaultFormatType) {
const defaultFormat = getDateTimeFormat(translateFn, allFormatMap, allFormatArray,
localeFormatPathPrefix, localeDefaultFormatTypeName, systemDefaultFormatType, datetime.defaultDateTimeFormatValue);
const ret = [];
ret.push({
type: datetime.defaultDateTimeFormatValue,
format: defaultFormat,
displayName: `${translateFn('Language Default')} (${utilities.formatTime(utilities.getCurrentDateTime(), defaultFormat)})`
});
for (let i = 0; i < allFormatArray.length; i++) {
const formatType = allFormatArray[i];
const format = translateFn(`${localeFormatPathPrefix}.${formatType.key}`);
ret.push({
type: formatType.type,
format: format,
displayName: utilities.formatTime(utilities.getCurrentDateTime(), format)
});
}
return ret;
}
function getDateTimeFormat(translateFn, allFormatMap, allFormatArray, localeFormatPathPrefix, localeDefaultFormatTypeName, systemDefaultFormatType, formatTypeValue) {
const type = utilities.getDateTimeFormatType(allFormatMap, allFormatArray,
localeDefaultFormatTypeName, systemDefaultFormatType, formatTypeValue);
return translateFn(`${localeFormatPathPrefix}.${type.key}`);
}
+10 -4
View File
@@ -87,12 +87,13 @@ export default {
}
});
},
register: ({ username, email, nickname, password, defaultCurrency, firstDayOfWeek }) => {
register: ({ username, email, nickname, password, language, defaultCurrency, firstDayOfWeek }) => {
return axios.post('register.json', {
username,
email,
nickname,
password,
language,
defaultCurrency,
firstDayOfWeek
});
@@ -135,16 +136,21 @@ export default {
getProfile: () => {
return axios.get('v1/users/profile/get.json');
},
updateProfile: ({ email, nickname, password, oldPassword, defaultCurrency, defaultAccountId, firstDayOfWeek, transactionEditScope }) => {
updateProfile: ({ email, nickname, password, oldPassword, defaultAccountId, transactionEditScope, language, defaultCurrency, firstDayOfWeek, longDateFormat, shortDateFormat, longTimeFormat, shortTimeFormat }) => {
return axios.post('v1/users/profile/update.json', {
email,
nickname,
password,
oldPassword,
defaultCurrency,
defaultAccountId,
transactionEditScope,
language,
defaultCurrency,
firstDayOfWeek,
transactionEditScope
longDateFormat,
shortDateFormat,
longTimeFormat,
shortTimeFormat
});
},
get2FAStatus: () => {
-3
View File
@@ -7,7 +7,6 @@ const settingsLocalStorageKey = 'ebk_app_settings';
const serverSettingsCookieKey = 'ebk_server_settings';
const defaultSettings = {
lang: 'en',
timeZone: '',
debug: false,
applicationLock: false,
@@ -129,8 +128,6 @@ function clearSettings() {
export default {
isProduction: () => process.env.NODE_ENV === 'production',
getLanguage: () => getOriginalOption('lang'),
setLanguage: value => setOption('lang', value),
getTimezone: () => getOption('timeZone'),
setTimezone: value => setOption('timeZone', value),
isEnableDebug: () => getOption('debug'),
+10 -10
View File
@@ -89,16 +89,6 @@ export function parseDateFromUnixTime(unixTime, utcOffset, currentUtcOffset) {
return moment.unix(unixTime);
}
export function is24HourFormat(format) {
if (format.indexOf('HH') >= 0 && format.indexOf('hh') < 0) {
return true;
} else if (format.indexOf('HH') < 0 && format.indexOf('hh') >= 0) {
return false;
}
return true;
}
export function formatUnixTime(unixTime, format, utcOffset, currentUtcOffset) {
return parseDateFromUnixTime(unixTime, utcOffset, currentUtcOffset).format(format);
}
@@ -214,6 +204,16 @@ export function getThisYearLastUnixTime() {
return moment.unix(getThisYearFirstUnixTime()).add(1, 'years').subtract(1, 'seconds').unix();
}
export function getDateTimeFormatType(allFormatMap, allFormatArray, localeDefaultFormatTypeName, systemDefaultFormatType, formatTypeValue) {
if (formatTypeValue > dateTimeConstants.defaultDateTimeFormatValue && allFormatArray[formatTypeValue - 1] && allFormatArray[formatTypeValue - 1].key) {
return allFormatArray[formatTypeValue - 1];
} else if (formatTypeValue === dateTimeConstants.defaultDateTimeFormatValue && allFormatMap[localeDefaultFormatTypeName] && allFormatMap[localeDefaultFormatTypeName].key) {
return allFormatMap[localeDefaultFormatTypeName];
} else {
return systemDefaultFormatType;
}
}
export function getShiftedDateRange(minTime, maxTime, scale) {
const minDateTime = parseDateFromUnixTime(minTime).set({ second: 0, millisecond: 0 });
const maxDateTime = parseDateFromUnixTime(maxTime).set({ second: 59, millisecond: 999 });
+2 -2
View File
@@ -31,7 +31,6 @@ import {
getCurrentUnixTime,
getCurrentDateTime,
parseDateFromUnixTime,
is24HourFormat,
formatUnixTime,
formatTime,
getUnixTime,
@@ -55,6 +54,7 @@ import {
getThisMonthLastUnixTime,
getThisYearFirstUnixTime,
getThisYearLastUnixTime,
getDateTimeFormatType,
getShiftedDateRange,
getDateRangeByDateType,
isDateRangeMatchFullYears,
@@ -123,7 +123,6 @@ export default {
getCurrentUnixTime,
getCurrentDateTime,
parseDateFromUnixTime,
is24HourFormat,
formatUnixTime,
formatTime,
getUnixTime,
@@ -147,6 +146,7 @@ export default {
getThisMonthLastUnixTime,
getThisYearFirstUnixTime,
getThisYearLastUnixTime,
getDateTimeFormatType,
getShiftedDateRange,
getDateRangeByDateType,
isDateRangeMatchFullYears,
+61 -18
View File
@@ -6,31 +6,62 @@ export default {
},
'default': {
'currency': 'USD',
'firstDayOfWeek': 'Sunday'
'firstDayOfWeek': 'Sunday',
'longDateFormat': 'MMDDYYYY',
'shortDateFormat': 'MMDDYYYY',
'longTimeFormat': 'HHMMSSA',
'shortTimeFormat': 'HHMMA'
},
'format': { // The type of date or time format is moment format, ref: https://momentjs.com/docs/#/displaying/
'date': {
'long': 'M/D/YYYY',
'short': 'M/D/YYYY'
'longDate': {
'yyyy_mm_dd': 'YYYY MMMM DD',
'mm_dd_yyyy': 'MMMM D, YYYY',
'dd_mm_yyyy': 'D MMMM, YYYY'
},
'datetime': {
'long': 'M/D/YYYY hh:mm:ss A',
'long-without-second': 'M/D/YYYY hh:mm A',
'shortDate': {
'yyyy_mm_dd': 'YYYY-M-D',
'mm_dd_yyyy': 'M/D/YYYY',
'dd_mm_yyyy': 'D/M/YYYY'
},
'year': {
'long': 'YYYY',
'short': 'YYYY'
'longYear': { // used in home page
'yyyy_mm_dd': 'YYYY',
'mm_dd_yyyy': 'YYYY',
'dd_mm_yyyy': 'YYYY'
},
'yearMonth': {
'long': 'YYYY-M',
'short': 'YYYY-M'
'shortYear': {// used in transaction statistics page
'yyyy_mm_dd': 'YYYY',
'mm_dd_yyyy': 'YYYY',
'dd_mm_yyyy': 'YYYY'
},
'monthDay': {
'long': 'M/D',
'short': 'M/D'
'longYearMonth': { // used in transaction list page
'yyyy_mm_dd': 'YYYY MMMM',
'mm_dd_yyyy': 'MMMM, YYYY',
'dd_mm_yyyy': 'MMMM, YYYY'
},
'hourMinute': {
'long': 'hh:mm A'
'shortYearMonth': { // used in transaction statistics page
'yyyy_mm_dd': 'YYYY-M',
'mm_dd_yyyy': 'MMM, YYYY',
'dd_mm_yyyy': 'MMM, YYYY'
},
'longMonthDay': { // used in home page
'yyyy_mm_dd': 'MMMM D',
'mm_dd_yyyy': 'MMMM D',
'dd_mm_yyyy': 'D MMMM'
},
'shortMonthDay': { // should be similar to the shortDate. it would be next to the shortDate content on the transaction statistics page
'yyyy_mm_dd': 'M/D',
'mm_dd_yyyy': 'M/D',
'dd_mm_yyyy': 'D/M'
},
'longTime': {
'hh_mm_ss': 'HH:mm:ss',
'a_hh_mm_ss': 'A hh:mm:ss',
'hh_mm_ss_a': 'hh:mm:ss A'
},
'shortTime': {
'hh_mm': 'HH:mm',
'a_hh_mm': 'A hh:mm',
'hh_mm_a': 'hh:mm A'
},
'currency': {
'symbol': '{symbol} {amount}'
@@ -41,6 +72,12 @@ export default {
'exportFilename': 'ezBookkeeping_{nickname}_export_data'
},
'datetime': {
'AM': {
'upperCase': 'AM'
},
'PM': {
'upperCase': 'PM'
},
'Monday': {
'min': 'Mo',
'short': 'Mon',
@@ -657,6 +694,7 @@ export default {
'None': 'None',
'Not Specified': 'Not Specified',
'No results': 'No results',
'Unknown': 'Unknown',
'Done': 'Done',
'Continue': 'Continue',
'Status': 'Status',
@@ -727,6 +765,10 @@ export default {
'Default Currency': 'Default Currency',
'Default Account': 'Default Account',
'First Day of Week': 'First Day of Week',
'Long Date Format': 'Long Date Format',
'Short Date Format': 'Short Date Format',
'Long Time Format': 'Long Time Format',
'Short Time Format': 'Short Time Format',
'Editable Transaction Scope': 'Editable Transaction Scope',
'Today or later': 'Today or later',
'Recent 24 hours or later': 'Recent 24 hours or later',
@@ -894,6 +936,7 @@ export default {
'Language': 'Language',
'Timezone': 'Timezone',
'System Default': 'System Default',
'Language Default': 'Language Default',
'Auto Update Exchange Rates Data': 'Auto Update Exchange Rates Data',
'Auto Get Current Geographic Location': 'Auto Get Current Geographic Location',
'Enable Thousands Separator': 'Enable Thousands Separator',
-2
View File
@@ -1,5 +1,3 @@
import 'moment/dist/locale/zh-cn.js';
import en from './en.js'
import zhHans from './zh_Hans.js'
+61 -18
View File
@@ -6,31 +6,62 @@ export default {
},
'default': {
'currency': 'CNY',
'firstDayOfWeek': 'Monday'
'firstDayOfWeek': 'Monday',
'longDateFormat': 'YYYYMMDD',
'shortDateFormat': 'YYYYMMDD',
'longTimeFormat': 'HHMMSS',
'shortTimeFormat': 'HHMM'
},
'format': {
'date': {
'long': 'YYYY年M月D日',
'short': 'YYYY-M-D'
'longDate': {
'yyyy_mm_dd': 'YYYY年M月D日',
'mm_dd_yyyy': 'M/D/YYYY',
'dd_mm_yyyy': 'D/M/YYYY'
},
'datetime': {
'long': 'YYYY年M月D日 HH:mm:ss',
'long-without-second': 'YYYY年M月D日 HH:mm',
'shortDate': {
'yyyy_mm_dd': 'YYYY-M-D',
'mm_dd_yyyy': 'M/D/YYYY',
'dd_mm_yyyy': 'D/M/YYYY'
},
'year': {
'long': 'YYYY年',
'short': 'YYYY'
'longYear': {
'yyyy_mm_dd': 'YYYY年',
'mm_dd_yyyy': 'YYYY',
'dd_mm_yyyy': 'YYYY年'
},
'yearMonth': {
'long': 'YYYY年M月',
'short': 'YYYY-M'
'shortYear': {
'yyyy_mm_dd': 'YYYY',
'mm_dd_yyyy': 'YYYY',
'dd_mm_yyyy': 'YYYY'
},
'monthDay': {
'long': 'M月D日',
'short': 'M-D'
'longYearMonth': {
'yyyy_mm_dd': 'YYYY年M月',
'mm_dd_yyyy': 'M/YYYY',
'dd_mm_yyyy': 'M/YYYY'
},
'hourMinute': {
'long': 'HH:mm'
'shortYearMonth': {
'yyyy_mm_dd': 'YYYY-M',
'mm_dd_yyyy': 'M/YYYY',
'dd_mm_yyyy': 'M/YYYY'
},
'longMonthDay': {
'yyyy_mm_dd': 'M月D日',
'mm_dd_yyyy': 'M/D',
'dd_mm_yyyy': 'D/M'
},
'shortMonthDay': {
'yyyy_mm_dd': 'M-D',
'mm_dd_yyyy': 'M/D',
'dd_mm_yyyy': 'D/M'
},
'longTime': {
'hh_mm_ss': 'HH:mm:ss',
'a_hh_mm_ss': 'A hh:mm:ss',
'hh_mm_ss_a': 'hh:mm:ss A'
},
'shortTime': {
'hh_mm': 'HH:mm',
'a_hh_mm': 'A hh:mm',
'hh_mm_a': 'hh:mm A'
},
'currency': {
'symbol': '{symbol} {amount}'
@@ -41,6 +72,12 @@ export default {
'exportFilename': 'ezBookkeeping_{nickname}_导出数据'
},
'datetime': {
'AM': {
'upperCase': '上午'
},
'PM': {
'upperCase': '下午'
},
'Monday': {
'min': '一',
'short': '周一',
@@ -657,6 +694,7 @@ export default {
'None': '无',
'Not Specified': '未指定',
'No results': '无结果',
'Unknown': '未知',
'Done': '完成',
'Continue': '继续',
'Status': '状态',
@@ -727,6 +765,10 @@ export default {
'Default Currency': '默认货币',
'Default Account': '默认账户',
'First Day of Week': '每周第一天',
'Long Date Format': '长日期格式',
'Short Date Format': '短日期格式',
'Long Time Format': '长时间格式',
'Short Time Format': '短时间格式',
'Editable Transaction Scope': '可编辑交易范围',
'Today or later': '今天或更晚',
'Recent 24 hours or later': '最近24小时或更晚',
@@ -894,6 +936,7 @@ export default {
'Language': '语言',
'Timezone': '时区',
'System Default': '系统默认',
'Language Default': '语言默认',
'Auto Update Exchange Rates Data': '自动更新汇率数据',
'Auto Get Current Geographic Location': '自动获取当前地理位置',
'Enable Thousands Separator': '启用千位分隔符',
+61 -7
View File
@@ -104,6 +104,22 @@ import {
getAllLongWeekdayNames,
getAllShortWeekdayNames,
getAllMinWeekdayNames,
getAllLongDateFormats,
getAllShortDateFormats,
getAllLongTimeFormats,
getAllShortTimeFormats,
getI18nLongDateFormat,
getI18nShortDateFormat,
getI18nLongTimeFormat,
getI18nShortTimeFormat,
getI18nLongYearFormat,
getI18nShortYearFormat,
getI18nLongYearMonthFormat,
getI18nShortYearMonthFormat,
getI18nLongMonthDayFormat,
getI18nShortMonthDayFormat,
isLongTime24HourFormat,
isShortTime24HourFormat,
getAllTimezones,
getAllCurrencies,
getDisplayCurrency,
@@ -186,10 +202,22 @@ app.use(store);
app.use(i18n);
function setLanguage(locale) {
if (settings.getLanguage() !== locale) {
settings.setLanguage(locale);
if (!locale) {
locale = getDefaultLanguage();
logger.info(`No specified language, use browser default language ${locale}`);
}
if (!getLanguageInfo(locale)) {
logger.warn(`Not found language ${locale}`);
return null;
}
if (i18n.global.locale === locale) {
return locale;
}
logger.info(`Apply current language to ${locale}`);
i18n.global.locale = locale;
moment.updateLocale(locale, {
months : app.config.globalProperties.$locale.getAllLongMonthNames(),
@@ -197,6 +225,13 @@ function setLanguage(locale) {
weekdays : app.config.globalProperties.$locale.getAllLongWeekdayNames(),
weekdaysShort : app.config.globalProperties.$locale.getAllShortWeekdayNames(),
weekdaysMin : app.config.globalProperties.$locale.getAllMinWeekdayNames(),
meridiem: function (hours) {
if (hours > 11) {
return i18n.global.t('datetime.PM.upperCase');
} else {
return i18n.global.t('datetime.AM.upperCase');
}
}
});
services.setLocale(locale);
document.querySelector('html').setAttribute('lang', locale);
@@ -225,12 +260,13 @@ function setTimezone(timezone) {
}
function initLocale() {
if (settings.getLanguage()) {
logger.info(`Current language is ${settings.getLanguage()}`);
setLanguage(settings.getLanguage());
const lastUserLanguage = store.getters.currentUserLanguage;
if (lastUserLanguage && getLanguageInfo(lastUserLanguage)) {
logger.info(`Last user language is ${lastUserLanguage}`);
setLanguage(lastUserLanguage);
} else {
logger.info(`No language is set, use browser default ${getDefaultLanguage()}`);
setLanguage(getDefaultLanguage());
setLanguage(null);
}
if (settings.getTimezone()) {
@@ -296,6 +332,24 @@ app.config.globalProperties.$locale = {
getAllLongWeekdayNames: () => getAllLongWeekdayNames(i18n.global.t),
getAllShortWeekdayNames: () => getAllShortWeekdayNames(i18n.global.t),
getAllMinWeekdayNames: () => getAllMinWeekdayNames(i18n.global.t),
getAllLongDateFormats: () => getAllLongDateFormats(i18n.global.t),
getAllShortDateFormats: () => getAllShortDateFormats(i18n.global.t),
getAllLongTimeFormats: () => getAllLongTimeFormats(i18n.global.t),
getAllShortTimeFormats: () => getAllShortTimeFormats(i18n.global.t),
getLongDateTimeFormat: () => getI18nLongDateFormat(i18n.global.t, store.getters.currentUserLongDateFormat) + ' ' + getI18nLongTimeFormat(i18n.global.t, store.getters.currentUserLongTimeFormat),
getShortDateTimeFormat: () => getI18nShortDateFormat(i18n.global.t, store.getters.currentUserShortDateFormat) + ' ' + getI18nShortTimeFormat(i18n.global.t, store.getters.currentUserShortTimeFormat),
getLongDateFormat: () => getI18nLongDateFormat(i18n.global.t, store.getters.currentUserLongDateFormat),
getShortDateFormat: () => getI18nShortDateFormat(i18n.global.t, store.getters.currentUserShortDateFormat),
getLongYearFormat: () => getI18nLongYearFormat(i18n.global.t, store.getters.currentUserLongDateFormat),
getShortYearFormat: () => getI18nShortYearFormat(i18n.global.t, store.getters.currentUserShortDateFormat),
getLongYearMonthFormat: () => getI18nLongYearMonthFormat(i18n.global.t, store.getters.currentUserLongDateFormat),
getShortYearMonthFormat: () => getI18nShortYearMonthFormat(i18n.global.t, store.getters.currentUserShortDateFormat),
getLongMonthDayFormat: () => getI18nLongMonthDayFormat(i18n.global.t, store.getters.currentUserLongDateFormat),
getShortMonthDayFormat: () => getI18nShortMonthDayFormat(i18n.global.t, store.getters.currentUserShortDateFormat),
getLongTimeFormat: () => getI18nLongTimeFormat(i18n.global.t, store.getters.currentUserLongTimeFormat),
getShortTimeFormat: () => getI18nShortTimeFormat(i18n.global.t, store.getters.currentUserShortTimeFormat),
isLongTime24HourFormat: () => isLongTime24HourFormat(i18n.global.t, store.getters.currentUserLongTimeFormat),
isShortTime24HourFormat: () => isShortTime24HourFormat(i18n.global.t, store.getters.currentUserShortTimeFormat),
setLanguage: setLanguage,
getTimezone: settings.getTimezone,
setTimezone: setTimezone,
+18 -3
View File
@@ -73,9 +73,14 @@ import {
clearUserInfoState,
resetState,
currentUserNickname,
currentUserDefaultCurrency,
currentUserDefaultAccountId,
currentUserLanguage,
currentUserDefaultCurrency,
currentUserFirstDayOfWeek,
currentUserLongDateFormat,
currentUserShortDateFormat,
currentUserLongTimeFormat,
currentUserShortTimeFormat,
} from './user.js';
import {
@@ -166,8 +171,13 @@ const stores = {
strict: !settings.isProduction(),
state: {
defaultSetting: {
language: '',
currency: currencyConstants.defaultCurrency,
firstDayOfWeek: datetimeConstants.defaultFirstDayOfWeek
firstDayOfWeek: datetimeConstants.defaultFirstDayOfWeek,
longDateFormat: 0,
shortDateFormat: 0,
longTimeFormat: 0,
shortTimeFormat: 0
},
currentUserInfo: userState.getUserInfo(),
latestExchangeRates: getExchangeRatesFromLocalStorage(),
@@ -210,9 +220,14 @@ const stores = {
getters: {
// user
currentUserNickname,
currentUserDefaultCurrency,
currentUserDefaultAccountId,
currentUserLanguage,
currentUserDefaultCurrency,
currentUserFirstDayOfWeek,
currentUserLongDateFormat,
currentUserShortDateFormat,
currentUserLongTimeFormat,
currentUserShortTimeFormat,
// exchange rates
exchangeRatesLastUpdateTime,
+38 -7
View File
@@ -133,6 +133,7 @@ export function register(context, { user }) {
password: user.password,
email: user.email,
nickname: user.nickname,
language: user.language,
defaultCurrency: user.defaultCurrency,
firstDayOfWeek: user.firstDayOfWeek
}).then(response => {
@@ -235,10 +236,15 @@ export function updateUserProfile(context, { profile, currentPassword }) {
oldPassword: currentPassword,
email: profile.email,
nickname: profile.nickname,
defaultCurrency: profile.defaultCurrency,
defaultAccountId: profile.defaultAccountId,
transactionEditScope: profile.transactionEditScope,
language: profile.language,
defaultCurrency: profile.defaultCurrency,
firstDayOfWeek: profile.firstDayOfWeek,
transactionEditScope: profile.transactionEditScope
longDateFormat: profile.longDateFormat,
shortDateFormat: profile.shortDateFormat,
longTimeFormat: profile.longTimeFormat,
shortTimeFormat: profile.shortTimeFormat
}).then(response => {
const data = response.data;
@@ -391,17 +397,42 @@ export function currentUserNickname(state) {
return userInfo.nickname || userInfo.username || null;
}
export function currentUserDefaultCurrency(state) {
const userInfo = state.currentUserInfo || {};
return userInfo.defaultCurrency || state.defaultSetting.currency;
}
export function currentUserDefaultAccountId(state) {
const userInfo = state.currentUserInfo || {};
return userInfo.defaultAccountId || '';
}
export function currentUserLanguage(state) {
const userInfo = state.currentUserInfo || {};
return userInfo.language || state.defaultSetting.language;
}
export function currentUserDefaultCurrency(state) {
const userInfo = state.currentUserInfo || {};
return userInfo.defaultCurrency || state.defaultSetting.currency;
}
export function currentUserFirstDayOfWeek(state) {
const userInfo = state.currentUserInfo || {};
return utilities.isNumber(userInfo.firstDayOfWeek) ? userInfo.firstDayOfWeek : state.defaultSetting.firstDayOfWeek;
}
export function currentUserLongDateFormat(state) {
const userInfo = state.currentUserInfo || {};
return utilities.isNumber(userInfo.longDateFormat) ? userInfo.longDateFormat : state.defaultSetting.longDateFormat;
}
export function currentUserShortDateFormat(state) {
const userInfo = state.currentUserInfo || {};
return utilities.isNumber(userInfo.shortDateFormat) ? userInfo.shortDateFormat : state.defaultSetting.shortDateFormat;
}
export function currentUserLongTimeFormat(state) {
const userInfo = state.currentUserInfo || {};
return utilities.isNumber(userInfo.longTimeFormat) ? userInfo.longTimeFormat : state.defaultSetting.longTimeFormat;
}
export function currentUserShortTimeFormat(state) {
const userInfo = state.currentUserInfo || {};
return utilities.isNumber(userInfo.shortTimeFormat) ? userInfo.shortTimeFormat : state.defaultSetting.shortTimeFormat;
}
+1 -1
View File
@@ -51,7 +51,7 @@ export default {
return this.$buildTime;
}
return this.$utilities.formatUnixTime(this.$buildTime, this.$t('format.datetime.long'));
return this.$utilities.formatUnixTime(this.$buildTime, this.$locale.getLongDateTimeFormat());
},
licenseLines() {
return this.$licenses.license.replaceAll(/\r/g, '').split('\n');
+1 -1
View File
@@ -111,7 +111,7 @@ export default {
return '';
}
return this.$utilities.formatUnixTime(this.exchangeRatesData.updateTime, this.$t('format.date.long'));
return this.$utilities.formatUnixTime(this.exchangeRatesData.updateTime, this.$locale.getLongDateFormat());
},
exchangeRateMap() {
const exchangeRateMap = {};
+6 -6
View File
@@ -235,19 +235,19 @@ export default {
return {
today: {
displayTime: self.$utilities.formatUnixTime(self.dateRange.today.startTime, self.$t('format.date.long')),
displayTime: self.$utilities.formatUnixTime(self.dateRange.today.startTime, self.$locale.getLongDateFormat()),
},
thisWeek: {
startTime: self.$utilities.formatUnixTime(self.dateRange.thisWeek.startTime, self.$t('format.monthDay.long')),
endTime: self.$utilities.formatUnixTime(self.dateRange.thisWeek.endTime, self.$t('format.monthDay.long'))
startTime: self.$utilities.formatUnixTime(self.dateRange.thisWeek.startTime, self.$locale.getLongMonthDayFormat()),
endTime: self.$utilities.formatUnixTime(self.dateRange.thisWeek.endTime, self.$locale.getLongMonthDayFormat())
},
thisMonth: {
displayTime: self.$utilities.formatUnixTime(self.dateRange.thisMonth.startTime, 'MMMM'),
startTime: self.$utilities.formatUnixTime(self.dateRange.thisMonth.startTime, self.$t('format.monthDay.long')),
endTime: self.$utilities.formatUnixTime(self.dateRange.thisMonth.endTime, self.$t('format.monthDay.long'))
startTime: self.$utilities.formatUnixTime(self.dateRange.thisMonth.startTime, self.$locale.getLongMonthDayFormat()),
endTime: self.$utilities.formatUnixTime(self.dateRange.thisMonth.endTime, self.$locale.getLongMonthDayFormat())
},
thisYear: {
displayTime: self.$utilities.formatUnixTime(self.dateRange.thisYear.startTime, self.$t('format.year.long'))
displayTime: self.$utilities.formatUnixTime(self.dateRange.thisYear.startTime, self.$locale.getLongYearFormat())
}
};
},
+9 -1
View File
@@ -200,6 +200,10 @@ export default {
return;
}
if (authResponse.user && authResponse.user.language) {
self.$locale.setLanguage(authResponse.user.language);
}
if (self.$settings.isAutoUpdateExchangeRatesData()) {
self.$store.dispatch('getLatestExchangeRates', { silent: true, force: false });
}
@@ -244,10 +248,14 @@ export default {
token: self.tempToken,
passcode: self.twoFAVerifyType === 'passcode' ? self.passcode : null,
recoveryCode: self.twoFAVerifyType === 'backupcode' ? self.backupCode : null
}).then(() => {
}).then(authResponse => {
self.verifying = false;
self.$hideLoading();
if (authResponse.user && authResponse.user.language) {
self.$locale.setLanguage(authResponse.user.language);
}
if (self.$settings.isAutoUpdateExchangeRatesData()) {
self.$store.dispatch('getLatestExchangeRates', { silent: true, force: false });
}
+1 -25
View File
@@ -16,18 +16,6 @@
<f7-block-title>{{ $t('Application') }}</f7-block-title>
<f7-list strong inset dividers>
<f7-list-item
:key="currentLocale + '_lang'"
:title="$t('Language')"
smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Language'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), popupCloseLinkText: $t('Done') }">
<select v-model="currentLocale">
<option :value="locale"
:key="locale"
v-for="(lang, locale) in allLanguages">{{ lang.displayName }}</option>
</select>
</f7-list-item>
<f7-list-item
:key="currentLocale + '_timezone'"
:title="$t('Timezone')"
smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Timezone'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), popupCloseLinkText: $t('Done') }">
<select v-model="currentTimezone">
@@ -57,7 +45,6 @@
</f7-list-item>
<f7-list-item
:key="currentLocale + '_currency_display'"
:title="$t('Currency Display Mode')"
smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Currency Display Mode'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), popupCloseLinkText: $t('Done') }">
<select v-model="currencyDisplayMode">
@@ -117,20 +104,9 @@ export default {
version() {
return 'v' + this.$version;
},
allLanguages() {
return this.$locale.getAllLanguageInfos();
},
allTimezones() {
return this.$locale.getAllTimezones(true);
},
currentLocale: {
get: function () {
return this.$i18n.locale;
},
set: function (value) {
this.$locale.setLanguage(value);
}
},
currentTimezone: {
get: function () {
return this.$locale.getTimezone();
@@ -144,7 +120,7 @@ export default {
},
exchangeRatesLastUpdateDate() {
const exchangeRatesLastUpdateTime = this.$store.getters.exchangeRatesLastUpdateTime;
return exchangeRatesLastUpdateTime ? this.$utilities.formatUnixTime(exchangeRatesLastUpdateTime, this.$t('format.date.long')) : '';
return exchangeRatesLastUpdateTime ? this.$utilities.formatUnixTime(exchangeRatesLastUpdateTime, this.$locale.getLongDateFormat()) : '';
},
isAutoUpdateExchangeRatesData: {
get: function () {
+7 -1
View File
@@ -188,6 +188,7 @@ export default {
confirmPassword: '',
email: '',
nickname: '',
language: self.$i18n.locale,
defaultCurrency: self.$store.state.defaultSetting.currency,
firstDayOfWeek: self.$constants.datetime.allWeekDays[self.$t('default.firstDayOfWeek')] ? self.$constants.datetime.allWeekDays[self.$t('default.firstDayOfWeek')].type : 0
},
@@ -221,6 +222,7 @@ export default {
const isCurrencyDefault = this.user.defaultCurrency === this.$store.state.defaultSetting.currency;
const isFirstWeekDayDefault = this.user.firstDayOfWeek === (this.$constants.datetime.allWeekDays[this.$t('default.firstDayOfWeek')] ? this.$constants.datetime.allWeekDays[this.$t('default.firstDayOfWeek')].type : 0);
this.user.language = value;
this.$locale.setLanguage(value);
if (isCurrencyDefault) {
@@ -324,7 +326,7 @@ export default {
self.$store.dispatch('register', {
user: self.user
}).then(() => {
}).then(response => {
if (!self.$user.isUserLogined()) {
self.submitting = false;
self.$hideLoading();
@@ -339,6 +341,10 @@ export default {
return;
}
if (response.user && response.user.language) {
self.$locale.setLanguage(response.user.language);
}
if (self.$settings.isAutoUpdateExchangeRatesData()) {
self.$store.dispatch('getLatestExchangeRates', { silent: true, force: false });
}
+22 -12
View File
@@ -113,7 +113,11 @@ export default {
self.$hideLoading();
self.$user.unlockTokenByWebAuthn(id, userName, userSecret);
self.$store.dispatch('refreshTokenAndRevokeOldToken');
self.$store.dispatch('refreshTokenAndRevokeOldToken').then(response => {
if (response.user && response.user.language) {
self.$locale.setLanguage(response.user.language);
}
});
if (self.$settings.isAutoUpdateExchangeRatesData()) {
self.$store.dispatch('getLatestExchangeRates', { silent: true, force: false });
@@ -136,34 +140,40 @@ export default {
});
},
unlockByPin(pinCode) {
if (!this.isPinCodeValid(pinCode)) {
const self = this;
if (!self.isPinCodeValid(pinCode)) {
return;
}
if (this.$ui.isModalShowing()) {
if (self.$ui.isModalShowing()) {
return;
}
const router = this.f7router;
const user = this.$store.state.currentUserInfo;
const router = self.f7router;
const user = self.$store.state.currentUserInfo;
if (!user || !user.username) {
this.$alert('An error has occurred');
self.$alert('An error has occurred');
return;
}
try {
this.$user.unlockTokenByPinCode(user.username, pinCode);
this.$store.dispatch('refreshTokenAndRevokeOldToken');
self.$user.unlockTokenByPinCode(user.username, pinCode);
self.$store.dispatch('refreshTokenAndRevokeOldToken').then(response => {
if (response.user && response.user.language) {
self.$locale.setLanguage(response.user.language);
}
});
if (this.$settings.isAutoUpdateExchangeRatesData()) {
this.$store.dispatch('getLatestExchangeRates', { silent: true, force: false });
if (self.$settings.isAutoUpdateExchangeRatesData()) {
self.$store.dispatch('getLatestExchangeRates', { silent: true, force: false });
}
router.refreshPage();
} catch (ex) {
this.$logger.error('failed to unlock by pin code', ex);
this.$toast('PIN code is wrong');
self.$logger.error('failed to unlock by pin code', ex);
self.$toast('PIN code is wrong');
}
},
relogin() {
@@ -217,10 +217,10 @@
</template>
<template #footer>
<div v-if="dateRange.type === allDateRanges.Custom.type && query.dateType === allDateRanges.Custom.type && query.startTime && query.endTime">
<span>{{ $utilities.formatUnixTime(query.startTime, $t('format.datetime.long-without-second')) }}</span>
<span>{{ $utilities.formatUnixTime(query.startTime, $locale.getLongDateTimeFormat()) }}</span>
<span>&nbsp;-&nbsp;</span>
<br/>
<span>{{ $utilities.formatUnixTime(query.endTime, $t('format.datetime.long-without-second')) }}</span>
<span>{{ $utilities.formatUnixTime(query.endTime, $locale.getLongDateTimeFormat()) }}</span>
</div>
</template>
</f7-list-item>
@@ -618,15 +618,15 @@ export default {
}
if (this.$utilities.isDateRangeMatchFullYears(query.startTime, query.endTime)) {
const displayStartTime = this.$utilities.formatUnixTime(query.startTime, this.$t('format.year.short'));
const displayEndTime = this.$utilities.formatUnixTime(query.endTime, this.$t('format.year.short'));
const displayStartTime = this.$utilities.formatUnixTime(query.startTime, this.$locale.getShortYearFormat());
const displayEndTime = this.$utilities.formatUnixTime(query.endTime, this.$locale.getShortYearFormat());
return displayStartTime !== displayEndTime ? `${displayStartTime} ~ ${displayEndTime}` : displayStartTime;
}
if (this.$utilities.isDateRangeMatchFullMonths(query.startTime, query.endTime)) {
const displayStartTime = this.$utilities.formatUnixTime(query.startTime, this.$t('format.yearMonth.short'));
const displayEndTime = this.$utilities.formatUnixTime(query.endTime, this.$t('format.yearMonth.short'));
const displayStartTime = this.$utilities.formatUnixTime(query.startTime, this.$locale.getShortYearMonthFormat());
const displayEndTime = this.$utilities.formatUnixTime(query.endTime, this.$locale.getShortYearMonthFormat());
return displayStartTime !== displayEndTime ? `${displayStartTime} ~ ${displayEndTime}` : displayStartTime;
}
@@ -634,13 +634,13 @@ export default {
const startTimeYear = this.$utilities.getYear(this.$utilities.parseDateFromUnixTime(query.startTime));
const endTimeYear = this.$utilities.getYear(this.$utilities.parseDateFromUnixTime(query.endTime));
const displayStartTime = this.$utilities.formatUnixTime(query.startTime, this.$t('format.date.short'));
const displayEndTime = this.$utilities.formatUnixTime(query.endTime, this.$t('format.date.short'));
const displayStartTime = this.$utilities.formatUnixTime(query.startTime, this.$locale.getShortDateFormat());
const displayEndTime = this.$utilities.formatUnixTime(query.endTime, this.$locale.getShortDateFormat());
if (displayStartTime === displayEndTime) {
return displayStartTime;
} else if (startTimeYear === endTimeYear) {
const displayShortEndTime = this.$utilities.formatUnixTime(query.endTime, this.$t('format.monthDay.short'));
const displayShortEndTime = this.$utilities.formatUnixTime(query.endTime, this.$locale.getShortMonthDayFormat());
return `${displayStartTime} ~ ${displayShortEndTime}`;
}
+1 -1
View File
@@ -213,7 +213,7 @@
link="#" no-chevron
:class="{ 'readonly': mode === 'view' }"
:header="$t('Transaction Time')"
:title="$utilities.formatUnixTime($utilities.getActualUnixTimeForStore(transaction.time, $utilities.getTimezoneOffsetMinutes(), $utilities.getBrowserTimezoneOffsetMinutes()), this.$t('format.datetime.long'))"
:title="$utilities.formatUnixTime($utilities.getActualUnixTimeForStore(transaction.time, $utilities.getTimezoneOffsetMinutes(), $utilities.getBrowserTimezoneOffsetMinutes()), $locale.getLongDateTimeFormat())"
@click="showTransactionDateTimeSheet = true"
>
<date-time-selection-sheet v-model:show="showTransactionDateTimeSheet"
+9 -4
View File
@@ -123,7 +123,7 @@
<f7-list-item>
<template #title>
<small>
<span>{{ $utilities.formatTime(transactionMonthList.yearMonth, $t('format.yearMonth.long')) }}</span>
<span>{{ $utilities.formatTime(transactionMonthList.yearMonth, $locale.getLongYearMonthFormat()) }}</span>
</small>
<small class="transaction-amount-statistics" v-if="showTotalAmountInTransactionListPage && transactionMonthList.totalAmount">
<span class="text-color-red">
@@ -202,7 +202,7 @@
</div>
<div class="item-footer">
<div class="transaction-footer">
<span>{{ $utilities.formatUnixTime(transaction.time, $t('format.hourMinute.long'), transaction.utcOffset, currentTimezoneOffsetMinutes) }}</span>
<span>{{ $utilities.formatUnixTime(transaction.time, $locale.getShortTimeFormat(), transaction.utcOffset, currentTimezoneOffsetMinutes) }}</span>
<span v-if="transaction.utcOffset !== currentTimezoneOffsetMinutes">{{ `(UTC${$utilities.getUtcOffsetByUtcOffsetMinutes(transaction.utcOffset)})` }}</span>
<span v-if="transaction.sourceAccount">·</span>
<span v-if="transaction.sourceAccount">{{ transaction.sourceAccount.name }}</span>
@@ -252,10 +252,10 @@
</template>
<template #footer>
<div v-if="dateRange.type === $constants.datetime.allDateRanges.Custom.type && query.dateType === $constants.datetime.allDateRanges.Custom.type && query.minTime && query.maxTime">
<span>{{ $utilities.formatUnixTime(query.minTime, $t('format.datetime.long-without-second')) }}</span>
<span>{{ $utilities.formatUnixTime(query.minTime, $locale.getLongDateTimeFormat()) }}</span>
<span>&nbsp;-&nbsp;</span>
<br/>
<span>{{ $utilities.formatUnixTime(query.maxTime, $t('format.datetime.long-without-second')) }}</span>
<span>{{ $utilities.formatUnixTime(query.maxTime, $locale.getLongDateTimeFormat()) }}</span>
</div>
</template>
</f7-list-item>
@@ -840,6 +840,11 @@ export default {
</script>
<style>
.list.transaction-amount-list .transaction-amount-statistics {
overflow: hidden;
text-overflow: ellipsis;
}
.list.transaction-amount-list .transaction-amount-statistics > span {
margin-left: 8px;
font-weight: normal;
+1 -1
View File
@@ -72,7 +72,7 @@ export default {
deviceType: this.$t(token.isCurrent ? 'Current' : 'Other Device'),
deviceInfo: this.$utilities.parseDeviceInfo(token.userAgent),
icon: this.getTokenIcon(token),
createdAt: this.$utilities.formatUnixTime(token.createdAt, this.$t('format.datetime.long'))
createdAt: this.$utilities.formatUnixTime(token.createdAt, this.$locale.getLongDateTimeFormat())
});
}
+218 -60
View File
@@ -16,12 +16,20 @@
</f7-list>
<f7-list strong inset dividers class="margin-vertical skeleton-text" v-if="loading">
<f7-list-item class="list-item-with-header-and-title list-item-no-item-after" header="Default Currency" title="Currency" link="#"></f7-list-item>
<f7-list-item class="list-item-with-header-and-title list-item-no-item-after" header="Default Account" title="Not Specified"></f7-list-item>
<f7-list-item class="list-item-with-header-and-title list-item-no-item-after" header="First Day of Week" title="Week Day" link="#"></f7-list-item>
<f7-list-item class="list-item-with-header-and-title list-item-no-item-after" header="Editable Transaction Scope" title="All" link="#"></f7-list-item>
</f7-list>
<f7-list strong inset dividers class="margin-vertical skeleton-text" v-if="loading">
<f7-list-item class="list-item-with-header-and-title list-item-no-item-after" header="Default Language" title="Language" link="#"></f7-list-item>
<f7-list-item class="list-item-with-header-and-title list-item-no-item-after" header="Default Currency" title="Currency" link="#"></f7-list-item>
<f7-list-item class="list-item-with-header-and-title list-item-no-item-after" header="First Day of Week" title="Week Day" link="#"></f7-list-item>
<f7-list-item class="list-item-with-header-and-title list-item-no-item-after" header="Long Date Format" title="YYYY-MM-DD" link="#"></f7-list-item>
<f7-list-item class="list-item-with-header-and-title list-item-no-item-after" header="Short Date Format" title="YYYY-MM-DD" link="#"></f7-list-item>
<f7-list-item class="list-item-with-header-and-title list-item-no-item-after" header="Long Time Format" title="HH:mm:ss" link="#"></f7-list-item>
<f7-list-item class="list-item-with-header-and-title list-item-no-item-after" header="Short Time Format" title="HH:mm" link="#"></f7-list-item>
</f7-list>
<f7-list form strong inset dividers class="margin-vertical" v-if="!loading">
<f7-list-input
type="password"
@@ -63,24 +71,6 @@
</f7-list>
<f7-list form strong inset dividers class="margin-vertical" v-if="!loading">
<f7-list-item
class="list-item-with-header-and-title list-item-no-item-after"
:header="$t('Default Currency')"
smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Currency Name'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), pageTitle: $t('Default Currency'), popupCloseLinkText: $t('Done') }"
>
<template #title>
<f7-block class="no-padding no-margin">
<span>{{ $t(`currency.${newProfile.defaultCurrency}`) }}&nbsp;</span>
<small class="smaller">{{ newProfile.defaultCurrency }}</small>
</f7-block>
</template>
<select autocomplete="transaction-currency" v-model="newProfile.defaultCurrency">
<option :value="currency.code"
:key="currency.code"
v-for="currency in allCurrencies">{{ currency.displayName }}</option>
</select>
</f7-list-item>
<f7-list-item
class="list-item-with-header-and-title"
link="#" no-chevron
@@ -103,19 +93,6 @@
</two-column-list-item-selection-sheet>
</f7-list-item>
<f7-list-item
class="list-item-with-header-and-title list-item-no-item-after"
:header="$t('First Day of Week')"
:title="getDayOfWeekName(newProfile.firstDayOfWeek)"
smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Date'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), pageTitle: $t('First Day of Week'), popupCloseLinkText: $t('Done') }"
>
<select v-model="newProfile.firstDayOfWeek">
<option :value="weekDay.type"
:key="weekDay.type"
v-for="weekDay in allWeekDays">{{ $t(`datetime.${weekDay.name}.long`) }}</option>
</select>
</f7-list-item>
<f7-list-item
class="list-item-with-header-and-title list-item-no-item-after"
:header="$t('Editable Transaction Scope')"
@@ -132,6 +109,105 @@
<f7-list-item class="ebk-list-item-error-info" v-if="extendInputIsInvalid" :footer="$t(extendInputInvalidProblemMessage)"></f7-list-item>
</f7-list>
<f7-list form strong inset dividers class="margin-vertical" v-if="!loading">
<f7-list-item
class="list-item-with-header-and-title list-item-no-item-after"
:header="$t('Language')"
:title="currentLanguageName"
smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Language'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), pageTitle: $t('Language'), popupCloseLinkText: $t('Done') }">
<select v-model="newProfile.language">
<option :value="language.code"
:key="language.code"
v-for="language in allLanguages">{{ language.displayName }}</option>
</select>
</f7-list-item>
<f7-list-item
class="list-item-with-header-and-title list-item-no-item-after"
:header="$t('Default Currency')"
smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Currency Name'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), pageTitle: $t('Default Currency'), popupCloseLinkText: $t('Done') }"
>
<template #title>
<f7-block class="no-padding no-margin">
<span>{{ $t(`currency.${newProfile.defaultCurrency}`) }}&nbsp;</span>
<small class="smaller">{{ newProfile.defaultCurrency }}</small>
</f7-block>
</template>
<select autocomplete="transaction-currency" v-model="newProfile.defaultCurrency">
<option :value="currency.code"
:key="currency.code"
v-for="currency in allCurrencies">{{ currency.displayName }}</option>
</select>
</f7-list-item>
<f7-list-item
class="list-item-with-header-and-title list-item-no-item-after"
:header="$t('First Day of Week')"
:title="currentDayOfWeekName"
smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Date'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), pageTitle: $t('First Day of Week'), popupCloseLinkText: $t('Done') }"
>
<select v-model="newProfile.firstDayOfWeek">
<option :value="weekDay.type"
:key="weekDay.type"
v-for="weekDay in allWeekDays">{{ $t(`datetime.${weekDay.name}.long`) }}</option>
</select>
</f7-list-item>
<f7-list-item
class="list-item-with-header-and-title list-item-no-item-after"
:header="$t('Long Date Format')"
:title="$utilities.getNameByKeyValue(allLongDateFormats, newProfile.longDateFormat, 'type', 'displayName')"
smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Long Date Format'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), pageTitle: $t('Long Date Format'), popupCloseLinkText: $t('Done') }"
>
<select v-model="newProfile.longDateFormat">
<option :value="format.type"
:key="format.type"
v-for="format in allLongDateFormats">{{ format.displayName }}</option>
</select>
</f7-list-item>
<f7-list-item
class="list-item-with-header-and-title list-item-no-item-after"
:header="$t('Short Date Format')"
:title="$utilities.getNameByKeyValue(allShortDateFormats, newProfile.shortDateFormat, 'type', 'displayName')"
smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Short Date Format'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), pageTitle: $t('Short Date Format'), popupCloseLinkText: $t('Done') }"
>
<select v-model="newProfile.shortDateFormat">
<option :value="format.type"
:key="format.type"
v-for="format in allShortDateFormats">{{ format.displayName }}</option>
</select>
</f7-list-item>
<f7-list-item
class="list-item-with-header-and-title list-item-no-item-after"
:header="$t('Long Time Format')"
:title="$utilities.getNameByKeyValue(allLongTimeFormats, newProfile.longTimeFormat, 'type', 'displayName')"
smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Long Time Format'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), pageTitle: $t('Long Time Format'), popupCloseLinkText: $t('Done') }"
>
<select v-model="newProfile.longTimeFormat">
<option :value="format.type"
:key="format.type"
v-for="format in allLongTimeFormats">{{ format.displayName }}</option>
</select>
</f7-list-item>
<f7-list-item
class="list-item-with-header-and-title list-item-no-item-after"
:header="$t('Short Time Format')"
:title="$utilities.getNameByKeyValue(allShortTimeFormats, newProfile.shortTimeFormat, 'type', 'displayName')"
smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Long Time Format'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), pageTitle: $t('Short Time Format'), popupCloseLinkText: $t('Done') }"
>
<select v-model="newProfile.shortTimeFormat">
<option :value="format.type"
:key="format.type"
v-for="format in allShortTimeFormats">{{ format.displayName }}</option>
</select>
</f7-list-item>
<f7-list-item class="ebk-list-item-error-info" v-if="langAndRegionInputIsInvalid" :footer="$t(langAndRegionInputInvalidProblemMessage)"></f7-list-item>
</f7-list>
<password-input-sheet :title="$t('Modify Password')"
:hint="$t('Please enter your current password when modifying your password')"
:confirm-disabled="saving"
@@ -155,18 +231,28 @@ export default {
confirmPassword: '',
email: '',
nickname: '',
defaultCurrency: '',
defaultAccountId: '',
transactionEditScope: 1,
language: '',
defaultCurrency: '',
firstDayOfWeek: 0,
transactionEditScope: 1
longDateFormat: 0,
shortDateFormat: 0,
longTimeFormat: 0,
shortTimeFormat: 0
},
oldProfile: {
email: '',
nickname: '',
defaultCurrency: '',
defaultAccountId: '',
transactionEditScope: 1,
language: '',
defaultCurrency: '',
firstDayOfWeek: 0,
transactionEditScope: 1
longDateFormat: 0,
shortDateFormat: 0,
longTimeFormat: 0,
shortTimeFormat: 0
},
currentPassword: '',
loading: true,
@@ -177,6 +263,30 @@ export default {
};
},
computed: {
allLanguages() {
const ret = [];
const allLanguageInfo = this.$locale.getAllLanguageInfos();
ret.push({
code: '',
displayName: this.$t('System Default')
});
for (let code in allLanguageInfo) {
if (!Object.prototype.hasOwnProperty.call(allLanguageInfo, code)) {
continue;
}
const languageInfo = allLanguageInfo[code];
ret.push({
code: code,
displayName: languageInfo.displayName
});
}
return ret;
},
allCurrencies() {
return this.$locale.getAllCurrencies();
},
@@ -192,6 +302,18 @@ export default {
allWeekDays() {
return this.$constants.datetime.allWeekDays;
},
allLongDateFormats() {
return this.$locale.getAllLongDateFormats();
},
allShortDateFormats() {
return this.$locale.getAllShortDateFormats();
},
allLongTimeFormats() {
return this.$locale.getAllLongTimeFormats();
},
allShortTimeFormats() {
return this.$locale.getAllShortTimeFormats();
},
allTransactionEditScopeTypes() {
return [{
value: 0,
@@ -216,6 +338,20 @@ export default {
name: 'This year or later'
}];
},
currentLanguageName() {
for (let i = 0; i < this.allLanguages.length; i++) {
if (this.allLanguages[i].code === this.newProfile.language) {
return this.allLanguages[i].displayName;
}
}
return this.$t('Unknown');
},
currentDayOfWeekName() {
const weekName = this.$utilities.getNameByKeyValue(this.$constants.datetime.allWeekDays, this.newProfile.firstDayOfWeek, 'type', 'name');
const i18nWeekNameKey = `datetime.${weekName}.long`;
return this.$t(i18nWeekNameKey);
},
inputIsNotChanged() {
return !!this.inputIsNotChangedProblemMessage;
},
@@ -225,16 +361,24 @@ export default {
extendInputIsInvalid() {
return !!this.extendInputInvalidProblemMessage;
},
langAndRegionInputIsInvalid() {
return !!this.langAndRegionInputInvalidProblemMessage;
},
inputIsNotChangedProblemMessage() {
if (!this.newProfile.password && !this.newProfile.confirmPassword && !this.newProfile.email && !this.newProfile.nickname) {
return 'Nothing has been modified';
} else if (!this.newProfile.password && !this.newProfile.confirmPassword &&
this.newProfile.email === this.oldProfile.email &&
this.newProfile.nickname === this.oldProfile.nickname &&
this.newProfile.defaultCurrency === this.oldProfile.defaultCurrency &&
this.newProfile.defaultAccountId === this.oldProfile.defaultAccountId &&
this.newProfile.transactionEditScope === this.oldProfile.transactionEditScope &&
this.newProfile.language === this.oldProfile.language &&
this.newProfile.defaultCurrency === this.oldProfile.defaultCurrency &&
this.newProfile.firstDayOfWeek === this.oldProfile.firstDayOfWeek &&
this.newProfile.transactionEditScope === this.oldProfile.transactionEditScope) {
this.newProfile.longDateFormat === this.oldProfile.longDateFormat &&
this.newProfile.shortDateFormat === this.oldProfile.shortDateFormat &&
this.newProfile.longTimeFormat === this.oldProfile.longTimeFormat &&
this.newProfile.shortTimeFormat === this.oldProfile.shortTimeFormat) {
return 'Nothing has been modified';
} else if (!this.newProfile.password && this.newProfile.confirmPassword) {
return 'Password cannot be empty';
@@ -258,6 +402,9 @@ export default {
}
},
extendInputInvalidProblemMessage() {
return null;
},
langAndRegionInputInvalidProblemMessage() {
if (!this.newProfile.defaultCurrency) {
return 'Default currency cannot be empty';
} else {
@@ -277,21 +424,7 @@ export default {
Promise.all(promises).then(responses => {
const profile = responses[1];
self.oldProfile.email = profile.email;
self.oldProfile.nickname = profile.nickname;
self.oldProfile.defaultCurrency = profile.defaultCurrency;
self.oldProfile.defaultAccountId = profile.defaultAccountId;
self.oldProfile.firstDayOfWeek = profile.firstDayOfWeek;
self.oldProfile.transactionEditScope = profile.transactionEditScope;
self.newProfile.email = self.oldProfile.email
self.newProfile.nickname = self.oldProfile.nickname;
self.newProfile.defaultCurrency = self.oldProfile.defaultCurrency;
self.newProfile.defaultAccountId = self.oldProfile.defaultAccountId;
self.newProfile.firstDayOfWeek = self.oldProfile.firstDayOfWeek;
self.newProfile.transactionEditScope = self.oldProfile.transactionEditScope;
self.setCurrentUserProfile(profile);
self.loading = false;
}).catch(error => {
if (error.processed) {
@@ -312,7 +445,7 @@ export default {
self.showInputPasswordSheet = false;
let problemMessage = self.inputIsNotChangedProblemMessage || self.inputInvalidProblemMessage || self.extendInputInvalidProblemMessage;
let problemMessage = self.inputIsNotChangedProblemMessage || self.inputInvalidProblemMessage || self.extendInputInvalidProblemMessage || self.langAndRegionInputInvalidProblemMessage;
if (problemMessage) {
self.$alert(problemMessage);
@@ -330,11 +463,16 @@ export default {
self.$store.dispatch('updateUserProfile', {
profile: self.newProfile,
currentPassword: self.currentPassword
}).then(() => {
}).then(response => {
self.saving = false;
self.$hideLoading();
self.currentPassword = '';
if (response.user) {
self.setCurrentUserProfile(response.user);
self.$locale.setLanguage(response.user.language);
}
self.$toast('Your profile has been successfully updated');
router.back();
}).catch(error => {
@@ -347,10 +485,30 @@ export default {
}
});
},
getDayOfWeekName(dayOfWeek) {
const weekName = this.$utilities.getNameByKeyValue(this.$constants.datetime.allWeekDays, dayOfWeek, 'type', 'name');
const i18nWeekNameKey = `datetime.${weekName}.long`;
return this.$t(i18nWeekNameKey);
setCurrentUserProfile(profile) {
this.oldProfile.email = profile.email;
this.oldProfile.nickname = profile.nickname;
this.oldProfile.defaultAccountId = profile.defaultAccountId;
this.oldProfile.transactionEditScope = profile.transactionEditScope;
this.oldProfile.language = profile.language;
this.oldProfile.defaultCurrency = profile.defaultCurrency;
this.oldProfile.firstDayOfWeek = profile.firstDayOfWeek;
this.oldProfile.longDateFormat = profile.longDateFormat;
this.oldProfile.shortDateFormat = profile.shortDateFormat;
this.oldProfile.longTimeFormat = profile.longTimeFormat;
this.oldProfile.shortTimeFormat = profile.shortTimeFormat;
this.newProfile.email = this.oldProfile.email
this.newProfile.nickname = this.oldProfile.nickname;
this.newProfile.defaultAccountId = this.oldProfile.defaultAccountId;
this.newProfile.transactionEditScope = this.oldProfile.transactionEditScope;
this.newProfile.language = this.oldProfile.language;
this.newProfile.defaultCurrency = this.oldProfile.defaultCurrency;
this.newProfile.firstDayOfWeek = this.oldProfile.firstDayOfWeek;
this.newProfile.longDateFormat = this.oldProfile.longDateFormat;
this.newProfile.shortDateFormat = this.oldProfile.shortDateFormat;
this.newProfile.longTimeFormat = this.oldProfile.longTimeFormat;
this.newProfile.shortTimeFormat = this.oldProfile.shortTimeFormat;
}
}
};