use i18n resource item to replace ambiguous configuration item

This commit is contained in:
MaysWind
2025-12-12 12:23:07 +08:00
parent c170cb42e6
commit 89dd306bb4
30 changed files with 90 additions and 25 deletions
-3
View File
@@ -1,7 +1,4 @@
[global] [global]
# Application instance name
app_name = ezBookkeeping
# Either "production", "development" # Either "production", "development"
mode = production mode = production
+2 -2
View File
@@ -13,7 +13,7 @@ import (
"github.com/mayswind/ezbookkeeping/pkg/utils" "github.com/mayswind/ezbookkeeping/pkg/utils"
) )
const mcpServerName = "ezBookkeeping-mcp" const mcpServerName = core.ApplicationName + "-mcp"
// ModelContextProtocolAPI represents model context protocol api // ModelContextProtocolAPI represents model context protocol api
type ModelContextProtocolAPI struct { type ModelContextProtocolAPI struct {
@@ -102,7 +102,7 @@ func (a *ModelContextProtocolAPI) InitializeHandler(c *core.WebContext, jsonRPCR
}, },
ServerInfo: &mcp.MCPImplementation{ ServerInfo: &mcp.MCPImplementation{
Name: mcpServerName, Name: mcpServerName,
Title: a.CurrentConfig().AppName, Title: core.ApplicationName,
Version: settings.Version, Version: settings.Version,
}, },
} }
+1 -1
View File
@@ -85,7 +85,7 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorEnableRequestHandler(c *core.WebCo
return nil, errs.ErrNotPermittedToPerformThisAction return nil, errs.ErrNotPermittedToPerformThisAction
} }
key, err := a.twoFactorAuthorizations.GenerateTwoFactorSecret(c, user) key, err := a.twoFactorAuthorizations.GenerateTwoFactorSecret(c, user, c.GetClientLocale())
if err != nil { if err != nil {
log.Errorf(c, "[twofactor_authorizations.TwoFactorEnableRequestHandler] failed to generate two-factor secret, because %s", err.Error()) log.Errorf(c, "[twofactor_authorizations.TwoFactorEnableRequestHandler] failed to generate two-factor secret, because %s", err.Error())
+4
View File
@@ -0,0 +1,4 @@
package core
// ApplicationName represents the application name
const ApplicationName = "ezBookkeeping"
@@ -27,7 +27,7 @@ func (p *OpenRouterChatCompletionsAPIProvider) BuildChatCompletionsHttpRequest(c
req.Header.Set("Authorization", "Bearer "+p.OpenRouterAPIKey) req.Header.Set("Authorization", "Bearer "+p.OpenRouterAPIKey)
req.Header.Set("HTTP-Referer", "https://ezbookkeeping.mayswind.net/") req.Header.Set("HTTP-Referer", "https://ezbookkeeping.mayswind.net/")
req.Header.Set("X-Title", "ezBookkeeping") req.Header.Set("X-Title", core.ApplicationName)
return req, nil return req, nil
} }
+6
View File
@@ -6,12 +6,18 @@ import (
// LocaleTextItems represents all text items need to be translated // LocaleTextItems represents all text items need to be translated
type LocaleTextItems struct { type LocaleTextItems struct {
GlobalTextItems *GlobalTextItems
DefaultTypes *DefaultTypes DefaultTypes *DefaultTypes
DataConverterTextItems *DataConverterTextItems DataConverterTextItems *DataConverterTextItems
VerifyEmailTextItems *VerifyEmailTextItems VerifyEmailTextItems *VerifyEmailTextItems
ForgetPasswordMailTextItems *ForgetPasswordMailTextItems ForgetPasswordMailTextItems *ForgetPasswordMailTextItems
} }
// GlobalTextItems represents global text items need to be translated
type GlobalTextItems struct {
AppName string
}
// DefaultTypes represents default types for the language // DefaultTypes represents default types for the language
type DefaultTypes struct { type DefaultTypes struct {
DecimalSeparator core.DecimalSeparator DecimalSeparator core.DecimalSeparator
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var de = &LocaleTextItems{ var de = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT,
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var en = &LocaleTextItems{ var en = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_DOT, DecimalSeparator: core.DECIMAL_SEPARATOR_DOT,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA,
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var es = &LocaleTextItems{ var es = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT,
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var fr = &LocaleTextItems{ var fr = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_SPACE, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_SPACE,
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var it = &LocaleTextItems{ var it = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT,
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var ja = &LocaleTextItems{ var ja = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_DOT, DecimalSeparator: core.DECIMAL_SEPARATOR_DOT,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA,
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var kn = &LocaleTextItems{ var kn = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_DOT, DecimalSeparator: core.DECIMAL_SEPARATOR_DOT,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA,
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var ko = &LocaleTextItems{ var ko = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_DOT, DecimalSeparator: core.DECIMAL_SEPARATOR_DOT,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA,
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var nl = &LocaleTextItems{ var nl = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT,
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var ptBR = &LocaleTextItems{ var ptBR = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_SPACE, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_SPACE,
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var ru = &LocaleTextItems{ var ru = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_SPACE, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_SPACE,
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var th = &LocaleTextItems{ var th = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_DOT, DecimalSeparator: core.DECIMAL_SEPARATOR_DOT,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA,
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var tr = &LocaleTextItems{ var tr = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT,
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var uk = &LocaleTextItems{ var uk = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_SPACE, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_SPACE,
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var vi = &LocaleTextItems{ var vi = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT,
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var zhHans = &LocaleTextItems{ var zhHans = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_DOT, DecimalSeparator: core.DECIMAL_SEPARATOR_DOT,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA,
+3
View File
@@ -5,6 +5,9 @@ import (
) )
var zhHant = &LocaleTextItems{ var zhHant = &LocaleTextItems{
GlobalTextItems: &GlobalTextItems{
AppName: "ezBookkeeping",
},
DefaultTypes: &DefaultTypes{ DefaultTypes: &DefaultTypes{
DecimalSeparator: core.DECIMAL_SEPARATOR_DOT, DecimalSeparator: core.DECIMAL_SEPARATOR_DOT,
DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA,
+1 -1
View File
@@ -59,7 +59,7 @@ func (s *ForgetPasswordService) SendPasswordResetEmail(c core.Context, user *mod
} }
templateParams := map[string]any{ templateParams := map[string]any{
"AppName": s.CurrentConfig().AppName, "AppName": localeTextItems.GlobalTextItems.AppName,
"ForgetPasswordMail": map[string]any{ "ForgetPasswordMail": map[string]any{
"Title": forgetPasswordTextItems.Title, "Title": forgetPasswordTextItems.Title,
"Salutation": fmt.Sprintf(forgetPasswordTextItems.SalutationFormat, user.Nickname), "Salutation": fmt.Sprintf(forgetPasswordTextItems.SalutationFormat, user.Nickname),
+3 -3
View File
@@ -21,13 +21,13 @@ import (
) )
// TokenUserAgentCreatedViaCli is the user agent of token created via cli // TokenUserAgentCreatedViaCli is the user agent of token created via cli
const TokenUserAgentCreatedViaCli = "ezbookkeeping Cli" const TokenUserAgentCreatedViaCli = core.ApplicationName + " Cli"
// TokenUserAgentForAPI is the user agent for API token // TokenUserAgentForAPI is the user agent for API token
const TokenUserAgentForAPI = "ezbookkeeping API" const TokenUserAgentForAPI = core.ApplicationName + " API"
// TokenUserAgentForMCP is the user agent for MCP token // TokenUserAgentForMCP is the user agent for MCP token
const TokenUserAgentForMCP = "ezbookkeeping MCP" const TokenUserAgentForMCP = core.ApplicationName + " MCP"
const tokenMaxExpiredAtUnixTime = int64(253402300799) // 9999-12-31 23:59:59 UTC const tokenMaxExpiredAtUnixTime = int64(253402300799) // 9999-12-31 23:59:59 UTC
+11 -2
View File
@@ -10,6 +10,7 @@ import (
"github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/datastore" "github.com/mayswind/ezbookkeeping/pkg/datastore"
"github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/locales"
"github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/models"
"github.com/mayswind/ezbookkeeping/pkg/settings" "github.com/mayswind/ezbookkeeping/pkg/settings"
"github.com/mayswind/ezbookkeeping/pkg/utils" "github.com/mayswind/ezbookkeeping/pkg/utils"
@@ -70,13 +71,21 @@ func (s *TwoFactorAuthorizationService) GetUserTwoFactorSettingByUid(c core.Cont
} }
// GenerateTwoFactorSecret generates a new 2fa secret // GenerateTwoFactorSecret generates a new 2fa secret
func (s *TwoFactorAuthorizationService) GenerateTwoFactorSecret(c core.Context, user *models.User) (*otp.Key, error) { func (s *TwoFactorAuthorizationService) GenerateTwoFactorSecret(c core.Context, user *models.User, backupLocale string) (*otp.Key, error) {
if user == nil { if user == nil {
return nil, errs.ErrUserNotFound return nil, errs.ErrUserNotFound
} }
locale := user.Language
if locale == "" {
locale = backupLocale
}
localeTextItems := locales.GetLocaleTextItems(locale)
key, err := totp.Generate(totp.GenerateOpts{ key, err := totp.Generate(totp.GenerateOpts{
Issuer: s.CurrentConfig().AppName, Issuer: localeTextItems.GlobalTextItems.AppName,
AccountName: user.Username, AccountName: user.Username,
Period: twoFactorPeriod, Period: twoFactorPeriod,
SecretSize: twoFactorSecretSize, SecretSize: twoFactorSecretSize,
+2 -2
View File
@@ -684,14 +684,14 @@ func (s *UserService) SendVerifyEmail(user *models.User, verifyEmailToken string
} }
templateParams := map[string]any{ templateParams := map[string]any{
"AppName": s.CurrentConfig().AppName, "AppName": localeTextItems.GlobalTextItems.AppName,
"VerifyEmail": map[string]any{ "VerifyEmail": map[string]any{
"Title": verifyEmailTextItems.Title, "Title": verifyEmailTextItems.Title,
"Salutation": fmt.Sprintf(verifyEmailTextItems.SalutationFormat, user.Nickname), "Salutation": fmt.Sprintf(verifyEmailTextItems.SalutationFormat, user.Nickname),
"DescriptionAboveBtn": verifyEmailTextItems.DescriptionAboveBtn, "DescriptionAboveBtn": verifyEmailTextItems.DescriptionAboveBtn,
"VerifyEmailUrl": verifyEmailUrl, "VerifyEmailUrl": verifyEmailUrl,
"VerifyEmail": verifyEmailTextItems.VerifyEmail, "VerifyEmail": verifyEmailTextItems.VerifyEmail,
"DescriptionBelowBtn": fmt.Sprintf(verifyEmailTextItems.DescriptionBelowBtnFormat, s.CurrentConfig().AppName, expireTimeInMinutes), "DescriptionBelowBtn": fmt.Sprintf(verifyEmailTextItems.DescriptionBelowBtnFormat, localeTextItems.GlobalTextItems.AppName, expireTimeInMinutes),
}, },
} }
-5
View File
@@ -145,8 +145,6 @@ const (
) )
const ( const (
defaultAppName string = "ezBookkeeping"
defaultHttpAddr string = "0.0.0.0" defaultHttpAddr string = "0.0.0.0"
defaultHttpPort uint16 = 8080 defaultHttpPort uint16 = 8080
defaultDomain string = "localhost" defaultDomain string = "localhost"
@@ -267,7 +265,6 @@ type MultiLanguageContentConfig struct {
// Config represents the global setting config // Config represents the global setting config
type Config struct { type Config struct {
// Global // Global
AppName string
Mode SystemMode Mode SystemMode
WorkingPath string WorkingPath string
@@ -595,8 +592,6 @@ func GetDefaultConfigFilePath() (string, error) {
} }
func loadGlobalConfiguration(config *Config, configFile *ini.File, sectionName string) error { func loadGlobalConfiguration(config *Config, configFile *ini.File, sectionName string) error {
config.AppName = getConfigItemStringValue(configFile, sectionName, "app_name", defaultAppName)
if getConfigItemStringValue(configFile, sectionName, "mode") == "production" { if getConfigItemStringValue(configFile, sectionName, "mode") == "production" {
config.Mode = MODE_PRODUCTION config.Mode = MODE_PRODUCTION
} else if getConfigItemStringValue(configFile, sectionName, "mode") == "development" { } else if getConfigItemStringValue(configFile, sectionName, "mode") == "development" {
+7 -3
View File
@@ -1,6 +1,10 @@
package settings package settings
import "fmt" import (
"fmt"
"github.com/mayswind/ezbookkeeping/pkg/core"
)
// ConfigContainer contains the current setting config // ConfigContainer contains the current setting config
type ConfigContainer struct { type ConfigContainer struct {
@@ -27,8 +31,8 @@ func (c *ConfigContainer) GetCurrentConfig() *Config {
func GetUserAgent() string { func GetUserAgent() string {
if Version == "" { if Version == "" {
return "ezBookkeeping" return core.ApplicationName
} }
return fmt.Sprintf("ezBookkeeping/%s", Version) return fmt.Sprintf("%s/%s", core.ApplicationName, Version)
} }
+1 -2
View File
@@ -10,8 +10,7 @@ import (
func TestClone(t *testing.T) { func TestClone(t *testing.T) {
expectedObject := &settings.Config{ expectedObject := &settings.Config{
AppName: "ezbookkeeping", Mode: settings.MODE_PRODUCTION,
Mode: settings.MODE_PRODUCTION,
DatabaseConfig: &settings.DatabaseConfig{ DatabaseConfig: &settings.DatabaseConfig{
DatabaseType: settings.MySqlDbType, DatabaseType: settings.MySqlDbType,
DatabaseHost: "localhost", DatabaseHost: "localhost",