[add] language pack support for table

This commit is contained in:
Max 2022-08-19 23:46:57 +08:00
parent 2349d17d99
commit 30346b1f7b
13 changed files with 375 additions and 73 deletions

98
table/lang.go Normal file
View 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
}
}
}

View file

@ -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
}

View file

@ -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"])
}

View file

@ -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
}

View file

@ -0,0 +1,10 @@
ID: 序号
SN: 编码
Name: 姓名
Kind: 类型
Cat:
Dog:
Description: 介绍
Keywords: 关键词
Please input the SN: 请输入编码
type the keywords...: 关键词...

View file

@ -0,0 +1,10 @@
ID: 序號
SN: 編碼
Name: 姓名
Kind: 類型
Description: 介绍
Keywords: 關鍵詞
Cat:
Dog:
Please input the SN: 請輸入編碼
type the keywords...: 關鍵詞...

View file

@ -8,7 +8,7 @@
"layout": {
"fieldset": [
{
"columns": [{ "name": "商务负责人", "width": 24 }]
"columns": [{ "name": "name", "width": 24 }]
}
]
}

View 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": {} }
}
}

View file

@ -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 }
]
}
]

View file

@ -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": {} }
},

View file

@ -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": {} }
},

View file

@ -30,7 +30,7 @@
"edit": {
"primary": "id",
"layout": {
"fieldset": [{ "columns": [{ "name": "ID", "width": 6 }] }]
"fieldset": [{ "columns": [{ "name": "id", "width": 6 }] }]
},
"actions": { "cancel": {} }
},

View file

@ -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": {} }
},