diff --git a/sui/core/build.go b/sui/core/build.go
index a2f4a9af..cff6099b 100644
--- a/sui/core/build.go
+++ b/sui/core/build.go
@@ -12,6 +12,9 @@ import (
var slotRe = regexp.MustCompile(`\[\{([^\}]+)\}\]`)
var cssRe = regexp.MustCompile(`([\.a-z0-9A-Z-:# ]+)\{`)
+var transStmtReSingle = regexp.MustCompile(`'::([^:']+)'`)
+var transStmtReDouble = regexp.MustCompile(`"::([^:"]+)"`)
+var transFuncRe = regexp.MustCompile(`__m\s*\(\s*["'](.*?)["']\s*\)`)
// Build build the page
func (page *Page) Build(ctx *BuildContext, option *BuildOption) (*goquery.Document, []string, error) {
@@ -73,6 +76,27 @@ func (page *Page) Build(ctx *BuildContext, option *BuildOption) (*goquery.Docume
ctx.scripts = append(ctx.scripts, scripts...)
ctx.styles = append(ctx.styles, styles...)
+ // Add the translation marks
+ sequence := 0
+ err = page.TranslateMarks(ctx, doc, &sequence)
+ if err != nil {
+ return nil, warnings, err
+ }
+
+ // Translate the scripts
+ if (scripts != nil) && len(scripts) > 0 {
+ for _, script := range scripts {
+ if script.Source == "" {
+ continue
+ }
+ trans, _, err := page.translateScript(script.Source, &sequence)
+ if err != nil {
+ return nil, ctx.warnings, err
+ }
+ ctx.translations = append(ctx.translations, trans...)
+ }
+ }
+
return doc, ctx.warnings, err
}
@@ -83,6 +107,10 @@ func (page *Page) BuildAsComponent(sel *goquery.Selection, ctx *BuildContext, op
return "", fmt.Errorf("The parent page is not set")
}
+ if ctx == nil {
+ ctx = NewBuildContext(nil)
+ }
+
// Push the current page onto the stack and increment the visit counter
ctx.stack = append(ctx.stack, page.Route)
ctx.visited[page.Route]++
@@ -151,11 +179,34 @@ func (page *Page) BuildAsComponent(sel *goquery.Selection, ctx *BuildContext, op
page.buildComponents(doc, ctx, &opt)
data := Data{"$props": page.Attrs}
data.ReplaceSelectionUse(slotRe, first)
+
+ // Add the translation marks
+ sequence := 0
+ err = page.TranslateMarks(ctx, doc, &sequence)
+ if err != nil {
+ return "", err
+ }
+
+ // Translate the scripts
+ if (scripts != nil) && len(scripts) > 0 {
+ for _, script := range scripts {
+ if script.Source == "" {
+ continue
+ }
+ trans, _, err := page.translateScript(script.Source, &sequence)
+ if err != nil {
+ return "", err
+ }
+ ctx.translations = append(ctx.translations, trans...)
+ }
+ }
+
html, err = body.Html()
if err != nil {
return "", err
}
sel.ReplaceWithHtml(html)
+ ctx.components[page.Route] = true
return html, nil
}
@@ -496,3 +547,162 @@ 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{}
+ *sequence = *sequence + 1
+
+ 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:
+
+ // Script
+ if node.Data == "script" {
+ code := goquery.NewDocumentFromNode(node).Text()
+ trans, _, err := page.translateScript(code, sequence)
+ if err != nil {
+ return nil, err
+ }
+ translations = append(translations, trans...)
+ break
+ }
+
+ sel := goquery.NewDocumentFromNode(node)
+ for _, attr := range node.Attr {
+
+ 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 {
+ 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.RemoveAttr("s:trans")
+ }
+
+ 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)
+ parentSel.RemoveAttr("s:trans")
+ 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
+ }
+ return translations, keys, nil
+}
diff --git a/sui/core/compile.go b/sui/core/compile.go
index 0dbfe851..27cd6735 100644
--- a/sui/core/compile.go
+++ b/sui/core/compile.go
@@ -5,20 +5,15 @@ import (
"regexp"
"strings"
- "github.com/PuerkitoBio/goquery"
"github.com/evanw/esbuild/pkg/api"
jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou/runtime/transform"
"github.com/yaoapp/kun/log"
- "golang.org/x/net/html"
)
var quoteRe = "'\"`"
var importRe = regexp.MustCompile(`import\s*\t*\n*[^;]*;`) // import { foo, bar } from 'hello'; ...
var importAssetsRe = regexp.MustCompile(`import\s*\t*\n*\s*['"]@assets\/([^'"]+)['"];`) // import '@assets/foo.js'; or import "@assets/foo.js";
-var transStmtReSingle = regexp.MustCompile(`'::([^:']+)'`)
-var transStmtReDouble = regexp.MustCompile(`"::([^:"]+)"`)
-var transFuncRe = regexp.MustCompile(`__m\s*\(\s*["'](.*?)["']\s*\)`)
// AssetsRe is the regexp for assets
var AssetsRe = regexp.MustCompile(`[` + quoteRe + `]@assets\/([^` + quoteRe + `]+)[` + quoteRe + `]`) // '@assets/foo.js' or "@assets/foo.js" or `@assets/foo`
@@ -90,12 +85,15 @@ func (page *Page) Compile(ctx *BuildContext, option *BuildOption) (string, []str
)
}
- // Add the translation marks
- sequence := 0
- err = page.TranslateMarks(ctx, option, doc, &sequence)
- if err != nil {
- return "", warnings, err
+ // Page Components
+ components := []string{}
+ if ctx != nil && ctx.components != nil && len(ctx.components) > 0 {
+ for route := range ctx.components {
+ components = append(components, route)
+ }
}
+ rawComponents, _ := jsoniter.MarshalToString(components)
+ body.AppendHtml("\n\n" + `\n\n")
page.ReplaceDocument(doc)
html, err := doc.Html()
@@ -140,6 +138,15 @@ func (page *Page) CompileAsComponent(ctx *BuildContext, option *BuildOption) (st
return "", warnings, err
}
+ // Page Components
+ components := []string{}
+ if ctx != nil && ctx.components != nil && len(ctx.components) > 0 {
+ for route := range ctx.components {
+ components = append(components, route)
+ }
+ }
+ rawComponents, _ := jsoniter.MarshalToString(components)
+
if body.Children().Length() == 0 {
return "", warnings, fmt.Errorf("page %s as component should have one root element", page.Route)
}
@@ -151,13 +158,7 @@ func (page *Page) CompileAsComponent(ctx *BuildContext, option *BuildOption) (st
body.Children().First().AppendHtml(fmt.Sprintf(``+"\n", rawScripts))
body.Children().First().AppendHtml(fmt.Sprintf(``+"\n", rawStyles))
body.Children().First().AppendHtml(fmt.Sprintf(``+"\n", rawOption))
-
- // Add the translation marks
- sequence := 0
- err = page.TranslateMarks(ctx, option, doc, &sequence)
- if err != nil {
- return "", warnings, err
- }
+ body.Children().First().AppendHtml(fmt.Sprintf(``+"\n", rawComponents))
html, err := body.Html()
return html, warnings, err
@@ -282,150 +283,3 @@ func (style StyleNode) HTML() string {
return ""
}
-
-// TranslateMarks add the translation marks to the document
-func (page *Page) TranslateMarks(ctx *BuildContext, option *BuildOption, 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{}
- *sequence = *sequence + 1
-
- 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:
-
- // Script
- if node.Data == "script" {
- code := goquery.NewDocumentFromNode(node).Text()
- if code != "" {
- translations := []Translation{}
- matches := transFuncRe.FindAllStringSubmatch(code, -1)
- for _, match := range matches {
- key := Namespace(page.Route, *sequence)
- translations = append(translations, Translation{
- Key: key,
- Message: match[1],
- Type: "script",
- })
- *sequence = *sequence + 1
- }
- }
- break
- }
-
- sel := goquery.NewDocumentFromNode(node)
- for _, attr := range node.Attr {
-
- 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 {
- key := Namespace(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.RemoveAttr("s:trans")
- }
-
- 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)
- parentSel.RemoveAttr("s:trans")
- translations = append(translations, trans...)
- }
- break
- }
-
- return translations, nil
-}
-
-func (page *Page) translateText(text string, sequence *int, typ 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 := Namespace(page.Route, *sequence)
- keys = append(keys, key)
- translations = append(translations, Translation{
- Key: key,
- Message: message,
- Type: typ,
- })
- *sequence = *sequence + 1
- }
- }
- return translations, keys, nil
-}
diff --git a/sui/core/context.go b/sui/core/context.go
index 2c3be60e..e22bf783 100644
--- a/sui/core/context.go
+++ b/sui/core/context.go
@@ -3,7 +3,7 @@ package core
// NewBuildContext create a new build context
func NewBuildContext(global *GlobalBuildContext) *BuildContext {
return &BuildContext{
- components: map[string]string{},
+ components: map[string]bool{},
sequence: 1,
scripts: []ScriptNode{},
scriptUnique: map[string]bool{},
diff --git a/sui/core/types.go b/sui/core/types.go
index 518270d9..c40c3998 100644
--- a/sui/core/types.go
+++ b/sui/core/types.go
@@ -47,7 +47,7 @@ type Page struct {
// BuildContext is the struct for the build context
type BuildContext struct {
- components map[string]string
+ components map[string]bool
jitComponents map[string]bool
sequence int
doc *goquery.Document
diff --git a/sui/core/utils.go b/sui/core/utils.go
index 6353de89..0cb7655f 100644
--- a/sui/core/utils.go
+++ b/sui/core/utils.go
@@ -55,13 +55,13 @@ func Namespace(name string, idx int, hash ...bool) string {
name = strings.ReplaceAll(name, "/", "_")
name = strings.ReplaceAll(name, "[", "_")
name = strings.ReplaceAll(name, "]", "_")
- ns := fmt.Sprintf("__namespace_%s", name)
+ ns := fmt.Sprintf("page_%s_%d", name, idx)
if len(hash) > 0 && hash[0] {
h := fnv.New64a()
h.Write([]byte(ns))
return fmt.Sprintf("ns_%x", h.Sum64())
}
- return fmt.Sprintf("__page_%s_%d", name, idx)
+ return ns
}
// ComponentName convert the name to component name
@@ -69,7 +69,7 @@ func ComponentName(name string, hash ...bool) string {
name = strings.ReplaceAll(name, "/", "_")
name = strings.ReplaceAll(name, "[", "_")
name = strings.ReplaceAll(name, "]", "_")
- cn := fmt.Sprintf("__component_%s", name)
+ cn := fmt.Sprintf("comp_%s", name)
if len(hash) > 0 && hash[0] {
h := fnv.New64a()
h.Write([]byte(cn))
@@ -77,3 +77,11 @@ func ComponentName(name string, hash ...bool) string {
}
return cn
}
+
+// TranslationKey convert the name to translation key
+func TranslationKey(name string, sequence int) string {
+ name = strings.ReplaceAll(name, "/", "_")
+ name = strings.ReplaceAll(name, "[", "_")
+ name = strings.ReplaceAll(name, "]", "_")
+ return fmt.Sprintf("trans_%s_%d", name, sequence)
+}