yao/agent/i18n/i18n.go
Max c54ef71d6a ⚠️ BREAKING: Removed the Studio package and renamed Neo to Agent. Configuration file path changed from neo/neo.yml to agent/agent.yml.
Remove deprecated studio package and refactor agent integration

- Deleted the studio package, which is no longer in use, to streamline the codebase.
- Updated references in the agent and chat modules to utilize the new agent package instead of the deprecated neo package.
- Ensured that all related middleware and routing functionalities are now aligned with the agent architecture, enhancing overall system coherence.
2025-11-06 18:13:54 +08:00

222 lines
4.3 KiB
Go

package i18n
import (
"path/filepath"
"strings"
"github.com/yaoapp/gou/application"
"github.com/yaoapp/gou/fs"
"github.com/yaoapp/kun/maps"
)
// Locales the locales
var Locales = map[string]map[string]I18n{}
// I18n the i18n struct
type I18n struct {
Locale string `json:"locale,omitempty" yaml:"locale,omitempty"`
Messages map[string]any `json:"messages,omitempty" yaml:"messages,omitempty"`
}
// Map the i18n map
type Map map[string]I18n
// Parse parse the input
func (i18n I18n) Parse(input any) any {
switch in := input.(type) {
case string:
trimed := strings.TrimSpace(in)
hasExp := strings.HasPrefix(trimed, "{{") && strings.HasSuffix(trimed, "}}")
if hasExp {
exp := strings.TrimSpace(strings.TrimPrefix(strings.TrimSuffix(trimed, "}}"), "{{"))
if _, ok := i18n.Messages[exp]; ok {
return i18n.Messages[exp]
}
return exp
}
if _, ok := i18n.Messages[trimed]; ok {
return i18n.Messages[trimed]
}
return in
case map[string]any:
new := map[string]any{}
for key, value := range in {
new[key] = i18n.Parse(value)
}
return new
case []any:
new := []any{}
for _, value := range in {
new = append(new, i18n.Parse(value))
}
return new
case []string:
new := []string{}
for _, value := range in {
new = append(new, i18n.Parse(value).(string))
}
return new
}
return input
}
// GetLocales get the locales from path
func GetLocales(path string) (Map, error) {
app, err := fs.Get("app")
if err != nil {
return nil, err
}
i18ns := Map{}
localesdir := filepath.Join(path, "locales")
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"))
i18ns[name] = I18n{Locale: name, Messages: messages}
}
}
return i18ns, nil
}
// Flatten flatten the i18n map
func (i18ns Map) Flatten() Map {
new := Map{}
for lang, i18n := range i18ns {
new[lang] = I18n{Locale: lang, Messages: maps.MapOf(i18n.Messages).Dot()}
// Add short lang
parts := strings.Split(lang, "-")
// en
if parts[0] != lang {
new[parts[0]] = new[lang]
}
// us
if len(parts) > 1 {
new[parts[1]] = new[lang]
}
}
return new
}
// FlattenWithGlobal flatten the i18n map with global i18n
func (i18ns Map) FlattenWithGlobal() Map {
// New i18n map
new := Map{}
// Global i18n
globalI18ns, hasGlobal := Locales["__global__"]
// Extend the i18n map with global i18n
for lang, i18n := range i18ns {
new[lang] = I18n{Locale: lang, Messages: maps.MapOf(i18n.Messages).Dot()}
if hasGlobal {
if global, has := globalI18ns[lang]; has {
for key, value := range global.Messages {
if _, ok := new[lang].Messages[key]; !ok {
new[lang].Messages[key] = value
}
}
}
}
// Add short lang
parts := strings.Split(lang, "-")
// en
if parts[0] != lang {
new[parts[0]] = new[lang]
}
// us
if len(parts) > 1 {
new[parts[1]] = new[lang]
}
}
return new
}
// Translate translate the input
func Translate(assistantID string, locale string, input any) any {
locale = strings.ToLower(strings.TrimSpace(locale))
i18ns, has := Locales[assistantID]
if !has {
i18ns = map[string]I18n{}
}
i18n, has := i18ns[locale]
if !has {
parts := strings.Split(locale, "-")
if len(parts) > 1 {
i18n, has = i18ns[parts[1]]
}
if !has {
i18n, has = i18ns[parts[0]]
}
}
if !has {
var hasGlobal bool = false
i18ns, hasGlobal = Locales["__global__"]
if hasGlobal {
i18n, has = i18ns[locale]
}
}
if has {
return i18n.Parse(input)
}
return input
}
// TranslateGlobal translate the input with global i18n
func TranslateGlobal(locale string, input any) any {
locale = strings.ToLower(strings.TrimSpace(locale))
i18ns, has := Locales["__global__"]
if !has {
i18ns = map[string]I18n{}
}
i18n, has := i18ns[locale]
if !has {
parts := strings.Split(locale, "-")
if len(parts) > 1 {
i18n, has = i18ns[parts[1]]
}
if !has {
i18n, has = i18ns[parts[0]]
}
}
if has {
return i18n.Parse(input)
}
return input
}