From 1b921cf7b072f7945c76bfac8ff4b65fe6e4deff Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 25 May 2025 10:51:02 +0800 Subject: [PATCH] Enhance i18n support and refactor API response handling in assistant functions - Introduced global i18n initialization and connector setup in the Load function for better localization support. - Refactored handleAssistantList, handleAssistantDetail, and handleAssistantTags functions to utilize the new Translate method for improved response translation based on user locale. - Simplified locale handling by removing redundant code and centralizing translation logic. --- neo/api.go | 50 +++++++++++---------- neo/assistant/i18n.go | 100 ++++++++++++++++++++++++++++++++++++++++++ neo/assistant/load.go | 35 ++------------- neo/load.go | 45 +++++++++++++++++++ 4 files changed, 175 insertions(+), 55 deletions(-) diff --git a/neo/api.go b/neo/api.go index 6ed5aefd..349c6b6a 100644 --- a/neo/api.go +++ b/neo/api.go @@ -889,22 +889,15 @@ func (neo *DSL) handleAssistantList(c *gin.Context) { return } + // Translate the response locale := "en-us" // Default locale + if loc := c.Query("locale"); loc != "" { + locale = strings.ToLower(strings.TrimSpace(loc)) + } for i, ast := range response.Data { id := ast["assistant_id"].(string) - if locales, ok := assistant.Locales[id]; ok { - if loc := c.Query("locale"); loc != "" { - loc = strings.ToLower(strings.TrimSpace(loc)) - if _, ok := locales[loc]; ok { - locale = loc - } - } - if i18n, ok := locales[locale]; ok { - response.Data[i] = i18n.Parse(ast).(map[string]interface{}) - } - } + response.Data[i] = assistant.Translate(locale, id, ast).(map[string]interface{}) } - c.JSON(200, response) c.Done() } @@ -995,18 +988,12 @@ func (neo *DSL) handleAssistantDetail(c *gin.Context) { } locale := "en-us" // Default locale - id := response.Data[0]["assistant_id"].(string) - if locales, ok := assistant.Locales[id]; ok { - if loc := c.Query("locale"); loc != "" { - loc = strings.ToLower(strings.TrimSpace(loc)) - if _, ok := locales[loc]; ok { - locale = loc - } - } - if i18n, ok := locales[locale]; ok { - response.Data[0] = i18n.Parse(response.Data[0]).(map[string]interface{}) - } + // Translate the response + if loc := c.Query("locale"); loc != "" { + locale = strings.ToLower(strings.TrimSpace(loc)) } + id := response.Data[0]["assistant_id"].(string) + response.Data[0] = assistant.Translate(locale, id, response.Data[0]).(map[string]interface{}) c.JSON(200, map[string]interface{}{"data": response.Data[0]}) c.Done() @@ -1118,6 +1105,21 @@ func (neo *DSL) handleAssistantTags(c *gin.Context) { return } - c.JSON(200, gin.H{"data": tags}) + // Translate the tags + locale := "en-us" // Default locale + if loc := c.Query("locale"); loc != "" { + locale = strings.ToLower(strings.TrimSpace(loc)) + } + + // Translate the tags + items := []map[string]interface{}{} + for _, value := range tags { + items = append(items, map[string]interface{}{ + "label": assistant.Translate(locale, "", value).(string), + "key": value, + }) + } + + c.JSON(200, gin.H{"data": items}) c.Done() } diff --git a/neo/assistant/i18n.go b/neo/assistant/i18n.go index bb1d455e..93a27307 100644 --- a/neo/assistant/i18n.go +++ b/neo/assistant/i18n.go @@ -1,7 +1,12 @@ package assistant import ( + "path/filepath" "strings" + + "github.com/yaoapp/gou/application" + "github.com/yaoapp/gou/fs" + "github.com/yaoapp/kun/maps" ) // Locales the locales @@ -49,3 +54,98 @@ func (i18n I18n) Parse(input any) any { return input } + +// GetI18n load the i18n from path +func GetI18n(path string) (map[string]I18n, error) { + app, err := fs.Get("app") + if err != nil { + return nil, err + } + + // Get the global i18n + globalI18ns, hasGlobal := Locales["__global__"] + // i18ns + localesdir := filepath.Join(path, "locales") + var i18ns map[string]I18n = map[string]I18n{} + if has, _ := app.Exists(localesdir); has { + locales, err := app.ReadDir(localesdir, true) + if err != nil { + return nil, err + } + + // load locales + for _, locale := range locales { + localeData, err := app.ReadFile(locale) + if err != nil { + return nil, err + } + var messages maps.Map = map[string]any{} + err = application.Parse(locale, localeData, &messages) + if err != nil { + return nil, err + } + + name := strings.ToLower(strings.TrimSuffix(filepath.Base(locale), ".yml")) + // Merge the global i18n + if hasGlobal { + global, has := globalI18ns[name] + if has { + for key, value := range global.Messages { + if _, ok := messages[key]; !ok { + messages[key] = value + } + } + } + } + + i18ns[name] = I18n{Locale: name, Messages: messages.Dot()} + namer := strings.Split(name, "-") + if len(namer) > 1 { + // Merge the global i18n + if hasGlobal { + global, has := globalI18ns[namer[0]] + if has { + for key, value := range global.Messages { + if _, ok := messages[key]; !ok { + messages[key] = value + } + } + } + } + i18ns[namer[0]] = I18n{Locale: name, Messages: messages.Dot()} + } + + } + } + return i18ns, nil +} + +// Translate translate the input +func Translate(locale string, id string, input any) any { + + locale = strings.ToLower(strings.TrimSpace(locale)) + i18ns, has := Locales[id] + if !has { + i18ns = map[string]I18n{} + } + + i18n, has := i18ns[locale] + if !has { + namer := strings.Split(locale, "-") + lang := namer[0] + i18n, has = i18ns[lang] + } + if !has { + var hasGlobal bool = false + i18ns, hasGlobal = Locales["__global__"] + if hasGlobal { + i18n, has = i18ns[locale] + } + } + + if has { + return i18n.Parse(input) + } + + return input +} diff --git a/neo/assistant/load.go b/neo/assistant/load.go index 9e9b9f31..4a50ae6f 100644 --- a/neo/assistant/load.go +++ b/neo/assistant/load.go @@ -14,7 +14,6 @@ import ( "github.com/yaoapp/gou/fs" "github.com/yaoapp/gou/rag/driver" v8 "github.com/yaoapp/gou/runtime/v8" - "github.com/yaoapp/kun/maps" "github.com/yaoapp/yao/neo/store" neovision "github.com/yaoapp/yao/neo/vision" "github.com/yaoapp/yao/openai" @@ -315,37 +314,11 @@ func LoadPath(path string) (*Assistant, error) { } // i18ns - localesdir := filepath.Join(path, "locales") - var i18ns map[string]I18n = map[string]I18n{} - if has, _ := app.Exists(localesdir); has { - locales, err := app.ReadDir(localesdir, true) - if err != nil { - return nil, err - } - - // load locales - for _, locale := range locales { - localeData, err := app.ReadFile(locale) - if err != nil { - return nil, err - } - var messages maps.Map - err = application.Parse(locale, localeData, &messages) - if err != nil { - return nil, err - } - if messages != nil { - name := strings.ToLower(strings.TrimSuffix(filepath.Base(locale), ".yml")) - i18ns[name] = I18n{Locale: name, Messages: messages.Dot()} - namer := strings.Split(name, "-") - if len(namer) > 1 { - i18ns[namer[0]] = I18n{Locale: name, Messages: messages.Dot()} - } - } - } - data["locales"] = i18ns + locales, err := GetI18n(path) + if err != nil { + return nil, err } - + data["locales"] = locales return loadMap(data) } diff --git a/neo/load.go b/neo/load.go index fa5dd4a8..b8c239d2 100644 --- a/neo/load.go +++ b/neo/load.go @@ -63,6 +63,18 @@ func Load(cfg config.Config) error { return err } + // Initialize Connectors + err = initConnectors() + if err != nil { + return err + } + + // Initialize Global I18n + err = initGlobalI18n() + if err != nil { + return err + } + // Initialize Assistant err = initAssistant() if err != nil { @@ -72,6 +84,39 @@ func Load(cfg config.Config) error { return nil } +// initGlobalI18n initialize the global i18n +func initGlobalI18n() error { + locales, err := assistant.GetI18n("neo") + if err != nil { + return err + } + assistant.Locales["__global__"] = locales + return nil +} + +// initConnectors initialize the connectors +func initConnectors() error { + path := filepath.Join("neo", "connectors.yml") + if exists, _ := application.App.Exists(path); !exists { + return nil + } + + // Open the connectors + bytes, err := application.App.Read(path) + if err != nil { + return err + } + + var connectors map[string]assistant.ConnectorSetting = map[string]assistant.ConnectorSetting{} + err = application.Parse("connectors.yml", bytes, &connectors) + if err != nil { + return err + } + + Neo.Connectors = connectors + return nil +} + // initStore initialize the store func initStore() error {