From 8e8a0ac8853d310a0bdb70da1c2d2f42c2a23431 Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 19 Jul 2024 07:20:57 +0800 Subject: [PATCH 1/3] Fix trans passing bug in SUI components --- sui/core/build.go | 210 +++---------------------------- sui/core/context.go | 8 ++ sui/core/translate.go | 205 ++++++++++++++++++++++++++++++ sui/core/types.go | 7 ++ sui/storages/local/local_test.go | 4 +- 5 files changed, 241 insertions(+), 193 deletions(-) create mode 100644 sui/core/translate.go diff --git a/sui/core/build.go b/sui/core/build.go index bccfc5dfb..2a0062d68 100644 --- a/sui/core/build.go +++ b/sui/core/build.go @@ -38,6 +38,7 @@ func (page *Page) Build(ctx *BuildContext, option *BuildOption) (*goquery.Docume ctx.sequence++ + page.transCtx = NewTranslateContext() namespace := Namespace(page.Route, ctx.sequence, option.ScriptMinify) page.namespace = namespace @@ -73,8 +74,7 @@ func (page *Page) Build(ctx *BuildContext, option *BuildOption) (*goquery.Docume } // Add the translation marks - sequence := 1 - err = page.TranslateMarks(ctx, doc, &sequence) + err = page.TranslateDocument(doc) if err != nil { return nil, warnings, err } @@ -85,21 +85,25 @@ func (page *Page) Build(ctx *BuildContext, option *BuildOption) (*goquery.Docume if script.Source == "" { continue } - trans, keys, err := page.translateScript(script.Source, &sequence) + trans, keys, err := page.translateScript(script.Source) if err != nil { return nil, ctx.warnings, err } if len(keys) > 0 { - ctx.translations = append(ctx.translations, trans...) + page.transCtx.translations = append(page.transCtx.translations, trans...) scripts[i].Attrs = append(script.Attrs, html.Attribute{Key: "s:trans-script", Val: strings.Join(keys, ",")}) } } } + if ctx.translations == nil { + ctx.translations = []Translation{} + } + ctx.translations = append(ctx.translations, page.transCtx.translations...) + // Append the scripts and styles ctx.scripts = append(ctx.scripts, scripts...) ctx.styles = append(ctx.styles, styles...) - return doc, ctx.warnings, err } @@ -134,6 +138,7 @@ func (page *Page) BuildAsComponent(sel *goquery.Selection, ctx *BuildContext, op namespace := Namespace(name, ctx.sequence, option.ScriptMinify) component := ComponentName(name, option.ScriptMinify) + page.transCtx = NewTranslateContext() page.namespace = namespace attrs := []html.Attribute{ {Key: "s:ns", Val: namespace}, @@ -142,6 +147,11 @@ func (page *Page) BuildAsComponent(sel *goquery.Selection, ctx *BuildContext, op {Key: "s:parent", Val: page.parent.namespace}, } + err := page.parent.TranslateSelection(sel) // Translate the component instance + if err != nil { + return "", err + } + ctx.sequence++ var opt = *option opt.IgnoreDocument = true @@ -178,7 +188,6 @@ func (page *Page) BuildAsComponent(sel *goquery.Selection, ctx *BuildContext, op // Pass the component props first := body.Children().First() - page.copyProps(ctx, sel, first, attrs...) page.copySlots(sel, first) page.copyChildren(sel, first) @@ -187,8 +196,7 @@ func (page *Page) BuildAsComponent(sel *goquery.Selection, ctx *BuildContext, op data.ReplaceSelectionUse(slotRe, first) // Add the translation marks - sequence := 1 - err = page.TranslateMarks(ctx, doc, &sequence) + err = page.TranslateDocument(doc) if err != nil { return "", err } @@ -199,12 +207,12 @@ func (page *Page) BuildAsComponent(sel *goquery.Selection, ctx *BuildContext, op if script.Source == "" { continue } - trans, keys, err := page.translateScript(script.Source, &sequence) + trans, keys, err := page.translateScript(script.Source) if err != nil { return "", err } if len(keys) > 0 { - ctx.translations = append(ctx.translations, trans...) + page.transCtx.translations = append(page.transCtx.translations, trans...) scripts[i].Attrs = append(script.Attrs, html.Attribute{Key: "s:trans-script", Val: strings.Join(keys, ",")}) } } @@ -214,11 +222,7 @@ func (page *Page) BuildAsComponent(sel *goquery.Selection, ctx *BuildContext, op ctx.scripts = append(ctx.scripts, scripts...) ctx.styles = append(ctx.styles, styles...) - source, err = body.Html() - if err != nil { - return "", err - } - sel.ReplaceWithHtml(source) + sel.ReplaceWithSelection(body.Contents()) ctx.components[page.Route] = true return source, nil } @@ -562,179 +566,3 @@ func addTabToEachLine(input string, prefix ...string) string { return strings.Join(lines, "\n") } - -// TranslateMarks add the translation marks to the document -func (page *Page) TranslateMarks(ctx *BuildContext, doc *goquery.Document, sequence *int) error { - - if doc.Length() == 0 { - return nil - } - - if ctx == nil { - ctx = NewBuildContext(nil) - } - - if ctx.translations == nil { - ctx.translations = []Translation{} - } - - root := doc.First() - translations, err := page.translateNode(root.Nodes[0], sequence) - if err != nil { - return err - } - - if translations != nil { - ctx.translations = append(ctx.translations, translations...) - } - return nil -} - -func (page *Page) translateNode(node *html.Node, sequence *int) ([]Translation, error) { - - translations := []Translation{} - - switch node.Type { - case html.DocumentNode: - for child := node.FirstChild; child != nil; child = child.NextSibling { - trans, err := page.translateNode(child, sequence) - if err != nil { - return nil, err - } - translations = append(translations, trans...) - } - break - - case html.ElementNode: - - sel := goquery.NewDocumentFromNode(node) - // Script - if node.Data == "script" { - if _, has := sel.Attr("s:trans-script"); has { - break - } - code := goquery.NewDocumentFromNode(node).Text() - trans, keys, err := page.translateScript(code, sequence) - if err != nil { - return nil, err - } - if len(keys) > 0 { - raw := strings.Join(keys, ",") - sel.SetAttr("s:trans-script", raw) - translations = append(translations, trans...) - } - break - } - - for _, attr := range node.Attr { - - if _, has := sel.Attr("s:trans-attr-" + attr.Key); has { - continue - } - - trans, keys, err := page.translateText(attr.Val, sequence, "attr") - if err != nil { - return nil, err - } - if len(keys) > 0 { - raw := strings.Join(keys, ",") - sel.SetAttr("s:trans-attr-"+attr.Key, raw) - translations = append(translations, trans...) - } - - } - - // Node Attributes - for child := node.FirstChild; child != nil; child = child.NextSibling { - trans, err := page.translateNode(child, sequence) - if err != nil { - return nil, err - } - translations = append(translations, trans...) - } - break - - case html.TextNode: - parentSel := goquery.NewDocumentFromNode(node.Parent) - if _, has := parentSel.Attr("s:trans"); has { - if _, has := parentSel.Attr("s:trans-node"); has { - break - } - - key := TranslationKey(page.Route, *sequence) - message := strings.TrimSpace(node.Data) - if message != "" { - translations = append(translations, Translation{ - Key: key, - Message: message, - Type: "text", - }) - parentSel.SetAttr("s:trans-node", key) - *sequence = *sequence + 1 - } - parentSel.SetAttr("s:trans-escape", "true") - } - - if _, has := parentSel.Attr("s:trans-text"); has { - break - } - trans, keys, err := page.translateText(node.Data, sequence, "text") - if err != nil { - return nil, err - } - if len(keys) > 0 { - raw := strings.Join(keys, ",") - parentSel.SetAttr("s:trans-text", raw) - translations = append(translations, trans...) - } - break - } - - return translations, nil -} - -func (page *Page) translateText(text string, sequence *int, transType string) ([]Translation, []string, error) { - translations := []Translation{} - matches := stmtRe.FindAllStringSubmatch(text, -1) - keys := []string{} - for _, match := range matches { - text := strings.TrimSpace(match[1]) - transMatches := transStmtReSingle.FindAllStringSubmatch(text, -1) - if len(transMatches) == 0 { - transMatches = transStmtReDouble.FindAllStringSubmatch(text, -1) - } - for _, transMatch := range transMatches { - message := strings.TrimSpace(transMatch[1]) - key := TranslationKey(page.Route, *sequence) - keys = append(keys, key) - translations = append(translations, Translation{ - Key: key, - Message: message, - Type: transType, - }) - *sequence = *sequence + 1 - } - } - return translations, keys, nil -} - -func (page *Page) translateScript(code string, sequence *int) ([]Translation, []string, error) { - - translations := []Translation{} - keys := []string{} - if code == "" { - return translations, keys, nil - } - matches := transFuncRe.FindAllStringSubmatch(code, -1) - for _, match := range matches { - key := TranslationKey(page.Route, *sequence) - translations = append(translations, Translation{ - Key: key, - Message: match[1], - Type: "script", - }) - *sequence = *sequence + 1 - keys = append(keys, key) - } - return translations, keys, nil -} diff --git a/sui/core/context.go b/sui/core/context.go index e39a3f77b..f8b78b056 100644 --- a/sui/core/context.go +++ b/sui/core/context.go @@ -17,6 +17,14 @@ func NewBuildContext(global *GlobalBuildContext) *BuildContext { } } +// NewTranslateContext create a new translate context +func NewTranslateContext() *TranslateContext { + return &TranslateContext{ + sequence: 1, + translations: []Translation{}, + } +} + // NewGlobalBuildContext create a new global build context func NewGlobalBuildContext() *GlobalBuildContext { return &GlobalBuildContext{ diff --git a/sui/core/translate.go b/sui/core/translate.go new file mode 100644 index 000000000..327ac4867 --- /dev/null +++ b/sui/core/translate.go @@ -0,0 +1,205 @@ +package core + +import ( + "fmt" + "strings" + + "github.com/PuerkitoBio/goquery" + "golang.org/x/net/html" +) + +// TranslateDocument translates the document +func (page *Page) TranslateDocument(doc *goquery.Document) error { + + if doc.Length() == 0 { + return nil + } + + if page.transCtx == nil { + return fmt.Errorf("TranslateMarks: context is nil") + } + + if page.transCtx.translations == nil { + page.transCtx.translations = []Translation{} + } + + root := doc.First() + return page.TranslateSelection(root) +} + +// TranslateSelection translates the selection +func (page *Page) TranslateSelection(sel *goquery.Selection) error { + + if sel.Length() == 0 { + return nil + } + + if page.transCtx == nil { + return fmt.Errorf("TranslateMarks: context is nil") + } + + if page.transCtx.translations == nil { + page.transCtx.translations = []Translation{} + } + + translations, err := page.translateNode(sel.Nodes[0]) + if err != nil { + return err + } + + if translations != nil { + page.transCtx.translations = append(page.transCtx.translations, translations...) + } + + return nil + +} + +func (page *Page) translateNode(node *html.Node) ([]Translation, error) { + + translations := []Translation{} + + switch node.Type { + case html.DocumentNode: + for child := node.FirstChild; child != nil; child = child.NextSibling { + trans, err := page.translateNode(child) + if err != nil { + return nil, err + } + translations = append(translations, trans...) + } + break + + case html.ElementNode: + + sel := goquery.NewDocumentFromNode(node) + // Script + if node.Data == "script" { + if _, has := sel.Attr("s:trans-script"); has { + break + } + code := goquery.NewDocumentFromNode(node).Text() + trans, keys, err := page.translateScript(code) + if err != nil { + return nil, err + } + if len(keys) > 0 { + raw := strings.Join(keys, ",") + sel.SetAttr("s:trans-script", raw) + translations = append(translations, trans...) + } + break + } + + for _, attr := range node.Attr { + + if _, has := sel.Attr("s:trans-attr-" + attr.Key); has { + continue + } + + trans, keys, err := page.translateText(attr.Val, "attr") + if err != nil { + return nil, err + } + if len(keys) > 0 { + raw := strings.Join(keys, ",") + sel.SetAttr("s:trans-attr-"+attr.Key, raw) + translations = append(translations, trans...) + } + + } + + // Node Attributes + for child := node.FirstChild; child != nil; child = child.NextSibling { + trans, err := page.translateNode(child) + if err != nil { + return nil, err + } + translations = append(translations, trans...) + } + break + + case html.TextNode: + parentSel := goquery.NewDocumentFromNode(node.Parent) + if _, has := parentSel.Attr("s:trans"); has { + if _, has := parentSel.Attr("s:trans-node"); has { + break + } + + key := TranslationKey(page.Route, page.transCtx.sequence) + message := strings.TrimSpace(node.Data) + if message != "" { + translations = append(translations, Translation{ + Key: key, + Message: message, + Type: "text", + }) + parentSel.SetAttr("s:trans-node", key) + page.transCtx.sequence = page.transCtx.sequence + 1 + } + parentSel.SetAttr("s:trans-escape", "true") + } + + if _, has := parentSel.Attr("s:trans-text"); has { + break + } + trans, keys, err := page.translateText(node.Data, "text") + if err != nil { + return nil, err + } + if len(keys) > 0 { + raw := strings.Join(keys, ",") + parentSel.SetAttr("s:trans-text", raw) + translations = append(translations, trans...) + } + break + } + + return translations, nil +} + +func (page *Page) translateText(text string, transType string) ([]Translation, []string, error) { + translations := []Translation{} + matches := stmtRe.FindAllStringSubmatch(text, -1) + keys := []string{} + for _, match := range matches { + text := strings.TrimSpace(match[1]) + transMatches := transStmtReSingle.FindAllStringSubmatch(text, -1) + if len(transMatches) == 0 { + transMatches = transStmtReDouble.FindAllStringSubmatch(text, -1) + } + for _, transMatch := range transMatches { + message := strings.TrimSpace(transMatch[1]) + key := TranslationKey(page.Route, page.transCtx.sequence) + keys = append(keys, key) + translations = append(translations, Translation{ + Key: key, + Message: message, + Type: transType, + }) + page.transCtx.sequence = page.transCtx.sequence + 1 + } + } + return translations, keys, nil +} + +func (page *Page) translateScript(code string) ([]Translation, []string, error) { + + translations := []Translation{} + keys := []string{} + if code == "" { + return translations, keys, nil + } + matches := transFuncRe.FindAllStringSubmatch(code, -1) + for _, match := range matches { + key := TranslationKey(page.Route, page.transCtx.sequence) + translations = append(translations, Translation{ + Key: key, + Message: match[1], + Type: "script", + }) + page.transCtx.sequence = page.transCtx.sequence + 1 + keys = append(keys, key) + } + return translations, keys, nil +} diff --git a/sui/core/types.go b/sui/core/types.go index c93c20282..5324a75dd 100644 --- a/sui/core/types.go +++ b/sui/core/types.go @@ -43,6 +43,7 @@ type Page struct { Attrs map[string]string `json:"-"` Attributes []html.Attribute `json:"-"` namespace string `json:"-"` + transCtx *TranslateContext `json:"-"` parent *Page `json:"-"` } @@ -63,6 +64,12 @@ type BuildContext struct { stack []string // Stack to manage build states } +// TranslateContext is the struct for the translate context +type TranslateContext struct { + sequence int + translations []Translation +} + // ScriptNode is the struct for the script node type ScriptNode struct { Source string `json:"source"` diff --git a/sui/storages/local/local_test.go b/sui/storages/local/local_test.go index fa669f4ba..a38caa43f 100644 --- a/sui/storages/local/local_test.go +++ b/sui/storages/local/local_test.go @@ -31,9 +31,9 @@ func TestGetTemplates(t *testing.T) { assert.Equal(t, "advanced", testTmpls[0].(*Template).ID) assert.Equal(t, "The advanced template", testTmpls[0].(*Template).Name) assert.Len(t, testTmpls[0].Themes(), 2) - assert.Len(t, testTmpls[0].Locales(), 4) + assert.Len(t, testTmpls[0].Locales(), 5) assert.Len(t, testTmpls[0].(*Template).Template.Themes, 2) - assert.Len(t, testTmpls[0].(*Template).Template.Locales, 4) + assert.Len(t, testTmpls[0].(*Template).Template.Locales, 5) // Basic Template assert.Equal(t, "basic", testTmpls[1].(*Template).ID) From af3a8a4ac4369e7553ebc8d3757c0dff2de68fa8 Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 19 Jul 2024 08:21:59 +0800 Subject: [PATCH 2/3] Refactor locale file writing logic in SUI page --- sui/storages/local/build.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sui/storages/local/build.go b/sui/storages/local/build.go index 30978f456..535dbf6fc 100644 --- a/sui/storages/local/build.go +++ b/sui/storages/local/build.go @@ -559,13 +559,13 @@ func (page *Page) writeLocaleFiles(ctx *core.BuildContext, data map[string]inter return nil } + components := ctx.GetComponents() translations := ctx.GetTranslations() - if len(translations) == 0 { + if len(translations) == 0 && len(components) == 0 { return nil } prefix := core.TranslationKeyPrefix(page.Route) files := page.localeFiles(data) - components := ctx.GetComponents() for name, file := range files { locale := page.tmpl.getLocale(name, page.Route) locale.MergeTranslations(translations, prefix) From 69e0070b0a8b82777ac8f65e4c3eb4b53063f36d Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 19 Jul 2024 16:08:00 +0800 Subject: [PATCH 3/3] Refactor prop regex patterns and methods in SUI core --- sui/core/build.go | 157 +++++++++++++++++++++++++++++++++++++--------- sui/core/data.go | 30 ++++++++- sui/core/types.go | 41 +++++++----- 3 files changed, 180 insertions(+), 48 deletions(-) diff --git a/sui/core/build.go b/sui/core/build.go index 2a0062d68..8a25a2827 100644 --- a/sui/core/build.go +++ b/sui/core/build.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/PuerkitoBio/goquery" + "github.com/yaoapp/kun/log" "golang.org/x/net/html" ) @@ -188,12 +189,15 @@ func (page *Page) BuildAsComponent(sel *goquery.Selection, ctx *BuildContext, op // Pass the component props first := body.Children().First() - page.copyProps(ctx, sel, first, attrs...) + // page.copyProps(ctx, sel, first, attrs...) + page.parseProps(sel, first, attrs...) page.copySlots(sel, first) page.copyChildren(sel, first) page.buildComponents(doc, ctx, &opt) - data := Data{"$props": page.Attrs} - data.ReplaceSelectionUse(slotRe, first) + page.replaceProps(first) + + // data := Data{"$props": page.Attrs} + // data.ReplaceSelectionUse(slotRe, first) // Add the translation marks err = page.TranslateDocument(doc) @@ -262,54 +266,145 @@ func (page *Page) copyChildren(from *goquery.Selection, to *goquery.Selection) e return nil } -func (page *Page) copyProps(ctx *BuildContext, from *goquery.Selection, to *goquery.Selection, extra ...html.Attribute) error { +func (page *Page) parseProps(from *goquery.Selection, to *goquery.Selection, extra ...html.Attribute) { attrs := from.Get(0).Attr - prefix := "s:prop" - if page.Attrs == nil { - page.Attrs = map[string]string{} + if page.props == nil { + page.props = map[string]PageProp{} + } + + if attrs == nil { + attrs = []html.Attribute{} } + for _, attr := range attrs { + if strings.HasPrefix(attr.Key, "s:") || attr.Key == "is" || attr.Key == "parsed" { continue } - if strings.HasPrefix(attr.Key, "...$props") { - data := Data{"$props": page.parent.Attrs} - val, err := data.Exec(fmt.Sprintf("{{ %s }}", attr.Key[3:])) - if err != nil { - ctx.warnings = append(ctx.warnings, err.Error()) - setError(to, err) - continue - } - switch value := val.(type) { - case map[string]string: - for key, value := range value { - page.Attrs[key] = value - key = fmt.Sprintf("%s:%s", prefix, key) - to.SetAttr(key, value) + if attr.Key == "...$props" && page.parent != nil { + if page.parent.props != nil { + for key, prop := range page.parent.props { + page.props[key] = prop } } continue } - val := attr.Val - if strings.HasPrefix(attr.Key, `...\$props`) { - val = fmt.Sprintf("{{ $props.%s }}", attr.Key[9:]) + if strings.HasPrefix(attr.Key, "...") && page.parent != nil { + val := attr.Key[3:] + key := fmt.Sprintf("s:prop:%s", attr.Key) + to.SetAttr(key, val) + continue } - if strings.HasPrefix(attr.Key, "...") { - val = attr.Key[3:] - } - page.Attrs[attr.Key] = val - key := fmt.Sprintf("%s:%s", prefix, attr.Key) - to.SetAttr(key, val) + trans := from.AttrOr(fmt.Sprintf("s:trans-attr-%s", attr.Key), "") + exp := stmtRe.Match([]byte(attr.Val)) + prop := PageProp{Key: attr.Key, Val: attr.Val, Trans: trans, Exp: exp} + page.props[attr.Key] = prop } - if len(extra) > 0 { + if extra != nil && len(extra) > 0 { for _, attr := range extra { + attrs = append(attrs, attr) to.SetAttr(attr.Key, attr.Val) } } +} + +func (page *Page) replaceProps(sel *goquery.Selection) error { + if page.props == nil || len(page.props) == 0 { + return nil + } + data := Data{} + for key, prop := range page.props { + data[key] = prop.Val + } + data["$props"] = data + return page.replacePropsNode(data, sel.Nodes[0]) +} + +func (page *Page) replacePropsText(text string, data Data) (string, []string) { + trans := []string{} + matched := PropFindAllStringSubmatch(text) + for _, match := range matched { + stmt := match[1] + val, err := data.ExecString(stmt) + if err != nil { + log.Error("[replaceProps] Replace %s: %s", stmt, err) + continue + } + + text = strings.ReplaceAll(text, match[0], val) + vars := PropGetVarNames(stmt) + for _, v := range vars { + if v == "" { + continue + } + + if prop, has := page.props[v]; has { + if prop.Trans == "" { + continue + } + trans = append(trans, prop.Trans) + } + } + } + + return text, trans +} + +func (page *Page) replacePropsNode(data Data, node *html.Node) error { + switch node.Type { + case html.TextNode: + text := node.Data + if strings.TrimSpace(text) == "" { + break + } + + text, trans := page.replacePropsText(text, data) + if len(trans) > 0 && node.Parent != nil { + node.Parent.Attr = append(node.Parent.Attr, html.Attribute{ + Key: "s:trans-text", + Val: strings.Join(trans, ","), + }) + } + + node.Data = text + break + + case html.ElementNode: + + // Attrs + attrs := []html.Attribute{} + for i, attr := range node.Attr { + + if (strings.HasPrefix(attr.Key, "s:") || attr.Key == "is") && !allowUsePropAttrs[attr.Key] { + continue + } + + val, trans := page.replacePropsText(attr.Val, data) + node.Attr[i] = html.Attribute{Key: attr.Key, Val: val} + if len(trans) > 0 { + key := fmt.Sprintf("s:trans-attr-%s", attr.Key) + attrs = append(attrs, html.Attribute{Key: key, Val: strings.Join(trans, ",")}) + } + } + + for _, attr := range attrs { + node.Attr = append(node.Attr, attr) + } + + // Children + for c := node.FirstChild; c != nil; c = c.NextSibling { + err := page.replacePropsNode(data, c) + if err != nil { + return err + } + } + + break + } return nil } diff --git a/sui/core/data.go b/sui/core/data.go index 6df33f67c..9fc26e95a 100644 --- a/sui/core/data.go +++ b/sui/core/data.go @@ -16,7 +16,9 @@ import ( // If set the map value, should keep the space at the end of the statement var stmtRe = regexp.MustCompile(`\{\{([\s\S]*?)\}\}`) -var propRe = regexp.MustCompile(`\[\{([\s\S]*?)\}\]`) +var propRe = regexp.MustCompile(`\[\{([\s\S]*?)\}\]`) // [{ xxx }] will be deprecated +var propNewRe = regexp.MustCompile(`\{%([\s\S]*)?%\}`) // {% xxx %} +var propVarNameRe = regexp.MustCompile(`(?:\$props\.)?(?:$begin:math:display$'([^']+)'$end:math:display$|(\w+))`) // Data data for the template type Data map[string]interface{} @@ -184,3 +186,29 @@ func _process(args ...any) (interface{}, error) { return res, nil } + +// PropFindAllStringSubmatch find all string submatch +func PropFindAllStringSubmatch(value string) [][]string { + matched := propNewRe.FindAllStringSubmatch(value, -1) + oldVersion := propRe.FindAllStringSubmatch(value, -1) // will be deprecated + if len(oldVersion) > 0 { + matched = append(matched, oldVersion...) + } + return matched +} + +// PropGetVarNames get the variable names +func PropGetVarNames(value string) []string { + matched := propVarNameRe.FindAllStringSubmatch(value, -1) + varNames := []string{} + for _, m := range matched { + m1 := strings.TrimSpace(m[1]) + m2 := strings.TrimSpace(m[2]) + if m1 != "" { + varNames = append(varNames, m1) + } else { + varNames = append(varNames, m2) + } + } + return varNames +} diff --git a/sui/core/types.go b/sui/core/types.go index 5324a75dd..7c81197ba 100644 --- a/sui/core/types.go +++ b/sui/core/types.go @@ -29,22 +29,31 @@ type Setting struct { // Page is the struct for the page type Page struct { - Route string `json:"route"` - Name string `json:"name,omitempty"` - CacheStore string `json:"-"` - TemplateID string `json:"-"` - SuiID string `json:"-"` - Config *PageConfig `json:"-"` - Path string `json:"-"` - Root string `json:"-"` - Codes SourceCodes `json:"-"` - Document []byte `json:"-"` - GlobalData []byte `json:"-"` - Attrs map[string]string `json:"-"` - Attributes []html.Attribute `json:"-"` - namespace string `json:"-"` - transCtx *TranslateContext `json:"-"` - parent *Page `json:"-"` + Route string `json:"route"` + Name string `json:"name,omitempty"` + CacheStore string `json:"-"` + TemplateID string `json:"-"` + SuiID string `json:"-"` + Config *PageConfig `json:"-"` + Path string `json:"-"` + Root string `json:"-"` + Codes SourceCodes `json:"-"` + Document []byte `json:"-"` + GlobalData []byte `json:"-"` + Attrs map[string]string `json:"-"` + Attributes []html.Attribute `json:"-"` + namespace string `json:"-"` + transCtx *TranslateContext `json:"-"` + parent *Page `json:"-"` + props map[string]PageProp `json:"-"` +} + +// PageProp is the struct for the page prop +type PageProp struct { + Key string `json:"key"` + Val string `json:"val"` + Exp bool `json:"exp"` + Trans string `json:"trans"` } // BuildContext is the struct for the build context