mirror of
https://github.com/miniflux/v2.git
synced 2025-08-31 18:31:01 +00:00
First commit
This commit is contained in:
commit
8ffb773f43
2121 changed files with 1118910 additions and 0 deletions
195
vendor/golang.org/x/text/cmd/gotext/extract.go
generated
vendored
Normal file
195
vendor/golang.org/x/text/cmd/gotext/extract.go
generated
vendored
Normal file
|
@ -0,0 +1,195 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// TODO:
|
||||
// - merge information into existing files
|
||||
// - handle different file formats (PO, XLIFF)
|
||||
// - handle features (gender, plural)
|
||||
// - message rewriting
|
||||
|
||||
var cmdExtract = &Command{
|
||||
Run: runExtract,
|
||||
UsageLine: "extract <package>*",
|
||||
Short: "extract 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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Load, parse and type-check the whole program.
|
||||
iprog, err := conf.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
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,
|
||||
},
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue