From 2349d17d99d89c7de4cdbcf877c627ac22f28d8c Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 19 Aug 2022 21:33:48 +0800 Subject: [PATCH] [add] language pack support for model --- app/app.go | 130 +++---------------------- app/app_test.go | 6 +- lang/lang.go | 36 +++++++ lang/lang_test.go | 16 +++ model/model.go | 8 ++ model/model_test.go | 12 ++- share/types.go | 3 +- tests/langs/en-US.json | 4 - tests/langs/zh-cn/flows/hello.flow.yml | 1 + tests/langs/zh-cn/global.yml | 7 ++ tests/langs/zh-cn/models/demo.mod.yml | 1 + tests/langs/zh-hk/flows/hello.flow.yml | 1 + tests/langs/zh-hk/global.yml | 7 ++ tests/langs/zh-hk/models/demo.mod.yml | 1 + tests/models/demo.mod.json | 35 +++++++ 15 files changed, 143 insertions(+), 125 deletions(-) create mode 100644 lang/lang.go create mode 100644 lang/lang_test.go delete mode 100644 tests/langs/en-US.json create mode 100644 tests/langs/zh-cn/flows/hello.flow.yml create mode 100644 tests/langs/zh-cn/global.yml create mode 100644 tests/langs/zh-cn/models/demo.mod.yml create mode 100644 tests/langs/zh-hk/flows/hello.flow.yml create mode 100644 tests/langs/zh-hk/global.yml create mode 100644 tests/langs/zh-hk/models/demo.mod.yml create mode 100644 tests/models/demo.mod.json diff --git a/app/app.go b/app/app.go index b9c2a83b..03333b8c 100644 --- a/app/app.go +++ b/app/app.go @@ -1,35 +1,32 @@ package app import ( - "fmt" - "os" - "path/filepath" - "strings" - jsoniter "github.com/json-iterator/go" + l "github.com/yaoapp/gou/lang" "github.com/yaoapp/kun/exception" - "github.com/yaoapp/kun/log" "github.com/yaoapp/kun/maps" "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/data" + "github.com/yaoapp/yao/lang" "github.com/yaoapp/yao/share" "github.com/yaoapp/yao/xfs" ) -// langs 语言包 -var langs = map[string]map[string]string{} - -// Load 加载应用信息 +// Load Application func Load(cfg config.Config) { - Init(cfg) - LoadInfo(cfg.Root) - LoadLang(cfg) - lang := strings.ToLower(share.App.Lang) + // Load language packs + lang.Load(cfg) + + // Set language pack share.App.L = map[string]string{} - if l, has := langs[lang]; has { - share.App.L = l + if l.Default != nil { + share.App.L = l.Default.Global } + + // Load Info + LoadInfo(cfg.Root) + } // L 语言包 @@ -40,49 +37,6 @@ func L(word string) string { return word } -// Init 应用初始化 -func Init(cfg config.Config) { - - // // UI文件目录 - // if _, err := os.Stat(cfg.RootUI); os.IsNotExist(err) { - // err := os.MkdirAll(cfg.RootUI, os.ModePerm) - // if err != nil { - // xlog.Printf("创建目录失败(%s) %s", cfg.RootUI, err) - // os.Exit(1) - // } - - // content, err := data.Asset("xiang/data/index.html") - // if err != nil { - // xlog.Printf("读取文件失败(%s) %s", cfg.RootUI, err) - // os.Exit(1) - // } - - // err = ioutil.WriteFile(filepath.Join(cfg.RootUI, "/index.html"), content, os.ModePerm) - // if err != nil { - // xlog.Printf("复制默认文件失败(%s) %s", cfg.RootUI, err) - // os.Exit(1) - // } - // } - - // // 数据库目录 - // if _, err := os.Stat(cfg.RootDB); os.IsNotExist(err) { - // err := os.MkdirAll(cfg.RootDB, os.ModePerm) - // if err != nil { - // xlog.Printf("创建目录失败(%s) %s", cfg.RootDB, err) - // os.Exit(1) - // } - // } - - // // 文件数据目录 - // if _, err := os.Stat(cfg.RootData); os.IsNotExist(err) { - // err := os.MkdirAll(cfg.RootData, os.ModePerm) - // if err != nil { - // xlog.Printf("创建目录失败(%s) %s", cfg.RootData, err) - // os.Exit(1) - // } - // } -} - // LoadInfo 应用信息 func LoadInfo(root string) { info := defaultInfo() @@ -106,71 +60,15 @@ func LoadInfo(root string) { info.Icons.Set("png", xfs.Encode(fs.MustReadFile("/yao/icons/icon.png"))) } + info.L = share.App.L share.App = info } -// LoadLang 加载语言包 -func LoadLang(cfg config.Config) error { - - var defaults = []share.Script{} - if os.Getenv("YAO_DEV") != "" { - defaults = share.GetFilesFS(filepath.Join(os.Getenv("YAO_DEV"), "yao"), ".json") - } else { - defaults = share.GetFilesBin("yao", ".json") - } - - for _, lang := range defaults { - if lang.Type != "langs" { - continue - } - content := lang.Content - name := strings.ToLower(lang.Name) // 这个读取函数需要优化 - lang := map[string]string{} - err := jsoniter.Unmarshal(content, &lang) - if err != nil { - log.With(log.F{"name": name}).Error(err.Error()) - } - langs[name] = lang - } - - if share.BUILDIN { - return LoadLangBuildIn("langs") - } - return LoadLangFrom(filepath.Join(cfg.Root, "langs")) -} - // LoadLangBuildIn 从制品中读取 func LoadLangBuildIn(dir string) error { return nil } -// LoadLangFrom 从特定目录加载 -func LoadLangFrom(dir string) error { - - if share.DirNotExists(dir) { - return fmt.Errorf("%s does not exists", dir) - } - - err := share.Walk(dir, ".json", func(root, filename string) { - name := strings.ToLower(share.SpecName(root, filename)) - content := share.ReadFile(filename) - lang := map[string]string{} - err := jsoniter.Unmarshal(content, &lang) - if err != nil { - log.With(log.F{"root": root, "file": filename}).Error(err.Error()) - } - if _, has := langs[name]; !has { - langs[name] = map[string]string{} - } - for src, dst := range lang { - langs[name][src] = dst - } - }) - - return err - -} - // defaultInfo 读取默认应用信息 func defaultInfo() share.AppInfo { info := share.AppInfo{ diff --git a/app/app_test.go b/app/app_test.go index 05305342..32ea49bc 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -1,6 +1,7 @@ package app import ( + "os" "testing" "github.com/stretchr/testify/assert" @@ -9,7 +10,8 @@ import ( ) func TestLoad(t *testing.T) { + os.Setenv("YAO_LANG", "zh-cn") Load(config.Conf) - assert.Equal(t, "Yao", share.App.L["Yao"]) - assert.Equal(t, "Xiang", share.App.L["象传"]) + assert.Equal(t, "YAO", share.App.L["Yao"]) + assert.Equal(t, "象传", share.App.L["Xiang"]) } diff --git a/lang/lang.go b/lang/lang.go new file mode 100644 index 00000000..69534959 --- /dev/null +++ b/lang/lang.go @@ -0,0 +1,36 @@ +package lang + +import ( + "os" + "path/filepath" + + "github.com/yaoapp/gou/lang" + "github.com/yaoapp/kun/log" + "github.com/yaoapp/yao/config" +) + +func init() { + lang.RegisterWidget("tables", "table") + lang.RegisterWidget("charts", "chart") + lang.RegisterWidget("kanban", "kanban") +} + +// Load language packs +func Load(cfg config.Config) error { + root := filepath.Join(cfg.Root, "langs") + err := lang.Load(root) + if err != nil { + return err + } + + name := os.Getenv("YAO_LANG") + if name != "" { + if _, has := lang.Dicts[name]; !has { + log.Error("The language pack %s does not found", name) + return nil + } + lang.Pick(name).AsDefault() + } + + return nil +} diff --git a/lang/lang_test.go b/lang/lang_test.go new file mode 100644 index 00000000..68763869 --- /dev/null +++ b/lang/lang_test.go @@ -0,0 +1,16 @@ +package lang + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/yaoapp/gou/lang" + "github.com/yaoapp/yao/config" + "github.com/yaoapp/yao/share" +) + +func TestLoad(t *testing.T) { + share.DBConnect(config.Conf.DB) + Load(config.Conf) + assert.Len(t, lang.Dicts, 2) +} diff --git a/model/model.go b/model/model.go index f4fa6f56..e71e8425 100644 --- a/model/model.go +++ b/model/model.go @@ -5,6 +5,7 @@ import ( "path/filepath" "github.com/yaoapp/gou" + "github.com/yaoapp/gou/lang" "github.com/yaoapp/kun/log" "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/share" @@ -31,7 +32,14 @@ func LoadFrom(dir string, prefix string) error { _, err := gou.LoadModelReturn(string(content), name) if err != nil { log.With(log.F{"root": root, "file": filename}).Error(err.Error()) + return } + + // Apply the language pack + if lang.Default != nil { + lang.Default.Apply(gou.Models[name]) + } + }) return err diff --git a/model/model_test.go b/model/model_test.go index 52a485b3..02df055f 100644 --- a/model/model_test.go +++ b/model/model_test.go @@ -1,17 +1,23 @@ package model import ( + "os" "testing" "github.com/stretchr/testify/assert" "github.com/yaoapp/gou" "github.com/yaoapp/yao/config" + "github.com/yaoapp/yao/lang" "github.com/yaoapp/yao/share" ) func TestLoad(t *testing.T) { + + os.Setenv("YAO_LANG", "zh-hk") + lang.Load(config.Conf) share.DBConnect(config.Conf.DB) + gou.Models = make(map[string]*gou.Model) Load(config.Conf) LoadFrom("not a path", "404.") @@ -23,5 +29,9 @@ func check(t *testing.T) { for key := range gou.Models { keys = append(keys, key) } - assert.Equal(t, 10, len(keys)) + assert.Equal(t, 11, len(keys)) + + demo := gou.Select("demo") + assert.Equal(t, demo.MetaData.Name, "演示") + assert.Equal(t, demo.Columns["action"].Label, "動作") } diff --git a/share/types.go b/share/types.go index 60ec16a9..705bf6d4 100644 --- a/share/types.go +++ b/share/types.go @@ -72,8 +72,7 @@ type Page struct { // AppInfo 应用信息 type AppInfo struct { Name string `json:"name,omitempty"` - Lang string `json:"lang,omitempty"` - L map[string]string `json:"-"` // 应用的语言包 + L map[string]string `json:"-"` Short string `json:"short,omitempty"` Version string `json:"version,omitempty"` Description string `json:"description,omitempty"` diff --git a/tests/langs/en-US.json b/tests/langs/en-US.json deleted file mode 100644 index 54d43606..00000000 --- a/tests/langs/en-US.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "Yao": "Yao", - "象传应用引擎": "Yao App Engine Over load" -} diff --git a/tests/langs/zh-cn/flows/hello.flow.yml b/tests/langs/zh-cn/flows/hello.flow.yml new file mode 100644 index 00000000..e15a69fa --- /dev/null +++ b/tests/langs/zh-cn/flows/hello.flow.yml @@ -0,0 +1 @@ +Latest: 最新信息 diff --git a/tests/langs/zh-cn/global.yml b/tests/langs/zh-cn/global.yml new file mode 100644 index 00000000..61133bfe --- /dev/null +++ b/tests/langs/zh-cn/global.yml @@ -0,0 +1,7 @@ +Demo: 演示 +Phone: 电话号码 +ZipCode: 邮政编码 +Uptime: 更新时间 +Action: 动作 +Yao: YAO +Xiang: 象传 diff --git a/tests/langs/zh-cn/models/demo.mod.yml b/tests/langs/zh-cn/models/demo.mod.yml new file mode 100644 index 00000000..8eb7cc67 --- /dev/null +++ b/tests/langs/zh-cn/models/demo.mod.yml @@ -0,0 +1 @@ +SN: 编码 diff --git a/tests/langs/zh-hk/flows/hello.flow.yml b/tests/langs/zh-hk/flows/hello.flow.yml new file mode 100644 index 00000000..e15a69fa --- /dev/null +++ b/tests/langs/zh-hk/flows/hello.flow.yml @@ -0,0 +1 @@ +Latest: 最新信息 diff --git a/tests/langs/zh-hk/global.yml b/tests/langs/zh-hk/global.yml new file mode 100644 index 00000000..c820c37e --- /dev/null +++ b/tests/langs/zh-hk/global.yml @@ -0,0 +1,7 @@ +Demo: 演示 +Phone: 電話號碼 +ZipCode: 郵政編碼 +Uptime: 更新時間 +Action: 動作 +Yao: YAO +Xiang: 像傳 diff --git a/tests/langs/zh-hk/models/demo.mod.yml b/tests/langs/zh-hk/models/demo.mod.yml new file mode 100644 index 00000000..30134633 --- /dev/null +++ b/tests/langs/zh-hk/models/demo.mod.yml @@ -0,0 +1 @@ +SN: 編碼 diff --git a/tests/models/demo.mod.json b/tests/models/demo.mod.json new file mode 100644 index 00000000..e827cdcd --- /dev/null +++ b/tests/models/demo.mod.json @@ -0,0 +1,35 @@ +{ + "name": "::Demo", + "connector": "trace", + "table": { "name": "user_trace", "comment": "::Demo" }, + "columns": [ + { "label": "ID", "name": "id", "type": "ID" }, + { + "label": "::SN", + "name": "user_sn", + "type": "string", + "length": 42, + "index": true + }, + { + "label": "::Uptime", + "name": "uptime", + "type": "datetime", + "index": true + }, + { + "label": "::Action", + "name": "action", + "type": "enum", + "option": ["进入", "离开"], + "index": true + } + ], + "indexes": [ + { + "name": "user_sn_action_unique", + "type": "unique", + "columns": ["user_sn", "action"] + } + ] +}