From 89dd306bb43d6290a6e82c31a645fa7c97a4ba59 Mon Sep 17 00:00:00 2001 From: MaysWind Date: Fri, 12 Dec 2025 12:23:07 +0800 Subject: [PATCH] use i18n resource item to replace ambiguous configuration item --- conf/ezbookkeeping.ini | 3 --- pkg/api/model_context_protocols.go | 4 ++-- pkg/api/twofactor_authorizations.go | 2 +- pkg/core/application.go | 4 ++++ .../openrouter_chat_completions_api_provider.go | 2 +- pkg/locales/base.go | 6 ++++++ pkg/locales/de.go | 3 +++ pkg/locales/en.go | 3 +++ pkg/locales/es.go | 3 +++ pkg/locales/fr.go | 3 +++ pkg/locales/it.go | 3 +++ pkg/locales/ja.go | 3 +++ pkg/locales/kn.go | 3 +++ pkg/locales/ko.go | 3 +++ pkg/locales/nl.go | 3 +++ pkg/locales/pt_br.go | 3 +++ pkg/locales/ru.go | 3 +++ pkg/locales/th.go | 3 +++ pkg/locales/tr.go | 3 +++ pkg/locales/uk.go | 3 +++ pkg/locales/vi.go | 3 +++ pkg/locales/zh_hans.go | 3 +++ pkg/locales/zh_hant.go | 3 +++ pkg/services/forget_passwords.go | 2 +- pkg/services/tokens.go | 6 +++--- pkg/services/twofactor_authorizations.go | 13 +++++++++++-- pkg/services/users.go | 4 ++-- pkg/settings/setting.go | 5 ----- pkg/settings/setting_container.go | 10 +++++++--- pkg/utils/object_test.go | 3 +-- 30 files changed, 90 insertions(+), 25 deletions(-) create mode 100644 pkg/core/application.go diff --git a/conf/ezbookkeeping.ini b/conf/ezbookkeeping.ini index c54f3c15..11e97c71 100644 --- a/conf/ezbookkeeping.ini +++ b/conf/ezbookkeeping.ini @@ -1,7 +1,4 @@ [global] -# Application instance name -app_name = ezBookkeeping - # Either "production", "development" mode = production diff --git a/pkg/api/model_context_protocols.go b/pkg/api/model_context_protocols.go index a5af8fd9..1cfc82ac 100644 --- a/pkg/api/model_context_protocols.go +++ b/pkg/api/model_context_protocols.go @@ -13,7 +13,7 @@ import ( "github.com/mayswind/ezbookkeeping/pkg/utils" ) -const mcpServerName = "ezBookkeeping-mcp" +const mcpServerName = core.ApplicationName + "-mcp" // ModelContextProtocolAPI represents model context protocol api type ModelContextProtocolAPI struct { @@ -102,7 +102,7 @@ func (a *ModelContextProtocolAPI) InitializeHandler(c *core.WebContext, jsonRPCR }, ServerInfo: &mcp.MCPImplementation{ Name: mcpServerName, - Title: a.CurrentConfig().AppName, + Title: core.ApplicationName, Version: settings.Version, }, } diff --git a/pkg/api/twofactor_authorizations.go b/pkg/api/twofactor_authorizations.go index e0b27b60..5371f0e7 100644 --- a/pkg/api/twofactor_authorizations.go +++ b/pkg/api/twofactor_authorizations.go @@ -85,7 +85,7 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorEnableRequestHandler(c *core.WebCo return nil, errs.ErrNotPermittedToPerformThisAction } - key, err := a.twoFactorAuthorizations.GenerateTwoFactorSecret(c, user) + key, err := a.twoFactorAuthorizations.GenerateTwoFactorSecret(c, user, c.GetClientLocale()) if err != nil { log.Errorf(c, "[twofactor_authorizations.TwoFactorEnableRequestHandler] failed to generate two-factor secret, because %s", err.Error()) diff --git a/pkg/core/application.go b/pkg/core/application.go new file mode 100644 index 00000000..0e89ac96 --- /dev/null +++ b/pkg/core/application.go @@ -0,0 +1,4 @@ +package core + +// ApplicationName represents the application name +const ApplicationName = "ezBookkeeping" diff --git a/pkg/llm/provider/openai/openrouter_chat_completions_api_provider.go b/pkg/llm/provider/openai/openrouter_chat_completions_api_provider.go index 6edd6bb3..90951310 100644 --- a/pkg/llm/provider/openai/openrouter_chat_completions_api_provider.go +++ b/pkg/llm/provider/openai/openrouter_chat_completions_api_provider.go @@ -27,7 +27,7 @@ func (p *OpenRouterChatCompletionsAPIProvider) BuildChatCompletionsHttpRequest(c req.Header.Set("Authorization", "Bearer "+p.OpenRouterAPIKey) 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 } diff --git a/pkg/locales/base.go b/pkg/locales/base.go index ff537e0e..c3d4ae30 100644 --- a/pkg/locales/base.go +++ b/pkg/locales/base.go @@ -6,12 +6,18 @@ import ( // LocaleTextItems represents all text items need to be translated type LocaleTextItems struct { + GlobalTextItems *GlobalTextItems DefaultTypes *DefaultTypes DataConverterTextItems *DataConverterTextItems VerifyEmailTextItems *VerifyEmailTextItems ForgetPasswordMailTextItems *ForgetPasswordMailTextItems } +// GlobalTextItems represents global text items need to be translated +type GlobalTextItems struct { + AppName string +} + // DefaultTypes represents default types for the language type DefaultTypes struct { DecimalSeparator core.DecimalSeparator diff --git a/pkg/locales/de.go b/pkg/locales/de.go index 4073ccff..37776ebc 100644 --- a/pkg/locales/de.go +++ b/pkg/locales/de.go @@ -5,6 +5,9 @@ import ( ) var de = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT, diff --git a/pkg/locales/en.go b/pkg/locales/en.go index 12a55f67..4bbc7f7a 100644 --- a/pkg/locales/en.go +++ b/pkg/locales/en.go @@ -5,6 +5,9 @@ import ( ) var en = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_DOT, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA, diff --git a/pkg/locales/es.go b/pkg/locales/es.go index dbc32cd8..b101b816 100644 --- a/pkg/locales/es.go +++ b/pkg/locales/es.go @@ -5,6 +5,9 @@ import ( ) var es = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT, diff --git a/pkg/locales/fr.go b/pkg/locales/fr.go index 903c1e60..0b78c5b3 100644 --- a/pkg/locales/fr.go +++ b/pkg/locales/fr.go @@ -5,6 +5,9 @@ import ( ) var fr = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_SPACE, diff --git a/pkg/locales/it.go b/pkg/locales/it.go index c51e161c..1d56a131 100644 --- a/pkg/locales/it.go +++ b/pkg/locales/it.go @@ -5,6 +5,9 @@ import ( ) var it = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT, diff --git a/pkg/locales/ja.go b/pkg/locales/ja.go index bec7c4ba..1e03e11c 100644 --- a/pkg/locales/ja.go +++ b/pkg/locales/ja.go @@ -5,6 +5,9 @@ import ( ) var ja = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_DOT, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA, diff --git a/pkg/locales/kn.go b/pkg/locales/kn.go index c70655a0..d61c31bb 100644 --- a/pkg/locales/kn.go +++ b/pkg/locales/kn.go @@ -5,6 +5,9 @@ import ( ) var kn = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_DOT, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA, diff --git a/pkg/locales/ko.go b/pkg/locales/ko.go index 1e2c4f01..d3a1e209 100644 --- a/pkg/locales/ko.go +++ b/pkg/locales/ko.go @@ -5,6 +5,9 @@ import ( ) var ko = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_DOT, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA, diff --git a/pkg/locales/nl.go b/pkg/locales/nl.go index a40ea347..4b9a2389 100644 --- a/pkg/locales/nl.go +++ b/pkg/locales/nl.go @@ -5,6 +5,9 @@ import ( ) var nl = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT, diff --git a/pkg/locales/pt_br.go b/pkg/locales/pt_br.go index 33b1b932..6f873d3c 100644 --- a/pkg/locales/pt_br.go +++ b/pkg/locales/pt_br.go @@ -5,6 +5,9 @@ import ( ) var ptBR = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_SPACE, diff --git a/pkg/locales/ru.go b/pkg/locales/ru.go index 2752ddd3..ca39212a 100644 --- a/pkg/locales/ru.go +++ b/pkg/locales/ru.go @@ -5,6 +5,9 @@ import ( ) var ru = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_SPACE, diff --git a/pkg/locales/th.go b/pkg/locales/th.go index 4aafbeb5..15df9d0e 100644 --- a/pkg/locales/th.go +++ b/pkg/locales/th.go @@ -5,6 +5,9 @@ import ( ) var th = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_DOT, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA, diff --git a/pkg/locales/tr.go b/pkg/locales/tr.go index 9de185c0..aa149bcc 100644 --- a/pkg/locales/tr.go +++ b/pkg/locales/tr.go @@ -5,6 +5,9 @@ import ( ) var tr = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT, diff --git a/pkg/locales/uk.go b/pkg/locales/uk.go index eaa03885..d16d8f72 100644 --- a/pkg/locales/uk.go +++ b/pkg/locales/uk.go @@ -5,6 +5,9 @@ import ( ) var uk = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_SPACE, diff --git a/pkg/locales/vi.go b/pkg/locales/vi.go index 79c70f71..7d908868 100644 --- a/pkg/locales/vi.go +++ b/pkg/locales/vi.go @@ -5,6 +5,9 @@ import ( ) var vi = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_COMMA, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_DOT, diff --git a/pkg/locales/zh_hans.go b/pkg/locales/zh_hans.go index 0798e011..a6b17cd3 100644 --- a/pkg/locales/zh_hans.go +++ b/pkg/locales/zh_hans.go @@ -5,6 +5,9 @@ import ( ) var zhHans = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_DOT, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA, diff --git a/pkg/locales/zh_hant.go b/pkg/locales/zh_hant.go index 81e50627..55857257 100644 --- a/pkg/locales/zh_hant.go +++ b/pkg/locales/zh_hant.go @@ -5,6 +5,9 @@ import ( ) var zhHant = &LocaleTextItems{ + GlobalTextItems: &GlobalTextItems{ + AppName: "ezBookkeeping", + }, DefaultTypes: &DefaultTypes{ DecimalSeparator: core.DECIMAL_SEPARATOR_DOT, DigitGroupingSymbol: core.DIGIT_GROUPING_SYMBOL_COMMA, diff --git a/pkg/services/forget_passwords.go b/pkg/services/forget_passwords.go index 8c976e37..cdfde19a 100644 --- a/pkg/services/forget_passwords.go +++ b/pkg/services/forget_passwords.go @@ -59,7 +59,7 @@ func (s *ForgetPasswordService) SendPasswordResetEmail(c core.Context, user *mod } templateParams := map[string]any{ - "AppName": s.CurrentConfig().AppName, + "AppName": localeTextItems.GlobalTextItems.AppName, "ForgetPasswordMail": map[string]any{ "Title": forgetPasswordTextItems.Title, "Salutation": fmt.Sprintf(forgetPasswordTextItems.SalutationFormat, user.Nickname), diff --git a/pkg/services/tokens.go b/pkg/services/tokens.go index 74f06490..f77a44c1 100644 --- a/pkg/services/tokens.go +++ b/pkg/services/tokens.go @@ -21,13 +21,13 @@ import ( ) // 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 -const TokenUserAgentForAPI = "ezbookkeeping API" +const TokenUserAgentForAPI = core.ApplicationName + " API" // 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 diff --git a/pkg/services/twofactor_authorizations.go b/pkg/services/twofactor_authorizations.go index 875778cc..90037297 100644 --- a/pkg/services/twofactor_authorizations.go +++ b/pkg/services/twofactor_authorizations.go @@ -10,6 +10,7 @@ import ( "github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/datastore" "github.com/mayswind/ezbookkeeping/pkg/errs" + "github.com/mayswind/ezbookkeeping/pkg/locales" "github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/settings" "github.com/mayswind/ezbookkeeping/pkg/utils" @@ -70,13 +71,21 @@ func (s *TwoFactorAuthorizationService) GetUserTwoFactorSettingByUid(c core.Cont } // 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 { return nil, errs.ErrUserNotFound } + locale := user.Language + + if locale == "" { + locale = backupLocale + } + + localeTextItems := locales.GetLocaleTextItems(locale) + key, err := totp.Generate(totp.GenerateOpts{ - Issuer: s.CurrentConfig().AppName, + Issuer: localeTextItems.GlobalTextItems.AppName, AccountName: user.Username, Period: twoFactorPeriod, SecretSize: twoFactorSecretSize, diff --git a/pkg/services/users.go b/pkg/services/users.go index d5eee3dc..afb753d8 100644 --- a/pkg/services/users.go +++ b/pkg/services/users.go @@ -684,14 +684,14 @@ func (s *UserService) SendVerifyEmail(user *models.User, verifyEmailToken string } templateParams := map[string]any{ - "AppName": s.CurrentConfig().AppName, + "AppName": localeTextItems.GlobalTextItems.AppName, "VerifyEmail": map[string]any{ "Title": verifyEmailTextItems.Title, "Salutation": fmt.Sprintf(verifyEmailTextItems.SalutationFormat, user.Nickname), "DescriptionAboveBtn": verifyEmailTextItems.DescriptionAboveBtn, "VerifyEmailUrl": verifyEmailUrl, "VerifyEmail": verifyEmailTextItems.VerifyEmail, - "DescriptionBelowBtn": fmt.Sprintf(verifyEmailTextItems.DescriptionBelowBtnFormat, s.CurrentConfig().AppName, expireTimeInMinutes), + "DescriptionBelowBtn": fmt.Sprintf(verifyEmailTextItems.DescriptionBelowBtnFormat, localeTextItems.GlobalTextItems.AppName, expireTimeInMinutes), }, } diff --git a/pkg/settings/setting.go b/pkg/settings/setting.go index 391a2471..9832b813 100644 --- a/pkg/settings/setting.go +++ b/pkg/settings/setting.go @@ -145,8 +145,6 @@ const ( ) const ( - defaultAppName string = "ezBookkeeping" - defaultHttpAddr string = "0.0.0.0" defaultHttpPort uint16 = 8080 defaultDomain string = "localhost" @@ -267,7 +265,6 @@ type MultiLanguageContentConfig struct { // Config represents the global setting config type Config struct { // Global - AppName string Mode SystemMode WorkingPath string @@ -595,8 +592,6 @@ func GetDefaultConfigFilePath() (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" { config.Mode = MODE_PRODUCTION } else if getConfigItemStringValue(configFile, sectionName, "mode") == "development" { diff --git a/pkg/settings/setting_container.go b/pkg/settings/setting_container.go index fe09f075..f9ad1c6f 100644 --- a/pkg/settings/setting_container.go +++ b/pkg/settings/setting_container.go @@ -1,6 +1,10 @@ package settings -import "fmt" +import ( + "fmt" + + "github.com/mayswind/ezbookkeeping/pkg/core" +) // ConfigContainer contains the current setting config type ConfigContainer struct { @@ -27,8 +31,8 @@ func (c *ConfigContainer) GetCurrentConfig() *Config { func GetUserAgent() string { if Version == "" { - return "ezBookkeeping" + return core.ApplicationName } - return fmt.Sprintf("ezBookkeeping/%s", Version) + return fmt.Sprintf("%s/%s", core.ApplicationName, Version) } diff --git a/pkg/utils/object_test.go b/pkg/utils/object_test.go index a8e7f1d3..10b9bd6a 100644 --- a/pkg/utils/object_test.go +++ b/pkg/utils/object_test.go @@ -10,8 +10,7 @@ import ( func TestClone(t *testing.T) { expectedObject := &settings.Config{ - AppName: "ezbookkeeping", - Mode: settings.MODE_PRODUCTION, + Mode: settings.MODE_PRODUCTION, DatabaseConfig: &settings.DatabaseConfig{ DatabaseType: settings.MySqlDbType, DatabaseHost: "localhost",