aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--go-xgettext/main.go357
-rw-r--r--src/gotext.go426
2 files changed, 426 insertions, 357 deletions
diff --git a/go-xgettext/main.go b/go-xgettext/main.go
deleted file mode 100644
index 881cb9f..0000000
--- a/go-xgettext/main.go
+++ /dev/null
@@ -1,357 +0,0 @@
-// -*- Mode: Go; indent-tabs-mode: t -*-
-
-/*
- * Copyright (C) 2015-2016 Canonical Ltd
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
-
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package main
-
-import (
- "fmt"
- "go/ast"
- "go/parser"
- "go/token"
- "io"
- "io/ioutil"
- "log"
- "os"
- "sort"
- "strings"
- "time"
-
- "github.com/jessevdk/go-flags"
-)
-
-type msgID struct {
- msgidPlural string
- comment string
- fname string
- line int
- formatHint string
-}
-
-var msgIDs map[string][]msgID
-
-func formatComment(com string) string {
- out := ""
- for _, rawline := range strings.Split(com, "\n") {
- line := rawline
- line = strings.TrimPrefix(line, "//")
- line = strings.TrimPrefix(line, "/*")
- line = strings.TrimSuffix(line, "*/")
- line = strings.TrimSpace(line)
- if line != "" {
- out += fmt.Sprintf("#. %s\n", line)
- }
- }
-
- return out
-}
-
-func findCommentsForTranslation(fset *token.FileSet, f *ast.File, posCall token.Position) string {
- com := ""
- for _, cg := range f.Comments {
- // search for all comments in the previous line
- for i := len(cg.List) - 1; i >= 0; i-- {
- c := cg.List[i]
-
- posComment := fset.Position(c.End())
- //println(posCall.Line, posComment.Line, c.Text)
- if posCall.Line == posComment.Line+1 {
- posCall = posComment
- com = fmt.Sprintf("%s\n%s", c.Text, com)
- }
- }
- }
-
- // only return if we have a matching prefix
- formatedComment := formatComment(com)
- needle := fmt.Sprintf("#. %s", opts.AddCommentsTag)
- if !strings.HasPrefix(formatedComment, needle) {
- formatedComment = ""
- }
-
- return formatedComment
-}
-
-func constructValue(val interface{}) string {
- switch val.(type) {
- case *ast.BasicLit:
- return val.(*ast.BasicLit).Value
- // this happens for constructs like:
- // gettext.Gettext("foo" + "bar")
- case *ast.BinaryExpr:
- // we only support string concat
- if val.(*ast.BinaryExpr).Op != token.ADD {
- return ""
- }
- left := constructValue(val.(*ast.BinaryExpr).X)
- // strip right " (or `)
- left = left[0 : len(left)-1]
- right := constructValue(val.(*ast.BinaryExpr).Y)
- // strip left " (or `)
- right = right[1:len(right)]
- return left + right
- default:
- panic(fmt.Sprintf("unknown type: %v", val))
- }
-}
-
-func inspectNodeForTranslations(fset *token.FileSet, f *ast.File, n ast.Node) bool {
- // FIXME: this assume we always have a "gettext.Gettext" style keyword
- var gettextSelector, gettextFuncName string
- l := strings.Split(opts.Keyword, ".")
-
- if len(l) > 1 {
- gettextSelector = l[0]
- gettextFuncName = l[1]
- } else {
- gettextFuncName = l[0]
- }
-
- var gettextSelectorPlural, gettextFuncNamePlural string
- l = strings.Split(opts.KeywordPlural, ".")
-
- if len(l) > 1 {
- gettextSelectorPlural = l[0]
- gettextFuncNamePlural = l[1]
- } else {
- gettextFuncNamePlural = l[0]
- }
-
- switch x := n.(type) {
- case *ast.CallExpr:
- var i18nStr, i18nStrPlural string
- //if sel, ok := x.Fun.(*ast.Ident); ok {
-
- //}
- switch sel := x.Fun.(type) {
- case *ast.Ident:
- if sel.Name == gettextFuncNamePlural {
- i18nStr = x.Args[0].(*ast.BasicLit).Value
- i18nStrPlural = x.Args[1].(*ast.BasicLit).Value
- }
- if sel.Name == gettextFuncName {
- i18nStr = constructValue(x.Args[0])
- }
- case *ast.SelectorExpr:
- if sel.Sel.Name == gettextFuncNamePlural && sel.X.(*ast.Ident).Name == gettextSelectorPlural {
- i18nStr = x.Args[0].(*ast.BasicLit).Value
- i18nStrPlural = x.Args[1].(*ast.BasicLit).Value
- }
-
- if sel.Sel.Name == gettextFuncName && sel.X.(*ast.Ident).Name == gettextSelector {
- i18nStr = constructValue(x.Args[0])
- }
- }
-
- if i18nStr == "" {
- break
- }
-
- // FIXME: too simplistic(?), no %% is considered
- formatHint := ""
- if strings.Contains(i18nStr, "%") || strings.Contains(i18nStrPlural, "%") {
- // well, not quite correct but close enough
- formatHint = "c-format"
- }
-
- msgidStr := formatI18nStr(i18nStr)
- posCall := fset.Position(n.Pos())
- msgIDs[msgidStr] = append(msgIDs[msgidStr], msgID{
- formatHint: formatHint,
- msgidPlural: formatI18nStr(i18nStrPlural),
- fname: posCall.Filename,
- line: posCall.Line,
- comment: findCommentsForTranslation(fset, f, posCall),
- })
- }
-
- return true
-}
-
-func formatI18nStr(s string) string {
- if s == "" {
- return ""
- }
- // the "`" is special
- if s[0] == '`' {
- // replace inner " with \"
- s = strings.Replace(s, "\"", "\\\"", -1)
- // replace \n with \\n
- s = strings.Replace(s, "\n", "\\n", -1)
- }
- // strip leading and trailing " (or `)
- s = s[1 : len(s)-1]
- return s
-}
-
-func processFiles(args []string) error {
- // go over the input files
- msgIDs = make(map[string][]msgID)
-
- fset := token.NewFileSet()
- for _, fname := range args {
- if err := processSingleGoSource(fset, fname); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func processSingleGoSource(fset *token.FileSet, fname string) error {
- fnameContent, err := ioutil.ReadFile(fname)
- if err != nil {
- panic(err)
- }
-
- // Create the AST by parsing src.
- f, err := parser.ParseFile(fset, fname, fnameContent, parser.ParseComments)
- if err != nil {
- panic(err)
- }
-
- ast.Inspect(f, func(n ast.Node) bool {
- return inspectNodeForTranslations(fset, f, n)
- })
-
- return nil
-}
-
-var formatTime = func() string {
- return time.Now().Format("2006-01-02 15:04-0700")
-}
-
-func writePotFile(out io.Writer) {
-
- header := fmt.Sprintf(`# 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.
-#
-#, fuzzy
-msgid ""
-msgstr "Project-Id-Version: %s\n"
- "Report-Msgid-Bugs-To: %s\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"
- "Language: \n"
- "MIME-Version: 1.0\n"
- "Content-Type: text/plain; charset=CHARSET\n"
- "Content-Transfer-Encoding: 8bit\n"
-
-`, opts.PackageName, opts.MsgIDBugsAddress, formatTime())
- fmt.Fprintf(out, "%s", header)
-
- // yes, this is the way to do it in go
- sortedKeys := []string{}
- for k := range msgIDs {
- sortedKeys = append(sortedKeys, k)
- }
- if opts.SortOutput {
- sort.Strings(sortedKeys)
- }
-
- // FIXME: use template here?
- for _, k := range sortedKeys {
- msgidList := msgIDs[k]
- for _, msgid := range msgidList {
- if opts.AddComments || opts.AddCommentsTag != "" {
- fmt.Fprintf(out, "%s", msgid.comment)
- }
- }
- if !opts.NoLocation {
- fmt.Fprintf(out, "#:")
- for _, msgid := range msgidList {
- fmt.Fprintf(out, " %s:%d", msgid.fname, msgid.line)
- }
- fmt.Fprintf(out, "\n")
- }
- msgid := msgidList[0]
- if msgid.formatHint != "" {
- fmt.Fprintf(out, "#, %s\n", msgid.formatHint)
- }
- var formatOutput = func(in string) string {
- // split string with \n into multiple lines
- // to make the output nicer
- out := strings.Replace(in, "\\n", "\\n\"\n \"", -1)
- // cleanup too aggressive splitting (empty "" lines)
- return strings.TrimSuffix(out, "\"\n \"")
- }
- fmt.Fprintf(out, "msgid \"%v\"\n", formatOutput(k))
- if msgid.msgidPlural != "" {
- fmt.Fprintf(out, "msgid_plural \"%v\"\n", formatOutput(msgid.msgidPlural))
- fmt.Fprintf(out, "msgstr[0] \"\"\n")
- fmt.Fprintf(out, "msgstr[1] \"\"\n")
- } else {
- fmt.Fprintf(out, "msgstr \"\"\n")
- }
- fmt.Fprintf(out, "\n")
- }
-
-}
-
-// FIXME: this must be setable via go-flags
-var opts struct {
- Output string `short:"o" long:"output" description:"output to specified file"`
-
- AddComments bool `short:"c" long:"add-comments" description:"place all comment blocks preceding keyword lines in output file"`
-
- AddCommentsTag string `long:"add-comments-tag" description:"place comment blocks starting with TAG and prceding keyword lines in output file"`
-
- SortOutput bool `short:"s" long:"sort-output" description:"generate sorted output"`
-
- NoLocation bool `long:"no-location" description:"do not write '#: filename:line' lines"`
-
- MsgIDBugsAddress string `long:"msgid-bugs-address" default:"EMAIL" description:"set report address for msgid bugs"`
-
- PackageName string `long:"package-name" description:"set package name in output"`
-
- Keyword string `short:"k" long:"keyword" default:"gettext.Gettext" description:"look for WORD as the keyword for singular strings"`
- KeywordPlural string `long:"keyword-plural" default:"gettext.NGettext" description:"look for WORD as the keyword for plural strings"`
-}
-
-func main() {
- // parse args
- args, err := flags.ParseArgs(&opts, os.Args)
- if err != nil {
- log.Fatalf("ParseArgs failed %s", err)
- }
-
- if err := processFiles(args[1:]); err != nil {
- log.Fatalf("processFiles failed with: %s", err)
- }
-
- out := os.Stdout
- if opts.Output != "" {
- var err error
- out, err = os.Create(opts.Output)
- if err != nil {
- log.Fatalf("failed to create %s: %s", opts.Output, err)
- }
- }
- writePotFile(out)
-}
diff --git a/src/gotext.go b/src/gotext.go
index 6c3d9fe..ae65d58 100644
--- a/src/gotext.go
+++ b/src/gotext.go
@@ -1,6 +1,21 @@
package gotext
import (
+ "fmt"
+ "flag"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "sort"
+ "strings"
+ "time"
+
+ g "gobang"
+ // "github.com/jessevdk/go-flags"
)
@@ -15,5 +30,416 @@ const (
_ = C.int(1)
)
+type msgID struct {
+ msgidPlural string
+ comment string
+ fname string
+ line int
+ formatHint string
+}
+
+var msgIDs map[string][]msgID
+
+func formatComment(com string) string {
+ out := ""
+ for _, rawline := range strings.Split(com, "\n") {
+ line := rawline
+ line = strings.TrimPrefix(line, "//")
+ line = strings.TrimPrefix(line, "/*")
+ line = strings.TrimSuffix(line, "*/")
+ line = strings.TrimSpace(line)
+ if line != "" {
+ out += fmt.Sprintf("#. %s\n", line)
+ }
+ }
+
+ return out
+}
+
+func findCommentsForTranslation(fset *token.FileSet, f *ast.File, posCall token.Position) string {
+ com := ""
+ for _, cg := range f.Comments {
+ // search for all comments in the previous line
+ for i := len(cg.List) - 1; i >= 0; i-- {
+ c := cg.List[i]
+
+ posComment := fset.Position(c.End())
+ //println(posCall.Line, posComment.Line, c.Text)
+ if posCall.Line == posComment.Line+1 {
+ posCall = posComment
+ com = fmt.Sprintf("%s\n%s", c.Text, com)
+ }
+ }
+ }
+
+ // only return if we have a matching prefix
+ formatedComment := formatComment(com)
+ needle := fmt.Sprintf("#. %s", opts.AddCommentsTag)
+ if !strings.HasPrefix(formatedComment, needle) {
+ formatedComment = ""
+ }
+
+ return formatedComment
+}
+
+func constructValue(val interface{}) string {
+ switch val.(type) {
+ case *ast.BasicLit:
+ return val.(*ast.BasicLit).Value
+ // this happens for constructs like:
+ // gettext.Gettext("foo" + "bar")
+ case *ast.BinaryExpr:
+ // we only support string concat
+ if val.(*ast.BinaryExpr).Op != token.ADD {
+ return ""
+ }
+ left := constructValue(val.(*ast.BinaryExpr).X)
+ // strip right " (or `)
+ left = left[0 : len(left)-1]
+ right := constructValue(val.(*ast.BinaryExpr).Y)
+ // strip left " (or `)
+ right = right[1:len(right)]
+ return left + right
+ default:
+ panic(fmt.Sprintf("unknown type: %v", val))
+ }
+}
+
+func inspectNodeForTranslations(fset *token.FileSet, f *ast.File, n ast.Node) bool {
+ // FIXME: this assume we always have a "gettext.Gettext" style keyword
+ var gettextSelector, gettextFuncName string
+ l := strings.Split(opts.Keyword, ".")
+
+ if len(l) > 1 {
+ gettextSelector = l[0]
+ gettextFuncName = l[1]
+ } else {
+ gettextFuncName = l[0]
+ }
+
+ var gettextSelectorPlural, gettextFuncNamePlural string
+ l = strings.Split(opts.KeywordPlural, ".")
+
+ if len(l) > 1 {
+ gettextSelectorPlural = l[0]
+ gettextFuncNamePlural = l[1]
+ } else {
+ gettextFuncNamePlural = l[0]
+ }
+
+ switch x := n.(type) {
+ case *ast.CallExpr:
+ var i18nStr, i18nStrPlural string
+ //if sel, ok := x.Fun.(*ast.Ident); ok {
+
+ //}
+ switch sel := x.Fun.(type) {
+ case *ast.Ident:
+ if sel.Name == gettextFuncNamePlural {
+ i18nStr = x.Args[0].(*ast.BasicLit).Value
+ i18nStrPlural = x.Args[1].(*ast.BasicLit).Value
+ }
+ if sel.Name == gettextFuncName {
+ i18nStr = constructValue(x.Args[0])
+ }
+ case *ast.SelectorExpr:
+ if sel.Sel.Name == gettextFuncNamePlural && sel.X.(*ast.Ident).Name == gettextSelectorPlural {
+ i18nStr = x.Args[0].(*ast.BasicLit).Value
+ i18nStrPlural = x.Args[1].(*ast.BasicLit).Value
+ }
+
+ if sel.Sel.Name == gettextFuncName && sel.X.(*ast.Ident).Name == gettextSelector {
+ i18nStr = constructValue(x.Args[0])
+ }
+ }
+
+ if i18nStr == "" {
+ break
+ }
+
+ // FIXME: too simplistic(?), no %% is considered
+ formatHint := ""
+ if strings.Contains(i18nStr, "%") || strings.Contains(i18nStrPlural, "%") {
+ // well, not quite correct but close enough
+ formatHint = "c-format"
+ }
+
+ msgidStr := formatI18nStr(i18nStr)
+ posCall := fset.Position(n.Pos())
+ msgIDs[msgidStr] = append(msgIDs[msgidStr], msgID{
+ formatHint: formatHint,
+ msgidPlural: formatI18nStr(i18nStrPlural),
+ fname: posCall.Filename,
+ line: posCall.Line,
+ comment: findCommentsForTranslation(fset, f, posCall),
+ })
+ }
+
+ return true
+}
+
+func formatI18nStr(s string) string {
+ if s == "" {
+ return ""
+ }
+ // the "`" is special
+ if s[0] == '`' {
+ // replace inner " with \"
+ s = strings.Replace(s, "\"", "\\\"", -1)
+ // replace \n with \\n
+ s = strings.Replace(s, "\n", "\\n", -1)
+ }
+ // strip leading and trailing " (or `)
+ s = s[1 : len(s)-1]
+ return s
+}
+
+func processFiles(args []string) error {
+ // go over the input files
+ msgIDs = make(map[string][]msgID)
+
+ fset := token.NewFileSet()
+ for _, fname := range args {
+ if err := processSingleGoSource(fset, fname); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func processSingleGoSource(fset *token.FileSet, fname string) error {
+ fnameContent, err := ioutil.ReadFile(fname)
+ if err != nil {
+ panic(err)
+ }
+
+ // Create the AST by parsing src.
+ f, err := parser.ParseFile(fset, fname, fnameContent, parser.ParseComments)
+ if err != nil {
+ panic(err)
+ }
+
+ ast.Inspect(f, func(n ast.Node) bool {
+ return inspectNodeForTranslations(fset, f, n)
+ })
+
+ return nil
+}
+
+var formatTime = func() string {
+ return time.Now().Format("2006-01-02 15:04-0700")
+}
+
+func writePotFile(out io.Writer) {
+
+ header := fmt.Sprintf(`# 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.
+#
+#, fuzzy
+msgid ""
+msgstr "Project-Id-Version: %s\n"
+ "Report-Msgid-Bugs-To: %s\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"
+ "Language: \n"
+ "MIME-Version: 1.0\n"
+ "Content-Type: text/plain; charset=CHARSET\n"
+ "Content-Transfer-Encoding: 8bit\n"
+
+`, opts.PackageName, opts.MsgIDBugsAddress, formatTime())
+ fmt.Fprintf(out, "%s", header)
+
+ // yes, this is the way to do it in go
+ sortedKeys := []string{}
+ for k := range msgIDs {
+ sortedKeys = append(sortedKeys, k)
+ }
+ if opts.SortOutput {
+ sort.Strings(sortedKeys)
+ }
+
+ // FIXME: use template here?
+ for _, k := range sortedKeys {
+ msgidList := msgIDs[k]
+ for _, msgid := range msgidList {
+ if opts.AddComments || opts.AddCommentsTag != "" {
+ fmt.Fprintf(out, "%s", msgid.comment)
+ }
+ }
+ if !opts.NoLocation {
+ fmt.Fprintf(out, "#:")
+ for _, msgid := range msgidList {
+ fmt.Fprintf(out, " %s:%d", msgid.fname, msgid.line)
+ }
+ fmt.Fprintf(out, "\n")
+ }
+ msgid := msgidList[0]
+ if msgid.formatHint != "" {
+ fmt.Fprintf(out, "#, %s\n", msgid.formatHint)
+ }
+ var formatOutput = func(in string) string {
+ // split string with \n into multiple lines
+ // to make the output nicer
+ out := strings.Replace(in, "\\n", "\\n\"\n \"", -1)
+ // cleanup too aggressive splitting (empty "" lines)
+ return strings.TrimSuffix(out, "\"\n \"")
+ }
+ fmt.Fprintf(out, "msgid \"%v\"\n", formatOutput(k))
+ if msgid.msgidPlural != "" {
+ fmt.Fprintf(out, "msgid_plural \"%v\"\n", formatOutput(msgid.msgidPlural))
+ fmt.Fprintf(out, "msgstr[0] \"\"\n")
+ fmt.Fprintf(out, "msgstr[1] \"\"\n")
+ } else {
+ fmt.Fprintf(out, "msgstr \"\"\n")
+ }
+ fmt.Fprintf(out, "\n")
+ }
+
+}
+
+// FIXME: this must be setable via go-flags
+type optsT struct {
+ Output string `short:"o" long:"output" description:"output to specified file"`
+
+ AddComments bool `short:"c" long:"add-comments" description:"place all comment blocks preceding keyword lines in output file"`
+
+ AddCommentsTag string `long:"add-comments-tag" description:"place comment blocks starting with TAG and prceding keyword lines in output file"`
+
+ SortOutput bool `short:"s" long:"sort-output" description:"generate sorted output"`
+
+ NoLocation bool `long:"no-location" description:"do not write '#: filename:line' lines"`
+
+ MsgIDBugsAddress string `long:"msgid-bugs-address" default:"EMAIL" description:"set report address for msgid bugs"`
+
+ PackageName string `long:"package-name" description:"set package name in output"`
+
+ Keyword string `short:"k" long:"keyword" default:"gt.Gettext" description:"look for WORD as the keyword for singular strings"`
+ KeywordPlural string `long:"keyword-plural" default:"gt.NGettext" description:"look for WORD as the keyword for plural strings"`
+}
+
+var opts optsT
+
+type argsT struct{
+ allArgs []string
+ subArgs []string
+}
+
+func usage(argv0 string, w io.Writer) {
+ fmt.Fprintf(
+ w,
+ "Usage: %s\n",
+ argv0,
+ )
+}
+
+func getopt(allArgs []string, w io.Writer) (argsT, int) {
+ argv0 := allArgs[0]
+ argv := allArgs[1:]
+ fs := flag.NewFlagSet("", flag.ContinueOnError)
+ fs.Usage = func() {}
+ fs.SetOutput(w)
+
+ output := fs.String(
+ "o",
+ "",
+ "output to specified file",
+ )
+ addComments := fs.Bool(
+ "c",
+ false,
+ "place all comment blocks preceding keyword lines in output file",
+ )
+ addCommentsTag := fs.String(
+ "A",
+ "",
+ "place comment blocks starting with TAG and prceding keyword lines in output file",
+ )
+ sortOutput := fs.Bool(
+ "s",
+ false,
+ "generate sorted output",
+ )
+ noLocation := fs.Bool(
+ "L",
+ false,
+ "do not write '#: filename:line' lines",
+ )
+ msgIDBugsAddress := fs.String(
+ "M",
+ "EMAIL",
+ "set report address for msgid bugs",
+ )
+ packageName := fs.String(
+ "N",
+ "",
+ "set package name in output",
+ )
+ keyword := fs.String(
+ "k",
+ "gt.Gettext",
+ "look for WORD as the keyword for singular strings",
+ )
+ keywordPlural := fs.String(
+ "K",
+ "gt.NGettext",
+ "look for WORD as the keyword for plural strings",
+ )
+
+ if fs.Parse(argv) != nil {
+ usage(argv0, w)
+ return argsT{}, 2
+ }
+
+ opts = optsT{
+ Output: *output,
+ AddComments: *addComments,
+ AddCommentsTag: *addCommentsTag,
+ SortOutput: *sortOutput,
+ NoLocation: *noLocation,
+ MsgIDBugsAddress: *msgIDBugsAddress,
+ PackageName: *packageName,
+ Keyword: *keyword,
+ KeywordPlural: *keywordPlural,
+ }
+
+ subArgs := fs.Args()
+
+ return argsT{
+ allArgs: allArgs,
+ subArgs: subArgs,
+ }, 0
+}
+
+
func Main() {
+ // parse args
+ /*
+ args, err := flags.ParseArgs(&opts, os.Args)
+ if err != nil {
+ log.Fatalf("ParseArgs failed %s", err)
+ }
+ */
+
+ g.Init()
+ args, rc := getopt(os.Args, os.Stderr)
+ g.ExitIf(rc)
+
+ if err := processFiles(args.subArgs); err != nil {
+ log.Fatalf("processFiles failed with: %s", err)
+ }
+
+ out := os.Stdout
+ if opts.Output != "" {
+ var err error
+ out, err = os.Create(opts.Output)
+ if err != nil {
+ log.Fatalf("failed to create %s: %s", opts.Output, err)
+ }
+ }
+ writePotFile(out)
}