package main import ( "bytes" "flag" "fmt" "io" "os" "path/filepath" "slices" "strings" "text/template/parse" "time" ) type config struct { arg int plural int context int domain int } type translation struct { msgid string msgidPlural string msgctxt string domain string } type transinfo struct { comment string locs []loc } type loc struct { file string line int } func (l loc) String() string { return fmt.Sprintf("%s:%d", l.file, l.line) } var ( currentFile []byte currentPath string lastComment string translations = make(map[translation]transinfo) configs = map[string]config{ "Get": {1, -1, -1, -1}, "GetC": {1, -1, 2, -1}, "GetD": {2, -1, -1, 1}, "GetDC": {2, -1, 3, 1}, "GetN": {1, 2, -1, -1}, "GetNC": {1, 2, 4, -1}, "GetND": {2, 3, -1, 1}, "GetNDC": {2, 3, 5, 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.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 , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: %s\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "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 != "" { fmt.Fprintln(outfile, "#.", ti.comment) } slices.SortFunc(ti.locs, func(a, b loc) int { if x := strings.Compare(a.file, b.file); x != 0 { return x } return a.line - b.line }) for _, x := range ti.locs { fmt.Fprintln(outfile, "#:", x) } if tl.msgctxt != "" { writeField(outfile, "msgctxt", tl.msgctxt) } writeField(outfile, "msgid", tl.msgid) if tl.msgidPlural != "" { writeField(outfile, "msgid_plural", tl.msgidPlural) writeField(outfile, "msgstr[0]", "") writeField(outfile, "msgstr[1]", "") } else { writeField(outfile, "msgstr", "") } fmt.Fprint(outfile, "\n") } } func process(path string) { currentPath = path currentFile = try2(os.ReadFile(path)) switch { case strings.HasSuffix(path, ".html.tmpl"): processHtml(path) case strings.HasSuffix(path, ".sql"): processSql(path) } } func writeField(w io.Writer, pfx, s string) { fmt.Fprintf(w, "%s ", pfx) if strings.ContainsRune(s, '\n') { fmt.Fprintln(w, "\"\"") lines := strings.SplitAfter(s, "\n") n := len(lines) if n > 1 && lines[n-1] == "" { lines = lines[:n-1] } for _, ss := range lines { writeLine(w, ss) } fmt.Fprintln(w, "\"\"") } else { writeLine(w, s) } } func writeLine(w io.Writer, s string) { fmt.Fprint(w, "\"") for _, c := range s { switch c { case '\\', '"': fmt.Fprintf(w, "\\%c", c) case '\n': fmt.Fprint(w, "\\n") default: fmt.Fprintf(w, "%c", c) } } fmt.Fprintln(w, "\"") } func getlinenr(p parse.Pos) int { return bytes.Count(currentFile[:p], []byte{'\n'}) + 1 } func try(err error) { if err != nil { die(err) } } func try2[T any](val T, err error) T { try(err) return val } func warn(err any) { fmt.Fprintf(os.Stderr, "%s: %s\n", filepath.Base(os.Args[0]), err) } func die(err any) { warn(err) os.Exit(1) }