commit 49b87d3a49b0878ee5908486fcd9592ff88fa206
parent 825527b12ffd644eac5beaa173de47354f2333e8
Author: lash <dev@holbrook.no>
Date: Thu, 2 Jan 2025 11:00:07 +0000
Add reverse gettext to resource generation
Diffstat:
3 files changed, 473 insertions(+), 280 deletions(-)
diff --git a/dev/gettext/export/main.go b/dev/gettext/export/main.go
@@ -0,0 +1,193 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+ "path"
+ "strings"
+
+ "git.defalsify.org/vise.git/debug"
+ "git.defalsify.org/vise.git/lang"
+ "git.defalsify.org/vise.git/resource"
+ "git.defalsify.org/vise.git/logging"
+ fsdb "git.defalsify.org/vise.git/db/fs"
+
+)
+
+var (
+ logg = logging.NewVanilla()
+)
+
+type translator struct {
+ langs []lang.Language
+ haveLang map[string]bool
+ ctx context.Context
+ rs *resource.PoResource
+ outPath string
+ madePath bool
+}
+
+func newTranslator(ctx context.Context, defaultLanguage lang.Language, inPath string, outPath string) *translator {
+ tr := &translator{
+ langs: []lang.Language{defaultLanguage},
+ haveLang: make(map[string]bool),
+ ctx: ctx,
+ rs: resource.NewPoResource(defaultLanguage, inPath),
+ outPath: outPath,
+ }
+ tr.haveLang[defaultLanguage.Code] = true
+ return tr
+}
+
+func(tr *translator) AddLang(ln lang.Language) error {
+ var ok bool
+ _, ok = tr.haveLang[ln.Code]
+ if !ok {
+ tr.langs = append(tr.langs, ln)
+ tr.rs = tr.rs.WithLanguage(ln)
+ tr.haveLang[ln.Code] = true
+ }
+ return nil
+}
+
+func(tr *translator) nodeFunc(node *debug.Node) error {
+ sym := node.Name
+ for i, ln := range(tr.langs) {
+ s, err := tr.rs.GetTemplate(tr.ctx, sym)
+ if err != nil {
+ logg.DebugCtxf(tr.ctx, "template not found", "sym", s)
+ continue
+ }
+ if s != sym {
+ if !tr.madePath {
+ err := os.MkdirAll(tr.outPath, 0700)
+ if err != nil {
+ return err
+ }
+ }
+ fb := sym
+ if i > 0 {
+ fb += "_" + ln.Code
+ }
+ fp := path.Join(tr.outPath, fb)
+ w, err := os.OpenFile(fp, os.O_WRONLY | os.O_CREATE, 0644)
+ if err != nil {
+ return err
+ }
+ c, err := w.Write([]byte(s))
+ defer w.Close()
+ if err != nil {
+ return err
+ }
+ logg.DebugCtxf(tr.ctx, "wrote node", "sym", sym, "bytes", c)
+ }
+ }
+ return nil
+}
+
+func(tr *translator) Close() error {
+ return nil
+}
+
+type langVar struct {
+ v []lang.Language
+}
+
+func(lv *langVar) Set(s string) error {
+ v, err := lang.LanguageFromCode(s)
+ if err != nil {
+ return err
+ }
+ lv.v = append(lv.v, v)
+ return err
+}
+
+func(lv *langVar) String() string {
+ var s []string
+ for _, v := range(lv.v) {
+ s = append(s, v.Code)
+ }
+ return strings.Join(s, ",")
+}
+
+func(lv *langVar) Langs() []lang.Language {
+ return lv.v
+}
+
+func main() {
+ var dir string
+ var inDir string
+ var outDir string
+ var root string
+ var langs langVar
+ var defaultLanguage string
+
+ flag.StringVar(&dir, "d", ".", "node resource dir to read from")
+ flag.StringVar(&inDir, "i", "", "gettext dir")
+ flag.StringVar(&outDir, "o", "locale", "output directory")
+ flag.StringVar(&root, "root", "root", "entry point symbol")
+ flag.Var(&langs, "l", "process for language")
+ flag.StringVar(&defaultLanguage, "defaultlanguage", "eng", "default language to resolve for")
+ flag.Parse()
+
+ fmt.Fprintf(os.Stderr, "starting session at symbol '%s' using resource dir: %s\n", root, dir)
+
+ err := os.MkdirAll(outDir, 0700)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "output dir create error: %v", err)
+ os.Exit(1)
+ }
+
+ ctx := context.Background()
+ rsStore := fsdb.NewFsDb()
+ err = rsStore.Connect(ctx, dir)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "resource db connect error: %v", err)
+ os.Exit(1)
+ }
+
+ rs := resource.NewDbResource(rsStore)
+
+ ln, err := lang.LanguageFromCode(defaultLanguage)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "invalid default language: %v", err)
+ os.Exit(1)
+ }
+ tr := newTranslator(ctx, ln, inDir, outDir)
+ defer tr.Close()
+ for _, ln := range(langs.Langs()) {
+ logg.DebugCtxf(ctx, "lang", "lang", ln)
+ err = tr.AddLang(ln)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "add language failed for %s: %v", ln.Code, err)
+ os.Exit(1)
+ }
+ }
+
+ nm := debug.NewNodeMap(root)
+ err = nm.Run(ctx, rs)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "node tree process fail: %v", err)
+ os.Exit(1)
+ }
+
+ for k, v := range(debug.NodeIndex) {
+ err = tr.nodeFunc(&v)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "translate process error for node %s: %v", k, err)
+ os.Exit(1)
+ }
+ }
+
+// for k, _ := range(debug.MenuIndex) {
+// logg.Tracef("processing menu", "sym", k)
+// err = tr.menuFunc(k)
+// if err != nil {
+// fmt.Fprintf(os.Stderr, "translate process error for menu %s: %v", k, err)
+// os.Exit(1)
+// }
+// }
+
+}
diff --git a/dev/gettext/import/main.go b/dev/gettext/import/main.go
@@ -0,0 +1,280 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "io"
+ "os"
+ "path"
+ "strings"
+
+ "git.defalsify.org/vise.git/debug"
+ "git.defalsify.org/vise.git/lang"
+ "git.defalsify.org/vise.git/resource"
+ "git.defalsify.org/vise.git/logging"
+ fsdb "git.defalsify.org/vise.git/db/fs"
+
+)
+
+var (
+ logg = logging.NewVanilla()
+)
+
+type translator struct {
+ langs []lang.Language
+ ctx context.Context
+ rs resource.Resource
+ newline bool
+ d string
+ w map[string]io.WriteCloser
+ mw map[string]io.WriteCloser
+}
+
+func newTranslator(ctx context.Context, rs resource.Resource, outPath string, newline bool) *translator {
+ return &translator{
+ ctx: ctx,
+ rs: rs,
+ d: outPath,
+ newline: newline,
+ w: make(map[string]io.WriteCloser),
+ mw: make(map[string]io.WriteCloser),
+ }
+}
+
+func(tr *translator) applyLanguage(node *debug.Node) {
+
+}
+
+func(tr *translator) ensureFileNameFor(ln lang.Language, domain string) (string, error) {
+ fileName := domain + ".po"
+ p := path.Join(tr.d, ln.Code)
+ err := os.MkdirAll(p, 0700)
+ if err != nil {
+ return "", err
+ }
+ return path.Join(p, fileName), nil
+}
+
+func(tr *translator) Close() error {
+ var s string
+ var err error
+ for _, v := range(tr.langs) {
+ o, ok := tr.w[v.Code]
+ if ok {
+ err = o.Close()
+ if err != nil {
+ s += fmt.Sprintf("\ntemplate writer close error %s: %v", v.Code, err)
+ }
+ }
+ o, ok = tr.mw[v.Code]
+ if ok {
+ err = o.Close()
+ if err != nil {
+ s += fmt.Sprintf("\nmenu writer close error %s: %v", v.Code, err)
+ }
+ }
+
+ }
+ if len(s) > 0 {
+ err = fmt.Errorf("%s", s)
+ }
+ return err
+}
+
+func(tr *translator) process(s string) error {
+ return nil
+}
+
+func(tr *translator) menuFunc(sym string) error {
+ var v string
+
+ for k, w := range(tr.mw) {
+ var s string
+ ln, err := lang.LanguageFromCode(k)
+ ctx := context.WithValue(tr.ctx, "Language", ln)
+ r, err := tr.rs.GetMenu(ctx, sym)
+ for _, v = range(strings.Split(r, "\n")) {
+ s += fmt.Sprintf("\t\"%s\"\n", v)
+ }
+ s = fmt.Sprintf(`msgid ""
+ "%s"
+msgstr ""
+%s
+
+`, sym, s)
+ if err == nil {
+ logg.DebugCtxf(tr.ctx, "menu translation found", "node", sym)
+ _, err = w.Write([]byte(s))
+ if err != nil {
+ return err
+ }
+ } else {
+ logg.DebugCtxf(tr.ctx, "no menuitem translation found", "node", sym)
+ }
+ }
+ return nil
+}
+
+// TODO: DRY; merge with menuFunc
+func(tr *translator) nodeFunc(node *debug.Node) error {
+ for k, w := range(tr.w) {
+ var s string
+ ln, err := lang.LanguageFromCode(k)
+ ctx := context.WithValue(tr.ctx, "Language", ln)
+ r, err := tr.rs.GetTemplate(ctx, node.Name)
+ for i, v := range(strings.Split(r, "\n")) {
+ if tr.newline {
+ if i > 0 {
+ s += "\\n\"\n"
+ } else if len(s) > 0 {
+ s += "\"\n"
+ }
+ s += fmt.Sprintf("\t\"%s", v)
+ } else {
+ s += fmt.Sprintf("\t\"%s\"\n", v)
+ }
+ }
+ if tr.newline {
+ if len(s) > 0 {
+ s += "\"\n"
+ }
+ }
+ s = fmt.Sprintf(`msgid ""
+ "%s"
+msgstr ""
+%s
+
+`, node.Name, s)
+ if err == nil {
+ _, err = w.Write([]byte(s))
+ if err != nil {
+ return err
+ }
+ } else {
+ logg.DebugCtxf(tr.ctx, "no template found", "node", node.Name)
+ }
+ }
+ return nil
+}
+
+func(tr *translator) AddLang(ln lang.Language) error {
+ s := fmt.Sprintf(`msgid ""
+msgstr ""
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Language: %s\n"
+
+`, ln.Code)
+
+ filePath, err := tr.ensureFileNameFor(ln, resource.TemplatePoDomain)
+ if err != nil {
+ return err
+ }
+ w, err := os.OpenFile(filePath, os.O_WRONLY | os.O_CREATE, 0644)
+ w.Write([]byte(s))
+ tr.w[ln.Code] = w
+
+ filePath, err = tr.ensureFileNameFor(ln, resource.MenuPoDomain)
+ if err != nil {
+ return err
+ }
+ w, err = os.OpenFile(filePath, os.O_WRONLY | os.O_CREATE, 0644)
+ w.Write([]byte(s))
+ tr.mw[ln.Code] = w
+
+ return err
+}
+
+type langVar struct {
+ v []lang.Language
+}
+
+func(lv *langVar) Set(s string) error {
+ v, err := lang.LanguageFromCode(s)
+ if err != nil {
+ return err
+ }
+ lv.v = append(lv.v, v)
+ return err
+}
+
+func(lv *langVar) String() string {
+ var s []string
+ for _, v := range(lv.v) {
+ s = append(s, v.Code)
+ }
+ return strings.Join(s, ",")
+}
+
+func(lv *langVar) Langs() []lang.Language {
+ return lv.v
+}
+
+func main() {
+ var dir string
+ var outDir string
+ var root string
+ var newline bool
+ var langs langVar
+
+ flag.StringVar(&dir, "i", ".", "resource dir to read from")
+ flag.StringVar(&outDir, "o", "locale", "output directory")
+ flag.StringVar(&root, "root", "root", "entry point symbol")
+ flag.BoolVar(&newline, "newline", false, "insert newlines in multiline strings")
+ flag.Var(&langs, "l", "process for language")
+ flag.Parse()
+
+ fmt.Fprintf(os.Stderr, "starting session at symbol '%s' using resource dir: %s\n", root, dir)
+
+ err := os.MkdirAll(outDir, 0700)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "output dir create error: %v", err)
+ os.Exit(1)
+ }
+
+ ctx := context.Background()
+ rsStore := fsdb.NewFsDb()
+ err = rsStore.Connect(ctx, dir)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "resource db connect error: %v", err)
+ os.Exit(1)
+ }
+
+ rs := resource.NewDbResource(rsStore)
+
+ tr := newTranslator(ctx, rs, outDir, newline)
+ defer tr.Close()
+ for _, ln := range(langs.Langs()) {
+ logg.DebugCtxf(ctx, "lang", "lang", ln)
+ err = tr.AddLang(ln)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "add language failed for %s: %v", ln.Code, err)
+ os.Exit(1)
+ }
+ }
+
+ nm := debug.NewNodeMap(root)
+ err = nm.Run(ctx, rs)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "node tree process fail: %v", err)
+ os.Exit(1)
+ }
+
+ for k, v := range(debug.NodeIndex) {
+ err = tr.nodeFunc(&v)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "translate process error for node %s: %v", k, err)
+ os.Exit(1)
+ }
+ }
+
+ for k, _ := range(debug.MenuIndex) {
+ logg.Tracef("processing menu", "sym", k)
+ err = tr.menuFunc(k)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "translate process error for menu %s: %v", k, err)
+ os.Exit(1)
+ }
+ }
+
+}
diff --git a/dev/walk/main.go b/dev/walk/main.go
@@ -1,280 +0,0 @@
-package main
-
-import (
- "context"
- "flag"
- "fmt"
- "io"
- "os"
- "path"
- "strings"
-
- "git.defalsify.org/vise.git/debug"
- "git.defalsify.org/vise.git/lang"
- "git.defalsify.org/vise.git/resource"
- "git.defalsify.org/vise.git/logging"
- fsdb "git.defalsify.org/vise.git/db/fs"
-
-)
-
-var (
- logg = logging.NewVanilla()
-)
-
-type translator struct {
- langs []lang.Language
- ctx context.Context
- rs resource.Resource
- newline bool
- d string
- w map[string]io.WriteCloser
- mw map[string]io.WriteCloser
-}
-
-func newTranslator(ctx context.Context, rs resource.Resource, outPath string, newline bool) *translator {
- return &translator{
- ctx: ctx,
- rs: rs,
- d: outPath,
- newline: newline,
- w: make(map[string]io.WriteCloser),
- mw: make(map[string]io.WriteCloser),
- }
-}
-
-func(tr *translator) applyLanguage(node *debug.Node) {
-
-}
-
-func(tr *translator) ensureFileNameFor(ln lang.Language, domain string) (string, error) {
- fileName := domain + ".po"
- p := path.Join(tr.d, ln.Code)
- err := os.MkdirAll(p, 0700)
- if err != nil {
- return "", err
- }
- return path.Join(p, fileName), nil
-}
-
-func(tr *translator) Close() error {
- var s string
- var err error
- for _, v := range(tr.langs) {
- o, ok := tr.w[v.Code]
- if ok {
- err = o.Close()
- if err != nil {
- s += fmt.Sprintf("\ntemplate writer close error %s: %v", v.Code, err)
- }
- }
- o, ok = tr.mw[v.Code]
- if ok {
- err = o.Close()
- if err != nil {
- s += fmt.Sprintf("\nmenu writer close error %s: %v", v.Code, err)
- }
- }
-
- }
- if len(s) > 0 {
- err = fmt.Errorf("%s", s)
- }
- return err
-}
-
-func(tr *translator) process(s string) error {
- return nil
-}
-
-func(tr *translator) menuFunc(sym string) error {
- var v string
-
- for k, w := range(tr.mw) {
- var s string
- ln, err := lang.LanguageFromCode(k)
- ctx := context.WithValue(tr.ctx, "Language", ln)
- r, err := tr.rs.GetMenu(ctx, sym)
- for _, v = range(strings.Split(r, "\n")) {
- s += fmt.Sprintf("\t\"%s\"\n", v)
- }
- s = fmt.Sprintf(`msgid ""
- "%s"
-msgstr ""
-%s
-
-`, sym, s)
- if err == nil {
- logg.DebugCtxf(tr.ctx, "menu translation found", "node", sym)
- _, err = w.Write([]byte(s))
- if err != nil {
- return err
- }
- } else {
- logg.DebugCtxf(tr.ctx, "no menuitem translation found", "node", sym)
- }
- }
- return nil
-}
-
-// TODO: DRY; merge with menuFunc
-func(tr *translator) nodeFunc(node *debug.Node) error {
- for k, w := range(tr.w) {
- var s string
- ln, err := lang.LanguageFromCode(k)
- ctx := context.WithValue(tr.ctx, "Language", ln)
- r, err := tr.rs.GetTemplate(ctx, node.Name)
- for i, v := range(strings.Split(r, "\n")) {
- if tr.newline {
- if i > 0 {
- s += "\\n\"\n"
- } else if len(s) > 0 {
- s += "\"\n"
- }
- s += fmt.Sprintf("\t\"%s", v)
- } else {
- s += fmt.Sprintf("\t\"%s\"\n", v)
- }
- }
- if tr.newline {
- if len(s) > 0 {
- s += "\"\n"
- }
- }
- s = fmt.Sprintf(`msgid ""
- "%s"
-msgstr ""
-%s
-
-`, node.Name, s)
- if err == nil {
- _, err = w.Write([]byte(s))
- if err != nil {
- return err
- }
- } else {
- logg.DebugCtxf(tr.ctx, "no template found", "node", node.Name)
- }
- }
- return nil
-}
-
-func(tr *translator) AddLang(ln lang.Language) error {
- s := fmt.Sprintf(`msgid ""
-msgstr ""
- "Content-Type: text/plain; charset=UTF-8\n"
- "Language: %s\n"
-
-`, ln.Code)
-
- filePath, err := tr.ensureFileNameFor(ln, resource.TemplatePoDomain)
- if err != nil {
- return err
- }
- w, err := os.OpenFile(filePath, os.O_WRONLY | os.O_CREATE, 0644)
- w.Write([]byte(s))
- tr.w[ln.Code] = w
-
- filePath, err = tr.ensureFileNameFor(ln, resource.MenuPoDomain)
- if err != nil {
- return err
- }
- w, err = os.OpenFile(filePath, os.O_WRONLY | os.O_CREATE, 0644)
- w.Write([]byte(s))
- tr.mw[ln.Code] = w
-
- return err
-}
-
-type langVar struct {
- v []lang.Language
-}
-
-func(lv *langVar) Set(s string) error {
- v, err := lang.LanguageFromCode(s)
- if err != nil {
- return err
- }
- lv.v = append(lv.v, v)
- return err
-}
-
-func(lv *langVar) String() string {
- var s []string
- for _, v := range(lv.v) {
- s = append(s, v.Code)
- }
- return strings.Join(s, ",")
-}
-
-func(lv *langVar) Langs() []lang.Language {
- return lv.v
-}
-
-func main() {
- var dir string
- var outDir string
- var root string
- var newline bool
- var langs langVar
-
- flag.StringVar(&dir, "d", ".", "resource dir to read from")
- flag.StringVar(&outDir, "o", "locale", "output directory")
- flag.StringVar(&root, "root", "root", "entry point symbol")
- flag.BoolVar(&newline, "newline", false, "insert newlines in multiline strings")
- flag.Var(&langs, "l", "process for language")
- flag.Parse()
-
- fmt.Fprintf(os.Stderr, "starting session at symbol '%s' using resource dir: %s\n", root, dir)
-
- err := os.MkdirAll(outDir, 0700)
- if err != nil {
- fmt.Fprintf(os.Stderr, "output dir create error: %v", err)
- os.Exit(1)
- }
-
- ctx := context.Background()
- rsStore := fsdb.NewFsDb()
- err = rsStore.Connect(ctx, dir)
- if err != nil {
- fmt.Fprintf(os.Stderr, "resource db connect error: %v", err)
- os.Exit(1)
- }
-
- rs := resource.NewDbResource(rsStore)
-
- tr := newTranslator(ctx, rs, outDir, newline)
- defer tr.Close()
- for _, ln := range(langs.Langs()) {
- logg.DebugCtxf(ctx, "lang", "lang", ln)
- err = tr.AddLang(ln)
- if err != nil {
- fmt.Fprintf(os.Stderr, "add language failed for %s: %v", ln.Code, err)
- os.Exit(1)
- }
- }
-
- nm := debug.NewNodeMap(root)
- err = nm.Run(ctx, rs)
- if err != nil {
- fmt.Fprintf(os.Stderr, "node tree process fail: %v", err)
- os.Exit(1)
- }
-
- for k, v := range(debug.NodeIndex) {
- err = tr.nodeFunc(&v)
- if err != nil {
- fmt.Fprintf(os.Stderr, "translate process error for node %s: %v", k, err)
- os.Exit(1)
- }
- }
-
- for k, _ := range(debug.MenuIndex) {
- logg.Tracef("processing menu", "sym", k)
- err = tr.menuFunc(k)
- if err != nil {
- fmt.Fprintf(os.Stderr, "translate process error for menu %s: %v", k, err)
- os.Exit(1)
- }
- }
-
-}