summaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/text/cmd/gotext/extract.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/text/cmd/gotext/extract.go')
-rw-r--r--vendor/golang.org/x/text/cmd/gotext/extract.go185
1 files changed, 15 insertions, 170 deletions
diff --git a/vendor/golang.org/x/text/cmd/gotext/extract.go b/vendor/golang.org/x/text/cmd/gotext/extract.go
index 79a9b596d..103d7e600 100644
--- a/vendor/golang.org/x/text/cmd/gotext/extract.go
+++ b/vendor/golang.org/x/text/cmd/gotext/extract.go
@@ -5,22 +5,7 @@
package main
import (
- "bytes"
- "encoding/json"
- "fmt"
- "go/ast"
- "go/build"
- "go/constant"
- "go/format"
- "go/parser"
- "go/types"
- "io/ioutil"
- "os"
- "path"
- "path/filepath"
- "strings"
-
- "golang.org/x/tools/go/loader"
+ "golang.org/x/text/message/pipeline"
)
// TODO:
@@ -29,167 +14,27 @@ import (
// - handle features (gender, plural)
// - message rewriting
+func init() {
+ lang = cmdExtract.Flag.String("lang", "en-US", "comma-separated list of languages to process")
+}
+
var cmdExtract = &Command{
Run: runExtract,
UsageLine: "extract <package>*",
- Short: "extract strings to be translated from code",
+ Short: "extracts strings to be translated from code",
}
-func runExtract(cmd *Command, args []string) error {
- if len(args) == 0 {
- args = []string{"."}
- }
-
- conf := loader.Config{
- Build: &build.Default,
- ParserMode: parser.ParseComments,
- }
-
- // Use the initial packages from the command line.
- args, err := conf.FromArgs(args, false)
+func runExtract(cmd *Command, config *pipeline.Config, args []string) error {
+ config.Packages = args
+ state, err := pipeline.Extract(config)
if err != nil {
- return err
+ return wrap(err, "extract failed")
}
-
- // Load, parse and type-check the whole program.
- iprog, err := conf.Load()
- if err != nil {
- return err
+ if err := state.Import(); err != nil {
+ return wrap(err, "import failed")
}
-
- // print returns Go syntax for the specified node.
- print := func(n ast.Node) string {
- var buf bytes.Buffer
- format.Node(&buf, conf.Fset, n)
- return buf.String()
+ if err := state.Merge(); err != nil {
+ return wrap(err, "merge failed")
}
-
- var translations []Translation
-
- for _, info := range iprog.InitialPackages() {
- for _, f := range info.Files {
- // Associate comments with nodes.
- cmap := ast.NewCommentMap(iprog.Fset, f, f.Comments)
- getComment := func(n ast.Node) string {
- cs := cmap.Filter(n).Comments()
- if len(cs) > 0 {
- return strings.TrimSpace(cs[0].Text())
- }
- return ""
- }
-
- // Find function calls.
- ast.Inspect(f, func(n ast.Node) bool {
- call, ok := n.(*ast.CallExpr)
- if !ok {
- return true
- }
-
- // Skip calls of functions other than
- // (*message.Printer).{Sp,Fp,P}rintf.
- sel, ok := call.Fun.(*ast.SelectorExpr)
- if !ok {
- return true
- }
- meth := info.Selections[sel]
- if meth == nil || meth.Kind() != types.MethodVal {
- return true
- }
- // TODO: remove cheap hack and check if the type either
- // implements some interface or is specifically of type
- // "golang.org/x/text/message".Printer.
- m, ok := extractFuncs[path.Base(meth.Recv().String())]
- if !ok {
- return true
- }
-
- // argn is the index of the format string.
- argn, ok := m[meth.Obj().Name()]
- if !ok || argn >= len(call.Args) {
- return true
- }
-
- // Skip calls with non-constant format string.
- fmtstr := info.Types[call.Args[argn]].Value
- if fmtstr == nil || fmtstr.Kind() != constant.String {
- return true
- }
-
- posn := conf.Fset.Position(call.Lparen)
- filepos := fmt.Sprintf("%s:%d:%d", filepath.Base(posn.Filename), posn.Line, posn.Column)
-
- // TODO: identify the type of the format argument. If it is not
- // a string, multiple keys may be defined.
- var key []string
-
- // TODO: replace substitutions (%v) with a translator friendly
- // notation. For instance:
- // "%d files remaining" -> "{numFiles} files remaining", or
- // "%d files remaining" -> "{arg1} files remaining"
- // Alternatively, this could be done at a later stage.
- msg := constant.StringVal(fmtstr)
-
- // Construct a Translation unit.
- c := Translation{
- Key: key,
- Position: filepath.Join(info.Pkg.Path(), filepos),
- Original: Text{Msg: msg},
- ExtractedComment: getComment(call.Args[0]),
- // TODO(fix): this doesn't get the before comment.
- // Comment: getComment(call),
- }
-
- for i, arg := range call.Args[argn+1:] {
- var val string
- if v := info.Types[arg].Value; v != nil {
- val = v.ExactString()
- }
- posn := conf.Fset.Position(arg.Pos())
- filepos := fmt.Sprintf("%s:%d:%d", filepath.Base(posn.Filename), posn.Line, posn.Column)
- c.Args = append(c.Args, Argument{
- ID: i + 1,
- Type: info.Types[arg].Type.String(),
- UnderlyingType: info.Types[arg].Type.Underlying().String(),
- Expr: print(arg),
- Value: val,
- Comment: getComment(arg),
- Position: filepath.Join(info.Pkg.Path(), filepos),
- // TODO report whether it implements
- // interfaces plural.Interface,
- // gender.Interface.
- })
- }
-
- translations = append(translations, c)
- return true
- })
- }
- }
-
- data, err := json.MarshalIndent(translations, "", " ")
- if err != nil {
- return err
- }
- for _, tag := range getLangs() {
- // TODO: merge with existing files, don't overwrite.
- os.MkdirAll(*dir, 0744)
- file := filepath.Join(*dir, fmt.Sprintf("gotext_%v.out.json", tag))
- if err := ioutil.WriteFile(file, data, 0744); err != nil {
- return fmt.Errorf("could not create file: %v", err)
- }
- }
- return nil
-}
-
-// extractFuncs indicates the types and methods for which to extract strings,
-// and which argument to extract.
-// TODO: use the types in conf.Import("golang.org/x/text/message") to extract
-// the correct instances.
-var extractFuncs = map[string]map[string]int{
- // TODO: Printer -> *golang.org/x/text/message.Printer
- "message.Printer": {
- "Printf": 0,
- "Sprintf": 0,
- "Fprintf": 1,
- },
+ return wrap(state.Export(), "export failed")
}