aboutsummaryrefslogtreecommitdiffhomepage
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/extpo/main.go (renamed from cmd/exttmpl/main.go)116
-rw-r--r--cmd/extwiki/main.go151
2 files changed, 222 insertions, 45 deletions
diff --git a/cmd/exttmpl/main.go b/cmd/extpo/main.go
index 9017ab8..6aa1503 100644
--- a/cmd/exttmpl/main.go
+++ b/cmd/extpo/main.go
@@ -10,6 +10,7 @@ import (
"slices"
"strings"
"text/template/parse"
+ "time"
)
type config struct {
@@ -22,7 +23,7 @@ type config struct {
type translation struct {
msgid string
msgidPlural string
- msgctx string
+ msgctxt string
domain string
}
@@ -41,12 +42,11 @@ func (l loc) String() string {
}
var (
- outfile *os.File
currentFile []byte
currentPath string
lastComment string
- translations map[translation]transinfo = make(map[translation]transinfo)
- configs = map[string]config{
+ translations = make(map[translation]transinfo)
+ configs = map[string]config{
"Get": {1, -1, -1, -1},
"GetC": {1, -1, 2, -1},
"GetD": {2, -1, -1, 1},
@@ -76,6 +76,7 @@ func main() {
os.Exit(1)
}
+ var outfile *os.File
if *outpath == "-" {
outfile = os.Stdout
} else {
@@ -86,8 +87,7 @@ func main() {
process(f)
}
- /* TODO: Use the correct date */
- fmt.Fprint(outfile, `# SOME DESCRIPTIVE TITLE.
+ fmt.Fprintf(outfile, `# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
@@ -97,7 +97,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-07-27 20:08+0200\n"
+"POT-Creation-Date: %s\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -105,7 +105,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-`)
+`, time.Now().Format("2006-01-02 15:04-0700"))
for tl, ti := range translations {
if ti.comment != "" {
@@ -122,8 +122,8 @@ msgstr ""
fmt.Fprintln(outfile, "#:", x)
}
- if tl.msgctx != "" {
- writeField(outfile, "msgctx", tl.msgctx)
+ if tl.msgctxt != "" {
+ writeField(outfile, "msgctxt", tl.msgctxt)
}
writeField(outfile, "msgid", tl.msgid)
if tl.msgidPlural != "" {
@@ -155,58 +155,84 @@ func processNode(node parse.Node) {
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:
- for _, cmd := range n.Pipe.Cmds {
- if len(cmd.Args) == 0 {
- continue
- }
+ processNode(n.Pipe)
+ case *parse.CommandNode:
+ if len(n.Args) == 0 {
+ break
+ }
- f, ok := cmd.Args[0].(*parse.FieldNode)
- if !ok || len(f.Ident) == 0 {
- continue
+ 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[f.Ident[len(f.Ident)-1]]
- if !ok {
- continue
+ cfg, ok := configs[funcname]
+ if !ok {
+ for _, pipe := range n.Args {
+ processNode(pipe)
}
+ break
+ }
- var (
- tl translation
- linenr int
- )
+ var (
+ tl translation
+ linenr int
+ )
- if sn, ok := cmd.Args[cfg.arg].(*parse.StringNode); ok {
- tl.msgid = sn.Text
- linenr = getlinenr(sn.Pos.Position())
- } else {
- continue
- }
- if cfg.plural != -1 {
- if sn, ok := cmd.Args[cfg.plural].(*parse.StringNode); ok {
- tl.msgidPlural = sn.Text
- }
+ 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 := cmd.Args[cfg.context].(*parse.StringNode); ok {
- tl.msgctx = 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
+ 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])
diff --git a/cmd/extwiki/main.go b/cmd/extwiki/main.go
new file mode 100644
index 0000000..76e0f3a
--- /dev/null
+++ b/cmd/extwiki/main.go
@@ -0,0 +1,151 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "maps"
+ "os"
+ "path/filepath"
+ "slices"
+ "sort"
+ "text/template/parse"
+)
+
+var (
+ titles = make(map[string]struct{})
+ configs = map[string]int{"Wikipedia": 1}
+)
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "Usage: %s [flags] template...\n",
+ filepath.Base(os.Args[0]))
+ flag.PrintDefaults()
+}
+
+func main() {
+ try(os.Chdir(filepath.Dir(os.Args[0])))
+
+ outpath := flag.String("out", "-", "output file")
+ flag.Usage = usage
+ flag.Parse()
+
+ if flag.NArg() < 1 {
+ flag.Usage()
+ os.Exit(1)
+ }
+
+ var outfile *os.File
+ if *outpath == "-" {
+ outfile = os.Stdout
+ } else {
+ outfile = try2(os.Create(*outpath))
+ }
+
+ for _, f := range flag.Args() {
+ process(f)
+ }
+
+ fmt.Fprint(outfile, `// Code generated by extwiki. DO NOT EDIT.
+
+package wikipedia
+
+var extractedTitles = [...]string{
+`)
+ xs := slices.Collect(maps.Keys(titles))
+ sort.Strings(xs)
+ for _, t := range xs {
+ fmt.Fprintf(outfile, "%q,\n", t)
+ }
+ fmt.Fprint(outfile, "}\n")
+}
+
+func process(path string) {
+ 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]
+ }
+
+ i, ok := configs[funcname]
+ if !ok {
+ for _, pipe := range n.Args {
+ processNode(pipe)
+ }
+ break
+ }
+
+ if sn, ok := n.Args[i].(*parse.StringNode); ok {
+ titles[sn.Text] = struct{}{}
+ }
+ }
+}
+
+func processBranch(n parse.BranchNode) {
+ processNode(n.List)
+ if n.ElseList != nil {
+ processNode(n.ElseList)
+ }
+}
+
+func try(err error) {
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: %s\n", filepath.Base(os.Args[0]), err)
+ os.Exit(1)
+ }
+}
+
+func try2[T any](val T, err error) T {
+ try(err)
+ return val
+}