[add] language pack support for table
This commit is contained in:
parent
2349d17d99
commit
30346b1f7b
13 changed files with 375 additions and 73 deletions
98
table/lang.go
Normal file
98
table/lang.go
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
package table
|
||||
|
||||
// Lang for applying a language pack
|
||||
func (table *Table) Lang(trans func(widget string, inst string, value *string) bool) {
|
||||
inst := table.Table
|
||||
widget := "table"
|
||||
|
||||
trans(widget, inst, &table.Name)
|
||||
trans(widget, inst, &table.Decription)
|
||||
|
||||
// Columns
|
||||
for name, column := range table.Columns {
|
||||
new := name
|
||||
trans(widget, inst, &new)
|
||||
trans(widget, inst, &column.Label)
|
||||
|
||||
// Props
|
||||
transMap(widget, inst, column.Edit.Props, trans)
|
||||
transMap(widget, inst, column.View.Props, trans)
|
||||
transMap(widget, inst, column.Form.Props, trans)
|
||||
|
||||
delete(table.Columns, name)
|
||||
table.Columns[new] = column
|
||||
}
|
||||
|
||||
// Filters
|
||||
for name, filter := range table.Filters {
|
||||
new := name
|
||||
trans(widget, inst, &new)
|
||||
trans(widget, inst, &filter.Label)
|
||||
delete(table.Filters, name)
|
||||
|
||||
// Props
|
||||
transMap(widget, inst, filter.Input.Props, trans)
|
||||
table.Filters[new] = filter
|
||||
}
|
||||
|
||||
// List
|
||||
transMap(widget, inst, table.List.Layout, trans)
|
||||
transMap(widget, inst, table.List.Option, trans)
|
||||
|
||||
// Edit
|
||||
transMap(widget, inst, table.Edit.Layout, trans)
|
||||
transMap(widget, inst, table.Edit.Option, trans)
|
||||
}
|
||||
|
||||
func transMap(widget string, inst string, values map[string]interface{}, trans func(widget string, inst string, value *string) bool) {
|
||||
for key, value := range values {
|
||||
|
||||
switch value.(type) {
|
||||
|
||||
case string:
|
||||
v := value.(string)
|
||||
trans(widget, inst, &v)
|
||||
values[key] = v
|
||||
break
|
||||
|
||||
case []interface{}:
|
||||
v := value.([]interface{})
|
||||
transArr(widget, inst, v, trans)
|
||||
values[key] = v
|
||||
break
|
||||
|
||||
case map[string]interface{}:
|
||||
v := value.(map[string]interface{})
|
||||
transMap(widget, inst, v, trans)
|
||||
values[key] = v
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func transArr(widget string, inst string, values []interface{}, trans func(widget string, inst string, value *string) bool) {
|
||||
for key, value := range values {
|
||||
switch value.(type) {
|
||||
|
||||
case string:
|
||||
v := value.(string)
|
||||
trans(widget, inst, &v)
|
||||
values[key] = v
|
||||
break
|
||||
|
||||
case []interface{}:
|
||||
v := value.([]interface{})
|
||||
transArr(widget, inst, v, trans)
|
||||
values[key] = v
|
||||
break
|
||||
|
||||
case map[string]interface{}:
|
||||
v := value.(map[string]interface{})
|
||||
transMap(widget, inst, v, trans)
|
||||
values[key] = v
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/xuri/excelize/v2"
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/gou/helper"
|
||||
"github.com/yaoapp/gou/lang"
|
||||
"github.com/yaoapp/kun/any"
|
||||
"github.com/yaoapp/kun/exception"
|
||||
"github.com/yaoapp/kun/log"
|
||||
|
|
@ -172,7 +173,20 @@ func LoadTable(source string, name string) (*Table, error) {
|
|||
table.loadColumns()
|
||||
table.loadFilters()
|
||||
table.loadAPIs()
|
||||
|
||||
err = table.Validate()
|
||||
if err != nil {
|
||||
log.Error("[Table] %s is not valid: %s ", table.Table, err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Tables[name] = &table
|
||||
|
||||
// Apply a language pack
|
||||
if lang.Default != nil {
|
||||
lang.Default.Apply(Tables[name])
|
||||
}
|
||||
|
||||
return Tables[name], nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,22 @@
|
|||
package table
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/yaoapp/yao/config"
|
||||
"github.com/yaoapp/yao/lang"
|
||||
"github.com/yaoapp/yao/model"
|
||||
"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)
|
||||
share.Load(config.Conf)
|
||||
model.Load(config.Conf)
|
||||
|
|
@ -48,5 +54,14 @@ func check(t *testing.T) {
|
|||
for key := range Tables {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
assert.Equal(t, 9, len(keys))
|
||||
assert.Equal(t, 10, len(keys))
|
||||
|
||||
demo := Select("demo")
|
||||
assert.NotNil(t, demo.Columns["類型"])
|
||||
assert.NotNil(t, demo.Columns["類型"].Edit.Props["options"])
|
||||
|
||||
options := demo.Columns["類型"].Edit.Props["options"].([]interface{})
|
||||
opt1 := options[0].(map[string]interface{})
|
||||
assert.Equal(t, "貓", opt1["label"])
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,132 @@
|
|||
package table
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Validate 校验表格格式
|
||||
// func (table Table) Validate() error {
|
||||
// return nil
|
||||
// }
|
||||
func (table Table) Validate() error {
|
||||
err := table.validateList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = table.validateEdit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (table Table) validateEdit() error {
|
||||
if table.Edit.Layout == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
fieldset, ok := table.Edit.Layout["fieldset"].([]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("edit.layout.columns is required")
|
||||
}
|
||||
|
||||
for idx, set := range fieldset {
|
||||
set, ok := set.(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("edit.layout.fieldset.%d format error", idx)
|
||||
}
|
||||
|
||||
columns, ok := set["columns"].([]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("edit.layout.fieldset.%d.columns format error", idx)
|
||||
}
|
||||
|
||||
for cidx, column := range columns {
|
||||
col, ismap := column.(map[string]interface{})
|
||||
name, isstr := column.(string)
|
||||
if !ismap && !isstr {
|
||||
return fmt.Errorf("edit.layout.fieldset.%d.columns.%d format error", idx, cidx)
|
||||
}
|
||||
|
||||
if ismap {
|
||||
v, has := col["name"]
|
||||
if !has {
|
||||
return fmt.Errorf("edit.layout.fieldset.%d.columns.%d.name is required", idx, cidx)
|
||||
}
|
||||
namestr, ok := v.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("edit.layout.fieldset.%d.columns.%d.name format error", idx, cidx)
|
||||
}
|
||||
name = namestr
|
||||
}
|
||||
|
||||
if _, has := table.Columns[name]; !has {
|
||||
return fmt.Errorf("edit.layout.fieldset.%d.columns.%d.name %s is not found in columns", idx, cidx, name)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (table Table) validateList() error {
|
||||
|
||||
if table.List.Layout == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// table.List.Layout
|
||||
columns, ok := table.List.Layout["columns"].([]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("list.layout.columns is required")
|
||||
}
|
||||
|
||||
for idx, column := range columns {
|
||||
|
||||
col, ismap := column.(map[string]interface{})
|
||||
name, isstr := column.(string)
|
||||
if !ismap && !isstr {
|
||||
return fmt.Errorf("list.layout.columns.%d format error", idx)
|
||||
}
|
||||
|
||||
if ismap {
|
||||
v, has := col["name"]
|
||||
if !has {
|
||||
return fmt.Errorf("list.layout.columns.%d.name is required", idx)
|
||||
}
|
||||
namestr, ok := v.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("list.layout.columns.%d.name format error", idx)
|
||||
}
|
||||
name = namestr
|
||||
}
|
||||
|
||||
if _, has := table.Columns[name]; !has {
|
||||
return fmt.Errorf("list.layout.columns.%d.name %s is not found in columns", idx, name)
|
||||
}
|
||||
}
|
||||
|
||||
filters, ok := table.List.Layout["filters"].([]interface{})
|
||||
if ok {
|
||||
for idx, fliter := range filters {
|
||||
fli, ok := fliter.(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("list.layout.fliters.%d format error", idx)
|
||||
}
|
||||
|
||||
name, has := fli["name"]
|
||||
if !has {
|
||||
return fmt.Errorf("list.layout.fliters.%d.name is required", idx)
|
||||
}
|
||||
|
||||
namestr, ok := name.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("list.layout.fliters.%d.name format error", idx)
|
||||
}
|
||||
|
||||
if _, has := table.Filters[namestr]; !has {
|
||||
return fmt.Errorf("list.layout.fliters.%d.name %s is not found in fliters", idx, namestr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
10
tests/langs/zh-cn/tables/demo.yml
Normal file
10
tests/langs/zh-cn/tables/demo.yml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
ID: 序号
|
||||
SN: 编码
|
||||
Name: 姓名
|
||||
Kind: 类型
|
||||
Cat: 猫
|
||||
Dog: 狗
|
||||
Description: 介绍
|
||||
Keywords: 关键词
|
||||
Please input the SN: 请输入编码
|
||||
type the keywords...: 关键词...
|
||||
10
tests/langs/zh-hk/tables/demo.yml
Normal file
10
tests/langs/zh-hk/tables/demo.yml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
ID: 序號
|
||||
SN: 編碼
|
||||
Name: 姓名
|
||||
Kind: 類型
|
||||
Description: 介绍
|
||||
Keywords: 關鍵詞
|
||||
Cat: 貓
|
||||
Dog: 狗
|
||||
Please input the SN: 請輸入編碼
|
||||
type the keywords...: 關鍵詞...
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"layout": {
|
||||
"fieldset": [
|
||||
{
|
||||
"columns": [{ "name": "商务负责人", "width": 24 }]
|
||||
"columns": [{ "name": "name", "width": 24 }]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
85
tests/tables/demo.tab.json
Normal file
85
tests/tables/demo.tab.json
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
{
|
||||
"name": "::Demo",
|
||||
"version": "1.0.0",
|
||||
"decription": "::Demo",
|
||||
"bind": { "model": "demo" },
|
||||
"apis": {},
|
||||
"columns": {
|
||||
"::ID": {
|
||||
"label": "::ID",
|
||||
"view": { "type": "label", "props": { "value": ":id" } }
|
||||
},
|
||||
"::SN": {
|
||||
"label": "::SN",
|
||||
"view": { "type": "label", "props": { "value": ":sn" } },
|
||||
"edit": {
|
||||
"type": "input",
|
||||
"props": { "value": ":sn", "placeholder": "::Please input the SN" }
|
||||
}
|
||||
},
|
||||
"::Name": {
|
||||
"label": "::Name",
|
||||
"view": { "type": "label", "props": { "value": ":name" } },
|
||||
"edit": { "type": "input", "props": { "value": ":name" } }
|
||||
},
|
||||
"::Kind": {
|
||||
"label": "::Kind",
|
||||
"view": { "type": "label", "props": { "value": ":kind" } },
|
||||
"edit": {
|
||||
"type": "select",
|
||||
"props": {
|
||||
"value": ":kind",
|
||||
"options": [
|
||||
{ "label": "::Cat", "value": "cat" },
|
||||
{ "label": "::Dog", "value": "dog" }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"::Description": {
|
||||
"label": "::Description",
|
||||
"view": { "type": "label", "props": { "value": ":desc" } },
|
||||
"edit": { "type": "textArea", "props": { "value": ":desc", "rows": 4 } }
|
||||
}
|
||||
},
|
||||
"filters": {
|
||||
"::Keywords": {
|
||||
"label": "::Keywords",
|
||||
"bind": "where.name.match",
|
||||
"input": {
|
||||
"type": "input",
|
||||
"props": { "placeholder": "::type the keywords..." }
|
||||
}
|
||||
}
|
||||
},
|
||||
"list": {
|
||||
"primary": "id",
|
||||
"layout": {
|
||||
"columns": [
|
||||
{ "name": "::ID", "width": 80 },
|
||||
{ "name": "::SN", "width": 100 },
|
||||
{ "name": "::Name", "width": 200 },
|
||||
{ "name": "::Kind" }
|
||||
],
|
||||
"filters": [{ "name": "::Keywords" }]
|
||||
},
|
||||
"actions": { "pagination": { "props": { "showTotal": true } } },
|
||||
"option": { "operation": { "unfold": true } }
|
||||
},
|
||||
"edit": {
|
||||
"primary": "id",
|
||||
"layout": {
|
||||
"fieldset": [
|
||||
{
|
||||
"columns": [
|
||||
{ "name": "::SN", "width": 8 },
|
||||
{ "name": "::Name", "width": 8 },
|
||||
{ "name": "::Kind", "width": 8 },
|
||||
{ "name": "::Description", "width": 24 }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"actions": { "cancel": {}, "save": {}, "delete": {} }
|
||||
}
|
||||
}
|
||||
|
|
@ -11,47 +11,13 @@
|
|||
"list": {
|
||||
"primary": "id",
|
||||
"layout": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "名称",
|
||||
"width": "240px"
|
||||
},
|
||||
{
|
||||
"name": "父节点"
|
||||
},
|
||||
{
|
||||
"name": "图标"
|
||||
},
|
||||
{
|
||||
"name": "状态"
|
||||
},
|
||||
{
|
||||
"name": "路由"
|
||||
},
|
||||
{
|
||||
"name": "排列"
|
||||
},
|
||||
{
|
||||
"name": "block布局"
|
||||
},
|
||||
{
|
||||
"name": "显示"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"name": "名称",
|
||||
"width": 6
|
||||
}
|
||||
]
|
||||
"columns": [{ "name": "name", "width": "240px" }],
|
||||
"filters": [{ "name": "name", "width": 6 }]
|
||||
},
|
||||
"actions": {
|
||||
"create": {
|
||||
"type": "button",
|
||||
"props": {
|
||||
"label": "新建菜单",
|
||||
"icon": "fas fa-plus"
|
||||
}
|
||||
"props": { "label": "新建菜单", "icon": "fas fa-plus" }
|
||||
},
|
||||
"view": {},
|
||||
"edit": {},
|
||||
|
|
@ -75,30 +41,8 @@
|
|||
"title": "基础信息",
|
||||
"description": "",
|
||||
"columns": [
|
||||
{
|
||||
"name": "名称",
|
||||
"width": 6
|
||||
},
|
||||
{
|
||||
"name": "图标",
|
||||
"width": 6
|
||||
},
|
||||
{
|
||||
"name": "路由",
|
||||
"width": 6
|
||||
},
|
||||
{
|
||||
"name": "排列",
|
||||
"width": 6
|
||||
},
|
||||
{
|
||||
"name": "block布局",
|
||||
"width": 6
|
||||
},
|
||||
{
|
||||
"name": "显示",
|
||||
"width": 6
|
||||
}
|
||||
{ "name": "name", "width": 6 },
|
||||
{ "name": "id", "width": 6 }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"list": {
|
||||
"primary": "id",
|
||||
"layout": {
|
||||
"columns": [{ "name": "ID", "width": 6 }],
|
||||
"columns": [{ "name": "id", "width": 6 }],
|
||||
"filters": []
|
||||
},
|
||||
"actions": {}
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
"edit": {
|
||||
"primary": "id",
|
||||
"layout": {
|
||||
"fieldset": [{ "columns": [{ "name": "ID", "width": 6 }] }]
|
||||
"fieldset": [{ "columns": [{ "name": "id", "width": 6 }] }]
|
||||
},
|
||||
"actions": { "cancel": {} }
|
||||
},
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"list": {
|
||||
"primary": "id",
|
||||
"layout": {
|
||||
"columns": [{ "name": "ID", "width": 6 }],
|
||||
"columns": [{ "name": "id", "width": 6 }],
|
||||
"filters": []
|
||||
},
|
||||
"actions": {}
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
"edit": {
|
||||
"primary": "id",
|
||||
"layout": {
|
||||
"fieldset": [{ "columns": [{ "name": "ID", "width": 6 }] }]
|
||||
"fieldset": [{ "columns": [{ "name": "id", "width": 6 }] }]
|
||||
},
|
||||
"actions": { "cancel": {} }
|
||||
},
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
"edit": {
|
||||
"primary": "id",
|
||||
"layout": {
|
||||
"fieldset": [{ "columns": [{ "name": "ID", "width": 6 }] }]
|
||||
"fieldset": [{ "columns": [{ "name": "id", "width": 6 }] }]
|
||||
},
|
||||
"actions": { "cancel": {} }
|
||||
},
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"list": {
|
||||
"primary": "id",
|
||||
"layout": {
|
||||
"columns": [{ "name": "ID", "width": 6 }],
|
||||
"columns": [{ "name": "id", "width": 6 }],
|
||||
"filters": []
|
||||
},
|
||||
"actions": {}
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
"edit": {
|
||||
"primary": "id",
|
||||
"layout": {
|
||||
"fieldset": [{ "columns": [{ "name": "ID", "width": 6 }] }]
|
||||
"fieldset": [{ "columns": [{ "name": "id", "width": 6 }] }]
|
||||
},
|
||||
"actions": { "cancel": {} }
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue