update text content

This commit is contained in:
MaysWind
2024-04-06 13:07:16 +08:00
parent cb57b216d0
commit 4b68ccf678
70 changed files with 557 additions and 563 deletions
+2 -2
View File
@@ -58,7 +58,7 @@ func updateAllDatabaseTablesStructure() error {
return err return err
} }
log.BootInfof("[database.updateAllDatabaseTablesStructure] two factor table maintained successfully") log.BootInfof("[database.updateAllDatabaseTablesStructure] two-factor table maintained successfully")
err = datastore.Container.UserStore.SyncStructs(new(models.TwoFactorRecoveryCode)) err = datastore.Container.UserStore.SyncStructs(new(models.TwoFactorRecoveryCode))
@@ -66,7 +66,7 @@ func updateAllDatabaseTablesStructure() error {
return err return err
} }
log.BootInfof("[database.updateAllDatabaseTablesStructure] two factor recovery code table maintained successfully") log.BootInfof("[database.updateAllDatabaseTablesStructure] two-factor recovery code table maintained successfully")
err = datastore.Container.TokenStore.SyncStructs(new(models.TokenRecord)) err = datastore.Container.TokenStore.SyncStructs(new(models.TokenRecord))
+3 -3
View File
@@ -475,11 +475,11 @@ func disableUser2FA(c *cli.Context) error {
err = clis.UserData.DisableUserTwoFactorAuthorization(c, username) err = clis.UserData.DisableUserTwoFactorAuthorization(c, username)
if err != nil { if err != nil {
log.BootErrorf("[user_data.disableUser2FA] error occurs when disabling user two factor authorization") log.BootErrorf("[user_data.disableUser2FA] error occurs when disabling user two-factor authorization")
return err return err
} }
log.BootInfof("[user_data.disableUser2FA] two factor authorization of user \"%s\" has been disabled", username) log.BootInfof("[user_data.disableUser2FA] two-factor authorization of user \"%s\" has been disabled", username)
return nil return nil
} }
@@ -570,7 +570,7 @@ func exportUserTransaction(c *cli.Context) error {
} }
if filePath == "" { if filePath == "" {
log.BootErrorf("[user_data.exportUserTransaction] export file path is not specified") log.BootErrorf("[user_data.exportUserTransaction] export file path is unspecified")
return os.ErrNotExist return os.ErrNotExist
} }
+1 -1
View File
@@ -242,7 +242,7 @@ func startWebServer(c *cli.Context) error {
apiV1Route.POST("/users/verify_email/resend.json", bindApi(api.Users.UserSendVerifyEmailByLoginedUserHandler)) apiV1Route.POST("/users/verify_email/resend.json", bindApi(api.Users.UserSendVerifyEmailByLoginedUserHandler))
} }
// Two Factor Authorization // Two-Factor Authorization
if config.EnableTwoFactor { if config.EnableTwoFactor {
apiV1Route.GET("/users/2fa/status.json", bindApi(api.TwoFactorAuthorizations.TwoFactorStatusHandler)) apiV1Route.GET("/users/2fa/status.json", bindApi(api.TwoFactorAuthorizations.TwoFactorStatusHandler))
apiV1Route.POST("/users/2fa/enable/request.json", bindApi(api.TwoFactorAuthorizations.TwoFactorEnableRequestHandler)) apiV1Route.POST("/users/2fa/enable/request.json", bindApi(api.TwoFactorAuthorizations.TwoFactorEnableRequestHandler))
+1 -1
View File
@@ -103,7 +103,7 @@ server_id = 0
# Used for signing, you must change it to keep your user data safe before you first run ezBookkeeping # Used for signing, you must change it to keep your user data safe before you first run ezBookkeeping
secret_key = secret_key =
# Set to true to enable two factor authorization # Set to true to enable two-factor authorization
enable_two_factor = true enable_two_factor = true
# Token expired seconds (0 - 4294967295), default is 2592000 (30 days) # Token expired seconds (0 - 4294967295), default is 2592000 (30 days)
+5 -5
View File
@@ -145,7 +145,7 @@ func (a *AccountsApi) AccountCreateHandler(c *core.Context) (any, *errs.Error) {
if accountCreateReq.Type == models.ACCOUNT_TYPE_SINGLE_ACCOUNT { if accountCreateReq.Type == models.ACCOUNT_TYPE_SINGLE_ACCOUNT {
if len(accountCreateReq.SubAccounts) > 0 { if len(accountCreateReq.SubAccounts) > 0 {
log.WarnfWithRequestId(c, "[accounts.AccountCreateHandler] account cannot have any sub accounts") log.WarnfWithRequestId(c, "[accounts.AccountCreateHandler] account cannot have any sub-accounts")
return nil, errs.ErrAccountCannotHaveSubAccounts return nil, errs.ErrAccountCannotHaveSubAccounts
} }
@@ -155,7 +155,7 @@ func (a *AccountsApi) AccountCreateHandler(c *core.Context) (any, *errs.Error) {
} }
} else if accountCreateReq.Type == models.ACCOUNT_TYPE_MULTI_SUB_ACCOUNTS { } else if accountCreateReq.Type == models.ACCOUNT_TYPE_MULTI_SUB_ACCOUNTS {
if len(accountCreateReq.SubAccounts) < 1 { if len(accountCreateReq.SubAccounts) < 1 {
log.WarnfWithRequestId(c, "[accounts.AccountCreateHandler] account does not have any sub accounts") log.WarnfWithRequestId(c, "[accounts.AccountCreateHandler] account does not have any sub-accounts")
return nil, errs.ErrAccountHaveNoSubAccount return nil, errs.ErrAccountHaveNoSubAccount
} }
@@ -173,17 +173,17 @@ func (a *AccountsApi) AccountCreateHandler(c *core.Context) (any, *errs.Error) {
subAccount := accountCreateReq.SubAccounts[i] subAccount := accountCreateReq.SubAccounts[i]
if subAccount.Category != accountCreateReq.Category { if subAccount.Category != accountCreateReq.Category {
log.WarnfWithRequestId(c, "[accounts.AccountCreateHandler] category of sub account not equals to parent") log.WarnfWithRequestId(c, "[accounts.AccountCreateHandler] category of sub-account not equals to parent")
return nil, errs.ErrSubAccountCategoryNotEqualsToParent return nil, errs.ErrSubAccountCategoryNotEqualsToParent
} }
if subAccount.Type != models.ACCOUNT_TYPE_SINGLE_ACCOUNT { if subAccount.Type != models.ACCOUNT_TYPE_SINGLE_ACCOUNT {
log.WarnfWithRequestId(c, "[accounts.AccountCreateHandler] sub account type invalid") log.WarnfWithRequestId(c, "[accounts.AccountCreateHandler] sub-account type invalid")
return nil, errs.ErrSubAccountTypeInvalid return nil, errs.ErrSubAccountTypeInvalid
} }
if subAccount.Currency == validators.ParentAccountCurrencyPlaceholder { if subAccount.Currency == validators.ParentAccountCurrencyPlaceholder {
log.WarnfWithRequestId(c, "[accounts.AccountCreateHandler] sub account cannot set currency placeholder") log.WarnfWithRequestId(c, "[accounts.AccountCreateHandler] sub-account cannot set currency placeholder")
return nil, errs.ErrAccountCurrencyInvalid return nil, errs.ErrAccountCurrencyInvalid
} }
} }
+6 -6
View File
@@ -77,7 +77,7 @@ func (a *AuthorizationsApi) AuthorizeHandler(c *core.Context) (any, *errs.Error)
twoFactorEnable, err = a.twoFactorAuthorizations.ExistsTwoFactorSetting(c, user.Uid) twoFactorEnable, err = a.twoFactorAuthorizations.ExistsTwoFactorSetting(c, user.Uid)
if err != nil { if err != nil {
log.ErrorfWithRequestId(c, "[authorizations.AuthorizeHandler] failed to check two factor setting for user \"uid:%d\", because %s", user.Uid, err.Error()) log.ErrorfWithRequestId(c, "[authorizations.AuthorizeHandler] failed to check two-factor setting for user \"uid:%d\", because %s", user.Uid, err.Error())
return nil, errs.Or(err, errs.ErrSystemError) return nil, errs.Or(err, errs.ErrSystemError)
} }
} }
@@ -122,7 +122,7 @@ func (a *AuthorizationsApi) TwoFactorAuthorizeHandler(c *core.Context) (any, *er
twoFactorSetting, err := a.twoFactorAuthorizations.GetUserTwoFactorSettingByUid(c, uid) twoFactorSetting, err := a.twoFactorAuthorizations.GetUserTwoFactorSettingByUid(c, uid)
if err != nil { if err != nil {
log.ErrorfWithRequestId(c, "[authorizations.TwoFactorAuthorizeHandler] failed to get two factor setting for user \"uid:%d\", because %s", uid, err.Error()) log.ErrorfWithRequestId(c, "[authorizations.TwoFactorAuthorizeHandler] failed to get two-factor setting for user \"uid:%d\", because %s", uid, err.Error())
return nil, errs.Or(err, errs.ErrSystemError) return nil, errs.Or(err, errs.ErrSystemError)
} }
@@ -165,7 +165,7 @@ func (a *AuthorizationsApi) TwoFactorAuthorizeHandler(c *core.Context) (any, *er
c.SetTextualToken(token) c.SetTextualToken(token)
c.SetTokenClaims(claims) c.SetTokenClaims(claims)
log.InfofWithRequestId(c, "[authorizations.TwoFactorAuthorizeHandler] user \"uid:%d\" has authorized two factor via passcode, token will be expired at %d", user.Uid, claims.ExpiresAt) log.InfofWithRequestId(c, "[authorizations.TwoFactorAuthorizeHandler] user \"uid:%d\" has authorized two-factor via passcode, token will be expired at %d", user.Uid, claims.ExpiresAt)
authResp := a.getAuthResponse(token, false, user) authResp := a.getAuthResponse(token, false, user)
return authResp, nil return authResp, nil
@@ -185,7 +185,7 @@ func (a *AuthorizationsApi) TwoFactorAuthorizeByRecoveryCodeHandler(c *core.Cont
enableTwoFactor, err := a.twoFactorAuthorizations.ExistsTwoFactorSetting(c, uid) enableTwoFactor, err := a.twoFactorAuthorizations.ExistsTwoFactorSetting(c, uid)
if err != nil { if err != nil {
log.WarnfWithRequestId(c, "[authorizations.TwoFactorAuthorizeByRecoveryCodeHandler] failed to get two factor setting for user \"uid:%d\", because %s", uid, err.Error()) log.WarnfWithRequestId(c, "[authorizations.TwoFactorAuthorizeByRecoveryCodeHandler] failed to get two-factor setting for user \"uid:%d\", because %s", uid, err.Error())
return nil, errs.Or(err, errs.ErrSystemError) return nil, errs.Or(err, errs.ErrSystemError)
} }
@@ -213,7 +213,7 @@ func (a *AuthorizationsApi) TwoFactorAuthorizeByRecoveryCodeHandler(c *core.Cont
err = a.twoFactorAuthorizations.GetAndUseUserTwoFactorRecoveryCode(c, uid, credential.RecoveryCode, user.Salt) err = a.twoFactorAuthorizations.GetAndUseUserTwoFactorRecoveryCode(c, uid, credential.RecoveryCode, user.Salt)
if err != nil { if err != nil {
log.WarnfWithRequestId(c, "[authorizations.TwoFactorAuthorizeByRecoveryCodeHandler] failed to get two factor recovery code for user \"uid:%d\", because %s", uid, err.Error()) log.WarnfWithRequestId(c, "[authorizations.TwoFactorAuthorizeByRecoveryCodeHandler] failed to get two-factor recovery code for user \"uid:%d\", because %s", uid, err.Error())
return nil, errs.Or(err, errs.ErrTwoFactorRecoveryCodeNotExist) return nil, errs.Or(err, errs.ErrTwoFactorRecoveryCodeNotExist)
} }
@@ -234,7 +234,7 @@ func (a *AuthorizationsApi) TwoFactorAuthorizeByRecoveryCodeHandler(c *core.Cont
c.SetTextualToken(token) c.SetTextualToken(token)
c.SetTokenClaims(claims) c.SetTokenClaims(claims)
log.InfofWithRequestId(c, "[authorizations.TwoFactorAuthorizeByRecoveryCodeHandler] user \"uid:%d\" has authorized two factor via recovery code \"%s\", token will be expired at %d", user.Uid, credential.RecoveryCode, claims.ExpiresAt) log.InfofWithRequestId(c, "[authorizations.TwoFactorAuthorizeByRecoveryCodeHandler] user \"uid:%d\" has authorized two-factor via recovery code \"%s\", token will be expired at %d", user.Uid, credential.RecoveryCode, claims.ExpiresAt)
authResp := a.getAuthResponse(token, false, user) authResp := a.getAuthResponse(token, false, user)
return authResp, nil return authResp, nil
+17 -17
View File
@@ -45,7 +45,7 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorStatusHandler(c *core.Context) (an
} }
if err != nil { if err != nil {
log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorStatusHandler] failed to get two factor setting, because %s", err.Error()) log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorStatusHandler] failed to get two-factor setting, because %s", err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed) return nil, errs.Or(err, errs.ErrOperationFailed)
} }
@@ -63,7 +63,7 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorEnableRequestHandler(c *core.Conte
enabled, err := a.twoFactorAuthorizations.ExistsTwoFactorSetting(c, uid) enabled, err := a.twoFactorAuthorizations.ExistsTwoFactorSetting(c, uid)
if err != nil { if err != nil {
log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableRequestHandler] failed to check two factor setting, because %s", err.Error()) log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableRequestHandler] failed to check two-factor setting, because %s", err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed) return nil, errs.Or(err, errs.ErrOperationFailed)
} }
@@ -84,14 +84,14 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorEnableRequestHandler(c *core.Conte
key, err := a.twoFactorAuthorizations.GenerateTwoFactorSecret(c, user) key, err := a.twoFactorAuthorizations.GenerateTwoFactorSecret(c, user)
if err != nil { if err != nil {
log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableRequestHandler] failed to generate two factor secret, because %s", err.Error()) log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableRequestHandler] failed to generate two-factor secret, because %s", err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed) return nil, errs.Or(err, errs.ErrOperationFailed)
} }
img, err := key.Image(240, 240) img, err := key.Image(240, 240)
if err != nil { if err != nil {
log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableRequestHandler] failed to generate two factor qrcode, because %s", err.Error()) log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableRequestHandler] failed to generate two-factor qrcode, because %s", err.Error())
return nil, errs.ErrOperationFailed return nil, errs.ErrOperationFailed
} }
@@ -123,7 +123,7 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorEnableConfirmHandler(c *core.Conte
exists, err := a.twoFactorAuthorizations.ExistsTwoFactorSetting(c, uid) exists, err := a.twoFactorAuthorizations.ExistsTwoFactorSetting(c, uid)
if err != nil { if err != nil {
log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableConfirmHandler] failed to check two factor setting, because %s", err.Error()) log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableConfirmHandler] failed to check two-factor setting, because %s", err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed) return nil, errs.Or(err, errs.ErrOperationFailed)
} }
@@ -154,25 +154,25 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorEnableConfirmHandler(c *core.Conte
recoveryCodes, err := a.twoFactorAuthorizations.GenerateTwoFactorRecoveryCodes() recoveryCodes, err := a.twoFactorAuthorizations.GenerateTwoFactorRecoveryCodes()
if err != nil { if err != nil {
log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableConfirmHandler] failed to generate two factor recovery codes for user \"uid:%d\", because %s", uid, err.Error()) log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableConfirmHandler] failed to generate two-factor recovery codes for user \"uid:%d\", because %s", uid, err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed) return nil, errs.Or(err, errs.ErrOperationFailed)
} }
err = a.twoFactorAuthorizations.CreateTwoFactorRecoveryCodes(c, uid, recoveryCodes, user.Salt) err = a.twoFactorAuthorizations.CreateTwoFactorRecoveryCodes(c, uid, recoveryCodes, user.Salt)
if err != nil { if err != nil {
log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableConfirmHandler] failed to create two factor recovery codes for user \"uid:%d\", because %s", uid, err.Error()) log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableConfirmHandler] failed to create two-factor recovery codes for user \"uid:%d\", because %s", uid, err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed) return nil, errs.Or(err, errs.ErrOperationFailed)
} }
err = a.twoFactorAuthorizations.CreateTwoFactorSetting(c, twoFactorSetting) err = a.twoFactorAuthorizations.CreateTwoFactorSetting(c, twoFactorSetting)
if err != nil { if err != nil {
log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableConfirmHandler] failed to create two factor setting for user \"uid:%d\", because %s", uid, err.Error()) log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableConfirmHandler] failed to create two-factor setting for user \"uid:%d\", because %s", uid, err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed) return nil, errs.Or(err, errs.ErrOperationFailed)
} }
log.InfofWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableConfirmHandler] user \"uid:%d\" has enabled two factor authorization", uid) log.InfofWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableConfirmHandler] user \"uid:%d\" has enabled two-factor authorization", uid)
now := time.Now().Unix() now := time.Now().Unix()
err = a.tokens.DeleteTokensBeforeTime(c, uid, now) err = a.tokens.DeleteTokensBeforeTime(c, uid, now)
@@ -236,7 +236,7 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorDisableHandler(c *core.Context) (a
enableTwoFactor, err := a.twoFactorAuthorizations.ExistsTwoFactorSetting(c, uid) enableTwoFactor, err := a.twoFactorAuthorizations.ExistsTwoFactorSetting(c, uid)
if err != nil { if err != nil {
log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorDisableHandler] failed to check two factor setting, because %s", err.Error()) log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorDisableHandler] failed to check two-factor setting, because %s", err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed) return nil, errs.Or(err, errs.ErrOperationFailed)
} }
@@ -247,18 +247,18 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorDisableHandler(c *core.Context) (a
err = a.twoFactorAuthorizations.DeleteTwoFactorRecoveryCodes(c, uid) err = a.twoFactorAuthorizations.DeleteTwoFactorRecoveryCodes(c, uid)
if err != nil { if err != nil {
log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorDisableHandler] failed to delete two factor recovery codes for user \"uid:%d\"", uid) log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorDisableHandler] failed to delete two-factor recovery codes for user \"uid:%d\"", uid)
return nil, errs.Or(err, errs.ErrOperationFailed) return nil, errs.Or(err, errs.ErrOperationFailed)
} }
err = a.twoFactorAuthorizations.DeleteTwoFactorSetting(c, uid) err = a.twoFactorAuthorizations.DeleteTwoFactorSetting(c, uid)
if err != nil { if err != nil {
log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorDisableHandler] failed to delete two factor setting for user \"uid:%d\"", uid) log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorDisableHandler] failed to delete two-factor setting for user \"uid:%d\"", uid)
return nil, errs.Or(err, errs.ErrOperationFailed) return nil, errs.Or(err, errs.ErrOperationFailed)
} }
log.InfofWithRequestId(c, "[twofactor_authorizations.TwoFactorDisableHandler] user \"uid:%d\" has disabled two factor authorization", uid) log.InfofWithRequestId(c, "[twofactor_authorizations.TwoFactorDisableHandler] user \"uid:%d\" has disabled two-factor authorization", uid)
return true, nil return true, nil
} }
@@ -291,7 +291,7 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorRecoveryCodeRegenerateHandler(c *c
enableTwoFactor, err := a.twoFactorAuthorizations.ExistsTwoFactorSetting(c, uid) enableTwoFactor, err := a.twoFactorAuthorizations.ExistsTwoFactorSetting(c, uid)
if err != nil { if err != nil {
log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorRecoveryCodeRegenerateHandler] failed to check two factor setting, because %s", err.Error()) log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorRecoveryCodeRegenerateHandler] failed to check two-factor setting, because %s", err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed) return nil, errs.Or(err, errs.ErrOperationFailed)
} }
@@ -302,14 +302,14 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorRecoveryCodeRegenerateHandler(c *c
recoveryCodes, err := a.twoFactorAuthorizations.GenerateTwoFactorRecoveryCodes() recoveryCodes, err := a.twoFactorAuthorizations.GenerateTwoFactorRecoveryCodes()
if err != nil { if err != nil {
log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorRecoveryCodeRegenerateHandler] failed to generate two factor recovery codes for user \"uid:%d\", because %s", uid, err.Error()) log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorRecoveryCodeRegenerateHandler] failed to generate two-factor recovery codes for user \"uid:%d\", because %s", uid, err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed) return nil, errs.Or(err, errs.ErrOperationFailed)
} }
err = a.twoFactorAuthorizations.CreateTwoFactorRecoveryCodes(c, uid, recoveryCodes, user.Salt) err = a.twoFactorAuthorizations.CreateTwoFactorRecoveryCodes(c, uid, recoveryCodes, user.Salt)
if err != nil { if err != nil {
log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorRecoveryCodeRegenerateHandler] failed to create two factor recovery codes for user \"uid:%d\", because %s", uid, err.Error()) log.ErrorfWithRequestId(c, "[twofactor_authorizations.TwoFactorRecoveryCodeRegenerateHandler] failed to create two-factor recovery codes for user \"uid:%d\", because %s", uid, err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed) return nil, errs.Or(err, errs.ErrOperationFailed)
} }
@@ -317,7 +317,7 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorRecoveryCodeRegenerateHandler(c *c
RecoveryCodes: recoveryCodes, RecoveryCodes: recoveryCodes,
} }
log.InfofWithRequestId(c, "[twofactor_authorizations.TwoFactorRecoveryCodeRegenerateHandler] user \"uid:%d\" has regenerated two factor recovery codes", uid) log.InfofWithRequestId(c, "[twofactor_authorizations.TwoFactorRecoveryCodeRegenerateHandler] user \"uid:%d\" has regenerated two-factor recovery codes", uid)
return recoveryCodesResp, nil return recoveryCodesResp, nil
} }
+5 -5
View File
@@ -393,7 +393,7 @@ func (l *UserDataCli) DisableUserTwoFactorAuthorization(c *cli.Context, username
enableTwoFactor, err := l.twoFactorAuthorizations.ExistsTwoFactorSetting(nil, uid) enableTwoFactor, err := l.twoFactorAuthorizations.ExistsTwoFactorSetting(nil, uid)
if err != nil { if err != nil {
log.BootErrorf("[user_data.DisableUserTwoFactorAuthorization] failed to check two factor setting, because %s", err.Error()) log.BootErrorf("[user_data.DisableUserTwoFactorAuthorization] failed to check two-factor setting, because %s", err.Error())
return err return err
} }
@@ -404,14 +404,14 @@ func (l *UserDataCli) DisableUserTwoFactorAuthorization(c *cli.Context, username
err = l.twoFactorAuthorizations.DeleteTwoFactorRecoveryCodes(nil, uid) err = l.twoFactorAuthorizations.DeleteTwoFactorRecoveryCodes(nil, uid)
if err != nil { if err != nil {
log.BootErrorf("[user_data.DisableUserTwoFactorAuthorization] failed to delete two factor recovery codes for user \"%s\"", username) log.BootErrorf("[user_data.DisableUserTwoFactorAuthorization] failed to delete two-factor recovery codes for user \"%s\"", username)
return err return err
} }
err = l.twoFactorAuthorizations.DeleteTwoFactorSetting(nil, uid) err = l.twoFactorAuthorizations.DeleteTwoFactorSetting(nil, uid)
if err != nil { if err != nil {
log.BootErrorf("[user_data.DisableUserTwoFactorAuthorization] failed to delete two factor setting for user \"%s\"", username) log.BootErrorf("[user_data.DisableUserTwoFactorAuthorization] failed to delete two-factor setting for user \"%s\"", username)
return err return err
} }
@@ -647,7 +647,7 @@ func (l *UserDataCli) checkTransactionAccount(c *cli.Context, transaction *model
} }
if account.ParentAccountId == models.LevelOneAccountParentId && accountHasChild[account.AccountId] { if account.ParentAccountId == models.LevelOneAccountParentId && accountHasChild[account.AccountId] {
log.BootErrorf("[user_data.checkTransactionAccount] the account \"id:%d\" of transaction \"id:%d\" is not a sub account", transaction.AccountId, transaction.TransactionId) log.BootErrorf("[user_data.checkTransactionAccount] the account \"id:%d\" of transaction \"id:%d\" is not a sub-account", transaction.AccountId, transaction.TransactionId)
return errs.ErrOperationFailed return errs.ErrOperationFailed
} }
@@ -660,7 +660,7 @@ func (l *UserDataCli) checkTransactionAccount(c *cli.Context, transaction *model
} }
if relatedAccount.ParentAccountId == models.LevelOneAccountParentId && accountHasChild[relatedAccount.AccountId] { if relatedAccount.ParentAccountId == models.LevelOneAccountParentId && accountHasChild[relatedAccount.AccountId] {
log.BootErrorf("[user_data.checkTransactionAccount] the related account \"id:%d\" of transaction \"id:%d\" is not a sub account", transaction.RelatedAccountId, transaction.TransactionId) log.BootErrorf("[user_data.checkTransactionAccount] the related account \"id:%d\" of transaction \"id:%d\" is not a sub-account", transaction.RelatedAccountId, transaction.TransactionId)
return errs.ErrOperationFailed return errs.ErrOperationFailed
} }
} }
+5 -5
View File
@@ -8,13 +8,13 @@ var (
ErrAccountNotFound = NewNormalError(NormalSubcategoryAccount, 1, http.StatusBadRequest, "account not found") ErrAccountNotFound = NewNormalError(NormalSubcategoryAccount, 1, http.StatusBadRequest, "account not found")
ErrAccountTypeInvalid = NewNormalError(NormalSubcategoryAccount, 2, http.StatusBadRequest, "account type is invalid") ErrAccountTypeInvalid = NewNormalError(NormalSubcategoryAccount, 2, http.StatusBadRequest, "account type is invalid")
ErrAccountCurrencyInvalid = NewNormalError(NormalSubcategoryAccount, 3, http.StatusBadRequest, "account currency is invalid") ErrAccountCurrencyInvalid = NewNormalError(NormalSubcategoryAccount, 3, http.StatusBadRequest, "account currency is invalid")
ErrAccountHaveNoSubAccount = NewNormalError(NormalSubcategoryAccount, 4, http.StatusBadRequest, "account must have at least one sub account") ErrAccountHaveNoSubAccount = NewNormalError(NormalSubcategoryAccount, 4, http.StatusBadRequest, "account must have at least one sub-account")
ErrAccountCannotHaveSubAccounts = NewNormalError(NormalSubcategoryAccount, 5, http.StatusBadRequest, "account cannot have sub accounts") ErrAccountCannotHaveSubAccounts = NewNormalError(NormalSubcategoryAccount, 5, http.StatusBadRequest, "account cannot have sub-accounts")
ErrParentAccountCannotSetCurrency = NewNormalError(NormalSubcategoryAccount, 6, http.StatusBadRequest, "parent account cannot set currency") ErrParentAccountCannotSetCurrency = NewNormalError(NormalSubcategoryAccount, 6, http.StatusBadRequest, "parent account cannot set currency")
ErrParentAccountCannotSetBalance = NewNormalError(NormalSubcategoryAccount, 7, http.StatusBadRequest, "parent account cannot set balance") ErrParentAccountCannotSetBalance = NewNormalError(NormalSubcategoryAccount, 7, http.StatusBadRequest, "parent account cannot set balance")
ErrSubAccountCategoryNotEqualsToParent = NewNormalError(NormalSubcategoryAccount, 8, http.StatusBadRequest, "sub account category not equals to parent") ErrSubAccountCategoryNotEqualsToParent = NewNormalError(NormalSubcategoryAccount, 8, http.StatusBadRequest, "sub-account category not equals to parent")
ErrSubAccountTypeInvalid = NewNormalError(NormalSubcategoryAccount, 9, http.StatusBadRequest, "sub account type invalid") ErrSubAccountTypeInvalid = NewNormalError(NormalSubcategoryAccount, 9, http.StatusBadRequest, "sub-account type invalid")
ErrCannotAddOrDeleteSubAccountsWhenModify = NewNormalError(NormalSubcategoryAccount, 10, http.StatusBadRequest, "cannot add or delete sub accounts when modify account") ErrCannotAddOrDeleteSubAccountsWhenModify = NewNormalError(NormalSubcategoryAccount, 10, http.StatusBadRequest, "cannot add or delete sub-accounts when modify account")
ErrSourceAccountNotFound = NewNormalError(NormalSubcategoryAccount, 11, http.StatusBadRequest, "source account not found") ErrSourceAccountNotFound = NewNormalError(NormalSubcategoryAccount, 11, http.StatusBadRequest, "source account not found")
ErrDestinationAccountNotFound = NewNormalError(NormalSubcategoryAccount, 12, http.StatusBadRequest, "destination account not found") ErrDestinationAccountNotFound = NewNormalError(NormalSubcategoryAccount, 12, http.StatusBadRequest, "destination account not found")
ErrAccountInUseCannotBeDeleted = NewNormalError(NormalSubcategoryAccount, 13, http.StatusBadRequest, "account is in use and cannot be deleted") ErrAccountInUseCannotBeDeleted = NewNormalError(NormalSubcategoryAccount, 13, http.StatusBadRequest, "account is in use and cannot be deleted")
+1 -1
View File
@@ -16,7 +16,7 @@ var (
ErrPageIndexInvalid = NewNormalError(NormalSubcategoryGlobal, 6, http.StatusBadRequest, "page index is invalid") ErrPageIndexInvalid = NewNormalError(NormalSubcategoryGlobal, 6, http.StatusBadRequest, "page index is invalid")
ErrPageCountInvalid = NewNormalError(NormalSubcategoryGlobal, 7, http.StatusBadRequest, "page count is invalid") ErrPageCountInvalid = NewNormalError(NormalSubcategoryGlobal, 7, http.StatusBadRequest, "page count is invalid")
ErrClientTimezoneOffsetInvalid = NewNormalError(NormalSubcategoryGlobal, 8, http.StatusBadRequest, "client timezone offset is invalid") ErrClientTimezoneOffsetInvalid = NewNormalError(NormalSubcategoryGlobal, 8, http.StatusBadRequest, "client timezone offset is invalid")
ErrQueryItemsEmpty = NewNormalError(NormalSubcategoryGlobal, 9, http.StatusBadRequest, "query items cannot be empty") ErrQueryItemsEmpty = NewNormalError(NormalSubcategoryGlobal, 9, http.StatusBadRequest, "query items cannot be blank")
ErrQueryItemsTooMuch = NewNormalError(NormalSubcategoryGlobal, 10, http.StatusBadRequest, "query items too much") ErrQueryItemsTooMuch = NewNormalError(NormalSubcategoryGlobal, 10, http.StatusBadRequest, "query items too much")
ErrQueryItemsInvalid = NewNormalError(NormalSubcategoryGlobal, 11, http.StatusBadRequest, "query items have invalid item") ErrQueryItemsInvalid = NewNormalError(NormalSubcategoryGlobal, 11, http.StatusBadRequest, "query items have invalid item")
ErrParameterInvalid = NewNormalError(NormalSubcategoryGlobal, 12, http.StatusBadRequest, "parameter invalid") ErrParameterInvalid = NewNormalError(NormalSubcategoryGlobal, 12, http.StatusBadRequest, "parameter invalid")
+2 -2
View File
@@ -11,8 +11,8 @@ var (
ErrCurrentInvalidToken = NewNormalError(NormalSubcategoryToken, 2, http.StatusUnauthorized, "current token is invalid") ErrCurrentInvalidToken = NewNormalError(NormalSubcategoryToken, 2, http.StatusUnauthorized, "current token is invalid")
ErrCurrentTokenExpired = NewNormalError(NormalSubcategoryToken, 3, http.StatusUnauthorized, "current token is expired") ErrCurrentTokenExpired = NewNormalError(NormalSubcategoryToken, 3, http.StatusUnauthorized, "current token is expired")
ErrCurrentInvalidTokenType = NewNormalError(NormalSubcategoryToken, 4, http.StatusUnauthorized, "current token type is invalid") ErrCurrentInvalidTokenType = NewNormalError(NormalSubcategoryToken, 4, http.StatusUnauthorized, "current token type is invalid")
ErrCurrentTokenRequire2FA = NewNormalError(NormalSubcategoryToken, 5, http.StatusUnauthorized, "current token requires two factor authorization") ErrCurrentTokenRequire2FA = NewNormalError(NormalSubcategoryToken, 5, http.StatusUnauthorized, "current token requires two-factor authorization")
ErrCurrentTokenNotRequire2FA = NewNormalError(NormalSubcategoryToken, 6, http.StatusUnauthorized, "current token does not require two factor authorization") ErrCurrentTokenNotRequire2FA = NewNormalError(NormalSubcategoryToken, 6, http.StatusUnauthorized, "current token does not require two-factor authorization")
ErrInvalidToken = NewNormalError(NormalSubcategoryToken, 7, http.StatusBadRequest, "token is invalid") ErrInvalidToken = NewNormalError(NormalSubcategoryToken, 7, http.StatusBadRequest, "token is invalid")
ErrInvalidTokenId = NewNormalError(NormalSubcategoryToken, 8, http.StatusBadRequest, "token id is invalid") ErrInvalidTokenId = NewNormalError(NormalSubcategoryToken, 8, http.StatusBadRequest, "token id is invalid")
ErrInvalidUserTokenId = NewNormalError(NormalSubcategoryToken, 9, http.StatusBadRequest, "user token id is invalid") ErrInvalidUserTokenId = NewNormalError(NormalSubcategoryToken, 9, http.StatusBadRequest, "user token id is invalid")
+5 -5
View File
@@ -2,11 +2,11 @@ package errs
import "net/http" import "net/http"
// Error codes related to two factor authorization // Error codes related to two-factor authorization
var ( var (
ErrPasscodeInvalid = NewNormalError(NormalSubcategoryTwofactor, 0, http.StatusUnauthorized, "passcode is invalid") ErrPasscodeInvalid = NewNormalError(NormalSubcategoryTwofactor, 0, http.StatusUnauthorized, "passcode is invalid")
ErrTwoFactorRecoveryCodeInvalid = NewNormalError(NormalSubcategoryTwofactor, 1, http.StatusUnauthorized, "two factor backup code is invalid") ErrTwoFactorRecoveryCodeInvalid = NewNormalError(NormalSubcategoryTwofactor, 1, http.StatusUnauthorized, "two-factor backup code is invalid")
ErrTwoFactorRecoveryCodeNotExist = NewNormalError(NormalSubcategoryTwofactor, 2, http.StatusUnauthorized, "two factor backup code does not exist") ErrTwoFactorRecoveryCodeNotExist = NewNormalError(NormalSubcategoryTwofactor, 2, http.StatusUnauthorized, "two-factor backup code does not exist")
ErrTwoFactorIsNotEnabled = NewNormalError(NormalSubcategoryTwofactor, 3, http.StatusBadRequest, "two factor is not enabled") ErrTwoFactorIsNotEnabled = NewNormalError(NormalSubcategoryTwofactor, 3, http.StatusBadRequest, "two-factor is not enabled")
ErrTwoFactorAlreadyEnabled = NewNormalError(NormalSubcategoryTwofactor, 4, http.StatusBadRequest, "two factor has already been enabled") ErrTwoFactorAlreadyEnabled = NewNormalError(NormalSubcategoryTwofactor, 4, http.StatusBadRequest, "two-factor has already been enabled")
) )
+1 -1
View File
@@ -47,7 +47,7 @@ func JWTTwoFactorAuthorization(c *core.Context) {
} }
if claims.Type != core.USER_TOKEN_TYPE_REQUIRE_2FA { if claims.Type != core.USER_TOKEN_TYPE_REQUIRE_2FA {
log.WarnfWithRequestId(c, "[authorization.JWTTwoFactorAuthorization] user \"uid:%d\" token is not need two factor authorization", claims.Uid) log.WarnfWithRequestId(c, "[authorization.JWTTwoFactorAuthorization] user \"uid:%d\" token is not need two-factor authorization", claims.Uid)
utils.PrintJsonErrorResult(c, errs.ErrCurrentTokenNotRequire2FA) utils.PrintJsonErrorResult(c, errs.ErrCurrentTokenNotRequire2FA)
return return
} }
+2 -2
View File
@@ -11,7 +11,7 @@ import (
// TransactionEditScope represents the scope which transaction can be edited // TransactionEditScope represents the scope which transaction can be edited
type TransactionEditScope byte type TransactionEditScope byte
// Editable Transaction Scopes // Editable Transaction Ranges
const ( const (
TRANSACTION_EDIT_SCOPE_NONE TransactionEditScope = 0 TRANSACTION_EDIT_SCOPE_NONE TransactionEditScope = 0
TRANSACTION_EDIT_SCOPE_ALL TransactionEditScope = 1 TRANSACTION_EDIT_SCOPE_ALL TransactionEditScope = 1
@@ -23,7 +23,7 @@ const (
TRANSACTION_EDIT_SCOPE_INVALID TransactionEditScope = 255 TRANSACTION_EDIT_SCOPE_INVALID TransactionEditScope = 255
) )
// String returns a textual representation of the editable transaction scopes enum // String returns a textual representation of the editable transaction ranges enum
func (s TransactionEditScope) String() string { func (s TransactionEditScope) String() string {
switch s { switch s {
case TRANSACTION_EDIT_SCOPE_NONE: case TRANSACTION_EDIT_SCOPE_NONE:
+3 -3
View File
@@ -54,7 +54,7 @@ func (s *AccountService) GetAllAccountsByUid(c *core.Context, uid int64) ([]*mod
return accounts, err return accounts, err
} }
// GetAccountAndSubAccountsByAccountId returns account model and sub account models according to account id // GetAccountAndSubAccountsByAccountId returns account model and sub-account models according to account id
func (s *AccountService) GetAccountAndSubAccountsByAccountId(c *core.Context, uid int64, accountId int64) ([]*models.Account, error) { func (s *AccountService) GetAccountAndSubAccountsByAccountId(c *core.Context, uid int64, accountId int64) ([]*models.Account, error) {
if uid <= 0 { if uid <= 0 {
return nil, errs.ErrUserIdInvalid return nil, errs.ErrUserIdInvalid
@@ -70,7 +70,7 @@ func (s *AccountService) GetAccountAndSubAccountsByAccountId(c *core.Context, ui
return accounts, err return accounts, err
} }
// GetSubAccountsByAccountId returns sub account models according to account id // GetSubAccountsByAccountId returns sub-account models according to account id
func (s *AccountService) GetSubAccountsByAccountId(c *core.Context, uid int64, accountId int64) ([]*models.Account, error) { func (s *AccountService) GetSubAccountsByAccountId(c *core.Context, uid int64, accountId int64) ([]*models.Account, error) {
if uid <= 0 { if uid <= 0 {
return nil, errs.ErrUserIdInvalid return nil, errs.ErrUserIdInvalid
@@ -127,7 +127,7 @@ func (s *AccountService) GetMaxDisplayOrder(c *core.Context, uid int64, category
} }
} }
// GetMaxSubAccountDisplayOrder returns the max display order of sub account according to account category and parent account id // GetMaxSubAccountDisplayOrder returns the max display order of sub-account according to account category and parent account id
func (s *AccountService) GetMaxSubAccountDisplayOrder(c *core.Context, uid int64, category models.AccountCategory, parentAccountId int64) (int32, error) { func (s *AccountService) GetMaxSubAccountDisplayOrder(c *core.Context, uid int64, category models.AccountCategory, parentAccountId int64) (int32, error) {
if uid <= 0 { if uid <= 0 {
return 0, errs.ErrUserIdInvalid return 0, errs.ErrUserIdInvalid
@@ -7,7 +7,7 @@
</div> </div>
</template> </template>
<template #subtitle> <template #subtitle>
<div class="text-body-1 text-center text-wrap mt-4">{{ $t('You can scan the below QR code on your mobile device.') }}</div> <div class="text-body-1 text-center text-wrap mt-4">{{ $t('You can scan the QR code below on your mobile device.') }}</div>
</template> </template>
<v-card-text class="mb-md-4"> <v-card-text class="mb-md-4">
<v-row> <v-row>
+1 -1
View File
@@ -19,7 +19,7 @@
</template> </template>
<template #error-content> <template #error-content>
<div class="padding-horizontal padding-bottom"> <div class="padding-horizontal padding-bottom">
<p class="no-margin">{{ $t('Please refresh the page and try again. If the error is still displayed, make sure that server map settings are set correctly.') }}</p> <p class="no-margin">{{ $t('Please refresh the page and try again. If the error persists, ensure that the server\'s map settings are correctly configured.') }}</p>
<div class="margin-top text-align-center"> <div class="margin-top text-align-center">
<f7-link @click="close" :text="$t('Close')"></f7-link> <f7-link @click="close" :text="$t('Close')"></f7-link>
</div> </div>
+1 -1
View File
@@ -45,7 +45,7 @@ const allAccountTypesArray = [
name: 'Single Account' name: 'Single Account'
}, { }, {
id: allAccountTypes.MultiSubAccounts, id: allAccountTypes.MultiSubAccounts,
name: 'Multi Sub Accounts' name: 'Multiple Sub-accounts'
} }
]; ];
+2 -2
View File
@@ -50,8 +50,8 @@ axios.interceptors.response.use(response => {
|| errorCode === 202002 // current token is invalid || errorCode === 202002 // current token is invalid
|| errorCode === 202003 // current token is expired || errorCode === 202003 // current token is expired
|| errorCode === 202004 // current token type is invalid || errorCode === 202004 // current token type is invalid
|| errorCode === 202005 // current token requires two factor authorization || errorCode === 202005 // current token requires two-factor authorization
|| errorCode === 202006 // current token does not require two factor authorization || errorCode === 202006 // current token does not require two-factor authorization
|| errorCode === 202012 // token is empty || errorCode === 202012 // token is empty
) { ) {
userState.clearTokenAndUserInfo(false); userState.clearTokenAndUserInfo(false);
+113 -116
View File
@@ -595,8 +595,8 @@ export default {
'current token is invalid': 'Current token is invalid', 'current token is invalid': 'Current token is invalid',
'current token is expired': 'Current token is expired', 'current token is expired': 'Current token is expired',
'current token type is invalid': 'Current token type is invalid', 'current token type is invalid': 'Current token type is invalid',
'current token requires two factor authorization': 'Current token requires two factor authorization', 'current token requires two-factor authorization': 'Current token requires two-factor authorization',
'current token does not require two factor authorization': 'Current token does not require two factor authorization', 'current token does not require two-factor authorization': 'Current token does not require two-factor authorization',
'token is invalid': 'Token is invalid', 'token is invalid': 'Token is invalid',
'token id is invalid': 'Token ID is invalid', 'token id is invalid': 'Token ID is invalid',
'user token id is invalid': 'User token ID is invalid', 'user token id is invalid': 'User token ID is invalid',
@@ -606,21 +606,21 @@ export default {
'email verify token is invalid or expired': 'Email verify token is invalid or expired', 'email verify token is invalid or expired': 'Email verify token is invalid or expired',
'password reset token is invalid or expired': 'Password reset token is invalid or expired', 'password reset token is invalid or expired': 'Password reset token is invalid or expired',
'passcode is invalid': 'Passcode is invalid', 'passcode is invalid': 'Passcode is invalid',
'two factor backup code is invalid': 'Two factor backup code is invalid', 'two-factor backup code is invalid': 'Two-factor backup code is invalid',
'two factor is not enabled': 'Two factor is not enabled', 'two-factor is not enabled': 'Two-factor is not enabled',
'two factor has already been enabled': 'Two factor has already been enabled', 'two-factor has already been enabled': 'Two-factor has already been enabled',
'two factor backup code does not exist': 'Two factor backup code does not exist', 'two-factor backup code does not exist': 'Two-factor backup code does not exist',
'account id is invalid': 'Account ID is invalid', 'account id is invalid': 'Account ID is invalid',
'account not found': 'Account is not found', 'account not found': 'Account is not found',
'account type is invalid': 'Account type is invalid', 'account type is invalid': 'Account type is invalid',
'account currency is invalid': 'Account currency is invalid', 'account currency is invalid': 'Account currency is invalid',
'account must have at least one sub account': 'Account must have at least one sub account', 'account must have at least one sub-account': 'Account must have at least one sub-account',
'account cannot have sub accounts': 'Account cannot have sub accounts', 'account cannot have sub-accounts': 'Account cannot have sub-accounts',
'parent account cannot set currency': 'Parent account cannot set currency', 'parent account cannot set currency': 'Parent account cannot set currency',
'parent account cannot set balance': 'Parent account cannot set balance', 'parent account cannot set balance': 'Parent account cannot set balance',
'sub account category not equals to parent': 'Sub account category does not equal to parent', 'sub-account category not equals to parent': 'Sub-account category does not equal to parent',
'sub account type invalid': 'Sub account type is invalid', 'sub-account type invalid': 'Sub-account type is invalid',
'cannot add or delete sub accounts when modify account': 'You cannot add or delete sub accounts when modify account', 'cannot add or delete sub-accounts when modify account': 'You cannot add or delete sub-accounts when modify account',
'source account not found': 'Source account is not found', 'source account not found': 'Source account is not found',
'destination account not found': 'Destination account is not found', 'destination account not found': 'Destination account is not found',
'account is in use and cannot be deleted': 'Account is in use and it cannot be deleted', 'account is in use and cannot be deleted': 'Account is in use and it cannot be deleted',
@@ -654,7 +654,7 @@ export default {
'transaction tag name already exists': 'Transaction tag title already exists', 'transaction tag name already exists': 'Transaction tag title already exists',
'transaction tag is in use and cannot be deleted': 'Transaction tag is in use and it cannot be deleted', 'transaction tag is in use and cannot be deleted': 'Transaction tag is in use and it cannot be deleted',
'data export not allowed': 'User data export is not allowed', 'data export not allowed': 'User data export is not allowed',
'query items cannot be empty': 'There are no query items', 'query items cannot be blank': 'There are no query items',
'query items too much': 'There are too many query items', 'query items too much': 'There are too many query items',
'query items have invalid item': 'There is invalid item in query items', 'query items have invalid item': 'There is invalid item in query items',
'parameter invalid': 'Parameter is invalid', 'parameter invalid': 'Parameter is invalid',
@@ -669,7 +669,7 @@ export default {
'oldPassword': 'Current Password', 'oldPassword': 'Current Password',
'defaultCurrency': 'Default Currency', 'defaultCurrency': 'Default Currency',
'firstDayOfWeek': 'First Day of Week', 'firstDayOfWeek': 'First Day of Week',
'transactionEditScope': 'Editable Transaction Scope', 'transactionEditScope': 'Editable Transaction Range',
'name': 'Name', 'name': 'Name',
'category': 'Category', 'category': 'Category',
'type': 'Type', 'type': 'Type',
@@ -713,13 +713,13 @@ export default {
'Add': 'Add', 'Add': 'Add',
'Apply': 'Apply', 'Apply': 'Apply',
'Save': 'Save', 'Save': 'Save',
'Save changes': 'Save changes', 'Save Changes': 'Save Changes',
'Reset': 'Reset', 'Reset': 'Reset',
'Update': 'Update', 'Update': 'Update',
'Refresh': 'Refresh', 'Refresh': 'Refresh',
'Clear': 'Clear', 'Clear': 'Clear',
'None': 'None', 'None': 'None',
'Not Specified': 'Not Specified', 'Unspecified': 'Unspecified',
'No results': 'No results', 'No results': 'No results',
'Unknown': 'Unknown', 'Unknown': 'Unknown',
'Miscellaneous': 'Miscellaneous', 'Miscellaneous': 'Miscellaneous',
@@ -760,7 +760,7 @@ export default {
'This year': 'This year', 'This year': 'This year',
'Last year': 'Last year', 'Last year': 'Last year',
'Custom Date': 'Custom Date', 'Custom Date': 'Custom Date',
'Begin Time': 'Begin Time', 'Start Time': 'Start Time',
'End Time': 'End Time', 'End Time': 'End Time',
'Select Date': 'Select Date', 'Select Date': 'Select Date',
'Select Time': 'Select Time', 'Select Time': 'Select Time',
@@ -768,7 +768,7 @@ export default {
'Custom': 'Custom', 'Custom': 'Custom',
'Pie Chart': 'Pie Chart', 'Pie Chart': 'Pie Chart',
'Bar Chart': 'Bar Chart', 'Bar Chart': 'Bar Chart',
'Sort By': 'Sort By', 'Sort by': 'Sort by',
'User': 'User', 'User': 'User',
'Application': 'Application', 'Application': 'Application',
'Danger Zone': 'Danger Zone', 'Danger Zone': 'Danger Zone',
@@ -787,15 +787,15 @@ export default {
'No data': 'No data', 'No data': 'No data',
'Zoom in': 'Zoom in', 'Zoom in': 'Zoom in',
'Zoom out': 'Zoom out', 'Zoom out': 'Zoom out',
'Drag and Drop to Change Order': 'Drag and Drop to Change Order', 'Drag to Reorder': 'Drag to Reorder',
'Save Display Order': 'Save Display Order', 'Save Display Order': 'Save Display Order',
'Change Language': 'Change Language', 'Change Language': 'Change Language',
'Date is too early': 'Date is too early', 'Date is too early': 'Date is too early',
'Welcome to ezBookkeeping': 'Welcome to ezBookkeeping', 'Welcome to ezBookkeeping': 'Welcome to ezBookkeeping',
'Please log in with your ezBookkeeping account': 'Please log in with your ezBookkeeping account', 'Please log in with your ezBookkeeping account': 'Please log in with your ezBookkeeping account',
'Unlock Application': 'Unlock Application', 'Unlock Application': 'Unlock Application',
'Please input your PIN code or use WebAuthn to unlock application': 'Please input your PIN code or use WebAuthn to unlock application', 'Please enter your PIN code or use WebAuthn to unlock application': 'Please enter your PIN code or use WebAuthn to unlock application',
'Please input your PIN code to unlock application': 'Please input your PIN code to unlock application', 'Please enter your PIN code to unlock application': 'Please enter your PIN code to unlock application',
'Can\'t Unlock?': 'Can\'t Unlock?', 'Can\'t Unlock?': 'Can\'t Unlock?',
'Re-login': 'Re-login', 'Re-login': 'Re-login',
'Username': 'Username', 'Username': 'Username',
@@ -804,7 +804,7 @@ export default {
'Password': 'Password', 'Password': 'Password',
'Your password': 'Your password', 'Your password': 'Your password',
'Your password, at least 6 characters': 'Your password, at least 6 characters', 'Your password, at least 6 characters': 'Your password, at least 6 characters',
'Confirmation Password': 'Confirmation Password', 'Confirm Password': 'Confirm Password',
'Re-enter the password': 'Re-enter the password', 'Re-enter the password': 'Re-enter the password',
'E-mail': 'E-mail', 'E-mail': 'E-mail',
'Your email address': 'Your email address', 'Your email address': 'Your email address',
@@ -817,7 +817,7 @@ export default {
'Short Date Format': 'Short Date Format', 'Short Date Format': 'Short Date Format',
'Long Time Format': 'Long Time Format', 'Long Time Format': 'Long Time Format',
'Short Time Format': 'Short Time Format', 'Short Time Format': 'Short Time Format',
'Editable Transaction Scope': 'Editable Transaction Scope', 'Editable Transaction Range': 'Editable Transaction Range',
'Today or later': 'Today or later', 'Today or later': 'Today or later',
'Recent 24 hours or later': 'Recent 24 hours or later', 'Recent 24 hours or later': 'Recent 24 hours or later',
'This week or later': 'This week or later', 'This week or later': 'This week or later',
@@ -825,55 +825,53 @@ export default {
'This year or later': 'This year or later', 'This year or later': 'This year or later',
'Log In': 'Log In', 'Log In': 'Log In',
'Click here to log in': 'Click here to log in', 'Click here to log in': 'Click here to log in',
'Back to log in': 'Back to log in', 'Back to login page': 'Back to login page',
'Back to home': 'Back to home', 'Back to home page': 'Back to home page',
'Don\'t have an account?': 'Don\'t have an account?', 'Don\'t have an account?': 'Don\'t have an account?',
'Forget Password?': 'Forget Password?', 'Forget Password?': 'Forget Password?',
'Create an account': 'Create an account', 'Create an account': 'Create an account',
'Username cannot be empty': 'Username cannot be empty', 'Username cannot be blank': 'Username cannot be blank',
'Password cannot be empty': 'Password cannot be empty', 'Password cannot be blank': 'Password cannot be blank',
'Current password cannot be empty': 'Current password cannot be empty', 'Current password cannot be blank': 'Current password cannot be blank',
'New password cannot be empty': 'New password cannot be empty', 'New password cannot be blank': 'New password cannot be blank',
'Confirmation password cannot be empty': 'Confirmation password cannot be empty', 'Password confirmation cannot be blank': 'Password confirmation cannot be blank',
'Password and confirmation password do not match': 'Password and confirmation password do not match', 'Password and password confirmation do not match': 'Password and password confirmation do not match',
'Email address cannot be empty': 'Email address cannot be empty', 'Email address cannot be blank': 'Email address cannot be blank',
'Nickname cannot be empty': 'Nickname cannot be empty', 'Nickname cannot be blank': 'Nickname cannot be blank',
'Default currency cannot be empty': 'Default currency cannot be empty', 'Default currency cannot be blank': 'Default currency cannot be blank',
'Unable to login': 'Unable to login', 'Unable to log in': 'Unable to log in',
'Two-Factor Authentication': 'Two-Factor Authentication', 'Two-Factor Authentication': 'Two-Factor Authentication',
'Two-factor authentication is not enabled yet.': 'Two-factor authentication is not enabled yet.', 'Two-factor authentication is not enabled yet.': 'Two-factor authentication is not enabled yet.',
'Two-factor authentication has been enabled.': 'Two-factor authentication has been enabled.', 'Two-factor authentication is already enabled.': 'Two-factor authentication is already enabled.',
'Disable two-factor authentication': 'Disable two-factor authentication',
'Enable two-factor authentication': 'Enable two-factor authentication',
'Passcode': 'Passcode', 'Passcode': 'Passcode',
'Backup Code': 'Backup Code', 'Backup Code': 'Backup Code',
'Verify': 'Verify', 'Verify': 'Verify',
'Passcode cannot be empty': 'Passcode cannot be empty', 'Passcode cannot be blank': 'Passcode cannot be blank',
'Backup code cannot be empty': 'Backup code cannot be empty', 'Backup code cannot be blank': 'Backup code cannot be blank',
'Unable to verify': 'Unable to verify', 'Unable to verify': 'Unable to verify',
'Use a backup code': 'Use a backup code', 'Use Backup Code': 'Use Backup Code',
'Use a passcode': 'Use a passcode', 'Use Passcode': 'Use Passcode',
'PIN code is invalid': 'PIN code is invalid', 'Invalid PIN code': 'Invalid PIN code',
'PIN code is wrong': 'PIN code is wrong', 'Incorrect PIN code': 'Incorrect PIN code',
'Verify your email': 'Verify your email', 'Verify your email': 'Verify your email',
'Verifying...': 'Verifying...', 'Verifying...': 'Verifying...',
'Resend Validation Email': 'Resend Validation Email', 'Resend Validation Email': 'Resend Validation Email',
'Validation email has been sent': 'Validation email has been sent', 'Validation email has been sent': 'Validation email has been sent',
'Unable to verify email': 'Unable to verify email', 'Unable to verify email': 'Unable to verify email',
'Unable to resend verify email': 'Unable to resend verify email', 'Unable to resend validation email': 'Unable to resend validation email',
'Send Reset Link': 'Send Reset Link', 'Send Reset Link': 'Send Reset Link',
'Please input your email address used for registration and we\'ll send you an email with reset password link': 'Please input your email address used for registration and we\'ll send you an email with reset password link', 'Please enter your email address used for registration and we\'ll send you an email with a reset password link': 'Please enter your email address used for registration and we\'ll send you an email with a reset password link',
'Password reset email has been sent': 'Password reset email has been sent', 'Password reset email has been sent': 'Password reset email has been sent',
'Unable to send password reset email': 'Unable to send password reset email', 'Unable to send password reset email': 'Unable to send password reset email',
'Reset Password': 'Reset Password', 'Reset Password': 'Reset Password',
'Update Password': 'Update Password', 'Update Password': 'Update Password',
'Please input your email address again, and input the new password.': 'Please input your email address again, and input the new password.', 'Please re-enter your email address, and then enter a new password.': 'Please re-enter your email address, and then enter a new password.',
'Password has been updated': 'Password has been updated', 'Password has been updated': 'Password has been updated',
'Unable to reset password': 'Unable to reset password', 'Unable to reset password': 'Unable to reset password',
'Sign Up': 'Sign Up', 'Sign Up': 'Sign Up',
'Overview': 'Overview', 'Overview': 'Overview',
'Asset Summary': 'Asset Summary', 'Asset Summary': 'Asset Summary',
'Trend in Income and Expense': 'Trend in Income and Expense', 'Income and Expense Trends': 'Income and Expense Trends',
'View Details': 'View Details', 'View Details': 'View Details',
'Transaction List': 'Transaction List', 'Transaction List': 'Transaction List',
'Transaction Details': 'Transaction Details', 'Transaction Details': 'Transaction Details',
@@ -883,7 +881,7 @@ export default {
'This Month': 'This Month', 'This Month': 'This Month',
'This Year': 'This Year', 'This Year': 'This Year',
'Monthly income': 'Monthly income', 'Monthly income': 'Monthly income',
'Unable to get transaction overview': 'Unable to get transaction overview', 'Unable to retrieve transaction overview': 'Unable to retrieve transaction overview',
'Data is up to date': 'Data is up to date', 'Data is up to date': 'Data is up to date',
'Data has been updated': 'Data has been updated', 'Data has been updated': 'Data has been updated',
'Net assets': 'Net assets', 'Net assets': 'Net assets',
@@ -900,7 +898,7 @@ export default {
'Receivables': 'Receivables', 'Receivables': 'Receivables',
'Investment Account': 'Investment Account', 'Investment Account': 'Investment Account',
'Balance': 'Balance', 'Balance': 'Balance',
'Unable to get account list': 'Unable to get account list', 'Unable to retrieve account list': 'Unable to retrieve account list',
'Account list is up to date': 'Account list is up to date', 'Account list is up to date': 'Account list is up to date',
'Account list has been updated': 'Account list has been updated', 'Account list has been updated': 'Account list has been updated',
'All Accounts': 'All Accounts', 'All Accounts': 'All Accounts',
@@ -909,38 +907,38 @@ export default {
'Edit Account': 'Edit Account', 'Edit Account': 'Edit Account',
'Account Category': 'Account Category', 'Account Category': 'Account Category',
'Single Account': 'Single Account', 'Single Account': 'Single Account',
'Multi Sub Accounts': 'Multi Sub Accounts', 'Multiple Sub-accounts': 'Multiple Sub-accounts',
'Account Type': 'Account Type', 'Account Type': 'Account Type',
'Account Name': 'Account Name', 'Account Name': 'Account Name',
'Your account name': 'Your account name', 'Your account name': 'Your account name',
'Main Account': 'Main Account', 'Main Account': 'Main Account',
'Sub Account': 'Sub Account', 'Sub Account': 'Sub Account',
'Sub Account Name': 'Sub Account Name', 'Sub-account Name': 'Sub-account Name',
'Your sub account name': 'Your sub account name', 'Your sub-account name': 'Your sub-account name',
'Account Icon': 'Account Icon', 'Account Icon': 'Account Icon',
'Sub Account Icon': 'Sub Account Icon', 'Sub-account Icon': 'Sub-account Icon',
'Account Color': 'Account Color', 'Account Color': 'Account Color',
'Sub Account Color': 'Sub Account Color', 'Sub-account Color': 'Sub-account Color',
'Currency': 'Currency', 'Currency': 'Currency',
'Account Balance': 'Account Balance', 'Account Balance': 'Account Balance',
'Sub Account Balance': 'Sub Account Balance', 'Sub-account Balance': 'Sub-account Balance',
'Description': 'Description', 'Description': 'Description',
'Your account description (optional)': 'Your account description (optional)', 'Your account description (optional)': 'Your account description (optional)',
'Your sub account description (optional)': 'Your sub account description (optional)', 'Your sub-account description (optional)': 'Your sub-account description (optional)',
'Add Sub Account': 'Add Sub Account', 'Add Sub-account': 'Add Sub-account',
'Remove Sub Account': 'Remove Sub Account', 'Remove Sub-account': 'Remove Sub-account',
'Are you sure you want to remove this sub account?': 'Are you sure you want to remove this sub account?', 'Are you sure you want to remove this sub-account?': 'Are you sure you want to remove this sub-account?',
'Account category cannot be empty': 'Account category cannot be empty', 'Account category cannot be blank': 'Account category cannot be blank',
'Account type cannot be empty': 'Account type cannot be empty', 'Account type cannot be blank': 'Account type cannot be blank',
'Account name cannot be empty': 'Account name cannot be empty', 'Account name cannot be blank': 'Account name cannot be blank',
'Account currency cannot be empty': 'Account currency cannot be empty', 'Account currency cannot be blank': 'Account currency cannot be blank',
'You have added a new account': 'You have added a new account', 'You have added a new account': 'You have added a new account',
'You have saved this account': 'You have saved this account', 'You have saved this account': 'You have saved this account',
'Unable to add account': 'Unable to add account', 'Unable to add account': 'Unable to add account',
'Unable to save account': 'Unable to save account', 'Unable to save account': 'Unable to save account',
'Show Hidden Account': 'Show Hidden Account', 'Show Hidden Accounts': 'Show Hidden Accounts',
'Hide Hidden Account': 'Hide Hidden Account', 'Hide Hidden Accounts': 'Hide Hidden Accounts',
'Unable to get account': 'Unable to get account', 'Unable to retrieve account': 'Unable to retrieve account',
'Unable to hide this account': 'Unable to hide this account', 'Unable to hide this account': 'Unable to hide this account',
'Unable to unhide this account': 'Unable to unhide this account', 'Unable to unhide this account': 'Unable to unhide this account',
'Unable to move account': 'Unable to move account', 'Unable to move account': 'Unable to move account',
@@ -965,7 +963,7 @@ export default {
'Source Account': 'Source Account', 'Source Account': 'Source Account',
'Destination Account': 'Destination Account', 'Destination Account': 'Destination Account',
'Transaction Time': 'Transaction Time', 'Transaction Time': 'Transaction Time',
'Transaction Time Zone': 'Transaction Time Zone', 'Transaction Timezone': 'Transaction Timezone',
'Same time as default timezone': 'Same time as default timezone', 'Same time as default timezone': 'Same time as default timezone',
'Geographic Location': 'Geographic Location', 'Geographic Location': 'Geographic Location',
'No Location': 'No Location', 'No Location': 'No Location',
@@ -974,20 +972,20 @@ export default {
'Location on Map': 'Location on Map', 'Location on Map': 'Location on Map',
'Update Geographic Location': 'Update Geographic Location', 'Update Geographic Location': 'Update Geographic Location',
'Clear Geographic Location': 'Clear Geographic Location', 'Clear Geographic Location': 'Clear Geographic Location',
'Unable to get current position': 'Unable to get current position', 'Unable to retrieve current position': 'Unable to retrieve current position',
'Cannot Initialize Map': 'Cannot Initialize Map', 'Cannot Initialize Map': 'Cannot Initialize Map',
'Unsupported Map Provider': 'Unsupported Map Provider', 'Unsupported Map Provider': 'Unsupported Map Provider',
'Please refresh the page and try again. If the error is still displayed, make sure that server map settings are set correctly.': 'Please refresh the page and try again. If the error is still displayed, make sure that server map settings are set correctly.', 'Please refresh the page and try again. If the error persists, ensure that the server\'s map settings are correctly configured.': 'Please refresh the page and try again. If the error persists, ensure that the server\'s map settings are correctly configured.',
'Tags': 'Tags', 'Tags': 'Tags',
'Your transaction description (optional)': 'Your transaction description (optional)', 'Your transaction description (optional)': 'Your transaction description (optional)',
'Are you sure you want to save this transaction whose amount is 0?': 'Are you sure you want to save this transaction whose amount is 0?', 'Are you sure you want to save this transaction with a zero amount?': 'Are you sure you want to save this transaction with a zero amount?',
'Unable to get transaction': 'Unable to get transaction', 'Unable to retrieve transaction': 'Unable to retrieve transaction',
'Unable to add transaction': 'Unable to add transaction', 'Unable to add transaction': 'Unable to add transaction',
'Unable to save transaction': 'Unable to save transaction', 'Unable to save transaction': 'Unable to save transaction',
'You have added a new transaction': 'You have added a new transaction', 'You have added a new transaction': 'You have added a new transaction',
'You have saved this transaction': 'You have saved this transaction', 'You have saved this transaction': 'You have saved this transaction',
'Search transaction description': 'Search transaction description', 'Search transaction description': 'Search transaction description',
'Unable to get transaction list': 'Unable to get transaction list', 'Unable to retrieve transaction list': 'Unable to retrieve transaction list',
'Custom Date Range': 'Custom Date Range', 'Custom Date Range': 'Custom Date Range',
'Transaction Detail': 'Transaction Detail', 'Transaction Detail': 'Transaction Detail',
'No transaction data': 'No transaction data', 'No transaction data': 'No transaction data',
@@ -995,18 +993,16 @@ export default {
'Amount value is not number': 'Amount value is not number', 'Amount value is not number': 'Amount value is not number',
'Amount value exceeds limitation': 'Amount value exceeds limitation', 'Amount value exceeds limitation': 'Amount value exceeds limitation',
'Unable to delete this transaction': 'Unable to delete this transaction', 'Unable to delete this transaction': 'Unable to delete this transaction',
'Unable to get transaction statistics': 'Unable to get transaction statistics', 'Unable to retrieve transaction statistics': 'Unable to retrieve transaction statistics',
'Categorical Analysis': 'Categorical Analysis', 'Categorical Analysis': 'Categorical Analysis',
'Total Amount': 'Total Amount', 'Total Amount': 'Total Amount',
'Total Assets': 'Total Assets', 'Total Assets': 'Total Assets',
'Total Liabilities': 'Total Liabilities', 'Total Liabilities': 'Total Liabilities',
'Total Expense': 'Total Expense', 'Total Expense': 'Total Expense',
'Total Income': 'Total Income', 'Total Income': 'Total Income',
'Expense Chart': 'Expense Chart',
'Expense By Account': 'Expense By Account', 'Expense By Account': 'Expense By Account',
'Expense By Primary Category': 'Expense By Primary Category', 'Expense By Primary Category': 'Expense By Primary Category',
'Expense By Secondary Category': 'Expense By Secondary Category', 'Expense By Secondary Category': 'Expense By Secondary Category',
'Income Chart': 'Income Chart',
'Income By Account': 'Income By Account', 'Income By Account': 'Income By Account',
'Income By Primary Category': 'Income By Primary Category', 'Income By Primary Category': 'Income By Primary Category',
'Income By Secondary Category': 'Income By Secondary Category', 'Income By Secondary Category': 'Income By Secondary Category',
@@ -1021,7 +1017,8 @@ export default {
'Default Date Range': 'Default Date Range', 'Default Date Range': 'Default Date Range',
'Default Account Filter': 'Default Account Filter', 'Default Account Filter': 'Default Account Filter',
'Default Transaction Category Filter': 'Default Transaction Category Filter', 'Default Transaction Category Filter': 'Default Transaction Category Filter',
'Default Sort By': 'Default Sort By', 'Sort Order': 'Sort Order',
'Default Sort Order': 'Default Sort Order',
'Amount': 'Amount', 'Amount': 'Amount',
'Display Order': 'Display Order', 'Display Order': 'Display Order',
'Name': 'Name', 'Name': 'Name',
@@ -1062,24 +1059,24 @@ export default {
'Use preset transaction categories': 'Use preset transaction categories', 'Use preset transaction categories': 'Use preset transaction categories',
'Use Preset Transaction Categories': 'Use Preset Transaction Categories', 'Use Preset Transaction Categories': 'Use Preset Transaction Categories',
'Preset Categories': 'Preset Categories', 'Preset Categories': 'Preset Categories',
'Set Whether You Use The Preset Transaction Categories': 'Set Whether You Use The Preset Transaction Categories', 'Set whether to use preset transaction categories': 'Set whether to use preset transaction categories',
'Complete': 'Complete', 'Complete': 'Complete',
'Registration Complete': 'Registration Complete', 'Registration Completed': 'Registration Completed',
'You have been successfully registered': 'You have been successfully registered', 'You have been successfully registered': 'You have been successfully registered',
'You have been successfully registered, but something wrong with adding preset categories. You can re-add preset categories in settings page anytime.': 'You have been successfully registered, but something wrong with adding preset categories. You can re-add preset categories in settings page anytime.', 'You have been successfully registered, but there was an failure when adding preset categories. You can re-add preset categories in settings page anytime.': 'You have been successfully registered, but there was an failure when adding preset categories. You can re-add preset categories in settings page anytime.',
'You have been successfully registered. Account activation link has been sent to your email address, please activate your account first.': 'You have been successfully registered. Account activation link has been sent to your email address, please activate your account first.', 'You have been successfully registered. An account activation link has been sent to your email address, please activate your account first.': 'You have been successfully registered. An account activation link has been sent to your email address, please activate your account first.',
'Unable to sign up': 'Unable to sign up', 'Unable to sign up': 'Unable to sign up',
'User registration is disabled': 'User registration is disabled', 'User registration is disabled': 'User registration is disabled',
'Unable to get user profile': 'Unable to get user profile', 'Unable to retrieve user profile': 'Unable to retrieve user profile',
'Basic': 'Basic', 'Basic': 'Basic',
'Security': 'Security', 'Security': 'Security',
'Basic Settings': 'Basic Settings', 'Basic Settings': 'Basic Settings',
'Security Settings': 'Security Settings', 'Security Settings': 'Security Settings',
'Two-Factor Authentication Settings': 'Two-Factor Authentication Settings', 'Two-Factor Authentication Settings': 'Two-Factor Authentication Settings',
'(Verified)': '(Verified)', '(Verified)': '(Verified)',
'(Unverified)': '(Unverified)', '(Not Verified)': '(Not Verified)',
'Email has been verified': 'Email has been verified', 'Email address is verified': 'Email address is verified',
'Email has not been verified': 'Email has not been verified', 'Email address is not verified': 'Email address is not verified',
'Username:': 'Username:', 'Username:': 'Username:',
'Current Password': 'Current Password', 'Current Password': 'Current Password',
'New Password': 'New Password', 'New Password': 'New Password',
@@ -1088,9 +1085,9 @@ export default {
'Nothing has been modified': 'Nothing has been modified', 'Nothing has been modified': 'Nothing has been modified',
'Your profile has been successfully updated': 'Your profile has been successfully updated', 'Your profile has been successfully updated': 'Your profile has been successfully updated',
'Unable to update user profile': 'Unable to update user profile', 'Unable to update user profile': 'Unable to update user profile',
'After the password is changed, other devices will be logged out, please log in again on other devices by using the new password.': 'After the password is changed, other devices will be logged out, please log in again on other devices by using the new password.', 'After changing the password, other devices will be logged out. Please use the new password to log in on other devices.': 'After changing the password, other devices will be logged out. Please use the new password to log in on other devices.',
'Data Management': 'Data Management', 'Data Management': 'Data Management',
'Unable to get user statistics data': 'Unable to get user statistics data', 'Unable to retrieve user statistics data': 'Unable to retrieve user statistics data',
'Export Data': 'Export Data', 'Export Data': 'Export Data',
'CSV (Comma-separated values) File': 'CSV (Comma-separated values) File', 'CSV (Comma-separated values) File': 'CSV (Comma-separated values) File',
'TSV (Tab-separated values) File': 'TSV (Tab-separated values) File', 'TSV (Tab-separated values) File': 'TSV (Tab-separated values) File',
@@ -1098,17 +1095,17 @@ export default {
'Export all transaction data to file.': 'Export all transaction data to file.', 'Export all transaction data to file.': 'Export all transaction data to file.',
'Are you sure you want to export all transaction data to file?': 'Are you sure you want to export all transaction data to file?', 'Are you sure you want to export all transaction data to file?': 'Are you sure you want to export all transaction data to file?',
'It may take a long time, please wait for a few minutes.': 'It may take a long time, please wait for a few minutes.', 'It may take a long time, please wait for a few minutes.': 'It may take a long time, please wait for a few minutes.',
'Unable to get exported user data': 'Unable to get exported user data', 'Unable to retrieve exported user data': 'Unable to retrieve exported user data',
'Save Data': 'Save Data', 'Save Data': 'Save Data',
'Are you sure you want to clear all data?': 'Are you sure you want to clear all data?', 'Are you sure you want to clear all data?': 'Are you sure you want to clear all data?',
'You CANNOT undo this action. This will clear your accounts, categories, tags and transactions data. Please input your current password to confirm.': 'You CANNOT undo this action. This will clear your accounts, categories, tags and transactions data. Please input your current password to confirm.', 'You CANNOT undo this action. This will clear your accounts, categories, tags and transactions data. Please enter your current password to confirm.': 'You CANNOT undo this action. This will clear your accounts, categories, tags and transactions data. Please enter your current password to confirm.',
'All user data has been cleared': 'All user data has been cleared', 'All user data has been cleared': 'All user data has been cleared',
'Unable to clear user data': 'Unable to clear user data', 'Unable to clear user data': 'Unable to clear user data',
'Device & Sessions': 'Device & Sessions', 'Device & Sessions': 'Device & Sessions',
'Device Info': 'Device Info', 'Device Info': 'Device Info',
'Last Activity Time': 'Last Activity Time', 'Last Activity Time': 'Last Activity Time',
'Logout All': 'Logout All', 'Logout All': 'Logout All',
'Unable to get session list': 'Unable to get session list', 'Unable to retrieve session list': 'Unable to retrieve session list',
'Session list is up to date': 'Session list is up to date', 'Session list is up to date': 'Session list is up to date',
'Session list has been updated': 'Session list has been updated', 'Session list has been updated': 'Session list has been updated',
'Current': 'Current', 'Current': 'Current',
@@ -1131,7 +1128,7 @@ export default {
'No available category': 'No available category', 'No available category': 'No available category',
'Add Default Categories': 'Add Default Categories', 'Add Default Categories': 'Add Default Categories',
'Default Categories': 'Default Categories', 'Default Categories': 'Default Categories',
'Unable to get category list': 'Unable to get category list', 'Unable to retrieve category list': 'Unable to retrieve category list',
'Category list is up to date': 'Category list is up to date', 'Category list is up to date': 'Category list is up to date',
'Category list has been updated': 'Category list has been updated', 'Category list has been updated': 'Category list has been updated',
'Unable to move category': 'Unable to move category', 'Unable to move category': 'Unable to move category',
@@ -1147,20 +1144,20 @@ export default {
'Category Icon': 'Category Icon', 'Category Icon': 'Category Icon',
'Category Color': 'Category Color', 'Category Color': 'Category Color',
'Your category description (optional)': 'Your category description (optional)', 'Your category description (optional)': 'Your category description (optional)',
'Category name cannot be empty': 'Category name cannot be empty', 'Category name cannot be blank': 'Category name cannot be blank',
'Unable to get category': 'Unable to get category', 'Unable to retrieve category': 'Unable to retrieve category',
'Unable to add category': 'Unable to add category', 'Unable to add category': 'Unable to add category',
'Unable to save category': 'Unable to save category', 'Unable to save category': 'Unable to save category',
'Unable to add preset categories': 'Unable to add preset categories', 'Unable to add preset categories': 'Unable to add preset categories',
'You have added a new category': 'You have added a new category', 'You have added a new category': 'You have added a new category',
'You have added preset categories': 'You have added preset categories', 'You have added preset categories': 'You have added preset categories',
'You have saved this category': 'You have saved this category', 'You have saved this category': 'You have saved this category',
'Show Hidden Transaction Category': 'Show Hidden Transaction Category', 'Show Hidden Transaction Categories': 'Show Hidden Transaction Categories',
'Hide Hidden Transaction Category': 'Hide Hidden Transaction Category', 'Hide Hidden Transaction Categories': 'Hide Hidden Transaction Categories',
'Transaction Tags': 'Transaction Tags', 'Transaction Tags': 'Transaction Tags',
'Tag Title': 'Tag Title', 'Tag Title': 'Tag Title',
'No available tag': 'No available tag', 'No available tag': 'No available tag',
'Unable to get tag list': 'Unable to get tag list', 'Unable to retrieve tag list': 'Unable to retrieve tag list',
'Tag list is up to date': 'Tag list is up to date', 'Tag list is up to date': 'Tag list is up to date',
'Tag list has been updated': 'Tag list has been updated', 'Tag list has been updated': 'Tag list has been updated',
'Unable to add tag': 'Unable to add tag', 'Unable to add tag': 'Unable to add tag',
@@ -1170,8 +1167,8 @@ export default {
'Unable to unhide this tag': 'Unable to unhide this tag', 'Unable to unhide this tag': 'Unable to unhide this tag',
'Are you sure you want to delete this tag?': 'Are you sure you want to delete this tag?', 'Are you sure you want to delete this tag?': 'Are you sure you want to delete this tag?',
'Unable to delete this tag': 'Unable to delete this tag', 'Unable to delete this tag': 'Unable to delete this tag',
'Show Hidden Transaction Tag': 'Show Hidden Transaction Tag', 'Show Hidden Transaction Tags': 'Show Hidden Transaction Tags',
'Hide Hidden Transaction Tag': 'Hide Hidden Transaction Tag', 'Hide Hidden Transaction Tags': 'Hide Hidden Transaction Tags',
'Are you sure you want to logout from this session?': 'Are you sure you want to logout from this session?', 'Are you sure you want to logout from this session?': 'Are you sure you want to logout from this session?',
'Unable to logout from this session': 'Unable to logout from this session', 'Unable to logout from this session': 'Unable to logout from this session',
'Are you sure you want to logout all other sessions?': 'Are you sure you want to logout all other sessions?', 'Are you sure you want to logout all other sessions?': 'Are you sure you want to logout all other sessions?',
@@ -1180,16 +1177,16 @@ export default {
'Regenerate Backup Codes': 'Regenerate Backup Codes', 'Regenerate Backup Codes': 'Regenerate Backup Codes',
'Enable Two-Factor Authentication': 'Enable Two-Factor Authentication', 'Enable Two-Factor Authentication': 'Enable Two-Factor Authentication',
'Disable Two-Factor Authentication': 'Disable Two-Factor Authentication', 'Disable Two-Factor Authentication': 'Disable Two-Factor Authentication',
'Please use two factor authentication app scan the below qrcode and input current passcode': 'Please use two factor authentication app scan the below qrcode and input current passcode', 'Please use a two-factor authentication app to scan the qrcode below and enter the current passcode.': 'Please use a two-factor authentication app to scan the qrcode below and enter the current passcode.',
'Please enter your current password when disable two factor authentication': 'Please enter your current password when disable two factor authentication', 'Your current password is required to disable two-factor authentication.': 'Your current password is required to disable two-factor authentication.',
'Please enter your current password when regenerate two factor authentication backup codes. If you regenerate backup codes, the old codes will be invalidated.': 'Please enter your current password when regenerate two factor authentication backup codes. If you regenerate backup codes, the old codes will be invalidated.', 'Your current password is required to regenerate backup codes for two-factor authentication. If you regenerate backup codes, the previous ones will become invalid.': 'Your current password is required to regenerate backup codes for two-factor authentication. If you regenerate backup codes, the previous ones will become invalid.',
'Please enter your current password when disable two factor authentication or regenerate two factor authentication backup codes. If you regenerate backup codes, the old codes will be invalidated.': 'Please enter your current password when disable two factor authentication or regenerate two factor authentication backup codes. If you regenerate backup codes, the old codes will be invalidated.', 'Your current password is required to disable two-factor authentication or regenerate backup codes for two-factor authentication. If you regenerate backup codes, the previous ones will become invalid.': 'Your current password is required to disable two-factor authentication or regenerate backup codes for two-factor authentication. If you regenerate backup codes, the previous ones will become invalid.',
'Please copy these backup codes to safe place, the below codes can only be shown once. If these codes were lost, you can regenerate backup codes at any time.': 'Please copy these backup codes to safe place, the below codes can only be shown once. If these codes were lost, you can regenerate backup codes at any time.', 'Please copy these backup codes to safe place, the following backup codes will be displayed only once. If these codes were lost, you can regenerate them at any time.': 'Please copy these backup codes to safe place, the following backup codes will be displayed only once. If these codes were lost, you can regenerate them at any time.',
'Backup codes copied': 'Backup codes copied', 'Backup codes copied': 'Backup codes copied',
'Two factor authentication has been disabled': 'Two factor authentication has been disabled', 'Two-factor authentication has been disabled': 'Two-factor authentication has been disabled',
'Unable to get current two factor authentication status': 'Unable to get current two factor authentication status', 'Unable to retrieve current two-factor authentication status': 'Unable to retrieve current two-factor authentication status',
'Unable to enable two factor authentication': 'Unable to enable two factor authentication', 'Unable to enable two-factor authentication': 'Unable to enable two-factor authentication',
'Unable to disable two factor authentication': 'Unable to disable two factor authentication', 'Unable to disable two-factor authentication': 'Unable to disable two-factor authentication',
'Lock Application': 'Lock Application', 'Lock Application': 'Lock Application',
'Log Out': 'Log Out', 'Log Out': 'Log Out',
'Are you sure you want to log out?': 'Are you sure you want to log out?', 'Are you sure you want to log out?': 'Are you sure you want to log out?',
@@ -1200,38 +1197,38 @@ export default {
'Enable Application Lock': 'Enable Application Lock', 'Enable Application Lock': 'Enable Application Lock',
'Disable Application Lock': 'Disable Application Lock', 'Disable Application Lock': 'Disable Application Lock',
'PIN Code': 'PIN Code', 'PIN Code': 'PIN Code',
'Unlock By PIN Code': 'Unlock By PIN Code', 'Unlock with PIN Code': 'Unlock with PIN Code',
'Unlock By WebAuthn': 'Unlock By WebAuthn', 'Unlock with WebAuthn': 'Unlock with WebAuthn',
'Please input a new 6-digit PIN code. PIN code would encrypt your local data, so you need input this PIN code when you launch this app. If this PIN code is lost, you should re-login.': 'Please input a new 6-digit PIN code. PIN code would encrypt your local data, so you need input this PIN code when you launch this app. If this PIN code is lost, you should re-login.', 'Please enter a new 6-digit PIN code. The PIN code would encrypt your local data, so you need to enter it every time you open this app. If this PIN code is lost, you will need to log in again.': 'Please enter a new 6-digit PIN code. The PIN code would encrypt your local data, so you need to enter it every time you open this app. If this PIN code is lost, you will need to log in again.',
'Please enter your current PIN code when disable application lock.': 'Please enter your current PIN code when disable application lock.', 'Your current PIN code is required to disable application lock.': 'Your current PIN code is required to disable application lock.',
'You have enabled WebAuthn successfully': 'You have enabled WebAuthn successfully', 'You have enabled WebAuthn successfully': 'You have enabled WebAuthn successfully',
'This device does not support WebAuthn': 'This device does not support WebAuthn', 'WebAuth is not supported on this device': 'WebAuth is not supported on this device',
'Failed to enable WebAuthn': 'Failed to enable WebAuthn', 'Failed to enable WebAuthn': 'Failed to enable WebAuthn',
'User has canceled authentication': 'User has canceled authentication', 'User has canceled authentication': 'User has canceled authentication',
'User has canceled or this device does not support WebAuthn': 'User has canceled or this device does not support WebAuthn', 'User has canceled or this device does not support WebAuthn': 'User has canceled or this device does not support WebAuthn',
'Failed to authenticate by WebAuthn': 'Failed to authenticate by WebAuthn', 'Failed to authenticate with WebAuthn': 'Failed to authenticate with WebAuthn',
'WebAuthn is not enabled': 'WebAuthn is not enabled', 'WebAuthn is not enabled': 'WebAuthn is not enabled',
'Are you sure you want to re-login?': 'Are you sure you want to re-login?', 'Are you sure you want to re-login?': 'Are you sure you want to re-login?',
'Exchange Rates Data': 'Exchange Rates Data', 'Exchange Rates Data': 'Exchange Rates Data',
'Base Currency': 'Base Currency', 'Base Currency': 'Base Currency',
'Base Amount': 'Base Amount', 'Base Amount': 'Base Amount',
'Set As Baseline': 'Set As Baseline', 'Set as Base': 'Set as Base',
'Last Updated': 'Last Updated', 'Last Updated': 'Last Updated',
'Data source': 'Data source', 'Data source': 'Data source',
'No exchange rates data': 'No exchange rates data', 'No exchange rates data': 'No exchange rates data',
'There is no exchange rates data for your default currency': 'There is no exchange rates data for your default currency', 'There is no exchange rates data for your default currency': 'There is no exchange rates data for your default currency',
'Exchange rates data has been updated': 'Exchange rates data has been updated', 'Exchange rates data has been updated': 'Exchange rates data has been updated',
'Exchange rates data is up to date': 'Exchange rates data is up to date', 'Exchange rates data is up to date': 'Exchange rates data is up to date',
'Unable to get exchange rates data': 'Unable to get exchange rates data', 'Unable to retrieve exchange rates data': 'Unable to retrieve exchange rates data',
'Use on Mobile Device': 'Use on Mobile Device', 'Use on Mobile Device': 'Use on Mobile Device',
'You can scan the below QR code on your mobile device.': 'You can scan the below QR code on your mobile device.', 'You can scan the QR code below on your mobile device.': 'You can scan the QR code below on your mobile device.',
'Switch to Mobile Version': 'Switch to Mobile Version', 'Switch to Mobile Version': 'Switch to Mobile Version',
'Switch to Desktop Version': 'Switch to Desktop Version', 'Switch to Desktop Version': 'Switch to Desktop Version',
'About': 'About', 'About': 'About',
'Build Time': 'Build Time', 'Build Time': 'Build Time',
'Official Website': 'Official Website', 'Official Website': 'Official Website',
'License': 'License', 'License': 'License',
'An error has occurred': 'An error has occurred', 'An error occurred': 'An error occurred',
'Parameter Invalid': 'Parameter Invalid', 'Parameter Invalid': 'Parameter Invalid',
'Numeric Overflow': 'Numeric Overflow', 'Numeric Overflow': 'Numeric Overflow',
}; };
+113 -116
View File
@@ -595,8 +595,8 @@ export default {
'current token is invalid': '当前认证令牌无效', 'current token is invalid': '当前认证令牌无效',
'current token is expired': '当前认证令牌已过期', 'current token is expired': '当前认证令牌已过期',
'current token type is invalid': '当前认证令牌类型无效', 'current token type is invalid': '当前认证令牌类型无效',
'current token requires two factor authorization': '当前认证令牌需要两步验证', 'current token requires two-factor authorization': '当前认证令牌需要两步验证',
'current token does not require two factor authorization': '当前认证令牌不需要两步验证', 'current token does not require two-factor authorization': '当前认证令牌不需要两步验证',
'token is invalid': '认证令牌无效', 'token is invalid': '认证令牌无效',
'token id is invalid': '认证令牌ID无效', 'token id is invalid': '认证令牌ID无效',
'user token id is invalid': '用户认证令牌ID无效', 'user token id is invalid': '用户认证令牌ID无效',
@@ -606,21 +606,21 @@ export default {
'email verify token is invalid or expired': '邮箱验证令牌无效或已过期', 'email verify token is invalid or expired': '邮箱验证令牌无效或已过期',
'password reset token is invalid or expired': '密码重置令牌无效或已过期', 'password reset token is invalid or expired': '密码重置令牌无效或已过期',
'passcode is invalid': '验证码无效', 'passcode is invalid': '验证码无效',
'two factor backup code is invalid': '两步验证备用码无效', 'two-factor backup code is invalid': '两步验证备用码无效',
'two factor is not enabled': '两步验证没有启用', 'two-factor is not enabled': '两步验证没有启用',
'two factor has already been enabled': '两步验证已经启用', 'two-factor has already been enabled': '两步验证已经启用',
'two factor backup code does not exist': '两步验证备用码不存在', 'two-factor backup code does not exist': '两步验证备用码不存在',
'account id is invalid': '账户ID无效', 'account id is invalid': '账户ID无效',
'account not found': '账户不存在', 'account not found': '账户不存在',
'account type is invalid': '账户类型无效', 'account type is invalid': '账户类型无效',
'account currency is invalid': '账户货币无效', 'account currency is invalid': '账户货币无效',
'account must have at least one sub account': '账户必须包含至少一个子账户', 'account must have at least one sub-account': '账户必须包含至少一个子账户',
'account cannot have sub accounts': '账户不能包含子账户', 'account cannot have sub-accounts': '账户不能包含子账户',
'parent account cannot set currency': '父账户不能设置货币', 'parent account cannot set currency': '父账户不能设置货币',
'parent account cannot set balance': '父账户不能设置余额', 'parent account cannot set balance': '父账户不能设置余额',
'sub account category not equals to parent': '子账户类别与父账户不同', 'sub-account category not equals to parent': '子账户类别与父账户不同',
'sub account type invalid': '子账户类型无效', 'sub-account type invalid': '子账户类型无效',
'cannot add or delete sub accounts when modify account': '您不能在修改账户时添加或删除子账户', 'cannot add or delete sub-accounts when modify account': '您不能在修改账户时添加或删除子账户',
'source account not found': '来源账户不存在', 'source account not found': '来源账户不存在',
'destination account not found': '目标账户不存在', 'destination account not found': '目标账户不存在',
'account is in use and cannot be deleted': '账户正在被使用,无法删除', 'account is in use and cannot be deleted': '账户正在被使用,无法删除',
@@ -654,7 +654,7 @@ export default {
'transaction tag name already exists': '交易标签标题已经存在', 'transaction tag name already exists': '交易标签标题已经存在',
'transaction tag is in use and cannot be deleted': '交易标签正在被使用,无法删除', 'transaction tag is in use and cannot be deleted': '交易标签正在被使用,无法删除',
'data export not allowed': '不允许用户数据导出', 'data export not allowed': '不允许用户数据导出',
'query items cannot be empty': '请求项目不能为空', 'query items cannot be blank': '请求项目不能为空',
'query items too much': '请求项目过多', 'query items too much': '请求项目过多',
'query items have invalid item': '请求项目中有非法项目', 'query items have invalid item': '请求项目中有非法项目',
'parameter invalid': '参数错误', 'parameter invalid': '参数错误',
@@ -713,13 +713,13 @@ export default {
'Add': '添加', 'Add': '添加',
'Apply': '应用', 'Apply': '应用',
'Save': '保存', 'Save': '保存',
'Save changes': '保存修改', 'Save Changes': '保存修改',
'Reset': '重置', 'Reset': '重置',
'Update': '更新', 'Update': '更新',
'Refresh': '刷新', 'Refresh': '刷新',
'Clear': '清除', 'Clear': '清除',
'None': '无', 'None': '无',
'Not Specified': '未指定', 'Unspecified': '未指定',
'No results': '无结果', 'No results': '无结果',
'Unknown': '未知', 'Unknown': '未知',
'Miscellaneous': '杂项', 'Miscellaneous': '杂项',
@@ -760,7 +760,7 @@ export default {
'This year': '今年', 'This year': '今年',
'Last year': '去年', 'Last year': '去年',
'Custom Date': '自定义日期', 'Custom Date': '自定义日期',
'Begin Time': '开始时间', 'Start Time': '开始时间',
'End Time': '结束时间', 'End Time': '结束时间',
'Select Date': '选择日期', 'Select Date': '选择日期',
'Select Time': '选择时间', 'Select Time': '选择时间',
@@ -768,7 +768,7 @@ export default {
'Custom': '自定义', 'Custom': '自定义',
'Pie Chart': '饼图', 'Pie Chart': '饼图',
'Bar Chart': '条形图', 'Bar Chart': '条形图',
'Sort By': '排序方式', 'Sort by': '排序方式',
'User': '用户', 'User': '用户',
'Application': '应用', 'Application': '应用',
'Danger Zone': '危险区域', 'Danger Zone': '危险区域',
@@ -787,16 +787,16 @@ export default {
'No data': '没有数据', 'No data': '没有数据',
'Zoom in': '放大', 'Zoom in': '放大',
'Zoom out': '缩小', 'Zoom out': '缩小',
'Drag and Drop to Change Order': '拖拽改变顺序', 'Drag to Reorder': '拖拽改变顺序',
'Save Display Order': '保存显示顺序', 'Save Display Order': '保存显示顺序',
'Change Language': '修改语言', 'Change Language': '修改语言',
'Date is too early': '日期过早', 'Date is too early': '日期过早',
'Welcome to ezBookkeeping': '欢迎使用 ezBookkeeping', 'Welcome to ezBookkeeping': '欢迎使用 ezBookkeeping',
'Please log in with your ezBookkeeping account': '请使用您的 ezBookkeeping 账号登录', 'Please log in with your ezBookkeeping account': '请使用您的 ezBookkeeping 账号登录',
'Unlock Application': '解锁应用', 'Unlock Application': '解锁应用',
'Please input your PIN code or use WebAuthn to unlock application': '请输入您的 PIN 码,或使用 WebAuthn 解锁应用', 'Please enter your PIN code or use WebAuthn to unlock application': '请输入您的 PIN 码,或使用 WebAuthn 解锁应用',
'Please input your PIN code to unlock application': '请输入您的 PIN 码解锁应用', 'Please enter your PIN code to unlock application': '请输入您的 PIN 码解锁应用',
'Can\'t Unlock?': '无法登录', 'Can\'t Unlock?': '无法解锁',
'Re-login': '重新登录', 'Re-login': '重新登录',
'Username': '用户名', 'Username': '用户名',
'Your username': '你的用户名', 'Your username': '你的用户名',
@@ -804,7 +804,7 @@ export default {
'Password': '密码', 'Password': '密码',
'Your password': '你的密码', 'Your password': '你的密码',
'Your password, at least 6 characters': '你的密码,至少6个字符', 'Your password, at least 6 characters': '你的密码,至少6个字符',
'Confirmation Password': '确认密码', 'Confirm Password': '确认密码',
'Re-enter the password': '再次输入密码', 'Re-enter the password': '再次输入密码',
'E-mail': '电子邮箱', 'E-mail': '电子邮箱',
'Your email address': '你的电子邮箱地址', 'Your email address': '你的电子邮箱地址',
@@ -817,7 +817,7 @@ export default {
'Short Date Format': '短日期格式', 'Short Date Format': '短日期格式',
'Long Time Format': '长时间格式', 'Long Time Format': '长时间格式',
'Short Time Format': '短时间格式', 'Short Time Format': '短时间格式',
'Editable Transaction Scope': '可编辑交易范围', 'Editable Transaction Range': '可编辑交易范围',
'Today or later': '今天或更晚', 'Today or later': '今天或更晚',
'Recent 24 hours or later': '最近24小时或更晚', 'Recent 24 hours or later': '最近24小时或更晚',
'This week or later': '本周或更晚', 'This week or later': '本周或更晚',
@@ -825,55 +825,53 @@ export default {
'This year or later': '今年或更晚', 'This year or later': '今年或更晚',
'Log In': '登录', 'Log In': '登录',
'Click here to log in': '点击这里登录', 'Click here to log in': '点击这里登录',
'Back to log in': '返回登录页', 'Back to login page': '返回登录页',
'Back to home': '返回首页', 'Back to home page': '返回首页',
'Don\'t have an account?': '还没有账号?', 'Don\'t have an account?': '还没有账号?',
'Forget Password?': '忘记密码?', 'Forget Password?': '忘记密码?',
'Create an account': '创建新账号', 'Create an account': '创建新账号',
'Username cannot be empty': '用户名不能为空', 'Username cannot be blank': '用户名不能为空',
'Password cannot be empty': '密码不能为空', 'Password cannot be blank': '密码不能为空',
'Current password cannot be empty': '当前密码不能为空', 'Current password cannot be blank': '当前密码不能为空',
'New password cannot be empty': '新密码不能为空', 'New password cannot be blank': '新密码不能为空',
'Confirmation password cannot be empty': '确认密码不能为空', 'Password confirmation cannot be blank': '确认密码不能为空',
'Password and confirmation password do not match': '密码和确认密码不匹配', 'Password and password confirmation do not match': '密码和确认密码不匹配',
'Email address cannot be empty': '电子邮箱地址不能为空', 'Email address cannot be blank': '电子邮箱地址不能为空',
'Nickname cannot be empty': '昵称不能为空', 'Nickname cannot be blank': '昵称不能为空',
'Default currency cannot be empty': '默认货币不能为空', 'Default currency cannot be blank': '默认货币不能为空',
'Unable to login': '无法登录', 'Unable to log in': '无法登录',
'Two-Factor Authentication': '两步验证', 'Two-Factor Authentication': '两步验证',
'Two-factor authentication is not enabled yet.': '两步验证没有启用。', 'Two-factor authentication is not enabled yet.': '两步验证没有启用。',
'Two-factor authentication has been enabled.': '两步验证已经启用。', 'Two-factor authentication is already enabled.': '两步验证已经启用。',
'Disable two-factor authentication': '禁用两步验证',
'Enable two-factor authentication': '启用两步验证',
'Passcode': '验证码', 'Passcode': '验证码',
'Backup Code': '备用码', 'Backup Code': '备用码',
'Verify': '验证', 'Verify': '验证',
'Passcode cannot be empty': '验证码不能为空', 'Passcode cannot be blank': '验证码不能为空',
'Backup code cannot be empty': '备用码不能为空', 'Backup code cannot be blank': '备用码不能为空',
'Unable to verify': '无法验证', 'Unable to verify': '无法验证',
'Use a backup code': '使用备用码', 'Use Backup Code': '使用备用码',
'Use a passcode': '使用验证码', 'Use Passcode': '使用验证码',
'PIN code is invalid': 'PIN码无效', 'Invalid PIN code': 'PIN码无效',
'PIN code is wrong': 'PIN码错误', 'Incorrect PIN code': 'PIN码错误',
'Verify your email': '验证您的邮箱', 'Verify your email': '验证您的邮箱',
'Verifying...': '正在验证...', 'Verifying...': '正在验证...',
'Resend Validation Email': '重发验证邮件', 'Resend Validation Email': '重发验证邮件',
'Validation email has been sent': '验证邮件已发送', 'Validation email has been sent': '验证邮件已发送',
'Unable to verify email': '无法验证邮箱', 'Unable to verify email': '无法验证邮箱',
'Unable to resend verify email': '无法重新发送验证邮件', 'Unable to resend validation email': '无法重新发送验证邮件',
'Send Reset Link': '发送重置链接', 'Send Reset Link': '发送重置链接',
'Please input your email address used for registration and we\'ll send you an email with reset password link': '请输入您注册时使用的电子邮箱地址,我们将发送一封包含重置密码链接的邮件给您', 'Please enter your email address used for registration and we\'ll send you an email with a reset password link': '请输入您注册时使用的电子邮箱地址,我们将发送一封包含重置密码链接的邮件给您',
'Password reset email has been sent': '重置密码邮件已发送', 'Password reset email has been sent': '重置密码邮件已发送',
'Unable to send password reset email': '无法发送重置密码邮件', 'Unable to send password reset email': '无法发送重置密码邮件',
'Reset Password': '重置密码', 'Reset Password': '重置密码',
'Update Password': '更新密码', 'Update Password': '更新密码',
'Please input your email address again, and input the new password.': '请再次输入您的邮箱,然后输入新的密码。', 'Please re-enter your email address, and then enter a new password.': '请再次输入您的邮箱,然后输入新的密码。',
'Password has been updated': '密码已经更新', 'Password has been updated': '密码已经更新',
'Unable to reset password': '无法重置密码', 'Unable to reset password': '无法重置密码',
'Sign Up': '注册', 'Sign Up': '注册',
'Overview': '总览', 'Overview': '总览',
'Asset Summary': '资产概要', 'Asset Summary': '资产概要',
'Trend in Income and Expense': '收入与支出趋势', 'Income and Expense Trends': '收入与支出趋势',
'View Details': '查看详情', 'View Details': '查看详情',
'Transaction List': '交易列表', 'Transaction List': '交易列表',
'Transaction Details': '交易详情', 'Transaction Details': '交易详情',
@@ -883,7 +881,7 @@ export default {
'This Month': '本月', 'This Month': '本月',
'This Year': '今年', 'This Year': '今年',
'Monthly income': '当月收入', 'Monthly income': '当月收入',
'Unable to get transaction overview': '无法获取交易概要', 'Unable to retrieve transaction overview': '无法获取交易概要',
'Data is up to date': '数据已是最新', 'Data is up to date': '数据已是最新',
'Data has been updated': '数据已更新', 'Data has been updated': '数据已更新',
'Net assets': '净资产', 'Net assets': '净资产',
@@ -900,7 +898,7 @@ export default {
'Receivables': '应收款项', 'Receivables': '应收款项',
'Investment Account': '投资账户', 'Investment Account': '投资账户',
'Balance': '余额', 'Balance': '余额',
'Unable to get account list': '无法获取账户列表', 'Unable to retrieve account list': '无法获取账户列表',
'Account list is up to date': '账户列表已是最新', 'Account list is up to date': '账户列表已是最新',
'Account list has been updated': '账户列表已更新', 'Account list has been updated': '账户列表已更新',
'All Accounts': '全部账户', 'All Accounts': '全部账户',
@@ -909,38 +907,38 @@ export default {
'Edit Account': '编辑账户', 'Edit Account': '编辑账户',
'Account Category': '账户分类', 'Account Category': '账户分类',
'Single Account': '单一账户', 'Single Account': '单一账户',
'Multi Sub Accounts': '多个子账户', 'Multiple Sub-accounts': '多个子账户',
'Account Type': '账户类型', 'Account Type': '账户类型',
'Account Name': '账户名称', 'Account Name': '账户名称',
'Your account name': '你的账户名称', 'Your account name': '你的账户名称',
'Main Account': '主账户', 'Main Account': '主账户',
'Sub Account': '子账户', 'Sub Account': '子账户',
'Sub Account Name': '子账户名称', 'Sub-account Name': '子账户名称',
'Your sub account name': '你的子账户名称', 'Your sub-account name': '你的子账户名称',
'Account Icon': '账户图标', 'Account Icon': '账户图标',
'Sub Account Icon': '子账户图标', 'Sub-account Icon': '子账户图标',
'Account Color': '账户颜色', 'Account Color': '账户颜色',
'Sub Account Color': '子账户颜色', 'Sub-account Color': '子账户颜色',
'Currency': '货币', 'Currency': '货币',
'Account Balance': '账户余额', 'Account Balance': '账户余额',
'Sub Account Balance': '子账户余额', 'Sub-account Balance': '子账户余额',
'Description': '描述', 'Description': '描述',
'Your account description (optional)': '你的账户描述 (可选)', 'Your account description (optional)': '你的账户描述 (可选)',
'Your sub account description (optional)': '你的子账户描述 (可选)', 'Your sub-account description (optional)': '你的子账户描述 (可选)',
'Add Sub Account': '添加子账户', 'Add Sub-account': '添加子账户',
'Remove Sub Account': '删除子账户', 'Remove Sub-account': '删除子账户',
'Are you sure you want to remove this sub account?': '您确定要移除该子账户?', 'Are you sure you want to remove this sub-account?': '您确定要移除该子账户?',
'Account category cannot be empty': '账户分类不能为空', 'Account category cannot be blank': '账户分类不能为空',
'Account type cannot be empty': '账户类型不能为空', 'Account type cannot be blank': '账户类型不能为空',
'Account name cannot be empty': '账户名称不能为空', 'Account name cannot be blank': '账户名称不能为空',
'Account currency cannot be empty': '账户货币不能为空', 'Account currency cannot be blank': '账户货币不能为空',
'You have added a new account': '您已经添加新账户', 'You have added a new account': '您已经添加新账户',
'You have saved this account': '您已经保存该账户', 'You have saved this account': '您已经保存该账户',
'Unable to add account': '无法添加账户', 'Unable to add account': '无法添加账户',
'Unable to save account': '无法保存账户', 'Unable to save account': '无法保存账户',
'Show Hidden Account': '显示隐藏的账户', 'Show Hidden Accounts': '显示隐藏的账户',
'Hide Hidden Account': '不显示隐藏的账户', 'Hide Hidden Accounts': '不显示隐藏的账户',
'Unable to get account': '无法获取账户', 'Unable to retrieve account': '无法获取账户',
'Unable to hide this account': '无法隐藏账户', 'Unable to hide this account': '无法隐藏账户',
'Unable to unhide this account': '无法取消隐藏账户', 'Unable to unhide this account': '无法取消隐藏账户',
'Unable to move account': '无法移动账户', 'Unable to move account': '无法移动账户',
@@ -965,7 +963,7 @@ export default {
'Source Account': '来源账户', 'Source Account': '来源账户',
'Destination Account': '目标账户', 'Destination Account': '目标账户',
'Transaction Time': '交易时间', 'Transaction Time': '交易时间',
'Transaction Time Zone': '交易时区', 'Transaction Timezone': '交易时区',
'Same time as default timezone': '与默认时区时间相同', 'Same time as default timezone': '与默认时区时间相同',
'Geographic Location': '地理位置', 'Geographic Location': '地理位置',
'No Location': '没有位置', 'No Location': '没有位置',
@@ -974,20 +972,20 @@ export default {
'Location on Map': '地图上的位置', 'Location on Map': '地图上的位置',
'Update Geographic Location': '更新地理位置', 'Update Geographic Location': '更新地理位置',
'Clear Geographic Location': '清除地理位置', 'Clear Geographic Location': '清除地理位置',
'Unable to get current position': '无法获取当前地理位置', 'Unable to retrieve current position': '无法获取当前地理位置',
'Cannot Initialize Map': '无法初始化地图', 'Cannot Initialize Map': '无法初始化地图',
'Unsupported Map Provider': '不支持的地图提供方', 'Unsupported Map Provider': '不支持的地图提供方',
'Please refresh the page and try again. If the error is still displayed, make sure that server map settings are set correctly.': '请刷新页面并重试。如果仍然显示错误,请确保正确设置了服务器地图设置。', 'Please refresh the page and try again. If the error persists, ensure that the server\'s map settings are correctly configured.': '请刷新页面并重试。如果仍然显示错误,请确保正确设置了服务器地图设置。',
'Tags': '标签', 'Tags': '标签',
'Your transaction description (optional)': '你的交易描述 (可选)', 'Your transaction description (optional)': '你的交易描述 (可选)',
'Are you sure you want to save this transaction whose amount is 0?': '您确定要保存这个金额为0的交易?', 'Are you sure you want to save this transaction with a zero amount?': '您确定要保存这个金额为0的交易?',
'Unable to get transaction': '无法获取交易', 'Unable to retrieve transaction': '无法获取交易',
'Unable to add transaction': '无法添加交易', 'Unable to add transaction': '无法添加交易',
'Unable to save transaction': '无法保存交易', 'Unable to save transaction': '无法保存交易',
'You have added a new transaction': '您已经添加新交易', 'You have added a new transaction': '您已经添加新交易',
'You have saved this transaction': '您已经保存该交易', 'You have saved this transaction': '您已经保存该交易',
'Search transaction description': '搜索交易描述', 'Search transaction description': '搜索交易描述',
'Unable to get transaction list': '无法获取交易列表', 'Unable to retrieve transaction list': '无法获取交易列表',
'Custom Date Range': '自定义日期范围', 'Custom Date Range': '自定义日期范围',
'Transaction Detail': '交易详情', 'Transaction Detail': '交易详情',
'No transaction data': '没有交易数据', 'No transaction data': '没有交易数据',
@@ -995,18 +993,16 @@ export default {
'Amount value is not number': '金额值不是数值', 'Amount value is not number': '金额值不是数值',
'Amount value exceeds limitation': '金额数值超出限制', 'Amount value exceeds limitation': '金额数值超出限制',
'Unable to delete this transaction': '无法删除该交易', 'Unable to delete this transaction': '无法删除该交易',
'Unable to get transaction statistics': '无法获取交易统计数据', 'Unable to retrieve transaction statistics': '无法获取交易统计数据',
'Categorical Analysis': '分类分析', 'Categorical Analysis': '分类分析',
'Total Amount': '总金额', 'Total Amount': '总金额',
'Total Assets': '总资产', 'Total Assets': '总资产',
'Total Liabilities': '总负债', 'Total Liabilities': '总负债',
'Total Expense': '总支出', 'Total Expense': '总支出',
'Total Income': '总收入', 'Total Income': '总收入',
'Expense Chart': '支出图表',
'Expense By Account': '账户支出', 'Expense By Account': '账户支出',
'Expense By Primary Category': '一级分类支出', 'Expense By Primary Category': '一级分类支出',
'Expense By Secondary Category': '二级分类支出', 'Expense By Secondary Category': '二级分类支出',
'Income Chart': '收入图表',
'Income By Account': '账户收入', 'Income By Account': '账户收入',
'Income By Primary Category': '一级分类收入', 'Income By Primary Category': '一级分类收入',
'Income By Secondary Category': '二级分类收入', 'Income By Secondary Category': '二级分类收入',
@@ -1021,7 +1017,8 @@ export default {
'Default Date Range': '默认时间范围', 'Default Date Range': '默认时间范围',
'Default Account Filter': '默认账号过滤', 'Default Account Filter': '默认账号过滤',
'Default Transaction Category Filter': '默认交易分类过滤', 'Default Transaction Category Filter': '默认交易分类过滤',
'Default Sort By': '默认排序方式', 'Sort Order': '排序方式',
'Default Sort Order': '默认排序方式',
'Amount': '金额', 'Amount': '金额',
'Display Order': '显示顺序', 'Display Order': '显示顺序',
'Name': '名称', 'Name': '名称',
@@ -1062,24 +1059,24 @@ export default {
'Use preset transaction categories': '使用预设交易分类', 'Use preset transaction categories': '使用预设交易分类',
'Use Preset Transaction Categories': '使用预设交易分类', 'Use Preset Transaction Categories': '使用预设交易分类',
'Preset Categories': '预设分类', 'Preset Categories': '预设分类',
'Set Whether You Use The Preset Transaction Categories': '设置是否使用预设交易分类', 'Set whether to use preset transaction categories': '设置是否使用预设交易分类',
'Complete': '完成', 'Complete': '完成',
'Registration Complete': '注册完成', 'Registration Completed': '注册完成',
'You have been successfully registered': '注册成功', 'You have been successfully registered': '注册成功',
'You have been successfully registered, but something wrong with adding preset categories. You can re-add preset categories in settings page anytime.': '您已经注册成功,但是添加预设分类时出错。您可以随时在设置页面中重新添加预设分类。', 'You have been successfully registered, but there was an failure when adding preset categories. You can re-add preset categories in settings page anytime.': '您已经注册成功,但是添加预设分类时出错。您可以随时在设置页面中重新添加预设分类。',
'You have been successfully registered. Account activation link has been sent to your email address, please activate your account first.': '您已经注册成功。账号激活链接已经发送到您的邮箱地址,请先激活您的账号。', 'You have been successfully registered. An account activation link has been sent to your email address, please activate your account first.': '您已经注册成功。账号激活链接已经发送到您的邮箱地址,请先激活您的账号。',
'Unable to sign up': '无法注册', 'Unable to sign up': '无法注册',
'User registration is disabled': '用户注册已禁用', 'User registration is disabled': '用户注册已禁用',
'Unable to get user profile': '无法获取用户信息', 'Unable to retrieve user profile': '无法获取用户信息',
'Basic': '基本', 'Basic': '基本',
'Security': '安全', 'Security': '安全',
'Basic Settings': '基本设置', 'Basic Settings': '基本设置',
'Security Settings': '安全设置', 'Security Settings': '安全设置',
'Two-Factor Authentication Settings': '两步验证设置', 'Two-Factor Authentication Settings': '两步验证设置',
'(Verified)': '(已验证)', '(Verified)': '(已验证)',
'(Unverified)': '(未验证)', '(Not Verified)': '(未验证)',
'Email has been verified': '邮箱地址已验证', 'Email address is verified': '邮箱地址已验证',
'Email has not been verified': '邮箱地址未验证', 'Email address is not verified': '邮箱地址未验证',
'Username:': '用户名:', 'Username:': '用户名:',
'Current Password': '当前密码', 'Current Password': '当前密码',
'New Password': '新密码', 'New Password': '新密码',
@@ -1088,9 +1085,9 @@ export default {
'Nothing has been modified': '没有修改的项目', 'Nothing has been modified': '没有修改的项目',
'Your profile has been successfully updated': '您的用户信息更新成功', 'Your profile has been successfully updated': '您的用户信息更新成功',
'Unable to update user profile': '无法更新用户信息', 'Unable to update user profile': '无法更新用户信息',
'After the password is changed, other devices will be logged out, please log in again on other devices by using the new password.': '密码修改后,其他设备将会退出登录,请使用新密码在其他设备上重新登录。', 'After changing the password, other devices will be logged out. Please use the new password to log in on other devices.': '密码修改后,其他设备将会退出登录,请使用新密码在其他设备上重新登录。',
'Data Management': '数据管理', 'Data Management': '数据管理',
'Unable to get user statistics data': '无法获取用户统计数据', 'Unable to retrieve user statistics data': '无法获取用户统计数据',
'Export Data': '导出数据', 'Export Data': '导出数据',
'CSV (Comma-separated values) File': 'CSV (逗号分隔的值) 文件', 'CSV (Comma-separated values) File': 'CSV (逗号分隔的值) 文件',
'TSV (Tab-separated values) File': 'TSV (制表符分隔的值) 文件', 'TSV (Tab-separated values) File': 'TSV (制表符分隔的值) 文件',
@@ -1098,17 +1095,17 @@ export default {
'Export all transaction data to file.': '导出所有交易数据到文件。', 'Export all transaction data to file.': '导出所有交易数据到文件。',
'Are you sure you want to export all transaction data to file?': '您确定要导出所有交易数据到文件?', 'Are you sure you want to export all transaction data to file?': '您确定要导出所有交易数据到文件?',
'It may take a long time, please wait for a few minutes.': '这可能花费一些时间,请稍等几分钟。', 'It may take a long time, please wait for a few minutes.': '这可能花费一些时间,请稍等几分钟。',
'Unable to get exported user data': '无法获取导出的用户数据', 'Unable to retrieve exported user data': '无法获取导出的用户数据',
'Save Data': '保存数据', 'Save Data': '保存数据',
'Are you sure you want to clear all data?': '您确定要清除所有数据?', 'Are you sure you want to clear all data?': '您确定要清除所有数据?',
'You CANNOT undo this action. This will clear your accounts, categories, tags and transactions data. Please input your current password to confirm.': '您不能撤销该操作。该操作将会清除您的账户、分类、标签以及交易数据。请输入您当前的密码以确认。', 'You CANNOT undo this action. This will clear your accounts, categories, tags and transactions data. Please enter your current password to confirm.': '您不能撤销该操作。该操作将会清除您的账户、分类、标签以及交易数据。请输入您当前的密码以确认。',
'All user data has been cleared': '用户所有数据已经清空', 'All user data has been cleared': '用户所有数据已经清空',
'Unable to clear user data': '无法清除用户数据', 'Unable to clear user data': '无法清除用户数据',
'Device & Sessions': '设备和会话', 'Device & Sessions': '设备和会话',
'Device Info': '设备信息', 'Device Info': '设备信息',
'Last Activity Time': '最后活跃时间', 'Last Activity Time': '最后活跃时间',
'Logout All': '注销全部', 'Logout All': '注销全部',
'Unable to get session list': '无法获取会话列表', 'Unable to retrieve session list': '无法获取会话列表',
'Session list is up to date': '会话列表已是最新', 'Session list is up to date': '会话列表已是最新',
'Session list has been updated': '会话列表已更新', 'Session list has been updated': '会话列表已更新',
'Current': '当前', 'Current': '当前',
@@ -1131,7 +1128,7 @@ export default {
'No available category': '没有可用的分类', 'No available category': '没有可用的分类',
'Add Default Categories': '添加默认分类', 'Add Default Categories': '添加默认分类',
'Default Categories': '默认分类', 'Default Categories': '默认分类',
'Unable to get category list': '无法获取分类列表', 'Unable to retrieve category list': '无法获取分类列表',
'Category list is up to date': '分类列表已是最新', 'Category list is up to date': '分类列表已是最新',
'Category list has been updated': '分类列表已更新', 'Category list has been updated': '分类列表已更新',
'Unable to move category': '无法移动分类', 'Unable to move category': '无法移动分类',
@@ -1147,20 +1144,20 @@ export default {
'Category Icon': '分类图标', 'Category Icon': '分类图标',
'Category Color': '分类颜色', 'Category Color': '分类颜色',
'Your category description (optional)': '你的分类描述 (可选)', 'Your category description (optional)': '你的分类描述 (可选)',
'Category name cannot be empty': '分类名称不能为空', 'Category name cannot be blank': '分类名称不能为空',
'Unable to get category': '无法获取分类', 'Unable to retrieve category': '无法获取分类',
'Unable to add category': '无法添加分类', 'Unable to add category': '无法添加分类',
'Unable to save category': '无法保存分类', 'Unable to save category': '无法保存分类',
'Unable to add preset categories': '无法添加预设分类', 'Unable to add preset categories': '无法添加预设分类',
'You have added a new category': '您已经添加新分类', 'You have added a new category': '您已经添加新分类',
'You have added preset categories': '您已经添加预设分类', 'You have added preset categories': '您已经添加预设分类',
'You have saved this category': '您已经保存该分类', 'You have saved this category': '您已经保存该分类',
'Show Hidden Transaction Category': '显示隐藏的交易分类', 'Show Hidden Transaction Categories': '显示隐藏的交易分类',
'Hide Hidden Transaction Category': '不显示隐藏的交易分类', 'Hide Hidden Transaction Categories': '不显示隐藏的交易分类',
'Transaction Tags': '交易标签', 'Transaction Tags': '交易标签',
'Tag Title': '标签标题', 'Tag Title': '标签标题',
'No available tag': '没有可用的标签', 'No available tag': '没有可用的标签',
'Unable to get tag list': '无法获取标签列表', 'Unable to retrieve tag list': '无法获取标签列表',
'Tag list is up to date': '标签列表已是最新', 'Tag list is up to date': '标签列表已是最新',
'Tag list has been updated': '标签列表已更新', 'Tag list has been updated': '标签列表已更新',
'Unable to add tag': '无法添加标签', 'Unable to add tag': '无法添加标签',
@@ -1170,8 +1167,8 @@ export default {
'Unable to unhide this tag': '无法取消隐藏该标签', 'Unable to unhide this tag': '无法取消隐藏该标签',
'Are you sure you want to delete this tag?': '您确定要删除该标签?', 'Are you sure you want to delete this tag?': '您确定要删除该标签?',
'Unable to delete this tag': '无法删除该标签', 'Unable to delete this tag': '无法删除该标签',
'Show Hidden Transaction Tag': '显示隐藏的交易标签', 'Show Hidden Transaction Tags': '显示隐藏的交易标签',
'Hide Hidden Transaction Tag': '不显示隐藏的交易标签', 'Hide Hidden Transaction Tags': '不显示隐藏的交易标签',
'Are you sure you want to logout from this session?': '您确定要退出该会话?', 'Are you sure you want to logout from this session?': '您确定要退出该会话?',
'Unable to logout from this session': '无法退出该会话', 'Unable to logout from this session': '无法退出该会话',
'Are you sure you want to logout all other sessions?': '您确定要退出其他所有会话?', 'Are you sure you want to logout all other sessions?': '您确定要退出其他所有会话?',
@@ -1180,16 +1177,16 @@ export default {
'Regenerate Backup Codes': '重新生成备用码', 'Regenerate Backup Codes': '重新生成备用码',
'Enable Two-Factor Authentication': '启用两步验证', 'Enable Two-Factor Authentication': '启用两步验证',
'Disable Two-Factor Authentication': '禁用两步验证', 'Disable Two-Factor Authentication': '禁用两步验证',
'Please use two factor authentication app scan the below qrcode and input current passcode': '请使用两步验证应用扫描下方的二维码并输入当前的验证码', 'Please use a two-factor authentication app to scan the qrcode below and enter the current passcode.': '请使用两步验证应用扫描下方的二维码并输入当前的验证码',
'Please enter your current password when disable two factor authentication': '禁用两步验证时需要输入您的当前密码', 'Your current password is required to disable two-factor authentication.': '禁用两步验证时需要输入您的当前密码',
'Please enter your current password when regenerate two factor authentication backup codes. If you regenerate backup codes, the old codes will be invalidated.': '重新生成两步验证备用码时需要输入您的当前密码。如果您重新生成备用码,之前的备用码将失效。', 'Your current password is required to regenerate backup codes for two-factor authentication. If you regenerate backup codes, the previous ones will become invalid.': '重新生成两步验证备用码时需要输入您的当前密码。如果您重新生成备用码,之前的备用码将失效。',
'Please enter your current password when disable two factor authentication or regenerate two factor authentication backup codes. If you regenerate backup codes, the old codes will be invalidated.': '禁用两步验证或重新生成两步验证备用码时需要输入您的当前密码。如果您重新生成备用码,之前的备用码将失效。', 'Your current password is required to disable two-factor authentication or regenerate backup codes for two-factor authentication. If you regenerate backup codes, the previous ones will become invalid.': '禁用两步验证或重新生成两步验证备用码时需要输入您的当前密码。如果您重新生成备用码,之前的备用码将失效。',
'Please copy these backup codes to safe place, the below codes can only be shown once. If these codes were lost, you can regenerate backup codes at any time.': '请将备用码复制到安全的地方,下列备用码只会展示一次。如果这些备用码丢失,您可以随时重新生成备用码。', 'Please copy these backup codes to safe place, the following backup codes will be displayed only once. If these codes were lost, you can regenerate them at any time.': '请将备用码复制到安全的地方,下列备用码只会展示一次。如果这些备用码丢失,您可以随时重新生成。',
'Backup codes copied': '备用码已复制', 'Backup codes copied': '备用码已复制',
'Two factor authentication has been disabled': '两步验证已经禁用', 'Two-factor authentication has been disabled': '两步验证已经禁用',
'Unable to get current two factor authentication status': '无法获取当前两步验证状态', 'Unable to retrieve current two-factor authentication status': '无法获取当前两步验证状态',
'Unable to enable two factor authentication': '无法启用两步验证', 'Unable to enable two-factor authentication': '无法启用两步验证',
'Unable to disable two factor authentication': '无法禁用两步验证', 'Unable to disable two-factor authentication': '无法禁用两步验证',
'Lock Application': '锁定应用', 'Lock Application': '锁定应用',
'Log Out': '退出登录', 'Log Out': '退出登录',
'Are you sure you want to log out?': '您确定要退出登录?', 'Are you sure you want to log out?': '您确定要退出登录?',
@@ -1200,38 +1197,38 @@ export default {
'Enable Application Lock': '启用应用锁', 'Enable Application Lock': '启用应用锁',
'Disable Application Lock': '禁用应用锁', 'Disable Application Lock': '禁用应用锁',
'PIN Code': 'PIN码', 'PIN Code': 'PIN码',
'Unlock By PIN Code': '使用PIN码解锁', 'Unlock with PIN Code': '使用PIN码解锁',
'Unlock By WebAuthn': '使用WebAuthn解锁', 'Unlock with WebAuthn': '使用WebAuthn解锁',
'Please input a new 6-digit PIN code. PIN code would encrypt your local data, so you need input this PIN code when you launch this app. If this PIN code is lost, you should re-login.': '请输入一个新的6位数字PIN码,PIN码会加密你的本地数据,所以您每次打开应用时都需要输入PIN码。如果您忘记了PIN码,您需要重新登录。', 'Please enter a new 6-digit PIN code. The PIN code would encrypt your local data, so you need to enter it every time you open this app. If this PIN code is lost, you will need to log in again.': '请输入一个新的6位数字PIN码,PIN码会加密你的本地数据,所以您每次打开应用时都需要输入PIN码。如果您忘记了PIN码,您需要重新登录。',
'Please enter your current PIN code when disable application lock.': '禁用应用锁时需要输入当前的PIN码。', 'Your current PIN code is required to disable application lock.': '禁用应用锁时需要输入当前的PIN码。',
'You have enabled WebAuthn successfully': '您已经成功开启 WebAuth', 'You have enabled WebAuthn successfully': '您已经成功开启 WebAuth',
'This device does not support WebAuthn': '当前设备不支持 WebAuth', 'WebAuth is not supported on this device': '当前设备不支持 WebAuth',
'Failed to enable WebAuthn': '启用 WebAuthn 失败', 'Failed to enable WebAuthn': '启用 WebAuthn 失败',
'User has canceled authentication': '用户已经取消认证', 'User has canceled authentication': '用户已经取消认证',
'User has canceled or this device does not support WebAuthn': '用户已取消或当前设备不支持 WebAuthn', 'User has canceled or this device does not support WebAuthn': '用户已取消或当前设备不支持 WebAuthn',
'Failed to authenticate by WebAuthn': '使用 WebAuthn 认证失败', 'Failed to authenticate with WebAuthn': '使用 WebAuthn 认证失败',
'WebAuthn is not enabled': 'WebAuthn 没有启用', 'WebAuthn is not enabled': 'WebAuthn 没有启用',
'Are you sure you want to re-login?': '您确定要重新登录?', 'Are you sure you want to re-login?': '您确定要重新登录?',
'Exchange Rates Data': '汇率数据', 'Exchange Rates Data': '汇率数据',
'Base Currency': '基准货币', 'Base Currency': '基准货币',
'Base Amount': '基准金额', 'Base Amount': '基准金额',
'Set As Baseline': '设置为基准', 'Set as Base': '设置为基准',
'Last Updated': '最后更新', 'Last Updated': '最后更新',
'Data source': '数据来源', 'Data source': '数据来源',
'No exchange rates data': '没有汇率数据', 'No exchange rates data': '没有汇率数据',
'There is no exchange rates data for your default currency': '没有您默认货币的汇率数据', 'There is no exchange rates data for your default currency': '没有您默认货币的汇率数据',
'Exchange rates data has been updated': '汇率数据已更新', 'Exchange rates data has been updated': '汇率数据已更新',
'Exchange rates data is up to date': '汇率数据已是最新', 'Exchange rates data is up to date': '汇率数据已是最新',
'Unable to get exchange rates data': '无法获取汇率数据', 'Unable to retrieve exchange rates data': '无法获取汇率数据',
'Use on Mobile Device': '在移动设备使用', 'Use on Mobile Device': '在移动设备使用',
'You can scan the below QR code on your mobile device.': '您可以在您的移动设备上扫描下方二维码。', 'You can scan the QR code below on your mobile device.': '您可以在您的移动设备上扫描下方二维码。',
'Switch to Mobile Version': '切换到移动版', 'Switch to Mobile Version': '切换到移动版',
'Switch to Desktop Version': '切换到桌面版', 'Switch to Desktop Version': '切换到桌面版',
'About': '关于', 'About': '关于',
'Build Time': '编译时间', 'Build Time': '编译时间',
'Official Website': '官方网站', 'Official Website': '官方网站',
'License': '许可协议', 'License': '许可协议',
'An error has occurred': '发生错误', 'An error occurred': '发生错误',
'Parameter Invalid': '参数错误', 'Parameter Invalid': '参数错误',
'Numeric Overflow': '数值溢出', 'Numeric Overflow': '数值溢出',
}; };
+4 -4
View File
@@ -677,7 +677,7 @@ export const useAccountsStore = defineStore('accounts', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result) { if (!data || !data.success || !data.result) {
reject({ message: 'Unable to get account list' }); reject({ message: 'Unable to retrieve account list' });
return; return;
} }
@@ -703,7 +703,7 @@ export const useAccountsStore = defineStore('accounts', {
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to get account list' }); reject({ message: 'Unable to retrieve account list' });
} else { } else {
reject(error); reject(error);
} }
@@ -718,7 +718,7 @@ export const useAccountsStore = defineStore('accounts', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result) { if (!data || !data.success || !data.result) {
reject({ message: 'Unable to get account' }); reject({ message: 'Unable to retrieve account' });
return; return;
} }
@@ -729,7 +729,7 @@ export const useAccountsStore = defineStore('accounts', {
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to get account' }); reject({ message: 'Unable to retrieve account' });
} else { } else {
reject(error); reject(error);
} }
+3 -3
View File
@@ -75,7 +75,7 @@ export const useExchangeRatesStore = defineStore('exchangeRates', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result) { if (!data || !data.success || !data.result) {
reject({ message: 'Unable to get exchange rates data' }); reject({ message: 'Unable to retrieve exchange rates data' });
return; return;
} }
@@ -94,14 +94,14 @@ export const useExchangeRatesStore = defineStore('exchangeRates', {
resolve(data.result); resolve(data.result);
}).catch(error => { }).catch(error => {
logger.error('failed to get latest exchange rates data', error); logger.error('failed to retrieve latest exchange rates data', error);
if (error && error.processed) { if (error && error.processed) {
reject(error); reject(error);
} else if (error.response && error.response.data && error.response.data.errorMessage) { } else if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else { } else {
reject({ message: 'Unable to get exchange rates data' }); reject({ message: 'Unable to retrieve exchange rates data' });
} }
}); });
}); });
+7 -7
View File
@@ -57,7 +57,7 @@ export const useRootStore = defineStore('root', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result || !data.result.token) { if (!data || !data.success || !data.result || !data.result.token) {
reject({ message: 'Unable to login' }); reject({ message: 'Unable to log in' });
return; return;
} }
@@ -93,7 +93,7 @@ export const useRootStore = defineStore('root', {
} else if (error.response && error.response.data && error.response.data.errorMessage) { } else if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else { } else {
reject({ message: 'Unable to login' }); reject({ message: 'Unable to log in' });
} }
}); });
}); });
@@ -115,7 +115,7 @@ export const useRootStore = defineStore('root', {
token: token token: token
}); });
} else { } else {
reject({ message: 'An error has occurred' }); reject({ message: 'An error occurred' });
return; return;
} }
@@ -293,7 +293,7 @@ export const useRootStore = defineStore('root', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result) { if (!data || !data.success || !data.result) {
reject({ message: 'Unable to resend verify email' }); reject({ message: 'Unable to resend validation email' });
return; return;
} }
@@ -306,7 +306,7 @@ export const useRootStore = defineStore('root', {
} else if (error.response && error.response.data && error.response.data.errorMessage) { } else if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else { } else {
reject({ message: 'Unable to resend verify email' }); reject({ message: 'Unable to resend validation email' });
} }
}); });
}); });
@@ -433,7 +433,7 @@ export const useRootStore = defineStore('root', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result) { if (!data || !data.success || !data.result) {
reject({ message: 'Unable to resend verify email' }); reject({ message: 'Unable to resend validation email' });
return; return;
} }
@@ -446,7 +446,7 @@ export const useRootStore = defineStore('root', {
} else if (error.response && error.response.data && error.response.data.errorMessage) { } else if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else { } else {
reject({ message: 'Unable to resend verify email' }); reject({ message: 'Unable to resend validation email' });
} }
}); });
}); });
+2 -2
View File
@@ -264,7 +264,7 @@ export const useOverviewStore = defineStore('overview', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result) { if (!data || !data.success || !data.result) {
reject({ message: 'Unable to get transaction overview' }); reject({ message: 'Unable to retrieve transaction overview' });
return; return;
} }
@@ -291,7 +291,7 @@ export const useOverviewStore = defineStore('overview', {
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to get transaction overview' }); reject({ message: 'Unable to retrieve transaction overview' });
} else { } else {
reject(error); reject(error);
} }
+3 -3
View File
@@ -589,7 +589,7 @@ export const useStatisticsStore = defineStore('statistics', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result) { if (!data || !data.success || !data.result) {
reject({ message: 'Unable to get transaction statistics' }); reject({ message: 'Unable to retrieve transaction statistics' });
return; return;
} }
@@ -606,12 +606,12 @@ export const useStatisticsStore = defineStore('statistics', {
resolve(data.result); resolve(data.result);
}).catch(error => { }).catch(error => {
logger.error('failed to get transaction statistics', error); logger.error('failed to retrieve transaction statistics', error);
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to get transaction statistics' }); reject({ message: 'Unable to retrieve transaction statistics' });
} else { } else {
reject(error); reject(error);
} }
+2 -2
View File
@@ -15,7 +15,7 @@ export const useTokensStore = defineStore('tokens', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result) { if (!data || !data.success || !data.result) {
reject({ message: 'Unable to get session list' }); reject({ message: 'Unable to retrieve session list' });
return; return;
} }
@@ -26,7 +26,7 @@ export const useTokensStore = defineStore('tokens', {
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to get session list' }); reject({ message: 'Unable to retrieve session list' });
} else { } else {
reject(error); reject(error);
} }
+7 -7
View File
@@ -515,7 +515,7 @@ export const useTransactionsStore = defineStore('transactions', {
} }
} }
reject({ message: 'Unable to get transaction list' }); reject({ message: 'Unable to retrieve transaction list' });
return; return;
} }
@@ -552,7 +552,7 @@ export const useTransactionsStore = defineStore('transactions', {
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to get transaction list' }); reject({ message: 'Unable to retrieve transaction list' });
} else { } else {
reject(error); reject(error);
} }
@@ -587,7 +587,7 @@ export const useTransactionsStore = defineStore('transactions', {
self.updateTransactionListInvalidState(true); self.updateTransactionListInvalidState(true);
} }
reject({ message: 'Unable to get transaction list' }); reject({ message: 'Unable to retrieve transaction list' });
return; return;
} }
@@ -620,7 +620,7 @@ export const useTransactionsStore = defineStore('transactions', {
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to get transaction list' }); reject({ message: 'Unable to retrieve transaction list' });
} else { } else {
reject(error); reject(error);
} }
@@ -635,7 +635,7 @@ export const useTransactionsStore = defineStore('transactions', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result) { if (!data || !data.success || !data.result) {
reject({ message: 'Unable to get transaction' }); reject({ message: 'Unable to retrieve transaction' });
return; return;
} }
@@ -646,7 +646,7 @@ export const useTransactionsStore = defineStore('transactions', {
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to get transaction' }); reject({ message: 'Unable to retrieve transaction' });
} else { } else {
reject(error); reject(error);
} }
@@ -681,7 +681,7 @@ export const useTransactionsStore = defineStore('transactions', {
submitTransaction.destinationAccountId = transaction.destinationAccountId; submitTransaction.destinationAccountId = transaction.destinationAccountId;
submitTransaction.destinationAmount = transaction.destinationAmount; submitTransaction.destinationAmount = transaction.destinationAmount;
} else { } else {
return Promise.reject('An error has occurred'); return Promise.reject('An error occurred');
} }
if (isEdit) { if (isEdit) {
+4 -4
View File
@@ -161,7 +161,7 @@ export const useTransactionCategoriesStore = defineStore('transactionCategories'
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result) { if (!data || !data.success || !data.result) {
reject({ message: 'Unable to get category list' }); reject({ message: 'Unable to retrieve category list' });
return; return;
} }
@@ -215,7 +215,7 @@ export const useTransactionCategoriesStore = defineStore('transactionCategories'
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to get category list' }); reject({ message: 'Unable to retrieve category list' });
} else { } else {
reject(error); reject(error);
} }
@@ -230,7 +230,7 @@ export const useTransactionCategoriesStore = defineStore('transactionCategories'
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result) { if (!data || !data.success || !data.result) {
reject({ message: 'Unable to get category' }); reject({ message: 'Unable to retrieve category' });
return; return;
} }
@@ -241,7 +241,7 @@ export const useTransactionCategoriesStore = defineStore('transactionCategories'
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to get category' }); reject({ message: 'Unable to retrieve category' });
} else { } else {
reject(error); reject(error);
} }
+2 -2
View File
@@ -103,7 +103,7 @@ export const useTransactionTagsStore = defineStore('transactionTags', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result) { if (!data || !data.success || !data.result) {
reject({ message: 'Unable to get tag list' }); reject({ message: 'Unable to retrieve tag list' });
return; return;
} }
@@ -129,7 +129,7 @@ export const useTransactionTagsStore = defineStore('transactionTags', {
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to get tag list' }); reject({ message: 'Unable to retrieve tag list' });
} else { } else {
reject(error); reject(error);
} }
+11 -11
View File
@@ -13,18 +13,18 @@ export const useTwoFactorAuthStore = defineStore('twoFactorAuth', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result || !isBoolean(data.result.enable)) { if (!data || !data.success || !data.result || !isBoolean(data.result.enable)) {
reject({ message: 'Unable to get current two factor authentication status' }); reject({ message: 'Unable to retrieve current two-factor authentication status' });
return; return;
} }
resolve(data.result); resolve(data.result);
}).catch(error => { }).catch(error => {
logger.error('failed to get 2fa status', error); logger.error('failed to retrieve 2fa status', error);
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to get current two factor authentication status' }); reject({ message: 'Unable to retrieve current two-factor authentication status' });
} else { } else {
reject(error); reject(error);
} }
@@ -37,7 +37,7 @@ export const useTwoFactorAuthStore = defineStore('twoFactorAuth', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result || !data.result.qrcode || !data.result.secret) { if (!data || !data.success || !data.result || !data.result.qrcode || !data.result.secret) {
reject({ message: 'Unable to enable two factor authentication' }); reject({ message: 'Unable to enable two-factor authentication' });
return; return;
} }
@@ -48,7 +48,7 @@ export const useTwoFactorAuthStore = defineStore('twoFactorAuth', {
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to enable two factor authentication' }); reject({ message: 'Unable to enable two-factor authentication' });
} else { } else {
reject(error); reject(error);
} }
@@ -64,7 +64,7 @@ export const useTwoFactorAuthStore = defineStore('twoFactorAuth', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result || !data.result.token) { if (!data || !data.success || !data.result || !data.result.token) {
reject({ message: 'Unable to enable two factor authentication' }); reject({ message: 'Unable to enable two-factor authentication' });
return; return;
} }
@@ -79,7 +79,7 @@ export const useTwoFactorAuthStore = defineStore('twoFactorAuth', {
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to enable two factor authentication' }); reject({ message: 'Unable to enable two-factor authentication' });
} else { } else {
reject(error); reject(error);
} }
@@ -94,7 +94,7 @@ export const useTwoFactorAuthStore = defineStore('twoFactorAuth', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result) { if (!data || !data.success || !data.result) {
reject({ message: 'Unable to disable two factor authentication' }); reject({ message: 'Unable to disable two-factor authentication' });
return; return;
} }
@@ -105,7 +105,7 @@ export const useTwoFactorAuthStore = defineStore('twoFactorAuth', {
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to disable two factor authentication' }); reject({ message: 'Unable to disable two-factor authentication' });
} else { } else {
reject(error); reject(error);
} }
@@ -120,7 +120,7 @@ export const useTwoFactorAuthStore = defineStore('twoFactorAuth', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result || !data.result.recoveryCodes || !data.result.recoveryCodes.length) { if (!data || !data.success || !data.result || !data.result.recoveryCodes || !data.result.recoveryCodes.length) {
reject({ message: 'Unable to regenerate two factor authentication backup codes' }); reject({ message: 'Unable to regenerate two-factor authentication backup codes' });
return; return;
} }
@@ -131,7 +131,7 @@ export const useTwoFactorAuthStore = defineStore('twoFactorAuth', {
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to regenerate two factor authentication backup codes' }); reject({ message: 'Unable to regenerate two-factor authentication backup codes' });
} else { } else {
reject(error); reject(error);
} }
+10 -10
View File
@@ -89,18 +89,18 @@ export const useUserStore = defineStore('user', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result) { if (!data || !data.success || !data.result) {
reject({ message: 'Unable to get user profile' }); reject({ message: 'Unable to retrieve user profile' });
return; return;
} }
resolve(data.result); resolve(data.result);
}).catch(error => { }).catch(error => {
logger.error('failed to get user profile', error); logger.error('failed to retrieve user profile', error);
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to get user profile' }); reject({ message: 'Unable to retrieve user profile' });
} else { } else {
reject(error); reject(error);
} }
@@ -113,18 +113,18 @@ export const useUserStore = defineStore('user', {
const data = response.data; const data = response.data;
if (!data || !data.success || !data.result) { if (!data || !data.success || !data.result) {
reject({ message: 'Unable to get user statistics data' }); reject({ message: 'Unable to retrieve user statistics data' });
return; return;
} }
resolve(data.result); resolve(data.result);
}).catch(error => { }).catch(error => {
logger.error('failed to get user statistics data', error); logger.error('failed to retrieve user statistics data', error);
if (error.response && error.response.data && error.response.data.errorMessage) { if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data }); reject({ error: error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to get user statistics data' }); reject({ message: 'Unable to retrieve user statistics data' });
} else { } else {
reject(error); reject(error);
} }
@@ -136,10 +136,10 @@ export const useUserStore = defineStore('user', {
services.getExportedUserData(fileType).then(response => { services.getExportedUserData(fileType).then(response => {
if (response && response.headers) { if (response && response.headers) {
if (fileType === 'csv' && response.headers['content-type'] !== 'text/csv') { if (fileType === 'csv' && response.headers['content-type'] !== 'text/csv') {
reject({ message: 'Unable to get exported user data' }); reject({ message: 'Unable to retrieve exported user data' });
return; return;
} else if (fileType === 'tsv' && response.headers['content-type'] !== 'text/tab-separated-values') { } else if (fileType === 'tsv' && response.headers['content-type'] !== 'text/tab-separated-values') {
reject({ message: 'Unable to get exported user data' }); reject({ message: 'Unable to retrieve exported user data' });
return; return;
} }
} }
@@ -147,12 +147,12 @@ export const useUserStore = defineStore('user', {
const blob = new Blob([response.data], { type: response.headers['content-type'] }); const blob = new Blob([response.data], { type: response.headers['content-type'] });
resolve(blob); resolve(blob);
}).catch(error => { }).catch(error => {
logger.error('failed to get user statistics data', error); logger.error('failed to retrieve user statistics data', error);
if (error.response && error.response.headers['content-type'] === 'text/text' && error.response && error.response.data) { if (error.response && error.response.headers['content-type'] === 'text/text' && error.response && error.response.data) {
reject({ message: 'error.' + error.response.data }); reject({ message: 'error.' + error.response.data });
} else if (!error.processed) { } else if (!error.processed) {
reject({ message: 'Unable to get exported user data' }); reject({ message: 'Unable to retrieve exported user data' });
} else { } else {
reject(error); reject(error);
} }
+1 -1
View File
@@ -112,7 +112,7 @@
:class="{ 'd-none': loading, 'hover-display': !loading }" :class="{ 'd-none': loading, 'hover-display': !loading }"
v-if="exchangeRate.currencyCode !== baseCurrency" v-if="exchangeRate.currencyCode !== baseCurrency"
@click="setAsBaseline(exchangeRate.currencyCode, getConvertedAmount(exchangeRate))"> @click="setAsBaseline(exchangeRate.currencyCode, getConvertedAmount(exchangeRate))">
{{ $t('Set As Baseline') }} {{ $t('Set as Base') }}
</v-btn> </v-btn>
<span>{{ getDisplayConvertedAmount(exchangeRate, isEnableThousandsSeparator) }}</span> <span>{{ getDisplayConvertedAmount(exchangeRate, isEnableThousandsSeparator) }}</span>
</div> </div>
+3 -3
View File
@@ -23,7 +23,7 @@
<v-card variant="flat" class="w-100 mt-0 px-4 pt-12" max-width="500"> <v-card variant="flat" class="w-100 mt-0 px-4 pt-12" max-width="500">
<v-card-text> <v-card-text>
<h4 class="text-h4 mb-2">{{ $t('Forget Password?') }}</h4> <h4 class="text-h4 mb-2">{{ $t('Forget Password?') }}</h4>
<p class="mb-0">{{ $t('Please input your email address used for registration and we\'ll send you an email with reset password link') }}</p> <p class="mb-0">{{ $t('Please enter your email address used for registration and we\'ll send you an email with a reset password link') }}</p>
</v-card-text> </v-card-text>
<v-card-text class="pb-0 mb-6"> <v-card-text class="pb-0 mb-6">
@@ -54,7 +54,7 @@
<router-link class="d-flex align-center justify-center" to="/login" <router-link class="d-flex align-center justify-center" to="/login"
:class="{ 'disabled': requesting }"> :class="{ 'disabled': requesting }">
<v-icon :icon="icons.left"/> <v-icon :icon="icons.left"/>
<span>{{ $t('Back to log in') }}</span> <span>{{ $t('Back to login page') }}</span>
</router-link> </router-link>
</v-col> </v-col>
</v-row> </v-row>
@@ -159,7 +159,7 @@ export default {
const self = this; const self = this;
if (!self.email) { if (!self.email) {
self.$refs.snackbar.showMessage('Email address cannot be empty'); self.$refs.snackbar.showMessage('Email address cannot be blank');
return; return;
} }
+4 -4
View File
@@ -265,12 +265,12 @@ export default {
const self = this; const self = this;
if (!self.username) { if (!self.username) {
self.$refs.snackbar.showMessage('Username cannot be empty'); self.$refs.snackbar.showMessage('Username cannot be blank');
return; return;
} }
if (!self.password) { if (!self.password) {
self.$refs.snackbar.showMessage('Password cannot be empty'); self.$refs.snackbar.showMessage('Password cannot be blank');
return; return;
} }
@@ -337,10 +337,10 @@ export default {
} }
if (self.twoFAVerifyType === 'passcode' && !self.passcode) { if (self.twoFAVerifyType === 'passcode' && !self.passcode) {
self.$refs.snackbar.showMessage('Passcode cannot be empty'); self.$refs.snackbar.showMessage('Passcode cannot be blank');
return; return;
} else if (self.twoFAVerifyType === 'backupcode' && !self.backupCode) { } else if (self.twoFAVerifyType === 'backupcode' && !self.backupCode) {
self.$refs.snackbar.showMessage('Backup code cannot be empty'); self.$refs.snackbar.showMessage('Backup code cannot be blank');
return; return;
} }
+7 -7
View File
@@ -23,7 +23,7 @@
<v-card variant="flat" class="w-100 mt-0 px-4 pt-12" max-width="500"> <v-card variant="flat" class="w-100 mt-0 px-4 pt-12" max-width="500">
<v-card-text> <v-card-text>
<h4 class="text-h4 mb-2">{{ $t('Reset Password') }}</h4> <h4 class="text-h4 mb-2">{{ $t('Reset Password') }}</h4>
<p class="mb-0">{{ $t('Please input your email address again, and input the new password.') }}</p> <p class="mb-0">{{ $t('Please enter your email address again, and input the new password.') }}</p>
</v-card-text> </v-card-text>
<v-card-text class="pb-0 mb-6"> <v-card-text class="pb-0 mb-6">
@@ -65,7 +65,7 @@
ref="confirmPasswordInput" ref="confirmPasswordInput"
:type="isConfirmPasswordVisible ? 'text' : 'password'" :type="isConfirmPasswordVisible ? 'text' : 'password'"
:disabled="updating" :disabled="updating"
:label="$t('Confirmation Password')" :label="$t('Confirm Password')"
:placeholder="$t('Re-enter the password')" :placeholder="$t('Re-enter the password')"
:append-inner-icon="isConfirmPasswordVisible ? icons.eyeSlash : icons.eye" :append-inner-icon="isConfirmPasswordVisible ? icons.eyeSlash : icons.eye"
v-model="confirmPassword" v-model="confirmPassword"
@@ -85,7 +85,7 @@
<router-link class="d-flex align-center justify-center" to="/login" <router-link class="d-flex align-center justify-center" to="/login"
:class="{ 'disabled': updating }"> :class="{ 'disabled': updating }">
<v-icon :icon="icons.left"/> <v-icon :icon="icons.left"/>
<span>{{ $t('Back to log in') }}</span> <span>{{ $t('Back to login page') }}</span>
</router-link> </router-link>
</v-col> </v-col>
</v-row> </v-row>
@@ -176,15 +176,15 @@ export default {
...mapStores(useRootStore, useSettingsStore), ...mapStores(useRootStore, useSettingsStore),
inputProblemMessage() { inputProblemMessage() {
if (!this.email) { if (!this.email) {
return 'Email address cannot be empty'; return 'Email address cannot be blank';
} else if (!this.newPassword && !this.confirmPassword) { } else if (!this.newPassword && !this.confirmPassword) {
return 'Nothing has been modified'; return 'Nothing has been modified';
} else if (!this.newPassword && this.confirmPassword) { } else if (!this.newPassword && this.confirmPassword) {
return 'New password cannot be empty'; return 'New password cannot be blank';
} else if (this.newPassword && !this.confirmPassword) { } else if (this.newPassword && !this.confirmPassword) {
return 'Confirmation password cannot be empty'; return 'Password confirmation cannot be blank';
} else if (this.newPassword && this.confirmPassword && this.newPassword !== this.confirmPassword) { } else if (this.newPassword && this.confirmPassword && this.newPassword !== this.confirmPassword) {
return 'Password and confirmation password do not match'; return 'Password and password confirmation do not match';
} else { } else {
return null; return null;
} }
+14 -14
View File
@@ -87,7 +87,7 @@
autocomplete="new-password" autocomplete="new-password"
clearable clearable
:disabled="submitting || navigateToHomePage" :disabled="submitting || navigateToHomePage"
:label="$t('Confirmation Password')" :label="$t('Confirm Password')"
:placeholder="$t('Re-enter the password')" :placeholder="$t('Re-enter the password')"
:type="isConfirmPasswordVisible ? 'text' : 'password'" :type="isConfirmPasswordVisible ? 'text' : 'password'"
:append-inner-icon="isConfirmPasswordVisible ? icons.eyeSlash : icons.eye" :append-inner-icon="isConfirmPasswordVisible ? icons.eyeSlash : icons.eye"
@@ -146,7 +146,7 @@
<v-window-item value="presetCategories" class="signup-preset-categories"> <v-window-item value="presetCategories" class="signup-preset-categories">
<h4 class="text-h4 mb-1">{{ $t('Preset Categories') }}</h4> <h4 class="text-h4 mb-1">{{ $t('Preset Categories') }}</h4>
<p class="text-sm mt-2 mb-5">{{ $t('Set Whether You Use The Preset Transaction Categories') }}</p> <p class="text-sm mt-2 mb-5">{{ $t('Set whether to use preset transaction categories') }}</p>
<v-row> <v-row>
<v-col cols="12" sm="6"> <v-col cols="12" sm="6">
@@ -207,7 +207,7 @@
</v-window-item> </v-window-item>
<v-window-item value="finalResult" v-if="finalResultMessage"> <v-window-item value="finalResult" v-if="finalResultMessage">
<h4 class="text-h4 mb-1">{{ $t('Registration Complete') }}</h4> <h4 class="text-h4 mb-1">{{ $t('Registration Completed') }}</h4>
<p class="my-5">{{ finalResultMessage }}</p> <p class="my-5">{{ finalResultMessage }}</p>
</v-window-item> </v-window-item>
</v-form> </v-form>
@@ -357,7 +357,7 @@ export default {
allSteps.push({ allSteps.push({
name: 'finalResult', name: 'finalResult',
title: this.$t('Complete'), title: this.$t('Complete'),
subTitle: this.$t('Registration Complete') subTitle: this.$t('Registration Completed')
}); });
} }
@@ -371,24 +371,24 @@ export default {
}, },
inputEmptyProblemMessage() { inputEmptyProblemMessage() {
if (!this.user.username) { if (!this.user.username) {
return 'Username cannot be empty'; return 'Username cannot be blank';
} else if (!this.user.nickname) { } else if (!this.user.nickname) {
return 'Nickname cannot be empty'; return 'Nickname cannot be blank';
} else if (!this.user.email) { } else if (!this.user.email) {
return 'Email address cannot be empty'; return 'Email address cannot be blank';
} else if (!this.user.password) { } else if (!this.user.password) {
return 'Password cannot be empty'; return 'Password cannot be blank';
} else if (!this.user.confirmPassword) { } else if (!this.user.confirmPassword) {
return 'Confirmation password cannot be empty'; return 'Password confirmation cannot be blank';
} else if (!this.user.defaultCurrency) { } else if (!this.user.defaultCurrency) {
return 'Default currency cannot be empty'; return 'Default currency cannot be blank';
} else { } else {
return null; return null;
} }
}, },
inputInvalidProblemMessage() { inputInvalidProblemMessage() {
if (this.user.password && this.user.confirmPassword && this.user.password !== this.user.confirmPassword) { if (this.user.password && this.user.confirmPassword && this.user.password !== this.user.confirmPassword) {
return 'Password and confirmation password do not match'; return 'Password and password confirmation do not match';
} else { } else {
return null; return null;
} }
@@ -453,10 +453,10 @@ export default {
self.submitting = false; self.submitting = false;
if (self.usePresetCategories && !response.presetCategoriesSaved) { if (self.usePresetCategories && !response.presetCategoriesSaved) {
self.finalResultMessage = self.$t('You have been successfully registered, but something wrong with adding preset categories. You can re-add preset categories in settings page anytime.'); self.finalResultMessage = self.$t('You have been successfully registered, but there was an failure when adding preset categories. You can re-add preset categories in settings page anytime.');
self.currentStep = 'finalResult'; self.currentStep = 'finalResult';
} else if (response.needVerifyEmail) { } else if (response.needVerifyEmail) {
self.finalResultMessage = self.$t('You have been successfully registered. Account activation link has been sent to your email address, please activate your account first.'); self.finalResultMessage = self.$t('You have been successfully registered. An account activation link has been sent to your email address, please activate your account first.');
self.currentStep = 'finalResult'; self.currentStep = 'finalResult';
} else { } else {
self.$refs.snackbar.showMessage('You have been successfully registered'); self.$refs.snackbar.showMessage('You have been successfully registered');
@@ -478,7 +478,7 @@ export default {
self.submitting = false; self.submitting = false;
if (self.usePresetCategories && !response.presetCategoriesSaved) { if (self.usePresetCategories && !response.presetCategoriesSaved) {
self.$refs.snackbar.showMessage('You have been successfully registered, but something wrong with adding preset categories. You can re-add preset categories in settings page anytime.'); self.$refs.snackbar.showMessage('You have been successfully registered, but there was an failure when adding preset categories. You can re-add preset categories in settings page anytime.');
} else { } else {
self.$refs.snackbar.showMessage('You have been successfully registered'); self.$refs.snackbar.showMessage('You have been successfully registered');
self.$router.replace('/'); self.$router.replace('/');
+10 -10
View File
@@ -23,8 +23,8 @@
<v-card variant="flat" class="w-100 mt-0 px-4 pt-12" max-width="500"> <v-card variant="flat" class="w-100 mt-0 px-4 pt-12" max-width="500">
<v-card-text> <v-card-text>
<h4 class="text-h4 mb-2">{{ $t('Unlock Application') }}</h4> <h4 class="text-h4 mb-2">{{ $t('Unlock Application') }}</h4>
<p class="mb-0" v-if="isWebAuthnAvailable">{{ $t('Please input your PIN code or use WebAuthn to unlock application') }}</p> <p class="mb-0" v-if="isWebAuthnAvailable">{{ $t('Please enter your PIN code or use WebAuthn to unlock application') }}</p>
<p class="mb-0" v-else-if="!isWebAuthnAvailable">{{ $t('Please input your PIN code to unlock application') }}</p> <p class="mb-0" v-else-if="!isWebAuthnAvailable">{{ $t('Please enter your PIN code to unlock application') }}</p>
</v-card-text> </v-card-text>
<v-card-text class="pb-0 mb-6"> <v-card-text class="pb-0 mb-6">
@@ -39,14 +39,14 @@
<v-col cols="12"> <v-col cols="12">
<v-btn block :disabled="!isPinCodeValid(pinCode) || verifyingByWebAuthn" <v-btn block :disabled="!isPinCodeValid(pinCode) || verifyingByWebAuthn"
@click="unlockByPin(pinCode)"> @click="unlockByPin(pinCode)">
{{ $t('Unlock By PIN Code') }} {{ $t('Unlock with PIN Code') }}
</v-btn> </v-btn>
</v-col> </v-col>
<v-col cols="12" v-if="isWebAuthnAvailable"> <v-col cols="12" v-if="isWebAuthnAvailable">
<v-btn block variant="tonal" :disabled="verifyingByWebAuthn" <v-btn block variant="tonal" :disabled="verifyingByWebAuthn"
@click="unlockByWebAuthn"> @click="unlockByWebAuthn">
{{ $t('Unlock By WebAuthn') }} {{ $t('Unlock with WebAuthn') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="verifyingByWebAuthn"></v-progress-circular> <v-progress-circular indeterminate size="22" class="ml-2" v-if="verifyingByWebAuthn"></v-progress-circular>
</v-btn> </v-btn>
</v-col> </v-col>
@@ -167,7 +167,7 @@ export default {
} }
if (!webauthn.isSupported()) { if (!webauthn.isSupported()) {
self.$refs.snackbar.showMessage('This device does not support WebAuthn'); self.$refs.snackbar.showMessage('WebAuth is not supported on this device');
return; return;
} }
@@ -197,11 +197,11 @@ export default {
logger.error('failed to use webauthn to verify', error); logger.error('failed to use webauthn to verify', error);
if (error.notSupported) { if (error.notSupported) {
self.$refs.snackbar.showMessage('This device does not support WebAuthn'); self.$refs.snackbar.showMessage('WebAuth is not supported on this device');
} else if (error.name === 'NotAllowedError') { } else if (error.name === 'NotAllowedError') {
self.$refs.snackbar.showMessage('User has canceled authentication'); self.$refs.snackbar.showMessage('User has canceled authentication');
} else if (error.invalid) { } else if (error.invalid) {
self.$refs.snackbar.showMessage('Failed to authenticate by WebAuthn'); self.$refs.snackbar.showMessage('Failed to authenticate with WebAuthn');
} else { } else {
self.$refs.snackbar.showMessage('User has canceled or this device does not support WebAuthn'); self.$refs.snackbar.showMessage('User has canceled or this device does not support WebAuthn');
} }
@@ -217,7 +217,7 @@ export default {
const user = self.userStore.currentUserInfo; const user = self.userStore.currentUserInfo;
if (!user || !user.username) { if (!user || !user.username) {
self.$refs.snackbar.showMessage('An error has occurred'); self.$refs.snackbar.showMessage('An error occurred');
return; return;
} }
@@ -236,8 +236,8 @@ export default {
self.$router.replace('/'); self.$router.replace('/');
} catch (ex) { } catch (ex) {
logger.error('failed to unlock by pin code', ex); logger.error('failed to unlock with pin code', ex);
self.$refs.snackbar.showMessage('PIN code is wrong'); self.$refs.snackbar.showMessage('Incorrect PIN code');
} }
}, },
relogin() { relogin() {
+4 -4
View File
@@ -24,7 +24,7 @@
<v-card-text> <v-card-text>
<h4 class="text-h4 mb-2">{{ $t('Verify your email') }}</h4> <h4 class="text-h4 mb-2">{{ $t('Verify your email') }}</h4>
<p class="mb-0" v-if="token && loading">{{ $t('Verifying...') }}</p> <p class="mb-0" v-if="token && loading">{{ $t('Verifying...') }}</p>
<p class="mb-0" v-if="token && verified">{{ $t('Email has been verified') }}</p> <p class="mb-0" v-if="token && verified">{{ $t('Email address is verified') }}</p>
<p class="mb-0" v-if="token && !verified && errorMessage">{{ errorMessage }}</p> <p class="mb-0" v-if="token && !verified && errorMessage">{{ errorMessage }}</p>
<p class="mb-0" v-if="!token && !email">{{ $t('Parameter Invalid') }}</p> <p class="mb-0" v-if="!token && !email">{{ $t('Parameter Invalid') }}</p>
<p class="mb-0" v-if="!token && email">{{ $t(hasValidEmailVerifyToken ? 'format.misc.accountActivationAndResendValidationEmailTip' : 'format.misc.resendValidationEmailTip', { email: email }) }}</p> <p class="mb-0" v-if="!token && email">{{ $t(hasValidEmailVerifyToken ? 'format.misc.accountActivationAndResendValidationEmailTip' : 'format.misc.resendValidationEmailTip', { email: email }) }}</p>
@@ -59,8 +59,8 @@
<router-link class="d-flex align-center justify-center" :to="verified ? '/' : '/login'" <router-link class="d-flex align-center justify-center" :to="verified ? '/' : '/login'"
:class="{ 'disabled': loading || resending }"> :class="{ 'disabled': loading || resending }">
<v-icon :icon="icons.left"/> <v-icon :icon="icons.left"/>
<span v-if="!verified">{{ $t('Back to log in') }}</span> <span v-if="!verified">{{ $t('Back to login page') }}</span>
<span v-else-if="verified">{{ $t('Back to home') }}</span> <span v-else-if="verified">{{ $t('Back to home page') }}</span>
</router-link> </router-link>
</v-col> </v-col>
</v-row> </v-row>
@@ -194,7 +194,7 @@ export default {
}).then(() => { }).then(() => {
self.loading = false; self.loading = false;
self.verified = true; self.verified = true;
self.$refs.snackbar.showMessage('Email has been verified'); self.$refs.snackbar.showMessage('Email address is verified');
}).catch(error => { }).catch(error => {
self.loading = false; self.loading = false;
self.verified = false; self.verified = false;
+3 -3
View File
@@ -75,10 +75,10 @@
<v-menu activator="parent"> <v-menu activator="parent">
<v-list> <v-list>
<v-list-item :prepend-icon="icons.show" <v-list-item :prepend-icon="icons.show"
:title="$t('Show Hidden Account')" :title="$t('Show Hidden Accounts')"
v-if="!showHidden" @click="showHidden = true"></v-list-item> v-if="!showHidden" @click="showHidden = true"></v-list-item>
<v-list-item :prepend-icon="icons.hide" <v-list-item :prepend-icon="icons.hide"
:title="$t('Hide Hidden Account')" :title="$t('Hide Hidden Accounts')"
v-if="showHidden" @click="showHidden = false"></v-list-item> v-if="showHidden" @click="showHidden = false"></v-list-item>
</v-list> </v-list>
</v-menu> </v-menu>
@@ -165,7 +165,7 @@
<span class="align-self-center"> <span class="align-self-center">
<v-icon :class="!loading && activeAccountCategoryVisibleAccountCount > 1 ? 'drag-handle' : 'disabled'" <v-icon :class="!loading && activeAccountCategoryVisibleAccountCount > 1 ? 'drag-handle' : 'disabled'"
:icon="icons.drag"/> :icon="icons.drag"/>
<v-tooltip activator="parent" v-if="!loading && activeAccountCategoryVisibleAccountCount > 1">{{ $t('Drag and Drop to Change Order') }}</v-tooltip> <v-tooltip activator="parent" v-if="!loading && activeAccountCategoryVisibleAccountCount > 1">{{ $t('Drag to Reorder') }}</v-tooltip>
</span> </span>
</div> </div>
@@ -13,7 +13,7 @@
<v-menu activator="parent"> <v-menu activator="parent">
<v-list> <v-list>
<v-list-item :prepend-icon="icons.add" <v-list-item :prepend-icon="icons.add"
:title="$t('Add Sub Account')" :title="$t('Add Sub-account')"
@click="addSubAccount"></v-list-item> @click="addSubAccount"></v-list-item>
</v-list> </v-list>
</v-menu> </v-menu>
@@ -90,22 +90,22 @@
clearable clearable
persistent-placeholder persistent-placeholder
:disabled="loading || submitting" :disabled="loading || submitting"
:label="currentAccountIndex < 0 ? $t('Account Name') : $t('Sub Account Name')" :label="currentAccountIndex < 0 ? $t('Account Name') : $t('Sub-account Name')"
:placeholder="currentAccountIndex < 0 ? $t('Your account name') : $t('Your sub account name')" :placeholder="currentAccountIndex < 0 ? $t('Your account name') : $t('Your sub-account name')"
v-model="selectedAccount.name" v-model="selectedAccount.name"
/> />
</v-col> </v-col>
<v-col cols="12" md="6"> <v-col cols="12" md="6">
<icon-select icon-type="account" <icon-select icon-type="account"
:all-icon-infos="allAccountIcons" :all-icon-infos="allAccountIcons"
:label="currentAccountIndex < 0 ? $t('Account Icon') : $t('Sub Account Icon')" :label="currentAccountIndex < 0 ? $t('Account Icon') : $t('Sub-account Icon')"
:color="selectedAccount.color" :color="selectedAccount.color"
:disabled="loading || submitting" :disabled="loading || submitting"
v-model="selectedAccount.icon" /> v-model="selectedAccount.icon" />
</v-col> </v-col>
<v-col cols="12" md="6"> <v-col cols="12" md="6">
<color-select :all-color-infos="allAccountColors" <color-select :all-color-infos="allAccountColors"
:label="currentAccountIndex < 0 ? $t('Account Color') : $t('Sub Account Color')" :label="currentAccountIndex < 0 ? $t('Account Color') : $t('Sub-account Color')"
:disabled="loading || submitting" :disabled="loading || submitting"
v-model="selectedAccount.color" /> v-model="selectedAccount.color" />
</v-col> </v-col>
@@ -131,8 +131,8 @@
<amount-input :disabled="loading || submitting || !!editAccountId" <amount-input :disabled="loading || submitting || !!editAccountId"
:persistent-placeholder="true" :persistent-placeholder="true"
:currency="selectedAccount.currency" :currency="selectedAccount.currency"
:label="currentAccountIndex < 0 ? $t('Account Balance') : $t('Sub Account Balance')" :label="currentAccountIndex < 0 ? $t('Account Balance') : $t('Sub-account Balance')"
:placeholder="currentAccountIndex < 0 ? $t('Account Balance') : $t('Sub Account Balance')" :placeholder="currentAccountIndex < 0 ? $t('Account Balance') : $t('Sub-account Balance')"
v-model="selectedAccount.balance"/> v-model="selectedAccount.balance"/>
</v-col> </v-col>
<v-col cols="12" md="12"> <v-col cols="12" md="12">
@@ -142,7 +142,7 @@
rows="3" rows="3"
:disabled="loading || submitting" :disabled="loading || submitting"
:label="$t('Description')" :label="$t('Description')"
:placeholder="currentAccountIndex < 0 ? $t('Your account description (optional)') : $t('Your sub account description (optional)')" :placeholder="currentAccountIndex < 0 ? $t('Your account description (optional)') : $t('Your sub-account description (optional)')"
v-model="selectedAccount.comment" v-model="selectedAccount.comment"
/> />
</v-col> </v-col>
@@ -333,7 +333,7 @@ export default {
removeSubAccount(subAccount) { removeSubAccount(subAccount) {
const self = this; const self = this;
self.$refs.confirmDialog.open('Are you sure you want to remove this sub account?').then(() => { self.$refs.confirmDialog.open('Are you sure you want to remove this sub-account?').then(() => {
for (let i = 0; i < self.subAccounts.length; i++) { for (let i = 0; i < self.subAccounts.length; i++) {
if (self.subAccounts[i] === subAccount) { if (self.subAccounts[i] === subAccount) {
self.subAccounts.splice(i, 1); self.subAccounts.splice(i, 1);
@@ -426,13 +426,13 @@ export default {
}, },
getInputEmptyProblemMessage(account, isSubAccount) { getInputEmptyProblemMessage(account, isSubAccount) {
if (!isSubAccount && !account.category) { if (!isSubAccount && !account.category) {
return 'Account category cannot be empty'; return 'Account category cannot be blank';
} else if (!isSubAccount && !account.type) { } else if (!isSubAccount && !account.type) {
return 'Account type cannot be empty'; return 'Account type cannot be blank';
} else if (!account.name) { } else if (!account.name) {
return 'Account name cannot be empty'; return 'Account name cannot be blank';
} else if (account.type === this.allAccountTypes.SingleAccount && !account.currency) { } else if (account.type === this.allAccountTypes.SingleAccount && !account.currency) {
return 'Account currency cannot be empty'; return 'Account currency cannot be blank';
} else { } else {
return null; return null;
} }
@@ -13,19 +13,19 @@
<v-card-text v-if="isEnableApplicationLock"> <v-card-text v-if="isEnableApplicationLock">
<v-switch :disabled="true" <v-switch :disabled="true"
:label="$t('Unlock By PIN Code')" :label="$t('Unlock with PIN Code')"
v-model="isEnableApplicationLock"/> v-model="isEnableApplicationLock"/>
<v-switch class="mt-2" :label="$t('Unlock By WebAuthn')" <v-switch class="mt-2" :label="$t('Unlock with WebAuthn')"
:loading="enablingWebAuthn" :loading="enablingWebAuthn"
v-model="isEnableApplicationLockWebAuthn"/> v-model="isEnableApplicationLockWebAuthn"/>
</v-card-text> </v-card-text>
<v-card-text class="pb-0"> <v-card-text class="pb-0">
<p class="text-body-1 font-weight-semibold" v-if="!isEnableApplicationLock"> <p class="text-body-1 font-weight-semibold" v-if="!isEnableApplicationLock">
{{ $t('Please input a new 6-digit PIN code. PIN code would encrypt your local data, so you need input this PIN code when you launch this app. If this PIN code is lost, you should re-login.') }} {{ $t('Please enter a new 6-digit PIN code. The PIN code would encrypt your local data, so you need to enter it every time you open this app. If this PIN code is lost, you will need to log in again.') }}
</p> </p>
<p class="text-body-1 font-weight-semibold" v-if="isEnableApplicationLock"> <p class="text-body-1 font-weight-semibold" v-if="isEnableApplicationLock">
{{ $t('Please enter your current PIN code when disable application lock.') }} {{ $t('Your current PIN code is required to disable application lock.') }}
</p> </p>
</v-card-text> </v-card-text>
@@ -120,7 +120,7 @@ export default {
self.enablingWebAuthn = false; self.enablingWebAuthn = false;
if (error.notSupported) { if (error.notSupported) {
self.$refs.snackbar.showMessage('This device does not support WebAuthn'); self.$refs.snackbar.showMessage('WebAuth is not supported on this device');
} else if (error.name === 'NotAllowedError') { } else if (error.name === 'NotAllowedError') {
self.$refs.snackbar.showMessage('User has canceled authentication'); self.$refs.snackbar.showMessage('User has canceled authentication');
} else if (error.invalid) { } else if (error.invalid) {
@@ -154,7 +154,7 @@ export default {
if (!this.pinCode || this.pinCode.length !== 6) { if (!this.pinCode || this.pinCode.length !== 6) {
this.pinCode = ''; this.pinCode = '';
this.$refs.snackbar.showMessage('PIN code is invalid'); this.$refs.snackbar.showMessage('Invalid PIN code');
return; return;
} }
@@ -162,7 +162,7 @@ export default {
if (!user || !user.username) { if (!user || !user.username) {
this.pinCode = ''; this.pinCode = '';
this.$refs.snackbar.showMessage('An error has occurred'); this.$refs.snackbar.showMessage('An error occurred');
return; return;
} }
@@ -182,7 +182,7 @@ export default {
if (!this.$user.isCorrectPinCode(this.pinCode)) { if (!this.$user.isCorrectPinCode(this.pinCode)) {
this.pinCode = ''; this.pinCode = '';
this.$refs.snackbar.showMessage('PIN code is wrong'); this.$refs.snackbar.showMessage('Incorrect PIN code');
return; return;
} }
@@ -49,8 +49,8 @@
item-title="displayName" item-title="displayName"
item-value="type" item-value="type"
persistent-placeholder persistent-placeholder
:label="$t('Default Sort By')" :label="$t('Default Sort Order')"
:placeholder="$t('Default Sort By')" :placeholder="$t('Default Sort Order')"
:items="allSortingTypes" :items="allSortingTypes"
v-model="defaultSortingType" v-model="defaultSortingType"
/> />
+3 -3
View File
@@ -60,10 +60,10 @@
<v-menu activator="parent"> <v-menu activator="parent">
<v-list> <v-list>
<v-list-item :prepend-icon="icons.show" <v-list-item :prepend-icon="icons.show"
:title="$t('Show Hidden Transaction Category')" :title="$t('Show Hidden Transaction Categories')"
v-if="!showHidden" @click="showHidden = true"></v-list-item> v-if="!showHidden" @click="showHidden = true"></v-list-item>
<v-list-item :prepend-icon="icons.hide" <v-list-item :prepend-icon="icons.hide"
:title="$t('Hide Hidden Transaction Category')" :title="$t('Hide Hidden Transaction Categories')"
v-if="showHidden" @click="showHidden = false"></v-list-item> v-if="showHidden" @click="showHidden = false"></v-list-item>
</v-list> </v-list>
</v-menu> </v-menu>
@@ -160,7 +160,7 @@
<span class="ml-2"> <span class="ml-2">
<v-icon :class="!loading && !updating && availableCategoryCount > 1 ? 'drag-handle' : 'disabled'" <v-icon :class="!loading && !updating && availableCategoryCount > 1 ? 'drag-handle' : 'disabled'"
:icon="icons.drag"/> :icon="icons.drag"/>
<v-tooltip activator="parent" v-if="!loading && !updating && availableCategoryCount > 1">{{ $t('Drag and Drop to Change Order') }}</v-tooltip> <v-tooltip activator="parent" v-if="!loading && !updating && availableCategoryCount > 1">{{ $t('Drag to Reorder') }}</v-tooltip>
</span> </span>
</div> </div>
</td> </td>
@@ -131,7 +131,7 @@ export default {
}, },
inputEmptyProblemMessage() { inputEmptyProblemMessage() {
if (!this.category.name) { if (!this.category.name) {
return 'Category name cannot be empty'; return 'Category name cannot be blank';
} else { } else {
return null; return null;
} }
@@ -1,7 +1,7 @@
<template> <template>
<v-card :class="{ 'disabled': disabled }"> <v-card :class="{ 'disabled': disabled }">
<template #title> <template #title>
<span>{{ $t('Trend in Income and Expense') }}</span> <span>{{ $t('Income and Expense Trends') }}</span>
</template> </template>
<v-card-text class="overview-monthly-chart-container overview-monthly-chart-overlay" v-if="loading && !hasAnyData"> <v-card-text class="overview-monthly-chart-container overview-monthly-chart-overlay" v-if="loading && !hasAnyData">
@@ -31,7 +31,7 @@
</v-select> </v-select>
</div> </div>
<div class="mx-6 mt-4" v-if="activeTab === 'categoricalAnalysis'"> <div class="mx-6 mt-4" v-if="activeTab === 'categoricalAnalysis'">
<span class="text-subtitle-2">{{ $t('Sort By') }}</span> <span class="text-subtitle-2">{{ $t('Sort Order') }}</span>
<v-select <v-select
item-title="name" item-title="name"
item-value="type" item-value="type"
+3 -3
View File
@@ -26,10 +26,10 @@
<v-menu activator="parent"> <v-menu activator="parent">
<v-list> <v-list>
<v-list-item :prepend-icon="icons.show" <v-list-item :prepend-icon="icons.show"
:title="$t('Show Hidden Transaction Tag')" :title="$t('Show Hidden Transaction Tags')"
v-if="!showHidden" @click="showHidden = true"></v-list-item> v-if="!showHidden" @click="showHidden = true"></v-list-item>
<v-list-item :prepend-icon="icons.hide" <v-list-item :prepend-icon="icons.hide"
:title="$t('Hide Hidden Transaction Tag')" :title="$t('Hide Hidden Transaction Tags')"
v-if="showHidden" @click="showHidden = false"></v-list-item> v-if="showHidden" @click="showHidden = false"></v-list-item>
</v-list> </v-list>
</v-menu> </v-menu>
@@ -154,7 +154,7 @@
<span class="ml-2"> <span class="ml-2">
<v-icon :class="!loading && !updating && availableTagCount > 1 ? 'drag-handle' : 'disabled'" <v-icon :class="!loading && !updating && availableTagCount > 1 ? 'drag-handle' : 'disabled'"
:icon="icons.drag"/> :icon="icons.drag"/>
<v-tooltip activator="parent" v-if="!loading && !updating && availableTagCount > 1">{{ $t('Drag and Drop to Change Order') }}</v-tooltip> <v-tooltip activator="parent" v-if="!loading && !updating && availableTagCount > 1">{{ $t('Drag to Reorder') }}</v-tooltip>
</span> </span>
</div> </div>
</td> </td>
@@ -185,7 +185,7 @@
persistent-placeholder persistent-placeholder
:readonly="mode === 'view'" :readonly="mode === 'view'"
:disabled="loading || submitting" :disabled="loading || submitting"
:label="$t('Timezone')" :label="$t('Transaction Timezone')"
:placeholder="!transaction.timeZone && transaction.timeZone !== '' ? `(${transactionDisplayTimezone}) ${transactionTimezoneTimeDifference}` : $t('Timezone')" :placeholder="!transaction.timeZone && transaction.timeZone !== '' ? `(${transactionDisplayTimezone}) ${transactionTimezoneTimeDifference}` : $t('Timezone')"
:items="allTimezones" :items="allTimezones"
:no-data-text="$t('No results')" :no-data-text="$t('No results')"
@@ -280,7 +280,7 @@
</template> </template>
<template #error-content> <template #error-content>
<p class="text-body-1"> <p class="text-body-1">
{{ $t('Please refresh the page and try again. If the error is still displayed, make sure that server map settings are set correctly.') }} {{ $t('Please refresh the page and try again. If the error persists, ensure that the server\'s map settings are correctly configured.') }}
</p> </p>
</template> </template>
</map-view> </map-view>
@@ -650,7 +650,7 @@ export default {
Promise.all(promises).then(function (responses) { Promise.all(promises).then(function (responses) {
if (self.editTransactionId && !responses[3]) { if (self.editTransactionId && !responses[3]) {
if (self.reject) { if (self.reject) {
self.reject('Unable to get transaction'); self.reject('Unable to retrieve transaction');
} }
return; return;
@@ -723,7 +723,7 @@ export default {
}; };
if (self.transaction.sourceAmount === 0) { if (self.transaction.sourceAmount === 0) {
self.$refs.confirmDialog.open('Are you sure you want to save this transaction whose amount is 0?').then(() => { self.$refs.confirmDialog.open('Are you sure you want to save this transaction with a zero amount?').then(() => {
doSubmit(); doSubmit();
}); });
} else { } else {
@@ -785,7 +785,7 @@ export default {
logger.warn('this browser does not support geo location'); logger.warn('this browser does not support geo location');
if (forceUpdate) { if (forceUpdate) {
self.$refs.snackbar.showMessage('Unable to get current position'); self.$refs.snackbar.showMessage('Unable to retrieve current position');
} }
return; return;
} }
@@ -796,7 +796,7 @@ export default {
self.geoLocationStatus = 'error'; self.geoLocationStatus = 'error';
if (forceUpdate) { if (forceUpdate) {
self.$refs.snackbar.showMessage('Unable to get current position'); self.$refs.snackbar.showMessage('Unable to retrieve current position');
} }
return; return;
@@ -809,11 +809,11 @@ export default {
longitude: position.coords.longitude longitude: position.coords.longitude
}; };
}, function (err) { }, function (err) {
logger.error('cannot get current position', err); logger.error('cannot retrieve current position', err);
self.geoLocationStatus = 'error'; self.geoLocationStatus = 'error';
if (forceUpdate) { if (forceUpdate) {
self.$refs.snackbar.showMessage('Unable to get current position'); self.$refs.snackbar.showMessage('Unable to retrieve current position');
} }
}); });
@@ -25,8 +25,8 @@
<span v-if="!loading">{{ oldProfile.username }}</span> <span v-if="!loading">{{ oldProfile.username }}</span>
</div> </div>
<div class="d-flex text-body-1 align-center" style="height: 40px;"> <div class="d-flex text-body-1 align-center" style="height: 40px;">
<span v-if="!loading && emailVerified">{{ $t('Email has been verified') }}</span> <span v-if="!loading && emailVerified">{{ $t('Email address is verified') }}</span>
<span v-if="!loading && !emailVerified">{{ $t('Email has not been verified') }}</span> <span v-if="!loading && !emailVerified">{{ $t('Email address is not verified') }}</span>
<v-btn class="ml-2 px-2" size="small" variant="text" :disabled="loading || resending" <v-btn class="ml-2 px-2" size="small" variant="text" :disabled="loading || resending"
@click="resendVerifyEmail" v-if="isUserVerifyEmailEnabled && !loading && !emailVerified"> @click="resendVerifyEmail" v-if="isUserVerifyEmailEnabled && !loading && !emailVerified">
{{ $t('Resend Validation Email') }} {{ $t('Resend Validation Email') }}
@@ -81,7 +81,7 @@
:label="$t('Default Account')" :label="$t('Default Account')"
:placeholder="$t('Default Account')" :placeholder="$t('Default Account')"
:items="allCategorizedAccounts" :items="allCategorizedAccounts"
:no-item-text="$t('Not Specified')" :no-item-text="$t('Unspecified')"
v-model="newProfile.defaultAccountId"> v-model="newProfile.defaultAccountId">
</two-column-select> </two-column-select>
</v-col> </v-col>
@@ -92,8 +92,8 @@
item-value="type" item-value="type"
persistent-placeholder persistent-placeholder
:disabled="loading || saving" :disabled="loading || saving"
:label="$t('Editable Transaction Scope')" :label="$t('Editable Transaction Range')"
:placeholder="$t('Editable Transaction Scope')" :placeholder="$t('Editable Transaction Range')"
:items="allTransactionEditScopeTypes" :items="allTransactionEditScopeTypes"
v-model="newProfile.transactionEditScope" v-model="newProfile.transactionEditScope"
/> />
@@ -208,7 +208,7 @@
<v-card-text class="d-flex flex-wrap gap-4"> <v-card-text class="d-flex flex-wrap gap-4">
<v-btn :disabled="inputIsNotChanged || inputIsInvalid || saving" @click="save"> <v-btn :disabled="inputIsNotChanged || inputIsInvalid || saving" @click="save">
{{ $t('Save changes') }} {{ $t('Save Changes') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="saving"></v-progress-circular> <v-progress-circular indeterminate size="22" class="ml-2" v-if="saving"></v-progress-circular>
</v-btn> </v-btn>
@@ -354,11 +354,11 @@ export default {
}, },
inputInvalidProblemMessage() { inputInvalidProblemMessage() {
if (!this.newProfile.email) { if (!this.newProfile.email) {
return 'Email address cannot be empty'; return 'Email address cannot be blank';
} else if (!this.newProfile.nickname) { } else if (!this.newProfile.nickname) {
return 'Nickname cannot be empty'; return 'Nickname cannot be blank';
} else if (!this.newProfile.defaultCurrency) { } else if (!this.newProfile.defaultCurrency) {
return 'Default currency cannot be empty'; return 'Default currency cannot be blank';
} else { } else {
return null; return null;
} }
@@ -368,7 +368,7 @@ export default {
}, },
langAndRegionInputInvalidProblemMessage() { langAndRegionInputInvalidProblemMessage() {
if (!this.newProfile.defaultCurrency) { if (!this.newProfile.defaultCurrency) {
return 'Default currency cannot be empty'; return 'Default currency cannot be blank';
} else { } else {
return null; return null;
} }
@@ -121,7 +121,7 @@
<v-card-text class="py-0"> <v-card-text class="py-0">
<span class="text-body-1 text-error"> <span class="text-body-1 text-error">
<v-icon :icon="icons.alert"/> <v-icon :icon="icons.alert"/>
{{ $t('You CANNOT undo this action. This will clear your accounts, categories, tags and transactions data. Please input your current password to confirm.') }} {{ $t('You CANNOT undo this action. This will clear your accounts, categories, tags and transactions data. Please enter your current password to confirm.') }}
</span> </span>
</v-card-text> </v-card-text>
@@ -277,7 +277,7 @@ export default {
const self = this; const self = this;
if (!self.currentPasswordForClearData) { if (!self.currentPasswordForClearData) {
self.$refs.snackbar.showMessage('Current password cannot be empty'); self.$refs.snackbar.showMessage('Current password cannot be blank');
return; return;
} }
@@ -4,7 +4,7 @@
<v-card :class="{ 'disabled': updatingPassword }" :title="$t('Modify Password')"> <v-card :class="{ 'disabled': updatingPassword }" :title="$t('Modify Password')">
<v-form> <v-form>
<v-card-text class="pt-0"> <v-card-text class="pt-0">
<span class="text-body-1">{{ $t('After the password is changed, other devices will be logged out, please log in again on other devices by using the new password.') }}</span> <span class="text-body-1">{{ $t('After changing the password, other devices will be logged out. Please use the new password to log in on other devices.') }}</span>
</v-card-text> </v-card-text>
<v-card-text> <v-card-text>
@@ -51,7 +51,7 @@
clearable clearable
:disabled="updatingPassword" :disabled="updatingPassword"
:type="isConfirmPasswordVisible ? 'text' : 'password'" :type="isConfirmPasswordVisible ? 'text' : 'password'"
:label="$t('Confirmation Password')" :label="$t('Confirm Password')"
:placeholder="$t('Re-enter the password')" :placeholder="$t('Re-enter the password')"
:append-inner-icon="isConfirmPasswordVisible ? icons.eyeSlash : icons.eye" :append-inner-icon="isConfirmPasswordVisible ? icons.eyeSlash : icons.eye"
v-model="confirmPassword" v-model="confirmPassword"
@@ -64,7 +64,7 @@
<v-card-text class="d-flex flex-wrap gap-4"> <v-card-text class="d-flex flex-wrap gap-4">
<v-btn :disabled="!currentPassword || !newPassword || !confirmPassword || updatingPassword" @click="updatePassword"> <v-btn :disabled="!currentPassword || !newPassword || !confirmPassword || updatingPassword" @click="updatePassword">
{{ $t('Save changes') }} {{ $t('Save Changes') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="updatingPassword"></v-progress-circular> <v-progress-circular indeterminate size="22" class="ml-2" v-if="updatingPassword"></v-progress-circular>
</v-btn> </v-btn>
</v-card-text> </v-card-text>
@@ -181,15 +181,15 @@ export default {
...mapStores(useRootStore, useSettingsStore, useUserStore, useTokensStore), ...mapStores(useRootStore, useSettingsStore, useUserStore, useTokensStore),
inputProblemMessage() { inputProblemMessage() {
if (!this.currentPassword) { if (!this.currentPassword) {
return 'Current password cannot be empty'; return 'Current password cannot be blank';
} else if (!this.newPassword && !this.confirmPassword) { } else if (!this.newPassword && !this.confirmPassword) {
return 'Nothing has been modified'; return 'Nothing has been modified';
} else if (!this.newPassword && this.confirmPassword) { } else if (!this.newPassword && this.confirmPassword) {
return 'New password cannot be empty'; return 'New password cannot be blank';
} else if (this.newPassword && !this.confirmPassword) { } else if (this.newPassword && !this.confirmPassword) {
return 'Confirmation password cannot be empty'; return 'Password confirmation cannot be blank';
} else if (this.newPassword && this.confirmPassword && this.newPassword !== this.confirmPassword) { } else if (this.newPassword && this.confirmPassword && this.newPassword !== this.confirmPassword) {
return 'Password and confirmation password do not match'; return 'Password and password confirmation do not match';
} else { } else {
return null; return null;
} }
@@ -10,13 +10,13 @@
<v-card-text class="pb-0"> <v-card-text class="pb-0">
<v-skeleton-loader class="skeleton-no-margin pt-2 pb-5" type="text" style="width: 150px" :loading="true" v-if="loading"></v-skeleton-loader> <v-skeleton-loader class="skeleton-no-margin pt-2 pb-5" type="text" style="width: 150px" :loading="true" v-if="loading"></v-skeleton-loader>
<p class="text-body-1 font-weight-semibold" v-if="!loading && !new2FAQRCode"> <p class="text-body-1 font-weight-semibold" v-if="!loading && !new2FAQRCode">
{{ status === true ? $t('Two-factor authentication has been enabled.') : $t('Two-factor authentication is not enabled yet.') }} {{ status === true ? $t('Two-factor authentication is already enabled.') : $t('Two-factor authentication is not enabled yet.') }}
</p> </p>
<p class="text-body-1" v-if="!loading && new2FAQRCode"> <p class="text-body-1" v-if="!loading && new2FAQRCode">
{{ $t('Please use two factor authentication app scan the below qrcode and input current passcode') }} {{ $t('Please use a two-factor authentication app to scan the qrcode below and enter the current passcode.') }}
</p> </p>
<p class="text-body-1" v-if="!loading && status === true"> <p class="text-body-1" v-if="!loading && status === true">
{{ $t('Please enter your current password when disable two factor authentication or regenerate two factor authentication backup codes. If you regenerate backup codes, the old codes will be invalidated.') }} {{ $t('Your current password is required to disable two-factor authentication or regenerate backup codes for two-factor authentication. If you regenerate backup codes, the previous ones will become invalid.') }}
</p> </p>
</v-card-text> </v-card-text>
@@ -58,7 +58,7 @@
<v-row> <v-row>
<v-col cols="12" class="d-flex flex-wrap gap-4"> <v-col cols="12" class="d-flex flex-wrap gap-4">
<v-btn :disabled="!currentPassword || loading || disabling " v-if="status === true" @click="disable"> <v-btn :disabled="!currentPassword || loading || disabling " v-if="status === true" @click="disable">
{{ $t('Disable two-factor authentication') }} {{ $t('Disable Two-Factor Authentication') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="disabling"></v-progress-circular> <v-progress-circular indeterminate size="22" class="ml-2" v-if="disabling"></v-progress-circular>
</v-btn> </v-btn>
<v-btn :disabled="!currentPassword || loading || regenerating" v-if="status === true" @click="regenerateBackupCode()"> <v-btn :disabled="!currentPassword || loading || regenerating" v-if="status === true" @click="regenerateBackupCode()">
@@ -66,7 +66,7 @@
<v-progress-circular indeterminate size="22" class="ml-2" v-if="regenerating"></v-progress-circular> <v-progress-circular indeterminate size="22" class="ml-2" v-if="regenerating"></v-progress-circular>
</v-btn> </v-btn>
<v-btn :disabled="loading || enabling" v-if="status === false && !new2FAQRCode" @click="enable"> <v-btn :disabled="loading || enabling" v-if="status === false && !new2FAQRCode" @click="enable">
{{ $t('Enable two-factor authentication') }} {{ $t('Enable Two-Factor Authentication') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="enabling"></v-progress-circular> <v-progress-circular indeterminate size="22" class="ml-2" v-if="enabling"></v-progress-circular>
</v-btn> </v-btn>
<v-btn :disabled="!currentPasscode || loading || enableConfirming" v-if="status === false && new2FAQRCode" @click="enableConfirm"> <v-btn :disabled="!currentPasscode || loading || enableConfirming" v-if="status === false && new2FAQRCode" @click="enableConfirm">
@@ -93,7 +93,7 @@
<v-card-text> <v-card-text>
<p class="text-body-1" v-if="status === true"> <p class="text-body-1" v-if="status === true">
{{ $t('Please copy these backup codes to safe place, the below codes can only be shown once. If these codes were lost, you can regenerate backup codes at any time.') }} {{ $t('Please copy these backup codes to safe place, the following backup codes will be displayed only once. If these codes were lost, you can regenerate them at any time.') }}
</p> </p>
<v-textarea class="backup-code" readonly="readonly" :rows="10" :value="currentBackupCode"/> <v-textarea class="backup-code" readonly="readonly" :rows="10" :value="currentBackupCode"/>
</v-card-text> </v-card-text>
@@ -207,7 +207,7 @@ export default {
const self = this; const self = this;
if (!self.currentPasscode) { if (!self.currentPasscode) {
self.$refs.snackbar.showMessage('Passcode cannot be empty'); self.$refs.snackbar.showMessage('Passcode cannot be blank');
return; return;
} }
@@ -252,7 +252,7 @@ export default {
const self = this; const self = this;
if (!self.currentPassword) { if (!self.currentPassword) {
self.$refs.snackbar.showMessage('Current password cannot be empty'); self.$refs.snackbar.showMessage('Current password cannot be blank');
return; return;
} }
@@ -273,7 +273,7 @@ export default {
self.disabling = false; self.disabling = false;
self.status = false; self.status = false;
self.$refs.snackbar.showMessage('Two factor authentication has been disabled'); self.$refs.snackbar.showMessage('Two-factor authentication has been disabled');
}).catch(error => { }).catch(error => {
self.disabling = false; self.disabling = false;
@@ -286,7 +286,7 @@ export default {
const self = this; const self = this;
if (!self.currentPassword) { if (!self.currentPassword) {
self.$refs.snackbar.showMessage('Current password cannot be empty'); self.$refs.snackbar.showMessage('Current password cannot be blank');
return; return;
} }
+8 -8
View File
@@ -8,11 +8,11 @@
<f7-list strong inset dividers class="margin-top"> <f7-list strong inset dividers class="margin-top">
<f7-list-item :title="$t('Status')" :after="$t(isEnableApplicationLock ? 'Enabled' : 'Disabled')"></f7-list-item> <f7-list-item :title="$t('Status')" :after="$t(isEnableApplicationLock ? 'Enabled' : 'Disabled')"></f7-list-item>
<f7-list-item v-if="isEnableApplicationLock"> <f7-list-item v-if="isEnableApplicationLock">
<span>{{ $t('Unlock By PIN Code') }}</span> <span>{{ $t('Unlock with PIN Code') }}</span>
<f7-toggle checked disabled></f7-toggle> <f7-toggle checked disabled></f7-toggle>
</f7-list-item> </f7-list-item>
<f7-list-item v-if="isEnableApplicationLock && isSupportedWebAuthn"> <f7-list-item v-if="isEnableApplicationLock && isSupportedWebAuthn">
<span>{{ $t('Unlock By WebAuthn') }}</span> <span>{{ $t('Unlock with WebAuthn') }}</span>
<f7-toggle :checked="isEnableApplicationLockWebAuthn" @toggle:change="isEnableApplicationLockWebAuthn = $event"></f7-toggle> <f7-toggle :checked="isEnableApplicationLockWebAuthn" @toggle:change="isEnableApplicationLockWebAuthn = $event"></f7-toggle>
</f7-list-item> </f7-list-item>
<f7-list-button v-if="isEnableApplicationLock" @click="disable(null)">{{ $t('Disable') }}</f7-list-button> <f7-list-button v-if="isEnableApplicationLock" @click="disable(null)">{{ $t('Disable') }}</f7-list-button>
@@ -20,14 +20,14 @@
</f7-list> </f7-list>
<pin-code-input-sheet :title="$t('PIN Code')" <pin-code-input-sheet :title="$t('PIN Code')"
:hint="$t('Please input a new 6-digit PIN code. PIN code would encrypt your local data, so you need input this PIN code when you launch this app. If this PIN code is lost, you should re-login.')" :hint="$t('Please enter a new 6-digit PIN code. The PIN code would encrypt your local data, so you need to enter it every time you open this app. If this PIN code is lost, you will need to log in again.')"
v-model:show="showInputPinCodeSheetForEnable" v-model:show="showInputPinCodeSheetForEnable"
v-model="currentPinCodeForEnable" v-model="currentPinCodeForEnable"
@pincode:confirm="enable"> @pincode:confirm="enable">
</pin-code-input-sheet> </pin-code-input-sheet>
<pin-code-input-sheet :title="$t('PIN Code')" <pin-code-input-sheet :title="$t('PIN Code')"
:hint="$t('Please enter your current PIN code when disable application lock.')" :hint="$t('Your current PIN code is required to disable application lock.')"
v-model:show="showInputPinCodeSheetForDisable" v-model:show="showInputPinCodeSheetForDisable"
v-model="currentPinCodeForDisable" v-model="currentPinCodeForDisable"
@pincode:confirm="disable"> @pincode:confirm="disable">
@@ -94,7 +94,7 @@ export default {
self.$hideLoading(); self.$hideLoading();
if (error.notSupported) { if (error.notSupported) {
self.$toast('This device does not support WebAuthn'); self.$toast('WebAuth is not supported on this device');
} else if (error.name === 'NotAllowedError') { } else if (error.name === 'NotAllowedError') {
self.$toast('User has canceled authentication'); self.$toast('User has canceled authentication');
} else if (error.invalid) { } else if (error.invalid) {
@@ -132,14 +132,14 @@ export default {
} }
if (!this.currentPinCodeForEnable || this.currentPinCodeForEnable.length !== 6) { if (!this.currentPinCodeForEnable || this.currentPinCodeForEnable.length !== 6) {
this.$alert('PIN code is invalid'); this.$alert('Invalid PIN code');
return; return;
} }
const user = this.userStore.currentUserInfo; const user = this.userStore.currentUserInfo;
if (!user || !user.username) { if (!user || !user.username) {
this.$alert('An error has occurred'); this.$alert('An error occurred');
return; return;
} }
@@ -163,7 +163,7 @@ export default {
} }
if (!this.$user.isCorrectPinCode(pinCode)) { if (!this.$user.isCorrectPinCode(pinCode)) {
this.$alert('PIN code is wrong'); this.$alert('Incorrect PIN code');
return; return;
} }
+1 -1
View File
@@ -57,7 +57,7 @@
</div> </div>
</template> </template>
<f7-swipeout-actions right v-if="exchangeRate.currencyCode !== baseCurrency"> <f7-swipeout-actions right v-if="exchangeRate.currencyCode !== baseCurrency">
<f7-swipeout-button color="primary" close :text="$t('Set As Baseline')" @click="setAsBaseline(exchangeRate.currencyCode, getConvertedAmount(exchangeRate))"></f7-swipeout-button> <f7-swipeout-button color="primary" close :text="$t('Set as Base')" @click="setAsBaseline(exchangeRate.currencyCode, getConvertedAmount(exchangeRate))"></f7-swipeout-button>
</f7-swipeout-actions> </f7-swipeout-actions>
</f7-list-item> </f7-list-item>
</f7-list> </f7-list>
+9 -9
View File
@@ -142,7 +142,7 @@
</div> </div>
<div class="padding-horizontal padding-bottom"> <div class="padding-horizontal padding-bottom">
<p class="no-margin"> <p class="no-margin">
<span>{{ $t('Please input your email address used for registration and we\'ll send you an email with reset password link') }}</span> <span>{{ $t('Please enter your email address used for registration and we\'ll send you an email with a reset password link') }}</span>
</p> </p>
<f7-list strong class="no-margin"> <f7-list strong class="no-margin">
<f7-list-input <f7-list-input
@@ -249,9 +249,9 @@ export default {
}, },
twoFAVerifyTypeSwitchName() { twoFAVerifyTypeSwitchName() {
if (this.twoFAVerifyType === 'backupcode') { if (this.twoFAVerifyType === 'backupcode') {
return 'Use a passcode'; return 'Use Passcode';
} else { } else {
return 'Use a backup code'; return 'Use Backup Code';
} }
}, },
currentLanguageCode() { currentLanguageCode() {
@@ -270,12 +270,12 @@ export default {
const router = self.f7router; const router = self.f7router;
if (!this.username) { if (!this.username) {
self.$alert('Username cannot be empty'); self.$alert('Username cannot be blank');
return; return;
} }
if (!this.password) { if (!this.password) {
self.$alert('Password cannot be empty'); self.$alert('Password cannot be blank');
return; return;
} }
@@ -346,10 +346,10 @@ export default {
} }
if (this.twoFAVerifyType === 'passcode' && !this.passcode) { if (this.twoFAVerifyType === 'passcode' && !this.passcode) {
self.$alert('Passcode cannot be empty'); self.$alert('Passcode cannot be blank');
return; return;
} else if (this.twoFAVerifyType === 'backupcode' && !this.backupCode) { } else if (this.twoFAVerifyType === 'backupcode' && !this.backupCode) {
self.$alert('Backup code cannot be empty'); self.$alert('Backup code cannot be blank');
return; return;
} }
@@ -388,7 +388,7 @@ export default {
const self = this; const self = this;
if (!self.forgetPasswordEmail) { if (!self.forgetPasswordEmail) {
self.$alert('Email address cannot be empty'); self.$alert('Email address cannot be blank');
return; return;
} }
@@ -416,7 +416,7 @@ export default {
const self = this; const self = this;
if (!self.currentPasswordForResendVerifyEmail) { if (!self.currentPasswordForResendVerifyEmail) {
self.$toast('Current password cannot be empty'); self.$toast('Current password cannot be blank');
return; return;
} }
+11 -11
View File
@@ -31,7 +31,7 @@
type="password" type="password"
autocomplete="new-password" autocomplete="new-password"
clear-button clear-button
:label="$t('Confirmation Password')" :label="$t('Confirm Password')"
:placeholder="$t('Re-enter the password')" :placeholder="$t('Re-enter the password')"
v-model:value="user.confirmPassword" v-model:value="user.confirmPassword"
></f7-list-input> ></f7-list-input>
@@ -257,24 +257,24 @@ export default {
}, },
inputEmptyProblemMessage() { inputEmptyProblemMessage() {
if (!this.user.username) { if (!this.user.username) {
return 'Username cannot be empty'; return 'Username cannot be blank';
} else if (!this.user.password) { } else if (!this.user.password) {
return 'Password cannot be empty'; return 'Password cannot be blank';
} else if (!this.user.confirmPassword) { } else if (!this.user.confirmPassword) {
return 'Confirmation password cannot be empty'; return 'Password confirmation cannot be blank';
} else if (!this.user.email) { } else if (!this.user.email) {
return 'Email address cannot be empty'; return 'Email address cannot be blank';
} else if (!this.user.nickname) { } else if (!this.user.nickname) {
return 'Nickname cannot be empty'; return 'Nickname cannot be blank';
} else if (!this.user.defaultCurrency) { } else if (!this.user.defaultCurrency) {
return 'Default currency cannot be empty'; return 'Default currency cannot be blank';
} else { } else {
return null; return null;
} }
}, },
inputInvalidProblemMessage() { inputInvalidProblemMessage() {
if (this.user.password && this.user.confirmPassword && this.user.password !== this.user.confirmPassword) { if (this.user.password && this.user.confirmPassword && this.user.password !== this.user.confirmPassword) {
return 'Password and confirmation password do not match'; return 'Password and password confirmation do not match';
} else { } else {
return null; return null;
} }
@@ -310,9 +310,9 @@ export default {
self.$hideLoading(); self.$hideLoading();
if (self.usePresetCategories && !response.presetCategoriesSaved) { if (self.usePresetCategories && !response.presetCategoriesSaved) {
self.$toast('You have been successfully registered, but something wrong with adding preset categories. You can re-add preset categories in settings page anytime.', 5000); self.$toast('You have been successfully registered, but there was an failure when adding preset categories. You can re-add preset categories in settings page anytime.', 5000);
} else if (response.needVerifyEmail) { } else if (response.needVerifyEmail) {
self.$toast('You have been successfully registered. Account activation link has been sent to your email address, please activate your account first.', 5000); self.$toast('You have been successfully registered. An account activation link has been sent to your email address, please activate your account first.', 5000);
} else { } else {
self.$toast('You have been successfully registered'); self.$toast('You have been successfully registered');
} }
@@ -334,7 +334,7 @@ export default {
self.$hideLoading(); self.$hideLoading();
if (self.usePresetCategories && !response.presetCategoriesSaved) { if (self.usePresetCategories && !response.presetCategoriesSaved) {
self.$toast('You have been successfully registered, but something wrong with adding preset categories. You can re-add preset categories in settings page anytime.'); self.$toast('You have been successfully registered, but there was an failure when adding preset categories. You can re-add preset categories in settings page anytime.');
} else { } else {
self.$toast('You have been successfully registered'); self.$toast('You have been successfully registered');
} }
+8 -8
View File
@@ -17,8 +17,8 @@
</f7-list> </f7-list>
<f7-list> <f7-list>
<f7-list-button :class="{ 'disabled': !isPinCodeValid(pinCode) }" :text="$t('Unlock By PIN Code')" @click="unlockByPin"></f7-list-button> <f7-list-button :class="{ 'disabled': !isPinCodeValid(pinCode) }" :text="$t('Unlock with PIN Code')" @click="unlockByPin"></f7-list-button>
<f7-list-button v-if="isWebAuthnAvailable" :text="$t('Unlock By WebAuthn')" @click="unlockByWebAuthn"></f7-list-button> <f7-list-button v-if="isWebAuthnAvailable" :text="$t('Unlock with WebAuthn')" @click="unlockByWebAuthn"></f7-list-button>
<f7-block-footer> <f7-block-footer>
<f7-link :text="$t('Re-login')" @click="relogin"></f7-link> <f7-link :text="$t('Re-login')" @click="relogin"></f7-link>
</f7-block-footer> </f7-block-footer>
@@ -120,7 +120,7 @@ export default {
} }
if (!webauthn.isSupported()) { if (!webauthn.isSupported()) {
self.$toast('This device does not support WebAuthn'); self.$toast('WebAuth is not supported on this device');
return; return;
} }
@@ -150,11 +150,11 @@ export default {
logger.error('failed to use webauthn to verify', error); logger.error('failed to use webauthn to verify', error);
if (error.notSupported) { if (error.notSupported) {
self.$toast('This device does not support WebAuthn'); self.$toast('WebAuth is not supported on this device');
} else if (error.name === 'NotAllowedError') { } else if (error.name === 'NotAllowedError') {
self.$toast('User has canceled authentication'); self.$toast('User has canceled authentication');
} else if (error.invalid) { } else if (error.invalid) {
self.$toast('Failed to authenticate by WebAuthn'); self.$toast('Failed to authenticate with WebAuthn');
} else { } else {
self.$toast('User has canceled or this device does not support WebAuthn'); self.$toast('User has canceled or this device does not support WebAuthn');
} }
@@ -175,7 +175,7 @@ export default {
const user = self.userStore.currentUserInfo; const user = self.userStore.currentUserInfo;
if (!user || !user.username) { if (!user || !user.username) {
self.$alert('An error has occurred'); self.$alert('An error occurred');
return; return;
} }
@@ -194,8 +194,8 @@ export default {
router.refreshPage(); router.refreshPage();
} catch (ex) { } catch (ex) {
logger.error('failed to unlock by pin code', ex); logger.error('failed to unlock with pin code', ex);
self.$toast('PIN code is wrong'); self.$toast('Incorrect PIN code');
} }
}, },
relogin() { relogin() {
+14 -14
View File
@@ -282,7 +282,7 @@
<f7-list-item group-title> <f7-list-item group-title>
<small>{{ $t('Sub Account') + ' #' + (idx + 1) }}</small> <small>{{ $t('Sub Account') + ' #' + (idx + 1) }}</small>
<f7-button rasied fill class="subaccount-delete-button" color="red" icon-f7="trash" icon-size="16px" <f7-button rasied fill class="subaccount-delete-button" color="red" icon-f7="trash" icon-size="16px"
:tooltip="$t('Remove Sub Account')" :tooltip="$t('Remove Sub-account')"
v-if="!editAccountId" v-if="!editAccountId"
@click="removeSubAccount(subAccount, false)"> @click="removeSubAccount(subAccount, false)">
</f7-button> </f7-button>
@@ -291,8 +291,8 @@
<f7-list-input <f7-list-input
type="text" type="text"
clear-button clear-button
:label="$t('Sub Account Name')" :label="$t('Sub-account Name')"
:placeholder="$t('Your sub account name')" :placeholder="$t('Your sub-account name')"
v-model:value="subAccount.name" v-model:value="subAccount.name"
></f7-list-input> ></f7-list-input>
@@ -304,7 +304,7 @@
<div class="item-content"> <div class="item-content">
<div class="item-inner"> <div class="item-inner">
<div class="item-header"> <div class="item-header">
<span>{{ $t('Sub Account Icon') }}</span> <span>{{ $t('Sub-account Icon') }}</span>
</div> </div>
<div class="item-title"> <div class="item-title">
<div class="list-item-custom-title no-padding"> <div class="list-item-custom-title no-padding">
@@ -326,7 +326,7 @@
<div class="item-content"> <div class="item-content">
<div class="item-inner"> <div class="item-inner">
<div class="item-header"> <div class="item-header">
<span>{{ $t('Sub Account Color') }}</span> <span>{{ $t('Sub-account Color') }}</span>
</div> </div>
<div class="item-title"> <div class="item-title">
<div class="list-item-custom-title no-padding"> <div class="list-item-custom-title no-padding">
@@ -370,7 +370,7 @@
link="#" no-chevron link="#" no-chevron
class="list-item-with-header-and-title" class="list-item-with-header-and-title"
:class="{ 'disabled': editAccountId }" :class="{ 'disabled': editAccountId }"
:header="$t('Sub Account Balance')" :header="$t('Sub-account Balance')"
:title="getAccountBalance(subAccount)" :title="getAccountBalance(subAccount)"
@click="subAccount.showBalanceSheet = true" @click="subAccount.showBalanceSheet = true"
> >
@@ -389,7 +389,7 @@
type="textarea" type="textarea"
style="height: auto" style="height: auto"
:label="$t('Description')" :label="$t('Description')"
:placeholder="$t('Your sub account description (optional)')" :placeholder="$t('Your sub-account description (optional)')"
v-textarea-auto-size v-textarea-auto-size
v-model:value="subAccount.comment" v-model:value="subAccount.comment"
></f7-list-input> ></f7-list-input>
@@ -398,7 +398,7 @@
<f7-actions close-by-outside-click close-on-escape :opened="showMoreActionSheet" @actions:closed="showMoreActionSheet = false"> <f7-actions close-by-outside-click close-on-escape :opened="showMoreActionSheet" @actions:closed="showMoreActionSheet = false">
<f7-actions-group> <f7-actions-group>
<f7-actions-button @click="addSubAccount">{{ $t('Add Sub Account') }}</f7-actions-button> <f7-actions-button @click="addSubAccount">{{ $t('Add Sub-account') }}</f7-actions-button>
</f7-actions-group> </f7-actions-group>
<f7-actions-group> <f7-actions-group>
<f7-actions-button bold close>{{ $t('Cancel') }}</f7-actions-button> <f7-actions-button bold close>{{ $t('Cancel') }}</f7-actions-button>
@@ -407,7 +407,7 @@
<f7-actions close-by-outside-click close-on-escape :opened="showDeleteActionSheet" @actions:closed="showDeleteActionSheet = false"> <f7-actions close-by-outside-click close-on-escape :opened="showDeleteActionSheet" @actions:closed="showDeleteActionSheet = false">
<f7-actions-group> <f7-actions-group>
<f7-actions-label>{{ $t('Are you sure you want to remove this sub account?') }}</f7-actions-label> <f7-actions-label>{{ $t('Are you sure you want to remove this sub-account?') }}</f7-actions-label>
<f7-actions-button color="red" @click="removeSubAccount(subAccountToDelete, true)">{{ $t('Remove') }}</f7-actions-button> <f7-actions-button color="red" @click="removeSubAccount(subAccountToDelete, true)">{{ $t('Remove') }}</f7-actions-button>
</f7-actions-group> </f7-actions-group>
<f7-actions-group> <f7-actions-group>
@@ -567,7 +567,7 @@ export default {
}, },
removeSubAccount(subAccount, confirm) { removeSubAccount(subAccount, confirm) {
if (!subAccount) { if (!subAccount) {
this.$alert('An error has occurred'); this.$alert('An error occurred');
return; return;
} }
@@ -676,13 +676,13 @@ export default {
}, },
getInputEmptyProblemMessage(account, isSubAccount) { getInputEmptyProblemMessage(account, isSubAccount) {
if (!isSubAccount && !account.category) { if (!isSubAccount && !account.category) {
return 'Account category cannot be empty'; return 'Account category cannot be blank';
} else if (!isSubAccount && !account.type) { } else if (!isSubAccount && !account.type) {
return 'Account type cannot be empty'; return 'Account type cannot be blank';
} else if (!account.name) { } else if (!account.name) {
return 'Account name cannot be empty'; return 'Account name cannot be blank';
} else if (account.type === this.allAccountTypes.SingleAccount && !account.currency) { } else if (account.type === this.allAccountTypes.SingleAccount && !account.currency) {
return 'Account currency cannot be empty'; return 'Account currency cannot be blank';
} else { } else {
return null; return null;
} }
+3 -3
View File
@@ -152,8 +152,8 @@
<f7-actions close-by-outside-click close-on-escape :opened="showMoreActionSheet" @actions:closed="showMoreActionSheet = false"> <f7-actions close-by-outside-click close-on-escape :opened="showMoreActionSheet" @actions:closed="showMoreActionSheet = false">
<f7-actions-group> <f7-actions-group>
<f7-actions-button @click="setSortable()">{{ $t('Sort') }}</f7-actions-button> <f7-actions-button @click="setSortable()">{{ $t('Sort') }}</f7-actions-button>
<f7-actions-button v-if="!showHidden" @click="showHidden = true">{{ $t('Show Hidden Account') }}</f7-actions-button> <f7-actions-button v-if="!showHidden" @click="showHidden = true">{{ $t('Show Hidden Accounts') }}</f7-actions-button>
<f7-actions-button v-if="showHidden" @click="showHidden = false">{{ $t('Hide Hidden Account') }}</f7-actions-button> <f7-actions-button v-if="showHidden" @click="showHidden = false">{{ $t('Hide Hidden Accounts') }}</f7-actions-button>
</f7-actions-group> </f7-actions-group>
<f7-actions-group> <f7-actions-group>
<f7-actions-button bold close>{{ $t('Cancel') }}</f7-actions-button> <f7-actions-button bold close>{{ $t('Cancel') }}</f7-actions-button>
@@ -408,7 +408,7 @@ export default {
const self = this; const self = this;
if (!account) { if (!account) {
self.$alert('An error has occurred'); self.$alert('An error occurred');
return; return;
} }
+1 -1
View File
@@ -187,7 +187,7 @@ export default {
}, },
inputEmptyProblemMessage() { inputEmptyProblemMessage() {
if (!this.category.name) { if (!this.category.name) {
return 'Category name cannot be empty'; return 'Category name cannot be blank';
} else { } else {
return null; return null;
} }
+3 -3
View File
@@ -66,8 +66,8 @@
<f7-actions close-by-outside-click close-on-escape :opened="showMoreActionSheet" @actions:closed="showMoreActionSheet = false"> <f7-actions close-by-outside-click close-on-escape :opened="showMoreActionSheet" @actions:closed="showMoreActionSheet = false">
<f7-actions-group> <f7-actions-group>
<f7-actions-button @click="setSortable()">{{ $t('Sort') }}</f7-actions-button> <f7-actions-button @click="setSortable()">{{ $t('Sort') }}</f7-actions-button>
<f7-actions-button v-if="!showHidden" @click="showHidden = true">{{ $t('Show Hidden Transaction Category') }}</f7-actions-button> <f7-actions-button v-if="!showHidden" @click="showHidden = true">{{ $t('Show Hidden Transaction Categories') }}</f7-actions-button>
<f7-actions-button v-if="showHidden" @click="showHidden = false">{{ $t('Hide Hidden Transaction Category') }}</f7-actions-button> <f7-actions-button v-if="showHidden" @click="showHidden = false">{{ $t('Hide Hidden Transaction Categories') }}</f7-actions-button>
</f7-actions-group> </f7-actions-group>
<f7-actions-group> <f7-actions-group>
<f7-actions-button bold close>{{ $t('Cancel') }}</f7-actions-button> <f7-actions-button bold close>{{ $t('Cancel') }}</f7-actions-button>
@@ -357,7 +357,7 @@ export default {
const self = this; const self = this;
if (!category) { if (!category) {
self.$alert('An error has occurred'); self.$alert('An error occurred');
return; return;
} }
+2 -2
View File
@@ -37,8 +37,8 @@
<f7-list-item :title="$t('Default Transaction Category Filter')" link="/statistic/filter/category?modifyDefault=1"></f7-list-item> <f7-list-item :title="$t('Default Transaction Category Filter')" link="/statistic/filter/category?modifyDefault=1"></f7-list-item>
<f7-list-item <f7-list-item
:title="$t('Default Sort By')" :title="$t('Default Sort Order')"
smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Sort By'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), popupCloseLinkText: $t('Done') }"> smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Sort Order'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), popupCloseLinkText: $t('Done') }">
<select v-model="defaultSortingType"> <select v-model="defaultSortingType">
<option :value="sortingType.type" <option :value="sortingType.type"
:key="sortingType.type" :key="sortingType.type"
@@ -31,7 +31,7 @@
<f7-card v-if="query.chartType === allChartTypes.Pie"> <f7-card v-if="query.chartType === allChartTypes.Pie">
<f7-card-header class="no-border display-block"> <f7-card-header class="no-border display-block">
<div class="statistics-chart-header full-line text-align-right"> <div class="statistics-chart-header full-line text-align-right">
<span style="margin-right: 4px;">{{ $t('Sort By') }}</span> <span style="margin-right: 4px;">{{ $t('Sort by') }}</span>
<f7-link href="#" popover-open=".sorting-type-popover-menu">{{ querySortingTypeName }}</f7-link> <f7-link href="#" popover-open=".sorting-type-popover-menu">{{ querySortingTypeName }}</f7-link>
</div> </div>
</f7-card-header> </f7-card-header>
@@ -84,7 +84,7 @@
{{ totalAmountName }} {{ totalAmountName }}
</div> </div>
<div class="align-self-flex-end"> <div class="align-self-flex-end">
<span style="margin-right: 4px;">{{ $t('Sort By') }}</span> <span style="margin-right: 4px;">{{ $t('Sort by') }}</span>
<f7-link href="#" popover-open=".sorting-type-popover-menu">{{ querySortingTypeName }}</f7-link> <f7-link href="#" popover-open=".sorting-type-popover-menu">{{ querySortingTypeName }}</f7-link>
</div> </div>
</div> </div>
+3 -3
View File
@@ -123,8 +123,8 @@
<f7-actions close-by-outside-click close-on-escape :opened="showMoreActionSheet" @actions:closed="showMoreActionSheet = false"> <f7-actions close-by-outside-click close-on-escape :opened="showMoreActionSheet" @actions:closed="showMoreActionSheet = false">
<f7-actions-group> <f7-actions-group>
<f7-actions-button @click="setSortable()">{{ $t('Sort') }}</f7-actions-button> <f7-actions-button @click="setSortable()">{{ $t('Sort') }}</f7-actions-button>
<f7-actions-button v-if="!showHidden" @click="showHidden = true">{{ $t('Show Hidden Transaction Tag') }}</f7-actions-button> <f7-actions-button v-if="!showHidden" @click="showHidden = true">{{ $t('Show Hidden Transaction Tags') }}</f7-actions-button>
<f7-actions-button v-if="showHidden" @click="showHidden = false">{{ $t('Hide Hidden Transaction Tag') }}</f7-actions-button> <f7-actions-button v-if="showHidden" @click="showHidden = false">{{ $t('Hide Hidden Transaction Tags') }}</f7-actions-button>
</f7-actions-group> </f7-actions-group>
<f7-actions-group> <f7-actions-group>
<f7-actions-button bold close>{{ $t('Cancel') }}</f7-actions-button> <f7-actions-button bold close>{{ $t('Cancel') }}</f7-actions-button>
@@ -392,7 +392,7 @@ export default {
const self = this; const self = this;
if (!tag) { if (!tag) {
self.$alert('An error has occurred'); self.$alert('An error occurred');
return; return;
} }
+10 -10
View File
@@ -33,7 +33,7 @@
<f7-list-item class="list-item-with-header-and-title list-item-title-hide-overflow" header="Category" title="Category Names"></f7-list-item> <f7-list-item class="list-item-with-header-and-title list-item-title-hide-overflow" header="Category" title="Category Names"></f7-list-item>
<f7-list-item class="list-item-with-header-and-title" header="Account" title="Account Name"></f7-list-item> <f7-list-item class="list-item-with-header-and-title" header="Account" title="Account Name"></f7-list-item>
<f7-list-item class="list-item-with-header-and-title" header="Transaction Time" title="YYYY/MM/DD HH:mm:ss"></f7-list-item> <f7-list-item class="list-item-with-header-and-title" header="Transaction Time" title="YYYY/MM/DD HH:mm:ss"></f7-list-item>
<f7-list-item class="list-item-with-header-and-title list-item-title-hide-overflow list-item-no-item-after" header="Transaction Time Zone" title="(UTC XX:XX) System Default" link="#" :no-chevron="mode === 'view'"></f7-list-item> <f7-list-item class="list-item-with-header-and-title list-item-title-hide-overflow list-item-no-item-after" header="Transaction Timezone" title="(UTC XX:XX) System Default" link="#" :no-chevron="mode === 'view'"></f7-list-item>
<f7-list-item class="list-item-with-header-and-title list-item-title-hide-overflow" header="Geographic Location" title="No Location"></f7-list-item> <f7-list-item class="list-item-with-header-and-title list-item-title-hide-overflow" header="Geographic Location" title="No Location"></f7-list-item>
<f7-list-item header="Tags"> <f7-list-item header="Tags">
<template #footer> <template #footer>
@@ -230,8 +230,8 @@
:no-chevron="mode === 'view'" :no-chevron="mode === 'view'"
class="list-item-with-header-and-title list-item-title-hide-overflow list-item-no-item-after" class="list-item-with-header-and-title list-item-title-hide-overflow list-item-no-item-after"
:class="{ 'readonly': mode === 'view' }" :class="{ 'readonly': mode === 'view' }"
:header="$t('Transaction Time Zone')" :header="$t('Transaction 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'), pageTitle: $t('Transaction Time Zone'), popupCloseLinkText: $t('Done') }"> 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'), pageTitle: $t('Transaction Timezone'), popupCloseLinkText: $t('Done') }">
<select v-model="transaction.timeZone"> <select v-model="transaction.timeZone">
<option :value="timezone.name" :key="timezone.name" <option :value="timezone.name" :key="timezone.name"
v-for="timezone in allTimezones">{{ timezone.displayNameWithUtcOffset }}</option> v-for="timezone in allTimezones">{{ timezone.displayNameWithUtcOffset }}</option>
@@ -668,8 +668,8 @@ export default {
Promise.all(promises).then(function (responses) { Promise.all(promises).then(function (responses) {
if (query.id && !responses[3]) { if (query.id && !responses[3]) {
self.$toast('Unable to get transaction'); self.$toast('Unable to retrieve transaction');
self.loadingError = 'Unable to get transaction'; self.loadingError = 'Unable to retrieve transaction';
return; return;
} }
@@ -749,7 +749,7 @@ export default {
}; };
if (self.transaction.sourceAmount === 0) { if (self.transaction.sourceAmount === 0) {
self.$confirm('Are you sure you want to save this transaction whose amount is 0?', () => { self.$confirm('Are you sure you want to save this transaction with a zero amount?', () => {
doSubmit(); doSubmit();
}); });
} else { } else {
@@ -763,7 +763,7 @@ export default {
logger.warn('this browser does not support geo location'); logger.warn('this browser does not support geo location');
if (forceUpdate) { if (forceUpdate) {
self.$toast('Unable to get current position'); self.$toast('Unable to retrieve current position');
} }
return; return;
} }
@@ -774,7 +774,7 @@ export default {
self.geoLocationStatus = 'error'; self.geoLocationStatus = 'error';
if (forceUpdate) { if (forceUpdate) {
self.$toast('Unable to get current position'); self.$toast('Unable to retrieve current position');
} }
return; return;
@@ -787,11 +787,11 @@ export default {
longitude: position.coords.longitude longitude: position.coords.longitude
}; };
}, function (err) { }, function (err) {
logger.error('cannot get current position', err); logger.error('cannot retrieve current position', err);
self.geoLocationStatus = 'error'; self.geoLocationStatus = 'error';
if (forceUpdate) { if (forceUpdate) {
self.$toast('Unable to get current position'); self.$toast('Unable to retrieve current position');
} }
}); });
+1 -1
View File
@@ -790,7 +790,7 @@ export default {
const self = this; const self = this;
if (!transaction) { if (!transaction) {
self.$alert('An error has occurred'); self.$alert('An error occurred');
return; return;
} }
@@ -56,7 +56,7 @@
</f7-sheet> </f7-sheet>
<password-input-sheet :title="$t('Are you sure you want to clear all data?')" <password-input-sheet :title="$t('Are you sure you want to clear all data?')"
:hint="$t('You CANNOT undo this action. This will clear your accounts, categories, tags and transactions data. Please input your current password to confirm.')" :hint="$t('You CANNOT undo this action. This will clear your accounts, categories, tags and transactions data. Please enter your current password to confirm.')"
:confirm-disabled="clearingData" :confirm-disabled="clearingData"
:cancel-disabled="clearingData" :cancel-disabled="clearingData"
color="red" color="red"
+5 -5
View File
@@ -15,7 +15,7 @@
</f7-list> </f7-list>
<passcode-input-sheet :title="$t('Enable Two-Factor Authentication')" <passcode-input-sheet :title="$t('Enable Two-Factor Authentication')"
:hint="$t('Please use two factor authentication app scan the below qrcode and input current passcode')" :hint="$t('Please use a two-factor authentication app to scan the qrcode below and enter the current passcode.')"
:confirm-disabled="enableConfirming" :confirm-disabled="enableConfirming"
:cancel-disabled="enableConfirming" :cancel-disabled="enableConfirming"
v-model:show="showInputPasscodeSheetForEnable" v-model:show="showInputPasscodeSheetForEnable"
@@ -27,7 +27,7 @@
</passcode-input-sheet> </passcode-input-sheet>
<password-input-sheet :title="$t('Disable Two-Factor Authentication')" <password-input-sheet :title="$t('Disable Two-Factor Authentication')"
:hint="$t('Please enter your current password when disable two factor authentication')" :hint="$t('Your current password is required to disable two-factor authentication.')"
:confirm-disabled="disabling" :confirm-disabled="disabling"
:cancel-disabled="disabling" :cancel-disabled="disabling"
v-model:show="showInputPasswordSheetForDisable" v-model:show="showInputPasswordSheetForDisable"
@@ -36,7 +36,7 @@
</password-input-sheet> </password-input-sheet>
<password-input-sheet :title="$t('Regenerate Backup Codes')" <password-input-sheet :title="$t('Regenerate Backup Codes')"
:hint="$t('Please enter your current password when regenerate two factor authentication backup codes. If you regenerate backup codes, the old codes will be invalidated.')" :hint="$t('Your current password is required to regenerate backup codes for two-factor authentication. If you regenerate backup codes, the previous ones will become invalid.')"
:confirm-disabled="regenerating" :confirm-disabled="regenerating"
:cancel-disabled="regenerating" :cancel-disabled="regenerating"
v-model:show="showInputPasswordSheetForRegenerate" v-model:show="showInputPasswordSheetForRegenerate"
@@ -46,7 +46,7 @@
<information-sheet class="backup-code-sheet" <information-sheet class="backup-code-sheet"
:title="$t('Backup Code')" :title="$t('Backup Code')"
:hint="$t('Please copy these backup codes to safe place, the below codes can only be shown once. If these codes were lost, you can regenerate backup codes at any time.')" :hint="$t('Please copy these backup codes to safe place, the following backup codes will be displayed only once. If these codes were lost, you can regenerate them at any time.')"
:information="currentBackupCode" :information="currentBackupCode"
:row-count="10" :row-count="10"
:enable-copy="true" :enable-copy="true"
@@ -187,7 +187,7 @@ export default {
self.status = false; self.status = false;
self.showInputPasswordSheetForDisable = false; self.showInputPasswordSheetForDisable = false;
self.$toast('Two factor authentication has been disabled'); self.$toast('Two-factor authentication has been disabled');
}).catch(error => { }).catch(error => {
self.disabling = false; self.disabling = false;
self.$hideLoading(); self.$hideLoading();
+15 -15
View File
@@ -11,14 +11,14 @@
<f7-list strong inset dividers class="margin-vertical skeleton-text" v-if="loading"> <f7-list strong inset dividers class="margin-vertical skeleton-text" v-if="loading">
<f7-list-input label="Password" placeholder="Your password"></f7-list-input> <f7-list-input label="Password" placeholder="Your password"></f7-list-input>
<f7-list-input label="Confirmation Password" placeholder="Re-enter the password"></f7-list-input> <f7-list-input label="Confirm Password" placeholder="Re-enter the password"></f7-list-input>
<f7-list-input label="E-mail" placeholder="Your email address"></f7-list-input> <f7-list-input label="E-mail" placeholder="Your email address"></f7-list-input>
<f7-list-input label="Nickname" placeholder="Your nickname"></f7-list-input> <f7-list-input label="Nickname" placeholder="Your nickname"></f7-list-input>
</f7-list> </f7-list>
<f7-list strong inset dividers class="margin-vertical skeleton-text" v-if="loading"> <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 Account" title="Not Specified"></f7-list-item> <f7-list-item class="list-item-with-header-and-title list-item-no-item-after" header="Default Account" title="Unspecified"></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-item class="list-item-with-header-and-title list-item-no-item-after" header="Editable Transaction Range" title="All" link="#"></f7-list-item>
</f7-list> </f7-list>
<f7-list strong inset dividers class="margin-vertical skeleton-text" v-if="loading"> <f7-list strong inset dividers class="margin-vertical skeleton-text" v-if="loading">
@@ -45,7 +45,7 @@
type="password" type="password"
autocomplete="new-password" autocomplete="new-password"
clear-button clear-button
:label="$t('Confirmation Password')" :label="$t('Confirm Password')"
:placeholder="$t('Re-enter the password')" :placeholder="$t('Re-enter the password')"
v-model:value="newProfile.confirmPassword" v-model:value="newProfile.confirmPassword"
></f7-list-input> ></f7-list-input>
@@ -54,7 +54,7 @@
type="email" type="email"
autocomplete="email" autocomplete="email"
clear-button clear-button
:label="$t('E-mail') + ' ' + (emailVerified ? $t('(Verified)') : $t('(Unverified)'))" :label="$t('E-mail') + ' ' + (emailVerified ? $t('(Verified)') : $t('(Not Verified)'))"
:placeholder="$t('Your email address')" :placeholder="$t('Your email address')"
v-model:value="newProfile.email" v-model:value="newProfile.email"
></f7-list-input> ></f7-list-input>
@@ -77,7 +77,7 @@
link="#" no-chevron link="#" no-chevron
:class="{ 'disabled': !allVisibleAccounts.length }" :class="{ 'disabled': !allVisibleAccounts.length }"
:header="$t('Default Account')" :header="$t('Default Account')"
:title="getNameByKeyValue(allAccounts, newProfile.defaultAccountId, 'id', 'name', $t('Not Specified'))" :title="getNameByKeyValue(allAccounts, newProfile.defaultAccountId, 'id', 'name', $t('Unspecified'))"
@click="showAccountSheet = true" @click="showAccountSheet = true"
> >
<two-column-list-item-selection-sheet primary-key-field="id" primary-value-field="category" <two-column-list-item-selection-sheet primary-key-field="id" primary-value-field="category"
@@ -96,9 +96,9 @@
<f7-list-item <f7-list-item
class="list-item-with-header-and-title list-item-no-item-after" class="list-item-with-header-and-title list-item-no-item-after"
:header="$t('Editable Transaction Scope')" :header="$t('Editable Transaction Range')"
:title="getNameByKeyValue(allTransactionEditScopeTypes, newProfile.transactionEditScope, 'type', 'displayName')" :title="getNameByKeyValue(allTransactionEditScopeTypes, newProfile.transactionEditScope, 'type', 'displayName')"
smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Date Range'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), pageTitle: $t('Editable Transaction Scope'), popupCloseLinkText: $t('Done') }" smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Date Range'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), pageTitle: $t('Editable Transaction Range'), popupCloseLinkText: $t('Done') }"
> >
<select v-model="newProfile.transactionEditScope"> <select v-model="newProfile.transactionEditScope">
<option :value="option.type" <option :value="option.type"
@@ -366,22 +366,22 @@ export default {
this.newProfile.shortTimeFormat === this.oldProfile.shortTimeFormat) { this.newProfile.shortTimeFormat === this.oldProfile.shortTimeFormat) {
return 'Nothing has been modified'; return 'Nothing has been modified';
} else if (!this.newProfile.password && this.newProfile.confirmPassword) { } else if (!this.newProfile.password && this.newProfile.confirmPassword) {
return 'Password cannot be empty'; return 'Password cannot be blank';
} else if (this.newProfile.password && !this.newProfile.confirmPassword) { } else if (this.newProfile.password && !this.newProfile.confirmPassword) {
return 'Confirmation password cannot be empty'; return 'Password confirmation cannot be blank';
} else { } else {
return null; return null;
} }
}, },
inputInvalidProblemMessage() { inputInvalidProblemMessage() {
if (this.newProfile.password && this.newProfile.confirmPassword && this.newProfile.password !== this.newProfile.confirmPassword) { if (this.newProfile.password && this.newProfile.confirmPassword && this.newProfile.password !== this.newProfile.confirmPassword) {
return 'Password and confirmation password do not match'; return 'Password and password confirmation do not match';
} else if (!this.newProfile.email) { } else if (!this.newProfile.email) {
return 'Email address cannot be empty'; return 'Email address cannot be blank';
} else if (!this.newProfile.nickname) { } else if (!this.newProfile.nickname) {
return 'Nickname cannot be empty'; return 'Nickname cannot be blank';
} else if (!this.newProfile.defaultCurrency) { } else if (!this.newProfile.defaultCurrency) {
return 'Default currency cannot be empty'; return 'Default currency cannot be blank';
} else { } else {
return null; return null;
} }
@@ -391,7 +391,7 @@ export default {
}, },
langAndRegionInputInvalidProblemMessage() { langAndRegionInputInvalidProblemMessage() {
if (!this.newProfile.defaultCurrency) { if (!this.newProfile.defaultCurrency) {
return 'Default currency cannot be empty'; return 'Default currency cannot be blank';
} else { } else {
return null; return null;
} }