diff --git a/api/handler_user.go b/api/handler_user.go index 5c4bf586..2a3d502f 100644 --- a/api/handler_user.go +++ b/api/handler_user.go @@ -12,6 +12,7 @@ import ( "github.com/gin-gonic/gin" "github.com/google/uuid" + "gorm.io/gorm" ) // handleLogout Add current token to blacklist @@ -60,6 +61,7 @@ func (s *Server) handleRegister(c *gin.Context) { var req struct { Email string `json:"email" binding:"required,email"` Password string `json:"password" binding:"required,min=6"` + Lang string `json:"lang"` } if err := c.ShouldBindJSON(&req); err != nil { @@ -67,6 +69,11 @@ func (s *Server) handleRegister(c *gin.Context) { return } + lang := req.Lang + if lang != "zh" && lang != "id" { + lang = "en" + } + // Check if email already exists _, err = s.store.User().GetByEmail(req.Email) if err == nil { @@ -103,7 +110,7 @@ func (s *Server) handleRegister(c *gin.Context) { } // Initialize default model and exchange configs for user - err = s.initUserDefaultConfigs(user.ID) + err = s.initUserDefaultConfigs(user.ID, lang) if err != nil { logger.Infof("Failed to initialize user default configs: %v", err) } @@ -216,8 +223,8 @@ func (s *Server) handleResetPassword(c *gin.Context) { } // initUserDefaultConfigs Initialize default configs for new user -func (s *Server) initUserDefaultConfigs(userID string) error { - if err := s.createDefaultStrategies(userID); err != nil { +func (s *Server) initUserDefaultConfigs(userID string, lang string) error { + if err := s.createDefaultStrategies(userID, lang); err != nil { logger.Warnf("Failed to create default strategies for user %s: %v", userID, err) // Non-fatal: user can create strategies manually } @@ -225,7 +232,35 @@ func (s *Server) initUserDefaultConfigs(userID string) error { return nil } -func (s *Server) createDefaultStrategies(userID string) error { +func (s *Server) createDefaultStrategies(userID string, lang string) error { + type strategyI18n struct { + name, description string + } + type strategyLocale struct { + balanced, conservative, aggressive strategyI18n + } + locales := map[string]strategyLocale{ + "zh": { + balanced: strategyI18n{"均衡策略", "系统默认策略。均衡风险收益,适合大多数市场环境。5倍杠杆,最多3个仓位。"}, + conservative: strategyI18n{"稳健策略", "系统默认策略。低杠杆保守操作,优先保护本金。3倍杠杆,专注主流资产。"}, + aggressive: strategyI18n{"积极策略", "系统默认策略。高杠杆主动交易,更广泛的币种选择,适合经验丰富的交易者。10倍杠杆,最多5个仓位。"}, + }, + "en": { + balanced: strategyI18n{"Balanced Strategy", "System default strategy. Balanced risk-reward, suitable for most market conditions. 5x leverage, up to 3 positions."}, + conservative: strategyI18n{"Conservative Strategy", "System default strategy. Low-leverage conservative trading, capital preservation first. 3x leverage, focused on major assets."}, + aggressive: strategyI18n{"Aggressive Strategy", "System default strategy. High-leverage active trading, wider asset selection, for experienced traders. 10x leverage, up to 5 positions."}, + }, + "id": { + balanced: strategyI18n{"Strategi Seimbang", "Strategi default sistem. Risiko-reward seimbang, cocok untuk sebagian besar kondisi pasar. Leverage 5x, hingga 3 posisi."}, + conservative: strategyI18n{"Strategi Konservatif", "Strategi default sistem. Trading konservatif leverage rendah, utamakan perlindungan modal. Leverage 3x, fokus aset utama."}, + aggressive: strategyI18n{"Strategi Agresif", "Strategi default sistem. Trading aktif leverage tinggi, pilihan aset lebih luas, untuk trader berpengalaman. Leverage 10x, hingga 5 posisi."}, + }, + } + locale, ok := locales[lang] + if !ok { + locale = locales["en"] + } + type strategyDef struct { name string description string @@ -235,16 +270,16 @@ func (s *Server) createDefaultStrategies(userID string) error { definitions := []strategyDef{ { - name: "均衡策略", - description: "系统默认策略。均衡风险收益,适合大多数市场环境。5倍杠杆,最多3个仓位。", + name: locale.balanced.name, + description: locale.balanced.description, isActive: true, applyConfig: func(c *store.StrategyConfig) { // Uses default config as-is }, }, { - name: "稳健策略", - description: "系统默认策略。低杠杆保守操作,优先保护本金。3倍杠杆,专注主流资产。", + name: locale.conservative.name, + description: locale.conservative.description, isActive: false, applyConfig: func(c *store.StrategyConfig) { c.RiskControl.BTCETHMaxLeverage = 3 @@ -258,8 +293,8 @@ func (s *Server) createDefaultStrategies(userID string) error { }, }, { - name: "积极策略", - description: "系统默认策略。高杠杆主动交易,更广泛的币种选择,适合经验丰富的交易者。10倍杠杆,最多5个仓位。", + name: locale.aggressive.name, + description: locale.aggressive.description, isActive: false, applyConfig: func(c *store.StrategyConfig) { c.RiskControl.BTCETHMaxLeverage = 10 @@ -276,8 +311,16 @@ func (s *Server) createDefaultStrategies(userID string) error { }, } + // GetDefaultStrategyConfig only supports zh/en; map id -> en + configLang := lang + if lang == "id" { + configLang = "en" + } + + // Pre-build all strategy objects before opening the transaction + var strategies []*store.Strategy for _, def := range definitions { - config := store.GetDefaultStrategyConfig("zh") + config := store.GetDefaultStrategyConfig(configLang) def.applyConfig(&config) strategy := &store.Strategy{ @@ -291,10 +334,16 @@ func (s *Server) createDefaultStrategies(userID string) error { if err := strategy.SetConfig(&config); err != nil { return fmt.Errorf("failed to set config for strategy %q: %w", def.name, err) } - if err := s.store.Strategy().Create(strategy); err != nil { - return fmt.Errorf("failed to create strategy %q: %w", def.name, err) - } - logger.Infof(" ✓ Created default strategy: %s (active=%v)", def.name, def.isActive) + strategies = append(strategies, strategy) } - return nil + + return s.store.Transaction(func(tx *gorm.DB) error { + for _, strategy := range strategies { + if err := tx.Create(strategy).Error; err != nil { + return fmt.Errorf("failed to create strategy %q: %w", strategy.Name, err) + } + logger.Infof(" ✓ Created default strategy: %s (active=%v)", strategy.Name, strategy.IsActive) + } + return nil + }) } diff --git a/web/src/contexts/AuthContext.tsx b/web/src/contexts/AuthContext.tsx index 803946b4..928daf6c 100644 --- a/web/src/contexts/AuthContext.tsx +++ b/web/src/contexts/AuthContext.tsx @@ -3,6 +3,7 @@ import { flushSync } from 'react-dom' import { getSystemConfig } from '../lib/config' import { reset401Flag, httpClient } from '../lib/httpClient' import { getPostAuthPath, setUserMode, type UserMode } from '../lib/onboarding' +import { useLanguage } from './LanguageContext' interface User { id: string @@ -41,6 +42,7 @@ interface AuthContextType { const AuthContext = createContext(undefined) export function AuthProvider({ children }: { children: React.ReactNode }) { + const { language } = useLanguage() const [user, setUser] = useState(null) const [token, setToken] = useState(null) const [isLoading, setIsLoading] = useState(true) @@ -208,7 +210,8 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { email: string password: string beta_code?: string - } = { email, password } + lang?: string + } = { email, password, lang: language } if (betaCode) { requestBody.beta_code = betaCode } diff --git a/web/src/pages/StrategyStudioPage.tsx b/web/src/pages/StrategyStudioPage.tsx index 17a9579f..5e4ee255 100644 --- a/web/src/pages/StrategyStudioPage.tsx +++ b/web/src/pages/StrategyStudioPage.tsx @@ -706,7 +706,7 @@ export function StrategyStudioPage() { -
+
{strategies.map((strategy) => (
-
- {strategy.name} +
+ {strategy.name}