diff options
Diffstat (limited to 'cmd/extpo')
| -rw-r--r-- | cmd/extpo/html.go | 114 | ||||
| -rw-r--r-- | cmd/extpo/main.go | 109 | ||||
| -rw-r--r-- | cmd/extpo/sql.go | 54 |
3 files changed, 173 insertions, 104 deletions
diff --git a/cmd/extpo/html.go b/cmd/extpo/html.go new file mode 100644 index 0000000..d53cbfa --- /dev/null +++ b/cmd/extpo/html.go @@ -0,0 +1,114 @@ +package main + +import ( + "strings" + "text/template/parse" +) + +func processHtml(path string) { + trees := make(map[string]*parse.Tree) + t := parse.New(path) + t.Mode |= parse.ParseComments | parse.SkipFuncCheck + try2(t.Parse(string(currentFile), "", "", trees)) + for _, t := range trees { + processHtmlNode(t.Root) + } +} + +func processHtmlNode(node parse.Node) { + switch n := node.(type) { + case *parse.ListNode: + for _, m := range n.Nodes { + processHtmlNode(m) + } + case *parse.PipeNode: + for _, m := range n.Cmds { + processHtmlNode(m) + } + case *parse.TemplateNode: + processHtmlNode(n.Pipe) + case *parse.IfNode: + processHtmlBranch(n.BranchNode) + case *parse.RangeNode: + processHtmlBranch(n.BranchNode) + case *parse.WithNode: + processHtmlBranch(n.BranchNode) + case *parse.BranchNode: + processHtmlBranch(*n) + case *parse.ActionNode: + processHtmlNode(n.Pipe) + case *parse.CommandNode: + if len(n.Args) == 0 { + break + } + + var funcname string + f, ok := n.Args[0].(*parse.FieldNode) + if !ok || len(f.Ident) == 0 { + ff, ok := n.Args[0].(*parse.VariableNode) + if !ok || len(ff.Ident) == 0 { + fff, ok := n.Args[0].(*parse.IdentifierNode) + if !ok { + for _, pipe := range n.Args { + processHtmlNode(pipe) + } + break + } + funcname = fff.Ident + } else { + funcname = ff.Ident[len(ff.Ident)-1] + } + } else { + funcname = f.Ident[len(f.Ident)-1] + } + + cfg, ok := configs[funcname] + if !ok { + for _, pipe := range n.Args { + processHtmlNode(pipe) + } + break + } + + var ( + tl translation + linenr int + ) + + if sn, ok := n.Args[cfg.arg].(*parse.StringNode); ok { + tl.msgid = sn.Text + linenr = getlinenr(sn.Pos.Position()) + } else { + break + } + if cfg.plural != -1 { + if sn, ok := n.Args[cfg.plural].(*parse.StringNode); ok { + tl.msgidPlural = sn.Text + } + } + if cfg.context != -1 { + if sn, ok := n.Args[cfg.context].(*parse.StringNode); ok { + tl.msgctxt = sn.Text + } + } + + ti := translations[tl] + if lastComment != "" { + ti.comment = lastComment + lastComment = "" + } + ti.locs = append(ti.locs, loc{currentPath, linenr}) + translations[tl] = ti + case *parse.CommentNode: + if strings.HasPrefix(n.Text, "/* TRANSLATORS:") { + lastComment = strings.TrimSpace(n.Text[2 : len(n.Text)-2]) + } + } +} + +func processHtmlBranch(n parse.BranchNode) { + processHtmlNode(n.List) + if n.ElseList != nil { + processHtmlNode(n.ElseList) + } +} diff --git a/cmd/extpo/main.go b/cmd/extpo/main.go index 6aa1503..5db7b7c 100644 --- a/cmd/extpo/main.go +++ b/cmd/extpo/main.go @@ -140,110 +140,11 @@ msgstr "" func process(path string) { currentPath = path currentFile = try2(os.ReadFile(path)) - trees := make(map[string]*parse.Tree) - t := parse.New(path) - t.Mode |= parse.ParseComments | parse.SkipFuncCheck - try2(t.Parse(string(currentFile), "", "", trees)) - for _, t := range trees { - processNode(t.Root) - } -} - -func processNode(node parse.Node) { - switch n := node.(type) { - case *parse.ListNode: - for _, m := range n.Nodes { - processNode(m) - } - case *parse.PipeNode: - for _, m := range n.Cmds { - processNode(m) - } - case *parse.TemplateNode: - processNode(n.Pipe) - case *parse.IfNode: - processBranch(n.BranchNode) - case *parse.RangeNode: - processBranch(n.BranchNode) - case *parse.WithNode: - processBranch(n.BranchNode) - case *parse.BranchNode: - processBranch(*n) - case *parse.ActionNode: - processNode(n.Pipe) - case *parse.CommandNode: - if len(n.Args) == 0 { - break - } - - var funcname string - f, ok := n.Args[0].(*parse.FieldNode) - if !ok || len(f.Ident) == 0 { - ff, ok := n.Args[0].(*parse.VariableNode) - if !ok || len(ff.Ident) == 0 { - fff, ok := n.Args[0].(*parse.IdentifierNode) - if !ok { - for _, pipe := range n.Args { - processNode(pipe) - } - break - } - funcname = fff.Ident - } else { - funcname = ff.Ident[len(ff.Ident)-1] - } - } else { - funcname = f.Ident[len(f.Ident)-1] - } - - cfg, ok := configs[funcname] - if !ok { - for _, pipe := range n.Args { - processNode(pipe) - } - break - } - - var ( - tl translation - linenr int - ) - - if sn, ok := n.Args[cfg.arg].(*parse.StringNode); ok { - tl.msgid = sn.Text - linenr = getlinenr(sn.Pos.Position()) - } else { - break - } - if cfg.plural != -1 { - if sn, ok := n.Args[cfg.plural].(*parse.StringNode); ok { - tl.msgidPlural = sn.Text - } - } - if cfg.context != -1 { - if sn, ok := n.Args[cfg.context].(*parse.StringNode); ok { - tl.msgctxt = sn.Text - } - } - - ti := translations[tl] - if lastComment != "" { - ti.comment = lastComment - lastComment = "" - } - ti.locs = append(ti.locs, loc{currentPath, linenr}) - translations[tl] = ti - case *parse.CommentNode: - if strings.HasPrefix(n.Text, "/* TRANSLATORS:") { - lastComment = strings.TrimSpace(n.Text[2 : len(n.Text)-2]) - } - } -} - -func processBranch(n parse.BranchNode) { - processNode(n.List) - if n.ElseList != nil { - processNode(n.ElseList) + switch { + case strings.HasSuffix(path, ".html.tmpl"): + processHtml(path) + case strings.HasSuffix(path, ".sql"): + processSql(path) } } diff --git a/cmd/extpo/sql.go b/cmd/extpo/sql.go new file mode 100644 index 0000000..43bea9c --- /dev/null +++ b/cmd/extpo/sql.go @@ -0,0 +1,54 @@ +package main + +import ( + "bytes" + "errors" + "io" + + "github.com/rqlite/sql" +) + +type sqlVisitor struct{} + +func processSql(path string) { + p := sql.NewParser(bytes.NewReader(currentFile)) + for { + stmt, err := p.ParseStatement() + switch { + case errors.Is(err, io.EOF): + return + case err != nil: + die(err) + } + sql.Walk(sqlVisitor{}, stmt) + } +} + +func processSqlArgs(msgidExpr, msgctxtExpr sql.Expr, pos sql.Pos) { + msgid, ok := msgidExpr.(*sql.StringLit) + if !ok { + return + } + msgctxt, ok := msgctxtExpr.(*sql.StringLit) + if !ok { + return + } + tl := translation{ + msgid: msgid.Value, + msgctxt: msgctxt.Value, + } + ti := translations[tl] + ti.locs = append(ti.locs, loc{currentPath, pos.Line}) + translations[tl] = ti +} + +func (v sqlVisitor) Visit(n sql.Node) (sql.Visitor, sql.Node, error) { + if cn, ok := n.(*sql.Call); ok && sql.IdentName(cn.Name) == "C_" { + processSqlArgs(cn.Args[0], cn.Args[1], cn.Lparen) + } + return v, n, nil +} + +func (v sqlVisitor) VisitEnd(n sql.Node) (sql.Node, error) { + return n, nil +} |