package i18n import ( "context" "epic/internal/dao" "epic/internal/model/entity" "epic/internal/util" "fmt" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gtime" "sync" "time" ) // I18nEnToZh 英文->中文映射表(示例) var I18nEnToZh = map[string]string{ // 英雄名称示例 "Achates": "雅卡泰丝", "Adin": "艾庭", "Angelica": "安洁莉卡", "Bellona": "维尔萝娜", "Charles": "查尔斯", "Charlotte": "夏绿蒂", // 职业示例 "knight": "骑士", "warrior": "战士", "assassin": "潜行者", "mage": "魔导士", "ranger": "射手", "manauser": "精灵师", // 属性示例 "fire": "火", "wind": "木", "ice": "水", "dark": "暗", "light": "光", // 星座示例 "scales": "天秤座", "lion": "狮子座", "waterbearer": "水瓶座", "archer": "射手座", "crab": "巨蟹座", "twins": "双子座", "bull": "金牛座", "fish": "双鱼座", "maiden": "处女座", "goat": "摩羯座", "scorpion": "天蝎座", "ram": "白羊座", // 这里可以继续添加你的完整映射... } // I18nZhToEn 中文->英文映射表(自动生成) var I18nZhToEn = func() map[string]string { m := make(map[string]string, len(I18nEnToZh)) for k, v := range I18nEnToZh { m[v] = k } return m }() type Logic struct { cache map[string]map[string]string // lang -> key -> value mutex sync.RWMutex } func New() *Logic { return &Logic{ cache: make(map[string]map[string]string), } } // 全局i18n实例 var globalI18nLogic *Logic var globalI18nMutex sync.RWMutex func init() { globalI18nLogic = New() } // GetI18nLogic 获取全局i18n实例 func GetI18nLogic() *Logic { globalI18nMutex.RLock() defer globalI18nMutex.RUnlock() return globalI18nLogic } // LoadFromDB 从数据库加载所有翻译到缓存 func (l *Logic) LoadFromDB(ctx context.Context) error { var mappings []*entity.EpicI18NMappings err := dao.EpicI18NMappings.Ctx(ctx). Where(dao.EpicI18NMappings.Columns().Status, 1). Where(dao.EpicI18NMappings.Columns().Deleted, 0). Scan(&mappings) if err != nil { return fmt.Errorf("加载i18n数据失败: %v", err) } l.mutex.Lock() defer l.mutex.Unlock() // 重新构建缓存 l.cache = make(map[string]map[string]string) for _, m := range mappings { if l.cache[m.Language] == nil { l.cache[m.Language] = make(map[string]string) } l.cache[m.Language][m.KeyName] = m.Value } util.Info(ctx, "i18n缓存加载完成,共", len(mappings), "条记录") return nil } // Get 获取指定key的指定语言翻译 func (l *Logic) Get(ctx context.Context, lang, key string) string { l.mutex.RLock() defer l.mutex.RUnlock() if m, ok := l.cache[lang]; ok { if v, ok := m[key]; ok { return v } } return key // 找不到返回原文 } // GetBatch 批量获取翻译 func (l *Logic) GetBatch(ctx context.Context, lang string, keys []string) map[string]string { l.mutex.RLock() defer l.mutex.RUnlock() result := make(map[string]string) if m, ok := l.cache[lang]; ok { for _, key := range keys { if v, ok := m[key]; ok { result[key] = v } else { result[key] = key // 找不到返回原文 } } } else { // 语言不存在,全部返回原文 for _, key := range keys { result[key] = key } } return result } // Refresh 刷新缓存 func (l *Logic) Refresh(ctx context.Context) error { return l.LoadFromDB(ctx) } // Add 添加翻译 func (l *Logic) Add(ctx context.Context, key, lang, value, category string) error { // 先保存到数据库 _, err := dao.EpicI18NMappings.Ctx(ctx).Data(g.Map{ dao.EpicI18NMappings.Columns().KeyName: key, dao.EpicI18NMappings.Columns().Language: lang, dao.EpicI18NMappings.Columns().Value: value, dao.EpicI18NMappings.Columns().Category: category, dao.EpicI18NMappings.Columns().Status: 1, dao.EpicI18NMappings.Columns().CreateTime: gtime.Now(), dao.EpicI18NMappings.Columns().UpdateTime: gtime.Now(), }).OnDuplicate("value", value).Insert() if err != nil { return fmt.Errorf("添加翻译失败: %v", err) } // 更新缓存 l.mutex.Lock() defer l.mutex.Unlock() if l.cache[lang] == nil { l.cache[lang] = make(map[string]string) } l.cache[lang][key] = value util.Info(ctx, "添加翻译:", lang, key, "->", value) return nil } // Update 更新翻译 func (l *Logic) Update(ctx context.Context, key, lang, value string) error { // 更新数据库 _, err := dao.EpicI18NMappings.Ctx(ctx). Where(dao.EpicI18NMappings.Columns().KeyName, key). Where(dao.EpicI18NMappings.Columns().Language, lang). Data(g.Map{ dao.EpicI18NMappings.Columns().Value: value, dao.EpicI18NMappings.Columns().UpdateTime: gtime.Now(), }).Update() if err != nil { return fmt.Errorf("更新翻译失败: %v", err) } // 更新缓存 l.mutex.Lock() defer l.mutex.Unlock() if l.cache[lang] == nil { l.cache[lang] = make(map[string]string) } l.cache[lang][key] = value util.Info(ctx, "更新翻译:", lang, key, "->", value) return nil } // Delete 删除翻译 func (l *Logic) Delete(ctx context.Context, key, lang string) error { // 软删除数据库记录 _, err := dao.EpicI18NMappings.Ctx(ctx). Where(dao.EpicI18NMappings.Columns().KeyName, key). Where(dao.EpicI18NMappings.Columns().Language, lang). Data(g.Map{ dao.EpicI18NMappings.Columns().Deleted: 1, dao.EpicI18NMappings.Columns().UpdateTime: gtime.Now(), }).Update() if err != nil { return fmt.Errorf("删除翻译失败: %v", err) } // 从缓存中删除 l.mutex.Lock() defer l.mutex.Unlock() if m, ok := l.cache[lang]; ok { delete(m, key) } util.Info(ctx, "删除翻译:", lang, key) return nil } // GetByCategory 根据分类获取翻译 func (l *Logic) GetByCategory(ctx context.Context, lang, category string) (map[string]string, error) { var mappings []*entity.EpicI18NMappings err := dao.EpicI18NMappings.Ctx(ctx). Where(dao.EpicI18NMappings.Columns().Language, lang). Where(dao.EpicI18NMappings.Columns().Category, category). Where(dao.EpicI18NMappings.Columns().Status, 1). Where(dao.EpicI18NMappings.Columns().Deleted, 0). Scan(&mappings) if err != nil { return nil, fmt.Errorf("获取分类翻译失败: %v", err) } result := make(map[string]string) for _, m := range mappings { result[m.KeyName] = m.Value } return result, nil } // ImportFromMap 从map批量导入翻译 func (l *Logic) ImportFromMap(ctx context.Context, lang string, mappings map[string]string, category string) error { if len(mappings) == 0 { return nil } // 批量插入数据库 var data []g.Map for key, value := range mappings { data = append(data, g.Map{ dao.EpicI18NMappings.Columns().KeyName: key, dao.EpicI18NMappings.Columns().Language: lang, dao.EpicI18NMappings.Columns().Value: value, dao.EpicI18NMappings.Columns().Category: category, dao.EpicI18NMappings.Columns().Status: 1, dao.EpicI18NMappings.Columns().CreateTime: gtime.Now(), dao.EpicI18NMappings.Columns().UpdateTime: gtime.Now(), }) } _, err := dao.EpicI18NMappings.Ctx(ctx).Data(data).OnDuplicate("value", g.Map{ dao.EpicI18NMappings.Columns().Value: g.Map{"value": "VALUES(value)"}, dao.EpicI18NMappings.Columns().UpdateTime: gtime.Now(), }).Insert() if err != nil { return fmt.Errorf("批量导入翻译失败: %v", err) } // 更新缓存 l.mutex.Lock() defer l.mutex.Unlock() if l.cache[lang] == nil { l.cache[lang] = make(map[string]string) } for key, value := range mappings { l.cache[lang][key] = value } util.Info(ctx, "批量导入翻译完成:", lang, category, "共", len(mappings), "条") return nil } // StartAutoRefresh 启动自动刷新 func (l *Logic) StartAutoRefresh(ctx context.Context) { // 启动时加载 if err := l.LoadFromDB(ctx); err != nil { util.Error(ctx, "初始加载i18n缓存失败:", err) } // 定时刷新(每小时) go func() { ticker := time.NewTicker(1 * time.Hour) defer ticker.Stop() for { select { case <-ticker.C: if err := l.Refresh(ctx); err != nil { util.Error(ctx, "定时刷新i18n缓存失败:", err) } case <-ctx.Done(): return } } }() } // En2Zh 英文转中文(静态映射) func En2Zh(s string) string { if v, ok := I18nEnToZh[s]; ok { return v } return s } // Zh2En 中文转英文(静态映射) func Zh2En(s string) string { if v, ok := I18nZhToEn[s]; ok { return v } return s } // GetI18n 获取指定key的指定语言翻译(优先使用数据库,找不到则使用静态映射) func GetI18n(ctx context.Context, lang, key string) string { // 优先使用数据库服务 if logic := GetI18nLogic(); logic != nil { result := logic.Get(ctx, lang, key) if result != key { return result } } // 数据库找不到,使用静态映射(仅支持中英文) if lang == "zh" { return En2Zh(key) } return key } // GetZh 获取中文翻译(便捷方法) func GetZh(ctx context.Context, key string) string { return GetI18n(ctx, "zh", key) } // GetEn 获取英文翻译(便捷方法) func GetEn(ctx context.Context, key string) string { return GetI18n(ctx, "en", key) } // GetI18nBatch 批量获取翻译 func GetI18nBatch(ctx context.Context, lang string, keys []string) map[string]string { if logic := GetI18nLogic(); logic != nil { return logic.GetBatch(ctx, lang, keys) } // 降级到静态映射 result := make(map[string]string) for _, key := range keys { result[key] = GetI18n(ctx, lang, key) } return result } // GetZhBatch 批量获取中文翻译(便捷方法) func GetZhBatch(ctx context.Context, keys []string) map[string]string { return GetI18nBatch(ctx, "zh", keys) } // GetEnBatch 批量获取英文翻译(便捷方法) func GetEnBatch(ctx context.Context, keys []string) map[string]string { return GetI18nBatch(ctx, "en", keys) } // RefreshI18n 刷新i18n缓存 func RefreshI18n(ctx context.Context) error { if logic := GetI18nLogic(); logic != nil { return logic.Refresh(ctx) } return nil } // AddI18n 添加翻译 func AddI18n(ctx context.Context, key, lang, value, category string) error { if logic := GetI18nLogic(); logic != nil { return logic.Add(ctx, key, lang, value, category) } return nil } // ImportI18nFromMap 从map批量导入翻译 func ImportI18nFromMap(ctx context.Context, lang string, mappings map[string]string, category string) error { if logic := GetI18nLogic(); logic != nil { return logic.ImportFromMap(ctx, lang, mappings, category) } return nil }